Skip to content

Commit e32f9c1

Browse files
authored
Merge branch 'main' into bugfix/issue-23824
2 parents 5133af4 + 0ed62db commit e32f9c1

38 files changed

+469
-161
lines changed

.eslintrc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ rules:
164164
jquery/no-parse-html: [2]
165165
jquery/no-prop: [0]
166166
jquery/no-proxy: [2]
167-
jquery/no-ready: [0]
167+
jquery/no-ready: [2]
168168
jquery/no-serialize: [2]
169169
jquery/no-show: [2]
170170
jquery/no-size: [2]

build/update-locales.sh

+4-11
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,10 @@ fi
1717

1818
mv ./options/locale/locale_en-US.ini ./options/
1919

20-
# the "ini" library for locale has many quirks
21-
# * `a="xx"` gets `xx` (no quote)
22-
# * `a=x\"y` gets `x\"y` (no unescaping)
23-
# * `a="x\"y"` gets `"x\"y"` (no unescaping, the quotes are still there)
24-
# * `a='x\"y'` gets `x\"y` (no unescaping, no quote)
25-
# * `a="foo` gets `"foo` (although the quote is not closed)
26-
# * 'a=`foo`' works like single-quote
27-
# crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes
28-
# crowdin always outputs quoted strings if there are quotes in the strings.
29-
30-
# this script helps to unquote the crowdin outputs for the quirky ini library
20+
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
21+
# see i18n_test.go for more details
22+
23+
# this script helps to unquote the Crowdin outputs for the quirky ini library
3124
# * find all `key="...\"..."` lines
3225
# * remove the leading quote
3326
# * remove the trailing quote

models/auth/source.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,14 @@ func UpdateSource(source *Source) error {
317317
}
318318
}
319319

320-
_, err := db.GetEngine(db.DefaultContext).ID(source.ID).AllCols().Update(source)
320+
has, err := db.GetEngine(db.DefaultContext).Where("name=? AND id!=?", source.Name, source.ID).Exist(new(Source))
321+
if err != nil {
322+
return err
323+
} else if has {
324+
return ErrSourceAlreadyExist{source.Name}
325+
}
326+
327+
_, err = db.GetEngine(db.DefaultContext).ID(source.ID).AllCols().Update(source)
321328
if err != nil {
322329
return err
323330
}

models/migrations/migrations.go

