diff --git a/.air.toml b/.air.toml
index de97bd8b29..3740c4d4aa 100644
--- a/.air.toml
+++ b/.air.toml
@@ -2,9 +2,10 @@ root = "."
tmp_dir = ".air"
[build]
+pre_cmd = ["killall -9 gitea 2>/dev/null || true"] # kill off potential zombie processes from previous runs
cmd = "make --no-print-directory backend"
bin = "gitea"
-delay = 1000
+delay = 2000
include_ext = ["go", "tmpl"]
include_file = ["main.go"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
diff --git a/.dockerignore b/.dockerignore
index b299c7313d..b696e1603c 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -95,6 +95,9 @@ cpu.out
/.air
/.go-licenses
+# Files and folders that were previously generated
+/public/assets/img/webpack
+
# Snapcraft
snap/.snapcraft/
parts/
diff --git a/.eslintrc.yaml b/.eslintrc.yaml
index 43edd14cec..3e4c6ea50b 100644
--- a/.eslintrc.yaml
+++ b/.eslintrc.yaml
@@ -318,7 +318,7 @@ rules:
jquery/no-serialize: [2]
jquery/no-show: [2]
jquery/no-size: [2]
- jquery/no-sizzle: [0]
+ jquery/no-sizzle: [2]
jquery/no-slide: [0]
jquery/no-submit: [0]
jquery/no-text: [0]
@@ -470,7 +470,7 @@ rules:
no-jquery/no-selector-prop: [2]
no-jquery/no-serialize: [2]
no-jquery/no-size: [2]
- no-jquery/no-sizzle: [0]
+ no-jquery/no-sizzle: [2]
no-jquery/no-slide: [2]
no-jquery/no-sub: [2]
no-jquery/no-support: [2]
@@ -537,7 +537,7 @@ rules:
no-underscore-dangle: [0]
no-unexpected-multiline: [2]
no-unmodified-loop-condition: [2]
- no-unneeded-ternary: [0]
+ no-unneeded-ternary: [2]
no-unreachable-loop: [2]
no-unreachable: [2]
no-unsafe-finally: [2]
@@ -716,12 +716,14 @@ rules:
unicorn/import-style: [0]
unicorn/new-for-builtins: [2]
unicorn/no-abusive-eslint-disable: [0]
+ unicorn/no-anonymous-default-export: [0]
unicorn/no-array-callback-reference: [0]
unicorn/no-array-for-each: [2]
unicorn/no-array-method-this-argument: [2]
unicorn/no-array-push-push: [2]
unicorn/no-array-reduce: [2]
unicorn/no-await-expression-member: [0]
+ unicorn/no-await-in-promise-methods: [2]
unicorn/no-console-spaces: [0]
unicorn/no-document-cookie: [2]
unicorn/no-empty-file: [2]
@@ -738,6 +740,7 @@ rules:
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
+ unicorn/no-single-promise-in-promise-methods: [2]
unicorn/no-static-only-class: [2]
unicorn/no-thenable: [2]
unicorn/no-this-assignment: [2]
diff --git a/.gitattributes b/.gitattributes
index 467b8a47b5..9fb4a4e83d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,6 @@
* text=auto eol=lf
*.tmpl linguist-language=Handlebars
+*.pb.go linguist-generated
/assets/*.json linguist-generated
/public/assets/img/svg/*.svg linguist-generated
/templates/swagger/v1_json.tmpl linguist-generated
diff --git a/.gitignore b/.gitignore
index 501fef7dcf..46c8b9b49c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,9 @@ cpu.out
/.air
/.go-licenses
+# Files and folders that were previously generated
+/public/assets/img/webpack
+
# Snapcraft
/gitea_a*.txt
snap/.snapcraft/
diff --git a/.golangci.yml b/.golangci.yml
index d6ce37f49a..27fee20f75 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -30,10 +30,6 @@ linters:
run:
timeout: 10m
- skip-dirs:
- - node_modules
- - public
- - web_src
linters-settings:
stylecheck:
@@ -90,10 +86,13 @@ linters-settings:
desc: do not use the internal package, use AddXxx function instead
- pkg: gopkg.in/ini.v1
desc: do not use the ini package, use gitea's config system instead
+ - pkg: gitea.com/go-chi/cache
+ desc: do not use the go-chi cache package, use gitea's cache system
issues:
max-issues-per-linter: 0
max-same-issues: 0
+ exclude-dirs: [node_modules, public, web_src]
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e119d0bec0..1c11ad4a7a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -159,11 +159,11 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fix the issue ref rendering for wiki (#28556) (#28559)
* Fix duplicate ID when deleting repo (#28520) (#28528)
* Only check online runner when detecting matching runners in workflows (#28286) (#28512)
- * Initalize stroage for orphaned repository doctor (#28487) (#28490)
+ * Initialize stroage for orphaned repository doctor (#28487) (#28490)
* Fix possible nil pointer access (#28428) (#28440)
* Don't show unnecessary citation JS error on UI (#28433) (#28437)
* DOCS
- * Update actions document about comparsion as Github Actions (#28560) (#28564)
+ * Update actions document about comparison as Github Actions (#28560) (#28564)
* Fix documents for "custom/public/assets/" (#28465) (#28467)
* MISC
* Fix inperformant query on retrifing review from database. (#28552) (#28562)
@@ -673,7 +673,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Docs: template variables (#26547)
* Update index doc (#26455)
* Update zh-cn documentation (#26406)
- * Fix typos and grammer problems for actions documentation (#26328)
+ * Fix typos and grammar problems for actions documentation (#26328)
* Update documentation for 1.21 actions (#26317)
* Doc update swagger doc for POST /orgs/{org}/teams (#26155)
* Doc sync authentication.md to zh-cn (#26117)
@@ -762,7 +762,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fix incorrect color of selected assignees when create issue (#26324) (#26372)
* Display human-readable text instead of cryptic filemodes (#26352) (#26358)
* Hide `last indexed SHA` when a repo could not be indexed yet (#26340) (#26345)
- * Fix the topic validation rule and suport dots (#26286) (#26303)
+ * Fix the topic validation rule and support dots (#26286) (#26303)
* Fix due date rendering the wrong date in issue (#26268) (#26274)
* Don't autosize textarea in diff view (#26233) (#26244)
* Fix commit compare style (#26209) (#26226)
@@ -989,7 +989,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Add dark mode to API Docs (#24971)
* Display file mode for new file and file mode changes (#24966)
* Make the 500 page load themes (#24953)
- * Show `bot` label next to username when rendering autor link if the user is a bot (#24943)
+ * Show `bot` label next to username when rendering author link if the user is a bot (#24943)
* Repo list improvements, fix bold helper classes (#24935)
* Improve queue and logger context (#24924)
* Improve RunMode / dev mode (#24886)
@@ -1384,7 +1384,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Replace `drone exec` to `act_runner exec` in test README.md (#24791)
* Update packages overview page (#24730)
* Docs for creating a user to run Gitea on Fedora/RHEL/CentOS (#24725)
- * Move actions as usage's subdirectory and update comparsion zh-cn version (#24719)
+ * Move actions as usage's subdirectory and update comparison zh-cn version (#24719)
* Document `redis-cluster` explicitly in config (#24717)
* Improve reverse-proxy document and fix nginx config bug (#24616)
* Fix broken `README` link (#24546)
@@ -1462,7 +1462,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Show visibility status of email in own profile (#23900)
* Refactor authors dropdown (send get request from frontend to avoid long wait time) (#23890)
* Add self to maintainers (#23644)
- * Upgrade to npm lockfile v3 and explicitely set it (#23561)
+ * Upgrade to npm lockfile v3 and explicitly set it (#23561)
* Improve indices for `action` table (#23532)
* Update JS dependencies, Require Node.js 16 (#23528)
* Add init file for Ubuntu (#23362)
@@ -1503,7 +1503,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fix issues list page multiple selection update milestones (#24660) (#24663)
* Fix: release page for empty or non-existing target (#24659)
* Fix close org projects (#24588) (#24591)
- * Refresh the refernce of the closed PR when reopening (#24231) (#24587)
+ * Refresh the references of the closed PR when reopening (#24231) (#24587)
* Fix the permission of team's `Actions` unit issue (#24536) (#24545)
* Bump go.etcd.io/bbolt and blevesearch deps (#23062) (#24519)
* Fix new wiki page mirror (#24518)
@@ -2644,7 +2644,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Feeds: render markdown to html (#19058)
* Allow users to self-request a PR review (#19030)
* Allow render HTML with css/js external links (#19017)
- * Fix script compatiable with OpenWrt (#19000)
+ * Fix script compatible with OpenWrt (#19000)
* Support ignore all santize for external renderer (#18984)
* Add note to GPG key response if user has no keys (#18961)
* Improve Stopwatch behavior (#18930)
@@ -2975,7 +2975,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Update go-org to v1.6.1 (#18932) (#18933)
* Fix `` html in translation (#18929) (#18931)
* Fix page and missing return on unadopted repos API (#18848) (#18927)
- * Allow adminstrator teams members to see other teams (#18918) (#18919)
+ * Allow administrator teams members to see other teams (#18918) (#18919)
* Don't treat BOM escape sequence as hidden character. (#18909) (#18910)
* Correctly link URLs to users/repos with dashes, dots or underscores (… (#18908)
* Fix redirect when using lowercase repo name (#18775) (#18902)
@@ -3323,7 +3323,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fixed issue merged/closed wording (#17973)
* Return nicer error for ForcePrivate (#17971)
* Fix overflow in commit graph (#17947)
- * Prevent services/mailer/mailer_test.go tests from deleteing data directory (#17941)
+ * Prevent services/mailer/mailer_test.go tests from deleting data directory (#17941)
* Use disable_form_autofill on Codebase and Gitbucket (#17936)
* Fix a panic in NotifyCreateIssueComment (caused by string truncation) (#17928)
* Fix markdown URL parsing (#17924)
@@ -3362,7 +3362,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Fixed emoji alias not parsed in links (#16221)
* Calculate label URL on API (#16186)
* TRANSLATION
- * Fix mispelling of starred as stared (#17465)
+ * Fix misspelling of starred as stared (#17465)
* Re-separate the color translation strings (#17390)
* Enable Malayalam, Greek, Persian, Hungarian & Indonesian by default (#16998)
* BUILD
@@ -3554,7 +3554,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Correctly return the number of Repositories for Organizations (#16807) (#16911)
* Test if LFS object is accessible (#16865) (#16904)
* Fix git.Blob.DataAsync(): close pipe since we return a NopCloser (#16899) (#16900)
- * Fix dump and restore respository (#16698) (#16898)
+ * Fix dump and restore repository (#16698) (#16898)
* Repare and Improve GetDiffRangeWithWhitespaceBehavior (#16894) (#16895)
* Fix wiki raw commit diff/patch view (#16891) (#16892)
* Ensure wiki repos are all closed (#16886) (#16888)
@@ -4164,7 +4164,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Improve Description in new/ edit Project template (#14429)
* Allow ssh-keygen on Windows to detect ssh key type (#14413)
* Display error if twofaSecret cannot be retrieved (#14372)
- * Sort issue search results by revelance (#14353)
+ * Sort issue search results by relevance (#14353)
* Implement ghost comment mitigation (#14349)
* Upgrade blevesearch dependency to v2.0.1 (#14346)
* Add edit, delete and reaction support to code review comments on issue page (#14339)
@@ -4337,7 +4337,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* BUGFIXES
* Fix race in LFS ContentStore.Put(...) (#14895) (#14913)
* Fix a couple of issues with a feeds (#14897) (#14903)
- * When transfering repository and database transaction failed, rollback the renames (#14864) (#14902)
+ * When transferring repository and database transaction failed, rollback the renames (#14864) (#14902)
* Fix race in local storage (#14888) (#14901)
* Fix 500 on pull view page if user is not loged in (#14885) (#14886)
* DOCS
@@ -4668,7 +4668,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Render the git graph on the server (#12333)
* Fix clone panel in wiki position not always align right (#12326)
* Rework 'make generate-images' (#12316)
- * Refactor webhook payload convertion (#12310)
+ * Refactor webhook payload conversion (#12310)
* Move jquery-minicolors to npm/webpack (#12305)
* Support use nvarchar for all varchar columns when using mssql (#12269)
* Update Octicons to v10 (#12240)
@@ -4744,7 +4744,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Add debug option to hooks (#11624)
* Log slow tests (#11487)
* TRANSLATION
- * Translate two small lables on commit statuse list (#12821)
+ * Translate two small lables on commit statutes list (#12821)
* Make issues.force_push_codes message shorter (#11575)
* BUILD
* Bump min required golang to 1.13 (#12717)
@@ -5123,7 +5123,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Add restricted user filter to LDAP authentication (#10600)
* Add Yandex OAuth2 provider (#8335) (#10564)
* Make avatar lookup occur at image request (#10540)
- * Prevent accidential selection of language stats bar (#10537)
+ * Prevent accidental selection of language stats bar (#10537)
* Add fluid-icon (#10491)
* Inform participants on UI too (#10473)
* Build with go 1.14 (and raise minimum go version to 1.12) (#10467)
@@ -5515,7 +5515,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
* Don't link wiki revision to commit (#9244)
* Change review content column to type text in db (#9229)
* Fixed topic regex pattern and added search by topic links after save (#9219)
- * Add language to user API responce (#9215)
+ * Add language to user API response (#9215)
* Correct tooltip message blocked by dependencies (#9211)
* Add SimpleMDE and Fix Image Paste for Issue/Comment Editor (#9197)
* Fix panic when diff (#9187)
@@ -6136,7 +6136,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Display original author and URL information when showing migrated issues/comments (#7352)
* Refactor filetype is not allowed errors (#7309)
* switch to use gliderlabs/ssh for builtin server (#7250)
- * Remove settting dependency on modules/session (#7237)
+ * Remove setting dependency on modules/session (#7237)
* Move all mail related codes from models to services/mailer (#7200)
* Support git.PATH entry in app.ini (#6772)
* Support setting cookie domain (#6288)
@@ -6311,7 +6311,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Fix markdown invoke sequence (#7513) (#7560)
* Reserve .well-known username (#7638)
* Do not leak secrets via timing side channel (#7364)
- * Ensure that decryption of cookie actually suceeds (#7363)
+ * Ensure that decryption of cookie actually succeeds (#7363)
* FEATURES
* Content API for Creating, Updating, Deleting Files (#6314)
* Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
@@ -6533,7 +6533,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Change UpdateRepoIndex api to include watchers (#7012)
* Move serv hook functionality & drop GitLogger (#6993)
* Add support of utf8mb4 for mysql (#6992)
- * Make webhook http connections resuable (#6976)
+ * Make webhook http connections reusable (#6976)
* Move xorm logger bridge from log to models so that log module could be a standalone package (#6944)
* Refactor models.NewRepoContext to extract git related codes to modules/git (#6941)
* Remove macaron dependent on models (#6940)
@@ -7104,7 +7104,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Fix data race on migrate repository (#5224)
* Fix sqlite and mssql lock (#5214)
* Fix sqlite lock (#5210)
- * Fix: Accept web-command cli flags if web-command is commited (#5200)
+ * Fix: Accept web-command cli flags if web-command is committed (#5200)
* Fix: Add secret to all webhook's payload where it has been missing (#5199)
* Fix race on updatesize (#5190)
* Fix create team, update team missing units (#5188)
@@ -7255,7 +7255,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Enforce token on api routes [fixed critical security issue #4357] (#4840)
* Update legacy branch and tag URLs in dashboard to new format (#4812)
* Slack webhook channel name cannot be empty or just contain an hashtag (#4786)
- * Add whitespace handling to PR-comparsion (#4683)
+ * Add whitespace handling to PR-comparison (#4683)
* Make reverse proxy auth optional (#4643)
* MySQL TLS (#4642)
* Make sure to set PR split view when creating/previewing a pull request (#4617)
@@ -7309,7 +7309,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Fix markdown image with link (#4675)
* Remove maxlines option for file logger (#5282)
* Fix wrong api request url for instances running in subfolders (#5261) (#5247)
- * Accept web-command cli flags if web-command is commited (#5245) (#5200)
+ * Accept web-command cli flags if web-command is committed (#5245) (#5200)
* Reduce join star, repo_topic, topic tables on repo search, to resolve extra columns problem on MSSQL (#5136) (#5229)
* Fix data race on migrate repository (#5224) (#5230)
* Add secret to all webhook's payload where it has been missing (#5208) (#5199)
@@ -7342,7 +7342,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Fix missing release title in webhook (#4783) (#4796)
* User shouldn't be able to approve or reject his/her own PR (#4729)
* Make sure to reset commit count in the cache on mirror syncing (#4720)
- * Fixed bug where team with admin privelege type doesn't get any unit (#4719)
+ * Fixed bug where team with admin privilege type doesn't get any unit (#4719)
* Fix incorrect caption of webhook setting (#4701) (#4717)
* Allow WIP marker to contains < or > (#4709)
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680)
@@ -7408,7 +7408,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* BUGFIXES
* Fix missing release title in webhook (#4783) (#4800)
* Make sure to reset commit count in the cache on mirror syncing (#4770)
- * Fixed bug where team with admin privelege type doesn't get any unit (#4759)
+ * Fixed bug where team with admin privilege type doesn't get any unit (#4759)
* Fix failure on creating pull request with assignees (#4583) (#4727)
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686)
* TRANSLATION
@@ -7759,7 +7759,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Fix inconsistencies in user settings UI (#2901)
* Fix attachments icon size on zoom in/out (#2853)
* Fix ignored errors in API route (#2850)
- * Fix activity css conflit with semantic ui (#2758)
+ * Fix activity css conflict with semantic ui (#2758)
* Fix notifications tabs according to semantic-ui docs (#2733)
* Fix typos in app.ini (#2732)
* Fix duplicated rel attribute (#2549)
@@ -7957,7 +7957,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* LFS: Return 404 for unimplemented endpoints (#1330)
* Show a link to password reset from user settings requiring a password (#862)
* Reserve the "explore" user/org name (#1222)
- * Send notifications to partecipants in issue comments (#1217)
+ * Send notifications to participants in issue comments (#1217)
* Improve style of user OpenID setting page (#1324)
* Use font-awesome OpenID icon more (#1320)
* Use readonly input form to show the validated OpenID URI (#1308)
@@ -8155,7 +8155,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* fix #1501 ssh hangs caused by #1461 (#1513)
* Fix empty file download (#1506)
* Fix broken v27 migration - change mirror interval from int to bigint (#1504)
- * Do not allow commiting to protected branch from online editor (#1502)
+ * Do not allow committing to protected branch from online editor (#1502)
* Add internal routes for ssh hook comands (#1471)
* Fix races within code.gitea.io/git.(*Command).RunInDirTimeoutPipeline (#1465)
* Simple quick fix for #1418 (#1456)
@@ -8183,7 +8183,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Make sure both scripts/ can live side by side (#1264)
* Fix nil-dereference bug (#1258)
* rewrite pre-commit, post-commit and options hooks (fixes #1250) (#1257)
- * Commit search appearence fixes (#1254)
+ * Commit search appearance fixes (#1254)
* Fix forget migration for wiki hooks (#1227)
* Fix repo settings external tracker failed and check external urls (#1215)
* Fix 500 caused by branches settings introduced by #1198 (#1214)
@@ -8267,7 +8267,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Only run coverage on merges/pushes to master (#1783)
* Remove stale rule from Makefile (#1782)
* feat: upgrade drone docker image to support multi-stage build. (#1732)
- * Realy don't cache apk index (#1694)
+ * Really don't cache apk index (#1694)
* Limit clone depth when drone-building (#1644)
* Refactor Dockerfile (#1632)
* Check if missing/modified/unused deps in vendor and fix errors (#1468)
@@ -8331,7 +8331,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Remove unused files (#2124)
* Improve org error handling (#2117)
* Absolute path for setting.CustomConf (#2085)
- * remove deprecated code for Gogs compitable (#2041)
+ * remove deprecated code for Gogs compatible (#2041)
* Refactor session close as xorm already does everything needed internally (#2020)
* SQLite has a query timeout. Hopefully fixes most 'database locked' errors (#1961)
* Use monospace font in githook editor (#1958)
@@ -8339,7 +8339,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Gracefully handle bare repositories on API operations. (#1932)
* Fix errors caused by force push (#1927)
* Display URLs in integration test logs (#1924)
- * Set TMPDIR enviroment variable for dump command (#1915)
+ * Set TMPDIR environment variable for dump command (#1915)
* Cache ctx.User in retrieveFeeds (#1902)
* Make `LocalCopyPath` a setting instead of a hard-coded path (#1881)
* Add check misspelling (#1877)
@@ -8348,7 +8348,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Rename misnamed migration (#1867)
* Support CRLF when splitting code lines for display (#1862)
* Add convert less css file step. (#1861)
- * Prevent accidential selection of line numbers in code view (#1860)
+ * Prevent accidental selection of line numbers in code view (#1860)
* Delete Public SSH Key tmp file after calculating fingerprint (#1855)
* Remove annoying difference in button heights. (#1853)
* Only run test coverage on master branch. (#1838)
@@ -8358,7 +8358,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should __not__ be
* Rename RepoCreationNum -> MaxCreationLimit (#1766)
* Add button to admin ui (#1738)
* Correct spelling mistakes (#1703)
- * Make openid support default false for compitable with v1.1 (#1650)
+ * Make openid support default false for compatible with v1.1 (#1650)
* Send mails as HTML as default. Setting for send as plain text. (#1648)
* fix potential lock when sqlite (#1647)
* Optimize png images via Google zopflipng [ci skip] (#1639)
diff --git a/Makefile b/Makefile
index 8489520920..2a78c907c0 100644
--- a/Makefile
+++ b/Makefile
@@ -25,17 +25,17 @@ COMMA := ,
XGO_VERSION := go-1.22.x
-AIR_PACKAGE ?= github.com/cosmtrek/air@v1.49.0
+AIR_PACKAGE ?= github.com/cosmtrek/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
-GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.56.1
+GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
-GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0
-GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.0.3
-ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.6.26
+GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
+GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
+ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -110,7 +110,6 @@ LDFLAGS := $(LDFLAGS) -X "main.MakeVersion=$(MAKE_VERSION)" -X "main.Version=$(G
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64
-GO_PACKAGES ?= $(filter-out code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration code.gitea.io/gitea/tests/e2e,$(shell $(GO) list ./... | grep -v /vendor/))
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
@@ -144,9 +143,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css
-ESLINT_FILES := web_src/js tools *.config.js tests/e2e
+ESLINT_FILES := web_src/js tools *.js tests/e2e
STYLELINT_FILES := web_src/css web_src/js/components/*.vue
-SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github
+SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.js *.md *.yml *.yaml *.toml))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
GO_SOURCES := $(wildcard *.go)
@@ -295,7 +294,7 @@ clean:
.PHONY: fmt
fmt:
- GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
+ @GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
@# whitespace before it
@@ -423,7 +422,7 @@ lint-go-windows:
lint-go-vet:
@echo "Running go vet..."
@GOOS= GOARCH= $(GO) build code.gitea.io/gitea-vet
- @$(GO) vet -vettool=gitea-vet $(GO_PACKAGES)
+ @$(GO) vet -vettool=gitea-vet ./...
.PHONY: lint-editorconfig
lint-editorconfig:
@@ -779,7 +778,7 @@ generate-backend: $(TAGS_PREREQ) generate-go
.PHONY: generate-go
generate-go: $(TAGS_PREREQ)
@echo "Running go generate..."
- @CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' $(GO_PACKAGES)
+ @CC= GOOS= GOARCH= $(GO) generate -tags '$(TAGS)' ./...
.PHONY: security-check
security-check:
diff --git a/assets/go-licenses.json b/assets/go-licenses.json
index be9022b694..ea73182a83 100644
--- a/assets/go-licenses.json
+++ b/assets/go-licenses.json
@@ -304,11 +304,6 @@
"path": "github.com/davecgh/go-spew/spew/LICENSE",
"licenseText": "ISC License\n\nCopyright (c) 2012-2016 Dave Collins \u003cdave@davec.name\u003e\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
},
- {
- "name": "github.com/denisenkom/go-mssqldb",
- "path": "github.com/denisenkom/go-mssqldb/LICENSE.txt",
- "licenseText": "Copyright (c) 2012 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
- },
{
"name": "github.com/dgryski/go-rendezvous",
"path": "github.com/dgryski/go-rendezvous/LICENSE",
@@ -759,6 +754,16 @@
"path": "github.com/microcosm-cc/bluemonday/LICENSE.md",
"licenseText": "SPDX short identifier: BSD-3-Clause\nhttps://opensource.org/licenses/BSD-3-Clause\n\nCopyright (c) 2014, David Kitchen \u003cdavid@buro9.com\u003e\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n* Neither the name of the organisation (Microcosm) nor the names of its\n contributors may be used to endorse or promote products derived from\n this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
+ {
+ "name": "github.com/microsoft/go-mssqldb",
+ "path": "github.com/microsoft/go-mssqldb/LICENSE.txt",
+ "licenseText": "Copyright (c) 2012 The Go Authors. All rights reserved.\nCopyright (c) Microsoft Corporation.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ },
+ {
+ "name": "github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg",
+ "path": "github.com/microsoft/go-mssqldb/internal/github.com/swisscom/mssql-always-encrypted/pkg/LICENSE.txt",
+ "licenseText": "Copyright (c) 2021 Swisscom (Switzerland) Ltd\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject 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, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n"
+ },
{
"name": "github.com/miekg/dns",
"path": "github.com/miekg/dns/LICENSE",
diff --git a/build/code-batch-process.go b/build/code-batch-process.go
index b3ee399420..cc2ab68026 100644
--- a/build/code-batch-process.go
+++ b/build/code-batch-process.go
@@ -69,6 +69,7 @@ func newFileCollector(fileFilter string, batchSize int) (*fileCollector, error)
co.includePatterns = append(co.includePatterns, regexp.MustCompile(`.*\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`.*\bbindata\.go$`))
+ co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`\.pb\.go$`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/gitea-repositories-meta`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`tests/integration/migration-test`))
co.excludePatterns = append(co.excludePatterns, regexp.MustCompile(`modules/git/tests`))
@@ -203,17 +204,6 @@ Example:
`, "file-batch-exec")
}
-func getGoVersion() string {
- goModFile, err := os.ReadFile("go.mod")
- if err != nil {
- log.Fatalf(`Faild to read "go.mod": %v`, err)
- os.Exit(1)
- }
- goModVersionRegex := regexp.MustCompile(`go \d+\.\d+`)
- goModVersionLine := goModVersionRegex.Find(goModFile)
- return string(goModVersionLine[3:])
-}
-
func newFileCollectorFromMainOptions(mainOptions map[string]string) (fc *fileCollector, err error) {
fileFilter := mainOptions["file-filter"]
if fileFilter == "" {
@@ -278,7 +268,8 @@ func main() {
log.Print("the -d option is not supported by gitea-fmt")
}
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-w")))
- cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", getGoVersion()}, substArgs...)))
+ cmdErrors = append(cmdErrors, passThroughCmd("gofmt", append([]string{"-w", "-r", "interface{} -> any"}, substArgs...)))
+ cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra"}, substArgs...)))
default:
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
}
diff --git a/cmd/admin_user_change_password.go b/cmd/admin_user_change_password.go
index 824d66d112..bd9063a8e4 100644
--- a/cmd/admin_user_change_password.go
+++ b/cmd/admin_user_change_password.go
@@ -36,6 +36,7 @@ var microcmdUserChangePassword = &cli.Command{
&cli.BoolFlag{
Name: "must-change-password",
Usage: "User must change password",
+ Value: true,
},
},
}
@@ -57,23 +58,18 @@ func runChangePassword(c *cli.Context) error {
return err
}
- var mustChangePassword optional.Option[bool]
- if c.IsSet("must-change-password") {
- mustChangePassword = optional.Some(c.Bool("must-change-password"))
- }
-
opts := &user_service.UpdateAuthOptions{
Password: optional.Some(c.String("password")),
- MustChangePassword: mustChangePassword,
+ MustChangePassword: optional.Some(c.Bool("must-change-password")),
}
if err := user_service.UpdateAuth(ctx, user, opts); err != nil {
switch {
case errors.Is(err, password.ErrMinLength):
- return fmt.Errorf("Password is not long enough. Needs to be at least %d", setting.MinPasswordLength)
+ return fmt.Errorf("password is not long enough, needs to be at least %d characters", setting.MinPasswordLength)
case errors.Is(err, password.ErrComplexity):
- return errors.New("Password does not meet complexity requirements")
+ return errors.New("password does not meet complexity requirements")
case errors.Is(err, password.ErrIsPwned):
- return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords")
+ return errors.New("the password is in a list of stolen passwords previously exposed in public data breaches, please try again with a different password, to see more details: https://haveibeenpwned.com/Passwords")
default:
return err
}
diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go
index a257ce21c8..403e3ee8d8 100644
--- a/cmd/admin_user_create.go
+++ b/cmd/admin_user_create.go
@@ -8,6 +8,7 @@ import (
"fmt"
auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
user_model "code.gitea.io/gitea/models/user"
pwd "code.gitea.io/gitea/modules/auth/password"
"code.gitea.io/gitea/modules/optional"
@@ -46,8 +47,9 @@ var microcmdUserCreate = &cli.Command{
Usage: "Generate a random password for the user",
},
&cli.BoolFlag{
- Name: "must-change-password",
- Usage: "Set this option to false to prevent forcing the user to change their password after initial login, (Default: true)",
+ Name: "must-change-password",
+ Usage: "Set to false to prevent forcing the user to change their password after initial login",
+ DisableDefaultText: true,
},
&cli.IntFlag{
Name: "random-password-length",
@@ -71,10 +73,10 @@ func runCreateUser(c *cli.Context) error {
}
if c.IsSet("name") && c.IsSet("username") {
- return errors.New("Cannot set both --name and --username flags")
+ return errors.New("cannot set both --name and --username flags")
}
if !c.IsSet("name") && !c.IsSet("username") {
- return errors.New("One of --name or --username flags must be set")
+ return errors.New("one of --name or --username flags must be set")
}
if c.IsSet("password") && c.IsSet("random-password") {
@@ -110,17 +112,21 @@ func runCreateUser(c *cli.Context) error {
return errors.New("must set either password or random-password flag")
}
- // always default to true
- changePassword := true
-
- // If this is the first user being created.
- // Take it as the admin and don't force a password update.
- if n := user_model.CountUsers(ctx, nil); n == 0 {
- changePassword = false
- }
-
+ isAdmin := c.Bool("admin")
+ mustChangePassword := true // always default to true
if c.IsSet("must-change-password") {
- changePassword = c.Bool("must-change-password")
+ // if the flag is set, use the value provided by the user
+ mustChangePassword = c.Bool("must-change-password")
+ } else {
+ // check whether there are users in the database
+ hasUserRecord, err := db.IsTableNotEmpty(&user_model.User{})
+ if err != nil {
+ return fmt.Errorf("IsTableNotEmpty: %w", err)
+ }
+ if !hasUserRecord && isAdmin {
+ // if this is the first admin being created, don't force to change password (keep the old behavior)
+ mustChangePassword = false
+ }
}
restricted := optional.None[bool]()
@@ -136,8 +142,8 @@ func runCreateUser(c *cli.Context) error {
Name: username,
Email: c.String("email"),
Passwd: password,
- IsAdmin: c.Bool("admin"),
- MustChangePassword: changePassword,
+ IsAdmin: isAdmin,
+ MustChangePassword: mustChangePassword,
Visibility: visibility,
}
diff --git a/cmd/hook.go b/cmd/hook.go
index 6a3358853d..c04591d79e 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -448,23 +448,26 @@ Gitea or set your environment appropriately.`, "")
func hookPrintResults(results []private.HookPostReceiveBranchResult) {
for _, res := range results {
- if !res.Message {
- continue
- }
-
- fmt.Fprintln(os.Stderr, "")
- if res.Create {
- fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res.Branch)
- fmt.Fprintf(os.Stderr, " %s\n", res.URL)
- } else {
- fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
- fmt.Fprintf(os.Stderr, " %s\n", res.URL)
- }
- fmt.Fprintln(os.Stderr, "")
- os.Stderr.Sync()
+ hookPrintResult(res.Message, res.Create, res.Branch, res.URL)
}
}
+func hookPrintResult(output, isCreate bool, branch, url string) {
+ if !output {
+ return
+ }
+ fmt.Fprintln(os.Stderr, "")
+ if isCreate {
+ fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
+ fmt.Fprintf(os.Stderr, " %s\n", url)
+ } else {
+ fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
+ fmt.Fprintf(os.Stderr, " %s\n", url)
+ }
+ fmt.Fprintln(os.Stderr, "")
+ os.Stderr.Sync()
+}
+
func pushOptions() map[string]string {
opts := make(map[string]string)
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
@@ -691,6 +694,12 @@ Gitea or set your environment appropriately.`, "")
}
err = writeFlushPktLine(ctx, os.Stdout)
+ if err == nil {
+ for _, res := range resp.Results {
+ hookPrintResult(res.ShouldShowMessage, res.IsCreatePR, res.HeadBranch, res.URL)
+ }
+ }
+
return err
}
diff --git a/cmd/web.go b/cmd/web.go
index 01386251be..ef8a7426c1 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) {
log.Info("* WorkPath: %s", setting.AppWorkPath)
log.Info("* CustomPath: %s", setting.CustomPath)
log.Info("* ConfigFile: %s", setting.CustomConf)
- log.Info("%s", msg)
+ log.Info("%s", msg) // show startup message
}
func serveInstall(ctx *cli.Context) error {
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 918252044b..b4e330184e 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -1553,8 +1553,9 @@ LEVEL = Info
;; The source of the username for new oauth2 accounts:
;; userid = use the userid / sub attribute
;; nickname = use the nickname attribute
+;; preferred_username = use the preferred_username attribute
;; email = use the username part of the email attribute
-;; Note: `nickname` and `email` options will normalize input strings using the following criteria:
+;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
;; - diacritics are removed
;; - the characters in the set `['´\x60]` are removed
;; - the characters in the set `[\s~+]` are replaced with `-`
@@ -2376,22 +2377,6 @@ LEVEL = Info
;; Enable issue by repository metrics; default is false
;ENABLED_ISSUE_BY_REPOSITORY = false
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;[task]
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; Task queue type, could be `channel` or `redis`.
-;QUEUE_TYPE = channel
-;;
-;; Task queue length, available only when `QUEUE_TYPE` is `channel`.
-;QUEUE_LENGTH = 1000
-;;
-;; Task queue connection string, available only when `QUEUE_TYPE` is `redis`.
-;; If there is a password of redis, use `redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` or `redis+cluster://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s` for `redis-clsuter`.
-;QUEUE_CONN_STR = "redis://127.0.0.1:6379/0?pool_size=100&idle_timeout=180s"
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[migrations]
diff --git a/docs/content/administration/command-line.en-us.md b/docs/content/administration/command-line.en-us.md
index 5049df35e0..752a8d4c6f 100644
--- a/docs/content/administration/command-line.en-us.md
+++ b/docs/content/administration/command-line.en-us.md
@@ -83,8 +83,7 @@ Admin operations:
- `--email value`: Email. Required.
- `--admin`: If provided, this makes the user an admin. Optional.
- `--access-token`: If provided, an access token will be created for the user. Optional. (default: false).
- - `--must-change-password`: If provided, the created user will be required to choose a newer password after the
- initial login. Optional. (default: true).
+ - `--must-change-password`: The created user will be required to set a new password after the initial login, default: true. It could be disabled by `--must-change-password=false`.
- `--random-password`: If provided, a randomly generated password will be used as the password of the created
user. The value of `--password` will be discarded. Optional.
- `--random-password-length`: If provided, it will be used to configure the length of the randomly generated
@@ -95,7 +94,7 @@ Admin operations:
- Options:
- `--username value`, `-u value`: Username. Required.
- `--password value`, `-p value`: New password. Required.
- - `--must-change-password`: If provided, the user is required to choose a new password after the login. Optional.
+ - `--must-change-password`: The user is required to set a new password after the login, default: true. It could be disabled by `--must-change-password=false`.
- Examples:
- `gitea admin user change-password --username myname --password asecurepassword`
- `must-change-password`:
diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md
index 9de7511964..9328177f50 100644
--- a/docs/content/administration/config-cheat-sheet.en-us.md
+++ b/docs/content/administration/config-cheat-sheet.en-us.md
@@ -608,9 +608,10 @@ And the following unique queues:
- `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users.
- `USERNAME`: **nickname**: The source of the username for new oauth2 accounts:
- `userid` - use the userid / sub attribute
- - `nickname` - use the nickname attribute
+ - `nickname` - use the nickname
+ - `preferred_username` - use the preferred_username
- `email` - use the username part of the email attribute
- - Note: `nickname` and `email` options will normalize input strings using the following criteria:
+ - Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
- diacritics are removed
- the characters in the set `['´\x60]` are removed
- the characters in the set `[\s~+]` are replaced with `-`
@@ -1197,14 +1198,6 @@ in this mapping or the filetype using heuristics.
- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Asia/Shanghai
-## Task (`task`)
-
-Task queue configuration has been moved to `queue.task`. However, the below configuration values are kept for backwards compatibility:
-
-- `QUEUE_TYPE`: **channel**: Task queue type, could be `channel` or `redis`.
-- `QUEUE_LENGTH`: **1000**: Task queue length, available only when `QUEUE_TYPE` is `channel`.
-- `QUEUE_CONN_STR`: **redis://127.0.0.1:6379/0**: Task queue connection string, available only when `QUEUE_TYPE` is `redis`. If redis needs a password, use `redis://123@127.0.0.1:6379/0` or `redis+cluster://123@127.0.0.1:6379/0`.
-
## Migrations (`migrations`)
- `MAX_ATTEMPTS`: **3**: Max attempts per http/https request on migrations.
diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md
index 759f39b576..e4945dd1c1 100644
--- a/docs/content/administration/config-cheat-sheet.zh-cn.md
+++ b/docs/content/administration/config-cheat-sheet.zh-cn.md
@@ -1128,15 +1128,6 @@ ALLOW_DATA_URI_IMAGES = true
- `DEFAULT_UI_LOCATION`:在 UI 上的默认时间位置,以便我们可以在 UI 上显示正确的用户时间。例如:Asia/Shanghai
-## 任务 (`task`)
-
-任务队列配置已移动到 `queue.task`。然而,以下配置值仍保留以确保向后兼容:
-
-- `QUEUE_TYPE`:**channel**:任务队列类型,可以是 `channel` 或 `redis`。
-- `QUEUE_LENGTH`:**1000**:任务队列长度,仅在 `QUEUE_TYPE` 为 `channel` 时可用。
-- `QUEUE_CONN_STR`:**redis://127.0.0.1:6379/0**:任务队列连接字符串,仅在 `QUEUE_TYPE` 为 `redis` 时可用。
- 如果 redis 需要密码,使用 `redis://123@127.0.0.1:6379/0` 或 `redis+cluster://123@127.0.0.1:6379/0`。
-
## 迁移 (`migrations`)
- `MAX_ATTEMPTS`:**3**:每次 http/https 请求的最大尝试次数(用于迁移)。
diff --git a/docs/content/usage/actions/act-runner.en-us.md b/docs/content/usage/actions/act-runner.en-us.md
index b2806bf5dd..942d126919 100644
--- a/docs/content/usage/actions/act-runner.en-us.md
+++ b/docs/content/usage/actions/act-runner.en-us.md
@@ -303,34 +303,3 @@ sudo systemctl enable act_runner --now
```
If using Docker, the `act_runner` user should also be added to the `docker` group before starting the service. Keep in mind that this effectively gives `act_runner` root access to the system [[1]](https://docs.docker.com/engine/security/#docker-daemon-attack-surface).
-
-## Configuration variable
-
-You can create configuration variables on the user, organization and repository level.
-The level of the variable depends on where you created it.
-
-### Naming conventions
-
-The following rules apply to variable names:
-
-- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
-
-- Variable names must not start with the `GITHUB_` and `GITEA_` prefix.
-
-- Variable names must not start with a number.
-
-- Variable names are case-insensitive.
-
-- Variable names must be unique at the level they are created at.
-
-- Variable names must not be `CI`.
-
-### Using variable
-
-After creating configuration variables, they will be automatically filled in the `vars` context.
-They can be accessed through expressions like `{{ vars.VARIABLE_NAME }}` in the workflow.
-
-### Precedence
-
-If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence:
-A repository variable will always be chosen over an organization/user variable.
diff --git a/docs/content/usage/actions/act-runner.zh-cn.md b/docs/content/usage/actions/act-runner.zh-cn.md
index 274b0f0692..e5ebff976d 100644
--- a/docs/content/usage/actions/act-runner.zh-cn.md
+++ b/docs/content/usage/actions/act-runner.zh-cn.md
@@ -258,32 +258,3 @@ Runner的标签用于确定Runner可以运行哪些Job以及如何运行它们
Runner将从Gitea实例获取Job并自动运行它们。
由于Act Runner仍处于开发中,建议定期检查最新版本并进行升级。
-
-## 变量
-
-您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。
-
-### 命名规则
-
-以下规则适用于变量名:
-
-- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。
-
-- 变量名称不能以 `GITHUB_` 和 `GITEA_` 前缀开头。
-
-- 变量名称不能以数字开头。
-
-- 变量名称不区分大小写。
-
-- 变量名称在创建它们的级别上必须是唯一的。
-
-- 变量名称不能为 “CI”。
-
-### 使用
-
-创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `{{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。
-
-### 优先级
-
-如果同名变量存在于多个级别,则级别最低的变量优先。
-仓库级别的变量总是比组织或者用户级别的变量优先被选中。
diff --git a/docs/content/usage/actions/design.en-us.md b/docs/content/usage/actions/design.en-us.md
index 29fa433e59..0d72c19dce 100644
--- a/docs/content/usage/actions/design.en-us.md
+++ b/docs/content/usage/actions/design.en-us.md
@@ -104,7 +104,7 @@ However, if a job container tries to fetch code from localhost, it will fail bec
### Connection 3, act runner to internet
When you use some actions like `actions/checkout@v4`, the act runner downloads the scripts, not the job containers.
-By default, it downloads from [gitea.com](http://gitea.com/), so it requires access to the internet.
+By default, it downloads from [github.com](http://github.com/), so it requires access to the internet. If you configure the `DEFAULT_ACTIONS_URL` to `self`, then it will download from your Gitea instance by default. Then it will not connect to internet when downloading the action itself.
It also downloads some docker images from Docker Hub by default, which also requires internet access.
However, internet access is not strictly necessary.
diff --git a/docs/content/usage/actions/design.zh-cn.md b/docs/content/usage/actions/design.zh-cn.md
index 8add1cf7c5..f48576477f 100644
--- a/docs/content/usage/actions/design.zh-cn.md
+++ b/docs/content/usage/actions/design.zh-cn.md
@@ -105,7 +105,8 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来
### 连接 3,act runner到互联网
当您使用诸如 `actions/checkout@v4` 的一些Actions时,act runner下载的是脚本,而不是Job容器。
-默认情况下,它从[gitea.com](http://gitea.com/)下载,因此需要访问互联网。
+默认情况下,它从[github.com](http://github.com/)下载,因此需要访问互联网。如果您设置的是 self,
+那么默认将从您的当前Gitea实例下载,那么此步骤不需要连接到互联网。
它还默认从Docker Hub下载一些Docker镜像,这也需要互联网访问。
然而,互联网访问并不是绝对必需的。
diff --git a/docs/content/usage/actions/variables.en-us.md b/docs/content/usage/actions/variables.en-us.md
new file mode 100644
index 0000000000..dee2e74234
--- /dev/null
+++ b/docs/content/usage/actions/variables.en-us.md
@@ -0,0 +1,41 @@
+---
+date: "2024-04-10T22:21:00+08:00"
+title: "Variables"
+slug: "actions-variables"
+sidebar_position: 25
+draft: false
+toc: false
+menu:
+ sidebar:
+ parent: "actions"
+ name: "Variables"
+ sidebar_position: 25
+ identifier: "actions-variables"
+---
+
+## Variables
+
+You can create configuration variables on the user, organization and repository level.
+The level of the variable depends on where you created it. When creating a variable, the
+key will be converted to uppercase. You need use uppercase on the yaml file.
+
+### Naming conventions
+
+The following rules apply to variable names:
+
+- Variable names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
+- Variable names must not start with the `GITHUB_` and `GITEA_` prefix.
+- Variable names must not start with a number.
+- Variable names are case-insensitive.
+- Variable names must be unique at the level they are created at.
+- Variable names must not be `CI`.
+
+### Using variable
+
+After creating configuration variables, they will be automatically filled in the `vars` context.
+They can be accessed through expressions like `${{ vars.VARIABLE_NAME }}` in the workflow.
+
+### Precedence
+
+If a variable with the same name exists at multiple levels, the variable at the lowest level takes precedence:
+A repository variable will always be chosen over an organization/user variable.
diff --git a/docs/content/usage/actions/variables.zh-cn.md b/docs/content/usage/actions/variables.zh-cn.md
new file mode 100644
index 0000000000..77643408a1
--- /dev/null
+++ b/docs/content/usage/actions/variables.zh-cn.md
@@ -0,0 +1,39 @@
+---
+date: "2024-04-10T22:21:00+08:00"
+title: "变量"
+slug: "actions-variables"
+sidebar_position: 25
+draft: false
+toc: false
+menu:
+ sidebar:
+ parent: "actions"
+ name: "变量"
+ sidebar_position: 25
+ identifier: "actions-variables"
+---
+
+## 变量
+
+您可以创建用户、组织和仓库级别的变量。变量的级别取决于创建它的位置。当创建变量时,变量的名称会被
+转换为大写,在yaml文件中引用时需要使用大写。
+
+### 命名规则
+
+以下规则适用于变量名:
+
+- 变量名称只能包含字母数字字符 (`[a-z]`, `[A-Z]`, `[0-9]`) 或下划线 (`_`)。不允许使用空格。
+- 变量名称不能以 `GITHUB_` 和 `GITEA_` 前缀开头。
+- 变量名称不能以数字开头。
+- 变量名称不区分大小写。
+- 变量名称在创建它们的级别上必须是唯一的。
+- 变量名称不能为 `CI`。
+
+### 使用
+
+创建配置变量后,它们将自动填充到 `vars` 上下文中。您可以在工作流中使用类似 `${{ vars.VARIABLE_NAME }}` 这样的表达式来使用它们。
+
+### 优先级
+
+如果同名变量存在于多个级别,则级别最低的变量优先。
+仓库级别的变量总是比组织或者用户级别的变量优先被选中。
diff --git a/go.mod b/go.mod
index b76eb74876..1e0f1ea8f8 100644
--- a/go.mod
+++ b/go.mod
@@ -24,7 +24,6 @@ require (
github.com/buildkite/terminal-to-html/v3 v3.11.0
github.com/caddyserver/certmagic v0.20.0
github.com/chi-middleware/proxy v1.1.1
- github.com/denisenkom/go-mssqldb v0.12.3
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
github.com/djherbis/buffer v1.2.0
github.com/djherbis/nio/v3 v3.0.1
@@ -77,6 +76,7 @@ require (
github.com/meilisearch/meilisearch-go v0.26.2
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
+ github.com/microsoft/go-mssqldb v1.7.0
github.com/minio/minio-go/v7 v7.0.69
github.com/msteinert/pam v1.2.0
github.com/nektos/act v0.2.52
@@ -105,11 +105,11 @@ require (
github.com/yuin/goldmark v1.7.0
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
github.com/yuin/goldmark-meta v1.1.0
- golang.org/x/crypto v0.21.0
+ golang.org/x/crypto v0.22.0
golang.org/x/image v0.15.0
- golang.org/x/net v0.22.0
+ golang.org/x/net v0.24.0
golang.org/x/oauth2 v0.18.0
- golang.org/x/sys v0.18.0
+ golang.org/x/sys v0.19.0
golang.org/x/text v0.14.0
golang.org/x/tools v0.19.0
google.golang.org/grpc v1.62.1
diff --git a/go.sum b/go.sum
index d82110177c..864bed6677 100644
--- a/go.sum
+++ b/go.sum
@@ -38,11 +38,20 @@ github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU=
github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U=
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
-github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ClickHouse/ch-go v0.61.5 h1:zwR8QbYI0tsMiEcze/uIMK+Tz1D3XZXLdNrlaOpeEI4=
github.com/ClickHouse/ch-go v0.61.5/go.mod h1:s1LJW/F/LcFs5HJnuogFMta50kKDO0lf9zzfrbl0RQg=
@@ -220,7 +229,6 @@ github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55k
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
-github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
@@ -355,7 +363,6 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
-github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@@ -513,6 +520,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
@@ -551,6 +560,8 @@ github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Cl
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
+github.com/microsoft/go-mssqldb v1.7.0 h1:sgMPW0HA6Ihd37Yx0MzHyKD726C2kY/8KJsQtXHNaAs=
+github.com/microsoft/go-mssqldb v1.7.0/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
@@ -574,7 +585,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 h1:j2kD3MT1z4PXCiUllUJF9mWUESr9TWKS7iEKsQ/IipM=
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM=
@@ -627,7 +637,8 @@ github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
-github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -836,7 +847,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@@ -846,8 +856,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
+golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
@@ -871,7 +881,6 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -881,8 +890,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
+golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -932,8 +941,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -943,8 +952,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -1022,7 +1031,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
diff --git a/models/actions/run_job_list.go b/models/actions/run_job_list.go
index 6ea6cb9d3b..6c5d3b3252 100644
--- a/models/actions/run_job_list.go
+++ b/models/actions/run_job_list.go
@@ -16,14 +16,9 @@ import (
type ActionJobList []*ActionRunJob
func (jobs ActionJobList) GetRunIDs() []int64 {
- ids := make(container.Set[int64], len(jobs))
- for _, j := range jobs {
- if j.RunID == 0 {
- continue
- }
- ids.Add(j.RunID)
- }
- return ids.Values()
+ return container.FilterSlice(jobs, func(j *ActionRunJob) (int64, bool) {
+ return j.RunID, j.RunID != 0
+ })
}
func (jobs ActionJobList) LoadRuns(ctx context.Context, withRepo bool) error {
diff --git a/models/actions/run_list.go b/models/actions/run_list.go
index 388bfc4f86..4046c7d369 100644
--- a/models/actions/run_list.go
+++ b/models/actions/run_list.go
@@ -19,19 +19,15 @@ type RunList []*ActionRun
// GetUserIDs returns a slice of user's id
func (runs RunList) GetUserIDs() []int64 {
- ids := make(container.Set[int64], len(runs))
- for _, run := range runs {
- ids.Add(run.TriggerUserID)
- }
- return ids.Values()
+ return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) {
+ return run.TriggerUserID, true
+ })
}
func (runs RunList) GetRepoIDs() []int64 {
- ids := make(container.Set[int64], len(runs))
- for _, run := range runs {
- ids.Add(run.RepoID)
- }
- return ids.Values()
+ return container.FilterSlice(runs, func(run *ActionRun) (int64, bool) {
+ return run.RepoID, true
+ })
}
func (runs RunList) LoadTriggerUser(ctx context.Context) error {
diff --git a/models/actions/runner_list.go b/models/actions/runner_list.go
index 87f0886b47..3ef8ebb254 100644
--- a/models/actions/runner_list.go
+++ b/models/actions/runner_list.go
@@ -16,14 +16,9 @@ type RunnerList []*ActionRunner
// GetUserIDs returns a slice of user's id
func (runners RunnerList) GetUserIDs() []int64 {
- ids := make(container.Set[int64], len(runners))
- for _, runner := range runners {
- if runner.OwnerID == 0 {
- continue
- }
- ids.Add(runner.OwnerID)
- }
- return ids.Values()
+ return container.FilterSlice(runners, func(runner *ActionRunner) (int64, bool) {
+ return runner.OwnerID, runner.OwnerID != 0
+ })
}
func (runners RunnerList) LoadOwners(ctx context.Context) error {
@@ -41,16 +36,9 @@ func (runners RunnerList) LoadOwners(ctx context.Context) error {
}
func (runners RunnerList) getRepoIDs() []int64 {
- repoIDs := make(container.Set[int64], len(runners))
- for _, runner := range runners {
- if runner.RepoID == 0 {
- continue
- }
- if _, ok := repoIDs[runner.RepoID]; !ok {
- repoIDs[runner.RepoID] = struct{}{}
- }
- }
- return repoIDs.Values()
+ return container.FilterSlice(runners, func(runner *ActionRunner) (int64, bool) {
+ return runner.RepoID, runner.RepoID > 0
+ })
}
func (runners RunnerList) LoadRepos(ctx context.Context) error {
diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go
index b806550b87..5361b94801 100644
--- a/models/actions/schedule_list.go
+++ b/models/actions/schedule_list.go
@@ -18,19 +18,15 @@ type ScheduleList []*ActionSchedule
// GetUserIDs returns a slice of user's id
func (schedules ScheduleList) GetUserIDs() []int64 {
- ids := make(container.Set[int64], len(schedules))
- for _, schedule := range schedules {
- ids.Add(schedule.TriggerUserID)
- }
- return ids.Values()
+ return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) {
+ return schedule.TriggerUserID, true
+ })
}
func (schedules ScheduleList) GetRepoIDs() []int64 {
- ids := make(container.Set[int64], len(schedules))
- for _, schedule := range schedules {
- ids.Add(schedule.RepoID)
- }
- return ids.Values()
+ return container.FilterSlice(schedules, func(schedule *ActionSchedule) (int64, bool) {
+ return schedule.RepoID, true
+ })
}
func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
@@ -44,6 +40,9 @@ func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
schedule.TriggerUser = user_model.NewActionsUser()
} else {
schedule.TriggerUser = users[schedule.TriggerUserID]
+ if schedule.TriggerUser == nil {
+ schedule.TriggerUser = user_model.NewGhostUser()
+ }
}
}
return nil
diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go
index e9ae268a6e..f7dac72f8b 100644
--- a/models/actions/schedule_spec_list.go
+++ b/models/actions/schedule_spec_list.go
@@ -16,11 +16,9 @@ import (
type SpecList []*ActionScheduleSpec
func (specs SpecList) GetScheduleIDs() []int64 {
- ids := make(container.Set[int64], len(specs))
- for _, spec := range specs {
- ids.Add(spec.ScheduleID)
- }
- return ids.Values()
+ return container.FilterSlice(specs, func(spec *ActionScheduleSpec) (int64, bool) {
+ return spec.ScheduleID, true
+ })
}
func (specs SpecList) LoadSchedules(ctx context.Context) error {
@@ -46,11 +44,9 @@ func (specs SpecList) LoadSchedules(ctx context.Context) error {
}
func (specs SpecList) GetRepoIDs() []int64 {
- ids := make(container.Set[int64], len(specs))
- for _, spec := range specs {
- ids.Add(spec.RepoID)
- }
- return ids.Values()
+ return container.FilterSlice(specs, func(spec *ActionScheduleSpec) (int64, bool) {
+ return spec.RepoID, true
+ })
}
func (specs SpecList) LoadRepos(ctx context.Context) error {
diff --git a/models/actions/task.go b/models/actions/task.go
index 96a6d2e80c..9946cf5233 100644
--- a/models/actions/task.go
+++ b/models/actions/task.go
@@ -11,6 +11,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -227,7 +228,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
if runner.RepoID != 0 {
jobCond = builder.Eq{"repo_id": runner.RepoID}
} else if runner.OwnerID != 0 {
- jobCond = builder.In("repo_id", builder.Select("id").From("repository").Where(builder.Eq{"owner_id": runner.OwnerID}))
+ jobCond = builder.In("repo_id", builder.Select("`repository`.id").From("repository").
+ Join("INNER", "repo_unit", "`repository`.id = `repo_unit`.repo_id").
+ Where(builder.Eq{"`repository`.owner_id": runner.OwnerID, "`repo_unit`.type": unit.TypeActions}))
}
if jobCond.IsValid() {
jobCond = builder.In("run_id", builder.Select("id").From("action_run").Where(jobCond))
diff --git a/models/actions/task_list.go b/models/actions/task_list.go
index b07d00b8db..5e17f91441 100644
--- a/models/actions/task_list.go
+++ b/models/actions/task_list.go
@@ -16,14 +16,9 @@ import (
type TaskList []*ActionTask
func (tasks TaskList) GetJobIDs() []int64 {
- ids := make(container.Set[int64], len(tasks))
- for _, t := range tasks {
- if t.JobID == 0 {
- continue
- }
- ids.Add(t.JobID)
- }
- return ids.Values()
+ return container.FilterSlice(tasks, func(t *ActionTask) (int64, bool) {
+ return t.JobID, t.JobID != 0
+ })
}
func (tasks TaskList) LoadJobs(ctx context.Context) error {
diff --git a/models/activities/action_list.go b/models/activities/action_list.go
index fdf0f35d4f..aafb7f8a26 100644
--- a/models/activities/action_list.go
+++ b/models/activities/action_list.go
@@ -22,11 +22,9 @@ import (
type ActionList []*Action
func (actions ActionList) getUserIDs() []int64 {
- userIDs := make(container.Set[int64], len(actions))
- for _, action := range actions {
- userIDs.Add(action.ActUserID)
- }
- return userIDs.Values()
+ return container.FilterSlice(actions, func(action *Action) (int64, bool) {
+ return action.ActUserID, true
+ })
}
func (actions ActionList) LoadActUsers(ctx context.Context) (map[int64]*user_model.User, error) {
@@ -50,11 +48,9 @@ func (actions ActionList) LoadActUsers(ctx context.Context) (map[int64]*user_mod
}
func (actions ActionList) getRepoIDs() []int64 {
- repoIDs := make(container.Set[int64], len(actions))
- for _, action := range actions {
- repoIDs.Add(action.RepoID)
- }
- return repoIDs.Values()
+ return container.FilterSlice(actions, func(action *Action) (int64, bool) {
+ return action.RepoID, true
+ })
}
func (actions ActionList) LoadRepositories(ctx context.Context) error {
@@ -80,18 +76,19 @@ func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]*
userMap = make(map[int64]*user_model.User)
}
- userSet := make(container.Set[int64], len(actions))
- for _, action := range actions {
+ missingUserIDs := container.FilterSlice(actions, func(action *Action) (int64, bool) {
if action.Repo == nil {
- continue
- }
- if _, ok := userMap[action.Repo.OwnerID]; !ok {
- userSet.Add(action.Repo.OwnerID)
+ return 0, false
}
+ _, alreadyLoaded := userMap[action.Repo.OwnerID]
+ return action.Repo.OwnerID, !alreadyLoaded
+ })
+ if len(missingUserIDs) == 0 {
+ return nil
}
if err := db.GetEngine(ctx).
- In("id", userSet.Values()).
+ In("id", missingUserIDs).
Find(&userMap); err != nil {
return fmt.Errorf("find user: %w", err)
}
@@ -135,6 +132,9 @@ func (actions ActionList) LoadComments(ctx context.Context) error {
commentIDs = append(commentIDs, action.CommentID)
}
}
+ if len(commentIDs) == 0 {
+ return nil
+ }
commentsMap := make(map[int64]*issues_model.Comment, len(commentIDs))
if err := db.GetEngine(ctx).In("id", commentIDs).Find(&commentsMap); err != nil {
diff --git a/models/activities/notification_list.go b/models/activities/notification_list.go
index 5858933391..0cbb91df3c 100644
--- a/models/activities/notification_list.go
+++ b/models/activities/notification_list.go
@@ -190,14 +190,12 @@ func (nl NotificationList) LoadAttributes(ctx context.Context) error {
}
func (nl NotificationList) getPendingRepoIDs() []int64 {
- ids := make(container.Set[int64], len(nl))
- for _, notification := range nl {
- if notification.Repository != nil {
- continue
+ return container.FilterSlice(nl, func(n *Notification) (int64, bool) {
+ if n.Repository != nil {
+ return 0, false
}
- ids.Add(notification.RepoID)
- }
- return ids.Values()
+ return n.RepoID, true
+ })
}
// LoadRepos loads repositories from database
diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go
index b9cfb1b251..1ed3b5df2a 100644
--- a/models/asymkey/ssh_key_fingerprint.go
+++ b/models/asymkey/ssh_key_fingerprint.go
@@ -76,23 +76,14 @@ func calcFingerprintNative(publicKeyContent string) (string, error) {
// CalcFingerprint calculate public key's fingerprint
func CalcFingerprint(publicKeyContent string) (string, error) {
// Call the method based on configuration
- var (
- fnName, fp string
- err error
- )
- if len(setting.SSH.KeygenPath) == 0 {
- fnName = "calcFingerprintNative"
- fp, err = calcFingerprintNative(publicKeyContent)
- } else {
- fnName = "calcFingerprintSSHKeygen"
- fp, err = calcFingerprintSSHKeygen(publicKeyContent)
- }
+ useNative := setting.SSH.KeygenPath == ""
+ calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen)
+ fp, err := calcFn(publicKeyContent)
if err != nil {
if IsErrKeyUnableVerify(err) {
- log.Info("%s", publicKeyContent)
return "", err
}
- return "", fmt.Errorf("%s: %w", fnName, err)
+ return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err)
}
return fp, nil
}
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index 9d53fffc78..bc1bcaef63 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -137,6 +137,11 @@ func (app *OAuth2Application) TableName() string {
// ContainsRedirectURI checks if redirectURI is allowed for app
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
+ // OAuth2 requires the redirect URI to be an exact match, no dynamic parts are allowed.
+ // https://stackoverflow.com/questions/55524480/should-dynamic-query-parameters-be-present-in-the-redirection-uri-for-an-oauth2
+ // https://www.rfc-editor.org/rfc/rfc6819#section-5.2.3.3
+ // https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
+ // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-12#section-3.1
contains := func(s string) bool {
s = strings.TrimSuffix(strings.ToLower(s), "/")
for _, u := range app.RedirectURIs {
diff --git a/models/db/consistency.go b/models/db/consistency.go
index d19732cf80..d0b0ab8315 100644
--- a/models/db/consistency.go
+++ b/models/db/consistency.go
@@ -10,21 +10,21 @@ import (
)
// CountOrphanedObjects count subjects with have no existing refobject anymore
-func CountOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) (int64, error) {
+func CountOrphanedObjects(ctx context.Context, subject, refObject, joinCond string) (int64, error) {
return GetEngine(ctx).
Table("`"+subject+"`").
- Join("LEFT", "`"+refobject+"`", joinCond).
- Where(builder.IsNull{"`" + refobject + "`.id"}).
+ Join("LEFT", "`"+refObject+"`", joinCond).
+ Where(builder.IsNull{"`" + refObject + "`.id"}).
Select("COUNT(`" + subject + "`.`id`)").
Count()
}
// DeleteOrphanedObjects delete subjects with have no existing refobject anymore
-func DeleteOrphanedObjects(ctx context.Context, subject, refobject, joinCond string) error {
+func DeleteOrphanedObjects(ctx context.Context, subject, refObject, joinCond string) error {
subQuery := builder.Select("`"+subject+"`.id").
From("`"+subject+"`").
- Join("LEFT", "`"+refobject+"`", joinCond).
- Where(builder.IsNull{"`" + refobject + "`.id"})
+ Join("LEFT", "`"+refObject+"`", joinCond).
+ Where(builder.IsNull{"`" + refObject + "`.id"})
b := builder.Delete(builder.In("id", subQuery)).From("`" + subject + "`")
_, err := GetEngine(ctx).Exec(b)
return err
diff --git a/models/db/engine.go b/models/db/engine.go
index 2a2743e927..26abf0b96c 100755
--- a/models/db/engine.go
+++ b/models/db/engine.go
@@ -21,9 +21,9 @@ import (
"xorm.io/xorm/names"
"xorm.io/xorm/schemas"
- _ "github.com/denisenkom/go-mssqldb" // Needed for the MSSQL driver
- _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver
- _ "github.com/lib/pq" // Needed for the Postgresql driver
+ _ "github.com/go-sql-driver/mysql" // Needed for the MySQL driver
+ _ "github.com/lib/pq" // Needed for the Postgresql driver
+ _ "github.com/microsoft/go-mssqldb" // Needed for the MSSQL driver
)
var (
@@ -284,8 +284,8 @@ func MaxBatchInsertSize(bean any) int {
}
// IsTableNotEmpty returns true if table has at least one record
-func IsTableNotEmpty(tableName string) (bool, error) {
- return x.Table(tableName).Exist()
+func IsTableNotEmpty(beanOrTableName any) (bool, error) {
+ return x.Table(beanOrTableName).Exist()
}
// DeleteAllRecords will delete all the records of this table
diff --git a/models/git/branch.go b/models/git/branch.go
index fa0781fed1..2979dff3d2 100644
--- a/models/git/branch.go
+++ b/models/git/branch.go
@@ -297,6 +297,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
sess := db.GetEngine(ctx)
+ // check whether from branch exist
var branch Branch
exist, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, from).Get(&branch)
if err != nil {
@@ -308,6 +309,24 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
}
}
+ // check whether to branch exist or is_deleted
+ var dstBranch Branch
+ exist, err = db.GetEngine(ctx).Where("repo_id=? AND name=?", repo.ID, to).Get(&dstBranch)
+ if err != nil {
+ return err
+ }
+ if exist {
+ if !dstBranch.IsDeleted {
+ return ErrBranchAlreadyExists{
+ BranchName: to,
+ }
+ }
+
+ if _, err := db.GetEngine(ctx).ID(dstBranch.ID).NoAutoCondition().Delete(&dstBranch); err != nil {
+ return err
+ }
+ }
+
// 1. update branch in database
if n, err := sess.Where("repo_id=? AND name=?", repo.ID, from).Update(&Branch{
Name: to,
@@ -362,12 +381,7 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
- // 5. do git action
- if err = gitAction(ctx, isDefault); err != nil {
- return err
- }
-
- // 6. insert renamed branch record
+ // 5. insert renamed branch record
renamedBranch := &RenamedBranch{
RepoID: repo.ID,
From: from,
@@ -378,6 +392,11 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, from, to str
return err
}
+ // 6. do git action
+ if err = gitAction(ctx, isDefault); err != nil {
+ return err
+ }
+
return committer.Commit()
}
diff --git a/models/git/branch_list.go b/models/git/branch_list.go
index 8319e5ecd0..980bd7b4c9 100644
--- a/models/git/branch_list.go
+++ b/models/git/branch_list.go
@@ -17,15 +17,12 @@ import (
type BranchList []*Branch
func (branches BranchList) LoadDeletedBy(ctx context.Context) error {
- ids := container.Set[int64]{}
- for _, branch := range branches {
- if !branch.IsDeleted {
- continue
- }
- ids.Add(branch.DeletedByID)
- }
+ ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) {
+ return branch.DeletedByID, branch.IsDeleted
+ })
+
usersMap := make(map[int64]*user_model.User, len(ids))
- if err := db.GetEngine(ctx).In("id", ids.Values()).Find(&usersMap); err != nil {
+ if err := db.GetEngine(ctx).In("id", ids).Find(&usersMap); err != nil {
return err
}
for _, branch := range branches {
@@ -41,14 +38,13 @@ func (branches BranchList) LoadDeletedBy(ctx context.Context) error {
}
func (branches BranchList) LoadPusher(ctx context.Context) error {
- ids := container.Set[int64]{}
- for _, branch := range branches {
- if branch.PusherID > 0 { // pusher_id maybe zero because some branches are sync by backend with no pusher
- ids.Add(branch.PusherID)
- }
- }
+ ids := container.FilterSlice(branches, func(branch *Branch) (int64, bool) {
+ // pusher_id maybe zero because some branches are sync by backend with no pusher
+ return branch.PusherID, branch.PusherID > 0
+ })
+
usersMap := make(map[int64]*user_model.User, len(ids))
- if err := db.GetEngine(ctx).In("id", ids.Values()).Find(&usersMap); err != nil {
+ if err := db.GetEngine(ctx).In("id", ids).Find(&usersMap); err != nil {
return err
}
for _, branch := range branches {
diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index bb75dcca26..c3cda7b73d 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -292,30 +292,27 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
}
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
-func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
+func GetLatestCommitStatusForPairs(ctx context.Context, repoSHAs []RepoSHA) (map[int64][]*CommitStatus, error) {
type result struct {
Index int64
RepoID int64
+ SHA string
}
- results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
+ results := make([]result, 0, len(repoSHAs))
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{})
}
// Create a disjunction of conditions for each repoID and SHA pair
- conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
- for repoID, sha := range repoIDsToLatestCommitSHAs {
- conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
+ conds := make([]builder.Cond, 0, len(repoSHAs))
+ for _, repoSHA := range repoSHAs {
+ conds = append(conds, builder.Eq{"repo_id": repoSHA.RepoID, "sha": repoSHA.SHA})
}
sess := getBase().Where(builder.Or(conds...)).
- Select("max( `index` ) as `index`, repo_id").
- GroupBy("context_hash, repo_id").OrderBy("max( `index` ) desc")
-
- if !listOptions.IsListAll() {
- sess = db.SetSessionPagination(sess, &listOptions)
- }
+ Select("max( `index` ) as `index`, repo_id, sha").
+ GroupBy("context_hash, repo_id, sha").OrderBy("max( `index` ) desc")
err := sess.Find(&results)
if err != nil {
@@ -332,7 +329,7 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHA
cond := builder.Eq{
"`index`": result.Index,
"repo_id": result.RepoID,
- "sha": repoIDsToLatestCommitSHAs[result.RepoID],
+ "sha": result.SHA,
}
conds = append(conds, cond)
}
diff --git a/models/git/commit_status_summary.go b/models/git/commit_status_summary.go
new file mode 100644
index 0000000000..7603e7aa65
--- /dev/null
+++ b/models/git/commit_status_summary.go
@@ -0,0 +1,88 @@
+// Copyright 2024 Gitea. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+ "context"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/setting"
+ api "code.gitea.io/gitea/modules/structs"
+
+ "xorm.io/builder"
+)
+
+// CommitStatusSummary holds the latest commit Status of a single Commit
+type CommitStatusSummary struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"`
+ SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"`
+ State api.CommitStatusState `xorm:"VARCHAR(7) NOT NULL"`
+ TargetURL string `xorm:"TEXT"`
+}
+
+func init() {
+ db.RegisterModel(new(CommitStatusSummary))
+}
+
+type RepoSHA struct {
+ RepoID int64
+ SHA string
+}
+
+func GetLatestCommitStatusForRepoAndSHAs(ctx context.Context, repoSHAs []RepoSHA) ([]*CommitStatus, error) {
+ cond := builder.NewCond()
+ for _, rs := range repoSHAs {
+ cond = cond.Or(builder.Eq{"repo_id": rs.RepoID, "sha": rs.SHA})
+ }
+
+ var summaries []CommitStatusSummary
+ if err := db.GetEngine(ctx).Where(cond).Find(&summaries); err != nil {
+ return nil, err
+ }
+
+ commitStatuses := make([]*CommitStatus, 0, len(repoSHAs))
+ for _, summary := range summaries {
+ commitStatuses = append(commitStatuses, &CommitStatus{
+ RepoID: summary.RepoID,
+ SHA: summary.SHA,
+ State: summary.State,
+ TargetURL: summary.TargetURL,
+ })
+ }
+ return commitStatuses, nil
+}
+
+func UpdateCommitStatusSummary(ctx context.Context, repoID int64, sha string) error {
+ commitStatuses, _, err := GetLatestCommitStatus(ctx, repoID, sha, db.ListOptionsAll)
+ if err != nil {
+ return err
+ }
+ state := CalcCommitStatus(commitStatuses)
+ // mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database,
+ // so we need to use insert in on duplicate
+ if setting.Database.Type.IsMySQL() {
+ _, err := db.GetEngine(ctx).Exec("INSERT INTO commit_status_summary (repo_id,sha,state,target_url) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE state=?",
+ repoID, sha, state.State, state.TargetURL, state.State)
+ return err
+ }
+
+ if cnt, err := db.GetEngine(ctx).Where("repo_id=? AND sha=?", repoID, sha).
+ Cols("state, target_url").
+ Update(&CommitStatusSummary{
+ State: state.State,
+ TargetURL: state.TargetURL,
+ }); err != nil {
+ return err
+ } else if cnt == 0 {
+ _, err = db.GetEngine(ctx).Insert(&CommitStatusSummary{
+ RepoID: repoID,
+ SHA: sha,
+ State: state.State,
+ TargetURL: state.TargetURL,
+ })
+ return err
+ }
+ return nil
+}
diff --git a/models/issues/comment.go b/models/issues/comment.go
index 6f65a5dbbc..353163ebd6 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -1272,10 +1272,9 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error {
return nil
}
- issueIDs := make(container.Set[int64])
- for _, comment := range comments {
- issueIDs.Add(comment.IssueID)
- }
+ issueIDs := container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.IssueID, true
+ })
ctx, committer, err := db.TxContext(ctx)
if err != nil {
@@ -1298,7 +1297,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error {
}
}
- for issueID := range issueIDs {
+ for _, issueID := range issueIDs {
if _, err := db.Exec(ctx, "UPDATE issue set num_comments = (SELECT count(*) FROM comment WHERE issue_id = ? AND `type`=?) WHERE id = ?",
issueID, CommentTypeComment, issueID); err != nil {
return err
diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go
index 0047b054ba..370b5396e0 100644
--- a/models/issues/comment_list.go
+++ b/models/issues/comment_list.go
@@ -17,13 +17,9 @@ import (
type CommentList []*Comment
func (comments CommentList) getPosterIDs() []int64 {
- posterIDs := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.PosterID > 0 {
- posterIDs.Add(comment.PosterID)
- }
- }
- return posterIDs.Values()
+ return container.FilterSlice(comments, func(c *Comment) (int64, bool) {
+ return c.PosterID, c.PosterID > 0
+ })
}
// LoadPosters loads posters
@@ -44,13 +40,9 @@ func (comments CommentList) LoadPosters(ctx context.Context) error {
}
func (comments CommentList) getLabelIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.LabelID > 0 {
- ids.Add(comment.LabelID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.LabelID, comment.LabelID > 0
+ })
}
func (comments CommentList) loadLabels(ctx context.Context) error {
@@ -94,13 +86,9 @@ func (comments CommentList) loadLabels(ctx context.Context) error {
}
func (comments CommentList) getMilestoneIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.MilestoneID > 0 {
- ids.Add(comment.MilestoneID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.MilestoneID, comment.MilestoneID > 0
+ })
}
func (comments CommentList) loadMilestones(ctx context.Context) error {
@@ -137,13 +125,9 @@ func (comments CommentList) loadMilestones(ctx context.Context) error {
}
func (comments CommentList) getOldMilestoneIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.OldMilestoneID > 0 {
- ids.Add(comment.OldMilestoneID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.OldMilestoneID, comment.OldMilestoneID > 0
+ })
}
func (comments CommentList) loadOldMilestones(ctx context.Context) error {
@@ -180,13 +164,9 @@ func (comments CommentList) loadOldMilestones(ctx context.Context) error {
}
func (comments CommentList) getAssigneeIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.AssigneeID > 0 {
- ids.Add(comment.AssigneeID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.AssigneeID, comment.AssigneeID > 0
+ })
}
func (comments CommentList) loadAssignees(ctx context.Context) error {
@@ -237,14 +217,9 @@ func (comments CommentList) loadAssignees(ctx context.Context) error {
// getIssueIDs returns all the issue ids on this comment list which issue hasn't been loaded
func (comments CommentList) getIssueIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.Issue != nil {
- continue
- }
- ids.Add(comment.IssueID)
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.IssueID, comment.Issue == nil
+ })
}
// Issues returns all the issues of comments
@@ -311,16 +286,12 @@ func (comments CommentList) LoadIssues(ctx context.Context) error {
}
func (comments CommentList) getDependentIssueIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
if comment.DependentIssue != nil {
- continue
+ return 0, false
}
- if comment.DependentIssueID > 0 {
- ids.Add(comment.DependentIssueID)
- }
- }
- return ids.Values()
+ return comment.DependentIssueID, comment.DependentIssueID > 0
+ })
}
func (comments CommentList) loadDependentIssues(ctx context.Context) error {
@@ -375,15 +346,9 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error {
// getAttachmentCommentIDs only return the comment ids which possibly has attachments
func (comments CommentList) getAttachmentCommentIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.Type == CommentTypeComment ||
- comment.Type == CommentTypeReview ||
- comment.Type == CommentTypeCode {
- ids.Add(comment.ID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.ID, comment.Type.HasAttachmentSupport()
+ })
}
// LoadAttachmentsByIssue loads attachments by issue id
@@ -451,13 +416,9 @@ func (comments CommentList) LoadAttachments(ctx context.Context) (err error) {
}
func (comments CommentList) getReviewIDs() []int64 {
- ids := make(container.Set[int64], len(comments))
- for _, comment := range comments {
- if comment.ReviewID > 0 {
- ids.Add(comment.ReviewID)
- }
- }
- return ids.Values()
+ return container.FilterSlice(comments, func(comment *Comment) (int64, bool) {
+ return comment.ReviewID, comment.ReviewID > 0
+ })
}
func (comments CommentList) loadReviews(ctx context.Context) error {
diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go
index 218891ad35..f8ee271a6b 100644
--- a/models/issues/issue_list.go
+++ b/models/issues/issue_list.go
@@ -21,16 +21,15 @@ type IssueList []*Issue
// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo
func (issues IssueList) getRepoIDs() []int64 {
- repoIDs := make(container.Set[int64], len(issues))
- for _, issue := range issues {
+ return container.FilterSlice(issues, func(issue *Issue) (int64, bool) {
if issue.Repo == nil {
- repoIDs.Add(issue.RepoID)
+ return issue.RepoID, true
}
if issue.PullRequest != nil && issue.PullRequest.HeadRepo == nil {
- repoIDs.Add(issue.PullRequest.HeadRepoID)
+ return issue.PullRequest.HeadRepoID, true
}
- }
- return repoIDs.Values()
+ return 0, false
+ })
}
// LoadRepositories loads issues' all repositories
@@ -74,11 +73,9 @@ func (issues IssueList) LoadRepositories(ctx context.Context) (repo_model.Reposi
}
func (issues IssueList) getPosterIDs() []int64 {
- posterIDs := make(container.Set[int64], len(issues))
- for _, issue := range issues {
- posterIDs.Add(issue.PosterID)
- }
- return posterIDs.Values()
+ return container.FilterSlice(issues, func(issue *Issue) (int64, bool) {
+ return issue.PosterID, true
+ })
}
func (issues IssueList) loadPosters(ctx context.Context) error {
@@ -193,11 +190,9 @@ func (issues IssueList) loadLabels(ctx context.Context) error {
}
func (issues IssueList) getMilestoneIDs() []int64 {
- ids := make(container.Set[int64], len(issues))
- for _, issue := range issues {
- ids.Add(issue.MilestoneID)
- }
- return ids.Values()
+ return container.FilterSlice(issues, func(issue *Issue) (int64, bool) {
+ return issue.MilestoneID, true
+ })
}
func (issues IssueList) loadMilestones(ctx context.Context) error {
diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go
index de3eceed37..b5557cad06 100644
--- a/models/issues/pull_list.go
+++ b/models/issues/pull_list.go
@@ -62,11 +62,13 @@ func CanMaintainerWriteToBranch(ctx context.Context, p access_model.Permission,
return true
}
- if len(p.Units) < 1 {
+ // the code below depends on units to get the repository ID, not ideal but just keep it for now
+ firstUnitRepoID := p.GetFirstUnitRepoID()
+ if firstUnitRepoID == 0 {
return false
}
- prs, err := GetUnmergedPullRequestsByHeadInfo(ctx, p.Units[0].RepoID, branch)
+ prs, err := GetUnmergedPullRequestsByHeadInfo(ctx, firstUnitRepoID, branch)
if err != nil {
return false
}
diff --git a/models/issues/reaction.go b/models/issues/reaction.go
index d5448636fe..eb7faefc79 100644
--- a/models/issues/reaction.go
+++ b/models/issues/reaction.go
@@ -305,14 +305,12 @@ func (list ReactionList) GroupByType() map[string]ReactionList {
}
func (list ReactionList) getUserIDs() []int64 {
- userIDs := make(container.Set[int64], len(list))
- for _, reaction := range list {
+ return container.FilterSlice(list, func(reaction *Reaction) (int64, bool) {
if reaction.OriginalAuthor != "" {
- continue
+ return 0, false
}
- userIDs.Add(reaction.UserID)
- }
- return userIDs.Values()
+ return reaction.UserID, true
+ })
}
func valuesUser(m map[int64]*user_model.User) []*user_model.User {
diff --git a/models/issues/review_list.go b/models/issues/review_list.go
index ec6cb07988..7b8c3d319c 100644
--- a/models/issues/review_list.go
+++ b/models/issues/review_list.go
@@ -38,12 +38,11 @@ func (reviews ReviewList) LoadReviewers(ctx context.Context) error {
}
func (reviews ReviewList) LoadIssues(ctx context.Context) error {
- issueIDs := container.Set[int64]{}
- for i := 0; i < len(reviews); i++ {
- issueIDs.Add(reviews[i].IssueID)
- }
+ issueIDs := container.FilterSlice(reviews, func(review *Review) (int64, bool) {
+ return review.IssueID, true
+ })
- issues, err := GetIssuesByIDs(ctx, issueIDs.Values())
+ issues, err := GetIssuesByIDs(ctx, issueIDs)
if err != nil {
return err
}
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 387cd96a53..cb3a64f48c 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -576,7 +576,14 @@ var migrations = []Migration{
// Gitea 1.22.0 ends at 294
+ // v294 -> v295
NewMigration("Add unique index for project issue table", v1_23.AddUniqueIndexForProjectIssue),
+ // v295 -> v296
+ NewMigration("Add commit status summary table", v1_23.AddCommitStatusSummary),
+ // v296 -> v297
+ NewMigration("Add missing field of commit status summary table", v1_23.AddCommitStatusSummary2),
+ // v297 -> v298
+ NewMigration("Add everyone_access_mode for repo_unit", v1_23.AddRepoUnitEveryoneAccessMode),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_11/v111.go b/models/migrations/v1_11/v111.go
index d757acb7d2..1722792a38 100644
--- a/models/migrations/v1_11/v111.go
+++ b/models/migrations/v1_11/v111.go
@@ -336,7 +336,7 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
if err != nil {
return false, err
}
- if perm.UnitsMode == nil {
+ if len(perm.UnitsMode) == 0 {
for _, u := range perm.Units {
if u.Type == UnitTypeCode {
return AccessModeWrite <= perm.AccessMode, nil
diff --git a/models/migrations/v1_23/v295.go b/models/migrations/v1_23/v295.go
new file mode 100644
index 0000000000..9a2003cfc1
--- /dev/null
+++ b/models/migrations/v1_23/v295.go
@@ -0,0 +1,18 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_23 //nolint
+
+import "xorm.io/xorm"
+
+func AddCommitStatusSummary(x *xorm.Engine) error {
+ type CommitStatusSummary struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"INDEX UNIQUE(repo_id_sha)"`
+ SHA string `xorm:"VARCHAR(64) NOT NULL INDEX UNIQUE(repo_id_sha)"`
+ State string `xorm:"VARCHAR(7) NOT NULL"`
+ }
+ // there is no migrations because if there is no data on this table, it will fall back to get data
+ // from commit status
+ return x.Sync2(new(CommitStatusSummary))
+}
diff --git a/models/migrations/v1_23/v296.go b/models/migrations/v1_23/v296.go
new file mode 100644
index 0000000000..495ae2ab23
--- /dev/null
+++ b/models/migrations/v1_23/v296.go
@@ -0,0 +1,16 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_23 //nolint
+
+import "xorm.io/xorm"
+
+func AddCommitStatusSummary2(x *xorm.Engine) error {
+ type CommitStatusSummary struct {
+ ID int64 `xorm:"pk autoincr"`
+ TargetURL string `xorm:"TEXT"`
+ }
+ // there is no migrations because if there is no data on this table, it will fall back to get data
+ // from commit status
+ return x.Sync(new(CommitStatusSummary))
+}
diff --git a/models/migrations/v1_23/v297.go b/models/migrations/v1_23/v297.go
new file mode 100644
index 0000000000..e79f04cf9c
--- /dev/null
+++ b/models/migrations/v1_23/v297.go
@@ -0,0 +1,17 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_23 //nolint
+
+import (
+ "code.gitea.io/gitea/models/perm"
+
+ "xorm.io/xorm"
+)
+
+func AddRepoUnitEveryoneAccessMode(x *xorm.Engine) error {
+ type RepoUnit struct { //revive:disable-line:exported
+ EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
+ }
+ return x.Sync(&RepoUnit{})
+}
diff --git a/models/organization/org.go b/models/organization/org.go
index ba0fd756e3..b33d15d29c 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -9,6 +9,7 @@ import (
"fmt"
"strings"
+ actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
@@ -402,6 +403,8 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
&TeamInvite{OrgID: org.ID},
&secret_model.Secret{OwnerID: org.ID},
&user_model.Blocking{BlockerID: org.ID},
+ &actions_model.ActionRunner{OwnerID: org.ID},
+ &actions_model.ActionRunnerToken{OwnerID: org.ID},
); err != nil {
return fmt.Errorf("DeleteBeans: %w", err)
}
diff --git a/models/organization/team.go b/models/organization/team.go
index 17db11c42d..e4e83fedee 100644
--- a/models/organization/team.go
+++ b/models/organization/team.go
@@ -130,11 +130,11 @@ func (t *Team) GetUnitsMap() map[string]string {
m := make(map[string]string)
if t.AccessMode >= perm.AccessModeAdmin {
for _, u := range unit.Units {
- m[u.NameKey] = t.AccessMode.String()
+ m[u.NameKey] = t.AccessMode.ToString()
}
} else {
for _, u := range t.Units {
- m[u.Unit().NameKey] = u.AccessMode.String()
+ m[u.Unit().NameKey] = u.AccessMode.ToString()
}
}
return m
@@ -174,23 +174,27 @@ func (t *Team) LoadMembers(ctx context.Context) (err error) {
return err
}
-// UnitEnabled returns if the team has the given unit type enabled
+// UnitEnabled returns true if the team has the given unit type enabled
func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool {
return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
}
-// UnitAccessMode returns if the team has the given unit type enabled
+// UnitAccessMode returns the access mode for the given unit type, "none" for non-existent units
func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
+ accessMode, _ := t.UnitAccessModeEx(ctx, tp)
+ return accessMode
+}
+
+func (t *Team) UnitAccessModeEx(ctx context.Context, tp unit.Type) (accessMode perm.AccessMode, exist bool) {
if err := t.LoadUnits(ctx); err != nil {
log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
}
-
- for _, unit := range t.Units {
- if unit.Type == tp {
- return unit.AccessMode
+ for _, u := range t.Units {
+ if u.Type == tp {
+ return u.AccessMode, true
}
}
- return perm.AccessModeNone
+ return perm.AccessModeNone, false
}
// IsUsableTeamName tests if a name could be as team name
diff --git a/models/perm/access/access.go b/models/perm/access/access.go
index b422a08614..6a0a901f71 100644
--- a/models/perm/access/access.go
+++ b/models/perm/access/access.go
@@ -63,13 +63,11 @@ func accessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Re
}
func maxAccessMode(modes ...perm.AccessMode) perm.AccessMode {
- max := perm.AccessModeNone
+ maxMode := perm.AccessModeNone
for _, mode := range modes {
- if mode > max {
- max = mode
- }
+ maxMode = max(maxMode, mode)
}
- return max
+ return maxMode
}
type userAccess struct {
diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go
index 4175cb9b92..9cce95b776 100644
--- a/models/perm/access/repo_permission.go
+++ b/models/perm/access/repo_permission.go
@@ -6,6 +6,7 @@ package access
import (
"context"
"fmt"
+ "slices"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
@@ -14,13 +15,15 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
)
// Permission contains all the permissions related variables to a repository for a user
type Permission struct {
AccessMode perm_model.AccessMode
- Units []*repo_model.RepoUnit
- UnitsMode map[unit.Type]perm_model.AccessMode
+
+ units []*repo_model.RepoUnit
+ unitsMode map[unit.Type]perm_model.AccessMode
}
// IsOwner returns true if current user is the owner of repository.
@@ -33,25 +36,44 @@ func (p *Permission) IsAdmin() bool {
return p.AccessMode >= perm_model.AccessModeAdmin
}
-// HasAccess returns true if the current user has at least read access to any unit of this repository
+// HasAccess returns true if the current user might have at least read access to any unit of this repository
func (p *Permission) HasAccess() bool {
- if p.UnitsMode == nil {
- return p.AccessMode >= perm_model.AccessModeRead
- }
- return len(p.UnitsMode) > 0
+ return len(p.unitsMode) > 0 || p.AccessMode >= perm_model.AccessModeRead
}
-// UnitAccessMode returns current user accessmode to the specify unit of the repository
-func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode {
- if p.UnitsMode == nil {
- for _, u := range p.Units {
- if u.Type == unitType {
- return p.AccessMode
- }
- }
- return perm_model.AccessModeNone
+// HasUnits returns true if the permission contains attached units
+func (p *Permission) HasUnits() bool {
+ return len(p.units) > 0
+}
+
+// GetFirstUnitRepoID returns the repo ID of the first unit, it is a fragile design and should NOT be used anymore
+// deprecated
+func (p *Permission) GetFirstUnitRepoID() int64 {
+ if len(p.units) > 0 {
+ return p.units[0].RepoID
+ }
+ return 0
+}
+
+// UnitAccessMode returns current user access mode to the specify unit of the repository
+func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode {
+ if p.unitsMode != nil {
+ // if the units map contains the access mode, use it, but admin/owner mode could override it
+ if m, ok := p.unitsMode[unitType]; ok {
+ return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m)
+ }
+ }
+ // if the units map does not contain the access mode, return the default access mode if the unit exists
+ hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType })
+ return util.Iif(hasUnit, p.AccessMode, perm_model.AccessModeNone)
+}
+
+func (p *Permission) SetUnitsWithDefaultAccessMode(units []*repo_model.RepoUnit, mode perm_model.AccessMode) {
+ p.units = units
+ p.unitsMode = make(map[unit.Type]perm_model.AccessMode)
+ for _, u := range p.units {
+ p.unitsMode[u.Type] = mode
}
- return p.UnitsMode[unitType]
}
// CanAccess returns true if user has mode access to the unit of the repository
@@ -102,23 +124,33 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool {
return p.CanWrite(unit.TypeIssues)
}
+func (p *Permission) ReadableUnitTypes() []unit.Type {
+ types := make([]unit.Type, 0, len(p.units))
+ for _, u := range p.units {
+ if p.CanRead(u.Type) {
+ types = append(types, u.Type)
+ }
+ }
+ return types
+}
+
func (p *Permission) LogString() string {
format := " 0 {
+ for _, u := range perm.units {
+ if perm.unitsMode == nil {
+ perm.unitsMode = make(map[unit.Type]perm_model.AccessMode)
}
- log.Trace("Permission Loaded for %-v in %-v:\nPermissions: %-+v",
- user,
- repo,
- perm)
- }()
+ if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.unitsMode[u.Type] {
+ perm.unitsMode[u.Type] = u.EveryoneAccessMode
+ }
+ }
}
+}
+
+// GetUserRepoPermission returns the user permissions to the repository
+func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) {
+ defer func() {
+ if err == nil {
+ applyEveryoneRepoPermission(user, &perm)
+ }
+ if log.IsTrace() {
+ log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm)
+ }
+ }()
+
+ if err = repo.LoadUnits(ctx); err != nil {
+ return perm, err
+ }
+ perm.units = repo.Units
// anonymous user visit private repo.
// TODO: anonymous user visit public unit of private repo???
@@ -152,7 +195,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
}
var isCollaborator bool
- var err error
if user != nil {
isCollaborator, err = repo_model.IsCollaborator(ctx, repo.ID, user.ID)
if err != nil {
@@ -160,7 +202,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
}
}
- if err := repo.LoadOwner(ctx); err != nil {
+ if err = repo.LoadOwner(ctx); err != nil {
return perm, err
}
@@ -171,12 +213,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
return perm, nil
}
- if err := repo.LoadUnits(ctx); err != nil {
- return perm, err
- }
-
- perm.Units = repo.Units
-
// anonymous visit public repo
if user == nil {
perm.AccessMode = perm_model.AccessModeRead
@@ -195,19 +231,16 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
return perm, err
}
- if err := repo.LoadOwner(ctx); err != nil {
- return perm, err
- }
if !repo.Owner.IsOrganization() {
return perm, nil
}
- perm.UnitsMode = make(map[unit.Type]perm_model.AccessMode)
+ perm.unitsMode = make(map[unit.Type]perm_model.AccessMode)
// Collaborators on organization
if isCollaborator {
for _, u := range repo.Units {
- perm.UnitsMode[u.Type] = perm.AccessMode
+ perm.unitsMode[u.Type] = perm.AccessMode
}
}
@@ -221,7 +254,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
for _, team := range teams {
if team.AccessMode >= perm_model.AccessModeAdmin {
perm.AccessMode = perm_model.AccessModeOwner
- perm.UnitsMode = nil
+ perm.unitsMode = nil
return perm, nil
}
}
@@ -229,30 +262,26 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
for _, u := range repo.Units {
var found bool
for _, team := range teams {
- teamMode := team.UnitAccessMode(ctx, u.Type)
- if teamMode > perm_model.AccessModeNone {
- m := perm.UnitsMode[u.Type]
- if m < teamMode {
- perm.UnitsMode[u.Type] = teamMode
- }
+ if teamMode, exist := team.UnitAccessModeEx(ctx, u.Type); exist {
+ perm.unitsMode[u.Type] = max(perm.unitsMode[u.Type], teamMode)
found = true
}
}
// for a public repo on an organization, a non-restricted user has read permission on non-team defined units.
if !found && !repo.IsPrivate && !user.IsRestricted {
- if _, ok := perm.UnitsMode[u.Type]; !ok {
- perm.UnitsMode[u.Type] = perm_model.AccessModeRead
+ if _, ok := perm.unitsMode[u.Type]; !ok {
+ perm.unitsMode[u.Type] = perm_model.AccessModeRead
}
}
}
// remove no permission units
- perm.Units = make([]*repo_model.RepoUnit, 0, len(repo.Units))
- for t := range perm.UnitsMode {
+ perm.units = make([]*repo_model.RepoUnit, 0, len(repo.Units))
+ for t := range perm.unitsMode {
for _, u := range repo.Units {
if u.Type == t {
- perm.Units = append(perm.Units, u)
+ perm.units = append(perm.units, u)
}
}
}
@@ -334,7 +363,7 @@ func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.
// Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface.
func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) {
if user.IsOrganization() {
- return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID)
+ return false, fmt.Errorf("organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID)
}
perm, err := GetUserRepoPermission(ctx, repo, user)
if err != nil {
diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go
new file mode 100644
index 0000000000..aaa53bb24f
--- /dev/null
+++ b/models/perm/access/repo_permission_test.go
@@ -0,0 +1,98 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package access
+
+import (
+ "testing"
+
+ perm_model "code.gitea.io/gitea/models/perm"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestApplyEveryoneRepoPermission(t *testing.T) {
+ perm := Permission{
+ AccessMode: perm_model.AccessModeNone,
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeNone},
+ },
+ }
+ applyEveryoneRepoPermission(nil, &perm)
+ assert.False(t, perm.CanRead(unit.TypeWiki))
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeNone,
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
+ },
+ }
+ applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ assert.True(t, perm.CanRead(unit.TypeWiki))
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeWrite,
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
+ },
+ }
+ applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ assert.True(t, perm.CanRead(unit.TypeWiki))
+ assert.False(t, perm.CanWrite(unit.TypeWiki)) // because there is no unit mode, so the everyone-mode is used as the unit's access mode
+
+ perm = Permission{
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
+ },
+ unitsMode: map[unit.Type]perm_model.AccessMode{
+ unit.TypeWiki: perm_model.AccessModeWrite,
+ },
+ }
+ applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ assert.True(t, perm.CanWrite(unit.TypeWiki))
+}
+
+func TestUnitAccessMode(t *testing.T) {
+ perm := Permission{
+ AccessMode: perm_model.AccessModeNone,
+ }
+ assert.Equal(t, perm_model.AccessModeNone, perm.UnitAccessMode(unit.TypeWiki), "no unit, no map, use AccessMode")
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeRead,
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki},
+ },
+ }
+ assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "only unit, no map, use AccessMode")
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeAdmin,
+ unitsMode: map[unit.Type]perm_model.AccessMode{
+ unit.TypeWiki: perm_model.AccessModeRead,
+ },
+ }
+ assert.Equal(t, perm_model.AccessModeAdmin, perm.UnitAccessMode(unit.TypeWiki), "no unit, only map, admin overrides map")
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeNone,
+ unitsMode: map[unit.Type]perm_model.AccessMode{
+ unit.TypeWiki: perm_model.AccessModeRead,
+ },
+ }
+ assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "no unit, only map, use map")
+
+ perm = Permission{
+ AccessMode: perm_model.AccessModeNone,
+ units: []*repo_model.RepoUnit{
+ {Type: unit.TypeWiki},
+ },
+ unitsMode: map[unit.Type]perm_model.AccessMode{
+ unit.TypeWiki: perm_model.AccessModeRead,
+ },
+ }
+ assert.Equal(t, perm_model.AccessModeRead, perm.UnitAccessMode(unit.TypeWiki), "has unit, and map, use map")
+}
diff --git a/models/perm/access_mode.go b/models/perm/access_mode.go
index a37bc1f0e1..0364191e2e 100644
--- a/models/perm/access_mode.go
+++ b/models/perm/access_mode.go
@@ -5,25 +5,25 @@ package perm
import (
"fmt"
+ "slices"
+
+ "code.gitea.io/gitea/modules/util"
)
// AccessMode specifies the users access mode
type AccessMode int
const (
- // AccessModeNone no access
- AccessModeNone AccessMode = iota // 0
- // AccessModeRead read access
- AccessModeRead // 1
- // AccessModeWrite write access
- AccessModeWrite // 2
- // AccessModeAdmin admin access
- AccessModeAdmin // 3
- // AccessModeOwner owner access
- AccessModeOwner // 4
+ AccessModeNone AccessMode = iota // 0: no access
+
+ AccessModeRead // 1: read access
+ AccessModeWrite // 2: write access
+ AccessModeAdmin // 3: admin access
+ AccessModeOwner // 4: owner access
)
-func (mode AccessMode) String() string {
+// ToString returns the string representation of the access mode, do not make it a Stringer, otherwise it's difficult to render in templates
+func (mode AccessMode) ToString() string {
switch mode {
case AccessModeRead:
return "read"
@@ -39,19 +39,24 @@ func (mode AccessMode) String() string {
}
func (mode AccessMode) LogString() string {
- return fmt.Sprintf("", mode, mode.String())
+ return fmt.Sprintf("", mode, mode.ToString())
}
// ParseAccessMode returns corresponding access mode to given permission string.
-func ParseAccessMode(permission string) AccessMode {
+func ParseAccessMode(permission string, allowed ...AccessMode) AccessMode {
+ m := AccessModeNone
switch permission {
case "read":
- return AccessModeRead
+ m = AccessModeRead
case "write":
- return AccessModeWrite
+ m = AccessModeWrite
case "admin":
- return AccessModeAdmin
+ m = AccessModeAdmin
default:
- return AccessModeNone
+ // the "owner" access is not really used for user input, it's mainly for checking access level in code, so don't parse it
}
+ if len(allowed) == 0 {
+ return m
+ }
+ return util.Iif(slices.Contains(allowed, m), m, AccessModeNone)
}
diff --git a/models/perm/access_mode_test.go b/models/perm/access_mode_test.go
new file mode 100644
index 0000000000..982fceee5a
--- /dev/null
+++ b/models/perm/access_mode_test.go
@@ -0,0 +1,22 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package perm
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestAccessMode(t *testing.T) {
+ names := []string{"none", "read", "write", "admin"}
+ for i, name := range names {
+ m := ParseAccessMode(name)
+ assert.Equal(t, AccessMode(i), m)
+ }
+ assert.Equal(t, AccessMode(4), AccessModeOwner)
+ assert.Equal(t, "owner", AccessModeOwner.ToString())
+ assert.Equal(t, AccessModeNone, ParseAccessMode("owner"))
+ assert.Equal(t, AccessModeNone, ParseAccessMode("invalid"))
+}
diff --git a/models/repo/issue.go b/models/repo/issue.go
index 6f6b565a00..0dd4fd5ed4 100644
--- a/models/repo/issue.go
+++ b/models/repo/issue.go
@@ -53,7 +53,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool {
var u *RepoUnit
var err error
if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil {
- log.Trace("%s", err)
+ log.Trace("IsDependenciesEnabled: %v", err)
return setting.Service.DefaultEnableDependencies
}
return u.IssuesConfig().EnableDependencies
diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go
index cb7cd47a8d..987c7df9b0 100644
--- a/models/repo/repo_list.go
+++ b/models/repo/repo_list.go
@@ -104,18 +104,19 @@ func (repos RepositoryList) LoadAttributes(ctx context.Context) error {
return nil
}
- set := make(container.Set[int64])
+ userIDs := container.FilterSlice(repos, func(repo *Repository) (int64, bool) {
+ return repo.OwnerID, true
+ })
repoIDs := make([]int64, len(repos))
for i := range repos {
- set.Add(repos[i].OwnerID)
repoIDs[i] = repos[i].ID
}
// Load owners.
- users := make(map[int64]*user_model.User, len(set))
+ users := make(map[int64]*user_model.User, len(userIDs))
if err := db.GetEngine(ctx).
Where("id > 0").
- In("id", set.Values()).
+ In("id", userIDs).
Find(&users); err != nil {
return fmt.Errorf("find users: %w", err)
}
diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go
index 5a841f4d31..fd5baa9488 100644
--- a/models/repo/repo_unit.go
+++ b/models/repo/repo_unit.go
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/setting"
@@ -41,11 +42,12 @@ func (err ErrUnitTypeNotExist) Unwrap() error {
// RepoUnit describes all units of a repository
type RepoUnit struct { //revive:disable-line:exported
- ID int64
- RepoID int64 `xorm:"INDEX(s)"`
- Type unit.Type `xorm:"INDEX(s)"`
- Config convert.Conversion `xorm:"TEXT"`
- CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
+ ID int64
+ RepoID int64 `xorm:"INDEX(s)"`
+ Type unit.Type `xorm:"INDEX(s)"`
+ Config convert.Conversion `xorm:"TEXT"`
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
+ EveryoneAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"`
}
func init() {
diff --git a/models/unit/unit.go b/models/unit/unit.go
index b216712d37..a78a2f1e47 100644
--- a/models/unit/unit.go
+++ b/models/unit/unit.go
@@ -191,16 +191,13 @@ type Unit struct {
NameKey string
URI string
DescKey string
- Idx int
+ Priority int
MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read.
}
// IsLessThan compares order of two units
func (u Unit) IsLessThan(unit Unit) bool {
- if (u.Type == TypeExternalTracker || u.Type == TypeExternalWiki) && unit.Type != TypeExternalTracker && unit.Type != TypeExternalWiki {
- return false
- }
- return u.Idx < unit.Idx
+ return u.Priority < unit.Priority
}
// MaxPerm returns the max perms of this unit
@@ -236,7 +233,7 @@ var (
"repo.ext_issues",
"/issues",
"repo.ext_issues.desc",
- 1,
+ 101,
perm.AccessModeRead,
}
@@ -272,7 +269,7 @@ var (
"repo.ext_wiki",
"/wiki",
"repo.ext_wiki.desc",
- 4,
+ 102,
perm.AccessModeRead,
}
diff --git a/modules/cache/cache.go b/modules/cache/cache.go
index 09afc8b7f7..2ca77bdb29 100644
--- a/modules/cache/cache.go
+++ b/modules/cache/cache.go
@@ -4,149 +4,75 @@
package cache
import (
- "fmt"
"strconv"
+ "time"
"code.gitea.io/gitea/modules/setting"
-
- mc "gitea.com/go-chi/cache"
-
- _ "gitea.com/go-chi/cache/memcache" // memcache plugin for cache
)
-var conn mc.Cache
-
-func newCache(cacheConfig setting.Cache) (mc.Cache, error) {
- return mc.NewCacher(mc.Options{
- Adapter: cacheConfig.Adapter,
- AdapterConfig: cacheConfig.Conn,
- Interval: cacheConfig.Interval,
- })
-}
+var defaultCache StringCache
// Init start cache service
func Init() error {
- var err error
-
- if conn == nil {
- if conn, err = newCache(setting.CacheService.Cache); err != nil {
+ if defaultCache == nil {
+ c, err := NewStringCache(setting.CacheService.Cache)
+ if err != nil {
return err
}
- if err = conn.Ping(); err != nil {
+ for i := 0; i < 10; i++ {
+ if err = c.Ping(); err == nil {
+ break
+ }
+ time.Sleep(time.Second)
+ }
+ if err != nil {
return err
}
+ defaultCache = c
}
-
- return err
+ return nil
}
// GetCache returns the currently configured cache
-func GetCache() mc.Cache {
- return conn
+func GetCache() StringCache {
+ return defaultCache
}
// GetString returns the key value from cache with callback when no key exists in cache
func GetString(key string, getFunc func() (string, error)) (string, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
+ if defaultCache == nil || setting.CacheService.TTL == 0 {
return getFunc()
}
-
- cached := conn.Get(key)
-
- if cached == nil {
+ cached, exist := defaultCache.Get(key)
+ if !exist {
value, err := getFunc()
if err != nil {
return value, err
}
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
- }
-
- if value, ok := cached.(string); ok {
- return value, nil
- }
-
- if stringer, ok := cached.(fmt.Stringer); ok {
- return stringer.String(), nil
- }
-
- return fmt.Sprintf("%s", cached), nil
-}
-
-// GetInt returns key value from cache with callback when no key exists in cache
-func GetInt(key string, getFunc func() (int, error)) (int, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
- return getFunc()
- }
-
- cached := conn.Get(key)
-
- if cached == nil {
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
- }
-
- switch v := cached.(type) {
- case int:
- return v, nil
- case string:
- value, err := strconv.Atoi(v)
- if err != nil {
- return 0, err
- }
- return value, nil
- default:
- value, err := getFunc()
- if err != nil {
- return value, err
- }
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
+ return value, defaultCache.Put(key, value, setting.CacheService.TTLSeconds())
}
+ return cached, nil
}
// GetInt64 returns key value from cache with callback when no key exists in cache
func GetInt64(key string, getFunc func() (int64, error)) (int64, error) {
- if conn == nil || setting.CacheService.TTL == 0 {
- return getFunc()
+ s, err := GetString(key, func() (string, error) {
+ v, err := getFunc()
+ return strconv.FormatInt(v, 10), err
+ })
+ if err != nil {
+ return 0, err
}
-
- cached := conn.Get(key)
-
- if cached == nil {
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
- }
-
- switch v := conn.Get(key).(type) {
- case int64:
- return v, nil
- case string:
- value, err := strconv.ParseInt(v, 10, 64)
- if err != nil {
- return 0, err
- }
- return value, nil
- default:
- value, err := getFunc()
- if err != nil {
- return value, err
- }
-
- return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
+ if s == "" {
+ return 0, nil
}
+ return strconv.ParseInt(s, 10, 64)
}
// Remove key from cache
func Remove(key string) {
- if conn == nil {
+ if defaultCache == nil {
return
}
- _ = conn.Delete(key)
+ _ = defaultCache.Delete(key)
}
diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go
index 6c358b0a78..c5b52a2086 100644
--- a/modules/cache/cache_redis.go
+++ b/modules/cache/cache_redis.go
@@ -11,7 +11,7 @@ import (
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/nosql"
- "gitea.com/go-chi/cache"
+ "gitea.com/go-chi/cache" //nolint:depguard
"github.com/redis/go-redis/v9"
)
diff --git a/modules/cache/cache_test.go b/modules/cache/cache_test.go
index 3f65040924..0c68cc26ee 100644
--- a/modules/cache/cache_test.go
+++ b/modules/cache/cache_test.go
@@ -14,7 +14,7 @@ import (
)
func createTestCache() {
- conn, _ = newCache(setting.Cache{
+ defaultCache, _ = NewStringCache(setting.Cache{
Adapter: "memory",
TTL: time.Minute,
})
@@ -25,7 +25,7 @@ func TestNewContext(t *testing.T) {
assert.NoError(t, Init())
setting.CacheService.Cache = setting.Cache{Adapter: "redis", Conn: "some random string"}
- con, err := newCache(setting.Cache{
+ con, err := NewStringCache(setting.Cache{
Adapter: "rand",
Conn: "false conf",
Interval: 100,
@@ -76,42 +76,6 @@ func TestGetString(t *testing.T) {
Remove("key")
}
-func TestGetInt(t *testing.T) {
- createTestCache()
-
- data, err := GetInt("key", func() (int, error) {
- return 0, fmt.Errorf("some error")
- })
- assert.Error(t, err)
- assert.Equal(t, 0, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 0, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 0, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 100, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 0, data)
- Remove("key")
-
- data, err = GetInt("key", func() (int, error) {
- return 100, nil
- })
- assert.NoError(t, err)
- assert.Equal(t, 100, data)
-
- data, err = GetInt("key", func() (int, error) {
- return 0, fmt.Errorf("some error")
- })
- assert.NoError(t, err)
- assert.Equal(t, 100, data)
- Remove("key")
-}
-
func TestGetInt64(t *testing.T) {
createTestCache()
diff --git a/modules/cache/cache_twoqueue.go b/modules/cache/cache_twoqueue.go
index f9de2563ec..1eda2debc4 100644
--- a/modules/cache/cache_twoqueue.go
+++ b/modules/cache/cache_twoqueue.go
@@ -10,7 +10,7 @@ import (
"code.gitea.io/gitea/modules/json"
- mc "gitea.com/go-chi/cache"
+ mc "gitea.com/go-chi/cache" //nolint:depguard
lru "github.com/hashicorp/golang-lru/v2"
)
diff --git a/modules/cache/string_cache.go b/modules/cache/string_cache.go
new file mode 100644
index 0000000000..4f659616f5
--- /dev/null
+++ b/modules/cache/string_cache.go
@@ -0,0 +1,120 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package cache
+
+import (
+ "errors"
+ "strings"
+
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
+
+ chi_cache "gitea.com/go-chi/cache" //nolint:depguard
+)
+
+type GetJSONError struct {
+ err error
+ cachedError string // Golang error can't be stored in cache, only the string message could be stored
+}
+
+func (e *GetJSONError) ToError() error {
+ if e.err != nil {
+ return e.err
+ }
+ return errors.New("cached error: " + e.cachedError)
+}
+
+type StringCache interface {
+ Ping() error
+
+ Get(key string) (string, bool)
+ Put(key, value string, ttl int64) error
+ Delete(key string) error
+ IsExist(key string) bool
+
+ PutJSON(key string, v any, ttl int64) error
+ GetJSON(key string, ptr any) (exist bool, err *GetJSONError)
+
+ ChiCache() chi_cache.Cache
+}
+
+type stringCache struct {
+ chiCache chi_cache.Cache
+}
+
+func NewStringCache(cacheConfig setting.Cache) (StringCache, error) {
+ adapter := util.IfZero(cacheConfig.Adapter, "memory")
+ interval := util.IfZero(cacheConfig.Interval, 60)
+ cc, err := chi_cache.NewCacher(chi_cache.Options{
+ Adapter: adapter,
+ AdapterConfig: cacheConfig.Conn,
+ Interval: interval,
+ })
+ if err != nil {
+ return nil, err
+ }
+ return &stringCache{chiCache: cc}, nil
+}
+
+func (sc *stringCache) Ping() error {
+ return sc.chiCache.Ping()
+}
+
+func (sc *stringCache) Get(key string) (string, bool) {
+ v := sc.chiCache.Get(key)
+ if v == nil {
+ return "", false
+ }
+ s, ok := v.(string)
+ return s, ok
+}
+
+func (sc *stringCache) Put(key, value string, ttl int64) error {
+ return sc.chiCache.Put(key, value, ttl)
+}
+
+func (sc *stringCache) Delete(key string) error {
+ return sc.chiCache.Delete(key)
+}
+
+func (sc *stringCache) IsExist(key string) bool {
+ return sc.chiCache.IsExist(key)
+}
+
+const cachedErrorPrefix = ":"
+
+func (sc *stringCache) PutJSON(key string, v any, ttl int64) error {
+ var s string
+ switch v := v.(type) {
+ case error:
+ s = cachedErrorPrefix + v.Error()
+ default:
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+ s = util.UnsafeBytesToString(b)
+ }
+ return sc.chiCache.Put(key, s, ttl)
+}
+
+func (sc *stringCache) GetJSON(key string, ptr any) (exist bool, getErr *GetJSONError) {
+ s, ok := sc.Get(key)
+ if !ok || s == "" {
+ return false, nil
+ }
+ s, isCachedError := strings.CutPrefix(s, cachedErrorPrefix)
+ if isCachedError {
+ return true, &GetJSONError{cachedError: s}
+ }
+ if err := json.Unmarshal(util.UnsafeStringToBytes(s), ptr); err != nil {
+ return false, &GetJSONError{err: err}
+ }
+ return true, nil
+}
+
+func (sc *stringCache) ChiCache() chi_cache.Cache {
+ return sc.chiCache
+}
diff --git a/modules/container/filter.go b/modules/container/filter.go
new file mode 100644
index 0000000000..37ec7c3d56
--- /dev/null
+++ b/modules/container/filter.go
@@ -0,0 +1,21 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package container
+
+import "slices"
+
+// FilterSlice ranges over the slice and calls include() for each element.
+// If the second returned value is true, the first returned value will be included in the resulting
+// slice (after deduplication).
+func FilterSlice[E any, T comparable](s []E, include func(E) (T, bool)) []T {
+ filtered := make([]T, 0, len(s)) // slice will be clipped before returning
+ seen := make(map[T]bool, len(s))
+ for i := range s {
+ if v, ok := include(s[i]); ok && !seen[v] {
+ filtered = append(filtered, v)
+ seen[v] = true
+ }
+ }
+ return slices.Clip(filtered)
+}
diff --git a/modules/container/filter_test.go b/modules/container/filter_test.go
new file mode 100644
index 0000000000..ad304e5abb
--- /dev/null
+++ b/modules/container/filter_test.go
@@ -0,0 +1,28 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package container
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFilterMapUnique(t *testing.T) {
+ result := FilterSlice([]int{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ }, func(i int) (int, bool) {
+ switch i {
+ case 0:
+ return 0, true // included later
+ case 1:
+ return 0, true // duplicate of previous (should be ignored)
+ case 2:
+ return 2, false // not included
+ default:
+ return i, true
+ }
+ })
+ assert.Equal(t, []int{0, 3, 4, 5, 6, 7, 8, 9}, result)
+}
diff --git a/modules/git/grep.go b/modules/git/grep.go
index a6c486112a..e7d238e586 100644
--- a/modules/git/grep.go
+++ b/modules/git/grep.go
@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"os"
+ "slices"
"strconv"
"strings"
@@ -27,6 +28,7 @@ type GrepOptions struct {
MaxResultLimit int
ContextLineNumber int
IsFuzzy bool
+ MaxLineLength int // the maximum length of a line to parse, exceeding chars will be truncated
}
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
@@ -71,10 +73,20 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
defer stdoutReader.Close()
isInBlock := false
- scanner := bufio.NewScanner(stdoutReader)
+ rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024))
var res *GrepResult
- for scanner.Scan() {
- line := scanner.Text()
+ for {
+ lineBytes, isPrefix, err := rd.ReadLine()
+ if isPrefix {
+ lineBytes = slices.Clone(lineBytes)
+ for isPrefix && err == nil {
+ _, isPrefix, err = rd.ReadLine()
+ }
+ }
+ if len(lineBytes) == 0 && err != nil {
+ break
+ }
+ line := string(lineBytes) // the memory of lineBytes is mutable
if !isInBlock {
if _ /* ref */, filename, ok := strings.Cut(line, ":"); ok {
isInBlock = true
@@ -100,7 +112,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
res.LineCodes = append(res.LineCodes, lineCode)
}
}
- return scanner.Err()
+ return nil
},
})
// git grep exits by cancel (killed), usually it is caused by the limit of results
diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go
index b5fa437c53..7f4ded478f 100644
--- a/modules/git/grep_test.go
+++ b/modules/git/grep_test.go
@@ -41,6 +41,16 @@ func TestGrepSearch(t *testing.T) {
},
}, res)
+ res, err = GrepSearch(context.Background(), repo, "void", GrepOptions{MaxResultLimit: 1, MaxLineLength: 39})
+ assert.NoError(t, err)
+ assert.Equal(t, []*GrepResult{
+ {
+ Filename: "java-hello/main.java",
+ LineNumbers: []int{3},
+ LineCodes: []string{" public static void main(String[] arg"},
+ },
+ }, res)
+
res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{})
assert.NoError(t, err)
assert.Len(t, res, 0)
diff --git a/modules/git/last_commit_cache.go b/modules/git/last_commit_cache.go
index 5b62b90b27..cf9c10d7b4 100644
--- a/modules/git/last_commit_cache.go
+++ b/modules/git/last_commit_cache.go
@@ -7,18 +7,11 @@ import (
"crypto/sha256"
"fmt"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
-// Cache represents a caching interface
-type Cache interface {
- // Put puts value into cache with key and expire time.
- Put(key string, val any, timeout int64) error
- // Get gets cached value by given key.
- Get(key string) any
-}
-
func getCacheKey(repoPath, commitID, entryPath string) string {
hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, commitID, entryPath)))
return fmt.Sprintf("last_commit:%x", hashBytes)
@@ -30,11 +23,11 @@ type LastCommitCache struct {
ttl func() int64
repo *Repository
commitCache map[string]*Commit
- cache Cache
+ cache cache.StringCache
}
// NewLastCommitCache creates a new last commit cache for repo
-func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache Cache) *LastCommitCache {
+func NewLastCommitCache(count int64, repoPath string, gitRepo *Repository, cache cache.StringCache) *LastCommitCache {
if cache == nil {
return nil
}
@@ -65,7 +58,7 @@ func (c *LastCommitCache) Get(ref, entryPath string) (*Commit, error) {
return nil, nil
}
- commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath)).(string)
+ commitID, ok := c.cache.Get(getCacheKey(c.repoPath, ref, entryPath))
if !ok || commitID == "" {
return nil, nil
}
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 56aa1cb49c..cef643bf18 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -709,7 +709,8 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
name += tail
image := false
- switch ext := filepath.Ext(link); ext {
+ ext := filepath.Ext(link)
+ switch ext {
// fast path: empty string, ignore
case "":
// leave image as false
@@ -767,11 +768,26 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
}
} else {
if !absoluteLink {
+ var base string
if ctx.IsWiki {
- link = util.URLJoin(ctx.Links.WikiLink(), link)
+ switch ext {
+ case "":
+ // no file extension, create a regular wiki link
+ base = ctx.Links.WikiLink()
+ default:
+ // we have a file extension:
+ // return a regular wiki link if it's a renderable file (extension),
+ // raw link otherwise
+ if Type(link) != "" {
+ base = ctx.Links.WikiLink()
+ } else {
+ base = ctx.Links.WikiRawLink()
+ }
+ }
} else {
- link = util.URLJoin(ctx.Links.SrcLink(), link)
+ base = ctx.Links.SrcLink()
}
+ link = util.URLJoin(base, link)
}
childNode.Type = html.TextNode
childNode.Data = name
diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go
index 55de65d196..916e74fb62 100644
--- a/modules/markup/html_test.go
+++ b/modules/markup/html_test.go
@@ -427,6 +427,10 @@ func TestRender_ShortLinks(t *testing.T) {
otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
+ renderableFileURL := util.URLJoin(tree, "markdown_file.md")
+ renderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "markdown_file.md")
+ unrenderableFileURL := util.URLJoin(tree, "file.zip")
+ unrenderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "file.zip")
favicon := "http://google.com/favicon.ico"
test(
@@ -481,6 +485,14 @@ func TestRender_ShortLinks(t *testing.T) {
"[[Link]] [[Other Link]] [[Link?]]",
`Link Other Link Link?
`,
`Link Other Link Link?
`)
+ test(
+ "[[markdown_file.md]]",
+ `markdown_file.md
`,
+ `markdown_file.md
`)
+ test(
+ "[[file.zip]]",
+ `file.zip
`,
+ `file.zip
`)
test(
"[[Link #.jpg]]",
`
`,
diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go
index a9c9024982..d9b67e43af 100644
--- a/modules/markup/markdown/markdown_test.go
+++ b/modules/markup/markdown/markdown_test.go
@@ -653,9 +653,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
@@ -711,9 +711,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
@@ -769,9 +769,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
@@ -829,9 +829,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
@@ -889,9 +889,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
@@ -951,9 +951,9 @@ space
Expected: `space @mention-user
/just/a/path.bin
https://example.com/file.bin
-local link
+local link
remote link
-local link
+local link
remote link
diff --git a/modules/markup/markdown/transform_link.go b/modules/markup/markdown/transform_link.go
index 8bf19ea4ce..7e305b74bc 100644
--- a/modules/markup/markdown/transform_link.go
+++ b/modules/markup/markdown/transform_link.go
@@ -4,6 +4,8 @@
package markdown
import (
+ "path/filepath"
+
"code.gitea.io/gitea/modules/markup"
giteautil "code.gitea.io/gitea/modules/util"
@@ -18,7 +20,16 @@ func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, r
if !isAnchorFragment && !markup.IsFullURLBytes(link) {
base := ctx.Links.Base
if ctx.IsWiki {
- base = ctx.Links.WikiLink()
+ if filepath.Ext(string(link)) == "" {
+ // This link doesn't have a file extension - assume a regular wiki link
+ base = ctx.Links.WikiLink()
+ } else if markup.Type(string(link)) != "" {
+ // If it's a file type we can render, use a regular wiki link
+ base = ctx.Links.WikiLink()
+ } else {
+ // Otherwise, use a raw link instead
+ base = ctx.Links.WikiRawLink()
+ }
} else if ctx.Links.HasBranchInfo() {
base = ctx.Links.SrcLink()
}
diff --git a/modules/markup/sanitizer.go b/modules/markup/sanitizer.go
index 77fbdf4520..570a1da248 100644
--- a/modules/markup/sanitizer.go
+++ b/modules/markup/sanitizer.go
@@ -65,7 +65,7 @@ func createDefaultPolicy() *bluemonday.Policy {
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-num$`)).OnElements("td")
policy.AllowAttrs("data-line-number").OnElements("span")
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^lines-code chroma$`)).OnElements("td")
- policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("code")
+ policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-inner$`)).OnElements("div")
// For code preview (unicode escape)
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^file-view( unicode-escaped)?$`)).OnElements("table")
diff --git a/modules/optional/serialization.go b/modules/optional/serialization.go
index 6688e78cd1..b120a0edf6 100644
--- a/modules/optional/serialization.go
+++ b/modules/optional/serialization.go
@@ -35,7 +35,7 @@ func (o *Option[T]) UnmarshalYAML(value *yaml.Node) error {
return nil
}
-func (o Option[T]) MarshalYAML() (interface{}, error) {
+func (o Option[T]) MarshalYAML() (any, error) {
if !o.Has() {
return nil, nil
}
diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go
index 3c478b1c02..1e98ddffde 100644
--- a/modules/packages/nuget/metadata.go
+++ b/modules/packages/nuget/metadata.go
@@ -48,16 +48,18 @@ const maxNuspecFileSize = 3 * 1024 * 1024
// Package represents a Nuget package
type Package struct {
- PackageType PackageType
- ID string
- Version string
- Metadata *Metadata
+ PackageType PackageType
+ ID string
+ Version string
+ Metadata *Metadata
+ NuspecContent *bytes.Buffer
}
// Metadata represents the metadata of a Nuget package
type Metadata struct {
Description string `json:"description,omitempty"`
ReleaseNotes string `json:"release_notes,omitempty"`
+ Readme string `json:"readme,omitempty"`
Authors string `json:"authors,omitempty"`
ProjectURL string `json:"project_url,omitempty"`
RepositoryURL string `json:"repository_url,omitempty"`
@@ -71,6 +73,7 @@ type Dependency struct {
Version string `json:"version"`
}
+// https://learn.microsoft.com/en-us/nuget/reference/nuspec
type nuspecPackage struct {
Metadata struct {
ID string `xml:"id"`
@@ -80,6 +83,7 @@ type nuspecPackage struct {
ProjectURL string `xml:"projectUrl"`
Description string `xml:"description"`
ReleaseNotes string `xml:"releaseNotes"`
+ Readme string `xml:"readme"`
PackageTypes struct {
PackageType []struct {
Name string `xml:"name,attr"`
@@ -89,6 +93,11 @@ type nuspecPackage struct {
URL string `xml:"url,attr"`
} `xml:"repository"`
Dependencies struct {
+ Dependency []struct {
+ ID string `xml:"id,attr"`
+ Version string `xml:"version,attr"`
+ Exclude string `xml:"exclude,attr"`
+ } `xml:"dependency"`
Group []struct {
TargetFramework string `xml:"targetFramework,attr"`
Dependency []struct {
@@ -122,16 +131,17 @@ func ParsePackageMetaData(r io.ReaderAt, size int64) (*Package, error) {
}
defer f.Close()
- return ParseNuspecMetaData(f)
+ return ParseNuspecMetaData(archive, f)
}
}
return nil, ErrMissingNuspecFile
}
// ParseNuspecMetaData parses a Nuspec file to retrieve the metadata of a Nuget package
-func ParseNuspecMetaData(r io.Reader) (*Package, error) {
+func ParseNuspecMetaData(archive *zip.Reader, r io.Reader) (*Package, error) {
+ var nuspecBuf bytes.Buffer
var p nuspecPackage
- if err := xml.NewDecoder(r).Decode(&p); err != nil {
+ if err := xml.NewDecoder(io.TeeReader(r, &nuspecBuf)).Decode(&p); err != nil {
return nil, err
}
@@ -166,6 +176,28 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) {
Dependencies: make(map[string][]Dependency),
}
+ if p.Metadata.Readme != "" {
+ f, err := archive.Open(p.Metadata.Readme)
+ if err == nil {
+ buf, _ := io.ReadAll(f)
+ m.Readme = string(buf)
+ _ = f.Close()
+ }
+ }
+
+ if len(p.Metadata.Dependencies.Dependency) > 0 {
+ deps := make([]Dependency, 0, len(p.Metadata.Dependencies.Dependency))
+ for _, dep := range p.Metadata.Dependencies.Dependency {
+ if dep.ID == "" || dep.Version == "" {
+ continue
+ }
+ deps = append(deps, Dependency{
+ ID: dep.ID,
+ Version: dep.Version,
+ })
+ }
+ m.Dependencies[""] = deps
+ }
for _, group := range p.Metadata.Dependencies.Group {
deps := make([]Dependency, 0, len(group.Dependency))
for _, dep := range group.Dependency {
@@ -182,10 +214,11 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) {
}
}
return &Package{
- PackageType: packageType,
- ID: p.Metadata.ID,
- Version: toNormalizedVersion(v),
- Metadata: m,
+ PackageType: packageType,
+ ID: p.Metadata.ID,
+ Version: toNormalizedVersion(v),
+ Metadata: m,
+ NuspecContent: &nuspecBuf,
}, nil
}
diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go
index bba2bff4a5..f466492f8a 100644
--- a/modules/packages/nuget/metadata_test.go
+++ b/modules/packages/nuget/metadata_test.go
@@ -6,7 +6,6 @@ package nuget
import (
"archive/zip"
"bytes"
- "strings"
"testing"
"github.com/stretchr/testify/assert"
@@ -19,6 +18,7 @@ const (
projectURL = "https://gitea.io"
description = "Package Description"
releaseNotes = "Package Release Notes"
+ readme = "Readme"
repositoryURL = "https://gitea.io/gitea/gitea"
targetFramework = ".NETStandard2.1"
dependencyID = "System.Text.Json"
@@ -36,6 +36,7 @@ const nuspecContent = `
` + description + `
` + releaseNotes + `
+ README.md
@@ -60,17 +61,19 @@ const symbolsNuspecContent = `
`
func TestParsePackageMetaData(t *testing.T) {
- createArchive := func(name, content string) []byte {
+ createArchive := func(files map[string]string) []byte {
var buf bytes.Buffer
archive := zip.NewWriter(&buf)
- w, _ := archive.Create(name)
- w.Write([]byte(content))
+ for name, content := range files {
+ w, _ := archive.Create(name)
+ w.Write([]byte(content))
+ }
archive.Close()
return buf.Bytes()
}
t.Run("MissingNuspecFile", func(t *testing.T) {
- data := createArchive("dummy.txt", "")
+ data := createArchive(map[string]string{"dummy.txt": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
@@ -78,7 +81,7 @@ func TestParsePackageMetaData(t *testing.T) {
})
t.Run("MissingNuspecFileInRoot", func(t *testing.T) {
- data := createArchive("sub/package.nuspec", "")
+ data := createArchive(map[string]string{"sub/package.nuspec": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
@@ -86,7 +89,7 @@ func TestParsePackageMetaData(t *testing.T) {
})
t.Run("InvalidNuspecFile", func(t *testing.T) {
- data := createArchive("package.nuspec", "")
+ data := createArchive(map[string]string{"package.nuspec": ""})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
@@ -94,10 +97,10 @@ func TestParsePackageMetaData(t *testing.T) {
})
t.Run("InvalidPackageId", func(t *testing.T) {
- data := createArchive("package.nuspec", `
+ data := createArchive(map[string]string{"package.nuspec": `
- `)
+ `})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
@@ -105,30 +108,34 @@ func TestParsePackageMetaData(t *testing.T) {
})
t.Run("InvalidPackageVersion", func(t *testing.T) {
- data := createArchive("package.nuspec", `
+ data := createArchive(map[string]string{"package.nuspec": `
- `+id+`
+ ` + id + `
- `)
+ `})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.Nil(t, np)
assert.ErrorIs(t, err, ErrNuspecInvalidVersion)
})
- t.Run("Valid", func(t *testing.T) {
- data := createArchive("package.nuspec", nuspecContent)
+ t.Run("MissingReadme", func(t *testing.T) {
+ data := createArchive(map[string]string{"package.nuspec": nuspecContent})
np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.NoError(t, err)
assert.NotNil(t, np)
+ assert.Empty(t, np.Metadata.Readme)
})
-}
-func TestParseNuspecMetaData(t *testing.T) {
t.Run("Dependency Package", func(t *testing.T) {
- np, err := ParseNuspecMetaData(strings.NewReader(nuspecContent))
+ data := createArchive(map[string]string{
+ "package.nuspec": nuspecContent,
+ "README.md": readme,
+ })
+
+ np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.NoError(t, err)
assert.NotNil(t, np)
assert.Equal(t, DependencyPackage, np.PackageType)
@@ -139,6 +146,7 @@ func TestParseNuspecMetaData(t *testing.T) {
assert.Equal(t, projectURL, np.Metadata.ProjectURL)
assert.Equal(t, description, np.Metadata.Description)
assert.Equal(t, releaseNotes, np.Metadata.ReleaseNotes)
+ assert.Equal(t, readme, np.Metadata.Readme)
assert.Equal(t, repositoryURL, np.Metadata.RepositoryURL)
assert.Len(t, np.Metadata.Dependencies, 1)
assert.Contains(t, np.Metadata.Dependencies, targetFramework)
@@ -148,13 +156,15 @@ func TestParseNuspecMetaData(t *testing.T) {
assert.Equal(t, dependencyVersion, deps[0].Version)
t.Run("NormalizedVersion", func(t *testing.T) {
- np, err := ParseNuspecMetaData(strings.NewReader(`
-
-
- test
- 1.04.5.2.5-rc.1+metadata
-
- `))
+ data := createArchive(map[string]string{"package.nuspec": `
+
+
+ test
+ 1.04.5.2.5-rc.1+metadata
+
+ `})
+
+ np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.NoError(t, err)
assert.NotNil(t, np)
assert.Equal(t, "1.4.5.2-rc.1", np.Version)
@@ -162,7 +172,9 @@ func TestParseNuspecMetaData(t *testing.T) {
})
t.Run("Symbols Package", func(t *testing.T) {
- np, err := ParseNuspecMetaData(strings.NewReader(symbolsNuspecContent))
+ data := createArchive(map[string]string{"package.nuspec": symbolsNuspecContent})
+
+ np, err := ParsePackageMetaData(bytes.NewReader(data), int64(len(data)))
assert.NoError(t, err)
assert.NotNil(t, np)
assert.Equal(t, SymbolsPackage, np.PackageType)
diff --git a/modules/private/hook.go b/modules/private/hook.go
index cab8c81224..79c3d48229 100644
--- a/modules/private/hook.go
+++ b/modules/private/hook.go
@@ -11,6 +11,7 @@ import (
"time"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
)
@@ -32,13 +33,13 @@ const (
)
// Bool checks for a key in the map and parses as a boolean
-func (g GitPushOptions) Bool(key string, def bool) bool {
+func (g GitPushOptions) Bool(key string) optional.Option[bool] {
if val, ok := g[key]; ok {
if b, err := strconv.ParseBool(val); err == nil {
- return b
+ return optional.Some(b)
}
}
- return def
+ return optional.None[bool]()
}
// HookOptions represents the options for the Hook calls
@@ -87,13 +88,17 @@ type HookProcReceiveResult struct {
// HookProcReceiveRefResult represents an individual result from ProcReceive
type HookProcReceiveRefResult struct {
- OldOID string
- NewOID string
- Ref string
- OriginalRef git.RefName
- IsForcePush bool
- IsNotMatched bool
- Err string
+ OldOID string
+ NewOID string
+ Ref string
+ OriginalRef git.RefName
+ IsForcePush bool
+ IsNotMatched bool
+ Err string
+ IsCreatePR bool
+ URL string
+ ShouldShowMessage bool
+ HeadBranch string
}
// HookPreReceive check whether the provided commits are allowed
diff --git a/modules/queue/backoff.go b/modules/queue/backoff.go
index cda7233567..02fc88574a 100644
--- a/modules/queue/backoff.go
+++ b/modules/queue/backoff.go
@@ -8,7 +8,7 @@ import (
"time"
)
-const (
+var (
backoffBegin = 50 * time.Millisecond
backoffUpper = 2 * time.Second
)
@@ -18,6 +18,14 @@ type (
backoffFuncErr func() (retry bool, err error)
)
+func mockBackoffDuration(d time.Duration) func() {
+ oldBegin, oldUpper := backoffBegin, backoffUpper
+ backoffBegin, backoffUpper = d, d
+ return func() {
+ backoffBegin, backoffUpper = oldBegin, oldUpper
+ }
+}
+
func backoffRetErr[T any](ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncRetErr[T]) (ret T, err error) {
d := begin
for {
diff --git a/modules/queue/workerqueue_test.go b/modules/queue/workerqueue_test.go
index e09669c542..a08b02a123 100644
--- a/modules/queue/workerqueue_test.go
+++ b/modules/queue/workerqueue_test.go
@@ -250,6 +250,7 @@ func TestWorkerPoolQueueShutdown(t *testing.T) {
func TestWorkerPoolQueueWorkerIdleReset(t *testing.T) {
defer test.MockVariableValue(&workerIdleDuration, 10*time.Millisecond)()
+ defer mockBackoffDuration(10 * time.Millisecond)()
handler := func(items ...int) (unhandled []int) {
time.Sleep(50 * time.Millisecond)
diff --git a/modules/session/store.go b/modules/session/store.go
index 4fa4d2848f..2f7ab7760b 100644
--- a/modules/session/store.go
+++ b/modules/session/store.go
@@ -6,6 +6,9 @@ package session
import (
"net/http"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/web/middleware"
+
"gitea.com/go-chi/session"
)
@@ -18,6 +21,10 @@ type Store interface {
// RegenerateSession regenerates the underlying session and returns the new store
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
+ // Ensure that a cookie with a trailing slash does not take precedence over
+ // the cookie written by the middleware.
+ middleware.DeleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
+
s, err := session.RegenerateSession(resp, req)
return s, err
}
diff --git a/modules/setting/config_provider.go b/modules/setting/config_provider.go
index 3fa3f3b50b..03f27ba203 100644
--- a/modules/setting/config_provider.go
+++ b/modules/setting/config_provider.go
@@ -315,21 +315,25 @@ func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting any) {
}
}
-// DeprecatedWarnings contains the warning message for various deprecations, including: setting option, file/folder, etc
-var DeprecatedWarnings []string
+// StartupProblems contains the messages for various startup problems, including: setting option, file/folder, etc
+var StartupProblems []string
+
+func logStartupProblem(skip int, level log.Level, format string, args ...any) {
+ msg := fmt.Sprintf(format, args...)
+ log.Log(skip+1, level, "%s", msg)
+ StartupProblems = append(StartupProblems, msg)
+}
func deprecatedSetting(rootCfg ConfigProvider, oldSection, oldKey, newSection, newKey, version string) {
if rootCfg.Section(oldSection).HasKey(oldKey) {
- msg := fmt.Sprintf("Deprecated config option `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version)
- log.Error("%v", msg)
- DeprecatedWarnings = append(DeprecatedWarnings, msg)
+ logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents, please use `[%s].%s` instead because this fallback will be/has been removed in %s", oldSection, oldKey, newSection, newKey, version)
}
}
// deprecatedSettingDB add a hint that the configuration has been moved to database but still kept in app.ini
func deprecatedSettingDB(rootCfg ConfigProvider, oldSection, oldKey string) {
if rootCfg.Section(oldSection).HasKey(oldKey) {
- log.Error("Deprecated `[%s]` `%s` present which has been copied to database table sys_setting", oldSection, oldKey)
+ logStartupProblem(1, log.ERROR, "Deprecation: config option `[%s].%s` presents but it won't take effect because it has been moved to admin panel -> config setting", oldSection, oldKey)
}
}
diff --git a/modules/setting/indexer.go b/modules/setting/indexer.go
index cec364d370..6877d70e3c 100644
--- a/modules/setting/indexer.go
+++ b/modules/setting/indexer.go
@@ -58,7 +58,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) {
if !filepath.IsAbs(Indexer.IssuePath) {
Indexer.IssuePath = filepath.ToSlash(filepath.Join(AppWorkPath, Indexer.IssuePath))
}
- checkOverlappedPath("indexer.ISSUE_INDEXER_PATH", Indexer.IssuePath)
+ checkOverlappedPath("[indexer].ISSUE_INDEXER_PATH", Indexer.IssuePath)
} else {
Indexer.IssueConnStr = sec.Key("ISSUE_INDEXER_CONN_STR").MustString(Indexer.IssueConnStr)
if Indexer.IssueType == "meilisearch" {
diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go
index 4d3bfd3eb6..6930197b22 100644
--- a/modules/setting/oauth2.go
+++ b/modules/setting/oauth2.go
@@ -22,11 +22,13 @@ const (
OAuth2UsernameNickname OAuth2UsernameType = "nickname"
// OAuth2UsernameEmail username of oauth2 email field will be used as gitea name
OAuth2UsernameEmail OAuth2UsernameType = "email"
+ // OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name
+ OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username"
)
func (username OAuth2UsernameType) isValid() bool {
switch username {
- case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail:
+ case OAuth2UsernameUserid, OAuth2UsernameNickname, OAuth2UsernameEmail, OAuth2UsernamePreferredUsername:
return true
}
return false
@@ -118,6 +120,10 @@ func loadOAuth2From(rootCfg ConfigProvider) {
return
}
+ if sec.HasKey("DEFAULT_APPLICATIONS") && sec.Key("DEFAULT_APPLICATIONS").String() == "" {
+ OAuth2.DefaultApplications = nil
+ }
+
// Handle the rename of ENABLE to ENABLED
deprecatedSetting(rootCfg, "oauth2", "ENABLE", "oauth2", "ENABLED", "v1.23.0")
if sec.HasKey("ENABLE") && !sec.HasKey("ENABLED") {
@@ -168,7 +174,7 @@ func GetGeneralTokenSigningSecret() []byte {
}
if generalSigningSecret.CompareAndSwap(old, &jwtSecret) {
// FIXME: in main branch, the signing token should be refactored (eg: one unique for LFS/OAuth2/etc ...)
- log.Warn("OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes")
+ logStartupProblem(1, log.WARN, "OAuth2 is not enabled, unable to use a persistent signing secret, a new one is generated, which is not persistent between restarts and cluster nodes")
return jwtSecret
}
return *generalSigningSecret.Load()
diff --git a/modules/setting/oauth2_test.go b/modules/setting/oauth2_test.go
index d822198619..4403f35892 100644
--- a/modules/setting/oauth2_test.go
+++ b/modules/setting/oauth2_test.go
@@ -32,3 +32,21 @@ JWT_SECRET = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
assert.Len(t, actual, 32)
assert.EqualValues(t, expected, actual)
}
+
+func TestOauth2DefaultApplications(t *testing.T) {
+ cfg, _ := NewConfigProviderFromData(``)
+ loadOAuth2From(cfg)
+ assert.Equal(t, []string{"git-credential-oauth", "git-credential-manager", "tea"}, OAuth2.DefaultApplications)
+
+ cfg, _ = NewConfigProviderFromData(`[oauth2]
+DEFAULT_APPLICATIONS = tea
+`)
+ loadOAuth2From(cfg)
+ assert.Equal(t, []string{"tea"}, OAuth2.DefaultApplications)
+
+ cfg, _ = NewConfigProviderFromData(`[oauth2]
+DEFAULT_APPLICATIONS =
+`)
+ loadOAuth2From(cfg)
+ assert.Nil(t, nil, OAuth2.DefaultApplications)
+}
diff --git a/modules/setting/repository.go b/modules/setting/repository.go
index a332d6adb3..8656ebc7ec 100644
--- a/modules/setting/repository.go
+++ b/modules/setting/repository.go
@@ -286,7 +286,7 @@ func loadRepositoryFrom(rootCfg ConfigProvider) {
RepoRootPath = filepath.Clean(RepoRootPath)
}
- checkOverlappedPath("repository.ROOT", RepoRootPath)
+ checkOverlappedPath("[repository].ROOT", RepoRootPath)
defaultDetectedCharsetsOrder := make([]string, 0, len(Repository.DetectedCharsetsOrder))
for _, charset := range Repository.DetectedCharsetsOrder {
diff --git a/modules/setting/server.go b/modules/setting/server.go
index 315faaeb21..7d6ece2727 100644
--- a/modules/setting/server.go
+++ b/modules/setting/server.go
@@ -331,7 +331,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
if !filepath.IsAbs(PprofDataPath) {
PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath)
}
- checkOverlappedPath("server.PPROF_DATA_PATH", PprofDataPath)
+ checkOverlappedPath("[server].PPROF_DATA_PATH", PprofDataPath)
landingPage := sec.Key("LANDING_PAGE").MustString("home")
switch landingPage {
diff --git a/modules/setting/session.go b/modules/setting/session.go
index 3cb1bfe7b5..afe63bfdb7 100644
--- a/modules/setting/session.go
+++ b/modules/setting/session.go
@@ -46,7 +46,7 @@ func loadSessionFrom(rootCfg ConfigProvider) {
SessionConfig.ProviderConfig = strings.Trim(sec.Key("PROVIDER_CONFIG").MustString(filepath.Join(AppDataPath, "sessions")), "\" ")
if SessionConfig.Provider == "file" && !filepath.IsAbs(SessionConfig.ProviderConfig) {
SessionConfig.ProviderConfig = filepath.Join(AppWorkPath, SessionConfig.ProviderConfig)
- checkOverlappedPath("session.PROVIDER_CONFIG", SessionConfig.ProviderConfig)
+ checkOverlappedPath("[session].PROVIDER_CONFIG", SessionConfig.ProviderConfig)
}
SessionConfig.CookieName = sec.Key("COOKIE_NAME").MustString("i_like_gitea")
SessionConfig.CookiePath = AppSubURL
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index 6aca9ec6cf..92bb0b6541 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -235,9 +235,7 @@ var configuredPaths = make(map[string]string)
func checkOverlappedPath(name, path string) {
// TODO: some paths shouldn't overlap (storage.xxx.path), while some could (data path is the base path for storage path)
if targetName, ok := configuredPaths[path]; ok && targetName != name {
- msg := fmt.Sprintf("Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name)
- log.Error("%s", msg)
- DeprecatedWarnings = append(DeprecatedWarnings, msg)
+ logStartupProblem(1, log.ERROR, "Configured path %q is used by %q and %q at the same time. The paths must be unique to prevent data loss.", path, targetName, name)
}
configuredPaths[path] = name
}
diff --git a/modules/setting/storage.go b/modules/setting/storage.go
index f4e33a53af..aeb61ac513 100644
--- a/modules/setting/storage.go
+++ b/modules/setting/storage.go
@@ -240,7 +240,7 @@ func getStorageForLocal(targetSec, overrideSec ConfigSection, tp targetSecType,
}
}
- checkOverlappedPath("storage."+name+".PATH", storage.Path)
+ checkOverlappedPath("[storage."+name+"].PATH", storage.Path)
return &storage, nil
}
diff --git a/modules/structs/repo_compare.go b/modules/structs/repo_compare.go
new file mode 100644
index 0000000000..8a12498705
--- /dev/null
+++ b/modules/structs/repo_compare.go
@@ -0,0 +1,10 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package structs
+
+// Compare represents a comparison between two commits.
+type Compare struct {
+ TotalCommits int `json:"total_commits"` // Total number of commits in the comparison.
+ Commits []*Commit `json:"commits"` // List of commits in the comparison.
+}
diff --git a/modules/structs/user.go b/modules/structs/user.go
index 21ecc1479e..ca6ab79944 100644
--- a/modules/structs/user.go
+++ b/modules/structs/user.go
@@ -20,6 +20,8 @@ type User struct {
// the user's authentication sign-in name.
// default: empty
LoginName string `json:"login_name"`
+ // The ID of the user's Authentication Source
+ SourceID int64 `json:"source_id"`
// the user's full name
FullName string `json:"full_name"`
// swagger:strfmt email
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 9e770a2606..360b48c594 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -34,6 +34,7 @@ func NewFuncMap() template.FuncMap {
// -----------------------------------------------------------------
// html/template related functions
"dict": dict, // it's lowercase because this name has been widely used. Our other functions should have uppercase names.
+ "Iif": Iif,
"Eval": Eval,
"SafeHTML": SafeHTML,
"HTMLFormat": HTMLFormat,
@@ -53,13 +54,13 @@ func NewFuncMap() template.FuncMap {
"JsonUtils": NewJsonUtils,
// -----------------------------------------------------------------
- // svg / avatar / icon
+ // svg / avatar / icon / color
"svg": svg.RenderHTML,
"EntryIcon": base.EntryIcon,
"MigrationIcon": MigrationIcon,
"ActionIcon": ActionIcon,
-
- "SortArrow": SortArrow,
+ "SortArrow": SortArrow,
+ "ContrastColor": util.ContrastColor,
// -----------------------------------------------------------------
// time / number / format
@@ -238,6 +239,17 @@ func DotEscape(raw string) string {
return strings.ReplaceAll(raw, ".", "\u200d.\u200d")
}
+// Iif is an "inline-if", similar util.Iif[T] but templates need the non-generic version,
+// and it could be simply used as "{{Iif expr trueVal}}" (omit the falseVal).
+func Iif(condition bool, vals ...any) any {
+ if condition {
+ return vals[0]
+ } else if len(vals) > 1 {
+ return vals[1]
+ }
+ return nil
+}
+
// Eval the expression and return the result, see the comment of eval.Expr for details.
// To use this helper function in templates, pass each token as a separate parameter.
//
diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go
index 6c1b4ab240..774385483b 100644
--- a/modules/templates/util_misc.go
+++ b/modules/templates/util_misc.go
@@ -142,35 +142,39 @@ type remoteAddress struct {
Password string
}
-func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress {
- a := remoteAddress{}
-
- remoteURL := m.OriginalURL
- if ignoreOriginalURL || remoteURL == "" {
- var err error
- remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
- if err != nil {
- log.Error("GetRemoteURL %v", err)
- return a
- }
+func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
+ ret := remoteAddress{}
+ remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
+ if err != nil {
+ log.Error("GetRemoteURL %v", err)
+ return ret
}
u, err := giturl.Parse(remoteURL)
if err != nil {
log.Error("giturl.Parse %v", err)
- return a
+ return ret
}
if u.Scheme != "ssh" && u.Scheme != "file" {
if u.User != nil {
- a.Username = u.User.Username()
- a.Password, _ = u.User.Password()
+ ret.Username = u.User.Username()
+ ret.Password, _ = u.User.Password()
}
- u.User = nil
}
- a.Address = u.String()
- return a
+ // The URL stored in the git repo could contain authentication,
+ // erase it, or it will be shown in the UI.
+ u.User = nil
+ ret.Address = u.String()
+ // Why not use m.OriginalURL to set ret.Address?
+ // It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository.
+ // However, the old code has already stored authentication in m.OriginalURL when updating mirror settings.
+ // That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased.
+ // Instead of doing this, why not directly use the authentication-erased URL from the Git repository?
+ // It should be the same as long as there are no bugs.
+
+ return ret
}
func FilenameIsImage(filename string) bool {
diff --git a/modules/templates/util_render.go b/modules/templates/util_render.go
index d1c9b082fa..659422aee7 100644
--- a/modules/templates/util_render.go
+++ b/modules/templates/util_render.go
@@ -123,16 +123,10 @@ func RenderIssueTitle(ctx context.Context, text string, metas map[string]string)
func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_model.Label) template.HTML {
var (
archivedCSSClass string
- textColor = "#111"
+ textColor = util.ContrastColor(label.Color)
labelScope = label.ExclusiveScope()
)
- r, g, b := util.HexToRBGColor(label.Color)
- // Determine if label text should be light or dark to be readable on background color
- if util.UseLightTextOnBackground(r, g, b) {
- textColor = "#eee"
- }
-
description := emoji.ReplaceAliases(template.HTMLEscapeString(label.Description))
if label.IsArchived() {
@@ -153,7 +147,7 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m
// Make scope and item background colors slightly darker and lighter respectively.
// More contrast needed with higher luminance, empirically tweaked.
- luminance := util.GetLuminance(r, g, b)
+ luminance := util.GetRelativeLuminance(label.Color)
contrast := 0.01 + luminance*0.03
// Ensure we add the same amount of contrast also near 0 and 1.
darken := contrast + math.Max(luminance+contrast-1.0, 0.0)
@@ -162,6 +156,7 @@ func RenderLabel(ctx context.Context, locale translation.Locale, label *issues_m
darkenFactor := math.Max(luminance-darken, 0.0) / math.Max(luminance, 1.0/255.0)
lightenFactor := math.Min(luminance+lighten, 1.0) / math.Max(luminance, 1.0/255.0)
+ r, g, b := util.HexToRBGColor(label.Color)
scopeBytes := []byte{
uint8(math.Min(math.Round(r*darkenFactor), 255)),
uint8(math.Min(math.Round(g*darkenFactor), 255)),
@@ -221,15 +216,16 @@ func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //n
return output
}
-func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string) template.HTML {
+func RenderLabels(ctx context.Context, locale translation.Locale, labels []*issues_model.Label, repoLink string, issue *issues_model.Issue) template.HTML {
+ isPullRequest := issue != nil && issue.IsPull
+ baseLink := fmt.Sprintf("%s/%s", repoLink, util.Iif(isPullRequest, "pulls", "issues"))
htmlCode := ``
for _, label := range labels {
// Protect against nil value in labels - shouldn't happen but would cause a panic if so
if label == nil {
continue
}
- htmlCode += fmt.Sprintf("%s ",
- repoLink, label.ID, RenderLabel(ctx, locale, label))
+ htmlCode += fmt.Sprintf(`%s `, baseLink, label.ID, RenderLabel(ctx, locale, label))
}
htmlCode += " "
return template.HTML(htmlCode)
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 15aee8912d..47c5da6485 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -7,17 +7,21 @@ import (
"context"
"html/template"
"os"
+ "strings"
"testing"
+ "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/translation"
"github.com/stretchr/testify/assert"
)
-const testInput = ` space @mention-user
+func testInput() string {
+ s := ` space @mention-user
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
@@ -36,8 +40,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
#123
- space
+ space
`
+ return strings.ReplaceAll(s, "", " ")
+}
var testMetas = map[string]string{
"user": "user13",
@@ -121,23 +127,23 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
#123
space`
- assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
+ assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput(), testMetas))
}
func TestRenderCommitMessage(t *testing.T) {
expected := `space @mention-user `
- assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas))
+ assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput(), testMetas))
}
func TestRenderCommitMessageLinkSubject(t *testing.T) {
expected := `space @mention-user `
- assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas))
+ assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput(), "https://example.com/link", testMetas))
}
func TestRenderIssueTitle(t *testing.T) {
- expected := ` space @mention-user
+ expected := ` space @mention-user
/just/a/path.bin
https://example.com/file.bin
[local link](file.bin)
@@ -156,9 +162,10 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
mail@domain.com
@mention-user test
#123
- space
+ space
`
- assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
+ expected = strings.ReplaceAll(expected, "", " ")
+ assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput(), testMetas))
}
func TestRenderMarkdownToHtml(t *testing.T) {
@@ -183,5 +190,20 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
#123
space
`
- assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput))
+ assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput()))
+}
+
+func TestRenderLabels(t *testing.T) {
+ ctx := context.Background()
+ locale := &translation.MockLocale{}
+
+ label := &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
+ issue := &issues.Issue{}
+ expected := `/owner/repo/issues?labels=123`
+ assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected)
+
+ label = &issues.Label{ID: 123, Name: "label-name", Color: "label-color"}
+ issue = &issues.Issue{IsPull: true}
+ expected = `/owner/repo/pulls?labels=123`
+ assert.Contains(t, RenderLabels(ctx, locale, []*issues.Label{label}, "/owner/repo", issue), expected)
}
diff --git a/modules/util/color.go b/modules/util/color.go
index 240b045c28..9c520dce78 100644
--- a/modules/util/color.go
+++ b/modules/util/color.go
@@ -4,22 +4,10 @@ package util
import (
"fmt"
- "math"
"strconv"
"strings"
)
-// Check similar implementation in web_src/js/utils/color.js and keep synchronization
-
-// Return R, G, B values defined in reletive luminance
-func getLuminanceRGB(channel float64) float64 {
- sRGB := channel / 255
- if sRGB <= 0.03928 {
- return sRGB / 12.92
- }
- return math.Pow((sRGB+0.055)/1.055, 2.4)
-}
-
// Get color as RGB values in 0..255 range from the hex color string (with or without #)
func HexToRBGColor(colorString string) (float64, float64, float64) {
hexString := colorString
@@ -47,19 +35,23 @@ func HexToRBGColor(colorString string) (float64, float64, float64) {
return r, g, b
}
-// return luminance given RGB channels
-// Reference from: https://www.w3.org/WAI/GL/wiki/Relative_luminance
-func GetLuminance(r, g, b float64) float64 {
- R := getLuminanceRGB(r)
- G := getLuminanceRGB(g)
- B := getLuminanceRGB(b)
- luminance := 0.2126*R + 0.7152*G + 0.0722*B
- return luminance
+// Returns relative luminance for a SRGB color - https://en.wikipedia.org/wiki/Relative_luminance
+// Keep this in sync with web_src/js/utils/color.js
+func GetRelativeLuminance(color string) float64 {
+ r, g, b := HexToRBGColor(color)
+ return (0.2126729*r + 0.7151522*g + 0.0721750*b) / 255
}
-// Reference from: https://firsching.ch/github_labels.html
-// In the future WCAG 3 APCA may be a better solution.
-// Check if text should use light color based on RGB of background
-func UseLightTextOnBackground(r, g, b float64) bool {
- return GetLuminance(r, g, b) < 0.453
+func UseLightText(backgroundColor string) bool {
+ return GetRelativeLuminance(backgroundColor) < 0.453
+}
+
+// Given a background color, returns a black or white foreground color that the highest
+// contrast ratio. In the future, the APCA contrast function, or CSS `contrast-color` will be better.
+// https://github.com/color-js/color.js/blob/eb7b53f7a13bb716ec8b28c7a56f052cd599acd9/src/contrast/APCA.js#L42
+func ContrastColor(backgroundColor string) string {
+ if UseLightText(backgroundColor) {
+ return "#fff"
+ }
+ return "#000"
}
diff --git a/modules/util/color_test.go b/modules/util/color_test.go
index d96ac36730..be6e6b122a 100644
--- a/modules/util/color_test.go
+++ b/modules/util/color_test.go
@@ -33,33 +33,31 @@ func Test_HexToRBGColor(t *testing.T) {
}
}
-func Test_UseLightTextOnBackground(t *testing.T) {
+func Test_UseLightText(t *testing.T) {
cases := []struct {
- r float64
- g float64
- b float64
- expected bool
+ color string
+ expected string
}{
- {215, 58, 74, true},
- {0, 117, 202, true},
- {207, 211, 215, false},
- {162, 238, 239, false},
- {112, 87, 255, true},
- {0, 134, 114, true},
- {228, 230, 105, false},
- {216, 118, 227, true},
- {255, 255, 255, false},
- {43, 134, 133, true},
- {43, 135, 134, true},
- {44, 135, 134, true},
- {59, 182, 179, true},
- {124, 114, 104, true},
- {126, 113, 108, true},
- {129, 112, 109, true},
- {128, 112, 112, true},
+ {"#d73a4a", "#fff"},
+ {"#0075ca", "#fff"},
+ {"#cfd3d7", "#000"},
+ {"#a2eeef", "#000"},
+ {"#7057ff", "#fff"},
+ {"#008672", "#fff"},
+ {"#e4e669", "#000"},
+ {"#d876e3", "#000"},
+ {"#ffffff", "#000"},
+ {"#2b8684", "#fff"},
+ {"#2b8786", "#fff"},
+ {"#2c8786", "#000"},
+ {"#3bb6b3", "#000"},
+ {"#7c7268", "#fff"},
+ {"#7e716c", "#fff"},
+ {"#81706d", "#fff"},
+ {"#807070", "#fff"},
+ {"#84b6eb", "#000"},
}
for n, c := range cases {
- result := UseLightTextOnBackground(c.r, c.g, c.b)
- assert.Equal(t, c.expected, result, "case %d: error should match", n)
+ assert.Equal(t, c.expected, ContrastColor(c.color), "case %d: error should match", n)
}
}
diff --git a/modules/util/util.go b/modules/util/util.go
index 3921002e2a..44b5a6ed81 100644
--- a/modules/util/util.go
+++ b/modules/util/util.go
@@ -214,7 +214,7 @@ func ToPointer[T any](val T) *T {
}
// Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal"
-func Iif[T comparable](condition bool, trueVal, falseVal T) T {
+func Iif[T any](condition bool, trueVal, falseVal T) T {
if condition {
return trueVal
}
diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go
index 621640895b..0bed726793 100644
--- a/modules/web/middleware/cookie.go
+++ b/modules/web/middleware/cookie.go
@@ -45,10 +45,32 @@ func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
SameSite: setting.SessionConfig.SameSite,
}
resp.Header().Add("Set-Cookie", cookie.String())
- if maxAge < 0 {
- // There was a bug in "setting.SessionConfig.CookiePath" code, the old default value of it was empty "".
- // So we have to delete the cookie on path="" again, because some old code leaves cookies on path="".
- cookie.Path = strings.TrimSuffix(setting.SessionConfig.CookiePath, "/")
- resp.Header().Add("Set-Cookie", cookie.String())
- }
+ // Previous versions would use a cookie path with a trailing /.
+ // These are more specific than cookies without a trailing /, so
+ // we need to delete these if they exist.
+ DeleteLegacySiteCookie(resp, name)
+}
+
+// DeleteLegacySiteCookie deletes the cookie with the given name at the cookie
+// path with a trailing /, which would unintentionally override the cookie.
+func DeleteLegacySiteCookie(resp http.ResponseWriter, name string) {
+ if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
+ // If the cookie path ends with /, no legacy cookies will take
+ // precedence, so do nothing. The exception is that cookies with no
+ // path could override other cookies, but it's complicated and we don't
+ // currently handle that.
+ return
+ }
+
+ cookie := &http.Cookie{
+ Name: name,
+ Value: "",
+ MaxAge: -1,
+ Path: setting.SessionConfig.CookiePath + "/",
+ Domain: setting.SessionConfig.Domain,
+ Secure: setting.SessionConfig.Secure,
+ HttpOnly: true,
+ SameSite: setting.SessionConfig.SameSite,
+ }
+ resp.Header().Add("Set-Cookie", cookie.String())
}
diff --git a/options/license/APL-1.0 b/options/license/APL-1.0
index 261f2d687c..0748f90cd9 100644
--- a/options/license/APL-1.0
+++ b/options/license/APL-1.0
@@ -210,21 +210,21 @@ PART 1: INITIAL CONTRIBUTOR AND DESIGNATED WEB SITE
The Initial Contributor is:
____________________________________________________
-
+
[Enter full name of Initial Contributor]
Address of Initial Contributor:
________________________________________________
-
+
________________________________________________
-
+
________________________________________________
-
+
[Enter address above]
The Designated Web Site is:
__________________________________________________
-
+
[Enter URL for Designated Web Site of Initial Contributor]
NOTE: The Initial Contributor is to complete this Part 1, along with Parts 2, 3, and 5, and, if applicable, Parts 4 and 6.
@@ -237,27 +237,27 @@ The date on which the Initial Work was first available under this License: _____
PART 3: GOVERNING JURISDICTION
-For the purposes of this License, the Governing Jurisdiction is _________________________________________________.
[Initial Contributor to Enter Governing Jurisdiction here]
+For the purposes of this License, the Governing Jurisdiction is _________________________________________________. [Initial Contributor to Enter Governing Jurisdiction here]
PART 4: THIRD PARTIES
For the purposes of this License, "Third Party" has the definition set forth below in the ONE paragraph selected by the Initial Contributor from paragraphs A, B, C, D and E when the Initial Work is distributed or otherwise made available by the Initial Contributor. To select one of the following paragraphs, the Initial Contributor must place an "X" or "x" in the selection box alongside the one respective paragraph selected.
SELECTION
-
+
BOX PARAGRAPH
-[ ] A. "THIRD PARTY" means any third party.
-
-
-[ ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b).
-
-
-[ ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest.
-
-
-[ ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
-
-
-[ ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
+[ ] A. "THIRD PARTY" means any third party.
+
+
+[ ] B. "THIRD PARTY" means any third party except for any of the following: (a) a wholly owned subsidiary of the Subsequent Contributor in question; (b) a legal entity (the "PARENT") that wholly owns the Subsequent Contributor in question; or (c) a wholly owned subsidiary of the wholly owned subsidiary in (a) or of the Parent in (b).
+
+
+[ ] C. "THIRD PARTY" means any third party except for any of the following: (a) any Person directly or indirectly owning a majority of the voting interest in the Subsequent Contributor or (b) any Person in which the Subsequent Contributor directly or indirectly owns a majority voting interest.
+
+
+[ ] D. "THIRD PARTY" means any third party except for any Person directly or indirectly controlled by the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
+
+
+[ ] E. "THIRD PARTY" means any third party except for any Person directly or indirectly controlling, controlled by, or under common control with the Subsequent Contributor. For purposes of this definition, "control" shall mean the power to direct or cause the direction of, the management and policies of such Person whether through the ownership of voting interests, by contract, or otherwise.
The default definition of "THIRD PARTY" is the definition set forth in paragraph A, if NONE OR MORE THAN ONE of paragraphs A, B, C, D or E in this Part 4 are selected by the Initial Contributor.
PART 5: NOTICE
@@ -271,8 +271,8 @@ PART 6: PATENT LICENSING TERMS
For the purposes of this License, paragraphs A, B, C, D and E of this Part 6 of Exhibit A are only incorporated and form part of the terms of the License if the Initial Contributor places an "X" or "x" in the selection box alongside the YES answer to the question immediately below.
Is this a Patents-Included License pursuant to Section 2.2 of the License?
-YES [ ]
-NO [ ]
+YES [ ]
+NO [ ]
By default, if YES is not selected by the Initial Contributor, the answer is NO.
diff --git a/options/license/BSD-2-clause-first-lines b/options/license/BSD-2-clause-first-lines
new file mode 100644
index 0000000000..3774caf24a
--- /dev/null
+++ b/options/license/BSD-2-clause-first-lines
@@ -0,0 +1,27 @@
+Copyright (C) 2006,2007,2009 NTT (Nippon Telegraph and Telephone
+Corporation). All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer as the first lines of this file unmodified.
+
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY NTT "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL NTT BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/options/license/IBM-pibs b/options/license/IBM-pibs
index 49454b8b1e..ee9c7be36d 100644
--- a/options/license/IBM-pibs
+++ b/options/license/IBM-pibs
@@ -4,5 +4,5 @@ Any user of this software should understand that IBM cannot provide technical su
Any person who transfers this source code or any derivative work must include the IBM copyright notice, this paragraph, and the preceding two paragraphs in the transferred software.
-COPYRIGHT I B M CORPORATION 2002
-LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+COPYRIGHT I B M CORPORATION 2002
+LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
diff --git a/options/license/NCGL-UK-2.0 b/options/license/NCGL-UK-2.0
index 31fbad6f83..15c4f63c22 100644
--- a/options/license/NCGL-UK-2.0
+++ b/options/license/NCGL-UK-2.0
@@ -12,15 +12,15 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice
This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations.
You are free to:
- copy, publish, distribute and transmit the Information;
+ copy, publish, distribute and transmit the Information;
adapt the Information;
exploit the Information for Non-Commercial purposes for example, by combining it with other information in your own product or application.
You are not permitted to:
- exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation.
+ exercise any of the rights granted to you by this licence in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation.
You must, where you do any of the above:
- acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
+ acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
If the Information Provider does not provide a specific attribution statement, you must use the following:
Contains information licensed under the Non-Commercial Government Licence v2.0.
diff --git a/options/license/NPL-1.1 b/options/license/NPL-1.1
index 62c5296400..0d5457ff04 100644
--- a/options/license/NPL-1.1
+++ b/options/license/NPL-1.1
@@ -2,7 +2,7 @@ Netscape Public LIcense version 1.1
AMENDMENTS
-The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License. Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1.
+The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla Public License Version 1.1 with the following Amendments, including Exhibit A-Netscape Public License. Files identified with "Exhibit A-Netscape Public License" are governed by the Netscape Public License Version 1.1.
Additional Terms applicable to the Netscape Public License.
@@ -28,7 +28,7 @@ Additional Terms applicable to the Netscape Public License.
Notwithstanding the limitations of Section 11 above, the provisions regarding litigation in Section 11(a), (b) and (c) of the License shall apply to all disputes relating to this License.
EXHIBIT A-Netscape Public License.
-
+
"The contents of this file are subject to the Netscape Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License.
@@ -37,8 +37,8 @@ The Original Code is Mozilla Communicator client code, released March 31, 1998.
The Initial Developer of the Original Code is Netscape Communications Corporation. Portions created by Netscape are Copyright (C) 1998-1999 Netscape Communications Corporation. All Rights Reserved.
Contributor(s): ______________________________________.
-
-Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License."
+
+Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the NPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the NPL or the [___] License."
Mozilla Public License Version 1.1
diff --git a/options/license/OCCT-PL b/options/license/OCCT-PL
index 85df3c73c5..9b6fccc1c9 100644
--- a/options/license/OCCT-PL
+++ b/options/license/OCCT-PL
@@ -6,7 +6,7 @@ OPEN CASCADE releases and makes publicly available the source code of the softwa
It is not the purpose of this license to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this license has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
Please read this license carefully and completely before downloading this software. By downloading, using, modifying, distributing and sublicensing this software, you indicate your acceptance to be bound by the terms and conditions of this license. If you do not want to accept or cannot accept for any reasons the terms and conditions of this license, please do not download or use in any manner this software.
-
+
1. Definitions
Unless there is something in the subject matter or in the context inconsistent therewith, the capitalized terms used in this License shall have the following meaning.
@@ -26,13 +26,13 @@ Unless there is something in the subject matter or in the context inconsistent t
"Software": means the Original Code, the Modifications, the combination of Original Code and any Modifications or any respective portions thereof.
"You" or "Your": means an individual or a legal entity exercising rights under this License
-
+
2. Acceptance of license
By using, reproducing, modifying, distributing or sublicensing the Software or any portion thereof, You expressly indicate Your acceptance of the terms and conditions of this License and undertake to act in accordance with all the provisions of this License applicable to You.
-
+
3. Scope and purpose
This License applies to the Software and You may not use, reproduce, modify, distribute, sublicense or circulate the Software, or any portion thereof, except as expressly provided under this License. Any attempt to otherwise use, reproduce, modify, distribute or sublicense the Software is void and will automatically terminate Your rights under this License.
-
+
4. Contributor license
Subject to the terms and conditions of this License, the Initial Developer and each of the Contributors hereby grant You a world-wide, royalty-free, irrevocable and non-exclusive license under the Applicable Intellectual Property Rights they own or control, to use, reproduce, modify, distribute and sublicense the Software provided that:
diff --git a/options/license/OGL-UK-1.0 b/options/license/OGL-UK-1.0
index a761c9916f..867c0e353b 100644
--- a/options/license/OGL-UK-1.0
+++ b/options/license/OGL-UK-1.0
@@ -10,20 +10,20 @@ The Licensor grants you a worldwide, royalty-free, perpetual, non-exclusive lice
This licence does not affect your freedom under fair dealing or fair use or any other copyright or database right exceptions and limitations.
You are free to:
- copy, publish, distribute and transmit the Information;
+ copy, publish, distribute and transmit the Information;
adapt the Information;
exploit the Information commercially for example, by combining it with other Information, or by including it in your own product or application.
You must, where you do any of the above:
- acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
- If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following:
Contains public sector information licensed under the Open Government Licence v1.0.
+ acknowledge the source of the Information by including any attribution statement specified by the Information Provider(s) and, where possible, provide a link to this licence;
+ If the Information Provider does not provide a specific attribution statement, or if you are using Information from several Information Providers and multiple attributions are not practical in your product or application, you may consider using the following: Contains public sector information licensed under the Open Government Licence v1.0.
ensure that you do not use the Information in a way that suggests any official status or that the Information Provider endorses you or your use of the Information;
ensure that you do not mislead others or misrepresent the Information or its source;
ensure that your use of the Information does not breach the Data Protection Act 1998 or the Privacy and Electronic Communications (EC Directive) Regulations 2003.
These are important conditions of this licence and if you fail to comply with them the rights granted to you under this licence, or any similar licence granted by the Licensor, will end automatically.
- Exemptions
+ Exemptions
This licence does not cover the use of:
- personal data in the Information;
@@ -48,22 +48,22 @@ Definitions
In this licence, the terms below have the following meanings:
-‘Information’
means information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence.
+‘Information’ means information protected by copyright or by database right (for example, literary and artistic works, content, data and source code) offered for use under the terms of this licence.
-‘Information Provider’
means the person or organisation providing the Information under this licence.
+‘Information Provider’ means the person or organisation providing the Information under this licence.
-‘Licensor’
means any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majesty’s Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence.
+‘Licensor’ means any Information Provider which has the authority to offer Information under the terms of this licence or the Controller of Her Majesty’s Stationery Office, who has the authority to offer Information subject to Crown copyright and Crown database rights and Information subject to copyright and database right that has been assigned to or acquired by the Crown, under the terms of this licence.
-‘Use’
as a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format.
+‘Use’ as a verb, means doing any act which is restricted by copyright or database right, whether in the original medium or in any other medium, and includes without limitation distributing, copying, adapting, modifying as may be technically necessary to use it in a different mode or format.
-‘You’
means the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence.
+‘You’ means the natural or legal person, or body of persons corporate or incorporate, acquiring rights under this licence.
About the Open Government Licence
The Controller of Her Majesty’s Stationery Office (HMSO) has developed this licence as a tool to enable Information Providers in the public sector to license the use and re-use of their Information under a common open licence. The Controller invites public sector bodies owning their own copyright and database rights to permit the use of their Information under this licence.
-The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controller’s offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework.
+The Controller of HMSO has authority to license Information subject to copyright and database right owned by the Crown. The extent of the Controller’s offer to license this Information under the terms of this licence is set out in the UK Government Licensing Framework.
This is version 1.0 of the Open Government Licence. The Controller of HMSO may, from time to time, issue new versions of the Open Government Licence. However, you may continue to use Information licensed under this version should you wish to do so.
These terms have been aligned to be interoperable with any Creative Commons Attribution Licence, which covers copyright, and Open Data Commons Attribution License, which covers database rights and applicable copyrights.
-Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website.
+Further context, best practice and guidance can be found in the UK Government Licensing Framework section on The National Archives website.
diff --git a/options/license/OSET-PL-2.1 b/options/license/OSET-PL-2.1
index 15f0c7758c..e0ed2e1398 100644
--- a/options/license/OSET-PL-2.1
+++ b/options/license/OSET-PL-2.1
@@ -100,7 +100,8 @@ If it is impossible for You to comply with any of the terms of this License with
5.1 Failure to Comply
The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60-days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30-days after Your receipt of the notice.
- 5.2 Patent Infringement Claims
If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
+ 5.2 Patent Infringement Claims
+ If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate.
5.3 Additional Compliance Terms
Notwithstanding the foregoing in this Section 5, for purposes of this Section, if You breach Section 3.1 (Distribution of Source Form), Section 3.2 (Distribution of Executable Form), Section 3.3 (Distribution of a Larger Work), or Section 3.4 (Notices), then becoming compliant as described in Section 5.1 must also include, no later than 30 days after receipt by You of notice of such violation by a Contributor, making the Covered Software available in Source Code Form as required by this License on a publicly available computer network for a period of no less than three (3) years.
diff --git a/options/license/SHL-2.0 b/options/license/SHL-2.0
index e522a396fe..9218b47a72 100644
--- a/options/license/SHL-2.0
+++ b/options/license/SHL-2.0
@@ -1,22 +1,22 @@
# Solderpad Hardware Licence Version 2.0
-This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation.
+This licence (the “Licence”) operates as a wraparound licence to the Apache License Version 2.0 (the “Apache License”) and grants to You the rights, and imposes the obligations, set out in the Apache License (which can be found here: http://apache.org/licenses/LICENSE-2.0), with the following extensions. It must be read in conjunction with the Apache License. Section 1 below modifies definitions in the Apache License, and section 2 below replaces sections 2 of the Apache License. You may, at your option, choose to treat any Work released under this License as released under the Apache License (thus ignoring all sections written below entirely). Words in italics indicate changes rom the Apache License, but are indicative and not to be taken into account in interpretation.
1. The definitions set out in the Apache License are modified as follows:
-Copyright any reference to ‘copyright’ (whether capitalised or not) includes ‘Rights’ (as defined below).
+Copyright any reference to ‘copyright’ (whether capitalised or not) includes ‘Rights’ (as defined below).
-Contribution also includes any design, as well as any work of authorship.
+Contribution also includes any design, as well as any work of authorship.
-Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof.
+Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of the Work and Derivative Works thereof.
-Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).
+Object form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).
-Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks).
+Rights means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks).
-Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files.
-Work also includes a design or work of authorship, whether in Source form or other Object form.
+Source form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files.
+Work also includes a design or work of authorship, whether in Source form or other Object form.
2. Grant of Licence
-2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist.
+2.1 Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, make, adapt, repair, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist.
diff --git a/options/license/SHL-2.1 b/options/license/SHL-2.1
index 4815a9e5ed..c9ae53741f 100644
--- a/options/license/SHL-2.1
+++ b/options/license/SHL-2.1
@@ -19,7 +19,7 @@ The following definitions shall replace the corresponding definitions in the Apa
"License" shall mean this Solderpad Hardware License version 2.1, being the terms and conditions for use, manufacture, instantiation, adaptation, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the Rights owner or entity authorized by the Rights owner that is granting the License.
-
+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship or design. For the purposes of this License, Derivative Works shall not include works that remain reversibly separable from, or merely link (or bind by name) or physically connect to or interoperate with the Work and Derivative Works thereof.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form or the application of a Source form to physical material, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design or physical object or material and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, moulds, artwork and semiconductor topographies (mask works).
diff --git a/options/license/SISSL b/options/license/SISSL
index 7d6ad9d66c..af38d02d92 100644
--- a/options/license/SISSL
+++ b/options/license/SISSL
@@ -36,13 +36,13 @@ Sun Industry Standards Source License - Version 1.1
2.0 SOURCE CODE LICENSE
- 2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:
+ 2.1 The Initial Developer Grant The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims:
(a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License.
- (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications.
+ (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices, including but not limited to Modifications.
3.0 DISTRIBUTION OBLIGATIONS
@@ -92,14 +92,14 @@ This License represents the complete agreement concerning subject matter hereof.
EXHIBIT A - Sun Standards License
-"The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________.
+"The contents of this file are subject to the Sun Standards License Version 1.1 (the "License"); You may not use this file except in compliance with the License. You may obtain a copy of the License at _______________________________.
-Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
+Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the License for the specific language governing rights and limitations under the License.
The Original Code is ______________________________________.
-The Initial Developer of the Original Code is:
+The Initial Developer of the Original Code is:
Sun Microsystems, Inc..
Portions created by: _______________________________________
diff --git a/options/license/Sun-PPP-2000 b/options/license/Sun-PPP-2000
new file mode 100644
index 0000000000..914c19544a
--- /dev/null
+++ b/options/license/Sun-PPP-2000
@@ -0,0 +1,13 @@
+Copyright (c) 2000 by Sun Microsystems, Inc.
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation is hereby granted, provided that the above copyright
+notice appears in all copies.
+
+SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
+THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
+ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
diff --git a/options/license/W3C-19980720 b/options/license/W3C-19980720
index a8554039ef..134879044d 100644
--- a/options/license/W3C-19980720
+++ b/options/license/W3C-19980720
@@ -4,7 +4,7 @@ Copyright (c) 1994-2002 World Wide Web Consortium, (Massachusetts Institute of T
This W3C work (including software, documents, or other related items) is being provided by the copyright holders under the following license. By obtaining, using and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions:
-Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
+Permission to use, copy, modify, and distribute this software and its documentation, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the software and documentation or portions thereof, including modifications, that you make:
1. The full text of this NOTICE in a location viewable to users of the redistributed or derivative work.
diff --git a/options/license/pkgconf b/options/license/pkgconf
new file mode 100644
index 0000000000..b8b2ffd996
--- /dev/null
+++ b/options/license/pkgconf
@@ -0,0 +1,7 @@
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+This software is provided 'as is' and without any warranty, express or
+implied. In no event shall the authors be liable for any damages arising
+from the use of this software.
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index 82a8fe5d45..57c44e4b26 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -164,8 +164,6 @@ search=Hledat...
type_tooltip=Druh vyhledávání
fuzzy=Fuzzy
fuzzy_tooltip=Zahrnout výsledky, které také úzce odpovídají hledanému výrazu
-match=Shoda
-match_tooltip=Zahrnout pouze výsledky, které odpovídají přesnému hledanému výrazu
repo_kind=Hledat repozitáře...
user_kind=Hledat uživatele...
org_kind=Hledat organizace...
@@ -714,7 +712,6 @@ cancel=Zrušit
language=Jazyk
ui=Motiv vzhledu
hidden_comment_types=Skryté typy komentářů
-hidden_comment_types_description=Zde zkontrolované typy komentářů nebudou zobrazeny na stránkách problémů. Zaškrtnutí „Štítek“ například odstraní všechny komentáře „ přidal/odstranil “.
hidden_comment_types.ref_tooltip=Komentáře, na které se odkazovalo z jiného úkolu/commitu/…
hidden_comment_types.issue_ref_tooltip=Komentáře, kde uživatel změní větev/značku spojenou s problémem
comment_type_group_reference=Reference
@@ -1286,7 +1283,6 @@ editor.or=nebo
editor.cancel_lower=Zrušit
editor.commit_signed_changes=Odevzdat podepsané změny
editor.commit_changes=Odevzdat změny
-editor.add_tmpl=Přidán „“
editor.add=Přidat %s
editor.update=Aktualizovat %s
editor.delete=Odstranit %s
@@ -3075,14 +3071,12 @@ auths.tips=Tipy
auths.tips.oauth2.general=Ověřování OAuth2
auths.tips.oauth2.general.tip=Při registraci nové OAuth2 autentizace by URL callbacku/přesměrování měla být:
auths.tip.oauth2_provider=Poskytovatel OAuth2
-auths.tip.bitbucket=Vytvořte nového OAuth konzumenta na https://bitbucket.org/account/user//oauth-consumers/new a přidejte oprávnění „Account“ - „Read“
auths.tip.nextcloud=Zaregistrujte nového OAuth konzumenta na vaší instanci pomocí následujícího menu „Nastavení -> Zabezpečení -> OAuth 2.0 klient“
auths.tip.dropbox=Vytvořte novou aplikaci na https://www.dropbox.com/developers/apps
auths.tip.facebook=Registrujte novou aplikaci na https://developers.facebook.com/apps a přidejte produkt „Facebook Login“
auths.tip.github=Registrujte novou OAuth aplikaci na https://github.com/settings/applications/new
auths.tip.gitlab_new=Zaregistrujte novou aplikaci na https://gitlab.com/-/profile/applications
auths.tip.google_plus=Získejte klientské pověření OAuth2 z Google API konzole na https://console.developers.google.com/
-auths.tip.openid_connect=Použijte OpenID URL pro objevování spojení (/.well-known/openid-configuration) k nastavení koncových bodů
auths.tip.twitter=Jděte na https://dev.twitter.com/apps, vytvořte aplikaci a ujistěte se, že volba „Allow this application to be used to Sign in with Twitter“ je povolená
auths.tip.discord=Registrujte novou aplikaci na https://discordapp.com/developers/applications/me
auths.tip.gitea=Registrovat novou Oauth2 aplikaci. Návod naleznete na https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 9a09c2922e..f591b75577 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -164,8 +164,6 @@ search=Suche ...
type_tooltip=Suchmodus
fuzzy=Ähnlich
fuzzy_tooltip=Ergebnisse einbeziehen, die dem Suchbegriff ähnlich sind
-match=Genau
-match_tooltip=Nur genau zum Suchbegriff passende Ergebnisse einbeziehen
repo_kind=Repositories durchsuchen ...
user_kind=Benutzer durchsuchen ...
org_kind=Organisationen durchsuchen ...
@@ -714,7 +712,6 @@ cancel=Abbrechen
language=Sprache
ui=Theme
hidden_comment_types=Ausgeblendeter Kommentartypen
-hidden_comment_types_description=Die hier markierten Kommentartypen werden nicht innerhalb der Issue-Seiten angezeigt. Das Überprüfen von "Label" entfernt beispielsweise alle " hinzugefügt/entfernt " Kommentare.
hidden_comment_types.ref_tooltip=Kommentare, in denen dieses Issue von einem anderen Issue/Commit referenziert wurde
hidden_comment_types.issue_ref_tooltip=Kommentare, bei denen der Benutzer den Branch/Tag des Issues ändert
comment_type_group_reference=Verweis auf Mitglieder
@@ -1287,7 +1284,6 @@ editor.or=oder
editor.cancel_lower=Abbrechen
editor.commit_signed_changes=Committe signierte Änderungen
editor.commit_changes=Änderungen committen
-editor.add_tmpl='' hinzufügen
editor.add=%s hinzugefügt
editor.update=%s aktualisiert
editor.delete=%s gelöscht
@@ -3083,14 +3079,12 @@ auths.tips=Tipps
auths.tips.oauth2.general=OAuth2-Authentifizierung
auths.tips.oauth2.general.tip=Beim Registrieren einer OAuth2-Anwendung sollte die Callback-URL folgendermaßen lauten:
auths.tip.oauth2_provider=OAuth2-Anbieter
-auths.tip.bitbucket=Registriere einen neuen OAuth-Consumer unter https://bitbucket.org/account/user//oauth-consumers/new und füge die Berechtigung „Account“ – „Read“ hinzu.
auths.tip.nextcloud=Registriere über das "Settings -> Security -> OAuth 2.0 client"-Menü einen neuen "OAuth consumer" auf der Nextcloud-Instanz
auths.tip.dropbox=Erstelle eine neue App auf https://www.dropbox.com/developers/apps.
auths.tip.facebook=Erstelle eine neue Anwendung auf https://developers.facebook.com/apps und füge das Produkt „Facebook Login“ hinzu.
auths.tip.github=Erstelle unter https://github.com/settings/applications/new eine neue OAuth-Anwendung.
auths.tip.gitlab_new=Erstelle eine neue Anwendung unter https://gitlab.com/-/profile/applications
auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google-API-Konsole unter https://console.developers.google.com/
-auths.tip.openid_connect=Benutze die OpenID-Connect-Discovery-URL (/.well-known/openid-configuration), um die Endpunkte zu spezifizieren
auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist
auths.tip.discord=Erstelle unter https://discordapp.com/developers/applications/me eine neue Anwendung.
auths.tip.gitea=Registriere eine neue OAuth2-Anwendung. Eine Anleitung findest du unter https://docs.gitea.com/development/oauth2-provider/
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index 6ce5ae1ce9..64db2348da 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -651,7 +651,6 @@ cancel=Ακύρωση
language=Γλώσσα
ui=Θέμα Διεπαφής
hidden_comment_types=Κρυμμένοι τύποι σχολίων
-hidden_comment_types_description=Οι τύποι σχολίων που επιλέγονται εδώ δε θα εμφανίζονται μέσα στις σελίδες ζητημάτων. Επιλέγοντας π.χ το "Σήματα", θα αφαιρεθούν όλα τα σχόλια σαν το " πρόσθεσε/αφαίρεσε τα σήματα ".
hidden_comment_types.ref_tooltip=Σχόλια όπου αυτό το ζήτημα αναφέρθηκε από άλλο ζήτημα/υποβολή/…
hidden_comment_types.issue_ref_tooltip=Σχόλια όπου ο χρήστης αλλάζει τον κλάδο/ετικέτα που σχετίζεται με το ζήτημα
comment_type_group_reference=Αναφορά
@@ -1214,7 +1213,6 @@ editor.or=ή
editor.cancel_lower=Ακύρωση
editor.commit_signed_changes=Υποβολή Υπογεγραμμένων Αλλαγών
editor.commit_changes=Υποβολή Αλλαγών
-editor.add_tmpl=Προσθήκη ''
editor.add=Προσθήκη %s
editor.update=Ενημέρωση %s
editor.delete=Διαγραφή %s
@@ -2970,13 +2968,11 @@ auths.tips=Συμβουλές
auths.tips.oauth2.general=Ταυτοποίηση OAuth2
auths.tips.oauth2.general.tip=Κατά την εγγραφή μιας νέας ταυτοποίησης OAuth2, το URL κλήσης/ανακατεύθυνσης πρέπει να είναι:
auths.tip.oauth2_provider=Πάροχος OAuth2
-auths.tip.bitbucket=Καταχωρήστε ένα νέο καταναλωτή OAuth στο https://bitbucket.org/account/user//oauth-consumers/new και προσθέστε το δικαίωμα 'Account' - 'Read'
auths.tip.nextcloud=`Καταχωρήστε ένα νέο καταναλωτή OAuth στην υπηρεσία σας χρησιμοποιώντας το παρακάτω μενού "Settings -> Security -> OAuth 2.0 client"`
auths.tip.dropbox=Δημιουργήστε μια νέα εφαρμογή στο https://www.dropbox.com/developers/apps
auths.tip.facebook=`Καταχωρήστε μια νέα εφαρμογή στο https://developers.facebook.com/apps και προσθέστε το προϊόν "Facebook Login"`
auths.tip.github=Καταχωρήστε μια νέα εφαρμογή OAuth στο https://github.com/settings/applications/new
auths.tip.google_plus=Αποκτήστε τα διαπιστευτήρια πελάτη OAuth2 από την κονσόλα API της Google στο https://console.developers.google.com/
-auths.tip.openid_connect=Χρησιμοποιήστε το OpenID Connect Discovery URL (/.well known/openid-configuration) για να καθορίσετε τα τελικά σημεία
auths.tip.twitter=Πηγαίνετε στο https://dev.twitter.com/apps, δημιουργήστε μια εφαρμογή και βεβαιωθείτε ότι η επιλογή “Allow this application to be used to Sign in with Twitter” είναι ενεργοποιημένη
auths.tip.discord=Καταχωρήστε μια νέα εφαρμογή στο https://discordapp.com/developers/applications/me
auths.tip.gitea=Καταχωρήστε μια νέα εφαρμογή OAuth2. Μπορείτε να βρείτε τον οδηγό στο https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 0a3d12d7a4..c602aba53d 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -164,8 +164,8 @@ search = Search...
type_tooltip = Search type
fuzzy = Fuzzy
fuzzy_tooltip = Include results that also match the search term closely
-match = Match
-match_tooltip = Include only results that match the exact search term
+exact = Exact
+exact_tooltip = Include only results that match the exact search term
repo_kind = Search repos...
user_kind = Search users...
org_kind = Search orgs...
@@ -179,6 +179,8 @@ branch_kind = Search branches...
commit_kind = Search commits...
runner_kind = Search runners...
no_results = No matching results found.
+issue_kind = Search issues...
+pull_kind = Search pulls...
keyword_search_unavailable = Searching by keyword is currently not available. Please contact the site administrator.
[aria]
@@ -714,7 +716,7 @@ cancel = Cancel
language = Language
ui = Theme
hidden_comment_types = Hidden comment types
-hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all " added/removed " comments.
+hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "{user} added/removed {label}" comments.
hidden_comment_types.ref_tooltip = Comments where this issue was referenced from another issue/commit/…
hidden_comment_types.issue_ref_tooltip = Comments where the user changes the branch/tag associated with the issue
comment_type_group_reference = Reference
@@ -885,6 +887,7 @@ repo_and_org_access = Repository and Organization Access
permissions_public_only = Public only
permissions_access_all = All (public, private, and limited)
select_permissions = Select permissions
+permission_not_set = Not set
permission_no_access = No Access
permission_read = Read
permission_write = Read and Write
@@ -1289,7 +1292,7 @@ editor.or = or
editor.cancel_lower = Cancel
editor.commit_signed_changes = Commit Signed Changes
editor.commit_changes = Commit Changes
-editor.add_tmpl = Add ''
+editor.add_tmpl = Add '{filename}'
editor.add = Add %s
editor.update = Update %s
editor.delete = Delete %s
@@ -2096,6 +2099,7 @@ settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable Repository Wiki
settings.use_internal_wiki = Use Built-In Wiki
settings.default_wiki_branch_name = Default Wiki Branch Name
+settings.default_wiki_everyone_access = Default Access Permission for signed-in users:
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch.
settings.use_external_wiki = Use External Wiki
settings.external_wiki_url = External Wiki URL
@@ -3087,14 +3091,14 @@ auths.tips = Tips
auths.tips.oauth2.general = OAuth2 Authentication
auths.tips.oauth2.general.tip = When registering a new OAuth2 authentication, the callback/redirect URL should be:
auths.tip.oauth2_provider = OAuth2 Provider
-auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user//oauth-consumers/new and add the permission 'Account' - 'Read'
+auths.tip.bitbucket = Register a new OAuth consumer on https://bitbucket.org/account/user/{your-username}/oauth-consumers/new and add the permission 'Account' - 'Read'
auths.tip.nextcloud = Register a new OAuth consumer on your instance using the following menu "Settings -> Security -> OAuth 2.0 client"
auths.tip.dropbox = Create a new application at https://www.dropbox.com/developers/apps
auths.tip.facebook = Register a new application at https://developers.facebook.com/apps and add the product "Facebook Login"
auths.tip.github = Register a new OAuth application on https://github.com/settings/applications/new
auths.tip.gitlab_new = Register a new application on https://gitlab.com/-/profile/applications
auths.tip.google_plus = Obtain OAuth2 client credentials from the Google API console at https://console.developers.google.com/
-auths.tip.openid_connect = Use the OpenID Connect Discovery URL (/.well-known/openid-configuration) to specify the endpoints
+auths.tip.openid_connect = Use the OpenID Connect Discovery URL "https://{server}/.well-known/openid-configuration" to specify the endpoints
auths.tip.twitter = Go to https://dev.twitter.com/apps, create an application and ensure that the “Allow this application to be used to Sign in with Twitter” option is enabled
auths.tip.discord = Register a new application on https://discordapp.com/developers/applications/me
auths.tip.gitea = Register a new OAuth2 application. Guide can be found at https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index fc78e1d439..d1d680c14c 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -648,7 +648,6 @@ cancel=Cancelar
language=Idioma
ui=Tema
hidden_comment_types=Tipos de comentarios ocultos
-hidden_comment_types_description=Los tipos de comentarios marcados aquí no se mostrarán dentro de las páginas de incidencia. Marcar "Etiqueta" por ejemplo elimina todos los comentarios " añadidos/eliminados ".
hidden_comment_types.ref_tooltip=Comentarios donde esta incidencia fue referenciada desde otra incidencia/commit/…
hidden_comment_types.issue_ref_tooltip=Comentarios donde el usuario cambia la rama/etiqueta asociada a la incidencia
comment_type_group_reference=Referencia
@@ -1207,7 +1206,6 @@ editor.or=o
editor.cancel_lower=Cancelar
editor.commit_signed_changes=Crear commit firmado de los cambios
editor.commit_changes=Crear commit de los cambios
-editor.add_tmpl=Añadir ''
editor.add=Añadir %s
editor.update=Actualizar %s
editor.delete=Eliminar %s
@@ -2953,13 +2951,11 @@ auths.tips=Consejos
auths.tips.oauth2.general=Autenticación OAuth2
auths.tips.oauth2.general.tip=Al registrar una nueva autenticación de OAuth2, la URL de devolución de llamada/redirección debe ser:
auths.tip.oauth2_provider=Proveedor OAuth2
-auths.tip.bitbucket=Registrar un nuevo usuario de OAuth en https://bitbucket.org/account/user//oauth-consumers/new y agregar el permiso 'Cuenta' - 'Lectura'
auths.tip.nextcloud=`Registre un nuevo consumidor OAuth en su instancia usando el siguiente menú "Configuración-> Seguridad-> cliente OAuth 2.0"`
auths.tip.dropbox=Crear nueva aplicación en https://www.dropbox.com/developers/apps
auths.tip.facebook=`Registre una nueva aplicación en https://developers.facebook.com/apps y agregue el producto "Facebook Login"`
auths.tip.github=Registre una nueva aplicación OAuth en https://github.com/settings/applications/new
auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola API de Google en https://console.developers.google.com/
-auths.tip.openid_connect=Use el OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar los puntos finales
auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada
auths.tip.discord=Registrar una nueva aplicación en https://discordapp.com/developers/applications/me
auths.tip.gitea=Registrar una nueva aplicación OAuth2. Puede encontrar la guía en https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index d19eb356d2..54a4911e5c 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -947,7 +947,6 @@ editor.or=یا
editor.cancel_lower=انصراف
editor.commit_signed_changes=اعمال تغییرات امضا شده
editor.commit_changes=تغییرات کامیت
-editor.add_tmpl=افزودن ''
editor.commit_message_desc=توضیحی تخصصی به دلخواه اضافه نمایید…
editor.signoff_desc=یک تریلر Signed-off-by توسط committer در انتهای پیام گزارش commit اضافه کنید.
editor.commit_directly_to_this_branch=ثبت کامیت به صورت مستقیم در انشعاب %s .
@@ -2297,13 +2296,11 @@ auths.sspi_default_language_helper=زبان پیش فرض برای کاربرا
auths.tips=ﻧﮑﺎﺕ
auths.tips.oauth2.general=احراز هویت OAuth2
auths.tip.oauth2_provider=تامین کننده OAuth2
-auths.tip.bitbucket=ثبت یک OAuth جدید مصرف کننده بر https://bitbucket.org/account/user//oauth-consumers/new و افزودن مجوز 'Account' - 'Read'
auths.tip.nextcloud=با استفاده از منوی زیر "تنظیمات -> امنیت -> مشتری OAuth 2.0" مصرف کننده OAuth جدیدی را در نمونه خود ثبت کنید
auths.tip.dropbox=یک برنامه جدید در https://www.dropbox.com/developers/apps بسازید
auths.tip.facebook=`یک برنامه جدید در https://developers.facebook.com/apps بسازید برای ورود از طریق فیس بوک قسمت محصولات "Facebook Login"`
auths.tip.github=یک برنامه OAuth جدید در https://github.com/settings/applications/new ثبت کنید
auths.tip.google_plus=اطلاعات مربوط به مشتری OAuth2 را از کلاینت API Google در https://console.developers.google.com/
-auths.tip.openid_connect=برای مشخص کردن نقاط پایانی از آدرس OpenID Connect Discovery URL ( /.well-known/openid-configuration) استفاده کنید.
auths.tip.twitter=به https://dev.twitter.com/apps بروید ، برنامه ای ایجاد کنید و اطمینان حاصل کنید که گزینه "اجازه استفاده از این برنامه برای ورود به سیستم با Twitter" را فعال کنید
auths.tip.discord=یک برنامه جدید را در https://discordapp.com/developers/applications/me ثبت کنید
auths.tip.yandex=`یک برنامه جدید در https://oauth.yandex.com/client/new ایجاد کنید. مجوزهای زیر را از بخش "Yandex.Passport API" انتخاب کنید: "دسترسی به آدرس ایمیل"، "دسترسی به آواتار کاربر" و "دسترسی به نام کاربری، نام و نام خانوادگی، جنسیت"`
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index f283209908..ace676281f 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -767,7 +767,6 @@ editor.or=tai
editor.cancel_lower=Peru
editor.commit_signed_changes=Commitoi vahvistetut muutokset
editor.commit_changes=Commitoi muutokset
-editor.add_tmpl=Lisää ''
editor.commit_directly_to_this_branch=Commitoi suoraan %s haaraan.
editor.create_new_branch=Luo uusi haara tälle commitille ja aloita vetopyyntö.
editor.create_new_branch_np=Luo uusi haara tälle commitille.
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index dc66402901..61a6a98379 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -150,6 +150,10 @@ filter.private=Privé
[search]
+exact=Exact
+exact_tooltip=Inclure uniquement les résultats qui correspondent exactement au terme de recherche
+issue_kind=Recherche de tickets…
+pull_kind=Recherche de demandes d’ajouts…
[aria]
navbar=Barre de navigation
@@ -654,7 +658,6 @@ cancel=Annuler
language=Langue
ui=Thème
hidden_comment_types=Catégories de commentaires masqués
-hidden_comment_types_description=Cochez les catégories suivantes pour masquer les commentaires correspondants des fils d'activité. Par exemple, « Label » cache les commentaires du genre « Cerise a attribué le label Bug il y a 2 heures. »
hidden_comment_types.ref_tooltip=Commentaires où ce ticket a été référencé sur un autre ticket, révision, etc.
hidden_comment_types.issue_ref_tooltip=Commentaires où l’utilisateur change la branche/étiquette associée au ticket
comment_type_group_reference=Référence
@@ -825,6 +828,7 @@ repo_and_org_access=Accès aux Organisations et Dépôts
permissions_public_only=Publique uniquement
permissions_access_all=Tout (public, privé et limité)
select_permissions=Sélectionner les autorisations
+permission_not_set=Non défini
permission_no_access=Aucun accès
permission_read=Lecture
permission_write=Lecture et écriture
@@ -1223,7 +1227,6 @@ editor.or=ou
editor.cancel_lower=Annuler
editor.commit_signed_changes=Réviser les changements (signé)
editor.commit_changes=Réviser les changements
-editor.add_tmpl=Ajouter ''
editor.add=Ajouter %s
editor.update=Actualiser %s
editor.delete=Supprimer %s
@@ -2018,6 +2021,7 @@ settings.branches.add_new_rule=Ajouter une nouvelle règle
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki du dépôt
settings.use_internal_wiki=Utiliser le wiki interne
+settings.default_wiki_everyone_access=Autorisation d’accès par défaut pour les utilisateurs connectés :
settings.use_external_wiki=Utiliser un wiki externe
settings.external_wiki_url=URL Wiki externe
settings.external_wiki_url_error=L’URL du wiki externe n’est pas une URL valide.
@@ -2997,13 +3001,11 @@ auths.tips=Conseils
auths.tips.oauth2.general=Authentification OAuth2
auths.tips.oauth2.general.tip=Lors de l'enregistrement d'une nouvelle authentification OAuth2, l'URL de rappel/redirection doit être :
auths.tip.oauth2_provider=Fournisseur OAuth2
-auths.tip.bitbucket=`Créez un nouveau jeton OAuth sur https://bitbucket.org/account/user//oauth-consumers/new et ajoutez la permission "Compte"-"Lecture"`
auths.tip.nextcloud=`Enregistrez un nouveau consommateur OAuth sur votre instance en utilisant le menu "Paramètres -> Sécurité -> Client OAuth 2.0"`
auths.tip.dropbox=Créez une nouvelle application sur https://www.dropbox.com/developers/apps
auths.tip.facebook=`Enregistrez une nouvelle application sur https://developers.facebook.com/apps et ajoutez le produit "Facebook Login"`
auths.tip.github=Créez une nouvelle application OAuth sur https://github.com/settings/applications/new
auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Google (https://console.developers.google.com/)
-auths.tip.openid_connect=Utilisez l'URL de découvert OpenID (/.well-known/openid-configuration) pour spécifier les points d'accès
auths.tip.twitter=Rendez-vous sur https://dev.twitter.com/apps, créez une application et assurez-vous que l'option "Autoriser l'application à être utilisée avec Twitter Connect" est activée
auths.tip.discord=Enregistrer une nouvelle application sur https://discordapp.com/developers/applications/me
auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index fb229090d4..bddd6dd582 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -711,7 +711,6 @@ editor.name_your_file=Fájl elnevezése…
editor.or=vagy
editor.cancel_lower=Mégse
editor.commit_changes=Változások Véglegesítése
-editor.add_tmpl='' hozzáadása
editor.commit_message_desc=Opcionális hosszabb leírás hozzáadása…
editor.commit_directly_to_this_branch=Mentés egyenesen a(z) %s ágba.
editor.create_new_branch=Hozzon létre egy új ágat ennek a commit-nak és indíts egy egyesítési kérést.
@@ -1401,12 +1400,10 @@ auths.enable_auto_register=Automatikus regisztráció engedélyezése
auths.tips=Tippek
auths.tips.oauth2.general=OAuth2 hitelesítés
auths.tip.oauth2_provider=OAuth2 szolgáltató
-auths.tip.bitbucket=Igényeljen egy új OAuth jogosultságot itt: https://bitbucket.org/account/user//oauth-consumers/new és adja hozzá jogosultságot a "Fiókok"-"Olvasás" alá
auths.tip.dropbox=Vegyen fel új alkalmazást itt: https://www.dropbox.com/developers/apps
auths.tip.facebook=Vegyen fel új alkalmazást itt: https://developers.facebook.com/apps majd adja hozzá a "Facebook Login"-t
auths.tip.github=Vegyen fel új OAuth alkalmazást itt: https://github.com/settings/applications/new
auths.tip.google_plus=Szerezzen OAuth2 kliens hitelesítési adatokat a Google API konzolban (https://console.developers.google.com/)
-auths.tip.openid_connect=Használja az OpenID kapcsolódás felfedező URL-t (/.well-known/openid-configuration) a végpontok beállításához
auths.tip.twitter=Menyjen ide: https://dev.twitter.com/apps, hozzon létre egy alkalmazást és győződjön meg róla, hogy az “Allow this application to be used to Sign in with Twitter” opció be van kapcsolva
auths.tip.discord=Vegyen fel új alkalmazást itt:
https://discordapp.com/developers/applications/me
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index ad7e0f4062..9261077831 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -620,7 +620,6 @@ editor.filename_help=Tambahkan direktori dengan mengetikkan nama direktori diiku
editor.or=atau
editor.cancel_lower=Batalkan
editor.commit_changes=Perubahan komitmen
-editor.add_tmpl=Tambahkan ''
editor.commit_message_desc=Tambahkan deskripsi opsional yang panjang…
editor.commit_directly_to_this_branch=Komitmen langsung ke %s cabang.
editor.create_new_branch=Membuat new branch untuk tarik komit ini mulai permintaan.
@@ -1118,7 +1117,6 @@ auths.tip.oauth2_provider=Penyediaan OAuth2
auths.tip.dropbox=Membuat aplikasi baru di https://www.dropbox.com/developers/apps
auths.tip.facebook=`Daftarkan sebuah aplikasi baru di https://developers.facebook.com/apps dan tambakan produk "Facebook Masuk"`
auths.tip.github=Mendaftar aplikasi OAuth baru di https://github.com/settings/applications/new
-auths.tip.openid_connect=Gunakan membuka ID yang terhubung ke jelajah URL (/.well-known/openid-configuration) untuk menentukan titik akhir
auths.delete=Menghapus Otentikasi Sumber
auths.delete_auth_title=Menghapus Otentikasi Sumber
@@ -1331,12 +1329,53 @@ runners.task_list.repository=Repositori
runners.task_list.commit=Memperbuat
runs.commit=Memperbuat
+runs.no_matching_online_runner_helper=Tidak ada runner online yang cocok dengan label: %s
+runs.actor=Aktor
+runs.status=Status
+runs.actors_no_select=Semua aktor
+runs.status_no_select=Semua status
+runs.no_results=Tidak ada hasil yang cocok.
+runs.no_workflows=Belum ada alur kerja.
+runs.no_workflows.quick_start=Tidak tahu cara memulai dengan Gitea Actions? Lihat panduan cepat .
+runs.no_workflows.documentation=Untuk informasi lebih lanjut tentang Gitea Actions, lihat dokumentasi .
+runs.no_runs=Alur kerja belum berjalan.
+runs.empty_commit_message=(pesan commit kosong)
+workflow.disable=Nonaktifkan Alur Kerja
+workflow.disable_success=Alur kerja '%s' berhasil dinonaktifkan.
+workflow.enable=Aktifkan Alur Kerja
+workflow.enable_success=Alur kerja '%s' berhasil diaktifkan.
+workflow.disabled=Alur kerja dinonaktifkan.
+need_approval_desc=Butuh persetujuan untuk menjalankan alur kerja untuk pull request fork.
+variables=Variabel
+variables.management=Managemen Variabel
+variables.creation=Tambah Variabel
+variables.none=Belum ada variabel.
+variables.deletion=Hapus variabel
+variables.deletion.description=Menghapus variabel bersifat permanen dan tidak dapat dibatalkan. Lanjutkan?
+variables.description=Variabel akan diteruskan ke beberapa tindakan dan tidak dapat dibaca sebaliknya.
+variables.id_not_exist=Variabel dengan ID %d tidak ada.
+variables.edit=Edit Variabel
+variables.deletion.failed=Gagal menghapus variabel.
+variables.deletion.success=Variabel telah dihapus.
+variables.creation.failed=Gagal menambahkan variabel.
+variables.creation.success=Variabel "%s" telah ditambahkan.
+variables.update.failed=Gagal mengedit variabel.
+variables.update.success=Variabel telah diedit.
[projects]
+type-1.display_name=Proyek Individu
+type-2.display_name=Proyek Repositori
+type-3.display_name=Proyek Organisasi
[git.filemode]
+changed_filemode=%[1]s → %[2]s
; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
+directory=Directory
+normal_file=Normal file
+executable_file=Executable file
+symbolic_link=Symbolic link
+submodule=Submodule
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 3165c4185b..a1116eddbc 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -697,7 +697,6 @@ editor.delete_this_file=Eyða Skrá
editor.name_your_file=Nefndu skrána þína…
editor.or=eða
editor.cancel_lower=Hætta við
-editor.add_tmpl=Bæta við „“
editor.create_new_branch=Búðu til nýja grein og sameiningarbeiðni fyrir þetta framlag.
editor.create_new_branch_np=Búðu til nýja grein fyrir þetta framlag.
editor.new_branch_name_desc=Heiti nýjar greinar…
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index 9a22995dfb..b15a78ccf4 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -1018,7 +1018,6 @@ editor.or=o
editor.cancel_lower=Annulla
editor.commit_signed_changes=Conferma modifiche firmate
editor.commit_changes=Apporta le modifiche
-editor.add_tmpl=Aggiungi ''
editor.patch=Applica Patch
editor.patching=Patching:
editor.new_patch=Nuova Patch
@@ -2489,13 +2488,11 @@ auths.sspi_default_language_helper=Lingua predefinita per gli utenti creati auto
auths.tips=Consigli
auths.tips.oauth2.general=Autenticazione OAuth2
auths.tip.oauth2_provider=OAuth2 Provider
-auths.tip.bitbucket=Registra un nuovo cliente OAuth su https://bitbucket.org/account/user//oauth-consumers/new e aggiungi il permesso 'Account' - 'Read'
auths.tip.nextcloud=`Registra un nuovo OAuth sulla tua istanza utilizzando il seguente menu "Impostazioni -> Sicurezza -> OAuth 2.0 client"`
auths.tip.dropbox=Crea una nuova applicazione su https://www.dropbox.com/developers/apps
auths.tip.facebook=`Registra una nuova applicazione su https://developers.facebook.com/apps e aggiungi il prodotto "Facebook Login"`
auths.tip.github=Registra una nuova applicazione OAuth su https://github.com/settings/applications/new
auths.tip.google_plus=Ottieni le credenziali del client OAuth2 dalla console API di Google su https://console.developers.google.com/
-auths.tip.openid_connect=Utilizza l'OpenID Connect Discovery URL (/.well-known/openid-configuration) per specificare gli endpoint
auths.tip.twitter=Vai su https://dev.twitter.com/apps, crea una applicazione e assicurati che l'opzione "Allow this application to be used to Sign In with Twitter" sia abilitata
auths.tip.discord=Registra una nuova applicazione su https://discordapp.com/developers/applications/me
auths.tip.yandex=`Crea una nuova applicazione su https://oauth.yandex.com/client/new. Seleziona i seguenti permessi da "Yandex. assport API": "Access to email address", "Access to user avatar" e "Access to username, name and surname, gender"`
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index eddad35073..dd5e58133e 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -25,6 +25,7 @@ enable_javascript=このウェブサイトにはJavaScriptが必要です。
toc=目次
licenses=ライセンス
return_to_gitea=Giteaに戻る
+more_items=その他の項目
username=ユーザー名
email=メールアドレス
@@ -113,6 +114,7 @@ loading=読み込み中…
error=エラー
error404=アクセスしようとしたページは存在しない か、閲覧が許可されていません 。
go_back=戻る
+invalid_data=無効なデータ: %v
never=無し
unknown=不明
@@ -143,13 +145,39 @@ name=名称
value=値
filter=フィルター
+filter.clear=フィルターをクリア
filter.is_archived=アーカイブ
+filter.not_archived=非アーカイブ
+filter.is_fork=フォーク
+filter.not_fork=非フォーク
+filter.is_mirror=ミラー
+filter.not_mirror=非ミラー
filter.is_template=テンプレート
+filter.not_template=非テンプレート
filter.public=公開
filter.private=プライベート
+no_results_found=見つかりません。
[search]
+search=検索…
+type_tooltip=検索タイプ
+fuzzy=あいまい
+fuzzy_tooltip=検索ワードに近い結果も含めます
+repo_kind=リポジトリを検索...
+user_kind=ユーザーを検索...
+org_kind=組織を検索...
+team_kind=チームを検索…
+code_kind=コードを検索...
+code_search_unavailable=現在コード検索は利用できません。 サイト管理者にお問い合わせください。
+code_search_by_git_grep=現在のコード検索結果は "git grep" で提供されています。 サイト管理者がリポジトリインデクサーを有効にすると、より良い結果が得られるかもしれません。
+package_kind=パッケージを検索...
+project_kind=プロジェクトを検索...
+branch_kind=ブランチを検索...
+commit_kind=コミットを検索...
+runner_kind=ランナーを検索...
+no_results=一致する結果が見つかりませんでした
+keyword_search_unavailable=現在キーワード検索は利用できません。 サイト管理者にお問い合わせください。
[aria]
navbar=ナビゲーションバー
@@ -256,6 +284,7 @@ email_title=メール設定
smtp_addr=SMTPホスト
smtp_port=SMTPポート
smtp_from=メール送信者
+smtp_from_invalid=「メール送信者」のアドレスが無効です
smtp_from_helper=Giteaが使用するメールアドレス。 メールアドレスのみ、または、 "名前" の形式で入力してください。
mailer_user=SMTPユーザー名
mailer_password=SMTPパスワード
@@ -315,6 +344,7 @@ env_config_keys=環境設定
env_config_keys_prompt=以下の環境変数も設定ファイルに適用されます:
[home]
+nav_menu=ナビゲーションメニュー
uname_holder=ユーザー名またはメールアドレス
password_holder=パスワード
switch_dashboard_context=ダッシュボードのコンテキスト切替
@@ -618,6 +648,23 @@ block.block.org=組織向けにユーザーをブロック
block.block.failure=ユーザーのブロックに失敗しました: %s
block.unblock=ブロックを解除
block.unblock.failure=ユーザーのブロック解除に失敗しました: %s
+block.blocked=あなたはこのユーザーをブロックしています。
+block.title=ユーザーをブロックする
+block.info=ユーザーをブロックすると、そのユーザーは、プルリクエストやイシューの作成、コメントの投稿など、リポジトリに対する操作ができなくなります。 ユーザーのブロックについてはよく確認してください。
+block.info_1=ユーザーをブロックすることで、あなたのアカウントとあなたのリポジトリに対する以下の行為を阻止します:
+block.info_2=あなたのアカウントのフォロー
+block.info_3=あなたのユーザー名で@メンションして通知を送ること
+block.info_4=そのユーザーのリポジトリに、あなたを共同作業者として招待すること
+block.info_5=リポジトリへの、スター、フォーク、ウォッチ
+block.info_6=イシューやプルリクエストの作成、コメント投稿
+block.info_7=イシューやプルリクエストでの、あなたのコメントに対するリアクションの送信
+block.user_to_block=ブロックするユーザー
+block.note=メモ
+block.note.title=メモ(任意):
+block.note.info=メモはブロックされるユーザーには表示されません。
+block.note.edit=メモを編集
+block.list=ブロックしたユーザー
+block.list.none=ブロックしているユーザーはいません。
[settings]
profile=プロフィール
@@ -660,9 +707,8 @@ cancel=キャンセル
language=言語
ui=テーマ
hidden_comment_types=非表示にするコメントの種類
-hidden_comment_types_description=ここでチェックを入れたコメントの種類は、イシューのページには表示されません。 たとえば「ラベル」にチェックを入れると、「<ユーザー> が <ラベル> を追加/削除」といったコメントはすべて除去されます。
-hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照されたというコメント
-hidden_comment_types.issue_ref_tooltip=このイシューに関連付けるブランチやタグをユーザーが変更したというコメント
+hidden_comment_types.ref_tooltip=このイシューが別のイシューやコミット等から参照された、というコメント
+hidden_comment_types.issue_ref_tooltip=このイシューのブランチやタグへの関連付けをユーザーが変更した、というコメント
comment_type_group_reference=参照
comment_type_group_label=ラベル
comment_type_group_milestone=マイルストーン
@@ -732,7 +778,7 @@ add_email_success=新しいメールアドレスを追加しました。
email_preference_set_success=メール設定を保存しました。
add_openid_success=新しいOpenIDアドレスを追加しました。
keep_email_private=メールアドレスを隠す
-keep_email_private_popup=これによりプロフィールでメールアドレスが隠され、Webインターフェースでのプルリクエスト作成やファイル編集でもメールアドレスが隠されます。 プッシュ済みのコミットは変更されません。
+keep_email_private_popup=あなたのプロフィールからメールアドレスが隠され、Webインターフェースを使ったプルリクエスト作成やファイル編集でも、メールアドレスが隠されます。 プッシュ済みのコミットは変更されません。 コミットであなたのアカウントに関連付ける場合は %s を使用してください。
openid_desc=OpenIDを使うと外部プロバイダーに認証を委任することができます。
manage_ssh_keys=SSHキーの管理
@@ -955,7 +1001,9 @@ fork_visibility_helper=フォークしたリポジトリの公開/非公開は
fork_branch=フォークにクローンされるブランチ
all_branches=すべてのブランチ
fork_no_valid_owners=このリポジトリには有効なオーナーがいないため、フォークできません。
+fork.blocked_user=リポジトリのオーナーがあなたをブロックしているため、リポジトリをフォークできません。
use_template=このテンプレートを使用
+open_with_editor=%s で開く
download_zip=ZIPファイルをダウンロード
download_tar=TAR.GZファイルをダウンロード
download_bundle=バンドルをダウンロード
@@ -1008,6 +1056,7 @@ watchers=ウォッチャー
stargazers=スターゲイザー
stars_remove_warning=これを指定すると、このリポジトリのスターはすべて削除されます。
forks=フォーク
+stars=スター
reactions_more=さらに %d 件
unit_disabled=サイト管理者がこのリポジトリセクションを無効にしています。
language_other=その他
@@ -1039,7 +1088,7 @@ transfer.no_permission_to_reject=この移転を拒否する権限がありま
desc.private=プライベート
desc.public=公開
desc.template=テンプレート
-desc.internal=組織内
+desc.internal=内部
desc.archived=アーカイブ
desc.sha256=SHA256
@@ -1129,6 +1178,7 @@ watch=ウォッチ
unstar=スター取消
star=スター
fork=フォーク
+action.blocked_user=リポジトリのオーナーがあなたをブロックしているため、アクションを実行できません。
download_archive=リポジトリをダウンロード
more_operations=その他の操作
@@ -1229,7 +1279,6 @@ editor.or=または
editor.cancel_lower=キャンセル
editor.commit_signed_changes=署名した変更をコミット
editor.commit_changes=変更をコミット
-editor.add_tmpl='<ファイル名>' を追加
editor.add=%s を追加
editor.update=%s を更新
editor.delete=%s を削除
@@ -1257,6 +1306,8 @@ editor.file_editing_no_longer_exists=編集中のファイル "%s" が、もう
editor.file_deleting_no_longer_exists=削除しようとしたファイル "%s" が、すでにリポジトリ内にありません。
editor.file_changed_while_editing=あなたが編集を開始したあと、ファイルの内容が変更されました。 ここをクリック して何が変更されたか確認するか、もう一度"変更をコミット"をクリック して上書きします。
editor.file_already_exists=ファイル "%s" は、このリポジトリに既に存在します。
+editor.commit_id_not_matching=コミットIDが編集を開始したときのIDと一致しません。 パッチ用のブランチにコミットしたあとマージしてください。
+editor.push_out_of_date=このプッシュは最新ではないようです。
editor.commit_empty_file_header=空ファイルのコミット
editor.commit_empty_file_text=コミットしようとしているファイルは空です。 続行しますか?
editor.no_changes_to_show=表示する変更箇所はありません。
@@ -1281,6 +1332,7 @@ commits.commits=コミット
commits.no_commits=共通のコミットはありません。 "%s" と "%s" の履歴はすべて異なっています。
commits.nothing_to_compare=二つのブランチは同じ内容です。
commits.search.tooltip=`キーワード "author:"、"committer:"、"after:"、"before:" を付けて指定できます。 例 "revert author:Alice before:2019-01-13"`
+commits.search_branch=このブランチ
commits.search_all=すべてのブランチ
commits.author=作成者
commits.message=メッセージ
@@ -1339,6 +1391,7 @@ projects.column.new=新しい列
projects.column.set_default=デフォルトに設定
projects.column.set_default_desc=この列を未分類のイシューやプルリクエストが入るデフォルトの列にします
projects.column.delete=列を削除
+projects.column.deletion_desc=プロジェクト列を削除すると、関連するすべてのイシューがデフォルトの列に移動します。 続行しますか?
projects.column.color=カラー
projects.open=オープン
projects.close=クローズ
@@ -1373,6 +1426,8 @@ issues.new.assignees=担当者
issues.new.clear_assignees=担当者をクリア
issues.new.no_assignees=担当者なし
issues.new.no_reviewers=レビューアなし
+issues.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、イシューを作成できません。
+issues.edit.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、内容を編集できません。
issues.choose.get_started=始める
issues.choose.open_external_link=オープン
issues.choose.blank=デフォルト
@@ -1487,6 +1542,7 @@ issues.close_comment_issue=コメントしてクローズ
issues.reopen_issue=再オープンする
issues.reopen_comment_issue=コメントして再オープン
issues.create_comment=コメントする
+issues.comment.blocked_user=投稿者またはリポジトリのオーナーがあなたをブロックしているため、コメントの作成や編集はできません。
issues.closed_at=`がイシューをクローズ %[2]s `
issues.reopened_at=`がイシューを再オープン %[2]s `
issues.commit_ref_at=`がコミットでこのイシューを参照 %[2]s `
@@ -1685,6 +1741,7 @@ compare.compare_head=比較
pulls.desc=プルリクエストとコードレビューの有効化。
pulls.new=新しいプルリクエスト
+pulls.new.blocked_user=リポジトリのオーナーがあなたをブロックしているため、プルリクエストを作成できません。
pulls.view=プルリクエストを表示
pulls.compare_changes=新規プルリクエスト
pulls.allow_edits_from_maintainers=メンテナーからの編集を許可する
@@ -1738,7 +1795,7 @@ pulls.is_checking=マージのコンフリクトを確認中です。 少し待
pulls.is_ancestor=このブランチは既にターゲットブランチに含まれています。マージするものはありません。
pulls.is_empty=このブランチの変更は既にターゲットブランチにあります。これは空のコミットになります。
pulls.required_status_check_failed=いくつかの必要なステータスチェックが成功していません。
-pulls.required_status_check_missing=必要なステータスチェックが見つかりません。
+pulls.required_status_check_missing=必要なチェックがいくつか抜けています。
pulls.required_status_check_administrator=管理者であるため、このプルリクエストをマージすることは可能です。
pulls.blocked_by_approvals=このプルリクエストはまだ承認数が足りません。 %[1]d/%[2]dの承認を得ています。
pulls.blocked_by_rejection=このプルリクエストは公式レビューアにより変更要請されています。
@@ -1906,7 +1963,9 @@ wiki.original_git_entry_tooltip=フレンドリーリンクを使用する代わ
activity=アクティビティ
activity.navbar.pulse=Pulse
+activity.navbar.code_frequency=コード更新頻度
activity.navbar.contributors=貢献者
+activity.navbar.recent_commits=最近のコミット
activity.period.filter_label=期間:
activity.period.daily=1日
activity.period.halfweekly=3日
@@ -2025,6 +2084,8 @@ settings.branches.add_new_rule=新しいルールを追加
settings.advanced_settings=拡張設定
settings.wiki_desc=Wikiを有効にする
settings.use_internal_wiki=ビルトインのWikiを使用する
+settings.default_wiki_branch_name=デフォルトのWikiブランチ名
+settings.failed_to_change_default_wiki_branch=デフォルトのWikiブランチを変更できませんでした。
settings.use_external_wiki=外部のWikiを使用する
settings.external_wiki_url=外部WikiのURL
settings.external_wiki_url_error=外部WikiのURLが有効なURLではありません。
@@ -2054,7 +2115,10 @@ settings.pulls.default_delete_branch_after_merge=デフォルトでプルリク
settings.pulls.default_allow_edits_from_maintainers=デフォルトでメンテナからの編集を許可する
settings.releases_desc=リリースを有効にする
settings.packages_desc=リポジトリパッケージレジストリを有効にする
-settings.projects_desc=リポジトリプロジェクトを有効にする
+settings.projects_desc=プロジェクトを有効にする
+settings.projects_mode_desc=プロジェクト モード (表示するプロジェクトの種類)
+settings.projects_mode_repo=リポジトリのプロジェクトのみ
+settings.projects_mode_owner=ユーザーや組織のプロジェクトのみ
settings.projects_mode_all=すべてのプロジェクト
settings.actions_desc=Actionsを有効にする
settings.admin_settings=管理者用設定
@@ -2081,6 +2145,7 @@ settings.convert_fork_succeed=フォークを通常のリポジトリに変換
settings.transfer=オーナー移転
settings.transfer.rejected=リポジトリの移転は拒否されました。
settings.transfer.success=リポジトリの移転が成功しました。
+settings.transfer.blocked_user=新しいオーナーがあなたをブロックしているため、リポジトリを移転できません。
settings.transfer_abort=転送をキャンセル
settings.transfer_abort_invalid=存在しないリポジトリの移転はキャンセルできません。
settings.transfer_abort_success=%s へのリポジトリ移転は正常にキャンセルされました。
@@ -2126,6 +2191,7 @@ settings.add_collaborator_success=共同作業者を追加しました。
settings.add_collaborator_inactive_user=アクティベートされていないユーザーを共同作業者として追加することはできません。
settings.add_collaborator_owner=共同作業者としてオーナーを追加することはできません。
settings.add_collaborator_duplicate=共同作業者として既にこのリポジトリに追加されています。
+settings.add_collaborator.blocked_user=共同作業者がリポジトリのオーナーによってブロックされているか、またはブロックしています。
settings.delete_collaborator=削除
settings.collaborator_deletion=共同作業者の削除
settings.collaborator_deletion_desc=共同作業者を削除し、このリポジトリへのアクセス権を取り消します。 続行しますか?
@@ -2564,13 +2630,16 @@ find_file.no_matching=一致するファイルが見つかりません
error.csv.too_large=このファイルは大きすぎるため表示できません。
error.csv.unexpected=このファイルは %d 行目の %d 文字目に予期しない文字が含まれているため表示できません。
error.csv.invalid_field_count=このファイルは %d 行目のフィールドの数が正しくないため表示できません。
+error.broken_git_hook=このリポジトリのGitフックが壊れているようです。 ドキュメント に従って修正し、その後いくつかのコミットをプッシュして状態を最新にしてください。
[graphs]
component_loading=%sを読み込み中...
component_loading_failed=%sを読み込めませんでした
component_loading_info=少し時間がかかるかもしれません…
component_failed_to_load=予期しないエラーが発生しました。
+code_frequency.what=コード更新頻度
contributors.what=実績
+recent_commits.what=最近のコミット
[org]
org_name_holder=組織名
@@ -2684,6 +2753,7 @@ teams.add_nonexistent_repo=追加しようとしているリポジトリは存
teams.add_duplicate_users=ユーザーは既にチームのメンバーです。
teams.repos.none=このチームがアクセスできるリポジトリはありません。
teams.members.none=このチームにはメンバーがいません。
+teams.members.blocked_user=組織によってブロックされているため、ユーザーを追加できません。
teams.specific_repositories=指定したリポジトリ
teams.specific_repositories_helper=メンバーは、明示的にチームへ追加したリポジトリにのみアクセスできます。 これを選択しても、すでにすべてのリポジトリ で追加されたリポジトリは自動的に除去されません 。
teams.all_repositories=すべてのリポジトリ
@@ -2696,6 +2766,7 @@ teams.invite.by=%s からの招待
teams.invite.description=下のボタンをクリックしてチームに参加してください。
[admin]
+maintenance=メンテナンス
dashboard=ダッシュボード
self_check=セルフチェック
identity_access=アイデンティティとアクセス
@@ -2719,6 +2790,7 @@ settings=管理設定
dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在実行しているのは %s です。 詳細は ブログ を確認してください。
dashboard.statistic=サマリー
+dashboard.maintenance_operations=メンテナンス操作
dashboard.system_status=システム状況
dashboard.operation_name=操作の名称
dashboard.operation_switch=切り替え
@@ -2904,12 +2976,12 @@ packages.size=サイズ
packages.published=配布
defaulthooks=デフォルトWebhook
-defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイド をご覧下さい。
+defaulthooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイド をご覧下さい。
defaulthooks.add_webhook=デフォルトWebhookの追加
defaulthooks.update_webhook=デフォルトWebhookの更新
systemhooks=システムWebhook
-systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイド をご覧下さい。
+systemhooks.desc=Webhookは、特定のGiteaイベントが発生したときに、サーバーにHTTP POSTリクエストを自動的に送信するものです。 ここで定義したWebhookは、システム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイド をご覧下さい。
systemhooks.add_webhook=システムWebhookを追加
systemhooks.update_webhook=システムWebhookを更新
@@ -3004,13 +3076,12 @@ auths.tips=ヒント
auths.tips.oauth2.general=OAuth2認証
auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります:
auths.tip.oauth2_provider=OAuth2プロバイダー
-auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/<あなたのユーザー名>/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。
auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。
auths.tip.dropbox=新しいアプリケーションを https://www.dropbox.com/developers/apps から登録してください。
auths.tip.facebook=新しいアプリケーションを https://developers.facebook.com/apps で登録し、"Facebook Login"を追加してください。
auths.tip.github=新しいOAuthアプリケーションを https://github.com/settings/applications/new から登録してください。
+auths.tip.gitlab_new=新しいアプリケーションを https://gitlab.com/-/profile/applications から登録してください。
auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコンソール https://console.developers.google.com/ から取得してください。
-auths.tip.openid_connect=OpenID Connect DiscoveryのURL (/.well-known/openid-configuration) をエンドポイントとして指定してください
auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。
auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。
auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります
@@ -3144,6 +3215,7 @@ config.picture_config=画像とアバターの設定
config.picture_service=画像サービス
config.disable_gravatar=Gravatarが無効
config.enable_federated_avatar=フェデレーテッド・アバター有効
+config.open_with_editor_app_help=クローンメニューの「~で開く」に表示するエディタ。 空白のままにするとデフォルトが使用されます。 展開するとデフォルトを確認できます。
config.git_config=Git設定
config.git_disable_diff_highlight=Diffのシンタックスハイライトが無効
@@ -3223,6 +3295,7 @@ notices.op=操作
notices.delete_success=システム通知を削除しました。
self_check.no_problem_found=今のところ問題は見つかっていません。
+self_check.startup_warnings=起動時の警告:
self_check.database_collation_mismatch=データベースに想定される照合順序: %s
self_check.database_collation_case_insensitive=データベースは照合順序 %s を使用しており、大文字小文字を区別しません。 Giteaはその照合順序でも動作するかもしれませんが、まれに期待どおり動作しないケースがあるかもしれません。
self_check.database_inconsistent_collation_columns=データベースは照合順序 %s を使用していますが、以下のカラムはそれと一致しない照合順序を使用しており、予期せぬ問題を引き起こす可能性があります。
@@ -3283,9 +3356,9 @@ raw_seconds=秒
raw_minutes=分
[dropzone]
-default_message=ここにファイルをドロップまたはクリックしてアップロードします。
+default_message=ファイルをここにドロップ、またはここをクリックしてアップロード
invalid_input_type=この種類のファイルはアップロードできません。
-file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) が最大サイズ ({{maxFilesize}} MB) を超えています。
+file_too_big=アップロードされたファイルのサイズ ({{filesize}} MB) は、最大サイズ ({{maxFilesize}} MB) を超えています。
remove_file=ファイル削除
[notification]
@@ -3310,7 +3383,7 @@ error.no_committer_account=コミッターのメールアドレスに対応す
error.no_gpg_keys_found=この署名に対応する既知のキーがデータベースに存在しません
error.not_signed_commit=署名されたコミットではありません
error.failed_retrieval_gpg_keys=コミッターのアカウントに登録されたキーを取得できませんでした
-error.probable_bad_signature=警告! このIDの鍵はデータベースに登録されていますが、その鍵でコミットの検証が通りません! これは疑わしいコミットです。
+error.probable_bad_signature=警告! このIDに該当する鍵がデータベースにありますが、コミットの検証が通りません! これは疑わしいコミットです。
error.probable_bad_default_signature=警告! これはデフォルト鍵のIDですが、デフォルト鍵ではコミットの検証が通りません! これは疑わしいコミットです。
[units]
@@ -3323,7 +3396,7 @@ title=パッケージ
desc=リポジトリ パッケージを管理します。
empty=パッケージはまだありません。
empty.documentation=パッケージレジストリの詳細については、 ドキュメント を参照してください。
-empty.repo=パッケージはアップロードしたけども、ここに表示されない? パッケージ設定 を開いて、パッケージをこのリポジトリにリンクしてください。
+empty.repo=パッケージはアップロード済みで、ここに表示されていないですか? パッケージ設定 を開いて、パッケージをこのリポジトリにリンクしてください。
registry.documentation=%sレジストリの詳細については、 ドキュメント を参照してください。
filter.type=タイプ
filter.type.all=すべて
@@ -3542,6 +3615,7 @@ runs.scheduled=スケジュール済み
runs.pushed_by=pushed by
runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s
runs.no_matching_online_runner_helper=ラベルに一致するオンラインのランナーが見つかりません: %s
+runs.no_job_without_needs=ワークフローには依存関係のないジョブが少なくとも1つ含まれている必要があります。
runs.actor=アクター
runs.status=ステータス
runs.actors_no_select=すべてのアクター
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index 9a15090012..6afb488414 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -651,7 +651,6 @@ cancel=Atcelt
language=Valoda
ui=Motīvs
hidden_comment_types=Attēlojot paslēpt šauds komentārus:
-hidden_comment_types_description=Komentāru veidi, kas atzīmēti, netiks rādīti problēmas lapā. Piemēram, atzīmējot "Etiķetes" netiks rādīti komentāri " pievienoja/noņēma ".
hidden_comment_types.ref_tooltip=Komentāri, kad problēmai tiek pievienota atsauce uz citu probēmu, komentāru, …
hidden_comment_types.issue_ref_tooltip=Komentāri par lietotāja izmaiņām ar problēmas saistīto atzaru/tagu
comment_type_group_reference=Atsauces
@@ -1215,7 +1214,6 @@ editor.or=vai
editor.cancel_lower=Atcelt
editor.commit_signed_changes=Apstiprināt parakstītu revīziju
editor.commit_changes=Pabeigt revīziju
-editor.add_tmpl=Pievienot ''
editor.add=Pievienot %s
editor.update=Atjaunot %s
editor.delete=Dzēst %s
@@ -2976,13 +2974,11 @@ auths.tips=Padomi
auths.tips.oauth2.general=OAuth2 autentifikācija
auths.tips.oauth2.general.tip=Kad tiek reģistrēta jauna OAuth2 autentifikācija, atzvanīšanas/pārvirzīšanas URL vajadzētu būt:
auths.tip.oauth2_provider=OAuth2 pakalpojuma sniedzējs
-auths.tip.bitbucket=Reģistrējiet jaunu OAuth klientu adresē https://bitbucket.org/account/user//oauth-consumers/new un piešķiriet tam "Account" - "Read" tiesības
auths.tip.nextcloud=`Reģistrējiet jaunu OAuth klientu jūsu instances sadāļā "Settings -> Security -> OAuth 2.0 client"`
auths.tip.dropbox=Izveidojiet jaunu aplikāciju adresē https://www.dropbox.com/developers/apps
auths.tip.facebook=`Reģistrējiet jaunu aplikāciju adresē https://developers.facebook.com/apps un pievienojiet produktu "Facebook Login"`
auths.tip.github=Reģistrējiet jaunu aplikāciju adresē https://github.com/settings/applications/new
auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles adresē https://console.developers.google.com/
-auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (/.well-known/openid-configuration), lai norādītu galapunktus
auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet lietotni un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter”
auths.tip.discord=Reģistrējiet jaunu aplikāciju adresē https://discordapp.com/developers/applications/me
auths.tip.gitea=Pievienot jaunu OAuth2 lietojumprogrammu. Dokumentācija ir pieejama https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 6b5122a86f..b0b081db5d 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -1016,7 +1016,6 @@ editor.or=of
editor.cancel_lower=Annuleer
editor.commit_signed_changes=Commit Ondertekende Wijzigingen
editor.commit_changes=Wijzigingen doorvoeren
-editor.add_tmpl='' toevoegen
editor.patch=Patch toepassen
editor.patching=Patchen:
editor.new_patch=Nieuwe Patch
@@ -2345,7 +2344,6 @@ auths.tip.dropbox=Maak een nieuwe applicatie aan op https://www.dropbox.com/deve
auths.tip.facebook=Registreer een nieuwe applicatie op https://developers.facebook.com/apps en voeg het product "Facebook Login" toe
auths.tip.github=Registreer een nieuwe OAuth toepassing op https://github.com/settings/applications/new
auths.tip.google_plus=Verkrijg OAuth2 client referenties van de Google API console op https://console.developers.google.com/
-auths.tip.openid_connect=Gebruik de OpenID Connect Discovery URL (/.well-known/openid-configuration) om de eindpunten op te geven
auths.tip.yandex=`Maak een nieuwe applicatie aan op https://oauth.yandex.com/client/new. Selecteer de volgende machtigingen van de "Yandex". assport API sectie: "Toegang tot e-mailadres", "Toegang tot avatar" en "Toegang tot gebruikersnaam, voornaam en achternaam, geslacht"`
auths.edit=Authenticatiebron bewerken
auths.activated=Deze authenticatiebron is geactiveerd
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index a1d7e95842..fd5db4109f 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -950,7 +950,6 @@ editor.or=lub
editor.cancel_lower=Anuluj
editor.commit_signed_changes=Zatwierdź podpisane zmiany
editor.commit_changes=Zatwierdź zmiany
-editor.add_tmpl=Dodanie ''
editor.commit_message_desc=Dodaj dodatkowy rozszerzony opis…
editor.commit_directly_to_this_branch=Zmieniaj bezpośrednio gałąź %s .
editor.create_new_branch=Stwórz nową gałąź dla tego commita i rozpocznij Pull Request.
@@ -2223,13 +2222,11 @@ auths.sspi_default_language_helper=Domyślny język dla użytkowników automatyc
auths.tips=Wskazówki
auths.tips.oauth2.general=Uwierzytelnianie OAuth2
auths.tip.oauth2_provider=Dostawca OAuth2
-auths.tip.bitbucket=`Zarejestruj nowego konsumenta OAuth na https://bitbucket.org/account/user//oauth-consumers/new i dodaj uprawnienie "Account" - "Read"`
auths.tip.nextcloud=`Zarejestruj nowego klienta OAuth w swojej instancji za pomocą menu "Ustawienia -> Bezpieczeństwo -> Klient OAuth 2.0"`
auths.tip.dropbox=Stwórz nową aplikację na https://www.dropbox.com/developers/apps
auths.tip.facebook=`Zarejestruj nową aplikację na https://developers.facebook.com/apps i dodaj produkt "Facebook Login"`
auths.tip.github=Zarejestruj nową aplikację OAuth na https://github.com/settings/applications/new
auths.tip.google_plus=Uzyskaj dane uwierzytelniające klienta OAuth2 z konsoli Google API na https://console.developers.google.com/
-auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (/.well-known/openid-configuration), aby określić punkty końcowe
auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona
auths.tip.discord=Zarejestruj nową aplikację na https://discordapp.com/developers/applications/me
auths.tip.yandex=`Utwórz nową aplikację na https://oauth.yandex.com/client/new. Wybierz następujące uprawnienia z "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"`
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 45f1c3b3f8..5a058c807b 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -652,7 +652,6 @@ cancel=Cancelar
language=Idioma
ui=Tema
hidden_comment_types=Tipos de comentários ocultos
-hidden_comment_types_description=Os tipos de comentários marcados aqui não serão exibidos nas páginas de issues. Marcar "Rótulo", por exemplo, remove todos os comentários " adicionou/removeu ".
hidden_comment_types.ref_tooltip=Comentários onde este issue foi referenciado de outro issue/commit/…
hidden_comment_types.issue_ref_tooltip=Comentários onde o usuário altera o branch/tag associado ao issue
comment_type_group_reference=Referência
@@ -1212,7 +1211,6 @@ editor.or=ou
editor.cancel_lower=Cancelar
editor.commit_signed_changes=Commit de alteradores assinadas
editor.commit_changes=Aplicar commit das alterações
-editor.add_tmpl=Adicionar ''
editor.add=Adicionar %s
editor.update=Atualizar %s
editor.delete=Excluir %s
@@ -2918,13 +2916,11 @@ auths.tips=Dicas
auths.tips.oauth2.general=Autenticação OAuth2
auths.tips.oauth2.general.tip=Ao registrar uma nova autenticação OAuth2, o URL de retorno de chamada/redirecionamento deve ser:
auths.tip.oauth2_provider=Provedor OAuth2
-auths.tip.bitbucket=Cadastrar um novo consumidor de OAuth em https://bitbucket.org/account/user/ e adicionar a permissão 'Account' - 'Read'
auths.tip.nextcloud=`Registre um novo consumidor OAuth em sua instância usando o seguinte menu "Configurações -> Segurança -> Cliente OAuth 2.0"`
auths.tip.dropbox=Criar um novo aplicativo em https://www.dropbox.com/developers/apps
auths.tip.facebook=`Cadastrar um novo aplicativo em https://developers.facebook.com/apps e adicionar o produto "Facebook Login"`
auths.tip.github=Cadastrar um novo aplicativo de OAuth na https://github.com/settings/applications/new
auths.tip.google_plus=Obter credenciais de cliente OAuth2 do console de API do Google em https://console.developers.google.com/
-auths.tip.openid_connect=Use o OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar os endpoints
auths.tip.twitter=Vá em https://dev.twitter.com/apps, crie um aplicativo e certifique-se de que está habilitada a opção “Allow this application to be used to Sign in with Twitter“
auths.tip.discord=Cadastrar um novo aplicativo em https://discordapp.com/developers/applications/me
auths.tip.yandex=`Crie um novo aplicativo em https://oauth.yandex.com/client/new. Selecione as seguintes permissões da seção "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"`
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 59b3d3df67..a90927a255 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -164,8 +164,8 @@ search=Pesquisar...
type_tooltip=Tipo de pesquisa
fuzzy=Aproximada
fuzzy_tooltip=Incluir também os resultados que estejam próximos do termo de pesquisa
-match=Fiel
-match_tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa
+exact=Fiel
+exact_tooltip=Incluir somente os resultados que correspondam rigorosamente ao termo de pesquisa
repo_kind=Pesquisar repositórios...
user_kind=Pesquisar utilizadores...
org_kind=Pesquisar organizações...
@@ -179,6 +179,8 @@ branch_kind=Pesquisar ramos...
commit_kind=Pesquisar cometimentos...
runner_kind=Pesquisar executores...
no_results=Não foram encontrados resultados correspondentes.
+issue_kind=Pesquisar questões...
+pull_kind=Pesquisar puxadas...
keyword_search_unavailable=Pesquisar por palavra-chave não está disponível, neste momento. Entre em contacto com o administrador.
[aria]
@@ -714,7 +716,7 @@ cancel=Cancelar
language=Idioma
ui=Tema
hidden_comment_types=Tipos de comentários ocultos
-hidden_comment_types_description=Os tipos de comentário marcados aqui não serão mostrados dentro das páginas das questões. Marcar "Rótulo", por exemplo, remove todos os comentários " adicionou/removeu ".
+hidden_comment_types_description=Os tipos de comentário marcados aqui não serão mostrados dentro das páginas das questões. Marcar "Rótulo", por exemplo, remove todos os comentários "{user} adicionou/removeu {label}".
hidden_comment_types.ref_tooltip=Comentários onde esta questão foi referenciada a partir de outra questão/cometimento/…
hidden_comment_types.issue_ref_tooltip=Comentários onde o utilizador altera o ramo/etiqueta associado à questão
comment_type_group_reference=Referência
@@ -885,6 +887,7 @@ repo_and_org_access=Acesso aos repositórios e às organizações
permissions_public_only=Apenas público
permissions_access_all=Tudo (público, privado e limitado)
select_permissions=Escolher permissões
+permission_not_set=Não definido
permission_no_access=Sem acesso
permission_read=Lidas
permission_write=Leitura e escrita
@@ -1289,7 +1292,7 @@ editor.or=ou
editor.cancel_lower=Cancelar
editor.commit_signed_changes=Cometer modificações assinadas
editor.commit_changes=Cometer modificações
-editor.add_tmpl=Adicionar ''
+editor.add_tmpl=Adicionar '{filename}'
editor.add=Adicionar %s
editor.update=Modificar %s
editor.delete=Eliminar %s
@@ -2096,6 +2099,7 @@ settings.advanced_settings=Configurações avançadas
settings.wiki_desc=Habilitar wiki do repositório
settings.use_internal_wiki=Usar o wiki nativo
settings.default_wiki_branch_name=Nome do ramo predefinido do wiki
+settings.default_wiki_everyone_access=Permissão de acesso predefinida para utilizadores registados:
settings.failed_to_change_default_wiki_branch=Falhou ao mudar o nome do ramo predefinido do wiki.
settings.use_external_wiki=Usar um wiki externo
settings.external_wiki_url=URL do wiki externo
@@ -3087,14 +3091,14 @@ auths.tips=Dicas
auths.tips.oauth2.general=Autenticação OAuth2
auths.tips.oauth2.general.tip=Ao registar uma nova autenticação OAuth2, o URL da ligação de retorno ou do reencaminhamento deve ser:
auths.tip.oauth2_provider=Fornecedor OAuth2
-auths.tip.bitbucket=Registe um novo consumidor de OAuth em https://bitbucket.org/account/user//oauth-consumers/new e adicione a permissão 'Account' - 'Read'
+auths.tip.bitbucket=Registe um novo consumidor de OAuth em https://bitbucket.org/account/user/{your-username}/oauth-consumers/new e adicione a permissão 'Account' - 'Read'
auths.tip.nextcloud=`Registe um novo consumidor OAuth na sua instância usando o seguinte menu "Configurações → Segurança → Cliente OAuth 2.0"`
auths.tip.dropbox=Crie uma nova aplicação em https://www.dropbox.com/developers/apps
auths.tip.facebook=`Registe uma nova aplicação em https://developers.facebook.com/apps e adicione o produto "Facebook Login"`
auths.tip.github=Registe uma nova aplicação OAuth em https://github.com/settings/applications/new
auths.tip.gitlab_new=Registe uma nova aplicação em https://gitlab.com/-/profile/applications
auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em https://console.developers.google.com/
-auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID (/.well-known/openid-configuration) para especificar os extremos
+auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID "https://{server}/.well-known/openid-configuration" para especificar os extremos
auths.tip.twitter=`Vá a https://dev.twitter.com/apps, crie uma aplicação e certifique-se de que está habilitada a opção "Allow this application to be used to Sign in with Twitter"`
auths.tip.discord=Registe uma nova aplicação em https://discordapp.com/developers/applications/me
auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em https://docs.gitea.com/development/oauth2-provider
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index 818dad1147..d4098aa952 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -649,7 +649,6 @@ cancel=Отмена
language=Язык
ui=Тема
hidden_comment_types=Скрытые типы комментариев
-hidden_comment_types_description=Отмеченные типы комментариев не будут отображаться на страницах задач. Например, если выбрать «Метки», не станет всех комментариев «<пользователь> добавил/удалил <метку>».
hidden_comment_types.ref_tooltip=Комментарии об упоминании задачи в другой задаче/коммите/…
hidden_comment_types.issue_ref_tooltip=Комментарии об изменении ветки/тега, связанных с этой задачей
comment_type_group_reference=Упоминания
@@ -1192,7 +1191,6 @@ editor.or=или
editor.cancel_lower=Отменить
editor.commit_signed_changes=Зафиксировать подписанные изменения
editor.commit_changes=Сохранить правки
-editor.add_tmpl=Добавить ''
editor.add=Добавить %s
editor.update=Обновить %s
editor.delete=Удалить %s
@@ -2909,13 +2907,11 @@ auths.sspi_default_language_helper=Язык по умолчанию для по
auths.tips=Советы
auths.tips.oauth2.general=Аутентификация OAuth2
auths.tip.oauth2_provider=Поставщик OAuth2
-auths.tip.bitbucket=`Создайте OAuth URI на странице https://bitbucket.org/account/user/<имя пользователя>/oauth-consumers/new и добавьте права "Account" - "Read"`
auths.tip.nextcloud=`Зарегистрируйте нового потребителя OAuth в вашем экземпляре, используя меню "Settings -> Security -> OAuth 2.0 client"`
auths.tip.dropbox=Добавьте новое приложение на https://www.dropbox.com/developers/apps
auths.tip.facebook=Зарегистрируйте новое приложение на https://developers.facebook.com/apps и добавьте модуль «Facebook Login»
auths.tip.github=Добавьте OAuth приложение на https://github.com/settings/applications/new
auths.tip.google_plus=Получите учётные данные клиента OAuth2 в консоли Google API на странице https://console.developers.google.com/
-auths.tip.openid_connect=Используйте OpenID Connect Discovery URL (/.well-known/openid-configuration) для автоматической настройки входа OAuth
auths.tip.twitter=Перейдите на https://dev.twitter.com/apps, создайте приложение и убедитесь, что включена опция «Разрешить это приложение для входа в систему с помощью Twitter»
auths.tip.discord=Добавьте новое приложение на https://discordapp.com/developers/applications/me
auths.tip.yandex=`Создайте новое приложение по адресу https://oauth.yandex.com/client/new. В разделе "API Яндекс.Паспорта" выберите следующие разрешения: "Доступ к адресу электронной почты", "Доступ к аватару пользователя" и "Доступ к имени пользователя, фамилии и полу"`
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 99559802c5..05538af971 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -919,7 +919,6 @@ editor.or=හෝ
editor.cancel_lower=අවලංගු කරන්න
editor.commit_signed_changes=අත්සන් කළ වෙනස්කම් සිදු කරන්න
editor.commit_changes=වෙනස්කම් සිදු කරන්න
-editor.add_tmpl='' එකතු කරන්න
editor.commit_message_desc=විකල්ප දීර්ඝ විස්තරයක් එක් කරන්න…
editor.signoff_desc=කැපවූ ලොග් පණිවිඩය අවසානයේ දී කැපකරු විසින් සිග්නෙඩ්-ඕෆ්-විසින් ට්රේලරයක් එක් කරන්න.
editor.commit_directly_to_this_branch=%s ශාඛාවට කෙලින්ම කැප කරන්න.
@@ -2261,7 +2260,6 @@ auths.tip.dropbox=https://www.dropbox.com/developers/apps හි නව යෙ
auths.tip.facebook=https://developers.facebook.com/apps හි නව යෙදුමක් ලියාපදිංචි කර නිෂ්පාදනය එකතු කරන්න “ෆේස්බුක් ලොගින් වන්න”
auths.tip.github=https://github.com/settings/applications/new හි නව OAUTH අයදුම්පතක් ලියාපදිංචි කරන්න
auths.tip.google_plus=ගූගල් API කොන්සෝලය වෙතින් OUT2 සේවාදායක අක්තපත්ර ලබා ගන්න https://console.developers.google.com/
-auths.tip.openid_connect=අන්ත ලක්ෂ්ය නියම කිරීම සඳහා OpenID Connect ඩිස්කවරි URL (/.හොඳින් දැන /openid-වින්යාසය) භාවිතා කරන්න
auths.tip.twitter=https://dev.twitter.com/apps වෙත යන්න, යෙදුමක් සාදන්න සහ “මෙම යෙදුම ට්විටර් සමඟ පුරනය වීමට භාවිතා කිරීමට ඉඩ දෙන්න” විකල්පය සක්රීය කර ඇති බවට සහතික වන්න
auths.tip.discord=https://discordapp.com/developers/applications/me හි නව අයදුම්පතක් ලියාපදිංචි කරන්න
auths.tip.yandex=https://oauth.yandex.com/client/new හි නව යෙදුමක් සාදන්න. “Yandex.Passport API” කොටසේ පහත සඳහන් අවසරයන් තෝරන්න: “විද්යුත් තැපැල් ලිපිනය වෙත ප්රවේශය”, “පරිශීලක අවතාර් වෙත ප්රවේශය” සහ “පරිශීලක නාමය, මුල් නම සහ වාසගම, ස්ත්රී පුරුෂ භාවය”
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index 9234e9aa58..5fe6288ad6 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -779,7 +779,6 @@ editor.or=eller
editor.cancel_lower=Avbryt
editor.commit_signed_changes=Committa signerade ändringar
editor.commit_changes=Checka in ändringar
-editor.add_tmpl=Lägg till ''
editor.commit_message_desc=Lägg till en valfri utökad beskrivning…
editor.commit_directly_to_this_branch=Checka in direkt till grenen %s .
editor.create_new_branch=Skapa en ny gren för denna incheckning och påbörja en hämtningsbegäran.
@@ -1801,12 +1800,10 @@ auths.enable_auto_register=Aktivera Automatisk Registrering
auths.tips=Tips
auths.tips.oauth2.general=OAuth2 Autensiering
auths.tip.oauth2_provider=OAuth2 leverantör
-auths.tip.bitbucket=Registrera en ny OAuth konsument på https://bitbucket.org/account/user//oauth-consumers/new och lägg till behörighet 'Account' - 'Read'
auths.tip.dropbox=Skapa en ny applikation på https://www.dropbox.com/developers/apps
auths.tip.facebook=Registrera en ny appliaktion på https://developers.facebook.com/apps och lägg till produkten ”Facebook-inloggning”
auths.tip.github=Registrera en ny OAuth applikation på https://github.com/settings/applications/new
auths.tip.google_plus=Erhåll inloggningsuppgifter för OAuth2 från Google API-konsolen på https://console.developers.google.com/
-auths.tip.openid_connect=Använd OpenID Connect Discovery länken (/.well-known/openid-configuration) för att ange slutpunkterna
auths.tip.twitter=Gå till https://dev.twitter.com/app, skapa en applikation och försäkra att alternativet "Allow this application to be used to Sign in with Twitter" är aktiverat
auths.tip.discord=Registrera en ny applikation på https://discordapp.com/developers/applications/me
auths.edit=Redigera autensieringskälla
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 119e1ef150..59c931afd2 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -25,6 +25,7 @@ enable_javascript=Bu web sitesinin çalışması için JavaScript gereklidir.
toc=İçindekiler Tablosu
licenses=Lisanslar
return_to_gitea=Gitea'ya Dön
+more_items=Daha fazla öğe
username=Kullanıcı Adı
email=E-posta Adresi
@@ -113,6 +114,7 @@ loading=Yükleniyor…
error=Hata
error404=Ulaşmaya çalıştığınız sayfa mevcut değil veya görüntüleme yetkiniz yok .
go_back=Geri Git
+invalid_data=Geçersiz veri: %v
never=Asla
unknown=Bilinmiyor
@@ -123,6 +125,7 @@ pin=Sabitle
unpin=Sabitlemeyi kaldır
artifacts=Yapılar
+confirm_delete_artifact=%s yapısını silmek istediğinizden emin misiniz?
archived=Arşivlenmiş
@@ -142,13 +145,43 @@ name=İsim
value=Değer
filter=Filtre
+filter.clear=Filtreyi Temizle
filter.is_archived=Arşivlenmiş
+filter.not_archived=Arşivlenmemiş
+filter.is_fork=Çatallanmış
+filter.not_fork=Çatallanmamış
+filter.is_mirror=Yansılanmış
+filter.not_mirror=Yansılanmamış
filter.is_template=Şablon
+filter.not_template=Şablon değil
filter.public=Genel
filter.private=Özel
+no_results_found=Sonuç bulunamadı.
[search]
+search=Ara...
+type_tooltip=Arama türü
+fuzzy=Bulanık
+fuzzy_tooltip=Arama terimine benzeyen sonuçları da içer
+exact=Tam
+exact_tooltip=Sadece arama terimiyle tamamen eşleşen sonuçları içer
+repo_kind=Depoları ara...
+user_kind=Kullanıcıları ara...
+org_kind=Organizasyonları ara...
+team_kind=Takımları ara...
+code_kind=Kod ara...
+code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin.
+code_search_by_git_grep=Mevcut kod arama sonuçları "git grep" ile sağlanıyor. Eğer yönetici Depo Dizinleyici'yi etkinleştirirse daha iyi sonuçlar çıkabilir.
+package_kind=Paketleri ara...
+project_kind=Projeleri ara...
+branch_kind=Dalları ara...
+commit_kind=İşlemeleri ara...
+runner_kind=Çalıştırıcıları ara...
+no_results=Eşleşen sonuç bulunamadı.
+issue_kind=Konuları ara...
+pull_kind=Değişiklikleri ara...
+keyword_search_unavailable=Anahtar kelime ile arama şu an mevcut değil. Lütfen site yöneticinizle iletişime geçin.
[aria]
navbar=Gezinti Çubuğu
@@ -255,6 +288,7 @@ email_title=E-posta Ayarları
smtp_addr=SMTP Sunucusu
smtp_port=SMTP Portu
smtp_from=E-posta Gönderen
+smtp_from_invalid=`"E-posta Olarak Gönder" adresi geçersiz`
smtp_from_helper=Gitea'nın kullanacağı e-posta adresi. Yalın bir e-posta adresi girin veya "İsim" biçimini kullanın.
mailer_user=SMTP Kullanıcı Adı
mailer_password=SMTP Parolası
@@ -314,6 +348,7 @@ env_config_keys=Ortam Yapılandırma
env_config_keys_prompt=Aşağıdaki ortam değişkenleri de yapılandırma dosyanıza eklenecektir:
[home]
+nav_menu=Gezinti Menüsü
uname_holder=Kullanıcı Adı veya E-Posta Adresi
password_holder=Parola
switch_dashboard_context=Panoya Geçiş Yap
@@ -362,6 +397,7 @@ forgot_password_title=Şifremi unuttum
forgot_password=Şifrenizi mi unuttunuz?
sign_up_now=Bir hesaba mı ihtiyacınız var? Hemen kaydolun.
sign_up_successful=Hesap başarılı bir şekilde oluşturuldu. Hoşgeldiniz!
+confirmation_mail_sent_prompt_ex=Yeni bir doğrulama e-postası %s adresine gönderildi. Lütfen kayıt sürecini tamamlamak için %s içinde gelen kutunuzu denetleyin. Eğer kayıt e-posta adresiniz hatalı ise, tekrar oturum açıp değiştirebilirsiniz.
must_change_password=Parolanızı güncelleyin
allow_password_change=Kullanıcıyı parola değiştirmeye zorla (önerilen)
reset_password_mail_sent_prompt=%s adresine bir onay e-postası gönderildi. Hesap kurtarma işlemini tamamlamak için lütfen gelen kutunuzu sonraki %s içinde kontrol edin.
@@ -371,6 +407,7 @@ prohibit_login=Oturum Açma Yasağı
prohibit_login_desc=Hesabınız ile oturum açmanız yasaklanmış, lütfen site yöneticinizle iletişime geçin.
resent_limit_prompt=Zaten bir etkinleştirme e-postası talep ettiniz. Lütfen 3 dakika bekleyip tekrar deneyin.
has_unconfirmed_mail=Merhaba %s, doğrulanmamış bir e-posta adresin var (%s ). Bir doğrulama e-postası almadıysanız ya da yenisine ihtiyacınız varsa lütfen aşağıdaki düğmeye tıklayın.
+change_unconfirmed_mail_address=Eğer kayıt e-posta adresiniz hatalı ise, burada değiştirebilir ve yeni bir doğrulama e-postası gönderebilirsiniz.
resend_mail=Etkinleştirme e-postasını tekrar almak için buraya tıklayın
email_not_associate=Bu e-posta adresi hiçbir hesap ile ilişkilendirilmemiştir.
send_reset_mail=Hesap Kurtarma E-postası Gönder
@@ -418,6 +455,7 @@ authorization_failed_desc=Geçersiz bir istek tespit ettiğimiz için yetkilendi
sspi_auth_failed=SSPI kimlik doğrulaması başarısız oldu
password_pwned=Seçtiğiniz parola, daha önce herkese açık veri ihlallerinde açığa çıkan bir çalınan parola listesindedir . Lütfen farklı bir parola ile tekrar deneyin ve başka yerlerde de bu parolayı değiştirmeyi düşünün.
password_pwned_err=HaveIBeenPwned'e yapılan istek tamamlanamadı
+last_admin=Son yöneticiyi silemezsiniz. En azından bir yönetici olmalıdır.
[mail]
view_it_on=%s üzerinde görüntüle
@@ -550,6 +588,7 @@ team_name_been_taken=Takım adı zaten alınmış.
team_no_units_error=En az bir depo bölümüne erişimine izin ver.
email_been_used=E-posta adresi zaten kullanılıyor.
email_invalid=E-posta adresi geçersiz.
+email_domain_is_not_allowed=Kullanıcı e-posta adresi %s alan adı EMAIL_DOMAIN_ALLOWLIST veya EMAIL_DOMAIN_BLOCKLIST ile çelişiyor. Lütfen işleminizin beklendiğinden emin olun.
openid_been_used=OpenID adresi "%s" zaten kullanılıyor.
username_password_incorrect=Kullanıcı adı veya parola hatalı.
password_complexity=Parola, karmaşıklık gereksinimlerini karşılamıyor:
@@ -561,6 +600,8 @@ enterred_invalid_repo_name=Girdiğiniz depo adı hatalı.
enterred_invalid_org_name=Girdiğiniz organizsyon adı hatalı.
enterred_invalid_owner_name=Yeni sahip ismi hatalı.
enterred_invalid_password=Girdiğiniz parola hatalı.
+unset_password=Oturum açma kullanıcısı parola belirlemedi.
+unsupported_login_type=Oturum açma türü hesap silmeyi desteklemiyor.
user_not_exist=Böyle bir kullanıcı yok.
team_not_exist=Böyle bir takım bulunmuyor.
last_org_owner=Son kullanıcıyı 'sahipler' takımından çıkaramazsınız. Bir organizasyonun en az bir sahibi olmalıdır.
@@ -583,6 +624,7 @@ org_still_own_packages=Bu organizasyon hala bir veya daha fazla pakete sahip, ö
target_branch_not_exist=Hedef dal mevcut değil.
+admin_cannot_delete_self=Yöneticiyken kendinizi silemezsiniz. Lütfen önce yönetici haklarınızı kaldırın.
[user]
change_avatar=Profil resmini değiştir…
@@ -609,6 +651,29 @@ form.name_reserved=`"%s" kullanıcı adı rezerve edilmiş.`
form.name_pattern_not_allowed=Kullanıcı adında "%s" deseni kullanılamaz.
form.name_chars_not_allowed=`"%s" kullanıcı adı geçersiz karakterler içeriyor.`
+block.block=Engelle
+block.block.user=Kullanıcıyı engelle
+block.block.org=Kullanıcıyı organizasyonda engelle
+block.block.failure=Kullanıcı engellenemedi: %s
+block.unblock=Engeli kaldır
+block.unblock.failure=Kullanıcının engeli kaldırılamadı: %s
+block.blocked=Bu kullanıcıyı engelledin.
+block.title=Bir kullanıcı engelle
+block.info=Bir kullanıcıyı engellemek depoarla, değişiklik isteği veya konu açmak veya yorumlamak gibi, etkileşim kurmasını önler. Bir kullanıcı engelleme hakkında daha fazlasını öğrenin.
+block.info_1=Bir kullanıcıyı engellemek, hesabınızda ve depolarınızda şu eylemleri önler:
+block.info_2=hesabınızı takip etmek
+block.info_3=kullanıcı adınızdan @bahsederek size bildirim göndermek
+block.info_4=kendi depolarına sizi katkıcı olarak davet etmek
+block.info_5=depolara yıldız koymak, çatallamak veya izlemek
+block.info_6=konu veya değişiklik isteği açmak ve yorum eklemek
+block.info_7=konularda veya değişiklik isteklerinde yorumlarınıza tepki vermek
+block.user_to_block=Engellenecek kullanıcı
+block.note=Not
+block.note.title=İsteğe bağlı not:
+block.note.info=Not engellenen kullanıcıya gösterilmez.
+block.note.edit=Notu düzenle
+block.list=Engellenmiş kullanıcılar
+block.list.none=Engellediğiniz kullanıcı yok.
[settings]
profile=Profil
@@ -651,7 +716,7 @@ cancel=İptal
language=Dil
ui=Tema
hidden_comment_types=Gizli yorum türleri
-hidden_comment_types_description=Burada işaretlenen yorum türleri konu sayfalarında görüntülenmeyecektir. Örneğin "Etiket" seçildiğinde tüm ", ekledi/çıkardı" yorumları kalkacaktır.
+hidden_comment_types_description=Burada işaretlenen yorum türleri konu sayfalarında görüntülenmeyecektir. Örneğin "Etiket" seçildiğinde tüm "{user}, {label} ekledi/çıkardı" yorumları kalkacaktır.
hidden_comment_types.ref_tooltip=Bu konuya başka konu/işlem tarafından değinilen yorumlar…
hidden_comment_types.issue_ref_tooltip=Kullanıcının konuyla ilişkili dalı/etiketi değiştirdiği yorumlar
comment_type_group_reference=Referans
@@ -822,6 +887,7 @@ repo_and_org_access=Depo ve Organizasyon Erişimi
permissions_public_only=Yalnızca herkese açık
permissions_access_all=Tümü (herkese açık, özel ve sınırlı)
select_permissions=İzinleri seçin
+permission_not_set=Ayarlanmadı
permission_no_access=Erişim Yok
permission_read=Okunmuş
permission_write=Okuma ve Yazma
@@ -946,7 +1012,9 @@ fork_visibility_helper=Çatallanmış bir deponun görünürlüğü değiştiril
fork_branch=Çatala klonlanacak dal
all_branches=Tüm dallar
fork_no_valid_owners=Geçerli bir sahibi olmadığı için bu depo çatallanamaz.
+fork.blocked_user=Depo çatallanamıyor, depo sahibi tarafından engellenmişsiniz.
use_template=Bu şablonu kullan
+open_with_editor=%s ile aç
download_zip=ZIP indir
download_tar=TAR.GZ indir
download_bundle=BUNDLE indir
@@ -962,6 +1030,8 @@ issue_labels_helper=Bir konu etiket seti seçin.
license=Lisans
license_helper=Bir lisans dosyası seçin.
license_helper_desc=Bir lisans, başkalarının kodunuzla neler yapıp yapamayacağını yönetir. Projeniz için hangisinin doğru olduğundan emin değil misiniz? Lisans seçme konusuna bakın
+object_format=Nesne Biçimi
+object_format_helper=Deponun nesne biçimi. Daha sonra değiştirilemez. SHA1 en uyumlu olandır.
readme=README
readme_helper=Bir README dosyası şablonu seçin.
readme_helper_desc=Projeniz için eksiksiz bir açıklama yazabileceğiniz yer burasıdır.
@@ -979,6 +1049,7 @@ mirror_prune=Buda
mirror_prune_desc=Kullanılmayan uzak depoları izleyen referansları kaldır
mirror_interval=Yansı Aralığı (geçerli zaman birimleri 'h', 'm', 's'). Periyodik senkronizasyonu devre dışı bırakmak için 0 kullanın. (Asgari aralık: %s)
mirror_interval_invalid=Yansı süre aralığı geçerli değil.
+mirror_sync=eşitlendi
mirror_sync_on_commit=İşlemeler gönderildiğinde senkronize et
mirror_address=URL'den Klonla
mirror_address_desc=Yetkilendirme bölümüne gerekli tüm kimlik bilgilerini girin.
@@ -996,6 +1067,7 @@ watchers=İzleyenler
stargazers=Yıldızlayanlar
stars_remove_warning=Bu depodan tüm yıldızları kaldıracaktır.
forks=Çatallamalar
+stars=Yıldızlar
reactions_more=ve %d daha fazla
unit_disabled=Site yöneticisi bu depo bölümünü devre dışı bıraktı.
language_other=Diğer
@@ -1029,6 +1101,7 @@ desc.public=Genel
desc.template=Şablon
desc.internal=Dahili
desc.archived=Arşivlenmiş
+desc.sha256=SHA256
template.items=Şablon Öğeleri
template.git_content=Git İçeriği (Varsayılan Dal)
@@ -1116,6 +1189,7 @@ watch=İzle
unstar=Yıldızı Kaldır
star=Yıldızla
fork=Çatalla
+action.blocked_user=İşlem gerçekleştirilemiyor, depo sahibi tarafından engellenmişsiniz.
download_archive=Depoyu İndir
more_operations=Daha Fazla İşlem
@@ -1162,6 +1236,8 @@ file_view_rendered=Oluşturulanları Görüntüle
file_view_raw=Ham Görünüm
file_permalink=Kalıcı Bağlantı
file_too_large=Bu dosya görüntülemek için çok büyük.
+code_preview_line_from_to=%[3]s içinde %[1]d ve %[2]d arasındaki satırlar
+code_preview_line_in=%[2]s içinde %[1]d satırı
invisible_runes_header=`Bu dosya görünmez Evrensel Kodlu karakter içeriyor`
invisible_runes_description=`Bu dosya, insanlar tarafından ayırt edilemeyen ama bir bilgisayar tarafından farklı bir şekilde işlenebilecek görünmez evrensel kodlu karakter içeriyor. Eğer bunu kasıtlı olarak yaptıysanız bu uyarıyı yok sayabilirsiniz. Gizli karakterleri göstermek için Kaçış Karakterli düğmesine tıklayın.`
ambiguous_runes_header=`Bu dosya muğlak Evrensel Kodlu karakter içeriyor`
@@ -1179,6 +1255,8 @@ audio_not_supported_in_browser=Tarayıcınız HTML5 'audio' etiketini desteklemi
stored_lfs=Git LFS ile depolandı
symbolic_link=Sembolik Bağlantı
executable_file=Çalıştırılabilir Dosya
+vendored=Sağlanmış
+generated=Üretilmiş
commit_graph=İşleme Grafiği
commit_graph.select=Dalları seç
commit_graph.hide_pr_refs=Değişiklik İsteklerini Gizle
@@ -1214,7 +1292,7 @@ editor.or=veya
editor.cancel_lower=İptal
editor.commit_signed_changes=İmzalı Değişiklikleri İşle
editor.commit_changes=Değişiklikleri Uygula
-editor.add_tmpl='' eklendi
+editor.add_tmpl='{filename}' ekle
editor.add=%s Ekle
editor.update=%s Güncelle
editor.delete=%s Sil
@@ -1242,6 +1320,8 @@ editor.file_editing_no_longer_exists=Düzenlenmekte olan "%s" dosyası artık bu
editor.file_deleting_no_longer_exists=Silinen "%s" dosyası artık bu depoda yer almıyor.
editor.file_changed_while_editing=Düzenlemeye başladığınızdan beri dosya içeriği değişti. Görmek için burayı tıklayın veya üzerine yazmak için değişiklikleri yine de işleyin .
editor.file_already_exists=Bu depoda "%s" isimli bir dosya zaten var.
+editor.commit_id_not_matching=İşleme ID'si, düzenlemeye başladığınız ID ile uyuşmuyor, bir yama dalına işleme yapın ve sonra birleştirin.
+editor.push_out_of_date=İtme eskimiş.
editor.commit_empty_file_header=Boş bir dosya işle
editor.commit_empty_file_text=İşlemek üzere olduğunuz dosya boş. Devam edilsin mi?
editor.no_changes_to_show=Gösterilecek değişiklik yok.
@@ -1266,6 +1346,7 @@ commits.commits=İşleme
commits.no_commits=Ortak bir işleme yok. "%s" ve "%s" tamamen farklı geçmişlere sahip.
commits.nothing_to_compare=Bu dallar eşit.
commits.search.tooltip=Anahtar kelimeleri "author:", "committer:", "after:" veya "before:" ile kullanabilirsiniz, örneğin "revert author:Alice before:2019-01-13".
+commits.search_branch=Bu Dal
commits.search_all=Tüm Dallar
commits.author=Yazar
commits.message=Mesaj
@@ -1324,6 +1405,7 @@ projects.column.new=Yeni Sütun
projects.column.set_default=Varsayılanı Ayarla
projects.column.set_default_desc=Bu sütunu kategorize edilmemiş konular ve değişiklik istekleri için varsayılan olarak ayarlayın
projects.column.delete=Sutün Sil
+projects.column.deletion_desc=Bir proje sütununun silinmesi, ilgili tüm konuları varsayılan sütuna taşır. Devam edilsin mi?
projects.column.color=Renk
projects.open=Aç
projects.close=Kapat
@@ -1358,6 +1440,8 @@ issues.new.assignees=Atananlar
issues.new.clear_assignees=Atamaları Temizle
issues.new.no_assignees=Atanan Kişi Yok
issues.new.no_reviewers=Değerlendirici yok
+issues.new.blocked_user=Konu oluşturulamıyor, depo sahibi tarafından engellenmişsiniz.
+issues.edit.blocked_user=İçerik düzenlenemiyor, gönderen veya depo sahibi tarafından engellenmişsiniz.
issues.choose.get_started=Başla
issues.choose.open_external_link=Aç
issues.choose.blank=Varsayılan
@@ -1472,6 +1556,7 @@ issues.close_comment_issue=Yorum Yap ve Kapat
issues.reopen_issue=Yeniden aç
issues.reopen_comment_issue=Yorum Yap ve Yeniden Aç
issues.create_comment=Yorum yap
+issues.comment.blocked_user=Yorum oluşturulamıyor veya düzenlenemiyor, gönderen veya depo sahibi tarafından engellenmişsiniz.
issues.closed_at=`%[2]s konusunu kapattı`
issues.reopened_at=`%[2]s konusunu yeniden açtı`
issues.commit_ref_at=`%[2]s işlemesinde bu konuyu işaret etti`
@@ -1670,6 +1755,7 @@ compare.compare_head=karşılaştır
pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir.
pulls.new=Yeni Değişiklik İsteği
+pulls.new.blocked_user=Değişiklik isteği oluşturulamıyor, depo sahibi tarafından engellenmişsiniz.
pulls.view=Değişiklik İsteği Görüntüle
pulls.compare_changes=Yeni Değişiklik İsteği
pulls.allow_edits_from_maintainers=Bakımcıların düzenlemelerine izin ver
@@ -1694,6 +1780,7 @@ pulls.select_commit_hold_shift_for_range=İşleme seç. Bir aralık seçmek içi
pulls.review_only_possible_for_full_diff=İnceleme sadece tam fark görüntülemede mümkündür
pulls.filter_changes_by_commit=İşleme ile süz
pulls.nothing_to_compare=Bu dallar eşit. Değişiklik isteği oluşturmaya gerek yok.
+pulls.nothing_to_compare_have_tag=Seçili dal/etiket aynı.
pulls.nothing_to_compare_and_allow_empty_pr=Bu dallar eşittir. Bu Dİ boş olacak.
pulls.has_pull_request=`Bu dallar arasında zaten bir değişiklik isteği var: %[2]s#%[3]d `
pulls.create=Değişiklik İsteği Oluştur
@@ -1752,6 +1839,7 @@ pulls.merge_pull_request=Birleştirme işlemi oluştur
pulls.rebase_merge_pull_request=Yeniden yapılandır ve ileri sar
pulls.rebase_merge_commit_pull_request=Yeniden yapılandır ve birleştirme işlemi oluştur
pulls.squash_merge_pull_request=Ezme işlemi oluştur
+pulls.fast_forward_only_merge_pull_request=Sadece ileri sarma
pulls.merge_manually=Elle birleştirildi
pulls.merge_commit_id=Birleştirme işlemesi kimliği
pulls.require_signed_wont_sign=Dal imzalı işlemeler gerektiriyor, ancak bu birleştirme imzalanmayacak
@@ -1888,6 +1976,10 @@ wiki.page_name_desc=Bu Viki sayfası için bir ad girin. Bazı özel isimler 'Ho
wiki.original_git_entry_tooltip=Kolay bağlantı kullanmak yerine özgün Git dosyasını görüntüle.
activity=Aktivite
+activity.navbar.pulse=Eğilim
+activity.navbar.code_frequency=Kod Frekansı
+activity.navbar.contributors=Katkıda Bulunanlar
+activity.navbar.recent_commits=Son İşlemeler
activity.period.filter_label=Dönem:
activity.period.daily=1 gün
activity.period.halfweekly=3 gün
@@ -1953,7 +2045,10 @@ activity.git_stats_and_deletions=ve
activity.git_stats_deletion_1=%d silme oldu
activity.git_stats_deletion_n=%d silme oldu
+contributors.contribution_type.filter_label=Katkı türü:
contributors.contribution_type.commits=İşleme
+contributors.contribution_type.additions=Eklemeler
+contributors.contribution_type.deletions=Silmeler
settings=Ayarlar
settings.desc=Ayarlar, deponun ayarlarını yönetebileceğiniz yerdir
@@ -1981,6 +2076,7 @@ settings.mirror_settings.docs.doc_link_title=Depoların yansısını nasıl olu
settings.mirror_settings.docs.doc_link_pull_section=belgelerin "uzak bir depodan çekmek" bölümü.
settings.mirror_settings.docs.pulling_remote_title=Uzak bir depodan çekmek
settings.mirror_settings.mirrored_repository=Yansıtılmış depo
+settings.mirror_settings.pushed_repository=İtilmiş depo
settings.mirror_settings.direction=Yön
settings.mirror_settings.direction.pull=Çek
settings.mirror_settings.direction.push=Gönder
@@ -2002,6 +2098,9 @@ settings.branches.add_new_rule=Yeni Kural Ekle
settings.advanced_settings=Gelişmiş Ayarlar
settings.wiki_desc=Depo Wiki'sini Etkinkleştir
settings.use_internal_wiki=Dahili Wiki Kullan
+settings.default_wiki_branch_name=Varsayılan Viki Dal Adı
+settings.default_wiki_everyone_access=Oturum açmış kullanıcılar için Varsayılan Erişim İzinleri:
+settings.failed_to_change_default_wiki_branch=Varsayılan viki dalı değiştirilemedi.
settings.use_external_wiki=Harici Wiki Kullan
settings.external_wiki_url=Harici Wiki bağlantısı
settings.external_wiki_url_error=Harici wiki URL'si geçerli bir URL değil.
@@ -2032,6 +2131,9 @@ settings.pulls.default_allow_edits_from_maintainers=Bakımcıların düzenlemele
settings.releases_desc=Depo Sürümlerini Etkinleştir
settings.packages_desc=Depo Paket Kütüğünü Etkinleştir
settings.projects_desc=Depo Projelerini Etkinleştir
+settings.projects_mode_desc=Proje Modu (ne tür projeler görüntülensin)
+settings.projects_mode_repo=Sadece depo projeleri
+settings.projects_mode_owner=Sadece kullanıcı veya organizasyon projeleri
settings.projects_mode_all=Tüm projeler
settings.actions_desc=Depo İşlemlerini Etkinleştir
settings.admin_settings=Yönetici Ayarları
@@ -2058,6 +2160,7 @@ settings.convert_fork_succeed=Çatal normal bir depoya dönüştürüldü.
settings.transfer=Sahipliği Aktar
settings.transfer.rejected=Depo aktarımı reddedildi.
settings.transfer.success=Depo aktarımı başarıyla tamamlandı.
+settings.transfer.blocked_user=Depo transfer edilemiyor, yeni sahibi tarafından engellenmişsiniz.
settings.transfer_abort=Aktarımı iptal et
settings.transfer_abort_invalid=Var olmayan bir depo aktarımını iptal edemezsiniz.
settings.transfer_abort_success=%s tarafına yapılan depo aktarımı başarıyla iptal edildi.
@@ -2103,6 +2206,7 @@ settings.add_collaborator_success=Katkıcı eklendi.
settings.add_collaborator_inactive_user=Etkin olmayan bir kullanıcı katkıcı olarak eklenemez.
settings.add_collaborator_owner=Bir sahip katkıcı olarak eklenemez.
settings.add_collaborator_duplicate=Katkıcı bu depoya zaten eklenmiş.
+settings.add_collaborator.blocked_user=Katkıcı depo sahibi tarafından engellenmiş veya depo sahibini engellemiş.
settings.delete_collaborator=Sil
settings.collaborator_deletion=Katkıcıyı Sil
settings.collaborator_deletion_desc=Bir katkıcıyı silmek, bu depoya erişimini iptal edecektir. Devam et?
@@ -2287,6 +2391,8 @@ settings.protect_approvals_whitelist_users=Beyaz listedeki incelemeciler:
settings.protect_approvals_whitelist_teams=Gözden geçirme için beyaz listedeki takımlar:
settings.dismiss_stale_approvals=Eski onayları reddet
settings.dismiss_stale_approvals_desc=Değişiklik isteğinin içeriğini değiştiren yeni işlemeler dala itildiğinde, eski onaylar reddedilir.
+settings.ignore_stale_approvals=Eskimiş onayları yoksay
+settings.ignore_stale_approvals_desc=Daha eski işlemelere (eski incelemelere) yapılmış olan onayları, Dİ'nin kaç onayı olduğunu belirlerken sayma. Eskimiş incelemeler atıldıysa bu ilgisizdir.
settings.require_signed_commits=İmzalı İşleme Gerekli
settings.require_signed_commits_desc=Reddetme, onlar imzasızsa veya doğrulanamazsa bu dala gönderir.
settings.protect_branch_name_pattern=Korunmuş Dal Adı Deseni
@@ -2342,6 +2448,7 @@ settings.archive.error=Depoyu arşivlemeye çalışırken bir hata oluştu. Daha
settings.archive.error_ismirror=Yansılanmış bir depoyu arşivleyemezsiniz.
settings.archive.branchsettings_unavailable=Depo arşivlenirse dal ayarları kullanılamaz.
settings.archive.tagsettings_unavailable=Depo arşivlenmişse etiket ayarları kullanılamaz.
+settings.archive.mirrors_unavailable=Depo arşivlenmişse yansılar kullanılamaz.
settings.unarchive.button=Depoyu Arşivden Çıkar
settings.unarchive.header=Bu Depoyu Arşivden Çıkar
settings.unarchive.text=Depoyu arşivden çıkarmak, yeni sorunların ve değişiklik isteklerinin yanı sıra işleme ve itme yeteneğini de geri kazandıracaktır.
@@ -2538,8 +2645,16 @@ find_file.no_matching=Eşleşen dosya bulunamadı
error.csv.too_large=Bu dosya çok büyük olduğu için işlenemiyor.
error.csv.unexpected=%d satırı ve %d sütununda beklenmeyen bir karakter içerdiğinden bu dosya işlenemiyor.
error.csv.invalid_field_count=%d satırında yanlış sayıda alan olduğundan bu dosya işlenemiyor.
+error.broken_git_hook=Bu deponun Git İstemcileri bozuk gibi gözüküyor. Onarmak için lütfen belgelere bakın, daha sonra durumu yenilemek için bazı işlemeler itin.
[graphs]
+component_loading=%s yükleniyor...
+component_loading_failed=%s yüklenemedi
+component_loading_info=Bu biraz sürebilir…
+component_failed_to_load=Beklenmedik bir hata oluştu.
+code_frequency.what=kod frekansı
+contributors.what=katkılar
+recent_commits.what=son işlemeler
[org]
org_name_holder=Organizasyon Adı
@@ -2653,6 +2768,7 @@ teams.add_nonexistent_repo=Eklemeye çalıştığınz depo mevcut değil. Lütfe
teams.add_duplicate_users=Kullanıcı zaten takımın üyesi.
teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi.
teams.members.none=Bu takımda üye yok.
+teams.members.blocked_user=Kullanıcı eklenemiyor, çünkü organizasyon tarafından engellenmiş.
teams.specific_repositories=Belirli depolar
teams.specific_repositories_helper=Üyeler, yalnızca takıma açıkça eklenen depolara erişebilir. Bunu seçmek, Tüm depolarla zaten eklenmiş olan depoları otomatik olarak kaldırmaz .
teams.all_repositories=Tüm depolar
@@ -2665,7 +2781,9 @@ teams.invite.by=%s tarafından davet edildi
teams.invite.description=Takıma katılmak için aşağıdaki düğmeye tıklayın.
[admin]
+maintenance=Bakım
dashboard=Pano
+self_check=Öz Denetim
identity_access=Kimlik ve Erişim
users=Kullanıcı Hesapları
organizations=Organizasyonlar
@@ -2687,6 +2805,7 @@ settings=Yönetici Ayarları
dashboard.new_version_hint=Gitea %s şimdi hazır, %s çalıştırıyorsunuz. Ayrıntılar için blog 'a bakabilirsiniz.
dashboard.statistic=Özet
+dashboard.maintenance_operations=Bakım İşlemleri
dashboard.system_status=Sistem Durumu
dashboard.operation_name=İşlem Adı
dashboard.operation_switch=Geç
@@ -2712,6 +2831,7 @@ dashboard.delete_missing_repos=Git dosyaları eksik olan tüm depoları sil
dashboard.delete_missing_repos.started=Git dosyaları eksik olan tüm depoları silme görevi başladı.
dashboard.delete_generated_repository_avatars=Oluşturulan depo resimlerini sil
dashboard.sync_repo_branches=Eşzamanlama git verisinden veritabanlarına dalları kaçırdı
+dashboard.sync_repo_tags=Etiketleri git verisinden veritabanına eşitle
dashboard.update_mirrors=Yansıları Güncelle
dashboard.repo_health_check=Tüm depoların sağlığını denetle
dashboard.check_repo_stats=Tüm depo istatistiklerini denetle
@@ -2766,6 +2886,7 @@ dashboard.stop_endless_tasks=Daimi görevleri durdur
dashboard.cancel_abandoned_jobs=Terkedilmiş görevleri iptal et
dashboard.start_schedule_tasks=Zamanlanmış görevleri başlat
dashboard.sync_branch.started=Dal Eşzamanlaması başladı
+dashboard.sync_tag.started=Etiket eşitlemesi başladı
dashboard.rebuild_issue_indexer=Konu indeksini yeniden oluştur
users.user_manage_panel=Kullanıcı Hesap Yönetimi
@@ -2970,13 +3091,14 @@ auths.tips=İpuçları
auths.tips.oauth2.general=OAuth2 Kimlik Doğrulama
auths.tips.oauth2.general.tip=Yeni bir OAuth2 kimlik doğrulama kaydederken, geri çağırma/yönlendirme URL'si şu olmalıdır:
auths.tip.oauth2_provider=OAuth2 Sağlayıcısı
-auths.tip.bitbucket=https://bitbucket.org/account/user//oauth-consumers/new adında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin
+auths.tip.bitbucket=https://bitbucket.org/account/user/{your-username}/oauth-consumers/new sayfasında yeni bir OAuth tüketicisi kaydedin ve 'Hesap' - 'Oku' iznini ekleyin
auths.tip.nextcloud=Aşağıdaki "Ayarlar -> Güvenlik -> OAuth 2.0 istemcisi" menüsünü kullanarak örneğinize yeni bir OAuth tüketicisi kaydedin
auths.tip.dropbox=https://www.dropbox.com/developers/apps adresinde yeni bir uygulama oluştur
auths.tip.facebook=https://developers.facebook.com/apps adresinde yeni bir uygulama kaydedin ve "Facebook Giriş" ürününü ekleyin
auths.tip.github=https://github.com/settings/applications/new adresinde yeni bir OAuth uygulaması kaydedin
+auths.tip.gitlab_new=https://gitlab.com/-/profile/applications adresinde yeni bir uygulama kaydedin
auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.developers.google.com/ adresindeki Google API konsolundan edinin
-auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini kullanın (/.well-known/openid-configuration)
+auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini (https://{server}/.well-known/openid-configuration) kullanın
auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun
auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin
auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.com/development/oauth2-provider adresinde bulunabilir
@@ -3110,6 +3232,7 @@ config.picture_config=Resim ve Avatar Yapılandırması
config.picture_service=Resim Servisi
config.disable_gravatar=Gravatar Hizmet Dışı
config.enable_federated_avatar=Birleştirilmiş Avatarları Etkinleştir
+config.open_with_editor_app_help=Klon menüsü için "Birlikte aç" düzenleyicileri. Boş bırakılırsa, varsayılan kullanılacaktır. Varsayılanı görmek için genişletin.
config.git_config=Git Yapılandırması
config.git_disable_diff_highlight=Değişiklik Sözdizimi Vurgusunu Devre Dışı Bırak
@@ -3188,6 +3311,13 @@ notices.desc=Açıklama
notices.op=İşlem
notices.delete_success=Sistem bildirimleri silindi.
+self_check.no_problem_found=Henüz bir sorun bulunmadı.
+self_check.startup_warnings=Başlangıç uyarıları:
+self_check.database_collation_mismatch=Veritabanının şu harmanlamayı kullanmasını bekle: %s
+self_check.database_collation_case_insensitive=Veritabanı %s harmanlamasını kullanıyor, bu duyarsız bir harmanlamadır. Her ne kadar Gitea bununla çalışabilse de, beklendiği gibi çalışmadığı nadir durumlar ortaya çıkabilir.
+self_check.database_inconsistent_collation_columns=Veritabanı %s harmanlamasını kullanıyor, ancak bu sütunlar uyumsuz harmanlamalar kullanıyor. Bu beklenmedik sorunlar oluşturabilir.
+self_check.database_fix_mysql=MySQL/MariaDB kullanıcıları "gitea doctor convert" komutunu harmanlama sorunlarını çözmek için kullanabilir veya "ALTER ... COLLATE ..." SQL'lerini şahsen çalıştırarak sorunu çözebilirler.
+self_check.database_fix_mssql=MSSQL kullanıcıları sorunu şu an sadece "ALTER ... COLLATE ..." SQL'lerini şahsen çalıştırarak çözebilirler.
[action]
create_repo=depo %s oluşturuldu
@@ -3375,6 +3505,7 @@ rpm.distros.suse=SUSE tabanlı dağıtımlarda
rpm.install=Paketi kurmak için, aşağıdaki komutu çalıştırın:
rpm.repository=Depo Bilgisi
rpm.repository.architectures=Mimariler
+rpm.repository.multiple_groups=Bu paket birçok grupta mevcut.
rubygems.install=Paketi gem ile kurmak için, şu komutu çalıştırın:
rubygems.install2=veya paketi Gemfile dosyasına ekleyin:
rubygems.dependencies.runtime=Çalışma Zamanı Bağımlılıkları
@@ -3501,12 +3632,15 @@ runs.scheduled=Zamanlanmış
runs.pushed_by=iten
runs.invalid_workflow_helper=İş akışı yapılandırma dosyası geçersiz. Lütfen yapılandırma dosyanızı denetleyin: %s
runs.no_matching_online_runner_helper=Şu etiket ile eşleşen çevrimiçi çalıştırıcı bulunamadı: %s
+runs.no_job_without_needs=İş akışı en azından bağımlılığı olmayan bir görev içermelidir.
runs.actor=Aktör
runs.status=Durum
runs.actors_no_select=Tüm aktörler
runs.status_no_select=Tüm durumlar
runs.no_results=Eşleşen sonuç yok.
runs.no_workflows=Henüz hiç bir iş akışı yok.
+runs.no_workflows.quick_start=Gitea İşlemlerini nasıl başlatacağınızı bilmiyor musunuz? Hızlı başlangıç kılavuzuna bakabilirsiniz.
+runs.no_workflows.documentation=Gitea İşlemleri hakkında daha fazla bilgi için, belgelere bakabilirsiniz.
runs.no_runs=İş akışı henüz hiç çalıştırılmadı.
runs.empty_commit_message=(boş işleme iletisi)
@@ -3525,6 +3659,7 @@ variables.none=Henüz hiçbir değişken yok.
variables.deletion=Değişkeni kaldır
variables.deletion.description=Bir değişkeni kaldırma kalıcıdır ve geri alınamaz. Devam edilsin mi?
variables.description=Değişkenler belirli işlemlere aktarılacaktır, bunun dışında okunamaz.
+variables.id_not_exist=%d kimlikli değişken mevcut değil.
variables.edit=Değişkeni Düzenle
variables.deletion.failed=Değişken kaldırılamadı.
variables.deletion.success=Değişken kaldırıldı.
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index e8a3acedda..613f39b3c9 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -955,7 +955,6 @@ editor.or=або
editor.cancel_lower=Скасувати
editor.commit_signed_changes=Внести підписані зміни
editor.commit_changes=Закомітити зміни
-editor.add_tmpl=Додати ''
editor.commit_message_desc=Додати необов'язковий розширений опис…
editor.signoff_desc=Додатиь Signed-off-by комітом в конці повідомлення журналу комітів.
editor.commit_directly_to_this_branch=Зробіть коміт прямо в гілку %s .
@@ -2306,13 +2305,11 @@ auths.sspi_default_language_helper=Типова мова для користув
auths.tips=Поради
auths.tips.oauth2.general=OAuth2 автентифікація
auths.tip.oauth2_provider=Постачальник OAuth2
-auths.tip.bitbucket=Створіть OAuth URI на сторінці https://bitbucket.org/account/user//oauth-consumers/new і додайте права 'Account' - 'Read'
auths.tip.nextcloud=`Зареєструйте нового споживача OAuth у вашому екземплярі за допомогою наступного меню "Налаштування -> Безпека -> клієнт OAuth 2.0"`
auths.tip.dropbox=Додайте новий додаток на https://www.dropbox.com/developers/apps
auths.tip.facebook=`Створіть новий додаток на https://developers.facebook.com/apps і додайте модуль "Facebook Login"`
auths.tip.github=Додайте OAuth додаток на https://github.com/settings/applications/new
auths.tip.google_plus=Отримайте облікові дані клієнта OAuth2 в консолі Google API на сторінці https://console.developers.google.com/
-auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (/.well-known/openid-configuration) для автоматичної настройки входу OAuth
auths.tip.twitter=Перейдіть на https://dev.twitter.com/apps, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter»
auths.tip.discord=Зареєструйте новий додаток на https://discordapp.com/developers/applications/me
auths.tip.yandex=`Створіть нову програму в https://oauth.yandex.com/client/new. Виберіть наступні дозволи з "Yandex. assport API": "Доступ до адреси електронної пошти", "Доступ до аватара" і "Доступ до імені користувача, імені та прізвища, статі"`
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 01058d48d2..aeba11fb9a 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -25,6 +25,7 @@ enable_javascript=此网站需要 JavaScript。
toc=目录
licenses=许可证
return_to_gitea=返回 Gitea
+more_items=更多选项
username=用户名
email=电子邮件地址
@@ -113,6 +114,7 @@ loading=正在加载...
error=错误
error404=您正尝试访问的页面 不存在 或 您尚未被授权 查看该页面。
go_back=返回
+invalid_data=无效数据: %v
never=从不
unknown=未知
@@ -143,13 +145,43 @@ name=名称
value=值
filter=过滤
+filter.clear=清除筛选器
filter.is_archived=已归档
+filter.not_archived=非存档
+filter.is_fork=派生
+filter.not_fork=非派生
+filter.is_mirror=镜像
+filter.not_mirror=非镜像
filter.is_template=模板
+filter.not_template=非模板
filter.public=公开
filter.private=私有库
+no_results_found=未找到结果
[search]
+search=搜索...
+type_tooltip=搜索类型
+fuzzy=模糊
+fuzzy_tooltip=包含近似匹配搜索词的结果
+exact=精确
+exact_tooltip=仅包含精确匹配搜索词的结果
+repo_kind=搜索仓库...
+user_kind=搜索用户...
+org_kind=搜索组织...
+team_kind=搜索团队...
+code_kind=搜索代码...
+code_search_unavailable=代码搜索当前不可用。请与网站管理员联系。
+code_search_by_git_grep=当前代码搜索结果由“git grep”提供。如果站点管理员启用仓库索引器,可能会有更好的结果。
+package_kind=搜索软件包...
+project_kind=搜索项目...
+branch_kind=搜索分支...
+commit_kind=搜索提交记录...
+runner_kind=搜索runners...
+no_results=未找到匹配结果
+issue_kind=搜索工单...
+pull_kind=搜索合并请求...
+keyword_search_unavailable=按关键字搜索当前不可用。请联系站点管理员。
[aria]
navbar=导航栏
@@ -256,6 +288,7 @@ email_title=电子邮箱设置
smtp_addr=SMTP 主机地址
smtp_port=SMTP 端口
smtp_from=电子邮件发件人
+smtp_from_invalid=`"发送电子邮件为"地址无效`
smtp_from_helper=请输入一个用于 Gitea 的电子邮件地址,或者使用完整格式:"名称"
mailer_user=SMTP 用户名
mailer_password=SMTP 密码
@@ -315,6 +348,7 @@ env_config_keys=环境配置
env_config_keys_prompt=以下环境变量也将应用于您的配置文件:
[home]
+nav_menu=导航菜单
uname_holder=用户名或邮箱
password_holder=密码
switch_dashboard_context=切换控制面板用户
@@ -363,6 +397,7 @@ forgot_password_title=忘记密码
forgot_password=忘记密码?
sign_up_now=还没帐户?马上注册。
sign_up_successful=帐户创建成功。欢迎!
+confirmation_mail_sent_prompt_ex=一封新的确认邮件已经发送到 %s 请在下一个 %s 中检查您的收件箱以完成注册过程。 如果您的注册电子邮件地址不正确,您可以重新登录并更改它。
must_change_password=更新您的密码
allow_password_change=要求用户更改密码(推荐)
reset_password_mail_sent_prompt=确认电子邮件已被发送到 %s 。请您在 %s 内检查您的收件箱 ,完成密码重置过程。
@@ -372,6 +407,7 @@ prohibit_login=禁止登录
prohibit_login_desc=您的帐户被禁止登录,请与网站管理员联系。
resent_limit_prompt=您请求发送激活邮件过于频繁,请等待 3 分钟后再试!
has_unconfirmed_mail=%s 您好,系统检测到您有一封发送至 %s 但未被确认的邮件。如果您未收到激活邮件,或需要重新发送,请单击下方的按钮。
+change_unconfirmed_mail_address=如果您的注册电子邮件地址不正确,您可以在此更改并重新发送新的确认电子邮件。
resend_mail=单击此处重新发送确认邮件
email_not_associate=您输入的邮箱地址未被关联到任何帐号!
send_reset_mail=发送账户恢复邮件
@@ -552,6 +588,7 @@ team_name_been_taken=团队名称已被使用。
team_no_units_error=至少选择一项仓库单元。
email_been_used=该电子邮件地址已在使用中。
email_invalid=此邮箱地址无效。
+email_domain_is_not_allowed=用户 %s 与EMAIL_DOMAIN_ALLOWLIT 或 EMAIL_DOMAIN_BLOCKLIT 冲突。请确保您的操作是预期的。
openid_been_used=OpenID 地址 "%s" 已被使用。
username_password_incorrect=用户名或密码不正确。
password_complexity=密码未达到复杂程度要求:
@@ -563,6 +600,8 @@ enterred_invalid_repo_name=输入的仓库名称不正确
enterred_invalid_org_name=您输入的组织名称不正确。
enterred_invalid_owner_name=新的所有者名称无效。
enterred_invalid_password=输入的密码不正确
+unset_password=登录用户没有设置密码。
+unsupported_login_type=此登录类型不支持手动删除帐户。
user_not_exist=该用户不存在
team_not_exist=团队不存在
last_org_owner=您不能从 "所有者" 团队中删除最后一个用户。组织中必须至少有一个所有者。
@@ -612,6 +651,29 @@ form.name_reserved=用户名 "%s" 被保留。
form.name_pattern_not_allowed=用户名中不允许使用 "%s" 格式。
form.name_chars_not_allowed=用户名 "%s" 包含无效字符。
+block.block=屏蔽
+block.block.user=屏蔽用户
+block.block.org=屏蔽用户访问组织
+block.block.failure=屏蔽用户失败: %s
+block.unblock=取消屏蔽
+block.unblock.failure=屏蔽用户失败: %s
+block.blocked=您已屏蔽此用户。
+block.title=屏蔽一个用户
+block.info=屏蔽用户会阻止他们与仓库进行交互,例如打开或评论合并请求或出现问题。了解更多关于屏蔽用户的信息。
+block.info_1=阻止用户在您的帐户和仓库中进行以下操作:
+block.info_2=关注你的账号
+block.info_3=通过@提及您的用户名向您发送通知
+block.info_4=邀请您作为协作者到他们的仓库中
+block.info_5=在仓库中点赞、派生或关注
+block.info_6=打开和评论工单或合并请求
+block.info_7=在问题或合并请求中对您的评论做出反应
+block.user_to_block=要屏蔽的用户
+block.note=备注
+block.note.title=可选备注:
+block.note.info=该备注对被屏蔽的用户不可见。
+block.note.edit=编辑备注
+block.list=已屏蔽用户
+block.list.none=您没有已屏蔽的用户。
[settings]
profile=个人信息
@@ -825,6 +887,7 @@ repo_and_org_access=仓库和组织访问权限
permissions_public_only=仅公开
permissions_access_all=全部(公开、私有和受限)
select_permissions=选择权限
+permission_not_set=未设置
permission_no_access=无访问权限
permission_read=可读
permission_write=读写
@@ -949,7 +1012,9 @@ fork_visibility_helper=无法更改派生仓库的可见性。
fork_branch=要克隆到 Fork 的分支
all_branches=所有分支
fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。
+fork.blocked_user=无法克隆仓库,因为您被仓库所有者屏蔽。
use_template=使用此模板
+open_with_editor=用 %s 打开
download_zip=下载 ZIP
download_tar=下载 TAR.GZ
download_bundle=下载 BUNDLE
@@ -1002,6 +1067,7 @@ watchers=关注者
stargazers=称赞者
stars_remove_warning=这将清除此仓库的所有点赞数。
forks=派生仓库
+stars=点赞数
reactions_more=再加载 %d
unit_disabled=站点管理员已禁用此仓库单元。
language_other=其它
@@ -1123,6 +1189,7 @@ watch=关注
unstar=取消点赞
star=点赞
fork=派生
+action.blocked_user=无法执行操作,因为您已被仓库所有者屏蔽。
download_archive=下载此仓库
more_operations=更多操作
@@ -1169,6 +1236,8 @@ file_view_rendered=渲染模式
file_view_raw=查看原始文件
file_permalink=永久链接
file_too_large=文件过大,无法显示。
+code_preview_line_from_to=在 %[3]s 的第 %[1]d 行到 %[2]d 行
+code_preview_line_in=在 %[2]s 的第 %[1]d 行
invisible_runes_header=`此文件含有不可见的 Unicode 字符`
invisible_runes_description=`此文件含有人类无法区分的不可见的 Unicode 字符,但可以由计算机进行不同的处理。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。`
ambiguous_runes_header=`此文件含有模棱两可的 Unicode 字符`
@@ -1223,7 +1292,7 @@ editor.or=或
editor.cancel_lower=取消
editor.commit_signed_changes=提交已签名的更改
editor.commit_changes=提交变更
-editor.add_tmpl=添加 ''
+editor.add_tmpl=添加 '{filename}'
editor.add=添加 %s
editor.update=更新 %s
editor.delete=删除 %s
@@ -1251,6 +1320,8 @@ editor.file_editing_no_longer_exists=正在编辑的文件 %s 已不存在。
editor.file_deleting_no_longer_exists=正在删除的文件 %s 已不存在。
editor.file_changed_while_editing=文件内容在您进行编辑时已经发生变动。单击此处 查看变动的具体内容,或者 再次提交 覆盖已发生的变动。
editor.file_already_exists=此仓库已经存在名为 %s 的文件。
+editor.commit_id_not_matching=提交ID与您开始编辑时的ID不匹配。请提交到补丁分支然后合并。
+editor.push_out_of_date=推送似乎已经过时。
editor.commit_empty_file_header=提交一个空文件
editor.commit_empty_file_text=您要提交的文件是空的,继续吗?
editor.no_changes_to_show=没有可以显示的变更。
@@ -1275,6 +1346,7 @@ commits.commits=次代码提交
commits.no_commits=没有共同的提交。%s 和 %s 的历史完全不同。
commits.nothing_to_compare=这些分支是相同的。
commits.search.tooltip=`您可以在关键词前加上前缀,如"author:", "committer:", "after:", 或"before:", 例如 "retrin author:Alice before:2019-01-13"`
+commits.search_branch=此分支
commits.search_all=所有分支
commits.author=作者
commits.message=备注
@@ -1333,6 +1405,7 @@ projects.column.new=创建列
projects.column.set_default=设为默认
projects.column.set_default_desc=设置此列为未分类问题和合并请求的默认值
projects.column.delete=删除列
+projects.column.deletion_desc=删除项目列会将所有相关问题移到“未分类”。是否继续?
projects.column.color=彩色
projects.open=开启
projects.close=关闭
@@ -1367,6 +1440,8 @@ issues.new.assignees=指派成员
issues.new.clear_assignees=取消指派成员
issues.new.no_assignees=未指派成员
issues.new.no_reviewers=无审核者
+issues.new.blocked_user=无法创建工单,因为您已被仓库所有者屏蔽。
+issues.edit.blocked_user=无法编辑内容,因为您已被仓库所有者或工单创建者屏蔽。
issues.choose.get_started=开始
issues.choose.open_external_link=开启
issues.choose.blank=默认模板
@@ -1481,6 +1556,7 @@ issues.close_comment_issue=评论并关闭
issues.reopen_issue=重新开启
issues.reopen_comment_issue=评论并重新开启
issues.create_comment=评论
+issues.comment.blocked_user=无法创建或编辑评论,因为您已被仓库所有者或工单创建者屏蔽。
issues.closed_at=`于 %[2]s 关闭此工单`
issues.reopened_at=`重新打开此问题 %[2]s `
issues.commit_ref_at=`于 %[2]s 在代码提交中引用了该工单`
@@ -1679,6 +1755,7 @@ compare.compare_head=比较
pulls.desc=启用合并请求和代码评审。
pulls.new=创建合并请求
+pulls.new.blocked_user=无法创建合并请求,因为您已被仓库所有者屏蔽。
pulls.view=查看拉取请求
pulls.compare_changes=创建合并请求
pulls.allow_edits_from_maintainers=允许维护者编辑
@@ -1762,6 +1839,7 @@ pulls.merge_pull_request=创建合并提交
pulls.rebase_merge_pull_request=变基后快进
pulls.rebase_merge_commit_pull_request=变基后创建合并提交
pulls.squash_merge_pull_request=创建压缩提交
+pulls.fast_forward_only_merge_pull_request=仅快进
pulls.merge_manually=手动合并
pulls.merge_commit_id=合并提交 ID
pulls.require_signed_wont_sign=分支需要签名的提交,但这个合并将不会被签名
@@ -1898,7 +1976,10 @@ wiki.page_name_desc=输入此 Wiki 页面的名称。特殊名称有:'Home', '
wiki.original_git_entry_tooltip=查看原始的 Git 文件而不是使用友好链接。
activity=动态
+activity.navbar.pulse=活动
+activity.navbar.code_frequency=代码频率
activity.navbar.contributors=贡献者
+activity.navbar.recent_commits=最近的提交
activity.period.filter_label=周期:
activity.period.daily=1 天
activity.period.halfweekly=3 天
@@ -2017,6 +2098,9 @@ settings.branches.add_new_rule=添加新规则
settings.advanced_settings=高级设置
settings.wiki_desc=启用仓库百科
settings.use_internal_wiki=使用内置百科
+settings.default_wiki_branch_name=默认百科分支名称
+settings.default_wiki_everyone_access=登录用户的默认访问权限:
+settings.failed_to_change_default_wiki_branch=更改百科默认分支失败。
settings.use_external_wiki=使用外部百科
settings.external_wiki_url=外部 Wiki 链接
settings.external_wiki_url_error=外部百科链接无效
@@ -2047,6 +2131,9 @@ settings.pulls.default_allow_edits_from_maintainers=默认开启允许维护者
settings.releases_desc=启用发布
settings.packages_desc=启用仓库软件包注册中心
settings.projects_desc=启用仓库项目
+settings.projects_mode_desc=项目模式 (要显示的项目类型)
+settings.projects_mode_repo=仅仓库项目
+settings.projects_mode_owner=仅限用户或组织项目
settings.projects_mode_all=所有项目
settings.actions_desc=启用 Actions
settings.admin_settings=管理员设置
@@ -2073,6 +2160,7 @@ settings.convert_fork_succeed=此派生仓库已经转换为普通仓库。
settings.transfer=转移仓库所有权
settings.transfer.rejected=代码库转移被拒绝。
settings.transfer.success=代码库转移成功。
+settings.transfer.blocked_user=无法传输仓库,因为您被新的所有者屏蔽。
settings.transfer_abort=取消转移
settings.transfer_abort_invalid=你不能取消不存在的代码库转移。
settings.transfer_abort_success=成功取消了将代码库转让给 %s。
@@ -2118,6 +2206,7 @@ settings.add_collaborator_success=协作者添加成功!
settings.add_collaborator_inactive_user=无法添加未激活的用户作为合作者。
settings.add_collaborator_owner=不能将所有者添加为协作者。
settings.add_collaborator_duplicate=合作者已经被添加到本仓库。
+settings.add_collaborator.blocked_user=此写作者被仓库所有者屏蔽,反之亦然。
settings.delete_collaborator=删除
settings.collaborator_deletion=删除协作者
settings.collaborator_deletion_desc=删除协作者后他将无法再对此仓库的访问。继续?
@@ -2556,13 +2645,16 @@ find_file.no_matching=没有找到匹配的文件
error.csv.too_large=无法渲染此文件,因为它太大了。
error.csv.unexpected=无法渲染此文件,因为它包含了意外字符,其位于第 %d 行和第 %d 列。
error.csv.invalid_field_count=无法渲染此文件,因为它在第 %d 行中的字段数有误。
+error.broken_git_hook=此仓库的 Git 钩子似乎已损坏。 请按照 文档 来修复它们,然后推送一些提交来刷新状态。
[graphs]
component_loading=正在加载 %s...
component_loading_failed=无法加载 %s
component_loading_info=这可能需要一点…
component_failed_to_load=意外的错误发生了。
+code_frequency.what=代码频率
contributors.what=贡献
+recent_commits.what=最近的提交
[org]
org_name_holder=组织名称
@@ -2676,6 +2768,7 @@ teams.add_nonexistent_repo=您尝试添加的仓库不存在,请先创建它
teams.add_duplicate_users=用户已经是团队成员。
teams.repos.none=此团队无法访问任何仓库。
teams.members.none=团队中没有成员。
+teams.members.blocked_user=不能添加用户因为他已经被该组织屏蔽。
teams.specific_repositories=指定仓库
teams.specific_repositories_helper=团队成员将只能访问添加到团队的仓库。 选择此项 将不会 自动删除已经添加的仓库。
teams.all_repositories=所有仓库
@@ -2688,6 +2781,7 @@ teams.invite.by=邀请人 %s
teams.invite.description=请点击下面的按钮加入团队。
[admin]
+maintenance=维护
dashboard=管理面板
self_check=自我检查
identity_access=身份及认证
@@ -2711,6 +2805,7 @@ settings=管理设置
dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 博客 了解详情。
dashboard.statistic=摘要
+dashboard.maintenance_operations=运维
dashboard.system_status=系统状态
dashboard.operation_name=操作名称
dashboard.operation_switch=开关
@@ -2996,13 +3091,14 @@ auths.tips=帮助提示
auths.tips.oauth2.general=OAuth2 认证
auths.tips.oauth2.general.tip=当注册新的 OAuth2 身份验证时,回调/重定向 URL 应该是:
auths.tip.oauth2_provider=OAuth2 提供程序
-auths.tip.bitbucket=`在 https://bitbucket.org/account/user//oauth-consumers/new 注册新的 OAuth 消费者同时添加权限"帐户"-"读"`
+auths.tip.bitbucket=在 https://bitbucket.org/account/user/{your username}/oauth-consumers/new 注册新的 OAuth 使用者同时添加权限“账号”-“读取”
auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Security) -> OAuth 2.0 client”在您的实例上注册一个新的 OAuth 客户端。
auths.tip.dropbox=在 https://www.dropbox.com/developers/apps 上创建一个新的应用程序
auths.tip.facebook=`在 https://developers.facebook.com/apps 注册一个新的应用,并添加产品"Facebook 登录"`
auths.tip.github=在 https://github.com/settings/applications/new 注册一个 OAuth 应用程序
+auths.tip.gitlab_new=在 https://gitlab.com/-/profile/applications 注册一个新的应用
auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google.com/) 获得 OAuth2 客户端凭据
-auths.tip.openid_connect=使用 OpenID 连接发现 URL (/.well-known/openid-configuration) 来指定终点
+auths.tip.openid_connect=使用 OpenID 连接发现 URL ({server}/.well-known/openid-configuration) 来指定终点
auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。
auths.tip.discord=在 https://discordapp.com/developers/applications/me 上注册新应用程序
auths.tip.gitea=注册一个新的 OAuth2 应用程序。可以访问 https://docs.gitea.com/development/oauth2-provider 查看帮助
@@ -3136,6 +3232,7 @@ config.picture_config=图片和头像配置
config.picture_service=图片服务
config.disable_gravatar=禁用 Gravatar 头像
config.enable_federated_avatar=启用 Federated Avatars
+config.open_with_editor_app_help=用于克隆菜单的编辑器。如果为空将使用默认值。展开可以查看默认值。
config.git_config=Git 配置
config.git_disable_diff_highlight=禁用差异对比语法高亮
@@ -3215,6 +3312,7 @@ notices.op=操作
notices.delete_success=系统通知已被删除。
self_check.no_problem_found=尚未发现问题。
+self_check.startup_warnings=启动警告:
self_check.database_collation_mismatch=期望数据库使用的校验方式:%s
self_check.database_collation_case_insensitive=数据库正在使用一个校验 %s, 这是一个不敏感的校验. 虽然Gitea可以与它合作,但可能有一些罕见的情况不如预期的那样起作用。
self_check.database_inconsistent_collation_columns=数据库正在使用%s的排序规则,但是这些列使用了不匹配的排序规则。这可能会造成一些意外问题。
@@ -3534,6 +3632,7 @@ runs.scheduled=已计划的
runs.pushed_by=推送者
runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s
runs.no_matching_online_runner_helper=没有匹配标签的在线 runner: %s
+runs.no_job_without_needs=工作流必须包含至少一个没有依赖关系的作业。
runs.actor=操作者
runs.status=状态
runs.actors_no_select=所有操作者
diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini
index d4b65239a6..2dbdeb2bae 100644
--- a/options/locale/locale_zh-HK.ini
+++ b/options/locale/locale_zh-HK.ini
@@ -809,7 +809,6 @@ auths.tip.oauth2_provider=OAuth2 提供者
auths.tip.dropbox=建立新 App 在 https://www.dropbox.com/developers/apps
auths.tip.facebook=`在 https://developers.facebook.com/apps 註冊一個新的應用,並且新增一個產品 "Facebook Login"`
auths.tip.github=在 https://github.com/settings/applications/new 註冊一個新的 OAuth 應用程式
-auths.tip.openid_connect=使用 OpenID 連接探索 URL (/.well-known/openid-configuration) 來指定節點
auths.delete=刪除認證來源
auths.delete_auth_title=刪除認證來源
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index 0447a7d8b7..3e7bd4ae20 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -1103,7 +1103,6 @@ editor.or=或
editor.cancel_lower=取消
editor.commit_signed_changes=提交簽署過的變更
editor.commit_changes=提交變更
-editor.add_tmpl=新增「」
editor.add=新增 %s
editor.update=更新 %s
editor.delete=刪除 %s
@@ -2704,13 +2703,11 @@ auths.sspi_default_language_helper=SSPI 認證方法自動建立之使用者的
auths.tips=幫助提示
auths.tips.oauth2.general=OAuth2 認證
auths.tip.oauth2_provider=OAuth2 提供者
-auths.tip.bitbucket=註冊新的 OAuth 客戶端並加入權限「Account - Read」。網址:https://bitbucket.org/account/user//oauth-consumers/new
auths.tip.nextcloud=在您的執行個體中,於選單「設定 -> 安全性 -> OAuth 2.0 客戶端」註冊新的 OAuth 客戶端
auths.tip.dropbox=建立新的 App。網址:https://www.dropbox.com/developers/apps
auths.tip.facebook=註冊新的應用程式並新增產品「Facebook 登入」。網址:https://developers.facebook.com/apps
auths.tip.github=註冊新的 OAuth 應用程式。網址:https://github.com/settings/applications/new
auths.tip.google_plus=從 Google API 控制台取得 OAuth2 用戶端憑證。網址:https://console.developers.google.com/
-auths.tip.openid_connect=使用 OpenID 連接探索 URL (/.well-known/openid-configuration) 來指定節點
auths.tip.twitter=建立應用程式並確保有啟用「Allow this application to be used to Sign in with Twitter」。網址:https://dev.twitter.com/apps
auths.tip.discord=註冊新的應用程式。網址:https://discordapp.com/developers/applications/me
auths.tip.yandex=建立新的應用程式,從「Yandex.Passport API」區塊選擇「Access to email address」、「Access to user avatar」和「Access to username, first name and surname, gender」。網址:https://oauth.yandex.com/client/new
diff --git a/package-lock.json b/package-lock.json
index a5f7a09ed0..61d86f6b7c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,7 +21,7 @@
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.0.1",
"clippie": "4.0.7",
- "css-loader": "6.10.0",
+ "css-loader": "7.1.1",
"dayjs": "1.11.10",
"dropzone": "6.0.0-beta.2",
"easymde": "2.18.0",
@@ -35,18 +35,18 @@
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "10.9.0",
"mini-css-extract-plugin": "2.8.1",
- "minimatch": "9.0.3",
+ "minimatch": "9.0.4",
"monaco-editor": "0.47.0",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.3.0",
"postcss": "8.4.38",
"postcss-loader": "8.1.1",
- "postcss-nesting": "12.1.0",
+ "postcss-nesting": "12.1.1",
"pretty-ms": "9.0.0",
"sortablejs": "1.15.2",
- "swagger-ui-dist": "5.12.0",
- "tailwindcss": "3.4.1",
- "temporal-polyfill": "0.2.3",
+ "swagger-ui-dist": "5.15.1",
+ "tailwindcss": "3.4.3",
+ "temporal-polyfill": "0.2.4",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@@ -56,7 +56,7 @@
"vanilla-colorful": "0.7.2",
"vue": "3.4.21",
"vue-bar-graph": "2.0.0",
- "vue-chartjs": "5.3.0",
+ "vue-chartjs": "5.3.1",
"vue-loader": "17.4.2",
"vue3-calendar-heatmap": "2.0.5",
"webpack": "5.91.0",
@@ -64,11 +64,11 @@
"wrap-ansi": "9.0.0"
},
"devDependencies": {
- "@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.42.1",
- "@stoplight/spectral-cli": "6.11.0",
+ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
+ "@playwright/test": "1.43.1",
+ "@stoplight/spectral-cli": "6.11.1",
"@stylistic/eslint-plugin-js": "1.7.0",
- "@stylistic/stylelint-plugin": "2.1.0",
+ "@stylistic/stylelint-plugin": "2.1.1",
"@vitejs/plugin-vue": "5.0.4",
"eslint": "8.57.0",
"eslint-plugin-array-func": "4.0.0",
@@ -77,25 +77,25 @@
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.4.0",
- "eslint-plugin-sonarjs": "0.24.0",
- "eslint-plugin-unicorn": "51.0.1",
- "eslint-plugin-vitest": "0.4.0",
+ "eslint-plugin-regexp": "2.5.0",
+ "eslint-plugin-sonarjs": "0.25.1",
+ "eslint-plugin-unicorn": "52.0.0",
+ "eslint-plugin-vitest": "0.4.1",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.24.0",
+ "eslint-plugin-vue": "9.24.1",
"eslint-plugin-vue-scoped-css": "2.8.0",
- "eslint-plugin-wc": "2.0.4",
- "happy-dom": "14.3.7",
+ "eslint-plugin-wc": "2.1.0",
+ "happy-dom": "14.7.1",
"markdownlint-cli": "0.39.0",
"postcss-html": "1.6.0",
- "stylelint": "16.3.0",
+ "stylelint": "16.3.1",
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0",
- "updates": "16.0.0",
+ "updates": "16.0.1",
"vite-string-plugin": "1.1.5",
- "vitest": "1.4.0"
+ "vitest": "1.5.0"
},
"engines": {
"node": ">= 18.0.0"
@@ -234,9 +234,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz",
- "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
+ "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -245,9 +245,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz",
- "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==",
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
+ "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -481,9 +481,9 @@
}
},
"node_modules/@csstools/selector-specificity": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.2.tgz",
- "integrity": "sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.3.tgz",
+ "integrity": "sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q==",
"funding": [
{
"type": "github",
@@ -865,9 +865,9 @@
}
},
"node_modules/@eslint-community/eslint-plugin-eslint-comments": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.1.0.tgz",
- "integrity": "sha512-B2mwipifrBS5E00vN8vME68laPMZ0h3sNGOEDj5g9iUN9k5EU99Omq0Nc325eKNoFFDnDtiHp3DqIjO+1bstag==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-4.3.0.tgz",
+ "integrity": "sha512-6e93KtgsndNkvwCCa07LOQJSwzzLLxwrFll3+huyFoiiQXWG0KBcmo0Q1bVgYQQDLfWOOZl2VPBsXqZL6vHIBQ==",
"dev": true,
"dependencies": {
"escape-string-regexp": "^4.0.0",
@@ -877,7 +877,7 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
"peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/@eslint-community/eslint-utils": {
@@ -1059,9 +1059,9 @@
}
},
"node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
- "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
"node_modules/@isaacs/cliui": {
@@ -1344,12 +1344,12 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
- "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.43.1.tgz",
+ "integrity": "sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA==",
"dev": true,
"dependencies": {
- "playwright": "1.42.1"
+ "playwright": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -1420,9 +1420,9 @@
"dev": true
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
- "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.2.tgz",
+ "integrity": "sha512-ahxSgCkAEk+P/AVO0vYr7DxOD3CwAQrT0Go9BJyGQ9Ef0QxVOfjDZMiF4Y2s3mLyPrjonchIMH/tbWHucJMykQ==",
"cpu": [
"arm"
],
@@ -1433,9 +1433,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
- "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.2.tgz",
+ "integrity": "sha512-lAarIdxZWbFSHFSDao9+I/F5jDaKyCqAPMq5HqnfpBw8dKDiCaaqM0lq5h1pQTLeIqueeay4PieGR5jGZMWprw==",
"cpu": [
"arm64"
],
@@ -1446,9 +1446,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
- "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.2.tgz",
+ "integrity": "sha512-SWsr8zEUk82KSqquIMgZEg2GE5mCSfr9sE/thDROkX6pb3QQWPp8Vw8zOq2GyxZ2t0XoSIUlvHDkrf5Gmf7x3Q==",
"cpu": [
"arm64"
],
@@ -1459,9 +1459,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
- "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.2.tgz",
+ "integrity": "sha512-o/HAIrQq0jIxJAhgtIvV5FWviYK4WB0WwV91SLUnsliw1lSAoLsmgEEgRWzDguAFeUEUUoIWXiJrPqU7vGiVkA==",
"cpu": [
"x64"
],
@@ -1472,9 +1472,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
- "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.2.tgz",
+ "integrity": "sha512-nwlJ65UY9eGq91cBi6VyDfArUJSKOYt5dJQBq8xyLhvS23qO+4Nr/RreibFHjP6t+5ap2ohZrUJcHv5zk5ju/g==",
"cpu": [
"arm"
],
@@ -1485,9 +1485,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
- "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.2.tgz",
+ "integrity": "sha512-Pg5TxxO2IVlMj79+c/9G0LREC9SY3HM+pfAwX7zj5/cAuwrbfj2Wv9JbMHIdPCfQpYsI4g9mE+2Bw/3aeSs2rQ==",
"cpu": [
"arm64"
],
@@ -1498,9 +1498,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
- "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.2.tgz",
+ "integrity": "sha512-cAOTjGNm84gc6tS02D1EXtG7tDRsVSDTBVXOLbj31DkwfZwgTPYZ6aafSU7rD/4R2a34JOwlF9fQayuTSkoclA==",
"cpu": [
"arm64"
],
@@ -1510,10 +1510,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.2.tgz",
+ "integrity": "sha512-4RyT6v1kXb7C0fn6zV33rvaX05P0zHoNzaXI/5oFHklfKm602j+N4mn2YvoezQViRLPnxP8M1NaY4s/5kXO5cw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
- "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.2.tgz",
+ "integrity": "sha512-KNUH6jC/vRGAKSorySTyc/yRYlCwN/5pnMjXylfBniwtJx5O7X17KG/0efj8XM3TZU7raYRXJFFReOzNmL1n1w==",
"cpu": [
"riscv64"
],
@@ -1523,10 +1536,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.2.tgz",
+ "integrity": "sha512-xPV4y73IBEXToNPa3h5lbgXOi/v0NcvKxU0xejiFw6DtIYQqOTMhZ2DN18/HrrP0PmiL3rGtRG9gz1QE8vFKXQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
- "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.2.tgz",
+ "integrity": "sha512-QBhtr07iFGmF9egrPOWyO5wciwgtzKkYPNLVCFZTmr4TWmY0oY2Dm/bmhHjKRwZoGiaKdNcKhFtUMBKvlchH+Q==",
"cpu": [
"x64"
],
@@ -1537,9 +1563,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
- "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.2.tgz",
+ "integrity": "sha512-8zfsQRQGH23O6qazZSFY5jP5gt4cFvRuKTpuBsC1ZnSWxV8ZKQpPqOZIUtdfMOugCcBvFGRa1pDC/tkf19EgBw==",
"cpu": [
"x64"
],
@@ -1550,9 +1576,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
- "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.2.tgz",
+ "integrity": "sha512-H4s8UjgkPnlChl6JF5empNvFHp77Jx+Wfy2EtmYPe9G22XV+PMuCinZVHurNe8ggtwoaohxARJZbaH/3xjB/FA==",
"cpu": [
"arm64"
],
@@ -1563,9 +1589,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
- "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.2.tgz",
+ "integrity": "sha512-djqpAjm/i8erWYF0K6UY4kRO3X5+T4TypIqw60Q8MTqSBaQNpNXDhxdjpZ3ikgb+wn99svA7jxcXpiyg9MUsdw==",
"cpu": [
"ia32"
],
@@ -1576,9 +1602,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
- "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.2.tgz",
+ "integrity": "sha512-teAqzLT0yTYZa8ZP7zhFKEx4cotS8Tkk5XiqNMJhD4CpaWB1BHARE4Qy+RzwnXvSAYv+Q3jAqCVBS+PS+Yee8Q==",
"cpu": [
"x64"
],
@@ -1686,9 +1712,9 @@
}
},
"node_modules/@stoplight/spectral-cli": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.11.0.tgz",
- "integrity": "sha512-IURDN47BPIf3q4ZyUPujGpBzuHWFE5yT34w9rTJ1GKA4SgdscEdQO9KoTjOPT4G4cvDlEV3bNxwQ3uRm7+wRlA==",
+ "version": "6.11.1",
+ "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.11.1.tgz",
+ "integrity": "sha512-1zqsQ0TOuVSnxxZ9mHBfC0IygV6ex7nAY6Mp59mLmw5fW103U9yPVK5ZcX9ZngCmr3PdteAnMDUIIaoDGso6nA==",
"dev": true,
"dependencies": {
"@stoplight/json": "~3.21.0",
@@ -1709,7 +1735,7 @@
"pony-cause": "^1.0.0",
"stacktracey": "^2.1.7",
"tslib": "^2.3.0",
- "yargs": "17.3.1"
+ "yargs": "~17.7.2"
},
"bin": {
"spectral": "dist/index.js"
@@ -1873,20 +1899,33 @@
}
},
"node_modules/@stoplight/spectral-parsers": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.3.tgz",
- "integrity": "sha512-J0KW5Rh5cHWnJQ3yN+cr/ijNFVirPSR0pkQbdrNX30VboEl083UEDrQ3yov9kjLVIWEk9t9kKE7Eo3QT/k4JLA==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@stoplight/spectral-parsers/-/spectral-parsers-1.0.4.tgz",
+ "integrity": "sha512-nCTVvtX6q71M8o5Uvv9kxU31Gk1TRmgD6/k8HBhdCmKG6FWcwgjiZouA/R3xHLn/VwTI/9k8SdG5Mkdy0RBqbQ==",
"dev": true,
"dependencies": {
"@stoplight/json": "~3.21.0",
- "@stoplight/types": "^13.6.0",
- "@stoplight/yaml": "~4.2.3",
+ "@stoplight/types": "^14.1.1",
+ "@stoplight/yaml": "~4.3.0",
"tslib": "^2.3.1"
},
"engines": {
"node": "^12.20 || >=14.13"
}
},
+ "node_modules/@stoplight/spectral-parsers/node_modules/@stoplight/types": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz",
+ "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.4",
+ "utility-types": "^3.10.0"
+ },
+ "engines": {
+ "node": "^12.20 || >=14.13"
+ }
+ },
"node_modules/@stoplight/spectral-ref-resolver": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@stoplight/spectral-ref-resolver/-/spectral-ref-resolver-1.0.4.tgz",
@@ -1955,6 +1994,27 @@
"node": ">=12"
}
},
+ "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/yaml": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz",
+ "integrity": "sha512-Mx01wjRAR9C7yLMUyYFTfbUf5DimEpHMkRDQ1PKLe9dfNILbgdxyrncsOXM3vCpsQ1Hfj4bPiGl+u4u6e9Akqw==",
+ "dev": true,
+ "dependencies": {
+ "@stoplight/ordered-object-literal": "^1.0.1",
+ "@stoplight/types": "^13.0.0",
+ "@stoplight/yaml-ast-parser": "0.0.48",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.8"
+ }
+ },
+ "node_modules/@stoplight/spectral-ruleset-migrator/node_modules/@stoplight/yaml-ast-parser": {
+ "version": "0.0.48",
+ "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz",
+ "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==",
+ "dev": true
+ },
"node_modules/@stoplight/spectral-rulesets": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.18.1.tgz",
@@ -2025,14 +2085,14 @@
}
},
"node_modules/@stoplight/yaml": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.2.3.tgz",
- "integrity": "sha512-Mx01wjRAR9C7yLMUyYFTfbUf5DimEpHMkRDQ1PKLe9dfNILbgdxyrncsOXM3vCpsQ1Hfj4bPiGl+u4u6e9Akqw==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@stoplight/yaml/-/yaml-4.3.0.tgz",
+ "integrity": "sha512-JZlVFE6/dYpP9tQmV0/ADfn32L9uFarHWxfcRhReKUnljz1ZiUM5zpX+PH8h5CJs6lao3TuFqnPm9IJJCEkE2w==",
"dev": true,
"dependencies": {
- "@stoplight/ordered-object-literal": "^1.0.1",
- "@stoplight/types": "^13.0.0",
- "@stoplight/yaml-ast-parser": "0.0.48",
+ "@stoplight/ordered-object-literal": "^1.0.5",
+ "@stoplight/types": "^14.1.1",
+ "@stoplight/yaml-ast-parser": "0.0.50",
"tslib": "^2.2.0"
},
"engines": {
@@ -2040,11 +2100,24 @@
}
},
"node_modules/@stoplight/yaml-ast-parser": {
- "version": "0.0.48",
- "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.48.tgz",
- "integrity": "sha512-sV+51I7WYnLJnKPn2EMWgS4EUfoP4iWEbrWwbXsj0MZCB/xOK8j6+C9fntIdOM50kpx45ZLC3s6kwKivWuqvyg==",
+ "version": "0.0.50",
+ "resolved": "https://registry.npmjs.org/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.50.tgz",
+ "integrity": "sha512-Pb6M8TDO9DtSVla9yXSTAxmo9GVEouq5P40DWXdOie69bXogZTkgvopCq+yEvTMA0F6PEvdJmbtTV3ccIp11VQ==",
"dev": true
},
+ "node_modules/@stoplight/yaml/node_modules/@stoplight/types": {
+ "version": "14.1.1",
+ "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-14.1.1.tgz",
+ "integrity": "sha512-/kjtr+0t0tjKr+heVfviO9FrU/uGLc+QNX3fHJc19xsCNYqU7lVhaXxDmEID9BZTjG+/r9pK9xP/xU02XGg65g==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.4",
+ "utility-types": "^3.10.0"
+ },
+ "engines": {
+ "node": "^12.20 || >=14.13"
+ }
+ },
"node_modules/@stylistic/eslint-plugin-js": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.7.0.tgz",
@@ -2065,9 +2138,9 @@
}
},
"node_modules/@stylistic/stylelint-plugin": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.0.tgz",
- "integrity": "sha512-mUZEW9uImHSbXeyzbFmHb8WPBv56UTaEnWL/3dGdAiJ54C+8GTfDwDVdI6gbqT9wV7zynkPu7tCXc5746H9mZQ==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-2.1.1.tgz",
+ "integrity": "sha512-xqHTmQZN7EbnFDW7jw0rAsdFNO4IRqvXhrh3qhUlIwF/x09Zm7kgs/ADktHxsTJYcw346PpGihsB0t4pZhpeHw==",
"dev": true,
"dependencies": {
"@csstools/css-parser-algorithms": "^2.5.0",
@@ -2144,9 +2217,9 @@
}
},
"node_modules/@types/eslint": {
- "version": "8.56.6",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.6.tgz",
- "integrity": "sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==",
+ "version": "8.56.9",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.9.tgz",
+ "integrity": "sha512-W4W3KcqzjJ0sHg2vAq9vfml6OhsJ53TcUjUqfzzZf/EChUtwspszj/S0pzMxnfRcO55/iGq47dscXw71Fxc4Zg==",
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -2196,9 +2269,9 @@
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@types/node": {
- "version": "20.11.30",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz",
- "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==",
+ "version": "20.12.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
+ "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
"dependencies": {
"undici-types": "~5.26.4"
}
@@ -2241,22 +2314,22 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz",
- "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.6.0.tgz",
+ "integrity": "sha512-gKmTNwZnblUdnTIJu3e9kmeRRzV2j1a/LUO27KNNAnIC5zjy1aSvXSRp4rVNlmAoHlQ7HzX42NbKpcSr4jF80A==",
"dev": true,
"dependencies": {
- "@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "7.4.0",
- "@typescript-eslint/type-utils": "7.4.0",
- "@typescript-eslint/utils": "7.4.0",
- "@typescript-eslint/visitor-keys": "7.4.0",
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/type-utils": "7.6.0",
+ "@typescript-eslint/utils": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
- "ignore": "^5.2.4",
+ "ignore": "^5.3.1",
"natural-compare": "^1.4.0",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2276,15 +2349,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz",
- "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.6.0.tgz",
+ "integrity": "sha512-usPMPHcwX3ZoPWnBnhhorc14NJw9J4HpSXQX4urF2TPKG0au0XhJoZyX62fmvdHONUkmyUe74Hzm1//XA+BoYg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "7.4.0",
- "@typescript-eslint/types": "7.4.0",
- "@typescript-eslint/typescript-estree": "7.4.0",
- "@typescript-eslint/visitor-keys": "7.4.0",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2304,13 +2377,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz",
- "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.6.0.tgz",
+ "integrity": "sha512-ngttyfExA5PsHSx0rdFgnADMYQi+Zkeiv4/ZxGYUWd0nLs63Ha0ksmp8VMxAIC0wtCFxMos7Lt3PszJssG/E6w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.4.0",
- "@typescript-eslint/visitor-keys": "7.4.0"
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2321,15 +2394,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz",
- "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.6.0.tgz",
+ "integrity": "sha512-NxAfqAPNLG6LTmy7uZgpK8KcuiS2NZD/HlThPXQRGwz6u7MDBWRVliEEl1Gj6U7++kVJTpehkhZzCJLMK66Scw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "7.4.0",
- "@typescript-eslint/utils": "7.4.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "@typescript-eslint/utils": "7.6.0",
"debug": "^4.3.4",
- "ts-api-utils": "^1.0.1"
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2348,9 +2421,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz",
- "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.6.0.tgz",
+ "integrity": "sha512-h02rYQn8J+MureCvHVVzhl69/GAfQGPQZmOMjG1KfCl7o3HtMSlPaPUAPu6lLctXI5ySRGIYk94clD/AUMCUgQ==",
"dev": true,
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2361,19 +2434,19 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz",
- "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.6.0.tgz",
+ "integrity": "sha512-+7Y/GP9VuYibecrCQWSKgl3GvUM5cILRttpWtnAu8GNL9j11e4tbuGZmZjJ8ejnKYyBRb2ddGQ3rEFCq3QjMJw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.4.0",
- "@typescript-eslint/visitor-keys": "7.4.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/visitor-keys": "7.6.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2389,18 +2462,18 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz",
- "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.6.0.tgz",
+ "integrity": "sha512-x54gaSsRRI+Nwz59TXpCsr6harB98qjXYzsRxGqvA5Ue3kQH+FxS7FYU81g/omn22ML2pZJkisy6Q+ElK8pBCA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@types/json-schema": "^7.0.12",
- "@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "7.4.0",
- "@typescript-eslint/types": "7.4.0",
- "@typescript-eslint/typescript-estree": "7.4.0",
- "semver": "^7.5.4"
+ "@types/json-schema": "^7.0.15",
+ "@types/semver": "^7.5.8",
+ "@typescript-eslint/scope-manager": "7.6.0",
+ "@typescript-eslint/types": "7.6.0",
+ "@typescript-eslint/typescript-estree": "7.6.0",
+ "semver": "^7.6.0"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2414,13 +2487,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz",
- "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==",
+ "version": "7.6.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.6.0.tgz",
+ "integrity": "sha512-4eLB7t+LlNUmXzfOu1VAIAdkjbu5xNSerURS9X/S5TUKWFRpXRQZbmtPqgKmYx8bj3J0irtQXSiWAOY82v+cgw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "7.4.0",
- "eslint-visitor-keys": "^3.4.1"
+ "@typescript-eslint/types": "7.6.0",
+ "eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@@ -2450,13 +2523,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.4.0.tgz",
- "integrity": "sha512-Jths0sWCJZ8BxjKe+p+eKsoqev1/T8lYcrjavEaz8auEJ4jAVY0GwW3JKmdVU4mmNPLPHixh4GNXP7GFtAiDHA==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.5.0.tgz",
+ "integrity": "sha512-0pzuCI6KYi2SIC3LQezmxujU9RK/vwC1U9R0rLuGlNGcOuDWxqWKu6nUdFsX9tH1WU0SXtAxToOsEjeUn1s3hA==",
"dev": true,
"dependencies": {
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"chai": "^4.3.10"
},
"funding": {
@@ -2464,12 +2537,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.4.0.tgz",
- "integrity": "sha512-EDYVSmesqlQ4RD2VvWo3hQgTJ7ZrFQ2VSJdfiJiArkCerDAGeyF1i6dHkmySqk573jLp6d/cfqCN+7wUB5tLgg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.5.0.tgz",
+ "integrity": "sha512-7HWwdxXP5yDoe7DTpbif9l6ZmDwCzcSIK38kTSIt6CFEpMjX4EpCgT6wUmS0xTXqMI6E/ONmfgRKmaujpabjZQ==",
"dev": true,
"dependencies": {
- "@vitest/utils": "1.4.0",
+ "@vitest/utils": "1.5.0",
"p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
@@ -2505,9 +2578,9 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.4.0.tgz",
- "integrity": "sha512-saAFnt5pPIA5qDGxOHxJ/XxhMFKkUSBJmVt5VgDsAqPTX6JP326r5C/c9UuCMPoXNzuudTPsYDZCoJ5ilpqG2A==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.5.0.tgz",
+ "integrity": "sha512-qpv3fSEuNrhAO3FpH6YYRdaECnnRjg9VxbhdtPwPRnzSfHVXnNzzrpX4cJxqiwgRMo7uRMWDFBlsBq4Cr+rO3A==",
"dev": true,
"dependencies": {
"magic-string": "^0.30.5",
@@ -2519,9 +2592,9 @@
}
},
"node_modules/@vitest/snapshot/node_modules/magic-string": {
- "version": "0.30.8",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
- "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+ "version": "0.30.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
+ "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
@@ -2531,9 +2604,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.4.0.tgz",
- "integrity": "sha512-Ywau/Qs1DzM/8Uc+yA77CwSegizMlcgTJuYGAi0jujOteJOUf1ujunHThYo243KG9nAyWT3L9ifPYZ5+As/+6Q==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.5.0.tgz",
+ "integrity": "sha512-vu6vi6ew5N5MMHJjD5PoakMRKYdmIrNJmyfkhRpQt5d9Ewhw9nZ5Aqynbi3N61bvk9UvZ5UysMT6ayIrZ8GA9w==",
"dev": true,
"dependencies": {
"tinyspy": "^2.2.0"
@@ -2543,9 +2616,9 @@
}
},
"node_modules/@vitest/utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.4.0.tgz",
- "integrity": "sha512-mx3Yd1/6e2Vt/PUC98DcqTirtfxUyAZ32uK82r8rZzbtBeBo+nqgnjx/LvqQdWsrvNtm14VmurNgcf4nqY5gJg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.5.0.tgz",
+ "integrity": "sha512-BDU0GNL8MWkRkSRdNFvCUCAVOeHaUlVJ9Tx0TYBZyXaaOTmGtUFObzchCivIBrIwKzvZA7A9sCejVhXM2aY98A==",
"dev": true,
"dependencies": {
"diff-sequences": "^29.6.3",
@@ -2610,9 +2683,9 @@
}
},
"node_modules/@vue/compiler-sfc/node_modules/magic-string": {
- "version": "0.30.8",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
- "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+ "version": "0.30.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
+ "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
@@ -3478,9 +3551,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001600",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz",
- "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==",
+ "version": "1.0.30001609",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz",
+ "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==",
"funding": [
{
"type": "opencollective",
@@ -3872,21 +3945,21 @@
}
},
"node_modules/css-loader": {
- "version": "6.10.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz",
- "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.1.tgz",
+ "integrity": "sha512-OxIR5P2mjO1PSXk44bWuQ8XtMK4dpEqpIyERCx3ewOo3I8EmbcxMPUc5ScLtQfgXtOojoMv57So4V/C02HQLsw==",
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.33",
- "postcss-modules-extract-imports": "^3.0.0",
- "postcss-modules-local-by-default": "^4.0.4",
- "postcss-modules-scope": "^3.1.1",
+ "postcss-modules-extract-imports": "^3.1.0",
+ "postcss-modules-local-by-default": "^4.0.5",
+ "postcss-modules-scope": "^3.2.0",
"postcss-modules-values": "^4.0.0",
"postcss-value-parser": "^4.2.0",
"semver": "^7.5.4"
},
"engines": {
- "node": ">= 12.13.0"
+ "node": ">= 18.12.0"
},
"funding": {
"type": "opencollective",
@@ -3894,7 +3967,7 @@
},
"peerDependencies": {
"@rspack/core": "0.x || 1.x",
- "webpack": "^5.0.0"
+ "webpack": "^5.27.0"
},
"peerDependenciesMeta": {
"@rspack/core": {
@@ -4724,9 +4797,9 @@
}
},
"node_modules/dompurify": {
- "version": "3.0.11",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.11.tgz",
- "integrity": "sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg=="
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz",
+ "integrity": "sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA=="
},
"node_modules/domutils": {
"version": "3.1.0",
@@ -4769,9 +4842,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.4.716",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.716.tgz",
- "integrity": "sha512-t/MXMzFKQC3UfMDpw7V5wdB/UAB8dWx4hEsy+fpPYJWW3gqh3u5T1uXp6vR+H6dGCPBxkRo+YBcapBLvbGQHRw=="
+ "version": "1.4.736",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz",
+ "integrity": "sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q=="
},
"node_modules/elkjs": {
"version": "0.9.2",
@@ -4823,9 +4896,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.11.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz",
- "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==",
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz",
+ "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==",
"bin": {
"envinfo": "dist/cli.js"
},
@@ -4842,9 +4915,9 @@
}
},
"node_modules/es-abstract": {
- "version": "1.23.2",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz",
- "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==",
+ "version": "1.23.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+ "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
"dev": true,
"dependencies": {
"array-buffer-byte-length": "^1.0.1",
@@ -4886,11 +4959,11 @@
"safe-regex-test": "^1.0.3",
"string.prototype.trim": "^1.2.9",
"string.prototype.trimend": "^1.0.8",
- "string.prototype.trimstart": "^1.0.7",
+ "string.prototype.trimstart": "^1.0.8",
"typed-array-buffer": "^1.0.2",
"typed-array-byte-length": "^1.0.1",
"typed-array-byte-offset": "^1.0.2",
- "typed-array-length": "^1.0.5",
+ "typed-array-length": "^1.0.6",
"unbox-primitive": "^1.0.2",
"which-typed-array": "^1.1.15"
},
@@ -5601,9 +5674,9 @@
}
},
"node_modules/eslint-plugin-regexp": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.4.0.tgz",
- "integrity": "sha512-OL2S6VPjQhs9s/NclQ0qattVq1J0GU8ox70/HIVy5Dxw+qbbdd7KQkyucsez2clEQjvdtDe12DTnPphFFUyXFg==",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.5.0.tgz",
+ "integrity": "sha512-I7vKcP0o75WS5SHiVNXN+Eshq49sbrweMQIuqSL3AId9AwDe9Dhbfug65vw64LxmOd4v+yf5l5Xt41y9puiq0g==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
@@ -5622,9 +5695,9 @@
}
},
"node_modules/eslint-plugin-sonarjs": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.24.0.tgz",
- "integrity": "sha512-87zp50mbbNrSTuoEOebdRQBPa0mdejA5UEjyuScyIw8hEpEjfWP89Qhkq5xVZfVyVSRQKZc9alVm7yRKQvvUmg==",
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.25.1.tgz",
+ "integrity": "sha512-5IOKvj/GMBNqjxBdItfotfRHo7w48496GOu1hxdeXuD0mB1JBlDCViiLHETDTfA8pDAVSBimBEQoetRXYceQEw==",
"dev": true,
"engines": {
"node": ">=16"
@@ -5634,9 +5707,9 @@
}
},
"node_modules/eslint-plugin-unicorn": {
- "version": "51.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-51.0.1.tgz",
- "integrity": "sha512-MuR/+9VuB0fydoI0nIn2RDA5WISRn4AsJyNSaNKLVwie9/ONvQhxOBbkfSICBPnzKrB77Fh6CZZXjgTt/4Latw==",
+ "version": "52.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-52.0.0.tgz",
+ "integrity": "sha512-1Yzm7/m+0R4djH0tjDjfVei/ju2w3AzUGjG6q8JnuNIL5xIwsflyCooW5sfBvQp2pMYQFSWWCFONsjCax1EHng==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.20",
@@ -5667,12 +5740,12 @@
}
},
"node_modules/eslint-plugin-vitest": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.4.0.tgz",
- "integrity": "sha512-3oWgZIwdWVBQ5plvkmOBjreIGLQRdYb7x54OP8uIRHeZyRVJIdOn9o/qWVb9292fDMC8jn7H7d9TSFBZqhrykQ==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.4.1.tgz",
+ "integrity": "sha512-+PnZ2u/BS+f5FiuHXz4zKsHPcMKHie+K+1Uvu/x91ovkCMEOJqEI8E9Tw1Wzx2QRz4MHOBHYf1ypO8N1K0aNAA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/utils": "^7.2.0"
+ "@typescript-eslint/utils": "^7.4.0"
},
"engines": {
"node": "^18.0.0 || >= 20.0.0"
@@ -5697,9 +5770,9 @@
"dev": true
},
"node_modules/eslint-plugin-vue": {
- "version": "9.24.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.0.tgz",
- "integrity": "sha512-9SkJMvF8NGMT9aQCwFc5rj8Wo1XWSMSHk36i7ZwdI614BU7sIOR28ZjuFPKp8YGymZN12BSEbiSwa7qikp+PBw==",
+ "version": "9.24.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.24.1.tgz",
+ "integrity": "sha512-wk3SuwmS1pZdcuJlokGYEi/buDOwD6KltvhIZyOnpJ/378dcQ4zchu9PAMbbLAaydCz1iYc5AozszcOOgZIIOg==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
@@ -5715,7 +5788,7 @@
"node": "^14.17.0 || >=16.0.0"
},
"peerDependencies": {
- "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0"
+ "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/eslint-plugin-vue-scoped-css": {
@@ -5745,9 +5818,9 @@
}
},
"node_modules/eslint-plugin-wc": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.0.4.tgz",
- "integrity": "sha512-ORu7MBv0hXIvq894EJad70m+AvHGbmrDdKT6lcgtCVVhEbuIAyxg0ilfqqqHOmsh8PfcUBeEae3y7CElKvm1KQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.1.0.tgz",
+ "integrity": "sha512-s/BGOtmpgQ2yifR6EC1OM9t0DwYLgg4ZAL07Kw4eXvBb5TYaPafI+65tswvnZvhH8FqcjERLbBZPPvYsvinkfg==",
"dev": true,
"dependencies": {
"is-valid-element-name": "^1.0.0",
@@ -6506,9 +6579,9 @@
}
},
"node_modules/happy-dom": {
- "version": "14.3.7",
- "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.3.7.tgz",
- "integrity": "sha512-lUfDRGzjrVJF2pnvh13OL+qEJ9eDpcedVLm77a3aMg8gPGKXfG+xFMNk3cOWetjucU8FveJ4qcSC/EX55nJ4fQ==",
+ "version": "14.7.1",
+ "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-14.7.1.tgz",
+ "integrity": "sha512-v60Q0evZ4clvMcrAh5/F8EdxDdfHdFrtffz/CNe10jKD+nFweZVxM91tW+UyY2L4AtpgIaXdZ7TQmiO1pfcwbg==",
"dev": true,
"dependencies": {
"entities": "^4.5.0",
@@ -7956,16 +8029,16 @@
}
},
"node_modules/markdownlint-cli/node_modules/glob": {
- "version": "10.3.10",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
- "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+ "version": "10.3.12",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
+ "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
- "jackspeak": "^2.3.5",
+ "jackspeak": "^2.3.6",
"minimatch": "^9.0.1",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
- "path-scurry": "^1.10.1"
+ "minipass": "^7.0.4",
+ "path-scurry": "^1.10.2"
},
"bin": {
"glob": "dist/esm/bin.mjs"
@@ -8608,9 +8681,9 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+ "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -9133,11 +9206,11 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-scurry": {
- "version": "1.10.1",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz",
- "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==",
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
+ "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
"dependencies": {
- "lru-cache": "^9.1.1 || ^10.0.0",
+ "lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
@@ -9293,12 +9366,12 @@
"dev": true
},
"node_modules/playwright": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
- "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz",
+ "integrity": "sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA==",
"dev": true,
"dependencies": {
- "playwright-core": "1.42.1"
+ "playwright-core": "1.43.1"
},
"bin": {
"playwright": "cli.js"
@@ -9311,9 +9384,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
- "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
+ "version": "1.43.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.43.1.tgz",
+ "integrity": "sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -9456,9 +9529,9 @@
}
},
"node_modules/postcss-modules-extract-imports": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
- "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
+ "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
"engines": {
"node": "^10 || ^12 || >= 14"
},
@@ -9467,9 +9540,9 @@
}
},
"node_modules/postcss-modules-local-by-default": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz",
- "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==",
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz",
+ "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==",
"dependencies": {
"icss-utils": "^5.0.0",
"postcss-selector-parser": "^6.0.2",
@@ -9483,9 +9556,9 @@
}
},
"node_modules/postcss-modules-scope": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz",
- "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz",
+ "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==",
"dependencies": {
"postcss-selector-parser": "^6.0.4"
},
@@ -9529,9 +9602,9 @@
}
},
"node_modules/postcss-nesting": {
- "version": "12.1.0",
- "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.0.tgz",
- "integrity": "sha512-QOYnosaZ+mlP6plQrAxFw09UUp2Sgtxj1BVHN+rSVbtV0Yx48zRt9/9F/ZOoxOKBBEsaJk2MYhhVRjeRRw5yuw==",
+ "version": "12.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-12.1.1.tgz",
+ "integrity": "sha512-qc74KvIAQNa5ujZKG1UV286dhaDW6basbUy2i9AzNU/T8C9hpvGu9NZzm1SfePe2yP7sPYgpA8d4sPVopn2Hhw==",
"funding": [
{
"type": "github",
@@ -9544,7 +9617,7 @@
],
"dependencies": {
"@csstools/selector-resolve-nested": "^1.1.0",
- "@csstools/selector-specificity": "^3.0.2",
+ "@csstools/selector-specificity": "^3.0.3",
"postcss-selector-parser": "^6.0.13"
},
"engines": {
@@ -10765,17 +10838,23 @@
}
},
"node_modules/strip-literal": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz",
- "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz",
+ "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==",
"dev": true,
"dependencies": {
- "js-tokens": "^8.0.2"
+ "js-tokens": "^9.0.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/strip-literal/node_modules/js-tokens": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz",
+ "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==",
+ "dev": true
+ },
"node_modules/style-search": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz",
@@ -10783,9 +10862,9 @@
"dev": true
},
"node_modules/stylelint": {
- "version": "16.3.0",
- "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.0.tgz",
- "integrity": "sha512-hqC6xNTbQ5HRGQXfIW4HwXcx09raIFz4W4XFbraeqWqYRVVY/ibYvI0dsu0ORMQY8re2bpDdCAeIa2cm+QJ4Sw==",
+ "version": "16.3.1",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.3.1.tgz",
+ "integrity": "sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw==",
"dev": true,
"dependencies": {
"@csstools/css-parser-algorithms": "^2.6.1",
@@ -11036,15 +11115,15 @@
}
},
"node_modules/sucrase/node_modules/glob": {
- "version": "10.3.10",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
- "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+ "version": "10.3.12",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
+ "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
"dependencies": {
"foreground-child": "^3.1.0",
- "jackspeak": "^2.3.5",
+ "jackspeak": "^2.3.6",
"minimatch": "^9.0.1",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
- "path-scurry": "^1.10.1"
+ "minipass": "^7.0.4",
+ "path-scurry": "^1.10.2"
},
"bin": {
"glob": "dist/esm/bin.mjs"
@@ -11147,9 +11226,9 @@
}
},
"node_modules/swagger-ui-dist": {
- "version": "5.12.0",
- "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.12.0.tgz",
- "integrity": "sha512-Rt1xUpbHulJVGbiQjq9yy9/r/0Pg6TmpcG+fXTaMePDc8z5WUw4LfaWts5qcNv/8ewPvBIbY7DKq7qReIKNCCQ=="
+ "version": "5.15.1",
+ "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.15.1.tgz",
+ "integrity": "sha512-Et/WY0NFdKj8sUBOyEx5P3VybsvGl7bo/y9JvgQ22TkH1a/KscQ0ZiQST2YeJ3cwCrIjYTbHbt165fkku0y1Ig=="
},
"node_modules/sync-fetch": {
"version": "0.4.5",
@@ -11180,9 +11259,9 @@
}
},
"node_modules/table": {
- "version": "6.8.1",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
- "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==",
+ "version": "6.8.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
+ "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
"dev": true,
"dependencies": {
"ajv": "^8.0.1",
@@ -11196,9 +11275,9 @@
}
},
"node_modules/tailwindcss": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
- "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
+ "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
@@ -11208,7 +11287,7 @@
"fast-glob": "^3.3.0",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
- "jiti": "^1.19.1",
+ "jiti": "^1.21.0",
"lilconfig": "^2.1.0",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
@@ -11285,22 +11364,22 @@
}
},
"node_modules/temporal-polyfill": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.3.tgz",
- "integrity": "sha512-7ZJRc7wq/1XjrOQYkkNpgo2qfE9XLrUU8D/DS+LAC/T0bYqZ46rW6dow0sOTXTPZS4bwer8bD/0OyuKQBfA3yw==",
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.2.4.tgz",
+ "integrity": "sha512-WA5p0CjQTkMjF9m8sP4wSYgpqI8m2d4q7wPUyaJOWhy4bI9mReLb2yGvTV4qf/DPMTe6H6M/Dig5KmTMB7ev6Q==",
"dependencies": {
- "temporal-spec": "^0.2.0"
+ "temporal-spec": "^0.2.4"
}
},
"node_modules/temporal-spec": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.0.tgz",
- "integrity": "sha512-r1AT0XdEp8TMQ13FLvOt8mOtAxDQsRt2QU5rSWCA7YfshddU651Y1NHVrceLANvixKdf9fYO8B/S9fXHodB7HQ=="
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.2.4.tgz",
+ "integrity": "sha512-lDMFv4nKQrSjlkHKAlHVqKrBG4DyFfa9F74cmBZ3Iy3ed8yvWnlWSIdi4IKfSqwmazAohBNwiN64qGx4y5Q3IQ=="
},
"node_modules/terser": {
- "version": "5.29.2",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz",
- "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==",
+ "version": "5.30.3",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz",
+ "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -11655,9 +11734,9 @@
}
},
"node_modules/typescript": {
- "version": "5.4.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz",
- "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==",
+ "version": "5.4.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
+ "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
"devOptional": true,
"peer": true,
"bin": {
@@ -11761,9 +11840,9 @@
}
},
"node_modules/updates": {
- "version": "16.0.0",
- "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.0.tgz",
- "integrity": "sha512-Ra3QUu/rfbSCsG83zNNvoRQt0FVT3qULBSALYTlwTDX6oyz7R5GQAYwqJoIG/RDjYAXpwr3usrInoyHHTP6cag==",
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/updates/-/updates-16.0.1.tgz",
+ "integrity": "sha512-If3NQKzGcA3aVgz2VyOXqQ+4uqYjPUPqh2PeZPtD+OKT4CTmxRYqoyFO+T3nwfccy4SiWy5AabWrBXXhVQ89Aw==",
"dev": true,
"bin": {
"updates": "dist/updates.js"
@@ -11854,13 +11933,13 @@
"integrity": "sha512-z2YZusTFC6KnLERx1cgoIRX2CjPRP0W75N+3CC6gbvdX5Ch47rZkEMGO2Xnf+IEmi3RiFLxS18gayMA27iU7Kg=="
},
"node_modules/vite": {
- "version": "5.2.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.6.tgz",
- "integrity": "sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==",
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
+ "integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
"dev": true,
"dependencies": {
"esbuild": "^0.20.1",
- "postcss": "^8.4.36",
+ "postcss": "^8.4.38",
"rollup": "^4.13.0"
},
"bin": {
@@ -11909,9 +11988,9 @@
}
},
"node_modules/vite-node": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.4.0.tgz",
- "integrity": "sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.5.0.tgz",
+ "integrity": "sha512-tV8h6gMj6vPzVCa7l+VGq9lwoJjW8Y79vst8QZZGiuRAfijU+EEWuc0kFpmndQrWhMMhet1jdSF+40KSZUqIIw==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -11957,9 +12036,9 @@
}
},
"node_modules/vite/node_modules/rollup": {
- "version": "4.13.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
- "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
+ "version": "4.14.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.2.tgz",
+ "integrity": "sha512-WkeoTWvuBoFjFAhsEOHKRoZ3r9GfTyhh7Vff1zwebEFLEFjT1lG3784xEgKiTa7E+e70vsC81roVL2MP4tgEEQ==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
@@ -11972,33 +12051,35 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.13.0",
- "@rollup/rollup-android-arm64": "4.13.0",
- "@rollup/rollup-darwin-arm64": "4.13.0",
- "@rollup/rollup-darwin-x64": "4.13.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
- "@rollup/rollup-linux-arm64-gnu": "4.13.0",
- "@rollup/rollup-linux-arm64-musl": "4.13.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.13.0",
- "@rollup/rollup-linux-x64-gnu": "4.13.0",
- "@rollup/rollup-linux-x64-musl": "4.13.0",
- "@rollup/rollup-win32-arm64-msvc": "4.13.0",
- "@rollup/rollup-win32-ia32-msvc": "4.13.0",
- "@rollup/rollup-win32-x64-msvc": "4.13.0",
+ "@rollup/rollup-android-arm-eabi": "4.14.2",
+ "@rollup/rollup-android-arm64": "4.14.2",
+ "@rollup/rollup-darwin-arm64": "4.14.2",
+ "@rollup/rollup-darwin-x64": "4.14.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.14.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.14.2",
+ "@rollup/rollup-linux-arm64-musl": "4.14.2",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.14.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.14.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.14.2",
+ "@rollup/rollup-linux-x64-gnu": "4.14.2",
+ "@rollup/rollup-linux-x64-musl": "4.14.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.14.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.14.2",
+ "@rollup/rollup-win32-x64-msvc": "4.14.2",
"fsevents": "~2.3.2"
}
},
"node_modules/vitest": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.4.0.tgz",
- "integrity": "sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.5.0.tgz",
+ "integrity": "sha512-d8UKgR0m2kjdxDWX6911uwxout6GHS0XaGH1cksSIVVG8kRlE7G7aBw7myKQCvDI5dT4j7ZMa+l706BIORMDLw==",
"dev": true,
"dependencies": {
- "@vitest/expect": "1.4.0",
- "@vitest/runner": "1.4.0",
- "@vitest/snapshot": "1.4.0",
- "@vitest/spy": "1.4.0",
- "@vitest/utils": "1.4.0",
+ "@vitest/expect": "1.5.0",
+ "@vitest/runner": "1.5.0",
+ "@vitest/snapshot": "1.5.0",
+ "@vitest/spy": "1.5.0",
+ "@vitest/utils": "1.5.0",
"acorn-walk": "^8.3.2",
"chai": "^4.3.10",
"debug": "^4.3.4",
@@ -12010,9 +12091,9 @@
"std-env": "^3.5.0",
"strip-literal": "^2.0.0",
"tinybench": "^2.5.1",
- "tinypool": "^0.8.2",
+ "tinypool": "^0.8.3",
"vite": "^5.0.0",
- "vite-node": "1.4.0",
+ "vite-node": "1.5.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
@@ -12027,8 +12108,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "1.4.0",
- "@vitest/ui": "1.4.0",
+ "@vitest/browser": "1.5.0",
+ "@vitest/ui": "1.5.0",
"happy-dom": "*",
"jsdom": "*"
},
@@ -12054,9 +12135,9 @@
}
},
"node_modules/vitest/node_modules/magic-string": {
- "version": "0.30.8",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
- "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+ "version": "0.30.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.9.tgz",
+ "integrity": "sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
@@ -12095,9 +12176,9 @@
}
},
"node_modules/vue-chartjs": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.0.tgz",
- "integrity": "sha512-8XqX0JU8vFZ+WA2/knz4z3ThClduni2Nm0BMe2u0mXgTfd9pXrmJ07QBI+WAij5P/aPmPMX54HCE1seWL37ZdQ==",
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.3.1.tgz",
+ "integrity": "sha512-rZjqcHBxKiHrBl0CIvcOlVEBwRhpWAVf6rDU3vUfa7HuSRmGtCslc0Oc8m16oAVuk0erzc1FCtH1VCriHsrz+A==",
"peerDependencies": {
"chart.js": "^4.1.1",
"vue": "^3.0.0-0 || ^2.7.0"
@@ -12664,18 +12745,18 @@
}
},
"node_modules/yargs": {
- "version": "17.3.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz",
- "integrity": "sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==",
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"dev": true,
"dependencies": {
- "cliui": "^7.0.2",
+ "cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
- "yargs-parser": "^21.0.0"
+ "yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
@@ -12690,6 +12771,37 @@
"node": ">=12"
}
},
+ "node_modules/yargs/node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
diff --git a/package.json b/package.json
index 004ac9e2bf..ff1ae4d49e 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,7 @@
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.0.1",
"clippie": "4.0.7",
- "css-loader": "6.10.0",
+ "css-loader": "7.1.1",
"dayjs": "1.11.10",
"dropzone": "6.0.0-beta.2",
"easymde": "2.18.0",
@@ -34,18 +34,18 @@
"license-checker-webpack-plugin": "0.2.1",
"mermaid": "10.9.0",
"mini-css-extract-plugin": "2.8.1",
- "minimatch": "9.0.3",
+ "minimatch": "9.0.4",
"monaco-editor": "0.47.0",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.3.0",
"postcss": "8.4.38",
"postcss-loader": "8.1.1",
- "postcss-nesting": "12.1.0",
+ "postcss-nesting": "12.1.1",
"pretty-ms": "9.0.0",
"sortablejs": "1.15.2",
- "swagger-ui-dist": "5.12.0",
- "tailwindcss": "3.4.1",
- "temporal-polyfill": "0.2.3",
+ "swagger-ui-dist": "5.15.1",
+ "tailwindcss": "3.4.3",
+ "temporal-polyfill": "0.2.4",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
@@ -55,7 +55,7 @@
"vanilla-colorful": "0.7.2",
"vue": "3.4.21",
"vue-bar-graph": "2.0.0",
- "vue-chartjs": "5.3.0",
+ "vue-chartjs": "5.3.1",
"vue-loader": "17.4.2",
"vue3-calendar-heatmap": "2.0.5",
"webpack": "5.91.0",
@@ -63,11 +63,11 @@
"wrap-ansi": "9.0.0"
},
"devDependencies": {
- "@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.42.1",
- "@stoplight/spectral-cli": "6.11.0",
+ "@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
+ "@playwright/test": "1.43.1",
+ "@stoplight/spectral-cli": "6.11.1",
"@stylistic/eslint-plugin-js": "1.7.0",
- "@stylistic/stylelint-plugin": "2.1.0",
+ "@stylistic/stylelint-plugin": "2.1.1",
"@vitejs/plugin-vue": "5.0.4",
"eslint": "8.57.0",
"eslint-plugin-array-func": "4.0.0",
@@ -76,25 +76,25 @@
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.4.0",
- "eslint-plugin-sonarjs": "0.24.0",
- "eslint-plugin-unicorn": "51.0.1",
- "eslint-plugin-vitest": "0.4.0",
+ "eslint-plugin-regexp": "2.5.0",
+ "eslint-plugin-sonarjs": "0.25.1",
+ "eslint-plugin-unicorn": "52.0.0",
+ "eslint-plugin-vitest": "0.4.1",
"eslint-plugin-vitest-globals": "1.5.0",
- "eslint-plugin-vue": "9.24.0",
+ "eslint-plugin-vue": "9.24.1",
"eslint-plugin-vue-scoped-css": "2.8.0",
- "eslint-plugin-wc": "2.0.4",
- "happy-dom": "14.3.7",
+ "eslint-plugin-wc": "2.1.0",
+ "happy-dom": "14.7.1",
"markdownlint-cli": "0.39.0",
"postcss-html": "1.6.0",
- "stylelint": "16.3.0",
+ "stylelint": "16.3.1",
"stylelint-declaration-block-no-ignored-properties": "2.8.0",
"stylelint-declaration-strict-value": "1.10.4",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "3.2.0",
- "updates": "16.0.0",
+ "updates": "16.0.1",
"vite-string-plugin": "1.1.5",
- "vitest": "1.4.0"
+ "vitest": "1.5.0"
},
"browserslist": [
"defaults"
diff --git a/poetry.lock b/poetry.lock
index 951a0fa7a8..1533ddc5ec 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -113,13 +113,13 @@ six = ">=1.13.0"
[[package]]
name = "json5"
-version = "0.9.24"
+version = "0.9.25"
description = "A Python implementation of the JSON5 data format."
optional = false
python-versions = ">=3.8"
files = [
- {file = "json5-0.9.24-py3-none-any.whl", hash = "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13"},
- {file = "json5-0.9.24.tar.gz", hash = "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8"},
+ {file = "json5-0.9.25-py3-none-any.whl", hash = "sha256:34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f"},
+ {file = "json5-0.9.25.tar.gz", hash = "sha256:548e41b9be043f9426776f05df8635a00fe06104ea51ed24b67f908856e151ae"},
]
[[package]]
diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go
index 1d07be3aec..b2f3e7af78 100644
--- a/routers/api/actions/runner/runner.go
+++ b/routers/api/actions/runner/runner.go
@@ -9,6 +9,8 @@ import (
"net/http"
actions_model "code.gitea.io/gitea/models/actions"
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
@@ -52,6 +54,18 @@ func (s *Service) Register(
return nil, errors.New("runner registration token has been invalidated, please use the latest one")
}
+ if runnerToken.OwnerID > 0 {
+ if _, err := user_model.GetUserByID(ctx, runnerToken.OwnerID); err != nil {
+ return nil, errors.New("owner of the token not found")
+ }
+ }
+
+ if runnerToken.RepoID > 0 {
+ if _, err := repo_model.GetRepositoryByID(ctx, runnerToken.RepoID); err != nil {
+ return nil, errors.New("repository of the token not found")
+ }
+ }
+
labels := req.Msg.Labels
// TODO: agent_labels should be removed from pb after Gitea 1.20 released.
// Old version runner's agent_labels slice is not empty and labels slice is empty.
diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go
index c28bc6c9d9..09156ece6b 100644
--- a/routers/api/packages/nuget/nuget.go
+++ b/routers/api/packages/nuget/nuget.go
@@ -388,7 +388,8 @@ func EnumeratePackageVersionsV3(ctx *context.Context) {
ctx.JSON(http.StatusOK, resp)
}
-// https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg
+// https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-manifest-nuspec
+// https://learn.microsoft.com/en-us/nuget/api/package-base-address-resource#download-package-content-nupkg
func DownloadPackageFile(ctx *context.Context) {
packageName := ctx.Params("id")
packageVersion := ctx.Params("version")
@@ -431,7 +432,7 @@ func UploadPackage(ctx *context.Context) {
return
}
- _, _, err := packages_service.CreatePackageAndAddFile(
+ pv, _, err := packages_service.CreatePackageAndAddFile(
ctx,
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
@@ -465,6 +466,33 @@ func UploadPackage(ctx *context.Context) {
return
}
+ nuspecBuf, err := packages_module.CreateHashedBufferFromReaderWithSize(np.NuspecContent, np.NuspecContent.Len())
+ if err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+ defer nuspecBuf.Close()
+
+ _, err = packages_service.AddFileToPackageVersionInternal(
+ ctx,
+ pv,
+ &packages_service.PackageFileCreationInfo{
+ PackageFileInfo: packages_service.PackageFileInfo{
+ Filename: strings.ToLower(fmt.Sprintf("%s.nuspec", np.ID)),
+ },
+ Data: nuspecBuf,
+ },
+ )
+ if err != nil {
+ switch err {
+ case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
+ apiError(ctx, http.StatusForbidden, err)
+ default:
+ apiError(ctx, http.StatusInternalServerError, err)
+ }
+ return
+ }
+
ctx.Status(http.StatusCreated)
}
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index 87a5b28fad..be907805d6 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -30,7 +30,7 @@ import (
user_service "code.gitea.io/gitea/services/user"
)
-func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64, loginName string) {
+func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64) {
if sourceID == 0 {
return
}
@@ -47,7 +47,6 @@ func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64
u.LoginType = source.Type
u.LoginSource = source.ID
- u.LoginName = loginName
}
// CreateUser create a user
@@ -83,12 +82,13 @@ func CreateUser(ctx *context.APIContext) {
Passwd: form.Password,
MustChangePassword: true,
LoginType: auth.Plain,
+ LoginName: form.LoginName,
}
if form.MustChangePassword != nil {
u.MustChangePassword = *form.MustChangePassword
}
- parseAuthSource(ctx, u, form.SourceID, form.LoginName)
+ parseAuthSource(ctx, u, form.SourceID)
if ctx.Written() {
return
}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 6a33fbee2e..fb8a08192f 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -209,11 +209,7 @@ func repoAssignment() func(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadUnits", err)
return
}
- ctx.Repo.Permission.Units = ctx.Repo.Repository.Units
- ctx.Repo.Permission.UnitsMode = make(map[unit.Type]perm.AccessMode)
- for _, u := range ctx.Repo.Repository.Units {
- ctx.Repo.Permission.UnitsMode[u.Type] = ctx.Repo.Permission.AccessMode
- }
+ ctx.Repo.Permission.SetUnitsWithDefaultAccessMode(ctx.Repo.Repository.Units, ctx.Repo.Permission.AccessMode)
} else {
ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
@@ -1066,6 +1062,8 @@ func Routes() *web.Route {
m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
m.Group("/{username}/{reponame}", func() {
+ m.Get("/compare/*", reqRepoReader(unit.TypeCode), repo.CompareDiff)
+
m.Combo("").Get(reqAnyRepoReader(), repo.Get).
Delete(reqToken(), reqOwner(), repo.Delete).
Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit)
diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go
index 3bd80de5c1..5973724782 100644
--- a/routers/api/v1/misc/nodeinfo.go
+++ b/routers/api/v1/misc/nodeinfo.go
@@ -29,9 +29,7 @@ func NodeInfo(ctx *context.APIContext) {
nodeInfoUsage := structs.NodeInfoUsage{}
if setting.Federation.ShareUserStatistics {
- var cached bool
- nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage)
-
+ cached, _ := ctx.Cache.GetJSON(cacheKeyNodeInfoUsage, &nodeInfoUsage)
if !cached {
usersTotal := int(user_model.CountUsers(ctx, nil))
now := time.Now()
@@ -53,7 +51,7 @@ func NodeInfo(ctx *context.APIContext) {
LocalComments: int(allComments),
}
- if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
+ if err := ctx.Cache.PutJSON(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
ctx.InternalServerError(err)
return
}
diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go
index 8d97e8a3f8..1744426ee8 100644
--- a/routers/api/v1/notify/repo.go
+++ b/routers/api/v1/notify/repo.go
@@ -10,7 +10,6 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -201,7 +200,6 @@ func ReadRepoNotifications(ctx *context.APIContext) {
if !ctx.FormBool("all") {
statuses := ctx.FormStrings("status-types")
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
- log.Error("%v", opts.Status)
}
nl, err := db.Find[activities_model.Notification](ctx, opts)
if err != nil {
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index 5e6b6a8658..baab486e52 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -437,7 +437,7 @@ func GetBranchProtection(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp))
+ ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp, repo))
}
// ListBranchProtections list branch protections for a repo
@@ -470,7 +470,7 @@ func ListBranchProtections(ctx *context.APIContext) {
}
apiBps := make([]*api.BranchProtection, len(bps))
for i := range bps {
- apiBps[i] = convert.ToBranchProtection(ctx, bps[i])
+ apiBps[i] = convert.ToBranchProtection(ctx, bps[i], repo)
}
ctx.JSON(http.StatusOK, apiBps)
@@ -681,7 +681,7 @@ func CreateBranchProtection(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusCreated, convert.ToBranchProtection(ctx, bp))
+ ctx.JSON(http.StatusCreated, convert.ToBranchProtection(ctx, bp, repo))
}
// EditBranchProtection edits a branch protection for a repo
@@ -959,7 +959,7 @@ func EditBranchProtection(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp))
+ ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp, repo))
}
// DeleteBranchProtection deletes a branch protection for a repo
diff --git a/routers/api/v1/repo/compare.go b/routers/api/v1/repo/compare.go
new file mode 100644
index 0000000000..549b9b7fa9
--- /dev/null
+++ b/routers/api/v1/repo/compare.go
@@ -0,0 +1,99 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "net/http"
+ "strings"
+
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/gitrepo"
+ api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/convert"
+)
+
+// CompareDiff compare two branches or commits
+func CompareDiff(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/compare/{basehead} Get commit comparison information
+ // ---
+ // summary: Get commit comparison information
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repo
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repo
+ // type: string
+ // required: true
+ // - name: basehead
+ // in: path
+ // description: compare two branches or commits
+ // type: string
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/Compare"
+ // "404":
+ // "$ref": "#/responses/notFound"
+
+ if ctx.Repo.GitRepo == nil {
+ gitRepo, err := gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "OpenRepository", err)
+ return
+ }
+ ctx.Repo.GitRepo = gitRepo
+ defer gitRepo.Close()
+ }
+
+ infoPath := ctx.Params("*")
+ infos := []string{ctx.Repo.Repository.DefaultBranch, ctx.Repo.Repository.DefaultBranch}
+ if infoPath != "" {
+ infos = strings.SplitN(infoPath, "...", 2)
+ if len(infos) != 2 {
+ if infos = strings.SplitN(infoPath, "..", 2); len(infos) != 2 {
+ infos = []string{ctx.Repo.Repository.DefaultBranch, infoPath}
+ }
+ }
+ }
+
+ _, _, headGitRepo, ci, _, _ := parseCompareInfo(ctx, api.CreatePullRequestOption{
+ Base: infos[0],
+ Head: infos[1],
+ })
+ if ctx.Written() {
+ return
+ }
+ defer headGitRepo.Close()
+
+ verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
+ files := ctx.FormString("files") == "" || ctx.FormBool("files")
+
+ apiCommits := make([]*api.Commit, 0, len(ci.Commits))
+ userCache := make(map[string]*user_model.User)
+ for i := 0; i < len(ci.Commits); i++ {
+ apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, ci.Commits[i], userCache,
+ convert.ToCommitOptions{
+ Stat: true,
+ Verification: verification,
+ Files: files,
+ })
+ if err != nil {
+ ctx.ServerError("toCommit", err)
+ return
+ }
+ apiCommits = append(apiCommits, apiCommit)
+ }
+
+ ctx.JSON(http.StatusOK, &api.Compare{
+ TotalCommits: len(ci.Commits),
+ Commits: apiCommits,
+ })
+}
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 6934b34b24..5e173abf88 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -311,7 +311,7 @@ func SearchIssues(ctx *context.APIContext) {
ctx.SetLinkHeader(int(total), limit)
ctx.SetTotalCountHeader(total)
- ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
}
// ListIssues list the issues of a repository
@@ -548,7 +548,7 @@ func ListIssues(ctx *context.APIContext) {
ctx.SetLinkHeader(int(total), listOptions.PageSize)
ctx.SetTotalCountHeader(total)
- ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
}
func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 {
@@ -614,7 +614,7 @@ func GetIssue(ctx *context.APIContext) {
ctx.NotFound()
return
}
- ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue))
}
// CreateIssue create an issue of a repository
@@ -737,7 +737,7 @@ func CreateIssue(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "GetIssueByID", err)
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue))
}
// EditIssue modify an issue of a repository
@@ -911,7 +911,7 @@ func EditIssue(ctx *context.APIContext) {
ctx.InternalServerError(err)
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue))
}
func DeleteIssue(ctx *context.APIContext) {
diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go
index d62e23aa02..7a5c6d554d 100644
--- a/routers/api/v1/repo/issue_attachment.go
+++ b/routers/api/v1/repo/issue_attachment.go
@@ -107,7 +107,7 @@ func ListIssueAttachments(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments)
+ ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue).Attachments)
}
// CreateIssueAttachment creates an attachment and saves the given file
diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go
index a42920d4fd..c40e92c01b 100644
--- a/routers/api/v1/repo/issue_dependency.go
+++ b/routers/api/v1/repo/issue_dependency.go
@@ -153,7 +153,7 @@ func GetIssueDependencies(ctx *context.APIContext) {
blockerIssues = append(blockerIssues, &blocker.Issue)
}
- ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, blockerIssues))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, blockerIssues))
}
// CreateIssueDependency create a new issue dependencies
@@ -214,7 +214,7 @@ func CreateIssueDependency(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
}
// RemoveIssueDependency remove an issue dependency
@@ -275,7 +275,7 @@ func RemoveIssueDependency(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target))
}
// GetIssueBlocks list issues that are blocked by this issue
@@ -381,7 +381,7 @@ func GetIssueBlocks(ctx *context.APIContext) {
issues = append(issues, &depMeta.Issue)
}
- ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
}
// CreateIssueBlocking block the issue given in the body by the issue in path
@@ -438,7 +438,7 @@ func CreateIssueBlocking(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
}
// RemoveIssueBlocking unblock the issue given in the body by the issue in path
@@ -495,7 +495,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency))
+ ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency))
}
func getParamsIssue(ctx *context.APIContext) *issues_model.Issue {
diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go
index 8fcf670fd0..af3e06332a 100644
--- a/routers/api/v1/repo/issue_pin.go
+++ b/routers/api/v1/repo/issue_pin.go
@@ -207,7 +207,7 @@ func ListPinnedIssues(ctx *context.APIContext) {
return
}
- ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues))
}
// ListPinnedPullRequests returns a list of all pinned PRs
diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go
index c640515881..f83855efac 100644
--- a/routers/api/v1/repo/issue_tracked_time.go
+++ b/routers/api/v1/repo/issue_tracked_time.go
@@ -138,7 +138,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
}
ctx.SetTotalCountHeader(count)
- ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes))
+ ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
}
// AddTime add time manual to the given issue
@@ -225,7 +225,7 @@ func AddTime(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
- ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, trackedTime))
+ ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, user, trackedTime))
}
// ResetIssueTime reset time manual to the given issue
@@ -455,7 +455,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
- ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes))
+ ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
}
// ListTrackedTimesByRepository lists all tracked times of the repository
@@ -567,7 +567,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
}
ctx.SetTotalCountHeader(count)
- ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes))
+ ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
}
// ListMyTrackedTimes lists all tracked times of the current user
@@ -629,5 +629,5 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
}
ctx.SetTotalCountHeader(count)
- ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes))
+ ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes))
}
diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go
index 3784826c20..fcd34a63a9 100644
--- a/routers/api/v1/swagger/repo.go
+++ b/routers/api/v1/swagger/repo.go
@@ -421,3 +421,9 @@ type swaggerRepoTasksList struct {
// in:body
Body api.ActionTaskResponse `json:"body"`
}
+
+// swagger:response Compare
+type swaggerCompare struct {
+ // in:body
+ Body api.Compare `json:"body"`
+}
diff --git a/routers/common/compare.go b/routers/common/compare.go
new file mode 100644
index 0000000000..4d1cc2f0d8
--- /dev/null
+++ b/routers/common/compare.go
@@ -0,0 +1,21 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ repo_model "code.gitea.io/gitea/models/repo"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/git"
+)
+
+// CompareInfo represents the collected results from ParseCompareInfo
+type CompareInfo struct {
+ HeadUser *user_model.User
+ HeadRepo *repo_model.Repository
+ HeadGitRepo *git.Repository
+ CompareInfo *git.CompareInfo
+ BaseBranch string
+ HeadBranch string
+ DirectComparison bool
+}
diff --git a/routers/private/actions.go b/routers/private/actions.go
index 53c2412308..696634b5e7 100644
--- a/routers/private/actions.go
+++ b/routers/private/actions.go
@@ -26,7 +26,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
defer rd.Close()
if err := json.NewDecoder(rd).Decode(&genRequest); err != nil {
- log.Error("%v", err)
+ log.Error("JSON Decode failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
})
@@ -35,7 +35,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
owner, repo, err := parseScope(ctx, genRequest.Scope)
if err != nil {
- log.Error("%v", err)
+ log.Error("parseScope failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
})
@@ -45,18 +45,18 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) {
token, err = actions_model.NewRunnerToken(ctx, owner, repo)
if err != nil {
- err := fmt.Sprintf("error while creating runner token: %v", err)
- log.Error("%v", err)
+ errMsg := fmt.Sprintf("error while creating runner token: %v", err)
+ log.Error("NewRunnerToken failed: %v", errMsg)
ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: err,
+ Err: errMsg,
})
return
}
} else if err != nil {
- err := fmt.Sprintf("could not get unactivated runner token: %v", err)
- log.Error("%v", err)
+ errMsg := fmt.Sprintf("could not get unactivated runner token: %v", err)
+ log.Error("GetLatestRunnerToken failed: %v", errMsg)
ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: err,
+ Err: errMsg,
})
return
}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 101ae92302..769a68970d 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -6,11 +6,12 @@ package private
import (
"fmt"
"net/http"
- "strconv"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
+ access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
+ 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/log"
@@ -159,8 +160,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
}
+ isPrivate := opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate)
+ isTemplate := opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate)
// Handle Push Options
- if len(opts.GitPushOptions) > 0 {
+ if isPrivate.Has() || isTemplate.Has() {
// load the repository
if repo == nil {
repo = loadRepository(ctx, ownerName, repoName)
@@ -171,13 +174,49 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
wasEmpty = repo.IsEmpty
}
- repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate)
- repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate)
- if err := repo_model.UpdateRepositoryCols(ctx, repo, "is_private", "is_template"); err != nil {
+ pusher, err := user_model.GetUserByID(ctx, opts.UserID)
+ if err != nil {
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
})
+ return
+ }
+ perm, err := access_model.GetUserRepoPermission(ctx, repo, pusher)
+ if err != nil {
+ log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
+ Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
+ })
+ return
+ }
+ if !perm.IsOwner() && !perm.IsAdmin() {
+ ctx.JSON(http.StatusNotFound, private.HookPostReceiveResult{
+ Err: "Permissions denied",
+ })
+ return
+ }
+
+ cols := make([]string, 0, len(opts.GitPushOptions))
+
+ if isPrivate.Has() {
+ repo.IsPrivate = isPrivate.Value()
+ cols = append(cols, "is_private")
+ }
+
+ if isTemplate.Has() {
+ repo.IsTemplate = isTemplate.Value()
+ cols = append(cols, "is_template")
+ }
+
+ if len(cols) > 0 {
+ if err := repo_model.UpdateRepositoryCols(ctx, repo, cols...); err != nil {
+ log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
+ ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
+ Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
+ })
+ return
+ }
}
}
@@ -192,42 +231,6 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
refFullName := opts.RefFullNames[i]
newCommitID := opts.NewCommitIDs[i]
- // post update for agit pull request
- // FIXME: use pr.Flow to test whether it's an Agit PR or a GH PR
- if git.DefaultFeatures.SupportProcReceive && refFullName.IsPull() {
- if repo == nil {
- repo = loadRepository(ctx, ownerName, repoName)
- if ctx.Written() {
- return
- }
- }
-
- pullIndex, _ := strconv.ParseInt(refFullName.PullName(), 10, 64)
- if pullIndex <= 0 {
- continue
- }
-
- pr, err := issues_model.GetPullRequestByIndex(ctx, repo.ID, pullIndex)
- if err != nil && !issues_model.IsErrPullRequestNotExist(err) {
- log.Error("Failed to get PR by index %v Error: %v", pullIndex, err)
- ctx.JSON(http.StatusInternalServerError, private.Response{
- Err: fmt.Sprintf("Failed to get PR by index %v Error: %v", pullIndex, err),
- })
- return
- }
- if pr == nil {
- continue
- }
-
- results = append(results, private.HookPostReceiveBranchResult{
- Message: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx),
- Create: false,
- Branch: "",
- URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
- })
- continue
- }
-
// If we've pushed a branch (and not deleted it)
if !git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() {
// First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index 32ec3003e2..4e59237ed3 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -481,11 +481,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool {
})
return false
}
- ctx.userPerm.Units = ctx.Repo.Repository.Units
- ctx.userPerm.UnitsMode = make(map[unit.Type]perm_model.AccessMode)
- for _, u := range ctx.Repo.Repository.Units {
- ctx.userPerm.UnitsMode[u.Type] = ctx.userPerm.AccessMode
- }
+ ctx.userPerm.SetUnitsWithDefaultAccessMode(ctx.Repo.Repository.Units, ctx.userPerm.AccessMode)
} else {
user, err := user_model.GetUserByID(ctx, ctx.opts.UserID)
if err != nil {
diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go
index 42b8e5abed..764c976fa9 100644
--- a/routers/private/hook_verification.go
+++ b/routers/private/hook_verification.go
@@ -47,7 +47,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
_ = stdoutWriter.Close()
err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env)
if err != nil {
- log.Error("%v", err)
+ log.Error("readAndVerifyCommitsFromShaReader failed: %v", err)
cancel()
}
_ = stdoutReader.Close()
@@ -66,7 +66,6 @@ func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository
line := scanner.Text()
err := readAndVerifyCommit(line, repo, env)
if err != nil {
- log.Error("%v", err)
return err
}
}
diff --git a/routers/private/mail.go b/routers/private/mail.go
index c19ee67896..cf3abb31c6 100644
--- a/routers/private/mail.go
+++ b/routers/private/mail.go
@@ -35,7 +35,7 @@ func SendEmail(ctx *context.PrivateContext) {
defer rd.Close()
if err := json.NewDecoder(rd).Decode(&mail); err != nil {
- log.Error("%v", err)
+ log.Error("JSON Decode failed: %v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
})
diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go
index 4dc0dfdef8..e6585d8833 100644
--- a/routers/web/admin/admin.go
+++ b/routers/web/admin/admin.go
@@ -117,11 +117,11 @@ func updateSystemStatus() {
sysStatus.NumGC = m.NumGC
}
-func prepareDeprecatedWarningsAlert(ctx *context.Context) {
- if len(setting.DeprecatedWarnings) > 0 {
- content := setting.DeprecatedWarnings[0]
- if len(setting.DeprecatedWarnings) > 1 {
- content += fmt.Sprintf(" (and %d more)", len(setting.DeprecatedWarnings)-1)
+func prepareStartupProblemsAlert(ctx *context.Context) {
+ if len(setting.StartupProblems) > 0 {
+ content := setting.StartupProblems[0]
+ if len(setting.StartupProblems) > 1 {
+ content += fmt.Sprintf(" (and %d more)", len(setting.StartupProblems)-1)
}
ctx.Flash.Error(content, true)
}
@@ -136,7 +136,7 @@ func Dashboard(ctx *context.Context) {
updateSystemStatus()
ctx.Data["SysStatus"] = sysStatus
ctx.Data["SSH"] = setting.SSH
- prepareDeprecatedWarningsAlert(ctx)
+ prepareStartupProblemsAlert(ctx)
ctx.HTML(http.StatusOK, tplDashboard)
}
@@ -191,10 +191,10 @@ func DashboardPost(ctx *context.Context) {
func SelfCheck(ctx *context.Context) {
ctx.Data["PageIsAdminSelfCheck"] = true
- ctx.Data["DeprecatedWarnings"] = setting.DeprecatedWarnings
- if len(setting.DeprecatedWarnings) == 0 && !setting.IsProd {
+ ctx.Data["StartupProblems"] = setting.StartupProblems
+ if len(setting.StartupProblems) == 0 && !setting.IsProd {
if time.Now().Unix()%2 == 0 {
- ctx.Data["DeprecatedWarnings"] = []string{"This is a test warning message in dev mode"}
+ ctx.Data["StartupProblems"] = []string{"This is a test warning message in dev mode"}
}
}
diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go
index 2f5f17e201..48f80dbbf1 100644
--- a/routers/web/admin/config.go
+++ b/routers/web/admin/config.go
@@ -165,7 +165,7 @@ func Config(ctx *context.Context) {
ctx.Data["Loggers"] = log.GetManager().DumpLoggers()
config.GetDynGetter().InvalidateCache()
- prepareDeprecatedWarningsAlert(ctx)
+ prepareStartupProblemsAlert(ctx)
ctx.HTML(http.StatusOK, tplConfig)
}
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index b93668c5a2..ea9d6f4c9c 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -403,7 +403,6 @@ func EditUserPost(ctx *context.Context) {
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form)
case password.IsErrIsPwnedRequest(err):
- log.Error("%s", err.Error())
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
default:
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index 8b5cd986b8..9ef32ebdb1 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -386,6 +386,13 @@ func getUserName(gothUser *goth.User) (string, error) {
switch setting.OAuth2Client.Username {
case setting.OAuth2UsernameEmail:
return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0])
+ case setting.OAuth2UsernamePreferredUsername:
+ preferredUsername, exists := gothUser.RawData["preferred_username"]
+ if exists {
+ return user_model.NormalizeUserName(preferredUsername.(string))
+ } else {
+ return "", fmt.Errorf("preferred_username is missing in received user data but configured as username source for user_id %q. Check if OPENID_CONNECT_SCOPES contains profile", gothUser.UserID)
+ }
case setting.OAuth2UsernameNickname:
return user_model.NormalizeUserName(gothUser.NickName)
default: // OAuth2UsernameUserid
diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go
index f6b76c1ffd..0e88fe68f9 100644
--- a/routers/web/auth/password.go
+++ b/routers/web/auth/password.go
@@ -214,7 +214,6 @@ func ResetPasswdPost(ctx *context.Context) {
case errors.Is(err, password.ErrIsPwned):
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil)
case password.IsErrIsPwnedRequest(err):
- log.Error("%s", err.Error())
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil)
default:
ctx.ServerError("UpdateAuth", err)
@@ -298,7 +297,6 @@ func MustChangePasswordPost(ctx *context.Context) {
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form)
case password.IsErrIsPwnedRequest(err):
- log.Error("%s", err.Error())
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form)
default:
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 596a370d2e..d439b11cf9 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"net/http"
- "net/url"
"strconv"
"strings"
@@ -195,14 +194,15 @@ func NewProjectPost(ctx *context.Context) {
// ChangeProjectStatus updates the status of a project between "open" and "close"
func ChangeProjectStatus(ctx *context.Context) {
- toClose := false
+ var toClose bool
switch ctx.Params(":action") {
case "open":
toClose = false
case "close":
toClose = true
default:
- ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects")
+ ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects")
+ return
}
id := ctx.ParamsInt64(":id")
@@ -210,7 +210,7 @@ func ChangeProjectStatus(ctx *context.Context) {
ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return
}
- ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action")))
+ ctx.JSONRedirect(fmt.Sprintf("%s/-/projects/%d", ctx.ContextUser.HomeLink(), id))
}
// DeleteProject delete a project
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index cfb0e859bd..035a92f228 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -35,6 +35,7 @@ import (
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/context/upload"
"code.gitea.io/gitea/services/gitdiff"
@@ -185,21 +186,10 @@ func setCsvCompareContext(ctx *context.Context) {
}
}
-// CompareInfo represents the collected results from ParseCompareInfo
-type CompareInfo struct {
- HeadUser *user_model.User
- HeadRepo *repo_model.Repository
- HeadGitRepo *git.Repository
- CompareInfo *git.CompareInfo
- BaseBranch string
- HeadBranch string
- DirectComparison bool
-}
-
// ParseCompareInfo parse compare info between two commit for preparing comparing references
-func ParseCompareInfo(ctx *context.Context) *CompareInfo {
+func ParseCompareInfo(ctx *context.Context) *common.CompareInfo {
baseRepo := ctx.Repo.Repository
- ci := &CompareInfo{}
+ ci := &common.CompareInfo{}
fileOnly := ctx.FormBool("file-only")
@@ -576,7 +566,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
// PrepareCompareDiff renders compare diff page
func PrepareCompareDiff(
ctx *context.Context,
- ci *CompareInfo,
+ ci *common.CompareInfo,
whitespaceBehavior git.TrustedCmdArgs,
) bool {
var (
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index 6c2d4a7390..1364d75676 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -2179,7 +2179,7 @@ func GetIssueInfo(ctx *context.Context) {
}
}
- ctx.JSON(http.StatusOK, convert.ToIssue(ctx, issue))
+ ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue))
}
// UpdateIssueTitle change issue's title
@@ -2709,7 +2709,7 @@ func SearchIssues(ctx *context.Context) {
}
ctx.SetTotalCountHeader(total)
- ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues))
}
func getUserIDForFilter(ctx *context.Context, queryName string) int64 {
@@ -2879,7 +2879,7 @@ func ListIssues(ctx *context.Context) {
}
ctx.SetTotalCountHeader(total)
- ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues))
+ ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues))
}
func BatchDeleteIssues(ctx *context.Context) {
@@ -3318,7 +3318,6 @@ func ChangeIssueReaction(ctx *context.Context) {
}
html, err := ctx.RenderToHTML(tplReactions, map[string]any{
- "ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/issues/%d/reactions", ctx.Repo.RepoLink, issue.Index),
"Reactions": issue.Reactions.GroupByType(),
})
@@ -3425,7 +3424,6 @@ func ChangeCommentReaction(ctx *context.Context) {
}
html, err := ctx.RenderToHTML(tplReactions, map[string]any{
- "ctxData": ctx.Data,
"ActionURL": fmt.Sprintf("%s/comments/%d/reactions", ctx.Repo.RepoLink, comment.ID),
"Reactions": comment.Reactions.GroupByType(),
})
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index a2db1fc770..9b765e89e8 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"net/http"
- "net/url"
"strings"
"code.gitea.io/gitea/models/db"
@@ -181,14 +180,10 @@ func ChangeProjectStatus(ctx *context.Context) {
id := ctx.ParamsInt64(":id")
if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil {
- if project_model.IsErrProjectNotExist(err) {
- ctx.NotFound("", err)
- } else {
- ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err)
- }
+ ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err)
return
}
- ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action")))
+ ctx.JSONRedirect(fmt.Sprintf("%s/projects/%d", ctx.Repo.RepoLink, id))
}
// DeleteProject delete a project
diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go
index b30dc3b061..4bab3f897a 100644
--- a/routers/web/repo/setting/protected_branch.go
+++ b/routers/web/repo/setting/protected_branch.go
@@ -313,7 +313,13 @@ func RenameBranchPost(ctx *context.Context) {
msg, err := repository.RenameBranch(ctx, ctx.Repo.Repository, ctx.Doer, ctx.Repo.GitRepo, form.From, form.To)
if err != nil {
- ctx.ServerError("RenameBranch", err)
+ switch {
+ case git_model.IsErrBranchAlreadyExists(err):
+ ctx.Flash.Error(ctx.Tr("repo.branch.branch_already_exists", form.To))
+ ctx.Redirect(fmt.Sprintf("%s/branches", ctx.Repo.RepoLink))
+ default:
+ ctx.ServerError("RenameBranch", err)
+ }
return
}
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index 00a5282f34..b55e259e4b 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -16,6 +16,7 @@ import (
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
+ "code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
@@ -476,9 +477,10 @@ func SettingsPost(ctx *context.Context) {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
} else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeWiki,
- Config: new(repo_model.UnitConfig),
+ RepoID: repo.ID,
+ Type: unit_model.TypeWiki,
+ Config: new(repo_model.UnitConfig),
+ EveryoneAccessMode: perm.ParseAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
})
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
} else {
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 8aa9dbb1be..9c1f4faa5f 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -684,7 +684,7 @@ func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input i
}
func checkHomeCodeViewable(ctx *context.Context) {
- if len(ctx.Repo.Units) > 0 {
+ if ctx.Repo.HasUnits() {
if ctx.Repo.Repository.IsBeingCreated() {
task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID)
if err != nil {
@@ -721,12 +721,13 @@ func checkHomeCodeViewable(ctx *context.Context) {
}
var firstUnit *unit_model.Unit
- for _, repoUnit := range ctx.Repo.Units {
- if repoUnit.Type == unit_model.TypeCode {
+ for _, repoUnitType := range ctx.Repo.Permission.ReadableUnitTypes() {
+ if repoUnitType == unit_model.TypeCode {
+ // we are doing this check in "code" unit related pages, so if the code unit is readable, no need to do any further redirection
return
}
- unit, ok := unit_model.Units[repoUnit.Type]
+ unit, ok := unit_model.Units[repoUnitType]
if ok && (firstUnit == nil || !firstUnit.IsLessThan(unit)) {
firstUnit = &unit
}
diff --git a/routers/web/repo/wiki_test.go b/routers/web/repo/wiki_test.go
index 8b5207f9d9..4602dcfeb4 100644
--- a/routers/web/repo/wiki_test.go
+++ b/routers/web/repo/wiki_test.go
@@ -200,12 +200,13 @@ func TestDeleteWikiPagePost(t *testing.T) {
func TestWikiRaw(t *testing.T) {
for filepath, filetype := range map[string]string{
- "jpeg.jpg": "image/jpeg",
- "images/jpeg.jpg": "image/jpeg",
- "Page With Spaced Name": "text/plain; charset=utf-8",
- "Page-With-Spaced-Name": "text/plain; charset=utf-8",
- "Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
- "Page-With-Spaced-Name.md": "text/plain; charset=utf-8",
+ "jpeg.jpg": "image/jpeg",
+ "images/jpeg.jpg": "image/jpeg",
+ "files/Non-Renderable-File.zip": "application/octet-stream",
+ "Page With Spaced Name": "text/plain; charset=utf-8",
+ "Page-With-Spaced-Name": "text/plain; charset=utf-8",
+ "Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
+ "Page-With-Spaced-Name.md": "text/plain; charset=utf-8",
} {
unittest.PrepareTestEnv(t)
@@ -226,6 +227,12 @@ func TestWikiRaw(t *testing.T) {
func TestDefaultWikiBranch(t *testing.T) {
unittest.PrepareTestEnv(t)
+ // repo with no wiki
+ repoWithNoWiki := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ assert.False(t, repoWithNoWiki.HasWiki())
+ assert.NoError(t, wiki_service.ChangeDefaultWikiBranch(db.DefaultContext, repoWithNoWiki, "main"))
+
+ // repo with wiki
assert.NoError(t, repo_model.UpdateRepositoryCols(db.DefaultContext, &repo_model.Repository{ID: 1, DefaultWikiBranch: "wrong-branch"}))
ctx, _ := contexttest.MockContext(t, "user2/repo1/wiki")
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index ff6c2a6c36..c3f34039e9 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -447,6 +447,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
User: ctx.Doer,
}
+ isFuzzy := ctx.FormBool("fuzzy")
+
// Search all repositories which
//
// As user:
@@ -546,7 +548,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// USING FINAL STATE OF opts FOR A QUERY.
var issues issues_model.IssueList
{
- issueIDs, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts))
+ issueIDs, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts).Copy(
+ func(o *issue_indexer.SearchOptions) { o.IsFuzzyKeyword = isFuzzy },
+ ))
if err != nil {
ctx.ServerError("issueIDsFromSearch", err)
return
@@ -567,7 +571,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// -------------------------------
// Fill stats to post to ctx.Data.
// -------------------------------
- issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts))
+ issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts).Copy(
+ func(o *issue_indexer.SearchOptions) { o.IsFuzzyKeyword = isFuzzy },
+ ))
if err != nil {
ctx.ServerError("getUserIssueStats", err)
return
@@ -621,6 +627,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.Data["SortType"] = sortType
ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["SelectLabels"] = selectedLabels
+ ctx.Data["IsFuzzy"] = isFuzzy
if isShowClosed {
ctx.Data["State"] = "closed"
@@ -634,6 +641,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
pager.AddParamString("sort", sortType)
pager.AddParamString("state", fmt.Sprint(ctx.Data["State"]))
pager.AddParamString("labels", selectedLabels)
+ pager.AddParamString("fuzzy", fmt.Sprintf("%v", isFuzzy))
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplIssues)
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index c93b70af76..8ea7548e51 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -74,7 +74,6 @@ func AccountPost(ctx *context.Context) {
case errors.Is(err, password.ErrIsPwned):
ctx.Flash.Error(ctx.Tr("auth.password_pwned"))
case password.IsErrIsPwnedRequest(err):
- log.Error("%s", err.Error())
ctx.Flash.Error(ctx.Tr("auth.password_pwned_err"))
default:
ctx.ServerError("UpdateAuth", err)
diff --git a/routers/web/web.go b/routers/web/web.go
index 4fff994e42..a6a4c1d987 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -54,10 +54,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
-const (
- // GzipMinSize represents min size to compress for the body size of response
- GzipMinSize = 1400
-)
+const GzipMinSize = 1400 // min size to compress for the body size of response
// optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
func optionsCorsHandler() func(next http.Handler) http.Handler {
@@ -493,6 +490,7 @@ func registerRoutes(m *web.Route) {
}, explore.Code)
m.Get("/topics/search", explore.TopicSearch)
}, ignExploreSignIn)
+
m.Group("/issues", func() {
m.Get("", user.Issues)
m.Get("/search", repo.SearchIssues)
@@ -802,6 +800,7 @@ func registerRoutes(m *web.Route) {
reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode)
reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases)
reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases)
+ reqRepoWikiReader := context.RequireRepoReader(unit.TypeWiki)
reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki)
reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues)
reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests)
@@ -838,12 +837,12 @@ func registerRoutes(m *web.Route) {
}
}
- // ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {
m.Get("/members", org.Members)
}, context.OrgAssignment())
}, ignSignIn)
+ // end "/org": members
m.Group("/org", func() {
m.Group("", func() {
@@ -958,9 +957,8 @@ func registerRoutes(m *web.Route) {
}, ctxDataSet("EnableOAuth2", setting.OAuth2.Enabled, "EnablePackages", setting.Packages.Enabled, "PageIsOrgSettings", true))
}, context.OrgAssignment(true, true))
}, reqSignIn)
- // ***** END: Organization *****
+ // end "/org": most org routes
- // ***** START: Repository *****
m.Group("/repo", func() {
m.Get("/create", repo.Create)
m.Post("/create", web.Bind(forms.CreateRepoForm{}), repo.CreatePost)
@@ -968,6 +966,7 @@ func registerRoutes(m *web.Route) {
m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost)
m.Get("/search", repo.SearchRepo)
}, reqSignIn)
+ // end "/repo": create, migrate, search
m.Group("/{username}/-", func() {
if setting.Packages.Enabled {
@@ -1008,7 +1007,6 @@ func registerRoutes(m *web.Route) {
m.Put("", web.Bind(forms.EditProjectBoardForm{}), org.EditProjectBoard)
m.Delete("", org.DeleteProjectBoard)
m.Post("/default", org.SetDefaultProjectBoard)
-
m.Post("/move", org.MoveIssues)
})
})
@@ -1023,125 +1021,152 @@ func registerRoutes(m *web.Route) {
m.Group("", func() {
m.Get("/code", user.CodeSearch)
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker)
- }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
+ }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
+ // end "/{username}/-": packages, projects, code
+
+ m.Group("/{username}/{reponame}/settings", func() {
+ m.Group("", func() {
+ m.Combo("").Get(repo_setting.Settings).
+ Post(web.Bind(forms.RepoSettingForm{}), repo_setting.SettingsPost)
+ }, repo_setting.SettingsCtxData)
+ m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo_setting.SettingsAvatar)
+ m.Post("/avatar/delete", repo_setting.SettingsDeleteAvatar)
+
+ m.Group("/collaboration", func() {
+ m.Combo("").Get(repo_setting.Collaboration).Post(repo_setting.CollaborationPost)
+ m.Post("/access_mode", repo_setting.ChangeCollaborationAccessMode)
+ m.Post("/delete", repo_setting.DeleteCollaboration)
+ m.Group("/team", func() {
+ m.Post("", repo_setting.AddTeamPost)
+ m.Post("/delete", repo_setting.DeleteTeam)
+ })
+ })
+
+ m.Group("/branches", func() {
+ m.Post("/", repo_setting.SetDefaultBranchPost)
+ }, repo.MustBeNotEmpty)
+
+ m.Group("/branches", func() {
+ m.Get("/", repo_setting.ProtectedBranchRules)
+ m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch).
+ Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost)
+ m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost)
+ }, repo.MustBeNotEmpty)
+
+ m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost)
+
+ m.Group("/tags", func() {
+ m.Get("", repo_setting.ProtectedTags)
+ m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.NewProtectedTagPost)
+ m.Post("/delete", context.RepoMustNotBeArchived(), repo_setting.DeleteProtectedTagPost)
+ m.Get("/{id}", repo_setting.EditProtectedTag)
+ m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.EditProtectedTagPost)
+ })
+
+ m.Group("/hooks/git", func() {
+ m.Get("", repo_setting.GitHooks)
+ m.Combo("/{name}").Get(repo_setting.GitHooksEdit).
+ Post(repo_setting.GitHooksEditPost)
+ }, context.GitHookService())
+
+ m.Group("/hooks", func() {
+ m.Get("", repo_setting.Webhooks)
+ m.Post("/delete", repo_setting.DeleteWebhook)
+ addWebhookAddRoutes()
+ m.Group("/{id}", func() {
+ m.Get("", repo_setting.WebHooksEdit)
+ m.Post("/test", repo_setting.TestWebhook)
+ m.Post("/replay/{uuid}", repo_setting.ReplayWebhook)
+ })
+ addWebhookEditRoutes()
+ }, webhooksEnabled)
+
+ m.Group("/keys", func() {
+ m.Combo("").Get(repo_setting.DeployKeys).
+ Post(web.Bind(forms.AddKeyForm{}), repo_setting.DeployKeysPost)
+ m.Post("/delete", repo_setting.DeleteDeployKey)
+ })
+
+ m.Group("/lfs", func() {
+ m.Get("/", repo_setting.LFSFiles)
+ m.Get("/show/{oid}", repo_setting.LFSFileGet)
+ m.Post("/delete/{oid}", repo_setting.LFSDelete)
+ m.Get("/pointers", repo_setting.LFSPointerFiles)
+ m.Post("/pointers/associate", repo_setting.LFSAutoAssociate)
+ m.Get("/find", repo_setting.LFSFileFind)
+ m.Group("/locks", func() {
+ m.Get("/", repo_setting.LFSLocks)
+ m.Post("/", repo_setting.LFSLockFile)
+ m.Post("/{lid}/unlock", repo_setting.LFSUnlock)
+ })
+ })
+ m.Group("/actions", func() {
+ m.Get("", repo_setting.RedirectToDefaultSetting)
+ addSettingsRunnersRoutes()
+ addSettingsSecretsRoutes()
+ addSettingsVariablesRoutes()
+ }, actions.MustEnableActions)
+ // the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
+ m.Group("/migrate", func() {
+ m.Post("/retry", repo.MigrateRetryPost)
+ m.Post("/cancel", repo.MigrateCancelPost)
+ })
+ },
+ reqSignIn, context.RepoAssignment, reqRepoAdmin, context.RepoRef(),
+ ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer),
+ )
+ // end "/{username}/{reponame}/settings"
+
+ // user/org home, including rss feeds
+ m.Get("/{username}/{reponame}", ignSignIn, context.RepoAssignment, context.RepoRef(), repo.SetEditorconfigIfExists, repo.Home)
m.Group("/{username}/{reponame}", func() {
- m.Group("/settings", func() {
- m.Group("", func() {
- m.Combo("").Get(repo_setting.Settings).
- Post(web.Bind(forms.RepoSettingForm{}), repo_setting.SettingsPost)
- }, repo_setting.SettingsCtxData)
- m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo_setting.SettingsAvatar)
- m.Post("/avatar/delete", repo_setting.SettingsDeleteAvatar)
-
- m.Group("/collaboration", func() {
- m.Combo("").Get(repo_setting.Collaboration).Post(repo_setting.CollaborationPost)
- m.Post("/access_mode", repo_setting.ChangeCollaborationAccessMode)
- m.Post("/delete", repo_setting.DeleteCollaboration)
- m.Group("/team", func() {
- m.Post("", repo_setting.AddTeamPost)
- m.Post("/delete", repo_setting.DeleteTeam)
- })
- })
-
- m.Group("/branches", func() {
- m.Post("/", repo_setting.SetDefaultBranchPost)
- }, repo.MustBeNotEmpty)
-
- m.Group("/branches", func() {
- m.Get("/", repo_setting.ProtectedBranchRules)
- m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch).
- Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost)
- m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost)
- }, repo.MustBeNotEmpty)
-
- m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost)
-
- m.Group("/tags", func() {
- m.Get("", repo_setting.ProtectedTags)
- m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.NewProtectedTagPost)
- m.Post("/delete", context.RepoMustNotBeArchived(), repo_setting.DeleteProtectedTagPost)
- m.Get("/{id}", repo_setting.EditProtectedTag)
- m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo_setting.EditProtectedTagPost)
- })
-
- m.Group("/hooks/git", func() {
- m.Get("", repo_setting.GitHooks)
- m.Combo("/{name}").Get(repo_setting.GitHooksEdit).
- Post(repo_setting.GitHooksEditPost)
- }, context.GitHookService())
-
- m.Group("/hooks", func() {
- m.Get("", repo_setting.Webhooks)
- m.Post("/delete", repo_setting.DeleteWebhook)
- addWebhookAddRoutes()
- m.Group("/{id}", func() {
- m.Get("", repo_setting.WebHooksEdit)
- m.Post("/test", repo_setting.TestWebhook)
- m.Post("/replay/{uuid}", repo_setting.ReplayWebhook)
- })
- addWebhookEditRoutes()
- }, webhooksEnabled)
-
- m.Group("/keys", func() {
- m.Combo("").Get(repo_setting.DeployKeys).
- Post(web.Bind(forms.AddKeyForm{}), repo_setting.DeployKeysPost)
- m.Post("/delete", repo_setting.DeleteDeployKey)
- })
-
- m.Group("/lfs", func() {
- m.Get("/", repo_setting.LFSFiles)
- m.Get("/show/{oid}", repo_setting.LFSFileGet)
- m.Post("/delete/{oid}", repo_setting.LFSDelete)
- m.Get("/pointers", repo_setting.LFSPointerFiles)
- m.Post("/pointers/associate", repo_setting.LFSAutoAssociate)
- m.Get("/find", repo_setting.LFSFileFind)
- m.Group("/locks", func() {
- m.Get("/", repo_setting.LFSLocks)
- m.Post("/", repo_setting.LFSLockFile)
- m.Post("/{lid}/unlock", repo_setting.LFSUnlock)
- })
- })
- m.Group("/actions", func() {
- m.Get("", repo_setting.RedirectToDefaultSetting)
- addSettingsRunnersRoutes()
- addSettingsSecretsRoutes()
- addSettingsVariablesRoutes()
- }, actions.MustEnableActions)
- // the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
- m.Group("/migrate", func() {
- m.Post("/retry", repo.MigrateRetryPost)
- m.Post("/cancel", repo.MigrateCancelPost)
- })
- }, ctxDataSet("PageIsRepoSettings", true, "LFSStartServer", setting.LFS.StartServer))
- }, reqSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoAdmin, context.RepoRef())
-
- m.Post("/{username}/{reponame}/action/{action}", reqSignIn, context.RepoAssignment, context.UnitTypes(), repo.Action)
-
- // Grouping for those endpoints not requiring authentication (but should respect ignSignIn)
- m.Group("/{username}/{reponame}", func() {
- m.Group("/milestone", func() {
- m.Get("/{id}", repo.MilestoneIssuesAndPulls)
- }, reqRepoIssuesOrPullsReader, context.RepoRef())
m.Get("/find/*", repo.FindFiles)
m.Group("/tree-list", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.TreeList)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList)
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList)
})
- m.Get("/compare", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists, ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
- m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
+ m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
+ m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
+ }, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
+ // end "/{username}/{reponame}": find, compare, list (code related)
+
+ m.Group("/{username}/{reponame}", func() {
+ m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because it would conflict with other routes like "/pulls/{index}"
+ m.Get("/pulls/posters", repo.PullPosters)
+ m.Get("/comments/{id}/attachments", repo.GetCommentAttachments)
+ m.Get("/labels", repo.RetrieveLabels, repo.Labels)
+ m.Get("/milestones", repo.Milestones)
+ m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls)
m.Group("/{type:issues|pulls}", func() {
m.Group("/{index}", func() {
m.Get("/info", repo.GetIssueInfo)
+ m.Get("/attachments", repo.GetIssueAttachments)
+ m.Get("/attachments/{uuid}", repo.GetAttachment)
+ m.Group("/content-history", func() {
+ m.Get("/overview", repo.GetContentHistoryOverview)
+ m.Get("/list", repo.GetContentHistoryList)
+ m.Get("/detail", repo.GetContentHistoryDetail)
+ })
+ })
+ }, context.RepoRef())
+ }, ignSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
+ // end "/{username}/{reponame}": view milestone, label, issue, pull, etc
+
+ m.Group("/{username}/{reponame}", func() {
+ m.Group("/{type:issues|pulls}", func() {
+ m.Get("", repo.Issues)
+ m.Group("/{index}", func() {
+ m.Get("", repo.ViewIssue)
})
})
- }, ignSignIn, context.RepoAssignment, context.UnitTypes()) // for "/{username}/{reponame}" which doesn't require authentication
+ }, ignSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests, unit.TypeExternalTracker))
+ // end "/{username}/{reponame}": issue/pull list, issue/pull view, external tracker
- // Grouping for those endpoints that do require authentication
- m.Group("/{username}/{reponame}", func() {
+ m.Group("/{username}/{reponame}", func() { // edit issues, pulls, labels, milestones, etc
m.Group("/issues", func() {
m.Group("/new", func() {
m.Combo("").Get(context.RepoRef(), repo.NewIssue).
@@ -1150,6 +1175,7 @@ func registerRoutes(m *web.Route) {
})
m.Get("/search", repo.ListIssues)
}, context.RepoMustNotBeArchived(), reqRepoIssueReader)
+
// FIXME: should use different URLs but mostly same logic for comments of issue and pull request.
// So they can apply their own enable/disable logic on routers.
m.Group("/{type:issues|pulls}", func() {
@@ -1179,10 +1205,7 @@ func registerRoutes(m *web.Route) {
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
m.Post("/delete", reqRepoAdmin, repo.DeleteIssue)
}, context.RepoMustNotBeArchived())
- m.Group("/{index}", func() {
- m.Get("/attachments", repo.GetIssueAttachments)
- m.Get("/attachments/{uuid}", repo.GetAttachment)
- })
+
m.Group("/{index}", func() {
m.Post("/content-history/soft-delete", repo.SoftDeleteContentHistory)
})
@@ -1191,25 +1214,25 @@ func registerRoutes(m *web.Route) {
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
- m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
+ m.Post("/request_review", repo.UpdatePullReviewRequest)
m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
- m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
+ m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
m.Post("/attachments", repo.UploadIssueAttachment)
m.Post("/attachments/remove", repo.DeleteAttachment)
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
}, context.RepoMustNotBeArchived())
+
m.Group("/comments/{id}", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction)
}, context.RepoMustNotBeArchived())
- m.Group("/comments/{id}", func() {
- m.Get("/attachments", repo.GetCommentAttachments)
- })
+
m.Post("/markup", web.Bind(structs.MarkupOption{}), misc.Markup)
+
m.Group("/labels", func() {
m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel)
@@ -1227,7 +1250,10 @@ func registerRoutes(m *web.Route) {
m.Group("/pull", func() {
m.Post("/{index}/target_branch", repo.UpdatePullRequestTarget)
}, context.RepoMustNotBeArchived())
+ }, reqSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
+ // end "/{username}/{reponame}": create or edit issues, pulls, labels, milestones
+ m.Group("/{username}/{reponame}", func() { // repo code
m.Group("", func() {
m.Group("", func() {
m.Combo("/_edit/*").Get(repo.EditFile).
@@ -1261,26 +1287,26 @@ func registerRoutes(m *web.Route) {
m.Post("/restore", repo.RestoreBranchPost)
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
- m.Combo("/fork", reqRepoCodeReader).Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
- }, reqSignIn, context.RepoAssignment, context.UnitTypes())
+ m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
+ }, reqSignIn, context.RepoAssignment, reqRepoCodeReader)
+ // end "/{username}/{reponame}": repo code
- // Tags
- m.Group("/{username}/{reponame}", func() {
+ m.Group("/{username}/{reponame}", func() { // repo tags
m.Group("/tags", func() {
m.Get("", repo.TagsList)
m.Get("/list", repo.GetTagList)
m.Get(".rss", feedEnabled, repo.TagsListFeedRSS)
m.Get(".atom", feedEnabled, repo.TagsListFeedAtom)
}, ctxDataSet("EnableFeed", setting.Other.EnableFeed),
- repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true))
+ repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, true))
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
- }, ignSignIn, context.RepoAssignment, context.UnitTypes())
+ }, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
+ // end "/{username}/{reponame}": repo tags
- // Releases
- m.Group("/{username}/{reponame}", func() {
+ m.Group("/{username}/{reponame}", func() { // repo releases
m.Group("/releases", func() {
- m.Get("/", repo.Releases)
+ m.Get("", repo.Releases)
m.Get("/tag/*", repo.SingleRelease)
m.Get("/latest", repo.LatestRelease)
m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS)
@@ -1300,148 +1326,141 @@ func registerRoutes(m *web.Route) {
m.Get("/edit/*", repo.EditRelease)
m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost)
}, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, repo.CommitInfoCache)
- }, ignSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoReleaseReader)
+ }, ignSignIn, context.RepoAssignment, reqRepoReleaseReader)
+ // end "/{username}/{reponame}": repo releases
- // to maintain compatibility with old attachments
- m.Group("/{username}/{reponame}", func() {
+ m.Group("/{username}/{reponame}", func() { // to maintain compatibility with old attachments
m.Get("/attachments/{uuid}", repo.GetAttachment)
- }, ignSignIn, context.RepoAssignment, context.UnitTypes())
+ }, ignSignIn, context.RepoAssignment)
+ // end "/{username}/{reponame}": compatibility with old attachments
m.Group("/{username}/{reponame}", func() {
m.Post("/topics", repo.TopicsPost)
- }, context.RepoAssignment, context.RepoMustNotBeArchived(), reqRepoAdmin)
+ }, context.RepoAssignment, reqRepoAdmin, context.RepoMustNotBeArchived())
m.Group("/{username}/{reponame}", func() {
- m.Group("", func() {
- m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because other routes like "/pulls/{index}" has higher priority
- m.Get("/{type:issues|pulls}", repo.Issues)
- m.Get("/{type:issues|pulls}/{index}", repo.ViewIssue)
- m.Group("/{type:issues|pulls}/{index}/content-history", func() {
- m.Get("/overview", repo.GetContentHistoryOverview)
- m.Get("/list", repo.GetContentHistoryList)
- m.Get("/detail", repo.GetContentHistoryDetail)
- })
- m.Get("/labels", reqRepoIssuesOrPullsReader, repo.RetrieveLabels, repo.Labels)
- m.Get("/milestones", reqRepoIssuesOrPullsReader, repo.Milestones)
- }, context.RepoRef())
-
if setting.Packages.Enabled {
m.Get("/packages", repo.Packages)
}
+ }, ignSignIn, context.RepoAssignment)
- m.Group("/projects", func() {
- m.Get("", repo.Projects)
- m.Get("/{id}", repo.ViewProject)
- m.Group("", func() { //nolint:dupl
- m.Get("/new", repo.RenderNewProject)
- m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost)
- m.Group("/{id}", func() {
- m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
- m.Post("/delete", repo.DeleteProject)
+ m.Group("/{username}/{reponame}/projects", func() {
+ m.Get("", repo.Projects)
+ m.Get("/{id}", repo.ViewProject)
+ m.Group("", func() { //nolint:dupl
+ m.Get("/new", repo.RenderNewProject)
+ m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost)
+ m.Group("/{id}", func() {
+ m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost)
+ m.Post("/delete", repo.DeleteProject)
- m.Get("/edit", repo.RenderEditProject)
- m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost)
- m.Post("/{action:open|close}", repo.ChangeProjectStatus)
+ m.Get("/edit", repo.RenderEditProject)
+ m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost)
+ m.Post("/{action:open|close}", repo.ChangeProjectStatus)
- m.Group("/{boardID}", func() {
- m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
- m.Delete("", repo.DeleteProjectBoard)
- m.Post("/default", repo.SetDefaultProjectBoard)
-
- m.Post("/move", repo.MoveIssues)
- })
+ m.Group("/{boardID}", func() {
+ m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard)
+ m.Delete("", repo.DeleteProjectBoard)
+ m.Post("/default", repo.SetDefaultProjectBoard)
+ m.Post("/move", repo.MoveIssues)
})
- }, reqRepoProjectsWriter, context.RepoMustNotBeArchived())
- }, reqRepoProjectsReader, repo.MustEnableRepoProjects)
+ })
+ }, reqRepoProjectsWriter, context.RepoMustNotBeArchived())
+ }, ignSignIn, context.RepoAssignment, reqRepoProjectsReader, repo.MustEnableRepoProjects)
+ // end "/{username}/{reponame}/projects"
- m.Group("/actions", func() {
- m.Get("", actions.List)
- m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
- m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
+ m.Group("/{username}/{reponame}/actions", func() {
+ m.Get("", actions.List)
+ m.Post("/disable", reqRepoAdmin, actions.DisableWorkflowFile)
+ m.Post("/enable", reqRepoAdmin, actions.EnableWorkflowFile)
- m.Group("/runs/{run}", func() {
+ m.Group("/runs/{run}", func() {
+ m.Combo("").
+ Get(actions.View).
+ Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
+ m.Group("/jobs/{job}", func() {
m.Combo("").
Get(actions.View).
Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
- m.Group("/jobs/{job}", func() {
- m.Combo("").
- Get(actions.View).
- Post(web.Bind(actions.ViewRequest{}), actions.ViewPost)
- m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
- m.Get("/logs", actions.Logs)
- })
- m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
- m.Post("/approve", reqRepoActionsWriter, actions.Approve)
- m.Get("/artifacts", actions.ArtifactsView)
- m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
- m.Delete("/artifacts/{artifact_name}", actions.ArtifactsDeleteView)
m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
+ m.Get("/logs", actions.Logs)
})
- m.Group("/workflows/{workflow_name}", func() {
- m.Get("/badge.svg", actions.GetWorkflowBadge)
- })
- }, reqRepoActionsReader, actions.MustEnableActions)
-
- m.Group("/wiki", func() {
- m.Combo("/").
- Get(repo.Wiki).
- Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
- m.Combo("/*").
- Get(repo.Wiki).
- Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
- m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
- m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
- }, repo.MustEnableWiki, func(ctx *context.Context) {
- ctx.Data["PageIsWiki"] = true
- ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
+ m.Post("/cancel", reqRepoActionsWriter, actions.Cancel)
+ m.Post("/approve", reqRepoActionsWriter, actions.Approve)
+ m.Get("/artifacts", actions.ArtifactsView)
+ m.Get("/artifacts/{artifact_name}", actions.ArtifactsDownloadView)
+ m.Delete("/artifacts/{artifact_name}", actions.ArtifactsDeleteView)
+ m.Post("/rerun", reqRepoActionsWriter, actions.Rerun)
})
+ m.Group("/workflows/{workflow_name}", func() {
+ m.Get("/badge.svg", actions.GetWorkflowBadge)
+ })
+ }, ignSignIn, context.RepoAssignment, reqRepoActionsReader, actions.MustEnableActions)
+ // end "/{username}/{reponame}/actions"
- m.Group("/wiki", func() {
- m.Get("/raw/*", repo.WikiRaw)
- }, repo.MustEnableWiki)
+ m.Group("/{username}/{reponame}/wiki", func() {
+ m.Combo("").
+ Get(repo.Wiki).
+ Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
+ m.Combo("/*").
+ Get(repo.Wiki).
+ Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
+ m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
+ m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
+ m.Get("/raw/*", repo.WikiRaw)
+ }, ignSignIn, context.RepoAssignment, repo.MustEnableWiki, reqRepoWikiReader, func(ctx *context.Context) {
+ ctx.Data["PageIsWiki"] = true
+ ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink()
+ })
+ // end "/{username}/{reponame}/wiki"
- m.Group("/activity", func() {
- m.Get("", repo.Activity)
- m.Get("/{period}", repo.Activity)
- m.Group("/contributors", func() {
- m.Get("", repo.Contributors)
- m.Get("/data", repo.ContributorsData)
- })
- m.Group("/code-frequency", func() {
- m.Get("", repo.CodeFrequency)
- m.Get("/data", repo.CodeFrequencyData)
- })
- m.Group("/recent-commits", func() {
- m.Get("", repo.RecentCommits)
- m.Get("/data", repo.RecentCommitsData)
- })
- }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases))
+ m.Group("/{username}/{reponame}/activity", func() {
+ m.Get("", repo.Activity)
+ m.Get("/{period}", repo.Activity)
+ m.Group("/contributors", func() {
+ m.Get("", repo.Contributors)
+ m.Get("/data", repo.ContributorsData)
+ })
+ m.Group("/code-frequency", func() {
+ m.Get("", repo.CodeFrequency)
+ m.Get("/data", repo.CodeFrequencyData)
+ })
+ m.Group("/recent-commits", func() {
+ m.Get("", repo.RecentCommits)
+ m.Get("/data", repo.RecentCommitsData)
+ })
+ },
+ ignSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases),
+ context.RepoRef(), repo.MustBeNotEmpty,
+ )
+ // end "/{username}/{reponame}/activity"
+ m.Group("/{username}/{reponame}", func() {
m.Group("/activity_author_data", func() {
m.Get("", repo.ActivityAuthors)
m.Get("/{period}", repo.ActivityAuthors)
- }, context.RepoRef(), repo.MustBeNotEmpty, context.RequireRepoReaderOr(unit.TypeCode))
+ }, context.RepoRef(), repo.MustBeNotEmpty)
m.Group("/archive", func() {
m.Get("/*", repo.Download)
m.Post("/*", repo.InitiateDownload)
- }, repo.MustBeNotEmpty, dlSourceEnabled, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty, dlSourceEnabled)
m.Group("/branches", func() {
m.Get("/list", repo.GetBranchesList)
m.Get("", repo.Branches)
- }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
+ }, repo.MustBeNotEmpty, context.RepoRef())
m.Group("/blob_excerpt", func() {
m.Get("/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
}, func(ctx *context.Context) gocontext.CancelFunc {
+ // FIXME: refactor this function, use separate routes for wiki/code
if ctx.FormBool("wiki") {
ctx.Data["PageIsWiki"] = true
repo.MustEnableWiki(ctx)
return nil
}
- reqRepoCodeReader(ctx)
if ctx.Written() {
return nil
}
@@ -1454,7 +1473,6 @@ func registerRoutes(m *web.Route) {
return cancel
})
- m.Get("/pulls/posters", repo.PullPosters)
m.Group("/pulls/{index}", func() {
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
m.Get(".diff", repo.DownloadPullDiff)
@@ -1488,7 +1506,7 @@ func registerRoutes(m *web.Route) {
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByIDOrLFS)
// "/*" route is deprecated, and kept for backward compatibility
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownloadOrLFS)
- }, repo.MustBeNotEmpty, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty)
m.Group("/raw", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownload)
@@ -1497,14 +1515,14 @@ func registerRoutes(m *web.Route) {
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByID)
// "/*" route is deprecated, and kept for backward compatibility
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
- }, repo.MustBeNotEmpty, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty)
m.Group("/render", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile)
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile)
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.RenderFile)
- }, repo.MustBeNotEmpty, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty)
m.Group("/commits", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
@@ -1512,20 +1530,20 @@ func registerRoutes(m *web.Route) {
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits)
// "/*" route is deprecated, and kept for backward compatibility
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.RefCommits)
- }, repo.MustBeNotEmpty, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty)
m.Group("/blame", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefBlame)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefBlame)
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefBlame)
- }, repo.MustBeNotEmpty, reqRepoCodeReader)
+ }, repo.MustBeNotEmpty)
m.Group("", func() {
m.Get("/graph", repo.Graph)
m.Get("/commit/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
m.Get("/commit/{sha:([a-f0-9]{7,64})$}/load-branches-and-tags", repo.LoadBranchesAndTags)
m.Get("/cherry-pick/{sha:([a-f0-9]{7,64})$}", repo.SetEditorconfigIfExists, repo.CherryPick)
- }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
+ }, repo.MustBeNotEmpty, context.RepoRef())
m.Get("/rss/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
m.Get("/atom/branch/*", context.RepoRefByType(context.RepoRefBranch), feedEnabled, feed.RenderBranchFeed)
@@ -1534,51 +1552,42 @@ func registerRoutes(m *web.Route) {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.Home)
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.Home)
- // "/*" route is deprecated, and kept for backward compatibility
- m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home)
+ m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.Home) // "/*" route is deprecated, and kept for backward compatibility
}, repo.SetEditorconfigIfExists)
- m.Group("", func() {
- m.Get("/forks", repo.Forks)
- }, context.RepoRef(), reqRepoCodeReader)
- m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
- }, ignSignIn, context.RepoAssignment, context.UnitTypes())
-
- m.Post("/{username}/{reponame}/lastcommit/*", ignSignInAndCsrf, context.RepoAssignment, context.UnitTypes(), context.RepoRefByType(context.RepoRefCommit), reqRepoCodeReader, repo.LastCommit)
+ m.Get("/forks", context.RepoRef(), repo.Forks)
+ m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff)
+ m.Post("/lastcommit/*", context.RepoRefByType(context.RepoRefCommit), repo.LastCommit)
+ }, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
+ // end "/{username}/{reponame}": repo code
m.Group("/{username}/{reponame}", func() {
m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers)
m.Get("/search", reqRepoCodeReader, repo.Search)
- }, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes())
+ m.Post("/action/{action}", reqSignIn, repo.Action)
+ }, ignSignIn, context.RepoAssignment, context.RepoRef())
- m.Group("/{username}", func() {
- m.Group("/{reponame}", func() {
- m.Get("", repo.SetEditorconfigIfExists, repo.Home)
- }, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes())
-
- m.Group("/{reponame}", func() {
- m.Group("/info/lfs", func() {
- m.Post("/objects/batch", lfs.CheckAcceptMediaType, lfs.BatchHandler)
- m.Put("/objects/{oid}/{size}", lfs.UploadHandler)
- m.Get("/objects/{oid}/{filename}", lfs.DownloadHandler)
- m.Get("/objects/{oid}", lfs.DownloadHandler)
- m.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler)
- m.Group("/locks", func() {
- m.Get("/", lfs.GetListLockHandler)
- m.Post("/", lfs.PostLockHandler)
- m.Post("/verify", lfs.VerifyLockHandler)
- m.Post("/{lid}/unlock", lfs.UnLockHandler)
- }, lfs.CheckAcceptMediaType)
- m.Any("/*", func(ctx *context.Context) {
- ctx.NotFound("", nil)
- })
- }, ignSignInAndCsrf, lfsServerEnabled)
-
- gitHTTPRouters(m)
- })
+ m.Group("/{username}/{reponame}", func() {
+ m.Group("/info/lfs", func() {
+ m.Post("/objects/batch", lfs.CheckAcceptMediaType, lfs.BatchHandler)
+ m.Put("/objects/{oid}/{size}", lfs.UploadHandler)
+ m.Get("/objects/{oid}/{filename}", lfs.DownloadHandler)
+ m.Get("/objects/{oid}", lfs.DownloadHandler)
+ m.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler)
+ m.Group("/locks", func() {
+ m.Get("/", lfs.GetListLockHandler)
+ m.Post("/", lfs.PostLockHandler)
+ m.Post("/verify", lfs.VerifyLockHandler)
+ m.Post("/{lid}/unlock", lfs.UnLockHandler)
+ }, lfs.CheckAcceptMediaType)
+ m.Any("/*", func(ctx *context.Context) {
+ ctx.NotFound("", nil)
+ })
+ }, ignSignInAndCsrf, lfsServerEnabled)
+ gitHTTPRouters(m)
})
- // ***** END: Repository *****
+ // end "/{username}/{reponame}.git": git support
m.Group("/notifications", func() {
m.Get("", user.Notifications)
@@ -1601,6 +1610,7 @@ func registerRoutes(m *web.Route) {
m.NotFound(func(w http.ResponseWriter, req *http.Request) {
ctx := context.GetWebContext(req)
+ routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "GlobalNotFound"))
ctx.NotFound("", nil)
})
}
diff --git a/services/actions/auth_test.go b/services/actions/auth_test.go
index f73ae8ae4c..12db2bae56 100644
--- a/services/actions/auth_test.go
+++ b/services/actions/auth_test.go
@@ -20,7 +20,7 @@ func TestCreateAuthorizationToken(t *testing.T) {
assert.Nil(t, err)
assert.NotEqual(t, "", token)
claims := jwt.MapClaims{}
- _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
+ _, err = jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (any, error) {
return setting.GetGeneralTokenSigningSecret(), nil
})
assert.Nil(t, err)
diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go
index 4236553927..eb031511f6 100644
--- a/services/actions/commit_status.go
+++ b/services/actions/commit_status.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
+ commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"
"github.com/nektos/act/pkg/jobparser"
)
@@ -122,18 +123,13 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
if err != nil {
return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
}
- if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
- Repo: repo,
- SHA: commitID,
- Creator: creator,
- CommitStatus: &git_model.CommitStatus{
- SHA: sha,
- TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
- Description: description,
- Context: ctxname,
- CreatorID: creator.ID,
- State: state,
- },
+ if err := commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &git_model.CommitStatus{
+ SHA: sha,
+ TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
+ Description: description,
+ Context: ctxname,
+ CreatorID: creator.ID,
+ State: state,
}); err != nil {
return fmt.Errorf("NewCommitStatus: %w", err)
}
diff --git a/services/actions/notifier.go b/services/actions/notifier.go
index eec5f814da..6551da39e7 100644
--- a/services/actions/notifier.go
+++ b/services/actions/notifier.go
@@ -49,7 +49,7 @@ func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{
Action: api.HookIssueOpened,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, issue.Poster, nil),
}).Notify(withMethod(ctx, "NewIssue"))
@@ -89,7 +89,7 @@ func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_mod
WithPayload(&api.IssuePayload{
Action: api.HookIssueEdited,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
}).
@@ -127,7 +127,7 @@ func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
}
apiIssue := &api.IssuePayload{
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
}
@@ -229,7 +229,7 @@ func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues
WithPayload(&api.IssuePayload{
Action: action,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
}).
@@ -293,7 +293,7 @@ func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, commen
payload := &api.IssueCommentPayload{
Action: action,
- Issue: convert.ToAPIIssue(ctx, comment.Issue),
+ Issue: convert.ToAPIIssue(ctx, doer, comment.Issue),
Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment),
Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 8c98f56af5..c48886a824 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -525,12 +525,9 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository)
}
// We need a notifyInput to call handleSchedules
- // Here we use the commit author as the Doer of the notifyInput
- commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email)
- if err != nil {
- return fmt.Errorf("get user by email: %w", err)
- }
- notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule)
+ // if repo is a mirror, commit author maybe an external user,
+ // so we use action user as the Doer of the notifyInput
+ notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule)
return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch)
}
diff --git a/services/agit/agit.go b/services/agit/agit.go
index eb3bafa906..52a70469e0 100644
--- a/services/agit/agit.go
+++ b/services/agit/agit.go
@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
+ "code.gitea.io/gitea/modules/setting"
notify_service "code.gitea.io/gitea/services/notify"
pull_service "code.gitea.io/gitea/services/pull"
)
@@ -145,10 +146,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
results = append(results, private.HookProcReceiveRefResult{
- Ref: pr.GetGitRefName(),
- OriginalRef: opts.RefFullNames[i],
- OldOID: objectFormat.EmptyObjectID().String(),
- NewOID: opts.NewCommitIDs[i],
+ Ref: pr.GetGitRefName(),
+ OriginalRef: opts.RefFullNames[i],
+ OldOID: objectFormat.EmptyObjectID().String(),
+ NewOID: opts.NewCommitIDs[i],
+ IsCreatePR: true,
+ URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
+ ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx),
+ HeadBranch: headBranch,
})
continue
}
@@ -208,11 +213,14 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
isForcePush := comment != nil && comment.IsForcePush
results = append(results, private.HookProcReceiveRefResult{
- OldOID: oldCommitID,
- NewOID: opts.NewCommitIDs[i],
- Ref: pr.GetGitRefName(),
- OriginalRef: opts.RefFullNames[i],
- IsForcePush: isForcePush,
+ OldOID: oldCommitID,
+ NewOID: opts.NewCommitIDs[i],
+ Ref: pr.GetGitRefName(),
+ OriginalRef: opts.RefFullNames[i],
+ IsForcePush: isForcePush,
+ IsCreatePR: false,
+ URL: fmt.Sprintf("%s/pulls/%d", repo.HTMLURL(), pr.Index),
+ ShouldShowMessage: setting.Git.PullRequestPushMessage && repo.AllowsPulls(ctx),
})
}
diff --git a/services/auth/source/oauth2/store.go b/services/auth/source/oauth2/store.go
index 394bf99463..90fa965602 100644
--- a/services/auth/source/oauth2/store.go
+++ b/services/auth/source/oauth2/store.go
@@ -9,6 +9,7 @@ import (
"net/http"
"code.gitea.io/gitea/modules/log"
+ session_module "code.gitea.io/gitea/modules/session"
chiSession "gitea.com/go-chi/session"
"github.com/gorilla/sessions"
@@ -65,7 +66,7 @@ func (st *SessionsStore) Save(r *http.Request, w http.ResponseWriter, session *s
chiStore := chiSession.GetSession(r)
if session.IsNew {
- _, _ = chiSession.RegenerateSession(w, r)
+ _, _ = session_module.RegenerateSession(w, r)
session.IsNew = false
}
diff --git a/services/context/api.go b/services/context/api.go
index b18a206b5e..c684add297 100644
--- a/services/context/api.go
+++ b/services/context/api.go
@@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- mc "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
@@ -21,15 +21,13 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
web_types "code.gitea.io/gitea/modules/web/types"
-
- "gitea.com/go-chi/cache"
)
// APIContext is a specific context for API service
type APIContext struct {
*Base
- Cache cache.Cache
+ Cache cache.StringCache
Doer *user_model.User // current signed-in user
IsSigned bool
@@ -217,7 +215,7 @@ func APIContexter() func(http.Handler) http.Handler {
base, baseCleanUp := NewBaseContext(w, req)
ctx := &APIContext{
Base: base,
- Cache: mc.GetCache(),
+ Cache: cache.GetCache(),
Repo: &Repository{PullRequest: &PullRequest{}},
Org: &APIOrganization{},
}
diff --git a/services/context/captcha.go b/services/context/captcha.go
index a1999900c9..41afe0e7d2 100644
--- a/services/context/captcha.go
+++ b/services/context/captcha.go
@@ -30,7 +30,7 @@ func GetImageCaptcha() *captcha.Captcha {
cpt = captcha.NewCaptcha(captcha.Options{
SubURL: setting.AppSubURL,
})
- cpt.Store = cache.GetCache()
+ cpt.Store = cache.GetCache().ChiCache()
})
return cpt
}
@@ -79,11 +79,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) {
case setting.CfTurnstile:
valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
default:
- ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
+ ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType))
return
}
if err != nil {
- log.Debug("%v", err)
+ log.Debug("Captcha Verify failed: %v", err)
}
if !valid {
diff --git a/services/context/context.go b/services/context/context.go
index 4b318f7e33..1641e995fb 100644
--- a/services/context/context.go
+++ b/services/context/context.go
@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
- mc "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/setting"
@@ -27,7 +27,6 @@ import (
"code.gitea.io/gitea/modules/web/middleware"
web_types "code.gitea.io/gitea/modules/web/types"
- "gitea.com/go-chi/cache"
"gitea.com/go-chi/session"
)
@@ -46,7 +45,7 @@ type Context struct {
Render Render
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
- Cache cache.Cache
+ Cache cache.StringCache
Csrf CSRFProtector
Flash *middleware.Flash
Session session.Store
@@ -102,6 +101,19 @@ func NewTemplateContextForWeb(ctx *Context) TemplateContext {
tmplCtx := NewTemplateContext(ctx)
tmplCtx["Locale"] = ctx.Base.Locale
tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx)
+ tmplCtx["RootData"] = ctx.Data
+ tmplCtx["Consts"] = map[string]any{
+ "RepoUnitTypeCode": unit.TypeCode,
+ "RepoUnitTypeIssues": unit.TypeIssues,
+ "RepoUnitTypePullRequests": unit.TypePullRequests,
+ "RepoUnitTypeReleases": unit.TypeReleases,
+ "RepoUnitTypeWiki": unit.TypeWiki,
+ "RepoUnitTypeExternalWiki": unit.TypeExternalWiki,
+ "RepoUnitTypeExternalTracker": unit.TypeExternalTracker,
+ "RepoUnitTypeProjects": unit.TypeProjects,
+ "RepoUnitTypePackages": unit.TypePackages,
+ "RepoUnitTypeActions": unit.TypeActions,
+ }
return tmplCtx
}
@@ -111,7 +123,7 @@ func NewWebContext(base *Base, render Render, session session.Store) *Context {
Render: render,
Session: session,
- Cache: mc.GetCache(),
+ Cache: cache.GetCache(),
Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"),
Repo: &Repository{PullRequest: &PullRequest{}},
Org: &Organization{},
diff --git a/services/context/repo.go b/services/context/repo.go
index 56e9fada0e..1f4c698afc 100644
--- a/services/context/repo.go
+++ b/services/context/repo.go
@@ -383,7 +383,6 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
ctx.NotFound("no access right", nil)
return
}
- ctx.Data["HasAccess"] = true
ctx.Data["Permission"] = &ctx.Repo.Permission
if repo.IsMirror {
@@ -1052,19 +1051,3 @@ func GitHookService() func(ctx *Context) {
}
}
}
-
-// UnitTypes returns a middleware to set unit types to context variables.
-func UnitTypes() func(ctx *Context) {
- return func(ctx *Context) {
- ctx.Data["UnitTypeCode"] = unit_model.TypeCode
- ctx.Data["UnitTypeIssues"] = unit_model.TypeIssues
- ctx.Data["UnitTypePullRequests"] = unit_model.TypePullRequests
- ctx.Data["UnitTypeReleases"] = unit_model.TypeReleases
- ctx.Data["UnitTypeWiki"] = unit_model.TypeWiki
- ctx.Data["UnitTypeExternalWiki"] = unit_model.TypeExternalWiki
- ctx.Data["UnitTypeExternalTracker"] = unit_model.TypeExternalTracker
- ctx.Data["UnitTypeProjects"] = unit_model.TypeProjects
- ctx.Data["UnitTypePackages"] = unit_model.TypePackages
- ctx.Data["UnitTypeActions"] = unit_model.TypeActions
- }
-}
diff --git a/services/convert/convert.go b/services/convert/convert.go
index b51db0ea34..a0c7259ec0 100644
--- a/services/convert/convert.go
+++ b/services/convert/convert.go
@@ -22,6 +22,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/git"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
@@ -106,33 +107,46 @@ func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName strin
return branch, nil
}
+// getWhitelistEntities returns the names of the entities that are in the whitelist
+func getWhitelistEntities[T *user_model.User | *organization.Team](entities []T, whitelistIDs []int64) []string {
+ whitelistUserIDsSet := container.SetOf(whitelistIDs...)
+ whitelistNames := make([]string, 0)
+ for _, entity := range entities {
+ switch v := any(entity).(type) {
+ case *user_model.User:
+ if whitelistUserIDsSet.Contains(v.ID) {
+ whitelistNames = append(whitelistNames, v.Name)
+ }
+ case *organization.Team:
+ if whitelistUserIDsSet.Contains(v.ID) {
+ whitelistNames = append(whitelistNames, v.Name)
+ }
+ }
+ }
+
+ return whitelistNames
+}
+
// ToBranchProtection convert a ProtectedBranch to api.BranchProtection
-func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api.BranchProtection {
- pushWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.WhitelistUserIDs)
+func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo *repo_model.Repository) *api.BranchProtection {
+ readers, err := access_model.GetRepoReaders(ctx, repo)
if err != nil {
- log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
+ log.Error("GetRepoReaders: %v", err)
}
- mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.MergeWhitelistUserIDs)
+
+ pushWhitelistUsernames := getWhitelistEntities(readers, bp.WhitelistUserIDs)
+ mergeWhitelistUsernames := getWhitelistEntities(readers, bp.MergeWhitelistUserIDs)
+ approvalsWhitelistUsernames := getWhitelistEntities(readers, bp.ApprovalsWhitelistUserIDs)
+
+ teamReaders, err := organization.OrgFromUser(repo.Owner).TeamsWithAccessToRepo(ctx, repo.ID, perm.AccessModeRead)
if err != nil {
- log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
- }
- approvalsWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.ApprovalsWhitelistUserIDs)
- if err != nil {
- log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err)
- }
- pushWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.WhitelistTeamIDs)
- if err != nil {
- log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
- }
- mergeWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.MergeWhitelistTeamIDs)
- if err != nil {
- log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
- }
- approvalsWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.ApprovalsWhitelistTeamIDs)
- if err != nil {
- log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err)
+ log.Error("Repo.Owner.TeamsWithAccessToRepo: %v", err)
}
+ pushWhitelistTeams := getWhitelistEntities(teamReaders, bp.WhitelistTeamIDs)
+ mergeWhitelistTeams := getWhitelistEntities(teamReaders, bp.MergeWhitelistTeamIDs)
+ approvalsWhitelistTeams := getWhitelistEntities(teamReaders, bp.ApprovalsWhitelistTeamIDs)
+
branchName := ""
if !git_model.IsRuleNameSpecial(bp.RuleName) {
branchName = bp.RuleName
@@ -346,7 +360,7 @@ func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]
Description: t.Description,
IncludesAllRepositories: t.IncludesAllRepositories,
CanCreateOrgRepo: t.CanCreateOrgRepo,
- Permission: t.AccessMode.String(),
+ Permission: t.AccessMode.ToString(),
Units: t.GetUnitNames(),
UnitsMap: t.GetUnitsMap(),
}
diff --git a/services/convert/issue.go b/services/convert/issue.go
index c6e06180c8..54b00cd88e 100644
--- a/services/convert/issue.go
+++ b/services/convert/issue.go
@@ -18,19 +18,19 @@ import (
api "code.gitea.io/gitea/modules/structs"
)
-func ToIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
- return toIssue(ctx, issue, WebAssetDownloadURL)
+func ToIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue {
+ return toIssue(ctx, doer, issue, WebAssetDownloadURL)
}
// ToAPIIssue converts an Issue to API format
// it assumes some fields assigned with values:
// Required - Poster, Labels,
// Optional - Milestone, Assignee, PullRequest
-func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue {
- return toIssue(ctx, issue, APIAssetDownloadURL)
+func ToAPIIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue {
+ return toIssue(ctx, doer, issue, APIAssetDownloadURL)
}
-func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue {
+func toIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue {
if err := issue.LoadLabels(ctx); err != nil {
return &api.Issue{}
}
@@ -44,7 +44,7 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func
apiIssue := &api.Issue{
ID: issue.ID,
Index: issue.Index,
- Poster: ToUser(ctx, issue.Poster, nil),
+ Poster: ToUser(ctx, issue.Poster, doer),
Title: issue.Title,
Body: issue.Content,
Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL),
@@ -114,25 +114,25 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func
}
// ToIssueList converts an IssueList to API format
-func ToIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
+func ToIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue {
result := make([]*api.Issue, len(il))
for i := range il {
- result[i] = ToIssue(ctx, il[i])
+ result[i] = ToIssue(ctx, doer, il[i])
}
return result
}
// ToAPIIssueList converts an IssueList to API format
-func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue {
+func ToAPIIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue {
result := make([]*api.Issue, len(il))
for i := range il {
- result[i] = ToAPIIssue(ctx, il[i])
+ result[i] = ToAPIIssue(ctx, doer, il[i])
}
return result
}
// ToTrackedTime converts TrackedTime to API format
-func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
+func ToTrackedTime(ctx context.Context, doer *user_model.User, t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
apiT = &api.TrackedTime{
ID: t.ID,
IssueID: t.IssueID,
@@ -141,7 +141,7 @@ func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.
Created: t.Created,
}
if t.Issue != nil {
- apiT.Issue = ToAPIIssue(ctx, t.Issue)
+ apiT.Issue = ToAPIIssue(ctx, doer, t.Issue)
}
if t.User != nil {
apiT.UserName = t.User.Name
@@ -192,10 +192,10 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop
}
// ToTrackedTimeList converts TrackedTimeList to API format
-func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList {
+func ToTrackedTimeList(ctx context.Context, doer *user_model.User, tl issues_model.TrackedTimeList) api.TrackedTimeList {
result := make([]*api.TrackedTime, 0, len(tl))
for _, t := range tl {
- result = append(result, ToTrackedTime(ctx, t))
+ result = append(result, ToTrackedTime(ctx, doer, t))
}
return result
}
diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go
index b034a50897..9ffaf1e84c 100644
--- a/services/convert/issue_comment.go
+++ b/services/convert/issue_comment.go
@@ -120,7 +120,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
return nil
}
- comment.TrackedTime = ToTrackedTime(ctx, c.Time)
+ comment.TrackedTime = ToTrackedTime(ctx, doer, c.Time)
}
if c.RefIssueID != 0 {
@@ -129,7 +129,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
log.Error("GetIssueByID(%d): %v", c.RefIssueID, err)
return nil
}
- comment.RefIssue = ToAPIIssue(ctx, issue)
+ comment.RefIssue = ToAPIIssue(ctx, doer, issue)
}
if c.RefCommentID != 0 {
@@ -180,7 +180,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu
}
if c.DependentIssue != nil {
- comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue)
+ comment.DependentIssue = ToAPIIssue(ctx, doer, c.DependentIssue)
}
return comment
diff --git a/services/convert/pull.go b/services/convert/pull.go
index 6d98121ed5..775bf3806d 100644
--- a/services/convert/pull.go
+++ b/services/convert/pull.go
@@ -33,7 +33,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u
return nil
}
- apiIssue := ToAPIIssue(ctx, pr.Issue)
+ apiIssue := ToAPIIssue(ctx, doer, pr.Issue)
if err := pr.LoadBaseRepo(ctx); err != nil {
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
return nil
diff --git a/services/convert/repository.go b/services/convert/repository.go
index 39efd304a9..3b293fe550 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -25,12 +25,13 @@ func ToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo a
func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission, isParent bool) *api.Repository {
var parent *api.Repository
- if permissionInRepo.Units == nil && permissionInRepo.UnitsMode == nil {
- // If Units and UnitsMode are both nil, it means that it's a hard coded permission,
- // like access_model.Permission{AccessMode: perm.AccessModeAdmin}.
- // So we need to load units for the repo, or UnitAccessMode will always return perm.AccessModeNone.
+ if !permissionInRepo.HasUnits() && permissionInRepo.AccessMode > perm.AccessModeNone {
+ // If units is empty, it means that it's a hard-coded permission, like access_model.Permission{AccessMode: perm.AccessModeAdmin}
+ // So we need to load units for the repo, otherwise UnitAccessMode will just return perm.AccessModeNone.
+ // TODO: this logic is still not right (because unit modes are not correctly prepared)
+ // the caller should prepare a proper "permission" before calling this function.
_ = repo.LoadUnits(ctx) // the error is not important, so ignore it
- permissionInRepo.Units = repo.Units
+ permissionInRepo.SetUnitsWithDefaultAccessMode(repo.Units, permissionInRepo.AccessMode)
}
cloneLink := repo.CloneLink()
diff --git a/services/convert/user.go b/services/convert/user.go
index 3521dd2f90..2957c58b14 100644
--- a/services/convert/user.go
+++ b/services/convert/user.go
@@ -75,6 +75,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap
if authed {
result.IsAdmin = user.IsAdmin
result.LoginName = user.LoginName
+ result.SourceID = user.LoginSource
result.LastLogin = user.LastLoginUnix.AsTime()
result.Language = user.Language
result.IsActive = user.IsActive
@@ -102,7 +103,7 @@ func User2UserSettings(user *user_model.User) api.UserSettings {
func ToUserAndPermission(ctx context.Context, user, doer *user_model.User, accessMode perm.AccessMode) api.RepoCollaboratorPermission {
return api.RepoCollaboratorPermission{
User: ToUser(ctx, user, doer),
- Permission: accessMode.String(),
- RoleName: accessMode.String(),
+ Permission: accessMode.ToString(),
+ RoleName: accessMode.ToString(),
}
}
diff --git a/services/doctor/dbconsistency.go b/services/doctor/dbconsistency.go
index e2dcb63f33..dfdf7b547a 100644
--- a/services/doctor/dbconsistency.go
+++ b/services/doctor/dbconsistency.go
@@ -61,26 +61,20 @@ func asFixer(fn func(ctx context.Context) error) func(ctx context.Context) (int6
}
}
-func genericOrphanCheck(name, subject, refobject, joincond string) consistencyCheck {
+func genericOrphanCheck(name, subject, refObject, joinCond string) consistencyCheck {
return consistencyCheck{
Name: name,
Counter: func(ctx context.Context) (int64, error) {
- return db.CountOrphanedObjects(ctx, subject, refobject, joincond)
+ return db.CountOrphanedObjects(ctx, subject, refObject, joinCond)
},
Fixer: func(ctx context.Context) (int64, error) {
- err := db.DeleteOrphanedObjects(ctx, subject, refobject, joincond)
+ err := db.DeleteOrphanedObjects(ctx, subject, refObject, joinCond)
return -1, err
},
}
}
-func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) error {
- // make sure DB version is uptodate
- if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil {
- logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
- return err
- }
-
+func prepareDBConsistencyChecks() []consistencyCheck {
consistencyChecks := []consistencyCheck{
{
// find labels without existing repo or org
@@ -210,7 +204,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
"oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"),
// find OAuth2Application without existing user
genericOrphanCheck("Orphaned OAuth2Application without existing User",
- "oauth2_application", "user", "oauth2_application.uid=`user`.id"),
+ "oauth2_application", "user", "oauth2_application.uid=0 OR oauth2_application.uid=`user`.id"),
// find OAuth2AuthorizationCode without existing OAuth2Grant
genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant",
"oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"),
@@ -224,7 +218,16 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
genericOrphanCheck("Orphaned Redirects without existing redirect user",
"user_redirect", "user", "user_redirect.redirect_user_id=`user`.id"),
)
+ return consistencyChecks
+}
+func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) error {
+ // make sure DB version is uptodate
+ if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil {
+ logger.Critical("Model version on the database does not match the current Gitea version. Model consistency will not be checked until the database is upgraded")
+ return err
+ }
+ consistencyChecks := prepareDBConsistencyChecks()
for _, c := range consistencyChecks {
if err := c.Run(ctx, logger, autofix); err != nil {
return err
diff --git a/services/doctor/dbconsistency_test.go b/services/doctor/dbconsistency_test.go
new file mode 100644
index 0000000000..4e4ac535b7
--- /dev/null
+++ b/services/doctor/dbconsistency_test.go
@@ -0,0 +1,51 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package doctor
+
+import (
+ "slices"
+ "testing"
+
+ "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/log"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestConsistencyCheck(t *testing.T) {
+ checks := prepareDBConsistencyChecks()
+ idx := slices.IndexFunc(checks, func(check consistencyCheck) bool {
+ return check.Name == "Orphaned OAuth2Application without existing User"
+ })
+ if !assert.NotEqual(t, -1, idx) {
+ return
+ }
+
+ _ = db.TruncateBeans(db.DefaultContext, &auth.OAuth2Application{}, &user.User{})
+ _ = db.TruncateBeans(db.DefaultContext, &auth.OAuth2Application{}, &auth.OAuth2Application{})
+
+ err := db.Insert(db.DefaultContext, &user.User{ID: 1})
+ assert.NoError(t, err)
+ err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-1", ClientID: "client-id-1"})
+ assert.NoError(t, err)
+ err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-2", ClientID: "client-id-2", UID: 1})
+ assert.NoError(t, err)
+ err = db.Insert(db.DefaultContext, &auth.OAuth2Application{Name: "test-oauth2-app-3", ClientID: "client-id-3", UID: 99999999})
+ assert.NoError(t, err)
+
+ unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-1"})
+ unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-2"})
+ unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-3"})
+
+ oauth2AppCheck := checks[idx]
+ err = oauth2AppCheck.Run(db.DefaultContext, log.GetManager().GetLogger(log.DEFAULT), true)
+ assert.NoError(t, err)
+
+ unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-1"})
+ unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ClientID: "client-id-2"})
+ unittest.AssertNotExistsBean(t, &auth.OAuth2Application{ClientID: "client-id-3"})
+}
diff --git a/services/doctor/doctor.go b/services/doctor/doctor.go
index 559f8e06da..a4eb5e16b9 100644
--- a/services/doctor/doctor.go
+++ b/services/doctor/doctor.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/storage"
)
// Check represents a Doctor check
@@ -25,6 +26,7 @@ type Check struct {
AbortIfFailed bool
SkipDatabaseInitialization bool
Priority int
+ InitStorage bool
}
func initDBSkipLogger(ctx context.Context) error {
@@ -84,6 +86,7 @@ func RunChecks(ctx context.Context, colorize, autofix bool, checks []*Check) err
logger := log.BaseLoggerToGeneralLogger(&doctorCheckLogger{colorize: colorize})
loggerStep := log.BaseLoggerToGeneralLogger(&doctorCheckStepLogger{colorize: colorize})
dbIsInit := false
+ storageIsInit := false
for i, check := range checks {
if !dbIsInit && !check.SkipDatabaseInitialization {
// Only open database after the most basic configuration check
@@ -94,6 +97,14 @@ func RunChecks(ctx context.Context, colorize, autofix bool, checks []*Check) err
}
dbIsInit = true
}
+ if !storageIsInit && check.InitStorage {
+ if err := storage.Init(); err != nil {
+ logger.Error("Error whilst initializing the storage: %v", err)
+ logger.Error("Check if you are using the right config file. You can use a --config directive to specify one.")
+ return nil
+ }
+ storageIsInit = true
+ }
logger.Info("\n[%d] %s", i+1, check.Title)
if err := check.Run(ctx, loggerStep, autofix); err != nil {
if check.AbortIfFailed {
diff --git a/services/doctor/main_test.go b/services/doctor/main_test.go
new file mode 100644
index 0000000000..0f365e21d0
--- /dev/null
+++ b/services/doctor/main_test.go
@@ -0,0 +1,14 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package doctor
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/unittest"
+)
+
+func TestMain(m *testing.M) {
+ unittest.MainTest(m)
+}
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index e45a2a1695..f49cc2e86b 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -134,6 +134,7 @@ type RepoSettingForm struct {
EnableWiki bool
EnableExternalWiki bool
DefaultWikiBranch string
+ DefaultWikiEveryoneAccess string
ExternalWikiURL string
EnableIssues bool
EnableExternalTracker bool
diff --git a/services/issue/pull.go b/services/issue/pull.go
index b7b63a7024..4a0009e82f 100644
--- a/services/issue/pull.go
+++ b/services/issue/pull.go
@@ -51,14 +51,14 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue,
return nil, err
}
- if pr.HeadRepo.IsFork {
- return nil, nil
- }
-
if err := pr.LoadBaseRepo(ctx); err != nil {
return nil, err
}
+ if pr.BaseRepo.IsFork {
+ return nil, nil
+ }
+
repo, err := gitrepo.OpenRepository(ctx, pr.BaseRepo)
if err != nil {
return nil, err
diff --git a/services/markup/processorhelper_codepreview_test.go b/services/markup/processorhelper_codepreview_test.go
index 01db792925..154e4e8e44 100644
--- a/services/markup/processorhelper_codepreview_test.go
+++ b/services/markup/processorhelper_codepreview_test.go
@@ -36,10 +36,10 @@ func TestProcessorHelperCodePreview(t *testing.T) {
@@ -63,7 +63,7 @@ func TestProcessorHelperCodePreview(t *testing.T) {
diff --git a/services/migrations/gitbucket.go b/services/migrations/gitbucket.go
index 5f11555839..4fe9e30a39 100644
--- a/services/migrations/gitbucket.go
+++ b/services/migrations/gitbucket.go
@@ -72,6 +72,11 @@ func (g *GitBucketDownloader) LogString() string {
// NewGitBucketDownloader creates a GitBucket downloader
func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader {
githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName)
+ // Gitbucket 4.40 uses different internal hard-coded perPage values.
+ // Issues, PRs, and other major parts use 25. Release page uses 10.
+ // Some API doesn't support paging yet. Sounds difficult, but using
+ // minimum number among them worked out very well.
+ githubDownloader.maxPerPage = 10
githubDownloader.SkipReactions = true
githubDownloader.SkipReviews = true
return &GitBucketDownloader{
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 2a38d4ba55..fa23986c54 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -13,6 +13,7 @@ import (
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
+ giturl "code.gitea.io/gitea/modules/git/url"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
@@ -30,10 +31,15 @@ const gitShortEmptySha = "0000000"
// UpdateAddress writes new address to Git repository and database
func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error {
+ u, err := giturl.Parse(addr)
+ if err != nil {
+ return fmt.Errorf("invalid addr: %v", err)
+ }
+
remoteName := m.GetRemoteName()
repoPath := m.GetRepository(ctx).RepoPath()
// Remove old remote
- _, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
+ _, _, err = git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
return err
}
@@ -70,7 +76,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error
}
}
- m.Repo.OriginalURL = addr
+ // erase authentication before storing in database
+ u.User = nil
+ m.Repo.OriginalURL = u.String()
return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url")
}
@@ -449,19 +457,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
return false
}
- var gitRepo *git.Repository
- if len(results) == 0 {
- log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo)
- } else {
- log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
- gitRepo, err = gitrepo.OpenRepository(ctx, m.Repo)
- if err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
- return false
- }
- defer gitRepo.Close()
+ gitRepo, err := gitrepo.OpenRepository(ctx, m.Repo)
+ if err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
+ return false
+ }
+ defer gitRepo.Close()
+ log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
+ if len(results) > 0 {
if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok {
+ log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err)
return false
}
}
@@ -534,16 +540,24 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
}
log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo)
- // Get latest commit date and update to current repository updated time
- commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
+ isEmpty, err := gitRepo.IsEmpty()
if err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
+ log.Error("SyncMirrors [repo: %-v]: unable to check empty git repo: %v", m.Repo, err)
return false
}
+ if !isEmpty {
+ // Get latest commit date and update to current repository updated time
+ commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
+ if err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
+ return false
+ }
+
+ if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
+ return false
+ }
- if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil {
- log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
- return false
}
log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo)
diff --git a/services/notify/notify.go b/services/notify/notify.go
index 16fbb6325d..0c8262ef7a 100644
--- a/services/notify/notify.go
+++ b/services/notify/notify.go
@@ -91,7 +91,7 @@ func AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues
// NewPullRequest notifies new pull request to notifiers
func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) {
if err := pr.LoadIssue(ctx); err != nil {
- log.Error("%v", err)
+ log.Error("LoadIssue failed: %v", err)
return
}
if err := pr.Issue.LoadPoster(ctx); err != nil {
@@ -112,7 +112,7 @@ func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *iss
// PullRequestReview notifies new pull request review
func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
if err := review.LoadReviewer(ctx); err != nil {
- log.Error("%v", err)
+ log.Error("LoadReviewer failed: %v", err)
return
}
for _, notifier := range notifiers {
diff --git a/services/pull/pull.go b/services/pull/pull.go
index c091b8608a..185a1895c9 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -989,12 +989,12 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co
for _, commit := range prInfo.Commits {
var committerOrAuthorName string
var commitTime time.Time
- if commit.Committer != nil {
- committerOrAuthorName = commit.Committer.Name
- commitTime = commit.Committer.When
- } else {
+ if commit.Author != nil {
committerOrAuthorName = commit.Author.Name
commitTime = commit.Author.When
+ } else {
+ committerOrAuthorName = commit.Committer.Name
+ commitTime = commit.Committer.When
}
commits = append(commits, CommitInfo{
diff --git a/services/repository/branch.go b/services/repository/branch.go
index 229ac54f30..d74e5819a1 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -26,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
notify_service "code.gitea.io/gitea/services/notify"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -119,17 +120,15 @@ func getDivergenceCacheKey(repoID int64, branchName string) string {
// getDivergenceFromCache gets the divergence from cache
func getDivergenceFromCache(repoID int64, branchName string) (*git.DivergeObject, bool) {
- data := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName))
+ data, ok := cache.GetCache().Get(getDivergenceCacheKey(repoID, branchName))
res := git.DivergeObject{
Ahead: -1,
Behind: -1,
}
- s, ok := data.([]byte)
- if !ok || len(s) == 0 {
+ if !ok || data == "" {
return &res, false
}
-
- if err := json.Unmarshal(s, &res); err != nil {
+ if err := json.Unmarshal(util.UnsafeStringToBytes(data), &res); err != nil {
log.Error("json.UnMarshal failed: %v", err)
return &res, false
}
@@ -141,7 +140,7 @@ func putDivergenceFromCache(repoID int64, branchName string, divergence *git.Div
if err != nil {
return err
}
- return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), bs, 30*24*60*60)
+ return cache.GetCache().Put(getDivergenceCacheKey(repoID, branchName), util.UnsafeBytesToString(bs), 30*24*60*60)
}
func DelDivergenceFromCache(repoID int64, branchName string) error {
diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go
index 145fc7d53c..8a62a603d4 100644
--- a/services/repository/commitstatus/commitstatus.go
+++ b/services/repository/commitstatus/commitstatus.go
@@ -7,6 +7,7 @@ import (
"context"
"crypto/sha256"
"fmt"
+ "slices"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
@@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/services/automerge"
@@ -25,12 +27,41 @@ func getCacheKey(repoID int64, brancheName string) string {
return fmt.Sprintf("commit_status:%x", hashBytes)
}
-func updateCommitStatusCache(ctx context.Context, repoID int64, branchName string, status api.CommitStatusState) error {
- c := cache.GetCache()
- return c.Put(getCacheKey(repoID, branchName), string(status), 3*24*60)
+type commitStatusCacheValue struct {
+ State string `json:"state"`
+ TargetURL string `json:"target_url"`
}
-func deleteCommitStatusCache(ctx context.Context, repoID int64, branchName string) error {
+func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheValue {
+ c := cache.GetCache()
+ statusStr, ok := c.Get(getCacheKey(repoID, branchName))
+ if ok && statusStr != "" {
+ var cv commitStatusCacheValue
+ err := json.Unmarshal([]byte(statusStr), &cv)
+ if err == nil && cv.State != "" {
+ return &cv
+ }
+ if err != nil {
+ log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err)
+ }
+ }
+ return nil
+}
+
+func updateCommitStatusCache(repoID int64, branchName string, state api.CommitStatusState, targetURL string) error {
+ c := cache.GetCache()
+ bs, err := json.Marshal(commitStatusCacheValue{
+ State: state.String(),
+ TargetURL: targetURL,
+ })
+ if err != nil {
+ log.Warn("updateCommitStatusCache: json.Marshal failed: %v", err)
+ return nil
+ }
+ return c.Put(getCacheKey(repoID, branchName), string(bs), 3*24*60)
+}
+
+func deleteCommitStatusCache(repoID int64, branchName string) error {
c := cache.GetCache()
return c.Delete(getCacheKey(repoID, branchName))
}
@@ -59,13 +90,19 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
sha = commit.ID.String()
}
- if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
- Repo: repo,
- Creator: creator,
- SHA: commit.ID,
- CommitStatus: status,
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
+ Repo: repo,
+ Creator: creator,
+ SHA: commit.ID,
+ CommitStatus: status,
+ }); err != nil {
+ return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
+ }
+
+ return git_model.UpdateCommitStatusSummary(ctx, repo.ID, commit.ID.String())
}); err != nil {
- return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
+ return err
}
defaultBranchCommit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
@@ -74,7 +111,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
}
if commit.ID.String() == defaultBranchCommit.ID.String() { // since one commit status updated, the combined commit status should be invalid
- if err := deleteCommitStatusCache(ctx, repo.ID, repo.DefaultBranch); err != nil {
+ if err := deleteCommitStatusCache(repo.ID, repo.DefaultBranch); err != nil {
log.Error("deleteCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
}
@@ -91,12 +128,12 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
// FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache
func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) {
results := make([]*git_model.CommitStatus, len(repos))
- c := cache.GetCache()
-
for i, repo := range repos {
- status, ok := c.Get(getCacheKey(repo.ID, repo.DefaultBranch)).(string)
- if ok && status != "" {
- results[i] = &git_model.CommitStatus{State: api.CommitStatusState(status)}
+ if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil {
+ results[i] = &git_model.CommitStatus{
+ State: api.CommitStatusState(cv.State),
+ TargetURL: cv.TargetURL,
+ }
}
}
@@ -114,8 +151,35 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep
return nil, fmt.Errorf("FindBranchesByRepoAndBranchName: %v", err)
}
+ var repoSHAs []git_model.RepoSHA
+ for id, sha := range repoIDsToLatestCommitSHAs {
+ repoSHAs = append(repoSHAs, git_model.RepoSHA{RepoID: id, SHA: sha})
+ }
+
+ summaryResults, err := git_model.GetLatestCommitStatusForRepoAndSHAs(ctx, repoSHAs)
+ if err != nil {
+ return nil, fmt.Errorf("GetLatestCommitStatusForRepoAndSHAs: %v", err)
+ }
+
+ for _, summary := range summaryResults {
+ for i, repo := range repos {
+ if repo.ID == summary.RepoID {
+ results[i] = summary
+ _ = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool {
+ return repoSHA.RepoID == repo.ID
+ })
+ if results[i].State != "" {
+ if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
+ log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
+ }
+ }
+ break
+ }
+ }
+ }
+
// call the database O(1) times to get the commit statuses for all repos
- repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptionsAll)
+ repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoSHAs)
if err != nil {
return nil, fmt.Errorf("GetLatestCommitStatusForPairs: %v", err)
}
@@ -124,7 +188,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep
if results[i] == nil {
results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID])
if results[i].State != "" {
- if err := updateCommitStatusCache(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil {
+ if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil {
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
}
diff --git a/services/repository/contributors_graph.go b/services/repository/contributors_graph.go
index 7c9f535ae0..b0d6de99ca 100644
--- a/services/repository/contributors_graph.go
+++ b/services/repository/contributors_graph.go
@@ -17,13 +17,12 @@ import (
"code.gitea.io/gitea/models/avatars"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
-
- "gitea.com/go-chi/cache"
)
const (
@@ -79,13 +78,13 @@ func findLastSundayBeforeDate(dateStr string) (string, error) {
}
// GetContributorStats returns contributors stats for git commits for given revision or default branch
-func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) {
+func GetContributorStats(ctx context.Context, cache cache.StringCache, repo *repo_model.Repository, revision string) (map[string]*ContributorData, error) {
// as GetContributorStats is resource intensive we cache the result
cacheKey := fmt.Sprintf(contributorStatsCacheKey, repo.FullName(), revision)
if !cache.IsExist(cacheKey) {
genReady := make(chan struct{})
- // dont start multible async generations
+ // dont start multiple async generations
_, run := generateLock.Load(cacheKey)
if run {
return nil, ErrAwaitGeneration
@@ -104,15 +103,11 @@ func GetContributorStats(ctx context.Context, cache cache.Cache, repo *repo_mode
}
}
// TODO: renew timeout of cache cache.UpdateTimeout(cacheKey, contributorStatsCacheTimeout)
-
- switch v := cache.Get(cacheKey).(type) {
- case error:
- return nil, v
- case map[string]*ContributorData:
- return v, nil
- default:
- return nil, fmt.Errorf("unexpected type in cache detected")
+ var res map[string]*ContributorData
+ if _, cacheErr := cache.GetJSON(cacheKey, &res); cacheErr != nil {
+ return nil, fmt.Errorf("cached error: %w", cacheErr.ToError())
}
+ return res, nil
}
// getExtendedCommitStats return the list of *ExtendedCommitStats for the given revision
@@ -205,13 +200,12 @@ func getExtendedCommitStats(repo *git.Repository, revision string /*, limit int
return extendedCommitStats, nil
}
-func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey string, repo *repo_model.Repository, revision string) {
+func generateContributorStats(genDone chan struct{}, cache cache.StringCache, cacheKey string, repo *repo_model.Repository, revision string) {
ctx := graceful.GetManager().HammerContext()
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
if err != nil {
- err := fmt.Errorf("OpenRepository: %w", err)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("OpenRepository: %w", err), contributorStatsCacheTimeout)
return
}
defer closer.Close()
@@ -221,13 +215,11 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey
}
extendedCommitStats, err := getExtendedCommitStats(gitRepo, revision)
if err != nil {
- err := fmt.Errorf("ExtendedCommitStats: %w", err)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("ExtendedCommitStats: %w", err), contributorStatsCacheTimeout)
return
}
if len(extendedCommitStats) == 0 {
- err := fmt.Errorf("no commit stats returned for revision '%s'", revision)
- _ = cache.Put(cacheKey, err, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, fmt.Errorf("no commit stats returned for revision '%s'", revision), contributorStatsCacheTimeout)
return
}
@@ -309,7 +301,7 @@ func generateContributorStats(genDone chan struct{}, cache cache.Cache, cacheKey
total.TotalCommits++
}
- _ = cache.Put(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout)
+ _ = cache.PutJSON(cacheKey, contributorsCommitStats, contributorStatsCacheTimeout)
generateLock.Delete(cacheKey)
if genDone != nil {
genDone <- struct{}{}
diff --git a/services/repository/contributors_graph_test.go b/services/repository/contributors_graph_test.go
index 3801a5eee4..f22c115276 100644
--- a/services/repository/contributors_graph_test.go
+++ b/services/repository/contributors_graph_test.go
@@ -10,9 +10,9 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
- "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/cache"
+ "code.gitea.io/gitea/modules/setting"
- "gitea.com/go-chi/cache"
"github.com/stretchr/testify/assert"
)
@@ -20,20 +20,18 @@ func TestRepository_ContributorsGraph(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
assert.NoError(t, repo.LoadOwner(db.DefaultContext))
- mockCache, err := cache.NewCacher(cache.Options{
- Adapter: "memory",
- Interval: 24 * 60,
- })
+ mockCache, err := cache.NewStringCache(setting.Cache{})
assert.NoError(t, err)
generateContributorStats(nil, mockCache, "key", repo, "404ref")
- err, isErr := mockCache.Get("key").(error)
- assert.True(t, isErr)
- assert.ErrorAs(t, err, &git.ErrNotExist{})
+ var data map[string]*ContributorData
+ _, getErr := mockCache.GetJSON("key", &data)
+ assert.NotNil(t, getErr)
+ assert.ErrorContains(t, getErr.ToError(), "object does not exist")
generateContributorStats(nil, mockCache, "key2", repo, "master")
- data, isData := mockCache.Get("key2").(map[string]*ContributorData)
- assert.True(t, isData)
+ exist, _ := mockCache.GetJSON("key2", &data)
+ assert.True(t, exist)
var keys []string
for k := range data {
keys = append(keys, k)
diff --git a/services/repository/delete.go b/services/repository/delete.go
index 8d6729f31b..7c7dfe2ddd 100644
--- a/services/repository/delete.go
+++ b/services/repository/delete.go
@@ -163,6 +163,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
&actions_model.ActionScheduleSpec{RepoID: repoID},
&actions_model.ActionSchedule{RepoID: repoID},
&actions_model.ActionArtifact{RepoID: repoID},
+ &actions_model.ActionRunnerToken{RepoID: repoID},
); err != nil {
return fmt.Errorf("deleteBeans: %w", err)
}
diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go
index 613b46d8f6..451a182155 100644
--- a/services/repository/files/cherry_pick.go
+++ b/services/repository/files/cherry_pick.go
@@ -28,7 +28,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil {
- log.Error("%v", err)
+ log.Error("NewTemporaryUploadRepository failed: %v", err)
}
defer t.Close()
if err := t.Clone(opts.OldBranch, false); err != nil {
diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go
index f6d5643dc9..e5f7e2af96 100644
--- a/services/repository/files/patch.go
+++ b/services/repository/files/patch.go
@@ -111,7 +111,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil {
- log.Error("%v", err)
+ log.Error("NewTemporaryUploadRepository failed: %v", err)
}
defer t.Close()
if err := t.Clone(opts.OldBranch, true); err != nil {
diff --git a/services/repository/files/update.go b/services/repository/files/update.go
index 4f7178184b..f029a9aefe 100644
--- a/services/repository/files/update.go
+++ b/services/repository/files/update.go
@@ -143,7 +143,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
t, err := NewTemporaryUploadRepository(ctx, repo)
if err != nil {
- log.Error("%v", err)
+ log.Error("NewTemporaryUploadRepository failed: %v", err)
}
defer t.Close()
hasOldBranch := true
diff --git a/services/user/delete.go b/services/user/delete.go
index 212cb83e03..889da3eb67 100644
--- a/services/user/delete.go
+++ b/services/user/delete.go
@@ -94,6 +94,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
&actions_model.ActionRunner{OwnerID: u.ID},
&user_model.Blocking{BlockerID: u.ID},
&user_model.Blocking{BlockeeID: u.ID},
+ &actions_model.ActionRunnerToken{OwnerID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %w", err)
}
diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go
index 1ab14fd6a7..587caf62ff 100644
--- a/services/webhook/notifier.go
+++ b/services/webhook/notifier.go
@@ -67,7 +67,7 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Action: api.HookIssueLabelCleared,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
})
@@ -168,7 +168,7 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)
apiIssue := &api.IssuePayload{
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
}
@@ -214,7 +214,7 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model
From: oldTitle,
},
},
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
})
@@ -250,7 +250,7 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
} else {
apiIssue := &api.IssuePayload{
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
CommitID: commitID,
@@ -281,7 +281,7 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{
Action: api.HookIssueOpened,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, issue.Poster, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, issue.Poster, nil),
}); err != nil {
@@ -349,7 +349,7 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod
From: oldContent,
},
},
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
})
@@ -384,7 +384,7 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us
permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer)
if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentEdited,
- Issue: convert.ToAPIIssue(ctx, c.Issue),
+ Issue: convert.ToAPIIssue(ctx, doer, c.Issue),
Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c),
Changes: &api.ChangesPayload{
Body: &api.ChangesFromPayload{
@@ -412,7 +412,7 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod
permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer)
if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentCreated,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Comment: convert.ToAPIComment(ctx, repo, comment),
Repository: convert.ToRepo(ctx, repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
@@ -449,7 +449,7 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us
permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer)
if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{
Action: api.HookIssueCommentDeleted,
- Issue: convert.ToAPIIssue(ctx, comment.Issue),
+ Issue: convert.ToAPIIssue(ctx, doer, comment.Issue),
Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment),
Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
@@ -533,7 +533,7 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{
Action: api.HookIssueLabelUpdated,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
})
@@ -575,7 +575,7 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m
err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{
Action: hookAction,
Index: issue.Index,
- Issue: convert.ToAPIIssue(ctx, issue),
+ Issue: convert.ToAPIIssue(ctx, doer, issue),
Repository: convert.ToRepo(ctx, issue.Repo, permission),
Sender: convert.ToUser(ctx, doer, nil),
})
diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index 1b921a44bd..fdcc5feefa 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -161,7 +161,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
if isOldWikiExist {
err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
if err != nil {
- log.Error("%v", err)
+ log.Error("RemoveFilesFromIndex failed: %v", err)
return err
}
}
@@ -171,18 +171,18 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
objectHash, err := gitRepo.HashObject(strings.NewReader(content))
if err != nil {
- log.Error("%v", err)
+ log.Error("HashObject failed: %v", err)
return err
}
if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil {
- log.Error("%v", err)
+ log.Error("AddObjectToIndex failed: %v", err)
return err
}
tree, err := gitRepo.WriteTree()
if err != nil {
- log.Error("%v", err)
+ log.Error("WriteTree failed: %v", err)
return err
}
@@ -207,7 +207,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts)
if err != nil {
- log.Error("%v", err)
+ log.Error("CommitTree failed: %v", err)
return err
}
@@ -222,11 +222,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
0,
),
}); err != nil {
- log.Error("%v", err)
+ log.Error("Push failed: %v", err)
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
return err
}
- return fmt.Errorf("Push: %w", err)
+ return fmt.Errorf("failed to push: %w", err)
}
return nil
@@ -370,6 +370,10 @@ func ChangeDefaultWikiBranch(ctx context.Context, repo *repo_model.Repository, n
return fmt.Errorf("unable to update database: %w", err)
}
+ if !repo.HasWiki() {
+ return nil
+ }
+
oldDefBranch, err := gitrepo.GetWikiDefaultBranch(ctx, repo)
if err != nil {
return fmt.Errorf("unable to get default branch: %w", err)
diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl
index 5ea003e5ec..68703cc884 100644
--- a/templates/admin/notice.tmpl
+++ b/templates/admin/notice.tmpl
@@ -49,7 +49,7 @@
-
+
{{ctx.Locale.Tr "admin.notices.delete_selected"}}
@@ -62,10 +62,7 @@
{{template "admin/layout_footer" .}}
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl
index 6a8e203694..a95f6b5120 100644
--- a/templates/admin/repo/unadopted.tmpl
+++ b/templates/admin/repo/unadopted.tmpl
@@ -54,7 +54,7 @@
- {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}}
+ {{template "base/modal_actions_confirm"}}
diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl
index c100ffd504..a6c2ac1ac9 100644
--- a/templates/admin/self_check.tmpl
+++ b/templates/admin/self_check.tmpl
@@ -5,11 +5,11 @@
{{ctx.Locale.Tr "admin.self_check"}}
- {{if .DeprecatedWarnings}}
+ {{if .StartupProblems}}
{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}
-
{{range .DeprecatedWarnings}}{{.}} {{end}}
+
{{range .StartupProblems}}{{.}} {{end}}
{{end}}
@@ -40,7 +40,7 @@
{{end}}
- {{if and (not .DeprecatedWarnings) (not .DatabaseCheckHasProblems)}}
+ {{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}}
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
diff --git a/templates/base/markup_codepreview.tmpl b/templates/base/markup_codepreview.tmpl
index c65ab28406..a1a4f26b47 100644
--- a/templates/base/markup_codepreview.tmpl
+++ b/templates/base/markup_codepreview.tmpl
@@ -17,7 +17,7 @@
{{- $lineEscapeStatus := index $.LineEscapeStatus $idx -}}
{{if $lineEscapeStatus.Escaped}} {{end}}
{{- end}}
- {{$line.FormattedContent}}
+ {{$line.FormattedContent}}
{{/* only div works, span generates incorrect HTML structure */}}
{{- end -}}
diff --git a/templates/base/modal_actions_confirm.tmpl b/templates/base/modal_actions_confirm.tmpl
index c44320deff..9f7eb4adf2 100644
--- a/templates/base/modal_actions_confirm.tmpl
+++ b/templates/base/modal_actions_confirm.tmpl
@@ -1,7 +1,6 @@
{{/*
Two buttons (negative, positive):
* ModalButtonTypes: "yes" (default) or "confirm"
-* ModalButtonColors: "primary" (default) / "blue" / "yellow"
* ModalButtonCancelText
* ModalButtonOkText
@@ -22,14 +21,7 @@ The ".ok.button" and ".cancel.button" selectors are also used by Fomantic Modal
{{end}}
{{if .ModalButtonCancelText}}{{$textNegitive = .ModalButtonCancelText}}{{end}}
{{if .ModalButtonOkText}}{{$textPositive = .ModalButtonOkText}}{{end}}
-
- {{$stylePositive := "primary"}}
- {{if eq .ModalButtonColors "blue"}}
- {{$stylePositive = "blue"}}
- {{else if eq .ModalButtonColors "yellow"}}
- {{$stylePositive = "yellow"}}
- {{end}}
{{svg "octicon-x"}} {{$textNegitive}}
- {{svg "octicon-check"}} {{$textPositive}}
+ {{svg "octicon-check"}} {{$textPositive}}
{{end}}
diff --git a/templates/devtest/fomantic-modal.tmpl b/templates/devtest/fomantic-modal.tmpl
index 5cd36721a7..f31cdc1983 100644
--- a/templates/devtest/fomantic-modal.tmpl
+++ b/templates/devtest/fomantic-modal.tmpl
@@ -1,6 +1,15 @@
{{template "base/head" .}}
{{template "base/alert" .}}
+
+
@@ -54,33 +63,11 @@
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
-
-
-
hello, this is the modal dialog content
- {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "blue")}}
-
-
-
-
-
hello, this is the modal dialog content
- {{template "base/modal_actions_confirm" (dict "ModalButtonColors" "yellow")}}
-
-
{{svg "octicon-x" 16 "inside close"}}
hello, this is the modal dialog content, this is a dangerous operation
{{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" "I know and must do this is dangerous operation")}}
-
-
-
{{template "base/footer" .}}
diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl
index bb4fc77a74..3b13c13be8 100644
--- a/templates/devtest/gitea-ui.tmpl
+++ b/templates/devtest/gitea-ui.tmpl
@@ -29,41 +29,13 @@
Basic Unclassed
Primary
Basic Primary
- Negative
- Basic Negative
- Positive
- Basic Positive
Recommended colors:
Red
Basic Red
- Green
- Basic Green
- Blue
- Basic Blue
- Orange
- Basic Orange
- Yellow
- Basic Yellow
-
-
- Supported but not recommended:
- Do not use if there is no strong requirement. Do not use grey/black buttons, they don't work well with dark theme.
- Secondary
- Basic Secondary
- Olive
- Basic Olive
- Teal
- Basic Teal
- Violet
- Basic Violet
- Purple
- Basic Purple
- Pink
- Basic Pink
- Brown
- Basic Brown
+ Green
+ Basic Green
Inline / Plain:
@@ -198,7 +170,7 @@
labeled button
123
- {{svg "octicon-x" 16}} button with very very very very very very very very long text
+ {{svg "octicon-x" 16}} button with very very very very very very very very long text
Input with SVG
@@ -271,10 +243,6 @@
button dropdown
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
- large dropdown
- {{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
@@ -290,10 +258,6 @@
button compact
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
- large compact
- {{svg "octicon-triangle-down" 14 "dropdown icon"}}
-
diff --git a/templates/devtest/label.tmpl b/templates/devtest/label.tmpl
new file mode 100644
index 0000000000..c4b52a3e23
--- /dev/null
+++ b/templates/devtest/label.tmpl
@@ -0,0 +1,27 @@
+{{template "base/head" .}}
+
+
+
+
Label
+
+ simple label
+ red label
+ green label
+
+
+ basic label
+ basic red label
+ basic green label
+
+
+ long content must be in a non-flex "gt-ellipsis" element, otherwise it won't get ellipsis. very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label
+
+
+ very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label
+
+
+ very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong label
+
+
+
+{{template "base/footer" .}}
diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl
index 8e619fa66f..a157cd4b75 100644
--- a/templates/explore/navbar.tmpl
+++ b/templates/explore/navbar.tmpl
@@ -11,7 +11,7 @@
{{svg "octicon-organization"}} {{ctx.Locale.Tr "explore.organizations"}}
- {{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}}
+ {{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}}
{{svg "octicon-code"}} {{ctx.Locale.Tr "explore.code"}}
diff --git a/templates/install.tmpl b/templates/install.tmpl
index 8a6956b546..f3117af547 100644
--- a/templates/install.tmpl
+++ b/templates/install.tmpl
@@ -174,7 +174,7 @@
{{ctx.Locale.Tr "install.smtp_from"}}
- {{ctx.Locale.Tr "install.smtp_from_helper"}}
+ {{ctx.Locale.TrString "install.smtp_from_helper"}}{{/* it contains lt/gt chars*/}}
{{ctx.Locale.Tr "install.mailer_user"}}
diff --git a/templates/org/projects/list.tmpl b/templates/org/projects/list.tmpl
index ec9cfece9a..80dde1c4d2 100644
--- a/templates/org/projects/list.tmpl
+++ b/templates/org/projects/list.tmpl
@@ -13,11 +13,9 @@
{{template "shared/user/profile_big_avatar" .}}
-
-
+
{{template "user/overview/header" .}}
-
- {{template "projects/list" .}}
+ {{template "projects/list" .}}
diff --git a/templates/org/projects/view.tmpl b/templates/org/projects/view.tmpl
index 495204b06d..e1ab81c4cd 100644
--- a/templates/org/projects/view.tmpl
+++ b/templates/org/projects/view.tmpl
@@ -1,7 +1,7 @@
{{template "base/head" .}}
{{template "shared/user/org_profile_avatar" .}}
-
+
{{template "user/overview/header" .}}
diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl
index 9311a46e38..b9e55dd587 100644
--- a/templates/org/team/sidebar.tmpl
+++ b/templates/org/team/sidebar.tmpl
@@ -79,7 +79,7 @@
{{if .IsOrganizationOwner}}
{{end}}
diff --git a/templates/package/content/nuget.tmpl b/templates/package/content/nuget.tmpl
index 0911260fba..f1fe420c0b 100644
--- a/templates/package/content/nuget.tmpl
+++ b/templates/package/content/nuget.tmpl
@@ -16,12 +16,11 @@
- {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes}}
+ {{if or .PackageDescriptor.Metadata.Description .PackageDescriptor.Metadata.ReleaseNotes .PackageDescriptor.Metadata.Readme}}
-
- {{if .PackageDescriptor.Metadata.Description}}{{.PackageDescriptor.Metadata.Description}}{{end}}
- {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{.PackageDescriptor.Metadata.ReleaseNotes}}{{end}}
-
+ {{if .PackageDescriptor.Metadata.Description}}{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Description}}
{{end}}
+ {{if .PackageDescriptor.Metadata.Readme}}{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.Readme}}
{{end}}
+ {{if .PackageDescriptor.Metadata.ReleaseNotes}}{{RenderMarkdownToHtml $.Context .PackageDescriptor.Metadata.ReleaseNotes}}
{{end}}
{{end}}
{{if .PackageDescriptor.Metadata.Dependencies}}
diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl
index 33dd758c79..f9b85360e0 100644
--- a/templates/projects/view.tmpl
+++ b/templates/projects/view.tmpl
@@ -66,13 +66,13 @@
{{range .Columns}}
-
+
{{.NumIssues ctx}}
- {{.Title}}
+
{{.Title}}
{{if $canWriteProject}}
@@ -153,9 +153,7 @@
{{end}}
-
-
-
+
{{range (index $.IssuesMap .ID)}}
diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl
index ac5049cf56..20330b5d62 100644
--- a/templates/repo/actions/runs_list.tmpl
+++ b/templates/repo/actions/runs_list.tmpl
@@ -1,4 +1,4 @@
-
+
{{if not .Runs}}
{{svg "octicon-no-entry" 48}}
@@ -28,14 +28,14 @@
-
-
{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
-
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+
+
{{svg "octicon-calendar" 16}}{{TimeSinceUnix .Updated ctx.Locale}}
+
{{svg "octicon-stopwatch" 16}}{{.Duration}}
+
{{end}}
diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl
index 30d1a3d78d..4ad3ed85c9 100644
--- a/templates/repo/blame.tmpl
+++ b/templates/repo/blame.tmpl
@@ -28,7 +28,7 @@
-
+
{{if .IsFileTooLarge}}
{{template "shared/filetoolarge" dict "RawFileLink" .RawFileLink}}
@@ -80,7 +80,7 @@
{{end}}{{/* end if .IsFileTooLarge */}}
diff --git a/templates/repo/code_frequency.tmpl b/templates/repo/code_frequency.tmpl
index 50ec1beb6b..79b45d4931 100644
--- a/templates/repo/code_frequency.tmpl
+++ b/templates/repo/code_frequency.tmpl
@@ -1,4 +1,4 @@
-{{if .Permission.CanRead $.UnitTypeCode}}
+{{if .Permission.CanRead ctx.Consts.RepoUnitTypeCode}}