From 94a6da3bc8204daebef7dd493d9a891c0d331d9c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 25 Sep 2025 09:32:30 -0700 Subject: [PATCH 01/88] Add changelog for 1.25.0-rc0 (#35531) --- CHANGELOG.md | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b72ac4849aa80..d672fc30b9615 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,207 @@ This changelog goes through the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). +## [1.25.0-rc0](https://github.com/go-gitea/gitea/releases/tag/1.25.0-rc0) - 2025-09-24 + +* BREAKING + * Return 201 Created for CreateVariable API responses (#34517) + * Add label 'state' to metric 'gitea_users' (#34326) +* SECURITY + * Upgrade security public key (#34956) +* FEATURES + * Stream repo zip/tar.gz/bundle achives by default (#35487) + * Use configurable remote name for git commands (#35172) + * Send email on Workflow Run Success/Failure (#34982) + * Refactor OpenIDConnect to support SSH/FullName sync (#34978) + * Refactor repo contents API and add "contents-ext" API (#34822) + * Add support for 3D/CAD file formats preview (#34794) + * Improve instance wide ssh commit signing (#34341) + * Edit file workflow for creating a fork and proposing changes (#34240) + * Follow file symlinks in the UI to their target (#28835) + * Allow renaming/moving binary/LFS files in the UI (#34350) +* PERFORMANCE + * Improve the performance when detecting the file editable (#34653) +* ENHANCEMENTS + * Enable more markdown paste features in textarea editor (#35494) + * Don't store repo archives on `gitea dump` (#35467) + * Always return the relevant status information, even if no status exists. (#35335) + * Add start time on perf trace because it seems some steps haven't been recorded. (#35282) + * Remove deprecated auth sources (#35272) + * When sorting issues by nearest due date, issues without due date should be sorted ascending (#35267) + * Disable field count validation of CSV viewer (#35228) + * Add `has_code` to repository REST API (#35214) + * Display pull request in merged commit view (#35202) + * Support Basic Authentication for archive downloads (#35087) + * Add hover background to table rows in user and repo admin page (#35072) + * Partially refresh notifications list (#35010) + * Also display "recently pushed branch" alert on PR view (#35001) + * Refactor time tracker UI (#34983) + * Improve CLI commands (#34973) + * Improve project & label color picker and image scroll (#34971) + * Improve NuGet API Parity (#21291) (#34940) + * Support getting last commit message using contents-ext API (#34904) + * Adds title on branch commit counts (#34869) + * Add "Cancel workflow run" button to Actions list page (#34817) + * Improve img lazy loading (#34804) + * Forks repository list page follow other repositories page (#34784) + * Add ff_only parameter to POST /repos/{owner}/{repo}/merge-upstream (#34770) + * Rework delete org and rename org UI (#34762) + * Improve nuget/rubygems package registries (#34741) + * Add repo file tree item link behavior (#34730) + * Add issue delete notifier (#34592) + * Improve Actions list (#34530) + * Add a default tab on repo header when migrating (#34503) + * Add post-installation redirect based on admin account status (#34493) + * Trigger 'unlabeled' event when label is Deleted from PR (#34316) + * Support annotated tags when using create release API (#31840) + * Use lfs label for lfs file rather than a long description (#34363) + * Add "View workflow file" to Actions list page (#34538) + * Move organization's visibility change to danger zone. (#34814) +* BUGFIXES + * Fix different behavior in status check pattern matching with double stars (#35474) + * Fix overflow in notifications list (#35446) + * Fix package link setting can only list limited repositories (#35394) + * Extend comment treepath length (#35389) + * Fix font-size in inline code comment preview (#35209) + * Move git config/remote to gitrepo package and add global lock to resolve possible conflict when updating repository git config file (#35151) + * Change some columns from text to longtext and fix column wrong type caused by xorm (#35141) + * Redirect to a presigned URL of HEAD for HEAD requests (#35088) + * Fix git commit committer parsing and add some tests (#35007) + * Fix OCI manifest parser (#34797) + * Refactor FindOrgOptions to use enum instead of bool, fix membership visibility (#34629) + * Fix notification count positioning for variable-width elements (#34597) + * Keeping consistent between UI and API about combined commit status state and fix some bugs (#34562) + * Fix possible panic (#34508) + * Fix autofocus behavior (#34397) + * Fix Actions API (#35204) + * Fix ListWorkflowRuns OpenAPI response model. (#35026) + * Small fix in Pull Requests page (#34612) + * Fix http auth header parsing (#34936) + * Fix modal + form abuse (#34921) + * Fix PR toggle WIP (#34920) + * Fix log fmt (#34810) + * Replace stopwatch toggle with explicit start/stop actions (#34818) + * Fix some package registry problems (#34759) + * Fix RPM package download routing & missing package version count (#34909) + * Fix repo search input height (#34330) + * Fix "The sidebar of the repository file list does not have a fixed height #34298" (#34321) + * Fix minor typos in two files #HSFDPMUW (#34944) + * Fix actions skipped commit status indicator (#34507) + * Fix job status aggregation logic (#35000) + * Fix broken OneDev migration caused by various REST API changes in OneDev 7.8.0 and later (#35216) + * Fix typo in oauth2_full_name_claim_name string (#35199) + * Fix typo in locale_en-US.ini (#35196) +* API + * Exposing TimeEstimate field in the API (#35475) + * UpdateBranch API supports renaming a branch (#35374) + * Add `owner` and `parent` fields clarification to docs (#35023) + * Improve OAuth2 provider (correct Issuer, respect ENABLED) (#34966) + * Add a `login`/`login-name`/`username` disambiguation to affected endpoint parameters and response/request models (#34901) + * Do not mutate incoming options to SearchRepositoryByName (#34553) + * Do not mutate incoming options to RenderUserSearch and SearchUsers (#34544) + * Export repo's manual merge settings (#34502) + * Add date range filtering to commit retrieval endpoints (#34497) + * Add endpoint deleting workflow run (#34337) + * Add workflow_run api + webhook (#33964) +* REFACTOR + * Move updateref and removeref to gitrepo and remove unnecessary open repository (#35511) + * Remove unused param `doer` (#34545) + * Split GetLatestCommitStatus as two functions (#34535) + * Use gitrepo.SetDefaultBranch when set default branch of wiki repository (#33911) + * Refactor editor (#34780) + * Refactor packages (#34777) + * Refactor container package (#34877) + * Refactor "change file" API (#34855) + * Rename pull request GetGitRefName to GetGitHeadRefName to prepare introducing GetGitMergeRefName (#35093) + * Move git command to git/gitcmd (#35483) + * Use db.WithTx/WithTx2 instead of TxContext when possible (#35428) + * Support Node.js 22.6 with type stripping (#35427) + * Migrate tools and configs to typescript, require node.js >= 22.18.0 (#35421) + * Check user and repo for redirects when using git via SSH transport (#35416) + * Remove the duplicated function GetTags (#35375) + * Refactor to use reflect.TypeFor (#35370) + * Deleting branch could delete broken branch which has database record but git branch is missing (#35360) + * Exit with success when already up to date (#35312) + * Split admin config settings templates to make it maintain easier (#35294) + * A small refactor to use context in the service layer (#35179) + * Refactor and update mail templates (#35150) + * Use db.WithTx/WithTx2 instead of TxContext when possible (#35130) + * Align `issue-title-buttons` with `list-header` (#35018) + * Add Notifications section in User Settings (#35008) + * Tweak placement of diff file menu (#34999) + * Refactor mail template and support preview (#34990) + * Rerun job only when run is done (#34970) + * Merge index.js (#34963) + * Refactor "delete-button" to "link-action" (#34962) + * Refactor webhook and fix feishu/lark secret (#34961) + * Exclude devtest.ts from tailwindcss (#34935) + * Refactor head navbar icons (#34922) + * Improve html escape (#34911) + * Improve tags list page (#34898) + * Improve `labels-list` rendering (#34846) + * Remove unused variable HUGO_VERSION (#34840) + * Correct migration tab name (#34826) + * Refactor template helper (#34819) + * Use `shallowRef` instead of `ref` in `.vue` files where possible (#34813) + * Use standalone function to update repository cols (#34811) + * Refactor wiki (#34805) + * Remove unnecessary duplicate code (#34733) + * Refactor embedded assets and drop unnecessary dependencies (#34692) + * Update x/crypto package and make builtin SSH use default parameters (#34667) + * Add `--color-logo`, matching the logo's primary color (#34639) + * Add openssh-keygen to rootless image (#34625) + * Replace update repository function in some places (#34566) + * Change "rejected" to "changes requested" in 3rd party PR review notification (#34481) + * Remove legacy template helper functions (#34426) + * Use run-name and evaluate workflow variables (#34301) + * Move HasWiki to repository service package (#33912) + * Move some functions from package git to gitrepo (#33910) +* TESTING + * Add webhook test for push event (#34442) + * Add a webhook push test for dev branch (#34421) + * Add migrations tests (#34456) (#34498) +* STYLE + * Enforce explanation for necessary nolints and fix bugs (#34883) + * Fix remaining issues after `gopls modernize` formatting (#34771) + * Update gofumpt, add go.mod ignore directive (#35434) + * Enforce nolint scope (#34851) + * Enable gocritic `equalFold` and fix issues (#34952) + * Run `gopls modernize` on codebase (#34751) + * Upgrade `gopls` to v0.19.0, add `make fix` (#34772) +* BUILD + * Use github.com/mholt/archives replace github.com/mholt/archiver (#35390) + * Update JS and PY dependencies (#35444) + * Upgrade devcontainer go version to 1.24.6 (#35298) + * Upgrade golang to 1.25.1 and add descriptions for the swagger structs' fields (#35418) + * Update JS and PY deps (#35191) + * Update JS and PY dependencies (#34391) + * Update go tool dependencies (#34845) + * Update `uint8-to-base64`, remove type stub (#34844) + * Switch to `@resvg/resvg-wasm` for `generate-images` (#35415) + * Switch to pnpm (#35274) + * Update chroma to v2.20.0 (#35220) + * Migrate to urfave v3 (#34510) + * Update JS deps, regenerate SVGs (#34640) + * Upgrade dependencies (#35384) + * Bump `@github/relative-time-element` to v4.4.8 (#34413) + * Update JS dependencies (#34951) + * Upgrade orgmode to v1.8.0 (#34721) + * Raise minimum Node.js version to 20, test on 24 (#34713) + * Update JS deps (#34701) + * Upgrade htmx to 2.0.6 (#34887) + * Update eslint to v9 (#35485) + * Update js dependencies (#35429) + * Clean up npm dependencies (#35508) + * Clean up npm dependencies (#35484) + * Bump setup-node to v5 (#35448) +* MISC + * Add gitignore rules to exclude LLM instruction files (#35076) + * Gitignore: Visual Studio settings folder (#34375) + * Improve language in en-US locale strings (#35124) + * Fixed all grammatical errors in locale_en-US.ini (#35053) + * Docs/fix typo and grammar in CONTRIBUTING.md (#35024) + * Improve english grammar and readability in locale_en-US.ini (#35017) + ## [1.24.0](https://github.com/go-gitea/gitea/releases/tag/1.24.0) - 2025-05-26 * BREAKING From 6c8879b832b11d205ff6b48cf9ed31dc46b96d3e Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 26 Sep 2025 07:11:21 +0800 Subject: [PATCH 02/88] Fix markup init after issue comment editing (#35536) (#35537) Backport #35536 by wxiaoguang Fix #35533 Co-authored-by: wxiaoguang --- routers/web/repo/issue_comment.go | 9 ++++-- templates/repo/issue/view_content.tmpl | 4 --- web_src/js/features/repo-issue-edit.ts | 42 ++++++++++++++------------ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go index cb5b2d801952d..592d1fbde0662 100644 --- a/routers/web/repo/issue_comment.go +++ b/routers/web/repo/issue_comment.go @@ -9,12 +9,14 @@ import ( "html/template" "net/http" "strconv" + "strings" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/renderhelper" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/htmlutil" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" repo_module "code.gitea.io/gitea/modules/repository" @@ -287,9 +289,10 @@ func UpdateCommentContent(ctx *context.Context) { ctx.ServerError("RenderString", err) return } - } else { - contentEmpty := fmt.Sprintf(`%s`, ctx.Tr("repo.issues.no_content")) - renderedContent = template.HTML(contentEmpty) + } + + if strings.TrimSpace(string(renderedContent)) == "" { + renderedContent = htmlutil.HTMLFormat(`%s`, ctx.Tr("repo.issues.no_content")) } ctx.JSON(http.StatusOK, map[string]any{ diff --git a/templates/repo/issue/view_content.tmpl b/templates/repo/issue/view_content.tmpl index a51a7f4fb14a9..56dea5cd4b16b 100644 --- a/templates/repo/issue/view_content.tmpl +++ b/templates/repo/issue/view_content.tmpl @@ -168,10 +168,6 @@ {{template "repo/issue/view_content/reference_issue_dialog" .}} {{template "shared/user/block_user_dialog" .}} -
- {{ctx.Locale.Tr "repo.issues.no_content"}} -
- -
+
diff --git a/web_src/js/svg.ts b/web_src/js/svg.ts index d3da9ca053e94..2ad9bffd51ac4 100644 --- a/web_src/js/svg.ts +++ b/web_src/js/svg.ts @@ -5,6 +5,7 @@ import giteaDoubleChevronLeft from '../../public/assets/img/svg/gitea-double-che import giteaDoubleChevronRight from '../../public/assets/img/svg/gitea-double-chevron-right.svg'; import giteaEmptyCheckbox from '../../public/assets/img/svg/gitea-empty-checkbox.svg'; import giteaExclamation from '../../public/assets/img/svg/gitea-exclamation.svg'; +import giteaRunning from '../../public/assets/img/svg/gitea-running.svg'; import octiconArchive from '../../public/assets/img/svg/octicon-archive.svg'; import octiconArrowSwitch from '../../public/assets/img/svg/octicon-arrow-switch.svg'; import octiconBlocked from '../../public/assets/img/svg/octicon-blocked.svg'; @@ -15,6 +16,7 @@ import octiconCheckCircleFill from '../../public/assets/img/svg/octicon-check-ci import octiconChevronDown from '../../public/assets/img/svg/octicon-chevron-down.svg'; import octiconChevronLeft from '../../public/assets/img/svg/octicon-chevron-left.svg'; import octiconChevronRight from '../../public/assets/img/svg/octicon-chevron-right.svg'; +import octiconCircle from '../../public/assets/img/svg/octicon-circle.svg'; import octiconClock from '../../public/assets/img/svg/octicon-clock.svg'; import octiconCode from '../../public/assets/img/svg/octicon-code.svg'; import octiconColumns from '../../public/assets/img/svg/octicon-columns.svg'; @@ -84,6 +86,7 @@ const svgs = { 'gitea-double-chevron-right': giteaDoubleChevronRight, 'gitea-empty-checkbox': giteaEmptyCheckbox, 'gitea-exclamation': giteaExclamation, + 'gitea-running': giteaRunning, 'octicon-archive': octiconArchive, 'octicon-arrow-switch': octiconArrowSwitch, 'octicon-blocked': octiconBlocked, @@ -94,6 +97,7 @@ const svgs = { 'octicon-chevron-down': octiconChevronDown, 'octicon-chevron-left': octiconChevronLeft, 'octicon-chevron-right': octiconChevronRight, + 'octicon-circle': octiconCircle, 'octicon-clock': octiconClock, 'octicon-code': octiconCode, 'octicon-columns': octiconColumns, diff --git a/web_src/svg/gitea-running.svg b/web_src/svg/gitea-running.svg new file mode 100644 index 0000000000000..6eccaddeed082 --- /dev/null +++ b/web_src/svg/gitea-running.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From f4512426a190b4b524b9f0440b24191a10480a25 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sun, 12 Oct 2025 04:25:03 +0800 Subject: [PATCH 13/88] Fix code tag style problem and LFS view bug (#35628) (#35636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport #35628 by lutinglt Signed-off-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com> Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com> Co-authored-by: wxiaoguang --- routers/web/repo/setting/lfs.go | 3 +-- templates/admin/config.tmpl | 10 +++++----- templates/admin/stacktrace-row.tmpl | 4 ++-- templates/base/alert_details.tmpl | 2 +- templates/projects/view.tmpl | 4 +++- templates/repo/settings/lfs_file.tmpl | 2 +- templates/repo/settings/webhook/history.tmpl | 4 ++-- templates/user/settings/keys_gpg.tmpl | 8 ++++---- templates/user/settings/keys_ssh.tmpl | 9 ++++----- web_src/css/base.css | 6 ++++-- web_src/css/form.css | 6 ++++++ 11 files changed, 33 insertions(+), 25 deletions(-) diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go index af6708e841f46..a558231df1224 100644 --- a/routers/web/repo/setting/lfs.go +++ b/routers/web/repo/setting/lfs.go @@ -270,8 +270,7 @@ func LFSFileGet(ctx *context.Context) { // FIXME: there is no IsPlainText set, but template uses it ctx.Data["IsTextFile"] = st.IsText() ctx.Data["FileSize"] = meta.Size - // FIXME: the last field is the URL-base64-encoded filename, it should not be "direct" - ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/%s.git/info/lfs/objects/%s/%s", setting.AppURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid), "direct") + ctx.Data["RawFileLink"] = fmt.Sprintf("%s/%s/%s.git/info/lfs/objects/%s", setting.AppSubURL, url.PathEscape(ctx.Repo.Repository.OwnerName), url.PathEscape(ctx.Repo.Repository.Name), url.PathEscape(meta.Oid)) switch { case st.IsRepresentableAsText(): if meta.Size >= setting.UI.MaxDisplayFileSize { diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 806347c72049d..080b2cd3d6bab 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -252,9 +252,9 @@ {{end}} {{if .CacheConn}}
{{ctx.Locale.Tr "admin.config.cache_conn"}}
-
{{.CacheConn}}
+
{{.CacheConn}}
{{ctx.Locale.Tr "admin.config.cache_item_ttl"}}
-
{{.CacheItemTTL}}
+
{{.CacheItemTTL}}
{{end}}
{{ctx.Locale.Tr "admin.config.cache_test"}}
@@ -275,7 +275,7 @@
{{ctx.Locale.Tr "admin.config.session_provider"}}
{{.SessionConfig.Provider}}
{{ctx.Locale.Tr "admin.config.provider_config"}}
-
{{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
+
{{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
{{ctx.Locale.Tr "admin.config.cookie_name"}}
{{.SessionConfig.CookieName}}
{{ctx.Locale.Tr "admin.config.gc_interval_time"}}
@@ -301,7 +301,7 @@
{{ctx.Locale.Tr "admin.config.git_max_diff_files"}}
{{.Git.MaxGitDiffFiles}}
{{ctx.Locale.Tr "admin.config.git_gc_args"}}
-
{{.Git.GCArgs}}
+
{{.Git.GCArgs}}
@@ -330,7 +330,7 @@ {{if .Loggers.access.IsEnabled}}
{{ctx.Locale.Tr "admin.config.access_log_template"}}
-
{{$.AccessLogTemplate}}
+
{{$.AccessLogTemplate}}
{{end}} {{range $loggerName, $loggerDetail := .Loggers}} diff --git a/templates/admin/stacktrace-row.tmpl b/templates/admin/stacktrace-row.tmpl index db7ed81c79370..356c517935f83 100644 --- a/templates/admin/stacktrace-row.tmpl +++ b/templates/admin/stacktrace-row.tmpl @@ -46,8 +46,8 @@
{{svg "octicon-dot-fill" 16}}
-
{{.Function}}
-
{{.File}}:{{.Line}}
+
{{.Function}}
+
{{.File}}:{{.Line}}
{{end}} diff --git a/templates/base/alert_details.tmpl b/templates/base/alert_details.tmpl index 6d4c1fb2db220..6380a72498c40 100644 --- a/templates/base/alert_details.tmpl +++ b/templates/base/alert_details.tmpl @@ -2,7 +2,7 @@ {{if .Details}}
{{.Summary}} - {{.Details | SanitizeHTML}} + {{.Details | SanitizeHTML}}
{{else}}
diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 692808a32dedc..21bc287643014 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -65,7 +65,9 @@
- {{$.Project.RenderedContent}} +
+ {{$.Project.RenderedContent}} +
diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl index cd1b168401d45..e9f4afda264cd 100644 --- a/templates/repo/settings/lfs_file.tmpl +++ b/templates/repo/settings/lfs_file.tmpl @@ -39,7 +39,7 @@ {{.LineNums}} -
    {{.FileContent}}
+
{{.FileContent}}
diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index 953ba69670eec..d27c1fb8b12cd 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -68,7 +68,7 @@ {{range $key, $val := .RequestInfo.Headers}}{{$key}}: {{$val}} {{end}}
{{ctx.Locale.Tr "repo.settings.webhook.payload"}}
-
{{or .RequestInfo.Body .PayloadContent}}
+
{{or .RequestInfo.Body .PayloadContent}}
{{else}} - {{end}} @@ -79,7 +79,7 @@
{{range $key, $val := .ResponseInfo.Headers}}{{$key}}: {{$val}}
 {{end}}
{{ctx.Locale.Tr "repo.settings.webhook.body"}}
-
{{.ResponseInfo.Body}}
+
{{.ResponseInfo.Body}}
{{else}} - {{end}} diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index e44a838b25a20..bb45ea58c5cb4 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -21,8 +21,8 @@
-

{{ctx.Locale.Tr "settings.gpg_token_help"}}

-

{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` .TokenToSign .PaddedKeyID}}

+ {{ctx.Locale.Tr "settings.gpg_token_help"}} +
{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` .TokenToSign .PaddedKeyID}}
@@ -89,8 +89,8 @@
-

{{ctx.Locale.Tr "settings.gpg_token_help"}}

-

{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` $.TokenToSign .PaddedKeyID}}

+ {{ctx.Locale.Tr "settings.gpg_token_help"}} +
{{printf `echo "%s" | gpg -a --default-key %s --detach-sig` $.TokenToSign .PaddedKeyID}}

diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index 9d62d4ab08f8b..02bcc937ffab9 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -77,16 +77,15 @@
-

{{ctx.Locale.Tr "settings.ssh_token_help"}}

-

echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey

+ {{ctx.Locale.Tr "settings.ssh_token_help"}} +
echo -n '{{$.TokenToSign}}' | ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey
Windows PowerShell -

cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey"

+
cmd /c "<NUL set /p=`"{{$.TokenToSign}}`"| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey"
-
Windows CMD -

set /p={{$.TokenToSign}}| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey

+
set /p={{$.TokenToSign}}| ssh-keygen -Y sign -n gitea -f /path_to_PrivateKey_or_RelatedPublicKey

diff --git a/web_src/css/base.css b/web_src/css/base.css index 9cef92019d08b..8b77e55fa3cd4 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -101,11 +101,13 @@ samp, font-size: 0.95em; /* compensate for monospace fonts being usually slightly larger */ } -code { +/* there are many blocks in non-markup(.markup code) / non-code-diff(code.code-inner) containers (for example: translation strings, etc), +so we need to make have default global styles, ".markup code" has its own styles and doesn't conflict, but `.code-inner` is special. +TODO: in the future, we should use `div` instead of `code` for `.code-inner` because it is a container for highlighted code line */ +code:not(.code-inner) { padding: 1px 4px; border-radius: var(--border-radius); background-color: var(--color-label-bg); - color: var(--color-label-text); } b, diff --git a/web_src/css/form.css b/web_src/css/form.css index 757edf72974b9..197c0f5af2002 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -228,6 +228,12 @@ textarea:focus, color: var(--color-text-light-1); } +.form .help pre.command-block { + white-space: pre-wrap; + overflow-wrap: anywhere; + margin: 0.25em 0 0.25em 1em; +} + .m-captcha-style { width: 100%; height: 5em; From 602af1499e0ee945563e7f5d592378ad150845c8 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Sat, 11 Oct 2025 23:48:39 -0400 Subject: [PATCH 14/88] bump archives&rar dep (#35637) (#35638) --- assets/go-licenses.json | 13 ++++++--- go.mod | 27 ++++++++++--------- go.sum | 59 ++++++++++++++++++++++------------------- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/assets/go-licenses.json b/assets/go-licenses.json index 9c19080e24618..b105757683141 100644 --- a/assets/go-licenses.json +++ b/assets/go-licenses.json @@ -1096,8 +1096,13 @@ }, { "name": "github.com/sorairolake/lzip-go", - "path": "github.com/sorairolake/lzip-go/LICENSE", - "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n---\n\nMIT License\n\nCopyright (c) 2024 Shun Sakai\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n" + "path": "github.com/sorairolake/lzip-go/LICENSE-APACHE", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n" + }, + { + "name": "github.com/spf13/afero", + "path": "github.com/spf13/afero/LICENSE.txt", + "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n" }, { "name": "github.com/ssor/bom", @@ -1225,8 +1230,8 @@ "licenseText": "Copyright (c) 2016-2024 Uber Technologies, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n" }, { - "name": "go4.org", - "path": "go4.org/LICENSE", + "name": "go4.org/readerutil", + "path": "go4.org/readerutil/LICENSE", "licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright {yyyy} {name of copyright owner}\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n\n" }, { diff --git a/go.mod b/go.mod index c5c72083b4f06..72d94e608effc 100644 --- a/go.mod +++ b/go.mod @@ -84,7 +84,7 @@ require ( github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-sqlite3 v1.14.32 github.com/meilisearch/meilisearch-go v0.33.2 - github.com/mholt/archives v0.1.3 + github.com/mholt/archives v0.1.5-0.20251009205813-e30ac6010726 github.com/microcosm-cc/bluemonday v1.0.27 github.com/microsoft/go-mssqldb v1.9.3 github.com/minio/minio-go/v7 v7.0.95 @@ -116,13 +116,13 @@ require ( github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-meta v1.1.0 gitlab.com/gitlab-org/api/client-go v0.142.4 - golang.org/x/crypto v0.41.0 + golang.org/x/crypto v0.42.0 golang.org/x/image v0.30.0 - golang.org/x/net v0.43.0 + golang.org/x/net v0.44.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.16.0 - golang.org/x/sys v0.35.0 - golang.org/x/text v0.28.0 + golang.org/x/sync v0.17.0 + golang.org/x/sys v0.36.0 + golang.org/x/text v0.30.0 google.golang.org/grpc v1.75.0 google.golang.org/protobuf v1.36.8 gopkg.in/ini.v1 v1.67.0 @@ -142,7 +142,7 @@ require ( github.com/DataDog/zstd v1.5.7 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/RoaringBitmap/roaring/v2 v2.10.0 // indirect - github.com/STARRY-S/zip v0.2.1 // indirect + github.com/STARRY-S/zip v0.2.3 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/andybalholm/cascadia v1.3.3 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect @@ -172,7 +172,7 @@ require ( github.com/blevesearch/zapx/v16 v16.2.4 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/bodgit/plumbing v1.3.0 // indirect - github.com/bodgit/sevenzip v1.6.0 // indirect + github.com/bodgit/sevenzip v1.6.1 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/boombuler/barcode v1.1.0 // indirect github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect @@ -233,14 +233,14 @@ require ( github.com/mikelolasagasti/xz v1.0.1 // indirect github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minlz v1.0.0 // indirect + github.com/minio/minlz v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/nwaples/rardecode/v2 v2.1.0 // indirect + github.com/nwaples/rardecode/v2 v2.2.0 // indirect github.com/olekukonko/cat v0.0.0-20250817074551-3280053e4e00 // indirect github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/ll v0.1.0 // indirect @@ -259,7 +259,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.3.1 // indirect - github.com/sorairolake/lzip-go v0.3.5 // indirect + github.com/sorairolake/lzip-go v0.3.8 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/tinylib/msgp v1.4.0 // indirect github.com/unknwon/com v1.0.1 // indirect @@ -278,9 +279,9 @@ require ( go.uber.org/zap/exp v0.3.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/mod v0.27.0 // indirect + golang.org/x/mod v0.28.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.36.0 // indirect + golang.org/x/tools v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 632209360b039..7ad6a91a59635 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06 github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= github.com/RoaringBitmap/roaring/v2 v2.10.0 h1:HbJ8Cs71lfCJyvmSptxeMX2PtvOC8yonlU0GQcy2Ak0= github.com/RoaringBitmap/roaring/v2 v2.10.0/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0= -github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= -github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= +github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= +github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk= github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0 h1:tgjwQrDH5m6jIYB7kac5IQZmfUzQNseac/e3H4VoCNE= github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.8.0/go.mod h1:1HmmMEVsr+0R1QWahSeMJkjSkq6CYAZu1aIbYSpfJ4o= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= @@ -193,8 +193,8 @@ github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTS github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= -github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= -github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= +github.com/bodgit/sevenzip v1.6.1 h1:kikg2pUMYC9ljU7W9SaqHXhym5HyKm8/M/jd31fYan4= +github.com/bodgit/sevenzip v1.6.1/go.mod h1:GVoYQbEVbOGT8n2pfqCIMRUaRjQ8F9oSqoBEqZh5fQ8= github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= github.com/bohde/codel v0.2.0 h1:fzF7ibgKmCfQbOzQCblmQcwzDRmV7WO7VMLm/hDvD3E= @@ -572,8 +572,8 @@ github.com/meilisearch/meilisearch-go v0.33.2 h1:YgsQSLYhAkRN2ias6I1KNRTjdYCN5w2 github.com/meilisearch/meilisearch-go v0.33.2/go.mod h1:6eOPcQ+OAuwXvnONlfSgfgvr7TIAWM/6OdhcVHg8cF0= github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458= -github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU= +github.com/mholt/archives v0.1.5-0.20251009205813-e30ac6010726 h1:WVjGWXBLI1Ggm2kHzNraCGgxFhLoK6gdpPSizCdxnx0= +github.com/mholt/archives v0.1.5-0.20251009205813-e30ac6010726/go.mod h1:3TPMmBLPsgszL+1As5zECTuKwKvIfj6YcwWPpeTAXF4= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/microsoft/go-mssqldb v1.9.3 h1:hy4p+LDC8LIGvI3JATnLVmBOLMJbmn5X400mr5j0lPs= @@ -588,8 +588,8 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU= github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo= -github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ= -github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= +github.com/minio/minlz v1.0.1 h1:OUZUzXcib8diiX+JYxyRLIdomyZYzHct6EShOKtQY2A= +github.com/minio/minlz v1.0.1/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -610,8 +610,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niklasfasching/go-org v1.9.1 h1:/3s4uTPOF06pImGa2Yvlp24yKXZoTYM+nsIlMzfpg/0= github.com/niklasfasching/go-org v1.9.1/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48= -github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U= -github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= +github.com/nwaples/rardecode/v2 v2.2.0 h1:4ufPGHiNe1rYJxYfehALLjup4Ls3ck42CWwjKiOqu0A= +github.com/nwaples/rardecode/v2 v2.2.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -714,9 +714,11 @@ github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= -github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= +github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik= +github.com/sorairolake/lzip-go v0.3.8/go.mod h1:JcBqGMV0frlxwrsE9sMWXDjqn3EeVf0/54YPsw66qkU= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -729,6 +731,7 @@ github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -838,8 +841,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -876,8 +879,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -906,8 +909,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -931,8 +934,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -975,8 +978,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -988,8 +991,8 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1004,8 +1007,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= @@ -1041,8 +1044,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From ae2e8c1f00865679cd71d737aea8c0c774e0410e Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 15 Oct 2025 12:16:06 +0800 Subject: [PATCH 15/88] Always create Actions logs stepsContainer (#35654) (#35672) Backport #35654 by wxiaoguang Co-authored-by: wxiaoguang --- web_src/js/components/RepoActionView.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index b90aef7411f0f..6e6733c7d01ac 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -601,7 +601,8 @@ export default defineComponent({
-
+ +
-
-
{{ i18nErrorOccurred }}
-
{{ i18nErrorMessage }}
+
+ {{ errorMessage }}
diff --git a/web_src/js/features/contextpopup.ts b/web_src/js/features/contextpopup.ts deleted file mode 100644 index 7477331dbeff5..0000000000000 --- a/web_src/js/features/contextpopup.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {createApp} from 'vue'; -import ContextPopup from '../components/ContextPopup.vue'; -import {parseIssueHref} from '../utils.ts'; -import {createTippy} from '../modules/tippy.ts'; - -export function initContextPopups() { - const refIssues = document.querySelectorAll('.ref-issue'); - attachRefIssueContextPopup(refIssues); -} - -export function attachRefIssueContextPopup(refIssues: NodeListOf) { - for (const refIssue of refIssues) { - if (refIssue.classList.contains('ref-external-issue')) continue; - - const issuePathInfo = parseIssueHref(refIssue.getAttribute('href')); - if (!issuePathInfo.ownerName) continue; - - const el = document.createElement('div'); - el.classList.add('tw-p-3'); - refIssue.parentNode.insertBefore(el, refIssue.nextSibling); - - const view = createApp(ContextPopup); - - try { - view.mount(el); - } catch (err) { - console.error(err); - el.textContent = 'ContextPopup failed to load'; - } - - createTippy(refIssue, { - theme: 'default', - content: el, - placement: 'top-start', - interactive: true, - role: 'dialog', - interactiveBorder: 5, - onShow: () => { - el.firstChild.dispatchEvent(new CustomEvent('ce-load-context-popup', {detail: issuePathInfo})); - }, - }); - } -} diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index bde7ec0324b5c..02d151e102b02 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -12,8 +12,6 @@ import {invertFileFolding} from './file-fold.ts'; import {parseDom} from '../utils.ts'; import {registerGlobalSelectorFunc} from '../modules/observer.ts'; -const {i18n} = window.config; - function initRepoDiffFileBox(el: HTMLElement) { // switch between "rendered" and "source", for image and CSV files queryElems(el, '.file-view-toggle', (btn) => btn.addEventListener('click', () => { @@ -86,7 +84,7 @@ function initRepoDiffConversationForm() { } } catch (error) { console.error('Error:', error); - showErrorToast(i18n.network_error); + showErrorToast(`Submit form failed: ${error}`); } finally { form?.classList.remove('is-loading'); } diff --git a/web_src/js/features/repo-editor.ts b/web_src/js/features/repo-editor.ts index f3ca13460cd5b..0825999edcd2a 100644 --- a/web_src/js/features/repo-editor.ts +++ b/web_src/js/features/repo-editor.ts @@ -1,7 +1,6 @@ import {html, htmlRaw} from '../utils/html.ts'; import {createCodeEditor} from './codeeditor.ts'; import {hideElem, queryElems, showElem, createElementFromHTML} from '../utils/dom.ts'; -import {attachRefIssueContextPopup} from './contextpopup.ts'; import {POST} from '../modules/fetch.ts'; import {initDropzone} from './dropzone.ts'; import {confirmModal} from './comp/ConfirmModal.ts'; @@ -199,5 +198,4 @@ export function initRepoEditor() { export function renderPreviewPanelContent(previewPanel: Element, htmlContent: string) { // the content is from the server, so it is safe to use innerHTML previewPanel.innerHTML = html`
${htmlRaw(htmlContent)}
`; - attachRefIssueContextPopup(previewPanel.querySelectorAll('p .ref-issue')); } diff --git a/web_src/js/features/repo-issue-edit.ts b/web_src/js/features/repo-issue-edit.ts index f883ee460b06c..43aee314e04f4 100644 --- a/web_src/js/features/repo-issue-edit.ts +++ b/web_src/js/features/repo-issue-edit.ts @@ -3,7 +3,6 @@ import {getComboMarkdownEditor, initComboMarkdownEditor, ComboMarkdownEditor} fr import {POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {hideElem, querySingleVisibleElem, showElem, type DOMEvent} from '../utils/dom.ts'; -import {attachRefIssueContextPopup} from './contextpopup.ts'; import {triggerUploadStateChanged} from './comp/EditorUpload.ts'; import {convertHtmlToMarkdown} from '../markup/html2markdown.ts'; import {applyAreYouSure, reinitializeAreYouSure} from '../vendor/jquery.are-you-sure.ts'; @@ -62,8 +61,6 @@ async function tryOnEditContent(e: DOMEvent) { renderContent = newRenderContent; rawContent.textContent = comboMarkdownEditor.value(); - const refIssues = renderContent.querySelectorAll('p .ref-issue'); - attachRefIssueContextPopup(refIssues); if (!commentContent.querySelector('.dropzone-attachments')) { if (data.attachments !== '') { diff --git a/web_src/js/index-domready.ts b/web_src/js/index-domready.ts index cfb6b89ea7296..8a3a27fa19c86 100644 --- a/web_src/js/index-domready.ts +++ b/web_src/js/index-domready.ts @@ -5,7 +5,6 @@ import '../../node_modules/easymde/dist/easymde.min.css'; // TODO: lazy load in import {initHtmx} from './htmx.ts'; import {initDashboardRepoList} from './features/dashboard.ts'; import {initGlobalCopyToClipboardListener} from './features/clipboard.ts'; -import {initContextPopups} from './features/contextpopup.ts'; import {initRepoGraphGit} from './features/repo-graph.ts'; import {initHeatmap} from './features/heatmap.ts'; import {initImageDiff} from './features/imagediff.ts'; @@ -97,7 +96,6 @@ const initPerformanceTracer = callInitFunctions([ initHeadNavbarContentToggle, initFootLanguageMenu, - initContextPopups, initHeatmap, initImageDiff, initMarkupAnchors, diff --git a/web_src/js/markup/content.ts b/web_src/js/markup/content.ts index cf88ed61de15b..d964c88989e02 100644 --- a/web_src/js/markup/content.ts +++ b/web_src/js/markup/content.ts @@ -5,6 +5,7 @@ import {initMarkupRenderAsciicast} from './asciicast.ts'; import {initMarkupTasklist} from './tasklist.ts'; import {registerGlobalSelectorFunc} from '../modules/observer.ts'; import {initMarkupRenderIframe} from './render-iframe.ts'; +import {initMarkupRefIssue} from './refissue.ts'; // code that runs for all markup content export function initMarkupContent(): void { @@ -15,5 +16,6 @@ export function initMarkupContent(): void { initMarkupCodeMath(el); initMarkupRenderAsciicast(el); initMarkupRenderIframe(el); + initMarkupRefIssue(el); }); } diff --git a/web_src/js/markup/refissue.ts b/web_src/js/markup/refissue.ts new file mode 100644 index 0000000000000..5a05de84fe912 --- /dev/null +++ b/web_src/js/markup/refissue.ts @@ -0,0 +1,41 @@ +import {queryElems} from '../utils/dom.ts'; +import {parseIssueHref} from '../utils.ts'; +import {createApp} from 'vue'; +import ContextPopup from '../components/ContextPopup.vue'; +import {createTippy, getAttachedTippyInstance} from '../modules/tippy.ts'; + +export function initMarkupRefIssue(el: HTMLElement) { + queryElems(el, '.ref-issue', (el) => { + el.addEventListener('mouseenter', showMarkupRefIssuePopup); + el.addEventListener('focus', showMarkupRefIssuePopup); + }); +} + +export function showMarkupRefIssuePopup(e: MouseEvent | FocusEvent) { + const refIssue = e.currentTarget as HTMLElement; + if (getAttachedTippyInstance(refIssue)) return; + if (refIssue.classList.contains('ref-external-issue')) return; + + const issuePathInfo = parseIssueHref(refIssue.getAttribute('href')); + if (!issuePathInfo.ownerName) return; + + const el = document.createElement('div'); + const tippy = createTippy(refIssue, { + theme: 'default', + content: el, + trigger: 'mouseenter focus', + placement: 'top-start', + interactive: true, + role: 'dialog', + interactiveBorder: 5, + // onHide() { return false }, // help to keep the popup and debug the layout + onShow: () => { + const view = createApp(ContextPopup, { + // backend: GetIssueInfo + loadIssueInfoUrl: `${window.config.appSubUrl}/${issuePathInfo.ownerName}/${issuePathInfo.repoName}/issues/${issuePathInfo.indexString}/info`, + }); + view.mount(el); + }, + }); + tippy.show(); +} diff --git a/web_src/js/modules/tippy.ts b/web_src/js/modules/tippy.ts index 2a1d998d76348..6f42a4f987a3c 100644 --- a/web_src/js/modules/tippy.ts +++ b/web_src/js/modules/tippy.ts @@ -209,3 +209,7 @@ export function showTemporaryTooltip(target: Element, content: Content): void { }, }); } + +export function getAttachedTippyInstance(el: Element): Instance | null { + return el._tippy ?? null; +} From 88a8571b9324c62a5691d059efee9eaa4b0c518f Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 29 Oct 2025 22:04:19 +0800 Subject: [PATCH 35/88] Update tab title when navigating file tree (#35757) (#35772) Backport #35757 by bytedream --- modules/web/middleware/data.go | 2 ++ routers/web/repo/view_file.go | 2 +- routers/web/repo/view_home.go | 3 +-- services/context/repo.go | 1 + templates/base/head.tmpl | 2 +- templates/repo/view_content.tmpl | 1 + web_src/js/components/ViewFileTreeStore.ts | 13 ++++++++++--- 7 files changed, 17 insertions(+), 7 deletions(-) diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index a47da0f836b36..41fb1e7e6f64d 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -22,6 +22,8 @@ func GetContextData(c context.Context) reqctx.ContextData { func CommonTemplateContextData() reqctx.ContextData { return reqctx.ContextData{ + "PageTitleCommon": setting.AppName, + "IsLandingPageOrganizations": setting.LandingPageURL == setting.LandingPageOrganizations, "ShowRegistrationButton": setting.Service.ShowRegistrationButton, diff --git a/routers/web/repo/view_file.go b/routers/web/repo/view_file.go index 8bb9fb62a786e..ea3920439d426 100644 --- a/routers/web/repo/view_file.go +++ b/routers/web/repo/view_file.go @@ -172,7 +172,7 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) { blob := entry.Blob() - ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefFullName.ShortName()) + ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefFullName.ShortName()) ctx.Data["FileIsSymlink"] = entry.IsLink() ctx.Data["FileTreePath"] = ctx.Repo.TreePath ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.RefTypeNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) diff --git a/routers/web/repo/view_home.go b/routers/web/repo/view_home.go index f475e93f60489..c0272c9347770 100644 --- a/routers/web/repo/view_home.go +++ b/routers/web/repo/view_home.go @@ -8,7 +8,6 @@ import ( "fmt" "html/template" "net/http" - "path" "strconv" "strings" "time" @@ -139,7 +138,7 @@ func prepareToRenderDirectory(ctx *context.Context) { if ctx.Repo.TreePath != "" { ctx.Data["HideRepoInfo"] = true - ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefFullName.ShortName()) + ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+ctx.Repo.TreePath, ctx.Repo.RefFullName.ShortName()) } subfolder, readmeFile, err := findReadmeFileInEntries(ctx, ctx.Repo.TreePath, entries, true) diff --git a/services/context/repo.go b/services/context/repo.go index 04ddba70fe07b..ea0cf62116116 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -537,6 +537,7 @@ func RepoAssignment(ctx *Context) { } ctx.Data["Title"] = repo.Owner.Name + "/" + repo.Name + ctx.Data["PageTitleCommon"] = repo.Name + " - " + setting.AppName ctx.Data["Repository"] = repo ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode) diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 62bc625bda669..a3ea4c454d7c4 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -2,7 +2,7 @@ - {{if .Title}}{{.Title}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}} + {{if .Title}}{{.Title}} - {{end}}{{.PageTitleCommon}} {{if .ManifestData}}{{end}} diff --git a/templates/repo/view_content.tmpl b/templates/repo/view_content.tmpl index 3ba04a9974940..66e4fffcb9b19 100644 --- a/templates/repo/view_content.tmpl +++ b/templates/repo/view_content.tmpl @@ -1,5 +1,6 @@ {{$isTreePathRoot := not .TreeNames}} +
{{template "repo/sub_menu" .}}
diff --git a/web_src/js/components/ViewFileTreeStore.ts b/web_src/js/components/ViewFileTreeStore.ts index 0e16b566509a1..61d9168aa6c3a 100644 --- a/web_src/js/components/ViewFileTreeStore.ts +++ b/web_src/js/components/ViewFileTreeStore.ts @@ -25,9 +25,16 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri }, async loadViewContent(url: string) { - url = url.includes('?') ? url.replace('?', '?only_content=true') : `${url}?only_content=true`; - const response = await GET(url); - document.querySelector('.repo-view-content').innerHTML = await response.text(); + const u = new URL(url, window.origin); + u.searchParams.set('only_content', 'true'); + const response = await GET(u.href); + const elViewContent = document.querySelector('.repo-view-content'); + elViewContent.innerHTML = await response.text(); + const elViewContentData = elViewContent.querySelector('.repo-view-content-data'); + if (!elViewContentData) return; // if error occurs, there is no such element + const t1 = elViewContentData.getAttribute('data-document-title'); + const t2 = elViewContentData.getAttribute('data-document-title-common'); + document.title = `${t1} - ${t2}`; // follow the format in head.tmpl: ... }, async navigateTreeView(treePath: string) { From cf644d565d09d1592526919f7eabbb683f5d83ae Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 29 Oct 2025 09:14:32 -0700 Subject: [PATCH 36/88] Update release notes for 1.25.0 (#35769) Co-authored-by: wxiaoguang --- CHANGELOG.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d672fc30b9615..24efa99352623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,14 @@ This changelog goes through the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). -## [1.25.0-rc0](https://github.com/go-gitea/gitea/releases/tag/1.25.0-rc0) - 2025-09-24 +## [1.25.0](https://github.com/go-gitea/gitea/releases/tag/1.25.0) - 2025-10-30 * BREAKING * Return 201 Created for CreateVariable API responses (#34517) * Add label 'state' to metric 'gitea_users' (#34326) * SECURITY * Upgrade security public key (#34956) + * Also include all security fixes in 1.24.x after 1.25.0-rc0 * FEATURES * Stream repo zip/tar.gz/bundle achives by default (#35487) * Use configurable remote name for git commands (#35172) @@ -60,7 +61,31 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Use lfs label for lfs file rather than a long description (#34363) * Add "View workflow file" to Actions list page (#34538) * Move organization's visibility change to danger zone. (#34814) + * Don't block site admin's operation if SECRET_KEY is lost (#35721) + * Make restricted users can access public repositories (#35693) + * The status icon of the Action step is consistent with GitHub (#35618) #35621 * BUGFIXES + * Update tab title when navigating file tree (#35757) #35772 + * Fix "ref-issue" handling in markup (#35739) #35771 + * Fix webhook to prevent tag events from bypassing branch filters targets (#35567) #35577 + * Fix markup init after issue comment editing (#35536) #35537 + * Fix creating pull request failure when the target branch name is the same as some tag (#35552) #35582 + * Fix auto-expand and auto-scroll for actions logs (#35570) (#35583) #35586 + * Use inputs context when parsing workflows (#35590) #35595 + * Fix diffpatch API endpoint (#35610) #35613 + * Creating push comments before invoke pull request checking (#35647) #35668 + * Fix missing Close when error occurs and abused connection pool (#35658) #35670 + * Fix build (#35674) + * Use LFS object size instead of blob size when viewing a LFS file (#35679) + * Fix workflow run event status while rerunning a failed job (#35689) + * Avoid emoji mismatch and allow to only enable chosen emojis (#35692) + * Refactor legacy code, fix LFS auth bypass, fix symlink bypass (#35708) + * Fix various trivial problems (#35714) + * Fix attachment file size limit in server backend (#35519) + * Honor delete branch on merge repo setting when using merge API (#35488) + * Fix external render, make iframe render work (#35727, #35730) + * Upgrade go mail to 0.7.2 (#35748) + * Revert #18491, fix oauth2 client link account (#35745) * Fix different behavior in status check pattern matching with double stars (#35474) * Fix overflow in notifications list (#35446) * Fix package link setting can only list limited repositories (#35394) @@ -172,6 +197,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Run `gopls modernize` on codebase (#34751) * Upgrade `gopls` to v0.19.0, add `make fix` (#34772) * BUILD + * bump archives&rar dep (#35637) #35638 * Use github.com/mholt/archives replace github.com/mholt/archiver (#35390) * Update JS and PY dependencies (#35444) * Upgrade devcontainer go version to 1.24.6 (#35298) From f85cd7aeb57298ea92f6489b5db32e2d4e120fcf Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 30 Oct 2025 01:51:16 +0800 Subject: [PATCH 37/88] Fix actions schedule update issue (#35767) (#35774) Backport #35767 by @Zettat123 Fix #34472 Add integration tests for actions schedule update. --------- Co-authored-by: Zettat123 Co-authored-by: wxiaoguang --- services/actions/notifier_helper.go | 20 +- tests/integration/actions_schedule_test.go | 294 +++++++++++++++++++++ 2 files changed, 302 insertions(+), 12 deletions(-) create mode 100644 tests/integration/actions_schedule_test.go diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 66916e9301742..0f21310c984b2 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -236,12 +236,12 @@ func notify(ctx context.Context, input *notifyInput) error { } if shouldDetectSchedules { - if err := handleSchedules(ctx, schedules, commit, input, ref.String()); err != nil { + if err := handleSchedules(ctx, schedules, commit, input, ref); err != nil { return err } } - return handleWorkflows(ctx, detectedWorkflows, commit, input, ref.String()) + return handleWorkflows(ctx, detectedWorkflows, commit, input, ref) } func skipWorkflows(ctx context.Context, input *notifyInput, commit *git.Commit) bool { @@ -293,7 +293,7 @@ func handleWorkflows( detectedWorkflows []*actions_module.DetectedWorkflow, commit *git.Commit, input *notifyInput, - ref string, + ref git.RefName, ) error { if len(detectedWorkflows) == 0 { log.Trace("repo %s with commit %s couldn't find workflows", input.Repo.RepoPath(), commit.ID) @@ -329,7 +329,7 @@ func handleWorkflows( WorkflowID: dwf.EntryName, TriggerUserID: input.Doer.ID, TriggerUser: input.Doer, - Ref: ref, + Ref: ref.String(), CommitSHA: commit.ID.String(), IsForkPullRequest: isForkPullRequest, Event: input.Event, @@ -500,13 +500,9 @@ func handleSchedules( detectedWorkflows []*actions_module.DetectedWorkflow, commit *git.Commit, input *notifyInput, - ref string, + ref git.RefName, ) error { - branch, err := commit.GetBranchName() - if err != nil { - return err - } - if branch != input.Repo.DefaultBranch { + if ref.BranchName() != input.Repo.DefaultBranch { log.Trace("commit branch is not default branch in repo") return nil } @@ -552,7 +548,7 @@ func handleSchedules( WorkflowID: dwf.EntryName, TriggerUserID: user_model.ActionsUserID, TriggerUser: user_model.NewActionsUser(), - Ref: ref, + Ref: ref.String(), CommitSHA: commit.ID.String(), Event: input.Event, EventPayload: string(p), @@ -614,5 +610,5 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) // so we use action user as the Doer of the notifyInput notifyInput := newNotifyInputForSchedules(repo) - return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) + return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, git.RefNameFromBranch(repo.DefaultBranch)) } diff --git a/tests/integration/actions_schedule_test.go b/tests/integration/actions_schedule_test.go new file mode 100644 index 0000000000000..84da13fb20ae6 --- /dev/null +++ b/tests/integration/actions_schedule_test.go @@ -0,0 +1,294 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "net/url" + "strconv" + "strings" + "testing" + + actions_model "code.gitea.io/gitea/models/actions" + auth_model "code.gitea.io/gitea/models/auth" + git_model "code.gitea.io/gitea/models/git" + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + unit_model "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/migration" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + mirror_service "code.gitea.io/gitea/services/mirror" + repo_service "code.gitea.io/gitea/services/repository" + files_service "code.gitea.io/gitea/services/repository/files" + + "github.com/stretchr/testify/assert" +) + +func TestScheduleUpdate(t *testing.T) { + t.Run("Push", testScheduleUpdatePush) + t.Run("PullMerge", testScheduleUpdatePullMerge) + t.Run("DisableAndEnableActionsUnit", testScheduleUpdateDisableAndEnableActionsUnit) + t.Run("ArchiveAndUnarchive", testScheduleUpdateArchiveAndUnarchive) + t.Run("MirrorSync", testScheduleUpdateMirrorSync) +} + +func testScheduleUpdatePush(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + newCron := "30 5 * * 1,3" + pushScheduleChange(t, u, repo, newCron) + branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + return branch.CommitID, newCron + }) +} + +func testScheduleUpdatePullMerge(t *testing.T) { + newBranchName := "feat1" + workflowTreePath := ".gitea/workflows/actions-schedule.yml" + workflowContent := `name: actions-schedule +on: + schedule: + - cron: '@every 2m' # update to 2m +jobs: + job: + runs-on: ubuntu-latest + steps: + - run: echo 'schedule workflow' +` + + mergeStyles := []repo_model.MergeStyle{ + repo_model.MergeStyleMerge, + repo_model.MergeStyleRebase, + repo_model.MergeStyleRebaseMerge, + repo_model.MergeStyleSquash, + repo_model.MergeStyleFastForwardOnly, + } + + for _, mergeStyle := range mergeStyles { + t.Run(string(mergeStyle), func(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + // update workflow file + _, err := files_service.ChangeRepoFiles(t.Context(), repo, user, &files_service.ChangeRepoFilesOptions{ + NewBranch: newBranchName, + Files: []*files_service.ChangeRepoFile{ + { + Operation: "update", + TreePath: workflowTreePath, + ContentReader: strings.NewReader(workflowContent), + }, + }, + Message: "update workflow schedule", + }) + assert.NoError(t, err) + + // create pull request + apiPull, err := doAPICreatePullRequest(testContext, repo.OwnerName, repo.Name, repo.DefaultBranch, newBranchName)(t) + assert.NoError(t, err) + + // merge pull request + testPullMerge(t, testContext.Session, repo.OwnerName, repo.Name, strconv.FormatInt(apiPull.Index, 10), mergeStyle, false) + + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID}) + return pull.MergedCommitID, "@every 2m" + }) + }) + } + + t.Run(string(repo_model.MergeStyleManuallyMerged), func(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + // enable manual-merge + doAPIEditRepository(testContext, &api.EditRepoOption{ + HasPullRequests: util.ToPointer(true), + AllowManualMerge: util.ToPointer(true), + })(t) + + // update workflow file + fileResp, err := files_service.ChangeRepoFiles(t.Context(), repo, user, &files_service.ChangeRepoFilesOptions{ + NewBranch: newBranchName, + Files: []*files_service.ChangeRepoFile{ + { + Operation: "update", + TreePath: workflowTreePath, + ContentReader: strings.NewReader(workflowContent), + }, + }, + Message: "update workflow schedule", + }) + assert.NoError(t, err) + + // merge and push + dstPath := t.TempDir() + u.Path = repo.FullName() + ".git" + u.User = url.UserPassword(repo.OwnerName, userPassword) + doGitClone(dstPath, u)(t) + doGitMerge(dstPath, "origin/"+newBranchName)(t) + doGitPushTestRepository(dstPath, "origin", repo.DefaultBranch)(t) + + // create pull request + apiPull, err := doAPICreatePullRequest(testContext, repo.OwnerName, repo.Name, repo.DefaultBranch, newBranchName)(t) + assert.NoError(t, err) + + // merge pull request manually + doAPIManuallyMergePullRequest(testContext, repo.OwnerName, repo.Name, fileResp.Commit.SHA, apiPull.Index)(t) + + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: apiPull.ID}) + assert.Equal(t, issues_model.PullRequestStatusManuallyMerged, pull.Status) + return pull.MergedCommitID, "@every 2m" + }) + }) +} + +func testScheduleUpdateMirrorSync(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + // create mirror repo + opts := migration.MigrateOptions{ + RepoName: "actions-schedule-mirror", + Description: "Test mirror for actions-schedule", + Private: false, + Mirror: true, + CloneAddr: repo.CloneLinkGeneral(t.Context()).HTTPS, + } + mirrorRepo, err := repo_service.CreateRepositoryDirectly(t.Context(), user, user, repo_service.CreateRepoOptions{ + Name: opts.RepoName, + Description: opts.Description, + IsPrivate: opts.Private, + IsMirror: opts.Mirror, + DefaultBranch: repo.DefaultBranch, + Status: repo_model.RepositoryBeingMigrated, + }, false) + assert.NoError(t, err) + assert.True(t, mirrorRepo.IsMirror) + mirrorRepo, err = repo_service.MigrateRepositoryGitData(t.Context(), user, mirrorRepo, opts, nil) + assert.NoError(t, err) + mirrorContext := NewAPITestContext(t, user.Name, mirrorRepo.Name, auth_model.AccessTokenScopeWriteRepository) + + // enable actions unit for mirror repo + assert.False(t, mirrorRepo.UnitEnabled(t.Context(), unit_model.TypeActions)) + doAPIEditRepository(mirrorContext, &api.EditRepoOption{ + HasActions: util.ToPointer(true), + })(t) + actionSchedule := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: mirrorRepo.ID}) + scheduleSpec := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: mirrorRepo.ID, ScheduleID: actionSchedule.ID}) + assert.Equal(t, "@every 1m", scheduleSpec.Spec) + + // update remote repo + newCron := "30 5,17 * * 2,4" + pushScheduleChange(t, u, repo, newCron) + repoDefaultBranch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + + // sync + ok := mirror_service.SyncPullMirror(t.Context(), mirrorRepo.ID) + assert.True(t, ok) + mirrorRepoDefaultBranch, err := git_model.GetBranch(t.Context(), mirrorRepo.ID, mirrorRepo.DefaultBranch) + assert.NoError(t, err) + assert.Equal(t, repoDefaultBranch.CommitID, mirrorRepoDefaultBranch.CommitID) + + // check updated schedule + actionSchedule = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: mirrorRepo.ID}) + scheduleSpec = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: mirrorRepo.ID, ScheduleID: actionSchedule.ID}) + assert.Equal(t, newCron, scheduleSpec.Spec) + + return repoDefaultBranch.CommitID, newCron + }) +} + +func testScheduleUpdateArchiveAndUnarchive(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + doAPIEditRepository(testContext, &api.EditRepoOption{ + Archived: util.ToPointer(true), + })(t) + assert.Zero(t, unittest.GetCount(t, &actions_model.ActionSchedule{RepoID: repo.ID})) + doAPIEditRepository(testContext, &api.EditRepoOption{ + Archived: util.ToPointer(false), + })(t) + branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + return branch.CommitID, "@every 1m" + }) +} + +func testScheduleUpdateDisableAndEnableActionsUnit(t *testing.T) { + doTestScheduleUpdate(t, func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) { + doAPIEditRepository(testContext, &api.EditRepoOption{ + HasActions: util.ToPointer(false), + })(t) + assert.Zero(t, unittest.GetCount(t, &actions_model.ActionSchedule{RepoID: repo.ID})) + doAPIEditRepository(testContext, &api.EditRepoOption{ + HasActions: util.ToPointer(true), + })(t) + branch, err := git_model.GetBranch(t.Context(), repo.ID, repo.DefaultBranch) + assert.NoError(t, err) + return branch.CommitID, "@every 1m" + }) +} + +type scheduleUpdateTrigger func(t *testing.T, u *url.URL, testContext APITestContext, user *user_model.User, repo *repo_model.Repository) (commitID, expectedSpec string) + +func doTestScheduleUpdate(t *testing.T, updateTrigger scheduleUpdateTrigger) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + apiRepo := createActionsTestRepo(t, token, "actions-schedule", false) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) + assert.NoError(t, repo.LoadAttributes(t.Context())) + httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository) + defer doAPIDeleteRepository(httpContext)(t) + + wfTreePath := ".gitea/workflows/actions-schedule.yml" + wfFileContent := `name: actions-schedule +on: + schedule: + - cron: '@every 1m' +jobs: + job: + runs-on: ubuntu-latest + steps: + - run: echo 'schedule workflow' +` + + opts1 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, "create "+wfTreePath, wfFileContent) + apiFileResp := createWorkflowFile(t, token, user2.Name, repo.Name, wfTreePath, opts1) + + actionSchedule := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: repo.ID, CommitSHA: apiFileResp.Commit.SHA}) + scheduleSpec := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: repo.ID, ScheduleID: actionSchedule.ID}) + assert.Equal(t, "@every 1m", scheduleSpec.Spec) + + commitID, expectedSpec := updateTrigger(t, u, httpContext, user2, repo) + + actionSchedule = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionSchedule{RepoID: repo.ID, CommitSHA: commitID}) + scheduleSpec = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionScheduleSpec{RepoID: repo.ID, ScheduleID: actionSchedule.ID}) + assert.Equal(t, expectedSpec, scheduleSpec.Spec) + }) +} + +func pushScheduleChange(t *testing.T, u *url.URL, repo *repo_model.Repository, newCron string) { + workflowTreePath := ".gitea/workflows/actions-schedule.yml" + workflowContent := `name: actions-schedule +on: + schedule: + - cron: '` + newCron + `' +jobs: + job: + runs-on: ubuntu-latest + steps: + - run: echo 'schedule workflow' +` + + dstPath := t.TempDir() + u.Path = repo.FullName() + ".git" + u.User = url.UserPassword(repo.OwnerName, userPassword) + doGitClone(dstPath, u)(t) + doGitCheckoutWriteFileCommit(localGitAddCommitOptions{ + LocalRepoPath: dstPath, + CheckoutBranch: repo.DefaultBranch, + TreeFilePath: workflowTreePath, + TreeFileContent: workflowContent, + })(t) + doGitPushTestRepository(dstPath, "origin", repo.DefaultBranch)(t) +} From 65a37572f38e6cc1f89ceedb568159dc00dd6610 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 30 Oct 2025 02:35:18 +0800 Subject: [PATCH 38/88] add pnpm to Snapcraft (#35778) (#35779) Backport #35778 by techknowlogick Co-authored-by: techknowlogick --- snap/snapcraft.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 46900f7b85e17..4f3c4e9ff4c9c 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -68,6 +68,7 @@ parts: override-build: | set -x sed -i 's/os.Getuid()/1/g' modules/setting/setting.go + npm install -g pnpm TAGS="bindata sqlite sqlite_unlock_notify pam cert" make build install -D gitea "${SNAPCRAFT_PART_INSTALL}/gitea" cp -r options "${SNAPCRAFT_PART_INSTALL}/" From 04b6f908893aee32c4aa4e263a11a71397436293 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 30 Oct 2025 02:31:42 -0600 Subject: [PATCH 39/88] Fix actions rerun bug (#35783) (#35784) Backport #35783 Fix #35780, fix #35782 Rerunning a job or a run is only allowed when the job is done and the run is done. Related PR: #34970 https://github.com/go-gitea/gitea/blob/98ff7d077376db1225f266095788c6bd9414288a/routers/web/repo/actions/view.go#L239 We don't need to check run status again in `rerunJob` because the run status has been changed before `rerunJob`. --- In fact, the bug described in the above issues will not occur on the main branch. Because `getRunJobs` is called before updating the run. https://github.com/go-gitea/gitea/blob/98ff7d077376db1225f266095788c6bd9414288a/routers/web/repo/actions/view.go#L425-L435 So the run status that `rerunJob` checks is the old status. --------- Co-authored-by: wxiaoguang --- go.mod | 2 +- routers/web/repo/actions/view.go | 36 ++++---- tests/integration/actions_rerun_test.go | 118 ++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 tests/integration/actions_rerun_test.go diff --git a/go.mod b/go.mod index 63c77593701a4..e4c0a5a989d3f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.gitea.io/gitea -go 1.25.1 +go 1.25.3 // rfc5280 said: "The serial number is an integer assigned by the CA to each certificate." // But some CAs use negative serial number, just relax the check. related: diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index 99fbf2a16a53b..9a7322f6eee89 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -412,6 +412,12 @@ func Rerun(ctx *context_module.Context) { return } + // rerun is not allowed if the run is not done + if !run.Status.IsDone() { + ctx.JSONError(ctx.Locale.Tr("actions.runs.not_done")) + return + } + // can not rerun job when workflow is disabled cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions) cfg := cfgUnit.ActionsConfig() @@ -420,23 +426,21 @@ func Rerun(ctx *context_module.Context) { return } - // reset run's start and stop time when it is done - if run.Status.IsDone() { - run.PreviousDuration = run.Duration() - run.Started = 0 - run.Stopped = 0 - run.Status = actions_model.StatusWaiting - if err := actions_model.UpdateRun(ctx, run, "started", "stopped", "status", "previous_duration"); err != nil { - ctx.ServerError("UpdateRun", err) - return - } + // reset run's start and stop time + run.PreviousDuration = run.Duration() + run.Started = 0 + run.Stopped = 0 + run.Status = actions_model.StatusWaiting + if err := actions_model.UpdateRun(ctx, run, "started", "stopped", "status", "previous_duration"); err != nil { + ctx.ServerError("UpdateRun", err) + return + } - if err := run.LoadAttributes(ctx); err != nil { - ctx.ServerError("run.LoadAttributes", err) - return - } - notify_service.WorkflowRunStatusUpdate(ctx, run.Repo, run.TriggerUser, run) + if err := run.LoadAttributes(ctx); err != nil { + ctx.ServerError("run.LoadAttributes", err) + return } + notify_service.WorkflowRunStatusUpdate(ctx, run.Repo, run.TriggerUser, run) job, jobs := getRunJobs(ctx, runIndex, jobIndex) if ctx.Written() { @@ -472,7 +476,7 @@ func Rerun(ctx *context_module.Context) { func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shouldBlock bool) error { status := job.Status - if !status.IsDone() || !job.Run.Status.IsDone() { + if !status.IsDone() { return nil } diff --git a/tests/integration/actions_rerun_test.go b/tests/integration/actions_rerun_test.go new file mode 100644 index 0000000000000..690d661e6c910 --- /dev/null +++ b/tests/integration/actions_rerun_test.go @@ -0,0 +1,118 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package integration + +import ( + "fmt" + "net/http" + "net/url" + "testing" + + auth_model "code.gitea.io/gitea/models/auth" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + + runnerv1 "code.gitea.io/actions-proto-go/runner/v1" +) + +func TestActionsRerun(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + session := loginUser(t, user2.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + apiRepo := createActionsTestRepo(t, token, "actions-rerun", false) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) + httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository) + defer doAPIDeleteRepository(httpContext)(t) + + runner := newMockRunner() + runner.registerAsRepoRunner(t, repo.OwnerName, repo.Name, "mock-runner", []string{"ubuntu-latest"}, false) + + wfTreePath := ".gitea/workflows/actions-rerun-workflow-1.yml" + wfFileContent := `name: actions-rerun-workflow-1 +on: + push: + paths: + - '.gitea/workflows/actions-rerun-workflow-1.yml' +jobs: + job1: + runs-on: ubuntu-latest + steps: + - run: echo 'job1' + job2: + runs-on: ubuntu-latest + needs: [job1] + steps: + - run: echo 'job2' +` + + opts := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, "create"+wfTreePath, wfFileContent) + createWorkflowFile(t, token, user2.Name, repo.Name, wfTreePath, opts) + + // fetch and exec job1 + job1Task := runner.fetchTask(t) + _, _, run := getTaskAndJobAndRunByTaskID(t, job1Task.Id) + runner.execTask(t, job1Task, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + // RERUN-FAILURE: the run is not done + req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%d/rerun", user2.Name, repo.Name, run.Index), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusBadRequest) + // fetch and exec job2 + job2Task := runner.fetchTask(t) + runner.execTask(t, job2Task, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + + // RERUN-1: rerun the run + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%d/rerun", user2.Name, repo.Name, run.Index), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusOK) + // fetch and exec job1 + job1TaskR1 := runner.fetchTask(t) + runner.execTask(t, job1TaskR1, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + // fetch and exec job2 + job2TaskR1 := runner.fetchTask(t) + runner.execTask(t, job2TaskR1, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + + // RERUN-2: rerun job1 + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%d/jobs/%d/rerun", user2.Name, repo.Name, run.Index, 0), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusOK) + // job2 needs job1, so rerunning job1 will also rerun job2 + // fetch and exec job1 + job1TaskR2 := runner.fetchTask(t) + runner.execTask(t, job1TaskR2, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + // fetch and exec job2 + job2TaskR2 := runner.fetchTask(t) + runner.execTask(t, job2TaskR2, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + + // RERUN-3: rerun job2 + req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%d/jobs/%d/rerun", user2.Name, repo.Name, run.Index, 1), map[string]string{ + "_csrf": GetUserCSRFToken(t, session), + }) + session.MakeRequest(t, req, http.StatusOK) + // only job2 will rerun + // fetch and exec job2 + job2TaskR3 := runner.fetchTask(t) + runner.execTask(t, job2TaskR3, &mockTaskOutcome{ + result: runnerv1.Result_RESULT_SUCCESS, + }) + runner.fetchNoTask(t) + }) +} From e194d89c74a57d0e83739e5fb7cbd52ac5b705e5 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 30 Oct 2025 17:06:44 +0800 Subject: [PATCH 40/88] Improve and fix markup code preview rendering (#35777) (#35787) Backport #35777 by @silverwind 1. Add the color on the link to the referenced file, which is the more likely thing the user wants to click 2. Use monospace font on the SHA 3. Tweak text colors 4. Change SHA link to go to the commit instead of the repo root with commit filter set 5. Added the repo name to the file link text 6. Fix broken line numbering rendering The only major difference to GitHub is now the missing line numbers. Before: Screenshot 2025-10-29 at 19 09 59 After: image For comparison, GitHub rendering: image Co-authored-by: silverwind --- modules/markup/sanitizer_default.go | 3 +++ services/markup/renderhelper_codepreview.go | 1 + services/markup/renderhelper_codepreview_test.go | 14 +++++++------- templates/base/markup_codepreview.tmpl | 4 ++-- web_src/css/markup/codepreview.css | 1 + 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/modules/markup/sanitizer_default.go b/modules/markup/sanitizer_default.go index 0fbf0f0b24c08..7fdf66c4bce5a 100644 --- a/modules/markup/sanitizer_default.go +++ b/modules/markup/sanitizer_default.go @@ -30,6 +30,9 @@ func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy { // Chroma always uses 1-2 letters for style names, we could tolerate it at the moment policy.AllowAttrs("class").Matching(regexp.MustCompile(`^\w{0,2}$`)).OnElements("span") + // Line numbers on codepreview + policy.AllowAttrs("data-line-number").OnElements("span") + // Custom URL-Schemes if len(setting.Markdown.CustomURLSchemes) > 0 { policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) diff --git a/services/markup/renderhelper_codepreview.go b/services/markup/renderhelper_codepreview.go index fa1eb824a2f54..44c0596dcecd8 100644 --- a/services/markup/renderhelper_codepreview.go +++ b/services/markup/renderhelper_codepreview.go @@ -110,6 +110,7 @@ func renderRepoFileCodePreview(ctx context.Context, opts markup.RenderCodePrevie "FilePath": opts.FilePath, "LineStart": opts.LineStart, "LineStop": realLineStop, + "RepoName": opts.RepoName, "RepoLink": dbRepo.Link(), "CommitID": opts.CommitID, "HighlightLines": highlightLines, diff --git a/services/markup/renderhelper_codepreview_test.go b/services/markup/renderhelper_codepreview_test.go index ea945584b427e..63e7f4d3bdf10 100644 --- a/services/markup/renderhelper_codepreview_test.go +++ b/services/markup/renderhelper_codepreview_test.go @@ -24,15 +24,15 @@ func TestRenderHelperCodePreview(t *testing.T) { OwnerName: "user2", RepoName: "repo1", CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", - FilePath: "/README.md", + FilePath: "README.md", LineStart: 1, LineStop: 2, }) assert.NoError(t, err) assert.Equal(t, `
- /README.md - repo.code_preview_line_from_to:1,2,65f1bf27bc + repo1/README.md + repo.code_preview_line_from_to:1,2,65f1bf27bc
@@ -52,14 +52,14 @@ func TestRenderHelperCodePreview(t *testing.T) { OwnerName: "user2", RepoName: "repo1", CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", - FilePath: "/README.md", + FilePath: "README.md", LineStart: 1, }) assert.NoError(t, err) assert.Equal(t, `
- /README.md - repo.code_preview_line_in:1,65f1bf27bc + repo1/README.md + repo.code_preview_line_in:1,65f1bf27bc
@@ -76,7 +76,7 @@ func TestRenderHelperCodePreview(t *testing.T) { OwnerName: "user15", RepoName: "big_test_private_1", CommitID: "65f1bf27bc3bf70f64657658635e66094edbcb4d", - FilePath: "/README.md", + FilePath: "README.md", LineStart: 1, LineStop: 10, }) diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl index a1a4f26b478da..e16848581d949 100644 --- a/templates/base/markup_codepreview.tmpl +++ b/templates/base/markup_codepreview.tmpl @@ -1,7 +1,7 @@
- {{.FilePath}} - {{$link := HTMLFormat `%s` .RepoLink .CommitID (.CommitID | ShortSha) -}} + {{.RepoName}}/{{.FilePath}} + {{$link := HTMLFormat `%s` .RepoLink .CommitID (.CommitID | ShortSha) -}} {{- if eq .LineStart .LineStop -}} {{ctx.Locale.Tr "repo.code_preview_line_in" .LineStart $link}} {{- else -}} diff --git a/web_src/css/markup/codepreview.css b/web_src/css/markup/codepreview.css index c9d19f5cc8523..155bb5a74d291 100644 --- a/web_src/css/markup/codepreview.css +++ b/web_src/css/markup/codepreview.css @@ -5,6 +5,7 @@ } .markup .code-preview-container .code-preview-header { + color: var(--color-text-light-1); border-bottom: 1px solid var(--color-secondary); padding: 0.5em; font-size: 12px; From d253e2055bc08b31ee50b5279571da05e5e72672 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 31 Oct 2025 10:33:27 +0800 Subject: [PATCH 41/88] Fix file extension on gogs.png (#35793) (#35799) Backport #35793 by @silverwind During https://github.com/go-gitea/gitea/issues/35790, it was noticed that this PNG image had the wrong file extension. I also verified `dingtalk.ico` and that one is actually an `.ico`. Co-authored-by: silverwind --- public/assets/img/{gogs.ico => gogs.png} | Bin templates/shared/webhook/icon.tmpl | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename public/assets/img/{gogs.ico => gogs.png} (100%) diff --git a/public/assets/img/gogs.ico b/public/assets/img/gogs.png similarity index 100% rename from public/assets/img/gogs.ico rename to public/assets/img/gogs.png diff --git a/templates/shared/webhook/icon.tmpl b/templates/shared/webhook/icon.tmpl index 105212eb56928..c7fb9813abf09 100644 --- a/templates/shared/webhook/icon.tmpl +++ b/templates/shared/webhook/icon.tmpl @@ -5,7 +5,7 @@ {{if eq .HookType "gitea"}} {{svg "gitea-gitea" $size "img"}} {{else if eq .HookType "gogs"}} - + {{else if eq .HookType "slack"}} {{else if eq .HookType "discord"}} From fddf6cd63fa32d1f85ff716e9046b2270208c9ea Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sat, 1 Nov 2025 05:00:14 +0800 Subject: [PATCH 42/88] Fix cli "Before" handling (#35797) (#35808) Backport #35797 by @wxiaoguang Regression of #34973 Fix #35796 Co-authored-by: wxiaoguang --- cmd/cmd.go | 6 ++++ cmd/keys.go | 2 +- cmd/main.go | 10 +++++-- cmd/main_test.go | 48 +++++++++++++++++++++++------- tests/integration/cmd_keys_test.go | 5 +++- 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/cmd/cmd.go b/cmd/cmd.go index 5b96bcbf9a91a..25e90a169501a 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -121,6 +121,12 @@ func globalBool(c *cli.Command, name string) bool { // Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever. func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cli.Command) (context.Context, error) { return func(ctx context.Context, c *cli.Command) (context.Context, error) { + if setting.InstallLock { + // During config loading, there might also be logs (for example: deprecation warnings). + // It must make sure that console logger is set up before config is loaded. + log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it.") + return nil, errors.New("console logger must be setup before config is loaded") + } level := defaultLevel if globalBool(c, "quiet") { level = log.FATAL diff --git a/cmd/keys.go b/cmd/keys.go index 5ca3b91e15e73..035d39bfb8625 100644 --- a/cmd/keys.go +++ b/cmd/keys.go @@ -19,7 +19,7 @@ import ( var CmdKeys = &cli.Command{ Name: "keys", Usage: "(internal) Should only be called by SSH server", - Hidden: true, // internal commands shouldn't not be visible + Hidden: true, // internal commands shouldn't be visible Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint", Before: PrepareConsoleLoggerLevel(log.FATAL), Action: runKeys, diff --git a/cmd/main.go b/cmd/main.go index 3fdaf48ed9665..da979ee5115a8 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -50,11 +50,15 @@ DEFAULT CONFIGURATION: func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) { originBefore := originCmd.Before - originCmd.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) { - prepareWorkPathAndCustomConf(cmd) + originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) { + ctx = ctxOrig if originBefore != nil { - return originBefore(ctx, cmd) + ctx, err = originBefore(ctx, cmd) + if err != nil { + return ctx, err + } } + prepareWorkPathAndCustomConf(cmd) return ctx, nil } } diff --git a/cmd/main_test.go b/cmd/main_test.go index d49ebfd4df41d..69ea1237c63f0 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" "github.com/urfave/cli/v3" @@ -28,11 +29,11 @@ func makePathOutput(workPath, customPath, customConf string) string { return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf) } -func newTestApp(testCmdAction cli.ActionFunc) *cli.Command { +func newTestApp(testCmd cli.Command) *cli.Command { app := NewMainApp(AppVersion{}) - testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction} - prepareSubcommandWithGlobalFlags(testCmd) - app.Commands = append(app.Commands, testCmd) + testCmd.Name = util.IfZero(testCmd.Name, "test-cmd") + prepareSubcommandWithGlobalFlags(&testCmd) + app.Commands = append(app.Commands, &testCmd) app.DefaultCommand = testCmd.Name return app } @@ -156,9 +157,11 @@ func TestCliCmd(t *testing.T) { for _, c := range cases { t.Run(c.cmd, func(t *testing.T) { - app := newTestApp(func(ctx context.Context, cmd *cli.Command) error { - _, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) - return nil + app := newTestApp(cli.Command{ + Action: func(ctx context.Context, cmd *cli.Command) error { + _, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf)) + return nil + }, }) for k, v := range c.env { t.Setenv(k, v) @@ -173,31 +176,54 @@ func TestCliCmd(t *testing.T) { } func TestCliCmdError(t *testing.T) { - app := newTestApp(func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }) + app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }}) r, err := runTestApp(app, "./gitea", "test-cmd") assert.Error(t, err) assert.Equal(t, 1, r.ExitCode) assert.Empty(t, r.Stdout) assert.Equal(t, "Command error: normal error\n", r.Stderr) - app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }) + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }}) r, err = runTestApp(app, "./gitea", "test-cmd") assert.Error(t, err) assert.Equal(t, 2, r.ExitCode) assert.Empty(t, r.Stdout) assert.Equal(t, "exit error\n", r.Stderr) - app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return nil }) + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such") assert.Error(t, err) assert.Equal(t, 1, r.ExitCode) assert.Empty(t, r.Stdout) assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr) - app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return nil }) + app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }}) r, err = runTestApp(app, "./gitea", "test-cmd") assert.NoError(t, err) assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called assert.Empty(t, r.Stdout) assert.Empty(t, r.Stderr) } + +func TestCliCmdBefore(t *testing.T) { + ctxNew := context.WithValue(context.Background(), any("key"), "value") + configValues := map[string]string{} + setting.CustomConf = "/tmp/any.ini" + var actionCtx context.Context + app := newTestApp(cli.Command{ + Before: func(context.Context, *cli.Command) (context.Context, error) { + configValues["before"] = setting.CustomConf + return ctxNew, nil + }, + Action: func(ctx context.Context, cmd *cli.Command) error { + configValues["action"] = setting.CustomConf + actionCtx = ctx + return nil + }, + }) + _, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd") + assert.NoError(t, err) + assert.Equal(t, ctxNew, actionCtx) + assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config") + assert.Equal(t, "/dev/null", configValues["action"]) +} diff --git a/tests/integration/cmd_keys_test.go b/tests/integration/cmd_keys_test.go index be226a01ecc5f..d911bdf17d2d3 100644 --- a/tests/integration/cmd_keys_test.go +++ b/tests/integration/cmd_keys_test.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/cmd" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" @@ -36,13 +37,15 @@ func Test_CmdKeys(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + // FIXME: this test is not quite right. Each "command run" always re-initializes settings + defer test.MockVariableValue(&cmd.CmdKeys.Before, nil)() // don't re-initialize logger during the test + var stdout, stderr bytes.Buffer app := &cli.Command{ Writer: &stdout, ErrWriter: &stderr, Commands: []*cli.Command{cmd.CmdKeys}, } - cmd.CmdKeys.HideHelp = true err := app.Run(t.Context(), append([]string{"prog"}, tt.args...)) if tt.wantErr { assert.Error(t, err) From e95378329beb7f136615b760b8bf27ce66f22d52 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Mon, 3 Nov 2025 02:20:27 +0800 Subject: [PATCH 43/88] Fix clone mixed bug (#35810) (#35822) --- cmd/serv.go | 14 ++++++----- tests/integration/wiki_test.go | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/cmd/serv.go b/cmd/serv.go index 72ca7c4a00404..4110fda0d50b4 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -18,7 +18,7 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/perm" - "code.gitea.io/gitea/models/repo" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/json" @@ -207,7 +207,7 @@ func runServ(ctx context.Context, c *cli.Command) error { username := repoPathFields[0] reponame := strings.TrimSuffix(repoPathFields[1], ".git") // “the-repo-name" or "the-repo-name.wiki" - if !repo.IsValidSSHAccessRepoName(reponame) { + if !repo_model.IsValidSSHAccessRepoName(reponame) { return fail(ctx, "Invalid repo name", "Invalid repo name: %s", reponame) } @@ -253,10 +253,12 @@ func runServ(ctx context.Context, c *cli.Command) error { return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error) } - // LowerCase and trim the repoPath as that's how they are stored. - // This should be done after splitting the repoPath into username and reponame - // so that username and reponame are not affected. - repoPath = strings.ToLower(results.OwnerName + "/" + results.RepoName + ".git") + // because the original repoPath maybe redirected, we need to use the returned actual repository information + if results.IsWiki { + repoPath = repo_model.RelativeWikiPath(results.OwnerName, results.RepoName) + } else { + repoPath = repo_model.RelativePath(results.OwnerName, results.RepoName) + } // LFS SSH protocol if verb == git.CmdVerbLfsTransfer { diff --git a/tests/integration/wiki_test.go b/tests/integration/wiki_test.go index c31f73eabf827..5718156ffad27 100644 --- a/tests/integration/wiki_test.go +++ b/tests/integration/wiki_test.go @@ -11,7 +11,9 @@ import ( "strings" "testing" + auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/tests" @@ -71,3 +73,46 @@ func Test_RepoWikiPages(t *testing.T) { assert.Equal(t, expectedPagePaths[i], pagePath) }) } + +func Test_WikiClone(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + username := "user2" + reponame := "repo1" + wikiPath := username + "/" + reponame + ".wiki.git" + keyname := "my-testing-key" + baseAPITestContext := NewAPITestContext(t, username, "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) + + u.Path = wikiPath + + t.Run("Clone HTTP", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + dstLocalPath := t.TempDir() + assert.NoError(t, git.Clone(t.Context(), u.String(), dstLocalPath, git.CloneRepoOptions{})) + content, err := os.ReadFile(filepath.Join(dstLocalPath, "Home.md")) + assert.NoError(t, err) + assert.Equal(t, "# Home page\n\nThis is the home page!\n", string(content)) + }) + + t.Run("Clone SSH", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + dstLocalPath := t.TempDir() + sshURL := createSSHUrl(wikiPath, u) + + withKeyFile(t, keyname, func(keyFile string) { + var keyID int64 + t.Run("CreateUserKey", doAPICreateUserKey(baseAPITestContext, "test-key", keyFile, func(t *testing.T, key api.PublicKey) { + keyID = key.ID + })) + assert.NotZero(t, keyID) + + // Setup clone folder + assert.NoError(t, git.Clone(t.Context(), sshURL.String(), dstLocalPath, git.CloneRepoOptions{})) + content, err := os.ReadFile(filepath.Join(dstLocalPath, "Home.md")) + assert.NoError(t, err) + assert.Equal(t, "# Home page\n\nThis is the home page!\n", string(content)) + }) + }) + }) +} From 8ffc1fbfbfd788d3a6e92c53ea7a4d68200dda6e Mon Sep 17 00:00:00 2001 From: Giteabot Date: Mon, 3 Nov 2025 17:08:13 +0800 Subject: [PATCH 44/88] Revert gomail to v0.7.0 to fix sending mail failed (#35816) (#35824) Backport #35816 by @lunny Revert gomail to the last work version to fix #35794 There is a problem between go mail v0.7.1 to prevent sending email work. https://github.com/wneessen/go-mail/compare/v0.7.0...v0.7.1 Co-authored-by: Lunny Xiao --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e4c0a5a989d3f..7e6c802ca5a42 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( github.com/ulikunitz/xz v0.5.15 github.com/urfave/cli-docs/v3 v3.0.0-alpha6 github.com/urfave/cli/v3 v3.4.1 - github.com/wneessen/go-mail v0.7.2 + github.com/wneessen/go-mail v0.7.0 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.7.13 diff --git a/go.sum b/go.sum index d5ea5f66631f6..2480f6c4d44dc 100644 --- a/go.sum +++ b/go.sum @@ -768,8 +768,8 @@ github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZ github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8= -github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= +github.com/wneessen/go-mail v0.7.0 h1:/Wmgd5AVjp5PA+Ken5EFfr+QR83gmqHli9HcAhh0vnU= +github.com/wneessen/go-mail v0.7.0/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= From 74dfadb543d3d450af71c7297db752352e2b563d Mon Sep 17 00:00:00 2001 From: Giteabot Date: Mon, 3 Nov 2025 17:37:01 +0800 Subject: [PATCH 45/88] Fix circular spin animation direction (#35785) (#35823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport #35785 by @lutinglt Wait for the status icon to rotate clockwise instead of counterclockwise before: ![GIF 2025-10-30 10-50-07](https://github.com/user-attachments/assets/3771b0bf-44e4-45a0-bde5-1b2b3dd8ba2a) after: ![GIF 2025-10-30 10-50-43](https://github.com/user-attachments/assets/c45307fe-39a4-4e60-b48e-9d922c407565) This can be merged to 1.25 Signed-off-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com> Signed-off-by: wxiaoguang Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com> Co-authored-by: lutinglt Co-authored-by: wxiaoguang --- templates/repo/actions/status.tmpl | 2 +- templates/repo/issue/view_content/pull_merge_box.tmpl | 2 +- web_src/css/modules/animations.css | 10 ++++------ web_src/js/components/ActionRunStatus.vue | 2 +- web_src/js/components/RepoActionView.vue | 2 +- web_src/js/components/RepoCodeFrequency.vue | 2 +- web_src/js/components/RepoContributors.vue | 2 +- web_src/js/components/RepoRecentCommits.vue | 2 +- web_src/js/components/ViewFileTreeItem.vue | 2 +- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/templates/repo/actions/status.tmpl b/templates/repo/actions/status.tmpl index 055bc714c947c..1e5465a97fbd6 100644 --- a/templates/repo/actions/status.tmpl +++ b/templates/repo/actions/status.tmpl @@ -16,7 +16,7 @@ {{else if eq .status "blocked"}} {{svg "octicon-blocked" $size (printf "text yellow %s" $className)}} {{else if eq .status "running"}} - {{svg "gitea-running" $size (printf "text yellow circular-spin %s" $className)}} + {{svg "gitea-running" $size (printf "text yellow rotate-clockwise %s" $className)}} {{else}}{{/*failure, unknown*/}} {{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}} {{end}} diff --git a/templates/repo/issue/view_content/pull_merge_box.tmpl b/templates/repo/issue/view_content/pull_merge_box.tmpl index 4de67be698502..53375d3ab011e 100644 --- a/templates/repo/issue/view_content/pull_merge_box.tmpl +++ b/templates/repo/issue/view_content/pull_merge_box.tmpl @@ -103,7 +103,7 @@ {{template "repo/issue/view_content/update_branch_by_merge" $}} {{else if .Issue.PullRequest.IsChecking}}
- {{svg "octicon-sync" 16 "circular-spin"}} + {{svg "gitea-running" 16 "rotate-clockwise"}} {{ctx.Locale.Tr "repo.pulls.is_checking"}}
{{else if .Issue.PullRequest.IsAncestor}} diff --git a/web_src/css/modules/animations.css b/web_src/css/modules/animations.css index deaaf83680bcb..779339c46b39d 100644 --- a/web_src/css/modules/animations.css +++ b/web_src/css/modules/animations.css @@ -116,14 +116,12 @@ code.language-math.is-loading::after { animation-timing-function: ease-in-out; } -/* FIXME: `octicon-sync` is counterclockwise, so this animation is also counterclockwise, it looks somewhat strange. -Ideally in the future we should use a better image for clockwise animation. */ -.circular-spin { - animation: circular-spin-keyframes 1s linear infinite; +.rotate-clockwise { + animation: rotate-clockwise-keyframes 1s linear infinite; } -@keyframes circular-spin-keyframes { +@keyframes rotate-clockwise-keyframes { 100% { - transform: rotate(-360deg); + transform: rotate(360deg); } } diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue index 22f79384e30fa..24fae920a8bf0 100644 --- a/web_src/js/components/ActionRunStatus.vue +++ b/web_src/js/components/ActionRunStatus.vue @@ -24,7 +24,7 @@ withDefaults(defineProps<{ - + diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 24c0f5300c480..300f635793456 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -608,7 +608,7 @@ export default defineComponent({ - + diff --git a/web_src/js/components/RepoCodeFrequency.vue b/web_src/js/components/RepoCodeFrequency.vue index 9afacbbf24948..efdf2bae713b8 100644 --- a/web_src/js/components/RepoCodeFrequency.vue +++ b/web_src/js/components/RepoCodeFrequency.vue @@ -150,7 +150,7 @@ const options: ChartOptions<'line'> = {
- + {{ locale.loadingInfo }}
diff --git a/web_src/js/components/RepoContributors.vue b/web_src/js/components/RepoContributors.vue index c3a32fe3fc462..08d63540e280b 100644 --- a/web_src/js/components/RepoContributors.vue +++ b/web_src/js/components/RepoContributors.vue @@ -381,7 +381,7 @@ export default defineComponent({
- + {{ locale.loadingInfo }}
diff --git a/web_src/js/components/RepoRecentCommits.vue b/web_src/js/components/RepoRecentCommits.vue index 8ca825993b2d2..39e86781d112d 100644 --- a/web_src/js/components/RepoRecentCommits.vue +++ b/web_src/js/components/RepoRecentCommits.vue @@ -128,7 +128,7 @@ const options: ChartOptions<'bar'> = {
- + {{ locale.loadingInfo }}
diff --git a/web_src/js/components/ViewFileTreeItem.vue b/web_src/js/components/ViewFileTreeItem.vue index 5173c7eb46c19..06d761dd65311 100644 --- a/web_src/js/components/ViewFileTreeItem.vue +++ b/web_src/js/components/ViewFileTreeItem.vue @@ -62,7 +62,7 @@ const onItemClick = (e: MouseEvent) => { @click.stop="onItemClick" >
- +
From 0a9cbf32280dfce404b85aee78c64ab29a7df301 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 4 Nov 2025 04:28:12 +0800 Subject: [PATCH 46/88] upgrade go mail to 0.7.2 and fix the bug (#35833) (#35837) Backport #35833 by @lunny patch from https://github.com/wneessen/go-mail/issues/504#issuecomment-3477890515. Thanks to @wneessen Co-authored-by: Lunny Xiao --- go.mod | 2 +- go.sum | 4 ++-- services/mailer/sender/smtp.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 7e6c802ca5a42..e4c0a5a989d3f 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( github.com/ulikunitz/xz v0.5.15 github.com/urfave/cli-docs/v3 v3.0.0-alpha6 github.com/urfave/cli/v3 v3.4.1 - github.com/wneessen/go-mail v0.7.0 + github.com/wneessen/go-mail v0.7.2 github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.1 github.com/yuin/goldmark v1.7.13 diff --git a/go.sum b/go.sum index 2480f6c4d44dc..d5ea5f66631f6 100644 --- a/go.sum +++ b/go.sum @@ -768,8 +768,8 @@ github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZ github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/wneessen/go-mail v0.7.0 h1:/Wmgd5AVjp5PA+Ken5EFfr+QR83gmqHli9HcAhh0vnU= -github.com/wneessen/go-mail v0.7.0/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= +github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8= +github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= diff --git a/services/mailer/sender/smtp.go b/services/mailer/sender/smtp.go index 8dc1b40b748b6..3207eee32fcec 100644 --- a/services/mailer/sender/smtp.go +++ b/services/mailer/sender/smtp.go @@ -128,7 +128,7 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error { return fmt.Errorf("failed to issue MAIL command: %w", err) } } else { - if err = client.Mail(from); err != nil { + if err = client.Mail(fmt.Sprintf("<%s>", from)); err != nil { return fmt.Errorf("failed to issue MAIL command: %w", err) } } From 8116742e2d4a591d45554bf4e9881b065b2a3ab2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 3 Nov 2025 17:19:50 -0800 Subject: [PATCH 47/88] Fix viewed files number is not right if not all files loaded (#35821) (#35844) Fix #35803 Backport #35821 Signed-off-by: silverwind Co-authored-by: silverwind --- models/pull/review_state.go | 13 +++++++++++++ routers/web/repo/pull.go | 7 ++++++- services/gitdiff/gitdiff.go | 8 +++----- templates/repo/diff/box.tmpl | 4 ++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/models/pull/review_state.go b/models/pull/review_state.go index 137af00eab2d0..e8b759c0cc62e 100644 --- a/models/pull/review_state.go +++ b/models/pull/review_state.go @@ -49,6 +49,19 @@ func init() { db.RegisterModel(new(ReviewState)) } +func (rs *ReviewState) GetViewedFileCount() int { + if len(rs.UpdatedFiles) == 0 { + return 0 + } + var numViewedFiles int + for _, state := range rs.UpdatedFiles { + if state == Viewed { + numViewedFiles++ + } + } + return numViewedFiles +} + // GetReviewState returns the ReviewState with all given values prefilled, whether or not it exists in the database. // If the review didn't exist before in the database, it won't afterwards either. // The returned boolean shows whether the review exists in the database diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index b7dd61c816e08..edccdef8b134c 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -753,12 +753,16 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) { // as the viewed information is designed to be loaded only on latest PR // diff and if you're signed in. var reviewState *pull_model.ReviewState + var numViewedFiles int if ctx.IsSigned && isShowAllCommits { reviewState, err = gitdiff.SyncUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diff, diffOptions) if err != nil { ctx.ServerError("SyncUserSpecificDiff", err) return } + if reviewState != nil { + numViewedFiles = reviewState.GetViewedFileCount() + } } diffShortStat, err := gitdiff.GetDiffShortStat(ctx.Repo.GitRepo, beforeCommitID, afterCommitID) @@ -767,10 +771,11 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) { return } ctx.Data["DiffShortStat"] = diffShortStat + ctx.Data["NumViewedFiles"] = numViewedFiles ctx.PageData["prReview"] = map[string]any{ "numberOfFiles": diffShortStat.NumFiles, - "numberOfViewedFiles": diff.NumViewedFiles, + "numberOfViewedFiles": numViewedFiles, } if err = diff.LoadComments(ctx, issue, ctx.Doer, ctx.Data["ShowOutdatedComments"].(bool)); err != nil { diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 1bb7c05ba2c54..615210ec23903 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -449,10 +449,9 @@ func getCommitFileLineCountAndLimitedContent(commit *git.Commit, filePath string // Diff represents a difference between two git trees. type Diff struct { - Start, End string - Files []*DiffFile - IsIncomplete bool - NumViewedFiles int // user-specific + Start, End string + Files []*DiffFile + IsIncomplete bool } // LoadComments loads comments into each line @@ -1342,7 +1341,6 @@ outer: // Check whether the file has already been viewed if fileViewedState == pull_model.Viewed { diffFile.IsViewed = true - diff.NumViewedFiles++ } } diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index e4d1efac57bd9..2f495351e5a35 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -27,9 +27,9 @@ {{if and .PageIsPullFiles $.SignedUserID (not .DiffNotAvailable)}}
- +
{{end}} {{template "repo/diff/whitespace_dropdown" .}} From 6a55749359958fa687f669e3c165fd27306506b9 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 3 Nov 2025 17:49:47 -0800 Subject: [PATCH 48/88] Fix incorrect pull request counter (#35819) (#35841) Fix #35781, #27472 Backport #35819 The PR will not correct the wrong numbers automatically. There is a cron task `check_repo_stats` which will be run when Gitea start or midnight. It will correct the numbers. --- models/actions/main_test.go | 2 + models/actions/run.go | 1 + models/actions/run_test.go | 35 +++++++++++++++++ models/activities/notification.go | 2 +- models/asymkey/gpg_key_verify.go | 2 +- models/fixtures/repository.yml | 2 + models/git/branch.go | 2 +- models/issues/comment.go | 5 +-- models/issues/issue_update.go | 55 ++++++++++++++++++++++++-- models/issues/milestone.go | 1 + models/issues/pull.go | 2 +- models/migrations/v1_18/v229.go | 1 + models/repo/topic.go | 2 +- services/issue/issue.go | 9 +---- tests/integration/pull_create_test.go | 56 +++++++++++++++++++++++++++ tests/integration/pull_merge_test.go | 48 +++++++++++++++++++++++ 16 files changed, 204 insertions(+), 21 deletions(-) create mode 100644 models/actions/run_test.go diff --git a/models/actions/main_test.go b/models/actions/main_test.go index 5d5089e3bba88..4af483813ab53 100644 --- a/models/actions/main_test.go +++ b/models/actions/main_test.go @@ -13,6 +13,8 @@ func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ FixtureFiles: []string{ "action_runner_token.yml", + "action_run.yml", + "repository.yml", }, }) } diff --git a/models/actions/run.go b/models/actions/run.go index f5ccba06c22b3..dd22901d70d56 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -184,6 +184,7 @@ func (run *ActionRun) IsSchedule() bool { func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error { _, err := db.GetEngine(ctx).ID(repo.ID). NoAutoTime(). + Cols("num_action_runs", "num_closed_action_runs"). SetExpr("num_action_runs", builder.Select("count(*)").From("action_run"). Where(builder.Eq{"repo_id": repo.ID}), diff --git a/models/actions/run_test.go b/models/actions/run_test.go new file mode 100644 index 0000000000000..c65ee1521d995 --- /dev/null +++ b/models/actions/run_test.go @@ -0,0 +1,35 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestUpdateRepoRunsNumbers(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // update the number to a wrong one, the original is 3 + _, err := db.GetEngine(t.Context()).ID(4).Cols("num_closed_action_runs").Update(&repo_model.Repository{ + NumClosedActionRuns: 2, + }) + assert.NoError(t, err) + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + assert.Equal(t, 4, repo.NumActionRuns) + assert.Equal(t, 2, repo.NumClosedActionRuns) + + // now update will correct them, only num_actionr_runs and num_closed_action_runs should be updated + err = updateRepoRunsNumbers(t.Context(), repo) + assert.NoError(t, err) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) + assert.Equal(t, 4, repo.NumActionRuns) + assert.Equal(t, 3, repo.NumClosedActionRuns) +} diff --git a/models/activities/notification.go b/models/activities/notification.go index b482e6020af2f..8a830c5aa26a8 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -386,7 +386,7 @@ func SetNotificationStatus(ctx context.Context, notificationID int64, user *user notification.Status = status - _, err = db.GetEngine(ctx).ID(notificationID).Update(notification) + _, err = db.GetEngine(ctx).ID(notificationID).Cols("status").Update(notification) return notification, err } diff --git a/models/asymkey/gpg_key_verify.go b/models/asymkey/gpg_key_verify.go index 55c64973b4121..5df0265c88082 100644 --- a/models/asymkey/gpg_key_verify.go +++ b/models/asymkey/gpg_key_verify.go @@ -78,7 +78,7 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st } key.Verified = true - if _, err := db.GetEngine(ctx).ID(key.ID).SetExpr("verified", true).Update(new(GPGKey)); err != nil { + if _, err := db.GetEngine(ctx).ID(key.ID).Cols("verified").Update(key); err != nil { return "", err } diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 552a78cbd2773..dfa514db37f21 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -110,6 +110,8 @@ num_closed_milestones: 0 num_projects: 0 num_closed_projects: 1 + num_action_runs: 4 + num_closed_action_runs: 3 is_private: false is_empty: false is_archived: false diff --git a/models/git/branch.go b/models/git/branch.go index 54351649cc5ec..7fef9f5ca35e1 100644 --- a/models/git/branch.go +++ b/models/git/branch.go @@ -368,7 +368,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str } // 1. update branch in database - if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{ + if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Cols("name").Update(&Branch{ Name: to, }); err != nil { return err diff --git a/models/issues/comment.go b/models/issues/comment.go index 3a4049700de1a..fd0500833e751 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -862,10 +862,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment if err = UpdateCommentAttachments(ctx, comment, opts.Attachments); err != nil { return err } - case CommentTypeReopen, CommentTypeClose: - if err = repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.Issue.IsPull, true); err != nil { - return err - } + // comment type reopen and close event have their own logic to update numbers but not here } // update the issue's updated_unix column return UpdateIssueCols(ctx, opts.Issue, "updated_unix") diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 553e99aece290..0a320ffc56fec 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -146,8 +146,19 @@ func updateIssueNumbers(ctx context.Context, issue *Issue, doer *user_model.User } // update repository's issue closed number - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { - return nil, err + switch cmtType { + case CommentTypeClose, CommentTypeMergePull: + // only increase closed count + if err := IncrRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { + return nil, err + } + case CommentTypeReopen: + // only decrease closed count + if err := DecrRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false, true); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("invalid comment type: %d", cmtType) } return CreateComment(ctx, &CreateCommentOptions{ @@ -318,7 +329,6 @@ type NewIssueOptions struct { Issue *Issue LabelIDs []int64 Attachments []string // In UUID format. - IsPull bool } // NewIssueWithIndex creates issue with given index @@ -369,7 +379,8 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue } } - if err := repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.IsPull, false); err != nil { + // Update repository issue total count + if err := IncrRepoIssueNumbers(ctx, opts.Repo.ID, opts.Issue.IsPull, true); err != nil { return err } @@ -439,6 +450,42 @@ func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, la }) } +// IncrRepoIssueNumbers increments repository issue numbers. +func IncrRepoIssueNumbers(ctx context.Context, repoID int64, isPull, totalOrClosed bool) error { + dbSession := db.GetEngine(ctx) + var colName string + if totalOrClosed { + colName = util.Iif(isPull, "num_pulls", "num_issues") + } else { + colName = util.Iif(isPull, "num_closed_pulls", "num_closed_issues") + } + _, err := dbSession.Incr(colName).ID(repoID). + NoAutoCondition().NoAutoTime(). + Update(new(repo_model.Repository)) + return err +} + +// DecrRepoIssueNumbers decrements repository issue numbers. +func DecrRepoIssueNumbers(ctx context.Context, repoID int64, isPull, includeTotal, includeClosed bool) error { + if !includeTotal && !includeClosed { + return fmt.Errorf("no numbers to decrease for repo id %d", repoID) + } + + dbSession := db.GetEngine(ctx) + if includeTotal { + colName := util.Iif(isPull, "num_pulls", "num_issues") + dbSession = dbSession.Decr(colName) + } + if includeClosed { + closedColName := util.Iif(isPull, "num_closed_pulls", "num_closed_issues") + dbSession = dbSession.Decr(closedColName) + } + _, err := dbSession.ID(repoID). + NoAutoCondition().NoAutoTime(). + Update(new(repo_model.Repository)) + return err +} + // UpdateIssueMentions updates issue-user relations for mentioned users. func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_model.User) error { if len(mentions) == 0 { diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 373f39f4ffe82..82a82ac9132b2 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -181,6 +181,7 @@ func updateMilestone(ctx context.Context, m *Milestone) error { func UpdateMilestoneCounters(ctx context.Context, id int64) error { e := db.GetEngine(ctx) _, err := e.ID(id). + Cols("num_issues", "num_closed_issues"). SetExpr("num_issues", builder.Select("count(*)").From("issue").Where( builder.Eq{"milestone_id": id}, )). diff --git a/models/issues/pull.go b/models/issues/pull.go index 7a37b627e1bd0..5669bed61e136 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -471,13 +471,13 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *Iss issue.Index = idx issue.Title = util.EllipsisDisplayString(issue.Title, 255) + issue.IsPull = true if err = NewIssueWithIndex(ctx, issue.Poster, NewIssueOptions{ Repo: repo, Issue: issue, LabelIDs: labelIDs, Attachments: uuids, - IsPull: true, }); err != nil { if repo_model.IsErrUserDoesNotHaveAccessToRepo(err) || IsErrNewIssueInsert(err) { return err diff --git a/models/migrations/v1_18/v229.go b/models/migrations/v1_18/v229.go index bc15e01390862..1f69724365a8d 100644 --- a/models/migrations/v1_18/v229.go +++ b/models/migrations/v1_18/v229.go @@ -21,6 +21,7 @@ func UpdateOpenMilestoneCounts(x *xorm.Engine) error { for _, id := range openMilestoneIDs { _, err := x.ID(id). + Cols("num_issues", "num_closed_issues"). SetExpr("num_issues", builder.Select("count(*)").From("issue").Where( builder.Eq{"milestone_id": id}, )). diff --git a/models/repo/topic.go b/models/repo/topic.go index baeae01efaee6..f8f706fc1a58a 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -159,7 +159,7 @@ func RemoveTopicsFromRepo(ctx context.Context, repoID int64) error { builder.In("id", builder.Select("topic_id").From("repo_topic").Where(builder.Eq{"repo_id": repoID}), ), - ).Cols("repo_count").SetExpr("repo_count", "repo_count-1").Update(&Topic{}) + ).Decr("repo_count").Update(&Topic{}) if err != nil { return err } diff --git a/services/issue/issue.go b/services/issue/issue.go index 62b330f8e20be..85e70d0761814 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -270,16 +270,9 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) ([]string, erro return nil, err } - // update the total issue numbers - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { + if err := issues_model.DecrRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true, issue.IsClosed); err != nil { return nil, err } - // if the issue is closed, update the closed issue numbers - if issue.IsClosed { - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { - return nil, err - } - } if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil { return nil, fmt.Errorf("error updating counters for milestone id %d: %w", diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 83babaca85bf4..17265c836a238 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -10,9 +10,12 @@ import ( "net/url" "path" "strings" + "sync" "testing" auth_model "code.gitea.io/gitea/models/auth" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git/gitcmd" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/tests" @@ -137,8 +140,15 @@ func TestPullCreate(t *testing.T) { session := loginUser(t, "user1") testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo1.NumPulls) + assert.Equal(t, 3, repo1.NumOpenPulls) resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") + repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 4, repo1.NumPulls) + assert.Equal(t, 4, repo1.NumOpenPulls) + // check the redirected URL url := test.RedirectURL(resp) assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url) @@ -285,6 +295,44 @@ func TestPullCreatePrFromBaseToFork(t *testing.T) { }) } +func TestPullCreateParallel(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + sessionFork := loginUser(t, "user1") + testRepoFork(t, sessionFork, "user2", "repo1", "user1", "repo1", "") + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo1.NumPulls) + assert.Equal(t, 3, repo1.NumOpenPulls) + + var wg sync.WaitGroup + for i := range 5 { + wg.Go(func() { + branchName := fmt.Sprintf("new-branch-%d", i) + testEditFileToNewBranch(t, sessionFork, "user1", "repo1", "master", branchName, "README.md", fmt.Sprintf("Hello, World (Edited) %d\n", i)) + + // Create a PR + resp := testPullCreateDirectly(t, sessionFork, createPullRequestOptions{ + BaseRepoOwner: "user2", + BaseRepoName: "repo1", + BaseBranch: "master", + HeadRepoOwner: "user1", + HeadRepoName: "repo1", + HeadBranch: branchName, + Title: fmt.Sprintf("This is a pull title %d", i), + }) + // check the redirected URL + url := test.RedirectURL(resp) + assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url) + }) + } + wg.Wait() + + repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 8, repo1.NumPulls) + assert.Equal(t, 8, repo1.NumOpenPulls) + }) +} + func TestCreateAgitPullWithReadPermission(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { dstPath := t.TempDir() @@ -300,8 +348,16 @@ func TestCreateAgitPullWithReadPermission(t *testing.T) { TreeFileContent: "temp content", })(t) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + err := gitcmd.NewCommand("push", "origin", "HEAD:refs/for/master", "-o").AddDynamicArguments("topic="+"test-topic").Run(t.Context(), &gitcmd.RunOpts{Dir: dstPath}) assert.NoError(t, err) + + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 4, repo.NumOpenPulls) }) } diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index c40c656a6860d..4020c880dfe11 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -99,12 +99,24 @@ func TestPullMerge(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 4, repo.NumOpenPulls) + elem := strings.Split(test.RedirectURL(resp), "/") assert.Equal(t, "pulls", elem[3]) testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + hookTasks, err = webhook.HookTasks(t.Context(), 1, 1) assert.NoError(t, err) assert.Len(t, hookTasks, hookTasksLenBefore+1) @@ -121,12 +133,24 @@ func TestPullRebase(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 4, repo.NumOpenPulls) + elem := strings.Split(test.RedirectURL(resp), "/") assert.Equal(t, "pulls", elem[3]) testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebase, false) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + hookTasks, err = webhook.HookTasks(t.Context(), 1, 1) assert.NoError(t, err) assert.Len(t, hookTasks, hookTasksLenBefore+1) @@ -143,12 +167,24 @@ func TestPullRebaseMerge(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n") + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + resp := testPullCreate(t, session, "user1", "repo1", false, "master", "master", "This is a pull title") + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 4, repo.NumOpenPulls) + elem := strings.Split(test.RedirectURL(resp), "/") assert.Equal(t, "pulls", elem[3]) testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebaseMerge, false) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + hookTasks, err = webhook.HookTasks(t.Context(), 1, 1) assert.NoError(t, err) assert.Len(t, hookTasks, hookTasksLenBefore+1) @@ -184,12 +220,24 @@ func TestPullCleanUpAfterMerge(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "") testEditFileToNewBranch(t, session, "user1", "repo1", "master", "feature/test", "README.md", "Hello, World (Edited - TestPullCleanUpAfterMerge)\n") + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + assert.Equal(t, 3, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + resp := testPullCreate(t, session, "user1", "repo1", false, "master", "feature/test", "This is a pull title") elem := strings.Split(test.RedirectURL(resp), "/") assert.Equal(t, "pulls", elem[3]) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 4, repo.NumOpenPulls) + testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) + assert.Equal(t, 4, repo.NumPulls) + assert.Equal(t, 3, repo.NumOpenPulls) + // Check PR branch deletion resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4]) respJSON := struct { From 297f63af429fa95d8dbeccabc729bf331800ce17 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 5 Nov 2025 02:04:08 +0800 Subject: [PATCH 49/88] Remove wrong code (#35846) (#35856) Backport #35846 by @lunny Follow #35821 Fix https://github.com/go-gitea/gitea/pull/35844#issuecomment-3483521045 The reviewed file numbers and progress have been set from backend so that we don't need to update the numbers when clicking `load more`. Co-authored-by: Lunny Xiao --- web_src/js/features/pull-view-file.ts | 8 -------- web_src/js/features/repo-diff.ts | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/web_src/js/features/pull-view-file.ts b/web_src/js/features/pull-view-file.ts index 1124886238c03..e563c13ef5d92 100644 --- a/web_src/js/features/pull-view-file.ts +++ b/web_src/js/features/pull-view-file.ts @@ -20,14 +20,6 @@ function refreshViewedFilesSummary() { .replace('%[2]d', prReview.numberOfFiles); } -// Explicitly recounts how many files the user has currently reviewed by counting the number of checked "viewed" checkboxes -// Additionally, the viewed files summary will be updated if it exists -export function countAndUpdateViewedFiles() { - // The number of files is constant, but the number of viewed files can change because files can be loaded dynamically - prReview.numberOfViewedFiles = document.querySelectorAll(`${viewedCheckboxSelector} > input[type=checkbox][checked]`).length; - refreshViewedFilesSummary(); -} - // Initializes a listener for all children of the given html element // (for example 'document' in the most basic case) // to watch for changes of viewed-file checkboxes diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index 02d151e102b02..ab08e6f03cf56 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -2,7 +2,7 @@ import {initRepoIssueContentHistory} from './repo-issue-content.ts'; import {initDiffFileTree} from './repo-diff-filetree.ts'; import {initDiffCommitSelect} from './repo-diff-commitselect.ts'; import {validateTextareaNonEmpty} from './comp/ComboMarkdownEditor.ts'; -import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndCollapseFilesButton} from './pull-view-file.ts'; +import {initViewedCheckboxListenerFor, initExpandAndCollapseFilesButton} from './pull-view-file.ts'; import {initImageDiff} from './imagediff.ts'; import {showErrorToast} from '../modules/toast.ts'; import {submitEventSubmitter, queryElemSiblings, hideElem, showElem, animateOnce, addDelegatedEventListener, createElementFromHTML, queryElems} from '../utils/dom.ts'; @@ -152,7 +152,6 @@ function onShowMoreFiles() { // TODO: replace these calls with the "observer.ts" methods initRepoIssueContentHistory(); initViewedCheckboxListenerFor(); - countAndUpdateViewedFiles(); initImageDiff(); initDiffHeaderPopup(); } From 7ea9722c1da111ac863473120828ffce1237b903 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 5 Nov 2025 02:22:26 +0800 Subject: [PATCH 50/88] Make ACME email optional (#35849) (#35857) Backport #35849 by @wxiaoguang Fix a regression from #33668 Fix #35847 Co-authored-by: wxiaoguang --- modules/setting/server.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/setting/server.go b/modules/setting/server.go index 38e166e02ad0d..cedca32da9e35 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -235,9 +235,6 @@ func loadServerFrom(rootCfg ConfigProvider) { deprecatedSetting(rootCfg, "server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL", "v1.19.0") AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("") } - if AcmeEmail == "" { - log.Fatal("ACME Email is not set (ACME_EMAIL).") - } } else { CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() From 61011f16480b9a7eed44fec9b18df3797caa74b6 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Tue, 4 Nov 2025 12:16:36 -0700 Subject: [PATCH 51/88] Add a doctor command to fix inconsistent run status (#35840) (#35845) Backport #35840 #35783 fixes an actions rerun bug. Due to this bug, some runs may be incorrectly marked as `StatusWaiting` even though all the jobs are in done status. These runs cannot be run or cancelled. This PR adds a new doctor command to fix the inconsistent run status. ``` gitea doctor check --run fix-actions-unfinished-run-status --fix ``` --- models/actions/run_test.go | 2 +- models/fixtures/action_run.yml | 21 ++++++ models/fixtures/action_run_job.yml | 15 +++++ models/fixtures/action_task.yml | 21 ++++++ models/fixtures/repo_unit.yml | 7 ++ services/doctor/actions.go | 101 +++++++++++++++++++++++++++++ services/doctor/actions_test.go | 24 +++++++ 7 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 services/doctor/actions_test.go diff --git a/models/actions/run_test.go b/models/actions/run_test.go index c65ee1521d995..6463d6f721211 100644 --- a/models/actions/run_test.go +++ b/models/actions/run_test.go @@ -30,6 +30,6 @@ func TestUpdateRepoRunsNumbers(t *testing.T) { err = updateRepoRunsNumbers(t.Context(), repo) assert.NoError(t, err) repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - assert.Equal(t, 4, repo.NumActionRuns) + assert.Equal(t, 5, repo.NumActionRuns) assert.Equal(t, 3, repo.NumClosedActionRuns) } diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 09dfa6cccbba3..8018ae770fc22 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -139,3 +139,24 @@ updated: 1683636626 need_approval: 0 approved_by: 0 + +- + id: 796 + title: "update actions" + repo_id: 4 + owner_id: 1 + workflow_id: "artifact.yaml" + index: 191 + trigger_user_id: 1 + ref: "refs/heads/master" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + trigger_event: "push" + is_fork_pull_request: 0 + status: 5 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 diff --git a/models/fixtures/action_run_job.yml b/models/fixtures/action_run_job.yml index 6c06d94aa44ca..789eb248a5c33 100644 --- a/models/fixtures/action_run_job.yml +++ b/models/fixtures/action_run_job.yml @@ -129,3 +129,18 @@ status: 5 started: 1683636528 stopped: 1683636626 + +- + id: 205 + run_id: 796 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + name: job_2 + attempt: 1 + job_id: job_2 + task_id: 55 + status: 3 + started: 1683636528 + stopped: 1683636626 diff --git a/models/fixtures/action_task.yml b/models/fixtures/action_task.yml index c79fb070506dd..95d3ee25d18a4 100644 --- a/models/fixtures/action_task.yml +++ b/models/fixtures/action_task.yml @@ -177,3 +177,24 @@ log_length: 0 log_size: 0 log_expired: 0 + +- + id: 55 + job_id: 205 + attempt: 1 + runner_id: 1 + status: 3 # 3 is the status code for "cancelled" + started: 1683636528 + stopped: 1683636626 + repo_id: 4 + owner_id: 1 + commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0 + is_fork_pull_request: 0 + token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4240c64a69a2cc1508825121b7b8394e48e00b1bf3718b2aaaab + token_salt: eeeeeeee + token_last_eight: eeeeeeee + log_filename: artifact-test2/2f/47.log + log_in_storage: 1 + log_length: 707 + log_size: 90179 + log_expired: 0 diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml index f6b6252da1f88..fa89e3f12ad76 100644 --- a/models/fixtures/repo_unit.yml +++ b/models/fixtures/repo_unit.yml @@ -733,3 +733,10 @@ type: 3 config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}" created_unix: 946684810 + +- + id: 111 + repo_id: 4 + type: 10 + config: "{}" + created_unix: 946684810 diff --git a/services/doctor/actions.go b/services/doctor/actions.go index 28e26c88ebe70..cd3d19b724f8a 100644 --- a/services/doctor/actions.go +++ b/services/doctor/actions.go @@ -7,12 +7,17 @@ import ( "context" "fmt" + actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" repo_service "code.gitea.io/gitea/services/repository" + + "xorm.io/builder" ) func disableMirrorActionsUnit(ctx context.Context, logger log.Logger, autofix bool) error { @@ -59,6 +64,95 @@ func disableMirrorActionsUnit(ctx context.Context, logger log.Logger, autofix bo return nil } +func fixUnfinishedRunStatus(ctx context.Context, logger log.Logger, autofix bool) error { + total := 0 + inconsistent := 0 + fixed := 0 + + cond := builder.In("status", []actions_model.Status{ + actions_model.StatusWaiting, + actions_model.StatusRunning, + actions_model.StatusBlocked, + }).And(builder.Lt{"updated": timeutil.TimeStampNow().AddDuration(-setting.Actions.ZombieTaskTimeout)}) + + err := db.Iterate( + ctx, + cond, + func(ctx context.Context, run *actions_model.ActionRun) error { + total++ + + jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID) + if err != nil { + return fmt.Errorf("GetRunJobsByRunID: %w", err) + } + expected := actions_model.AggregateJobStatus(jobs) + if expected == run.Status { + return nil + } + + inconsistent++ + logger.Warn("Run %d (repo_id=%d, index=%d) has status %s, expected %s", run.ID, run.RepoID, run.Index, run.Status, expected) + + if !autofix { + return nil + } + + run.Started, run.Stopped = getRunTimestampsFromJobs(run, expected, jobs) + run.Status = expected + + if err := actions_model.UpdateRun(ctx, run, "status", "started", "stopped"); err != nil { + return fmt.Errorf("UpdateRun: %w", err) + } + fixed++ + + return nil + }, + ) + if err != nil { + logger.Critical("Unable to iterate unfinished runs: %v", err) + return err + } + + if inconsistent == 0 { + logger.Info("Checked %d unfinished runs; all statuses are consistent.", total) + return nil + } + + if autofix { + logger.Info("Checked %d unfinished runs; fixed %d of %d runs.", total, fixed, inconsistent) + } else { + logger.Warn("Checked %d unfinished runs; found %d runs need to be fixed", total, inconsistent) + } + + return nil +} + +func getRunTimestampsFromJobs(run *actions_model.ActionRun, newStatus actions_model.Status, jobs actions_model.ActionJobList) (started, stopped timeutil.TimeStamp) { + started = run.Started + if (newStatus.IsRunning() || newStatus.IsDone()) && started.IsZero() { + var earliest timeutil.TimeStamp + for _, job := range jobs { + if job.Started > 0 && (earliest.IsZero() || job.Started < earliest) { + earliest = job.Started + } + } + started = earliest + } + + stopped = run.Stopped + if newStatus.IsDone() && stopped.IsZero() { + var latest timeutil.TimeStamp + for _, job := range jobs { + if job.Stopped > latest { + latest = job.Stopped + } + } + stopped = latest + } + + return started, stopped +} + func init() { Register(&Check{ Title: "Disable the actions unit for all mirrors", @@ -67,4 +161,11 @@ func init() { Run: disableMirrorActionsUnit, Priority: 9, }) + Register(&Check{ + Title: "Fix inconsistent status for unfinished actions runs", + Name: "fix-actions-unfinished-run-status", + IsDefault: false, + Run: fixUnfinishedRunStatus, + Priority: 9, + }) } diff --git a/services/doctor/actions_test.go b/services/doctor/actions_test.go new file mode 100644 index 0000000000000..a3cca54b9fc91 --- /dev/null +++ b/services/doctor/actions_test.go @@ -0,0 +1,24 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package doctor + +import ( + "testing" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/log" + + "github.com/stretchr/testify/assert" +) + +func Test_fixUnfinishedRunStatus(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + fixUnfinishedRunStatus(t.Context(), log.GetLogger(log.DEFAULT), true) + + // check if the run is cancelled by id + run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 796}) + assert.Equal(t, actions_model.StatusCancelled, run.Status) +} From 470b21056a53d669901c6fdf11022abdee88bdcd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 4 Nov 2025 11:17:59 -0800 Subject: [PATCH 52/88] Add changelog for 1.25.1 and add missing chagnelog for 1.24.x (#35838) --- CHANGELOG.md | 149 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 140 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24efa99352623..dc689ef410c1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,26 @@ This changelog goes through the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.com). -## [1.25.0](https://github.com/go-gitea/gitea/releases/tag/1.25.0) - 2025-10-30 +## [1.25.1](https://github.com/go-gitea/gitea/releases/tag/v1.25.1) - 2025-11-03 + +* BUGFIXES + * Make ACME email optional (#35849) #35857 + * Add a doctor command to fix inconsistent run status (#35840) (#35845) + * Remove wrong code (#35846) + * Fix viewed files number is not right if not all files loaded (#35821) (#35844) + * Fix incorrect pull request counter (#35819) (#35841) + * Upgrade go mail to 0.7.2 and fix the bug (#35833) (#35837) + * Revert gomail to v0.7.0 to fix sending mail failed (#35816) (#35824) + * Fix clone mixed bug (#35810) (#35822) + * Fix cli "Before" handling (#35797) (#35808) + * Improve and fix markup code preview rendering (#35777) (#35787) + * Fix actions rerun bug (#35783) (#35784) + * Fix actions schedule update issue (#35767) (#35774) + * Fix circular spin animation direction (#35785) (#35823) + * Fix file extension on gogs.png (#35793) (#35799) + * Add pnpm to Snapcraft (#35778) + +## [1.25.0](https://github.com/go-gitea/gitea/releases/tag/v1.25.0) - 2025-10-30 * BREAKING * Return 201 Created for CreateVariable API responses (#34517) @@ -231,7 +250,119 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Docs/fix typo and grammar in CONTRIBUTING.md (#35024) * Improve english grammar and readability in locale_en-US.ini (#35017) -## [1.24.0](https://github.com/go-gitea/gitea/releases/tag/1.24.0) - 2025-05-26 +## [1.24.7](https://github.com/go-gitea/gitea/releases/tag/v1.24.7) - 2025-10-24 + +* SECURITY + * Refactor legacy code (#35708) (#35713) + * Fixing issue #35530: Password Leak in Log Messages (#35584) (#35665) + * Fix a bug missed return (#35655) (#35671) +* BUGFIXES + * Fix inputing review comment will remove reviewer (#35591) (#35664) +* TESTING + * Mock external service in hcaptcha TestCaptcha (#35604) (#35663) + * Fix build (#35669) + +## [1.24.6](https://github.com/go-gitea/gitea/releases/tag/v1.24.6) - 2025-09-10 + +* SECURITY + * Upgrade xz to v0.5.15 (#35385) +* BUGFIXES + * Fix a compare page 404 bug when the pull request disabled (#35441) (#35453) + * Fix bug when issue disabled, pull request number in the commit message cannot be redirected (#35420) (#35442) + * Add author.name field to Swift Package Registry API response (#35410) (#35431) + * Remove usernames when empty in discord webhook (#35412) (#35417) + * Allow foreachref parser to grow its buffer (#35365) (#35376) + * Allow deleting comment with content via API like web did (#35346) (#35354) + * Fix atom/rss mixed error (#35345) (#35347) + * Fix review request webhook bug (#35339) + * Remove duplicate html IDs (#35210) (#35325) + * Fix LFS range size header response (#35277) (#35293) + * Fix GitHub release assets URL validation (#35287) (#35290) + * Fix token lifetime, closes #35230 (#35271) (#35281) + * Fix push commits comments when changing the pull request target branch (#35386) (#35443) + +## [1.24.5](https://github.com/go-gitea/gitea/releases/tag/v1.24.5) - 2025-08-12 + +* BUGFIXES + * Fix a bug where lfs gc never worked. (#35198) (#35255) + * Reload issue when sending webhook to make num comments is right. (#35243) (#35248) + * Fix bug when review pull request commits (#35192) (#35246) +* MISC + * Vertically center "Show Resolved" (#35211) (#35218) + +## [1.24.4](https://github.com/go-gitea/gitea/releases/tag/v1.24.4) - 2025-08-03 + +* BUGFIXES + * Fix various bugs (1.24) (#35186) + * Fix migrate input box bug (#35166) (#35171) + * Only hide dropzone when no files have been uploaded (#35156) (#35167) + * Fix review comment/dimiss comment x reference can be refereced back (#35094) (#35099) + * Fix submodule nil check (#35096) (#35098) +* MISC + * Don't use full-file highlight when there is a git diff textconv (#35114) (#35119) + * Increase gap on latest commit (#35104) (#35113) + +## [1.24.3](https://github.com/go-gitea/gitea/releases/tag/v1.24.3) - 2025-07-15 + +* BUGFIXES + * Fix form property assignment edge case (#35073) (#35078) + * Improve submodule relative path handling (#35056) (#35075) + * Fix incorrect comment diff hunk parsing, fix github asset ID nil panic (#35046) (#35055) + * Fix updating user visibility (#35036) (#35044) + * Support base64-encoded agit push options (#35037) (#35041) + * Make submodule link work with relative path (#35034) (#35038) + * Fix bug when displaying git user avatar in commits list (#35006) + * Fix API response for swagger spec (#35029) + * Start automerge check again after the conflict check and the schedule (#34988) (#35002) + * Fix the response format for actions/workflows (#35009) (#35016) + * Fix repo settings and protocol log problems (#35012) (#35013) + * Fix project images scroll (#34971) (#34972) + * Mark old reviews as stale on agit pr updates (#34933) (#34965) + * Fix git graph page (#34948) (#34949) + * Don't send trigger for a pending review's comment create/update/delete (#34928) (#34939) + * Fix some log and UI problems (#34863) (#34868) + * Fix archive API (#34853) (#34857) + * Ignore force pushes for changed files in a PR review (#34837) (#34843) + * Fix SSH LFS timeout (#34838) (#34842) + * Fix team permissions (#34827) (#34836) + * Fix job status aggregation logic (#34823) (#34835) + * Fix issue filter (#34914) (#34915) + * Fix typo in pull request merge warning message text (#34899) (#34903) + * Support the open-icon of folder (#34168) (#34896) + * Optimize flex layout of release attachment area (#34885) (#34886) + * Fix the issue of abnormal interface when there is no issue-item on the project page (#34791) (#34880) + * Skip updating timestamp when sync branch (#34875) + * Fix required contexts and commit status matching bug (#34815) (#34829) + +## [1.24.2](https://github.com/go-gitea/gitea/releases/tag/v1.24.2) - 2025-06-20 + +* BUGFIXES + * Fix container range bug (#34795) (#34796) + * Upgrade chi to v5.2.2 (#34798) (#34799) +* BUILD + * Bump poetry feature to new url for dev container (#34787) (#34790) + +## [1.24.1](https://github.com/go-gitea/gitea/releases/tag/v1.24.1) - 2025-06-18 + +* ENHANCEMENTS + * Improve alignment of commit status icon on commit page (#34750) (#34757) + * Support title and body query parameters for new PRs (#34537) (#34752) + +* BUGFIXES + * When using rules to delete packages, remove unclean bugs (#34632) (#34761) + * Fix ghost user in feeds when pushing in an actions, it should be gitea-actions (#34703) (#34756) + * Prevent double markdown link brackets when pasting URL (#34745) (#34748) + * Prevent duplicate form submissions when creating forks (#34714) (#34735) + * Fix markdown wrap (#34697) (#34702) + * Fix pull requests API convert panic when head repository is deleted. (#34685) (#34687) + * Fix commit message rendering and some UI problems (#34680) (#34683) + * Fix container range bug (#34725) (#34732) + * Fix incorrect cli default values (#34765) (#34766) + * Fix dropdown filter (#34708) (#34711) + * Hide href attribute of a tag if there is no target_url (#34556) (#34684) + * Fix tag target (#34781) #34783 + +## [1.24.0](https://github.com/go-gitea/gitea/releases/tag/v1.24.0) - 2025-05-26 * BREAKING * Make Gitea always use its internal config, ignore `/etc/gitconfig` (#33076) @@ -601,7 +732,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Bump x/net (#32896) (#32900) * Only activity tab needs heatmap data loading (#34652) -## [1.23.8](https://github.com/go-gitea/gitea/releases/tag/1.23.8) - 2025-05-11 +## [1.23.8](https://github.com/go-gitea/gitea/releases/tag/v1.23.8) - 2025-05-11 * SECURITY * Fix a bug when uploading file via lfs ssh command (#34408) (#34411) @@ -628,7 +759,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * Bump go version in go.mod (#34160) * remove hardcoded 'code' string in clone_panel.tmpl (#34153) (#34158) -## [1.23.7](https://github.com/go-gitea/gitea/releases/tag/1.23.7) - 2025-04-07 +## [1.23.7](https://github.com/go-gitea/gitea/releases/tag/v1.23.7) - 2025-04-07 * Enhancements * Add a config option to block "expensive" pages for anonymous users (#34024) (#34071) @@ -726,7 +857,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com). * BUGFIXES * Fix a bug caused by status webhook template #33512 -## [1.23.2](https://github.com/go-gitea/gitea/releases/tag/1.23.2) - 2025-02-04 +## [1.23.2](https://github.com/go-gitea/gitea/releases/tag/v1.23.2) - 2025-02-04 * BREAKING * Add tests for webhook and fix some webhook bugs (#33396) (#33442) @@ -3256,7 +3387,7 @@ Key highlights of this release encompass significant changes categorized under ` * Improve decryption failure message (#24573) (#24575) * Makefile: Use portable !, not GNUish -not, with find(1). (#24565) (#24572) -## [1.19.3](https://github.com/go-gitea/gitea/releases/tag/1.19.3) - 2023-05-03 +## [1.19.3](https://github.com/go-gitea/gitea/releases/tag/v1.19.3) - 2023-05-03 * SECURITY * Use golang 1.20.4 to fix CVE-2023-24539, CVE-2023-24540, and CVE-2023-29400 @@ -3269,7 +3400,7 @@ Key highlights of this release encompass significant changes categorized under ` * Fix incorrect CurrentUser check for docker rootless (#24435) * Getting the tag list does not require being signed in (#24413) (#24416) -## [1.19.2](https://github.com/go-gitea/gitea/releases/tag/1.19.2) - 2023-04-26 +## [1.19.2](https://github.com/go-gitea/gitea/releases/tag/v1.19.2) - 2023-04-26 * SECURITY * Require repo scope for PATs for private repos and basic authentication (#24362) (#24364) @@ -3768,7 +3899,7 @@ Key highlights of this release encompass significant changes categorized under ` * Display attachments of review comment when comment content is blank (#23035) (#23046) * Return empty url for submodule tree entries (#23043) (#23048) -## [1.18.4](https://github.com/go-gitea/gitea/releases/tag/1.18.4) - 2023-02-20 +## [1.18.4](https://github.com/go-gitea/gitea/releases/tag/v1.18.4) - 2023-02-20 * SECURITY * Provide the ability to set password hash algorithm parameters (#22942) (#22943) @@ -4195,7 +4326,7 @@ Key highlights of this release encompass significant changes categorized under ` * Fix the mode of custom dir to 0700 in docker-rootless (#20861) (#20867) * Fix UI mis-align for PR commit history (#20845) (#20859) -## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/1.17.1) - 2022-08-17 +## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/v1.17.1) - 2022-08-17 * SECURITY * Correctly escape within tribute.js (#20831) (#20832) From f84bf259ad8d6dce2b609a964f7a422fbbc8bbb6 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 6 Nov 2025 01:19:47 +0800 Subject: [PATCH 53/88] Fix gogit ListEntriesRecursiveWithSize (#35862) It needs to use full git path. Fix #35852. --- modules/git/tree_entry_gogit.go | 5 +++++ modules/git/tree_gogit.go | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/git/tree_entry_gogit.go b/modules/git/tree_entry_gogit.go index e6845f1c776fe..1e6eec8ed4aae 100644 --- a/modules/git/tree_entry_gogit.go +++ b/modules/git/tree_entry_gogit.go @@ -19,12 +19,17 @@ type TreeEntry struct { gogitTreeEntry *object.TreeEntry ptree *Tree + fullName string + size int64 sized bool } // Name returns the name of the entry func (te *TreeEntry) Name() string { + if te.fullName != "" { + return te.fullName + } return te.gogitTreeEntry.Name } diff --git a/modules/git/tree_gogit.go b/modules/git/tree_gogit.go index 272b018ffdd18..421b0ecb0f0f9 100644 --- a/modules/git/tree_gogit.go +++ b/modules/git/tree_gogit.go @@ -69,7 +69,7 @@ func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) { seen := map[plumbing.Hash]bool{} walker := object.NewTreeWalker(t.gogitTree, true, seen) for { - _, entry, err := walker.Next() + fullName, entry, err := walker.Next() if err == io.EOF { break } @@ -84,6 +84,7 @@ func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) { ID: ParseGogitHash(entry.Hash), gogitTreeEntry: &entry, ptree: t, + fullName: fullName, } entries = append(entries, convertedEntry) } From 24189dcced2e79a9d360360d4ab60bd02421ceeb Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 6 Nov 2025 01:29:06 +0800 Subject: [PATCH 54/88] Fix pull description code label background (#35865) (#35870) Backport #35865 by @silverwind Fix visual regression from https://github.com/go-gitea/gitea/pull/35567: Before: image After: image Co-authored-by: silverwind --- web_src/css/repo.css | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 070623d24e899..206a591fbdaf1 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -387,6 +387,7 @@ td .commit-summary { .repository.view.issue .pull-desc code { color: var(--color-primary); + background: transparent; } .repository.view.issue .pull-desc a[data-clipboard-text] { From 154d7521a5ae18f739bb35125cab02a87ace4ec1 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 6 Nov 2025 13:08:06 +0800 Subject: [PATCH 55/88] fix(api/repo/contents): set the dates to now when not specified by the caller (#35861) (#35874) Backport #35861 by @divyun Since 1.25.0, the dates get set to `2001-01-01T00:00:00Z`, when not specified by the caller. Fixes #35860 Co-authored-by: Divyun Raje Vaid --- routers/api/v1/repo/file.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index cd787b9da33e1..21ed72b732688 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -369,11 +369,11 @@ func ReqChangeRepoFileOptionsAndCheck(ctx *context.APIContext) { }, Signoff: commonOpts.Signoff, } - if commonOpts.Dates.Author.IsZero() { - commonOpts.Dates.Author = time.Now() + if changeFileOpts.Dates.Author.IsZero() { + changeFileOpts.Dates.Author = time.Now() } - if commonOpts.Dates.Committer.IsZero() { - commonOpts.Dates.Committer = time.Now() + if changeFileOpts.Dates.Committer.IsZero() { + changeFileOpts.Dates.Committer = time.Now() } ctx.Data["__APIChangeRepoFilesOptions"] = changeFileOpts } From 289bd9694b3d1be20233c6f473f0080c67da242b Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 6 Nov 2025 14:06:36 +0800 Subject: [PATCH 56/88] Remove padding override on `.ui .sha.label` (#35864) (#35873) Backport #35864 by @silverwind Since upgrading to v1.25, I noticed the SHA labels have slightly different padding than before. I can't pinpoint exactly which change it was. Fix it by removing the padding override on `.ui .sha.label` and make the one on`.ui.label` (`2px 6px`) take effect which matches 1.24 rendering. Before: image After: image Co-authored-by: silverwind --- web_src/css/base.css | 1 - 1 file changed, 1 deletion(-) diff --git a/web_src/css/base.css b/web_src/css/base.css index 8b77e55fa3cd4..3c8dd1a435458 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -626,7 +626,6 @@ img.ui.avatar, font-family: var(--fonts-monospace); font-size: 13px; font-weight: var(--font-weight-normal); - padding: 3px 5px; flex-shrink: 0; } From 5842cd23a601b5568f4dd985d5ba375eb4ca41c3 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 6 Nov 2025 16:51:49 +0800 Subject: [PATCH 57/88] Contribution heatmap improvements (#35876) (#35880) Backport #35876 by @silverwind 1. Set a fixed height on the element, preventing the content after the element from shifting on page load. This uses CSS [container query length units](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_containment/Container_queries#container_query_length_units) as I saw no other way because of the non-linear scaling of the element. 2. Move the "total-contributions" text into the existing vue slot, eliminating the need for absolute positioning. Co-authored-by: silverwind Co-authored-by: wxiaoguang --- templates/user/heatmap.tmpl | 4 +- web_src/css/features/heatmap.css | 57 +++++++++++------------ web_src/js/components/ActivityHeatmap.vue | 7 ++- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/templates/user/heatmap.tmpl b/templates/user/heatmap.tmpl index b604b929a3bd2..6186edd4dd519 100644 --- a/templates/user/heatmap.tmpl +++ b/templates/user/heatmap.tmpl @@ -1,4 +1,5 @@ {{if .HeatmapData}} +
-
+
+
{{end}} diff --git a/web_src/css/features/heatmap.css b/web_src/css/features/heatmap.css index c064590c4669b..e40adf1fe48fc 100644 --- a/web_src/css/features/heatmap.css +++ b/web_src/css/features/heatmap.css @@ -4,23 +4,44 @@ position: relative; } -/* before the Vue component is mounted, show a loading indicator with dummy size */ -/* the ratio is guesswork, see https://github.com/razorness/vue3-calendar-heatmap/issues/26 */ -#user-heatmap.is-loading { - aspect-ratio: 5.415; /* the size is about 790 x 145 */ +.activity-heatmap-container { + container-type: inline-size; } -.user.profile #user-heatmap.is-loading { - aspect-ratio: 5.645; /* the size is about 953 x 169 */ + +@container (width > 0) { + #user-heatmap { + /* Set element to fixed height so that it does not resize after load. The calculation is complex + because the element does not scale with a fixed aspect ratio. */ + height: calc((100cqw / 5) - (100cqw / 25) + 20px); + } +} + +/* Fallback height adjustment above for browsers that don't support container queries */ +@supports not (container-type: inline-size) { + /* Before the Vue component is mounted, show a loading indicator with dummy size */ + /* The ratio is guesswork for legacy browsers, new browsers use the "@container" approach above */ + #user-heatmap.is-loading { + aspect-ratio: 5.4823972051; /* the size is about 816 x 148.84 */ + } + .user.profile #user-heatmap.is-loading { + aspect-ratio: 5.6290608387; /* the size is about 953 x 169.3 */ + } } #user-heatmap text { fill: currentcolor !important; } +/* root legend */ +#user-heatmap .vch__container > .vch__legend { + display: flex; + font-size: 11px; + justify-content: space-between; +} + /* for the "Less" and "More" legend */ #user-heatmap .vch__legend .vch__legend { display: flex; - font-size: 11px; align-items: center; justify-content: right; } @@ -34,25 +55,3 @@ #user-heatmap .vch__day__square:hover { outline: 1.5px solid var(--color-text); } - -/* move the "? contributions in the last ? months" text from top to bottom */ -#user-heatmap .total-contributions { - font-size: 11px; - position: absolute; - bottom: 0; - left: 25px; -} - -@media (max-width: 1200px) { - #user-heatmap .total-contributions { - left: 21px; - } -} - -@media (max-width: 1000px) { - #user-heatmap .total-contributions { - font-size: 10px; - left: 17px; - bottom: -4px; - } -} diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index 296cb61cff516..d805817630ca4 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -53,9 +53,6 @@ function handleDayClick(e: Event & {date: Date}) { } From e5b404ec5384679d164b56da3d727eae1032acae Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 7 Nov 2025 11:25:34 +0800 Subject: [PATCH 58/88] Fix avatar upload error handling (#35887) (#35890) Backport #35887 --- services/auth/source/ldap/source_authenticate.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index 6005a4744ae2f..4463bcc05446c 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -105,9 +105,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u } } if source.AttributeAvatar != "" { - if err := user_service.UploadAvatar(ctx, user, sr.Avatar); err != nil { - return user, err - } + _ = user_service.UploadAvatar(ctx, user, sr.Avatar) } } From 70ee6b90295b41ca25ff2cbf3a1696f4eb0c0c68 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sun, 9 Nov 2025 00:37:00 +0800 Subject: [PATCH 59/88] Fix conda null depend issue (#35900) (#35902) Backport #35900 by Luohaothu This fixes issue #35895 Co-authored-by: Luohao Wang --- routers/api/packages/conda/conda.go | 2 +- tests/integration/api_packages_conda_test.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go index f496002bb5a5e..8519ae3e082d9 100644 --- a/routers/api/packages/conda/conda.go +++ b/routers/api/packages/conda/conda.go @@ -148,7 +148,7 @@ func EnumeratePackages(ctx *context.Context) { Timestamp: fileMetadata.Timestamp, Build: fileMetadata.Build, BuildNumber: fileMetadata.BuildNumber, - Dependencies: fileMetadata.Dependencies, + Dependencies: util.SliceNilAsEmpty(fileMetadata.Dependencies), License: versionMetadata.License, LicenseFamily: versionMetadata.LicenseFamily, HashMD5: pfd.Blob.HashMD5, diff --git a/tests/integration/api_packages_conda_test.go b/tests/integration/api_packages_conda_test.go index b69a8c906686b..8dbcba5b54d1f 100644 --- a/tests/integration/api_packages_conda_test.go +++ b/tests/integration/api_packages_conda_test.go @@ -237,6 +237,8 @@ func TestPackageConda(t *testing.T) { assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5) assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256) assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size) + assert.NotNil(t, packageInfo.Dependencies) + assert.Empty(t, packageInfo.Dependencies) }) t.Run(".conda", func(t *testing.T) { @@ -268,6 +270,8 @@ func TestPackageConda(t *testing.T) { assert.Equal(t, pd.Files[0].Blob.HashMD5, packageInfo.HashMD5) assert.Equal(t, pd.Files[0].Blob.HashSHA256, packageInfo.HashSHA256) assert.Equal(t, pd.Files[0].Blob.Size, packageInfo.Size) + assert.NotNil(t, packageInfo.Dependencies) + assert.Empty(t, packageInfo.Dependencies) }) }) } From 1ca4fef611c0ef871cf1207a512e82c1ac4358a2 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sun, 9 Nov 2025 11:44:53 +0800 Subject: [PATCH 60/88] Fix team member access check (#35899) (#35905) Backport #35899 by wxiaoguang Fix #35499 Co-authored-by: wxiaoguang --- models/git/protected_branch.go | 8 ++- models/organization/team_repo.go | 37 ++++++++--- models/perm/access/repo_permission.go | 65 +++++++++----------- models/perm/access/repo_permission_test.go | 16 ++++- routers/web/repo/setting/protected_branch.go | 5 +- routers/web/repo/setting/protected_tag.go | 4 +- services/convert/convert.go | 4 +- 7 files changed, 83 insertions(+), 56 deletions(-) diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index 13e1ced0e1849..1085c14cae663 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -466,11 +466,13 @@ func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, c return currentWhitelist, nil } + prUserIDs, err := access_model.GetUserIDsWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests) + if err != nil { + return nil, err + } whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - if reader, err := access_model.IsRepoReader(ctx, repo, userID); err != nil { - return nil, err - } else if !reader { + if !prUserIDs.Contains(userID) { continue } whitelist = append(whitelist, userID) diff --git a/models/organization/team_repo.go b/models/organization/team_repo.go index b3e266dbc7651..2652b34c6f7d8 100644 --- a/models/organization/team_repo.go +++ b/models/organization/team_repo.go @@ -53,24 +53,45 @@ func RemoveTeamRepo(ctx context.Context, teamID, repoID int64) error { // GetTeamsWithAccessToAnyRepoUnit returns all teams in an organization that have given access level to the repository special unit. // This function is only used for finding some teams that can be used as branch protection allowlist or reviewers, it isn't really used for access control. // FIXME: TEAM-UNIT-PERMISSION this logic is not complete, search the fixme keyword to see more details -func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) ([]*Team, error) { - teams := make([]*Team, 0, 5) +func GetTeamsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teams []*Team, err error) { + teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...) + if err != nil { + return nil, err + } + if len(teamIDs) == 0 { + return teams, nil + } + err = db.GetEngine(ctx).Where(builder.In("id", teamIDs)).OrderBy("team.name").Find(&teams) + return teams, err +} +func getTeamIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (teamIDs []int64, err error) { sub := builder.Select("team_id").From("team_unit"). Where(builder.Expr("team_unit.team_id = team.id")). And(builder.In("team_unit.type", append([]unit.Type{unitType}, unitTypesMore...))). And(builder.Expr("team_unit.access_mode >= ?", mode)) - err := db.GetEngine(ctx). + err = db.GetEngine(ctx). + Select("team.id"). + Table("team"). Join("INNER", "team_repo", "team_repo.team_id = team.id"). - And("team_repo.org_id = ?", orgID). - And("team_repo.repo_id = ?", repoID). + And("team_repo.org_id = ? AND team_repo.repo_id = ?", orgID, repoID). And(builder.Or( builder.Expr("team.authorize >= ?", mode), builder.In("team.id", sub), )). - OrderBy("name"). - Find(&teams) + Find(&teamIDs) + return teamIDs, err +} - return teams, err +func GetTeamUserIDsWithAccessToAnyRepoUnit(ctx context.Context, orgID, repoID int64, mode perm.AccessMode, unitType unit.Type, unitTypesMore ...unit.Type) (userIDs []int64, err error) { + teamIDs, err := getTeamIDsWithAccessToAnyRepoUnit(ctx, orgID, repoID, mode, unitType, unitTypesMore...) + if err != nil { + return nil, err + } + if len(teamIDs) == 0 { + return userIDs, nil + } + err = db.GetEngine(ctx).Table("team_user").Select("uid").Where(builder.In("team_id", teamIDs)).Find(&userIDs) + return userIDs, err } diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 678b18442ee57..b663a6c05b940 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -14,6 +14,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -458,54 +459,44 @@ func HasAnyUnitAccess(ctx context.Context, userID int64, repo *repo_model.Reposi return perm.HasAnyUnitAccess(), nil } -// getUsersWithAccessMode returns users that have at least given access mode to the repository. -func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode) (_ []*user_model.User, err error) { - if err = repo.LoadOwner(ctx); err != nil { +func GetUsersWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (users []*user_model.User, err error) { + userIDs, err := GetUserIDsWithUnitAccess(ctx, repo, mode, unitType) + if err != nil { return nil, err } + if len(userIDs) == 0 { + return users, nil + } + if err = db.GetEngine(ctx).In("id", userIDs.Values()).OrderBy("`name`").Find(&users); err != nil { + return nil, err + } + return users, nil +} +func GetUserIDsWithUnitAccess(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode, unitType unit.Type) (container.Set[int64], error) { + userIDs := container.Set[int64]{} e := db.GetEngine(ctx) accesses := make([]*Access, 0, 10) - if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil { + if err := e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil { return nil, err } + for _, a := range accesses { + userIDs.Add(a.UserID) + } - // Leave a seat for owner itself to append later, but if owner is an organization - // and just waste 1 unit is cheaper than re-allocate memory once. - users := make([]*user_model.User, 0, len(accesses)+1) - if len(accesses) > 0 { - userIDs := make([]int64, len(accesses)) - for i := 0; i < len(accesses); i++ { - userIDs[i] = accesses[i].UserID - } - - if err = e.In("id", userIDs).Find(&users); err != nil { - return nil, err - } + if err := repo.LoadOwner(ctx); err != nil { + return nil, err } if !repo.Owner.IsOrganization() { - users = append(users, repo.Owner) - } - - return users, nil -} - -// GetRepoReaders returns all users that have explicit read access or higher to the repository. -func GetRepoReaders(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeRead) -} - -// GetRepoWriters returns all users that have write access to the repository. -func GetRepoWriters(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeWrite) -} - -// IsRepoReader returns true if user has explicit read access or higher to the repository. -func IsRepoReader(ctx context.Context, repo *repo_model.Repository, userID int64) (bool, error) { - if repo.OwnerID == userID { - return true, nil + userIDs.Add(repo.Owner.ID) + } else { + teamUserIDs, err := organization.GetTeamUserIDsWithAccessToAnyRepoUnit(ctx, repo.OwnerID, repo.ID, mode, unitType) + if err != nil { + return nil, err + } + userIDs.AddMultiple(teamUserIDs...) } - return db.GetEngine(ctx).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{}) + return userIDs, nil } // CheckRepoUnitUser check whether user could visit the unit of this repository diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go index d81dfba288e2c..a36be213ece1a 100644 --- a/models/perm/access/repo_permission_test.go +++ b/models/perm/access/repo_permission_test.go @@ -169,9 +169,9 @@ func TestGetUserRepoPermission(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) team := &organization.Team{OrgID: org.ID, LowerName: "test_team"} require.NoError(t, db.Insert(ctx, team)) + require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID})) t.Run("DoerInTeamWithNoRepo", func(t *testing.T) { - require.NoError(t, db.Insert(ctx, &organization.TeamUser{OrgID: org.ID, TeamID: team.ID, UID: user.ID})) perm, err := GetUserRepoPermission(ctx, repo32, user) require.NoError(t, err) assert.Equal(t, perm_model.AccessModeRead, perm.AccessMode) @@ -219,6 +219,15 @@ func TestGetUserRepoPermission(t *testing.T) { assert.Equal(t, perm_model.AccessModeNone, perm.AccessMode) assert.Equal(t, perm_model.AccessModeNone, perm.unitsMode[unit.TypeCode]) assert.Equal(t, perm_model.AccessModeRead, perm.unitsMode[unit.TypeIssues]) + + users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeRead, unit.TypeIssues) + require.NoError(t, err) + require.Len(t, users, 1) + assert.Equal(t, user.ID, users[0].ID) + + users, err = GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues) + require.NoError(t, err) + require.Empty(t, users) }) require.NoError(t, db.Insert(ctx, repo_model.Collaboration{RepoID: repo3.ID, UserID: user.ID, Mode: perm_model.AccessModeWrite})) @@ -229,5 +238,10 @@ func TestGetUserRepoPermission(t *testing.T) { assert.Equal(t, perm_model.AccessModeWrite, perm.AccessMode) assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeCode]) assert.Equal(t, perm_model.AccessModeWrite, perm.unitsMode[unit.TypeIssues]) + + users, err := GetUsersWithUnitAccess(ctx, repo3, perm_model.AccessModeWrite, unit.TypeIssues) + require.NoError(t, err) + require.Len(t, users, 1) + assert.Equal(t, user.ID, users[0].ID) }) } diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index 152f67550cc6c..f2b2019ebd39f 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -73,10 +73,9 @@ func SettingsProtectedBranch(c *context.Context) { c.Data["PageIsSettingsBranches"] = true c.Data["Title"] = c.Locale.TrString("repo.settings.protected_branch") + " - " + rule.RuleName - - users, err := access_model.GetRepoReaders(c, c.Repo.Repository) + users, err := access_model.GetUsersWithUnitAccess(c, c.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests) if err != nil { - c.ServerError("Repo.Repository.GetReaders", err) + c.ServerError("GetUsersWithUnitAccess", err) return } c.Data["Users"] = users diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index 50f5a28c4c7f2..4b560e6f22451 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -149,9 +149,9 @@ func setTagsContext(ctx *context.Context) error { } ctx.Data["ProtectedTags"] = protectedTags - users, err := access_model.GetRepoReaders(ctx, ctx.Repo.Repository) + users, err := access_model.GetUsersWithUnitAccess(ctx, ctx.Repo.Repository, perm.AccessModeRead, unit.TypePullRequests) if err != nil { - ctx.ServerError("Repo.Repository.GetReaders", err) + ctx.ServerError("GetUsersWithUnitAccess", err) return err } ctx.Data["Users"] = users diff --git a/services/convert/convert.go b/services/convert/convert.go index 0de38221409bb..633edfed4b32e 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -139,7 +139,7 @@ func getWhitelistEntities[T *user_model.User | *organization.Team](entities []T, // ToBranchProtection convert a ProtectedBranch to api.BranchProtection func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo *repo_model.Repository) *api.BranchProtection { - readers, err := access_model.GetRepoReaders(ctx, repo) + readers, err := access_model.GetUsersWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests) if err != nil { log.Error("GetRepoReaders: %v", err) } @@ -720,7 +720,7 @@ func ToAnnotatedTagObject(repo *repo_model.Repository, commit *git.Commit) *api. // ToTagProtection convert a git.ProtectedTag to an api.TagProtection func ToTagProtection(ctx context.Context, pt *git_model.ProtectedTag, repo *repo_model.Repository) *api.TagProtection { - readers, err := access_model.GetRepoReaders(ctx, repo) + readers, err := access_model.GetUsersWithUnitAccess(ctx, repo, perm.AccessModeRead, unit.TypePullRequests) if err != nil { log.Error("GetRepoReaders: %v", err) } From 2b71bf283bdd73ddfd4aa1938d161cdf4cebd17a Mon Sep 17 00:00:00 2001 From: Giteabot Date: Sun, 9 Nov 2025 14:51:36 +0800 Subject: [PATCH 61/88] Display source code downloads last for release attachments (#35897) (#35903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backport #35897 by lutinglt Typically, you want to download the binaries, not the source code. Co-authored-by: 鲁汀 <131967983+lutinglt@users.noreply.github.com> Co-authored-by: Lunny Xiao --- templates/repo/release/list.tmpl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 882ffe40b7e1b..b7a60a44edcf9 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -78,18 +78,6 @@ {{ctx.Locale.Tr "repo.release.downloads"}}
{{end}} + {{if and (not $.DisableDownloadSourceArchives) (not $release.IsDraft) ($.Permission.CanRead ctx.Consts.RepoUnitTypeCode)}} +
  • + + {{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (ZIP) + +
  • +
  • + + {{svg "octicon-file-zip" 16 "download-icon"}}{{ctx.Locale.Tr "repo.release.source_code"}} (TAR.GZ) + +
  • + {{end}}
    From db876d8f178e295e0afa10a4a940ec2ecea5c06b Mon Sep 17 00:00:00 2001 From: Giteabot Date: Mon, 10 Nov 2025 15:42:14 +0800 Subject: [PATCH 62/88] Fix #35763: Add proper page title for project pages (#35773) (#35909) Backport #35773 by @mithileshgupta12 Co-authored-by: Mithilesh Gupta Co-authored-by: Mithilesh Gupta --- routers/web/org/projects.go | 1 + 1 file changed, 1 insertion(+) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 059cce8281323..d524409c4148a 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -436,6 +436,7 @@ func ViewProject(ctx *context.Context) { ctx.Data["Project"] = project ctx.Data["IssuesMap"] = issuesMap ctx.Data["Columns"] = columns + ctx.Data["Title"] = fmt.Sprintf("%s - %s", project.Title, ctx.ContextUser.DisplayName()) if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil { ctx.ServerError("RenderUserOrgHeader", err) From 327f2207dce46c96d01e3109564ef61d2c87f008 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 11 Nov 2025 00:12:25 +0800 Subject: [PATCH 63/88] Make OAuth2 issuer configurable (#35915) (#35916) Backport #35915 by wxiaoguang --- custom/conf/app.example.ini | 5 ++++ modules/setting/oauth2.go | 1 + services/oauth2_provider/access_token.go | 6 +++- tests/integration/oauth_test.go | 36 ++++++++++++++++-------- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5fee78af54df8..33bfe752a0f12 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -567,6 +567,11 @@ ENABLED = true ;; Alternative location to specify OAuth2 authentication secret. You cannot specify both this and JWT_SECRET, and must pick one ;JWT_SECRET_URI = file:/etc/gitea/oauth2_jwt_secret ;; +;; The "issuer" claim identifies the principal that issued the JWT. +;; Gitea 1.25 makes it default to "ROOT_URL without the last slash" to follow the standard. +;; If you have old logins from before 1.25, you may want to set it to the old (non-standard) value "ROOT_URL with the last slash". +;JWT_CLAIM_ISSUER = +;; ;; Lifetime of an OAuth2 access token in seconds ;ACCESS_TOKEN_EXPIRATION_TIME = 3600 ;; diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 1a88f3cb0825c..ae2a9d7bee71c 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -96,6 +96,7 @@ var OAuth2 = struct { InvalidateRefreshTokens bool JWTSigningAlgorithm string `ini:"JWT_SIGNING_ALGORITHM"` JWTSigningPrivateKeyFile string `ini:"JWT_SIGNING_PRIVATE_KEY_FILE"` + JWTClaimIssuer string `ini:"JWT_CLAIM_ISSUER"` MaxTokenLength int DefaultApplications []string }{ diff --git a/services/oauth2_provider/access_token.go b/services/oauth2_provider/access_token.go index dce4ac765b7a6..3a77c86d9e56d 100644 --- a/services/oauth2_provider/access_token.go +++ b/services/oauth2_provider/access_token.go @@ -112,8 +112,12 @@ func NewJwtRegisteredClaimsFromUser(clientID string, grantUserID int64, exp *jwt // to retrieve the configuration information. This MUST also be identical to the "iss" Claim value in ID Tokens issued from this Issuer. // * https://accounts.google.com/.well-known/openid-configuration // * https://github.com/login/oauth/.well-known/openid-configuration + issuer := setting.OAuth2.JWTClaimIssuer + if issuer == "" { + issuer = strings.TrimSuffix(setting.AppURL, "/") + } return jwt.RegisteredClaims{ - Issuer: strings.TrimSuffix(setting.AppURL, "/"), + Issuer: issuer, Audience: []string{clientID}, Subject: strconv.FormatInt(grantUserID, 10), ExpiresAt: exp, diff --git a/tests/integration/oauth_test.go b/tests/integration/oauth_test.go index eab95ba688fed..e7edace6536cd 100644 --- a/tests/integration/oauth_test.go +++ b/tests/integration/oauth_test.go @@ -919,20 +919,32 @@ func TestOAuth_GrantScopesClaimAllGroups(t *testing.T) { } func testOAuth2WellKnown(t *testing.T) { + defer test.MockVariableValue(&setting.AppURL, "https://try.gitea.io/")() urlOpenidConfiguration := "/.well-known/openid-configuration" - defer test.MockVariableValue(&setting.AppURL, "https://try.gitea.io/")() - req := NewRequest(t, "GET", urlOpenidConfiguration) - resp := MakeRequest(t, req, http.StatusOK) - var respMap map[string]any - DecodeJSON(t, resp, &respMap) - assert.Equal(t, "https://try.gitea.io", respMap["issuer"]) - assert.Equal(t, "https://try.gitea.io/login/oauth/authorize", respMap["authorization_endpoint"]) - assert.Equal(t, "https://try.gitea.io/login/oauth/access_token", respMap["token_endpoint"]) - assert.Equal(t, "https://try.gitea.io/login/oauth/keys", respMap["jwks_uri"]) - assert.Equal(t, "https://try.gitea.io/login/oauth/userinfo", respMap["userinfo_endpoint"]) - assert.Equal(t, "https://try.gitea.io/login/oauth/introspect", respMap["introspection_endpoint"]) - assert.Equal(t, []any{"RS256"}, respMap["id_token_signing_alg_values_supported"]) + t.Run("WellKnown", func(t *testing.T) { + req := NewRequest(t, "GET", urlOpenidConfiguration) + resp := MakeRequest(t, req, http.StatusOK) + var respMap map[string]any + DecodeJSON(t, resp, &respMap) + assert.Equal(t, "https://try.gitea.io", respMap["issuer"]) + assert.Equal(t, "https://try.gitea.io/login/oauth/authorize", respMap["authorization_endpoint"]) + assert.Equal(t, "https://try.gitea.io/login/oauth/access_token", respMap["token_endpoint"]) + assert.Equal(t, "https://try.gitea.io/login/oauth/keys", respMap["jwks_uri"]) + assert.Equal(t, "https://try.gitea.io/login/oauth/userinfo", respMap["userinfo_endpoint"]) + assert.Equal(t, "https://try.gitea.io/login/oauth/introspect", respMap["introspection_endpoint"]) + assert.Equal(t, []any{"RS256"}, respMap["id_token_signing_alg_values_supported"]) + }) + + t.Run("WellKnownWithIssuer", func(t *testing.T) { + defer test.MockVariableValue(&setting.OAuth2.JWTClaimIssuer, "https://try.gitea.io/")() + req := NewRequest(t, "GET", urlOpenidConfiguration) + resp := MakeRequest(t, req, http.StatusOK) + var respMap map[string]any + DecodeJSON(t, resp, &respMap) + assert.Equal(t, "https://try.gitea.io/", respMap["issuer"]) // has trailing by JWTClaimIssuer + assert.Equal(t, "https://try.gitea.io/login/oauth/authorize", respMap["authorization_endpoint"]) + }) defer test.MockVariableValue(&setting.OAuth2.Enabled, false)() MakeRequest(t, NewRequest(t, "GET", urlOpenidConfiguration), http.StatusNotFound) From ce70863793e10e610ec85c9442f6f237000833f1 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 11 Nov 2025 09:39:35 +0800 Subject: [PATCH 64/88] Use correct form field for allowed force push users in branch protection API (#35894) (#35908) Backport #35894 by zorrobiwan Signed-off-by: Alberty Pascal Co-authored-by: Alberty Pascal --- routers/api/v1/repo/branch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 65fac45aa11f2..ea2b47c95c48f 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -897,7 +897,7 @@ func EditBranchProtection(ctx *context.APIContext) { } else { whitelistUsers = protectBranch.WhitelistUserIDs } - if form.ForcePushAllowlistDeployKeys != nil { + if form.ForcePushAllowlistUsernames != nil { forcePushAllowlistUsers, err = user_model.GetUserIDsByNames(ctx, form.ForcePushAllowlistUsernames, false) if err != nil { if user_model.IsErrUserNotExist(err) { From 01873a99c156059d326dd689939f0dbc41cf34e1 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Tue, 11 Nov 2025 10:24:06 +0800 Subject: [PATCH 65/88] Allow to display embed images/pdfs when SERVE_DIRECT was enabled on MinIO storage (#35882) (#35917) Backport #35882 by lifegpc Co-authored-by: lifegpc Co-authored-by: wxiaoguang --- modules/storage/azureblob.go | 1 + modules/storage/minio.go | 34 +++++++++++++++++++++++++++++----- routers/web/repo/view.go | 1 + 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/modules/storage/azureblob.go b/modules/storage/azureblob.go index 6860d81131b65..e7297cec77a0f 100644 --- a/modules/storage/azureblob.go +++ b/modules/storage/azureblob.go @@ -250,6 +250,7 @@ func (a *AzureBlobStorage) Delete(path string) error { func (a *AzureBlobStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL, error) { blobClient := a.getBlobClient(path) + // TODO: OBJECT-STORAGE-CONTENT-TYPE: "browser inline rendering images/PDF" needs proper Content-Type header from storage startTime := time.Now() u, err := blobClient.GetSASURL(sas.BlobPermissions{ Read: true, diff --git a/modules/storage/minio.go b/modules/storage/minio.go index 01f2c16267971..6993ac2d922b1 100644 --- a/modules/storage/minio.go +++ b/modules/storage/minio.go @@ -279,20 +279,44 @@ func (m *MinioStorage) Delete(path string) error { } // URL gets the redirect URL to a file. The presigned link is valid for 5 minutes. -func (m *MinioStorage) URL(path, name, method string, serveDirectReqParams url.Values) (*url.URL, error) { +func (m *MinioStorage) URL(storePath, name, method string, serveDirectReqParams url.Values) (*url.URL, error) { // copy serveDirectReqParams reqParams, err := url.ParseQuery(serveDirectReqParams.Encode()) if err != nil { return nil, err } - // TODO it may be good to embed images with 'inline' like ServeData does, but we don't want to have to read the file, do we? - reqParams.Set("response-content-disposition", "attachment; filename=\""+quoteEscaper.Replace(name)+"\"") + + // Here we might not know the real filename, and it's quite inefficient to detect the mine type by pre-fetching the object head. + // So we just do a quick detection by extension name, at least if works for the "View Raw File" for an LFS file on the Web UI. + // Detect content type by extension name, only support the well-known safe types for inline rendering. + // TODO: OBJECT-STORAGE-CONTENT-TYPE: need a complete solution and refactor for Azure in the future + ext := path.Ext(name) + inlineExtMimeTypes := map[string]string{ + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".webp": "image/webp", + ".avif": "image/avif", + // ATTENTION! Don't support unsafe types like HTML/SVG due to security concerns: they can contain JS code, and maybe they need proper Content-Security-Policy + // HINT: PDF-RENDER-SANDBOX: PDF won't render in sandboxed context, it seems fine to render it inline + ".pdf": "application/pdf", + + // TODO: refactor with "modules/public/mime_types.go", for example: "DetectWellKnownSafeInlineMimeType" + } + if mimeType, ok := inlineExtMimeTypes[ext]; ok { + reqParams.Set("response-content-type", mimeType) + reqParams.Set("response-content-disposition", "inline") + } else { + reqParams.Set("response-content-disposition", fmt.Sprintf(`attachment; filename="%s"`, quoteEscaper.Replace(name))) + } + expires := 5 * time.Minute if method == http.MethodHead { - u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams) + u, err := m.client.PresignedHeadObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams) return u, convertMinioErr(err) } - u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(path), expires, reqParams) + u, err := m.client.PresignedGetObject(m.ctx, m.bucket, m.buildMinioPath(storePath), expires, reqParams) return u, convertMinioErr(err) } diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 1d05a3aa51c19..86db44d41b632 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -95,6 +95,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) (buf []b meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid) if err != nil { // fallback to a plain file + fi.lfsMeta = &pointer log.Warn("Unable to access LFS pointer %s in repo %d: %v", pointer.Oid, repoID, err) return buf, dataRc, fi, nil } From 1d9ae7ac2303c7f5cd32f5c1675ced45e8845dda Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 12 Nov 2025 07:24:21 +0800 Subject: [PATCH 66/88] Load jQuery as early as possible to support custom scripts (#35926) (#35929) Backport #35926 by wxiaoguang Fix #35923 Co-authored-by: wxiaoguang --- web_src/js/index-domready.ts | 1 - web_src/js/index.ts | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web_src/js/index-domready.ts b/web_src/js/index-domready.ts index 8a3a27fa19c86..2ac9889758186 100644 --- a/web_src/js/index-domready.ts +++ b/web_src/js/index-domready.ts @@ -1,4 +1,3 @@ -import './globals.ts'; import '../fomantic/build/fomantic.js'; import '../../node_modules/easymde/dist/easymde.min.css'; // TODO: lazy load in "switchToEasyMDE" diff --git a/web_src/js/index.ts b/web_src/js/index.ts index af53cc488cd12..153b8049c9119 100644 --- a/web_src/js/index.ts +++ b/web_src/js/index.ts @@ -1,5 +1,10 @@ // bootstrap module must be the first one to be imported, it handles webpack lazy-loading and global errors import './bootstrap.ts'; + +// many users expect to use jQuery in their custom scripts (https://docs.gitea.com/administration/customizing-gitea#example-plantuml) +// so load globals (including jQuery) as early as possible +import './globals.ts'; + import './webcomponents/index.ts'; import {onDomReady} from './utils/dom.ts'; From 01fa8b2b7ecf535620e18ea9c5c99a1f5cb61349 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 13 Nov 2025 02:26:27 +0800 Subject: [PATCH 67/88] Limit read bytes instead of ReadAll (#35928) (#35934) Backport #35928 by wxiaoguang Co-authored-by: wxiaoguang --- modules/actions/workflows.go | 4 +-- modules/issue/template/unmarshal.go | 3 +- modules/packages/nuget/metadata.go | 2 +- modules/packages/pub/metadata.go | 2 +- modules/util/io.go | 2 +- routers/web/repo/wiki.go | 2 +- services/issue/template.go | 4 +-- services/repository/generate.go | 46 ++++++++++++++++------------ services/repository/generate_test.go | 26 ++++++++++++++++ services/webhook/deliver.go | 3 +- 10 files changed, 64 insertions(+), 30 deletions(-) diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go index 69f71bf6519df..26a6ebc37009c 100644 --- a/modules/actions/workflows.go +++ b/modules/actions/workflows.go @@ -5,7 +5,6 @@ package actions import ( "bytes" - "io" "slices" "strings" @@ -13,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/glob" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/nektos/act/pkg/jobparser" @@ -77,7 +77,7 @@ func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) { if err != nil { return nil, err } - content, err := io.ReadAll(f) + content, err := util.ReadWithLimit(f, 1024*1024) _ = f.Close() if err != nil { return nil, err diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index 1d8e9dd02d995..ceab6babf4c44 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -5,7 +5,6 @@ package template import ( "fmt" - "io" "path" "strconv" @@ -76,7 +75,7 @@ func unmarshalFromEntry(entry *git.TreeEntry, filename string) (*api.IssueTempla } defer r.Close() - content, err := io.ReadAll(r) + content, err := util.ReadWithLimit(r, 1024*1024) if err != nil { return nil, fmt.Errorf("read all: %w", err) } diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 513b4dd2b91e1..51246273957e5 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -216,7 +216,7 @@ func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) { if p.Metadata.Readme != "" { f, err := archive.Open(p.Metadata.Readme) if err == nil { - buf, _ := io.ReadAll(f) + buf, _ := util.ReadWithLimit(f, 1024*1024) m.Readme = string(buf) _ = f.Close() } diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go index 9b00472eb2785..a2cf6b728ab9f 100644 --- a/modules/packages/pub/metadata.go +++ b/modules/packages/pub/metadata.go @@ -89,7 +89,7 @@ func ParsePackage(r io.Reader) (*Package, error) { return nil, err } } else if strings.EqualFold(hd.Name, "readme.md") { - data, err := io.ReadAll(tr) + data, err := util.ReadWithLimit(tr, 1024*1024) if err != nil { return nil, err } diff --git a/modules/util/io.go b/modules/util/io.go index b3dde9d1f69d4..f5a3d320e54d2 100644 --- a/modules/util/io.go +++ b/modules/util/io.go @@ -29,7 +29,7 @@ func ReadAtMost(r io.Reader, buf []byte) (n int, err error) { // ReadWithLimit reads at most "limit" bytes from r into buf. // If EOF or ErrUnexpectedEOF occurs while reading, err will be nil. func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) { - return readWithLimit(r, 1024, n) + return readWithLimit(r, 4*1024, n) } func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) { diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 289db11a4f830..31e6325217b8a 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -133,7 +133,7 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte { return nil } defer reader.Close() - content, err := io.ReadAll(reader) + content, err := util.ReadWithLimit(reader, 5*1024*1024) // 5MB should be enough for a wiki page if err != nil { ctx.ServerError("ReadAll", err) return nil diff --git a/services/issue/template.go b/services/issue/template.go index 4b0f1aa987047..99977c67cf88b 100644 --- a/services/issue/template.go +++ b/services/issue/template.go @@ -5,7 +5,6 @@ package issue import ( "fmt" - "io" "net/url" "path" "strings" @@ -15,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/issue/template" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "gopkg.in/yaml.v3" ) @@ -65,7 +65,7 @@ func GetTemplateConfig(gitRepo *git.Repository, path string, commit *git.Commit) defer reader.Close() - configContent, err := io.ReadAll(reader) + configContent, err := util.ReadWithLimit(reader, 1024*1024) if err != nil { return GetDefaultTemplateConfig(), err } diff --git a/services/repository/generate.go b/services/repository/generate.go index 5fc29939c5ffa..8da6be01f6f3b 100644 --- a/services/repository/generate.go +++ b/services/repository/generate.go @@ -7,7 +7,9 @@ import ( "bufio" "bytes" "context" + "errors" "fmt" + "io/fs" "os" "path/filepath" "regexp" @@ -138,31 +140,37 @@ func (gt *giteaTemplateFileMatcher) Match(s string) bool { return false } -func readGiteaTemplateFile(tmpDir string) (*giteaTemplateFileMatcher, error) { - localPath := filepath.Join(tmpDir, ".gitea", "template") - if _, err := os.Stat(localPath); os.IsNotExist(err) { - return nil, nil - } else if err != nil { +func readLocalTmpRepoFileContent(localPath string, limit int) ([]byte, error) { + ok, err := util.IsRegularFile(localPath) + if err != nil { return nil, err + } else if !ok { + return nil, fs.ErrNotExist } - content, err := os.ReadFile(localPath) + f, err := os.Open(localPath) if err != nil { return nil, err } + defer f.Close() + + return util.ReadWithLimit(f, limit) +} +func readGiteaTemplateFile(tmpDir string) (*giteaTemplateFileMatcher, error) { + localPath := filepath.Join(tmpDir, ".gitea", "template") + content, err := readLocalTmpRepoFileContent(localPath, 1024*1024) + if err != nil { + return nil, err + } return newGiteaTemplateFileMatcher(localPath, content), nil } func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, templateRepo, generateRepo *repo_model.Repository) error { tmpFullPath := filepath.Join(tmpDir, tmpDirSubPath) - if ok, err := util.IsRegularFile(tmpFullPath); !ok { - return err - } - - content, err := os.ReadFile(tmpFullPath) + content, err := readLocalTmpRepoFileContent(tmpFullPath, 1024*1024) if err != nil { - return err + return util.Iif(errors.Is(err, fs.ErrNotExist), nil, err) } if err := util.Remove(tmpFullPath); err != nil { return err @@ -172,7 +180,7 @@ func substGiteaTemplateFile(ctx context.Context, tmpDir, tmpDirSubPath string, t substSubPath := filepath.Clean(filePathSanitize(generateExpansion(ctx, tmpDirSubPath, templateRepo, generateRepo))) newLocalPath := filepath.Join(tmpDir, substSubPath) regular, err := util.IsRegularFile(newLocalPath) - if canWrite := regular || os.IsNotExist(err); !canWrite { + if canWrite := regular || errors.Is(err, fs.ErrNotExist); !canWrite { return nil } if err := os.MkdirAll(filepath.Dir(newLocalPath), 0o755); err != nil { @@ -242,15 +250,15 @@ func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *r // Variable expansion fileMatcher, err := readGiteaTemplateFile(tmpDir) - if err != nil { - return fmt.Errorf("readGiteaTemplateFile: %w", err) - } - - if fileMatcher != nil { + if err == nil { err = processGiteaTemplateFile(ctx, tmpDir, templateRepo, generateRepo, fileMatcher) if err != nil { - return err + return fmt.Errorf("processGiteaTemplateFile: %w", err) } + } else if errors.Is(err, fs.ErrNotExist) { + log.Debug("skip processing repo template files: no available .gitea/template") + } else { + return fmt.Errorf("readGiteaTemplateFile: %w", err) } if err = git.InitRepository(ctx, tmpDir, false, templateRepo.ObjectFormatName); err != nil { diff --git a/services/repository/generate_test.go b/services/repository/generate_test.go index 19b84c7bde72e..9c01911ded059 100644 --- a/services/repository/generate_test.go +++ b/services/repository/generate_test.go @@ -4,6 +4,7 @@ package repository import ( + "io/fs" "os" "path/filepath" "testing" @@ -175,6 +176,31 @@ func TestProcessGiteaTemplateFile(t *testing.T) { // subst from a link, skip, and the target is unchanged assertSymLink("subst-${TEMPLATE_NAME}-from-link", tmpDir+"/sub/link-target") } + + { + templateFilePath := tmpDir + "/.gitea/template" + + _ = os.Remove(templateFilePath) + _, err := os.Lstat(templateFilePath) + require.ErrorIs(t, err, fs.ErrNotExist) + _, err = readGiteaTemplateFile(tmpDir) // no template file + require.ErrorIs(t, err, fs.ErrNotExist) + + _ = os.WriteFile(templateFilePath+".target", []byte("test-data-target"), 0o644) + _ = os.Symlink(templateFilePath+".target", templateFilePath) + content, _ := os.ReadFile(templateFilePath) + require.Equal(t, "test-data-target", string(content)) + _, err = readGiteaTemplateFile(tmpDir) // symlinked template file + require.ErrorIs(t, err, fs.ErrNotExist) + + _ = os.Remove(templateFilePath) + _ = os.WriteFile(templateFilePath, []byte("test-data-regular"), 0o644) + content, _ = os.ReadFile(templateFilePath) + require.Equal(t, "test-data-regular", string(content)) + fm, err := readGiteaTemplateFile(tmpDir) // regular template file + require.NoError(t, err) + assert.Len(t, fm.globs, 1) + } } func TestTransformers(t *testing.T) { diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go index b6611a3576df5..58fba9f68df00 100644 --- a/services/webhook/deliver.go +++ b/services/webhook/deliver.go @@ -30,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" webhook_module "code.gitea.io/gitea/modules/webhook" ) @@ -264,7 +265,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error { t.ResponseInfo.Headers[k] = strings.Join(vals, ",") } - p, err := io.ReadAll(resp.Body) + p, err := util.ReadWithLimit(resp.Body, 1024*1024) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("read body: %s", err) return fmt.Errorf("unable to deliver webhook task[%d] in %s as unable to read response body: %w", t.ID, w.URL, err) From 15f3e9d5a5ff7e3e6045a77441ee57b018383fa9 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Thu, 13 Nov 2025 07:31:05 +0800 Subject: [PATCH 68/88] Don't show unnecessary error message to end users for DeleteBranchAfterMerge (#35937) (#35941) Backport #35937 by wxiaoguang Co-authored-by: wxiaoguang --- routers/web/repo/pull.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index edccdef8b134c..a9dd95f2d4a62 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1208,7 +1208,11 @@ func MergePullRequest(ctx *context.Context) { func deleteBranchAfterMergeAndFlashMessage(ctx *context.Context, prID int64) { var fullBranchName string err := repo_service.DeleteBranchAfterMerge(ctx, ctx.Doer, prID, &fullBranchName) - if errTr := util.ErrorAsTranslatable(err); errTr != nil { + if errors.Is(err, util.ErrPermissionDenied) || errors.Is(err, util.ErrNotExist) { + // no need to show error to end users if no permission or branch not exist + log.Debug("DeleteBranchAfterMerge (ignore unnecessary error): %v", err) + return + } else if errTr := util.ErrorAsTranslatable(err); errTr != nil { ctx.Flash.Error(errTr.Translate(ctx.Locale)) return } else if err == nil { From d67cd622d0e081a51905d035867ad1b81a30da1c Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 14 Nov 2025 10:15:36 +0800 Subject: [PATCH 69/88] Fix corrupted external render content (#35946) (#35950) Backport #35946 by wxiaoguang Fix #35944 Co-authored-by: wxiaoguang --- go.mod | 14 ++-- go.sum | 32 ++++---- routers/web/repo/view_file.go | 11 +-- .../user30/renderer.git/HEAD | 1 - .../user30/renderer.git/config | 6 -- .../user30/renderer.git/description | 1 - .../user30/renderer.git/hooks/post-receive | 15 ---- .../renderer.git/hooks/post-receive.d/gitea | 2 - .../user30/renderer.git/hooks/pre-receive | 15 ---- .../renderer.git/hooks/pre-receive.d/gitea | 2 - .../user30/renderer.git/hooks/update | 14 ---- .../user30/renderer.git/hooks/update.d/gitea | 2 - .../06/0d5c2acd8bf4b6f14010acd1a73d73392ec46e | Bin 56 -> 0 bytes .../45/14a93050edb2c3165bdd0a3c03be063e879e68 | Bin 50 -> 0 bytes .../c9/61cc4d1ba6b7ee1ba228a9a02b00b7746d8033 | Bin 789 -> 0 bytes .../user30/renderer.git/packed-refs | 2 - .../user30/renderer.git/refs/.keep | 0 tests/integration/markup_external_test.go | 75 +++++++++++++----- tests/sqlite.ini.tmpl | 2 +- 19 files changed, 83 insertions(+), 111 deletions(-) delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/HEAD delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/config delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/description delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive.d/gitea delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive.d/gitea delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/update delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/hooks/update.d/gitea delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/objects/06/0d5c2acd8bf4b6f14010acd1a73d73392ec46e delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/objects/45/14a93050edb2c3165bdd0a3c03be063e879e68 delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/objects/c9/61cc4d1ba6b7ee1ba228a9a02b00b7746d8033 delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/packed-refs delete mode 100644 tests/gitea-repositories-meta/user30/renderer.git/refs/.keep diff --git a/go.mod b/go.mod index e4c0a5a989d3f..d02b8e75e5df5 100644 --- a/go.mod +++ b/go.mod @@ -116,13 +116,13 @@ require ( github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-meta v1.1.0 gitlab.com/gitlab-org/api/client-go v0.142.4 - golang.org/x/crypto v0.42.0 + golang.org/x/crypto v0.44.0 golang.org/x/image v0.30.0 - golang.org/x/net v0.44.0 + golang.org/x/net v0.46.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.17.0 - golang.org/x/sys v0.37.0 - golang.org/x/text v0.30.0 + golang.org/x/sync v0.18.0 + golang.org/x/sys v0.38.0 + golang.org/x/text v0.31.0 google.golang.org/grpc v1.75.0 google.golang.org/protobuf v1.36.8 gopkg.in/ini.v1 v1.67.0 @@ -279,9 +279,9 @@ require ( go.uber.org/zap/exp v0.3.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/mod v0.28.0 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/tools v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index d5ea5f66631f6..fdf3874d21e69 100644 --- a/go.sum +++ b/go.sum @@ -840,8 +840,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -878,8 +878,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -908,8 +908,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -932,8 +932,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -975,8 +975,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -987,8 +987,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1002,8 +1002,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= @@ -1039,8 +1039,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/routers/web/repo/view_file.go b/routers/web/repo/view_file.go index ea3920439d426..167cd5f927f38 100644 --- a/routers/web/repo/view_file.go +++ b/routers/web/repo/view_file.go @@ -92,8 +92,6 @@ func handleFileViewRenderMarkup(ctx *context.Context, filename string, sniffedTy ctx.ServerError("Render", err) return true } - // to prevent iframe from loading third-party url - ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'") return true } @@ -241,14 +239,17 @@ func prepareFileView(ctx *context.Context, entry *git.TreeEntry) { // * IsRenderableXxx: some files are rendered by backend "markup" engine, some are rendered by frontend (pdf, 3d) // * DefaultViewMode: when there is no "display" query parameter, which view mode should be used by default, source or rendered - utf8Reader := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{}) + contentReader := io.MultiReader(bytes.NewReader(buf), dataRc) + if fInfo.st.IsRepresentableAsText() { + contentReader = charset.ToUTF8WithFallbackReader(contentReader, charset.ConvertOpts{}) + } switch { case fInfo.blobOrLfsSize >= setting.UI.MaxDisplayFileSize: ctx.Data["IsFileTooLarge"] = true - case handleFileViewRenderMarkup(ctx, entry.Name(), fInfo.st, buf, utf8Reader): + case handleFileViewRenderMarkup(ctx, entry.Name(), fInfo.st, buf, contentReader): // it also sets ctx.Data["FileContent"] and more ctx.Data["IsMarkup"] = true - case handleFileViewRenderSource(ctx, entry.Name(), attrs, fInfo, utf8Reader): + case handleFileViewRenderSource(ctx, entry.Name(), attrs, fInfo, contentReader): // it also sets ctx.Data["FileContent"] and more ctx.Data["IsDisplayingSource"] = true case handleFileViewRenderImage(ctx, fInfo, buf): diff --git a/tests/gitea-repositories-meta/user30/renderer.git/HEAD b/tests/gitea-repositories-meta/user30/renderer.git/HEAD deleted file mode 100644 index cb089cd89a7d7..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/HEAD +++ /dev/null @@ -1 +0,0 @@ -ref: refs/heads/master diff --git a/tests/gitea-repositories-meta/user30/renderer.git/config b/tests/gitea-repositories-meta/user30/renderer.git/config deleted file mode 100644 index e6da231579bcc..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/config +++ /dev/null @@ -1,6 +0,0 @@ -[core] - repositoryformatversion = 0 - filemode = true - bare = true - ignorecase = true - precomposeunicode = true diff --git a/tests/gitea-repositories-meta/user30/renderer.git/description b/tests/gitea-repositories-meta/user30/renderer.git/description deleted file mode 100644 index 04c23973b8a8a..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/description +++ /dev/null @@ -1 +0,0 @@ -The repository will be used to test third-party renderer in TestExternalMarkupRenderer diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive b/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive deleted file mode 100644 index f1f2709dddeea..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -data=$(cat) -exitcodes="" -hookname=$(basename $0) -GIT_DIR=${GIT_DIR:-$(dirname $0)} - -for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do -test -x "${hook}" && test -f "${hook}" || continue -echo "${data}" | "${hook}" -exitcodes="${exitcodes} $?" -done - -for i in ${exitcodes}; do -[ ${i} -eq 0 ] || exit ${i} -done diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive.d/gitea b/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive.d/gitea deleted file mode 100644 index 43a948da3a983..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/post-receive.d/gitea +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive b/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive deleted file mode 100644 index f1f2709dddeea..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -data=$(cat) -exitcodes="" -hookname=$(basename $0) -GIT_DIR=${GIT_DIR:-$(dirname $0)} - -for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do -test -x "${hook}" && test -f "${hook}" || continue -echo "${data}" | "${hook}" -exitcodes="${exitcodes} $?" -done - -for i in ${exitcodes}; do -[ ${i} -eq 0 ] || exit ${i} -done diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive.d/gitea b/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive.d/gitea deleted file mode 100644 index 49d09406364a5..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/pre-receive.d/gitea +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/update b/tests/gitea-repositories-meta/user30/renderer.git/hooks/update deleted file mode 100644 index df5bd27f106f2..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/update +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -exitcodes="" -hookname=$(basename $0) -GIT_DIR=${GIT_DIR:-$(dirname $0)} - -for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do -test -x "${hook}" && test -f "${hook}" || continue -"${hook}" $1 $2 $3 -exitcodes="${exitcodes} $?" -done - -for i in ${exitcodes}; do -[ ${i} -eq 0 ] || exit ${i} -done diff --git a/tests/gitea-repositories-meta/user30/renderer.git/hooks/update.d/gitea b/tests/gitea-repositories-meta/user30/renderer.git/hooks/update.d/gitea deleted file mode 100644 index 38101c242664a..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/hooks/update.d/gitea +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3 diff --git a/tests/gitea-repositories-meta/user30/renderer.git/objects/06/0d5c2acd8bf4b6f14010acd1a73d73392ec46e b/tests/gitea-repositories-meta/user30/renderer.git/objects/06/0d5c2acd8bf4b6f14010acd1a73d73392ec46e deleted file mode 100644 index 994f25602cd6d8b6a48735b7520ee0dc1f6c307b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56 zcmV-80LTA$0V^p=O;s?qWH2-^Ff%bx2y%6F@paY9D9O!Xa1~i;5b$=>VX^4DTsF-6 O*zDTpWdHz1$qy%Vr5Mrx diff --git a/tests/gitea-repositories-meta/user30/renderer.git/objects/45/14a93050edb2c3165bdd0a3c03be063e879e68 b/tests/gitea-repositories-meta/user30/renderer.git/objects/45/14a93050edb2c3165bdd0a3c03be063e879e68 deleted file mode 100644 index b1fff27753835c235faa542aeeb6708413501109..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50 zcmV-20L}k+0ZYosPf{>8XRt}hEVJX{EJ-acQAn*QNiE7t%uy&x%}YrwN-g5D(FaQd I08PXWv=3tx761SM diff --git a/tests/gitea-repositories-meta/user30/renderer.git/objects/c9/61cc4d1ba6b7ee1ba228a9a02b00b7746d8033 b/tests/gitea-repositories-meta/user30/renderer.git/objects/c9/61cc4d1ba6b7ee1ba228a9a02b00b7746d8033 deleted file mode 100644 index 66488767ae90c8665d6a1ce53faa21a44d6421d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 789 zcmV+w1M2*E0iBdd6RJiOg|p^Y^qxwXS{keJQelum6a#up&z~m`^d0ZaKV(IR{ye{jOY!1cC%%%V!vh8I{gc z*^l5bcijiXRoa8!-(PL!?v-_a7HwKJzu~_9190MIBXTS+ZUD_nEK7aqH*?DV*Ksiv z&#C~w{x!-Ts!9jzD2 z_XdAlFzj`?wdZzI%W6@3|8fdoI3llLm>|NZy5Am&(qDU$+gDRbcjWL2FDGcxmT+Lr zW;S5sCFrAKt4n$QxJjW*0m%`^hlS>2K(Cj%*3coTqgpC;yKOu?8Cplmgo~cYEp2GD zuM*i^8yyrc(N?QA1PT!QgADnzEbIR35UGbkbKP~h3GKo{?VV(sa{G9g$DU11*+p+# z{gBNn`rKML*`(1FxW~`okU%0jrS=UPd{0~-G96qUuaEroxD~j(+(I*Ev}adVzA7kA z`AVei*)@oao)l=vLsxG7vcIzD=Um@k(mNRIv@iStKN%*v#gpt}Ee-qEr8b%EWVLP5 zjZEe^?ly)e3K)w!Kk4E^xOZAus#65kvHCPurWKy8bBcV+@V!t+L^?I7=aQ?DPsYrv zo4wT_hTJGHiSSKN`T^3K_xPB^Cw9-4ZY00RNGgq&=476$3=d(jd&xoERPSZxTA`D3 z7}9k`0l}`<4h@)92n^ZK;{E&FSm|ZqCkDF0(t2Cc##>WKJUT6Bt449p#K(hKS`U&) zm;x7=VO7;-P3v@ZRIyvZd$Old<{bUp4Xf7Vve367%MKO3Xj))P%^5CF`3iOJy<92K z(aS-&B;3l`F~gZ2$I{P@NX|UcFY7QjAsXwfd>n>oqV*$vRz&Nu&wU#DcF`O64+Y{S znUiaT3=-DiZ48*)JR=*;3ER|a;Jf$^swEt=h TRdwGtFpT{@!xQxrb9G4{#m9=~ diff --git a/tests/gitea-repositories-meta/user30/renderer.git/packed-refs b/tests/gitea-repositories-meta/user30/renderer.git/packed-refs deleted file mode 100644 index 63f8af0f129eb..0000000000000 --- a/tests/gitea-repositories-meta/user30/renderer.git/packed-refs +++ /dev/null @@ -1,2 +0,0 @@ -# pack-refs with: peeled fully-peeled sorted -c961cc4d1ba6b7ee1ba228a9a02b00b7746d8033 refs/heads/master diff --git a/tests/gitea-repositories-meta/user30/renderer.git/refs/.keep b/tests/gitea-repositories-meta/user30/renderer.git/refs/.keep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/tests/integration/markup_external_test.go b/tests/integration/markup_external_test.go index 9985333cd7d34..b965766b5c5e0 100644 --- a/tests/integration/markup_external_test.go +++ b/tests/integration/markup_external_test.go @@ -12,6 +12,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/external" "code.gitea.io/gitea/modules/setting" @@ -25,29 +26,45 @@ import ( func TestExternalMarkupRenderer(t *testing.T) { defer tests.PrepareTestEnv(t)() if !setting.Database.Type.IsSQLite3() { - t.Skip() + t.Skip("only SQLite3 test config supports external markup renderer") return } + const binaryContentPrefix = "any prefix text." + const binaryContent = binaryContentPrefix + "\xfe\xfe\xfe\x00\xff\xff" + detectedEncoding, _ := charset.DetectEncoding([]byte(binaryContent)) + assert.NotEqual(t, binaryContent, strings.ToValidUTF8(binaryContent, "?")) + assert.Equal(t, "ISO-8859-2", detectedEncoding) // even if the binary content can be detected as text encoding, it shouldn't affect the raw rendering + onGiteaRun(t, func(t *testing.T, _ *url.URL) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - _, err := createFile(user2, repo1, "file.no-sanitizer", "master", `any content`) + _, err := createFileInBranch(user2, repo1, createFileInBranchOptions{}, map[string]string{ + "test.html": `
    `, + "html.no-sanitizer": ``, + "bin.no-sanitizer": binaryContent, + }) require.NoError(t, err) t.Run("RenderNoSanitizer", func(t *testing.T) { - req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/file.no-sanitizer") + req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/html.no-sanitizer") resp := MakeRequest(t, req, http.StatusOK) - doc := NewHTMLParser(t, resp.Body) - div := doc.Find("div.file-view") + div := NewHTMLParser(t, resp.Body).Find("div.file-view") data, err := div.Html() assert.NoError(t, err) - assert.Equal(t, ``, strings.TrimSpace(data)) + assert.Equal(t, ``, strings.TrimSpace(data)) + + req = NewRequest(t, "GET", "/user2/repo1/src/branch/master/bin.no-sanitizer") + resp = MakeRequest(t, req, http.StatusOK) + div = NewHTMLParser(t, resp.Body).Find("div.file-view") + data, err = div.Html() + assert.NoError(t, err) + assert.Equal(t, strings.ReplaceAll(binaryContent, "\x00", ""), strings.TrimSpace(data)) // HTML template engine removes the null bytes }) }) t.Run("RenderContentDirectly", func(t *testing.T) { - req := NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html") + req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/test.html") resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, "text/html; charset=utf-8", resp.Header().Get("Content-Type")) @@ -55,18 +72,21 @@ func TestExternalMarkupRenderer(t *testing.T) { div := doc.Find("div.file-view") data, err := div.Html() assert.NoError(t, err) - assert.Equal(t, "
    \n\ttest external renderer\n
    ", strings.TrimSpace(data)) + // the content is fully sanitized + assert.Equal(t, `
    <script></script>
    `, strings.TrimSpace(data)) }) - // above tested "no-sanitizer" mode, then we test iframe mode below + // above tested in-page rendering (no iframe), then we test iframe mode below r := markup.GetRendererByFileName("any-file.html").(*external.Renderer) defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)() + assert.True(t, r.NeedPostProcess()) r = markup.GetRendererByFileName("any-file.no-sanitizer").(*external.Renderer) defer test.MockVariableValue(&r.RenderContentMode, setting.RenderContentModeIframe)() + assert.False(t, r.NeedPostProcess()) t.Run("RenderContentInIFrame", func(t *testing.T) { t.Run("DefaultSandbox", func(t *testing.T) { - req := NewRequest(t, "GET", "/user30/renderer/src/branch/master/README.html") + req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/test.html") t.Run("ParentPage", func(t *testing.T) { respParent := MakeRequest(t, req, http.StatusOK) @@ -77,31 +97,42 @@ func TestExternalMarkupRenderer(t *testing.T) { // default sandbox on parent page assert.Equal(t, "allow-scripts allow-popups", iframe.AttrOr("sandbox", "")) - assert.Equal(t, "/user30/renderer/render/branch/master/README.html", iframe.AttrOr("data-src", "")) + assert.Equal(t, "/user2/repo1/render/branch/master/test.html", iframe.AttrOr("data-src", "")) }) t.Run("SubPage", func(t *testing.T) { - req = NewRequest(t, "GET", "/user30/renderer/render/branch/master/README.html") + req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/test.html") respSub := MakeRequest(t, req, http.StatusOK) assert.Equal(t, "text/html; charset=utf-8", respSub.Header().Get("Content-Type")) // default sandbox in sub page response assert.Equal(t, "frame-src 'self'; sandbox allow-scripts allow-popups", respSub.Header().Get("Content-Security-Policy")) - assert.Equal(t, "
    \n\ttest external renderer\n
    \n", respSub.Body.String()) + // FIXME: actually here is a bug (legacy design problem), the "PostProcess" will escape "
    <script></script>
    `, respSub.Body.String()) }) }) t.Run("NoSanitizerNoSandbox", func(t *testing.T) { - req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/file.no-sanitizer") - respParent := MakeRequest(t, req, http.StatusOK) - iframe := NewHTMLParser(t, respParent.Body).Find("iframe.external-render-iframe") - assert.Equal(t, "/user2/repo1/render/branch/master/file.no-sanitizer", iframe.AttrOr("data-src", "")) + t.Run("BinaryContent", func(t *testing.T) { + req := NewRequest(t, "GET", "/user2/repo1/src/branch/master/bin.no-sanitizer") + respParent := MakeRequest(t, req, http.StatusOK) + iframe := NewHTMLParser(t, respParent.Body).Find("iframe.external-render-iframe") + assert.Equal(t, "/user2/repo1/render/branch/master/bin.no-sanitizer", iframe.AttrOr("data-src", "")) - req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/file.no-sanitizer") - respSub := MakeRequest(t, req, http.StatusOK) + req = NewRequest(t, "GET", "/user2/repo1/render/branch/master/bin.no-sanitizer") + respSub := MakeRequest(t, req, http.StatusOK) + assert.Equal(t, binaryContent, respSub.Body.String()) // raw content should keep the raw bytes (including invalid UTF-8 bytes), and no "external-render-iframe" helpers + + // no sandbox (disabled by RENDER_CONTENT_SANDBOX) + assert.Empty(t, iframe.AttrOr("sandbox", "")) + assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy")) + }) - // no sandbox (disabled by RENDER_CONTENT_SANDBOX) - assert.Empty(t, iframe.AttrOr("sandbox", "")) - assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy")) + t.Run("HTMLContentWithExternalRenderIframeHelper", func(t *testing.T) { + req := NewRequest(t, "GET", "/user2/repo1/render/branch/master/html.no-sanitizer") + respSub := MakeRequest(t, req, http.StatusOK) + assert.Equal(t, ``, respSub.Body.String()) + assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy")) + }) }) }) } diff --git a/tests/sqlite.ini.tmpl b/tests/sqlite.ini.tmpl index f39888874f998..e2d9d768d5756 100644 --- a/tests/sqlite.ini.tmpl +++ b/tests/sqlite.ini.tmpl @@ -122,7 +122,7 @@ RENDER_CONTENT_MODE = sanitized [markup.no-sanitizer] ENABLED = true FILE_EXTENSIONS = .no-sanitizer -RENDER_COMMAND = echo '' +RENDER_COMMAND = go run build/test-echo.go ; This test case is reused, at first it is used to test "no-sanitizer" (sandbox doesn't take effect here) ; Then it will be updated and used to test "iframe + sandbox-disabled" RENDER_CONTENT_MODE = no-sanitizer From 1b01d6de82bb4f9d7682e163bf8f18dbc02ff450 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Fri, 14 Nov 2025 12:22:23 +0800 Subject: [PATCH 70/88] Fix container push tag overwriting (#35936) (#35954) Backport #35936 by wxiaoguang Fix #35853 Co-authored-by: wxiaoguang --- routers/api/packages/container/manifest.go | 37 +++++++++---------- .../api_packages_container_test.go | 36 ++++++++++++------ 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go index de40215aa762b..e408f6ee3b756 100644 --- a/routers/api/packages/container/manifest.go +++ b/routers/api/packages/container/manifest.go @@ -10,7 +10,6 @@ import ( "io" "os" "strings" - "time" "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" @@ -260,6 +259,13 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met return nil, err } + // "docker buildx imagetools create" multi-arch operations: + // {"type":"oci","is_tagged":false,"platform":"unknown/unknown"} + // {"type":"oci","is_tagged":false,"platform":"linux/amd64","layer_creation":["ADD file:9233f6f2237d79659a9521f7e390df217cec49f1a8aa3a12147bbca1956acdb9 in /","CMD [\"/bin/sh\"]"]} + // {"type":"oci","is_tagged":false,"platform":"unknown/unknown"} + // {"type":"oci","is_tagged":false,"platform":"linux/arm64","layer_creation":["ADD file:df53811312284306901fdaaff0a357a4bf40d631e662fe9ce6d342442e494b6c in /","CMD [\"/bin/sh\"]"]} + // {"type":"oci","is_tagged":true,"manifests":[{"platform":"linux/amd64","digest":"sha256:72bb73e706c0dec424d00a1febb21deaf1175a70ead009ad8b159729cfcf5769","size":2819478},{"platform":"linux/arm64","digest":"sha256:9e1426dd084a3221663b85ca1ee99d140c50b153917a5c5604c1f9b78229fd24","size":2716499},{"platform":"unknown/unknown","digest":"sha256:b93f03d0ae11b988243e1b2cd8d29accf5b9670547b7bd8c7d96abecc7283e6e","size":1798},{"platform":"unknown/unknown","digest":"sha256:f034b182ba66366c63a5d195c6dfcd3333c027409c0ac98e55ade36aaa3b2963","size":1798}]} + _pv := &packages_model.PackageVersion{ PackageID: p.ID, CreatorID: mci.Creator.ID, @@ -273,25 +279,16 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met log.Error("Error inserting package: %v", err) return nil, err } - - if container_module.IsMediaTypeImageIndex(mci.MediaType) { - if pv.CreatedUnix.AsTime().Before(time.Now().Add(-24 * time.Hour)) { - if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil { - return nil, err - } - // keep download count on overwriting - _pv.DownloadCount = pv.DownloadCount - if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil { - if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) { - log.Error("Error inserting package: %v", err) - return nil, err - } - } - } else { - err = packages_model.UpdateVersion(ctx, &packages_model.PackageVersion{ID: pv.ID, MetadataJSON: _pv.MetadataJSON}) - if err != nil { - return nil, err - } + if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil { + return nil, err + } + // keep download count on overwriting + _pv.DownloadCount = pv.DownloadCount + pv, err = packages_model.GetOrInsertVersion(ctx, _pv) + if err != nil { + if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) { + log.Error("Error inserting package: %v", err) + return nil, err } } } diff --git a/tests/integration/api_packages_container_test.go b/tests/integration/api_packages_container_test.go index 7e93cb47a2253..3c2d8bac33ed5 100644 --- a/tests/integration/api_packages_container_test.go +++ b/tests/integration/api_packages_container_test.go @@ -28,6 +28,7 @@ import ( oci "github.com/opencontainers/image-spec/specs-go/v1" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestPackageContainer(t *testing.T) { @@ -70,13 +71,12 @@ func TestPackageContainer(t *testing.T) { manifestDigest := "sha256:4f10484d1c1bb13e3956b4de1cd42db8e0f14a75be1617b60f2de3cd59c803c6" manifestContent := `{"schemaVersion":2,"mediaType":"` + container_module.ContentTypeDockerDistributionManifestV2 + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` - manifestContentType := container_module.ContentTypeDockerDistributionManifestV2 untaggedManifestDigest := "sha256:4305f5f5572b9a426b88909b036e52ee3cf3d7b9c1b01fac840e90747f56623d" untaggedManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageManifest + `","config":{"mediaType":"application/vnd.docker.container.image.v1+json","digest":"sha256:4607e093bec406eaadb6f3a340f63400c9d3a7038680744c406903766b938f0d","size":1069},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4","size":32}]}` - indexManifestDigest := "sha256:bab112d6efb9e7f221995caaaa880352feb5bd8b1faf52fae8d12c113aa123ec" - indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}` + indexManifestDigest := "sha256:2c6b5afb967d5de02795ee1d177c3746d005df4b4c2b829385b0d186b3414b6b" + indexManifestContent := `{"schemaVersion":2,"mediaType":"` + oci.MediaTypeImageIndex + `","is_tagged":true,"manifests":[{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"` + manifestDigest + `","platform":{"os":"linux","architecture":"arm","variant":"v7"}},{"mediaType":"` + oci.MediaTypeImageManifest + `","digest":"` + untaggedManifestDigest + `","platform":{"os":"linux","architecture":"arm64","variant":"v8"}}]}` anonymousToken := "" userToken := "" @@ -467,15 +467,16 @@ func TestPackageContainer(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, pv.DownloadCount) - // Overwrite existing tag should keep the download count - req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)). - AddTokenAuth(userToken). - SetHeader("Content-Type", oci.MediaTypeImageManifest) - MakeRequest(t, req, http.StatusCreated) + t.Run("OverwriteTagKeepDownloadCount", func(t *testing.T) { + req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)). + AddTokenAuth(userToken). + SetHeader("Content-Type", oci.MediaTypeImageManifest) + MakeRequest(t, req, http.StatusCreated) - pv, err = packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, tag) - assert.NoError(t, err) - assert.EqualValues(t, 1, pv.DownloadCount) + pv, err = packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, tag) + assert.NoError(t, err) + assert.EqualValues(t, 1, pv.DownloadCount) + }) }) t.Run("HeadManifest", func(t *testing.T) { @@ -505,7 +506,7 @@ func TestPackageContainer(t *testing.T) { resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, strconv.Itoa(len(manifestContent)), resp.Header().Get("Content-Length")) - assert.Equal(t, manifestContentType, resp.Header().Get("Content-Type")) + assert.Equal(t, oci.MediaTypeImageManifest, resp.Header().Get("Content-Type")) // the manifest is overwritten by above OverwriteTagKeepDownloadCount assert.Equal(t, manifestDigest, resp.Header().Get("Docker-Content-Digest")) assert.Equal(t, manifestContent, resp.Body.String()) }) @@ -599,6 +600,17 @@ func TestPackageContainer(t *testing.T) { assert.True(t, pd.Files[0].File.IsLead) assert.Equal(t, oci.MediaTypeImageIndex, pd.Files[0].Properties.GetByName(container_module.PropertyMediaType)) assert.Equal(t, indexManifestDigest, pd.Files[0].Properties.GetByName(container_module.PropertyDigest)) + + lastPackageVersionID := pv.ID + t.Run("UploadAgain", func(t *testing.T) { + req := NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, multiTag), strings.NewReader(indexManifestContent)). + AddTokenAuth(userToken). + SetHeader("Content-Type", oci.MediaTypeImageIndex) + MakeRequest(t, req, http.StatusCreated) + pv, err := packages_model.GetVersionByNameAndVersion(t.Context(), user.ID, packages_model.TypeContainer, image, multiTag) + require.NoError(t, err) + assert.NotEqual(t, lastPackageVersionID, pv.ID) + }) }) t.Run("HeadBlob", func(t *testing.T) { From f93e2cf3016ff3eb1bb5aa3ee9b116918da70735 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 19 Nov 2025 15:16:54 +0800 Subject: [PATCH 71/88] Misc CSS fixes (#35888) (#35981) Backport #35888 by @silverwind Fixes: https://github.com/go-gitea/gitea/issues/35913 Fixes: https://github.com/go-gitea/gitea/issues/35942 Contains a number of minor CSS fixes. Fix missing border on targeted speech bubble Screenshot 2025-11-06 at 22 43 31 Add padding to inline comments, slightly more padding around emoji button Screenshot 2025-11-06 at 22 38 39 Center text on header in code search results Screenshot 2025-11-06 at 22 08 01 Tweak emoji selector, reducing font size primarily Screenshot 2025-11-06 at 22 29 46 Minor tweaks to repo sidebar, reduce font size by 1px, center "Release" text with label. image Fix issue comment buttons being misaligned on mobile Screenshot 2025-11-06 at 22 50 19 Add highlight to actions re-run icon Screenshot 2025-11-06 at 23 04 30 Fix actions re-run button overflow image Signed-off-by: silverwind Co-authored-by: silverwind Co-authored-by: wxiaoguang --- templates/repo/home_sidebar_bottom.tmpl | 2 +- templates/repo/home_sidebar_top.tmpl | 2 +- templates/shared/search/code/results.tmpl | 2 +- web_src/css/repo.css | 24 +++++++++++++++-------- web_src/css/repo/reactions.css | 10 +++++----- web_src/css/review.css | 2 +- web_src/js/components/RepoActionView.vue | 4 ++-- 7 files changed, 27 insertions(+), 19 deletions(-) diff --git a/templates/repo/home_sidebar_bottom.tmpl b/templates/repo/home_sidebar_bottom.tmpl index 01e630ccbfb2a..4ba6aa05bf67f 100644 --- a/templates/repo/home_sidebar_bottom.tmpl +++ b/templates/repo/home_sidebar_bottom.tmpl @@ -6,8 +6,8 @@
    diff --git a/templates/repo/home_sidebar_top.tmpl b/templates/repo/home_sidebar_top.tmpl index 8c2089c839a52..edbf01db09636 100644 --- a/templates/repo/home_sidebar_top.tmpl +++ b/templates/repo/home_sidebar_top.tmpl @@ -9,7 +9,7 @@
    {{ctx.Locale.Tr "repo.repo_desc"}}
    -
    +
    {{- $description := .Repository.DescriptionHTML ctx -}} diff --git a/templates/shared/search/code/results.tmpl b/templates/shared/search/code/results.tmpl index 8a08f5c25cb0d..42f7a181a385a 100644 --- a/templates/shared/search/code/results.tmpl +++ b/templates/shared/search/code/results.tmpl @@ -12,7 +12,7 @@ {{range $result := .SearchResults}} {{$repo := or $.Repo (index $.RepoMaps .RepoID)}}
    -

    +

    {{if not $.Repo}} {{$repo.FullName}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 206a591fbdaf1..9b70e0e6dbaa1 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -528,9 +528,12 @@ td .commit-summary { } .repository.view.issue .comment-list .timeline-item .comment-text-line { + /* TODO: this "line-height" is not ideal (actually it is abused), many layouts depend on this magic value, + for example: alignment of the header arrow and the avatar, view PR commit list left icon layout, dismiss review with reason, etc */ line-height: 32px; vertical-align: middle; color: var(--color-text-light); + min-width: 0; } .repository.view.issue .comment-list .timeline-item .comment-text-line .ui.label { @@ -601,9 +604,6 @@ td .commit-summary { width: 100%; margin: 0; } - .repository.view.issue .comment-list .comment .content .form .button:not(:last-child) { - margin-bottom: 1rem; - } } .repository.view.issue .comment-list .comment .merge-section { @@ -654,7 +654,7 @@ td .commit-summary { .repository.view.issue .comment-list .code-comment { border: 1px solid transparent; - margin: 0; + padding: 8px; } .repository.view.issue .comment-list .code-comment .comment-header { @@ -664,6 +664,7 @@ td .commit-summary { } .repository.view.issue .comment-list .code-comment .comment-content { + margin-top: 6px; margin-left: 24px; } @@ -1286,9 +1287,9 @@ td .commit-summary { box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; } -.comment:target .header::before { +.comment:target .comment-header::before { border-right-color: var(--color-primary) !important; - filter: drop-shadow(-3px 0 0 var(--color-primary-alpha-30)) !important; + filter: drop-shadow(-4px 0 0 var(--color-primary-alpha-30)) !important; } .code-comment:target, @@ -1308,7 +1309,6 @@ td .commit-summary { padding: 0.5em 1rem; position: relative; color: var(--color-text); - min-height: 41px; display: flex; justify-content: space-between; align-items: center; @@ -1316,6 +1316,10 @@ td .commit-summary { gap: 0.25em; } +.comment-header.avatar-content-left-arrow { + min-height: 41px; /* for a comment header with left arrow, the arrow is absolutely positioned, but the header content varies (for example: no "roles", etc), so it needs a min-height */ +} + .comment-header.avatar-content-left-arrow::after { border-right-color: var(--color-box-header); } @@ -1339,7 +1343,7 @@ td .commit-summary { .comment-header-right { display: flex; align-items: center; - gap: 0.5em; + gap: 6px; } .comment-header-right { @@ -1347,6 +1351,10 @@ td .commit-summary { justify-content: end; } +.comment-header-right > .item.action { + padding: 4px; /* add some padding to make click area larger for the "item action ... ui dropdown" items */ +} + .comment-body { background: var(--color-box-body); border: none !important; diff --git a/web_src/css/repo/reactions.css b/web_src/css/repo/reactions.css index 8fe01af4f0676..f7db80fbbcc65 100644 --- a/web_src/css/repo/reactions.css +++ b/web_src/css/repo/reactions.css @@ -41,16 +41,16 @@ margin-left: 4px; } -.ui.dropdown.select-reaction .menu { - min-width: 170px; /* item-outer-width * 4 */ +.ui.dropdown.select-reaction .menu.visible { + display: grid !important; + grid-template-columns: repeat(4, 1fr); + padding: 4px; } .ui.dropdown.select-reaction .menu > .item { - float: left; - margin: 4px; - font-size: 20px; width: 34px; height: 34px; + font-size: 16px; border-radius: var(--border-radius); display: flex; align-items: center; diff --git a/web_src/css/review.css b/web_src/css/review.css index 23383c051cccb..2a128ee7727f7 100644 --- a/web_src/css/review.css +++ b/web_src/css/review.css @@ -52,7 +52,7 @@ } .comment-code-cloud { - padding: 0.5rem 1rem !important; + padding: 0.5rem !important; position: relative; } diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 300f635793456..00748ee9bb260 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -489,7 +489,7 @@ export default defineComponent({ -

    @@ -520,7 +520,7 @@ export default defineComponent({ {{ job.name }}
    - + {{ job.duration }} From e3bfee80dd0bf23a4cf2f863485abd73137f6488 Mon Sep 17 00:00:00 2001 From: Giteabot Date: Wed, 19 Nov 2025 17:43:48 +0800 Subject: [PATCH 72/88] Change project default column icon to 'star' (#35967) (#35979) Backport #35967 by @DrMaxNix Consistently use a `star` icon to highlight the default column of a project. The icon is both shown while viewing the project, as well as while changing the default status of this column. image Co-authored-by: DrMaxNix --- options/locale/locale_en-US.ini | 1 + templates/projects/view.tmpl | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index be715fbf3c059..efc2d9d86d72f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1481,6 +1481,7 @@ projects.column.new_submit = "Create Column" projects.column.new = "New Column" projects.column.set_default = "Set Default" projects.column.set_default_desc = "Set this column as default for uncategorized issues and pulls" +projects.column.default_column_hint = "New issues added to this project will be added to this column" projects.column.delete = "Delete Column" projects.column.deletion_desc = "Deleting a project column moves all related issues to the default column. Continue?" projects.column.color = "Color" diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl index 21bc287643014..5801396e3c5bc 100644 --- a/templates/projects/view.tmpl +++ b/templates/projects/view.tmpl @@ -78,7 +78,9 @@
    {{.NumIssues}}
    -
    {{.Title}}
    +
    + {{if .Default}}{{svg "octicon-star"}} {{end}}{{.Title}} +
    {{if $canWriteProject}}