+2
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,8 @@ var migrations = []Migration{
477477
NewMigration("Add version column to action_runner table", v1_20.AddVersionToActionRunner),
478478
// v249 -> v250
479479
NewMigration("Improve Action table indices v3", v1_20.ImproveActionTableIndices),
480+
// v250 -> v251
481+
NewMigration("Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch),
480482
}
481483

482484
// GetCurrentDBVersion returns the current db version

models/migrations/v1_20/v250.go

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_20 //nolint
5+
6+
import (
7+
"strings"
8+
9+
"code.gitea.io/gitea/modules/json"
10+
11+
"xorm.io/xorm"
12+
)
13+
14+
func ChangeContainerMetadataMultiArch(x *xorm.Engine) error {
15+
sess := x.NewSession()
16+
defer sess.Close()
17+
18+
if err := sess.Begin(); err != nil {
19+
return err
20+
}
21+
22+
type PackageVersion struct {
23+
ID int64 `xorm:"pk"`
24+
MetadataJSON string `xorm:"metadata_json"`
25+
}
26+
27+
type PackageBlob struct{}
28+
29+
// Get all relevant packages (manifest list images have a container.manifest.reference property)
30+
31+
var pvs []*PackageVersion
32+
err := sess.
33+
Table("package_version").
34+
Select("id, metadata_json").
35+
Where("id IN (SELECT DISTINCT ref_id FROM package_property WHERE ref_type = 0 AND name = 'container.manifest.reference')").
36+
Find(&pvs)
37+
if err != nil {
38+
return err
39+
}
40+
41+
type MetadataOld struct {
42+
Type string `json:"type"`
43+
IsTagged bool `json:"is_tagged"`
44+
Platform string `json:"platform,omitempty"`
45+
Description string `json:"description,omitempty"`
46+
Authors []string `json:"authors,omitempty"`
47+
Licenses string `json:"license,omitempty"`
48+
ProjectURL string `json:"project_url,omitempty"`
49+
RepositoryURL string `json:"repository_url,omitempty"`
50+
DocumentationURL string `json:"documentation_url,omitempty"`
51+
Labels map[string]string `json:"labels,omitempty"`
52+
ImageLayers []string `json:"layer_creation,omitempty"`
53+
MultiArch map[string]string `json:"multiarch,omitempty"`
54+
}
55+
56+
type Manifest struct {
57+
Platform string `json:"platform"`
58+
Digest string `json:"digest"`
59+
Size int64 `json:"size"`
60+
}
61+
62+
type MetadataNew struct {
63+
Type string `json:"type"`
64+
IsTagged bool `json:"is_tagged"`
65+
Platform string `json:"platform,omitempty"`
66+
Description string `json:"description,omitempty"`
67+
Authors []string `json:"authors,omitempty"`
68+
Licenses string `json:"license,omitempty"`
69+
ProjectURL string `json:"project_url,omitempty"`
70+
RepositoryURL string `json:"repository_url,omitempty"`
71+
DocumentationURL string `json:"documentation_url,omitempty"`
72+
Labels map[string]string `json:"labels,omitempty"`
73+
ImageLayers []string `json:"layer_creation,omitempty"`
74+
Manifests []*Manifest `json:"manifests,omitempty"`
75+
}
76+
77+
for _, pv := range pvs {
78+
var old *MetadataOld
79+
if err := json.Unmarshal([]byte(pv.MetadataJSON), &old); err != nil {
80+
return err
81+
}
82+
83+
// Calculate the size of every contained manifest
84+
85+
manifests := make([]*Manifest, 0, len(old.MultiArch))
86+
for platform, digest := range old.MultiArch {
87+
size, err := sess.
88+
Table("package_blob").
89+
Join("INNER", "package_file", "package_blob.id = package_file.blob_id").
90+
Join("INNER", "package_version pv", "pv.id = package_file.version_id").
91+
Join("INNER", "package_version pv2", "pv2.package_id = pv.package_id").
92+
Where("pv.lower_version = ? AND pv2.id = ?", strings.ToLower(digest), pv.ID).
93+
SumInt(new(PackageBlob), "size")
94+
if err != nil {
95+
return err
96+
}
97+
98+
manifests = append(manifests, &Manifest{
99+
Platform: platform,
100+
Digest: digest,
101+
Size: size,
102+
})
103+
}
104+
105+
// Convert to new metadata format
106+
107+
new := &MetadataNew{
108+
Type: old.Type,
109+
IsTagged: old.IsTagged,
110+
Platform: old.Platform,
111+
Description: old.Description,
112+
Authors: old.Authors,
113+
Licenses: old.Licenses,
114+
ProjectURL: old.ProjectURL,
115+
RepositoryURL: old.RepositoryURL,
116+
DocumentationURL: old.DocumentationURL,
117+
Labels: old.Labels,
118+
ImageLayers: old.ImageLayers,
119+
Manifests: manifests,
120+
}
121+
122+
metadataJSON, err := json.Marshal(new)
123+
if err != nil {
124+
return err
125+
}
126+
127+
pv.MetadataJSON = string(metadataJSON)
128+
129+
if _, err := sess.ID(pv.ID).Update(pv); err != nil {
130+
return err
131+
}
132+
}
133+
134+
return sess.Commit()
135+
}

modules/packages/container/metadata.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ type Metadata struct {
6262
DocumentationURL string `json:"documentation_url,omitempty"`
6363
Labels map[string]string `json:"labels,omitempty"`
6464
ImageLayers []string `json:"layer_creation,omitempty"`
65-
MultiArch map[string]string `json:"multiarch,omitempty"`
65+
Manifests []*Manifest `json:"manifests,omitempty"`
66+
}
67+
68+
type Manifest struct {
69+
Platform string `json:"platform"`
70+
Digest string `json:"digest"`
71+
Size int64 `json:"size"`
6672
}
6773

6874
// ParseImageConfig parses the metadata of an image config

modules/packages/container/metadata_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestParseImageConfig(t *testing.T) {
4646
},
4747
metadata.Labels,
4848
)
49-
assert.Empty(t, metadata.MultiArch)
49+
assert.Empty(t, metadata.Manifests)
5050

5151
configHelm := `{"description":"` + description + `", "home": "` + projectURL + `", "sources": ["` + repositoryURL + `"], "maintainers":[{"name":"` + author + `"}]}`
5252

modules/public/public.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,15 @@ func AssetsHandlerFunc(opts *Options) http.HandlerFunc {
4545
return
4646
}
4747

48-
var corsSent bool
4948
if opts.CorsHandler != nil {
49+
var corsSent bool
5050
opts.CorsHandler(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
5151
corsSent = true
5252
})).ServeHTTP(resp, req)
53-
}
54-
// If CORS is not sent, the response must have been written by other handlers
55-
if !corsSent {
56-
return
53+
// If CORS is not sent, the response must have been written by other handlers
54+
if !corsSent {
55+
return
56+
}
5757
}
5858

