diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 17d6cd3a35e0..b4b4f3a8a2be 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 43ec470ad0ec..04923acdcb9a 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/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 12458e954ade..570c4f47041d 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 8c07184b21ee..3d12be477c74 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()) + }) } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6e7ce7e67fd3..13821da44d67 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/user" + "code.gitea.io/gitea/modules/util" ) // settings @@ -158,9 +159,11 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { func loadRunModeFrom(rootCfg ConfigProvider) { rootSec := rootCfg.Section("") RunUser = rootSec.Key("RUN_USER").MustString(user.CurrentUsername()) + // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. unsafeAllowRunAsRoot := ConfigSectionKeyBool(rootSec, "I_AM_BEING_UNSAFE_RUNNING_AS_ROOT") + unsafeAllowRunAsRoot = unsafeAllowRunAsRoot || util.OptionalBoolParse(os.Getenv("GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT")).Value() RunMode = os.Getenv("GITEA_RUN_MODE") if RunMode == "" { RunMode = rootSec.Key("RUN_MODE").MustString("prod") diff --git a/modules/structs/user.go b/modules/structs/user.go index c43558be5d2b..21ecc1479e2b 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 e03862d7b9aa..471e7d9c4e3f 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 fb6d185ee7de..e2ad511d2b96 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/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index d84191dca2b1..fafb6ab40efe 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/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 221b34b7f813..f835df084dd2 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": { diff --git a/templates/user/dashboard/milestones.tmpl b/templates/user/dashboard/milestones.tmpl index 7cde02291be7..fd684fcabf58 100644 --- a/templates/user/dashboard/milestones.tmpl +++ b/templates/user/dashboard/milestones.tmpl @@ -62,8 +62,8 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}