chore: adapt to go 1.27

Restore the toolchain pin renovate dropped. The go directive has to lose
its patch version for that: go removes a toolchain equal to it, and every
go command then refuses to run until go.mod is tidied.

Go 1.27 changes the flate encoder, so the sizes and checksums pinned by
package tests move with the compressed output. Hash the avatar test input
directly instead of a png, which has no bearing on what it asserts.

encoding/json v2 is no longer an experiment, so drop the v1 implementation
and GOEXPERIMENT=jsonv2 with it.

Assisted-by: Claude Code:Opus 5
This commit is contained in:
silverwind
2026-08-19 19:49:51 +02:00
parent 1f3901c149
commit 052bc4b496
21 changed files with 54 additions and 132 deletions
+2 -3
View File
@@ -37,7 +37,7 @@ jobs:
- uses: ./.github/actions/go-setup
- run: make deps-backend deps-tools
- run: TAGS="bindata" make backend
- run: TAGS="bindata gogit" GOEXPERIMENT="" make backend
- run: TAGS="bindata gogit" make backend
- name: warm test compile cache (bindata)
env:
TAGS: bindata
@@ -46,13 +46,12 @@ jobs:
- name: warm test compile cache (bindata gogit)
env:
TAGS: bindata gogit
GOEXPERIMENT:
GOTEST_FLAGS: -race -list=^$$ -count=1
run: make test-backend
- name: warm integration compile cache
run: |
TAGS="bindata" make test-integration-compile
TAGS="bindata gogit" GOEXPERIMENT="" make test-integration-compile
TAGS="bindata gogit" make test-integration-compile
TAGS="bindata gogit" GOTEST_FLAGS="-race" make test-integration-compile
lint:
-3
View File
@@ -96,7 +96,6 @@ jobs:
- run: make backend
env:
TAGS: bindata gogit
GOEXPERIMENT:
- run: GITEA_TEST_DATABASE=sqlite make test-migration
env:
TAGS: bindata gogit
@@ -107,7 +106,6 @@ jobs:
# sqlite driver can contain large amount of Golang code, so don't use race detector for it, otherwise, extremely slow
GOTEST_FLAGS: -timeout=40m
TAGS: bindata gogit
GOEXPERIMENT:
test-unit:
if: needs.files-changed.outputs.backend == 'true'
@@ -170,7 +168,6 @@ jobs:
env:
GOTEST_FLAGS: -race -timeout=20m
TAGS: bindata gogit
GOEXPERIMENT:
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
GITEA_TEST_CI_SKIP_EXTERNAL: true
- run: make test-check
+1 -5
View File
@@ -1,10 +1,6 @@
DIST := dist
DIST_DIRS := $(DIST)/binaries $(DIST)/release
# By default use go's 1.25 experimental json v2 library when building
# TODO: remove when no longer experimental
export GOEXPERIMENT ?= jsonv2
GO ?= go
SHASUM ?= shasum -a 256
COMMA := ,
@@ -516,7 +512,7 @@ generate-go: $(TAGS_PREREQ)
.PHONY: security-check
security-check:
GOEXPERIMENT= go run $(GOVULNCHECK_PACKAGE) -show color ./... || true
go run $(GOVULNCHECK_PACKAGE) -show color ./... || true
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
+1
View File
@@ -36,6 +36,7 @@ var curveStringMap = map[string]tls.CurveID{
"p256": tls.CurveP256,
"p384": tls.CurveP384,
"p521": tls.CurveP521,
"mlkem1024": tls.MLKEM1024,
"x25519mlkem768": tls.X25519MLKEM768,
"secp256r1mlkem768": tls.SecP256r1MLKEM768,
"secp384r1mlkem1024": tls.SecP384r1MLKEM1024,
+3 -1
View File
@@ -1,6 +1,8 @@
module gitea.dev
go 1.27.0
go 1.27
toolchain go1.27.0
require (
connectrpc.com/connect v1.20.0
+3 -3
View File
@@ -186,11 +186,11 @@ func (l *Label) ExclusiveScope() string {
if !l.Exclusive {
return ""
}
lastIndex := strings.LastIndex(l.Name, "/")
if lastIndex == -1 || lastIndex == 0 || lastIndex == len(l.Name)-1 {
scope, name, found := strings.CutLast(l.Name, "/")
if !found || scope == "" || name == "" {
return ""
}
return l.Name[:lastIndex]
return scope
}
// CompareLabelForDisplay compares labels for displaying them in dropdowns or lists.
+3 -3
View File
@@ -16,11 +16,11 @@ import (
// LookupFederatedHost returns the avatar host from the email domain's SRV record. https://wiki.libravatar.org/api/
func LookupFederatedHost(ctx context.Context, email string, secure bool) string {
at := strings.LastIndexByte(email, '@')
if at < 0 {
_, domain, found := strings.CutLast(email, "@")
if !found {
return ""
}
domain := strings.ToLower(email[at+1:])
domain = strings.ToLower(domain)
service, defaultPort := "avatars", uint16(80)
if secure {
+4 -9
View File
@@ -4,9 +4,6 @@
package avatar_test
import (
"bytes"
"image"
"image/png"
"testing"
"gitea.dev/modules/avatar"
@@ -15,12 +12,10 @@ import (
)
func Test_HashAvatar(t *testing.T) {
myImage := image.NewRGBA(image.Rect(0, 0, 32, 32))
var buff bytes.Buffer
png.Encode(&buff, myImage)
data := []byte("data")
assert.Equal(t, "9ddb5bac41d57e72aa876321d0c09d71090c05f94bc625303801be2f3240d2cb", avatar.HashAvatar(1, buff.Bytes()))
assert.Equal(t, "9a5d44e5d637b9582a976676e8f3de1dccd877c2fe3e66ca3fab1629f2f47609", avatar.HashAvatar(8, buff.Bytes()))
assert.Equal(t, "ed7399158672088770de6f5211ce15528ebd675e92fc4fc060c025f4b2794ccb", avatar.HashAvatar(1024, buff.Bytes()))
assert.Equal(t, "912b5d144e1f82719c79d4014fd9dc075aea506be410fb782d50c4f299f845f4", avatar.HashAvatar(1, data))
assert.Equal(t, "55e41725707388f35483f881b2f38405fd9a6883365a862b8a5350ed6737c6fe", avatar.HashAvatar(8, data))
assert.Equal(t, "473f06c83edcf69a9122db1d32f7649ebaa2680678e20ed0f868d25bd272abe8", avatar.HashAvatar(1024, data))
assert.Equal(t, "161178642c7d59eb25a61dddced5e6b66eae1c70880d5f148b1b497b767e72d9", avatar.HashAvatar(1024, []byte{}))
}
+12 -12
View File
@@ -55,12 +55,12 @@ func GetSigningKey(ctx context.Context) (*SigningKey, *Signature) {
}
return &SigningKey{
KeyID: strings.TrimSpace(signingKey),
Format: strings.TrimSpace(format),
}, &Signature{
Name: strings.TrimSpace(signingName),
Email: strings.TrimSpace(signingEmail),
}
KeyID: strings.TrimSpace(signingKey),
Format: strings.TrimSpace(format),
}, &Signature{
Name: strings.TrimSpace(signingName),
Email: strings.TrimSpace(signingEmail),
}
}
if setting.Repository.Signing.SigningKey == "" {
@@ -68,10 +68,10 @@ func GetSigningKey(ctx context.Context) (*SigningKey, *Signature) {
}
return &SigningKey{
KeyID: setting.Repository.Signing.SigningKey,
Format: setting.Repository.Signing.SigningFormat,
}, &Signature{
Name: setting.Repository.Signing.SigningName,
Email: setting.Repository.Signing.SigningEmail,
}
KeyID: setting.Repository.Signing.SigningKey,
Format: setting.Repository.Signing.SigningFormat,
}, &Signature{
Name: setting.Repository.Signing.SigningName,
Email: setting.Repository.Signing.SigningEmail,
}
}
-25
View File
@@ -1,25 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build !goexperiment.jsonv2
package json
import (
"encoding/json" //nolint:depguard // this package wraps it
"io"
)
func getDefaultJSONHandler() Interface {
return jsonV1{}
}
func MarshalKeepOptionalEmpty(v any) ([]byte, error) {
return DefaultJSONHandler.Marshal(v)
}
func NewDecoderCaseInsensitive(reader io.Reader) Decoder {
return DefaultJSONHandler.NewDecoder(reader)
}
type Value = json.RawMessage
-38
View File
@@ -1,38 +0,0 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package json
import (
"bytes"
"encoding/json" //nolint:depguard // this package wraps it
"io"
)
type jsonV1 struct{}
var _ Interface = jsonV1{}
func (jsonV1) Marshal(v any) ([]byte, error) {
return json.Marshal(v)
}
func (jsonV1) MarshalWrite(w io.Writer, v any) error {
return json.NewEncoder(w).Encode(v)
}
func (jsonV1) Unmarshal(data []byte, v any) error {
return json.Unmarshal(data, v)
}
func (jsonV1) NewEncoder(writer io.Writer) Encoder {
return json.NewEncoder(writer)
}
func (jsonV1) NewDecoder(reader io.Reader) Decoder {
return json.NewDecoder(reader)
}
func (jsonV1) Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
return json.Indent(dst, src, prefix, indent)
}
-3
View File
@@ -1,8 +1,6 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//go:build goexperiment.jsonv2
package json
import (
@@ -14,7 +12,6 @@ import (
)
// JSONv2 implements Interface via encoding/json/v2
// Requires GOEXPERIMENT=jsonv2 to be set at build time
type JSONv2 struct {
marshalOptions jsonv2.Options
marshalKeepOptionalEmptyOptions jsonv2.Options
+1 -1
View File
@@ -95,7 +95,7 @@ func TestParsePackage(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, p)
assert.Equal(t, "Q1SRYURM5+uQDqfHSwTnNIOIuuDVQ=", p.FileMetadata.Checksum)
assert.Equal(t, "Q1GfcV5dUrPr1xIRekqPYGehdxjL8=", p.FileMetadata.Checksum)
})
}
+3 -3
View File
@@ -64,12 +64,12 @@ func IsEmailDomainListed(globs []glob.Glob, email string) bool {
return false
}
n := strings.LastIndex(email, "@")
if n <= 0 {
localPart, domain, found := strings.CutLast(email, "@")
if !found || localPart == "" {
return false
}
domain := strings.ToLower(email[n+1:])
domain = strings.ToLower(domain)
for _, g := range globs {
if g.Match(domain) {
+3 -5
View File
@@ -83,12 +83,10 @@ func transformDiffTreeForWeb(renderedIconPool *fileicon.RenderedIconPool, diffTr
dirNodes := map[string]*WebDiffFileItem{"": &dft.TreeRoot}
addItem := func(item *WebDiffFileItem) {
var parentPath string
pos := strings.LastIndexByte(item.FullName, '/')
if pos == -1 {
item.DisplayName = item.FullName
if dir, name, found := strings.CutLast(item.FullName, "/"); found {
parentPath, item.DisplayName = dir, name
} else {
parentPath = item.FullName[:pos]
item.DisplayName = item.FullName[pos+1:]
item.DisplayName = item.FullName
}
parentNode, parentExists := dirNodes[parentPath]
if !parentExists {
@@ -209,7 +209,7 @@ func TestPackageComposer(t *testing.T) {
assert.Len(t, pkgs[0].Authors, 1)
assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
assert.Equal(t, "zip", pkgs[0].Dist.Type)
assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
assert.Equal(t, "f2d7c9059b66874092336aac6b0e96c98b3916c6", pkgs[0].Dist.Checksum)
assert.Len(t, pkgs[0].Bin, 1)
assert.Equal(t, packageBin, pkgs[0].Bin[0])
@@ -239,7 +239,7 @@ func TestPackageComposer(t *testing.T) {
assert.Len(t, pkgs[0].Authors, 1)
assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
assert.Equal(t, "zip", pkgs[0].Dist.Type)
assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
assert.Equal(t, "f2d7c9059b66874092336aac6b0e96c98b3916c6", pkgs[0].Dist.Checksum)
assert.Len(t, pkgs[0].Bin, 1)
assert.Equal(t, packageBin, pkgs[0].Bin[0])
assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
+2 -2
View File
@@ -426,13 +426,13 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`)
pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(633), pb.Size)
assert.Equal(t, int64(635), pb.Size)
case fmt.Sprintf("%s.%s.snupkg", packageName, packageVersion):
assert.False(t, pf.IsLead)
pb, err := packages.GetBlobByID(t.Context(), pf.BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(616), pb.Size)
assert.Equal(t, int64(617), pb.Size)
case packageName + ".nuspec":
assert.False(t, pf.IsLead)
+3 -3
View File
@@ -238,15 +238,15 @@ gpgkey=%sapi/packages/%s/rpm/repository.key`,
switch d.Type {
case "primary":
assert.EqualValues(t, 722, d.Size)
assert.EqualValues(t, 721, d.Size)
assert.EqualValues(t, 1759, d.OpenSize)
assert.Equal(t, "repodata/primary.xml.gz", d.Location.Href)
case "filelists":
assert.EqualValues(t, 257, d.Size)
assert.EqualValues(t, 254, d.Size)
assert.EqualValues(t, 326, d.OpenSize)
assert.Equal(t, "repodata/filelists.xml.gz", d.Location.Href)
case "other":
assert.EqualValues(t, 306, d.Size)
assert.EqualValues(t, 307, d.Size)
assert.EqualValues(t, 394, d.OpenSize)
assert.Equal(t, "repodata/other.xml.gz", d.Location.Href)
}
@@ -245,8 +245,8 @@ func TestPackageRubyGems(t *testing.T) {
b, _ := base64.StdEncoding.DecodeString(`eJxi4Si1EndPzbWyCi5ITc5My0xOLMnMz2M8zMIRLeGpxGWsZ6RnzGbF5hqSyempxJWeWZKayGbN
EBJqJQjWFZZaVJyZnxfN5qnEZahnoGcKkjTwVBJyB6lUKEhMzk5MTwULGngqcRaVJlWCONEMBp5K
DGAWSKc7zFhPJamg0qRK99TcYphehZLU4hKInFhGSUlBsZW+PtgZepn5+iDxECRzDUDGcfh6hoA4
gAAAAP//MS06Gw==`)
DGAWSKc7zFhPJamg0qRK99TcYphehZLU4hKQSk8lsYySkoJiK319sDP0MvP1QeIhSOYagBzC4esZ
wmbNEAIYADEtOhs=`)
assert.Equal(t, b, resp.Body.Bytes())
pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeRubyGems)
@@ -266,11 +266,11 @@ gAAAAP//MS06Gw==`)
assert.Equal(t, expectedContent, resp.Body.Bytes())
}
b, _ := base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3NwZWNzLjQuOABi4Yhmi+bwVOJKzyxJTWSzYnMNCbUSdE/NtbIKSy0qzszPi2bzVOIy1DPQM2WzZgjxVOIsKk2qBDEBAQAA///xOEYKOwAAAA==`)
b, _ := base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3NwZWNzLjQuOAAAOwDE/wQIWwZbCEkiCmdpdGVhBjoGRVRVOhFHZW06OlZlcnNpb25bBkkiCjEuMC41BjsAVEkiCXJ1YnkGOwBUAwDxOEYKOwAAAA==`)
enumeratePackages(t, "specs.4.8.gz", b)
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/2xhdGVzdF9zcGVjcy40LjgAYuGIZovm8FTiSs8sSU1ks2JzDQm1EnRPzbWyCkstKs7Mz4tm81TiMtQz0DNls2YI8VTiLCpNqgQxAQEAAP//8ThGCjsAAAA=`)
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/2xhdGVzdF9zcGVjcy40LjgAADsAxP8ECFsGWwhJIgpnaXRlYQY6BkVUVToRR2VtOjpWZXJzaW9uWwZJIgoxLjAuNQY7AFRJIglydWJ5BjsAVAMA8ThGCjsAAAA=`)
enumeratePackages(t, "latest_specs.4.8.gz", b)
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3ByZXJlbGVhc2Vfc3BlY3MuNC44AGLhiGYABAAA//9snXr5BAAAAA==`)
b, _ = base64.StdEncoding.DecodeString(`H4sICAAAAAAA/3ByZXJlbGVhc2Vfc3BlY3MuNC44AAAEAPv/BAhbAAMAbJ16+QQAAAA=`)
enumeratePackages(t, "prerelease_specs.4.8.gz", b)
})
@@ -295,8 +295,8 @@ gAAAAP//MS06Gw==`)
req := NewRequest(t, "GET", root+"/versions").AddBasicAuth(user.Name)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, `---
gitea 1.0.5 08843c2dd0ea19910e6b056b98e38f1c
gitea-another 0.99 8b639e4048d282941485368ec42609be
gitea 1.0.5 6dc029f6875c637b6e2236c5056f431d
gitea-another 0.99 3f0251d551c97733836b9c983366c36d
`, resp.Body.String())
})
@@ -164,6 +164,6 @@ func TestPackageVagrant(t *testing.T) {
provider := version.Providers[0]
assert.Equal(t, packageProvider, provider.Name)
assert.Equal(t, "sha512", provider.ChecksumType)
assert.Equal(t, "259bebd6160acad695016d22a45812e26f187aaf78e71a4c23ee3201528346293f991af3468a8c6c5d2a21d7d9e1bdc1bf79b87110b2fddfcc5a0d45963c7c30", provider.Checksum)
assert.Equal(t, "27c97e5881fe03dd224dff72dba0d5e7e25c9a0114c1f187f5ce228d7018a3a91398c32b8bc1c11d20d71447169751883da5dab996ff4b173f69fbeed069662e", provider.Checksum)
})
}
+3 -3
View File
@@ -424,13 +424,13 @@ func TestAPIUploadAssetRelease(t *testing.T) {
resp := performUpload(t, assetURL, bufImageBytes, http.StatusCreated)
attachment := DecodeJSON(t, resp, &api.Attachment{})
assert.Equal(t, filename, attachment.Name)
assert.EqualValues(t, 104, attachment.Size)
assert.EqualValues(t, len(bufImageBytes), attachment.Size)
})
t.Run("UploadWithName", func(t *testing.T) {
resp := performUpload(t, assetURL+"?name=test-asset", bufImageBytes, http.StatusCreated)
attachment := DecodeJSON(t, resp, &api.Attachment{})
assert.Equal(t, "test-asset", attachment.Name)
assert.EqualValues(t, 104, attachment.Size)
assert.EqualValues(t, len(bufImageBytes), attachment.Size)
})
})
@@ -449,6 +449,6 @@ func TestAPIUploadAssetRelease(t *testing.T) {
attachment := DecodeJSON(t, resp, &api.Attachment{})
assert.Equal(t, "stream.bin", attachment.Name)
assert.EqualValues(t, 104, attachment.Size)
assert.EqualValues(t, len(bufImageBytes), attachment.Size)
})
}