5959
file := req.URL.Path[len(opts.Prefix):]

modules/translation/i18n/i18n_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package i18n
55

66
import (
7+
"strings"
78
"testing"
89

910
"github.com/stretchr/testify/assert"
@@ -75,3 +76,56 @@ c=22
7576
assert.Equal(t, "21", ls.Tr("lang1", "b"))
7677
assert.Equal(t, "22", ls.Tr("lang1", "c"))
7778
}
79+
80+
func TestLocaleStoreQuirks(t *testing.T) {
81+
const nl = "\n"
82+
q := func(q1, s string, q2 ...string) string {
83+
return q1 + s + strings.Join(q2, "")
84+
}
85+
testDataList := []struct {
86+
in string
87+
out string
88+
hint string
89+
}{
90+
{` xx`, `xx`, "simple, no quote"},
91+
{`" xx"`, ` xx`, "simple, double-quote"},
92+
{`' xx'`, ` xx`, "simple, single-quote"},
93+
{"` xx`", ` xx`, "simple, back-quote"},
94+
95+
{`x\"y`, `x\"y`, "no unescape, simple"},
96+
{q(`"`, `x\"y`, `"`), `"x\"y"`, "unescape, double-quote"},
97+
{q(`'`, `x\"y`, `'`), `x\"y`, "no unescape, single-quote"},
98+
{q("`", `x\"y`, "`"), `x\"y`, "no unescape, back-quote"},
99+
100+
{q(`"`, `x\"y`) + nl + "b=", `"x\"y`, "half open, double-quote"},
101+
{q(`'`, `x\"y`) + nl + "b=", `'x\"y`, "half open, single-quote"},
102+
{q("`", `x\"y`) + nl + "b=`", `x\"y` + nl + "b=", "half open, back-quote, multi-line"},
103+
104+
{`x ; y`, `x ; y`, "inline comment (;)"},
105+
{`x # y`, `x # y`, "inline comment (#)"},
106+
{`x \; y`, `x ; y`, `inline comment (\;)`},
107+
{`x \# y`, `x # y`, `inline comment (\#)`},
108+
}
109+
110+
for _, testData := range testDataList {
111+
ls := NewLocaleStore()
112+
err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil)
113+
assert.NoError(t, err, testData.hint)
114+
assert.Equal(t, testData.out, ls.Tr("lang1", "a"), testData.hint)
115+
assert.NoError(t, ls.Close())
116+
}
117+
118+
// TODO: Crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes
119+
// and Crowdin always outputs quoted strings if there are quotes in the strings.
120+
// So, Gitea's `key="quoted" unquoted` content shouldn't be used on Crowdin directly,
121+
// it should be converted to `key="\"quoted\" unquoted"` first.
122+
// TODO: We can not use UnescapeValueDoubleQuotes=true, because there are a lot of back-quotes in en-US.ini,
123+
// then Crowdin will output:
124+
// > key = "`x \" y`"
125+
// Then Gitea will read a string with back-quotes, which is incorrect.
126+
// TODO: Crowdin might generate multi-line strings, quoted by double-quote, it's not supported by LocaleStore
127+
// LocaleStore uses back-quote for multi-line strings, it's not supported by Crowdin.
128+
// TODO: Crowdin doesn't support back-quote as string quoter, it mainly uses double-quote
129+
// so, the following line will be parsed as: value="`first", comment="second`" on Crowdin
130+
// > a = `first; second`
131+
}

options/locale/locale_en-US.ini

