From e79a807a8461a73bd66146d816f635b66e198c89 Mon Sep 17 00:00:00 2001 From: coldWater <254244460@qq.com> Date: Thu, 14 Mar 2024 10:51:55 +0800 Subject: [PATCH 1/6] Refactor markup/csv: don't read all to memory (#29760) --- modules/markup/csv/csv.go | 57 +++++++++++++++++++++++++++------- modules/markup/csv/csv_test.go | 10 ++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 12458e954ade9..570c4f47041da 100644 --- a/modules/markup/csv/csv.go +++ b/modules/markup/csv/csv.go @@ -77,29 +77,62 @@ func writeField(w io.Writer, element, class, field string) error { } // Render implements markup.Renderer -func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { +func (r Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { tmpBlock := bufio.NewWriter(output) + maxSize := setting.UI.CSV.MaxFileSize - // FIXME: don't read all to memory - rawBytes, err := io.ReadAll(input) + if maxSize == 0 { + return r.tableRender(ctx, input, tmpBlock) + } + + rawBytes, err := io.ReadAll(io.LimitReader(input, maxSize+1)) if err != nil { return err } - if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < int64(len(rawBytes)) { - if _, err := tmpBlock.WriteString("
"); err != nil {
-			return err
-		}
-		if _, err := tmpBlock.WriteString(html.EscapeString(string(rawBytes))); err != nil {
-			return err
+	if int64(len(rawBytes)) <= maxSize {
+		return r.tableRender(ctx, bytes.NewReader(rawBytes), tmpBlock)
+	}
+	return r.fallbackRender(io.MultiReader(bytes.NewReader(rawBytes), input), tmpBlock)
+}
+
+func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error {
+	_, err := tmpBlock.WriteString("
")
+	if err != nil {
+		return err
+	}
+
+	scan := bufio.NewScanner(input)
+	scan.Split(bufio.ScanRunes)
+	for scan.Scan() {
+		switch scan.Text() {
+		case `&`:
+			_, err = tmpBlock.WriteString("&")
+		case `'`:
+			_, err = tmpBlock.WriteString("'") // "'" is shorter than "'" and apos was not in HTML until HTML5.
+		case `<`:
+			_, err = tmpBlock.WriteString("<")
+		case `>`:
+			_, err = tmpBlock.WriteString(">")
+		case `"`:
+			_, err = tmpBlock.WriteString(""") // """ is shorter than """.
+		default:
+			_, err = tmpBlock.Write(scan.Bytes())
 		}
-		if _, err := tmpBlock.WriteString("
"); err != nil { + if err != nil { return err } - return tmpBlock.Flush() } - rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, bytes.NewReader(rawBytes)) + _, err = tmpBlock.WriteString("
") + if err != nil { + return err + } + return tmpBlock.Flush() +} + +func (Renderer) tableRender(ctx *markup.RenderContext, input io.Reader, tmpBlock *bufio.Writer) error { + rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, input) if err != nil { return err } diff --git a/modules/markup/csv/csv_test.go b/modules/markup/csv/csv_test.go index 8c07184b21eeb..3d12be477c745 100644 --- a/modules/markup/csv/csv_test.go +++ b/modules/markup/csv/csv_test.go @@ -4,6 +4,8 @@ package markup import ( + "bufio" + "bytes" "strings" "testing" @@ -29,4 +31,12 @@ func TestRenderCSV(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, v, buf.String()) } + + t.Run("fallbackRender", func(t *testing.T) { + var buf bytes.Buffer + err := render.fallbackRender(strings.NewReader("1,\n2,"), bufio.NewWriter(&buf)) + assert.NoError(t, err) + want := "
1,<a>\n2,<b>
" + assert.Equal(t, want, buf.String()) + }) } From 7a90e5954f8515329f20ff0e391130e1ee7b8864 Mon Sep 17 00:00:00 2001 From: Denys Konovalov Date: Thu, 14 Mar 2024 04:18:04 +0100 Subject: [PATCH 2/6] add skip ci support for pull request title (#29774) Extends #28075 to support [skip ci] inside PR titles. Close #29265 --- custom/conf/app.example.ini | 2 +- .../config-cheat-sheet.en-us.md | 2 +- services/actions/notifier_helper.go | 10 ++-- tests/integration/actions_trigger_test.go | 51 ++++++++++++++++--- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 17d6cd3a35e02..b4b4f3a8a2bea 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2608,7 +2608,7 @@ LEVEL = Info ;ENDLESS_TASK_TIMEOUT = 3h ;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time ;ABANDONED_JOB_TIMEOUT = 24h -;; Strings committers can place inside a commit message to skip executing the corresponding actions workflow +;; Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow ;SKIP_WORKFLOW_STRINGS = [skip ci],[ci skip],[no ci],[skip actions],[actions skip] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 43ec470ad0ecb..04923acdcb9ab 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1406,7 +1406,7 @@ PROXY_HOSTS = *.github.com - `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time - `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time - `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time -- `SKIP_WORKFLOW_STRINGS`: **[skip ci],[ci skip],[no ci],[skip actions],[actions skip]**: Strings committers can place inside a commit message to skip executing the corresponding actions workflow +- `SKIP_WORKFLOW_STRINGS`: **[skip ci],[ci skip],[no ci],[skip actions],[actions skip]**: Strings committers can place inside a commit message or PR title to skip executing the corresponding actions workflow `DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path. For example, `uses: actions/checkout@v4` means `https://github.com/actions/checkout@v4` since the value of `DEFAULT_ACTIONS_URL` is `github`. diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index d84191dca2b17..fafb6ab40efed 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -157,7 +157,7 @@ func notify(ctx context.Context, input *notifyInput) error { return fmt.Errorf("gitRepo.GetCommit: %w", err) } - if skipWorkflowsForCommit(input, commit) { + if skipWorkflows(input, commit) { return nil } @@ -223,8 +223,8 @@ func notify(ctx context.Context, input *notifyInput) error { return handleWorkflows(ctx, detectedWorkflows, commit, input, ref) } -func skipWorkflowsForCommit(input *notifyInput, commit *git.Commit) bool { - // skip workflow runs with a configured skip-ci string in commit message if the event is push or pull_request(_sync) +func skipWorkflows(input *notifyInput, commit *git.Commit) bool { + // skip workflow runs with a configured skip-ci string in commit message or pr title if the event is push or pull_request(_sync) // https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs skipWorkflowEvents := []webhook_module.HookEventType{ webhook_module.HookEventPush, @@ -233,6 +233,10 @@ func skipWorkflowsForCommit(input *notifyInput, commit *git.Commit) bool { } if slices.Contains(skipWorkflowEvents, input.Event) { for _, s := range setting.Actions.SkipWorkflowStrings { + if input.PullRequest != nil && strings.Contains(input.PullRequest.Issue.Title, s) { + log.Debug("repo %s: skipped run for pr %v because of %s string", input.Repo.RepoPath(), input.PullRequest.Issue.ID, s) + return true + } if strings.Contains(commit.CommitMessage, s) { log.Debug("repo %s with commit %s: skipped run because of %s string", input.Repo.RepoPath(), commit.ID, s) return true diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 7744f33e5751f..9a8bfc5db6ecf 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -20,6 +20,7 @@ import ( actions_module "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" files_service "code.gitea.io/gitea/services/repository/files" @@ -199,6 +200,7 @@ func TestPullRequestTargetEvent(t *testing.T) { func TestSkipCI(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { + session := loginUser(t, "user2") user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // create the repo @@ -209,7 +211,7 @@ func TestSkipCI(t *testing.T) { Gitignores: "Go", License: "MIT", Readme: "Default", - DefaultBranch: "main", + DefaultBranch: "master", IsPrivate: false, }) assert.NoError(t, err) @@ -228,12 +230,12 @@ func TestSkipCI(t *testing.T) { { Operation: "create", TreePath: ".gitea/workflows/pr.yml", - ContentReader: strings.NewReader("name: test\non:\n push:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), + ContentReader: strings.NewReader("name: test\non:\n push:\n branches: [master]\n pull_request:\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - run: echo helloworld\n"), }, }, Message: "add workflow", - OldBranch: "main", - NewBranch: "main", + OldBranch: "master", + NewBranch: "master", Author: &files_service.IdentityOptions{ Name: user2.Name, Email: user2.Email, @@ -263,8 +265,8 @@ func TestSkipCI(t *testing.T) { }, }, Message: fmt.Sprintf("%s add bar", setting.Actions.SkipWorkflowStrings[0]), - OldBranch: "main", - NewBranch: "main", + OldBranch: "master", + NewBranch: "master", Author: &files_service.IdentityOptions{ Name: user2.Name, Email: user2.Email, @@ -283,5 +285,42 @@ func TestSkipCI(t *testing.T) { // the commit message contains a configured skip-ci string, so there is still only 1 record assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) + + // add file to new branch + addFileToBranchResp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + Files: []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "test-skip-ci", + ContentReader: strings.NewReader("test-skip-ci"), + }, + }, + Message: "add test file", + OldBranch: "master", + NewBranch: "test-skip-ci", + Author: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Committer: &files_service.IdentityOptions{ + Name: user2.Name, + Email: user2.Email, + }, + Dates: &files_service.CommitDateOptions{ + Author: time.Now(), + Committer: time.Now(), + }, + }) + assert.NoError(t, err) + assert.NotEmpty(t, addFileToBranchResp) + + resp := testPullCreate(t, session, "user2", "skip-ci", true, "master", "test-skip-ci", "[skip ci] test-skip-ci") + + // check the redirected URL + url := test.RedirectURL(resp) + assert.Regexp(t, "^/user2/skip-ci/pulls/[0-9]*$", url) + + // the pr title contains a configured skip-ci string, so there is still only 1 record + assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID})) }) } From eb8c34fc367f324226625d39d0487f945269cd73 Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 14 Mar 2024 05:30:10 +0100 Subject: [PATCH 3/6] Tweak actions view sticky (#29781) Add some space when the left side items are sticky due to scrolling the right side. image --- web_src/js/components/RepoActionView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 96414315080e0..484a3677c54d7 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -524,7 +524,7 @@ export function initRepositoryActionView() { width: 30%; max-width: 400px; position: sticky; - top: 0; + top: 12px; max-height: 100vh; overflow-y: auto; } From 2033eb7c1138a06ea052e6c6e6e5799187519e16 Mon Sep 17 00:00:00 2001 From: sillyguodong <33891828+sillyguodong@users.noreply.github.com> Date: Thu, 14 Mar 2024 12:59:52 +0800 Subject: [PATCH 4/6] Fix lint-swagger warning (#29787) Caused by: #23106 Fix: https://github.com/go-gitea/gitea/actions/runs/8274650046/job/22640335697 1. Delete `UserBadgeList` in `options.go`, because it wasn't used. (The struct defined in `options.go` is the struct used to parse the request body) 2. Move `BadgeList` struct under `routers/api/v1/swagger` folder which response should be defined in. --- modules/structs/user.go | 7 ------- routers/api/v1/swagger/options.go | 3 --- routers/api/v1/swagger/user.go | 7 +++++++ templates/swagger/v1_json.tmpl | 17 +---------------- 4 files changed, 8 insertions(+), 26 deletions(-) diff --git a/modules/structs/user.go b/modules/structs/user.go index c43558be5d2bf..21ecc1479e2b5 100644 --- a/modules/structs/user.go +++ b/modules/structs/user.go @@ -132,10 +132,3 @@ type UserBadgeOption struct { // example: ["badge1","badge2"] BadgeSlugs []string `json:"badge_slugs" binding:"Required"` } - -// BadgeList -// swagger:response BadgeList -type BadgeList struct { - // in:body - Body []Badge `json:"body"` -} diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index e03862d7b9aa6..471e7d9c4e3f6 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -193,7 +193,4 @@ type swaggerParameterBodies struct { // in:body UserBadgeOption api.UserBadgeOption - - // in:body - UserBadgeList api.BadgeList } diff --git a/routers/api/v1/swagger/user.go b/routers/api/v1/swagger/user.go index fb6d185ee7de3..e2ad511d2b966 100644 --- a/routers/api/v1/swagger/user.go +++ b/routers/api/v1/swagger/user.go @@ -48,3 +48,10 @@ type swaggerResponseUserSettings struct { // in:body Body []api.UserSettings `json:"body"` } + +// BadgeList +// swagger:response BadgeList +type swaggerResponseBadgeList struct { + // in:body + Body []api.Badge `json:"body"` +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 221b34b7f8138..f835df084dd22 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -17413,21 +17413,6 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, - "BadgeList": { - "description": "BadgeList", - "type": "object", - "properties": { - "body": { - "description": "in:body", - "type": "array", - "items": { - "$ref": "#/definitions/Badge" - }, - "x-go-name": "Body" - } - }, - "x-go-package": "code.gitea.io/gitea/modules/structs" - }, "Branch": { "description": "Branch represents a repository branch", "type": "object", @@ -24722,7 +24707,7 @@ "parameterBodies": { "description": "parameterBodies", "schema": { - "$ref": "#/definitions/BadgeList" + "$ref": "#/definitions/UserBadgeOption" } }, "redirect": { From 8d979f16928b11779c04c4b547dee3d748cadd51 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 14 Mar 2024 15:40:52 +0800 Subject: [PATCH 5/6] Fix missing translation on milestons (#29785) Caused by #26569 Fix #29778 --- templates/user/dashboard/milestones.tmpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 7cde02291be70..fd684fcabf581 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -62,8 +62,8 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}