diff --git a/build/update-locales.sh b/build/update-locales.sh index 596ddfec032b2..6f9ee334be4a4 100755 --- a/build/update-locales.sh +++ b/build/update-locales.sh @@ -17,17 +17,10 @@ fi mv ./options/locale/locale_en-US.ini ./options/ -# the "ini" library for locale has many quirks -# * `a="xx"` gets `xx` (no quote) -# * `a=x\"y` gets `x\"y` (no unescaping) -# * `a="x\"y"` gets `"x\"y"` (no unescaping, the quotes are still there) -# * `a='x\"y'` gets `x\"y` (no unescaping, no quote) -# * `a="foo` gets `"foo` (although the quote is not closed) -# * 'a=`foo`' works like single-quote -# crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes -# crowdin always outputs quoted strings if there are quotes in the strings. - -# this script helps to unquote the crowdin outputs for the quirky ini library +# the "ini" library for locale has many quirks, its behavior is different from Crowdin. +# see i18n_test.go for more details + +# this script helps to unquote the Crowdin outputs for the quirky ini library # * find all `key="...\"..."` lines # * remove the leading quote # * remove the trailing quote diff --git a/go.mod b/go.mod index ba7ab27c193e7..1ee95b9f59063 100644 --- a/go.mod +++ b/go.mod @@ -289,7 +289,7 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142 replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix -replace github.com/nektos/act => gitea.com/gitea/act v0.243.1 +replace github.com/nektos/act => gitea.com/gitea/act v0.243.2-0.20230329055922-5e76853b55ab exclude github.com/gofrs/uuid v3.2.0+incompatible diff --git a/go.sum b/go.sum index 0faea93e2273e..6bbbbf6eea086 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsi dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= -gitea.com/gitea/act v0.243.1 h1:zIVlhGOLE4SHFPW++u3+5Y/jX5mub3QIhB13oNf6rtA= -gitea.com/gitea/act v0.243.1/go.mod h1:iLHCXqOPUElA2nSyHo4wtxSmvdkym3WU7CkP3AxF39Q= +gitea.com/gitea/act v0.243.2-0.20230329055922-5e76853b55ab h1:HDImhO/XpMJrw2PJcADI/wgur9Gro/pegLFaRt8Wpg0= +gitea.com/gitea/act v0.243.2-0.20230329055922-5e76853b55ab/go.mod h1:mabw6AZAiDgxGlK83orWLrNERSPvgBJzEUS3S7u2bHI= gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681 h1:MMSPgnVULVwV9kEBgvyEUhC9v/uviZ55hPJEMjpbNR4= gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc= gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= diff --git a/models/actions/run.go b/models/actions/run.go index 1af8f897fa08a..22041b65a9b1a 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -197,7 +197,9 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork for _, v := range jobs { id, job := v.Job() needs := job.Needs() - job.EraseNeeds() + if err := v.SetJob(id, job.EraseNeeds()); err != nil { + return err + } payload, _ := v.Marshal() status := StatusWaiting if len(needs) > 0 || run.NeedApproval { diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 1b8b6cc7efb9f..76c144bb2b0f5 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -122,8 +122,8 @@ func detectMatched(commit *git.Commit, triggedEvent webhook_module.HookEventType webhook_module.HookEventRepository, webhook_module.HookEventRelease, webhook_module.HookEventPackage: - if len(evt.Acts) != 0 { - log.Warn("Ignore unsupported %s event arguments %q", triggedEvent, evt.Acts) + if len(evt.Acts()) != 0 { + log.Warn("Ignore unsupported %s event arguments %v", triggedEvent, evt.Acts()) } // no special filter parameters for these events, just return true if name matched return true @@ -148,7 +148,7 @@ func detectMatched(commit *git.Commit, triggedEvent webhook_module.HookEventType func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobparser.Event) bool { // with no special filter parameters - if len(evt.Acts) == 0 { + if len(evt.Acts()) == 0 { return true } @@ -157,7 +157,7 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa hasTagFilter := false refName := git.RefName(pushPayload.Ref) // all acts conditions should be satisfied - for cond, vals := range evt.Acts { + for cond, vals := range evt.Acts() { switch cond { case "branches": hasBranchFilter = true @@ -241,18 +241,18 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa if hasBranchFilter && hasTagFilter { matchTimes++ } - return matchTimes == len(evt.Acts) + return matchTimes == len(evt.Acts()) } func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *jobparser.Event) bool { // with no special filter parameters - if len(evt.Acts) == 0 { + if len(evt.Acts()) == 0 { return true } matchTimes := 0 // all acts conditions should be satisfied - for cond, vals := range evt.Acts { + for cond, vals := range evt.Acts() { switch cond { case "types": for _, val := range vals { @@ -265,19 +265,19 @@ func matchIssuesEvent(commit *git.Commit, issuePayload *api.IssuePayload, evt *j log.Warn("issue event unsupported condition %q", cond) } } - return matchTimes == len(evt.Acts) + return matchTimes == len(evt.Acts()) } func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload, evt *jobparser.Event) bool { // with no special filter parameters - if len(evt.Acts) == 0 { + if len(evt.Acts()) == 0 { // defaultly, only pull request opened and synchronized will trigger workflow return prPayload.Action == api.HookIssueSynchronized || prPayload.Action == api.HookIssueOpened } matchTimes := 0 // all acts conditions should be satisfied - for cond, vals := range evt.Acts { + for cond, vals := range evt.Acts() { switch cond { case "types": action := prPayload.Action @@ -339,18 +339,18 @@ func matchPullRequestEvent(commit *git.Commit, prPayload *api.PullRequestPayload log.Warn("pull request event unsupported condition %q", cond) } } - return matchTimes == len(evt.Acts) + return matchTimes == len(evt.Acts()) } func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCommentPayload, evt *jobparser.Event) bool { // with no special filter parameters - if len(evt.Acts) == 0 { + if len(evt.Acts()) == 0 { return true } matchTimes := 0 // all acts conditions should be satisfied - for cond, vals := range evt.Acts { + for cond, vals := range evt.Acts() { switch cond { case "types": for _, val := range vals { @@ -363,5 +363,5 @@ func matchIssueCommentEvent(commit *git.Commit, issueCommentPayload *api.IssueCo log.Warn("issue comment unsupported condition %q", cond) } } - return matchTimes == len(evt.Acts) + return matchTimes == len(evt.Acts()) } diff --git a/modules/translation/i18n/i18n_test.go b/modules/translation/i18n/i18n_test.go index 76a91522bad27..085d03811f6de 100644 --- a/modules/translation/i18n/i18n_test.go +++ b/modules/translation/i18n/i18n_test.go @@ -4,6 +4,7 @@ package i18n import ( + "strings" "testing" "github.com/stretchr/testify/assert" @@ -75,3 +76,56 @@ c=22 assert.Equal(t, "21", ls.Tr("lang1", "b")) assert.Equal(t, "22", ls.Tr("lang1", "c")) } + +func TestLocaleStoreQuirks(t *testing.T) { + const nl = "\n" + q := func(q1, s string, q2 ...string) string { + return q1 + s + strings.Join(q2, "") + } + testDataList := []struct { + in string + out string + hint string + }{ + {` xx`, `xx`, "simple, no quote"}, + {`" xx"`, ` xx`, "simple, double-quote"}, + {`' xx'`, ` xx`, "simple, single-quote"}, + {"` xx`", ` xx`, "simple, back-quote"}, + + {`x\"y`, `x\"y`, "no unescape, simple"}, + {q(`"`, `x\"y`, `"`), `"x\"y"`, "unescape, double-quote"}, + {q(`'`, `x\"y`, `'`), `x\"y`, "no unescape, single-quote"}, + {q("`", `x\"y`, "`"), `x\"y`, "no unescape, back-quote"}, + + {q(`"`, `x\"y`) + nl + "b=", `"x\"y`, "half open, double-quote"}, + {q(`'`, `x\"y`) + nl + "b=", `'x\"y`, "half open, single-quote"}, + {q("`", `x\"y`) + nl + "b=`", `x\"y` + nl + "b=", "half open, back-quote, multi-line"}, + + {`x ; y`, `x ; y`, "inline comment (;)"}, + {`x # y`, `x # y`, "inline comment (#)"}, + {`x \; y`, `x ; y`, `inline comment (\;)`}, + {`x \# y`, `x # y`, `inline comment (\#)`}, + } + + for _, testData := range testDataList { + ls := NewLocaleStore() + err := ls.AddLocaleByIni("lang1", "Lang1", []byte("a="+testData.in), nil) + assert.NoError(t, err, testData.hint) + assert.Equal(t, testData.out, ls.Tr("lang1", "a"), testData.hint) + assert.NoError(t, ls.Close()) + } + + // TODO: Crowdin needs the strings to be quoted correctly and doesn't like incomplete quotes + // and Crowdin always outputs quoted strings if there are quotes in the strings. + // So, Gitea's `key="quoted" unquoted` content shouldn't be used on Crowdin directly, + // it should be converted to `key="\"quoted\" unquoted"` first. + // TODO: We can not use UnescapeValueDoubleQuotes=true, because there are a lot of back-quotes in en-US.ini, + // then Crowdin will output: + // > key = "`x \" y`" + // Then Gitea will read a string with back-quotes, which is incorrect. + // TODO: Crowdin might generate multi-line strings, quoted by double-quote, it's not supported by LocaleStore + // LocaleStore uses back-quote for multi-line strings, it's not supported by Crowdin. + // TODO: Crowdin doesn't support back-quote as string quoter, it mainly uses double-quote + // so, the following line will be parsed as: value="`first", comment="second`" on Crowdin + // > a = `first; second` +} diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4a529535c2a67..e8797cabea83e 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2141,10 +2141,10 @@ settings.dismiss_stale_approvals_desc = When new commits that change the content settings.require_signed_commits = Require Signed Commits settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable. settings.protect_branch_name_pattern = Protected Branch Name Pattern -settings.protect_protected_file_patterns = `Protected file patterns (separated using semicolon ';'):` -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 github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt.` -settings.protect_unprotected_file_patterns = `Unprotected file patterns (separated using semicolon ';'):` -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 github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt.` +settings.protect_protected_file_patterns = "Protected file patterns (separated using semicolon ';'):" +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 github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt." +settings.protect_unprotected_file_patterns = "Unprotected file patterns (separated using semicolon ';'):" +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 github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt." settings.add_protected_branch = Enable protection settings.delete_protected_branch = Disable protection settings.update_protect_branch_success = Branch protection for rule '%s' has been updated. @@ -2281,6 +2281,8 @@ diff.image.side_by_side = Side by Side diff.image.swipe = Swipe diff.image.overlay = Overlay diff.has_escaped = This line has hidden Unicode characters +diff.show_file_tree = Show file tree +diff.hide_file_tree = Hide file tree releases.desc = Track project versions and downloads. release.releases = Releases diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index abdd4ee62cfd8..35ca44c375bd6 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -1068,6 +1068,7 @@ release=リリース releases=リリース tag=タグ released_this=がこれをリリース +tagged_this=がタグ付け file.title=%s at %s file_raw=Raw file_history=履歴 @@ -1276,6 +1277,7 @@ issues.choose.blank=デフォルト issues.choose.blank_about=デフォルトのテンプレートからイシューを作成。 issues.choose.ignore_invalid_templates=無効なテンプレートが無視されました issues.choose.invalid_templates=無効なテンプレートが%v 件見つかりました +issues.choose.invalid_config=イシューの設定にエラーがあります: issues.no_ref=ブランチ/タグ指定なし issues.create=イシューを作成 issues.new_label=新しいラベル @@ -1489,6 +1491,9 @@ issues.due_date_invalid=期日が正しくないか範囲を超えています issues.dependency.title=依存関係 issues.dependency.issue_no_dependencies=依存関係が設定されていません。 issues.dependency.pr_no_dependencies=依存関係が設定されていません。 +issues.dependency.no_permission_1=%d 個の依存関係への読み取り権限がありません +issues.dependency.no_permission_n=%d 個の依存関係への読み取り権限がありません +issues.dependency.no_permission.can_remove=この依存関係への読み取り権限はありませんが、この依存関係は削除できます issues.dependency.add=依存関係を追加... issues.dependency.cancel=キャンセル issues.dependency.remove=削除 @@ -2284,6 +2289,7 @@ release.compare=比較 release.edit=編集 release.ahead.commits=%d件のコミット release.ahead.target=が、このリリース後 %s に追加されています +tag.ahead.target=が、このタグ付け後 %s に追加されています release.source_code=ソースコード release.new_subheader=リリースで、プロジェクトのバージョンを整理します。 release.edit_subheader=リリースで、プロジェクトのバージョンを整理します。 diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 643b9eaf909b4..3ce03bc93a0c9 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2135,7 +2135,7 @@ settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被 settings.require_signed_commits=需要签名提交 settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支 settings.protect_branch_name_pattern=受保护的分支名称模式 -settings.protect_protected_file_patterns=`受保护的文件模式(使用分号分隔 ' ;'):` +settings.protect_protected_file_patterns=`"受保护的文件模式 (使用分号 '\;' 分隔):" ;'):`` settings.protect_protected_file_patterns_desc=`即使用户有权添加、编辑或删除此分支中的文件,也不允许直接更改受保护的文件。 可以使用分号分隔多个模式(' ;'). See github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt.` settings.protect_unprotected_file_patterns=`不受保护的文件模式 (使用分号分隔 ' ;'):` settings.protect_unprotected_file_patterns_desc=`如果用户有写入权限,则允许直接更改的不受保护的文件,以绕过推送限制。可以使用分号分隔多重模式 (' ;'). See github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt.` diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 1bb9d0480682e..531f14d08627e 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -105,6 +105,7 @@ func NewUserPost(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true ctx.Data["DefaultUserVisibilityMode"] = setting.Service.DefaultUserVisibilityMode + ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() sources, err := auth.Sources() if err != nil { @@ -273,6 +274,7 @@ func EditUserPost(ctx *context.Context) { ctx.Data["PageIsAdmin"] = true ctx.Data["PageIsAdminUsers"] = true ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations + ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() u := prepareUserInfo(ctx) if ctx.Written() { @@ -314,13 +316,13 @@ func EditUserPost(ctx *context.Context) { log.Error(err.Error()) errMsg = ctx.Tr("auth.password_pwned_err") } - ctx.RenderWithErr(errMsg, tplUserNew, &form) + ctx.RenderWithErr(errMsg, tplUserEdit, &form) return } if err := user_model.ValidateEmail(form.Email); err != nil { ctx.Data["Err_Email"] = true - ctx.RenderWithErr(ctx.Tr("form.email_error"), tplUserNew, &form) + ctx.RenderWithErr(ctx.Tr("form.email_error"), tplUserEdit, &form) return } @@ -336,7 +338,10 @@ func EditUserPost(ctx *context.Context) { if len(form.UserName) != 0 && u.Name != form.UserName { if err := user_setting.HandleUsernameChange(ctx, u, form.UserName); err != nil { - ctx.Redirect(setting.AppSubURL + "/admin/users") + if ctx.Written() { + return + } + ctx.RenderWithErr(ctx.Flash.ErrorMsg, tplUserEdit, &form) return } u.Name = form.UserName diff --git a/templates/repo/commit_status.tmpl b/templates/repo/commit_status.tmpl index 470869b381c03..d52e151247afa 100644 --- a/templates/repo/commit_status.tmpl +++ b/templates/repo/commit_status.tmpl @@ -1,5 +1,5 @@ {{if eq .State "pending"}} - {{svg "octicon-dot-fill" 18 "commit-status icon text yellow"}} + {{svg "octicon-dot-fill" 18 "commit-status icon text grey"}} {{end}} {{if eq .State "running"}} {{svg "octicon-dot-fill" 18 "commit-status icon text yellow"}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 4a5fc4b7cf13f..36e669276eff9 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -15,11 +15,18 @@
- + +
{{svg "octicon-diff" 16 "gt-mr-2"}}{{.locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
@@ -68,6 +75,9 @@
+
{{range $i, $file := .Diff.Files}} {{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}} diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 38ed3873ba4c8..80d1bec579552 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -29,9 +29,7 @@
{{if $.CanWriteIssuesOrPulls}} -
- -
+ {{end}} {{template "repo/issue/openclose" .}}
@@ -179,12 +177,12 @@ {{end}} -