+4-4
Original file line numberDiff line numberDiff line change
@@ -2140,10 +2140,10 @@ settings.dismiss_stale_approvals_desc = When new commits that change the content
21402140
settings.require_signed_commits = Require Signed Commits
21412141
settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable.
21422142
settings.protect_branch_name_pattern = Protected Branch Name Pattern
2143-
settings.protect_protected_file_patterns = `Protected file patterns (separated using semicolon ';'):`
2144-
settings.protect_protected_file_patterns_desc = `Protected files are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon (';'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
2145-
settings.protect_unprotected_file_patterns = `Unprotected file patterns (separated using semicolon ';'):`
2146-
settings.protect_unprotected_file_patterns_desc = `Unprotected files that are allowed to be changed directly if user has write access, bypassing push restriction. Multiple patterns can be separated using semicolon (';'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
2143+
settings.protect_protected_file_patterns = "Protected file patterns (separated using semicolon ';'):"
2144+
settings.protect_protected_file_patterns_desc = "Protected files are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon (';'). See <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>."
2145+
settings.protect_unprotected_file_patterns = "Unprotected file patterns (separated using semicolon ';'):"
2146+
settings.protect_unprotected_file_patterns_desc = "Unprotected files that are allowed to be changed directly if user has write access, bypassing push restriction. Multiple patterns can be separated using semicolon (';'). See <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>."
21472147
settings.add_protected_branch = Enable protection
21482148
settings.delete_protected_branch = Disable protection
21492149
settings.update_protect_branch_success = Branch protection for rule '%s' has been updated.

options/locale/locale_pt-PT.ini

+8-4
Original file line numberDiff line numberDiff line change
@@ -2140,10 +2140,10 @@ settings.dismiss_stale_approvals_desc=Quando novos cometimentos que mudam o cont
21402140
settings.require_signed_commits=Exigir cometimentos assinados
21412141
settings.require_signed_commits_desc=Rejeitar envios para este ramo que não estejam assinados ou que não sejam validáveis.
21422142
settings.protect_branch_name_pattern=Padrão do nome do ramo protegido
2143-
settings.protect_protected_file_patterns=`Padrões de ficheiros protegidos (separados com ponto e vírgula ' ;'):`
2144-
settings.protect_protected_file_patterns_desc=`Não é permitido alterar imediatamente ficheiros protegidos, mesmo que o utilizador tenha autorização para adicionar, editar ou eliminar ficheiros neste ramo. Podem ser usados múltiplos padrões separados por ponto e vírgula (' ;'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
2145-
settings.protect_unprotected_file_patterns=`Padrões de ficheiros desprotegidos (separados com ponto e vírgula ' ;'):`
2146-
settings.protect_unprotected_file_patterns_desc=`Ficheiros desprotegidos que é permitido alterar imediatamente se o utilizador tiver permissão de escrita, passando ao lado da restrição no envio. Podem ser usados múltiplos padrões separados por ponto e vírgula (' ;'). See <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> documentation for pattern syntax. Examples: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.`
2143+
settings.protect_protected_file_patterns=Padrões de ficheiros protegidos (separados com ponto e vírgula ';'):
2144+
settings.protect_protected_file_patterns_desc=Ficheiros protegidos não podem ser modificados imediatamente, mesmo que o utilizador tenha direitos para adicionar, editar ou eliminar ficheiros neste ramo. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> para ver a sintaxe. Exemplos: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
2145+
settings.protect_unprotected_file_patterns=Padrões de ficheiros desprotegidos (separados com ponto e vírgula ';'):
2146+
settings.protect_unprotected_file_patterns_desc=Ficheiros desprotegidos que podem ser modificados imediatamente se o utilizador tiver direitos de escrita, contornando a restrição no envio. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em <a href='https://pkg.go.dev/github.com/gobwas/glob#Compile'>github.com/gobwas/glob</a> para ver a sintaxe. Exemplos: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
21472147
settings.add_protected_branch=Habilitar salvaguarda
21482148
settings.delete_protected_branch=Desabilitar salvaguarda
21492149
settings.update_protect_branch_success=A salvaguarda do ramo '%s' foi modificada.
@@ -2280,6 +2280,8 @@ diff.image.side_by_side=Lado a Lado
22802280
diff.image.swipe=Deslizar
22812281
diff.image.overlay=Sobrepor
22822282
diff.has_escaped=Esta linha tem caracteres unicode escondidos
2283+
diff.show_file_tree=Mostrar árvore de ficheiros
2284+
diff.hide_file_tree=Esconder árvore de ficheiros
22832285

22842286
releases.desc=Acompanhe as versões e as descargas do repositório.
22852287
release.releases=Lançamentos
@@ -2293,6 +2295,7 @@ release.compare=Comparar
22932295
release.edit=editar
22942296
release.ahead.commits=<strong>%d</strong> cometimentos
22952297
release.ahead.target=para %s desde este lançamento
2298+
tag.ahead.target=para o ramo %s desde esta etiqueta
22962299
release.source_code=Código fonte
22972300
release.new_subheader=Lançamentos organizam as versões do trabalho.
22982301
release.edit_subheader=Lançamentos organizam as versões do trabalho.
@@ -3364,6 +3367,7 @@ runners.status.idle=Parada
33643367
runners.status.active=Em funcionamento
33653368
runners.status.offline=Desconectada
33663369
runners.version=Versão
3370+
runners.reset_registration_token_success=O código de incrição do executor foi reposto com sucesso
33673371

33683372
runs.all_workflows=Todas as sequências de trabalho
33693373
runs.open_tab=%d abertas

0 commit comments

Comments
 (0)