mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-20 00:19:08 +03:00
Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a330f42f01 | ||
![]() |
531f36ea4a | ||
![]() |
b4f0eed969 | ||
![]() |
63b3a33bf2 | ||
![]() |
9899989ece | ||
![]() |
0fad40dd8c | ||
![]() |
e637008fe3 | ||
![]() |
fd281518ae | ||
![]() |
e10d222434 | ||
![]() |
7a35f90b29 | ||
![]() |
d371aa3031 | ||
![]() |
81768675d4 | ||
![]() |
39cc72562b | ||
![]() |
bc83fb26ef | ||
![]() |
68736ec292 | ||
![]() |
3df11c07a8 | ||
![]() |
96fff862dc | ||
![]() |
968c04c7da | ||
![]() |
27de60381d | ||
![]() |
d2d763318c | ||
![]() |
610b2fb88d | ||
![]() |
0858a36016 | ||
![]() |
fef364e7d6 | ||
![]() |
ce6a60a38b | ||
![]() |
74159a8855 | ||
![]() |
ce6464123f | ||
![]() |
7f0050cf39 | ||
![]() |
c102e344f3 | ||
![]() |
f27128bf94 | ||
![]() |
f35ab5cd52 | ||
![]() |
0137bc4e5c | ||
![]() |
eed0968c37 | ||
![]() |
a0b65ed17f | ||
![]() |
ad1b76540e | ||
![]() |
6636b37a9c | ||
![]() |
af5e5e8f00 | ||
![]() |
0e0ebf68d7 | ||
![]() |
90bd08ceef | ||
![]() |
0c581106d2 | ||
![]() |
e18e31d557 | ||
![]() |
e1026feddc | ||
![]() |
d670820722 | ||
![]() |
a8f98fd3be | ||
![]() |
c442c682ef | ||
![]() |
57868c2315 | ||
![]() |
b1c21880c1 | ||
![]() |
1e71ad89ce | ||
![]() |
c20642fa99 | ||
![]() |
a4291fd553 | ||
![]() |
fa5a064559 | ||
![]() |
cb42232080 | ||
![]() |
c8ffe777cf | ||
![]() |
e98dd6ee5b |
393
CHANGELOG.md
393
CHANGELOG.md
@ -4,6 +4,399 @@ This changelog goes through the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||
|
||||
## [1.23.0](https://github.com/go-gitea/gitea/releases/tag/v1.23.0) - 2025-01-08
|
||||
|
||||
* BREAKING
|
||||
* Rename config option `[camo].Allways` to `[camo].Always` (#32097)
|
||||
* Remove SHA1 for support for ssh rsa signing (#31857)
|
||||
* Use UTC as default timezone when schedule Actions cron tasks (#31742)
|
||||
* Delete Actions logs older than 1 year by default (#31735)
|
||||
* Make OIDC introspection authentication strictly require Client ID and secret (#31632)
|
||||
|
||||
* SECURITY
|
||||
* Include file extension checks in attachment API (#32151)
|
||||
* Include all security fixes which have been backported to v1.22
|
||||
|
||||
* FEATURES
|
||||
* Allow to fork repository into the same owner (#32819)
|
||||
* Support "merge upstream branch" (Sync fork) (#32741)
|
||||
* Add Arch package registry (#32692)
|
||||
* Allow to disable the password-based login (sign-in) form (#32687)
|
||||
* Allow cropping an avatar before setting it (#32565)
|
||||
* Support quote selected comments to reply (#32431)
|
||||
* Add reviewers selection to new pull request (#32403)
|
||||
* Suggestions for issues (#32327)
|
||||
* Add priority to protected branch (#32286)
|
||||
* Included tag search capabilities (#32045)
|
||||
* Add option to filter board cards by labels and assignees (#31999)
|
||||
* Add automatic light/dark option for the colorblind theme (#31997)
|
||||
* Support migration from AWS CodeCommit (#31981)
|
||||
* Introduce globallock as distributed locks (#31908 & #31813)
|
||||
* Support compression for Actions logs & enable by default (#31761 & #32013)
|
||||
* Add pure SSH LFS support (#31516)
|
||||
* Add Passkey login support (#31504)
|
||||
* Actions support workflow dispatch event (#28163)
|
||||
* Support repo license (#24872)
|
||||
* Issue time estimate, meaningful time tracking (#23113)
|
||||
* GitHub like repo home page (#32213 & #32847)
|
||||
* Rearrange Clone Panel (#31142)
|
||||
* Enhancing Gitea OAuth2 Provider with Granular Scopes for Resource Access (#32573)
|
||||
* Use env GITEA_RUNNER_REGISTRATION_TOKEN as global runner token (#32946) #32964
|
||||
* Update i18n.go - Language Picker (#32933) #32935
|
||||
|
||||
* PERFORMANCE
|
||||
* Perf: add extra index to notification table (#32395)
|
||||
* Introduce OrgList and add LoadTeams, optimaze Load teams for orgs (#32543)
|
||||
* Improve performance of diffs (#32393)
|
||||
* Make LFS http_client parallel within a batch. (#32369)
|
||||
* Add new index for action to resolve the performance problem (#32333)
|
||||
* Improve get feed with pagination (#31821)
|
||||
* Performance improvements for pull request list API (#30490)
|
||||
* Use batch database operations instead of one by one to optimze api pulls (#32680)
|
||||
* Use gitrepo.GetTreePathLatestCommit to get file lastest commit instead from latest commit cache (#32987) #33046
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Code
|
||||
* Remove unnecessary border in repo home page sidebar (#32767)
|
||||
* Add 'Copy path' button to file view (#32584)
|
||||
* Improve diff file tree (#32658)
|
||||
* Add new [lfs_client].BATCH_SIZE and [server].LFS_MAX_BATCH_SIZE config settings. (#32307)
|
||||
* Updated tokenizer to better matching when search for code snippets (#32261)
|
||||
* Change the code search to sort results by relevance (#32134)
|
||||
* Support migrating GitHub/GitLab PR draft status (#32242)
|
||||
* Move lock icon position and add additional tooltips to branch list page (#31839)
|
||||
* Add tag name in the commits list (#31082)
|
||||
* Add `MAX_ROWS` option for CSV rendering (#30268)
|
||||
* Allow code search by filename (#32210)
|
||||
* Make git push options accept short name (#32245)
|
||||
* Repo file list enhancements (#32835)
|
||||
|
||||
* Markdown & Editor
|
||||
* Refactor markdown math render, add dollor-backquote syntax support (#32831)
|
||||
* Make Monaco theme follow browser, fully type codeeditor.ts (#32756)
|
||||
* Refactor markdown editor and use it for milestone description editor (#32688)
|
||||
* Add some handy markdown editor features (#32400)
|
||||
* Improve markdown textarea for indentation and lists (#31406)
|
||||
|
||||
* Issue
|
||||
* Add label/author/assignee filters to the user/org home issue list (#32779)
|
||||
* Refactor issue filter (labels, poster, assignee) (#32771)
|
||||
* Style unification for the issue_management area (#32605)
|
||||
* Add "View all branches/tags" entry to Branch Selector (#32653)
|
||||
* Improve textarea paste (#31948)
|
||||
* Add avif image file support (#32508)
|
||||
* Prevent from submitting issue/comment on uploading (#32263)
|
||||
* Issue Templates: add option to have dropdown printed list (#31577)
|
||||
* Allow searching issues by ID (#31479)
|
||||
* Add `is_archived` option for issue indexer (#32735)
|
||||
* Improve attachment upload methods (#30513)
|
||||
* Support issue template assignees (#31083)
|
||||
* Prevent simultaneous editing of comments and issues (#31053)
|
||||
* Add issue comment when moving issues from one column to another of the project (#29311)
|
||||
|
||||
* Pull Request
|
||||
* Display head branch more comfortable on pull request view (#32000)
|
||||
* Simplify review UI (#31062)
|
||||
* Allow force push to protected branches (#28086)
|
||||
* Add line-through for deleted branch on pull request view page (#32500)
|
||||
* Support requested_reviewers data in comment webhook events (#26178)
|
||||
* Allow maintainers to view and edit files of private repos when "Allow maintainers to edit" is enabled (#32215)
|
||||
* Allow including `Reviewed-on`/`Reviewed-by` lines for custom merge messages (#31211)
|
||||
|
||||
* Actions
|
||||
* Render job title as commit message (#32748)
|
||||
* Refactor RepoActionView.vue, add `::group::` support (#32713)
|
||||
* Make RepoActionView.vue support `##[group]` (#32770)
|
||||
* Support `pull_request_target` event for commit status (#31703)
|
||||
* Detect whether action view branch was deleted (#32764)
|
||||
* Allow users with write permission to run actions (#32644)
|
||||
* Show latest run when visit /run/latest (#31808)
|
||||
|
||||
* Packages
|
||||
* Improve rubygems package registry (#31357)
|
||||
* Add support for npm bundleDependencies (#30751)
|
||||
* Add signature support for the RPM module (#27069)
|
||||
* Extract and display readme and comments for Composer packages (#30927)
|
||||
|
||||
* Project
|
||||
* Add title to project view page (#32747)
|
||||
* Set the columns height to hug all its contents (#31726)
|
||||
* Rename project `board` -> `column` to make the UI less confusing (#30170)
|
||||
|
||||
* User & Organazition
|
||||
* Use better name for userinfo structure (#32544)
|
||||
* Use user.FullName in Oauth2 id_token response (#32542)
|
||||
* Limit org member view of restricted users (#32211)
|
||||
* Allow disabling authentication related user features (#31535)
|
||||
* Add option to change mail from user display name (#31528)
|
||||
* Use FullName in Emails to address the recipient if possible (#31527)
|
||||
|
||||
* Administration
|
||||
* Add support for a credentials chain for minio access (#31051)
|
||||
* Move admin routers from /admin to /-/admin (#32189)
|
||||
* Add cache test for admins (#31265)
|
||||
* Add option for mailer to override mail headers (#27860)
|
||||
* Azure blob storage support (#30995)
|
||||
* Supports forced use of S3 virtual-hosted style (#30969)
|
||||
* Move repository visibility to danger zone in the settings area (#31126)
|
||||
|
||||
* Others
|
||||
* Remove urls from translations (#31950)
|
||||
* Simplify 404/500 page (#31409)
|
||||
* Optimize installation-page experience (#32558)
|
||||
* Refactor login page (#31530)
|
||||
* Add new event commit status creation and webhook implementation (#27151)
|
||||
* Repo Activity: count new issues that were closed (#31776)
|
||||
* Set manual `tabindex`es on login page (#31689)
|
||||
* Add `YEAR`, `MONTH`, `MONTH_ENGLISH`, `DAY` variables for template repos (#31584)
|
||||
* Add typescript guideline and typescript-specific eslint plugins and fix issues (#31521)
|
||||
* Make toast support preventDuplicates (#31501)
|
||||
* Fix tautological conditions (#30735)
|
||||
* Issue change title notifications (#33050) #33065
|
||||
|
||||
* API
|
||||
* Implement update branch API (#32433)
|
||||
* Fix missing outputs for jobs with matrix (#32823)
|
||||
* Make API "compare" accept commit IDs (#32801)
|
||||
* Add github compatible tarball download API endpoints (#32572)
|
||||
* Harden runner updateTask and updateLog api (#32462)
|
||||
* Add `DISABLE_ORGANIZATIONS_PAGE` and `DISABLE_CODE_PAGE` settings for explore pages and fix an issue related to user search (#32288)
|
||||
* Make admins adhere to branch protection rules (#32248)
|
||||
* Calculate `PublicOnly` for org membership only once (#32234)
|
||||
* Allow filtering PRs by poster in the ListPullRequests API (#32209)
|
||||
* Return 404 instead of error when commit not exist (#31977)
|
||||
* Save initial signup information for users to aid in spam prevention (#31852)
|
||||
* Fix upload maven pacakge parallelly (#31851)
|
||||
* Fix null requested_reviewer from API (#31773)
|
||||
* Add permission description for API to add repo collaborator (#31744)
|
||||
* Add return type to GetRawFileOrLFS and GetRawFile (#31680)
|
||||
* Add skip secondary authorization option for public oauth2 clients (#31454)
|
||||
* Add tag protection via rest api #17862 (#31295)
|
||||
* Document possible action types for the user activity feed API (#31196)
|
||||
* Add topics for repository API (#31127)
|
||||
* Add support for searching users by email (#30908)
|
||||
* Add API endpoints for getting action jobs status (#26673)
|
||||
|
||||
* REFACTOR
|
||||
* Update JS and PY dependencies (#31940)
|
||||
* Enable `no-jquery/no-parse-html-literal` and fix violation (#31684)
|
||||
* Refactor image diff (#31444)
|
||||
* Refactor CSRF token (#32216)
|
||||
* Fix some typescript issues (#32586)
|
||||
* Refactor names (#31405)
|
||||
* Use per package global lock for container uploads instead of memory lock (#31860)
|
||||
* Move team related functions to service layer (#32537)
|
||||
* Move GetFeeds to service layer (#32526)
|
||||
* Resolve lint for unused parameter and unnecessary type arguments (#30750)
|
||||
* Reimplement GetUserOrgsList to make it simple and clear (#32486)
|
||||
* Move some functions from issue.go to standalone files (#32468)
|
||||
* Refactor sidebar assignee&milestone&project selectors (#32465)
|
||||
* Refactor sidebar label selector (#32460)
|
||||
* Fix a number of typescript issues (#32459)
|
||||
* Refactor language menu and dom utils (#32450)
|
||||
* Refactor issue page info (#32445)
|
||||
* Split issue sidebar into small templates (#32444)
|
||||
* Refactor template ctx and render utils (#32422)
|
||||
* Refactor repo legacy (#32404)
|
||||
* Refactor markup package (#32399)
|
||||
* Refactor markup render system (#32533 & #32589 & #32612)
|
||||
* Refactor the DB migration system slightly (#32344)
|
||||
* Remove jQuery import from some files (#32512)
|
||||
* Strict pagination check (#32548)
|
||||
* Split mail sender sub package from mailer service package (#32618)
|
||||
* Remove outdated code about fixture generation (#32708)
|
||||
* Refactor RepoBranchTagSelector (#32681)
|
||||
* Refactor issue list (#32755)
|
||||
* Refactor LabelEdit (#32752)
|
||||
* Split issue/pull view router function as multiple smaller functions (#32749)
|
||||
* Refactor some LDAP code (#32849)
|
||||
* Unify repo search order by logic (#30876)
|
||||
* Remove duplicate empty repo check in delete branch API (#32569)
|
||||
* Replace deprecated `math/rand` functions (#30733)
|
||||
* Remove fomantic dimmer module (#30723)
|
||||
* Add types to fetch,toast,bootstrap,svg (#31627)
|
||||
* Refactor webhook (#31587)
|
||||
* Move AddCollabrator and CreateRepositoryByExample to service layer (#32419)
|
||||
* Refactor RepoRefByType (#32413)
|
||||
* Refactor: remove redundant err declarations (#32381)
|
||||
* Refactor markup code (#31399)
|
||||
* Refactor render system (orgmode) (#32671)
|
||||
* Refactor render system (#32492)
|
||||
* Refactor markdown render (#32736 & #32728)
|
||||
* Refactor repo unit "disabled" check (#31389)
|
||||
* Refactor route path normalization (#31381)
|
||||
* Refactor to use UnsafeStringToBytes (#31358)
|
||||
* Migrate vue components to setup (#32329)
|
||||
* Refactor globallock (#31933)
|
||||
* Use correct function name (#31887)
|
||||
* Use a common message template instead of a special one (#31878)
|
||||
* Fix a number of Typescript issues (#31877)
|
||||
* Refactor dropzone (#31482)
|
||||
* Move custom `tw-` helpers to tailwind plugin (#31184)
|
||||
* Replace `gt-word-break` with `tw-break-anywhere` (#31183)
|
||||
* Drop `IDOrderDesc` for listing Actions task and always order by `id DESC` (#31150)
|
||||
* Split common-global.js into separate files (#31438)
|
||||
* Improve detecting empty files (#31332)
|
||||
* Use `querySelector` over alternative DOM methods (#31280)
|
||||
* Remove jQuery `.text()` (#30506)
|
||||
* Use repo as of renderctx's member rather than a repoPath on metas (#29222)
|
||||
* Refactor some frontend problems (#32646)
|
||||
* Refactor DateUtils and merge TimeSince (#32409)
|
||||
* Replace DateTime with proper functions (#32402)
|
||||
* Replace DateTime with DateUtils (#32383)
|
||||
* Convert frontend code to typescript (#31559)
|
||||
* Refactor maven package registry (#33049) #33057
|
||||
* Refactor testfixtures #33028
|
||||
|
||||
* BUGFIXES
|
||||
* Fix issues with inconsistent spacing in areas (#32607)
|
||||
* Fix incomplete Actions status aggregations (#32859)
|
||||
* In some lfs server implementations, they require the ref attribute. (#32838)
|
||||
* Update the list of watchers and stargazers when clicking watch/unwatch or star/unstar (#32570)
|
||||
* Fix `recentupdate` sorting bugs (#32505)
|
||||
* Fix incorrect "Target branch does not exist" in PR title (#32222)
|
||||
* Handle "close" actionable references for manual merges (#31879)
|
||||
* render plain text file if the LFS object doesn't exist (#31812)
|
||||
* Fix Null Pointer error for CommitStatusesHideActionsURL (#31731)
|
||||
* Fix loadRepository error when access user dashboard (#31719)
|
||||
* Hide the "Details" link of commit status when the user cannot access actions (#30156)
|
||||
* Fix duplicate dropdown dividers (#32760)
|
||||
* Fix SSPI button visibility when SSPI is the only enabled method (#32841)
|
||||
* Fix overflow on org header (#32837)
|
||||
* Exclude protected branches from recently pushed (#31748)
|
||||
* Fix large image overflow in comment page (#31740)
|
||||
* Fix milestone deadline and date related problems (#32339)
|
||||
* Fix markdown preview $$ support (#31514)
|
||||
* Fix a compilation error in the Gitpod environment (#32559)
|
||||
* Fix PR diff review form submit (#32596)
|
||||
* Fix a number of typescript issues (#32308)
|
||||
* Fix some function names in comment (#32300)
|
||||
* Fix absolute-date (#32375)
|
||||
* Clarify Actions resources ownership (#31724)
|
||||
* Try to fix ACME directory problem (#33072) #33077
|
||||
* Inherit submodules from template repository content (#16237) #33068
|
||||
* Use project's redirect url instead of composing url (#33058) #33064
|
||||
* Fix toggle commit body button ui when latest commit message is long (#32997) #33034
|
||||
* Fix package error handling and npm meta and empty repo guide #33112
|
||||
* Fix empty git repo handling logic and fix mobile view (#33101) #33102
|
||||
* Fix line-number and scroll bugs (#33094) #33095
|
||||
* Fix bleve fuzziness search (#33078) #33087
|
||||
* Fix broken forms #33082
|
||||
* Fix empty repo updated time (#33120) #33124
|
||||
* Add missing transaction when set merge #33113
|
||||
* Fix issue comment number (#30556) #33055
|
||||
* Fix duplicate co-author in squashed merge commit messages (#33020) #33054
|
||||
* Fix Agit pull request permission check (#32999) #33005
|
||||
* Fix scoped label ui when contains emoji (#33007) #33014
|
||||
* Fix bug on activities (#33008) #33016
|
||||
* Fix review code comment avatar alignment (#33031) #33032
|
||||
* Fix templating in pull request comparison (#33025) #33038
|
||||
* Fix bug automerge cannot be chosed when there is only 1 merge style (#33040) #33043
|
||||
* Fix settings not being loaded at CLI (#26402) #33048
|
||||
* Support for email addresses containing uppercase characters when activating user account (#32998) #33001
|
||||
* Support org labels when adding labels by label names (#32988) #32996
|
||||
* Do not render truncated links in markdown (#32980) #32983
|
||||
* Demilestone should not include milestone (#32923) #32979
|
||||
* Fix Azure blob object Seek (#32974) #32975
|
||||
* Fix maven pom inheritance (#32943) #32976
|
||||
* Fix textarea newline handle (#32966) #32977
|
||||
* Fix outdated tmpl code (#32953) #32961
|
||||
* Fix commit range paging (#32944) #32962
|
||||
* Fix repo avatar conflict (#32958) #32960
|
||||
* Fix trailing comma not matched in the case of alphanumeric issue (#32945)
|
||||
* Relax the version checking for Arch packages (#32908) #32913
|
||||
* Add more load functions to make sure the reference object loaded (#32901) #32912
|
||||
* Filter reviews of one pull request in memory instead of database to reduce slow response because of lacking database index (#33106) #33128
|
||||
* Fix git remote error check, fix dependencies, fix js error (#33129) #33133
|
||||
|
||||
* MISC
|
||||
* Optimize branch protection rule loading (#32280)
|
||||
* Bump to go 1.23 (#31855)
|
||||
* Remove unused call to $.HeadRepo in view_title template (#32317)
|
||||
* Do not display `attestation-manifest` and use short sha256 instead of full sha256 (#32851)
|
||||
* Upgrade htmx to 2.0.4 (#32834)
|
||||
* Improve JSX/TSX support in code editor (#32833)
|
||||
* Add User-Agent for gitea's self-implemented lfs client. (#32832)
|
||||
* Use errors.New to replace fmt.Errorf with no parameters (#32800)
|
||||
* Add "n commits" link to contributors in contributors graph page (#32799)
|
||||
* Update dependencies, tweak eslint (#32719)
|
||||
* Remove all "floated" CSS styles (#32691)
|
||||
* Show tag name on branch/tag selector if repo shown from tag ref (#32689)
|
||||
* Use new mail package instead of an unmintained one (#32682)
|
||||
* Optimize the styling of icon buttons within file-header-right (#32675)
|
||||
* Validate OAuth Redirect URIs (#32643)
|
||||
* Support optional/configurable IAMEndpoint for Minio Client (#32581) (#32581)
|
||||
* Make search box in issue sidebar dropdown list always show when scrolling (#32576)
|
||||
* Bump CI,Flake and Snap to Node 22 (#32487)
|
||||
* Update `github.com/meilisearch/meilisearch-go` (#32484)
|
||||
* Add `DEFAULT_MIRROR_REPO_UNITS` and `DEFAULT_TEMPLATE_REPO_UNITS` options (#32416)
|
||||
* Update go dependencies (#32389)
|
||||
* Update JS and PY dependencies (#32388)
|
||||
* Upgrade rollup to 4.24.0 (#32312)
|
||||
* Upgrade vue to 3.5.12 (#32311)
|
||||
* Improve the maintainblity of the reserved username list (#32229)
|
||||
* Upgrade htmx to 2.0.3 (#32192)
|
||||
* Count typescript files as frontend for labeling (#32088)
|
||||
* Only use Host header from reverse proxy (#32060)
|
||||
* Failed authentications are logged to level Warning (#32016)
|
||||
* Enhance USER_DISABLED_FEATURES to allow disabling change username or full name (#31959)
|
||||
* Distinguish official vs non-official reviews, add tool tips, and upgr… (#31924)
|
||||
* Update mermaid to v11 (#31913)
|
||||
* Bump relative-time-element to v4.4.3 (#31910)
|
||||
* Upgrade `htmx` to `2.0.2` (#31847)
|
||||
* Add warning message in merge instructions when `AutodetectManualMerge` was not enabled (#31805)
|
||||
* Add types to various low-level functions (#31781)
|
||||
* Update JS dependencies (#31766)
|
||||
* Remove unused code from models/repos/release.go (#31756)
|
||||
* Support delete user email in admin panel (#31690)
|
||||
* Add `username` to OIDC introspection response (#31688)
|
||||
* Use GetDisplayName() instead of DisplayName() to generate rss feeds (#31687)
|
||||
* Code editor theme enhancements (#31629)
|
||||
* Update JS dependencies (#31616)
|
||||
* Add types for js globals (#31586)
|
||||
* Add back esbuild-loader for .js files (#31585)
|
||||
* Don't show hidden labels when filling out an issue template (#31576)
|
||||
* Allow synchronizing user status from OAuth2 login providers (#31572)
|
||||
* Display app name in the registration email title (#31562)
|
||||
* Use stable version of fabric (#31526)
|
||||
* Support legacy _links LFS batch responses (#31513)
|
||||
* Fix JS error with disabled attachment and easymde (#31511)
|
||||
* Always use HTML attributes for avatar size (#31509)
|
||||
* Use nolyfill to remove some polyfills (#31468)
|
||||
* Disable issue/PR comment button given empty input (#31463)
|
||||
* Add simple JS init performance trace (#31459)
|
||||
* Bump htmx to 2.0.0 (#31413)
|
||||
* Update JS dependencies, remove `eslint-plugin-jquery` (#31402)
|
||||
* Split org Propfile README to a new tab `overview` (#31373)
|
||||
* Update nix flake and add gofumpt (#31320)
|
||||
* Code optimization (#31315)
|
||||
* Enable poetry non-package mode (#31282)
|
||||
* Optimize profile layout to enhance visual experience (#31278)
|
||||
* Update `golang.org/x/net` (#31260)
|
||||
* Bump `@github/relative-time-element` to v4.4.1 (#31232)
|
||||
* Remove unnecessary inline style for tab-size (#31224)
|
||||
* Update golangci-lint to v1.59.0 (#31221)
|
||||
* Update chroma to v2.14.0 (#31177)
|
||||
* Update JS dependencies (#31120)
|
||||
* Improve the handling of `jobs.<job_id>.if` (#31070)
|
||||
* Clean up revive linter config, tweak golangci output (#30980)
|
||||
* Use CSS `inset` shorthand (#30939)
|
||||
* Forbid deprecated `break-word` in CSS (#30934)
|
||||
* Remove obsolete monaco workaround (#30893)
|
||||
* Update JS dependencies, add new eslint rules (#30840)
|
||||
* Fix body margin shifting with modals, fix error on project column edit (#30831)
|
||||
* Remove disk-clean workflow (#30741)
|
||||
* Bump `github.com/google/go-github` to v61 (#30738)
|
||||
* Add built js files to eslint ignore (#30737)
|
||||
* Use `ProtonMail/go-crypto` for `opengpg` in tests (#30736)
|
||||
* Upgrade xorm to v1.3.9 and improve some migrations Sync (#29899)
|
||||
* Added default sorting milestones by name (#27084)
|
||||
* Enable `unparam` linter (#31277)
|
||||
* Use Alpine 3.21 for the docker images (#32924) #32951
|
||||
* Bump x/net (#32896) #32899
|
||||
* Use -s -w ldflags for release artifacts (#33041) #33042
|
||||
* Remove aws go sdk package dependency (#33029) #33047
|
||||
|
||||
## [1.22.4](https://github.com/go-gitea/gitea/releases/tag/v1.22.4) - 2024-11-14
|
||||
|
||||
* SECURITY
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Build stage
|
||||
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
|
||||
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-direct}
|
||||
@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||
|
||||
FROM docker.io/library/alpine:3.20
|
||||
FROM docker.io/library/alpine:3.21
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
|
||||
EXPOSE 22 3000
|
||||
@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea
|
||||
VOLUME ["/data"]
|
||||
|
||||
ENTRYPOINT ["/usr/bin/entrypoint"]
|
||||
CMD ["/bin/s6-svscan", "/etc/s6"]
|
||||
CMD ["/usr/bin/s6-svscan", "/etc/s6"]
|
||||
|
||||
COPY --from=build-env /tmp/local /
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Build stage
|
||||
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
|
||||
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-direct}
|
||||
@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
|
||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||
|
||||
FROM docker.io/library/alpine:3.20
|
||||
FROM docker.io/library/alpine:3.21
|
||||
LABEL maintainer="maintainers@gitea.io"
|
||||
|
||||
EXPOSE 2222 3000
|
||||
|
10
Makefile
10
Makefile
@ -806,22 +806,22 @@ $(DIST_DIRS):
|
||||
|
||||
.PHONY: release-windows
|
||||
release-windows: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq (,$(findstring gogit,$(TAGS)))
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'osusergo gogit $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
endif
|
||||
|
||||
.PHONY: release-linux
|
||||
release-linux: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w -linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-darwin
|
||||
release-darwin: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-freebsd
|
||||
release-freebsd: | $(DIST_DIRS)
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-s -w $(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||
|
||||
.PHONY: release-copy
|
||||
release-copy: | $(DIST_DIRS)
|
||||
|
72
assets/go-licenses.json
generated
72
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@ -69,6 +69,10 @@ var microcmdUserCreate = &cli.Command{
|
||||
}
|
||||
|
||||
func runCreateUser(c *cli.Context) error {
|
||||
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
|
||||
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
||||
setting.LoadSettings()
|
||||
|
||||
if err := argsSet(c, "email"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
11
cmd/web.go
11
cmd/web.go
@ -12,6 +12,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "net/http/pprof" // Used for debugging if enabled and a web server is running
|
||||
|
||||
@ -115,6 +116,16 @@ func showWebStartupMessage(msg string) {
|
||||
log.Info("* CustomPath: %s", setting.CustomPath)
|
||||
log.Info("* ConfigFile: %s", setting.CustomConf)
|
||||
log.Info("%s", msg) // show startup message
|
||||
|
||||
if setting.CORSConfig.Enabled {
|
||||
log.Info("CORS Service Enabled")
|
||||
}
|
||||
if setting.DefaultUILocation != time.Local {
|
||||
log.Info("Default UI Location is %v", setting.DefaultUILocation.String())
|
||||
}
|
||||
if setting.MailService != nil {
|
||||
log.Info("Mail Service Enabled: RegisterEmailConfirm=%v, Service.EnableNotifyMail=%v", setting.Service.RegisterEmailConfirm, setting.Service.EnableNotifyMail)
|
||||
}
|
||||
}
|
||||
|
||||
func serveInstall(ctx *cli.Context) error {
|
||||
|
@ -54,7 +54,7 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||
altTLSALPNPort = p
|
||||
}
|
||||
|
||||
magic := certmagic.NewDefault()
|
||||
magic := &certmagic.Default
|
||||
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||
// Try to use private CA root if provided, otherwise defaults to system's trust
|
||||
var certPool *x509.CertPool
|
||||
|
@ -1482,6 +1482,10 @@ LEVEL = Info
|
||||
;REPO_INDEXER_EXCLUDE =
|
||||
;;
|
||||
;MAX_FILE_SIZE = 1048576
|
||||
;;
|
||||
;; Bleve engine has performance problems with fuzzy search, so we limit the fuzziness to 0 by default to disable it.
|
||||
;; If you'd like to enable it, you can set it to a value between 0 and 2.
|
||||
;TYPE_BLEVE_MAX_FUZZINESS = 0
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
37
go.mod
37
go.mod
@ -24,11 +24,10 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
github.com/ProtonMail/go-crypto v1.0.0
|
||||
github.com/ProtonMail/go-crypto v1.1.4
|
||||
github.com/PuerkitoBio/goquery v1.10.0
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
||||
github.com/alecthomas/chroma/v2 v2.14.0
|
||||
github.com/aws/aws-sdk-go v1.55.5
|
||||
github.com/alecthomas/chroma/v2 v2.15.0
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.27.3
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||
@ -55,13 +54,12 @@ require (
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-co-op/gocron v1.37.0
|
||||
github.com/go-enry/go-enry/v2 v2.9.1
|
||||
github.com/go-git/go-billy/v5 v5.6.0
|
||||
github.com/go-git/go-git/v5 v5.12.0
|
||||
github.com/go-git/go-billy/v5 v5.6.1
|
||||
github.com/go-git/go-git/v5 v5.13.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.8
|
||||
github.com/go-redsync/redsync/v4 v4.13.0
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/go-swagger/go-swagger v0.31.0
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.11.0
|
||||
github.com/go-webauthn/webauthn v0.11.2
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||
@ -109,7 +107,7 @@ require (
|
||||
github.com/sassoftware/go-rpmutils v0.4.0
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/tstranex/u2f v1.0.0
|
||||
github.com/ulikunitz/xz v0.5.12
|
||||
@ -121,14 +119,14 @@ require (
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
golang.org/x/crypto v0.31.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/image v0.21.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/net v0.34.0
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/sys v0.28.0
|
||||
golang.org/x/sys v0.29.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/tools v0.26.0
|
||||
golang.org/x/tools v0.29.0
|
||||
google.golang.org/grpc v1.67.1
|
||||
google.golang.org/protobuf v1.35.1
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
@ -145,8 +143,6 @@ require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
github.com/ClickHouse/ch-go v0.63.1 // indirect
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.24.0 // indirect
|
||||
github.com/DataDog/zstd v1.5.6 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||
@ -191,7 +187,7 @@ require (
|
||||
github.com/couchbase/gomemcached v0.3.2 // indirect
|
||||
github.com/couchbase/goutils v0.1.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.4 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
@ -204,8 +200,6 @@ require (
|
||||
github.com/go-ap/errors v0.0.0-20240910140019-1e9d33cc1568 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
github.com/go-faster/city v1.0.1 // indirect
|
||||
github.com/go-faster/errors v0.7.1 // indirect
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
@ -226,7 +220,7 @@ require (
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
@ -261,6 +255,7 @@ require (
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/mmcloughlin/avo v0.6.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
@ -270,10 +265,9 @@ require (
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||
github.com/paulmach/orb v0.11.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.60.1 // indirect
|
||||
@ -285,7 +279,6 @@ require (
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
@ -310,13 +303,11 @@ require (
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.etcd.io/bbolt v1.3.11 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opentelemetry.io/otel v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.31.0 // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
140
go.sum
140
go.sum
@ -59,10 +59,6 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzS
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/ClickHouse/ch-go v0.63.1 h1:s2JyZvWLTCSAGdtjMBBmAgQQHMco6pawLJMOXi0FODM=
|
||||
github.com/ClickHouse/ch-go v0.63.1/go.mod h1:I1kJJCL3WJcBMGe1m+HVK0+nREaG+JOYYBWjrDrF3R0=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.24.0 h1:L/n/pVVpk95KtkHOiKuSnO7cu2ckeW4gICbbOh5qs74=
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.24.0/go.mod h1:iDTViXk2Fgvf1jn2dbJd1ys+fBkdD1UMRnXlwmhijhQ=
|
||||
github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY=
|
||||
github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
|
||||
@ -75,8 +71,8 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
|
||||
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE=
|
||||
github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/PuerkitoBio/goquery v1.10.0 h1:6fiXdLuUvYs2OJSvNRqlNPoBm6YABE226xrbavY5Wv4=
|
||||
github.com/PuerkitoBio/goquery v1.10.0/go.mod h1:TjZZl68Q3eGHNBA8CWaxAN7rOU1EbDz3CWuolcO5Yu4=
|
||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||
@ -85,11 +81,11 @@ github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv
|
||||
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3 h1:BP0HiyNT3AQEYi+if3wkRcIdQFHtsw6xX3Kx0glckgA=
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3/go.mod h1:hMNtySovKkn2gdDuLqnqveP+mfhUSaBdoBcr2I7Zt0E=
|
||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
||||
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
@ -109,8 +105,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
|
||||
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM=
|
||||
@ -194,7 +188,6 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk=
|
||||
github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0=
|
||||
github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE=
|
||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||
@ -211,7 +204,6 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
|
||||
github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
@ -229,16 +221,14 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
|
||||
github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
|
||||
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
|
||||
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
||||
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21 h1:PdsjTl0Cg+ZJgOx/CFV5NNgO1ThTreqdgKYiDCMHJwA=
|
||||
@ -262,8 +252,8 @@ github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJ
|
||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 h1:dKG8sc7n321deIVRcQtwlMNoBEra7j0qQ8RwxO8RN0w=
|
||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2/go.mod h1:7dvD3GCm7eBw53xZ/lsiq72LqobdMg3ITbMBxnmJmqY=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
|
||||
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||
github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
||||
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
|
||||
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
|
||||
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||
@ -317,20 +307,16 @@ github.com/go-enry/go-enry/v2 v2.9.1 h1:G9iDteJ/Mc0F4Di5NeQknf83R2OkRbwY9cAYmcqV
|
||||
github.com/go-enry/go-enry/v2 v2.9.1/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8=
|
||||
github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo=
|
||||
github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
|
||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
|
||||
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8=
|
||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
|
||||
github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
|
||||
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
|
||||
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
|
||||
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
|
||||
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
|
||||
@ -372,8 +358,6 @@ github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
||||
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.11.0 h1:XxQr8AnPORcZkyNd7go5UNLPD3dULN8ixYISlzrlfEQ=
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.11.0/go.mod h1:THmudHF1Ixq++J2/UodcJpxUphfyEd77m83TvDtryqE=
|
||||
github.com/go-webauthn/webauthn v0.11.2 h1:Fgx0/wlmkClTKlnOsdOQ+K5HcHDsDcYIvtYmfhEOSUc=
|
||||
github.com/go-webauthn/webauthn v0.11.2/go.mod h1:aOtudaF94pM71g3jRwTYYwQTG1KyTILTcZqN1srkmD0=
|
||||
github.com/go-webauthn/x v0.1.15 h1:eG1OhggBJTkDE8gUeOlGRbRe8E/PSVG26YG4AyFbwkU=
|
||||
@ -385,7 +369,6 @@ github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm
|
||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||
@ -400,8 +383,8 @@ github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217 h1:HKlyj6in2JV6wVkmQ4XmG/EIm+SCYlPZ+V4GWit7Z+I=
|
||||
github.com/golang/geo v0.0.0-20230421003525-6adc56603217/go.mod h1:8wI0hitZ3a1IxZfeH3/5I97CI8i5cLGsYe7xNhQGs9U=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@ -410,7 +393,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@ -497,22 +479,6 @@ github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI
|
||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
|
||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
|
||||
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
|
||||
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
|
||||
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
|
||||
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
|
||||
github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
|
||||
github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA=
|
||||
github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
|
||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
|
||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
@ -533,10 +499,6 @@ github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bB
|
||||
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
||||
github.com/jhillyerd/enmime v1.3.0 h1:LV5kzfLidiOr8qRGIpYYmUZCnhrPbcFAnAFUnWn99rw=
|
||||
github.com/jhillyerd/enmime v1.3.0/go.mod h1:6c6jg5HdRRV2FtvVL69LjiX1M8oE0xDX9VEhV3oy4gs=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
@ -550,11 +512,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
|
||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 h1:cTxwSmnaqLoo+4tLukHoB9iqHOu3LmLhRmgUxZo6Vp4=
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
@ -624,12 +583,13 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
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/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=
|
||||
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||
@ -670,9 +630,6 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
|
||||
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
@ -680,8 +637,8 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG
|
||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
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/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI=
|
||||
github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s=
|
||||
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=
|
||||
@ -735,8 +692,6 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6Ng
|
||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
@ -783,21 +738,19 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
|
||||
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||
@ -823,9 +776,6 @@ github.com/xanzy/go-gitlab v0.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+D
|
||||
github.com/xanzy/go-gitlab v0.112.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
@ -842,9 +792,7 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
|
||||
github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBzPCRjkCNs=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
@ -863,13 +811,8 @@ github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
|
||||
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
|
||||
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
|
||||
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
||||
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
|
||||
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
@ -886,16 +829,14 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
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-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
|
||||
@ -909,8 +850,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -922,18 +863,16 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
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.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -941,7 +880,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
@ -974,8 +912,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -985,14 +921,12 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
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=
|
||||
@ -1000,15 +934,13 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
@ -1022,16 +954,14 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -1046,8 +976,6 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -69,7 +69,7 @@ func TestAggregateJobStatus(t *testing.T) {
|
||||
{[]Status{StatusFailure, StatusBlocked}, StatusFailure},
|
||||
|
||||
// skipped with other status
|
||||
// TODO: need to clarify whether a PR with "skipped" job status is considered as "mergeable" or not.
|
||||
// "all skipped" is also considered as "mergeable" by "services/actions.toCommitStatus", the same as GitHub
|
||||
{[]Status{StatusSkipped}, StatusSkipped},
|
||||
{[]Status{StatusSkipped, StatusSuccess}, StatusSuccess},
|
||||
{[]Status{StatusSkipped, StatusFailure}, StatusFailure},
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
@ -51,7 +52,7 @@ func GetRunnerToken(ctx context.Context, token string) (*ActionRunnerToken, erro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if !has {
|
||||
return nil, fmt.Errorf("runner token %q: %w", token, util.ErrNotExist)
|
||||
return nil, fmt.Errorf(`runner token "%s...": %w`, base.TruncateString(token, 3), util.ErrNotExist)
|
||||
}
|
||||
return &runnerToken, nil
|
||||
}
|
||||
@ -68,19 +69,15 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string
|
||||
return err
|
||||
}
|
||||
|
||||
// NewRunnerToken creates a new active runner token and invalidate all old tokens
|
||||
// NewRunnerTokenWithValue creates a new active runner token and invalidate all old tokens
|
||||
// ownerID will be ignored and treated as 0 if repoID is non-zero.
|
||||
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
func NewRunnerTokenWithValue(ctx context.Context, ownerID, repoID int64, token string) (*ActionRunnerToken, error) {
|
||||
if ownerID != 0 && repoID != 0 {
|
||||
// It's trying to create a runner token that belongs to a repository, but OwnerID has been set accidentally.
|
||||
// Remove OwnerID to avoid confusion; it's not worth returning an error here.
|
||||
ownerID = 0
|
||||
}
|
||||
|
||||
token, err := util.CryptoRandomString(40)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runnerToken := &ActionRunnerToken{
|
||||
OwnerID: ownerID,
|
||||
RepoID: repoID,
|
||||
@ -95,11 +92,19 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.GetEngine(ctx).Insert(runnerToken)
|
||||
_, err := db.GetEngine(ctx).Insert(runnerToken)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
token, err := util.CryptoRandomString(40)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewRunnerTokenWithValue(ctx, ownerID, repoID, token)
|
||||
}
|
||||
|
||||
// GetLatestRunnerToken returns the latest runner token
|
||||
func GetLatestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) {
|
||||
if ownerID != 0 && repoID != 0 {
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
@ -337,8 +338,10 @@ func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *
|
||||
func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
|
||||
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
|
||||
And("issue.is_pull = ?", false).
|
||||
And("issue.created_unix >= ?", fromTime.Unix()).
|
||||
Or("issue.closed_unix >= ?", fromTime.Unix())
|
||||
And(builder.Or(
|
||||
builder.Gte{"issue.created_unix": fromTime.Unix()},
|
||||
builder.Gte{"issue.closed_unix": fromTime.Unix()},
|
||||
))
|
||||
|
||||
return sess
|
||||
}
|
||||
|
@ -64,7 +64,7 @@
|
||||
name: job2
|
||||
attempt: 1
|
||||
job_id: job2
|
||||
needs: [job1]
|
||||
needs: '["job1"]'
|
||||
task_id: 51
|
||||
status: 5
|
||||
started: 1683636528
|
||||
|
@ -96,3 +96,14 @@
|
||||
num_issues: 0
|
||||
num_closed_issues: 0
|
||||
archived_unix: 0
|
||||
|
||||
-
|
||||
id: 10
|
||||
repo_id: 3
|
||||
org_id: 0
|
||||
name: repo3label1
|
||||
color: '#112233'
|
||||
exclusive: false
|
||||
num_issues: 0
|
||||
num_closed_issues: 0
|
||||
archived_unix: 0
|
||||
|
@ -2,23 +2,23 @@
|
||||
id: 1
|
||||
repo_id: 4
|
||||
name_pattern: /v.+/
|
||||
allowlist_user_i_ds: []
|
||||
allowlist_team_i_ds: []
|
||||
allowlist_user_i_ds: "[]"
|
||||
allowlist_team_i_ds: "[]"
|
||||
created_unix: 1715596037
|
||||
updated_unix: 1715596037
|
||||
-
|
||||
id: 2
|
||||
repo_id: 1
|
||||
name_pattern: v-*
|
||||
allowlist_user_i_ds: []
|
||||
allowlist_team_i_ds: []
|
||||
allowlist_user_i_ds: "[]"
|
||||
allowlist_team_i_ds: "[]"
|
||||
created_unix: 1715596037
|
||||
updated_unix: 1715596037
|
||||
-
|
||||
id: 3
|
||||
repo_id: 1
|
||||
name_pattern: v-1.1
|
||||
allowlist_user_i_ds: [2]
|
||||
allowlist_team_i_ds: []
|
||||
allowlist_user_i_ds: "[2]"
|
||||
allowlist_team_i_ds: "[]"
|
||||
created_unix: 1715596037
|
||||
updated_unix: 1715596037
|
||||
|
@ -197,6 +197,20 @@ func (t CommentType) HasMailReplySupport() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (t CommentType) CountedAsConversation() bool {
|
||||
for _, ct := range ConversationCountedCommentType() {
|
||||
if t == ct {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ConversationCountedCommentType returns the comment types that are counted as a conversation
|
||||
func ConversationCountedCommentType() []CommentType {
|
||||
return []CommentType{CommentTypeComment, CommentTypeReview}
|
||||
}
|
||||
|
||||
// RoleInRepo presents the user's participation in the repo
|
||||
type RoleInRepo string
|
||||
|
||||
@ -893,7 +907,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment
|
||||
}
|
||||
fallthrough
|
||||
case CommentTypeComment:
|
||||
if _, err = db.Exec(ctx, "UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
|
||||
if err := UpdateIssueNumComments(ctx, opts.Issue.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
fallthrough
|
||||
@ -1182,8 +1196,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if comment.Type == CommentTypeComment {
|
||||
if _, err := e.ID(comment.IssueID).Decr("num_comments").Update(new(Issue)); err != nil {
|
||||
if comment.Type.CountedAsConversation() {
|
||||
if err := UpdateIssueNumComments(ctx, comment.IssueID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -1300,6 +1314,21 @@ func (c *Comment) HasOriginalAuthor() bool {
|
||||
return c.OriginalAuthor != "" && c.OriginalAuthorID != 0
|
||||
}
|
||||
|
||||
func UpdateIssueNumCommentsBuilder(issueID int64) *builder.Builder {
|
||||
subQuery := builder.Select("COUNT(*)").From("`comment`").Where(
|
||||
builder.Eq{"issue_id": issueID}.And(
|
||||
builder.In("`type`", ConversationCountedCommentType()),
|
||||
))
|
||||
|
||||
return builder.Update(builder.Eq{"num_comments": subQuery}).
|
||||
From("`issue`").Where(builder.Eq{"id": issueID})
|
||||
}
|
||||
|
||||
func UpdateIssueNumComments(ctx context.Context, issueID int64) error {
|
||||
_, err := db.GetEngine(ctx).Exec(UpdateIssueNumCommentsBuilder(issueID))
|
||||
return err
|
||||
}
|
||||
|
||||
// InsertIssueComments inserts many comments of issues.
|
||||
func InsertIssueComments(ctx context.Context, comments []*Comment) error {
|
||||
if len(comments) == 0 {
|
||||
@ -1332,8 +1361,7 @@ func InsertIssueComments(ctx context.Context, comments []*Comment) error {
|
||||
}
|
||||
|
||||
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 {
|
||||
if err := UpdateIssueNumComments(ctx, issueID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -97,3 +97,12 @@ func TestMigrate_InsertIssueComments(t *testing.T) {
|
||||
|
||||
unittest.CheckConsistencyFor(t, &issues_model.Issue{})
|
||||
}
|
||||
|
||||
func Test_UpdateIssueNumComments(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
|
||||
assert.NoError(t, issues_model.UpdateIssueNumComments(db.DefaultContext, issue2.ID))
|
||||
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.EqualValues(t, 1, issue2.NumComments)
|
||||
}
|
||||
|
@ -349,6 +349,17 @@ func GetLabelIDsInRepoByNames(ctx context.Context, repoID int64, labelNames []st
|
||||
Find(&labelIDs)
|
||||
}
|
||||
|
||||
// GetLabelIDsInOrgByNames returns a list of labelIDs by names in a given org.
|
||||
func GetLabelIDsInOrgByNames(ctx context.Context, orgID int64, labelNames []string) ([]int64, error) {
|
||||
labelIDs := make([]int64, 0, len(labelNames))
|
||||
return labelIDs, db.GetEngine(ctx).Table("label").
|
||||
Where("org_id = ?", orgID).
|
||||
In("name", labelNames).
|
||||
Asc("name").
|
||||
Cols("id").
|
||||
Find(&labelIDs)
|
||||
}
|
||||
|
||||
// BuildLabelNamesIssueIDsCondition returns a builder where get issue ids match label names
|
||||
func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder {
|
||||
return builder.Select("issue_label.issue_id").
|
||||
|
@ -301,7 +301,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||
reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -320,7 +320,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error {
|
||||
|
||||
// LoadRequestedReviewersTeams loads the requested reviewers teams.
|
||||
func (pr *PullRequest) LoadRequestedReviewersTeams(ctx context.Context) error {
|
||||
reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||
reviews, _, err := GetReviewsByIssueID(ctx, pr.Issue.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -639,6 +639,10 @@ func InsertReviews(ctx context.Context, reviews []*Review) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := UpdateIssueNumComments(ctx, review.IssueID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
|
@ -5,6 +5,8 @@ package issues
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"sort"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
organization_model "code.gitea.io/gitea/models/organization"
|
||||
@ -153,43 +155,60 @@ func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) {
|
||||
return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{})
|
||||
}
|
||||
|
||||
// GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request
|
||||
func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
}
|
||||
|
||||
// GetReviewsByIssueID gets the latest review of each reviewer for a pull request
|
||||
func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) {
|
||||
// The first returned parameter is the latest review of each individual reviewer or team
|
||||
// The second returned parameter is the latest review of each original author which is migrated from other systems
|
||||
// The reviews are sorted by updated time
|
||||
func GetReviewsByIssueID(ctx context.Context, issueID int64) (latestReviews, migratedOriginalReviews ReviewList, err error) {
|
||||
reviews := make([]*Review, 0, 10)
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
// Get latest review of each reviewer, sorted in order they were made
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC",
|
||||
issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, false).
|
||||
Find(&reviews); err != nil {
|
||||
return nil, err
|
||||
// Get all reviews for the issue id
|
||||
if err := db.GetEngine(ctx).Where("issue_id=?", issueID).OrderBy("updated_unix ASC").Find(&reviews); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// filter them in memory to get the latest review of each reviewer
|
||||
// Since the reviews should not be too many for one issue, less than 100 commonly, it's acceptable to do this in memory
|
||||
// And since there are too less indexes in review table, it will be very slow to filter in the database
|
||||
reviewersMap := make(map[int64][]*Review) // key is reviewer id
|
||||
originalReviewersMap := make(map[int64][]*Review) // key is original author id
|
||||
reviewTeamsMap := make(map[int64][]*Review) // key is reviewer team id
|
||||
countedReivewTypes := []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest}
|
||||
for _, review := range reviews {
|
||||
if review.ReviewerTeamID == 0 && slices.Contains(countedReivewTypes, review.Type) && !review.Dismissed {
|
||||
if review.OriginalAuthorID != 0 {
|
||||
originalReviewersMap[review.OriginalAuthorID] = append(originalReviewersMap[review.OriginalAuthorID], review)
|
||||
} else {
|
||||
reviewersMap[review.ReviewerID] = append(reviewersMap[review.ReviewerID], review)
|
||||
}
|
||||
} else if review.ReviewerTeamID != 0 && review.OriginalAuthorID == 0 {
|
||||
reviewTeamsMap[review.ReviewerTeamID] = append(reviewTeamsMap[review.ReviewerTeamID], review)
|
||||
}
|
||||
}
|
||||
|
||||
individualReviews := make([]*Review, 0, 10)
|
||||
for _, reviews := range reviewersMap {
|
||||
individualReviews = append(individualReviews, reviews[len(reviews)-1])
|
||||
}
|
||||
sort.Slice(individualReviews, func(i, j int) bool {
|
||||
return individualReviews[i].UpdatedUnix < individualReviews[j].UpdatedUnix
|
||||
})
|
||||
|
||||
originalReviews := make([]*Review, 0, 10)
|
||||
for _, reviews := range originalReviewersMap {
|
||||
originalReviews = append(originalReviews, reviews[len(reviews)-1])
|
||||
}
|
||||
sort.Slice(originalReviews, func(i, j int) bool {
|
||||
return originalReviews[i].UpdatedUnix < originalReviews[j].UpdatedUnix
|
||||
})
|
||||
|
||||
teamReviewRequests := make([]*Review, 0, 5)
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id <> 0 AND original_author_id = 0 GROUP BY issue_id, reviewer_team_id) ORDER BY review.updated_unix ASC",
|
||||
issueID).
|
||||
Find(&teamReviewRequests); err != nil {
|
||||
return nil, err
|
||||
for _, reviews := range reviewTeamsMap {
|
||||
teamReviewRequests = append(teamReviewRequests, reviews[len(reviews)-1])
|
||||
}
|
||||
sort.Slice(teamReviewRequests, func(i, j int) bool {
|
||||
return teamReviewRequests[i].UpdatedUnix < teamReviewRequests[j].UpdatedUnix
|
||||
})
|
||||
|
||||
if len(teamReviewRequests) > 0 {
|
||||
reviews = append(reviews, teamReviewRequests...)
|
||||
}
|
||||
|
||||
return reviews, nil
|
||||
return append(individualReviews, teamReviewRequests...), originalReviews, nil
|
||||
}
|
||||
|
@ -162,8 +162,9 @@ func TestGetReviewersByIssueID(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||
allReviews, migratedReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, migratedReviews)
|
||||
for _, review := range allReviews {
|
||||
assert.NoError(t, review.LoadReviewer(db.DefaultContext))
|
||||
}
|
||||
|
@ -248,6 +248,18 @@ func GetPackageByID(ctx context.Context, packageID int64) (*Package, error) {
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// UpdatePackageNameByID updates the package's name, it is only for internal usage, for example: rename some legacy packages
|
||||
func UpdatePackageNameByID(ctx context.Context, ownerID int64, packageType Type, packageID int64, name string) error {
|
||||
var cond builder.Cond = builder.Eq{
|
||||
"package.id": packageID,
|
||||
"package.owner_id": ownerID,
|
||||
"package.type": packageType,
|
||||
"package.is_internal": false,
|
||||
}
|
||||
_, err := db.GetEngine(ctx).Where(cond).Update(&Package{Name: name, LowerName: strings.ToLower(name)})
|
||||
return err
|
||||
}
|
||||
|
||||
// GetPackageByName gets a package by name
|
||||
func GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) {
|
||||
var cond builder.Cond = builder.Eq{
|
||||
|
@ -126,6 +126,14 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func ProjectLinkForOrg(org *user_model.User, projectID int64) string { //nolint
|
||||
return fmt.Sprintf("%s/-/projects/%d", org.HomeLink(), projectID)
|
||||
}
|
||||
|
||||
func ProjectLinkForRepo(repo *repo_model.Repository, projectID int64) string { //nolint
|
||||
return fmt.Sprintf("%s/projects/%d", repo.Link(), projectID)
|
||||
}
|
||||
|
||||
// Link returns the project's relative URL.
|
||||
func (p *Project) Link(ctx context.Context) string {
|
||||
if p.OwnerID > 0 {
|
||||
@ -134,7 +142,7 @@ func (p *Project) Link(ctx context.Context) string {
|
||||
log.Error("LoadOwner: %v", err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID)
|
||||
return ProjectLinkForOrg(p.Owner, p.ID)
|
||||
}
|
||||
if p.RepoID > 0 {
|
||||
err := p.LoadRepo(ctx)
|
||||
@ -142,7 +150,7 @@ func (p *Project) Link(ctx context.Context) string {
|
||||
log.Error("LoadRepo: %v", err)
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%s/projects/%d", p.Repo.Link(), p.ID)
|
||||
return ProjectLinkForRepo(p.Repo, p.ID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ import (
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// Init initialize model
|
||||
@ -27,7 +29,7 @@ func Init(ctx context.Context) error {
|
||||
}
|
||||
|
||||
type repoChecker struct {
|
||||
querySQL func(ctx context.Context) ([]map[string][]byte, error)
|
||||
querySQL func(ctx context.Context) ([]int64, error)
|
||||
correctSQL func(ctx context.Context, id int64) error
|
||||
desc string
|
||||
}
|
||||
@ -38,8 +40,7 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) {
|
||||
log.Error("Select %s: %v", checker.desc, err)
|
||||
return
|
||||
}
|
||||
for _, result := range results {
|
||||
id, _ := strconv.ParseInt(string(result["id"]), 10, 64)
|
||||
for _, id := range results {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Warn("CheckRepoStats: Cancelled before checking %s for with id=%d", checker.desc, id)
|
||||
@ -54,21 +55,23 @@ func repoStatsCheck(ctx context.Context, checker *repoChecker) {
|
||||
}
|
||||
}
|
||||
|
||||
func StatsCorrectSQL(ctx context.Context, sql string, id int64) error {
|
||||
_, err := db.GetEngine(ctx).Exec(sql, id, id)
|
||||
func StatsCorrectSQL(ctx context.Context, sql any, ids ...any) error {
|
||||
args := []any{sql}
|
||||
args = append(args, ids...)
|
||||
_, err := db.GetEngine(ctx).Exec(args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func repoStatsCorrectNumWatches(ctx context.Context, id int64) error {
|
||||
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id)
|
||||
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=? AND mode<>2) WHERE id=?", id, id)
|
||||
}
|
||||
|
||||
func repoStatsCorrectNumStars(ctx context.Context, id int64) error {
|
||||
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id)
|
||||
return StatsCorrectSQL(ctx, "UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", id, id)
|
||||
}
|
||||
|
||||
func labelStatsCorrectNumIssues(ctx context.Context, id int64) error {
|
||||
return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id)
|
||||
return StatsCorrectSQL(ctx, "UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", id, id)
|
||||
}
|
||||
|
||||
func labelStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error {
|
||||
@ -105,11 +108,11 @@ func milestoneStatsCorrectNumIssuesRepo(ctx context.Context, id int64) error {
|
||||
}
|
||||
|
||||
func userStatsCorrectNumRepos(ctx context.Context, id int64) error {
|
||||
return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id)
|
||||
return StatsCorrectSQL(ctx, "UPDATE `user` SET num_repos=(SELECT COUNT(*) FROM `repository` WHERE owner_id=?) WHERE id=?", id, id)
|
||||
}
|
||||
|
||||
func repoStatsCorrectIssueNumComments(ctx context.Context, id int64) error {
|
||||
return StatsCorrectSQL(ctx, "UPDATE `issue` SET num_comments=(SELECT COUNT(*) FROM `comment` WHERE issue_id=? AND type=0) WHERE id=?", id)
|
||||
return StatsCorrectSQL(ctx, issues_model.UpdateIssueNumCommentsBuilder(id))
|
||||
}
|
||||
|
||||
func repoStatsCorrectNumIssues(ctx context.Context, id int64) error {
|
||||
@ -128,9 +131,12 @@ func repoStatsCorrectNumClosedPulls(ctx context.Context, id int64) error {
|
||||
return repo_model.UpdateRepoIssueNumbers(ctx, id, true, true)
|
||||
}
|
||||
|
||||
func statsQuery(args ...any) func(context.Context) ([]map[string][]byte, error) {
|
||||
return func(ctx context.Context) ([]map[string][]byte, error) {
|
||||
return db.GetEngine(ctx).Query(args...)
|
||||
// statsQuery returns a function that queries the database for a list of IDs
|
||||
// sql could be a string or a *builder.Builder
|
||||
func statsQuery(sql any, args ...any) func(context.Context) ([]int64, error) {
|
||||
return func(ctx context.Context) ([]int64, error) {
|
||||
var ids []int64
|
||||
return ids, db.GetEngine(ctx).SQL(sql, args...).Find(&ids)
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +207,16 @@ func CheckRepoStats(ctx context.Context) error {
|
||||
},
|
||||
// Issue.NumComments
|
||||
{
|
||||
statsQuery("SELECT `issue`.id FROM `issue` WHERE `issue`.num_comments!=(SELECT COUNT(*) FROM `comment` WHERE issue_id=`issue`.id AND type=0)"),
|
||||
statsQuery(builder.Select("`issue`.id").From("`issue`").Where(
|
||||
builder.Neq{
|
||||
"`issue`.num_comments": builder.Select("COUNT(*)").From("`comment`").Where(
|
||||
builder.Expr("issue_id = `issue`.id").And(
|
||||
builder.In("type", issues_model.ConversationCountedCommentType()),
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
repoStatsCorrectIssueNumComments,
|
||||
"issue count 'num_comments'",
|
||||
},
|
||||
|
@ -276,6 +276,8 @@ func (repo *Repository) IsBroken() bool {
|
||||
}
|
||||
|
||||
// MarkAsBrokenEmpty marks the repo as broken and empty
|
||||
// FIXME: the status "broken" and "is_empty" were abused,
|
||||
// The code always set them together, no way to distinguish whether a repo is really "empty" or "broken"
|
||||
func (repo *Repository) MarkAsBrokenEmpty() {
|
||||
repo.Status = RepositoryBroken
|
||||
repo.IsEmpty = true
|
||||
|
@ -46,6 +46,12 @@ func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateRepositoryColsNoAutoTime updates repository's columns and but applies time change automatically
|
||||
func UpdateRepositoryColsNoAutoTime(ctx context.Context, repo *Repository, cols ...string) error {
|
||||
_, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).NoAutoTime().Update(repo)
|
||||
return err
|
||||
}
|
||||
|
||||
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
||||
type ErrReachLimitOfRepo struct {
|
||||
Limit int
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -22,3 +23,16 @@ func TestDoctorUserStarNum(t *testing.T) {
|
||||
|
||||
assert.NoError(t, DoctorUserStarNum(db.DefaultContext))
|
||||
}
|
||||
|
||||
func Test_repoStatsCorrectIssueNumComments(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.NotNil(t, issue2)
|
||||
assert.EqualValues(t, 0, issue2.NumComments) // the fixture data is wrong, but we don't fix it here
|
||||
|
||||
assert.NoError(t, repoStatsCorrectIssueNumComments(db.DefaultContext, 2))
|
||||
// reload the issue
|
||||
issue2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
|
||||
assert.EqualValues(t, 1, issue2.NumComments)
|
||||
}
|
||||
|
@ -6,19 +6,21 @@ package unittest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/go-testfixtures/testfixtures/v3"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
var fixturesLoader *testfixtures.Loader
|
||||
type FixturesLoader interface {
|
||||
Load() error
|
||||
}
|
||||
|
||||
var fixturesLoader FixturesLoader
|
||||
|
||||
// GetXORMEngine gets the XORM engine
|
||||
func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
@ -31,38 +33,7 @@ func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
|
||||
// InitFixtures initialize test fixtures for a test database
|
||||
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
|
||||
e := GetXORMEngine(engine...)
|
||||
var fixtureOptionFiles func(*testfixtures.Loader) error
|
||||
if opts.Dir != "" {
|
||||
fixtureOptionFiles = testfixtures.Directory(opts.Dir)
|
||||
} else {
|
||||
fixtureOptionFiles = testfixtures.Files(opts.Files...)
|
||||
}
|
||||
dialect := "unknown"
|
||||
switch e.Dialect().URI().DBType {
|
||||
case schemas.POSTGRES:
|
||||
dialect = "postgres"
|
||||
case schemas.MYSQL:
|
||||
dialect = "mysql"
|
||||
case schemas.MSSQL:
|
||||
dialect = "mssql"
|
||||
case schemas.SQLITE:
|
||||
dialect = "sqlite3"
|
||||
default:
|
||||
fmt.Println("Unsupported RDBMS for integration tests")
|
||||
os.Exit(1)
|
||||
}
|
||||
loaderOptions := []func(loader *testfixtures.Loader) error{
|
||||
testfixtures.Database(e.DB().DB),
|
||||
testfixtures.Dialect(dialect),
|
||||
testfixtures.DangerousSkipTestDatabaseCheck(),
|
||||
fixtureOptionFiles,
|
||||
}
|
||||
|
||||
if e.Dialect().URI().DBType == schemas.POSTGRES {
|
||||
loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
|
||||
}
|
||||
|
||||
fixturesLoader, err = testfixtures.New(loaderOptions...)
|
||||
fixturesLoader, err = NewFixturesLoader(e, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
201
models/unittest/fixtures_loader.go
Normal file
201
models/unittest/fixtures_loader.go
Normal file
@ -0,0 +1,201 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package unittest
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type fixtureItem struct {
|
||||
tableName string
|
||||
tableNameQuoted string
|
||||
sqlInserts []string
|
||||
sqlInsertArgs [][]any
|
||||
|
||||
mssqlHasIdentityColumn bool
|
||||
}
|
||||
|
||||
type fixturesLoaderInternal struct {
|
||||
db *sql.DB
|
||||
dbType schemas.DBType
|
||||
files []string
|
||||
fixtures map[string]*fixtureItem
|
||||
quoteObject func(string) string
|
||||
paramPlaceholder func(idx int) string
|
||||
}
|
||||
|
||||
func (f *fixturesLoaderInternal) mssqlTableHasIdentityColumn(db *sql.DB, tableName string) (bool, error) {
|
||||
row := db.QueryRow(`SELECT COUNT(*) FROM sys.identity_columns WHERE OBJECT_ID = OBJECT_ID(?)`, tableName)
|
||||
var count int
|
||||
if err := row.Scan(&count); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (f *fixturesLoaderInternal) preprocessFixtureRow(row []map[string]any) (err error) {
|
||||
for _, m := range row {
|
||||
for k, v := range m {
|
||||
if s, ok := v.(string); ok {
|
||||
if strings.HasPrefix(s, "0x") {
|
||||
if m[k], err = hex.DecodeString(s[2:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fixturesLoaderInternal) prepareFixtureItem(file string) (_ *fixtureItem, err error) {
|
||||
fixture := &fixtureItem{}
|
||||
fixture.tableName, _, _ = strings.Cut(filepath.Base(file), ".")
|
||||
fixture.tableNameQuoted = f.quoteObject(fixture.tableName)
|
||||
|
||||
if f.dbType == schemas.MSSQL {
|
||||
fixture.mssqlHasIdentityColumn, err = f.mssqlTableHasIdentityColumn(f.db, fixture.tableName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read file %q: %w", file, err)
|
||||
}
|
||||
|
||||
var rows []map[string]any
|
||||
if err = yaml.Unmarshal(data, &rows); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal yaml data from %q: %w", file, err)
|
||||
}
|
||||
if err = f.preprocessFixtureRow(rows); err != nil {
|
||||
return nil, fmt.Errorf("failed to preprocess fixture rows from %q: %w", file, err)
|
||||
}
|
||||
|
||||
var sqlBuf []byte
|
||||
var sqlArguments []any
|
||||
for _, row := range rows {
|
||||
sqlBuf = append(sqlBuf, fmt.Sprintf("INSERT INTO %s (", fixture.tableNameQuoted)...)
|
||||
for k, v := range row {
|
||||
sqlBuf = append(sqlBuf, f.quoteObject(k)...)
|
||||
sqlBuf = append(sqlBuf, ","...)
|
||||
sqlArguments = append(sqlArguments, v)
|
||||
}
|
||||
sqlBuf = sqlBuf[:len(sqlBuf)-1]
|
||||
sqlBuf = append(sqlBuf, ") VALUES ("...)
|
||||
paramIdx := 1
|
||||
for range row {
|
||||
sqlBuf = append(sqlBuf, f.paramPlaceholder(paramIdx)...)
|
||||
sqlBuf = append(sqlBuf, ',')
|
||||
paramIdx++
|
||||
}
|
||||
sqlBuf[len(sqlBuf)-1] = ')'
|
||||
fixture.sqlInserts = append(fixture.sqlInserts, string(sqlBuf))
|
||||
fixture.sqlInsertArgs = append(fixture.sqlInsertArgs, slices.Clone(sqlArguments))
|
||||
sqlBuf = sqlBuf[:0]
|
||||
sqlArguments = sqlArguments[:0]
|
||||
}
|
||||
return fixture, nil
|
||||
}
|
||||
|
||||
func (f *fixturesLoaderInternal) loadFixtures(tx *sql.Tx, file string) (err error) {
|
||||
fixture := f.fixtures[file]
|
||||
if fixture == nil {
|
||||
if fixture, err = f.prepareFixtureItem(file); err != nil {
|
||||
return err
|
||||
}
|
||||
f.fixtures[file] = fixture
|
||||
}
|
||||
|
||||
_, err = tx.Exec(fmt.Sprintf("DELETE FROM %s", fixture.tableNameQuoted)) // sqlite3 doesn't support truncate
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fixture.mssqlHasIdentityColumn {
|
||||
_, err = tx.Exec(fmt.Sprintf("SET IDENTITY_INSERT %s ON", fixture.tableNameQuoted))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _, err = tx.Exec(fmt.Sprintf("SET IDENTITY_INSERT %s OFF", fixture.tableNameQuoted)) }()
|
||||
}
|
||||
for i := range fixture.sqlInserts {
|
||||
_, err = tx.Exec(fixture.sqlInserts[i], fixture.sqlInsertArgs[i]...)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fixturesLoaderInternal) Load() error {
|
||||
tx, err := f.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
for _, file := range f.files {
|
||||
if err := f.loadFixtures(tx, file); err != nil {
|
||||
return fmt.Errorf("failed to load fixtures from %s: %w", file, err)
|
||||
}
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func FixturesFileFullPaths(dir string, files []string) ([]string, error) {
|
||||
if files != nil && len(files) == 0 {
|
||||
return nil, nil // load nothing
|
||||
}
|
||||
files = slices.Clone(files)
|
||||
if len(files) == 0 {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range entries {
|
||||
files = append(files, e.Name())
|
||||
}
|
||||
}
|
||||
for i, file := range files {
|
||||
if !filepath.IsAbs(file) {
|
||||
files[i] = filepath.Join(dir, file)
|
||||
}
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, error) {
|
||||
files, err := FixturesFileFullPaths(opts.Dir, opts.Files)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get fixtures files: %w", err)
|
||||
}
|
||||
f := &fixturesLoaderInternal{db: x.DB().DB, dbType: x.Dialect().URI().DBType, files: files, fixtures: map[string]*fixtureItem{}}
|
||||
switch f.dbType {
|
||||
case schemas.SQLITE:
|
||||
f.quoteObject = func(s string) string { return fmt.Sprintf(`"%s"`, s) }
|
||||
f.paramPlaceholder = func(idx int) string { return "?" }
|
||||
case schemas.POSTGRES:
|
||||
f.quoteObject = func(s string) string { return fmt.Sprintf(`"%s"`, s) }
|
||||
f.paramPlaceholder = func(idx int) string { return fmt.Sprintf(`$%d`, idx) }
|
||||
case schemas.MYSQL:
|
||||
f.quoteObject = func(s string) string { return fmt.Sprintf("`%s`", s) }
|
||||
f.paramPlaceholder = func(idx int) string { return "?" }
|
||||
case schemas.MSSQL:
|
||||
f.quoteObject = func(s string) string { return fmt.Sprintf("[%s]", s) }
|
||||
f.paramPlaceholder = func(idx int) string { return "?" }
|
||||
}
|
||||
return f, nil
|
||||
}
|
@ -357,8 +357,8 @@ func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddres
|
||||
if user := GetVerifyUser(ctx, code); user != nil {
|
||||
// time limit code
|
||||
prefix := code[:base.TimeLimitCodeLength]
|
||||
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
|
||||
|
||||
opts := &TimeLimitCodeOptions{Purpose: TimeLimitCodeActivateEmail, NewEmail: email}
|
||||
data := makeTimeLimitCodeHashData(opts, user)
|
||||
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
|
||||
emailAddress := &EmailAddress{UID: user.ID, Email: email}
|
||||
if has, _ := db.GetEngine(ctx).Get(emailAddress); has {
|
||||
@ -486,10 +486,10 @@ func ActivateUserEmail(ctx context.Context, userID int64, email string, activate
|
||||
|
||||
// Activate/deactivate a user's primary email address and account
|
||||
if addr.IsPrimary {
|
||||
user, exist, err := db.Get[User](ctx, builder.Eq{"id": userID, "email": email})
|
||||
user, exist, err := db.Get[User](ctx, builder.Eq{"id": userID})
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exist {
|
||||
} else if !exist || !strings.EqualFold(user.Email, email) {
|
||||
return fmt.Errorf("no user with ID: %d and Email: %s", userID, email)
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,8 @@ func (u *User) BeforeUpdate() {
|
||||
u.MaxRepoCreation = -1
|
||||
}
|
||||
|
||||
// Organization does not need email
|
||||
// FIXME: this email doesn't need to be in lowercase, because the emails are mainly managed by the email table with lower_email field
|
||||
// This trick could be removed in new releases to display the user inputed email as-is.
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
if !u.IsOrganization() {
|
||||
if len(u.AvatarEmail) == 0 {
|
||||
@ -310,17 +311,6 @@ func (u *User) OrganisationLink() string {
|
||||
return setting.AppSubURL + "/org/" + url.PathEscape(u.Name)
|
||||
}
|
||||
|
||||
// GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
|
||||
func (u *User) GenerateEmailActivateCode(email string) string {
|
||||
code := base.CreateTimeLimitCode(
|
||||
fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
|
||||
setting.Service.ActiveCodeLives, time.Now(), nil)
|
||||
|
||||
// Add tail hex username
|
||||
code += hex.EncodeToString([]byte(u.LowerName))
|
||||
return code
|
||||
}
|
||||
|
||||
// GetUserFollowers returns range of user's followers.
|
||||
func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
@ -848,12 +838,38 @@ func GetVerifyUser(ctx context.Context, code string) (user *User) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyUserActiveCode verifies active code when active account
|
||||
func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
|
||||
type TimeLimitCodePurpose string
|
||||
|
||||
const (
|
||||
TimeLimitCodeActivateAccount TimeLimitCodePurpose = "activate_account"
|
||||
TimeLimitCodeActivateEmail TimeLimitCodePurpose = "activate_email"
|
||||
TimeLimitCodeResetPassword TimeLimitCodePurpose = "reset_password"
|
||||
)
|
||||
|
||||
type TimeLimitCodeOptions struct {
|
||||
Purpose TimeLimitCodePurpose
|
||||
NewEmail string
|
||||
}
|
||||
|
||||
func makeTimeLimitCodeHashData(opts *TimeLimitCodeOptions, u *User) string {
|
||||
return fmt.Sprintf("%s|%d|%s|%s|%s|%s", opts.Purpose, u.ID, strings.ToLower(util.IfZero(opts.NewEmail, u.Email)), u.LowerName, u.Passwd, u.Rands)
|
||||
}
|
||||
|
||||
// GenerateUserTimeLimitCode generates a time-limit code based on user information and given e-mail.
|
||||
// TODO: need to use cache or db to store it to make sure a code can only be consumed once
|
||||
func GenerateUserTimeLimitCode(opts *TimeLimitCodeOptions, u *User) string {
|
||||
data := makeTimeLimitCodeHashData(opts, u)
|
||||
code := base.CreateTimeLimitCode(data, setting.Service.ActiveCodeLives, time.Now(), nil)
|
||||
code += hex.EncodeToString([]byte(u.LowerName)) // Add tail hex username
|
||||
return code
|
||||
}
|
||||
|
||||
// VerifyUserTimeLimitCode verifies the time-limit code
|
||||
func VerifyUserTimeLimitCode(ctx context.Context, opts *TimeLimitCodeOptions, code string) (user *User) {
|
||||
if user = GetVerifyUser(ctx, code); user != nil {
|
||||
// time limit code
|
||||
prefix := code[:base.TimeLimitCodeLength]
|
||||
data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
|
||||
data := makeTimeLimitCodeHashData(opts, user)
|
||||
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
|
||||
return user
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ func BinToHex(objectFormat ObjectFormat, sha, out []byte) []byte {
|
||||
return out
|
||||
}
|
||||
|
||||
// ParseTreeLine reads an entry from a tree in a cat-file --batch stream
|
||||
// ParseCatFileTreeLine reads an entry from a tree in a cat-file --batch stream
|
||||
// This carefully avoids allocations - except where fnameBuf is too small.
|
||||
// It is recommended therefore to pass in an fnameBuf large enough to avoid almost all allocations
|
||||
//
|
||||
@ -261,7 +261,7 @@ func BinToHex(objectFormat ObjectFormat, sha, out []byte) []byte {
|
||||
// <mode-in-ascii-dropping-initial-zeros> SP <fname> NUL <binary HASH>
|
||||
//
|
||||
// We don't attempt to convert the raw HASH to save a lot of time
|
||||
func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
|
||||
func ParseCatFileTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBuf, shaBuf []byte) (mode, fname, sha []byte, n int, err error) {
|
||||
var readBytes []byte
|
||||
|
||||
// Read the Mode & fname
|
||||
@ -271,7 +271,7 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
|
||||
}
|
||||
idx := bytes.IndexByte(readBytes, ' ')
|
||||
if idx < 0 {
|
||||
log.Debug("missing space in readBytes ParseTreeLine: %s", readBytes)
|
||||
log.Debug("missing space in readBytes ParseCatFileTreeLine: %s", readBytes)
|
||||
return mode, fname, sha, n, &ErrNotExist{}
|
||||
}
|
||||
|
||||
|
78
modules/git/parse.go
Normal file
78
modules/git/parse.go
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
)
|
||||
|
||||
var sepSpace = []byte{' '}
|
||||
|
||||
type LsTreeEntry struct {
|
||||
ID ObjectID
|
||||
EntryMode EntryMode
|
||||
Name string
|
||||
Size optional.Option[int64]
|
||||
}
|
||||
|
||||
func parseLsTreeLine(line []byte) (*LsTreeEntry, error) {
|
||||
// expect line to be of the form:
|
||||
// <mode> <type> <sha> <space-padded-size>\t<filename>
|
||||
// <mode> <type> <sha>\t<filename>
|
||||
|
||||
var err error
|
||||
posTab := bytes.IndexByte(line, '\t')
|
||||
if posTab == -1 {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (no tab): %q", line)
|
||||
}
|
||||
|
||||
entry := new(LsTreeEntry)
|
||||
|
||||
entryAttrs := line[:posTab]
|
||||
entryName := line[posTab+1:]
|
||||
|
||||
entryMode, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
|
||||
_ /* entryType */, entryAttrs, _ = bytes.Cut(entryAttrs, sepSpace) // the type is not used, the mode is enough to determine the type
|
||||
entryObjectID, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
|
||||
if len(entryAttrs) > 0 {
|
||||
entrySize := entryAttrs // the last field is the space-padded-size
|
||||
size, _ := strconv.ParseInt(strings.TrimSpace(string(entrySize)), 10, 64)
|
||||
entry.Size = optional.Some(size)
|
||||
}
|
||||
|
||||
switch string(entryMode) {
|
||||
case "100644":
|
||||
entry.EntryMode = EntryModeBlob
|
||||
case "100755":
|
||||
entry.EntryMode = EntryModeExec
|
||||
case "120000":
|
||||
entry.EntryMode = EntryModeSymlink
|
||||
case "160000":
|
||||
entry.EntryMode = EntryModeCommit
|
||||
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
|
||||
entry.EntryMode = EntryModeTree
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
|
||||
}
|
||||
|
||||
entry.ID, err = NewIDFromString(string(entryObjectID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
|
||||
}
|
||||
|
||||
if len(entryName) > 0 && entryName[0] == '"' {
|
||||
entry.Name, err = strconv.Unquote(string(entryName))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
|
||||
}
|
||||
} else {
|
||||
entry.Name = string(entryName)
|
||||
}
|
||||
return entry, nil
|
||||
}
|
@ -10,8 +10,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
@ -21,71 +19,30 @@ func ParseTreeEntries(data []byte) ([]*TreeEntry, error) {
|
||||
return parseTreeEntries(data, nil)
|
||||
}
|
||||
|
||||
var sepSpace = []byte{' '}
|
||||
|
||||
// parseTreeEntries FIXME this function's design is not right, it should make the caller read all data into memory
|
||||
func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||
var err error
|
||||
entries := make([]*TreeEntry, 0, bytes.Count(data, []byte{'\n'})+1)
|
||||
for pos := 0; pos < len(data); {
|
||||
// expect line to be of the form:
|
||||
// <mode> <type> <sha> <space-padded-size>\t<filename>
|
||||
// <mode> <type> <sha>\t<filename>
|
||||
posEnd := bytes.IndexByte(data[pos:], '\n')
|
||||
if posEnd == -1 {
|
||||
posEnd = len(data)
|
||||
} else {
|
||||
posEnd += pos
|
||||
}
|
||||
|
||||
line := data[pos:posEnd]
|
||||
posTab := bytes.IndexByte(line, '\t')
|
||||
if posTab == -1 {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (no tab): %q", line)
|
||||
}
|
||||
|
||||
entry := new(TreeEntry)
|
||||
entry.ptree = ptree
|
||||
|
||||
entryAttrs := line[:posTab]
|
||||
entryName := line[posTab+1:]
|
||||
|
||||
entryMode, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
|
||||
_ /* entryType */, entryAttrs, _ = bytes.Cut(entryAttrs, sepSpace) // the type is not used, the mode is enough to determine the type
|
||||
entryObjectID, entryAttrs, _ := bytes.Cut(entryAttrs, sepSpace)
|
||||
if len(entryAttrs) > 0 {
|
||||
entrySize := entryAttrs // the last field is the space-padded-size
|
||||
entry.size, _ = strconv.ParseInt(strings.TrimSpace(string(entrySize)), 10, 64)
|
||||
entry.sized = true
|
||||
}
|
||||
|
||||
switch string(entryMode) {
|
||||
case "100644":
|
||||
entry.entryMode = EntryModeBlob
|
||||
case "100755":
|
||||
entry.entryMode = EntryModeExec
|
||||
case "120000":
|
||||
entry.entryMode = EntryModeSymlink
|
||||
case "160000":
|
||||
entry.entryMode = EntryModeCommit
|
||||
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
|
||||
entry.entryMode = EntryModeTree
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown type: %v", string(entryMode))
|
||||
}
|
||||
|
||||
entry.ID, err = NewIDFromString(string(entryObjectID))
|
||||
lsTreeLine, err := parseLsTreeLine(line)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (invalid object id): %q, err: %w", line, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(entryName) > 0 && entryName[0] == '"' {
|
||||
entry.name, err = strconv.Unquote(string(entryName))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid ls-tree output (invalid name): %q, err: %w", line, err)
|
||||
}
|
||||
} else {
|
||||
entry.name = string(entryName)
|
||||
entry := &TreeEntry{
|
||||
ptree: ptree,
|
||||
ID: lsTreeLine.ID,
|
||||
entryMode: lsTreeLine.EntryMode,
|
||||
name: lsTreeLine.Name,
|
||||
size: lsTreeLine.Size.Value(),
|
||||
sized: lsTreeLine.Size.Has(),
|
||||
}
|
||||
|
||||
pos = posEnd + 1
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
@ -100,7 +57,7 @@ func catBatchParseTreeEntries(objectFormat ObjectFormat, ptree *Tree, rd *bufio.
|
||||
|
||||
loop:
|
||||
for sz > 0 {
|
||||
mode, fname, sha, count, err := ParseTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf)
|
||||
mode, fname, sha, count, err := ParseCatFileTreeLine(objectFormat, rd, modeBuf, fnameBuf, shaBuf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break loop
|
||||
|
@ -114,7 +114,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
|
||||
case "tree":
|
||||
var n int64
|
||||
for n < size {
|
||||
mode, fname, binObjectID, count, err := git.ParseTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf)
|
||||
mode, fname, binObjectID, count, err := git.ParseCatFileTreeLine(objectID.Type(), batchReader, modeBuf, fnameBuf, workingShaBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
giturl "code.gitea.io/gitea/modules/git/url"
|
||||
)
|
||||
@ -37,3 +38,12 @@ func GetRemoteURL(ctx context.Context, repoPath, remoteName string) (*giturl.Git
|
||||
}
|
||||
return giturl.Parse(addr)
|
||||
}
|
||||
|
||||
// IsRemoteNotExistError checks the prefix of the error message to see whether a remote does not exist.
|
||||
func IsRemoteNotExistError(err error) bool {
|
||||
// see: https://github.com/go-gitea/gitea/issues/32889#issuecomment-2571848216
|
||||
// Should not add space in the end, sometimes git will add a `:`
|
||||
prefix1 := "exit status 128 - fatal: No such remote" // git < 2.30
|
||||
prefix2 := "exit status 2 - error: No such remote" // git >= 2.30
|
||||
return strings.HasPrefix(err.Error(), prefix1) || strings.HasPrefix(err.Error(), prefix2)
|
||||
}
|
||||
|
@ -216,8 +216,6 @@ type CommitsByFileAndRangeOptions struct {
|
||||
|
||||
// CommitsByFileAndRange return the commits according revision file and the page
|
||||
func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) ([]*Commit, error) {
|
||||
skip := (opts.Page - 1) * setting.Git.CommitsRangeSize
|
||||
|
||||
stdoutReader, stdoutWriter := io.Pipe()
|
||||
defer func() {
|
||||
_ = stdoutReader.Close()
|
||||
@ -226,8 +224,8 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions)
|
||||
go func() {
|
||||
stderr := strings.Builder{}
|
||||
gitCmd := NewCommand(repo.Ctx, "rev-list").
|
||||
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize*opts.Page).
|
||||
AddOptionFormat("--skip=%d", skip)
|
||||
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize).
|
||||
AddOptionFormat("--skip=%d", (opts.Page-1)*setting.Git.CommitsRangeSize)
|
||||
gitCmd.AddDynamicArguments(opts.Revision)
|
||||
|
||||
if opts.Not != "" {
|
||||
|
@ -8,7 +8,11 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRepository_GetCommitBranches(t *testing.T) {
|
||||
@ -126,3 +130,21 @@ func TestGetRefCommitID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitsByFileAndRange(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Git.CommitsRangeSize, 2)()
|
||||
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||
bareRepo1, err := openRepositoryWithDefaultContext(bareRepo1Path)
|
||||
require.NoError(t, err)
|
||||
defer bareRepo1.Close()
|
||||
|
||||
// "foo" has 3 commits in "master" branch
|
||||
commits, err := bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 1})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, commits, 2)
|
||||
|
||||
commits, err = bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{Revision: "master", File: "foo", Page: 2})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, commits, 1)
|
||||
}
|
||||
|
66
modules/git/submodule.go
Normal file
66
modules/git/submodule.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
type TemplateSubmoduleCommit struct {
|
||||
Path string
|
||||
Commit string
|
||||
}
|
||||
|
||||
// GetTemplateSubmoduleCommits returns a list of submodules paths and their commits from a repository
|
||||
// This function is only for generating new repos based on existing template, the template couldn't be too large.
|
||||
func GetTemplateSubmoduleCommits(ctx context.Context, repoPath string) (submoduleCommits []TemplateSubmoduleCommit, _ error) {
|
||||
stdoutReader, stdoutWriter, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := &RunOpts{
|
||||
Dir: repoPath,
|
||||
Stdout: stdoutWriter,
|
||||
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
|
||||
_ = stdoutWriter.Close()
|
||||
defer stdoutReader.Close()
|
||||
|
||||
scanner := bufio.NewScanner(stdoutReader)
|
||||
for scanner.Scan() {
|
||||
entry, err := parseLsTreeLine(scanner.Bytes())
|
||||
if err != nil {
|
||||
cancel()
|
||||
return err
|
||||
}
|
||||
if entry.EntryMode == EntryModeCommit {
|
||||
submoduleCommits = append(submoduleCommits, TemplateSubmoduleCommit{Path: entry.Name, Commit: entry.ID.String()})
|
||||
}
|
||||
}
|
||||
return scanner.Err()
|
||||
},
|
||||
}
|
||||
err = NewCommand(ctx, "ls-tree", "-r", "--", "HEAD").Run(opts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetTemplateSubmoduleCommits: error running git ls-tree: %v", err)
|
||||
}
|
||||
return submoduleCommits, nil
|
||||
}
|
||||
|
||||
// AddTemplateSubmoduleIndexes Adds the given submodules to the git index.
|
||||
// It is only for generating new repos based on existing template, requires the .gitmodules file to be already present in the work dir.
|
||||
func AddTemplateSubmoduleIndexes(ctx context.Context, repoPath string, submodules []TemplateSubmoduleCommit) error {
|
||||
for _, submodule := range submodules {
|
||||
cmd := NewCommand(ctx, "update-index", "--add", "--cacheinfo", "160000").AddDynamicArguments(submodule.Commit, submodule.Path)
|
||||
if stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath}); err != nil {
|
||||
log.Error("Unable to add %s as submodule to repo %s: stdout %s\nError: %v", submodule.Path, repoPath, stdout, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
48
modules/git/submodule_test.go
Normal file
48
modules/git/submodule_test.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetTemplateSubmoduleCommits(t *testing.T) {
|
||||
testRepoPath := filepath.Join(testReposDir, "repo4_submodules")
|
||||
submodules, err := GetTemplateSubmoduleCommits(DefaultContext, testRepoPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Len(t, submodules, 2)
|
||||
|
||||
assert.EqualValues(t, "<°)))><", submodules[0].Path)
|
||||
assert.EqualValues(t, "d2932de67963f23d43e1c7ecf20173e92ee6c43c", submodules[0].Commit)
|
||||
|
||||
assert.EqualValues(t, "libtest", submodules[1].Path)
|
||||
assert.EqualValues(t, "1234567890123456789012345678901234567890", submodules[1].Commit)
|
||||
}
|
||||
|
||||
func TestAddTemplateSubmoduleIndexes(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
tmpDir := t.TempDir()
|
||||
var err error
|
||||
_, _, err = NewCommand(ctx, "init").RunStdString(&RunOpts{Dir: tmpDir})
|
||||
require.NoError(t, err)
|
||||
_ = os.Mkdir(filepath.Join(tmpDir, "new-dir"), 0o755)
|
||||
err = AddTemplateSubmoduleIndexes(ctx, tmpDir, []TemplateSubmoduleCommit{{Path: "new-dir", Commit: "1234567890123456789012345678901234567890"}})
|
||||
require.NoError(t, err)
|
||||
_, _, err = NewCommand(ctx, "add", "--all").RunStdString(&RunOpts{Dir: tmpDir})
|
||||
require.NoError(t, err)
|
||||
_, _, err = NewCommand(ctx, "-c", "user.name=a", "-c", "user.email=b", "commit", "-m=test").RunStdString(&RunOpts{Dir: tmpDir})
|
||||
require.NoError(t, err)
|
||||
submodules, err := GetTemplateSubmoduleCommits(DefaultContext, tmpDir)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, submodules, 1)
|
||||
assert.EqualValues(t, "new-dir", submodules[0].Path)
|
||||
assert.EqualValues(t, "1234567890123456789012345678901234567890", submodules[0].Commit)
|
||||
}
|
1
modules/git/tests/repos/repo4_submodules/HEAD
Normal file
1
modules/git/tests/repos/repo4_submodules/HEAD
Normal file
@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
4
modules/git/tests/repos/repo4_submodules/config
Normal file
4
modules/git/tests/repos/repo4_submodules/config
Normal file
@ -0,0 +1,4 @@
|
||||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
x<01><>[
|
||||
Β0EύΞ*ζ_<CEB6>ι$MΡ5tifBk IΕ•Ή7ζk~ήΓ9ά<39>—εά ό¦π.jΦΘ ΕOΪδΙ"zΒ`ί#I<>irF…µΝΉΐΨ$%ΉΒης|4)°―?tΌΙ=”Λ:K¦ο#[$DΏ―ϋΏ^<5E><>…΅®Σ’y½HU/<2F>f?G
|
@ -0,0 +1 @@
|
||||
e1e59caba97193d48862d6809912043871f37437
|
@ -17,7 +17,7 @@ func NewTree(repo *Repository, id ObjectID) *Tree {
|
||||
}
|
||||
}
|
||||
|
||||
// SubTree get a sub tree by the sub dir path
|
||||
// SubTree get a subtree by the sub dir path
|
||||
func (t *Tree) SubTree(rpath string) (*Tree, error) {
|
||||
if len(rpath) == 0 {
|
||||
return t, nil
|
||||
@ -62,3 +62,14 @@ func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error
|
||||
|
||||
return filelist, err
|
||||
}
|
||||
|
||||
// GetTreePathLatestCommit returns the latest commit of a tree path
|
||||
func (repo *Repository) GetTreePathLatestCommit(refName, treePath string) (*Commit, error) {
|
||||
stdout, _, err := NewCommand(repo.Ctx, "rev-list", "-1").
|
||||
AddDynamicArguments(refName).AddDashesAndList(treePath).
|
||||
RunStdString(&RunOpts{Dir: repo.Path})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.GetCommit(strings.TrimSpace(stdout))
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
|
||||
ptree: t,
|
||||
ID: t.ID,
|
||||
name: "",
|
||||
fullName: "",
|
||||
entryMode: EntryModeTree,
|
||||
}, nil
|
||||
}
|
||||
|
@ -9,23 +9,17 @@ import "code.gitea.io/gitea/modules/log"
|
||||
|
||||
// TreeEntry the leaf in the git tree
|
||||
type TreeEntry struct {
|
||||
ID ObjectID
|
||||
|
||||
ID ObjectID
|
||||
ptree *Tree
|
||||
|
||||
entryMode EntryMode
|
||||
name string
|
||||
|
||||
size int64
|
||||
sized bool
|
||||
fullName string
|
||||
size int64
|
||||
sized bool
|
||||
}
|
||||
|
||||
// Name returns the name of the entry
|
||||
func (te *TreeEntry) Name() string {
|
||||
if te.fullName != "" {
|
||||
return te.fullName
|
||||
}
|
||||
return te.name
|
||||
}
|
||||
|
||||
|
@ -25,3 +25,18 @@ func TestSubTree_Issue29101(t *testing.T) {
|
||||
assert.True(t, IsErrNotExist(err))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_GetTreePathLatestCommit(t *testing.T) {
|
||||
repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo6_blame"))
|
||||
assert.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
commitID, err := repo.GetBranchCommitID("master")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7", commitID)
|
||||
|
||||
commit, err := repo.GetTreePathLatestCommit("master", "blame.txt")
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, commit)
|
||||
assert.EqualValues(t, "45fb6cbc12f970b04eacd5cd4165edd11c8d7376", commit.ID.String())
|
||||
}
|
||||
|
@ -123,13 +123,12 @@ func Init() {
|
||||
for _, indexerData := range items {
|
||||
log.Trace("IndexerData Process Repo: %d", indexerData.RepoID)
|
||||
if err := index(ctx, indexer, indexerData.RepoID); err != nil {
|
||||
unhandled = append(unhandled, indexerData)
|
||||
if !setting.IsInTesting {
|
||||
log.Error("Codes indexer handler: index error for repo %v: %v", indexerData.RepoID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return unhandled
|
||||
return nil // do not re-queue the failed items, otherwise some broken repo will block the queue
|
||||
}
|
||||
|
||||
indexerQueue = queue.CreateUniqueQueue(ctx, "code_indexer", handler)
|
||||
|
@ -15,6 +15,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/indexer/code/bleve"
|
||||
"code.gitea.io/gitea/modules/indexer/code/elasticsearch"
|
||||
"code.gitea.io/gitea/modules/indexer/code/internal"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
_ "code.gitea.io/gitea/models"
|
||||
_ "code.gitea.io/gitea/models/actions"
|
||||
@ -279,7 +281,7 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) {
|
||||
|
||||
func TestBleveIndexAndSearch(t *testing.T) {
|
||||
unittest.PrepareTestEnv(t)
|
||||
|
||||
defer test.MockVariableValue(&setting.Indexer.TypeBleveMaxFuzzniess, 2)()
|
||||
dir := t.TempDir()
|
||||
|
||||
idx := bleve.NewIndexer(dir)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/blevesearch/bleve/v2"
|
||||
@ -54,9 +55,9 @@ func openIndexer(path string, latestVersion int) (bleve.Index, int, error) {
|
||||
return index, 0, nil
|
||||
}
|
||||
|
||||
// This method test the GuessFuzzinessByKeyword method. The fuzziness is based on the levenshtein distance and determines how many chars
|
||||
// may be different on two string and they still be considered equivalent.
|
||||
// Given a phrasse, its shortest word determines its fuzziness. If a phrase uses CJK (eg: `갃갃갃` `啊啊啊`), the fuzziness is zero.
|
||||
// GuessFuzzinessByKeyword guesses fuzziness based on the levenshtein distance and determines how many chars
|
||||
// may be different on two string, and they still be considered equivalent.
|
||||
// Given a phrase, its shortest word determines its fuzziness. If a phrase uses CJK (eg: `갃갃갃` `啊啊啊`), the fuzziness is zero.
|
||||
func GuessFuzzinessByKeyword(s string) int {
|
||||
tokenizer := unicode_tokenizer.NewUnicodeTokenizer()
|
||||
tokens := tokenizer.Tokenize([]byte(s))
|
||||
@ -85,5 +86,5 @@ func guessFuzzinessByKeyword(s string) int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return min(maxFuzziness, len(s)/4)
|
||||
return min(min(setting.Indexer.TypeBleveMaxFuzzniess, maxFuzziness), len(s)/4)
|
||||
}
|
||||
|
@ -7,10 +7,15 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBleveGuessFuzzinessByKeyword(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.Indexer.TypeBleveMaxFuzzniess, 2)()
|
||||
|
||||
scenarios := []struct {
|
||||
Input string
|
||||
Fuzziness int // See util.go for the definition of fuzziness in this particular context
|
||||
@ -46,7 +51,7 @@ func TestBleveGuessFuzzinessByKeyword(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(fmt.Sprintf("ensure fuzziness of '%s' is '%d'", scenario.Input, scenario.Fuzziness), func(t *testing.T) {
|
||||
t.Run(fmt.Sprintf("Fuziniess:%s=%d", scenario.Input, scenario.Fuzziness), func(t *testing.T) {
|
||||
assert.Equal(t, scenario.Fuzziness, GuessFuzzinessByKeyword(scenario.Input))
|
||||
})
|
||||
}
|
||||
|
@ -13,10 +13,9 @@ import (
|
||||
type Event struct {
|
||||
Time time.Time
|
||||
|
||||
GoroutinePid string
|
||||
Caller string
|
||||
Filename string
|
||||
Line int
|
||||
Caller string
|
||||
Filename string
|
||||
Line int
|
||||
|
||||
Level Level
|
||||
|
||||
@ -218,17 +217,16 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms
|
||||
}
|
||||
|
||||
if flags&Lgopid == Lgopid {
|
||||
if event.GoroutinePid != "" {
|
||||
buf = append(buf, '[')
|
||||
if mode.Colorize {
|
||||
buf = append(buf, ColorBytes(FgHiYellow)...)
|
||||
}
|
||||
buf = append(buf, event.GoroutinePid...)
|
||||
if mode.Colorize {
|
||||
buf = append(buf, resetBytes...)
|
||||
}
|
||||
buf = append(buf, ']', ' ')
|
||||
deprecatedGoroutinePid := "no-gopid" // use a dummy value to avoid breaking the log format
|
||||
buf = append(buf, '[')
|
||||
if mode.Colorize {
|
||||
buf = append(buf, ColorBytes(FgHiYellow)...)
|
||||
}
|
||||
buf = append(buf, deprecatedGoroutinePid...)
|
||||
if mode.Colorize {
|
||||
buf = append(buf, resetBytes...)
|
||||
}
|
||||
buf = append(buf, ']', ' ')
|
||||
}
|
||||
buf = append(buf, msg...)
|
||||
|
||||
|
@ -24,34 +24,32 @@ func TestItoa(t *testing.T) {
|
||||
func TestEventFormatTextMessage(t *testing.T) {
|
||||
res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: 0xffffffff}},
|
||||
&Event{
|
||||
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
Caller: "caller",
|
||||
Filename: "filename",
|
||||
Line: 123,
|
||||
GoroutinePid: "pid",
|
||||
Level: ERROR,
|
||||
Stacktrace: "stacktrace",
|
||||
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
Caller: "caller",
|
||||
Filename: "filename",
|
||||
Line: 123,
|
||||
Level: ERROR,
|
||||
Stacktrace: "stacktrace",
|
||||
},
|
||||
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
||||
)
|
||||
|
||||
assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [pid] msg format: arg0 arg1
|
||||
assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1
|
||||
stacktrace
|
||||
|
||||
`, string(res))
|
||||
|
||||
res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: 0xffffffff}},
|
||||
&Event{
|
||||
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
Caller: "caller",
|
||||
Filename: "filename",
|
||||
Line: 123,
|
||||
GoroutinePid: "pid",
|
||||
Level: ERROR,
|
||||
Stacktrace: "stacktrace",
|
||||
Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
|
||||
Caller: "caller",
|
||||
Filename: "filename",
|
||||
Line: 123,
|
||||
Level: ERROR,
|
||||
Stacktrace: "stacktrace",
|
||||
},
|
||||
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
|
||||
)
|
||||
|
||||
assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mpid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
|
||||
assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ const (
|
||||
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
|
||||
Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info
|
||||
Llevel // Provided level in brackets [INFO]
|
||||
Lgopid // the Goroutine-PID of the context
|
||||
Lgopid // the Goroutine-PID of the context, deprecated and it is always a const value
|
||||
|
||||
Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename
|
||||
LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial // default
|
||||
|
@ -1,19 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package log
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel
|
||||
func runtime_getProfLabel() unsafe.Pointer //nolint
|
||||
|
||||
type labelMap map[string]string
|
||||
|
||||
func getGoroutineLabels() map[string]string {
|
||||
l := (*labelMap)(runtime_getProfLabel())
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
return *l
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime/pprof"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_getGoroutineLabels(t *testing.T) {
|
||||
pprof.Do(context.Background(), pprof.Labels(), func(ctx context.Context) {
|
||||
currentLabels := getGoroutineLabels()
|
||||
pprof.ForLabels(ctx, func(key, value string) bool {
|
||||
assert.EqualValues(t, value, currentLabels[key])
|
||||
return true
|
||||
})
|
||||
|
||||
pprof.Do(ctx, pprof.Labels("Test_getGoroutineLabels", "Test_getGoroutineLabels_child1"), func(ctx context.Context) {
|
||||
currentLabels := getGoroutineLabels()
|
||||
pprof.ForLabels(ctx, func(key, value string) bool {
|
||||
assert.EqualValues(t, value, currentLabels[key])
|
||||
return true
|
||||
})
|
||||
if assert.NotNil(t, currentLabels) {
|
||||
assert.EqualValues(t, "Test_getGoroutineLabels_child1", currentLabels["Test_getGoroutineLabels"])
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
@ -200,11 +200,6 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
|
||||
event.Stacktrace = Stack(skip + 1)
|
||||
}
|
||||
|
||||
labels := getGoroutineLabels()
|
||||
if labels != nil {
|
||||
event.GoroutinePid = labels["pid"]
|
||||
}
|
||||
|
||||
// get a simple text message without color
|
||||
msgArgs := make([]any, len(logArgs))
|
||||
copy(msgArgs, logArgs)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/markup/common"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
"golang.org/x/net/html/atom"
|
||||
@ -171,6 +172,10 @@ func linkProcessor(ctx *RenderContext, node *html.Node) {
|
||||
}
|
||||
|
||||
uri := node.Data[m[0]:m[1]]
|
||||
remaining := node.Data[m[1]:]
|
||||
if util.IsLikelySplitLeftPart(remaining) {
|
||||
return
|
||||
}
|
||||
replaceContent(node, m[0], m[1], createLink(ctx, uri, uri, "" /*link*/))
|
||||
node = node.NextSibling.NextSibling
|
||||
}
|
||||
|
@ -206,6 +206,16 @@ func TestRender_links(t *testing.T) {
|
||||
test(
|
||||
"ftps://gitea.com",
|
||||
`<p>ftps://gitea.com</p>`)
|
||||
|
||||
t.Run("LinkSplit", func(t *testing.T) {
|
||||
input, _ := util.SplitStringAtByteN("http://10.1.2.3", 12)
|
||||
assert.Equal(t, "http://10…", input)
|
||||
test(input, "<p>http://10…</p>")
|
||||
|
||||
input, _ = util.SplitStringAtByteN("http://10.1.2.3", 13)
|
||||
assert.Equal(t, "http://10.…", input)
|
||||
test(input, "<p>http://10.…</p>")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRender_email(t *testing.T) {
|
||||
|
@ -129,7 +129,8 @@ func SpecializedMarkdown(ctx *markup.RenderContext) *GlodmarkRender {
|
||||
Enabled: setting.Markdown.EnableMath,
|
||||
ParseDollarInline: true,
|
||||
ParseDollarBlock: true,
|
||||
ParseSquareBlock: true, // TODO: this is a bad syntax, it should be deprecated in the future (by some config options)
|
||||
ParseSquareBlock: true, // TODO: this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping, it should be deprecated in the future (by some config options)
|
||||
// ParseBracketInline: true, // TODO: this is also a bad syntax "\( ... \)", it also conflicts, it should be deprecated in the future
|
||||
}),
|
||||
meta.Meta,
|
||||
),
|
||||
|
@ -103,8 +103,8 @@ func HelloWorld() {
|
||||
}
|
||||
#+end_src
|
||||
`, `<div class="src src-go">
|
||||
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints "Hello World"
|
||||
</span><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
||||
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints "Hello World"</span>
|
||||
<span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
|
||||
<span class="p">}</span></code></pre>
|
||||
</div>`)
|
||||
|
@ -43,8 +43,9 @@ var (
|
||||
ErrInvalidArchitecture = util.NewInvalidArgumentErrorf("package architecture is invalid")
|
||||
|
||||
// https://man.archlinux.org/man/PKGBUILD.5
|
||||
namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`)
|
||||
versionPattern = regexp.MustCompile(`\A(?:[0-9]:)?[a-zA-Z0-9.+~]+(?:-[a-zA-Z0-9.+-~]+)?\z`)
|
||||
namePattern = regexp.MustCompile(`\A[a-zA-Z0-9@._+-]+\z`)
|
||||
// (epoch:pkgver-pkgrel)
|
||||
versionPattern = regexp.MustCompile(`\A(?:\d:)?[\w.+~]+(?:-[-\w.+~]+)?\z`)
|
||||
)
|
||||
|
||||
type Package struct {
|
||||
@ -69,10 +70,12 @@ type FileMetadata struct {
|
||||
Packager string `json:"packager,omitempty"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Provides []string `json:"provides,omitempty"`
|
||||
Replaces []string `json:"replaces,omitempty"`
|
||||
Depends []string `json:"depends,omitempty"`
|
||||
OptDepends []string `json:"opt_depends,omitempty"`
|
||||
MakeDepends []string `json:"make_depends,omitempty"`
|
||||
CheckDepends []string `json:"check_depends,omitempty"`
|
||||
Conflicts []string `json:"conflicts,omitempty"`
|
||||
XData []string `json:"xdata,omitempty"`
|
||||
Backup []string `json:"backup,omitempty"`
|
||||
Files []string `json:"files,omitempty"`
|
||||
@ -201,12 +204,16 @@ func ParsePackageInfo(r io.Reader) (*Package, error) {
|
||||
p.FileMetadata.Provides = append(p.FileMetadata.Provides, value)
|
||||
case "depend":
|
||||
p.FileMetadata.Depends = append(p.FileMetadata.Depends, value)
|
||||
case "replaces":
|
||||
p.FileMetadata.Replaces = append(p.FileMetadata.Replaces, value)
|
||||
case "optdepend":
|
||||
p.FileMetadata.OptDepends = append(p.FileMetadata.OptDepends, value)
|
||||
case "makedepend":
|
||||
p.FileMetadata.MakeDepends = append(p.FileMetadata.MakeDepends, value)
|
||||
case "checkdepend":
|
||||
p.FileMetadata.CheckDepends = append(p.FileMetadata.CheckDepends, value)
|
||||
case "conflict":
|
||||
p.FileMetadata.Conflicts = append(p.FileMetadata.Conflicts, value)
|
||||
case "backup":
|
||||
p.FileMetadata.Backup = append(p.FileMetadata.Backup, value)
|
||||
case "group":
|
||||
|
@ -42,8 +42,10 @@ depend = gitea
|
||||
provides = common
|
||||
provides = gitea
|
||||
optdepend = hex
|
||||
replaces = gogs
|
||||
checkdepend = common
|
||||
makedepend = cmake
|
||||
conflict = ninja
|
||||
backup = usr/bin/paket1`)
|
||||
}
|
||||
|
||||
@ -120,6 +122,14 @@ func TestParsePackageInfo(t *testing.T) {
|
||||
assert.ErrorIs(t, err, ErrInvalidName)
|
||||
})
|
||||
|
||||
t.Run("Regexp", func(t *testing.T) {
|
||||
assert.Regexp(t, versionPattern, "1.2_3~4+5")
|
||||
assert.Regexp(t, versionPattern, "1:2_3~4+5")
|
||||
assert.NotRegexp(t, versionPattern, "a:1.0.0-1")
|
||||
assert.NotRegexp(t, versionPattern, "0.0.1/1-1")
|
||||
assert.NotRegexp(t, versionPattern, "1.0.0 -1")
|
||||
})
|
||||
|
||||
t.Run("InvalidVersion", func(t *testing.T) {
|
||||
data := createPKGINFOContent(packageName, "")
|
||||
|
||||
@ -149,8 +159,10 @@ func TestParsePackageInfo(t *testing.T) {
|
||||
assert.ElementsMatch(t, []string{"group"}, p.FileMetadata.Groups)
|
||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Provides)
|
||||
assert.ElementsMatch(t, []string{"common", "gitea"}, p.FileMetadata.Depends)
|
||||
assert.ElementsMatch(t, []string{"gogs"}, p.FileMetadata.Replaces)
|
||||
assert.ElementsMatch(t, []string{"hex"}, p.FileMetadata.OptDepends)
|
||||
assert.ElementsMatch(t, []string{"common"}, p.FileMetadata.CheckDepends)
|
||||
assert.ElementsMatch(t, []string{"ninja"}, p.FileMetadata.Conflicts)
|
||||
assert.ElementsMatch(t, []string{"cmake"}, p.FileMetadata.MakeDepends)
|
||||
assert.ElementsMatch(t, []string{"usr/bin/paket1"}, p.FileMetadata.Backup)
|
||||
})
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
|
||||
"golang.org/x/net/html/charset"
|
||||
@ -31,18 +32,27 @@ type Dependency struct {
|
||||
}
|
||||
|
||||
type pomStruct struct {
|
||||
XMLName xml.Name `xml:"project"`
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Version string `xml:"version"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
URL string `xml:"url"`
|
||||
Licenses []struct {
|
||||
XMLName xml.Name `xml:"project"`
|
||||
|
||||
Parent struct {
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Version string `xml:"version"`
|
||||
} `xml:"parent"`
|
||||
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
Version string `xml:"version"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description"`
|
||||
URL string `xml:"url"`
|
||||
|
||||
Licenses []struct {
|
||||
Name string `xml:"name"`
|
||||
URL string `xml:"url"`
|
||||
Distribution string `xml:"distribution"`
|
||||
} `xml:"licenses>license"`
|
||||
|
||||
Dependencies []struct {
|
||||
GroupID string `xml:"groupId"`
|
||||
ArtifactID string `xml:"artifactId"`
|
||||
@ -81,8 +91,16 @@ func ParsePackageMetaData(r io.Reader) (*Metadata, error) {
|
||||
})
|
||||
}
|
||||
|
||||
pomGroupID := pom.GroupID
|
||||
if pomGroupID == "" {
|
||||
// the current module could inherit parent: https://maven.apache.org/pom.html#Inheritance
|
||||
pomGroupID = pom.Parent.GroupID
|
||||
}
|
||||
if pomGroupID == "" {
|
||||
return nil, util.ErrInvalidArgument
|
||||
}
|
||||
return &Metadata{
|
||||
GroupID: pom.GroupID,
|
||||
GroupID: pomGroupID,
|
||||
ArtifactID: pom.ArtifactID,
|
||||
Name: pom.Name,
|
||||
Description: pom.Description,
|
||||
|
@ -7,7 +7,10 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
)
|
||||
|
||||
@ -86,4 +89,35 @@ func TestParsePackageMetaData(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, m)
|
||||
})
|
||||
|
||||
t.Run("ParentInherit", func(t *testing.T) {
|
||||
pom := `<?xml version="1.0"?>
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.mycompany.app</groupId>
|
||||
<artifactId>my-app</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>submodule1</artifactId>
|
||||
</project>
|
||||
`
|
||||
m, err := ParsePackageMetaData(strings.NewReader(pom))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, m)
|
||||
|
||||
assert.Equal(t, "com.mycompany.app", m.GroupID)
|
||||
assert.Equal(t, "submodule1", m.ArtifactID)
|
||||
})
|
||||
|
||||
t.Run("ParentInherit", func(t *testing.T) {
|
||||
pom := `<?xml version="1.0"?>
|
||||
<project>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId></artifactId>
|
||||
</project>
|
||||
`
|
||||
_, err := ParsePackageMetaData(strings.NewReader(pom))
|
||||
require.ErrorIs(t, err, util.ErrInvalidArgument)
|
||||
})
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ type PackageMetadataVersion struct {
|
||||
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
||||
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
||||
PeerDependenciesMeta map[string]any `json:"peerDependenciesMeta,omitempty"`
|
||||
Bin map[string]string `json:"bin,omitempty"`
|
||||
OptionalDependencies map[string]string `json:"optionalDependencies,omitempty"`
|
||||
Readme string `json:"readme,omitempty"`
|
||||
@ -222,6 +223,7 @@ func ParsePackage(r io.Reader) (*Package, error) {
|
||||
BundleDependencies: meta.BundleDependencies,
|
||||
DevelopmentDependencies: meta.DevDependencies,
|
||||
PeerDependencies: meta.PeerDependencies,
|
||||
PeerDependenciesMeta: meta.PeerDependenciesMeta,
|
||||
OptionalDependencies: meta.OptionalDependencies,
|
||||
Bin: meta.Bin,
|
||||
Readme: meta.Readme,
|
||||
|
@ -19,6 +19,7 @@ type Metadata struct {
|
||||
BundleDependencies []string `json:"bundleDependencies,omitempty"`
|
||||
DevelopmentDependencies map[string]string `json:"development_dependencies,omitempty"`
|
||||
PeerDependencies map[string]string `json:"peer_dependencies,omitempty"`
|
||||
PeerDependenciesMeta map[string]any `json:"peer_dependencies_meta,omitempty"`
|
||||
OptionalDependencies map[string]string `json:"optional_dependencies,omitempty"`
|
||||
Bin map[string]string `json:"bin,omitempty"`
|
||||
Readme string `json:"readme,omitempty"`
|
||||
|
@ -32,7 +32,7 @@ var (
|
||||
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
|
||||
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
|
||||
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
|
||||
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`)
|
||||
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`)
|
||||
// crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository
|
||||
// e.g. org/repo#12345
|
||||
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)
|
||||
|
@ -463,6 +463,7 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) {
|
||||
"ABC-123:",
|
||||
"\"ABC-123\"",
|
||||
"'ABC-123'",
|
||||
"ABC-123, unknown PR",
|
||||
}
|
||||
falseTestCases := []string{
|
||||
"RC-08",
|
||||
|
@ -6,6 +6,7 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
@ -51,6 +52,9 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
|
||||
{
|
||||
branches, _, err := gitRepo.GetBranchNames(0, 0)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "ref file is empty") {
|
||||
return 0, nil
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
log.Trace("SyncRepoBranches[%s]: branches[%d]: %v", repo.FullName(), len(branches), branches)
|
||||
|
@ -12,6 +12,9 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
)
|
||||
|
||||
// CanUserForkBetweenOwners returns true if user can fork between owners.
|
||||
// By default, a user can fork a repository from another owner, but not from themselves.
|
||||
// Many users really like to fork their own repositories, so add an experimental setting to allow this.
|
||||
func CanUserForkBetweenOwners(id1, id2 int64) bool {
|
||||
if id1 != id2 {
|
||||
return true
|
||||
|
@ -31,12 +31,7 @@ func Test_getLicense(t *testing.T) {
|
||||
|
||||
Copyright (c) 2023 Gitea
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
`,
|
||||
Permission is hereby granted`,
|
||||
wantErr: assert.NoError,
|
||||
},
|
||||
{
|
||||
@ -53,7 +48,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) {
|
||||
return
|
||||
}
|
||||
assert.Equalf(t, tt.want, string(got), "GetLicense(%v, %v)", tt.args.name, tt.args.values)
|
||||
assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.args.name, tt.args.values)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,6 @@ package setting
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// CORSConfig defines CORS settings
|
||||
@ -28,7 +26,4 @@ var CORSConfig = struct {
|
||||
|
||||
func loadCorsFrom(rootCfg ConfigProvider) {
|
||||
mustMapSetting(rootCfg, "cors", &CORSConfig)
|
||||
if CORSConfig.Enabled {
|
||||
log.Info("CORS Service Enabled")
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ var defaultI18nLangNames = []string{
|
||||
"zh-TW", "繁體中文(台灣)",
|
||||
"de-DE", "Deutsch",
|
||||
"fr-FR", "Français",
|
||||
"ga-IE", "Gaeilge",
|
||||
"nl-NL", "Nederlands",
|
||||
"lv-LV", "Latviešu",
|
||||
"ru-RU", "Русский",
|
||||
|
@ -31,6 +31,8 @@ var Indexer = struct {
|
||||
IncludePatterns []*GlobMatcher
|
||||
ExcludePatterns []*GlobMatcher
|
||||
ExcludeVendored bool
|
||||
|
||||
TypeBleveMaxFuzzniess int
|
||||
}{
|
||||
IssueType: "bleve",
|
||||
IssuePath: "indexers/issues.bleve",
|
||||
@ -88,6 +90,7 @@ func loadIndexerFrom(rootCfg ConfigProvider) {
|
||||
Indexer.ExcludeVendored = sec.Key("REPO_INDEXER_EXCLUDE_VENDORED").MustBool(true)
|
||||
Indexer.MaxIndexerFileSize = sec.Key("MAX_FILE_SIZE").MustInt64(1024 * 1024)
|
||||
Indexer.StartupTimeout = sec.Key("STARTUP_TIMEOUT").MustDuration(30 * time.Second)
|
||||
Indexer.TypeBleveMaxFuzzniess = sec.Key("TYPE_BLEVE_MAX_FUZZINESS").MustInt(0)
|
||||
}
|
||||
|
||||
// IndexerGlobFromString parses a comma separated list of patterns and returns a glob.Glob slice suited for repo indexing
|
||||
@ -97,7 +100,7 @@ func IndexerGlobFromString(globstr string) []*GlobMatcher {
|
||||
expr = strings.TrimSpace(expr)
|
||||
if expr != "" {
|
||||
if g, err := GlobMatcherCompile(expr, '.', '/'); err != nil {
|
||||
log.Info("Invalid glob expression '%s' (skipped): %v", expr, err)
|
||||
log.Warn("Invalid glob expression '%s' (skipped): %v", expr, err)
|
||||
} else {
|
||||
extarr = append(extarr, g)
|
||||
}
|
||||
|
@ -255,8 +255,6 @@ func loadMailerFrom(rootCfg ConfigProvider) {
|
||||
MailService.OverrideEnvelopeFrom = true
|
||||
MailService.EnvelopeFrom = parsed.Address
|
||||
}
|
||||
|
||||
log.Info("Mail Service Enabled")
|
||||
}
|
||||
|
||||
func loadRegisterMailFrom(rootCfg ConfigProvider) {
|
||||
@ -267,7 +265,6 @@ func loadRegisterMailFrom(rootCfg ConfigProvider) {
|
||||
return
|
||||
}
|
||||
Service.RegisterEmailConfirm = true
|
||||
log.Info("Register Mail Service Enabled")
|
||||
}
|
||||
|
||||
func loadNotifyMailFrom(rootCfg ConfigProvider) {
|
||||
@ -278,7 +275,6 @@ func loadNotifyMailFrom(rootCfg ConfigProvider) {
|
||||
return
|
||||
}
|
||||
Service.EnableNotifyMail = true
|
||||
log.Info("Notify Mail Service Enabled")
|
||||
}
|
||||
|
||||
func tryResolveAddr(addr string) []net.IPAddr {
|
||||
|
@ -73,6 +73,4 @@ func loadSessionFrom(rootCfg ConfigProvider) {
|
||||
SessionConfig.ProviderConfig = string(shadowConfig)
|
||||
SessionConfig.OriginalProvider = SessionConfig.Provider
|
||||
SessionConfig.Provider = "VirtualSession"
|
||||
|
||||
log.Info("Session Service Enabled")
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ func loadTimeFrom(rootCfg ConfigProvider) {
|
||||
if err != nil {
|
||||
log.Fatal("Load time zone failed: %v", err)
|
||||
}
|
||||
log.Info("Default UI Location is %v", zone)
|
||||
}
|
||||
if DefaultUILocation == nil {
|
||||
DefaultUILocation = time.Local
|
||||
|
@ -70,7 +70,7 @@ func (a *azureBlobObject) Seek(offset int64, whence int) (int64, error) {
|
||||
case io.SeekCurrent:
|
||||
offset += a.offset
|
||||
case io.SeekEnd:
|
||||
offset = a.Size - offset
|
||||
offset = a.Size + offset
|
||||
default:
|
||||
return 0, errors.New("Seek: invalid whence")
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
@ -54,3 +56,46 @@ func TestAzureBlobStoragePath(t *testing.T) {
|
||||
assert.Equal(t, "base/a", m.buildAzureBlobPath("/a"))
|
||||
assert.Equal(t, "base/a/b", m.buildAzureBlobPath("/a/b/"))
|
||||
}
|
||||
|
||||
func Test_azureBlobObject(t *testing.T) {
|
||||
if os.Getenv("CI") == "" {
|
||||
t.Skip("azureBlobStorage not present outside of CI")
|
||||
return
|
||||
}
|
||||
|
||||
s, err := NewStorage(setting.AzureBlobStorageType, &setting.Storage{
|
||||
AzureBlobConfig: setting.AzureBlobStorageConfig{
|
||||
// https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio-code#ip-style-url
|
||||
Endpoint: "http://devstoreaccount1.azurite.local:10000",
|
||||
// https://learn.microsoft.com/azure/storage/common/storage-use-azurite?tabs=visual-studio-code#well-known-storage-account-and-key
|
||||
AccountName: "devstoreaccount1",
|
||||
AccountKey: "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==",
|
||||
Container: "test",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
data := "Q2xTckt6Y1hDOWh0"
|
||||
_, err = s.Save("test.txt", bytes.NewBufferString(data), int64(len(data)))
|
||||
assert.NoError(t, err)
|
||||
obj, err := s.Open("test.txt")
|
||||
assert.NoError(t, err)
|
||||
offset, err := obj.Seek(2, io.SeekStart)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 2, offset)
|
||||
buf1 := make([]byte, 3)
|
||||
read, err := obj.Read(buf1)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 3, read)
|
||||
assert.Equal(t, data[2:5], string(buf1))
|
||||
offset, err = obj.Seek(-5, io.SeekEnd)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, len(data)-5, offset)
|
||||
buf2 := make([]byte, 4)
|
||||
read, err = obj.Read(buf2)
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, 4, read)
|
||||
assert.Equal(t, data[11:15], string(buf2))
|
||||
assert.NoError(t, obj.Close())
|
||||
assert.NoError(t, s.Delete("test.txt"))
|
||||
}
|
||||
|
@ -13,9 +13,7 @@ import (
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
FixtureFiles: []string{""}, // load nothing
|
||||
})
|
||||
unittest.MainTest(m, &unittest.TestOptions{FixtureFiles: []string{ /* load nothing */ }})
|
||||
}
|
||||
|
||||
type testItem1 struct {
|
||||
@ -36,8 +34,6 @@ func (*testItem2) Name() string {
|
||||
}
|
||||
|
||||
func TestAppStateDB(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
as := &DBStore{}
|
||||
|
||||
item1 := new(testItem1)
|
||||
|
@ -3,7 +3,10 @@
|
||||
|
||||
package util
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func isSnakeCaseUpper(c byte) bool {
|
||||
return 'A' <= c && c <= 'Z'
|
||||
@ -95,3 +98,15 @@ func UnsafeBytesToString(b []byte) string {
|
||||
func UnsafeStringToBytes(s string) []byte {
|
||||
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||
}
|
||||
|
||||
// SplitTrimSpace splits the string at given separator and trims leading and trailing space
|
||||
func SplitTrimSpace(input, sep string) []string {
|
||||
input = strings.TrimSpace(input)
|
||||
var stringList []string
|
||||
for _, s := range strings.Split(input, sep) {
|
||||
if s = strings.TrimSpace(s); s != "" {
|
||||
stringList = append(stringList, s)
|
||||
}
|
||||
}
|
||||
return stringList
|
||||
}
|
||||
|
@ -45,3 +45,8 @@ func TestToSnakeCase(t *testing.T) {
|
||||
assert.Equal(t, expected, ToSnakeCase(input))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitTrimSpace(t *testing.T) {
|
||||
assert.Equal(t, []string{"a", "b", "c"}, SplitTrimSpace("a\nb\nc", "\n"))
|
||||
assert.Equal(t, []string{"a", "b"}, SplitTrimSpace("\r\na\n\r\nb\n\n", "\n"))
|
||||
}
|
||||
|
@ -14,6 +14,10 @@ const (
|
||||
asciiEllipsis = "..."
|
||||
)
|
||||
|
||||
func IsLikelySplitLeftPart(s string) bool {
|
||||
return strings.HasSuffix(s, utf8Ellipsis) || strings.HasSuffix(s, asciiEllipsis)
|
||||
}
|
||||
|
||||
// SplitStringAtByteN splits a string at byte n accounting for rune boundaries. (Combining characters are not accounted for.)
|
||||
func SplitStringAtByteN(input string, n int) (left, right string) {
|
||||
if len(input) <= n {
|
||||
@ -38,19 +42,3 @@ func SplitStringAtByteN(input string, n int) (left, right string) {
|
||||
|
||||
return input[:end] + utf8Ellipsis, utf8Ellipsis + input[end:]
|
||||
}
|
||||
|
||||
// SplitTrimSpace splits the string at given separator and trims leading and trailing space
|
||||
func SplitTrimSpace(input, sep string) []string {
|
||||
// Trim initial leading & trailing space
|
||||
input = strings.TrimSpace(input)
|
||||
// replace CRLF with LF
|
||||
input = strings.ReplaceAll(input, "\r\n", "\n")
|
||||
|
||||
var stringList []string
|
||||
for _, s := range strings.Split(input, sep) {
|
||||
// trim leading and trailing space
|
||||
stringList = append(stringList, strings.TrimSpace(s))
|
||||
}
|
||||
|
||||
return stringList
|
||||
}
|
||||
|
@ -1231,6 +1231,7 @@ create_new_repo_command = Creating a new repository on the command line
|
||||
push_exist_repo = Pushing an existing repository from the command line
|
||||
empty_message = This repository does not contain any content.
|
||||
broken_message = The Git data underlying this repository cannot be read. Contact the administrator of this instance or delete this repository.
|
||||
no_branch = This repository doesn’t have any branches.
|
||||
|
||||
code = Code
|
||||
code.desc = Access source code, files, commits and branches.
|
||||
@ -1946,8 +1947,8 @@ pulls.delete.title = Delete this pull request?
|
||||
pulls.delete.text = Do you really want to delete this pull request? (This will permanently remove all content. Consider closing it instead, if you intend to keep it archived)
|
||||
|
||||
pulls.recently_pushed_new_branches = You pushed on branch <strong>%[1]s</strong> %[2]s
|
||||
pulls.upstream_diverging_prompt_behind_1 = This branch is %d commit behind %s
|
||||
pulls.upstream_diverging_prompt_behind_n = This branch is %d commits behind %s
|
||||
pulls.upstream_diverging_prompt_behind_1 = This branch is %[1]d commit behind %[2]s
|
||||
pulls.upstream_diverging_prompt_behind_n = This branch is %[1]d commits behind %[2]s
|
||||
pulls.upstream_diverging_prompt_base_newer = The base branch %s has new changes
|
||||
pulls.upstream_diverging_merge = Sync fork
|
||||
|
||||
@ -3722,6 +3723,7 @@ runners.status.active = Active
|
||||
runners.status.offline = Offline
|
||||
runners.version = Version
|
||||
runners.reset_registration_token = Reset registration token
|
||||
runners.reset_registration_token_confirm = Would you like to invalidate the current token and generate a new one?
|
||||
runners.reset_registration_token_success = Runner registration token reset successfully
|
||||
|
||||
runs.all_workflows = All Workflows
|
||||
|
@ -1676,7 +1676,6 @@ issues.timetracker_timer_stop=Arrêter le minuteur
|
||||
issues.timetracker_timer_discard=Annuler le minuteur
|
||||
issues.timetracker_timer_manually_add=Pointer du temps
|
||||
|
||||
issues.time_estimate_placeholder=1h 2m
|
||||
issues.time_estimate_set=Définir le temps estimé
|
||||
issues.time_estimate_display=Estimation : %s
|
||||
issues.change_time_estimate_at=a changé le temps estimé à <b>%s</b> %s
|
||||
|
@ -1676,7 +1676,6 @@ issues.timetracker_timer_stop=Stop an t-amadóir
|
||||
issues.timetracker_timer_discard=Déan an t-amadóir a scriosadh
|
||||
issues.timetracker_timer_manually_add=Cuir Am leis
|
||||
|
||||
issues.time_estimate_placeholder=1u 2n
|
||||
issues.time_estimate_set=Socraigh am measta
|
||||
issues.time_estimate_display=Meastachán: %s
|
||||
issues.change_time_estimate_at=d'athraigh an meastachán ama go <b>%s</b> %s
|
||||
|
@ -1679,7 +1679,6 @@ issues.timetracker_timer_stop=Parar cronómetro
|
||||
issues.timetracker_timer_discard=Descartar cronómetro
|
||||
issues.timetracker_timer_manually_add=Adicionar tempo
|
||||
|
||||
issues.time_estimate_placeholder=1h 2m
|
||||
issues.time_estimate_set=Definir tempo estimado
|
||||
issues.time_estimate_display=Estimativa: %s
|
||||
issues.change_time_estimate_at=alterou a estimativa de tempo para <b>%s</b> %s
|
||||
@ -2632,6 +2631,7 @@ release.new_release=Novo lançamento
|
||||
release.draft=Rascunho
|
||||
release.prerelease=Pré-lançamento
|
||||
release.stable=Estável
|
||||
release.latest=Mais recente
|
||||
release.compare=Comparar
|
||||
release.edit=editar
|
||||
release.ahead.commits=<strong>%d</strong> cometimentos
|
||||
|
@ -93,6 +93,7 @@ remove_all=移除所有
|
||||
remove_label_str=`删除标签 "%s"`
|
||||
edit=编辑
|
||||
view=查看
|
||||
test=测试
|
||||
|
||||
enabled=启用
|
||||
disabled=禁用
|
||||
@ -103,6 +104,7 @@ copy_url=复制网址
|
||||
copy_hash=复制哈希值
|
||||
copy_content=复制内容
|
||||
copy_branch=复制分支名
|
||||
copy_path=复制路径
|
||||
copy_success=复制成功!
|
||||
copy_error=复制失败
|
||||
copy_type_unsupported=无法复制此类型的文件内容
|
||||
@ -143,6 +145,7 @@ confirm_delete_selected=确认删除所有选中项目?
|
||||
|
||||
name=名称
|
||||
value=值
|
||||
readme=自述文档
|
||||
|
||||
filter=过滤
|
||||
filter.clear=清除筛选器
|
||||
@ -178,6 +181,7 @@ package_kind=搜索软件包...
|
||||
project_kind=搜索项目...
|
||||
branch_kind=搜索分支...
|
||||
tag_kind=搜索标签...
|
||||
tag_tooltip=搜索匹配的标签。使用“%”来匹配任何序列的数字
|
||||
commit_kind=搜索提交记录...
|
||||
runner_kind=搜索runners...
|
||||
no_results=未找到匹配结果
|
||||
@ -223,16 +227,20 @@ string.desc=Z - A
|
||||
|
||||
[error]
|
||||
occurred=发生了一个错误
|
||||
report_message=如果您确定这是一个 Gitea bug,请在 <a href="%s" target="_blank">这里</a> 搜索问题,或在必要时创建一个新工单。
|
||||
not_found=找不到目标。
|
||||
network_error=网络错误
|
||||
|
||||
[startpage]
|
||||
app_desc=一款极易搭建的自助 Git 服务
|
||||
install=易安装
|
||||
install_desc=通过 <a target="_blank" rel="noopener noreferrer" href="%[1]s">二进制</a> 来运行;或者通过 <a target="_blank" rel="noopener noreferrer" href="%[2]s">Docker</a> 来运行;或者通过 <a target="_blank" rel="noopener noreferrer" href="%[3]s">安装包</a> 来运行。
|
||||
platform=跨平台
|
||||
platform_desc=任何 <a target="_blank" rel="noopener noreferrer" href="%s">Go 语言</a> 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行!
|
||||
lightweight=轻量级
|
||||
lightweight_desc=一个廉价的树莓派的配置足以满足 Gitea 的最低系统硬件要求。最大程度上节省您的服务器资源!
|
||||
license=开源化
|
||||
license_desc=所有的代码都开源在 <a target="_blank" rel="noopener noreferrer" href="%[1]s">%[2]s</a> 上,赶快加入我们来<a target="_blank" rel="noopener noreferrer" href="%[3]s">共同发展</a>这个伟大的项目!还等什么?成为贡献者吧!
|
||||
|
||||
[install]
|
||||
install=安装页面
|
||||
@ -346,6 +354,7 @@ enable_update_checker=启用更新检查
|
||||
enable_update_checker_helper=通过连接到 gitea.io 定期检查新版本发布。
|
||||
env_config_keys=环境配置
|
||||
env_config_keys_prompt=以下环境变量也将应用于您的配置文件:
|
||||
config_write_file_prompt=这些配置选项将写入以下位置: %s
|
||||
|
||||
[home]
|
||||
nav_menu=导航菜单
|
||||
@ -386,6 +395,7 @@ relevant_repositories=只显示相关的仓库, <a href="%s">显示未过滤
|
||||
|
||||
[auth]
|
||||
create_new_account=注册帐号
|
||||
already_have_account=已有账号?
|
||||
sign_in_now=立即登录
|
||||
disable_register_prompt=对不起,注册功能已被关闭。请联系网站管理员。
|
||||
disable_register_mail=已禁用注册的电子邮件确认。
|
||||
@ -394,6 +404,7 @@ remember_me=记住此设备
|
||||
remember_me.compromised=登录令牌不再有效,因为它可能表明帐户已被破坏。请检查您的帐户是否有异常活动。
|
||||
forgot_password_title=忘记密码
|
||||
forgot_password=忘记密码?
|
||||
need_account=需要一个帐户?
|
||||
sign_up_now=还没账号?马上注册。
|
||||
sign_up_successful=帐户创建成功。欢迎!
|
||||
confirmation_mail_sent_prompt_ex=一封新的确认邮件已经发送到 <b>%s</b>请在下一个 %s 中检查您的收件箱以完成注册过程。 如果您的注册电子邮件地址不正确,您可以重新登录并更改它。
|
||||
@ -449,12 +460,15 @@ authorize_application=应用授权
|
||||
authorize_redirect_notice=如果您授权此应用,您将会被重定向到 %s。
|
||||
authorize_application_created_by=此应用由%s创建。
|
||||
authorize_application_description=如果您允许,它将能够读取和修改您的所有帐户信息,包括私人仓库和组织。
|
||||
authorize_application_with_scopes=范围: %s
|
||||
authorize_title=授权 %s 访问您的帐户?
|
||||
authorization_failed=授权失败
|
||||
authorization_failed_desc=因为检测到无效请求,授权失败。请尝试联系您授权应用的管理员。
|
||||
sspi_auth_failed=SSPI 认证失败
|
||||
password_pwned=此密码出现在 <a target="_blank" rel="noopener noreferrer" href="%s">被盗密码</a> 列表上并且曾经被公开。 请使用另一个密码再试一次。
|
||||
password_pwned_err=无法完成对 HaveIBeenPwned 的请求
|
||||
last_admin=您不能删除最后一个管理员。必须至少保留一个管理员。
|
||||
signin_passkey=使用密钥登录
|
||||
back_to_sign_in=返回登录页面
|
||||
|
||||
[mail]
|
||||
@ -574,6 +588,8 @@ lang_select_error=从列表中选出语言
|
||||
|
||||
username_been_taken=用户名已被使用。
|
||||
username_change_not_local_user=非本地用户不允许更改用户名。
|
||||
change_username_disabled=更改用户名已被禁用。
|
||||
change_full_name_disabled=更改用户全名已禁用
|
||||
username_has_not_been_changed=用户名未更改
|
||||
repo_name_been_taken=仓库名称已被使用。
|
||||
repository_force_private=“强制私有”已启用:私有仓库不能被公开。
|
||||
@ -623,6 +639,7 @@ org_still_own_repo=该组织仍然是某些仓库的拥有者,请先删除或
|
||||
org_still_own_packages=该组织仍然是一个或多个软件包的拥有者,请先删除它们。
|
||||
|
||||
target_branch_not_exist=目标分支不存在。
|
||||
target_ref_not_exist=目标引用 %s 不存在
|
||||
|
||||
admin_cannot_delete_self=当您是管理员时,您不能删除自己。请先移除您的管理员权限
|
||||
|
||||
@ -688,14 +705,18 @@ applications=应用
|
||||
orgs=管理组织
|
||||
repos=仓库列表
|
||||
delete=删除帐户
|
||||
twofa=两步验证(TOTP)
|
||||
account_link=已绑定帐户
|
||||
organization=组织
|
||||
uid=UID
|
||||
webauthn=两步验证(安全密钥)
|
||||
|
||||
public_profile=公开信息
|
||||
biography_placeholder=告诉我们一点您自己! (您可以使用Markdown)
|
||||
location_placeholder=与他人分享你的大概位置
|
||||
profile_desc=控制您的个人资料对其他用户的显示方式。您的主要电子邮件地址将用于通知、密码恢复和基于网页界面的 Git 操作
|
||||
password_username_disabled=不允许非本地用户更改他们的用户名。更多详情请联系您的系统管理员。
|
||||
password_full_name_disabled=您无权更改他们的全名。请联系您的站点管理员了解更多详情。
|
||||
full_name=自定义名称
|
||||
website=个人网站
|
||||
location=所在地区
|
||||
@ -745,6 +766,7 @@ uploaded_avatar_not_a_image=上传的文件不是一张图片。
|
||||
uploaded_avatar_is_too_big=上传的文件大小(%d KiB) 超过最大限制(%d KiB)。
|
||||
update_avatar_success=您的头像已更新。
|
||||
update_user_avatar_success=用户头像已更新。
|
||||
cropper_prompt=您可以在保存前编辑图像。编辑的图像将被保存为 PNG 格式。
|
||||
|
||||
change_password=更新密码
|
||||
old_password=当前密码
|
||||
@ -787,6 +809,7 @@ add_email_success=新的电子邮件地址已添加。
|
||||
email_preference_set_success=电子邮件首选项已成功设置。
|
||||
add_openid_success=新的 OpenID 地址已添加。
|
||||
keep_email_private=隐藏电子邮件地址
|
||||
keep_email_private_popup=这将会隐藏您的电子邮件地址,不仅在您的个人资料中,还在您使用Web界面创建合并请求或编辑文件时。已推送的提交将不会被修改。在提交中使用 %s 以和您的账号关联。
|
||||
openid_desc=OpenID 让你可以将认证转发到外部服务。
|
||||
|
||||
manage_ssh_keys=管理 SSH 密钥
|
||||
@ -905,6 +928,7 @@ create_oauth2_application_success=您已成功创建了一个新的 OAuth2 应
|
||||
update_oauth2_application_success=您已成功更新了此 OAuth2 应用。
|
||||
oauth2_application_name=应用名称
|
||||
oauth2_confidential_client=机密客户端。是否是能够维持凭据机密性的应用,比如网页应用程序。如果是本地应用程序请不要勾选,包括桌面和移动端应用。
|
||||
oauth2_skip_secondary_authorization=首次授权后允许公共客户端跳过授权步骤。 <strong>可能会带来安全风险。</strong>
|
||||
oauth2_redirect_uris=重定向 URI。每行一个 URI。
|
||||
save_application=保存
|
||||
oauth2_client_id=客户端ID
|
||||
@ -915,6 +939,7 @@ oauth2_client_secret_hint=您离开或刷新此页面后将不会再显示此密
|
||||
oauth2_application_edit=编辑
|
||||
oauth2_application_create_description=OAuth2 应用允许您的第三方应用程序访问此实例的用户帐户。
|
||||
oauth2_application_remove_description=移除一个OAuth2应用将会阻止它访问此实例上的已授权用户账户。是否继续?
|
||||
oauth2_application_locked=如果配置启用,Gitea预注册一些OAuth2应用程序。 为了防止意外的行为, 这些应用既不能编辑也不能删除。请参阅OAuth2文档以获取更多信息。
|
||||
|
||||
authorized_oauth2_applications=已授权的 OAuth2 应用
|
||||
authorized_oauth2_applications_description=您已授予这些第三方应用程序访问您的个人 Gitea 账户的权限。请撤销那些您不再需要的应用程序的访问权限。
|
||||
@ -923,20 +948,26 @@ revoke_oauth2_grant=撤回权限
|
||||
revoke_oauth2_grant_description=确定撤销此三方应用程序的授权,并阻止此应用程序访问您的数据?
|
||||
revoke_oauth2_grant_success=成功撤销了访问权限。
|
||||
|
||||
twofa_desc=为保护你的账号密码安全,你可以使用智能手机或其它设备来接收时间强相关的一次性密码(TOTP)。
|
||||
twofa_recovery_tip=如果您丢失了您的设备,您将能够使用一次性恢复密钥来重新获得对您账户的访问。
|
||||
twofa_is_enrolled=你的账号<strong>已启用</strong>了两步验证。
|
||||
twofa_not_enrolled=你的账号未开启两步验证。
|
||||
twofa_disable=禁用两步认证
|
||||
twofa_scratch_token_regenerate=重新生成初始令牌
|
||||
twofa_scratch_token_regenerated=您的初始令牌现在是 %s。将其存放在安全的地方,它将不会再次显示。
|
||||
twofa_enroll=启用两步验证
|
||||
twofa_disable_note=如果需要, 可以禁用双因素身份验证。
|
||||
twofa_disable_desc=关掉两步验证会使得您的账号不安全,继续执行?
|
||||
regenerate_scratch_token_desc=如果您丢失了您的恢复密钥或已经使用它登录, 您可以在这里重置它。
|
||||
twofa_disabled=两步验证已被禁用。
|
||||
scan_this_image=使用您的授权应用扫描这张图片:
|
||||
or_enter_secret=或者输入密钥:%s
|
||||
then_enter_passcode=并输入应用程序中显示的密码:
|
||||
passcode_invalid=密码不正确。再试一次。
|
||||
twofa_enrolled=你的账号已经启用了两步验证。请保存初始令牌(%s)到一个安全的地方,此令牌仅显示一次。
|
||||
twofa_failed_get_secret=获取 secret 失败。
|
||||
|
||||
webauthn_desc=安全密钥是包含加密密钥的硬件设备。它们可以用于双因素身份验证。安全密钥必须支持 <a rel="noreferrer" target="_blank" href="%s">WebAuthn 身份验证器</a> 标准。
|
||||
webauthn_register_key=添加安全密钥
|
||||
webauthn_nickname=昵称
|
||||
webauthn_delete_key=移除安全密钥
|
||||
@ -1002,6 +1033,8 @@ fork_to_different_account=派生到其他账号
|
||||
fork_visibility_helper=无法更改派生仓库的可见性。
|
||||
fork_branch=要克隆到 Fork 的分支
|
||||
all_branches=所有分支
|
||||
view_all_branches=查看所有分支
|
||||
view_all_tags=查看所有标签
|
||||
fork_no_valid_owners=这个代码仓库无法被派生,因为没有有效的所有者。
|
||||
fork.blocked_user=无法克隆仓库,因为您被仓库所有者屏蔽。
|
||||
use_template=使用此模板
|
||||
@ -1013,6 +1046,8 @@ generate_repo=生成仓库
|
||||
generate_from=生成自
|
||||
repo_desc=仓库描述
|
||||
repo_desc_helper=输入简要描述 (可选)
|
||||
repo_no_desc=无详细信息
|
||||
repo_lang=编程语言
|
||||
repo_gitignore_helper=选择 .gitignore 模板。
|
||||
repo_gitignore_helper_desc=从常见语言的模板列表中选择忽略跟踪的文件。默认情况下,由开发或构建工具生成的特殊文件都包含在 .gitignore 中。
|
||||
issue_labels=工单标签
|
||||
@ -1074,6 +1109,7 @@ delete_preexisting_success=删除 %s 中未收录的文件
|
||||
blame_prior=查看此更改前的 blame
|
||||
blame.ignore_revs=忽略 <a href="%s">.git-blame-ignore-revs</a> 的修订。点击 <a href="%s">绕过</a> 并查看正常的 Blame 视图。
|
||||
blame.ignore_revs.failed=忽略 <a href="%s">.git-blame-ignore-revs</a> 版本失败。
|
||||
user_search_tooltip=最多显示30名用户
|
||||
|
||||
tree_path_not_found_commit=路径%[1]s 在提交 %[2]s 中不存在
|
||||
tree_path_not_found_branch=路径 %[1]s 不存在于分支 %[2]s 中。
|
||||
@ -1222,6 +1258,7 @@ releases=版本发布
|
||||
tag=Git标签
|
||||
released_this=发布
|
||||
tagged_this=已标记
|
||||
file.title=%s 位于 %s
|
||||
file_raw=原始文件
|
||||
file_history=文件历史
|
||||
file_view_source=源码模式
|
||||
@ -1238,6 +1275,7 @@ ambiguous_runes_header=`此文件含有模棱两可的 Unicode 字符`
|
||||
ambiguous_runes_description=`此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。`
|
||||
invisible_runes_line=`此行含有不可见的 unicode 字符`
|
||||
ambiguous_runes_line=`此行有模棱两可的 unicode 字符`
|
||||
ambiguous_character=`%[1]c [U+%04[1]X] 容易和 %[2]c [U+%04[2]X] 混淆`
|
||||
|
||||
escape_control_characters=Escape
|
||||
unescape_control_characters=Unescape
|
||||
@ -1429,6 +1467,7 @@ issues.new.clear_milestone=取消选中里程碑
|
||||
issues.new.assignees=指派成员
|
||||
issues.new.clear_assignees=取消指派成员
|
||||
issues.new.no_assignees=未指派成员
|
||||
issues.new.no_reviewers=无审核者
|
||||
issues.new.blocked_user=无法创建工单,因为您已被仓库所有者屏蔽。
|
||||
issues.edit.already_changed=无法保存对工单的更改。其内容似乎已被其他用户更改。 请刷新页面并重新编辑以避免覆盖他们的更改
|
||||
issues.edit.blocked_user=无法编辑内容,因为您已被仓库所有者或工单创建者屏蔽。
|
||||
@ -1457,6 +1496,7 @@ issues.remove_labels=于 %[2]s 删除了标签 %[1]s
|
||||
issues.add_remove_labels=于 %[3]s 添加了标签 %[1]s ,删除了标签 %[2]s
|
||||
issues.add_milestone_at=`于 %[2]s 添加了里程碑 <b>%[1]s</b>`
|
||||
issues.add_project_at=`于 %[2]s 将此添加到 <b>%[1]s</b> 项目`
|
||||
issues.move_to_column_of_project=`将此对象移至 %s 的 %s 中在 %s 上`
|
||||
issues.change_milestone_at=`%[3]s 修改了里程碑从 <b>%[1]s</b> 到 <b>%[2]s</b>`
|
||||
issues.change_project_at=于 %[3]s 将此从项目 <b>%[1]s</b> 移到 <b>%[2]s</b>
|
||||
issues.remove_milestone_at=`%[2]s 删除了里程碑 <b>%[1]s</b>`
|
||||
@ -1488,6 +1528,8 @@ issues.filter_assignee=指派人筛选
|
||||
issues.filter_assginee_no_select=所有指派成员
|
||||
issues.filter_assginee_no_assignee=未指派
|
||||
issues.filter_poster=作者
|
||||
issues.filter_user_placeholder=搜索用户
|
||||
issues.filter_user_no_select=所有用户
|
||||
issues.filter_type=类型筛选
|
||||
issues.filter_type.all_issues=所有工单
|
||||
issues.filter_type.assigned_to_you=指派给您的
|
||||
@ -1541,7 +1583,9 @@ issues.no_content=没有提供说明。
|
||||
issues.close=关闭工单
|
||||
issues.comment_pull_merged_at=已合并提交 %[1]s 到 %[2]s %[3]s
|
||||
issues.comment_manually_pull_merged_at=手动合并提交 %[1]s 到 %[2]s %[3]s
|
||||
issues.close_comment_issue=评论并关闭
|
||||
issues.reopen_issue=重新开启
|
||||
issues.reopen_comment_issue=评论并重新开启
|
||||
issues.create_comment=评论
|
||||
issues.comment.blocked_user=无法创建或编辑评论,因为您已被仓库所有者或工单创建者屏蔽。
|
||||
issues.closed_at=`于 <a id="%[1]s" href="#%[1]s">%[2]s</a> 关闭此工单`
|
||||
@ -1630,12 +1674,25 @@ issues.delete.title=是否删除工单?
|
||||
issues.delete.text=您真的要删除这个工单吗?(该操作将会永久删除所有内容。如果您需要保留,请关闭它)
|
||||
|
||||
issues.tracker=时间跟踪
|
||||
issues.timetracker_timer_start=启动计时器
|
||||
issues.timetracker_timer_stop=停止计时器
|
||||
issues.timetracker_timer_discard=删除计时器
|
||||
issues.timetracker_timer_manually_add=添加时间
|
||||
|
||||
issues.time_estimate_set=设置预计时间
|
||||
issues.time_estimate_display=预计: %s
|
||||
issues.change_time_estimate_at=将预计时间修改为 <b>%s</b> %s
|
||||
issues.remove_time_estimate_at=删除预计时间 %s
|
||||
issues.time_estimate_invalid=预计时间格式无效
|
||||
issues.start_tracking_history=`开始工作 %s`
|
||||
issues.tracker_auto_close=当此工单关闭时,自动停止计时器
|
||||
issues.tracking_already_started=`你已经开始对 <a href="%s">另一个工单</a> 进行时间跟踪!`
|
||||
issues.stop_tracking_history=`停止工作 %s`
|
||||
issues.cancel_tracking_history=`取消时间跟踪 %s`
|
||||
issues.del_time=删除此时间跟踪日志
|
||||
issues.add_time_history=`添加计时 %s`
|
||||
issues.del_time_history=`已删除时间 %s`
|
||||
issues.add_time_manually=手动添加时间
|
||||
issues.add_time_hours=小时
|
||||
issues.add_time_minutes=分钟
|
||||
issues.add_time_sum_to_small=没有输入时间。
|
||||
@ -1695,6 +1752,7 @@ issues.dependency.add_error_dep_not_same_repo=这两个工单必须在同一仓
|
||||
issues.review.self.approval=您不能批准您自己的合并请求。
|
||||
issues.review.self.rejection=您不能请求对您自己的合并请求进行更改。
|
||||
issues.review.approve=于 %s 批准此合并请求
|
||||
issues.review.comment=评审于 %s
|
||||
issues.review.dismissed=于 %[2]s 取消了 %[1]s 的评审
|
||||
issues.review.dismissed_label=已取消
|
||||
issues.review.left_comment=留下了一条评论
|
||||
@ -1720,6 +1778,10 @@ issues.review.resolve_conversation=已解决问题
|
||||
issues.review.un_resolve_conversation=未解决问题
|
||||
issues.review.resolved_by=标记问题为已解决
|
||||
issues.review.commented=评论
|
||||
issues.review.official=已批准
|
||||
issues.review.requested=等待审核
|
||||
issues.review.rejected=请求变更
|
||||
issues.review.stale=批准后已更新
|
||||
issues.review.unofficial=非官方审批数
|
||||
issues.assignee.error=因为未知原因,并非所有的指派都成功。
|
||||
issues.reference_issue.body=内容
|
||||
@ -1837,7 +1899,9 @@ pulls.unrelated_histories=合并失败:两个分支没有共同历史。提示
|
||||
pulls.merge_out_of_date=合并失败:在生成合并时,主分支已更新。提示:再试一次。
|
||||
pulls.head_out_of_date=合并失败:在生成合并时,head 已更新。提示:再试一次。
|
||||
pulls.has_merged=失败:合并请求已经被合并,您不能再次合并或更改目标分支。
|
||||
pulls.push_rejected=推送失败:推送被拒绝。审查此仓库的 Git 钩子。
|
||||
pulls.push_rejected_summary=详细拒绝信息
|
||||
pulls.push_rejected_no_message=推送失败:此推送被拒绝但未提供其他信息。请检查此仓库的 Git 钩子。
|
||||
pulls.open_unmerged_pull_exists=`您不能执行重新打开操作, 因为已经存在相同的合并请求 (#%d)。`
|
||||
pulls.status_checking=一些检测仍在等待运行
|
||||
pulls.status_checks_success=所有检测均成功
|
||||
@ -1881,6 +1945,10 @@ pulls.delete.title=删除此合并请求?
|
||||
pulls.delete.text=你真的要删除这个合并请求吗? (这将永久删除所有内容。如果你打算将内容存档,请考虑关闭它)
|
||||
|
||||
pulls.recently_pushed_new_branches=您已经于%[2]s推送了分支 <strong>%[1]s</strong>
|
||||
pulls.upstream_diverging_prompt_behind_1=该分支落后于 %s %d 个提交
|
||||
pulls.upstream_diverging_prompt_behind_n=该分支落后于 %s %d 个提交
|
||||
pulls.upstream_diverging_prompt_base_newer=基础分支 %s 有新的更改
|
||||
pulls.upstream_diverging_merge=同步派生
|
||||
|
||||
pull.deleted_branch=(已删除): %s
|
||||
pull.agit_documentation=查看有关 AGit 的文档
|
||||
@ -1894,6 +1962,7 @@ milestones.no_due_date=暂无截止日期
|
||||
milestones.open=开启
|
||||
milestones.close=关闭
|
||||
milestones.new_subheader=里程碑可以帮助您组织工单并跟踪其进度。
|
||||
milestones.completeness=<strong>%d%%</strong> 已完成
|
||||
milestones.create=创建里程碑
|
||||
milestones.title=标题
|
||||
milestones.desc=描述
|
||||
@ -2116,6 +2185,7 @@ 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_mode_desc=项目模式 (要显示的项目类型)
|
||||
settings.projects_mode_repo=仅仓库项目
|
||||
settings.projects_mode_owner=仅限用户或组织项目
|
||||
@ -2155,6 +2225,7 @@ settings.transfer_in_progress=当前正在进行转让。 如果你想将此代
|
||||
settings.transfer_notices_1=- 如果将此仓库转移给其他用户, 您将失去对此仓库的访问权限。
|
||||
settings.transfer_notices_2=-如果将其转移到您 (共同) 拥有的组织,您可以继续访问该仓库。
|
||||
settings.transfer_notices_3=- 如果仓库是私有的并且被转移给某个用户,那么此操作可以确保该用户至少具有读权限(以及必要时的更改权限)。
|
||||
settings.transfer_notices_4=- 如果存储库属于某个组织,而您将其转移给另一个组织或个人,那么您将失去存储库工单与其组织项目系统之间的链接。
|
||||
settings.transfer_owner=新拥有者
|
||||
settings.transfer_perform=执行转让
|
||||
settings.transfer_started=该代码库已被标记为转让并等待来自 %s 的确认
|
||||
@ -2291,6 +2362,7 @@ settings.event_pull_request_merge=合并请求合并
|
||||
settings.event_package=软件包
|
||||
settings.event_package_desc=软件包已在仓库中被创建或删除。
|
||||
settings.branch_filter=分支过滤
|
||||
settings.branch_filter_desc=推送、创建,删除分支事件的分支白名单,使用 glob 模式匹配指定。若为空或 <code>*</code>,则将报告所有分支的事件。语法文档见 <a href="%[1]s">%[2]s</a>。示例:<code>master</code>,<code>{master,release*}</code>。
|
||||
settings.authorization_header=授权标头
|
||||
settings.authorization_header_desc=当存在时将被作为授权标头包含在内。例如: %s。
|
||||
settings.active=激活
|
||||
@ -2336,25 +2408,53 @@ settings.deploy_key_deletion=删除部署密钥
|
||||
settings.deploy_key_deletion_desc=删除部署密钥将取消此密钥对此仓库的访问权限。继续?
|
||||
settings.deploy_key_deletion_success=部署密钥已删除。
|
||||
settings.branches=分支
|
||||
settings.protected_branch=分支保护
|
||||
settings.protected_branch.save_rule=保存规则
|
||||
settings.protected_branch.delete_rule=删除规则
|
||||
settings.protected_branch_can_push=是否允许推送?
|
||||
settings.protected_branch_can_push_yes=你可以推
|
||||
settings.protected_branch_can_push_no=你不能推送
|
||||
settings.branch_protection=分支 '<b>%s</b>' 的保护规则
|
||||
settings.protect_this_branch=启用分支保护
|
||||
settings.protect_this_branch_desc=阻止删除并限制Git推送和合并到分支。
|
||||
settings.protect_disable_push=禁用推送
|
||||
settings.protect_disable_push_desc=此分支不允许推送。
|
||||
settings.protect_disable_force_push=禁用强制推送
|
||||
settings.protect_disable_force_push_desc=此分支禁止强制推送。
|
||||
settings.protect_enable_push=启用推送
|
||||
settings.protect_enable_push_desc=任何拥有写访问权限的人将被允许推送到此分支(但不能强行推送)。
|
||||
settings.protect_enable_force_push_all=启用强制推送
|
||||
settings.protect_enable_force_push_all_desc=任何拥有推送权限的人都可以对这个分支进行强制推送。
|
||||
settings.protect_enable_force_push_allowlist=强制推送白名单
|
||||
settings.protect_enable_force_push_allowlist_desc=只有白名单中的用户或团队才能强制推送到这个分支。
|
||||
settings.protect_enable_merge=启用合并
|
||||
settings.protect_enable_merge_desc=任何具有写入权限的人都可以将合并请求合并到此分支中。
|
||||
settings.protect_whitelist_committers=受白名单限制的推送
|
||||
settings.protect_whitelist_committers_desc=只有列入白名单的用户或团队才能被允许推送到此分支(但不能强行推送)。
|
||||
settings.protect_whitelist_deploy_keys=具有推送权限的部署密钥白名单。
|
||||
settings.protect_whitelist_users=推送白名单用户:
|
||||
settings.protect_whitelist_teams=推送白名单团队:
|
||||
settings.protect_force_push_allowlist_users=允许强制推送的白名单用户:
|
||||
settings.protect_force_push_allowlist_teams=允许强制推送的白名单团队:
|
||||
settings.protect_force_push_allowlist_deploy_keys=允许白名单中的部署密钥进行强制推送。
|
||||
settings.protect_merge_whitelist_committers=启用合并白名单
|
||||
settings.protect_merge_whitelist_committers_desc=仅允许白名单用户或团队合并合并请求到此分支。
|
||||
settings.protect_merge_whitelist_users=合并白名单用户:
|
||||
settings.protect_merge_whitelist_teams=合并白名单团队:
|
||||
settings.protect_check_status_contexts=启用状态检查
|
||||
settings.protect_status_check_patterns=状态检查模式:
|
||||
settings.protect_status_check_patterns_desc=输入模式,指定哪些状态检查必须通过,才能将分支合并到符合此规则的分支中去。每一行指定一个模式,模式不能为空。
|
||||
settings.protect_check_status_contexts_desc=要求状态检查通过才能合并。如果启用,提交必须先推送到另一个分支,然后再合并或推送到匹配这些保护规则的分支。如果没有选择具体的状态检查上下文,则所有的状态检查都通过才能合并。
|
||||
settings.protect_check_status_contexts_list=此仓库上周进行过的状态检查
|
||||
settings.protect_status_check_matched=匹配
|
||||
settings.protect_invalid_status_check_pattern=无效的状态检查规则:“%s”。
|
||||
settings.protect_no_valid_status_check_patterns=没有有效的状态检查规则。
|
||||
settings.protect_required_approvals=所需的批准:
|
||||
settings.protect_required_approvals_desc=只允许合并有足够审核的合并请求。要求的审核必须来自白名单或者有权限的用户或团队。
|
||||
settings.protect_approvals_whitelist_enabled=仅列入白名单的用户或团队才可批准
|
||||
settings.protect_approvals_whitelist_enabled_desc=只有白名单用户或团队的审核才能计数。 如果规则没有批准白名单,来自任何有写访问权限的人的审核都将计数。
|
||||
settings.protect_approvals_whitelist_users=审查者白名单:
|
||||
settings.protect_approvals_whitelist_teams=审查团队白名单:
|
||||
settings.dismiss_stale_approvals=取消过时的批准
|
||||
settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被推送到分支时,旧的批准将被撤销。
|
||||
settings.ignore_stale_approvals=忽略过期批准
|
||||
@ -2362,12 +2462,18 @@ settings.ignore_stale_approvals_desc=对旧提交(过期审核)的批准将
|
||||
settings.require_signed_commits=需要签名提交
|
||||
settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支
|
||||
settings.protect_branch_name_pattern=受保护的分支名称模式
|
||||
settings.protect_branch_name_pattern_desc=分支保护的名称匹配规则。语法请参阅 <a href="%s">文档</a> 。如:main, release/**
|
||||
settings.protect_patterns=规则
|
||||
settings.protect_protected_file_patterns=受保护的文件模式(使用分号 ';' 分隔):
|
||||
settings.protect_protected_file_patterns_desc=即使用户有权添加、编辑或删除此分支中的文件,也不允许直接更改受保护的文件。 可以使用分号 (';') 分隔多个模式。 见<a href='%[1]s'>%[2]s</a>文档了解模式语法。例如: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>
|
||||
settings.protect_unprotected_file_patterns=不受保护的文件模式(使用分号 ';' 分隔):
|
||||
settings.protect_unprotected_file_patterns_desc=如果用户有写权限,则允许直接更改的不受保护的文件,以绕过推送限制。可以使用分号分隔多个模式 (';')。 见 <a href='%[1]s'>%[2]s</a> 文档了解模式语法。例如: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>
|
||||
settings.add_protected_branch=启用保护
|
||||
settings.delete_protected_branch=禁用保护
|
||||
settings.update_protect_branch_success=分支保护规则 %s 更新成功。
|
||||
settings.remove_protected_branch_success=移除分支保护规则"%s"成功。
|
||||
settings.remove_protected_branch_failed=移除分支保护规则"%s"失败。
|
||||
settings.protected_branch_deletion=删除分支保护
|
||||
settings.protected_branch_deletion_desc=禁用分支保护允许具有写入权限的用户推送提交到此分支。继续?
|
||||
settings.block_rejected_reviews=拒绝审核阻止了此合并
|
||||
settings.block_rejected_reviews_desc=如果官方审查人员要求作出改动,即使有足够的批准,合并也不允许。
|
||||
@ -2375,8 +2481,11 @@ settings.block_on_official_review_requests=有官方审核阻止了代码合并
|
||||
settings.block_on_official_review_requests_desc=处于评审状态时,即使有足够的批准,也不能合并。
|
||||
settings.block_outdated_branch=如果合并请求已经过时,阻止合并
|
||||
settings.block_outdated_branch_desc=当头部分支落后基础分支时,不能合并。
|
||||
settings.block_admin_merge_override=管理员须遵守分支保护规则
|
||||
settings.block_admin_merge_override_desc=管理员须遵守分支保护规则,不能规避该规则。
|
||||
settings.default_branch_desc=请选择一个默认的分支用于合并请求和提交:
|
||||
settings.merge_style_desc=合并方式
|
||||
settings.default_merge_style_desc=默认合并风格
|
||||
settings.choose_branch=选择一个分支...
|
||||
settings.no_protected_branch=没有受保护的分支
|
||||
settings.edit_protected_branch=编辑
|
||||
@ -2392,12 +2501,25 @@ settings.tags.protection.allowed.teams=允许的团队
|
||||
settings.tags.protection.allowed.noone=无
|
||||
settings.tags.protection.create=保护Git标签
|
||||
settings.tags.protection.none=没有受保护的Git标签
|
||||
settings.tags.protection.pattern.description=你可以使用单个名称或 glob 模式匹配或正则表达式来匹配多个标签。了解详情请访问 <a target="_blank" rel="noopener" href="%s">保护Git标签指南</a>。
|
||||
settings.bot_token=Bot 令牌
|
||||
settings.chat_id=聊天 ID
|
||||
settings.thread_id=线程 ID
|
||||
settings.matrix.homeserver_url=主服务器网址
|
||||
settings.matrix.room_id=房间ID
|
||||
settings.matrix.message_type=消息类型
|
||||
settings.visibility.private.button=设为私有
|
||||
settings.visibility.private.text=将可见性更改为私有不仅会使仓库仅对允许的成员可见,而且可能会消除它与派生仓库、关注者和点赞之间的关系。
|
||||
settings.visibility.private.bullet_title=<strong>将可见性改为私有将会:</strong>
|
||||
settings.visibility.private.bullet_one=使仓库只对允许的成员可见。
|
||||
settings.visibility.private.bullet_two=可能会删除它与 <strong>派生仓库</strong>、 <strong>关注者</strong>和 <strong>点赞</strong> 之间的关系。
|
||||
settings.visibility.public.button=设为公开
|
||||
settings.visibility.public.text=将可见性更改为公开会使任何人都可见。
|
||||
settings.visibility.public.bullet_title=<strong>将可见性改为公开将会:</strong>
|
||||
settings.visibility.public.bullet_one=使仓库让任何人都可见。
|
||||
settings.visibility.success=仓库可见性已更改。
|
||||
settings.visibility.error=试图更改仓库可见性时出错。
|
||||
settings.visibility.fork_error=无法更改派生仓库的可见性。
|
||||
settings.archive.button=归档仓库
|
||||
settings.archive.header=归档此仓库
|
||||
settings.archive.text=归档仓库将使其完全只读。它将在首页隐藏。没有人(甚至你!)能够进行新的提交,或打开工单及合并请求。
|
||||
@ -2509,6 +2631,7 @@ release.new_release=发布新版
|
||||
release.draft=草稿
|
||||
release.prerelease=预发行
|
||||
release.stable=稳定
|
||||
release.latest=最新版本
|
||||
release.compare=比较
|
||||
release.edit=编辑
|
||||
release.ahead.commits=<strong>%d</strong> 次提交
|
||||
@ -2593,6 +2716,7 @@ tag.create_success=标签"%s"已存在
|
||||
|
||||
topic.manage_topics=管理主题
|
||||
topic.done=保存
|
||||
topic.count_prompt=您最多选择25个主题
|
||||
topic.format_prompt=主题必须以字母或数字开头,可以包含连字符 ('-') 和句点 ('.'),长度不得超过35个字符。字符必须为小写。
|
||||
|
||||
find_file.go_to_file=转到文件
|
||||
@ -2665,6 +2789,7 @@ settings.delete_prompt=删除操作会永久清除该组织的信息,并且 <s
|
||||
settings.confirm_delete_account=确认删除组织
|
||||
settings.delete_org_title=删除组织
|
||||
settings.delete_org_desc=此组织将会被永久删除,确认继续吗?
|
||||
settings.hooks_desc=在此处添加的 Web 钩子将会应用到该组织下的 <strong>所有仓库</strong>。
|
||||
|
||||
settings.labels_desc=添加能够被该组织下的 <strong>所有仓库</strong> 的工单使用的标签。
|
||||
|
||||
@ -2689,6 +2814,7 @@ teams.leave.detail=离开 %s?
|
||||
teams.can_create_org_repo=创建仓库
|
||||
teams.can_create_org_repo_helper=成员可以在组织中创建仓库。创建者将自动获得创建的仓库的管理员权限。
|
||||
teams.none_access=无访问权限
|
||||
teams.none_access_helper=成员无法查看此单元或对其执行任何其他操作。对公开仓库无此影响。
|
||||
teams.general_access=常规访问
|
||||
teams.general_access_helper=成员权限将由以下权限表决定。
|
||||
teams.read_access=可读
|
||||
@ -2757,6 +2883,7 @@ last_page=末页
|
||||
total=总计:%d
|
||||
settings=管理设置
|
||||
|
||||
dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 <a target="_blank" rel="noreferrer" href="%s">博客</a> 了解详情。
|
||||
dashboard.statistic=摘要
|
||||
dashboard.maintenance_operations=运维
|
||||
dashboard.system_status=系统状态
|
||||
@ -2799,6 +2926,7 @@ dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在
|
||||
dashboard.sync_external_users=同步外部用户数据
|
||||
dashboard.cleanup_hook_task_table=清理 hook_task 表
|
||||
dashboard.cleanup_packages=清理过期的软件包
|
||||
dashboard.cleanup_actions=清理过期的 Actions 资源
|
||||
dashboard.server_uptime=服务运行时间
|
||||
dashboard.current_goroutine=当前 Goroutines 数量
|
||||
dashboard.current_memory_usage=当前内存使用量
|
||||
@ -2828,12 +2956,19 @@ dashboard.total_gc_time=GC 暂停时间总量
|
||||
dashboard.total_gc_pause=GC 暂停时间总量
|
||||
dashboard.last_gc_pause=上次 GC 暂停时间
|
||||
dashboard.gc_times=GC 执行次数
|
||||
dashboard.delete_old_actions=从数据库中删除所有旧操作记录
|
||||
dashboard.delete_old_actions.started=已开始从数据库中删除所有旧操作记录。
|
||||
dashboard.update_checker=更新检查器
|
||||
dashboard.delete_old_system_notices=从数据库中删除所有旧系统通知
|
||||
dashboard.gc_lfs=垃圾回收 LFS 元数据
|
||||
dashboard.stop_zombie_tasks=停止僵尸任务
|
||||
dashboard.stop_endless_tasks=停止无法停止的任务
|
||||
dashboard.cancel_abandoned_jobs=取消丢弃的任务
|
||||
dashboard.start_schedule_tasks=开始Actions调度任务
|
||||
dashboard.sync_branch.started=分支同步已开始
|
||||
dashboard.sync_tag.started=标签同步已开始
|
||||
dashboard.rebuild_issue_indexer=重建工单索引
|
||||
dashboard.sync_repo_licenses=重新仓库许可证探测
|
||||
|
||||
users.user_manage_panel=用户帐户管理
|
||||
users.new_account=创建新帐户
|
||||
@ -2905,6 +3040,10 @@ emails.not_updated=无法更新请求的电子邮件地址: %v
|
||||
emails.duplicate_active=此电子邮件地址已被另一个用户激活使用。
|
||||
emails.change_email_header=更新电子邮件属性
|
||||
emails.change_email_text=您确定要更新该电子邮件地址吗?
|
||||
emails.delete=删除电子邮件
|
||||
emails.delete_desc=您确定要删除该电子邮件地址?
|
||||
emails.deletion_success=电子邮件地址已被删除。
|
||||
emails.delete_primary_email_error=您不能删除主电子邮件。
|
||||
|
||||
orgs.org_manage_panel=组织管理
|
||||
orgs.name=名称
|
||||
@ -2937,10 +3076,12 @@ packages.size=大小
|
||||
packages.published=已发布
|
||||
|
||||
defaulthooks=默认Web钩子
|
||||
defaulthooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出 HTTP POST 请求。这里定义的 Web 钩子是默认配置,将被复制到所有新的仓库中。详情请访问 <a target="_blank" rel="noopener" href="%s">Web 钩子指南</a>。
|
||||
defaulthooks.add_webhook=添加默认Web 钩子
|
||||
defaulthooks.update_webhook=更新默认 Web 钩子
|
||||
|
||||
systemhooks=系统 Web 钩子
|
||||
systemhooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出HTTP POST请求。这里定义的 Web 钩子将作用于系统上的所有仓库,所以请考虑这可能带来的任何性能影响。了解详情请访问 <a target="_blank" rel="noopener" href="%s">Web 钩子指南</a>。
|
||||
systemhooks.add_webhook=添加系统 Web 钩子
|
||||
systemhooks.update_webhook=更新系统 Web 钩子
|
||||
|
||||
@ -3035,8 +3176,18 @@ auths.tips=帮助提示
|
||||
auths.tips.oauth2.general=OAuth2 认证
|
||||
auths.tips.oauth2.general.tip=当注册新的 OAuth2 身份验证时,回调/重定向 URL 应该是:
|
||||
auths.tip.oauth2_provider=OAuth2 提供程序
|
||||
auths.tip.bitbucket=在 %s 注册新的 OAuth 使用者同时添加权限“账号”-“读取”
|
||||
auths.tip.nextcloud=使用下面的菜单“设置(Settings) -> 安全(Security) -> OAuth 2.0 client”在您的实例上注册一个新的 OAuth 客户端。
|
||||
auths.tip.dropbox=在 %s 上创建一个新的应用程序
|
||||
auths.tip.facebook=`在 %s 注册一个新的应用,并添加产品"Facebook 登录"`
|
||||
auths.tip.github=在 %s 注册一个 OAuth 应用程序
|
||||
auths.tip.gitlab_new=在 %s 注册一个新的应用
|
||||
auths.tip.google_plus=从谷歌 API 控制台 %s 获得 OAuth2 客户端凭据
|
||||
auths.tip.openid_connect=使用 OpenID 连接发现 URL ({server}/.well-known/openid-configuration) 来指定终点
|
||||
auths.tip.twitter=访问 %s,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。
|
||||
auths.tip.discord=在 %s 上注册新应用程序
|
||||
auths.tip.gitea=注册一个新的 OAuth2 应用程序。可以访问 %s 查看帮助
|
||||
auths.tip.yandex=在 %s 上创建一个新的应用程序。在“ Yandex.Passport API”这部分中选择以下权限:“访问电子邮件地址(Access to email address)”,“访问用户头像(Access to user avatar)”和“访问用户名,名字和姓氏,性别(Access to username, first name and surname, genderAccess to username, first name and surname, gender)”
|
||||
auths.tip.mastodon=输入您想要认证的 mastodon 实例的自定义 URL (或使用默认值)
|
||||
auths.edit=修改认证源
|
||||
auths.activated=该认证源已经启用
|
||||
@ -3153,6 +3304,9 @@ config.cache_interval=Cache 周期
|
||||
config.cache_conn=Cache 连接字符串
|
||||
config.cache_item_ttl=缓存项目 TTL
|
||||
config.cache_test=测试缓存
|
||||
config.cache_test_failed=缓存测试失败: %v。
|
||||
config.cache_test_slow=缓存测试成功,但响应缓慢: %s。
|
||||
config.cache_test_succeeded=缓存测试成功,在 %s 时间内得到响应。
|
||||
|
||||
config.session_config=Session 配置
|
||||
config.session_provider=Session 提供者
|
||||
@ -3199,6 +3353,7 @@ monitor.next=下次执行时间
|
||||
monitor.previous=上次执行时间
|
||||
monitor.execute_times=执行次数
|
||||
monitor.process=运行中进程
|
||||
monitor.stacktrace=调用栈踪迹
|
||||
monitor.processes_count=%d 个进程
|
||||
monitor.download_diagnosis_report=下载诊断报告
|
||||
monitor.desc=进程描述
|
||||
@ -3206,6 +3361,8 @@ monitor.start=开始时间
|
||||
monitor.execute_time=执行时长
|
||||
monitor.last_execution_result=结果
|
||||
monitor.process.cancel=中止进程
|
||||
monitor.process.cancel_desc=中止一个进程可能导致数据丢失
|
||||
monitor.process.cancel_notices=中止:<strong>%s</strong> ?
|
||||
monitor.process.children=子进程
|
||||
|
||||
monitor.queues=队列
|
||||
@ -3307,6 +3464,8 @@ raw_minutes=分钟
|
||||
|
||||
[dropzone]
|
||||
default_message=拖动文件或者点击此处上传。
|
||||
invalid_input_type=您不能上传该类型的文件
|
||||
file_too_big=文件体积({{filesize}} MB)超过了最大允许体积({{maxFilesize}} MB)
|
||||
remove_file=移除文件
|
||||
|
||||
[notification]
|
||||
@ -3378,6 +3537,8 @@ alpine.repository=仓库信息
|
||||
alpine.repository.branches=分支
|
||||
alpine.repository.repositories=仓库管理
|
||||
alpine.repository.architectures=架构
|
||||
arch.registry=添加具有相关仓库和架构的服务器到 <code>/etc/pacman.conf</code> 中:
|
||||
arch.install=使用 pacman 同步软件包:
|
||||
arch.repository=仓库信息
|
||||
arch.repository.repositories=仓库管理
|
||||
arch.repository.architectures=架构
|
||||
@ -3456,6 +3617,7 @@ settings.link=将此软件包链接到仓库
|
||||
settings.link.description=如果您将一个软件包与一个代码库链接起来,软件包将显示在代码库的软件包列表中。
|
||||
settings.link.select=选择仓库
|
||||
settings.link.button=更新仓库链接
|
||||
settings.link.success=仓库链接已成功更新。
|
||||
settings.link.error=更新仓库链接失败。
|
||||
settings.delete=删除软件包
|
||||
settings.delete.description=删除软件包是永久性的,无法撤消。
|
||||
@ -3579,12 +3741,18 @@ runs.no_workflows.quick_start=不知道如何使用 Gitea Actions吗?请查看
|
||||
runs.no_workflows.documentation=关于Gitea Actions的更多信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="%s">文档</a>。
|
||||
runs.no_runs=工作流尚未运行过。
|
||||
runs.empty_commit_message=(空白的提交消息)
|
||||
runs.expire_log_message=旧的日志已被清除
|
||||
|
||||
workflow.disable=禁用工作流
|
||||
workflow.disable_success=工作流 '%s' 已成功禁用。
|
||||
workflow.enable=启用工作流
|
||||
workflow.enable_success=工作流 '%s' 已成功启用。
|
||||
workflow.disabled=工作流已禁用。
|
||||
workflow.run=运行工作流
|
||||
workflow.not_found=工作流 %s 未找到。
|
||||
workflow.run_success=工作流 %s 已成功运行。
|
||||
workflow.from_ref=使用工作流从
|
||||
workflow.has_workflow_dispatch=此 Workflow 有一个 Workflow_dispatch 事件触发器。
|
||||
|
||||
need_approval_desc=该工作流由派生仓库的合并请求所触发,需要批准方可运行。
|
||||
|
||||
@ -3605,6 +3773,7 @@ variables.update.failed=编辑变量失败。
|
||||
variables.update.success=该变量已被编辑。
|
||||
|
||||
[projects]
|
||||
deleted.display_name=已删除项目
|
||||
type-1.display_name=个人项目
|
||||
type-2.display_name=仓库项目
|
||||
type-3.display_name=组织项目
|
||||
|
174
package-lock.json
generated
174
package-lock.json
generated
@ -87,7 +87,7 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-import-resolver-typescript": "3.7.0",
|
||||
"eslint-plugin-array-func": "4.0.0",
|
||||
"eslint-plugin-github": "5.1.3",
|
||||
"eslint-plugin-github": "5.0.2",
|
||||
"eslint-plugin-import-x": "4.5.0",
|
||||
"eslint-plugin-no-jquery": "3.1.0",
|
||||
"eslint-plugin-no-use-extend-native": "0.5.0",
|
||||
@ -8241,166 +8241,35 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-5.1.3.tgz",
|
||||
"integrity": "sha512-/0lyEqLLodXW3p+D9eYtmEp6e9DcJmV5FhnE9wNWV1bcqyShuZFXn5kOeJIvxSbFbdbrKiNO8zFiV/VXeSpRSw==",
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-5.0.2.tgz",
|
||||
"integrity": "sha512-nMdzWJQ5CimjQDY6SFeJ0KIXuNFf0dgDWEd4eP3UWfuTuP/dXcZJDg7MQRvAFt743T1zUi4+/HdOihfu8xJkLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint/compat": "^1.2.3",
|
||||
"@eslint/eslintrc": "^3.1.0",
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@github/browserslist-config": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"aria-query": "^5.3.0",
|
||||
"eslint-config-prettier": ">=8.0.0",
|
||||
"eslint-plugin-escompat": "^3.11.3",
|
||||
"eslint-plugin-escompat": "^3.3.3",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-filenames": "^1.3.2",
|
||||
"eslint-plugin-i18n-text": "^1.0.1",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-no-only-tests": "^3.0.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-rule-documentation": ">=1.0.0",
|
||||
"globals": "^15.12.0",
|
||||
"jsx-ast-utils": "^3.3.2",
|
||||
"prettier": "^3.0.0",
|
||||
"svg-element-attributes": "^1.3.1",
|
||||
"typescript-eslint": "^8.14.0"
|
||||
"svg-element-attributes": "^1.3.1"
|
||||
},
|
||||
"bin": {
|
||||
"eslint-ignore-errors": "bin/eslint-ignore-errors.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8 || ^9"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/@eslint/compat": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.4.tgz",
|
||||
"integrity": "sha512-S8ZdQj/N69YAtuqFt7653jwcvuUj131+6qGLUyDqfDg1OIoBQ66OCuXC473YQfO2AaxITTutiRQiDwoo7ZLYyg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^9.10.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"eslint": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/@eslint/eslintrc": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz",
|
||||
"integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
|
||||
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/@eslint/js": {
|
||||
"version": "9.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz",
|
||||
"integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/epoberezkin"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/globals": {
|
||||
"version": "15.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz",
|
||||
"integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/eslint-plugin-github/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"eslint": "^8.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-i18n-text": {
|
||||
@ -15178,33 +15047,6 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.17.0",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.17.0.tgz",
|
||||
"integrity": "sha512-409VXvFd/f1br1DCbuKNFqQpXICoTB+V51afcwG1pn1a3Cp92MqAUges3YjwEdQ0cMUoCIodjVDAYzyD8h3SYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.17.0",
|
||||
"@typescript-eslint/parser": "8.17.0",
|
||||
"@typescript-eslint/utils": "8.17.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/typo-js": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.4.tgz",
|
||||
|
@ -86,7 +86,7 @@
|
||||
"eslint": "8.57.0",
|
||||
"eslint-import-resolver-typescript": "3.7.0",
|
||||
"eslint-plugin-array-func": "4.0.0",
|
||||
"eslint-plugin-github": "5.1.3",
|
||||
"eslint-plugin-github": "5.0.2",
|
||||
"eslint-plugin-import-x": "4.5.0",
|
||||
"eslint-plugin-no-jquery": "3.1.0",
|
||||
"eslint-plugin-no-use-extend-native": "0.5.0",
|
||||
|
@ -111,12 +111,11 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
|
||||
}
|
||||
var err error
|
||||
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
||||
if err == packages_model.ErrDuplicatePackage {
|
||||
created = false
|
||||
} else {
|
||||
if !errors.Is(err, packages_model.ErrDuplicatePackage) {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return err
|
||||
}
|
||||
created = false
|
||||
}
|
||||
|
||||
if created {
|
||||
@ -135,7 +134,7 @@ func getOrCreateUploadVersion(ctx context.Context, pi *packages_service.PackageI
|
||||
MetadataJSON: "null",
|
||||
}
|
||||
if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
|
||||
if err != packages_model.ErrDuplicatePackageVersion {
|
||||
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return err
|
||||
}
|
||||
@ -161,7 +160,7 @@ func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, p
|
||||
}
|
||||
var err error
|
||||
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
||||
if err == packages_model.ErrDuplicatePackageFile {
|
||||
if errors.Is(err, packages_model.ErrDuplicatePackageFile) {
|
||||
return nil
|
||||
}
|
||||
log.Error("Error inserting package file: %v", err)
|
||||
|
@ -324,7 +324,7 @@ func GetUploadBlob(ctx *context.Context) {
|
||||
|
||||
upload, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
||||
if err != nil {
|
||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
||||
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -345,7 +345,7 @@ func UploadBlob(ctx *context.Context) {
|
||||
|
||||
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
||||
if err != nil {
|
||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
||||
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -396,7 +396,7 @@ func EndUploadBlob(ctx *context.Context) {
|
||||
|
||||
uploader, err := container_service.NewBlobUploader(ctx, ctx.PathParam("uuid"))
|
||||
if err != nil {
|
||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
||||
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -465,7 +465,7 @@ func CancelUploadBlob(ctx *context.Context) {
|
||||
|
||||
_, err := packages_model.GetBlobUploadByID(ctx, uuid)
|
||||
if err != nil {
|
||||
if err == packages_model.ErrPackageBlobUploadNotExist {
|
||||
if errors.Is(err, packages_model.ErrPackageBlobUploadNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUploadUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -501,7 +501,7 @@ func getBlobFromContext(ctx *context.Context) (*packages_model.PackageFileDescri
|
||||
func HeadBlob(ctx *context.Context) {
|
||||
blob, err := getBlobFromContext(ctx)
|
||||
if err != nil {
|
||||
if err == container_model.ErrContainerBlobNotExist {
|
||||
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -520,7 +520,7 @@ func HeadBlob(ctx *context.Context) {
|
||||
func GetBlob(ctx *context.Context) {
|
||||
blob, err := getBlobFromContext(ctx)
|
||||
if err != nil {
|
||||
if err == container_model.ErrContainerBlobNotExist {
|
||||
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||
apiErrorDefined(ctx, errBlobUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -639,7 +639,7 @@ func getManifestFromContext(ctx *context.Context) (*packages_model.PackageFileDe
|
||||
func HeadManifest(ctx *context.Context) {
|
||||
manifest, err := getManifestFromContext(ctx)
|
||||
if err != nil {
|
||||
if err == container_model.ErrContainerBlobNotExist {
|
||||
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||
apiErrorDefined(ctx, errManifestUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -659,7 +659,7 @@ func HeadManifest(ctx *context.Context) {
|
||||
func GetManifest(ctx *context.Context) {
|
||||
manifest, err := getManifestFromContext(ctx)
|
||||
if err != nil {
|
||||
if err == container_model.ErrContainerBlobNotExist {
|
||||
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||
apiErrorDefined(ctx, errManifestUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@ -739,7 +739,7 @@ func GetTagList(ctx *context.Context) {
|
||||
image := ctx.PathParam("image")
|
||||
|
||||
if _, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.TypeContainer, image); err != nil {
|
||||
if err == packages_model.ErrPackageNotExist {
|
||||
if errors.Is(err, packages_model.ErrPackageNotExist) {
|
||||
apiErrorDefined(ctx, errNameUnknown)
|
||||
} else {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
|
@ -240,7 +240,7 @@ func processImageManifestIndex(ctx context.Context, mci *manifestCreationInfo, b
|
||||
IsManifest: true,
|
||||
})
|
||||
if err != nil {
|
||||
if err == container_model.ErrContainerBlobNotExist {
|
||||
if errors.Is(err, container_model.ErrContainerBlobNotExist) {
|
||||
return errManifestBlobUnknown
|
||||
}
|
||||
return err
|
||||
@ -321,12 +321,11 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
||||
}
|
||||
var err error
|
||||
if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
|
||||
if err == packages_model.ErrDuplicatePackage {
|
||||
created = false
|
||||
} else {
|
||||
if !errors.Is(err, packages_model.ErrDuplicatePackage) {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
created = false
|
||||
}
|
||||
|
||||
if created {
|
||||
@ -352,21 +351,23 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
|
||||
}
|
||||
var pv *packages_model.PackageVersion
|
||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
||||
if err == packages_model.ErrDuplicatePackageVersion {
|
||||
if err := packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// keep download count on overwrite
|
||||
_pv.DownloadCount = pv.DownloadCount
|
||||
if err = packages_service.DeletePackageVersionAndReferences(ctx, pv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
||||
// keep download count on overwrite
|
||||
_pv.DownloadCount = pv.DownloadCount
|
||||
|
||||
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
|
||||
if !errors.Is(err, packages_model.ErrDuplicatePackageVersion) {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
log.Error("Error inserting package: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +418,7 @@ func createFileFromBlobReference(ctx context.Context, pv, uploadVersion *package
|
||||
}
|
||||
var err error
|
||||
if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
|
||||
if err == packages_model.ErrDuplicatePackageFile {
|
||||
if errors.Is(err, packages_model.ErrDuplicatePackageFile) {
|
||||
// Skip this blob because the manifest contains the same filesystem layer multiple times.
|
||||
return nil
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user