Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Anthony Wang 2022-08-10 15:07:13 -05:00
commit ecefb6a2d0
Signed by: a
GPG key ID: BC96B00AEC5F2D76
188 changed files with 4468 additions and 3533 deletions

View file

@ -25,7 +25,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.18
image: golang:1.19
pull: always
commands:
- make deps-backend
@ -88,7 +88,7 @@ steps:
depends_on: [deps-frontend]
- name: checks-backend
image: golang:1.18
image: golang:1.19
commands:
- make checks-backend
depends_on: [deps-backend]
@ -122,7 +122,7 @@ steps:
path: /go
- name: build-backend-arm64
image: golang:1.18
image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@ -138,7 +138,7 @@ steps:
path: /go
- name: build-backend-windows
image: golang:1.18
image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@ -153,7 +153,7 @@ steps:
path: /go
- name: build-backend-386
image: golang:1.18
image: golang:1.19
environment:
GO111MODULE: on
GOPROXY: https://goproxy.io
@ -243,7 +243,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.18
image: golang:1.19
pull: always
commands:
- make deps-backend
@ -360,7 +360,7 @@ steps:
path: /go
- name: generate-coverage
image: golang:1.18
image: golang:1.19
commands:
- make coverage
environment:
@ -436,7 +436,7 @@ steps:
- pull_request
- name: deps-backend
image: golang:1.18
image: golang:1.19
pull: always
commands:
- make deps-backend
@ -578,7 +578,7 @@ trigger:
steps:
- name: download
image: golang:1.18
image: golang:1.19
pull: always
commands:
- timeout -s ABRT 40m make generate-license generate-gitignore
@ -640,7 +640,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.18
image: golang:1.19
pull: always
commands:
- make deps-backend
@ -649,7 +649,7 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.18.x
image: techknowlogick/xgo:go-1.19.x
pull: always
commands:
# Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved
@ -760,7 +760,7 @@ steps:
- make deps-frontend
- name: deps-backend
image: golang:1.18
image: golang:1.19
pull: always
commands:
- make deps-backend
@ -769,7 +769,7 @@ steps:
path: /go
- name: static
image: techknowlogick/xgo:go-1.18.x
image: techknowlogick/xgo:go-1.19.x
pull: always
commands:
# Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved

View file

@ -30,7 +30,7 @@ overrides:
env:
worker: true
rules:
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top]
- files: ["build/generate-images.js"]
rules:
import/no-unresolved: [0]
@ -109,7 +109,7 @@ rules:
import/no-extraneous-dependencies: [2]
import/no-import-module-exports: [0]
import/no-internal-modules: [0]
import/no-mutable-exports: [2]
import/no-mutable-exports: [0]
import/no-named-as-default-member: [0]
import/no-named-as-default: [2]
import/no-named-default: [0]
@ -121,7 +121,7 @@ rules:
import/no-restricted-paths: [0]
import/no-self-import: [2]
import/no-unassigned-import: [0]
import/no-unresolved: [2, {commonjs: true}]
import/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}]
import/no-unused-modules: [2, {unusedExports: true}]
import/no-useless-path-segments: [2, {commonjs: true}]
import/no-webpack-loader-syntax: [2]
@ -211,7 +211,7 @@ rules:
no-compare-neg-zero: [2]
no-cond-assign: [2, except-parens]
no-confusing-arrow: [0]
no-console: [1, {allow: [info, warn, error]}]
no-console: [1, {allow: [debug, info, warn, error]}]
no-const-assign: [2]
no-constant-binary-expression: [2]
no-constant-condition: [0]
@ -287,7 +287,7 @@ rules:
no-redeclare: [2]
no-regex-spaces: [2]
no-restricted-exports: [0]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top]
no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename]
no-restricted-imports: [0]
no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement]
no-return-assign: [0]
@ -321,7 +321,7 @@ rules:
no-unused-labels: [2]
no-unused-private-class-members: [2]
no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}]
no-use-before-define: [2, nofunc]
no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}]
no-useless-backreference: [0]
no-useless-call: [2]
no-useless-catch: [2]
@ -347,7 +347,7 @@ rules:
padded-blocks: [2, never]
padding-line-between-statements: [0]
prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}]
prefer-const: [2, {destructuring: all}]
prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}]
prefer-destructuring: [0]
prefer-exponentiation-operator: [2]
prefer-named-capture-group: [0]
@ -449,7 +449,7 @@ rules:
unicorn/no-new-array: [0]
unicorn/no-new-buffer: [0]
unicorn/no-null: [0]
unicorn/no-object-as-default-parameter: [2]
unicorn/no-object-as-default-parameter: [0]
unicorn/no-process-exit: [0]
unicorn/no-reduce: [2]
unicorn/no-static-only-class: [2]
@ -475,7 +475,7 @@ rules:
unicorn/prefer-array-index-of: [2]
unicorn/prefer-array-some: [2]
unicorn/prefer-at: [0]
unicorn/prefer-code-point: [2]
unicorn/prefer-code-point: [0]
unicorn/prefer-dataset: [2]
unicorn/prefer-date-now: [2]
unicorn/prefer-default-parameters: [0]

View file

@ -29,7 +29,7 @@ linters:
fast: false
run:
go: 1.18
go: 1.19
timeout: 10m
skip-dirs:
- node_modules
@ -75,7 +75,7 @@ linters-settings:
- name: modifies-value-receiver
gofumpt:
extra-rules: true
lang-version: "1.18"
lang-version: "1.19"
depguard:
# TODO: use depguard to replace import checks in gitea-vet
list-type: denylist

View file

@ -4,6 +4,314 @@ This changelog goes through all 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.io).
## [1.17.0](https://github.com/go-gitea/gitea/releases/tag/v1.17.0) - 2022-07-30
* BREAKING
* Require go1.18 for Gitea 1.17 (#19918)
* Make AppDataPath absolute against the AppWorkPath if it is not (#19815)
* Nuke the incorrect permission report on /api/v1/notifications (#19761)
* Refactor git module, make Gitea use internal git config (#19732)
* Remove `RequireHighlightJS` field, update plantuml example. (#19615)
* Increase minimal required git version to 2.0 (#19577)
* Add a directory prefix `gitea-src-VERSION` to release-tar-file (#19396)
* Use "main" as default branch name (#19354)
* Make cron task no notice on success (#19221)
* Add pam account authorization check (#19040)
* Show messages for users if the ROOT_URL is wrong, show JavaScript errors (#18971)
* Refactor mirror code & fix StartToMirror (#18904)
* Remove deprecated SSH ciphers from default (#18697)
* Add the possibility to allow the user to have a favicon which differs from the main logo (#18542)
* Update reserved usernames list (#18438)
* Support custom ACME provider (#18340)
* Change initial TrustModel to committer (#18335)
* Update HTTP status codes (#18063)
* Upgrade Alpine from 3.13 to 3.15 (#18050)
* Restrict email address validation (#17688)
* Refactor Router Logger (#17308)
* SECURITY
* Use git.HOME_PATH for Git HOME directory (#20114) (#20293)
* Add write check for creating Commit Statuses (#20332) (#20333)
* Remove deprecated SSH ciphers from default (#18697)
* FEDERATION
* Return statistic information for nodeinfo (#19561)
* Add Webfinger endpoint (#19462)
* Store the foreign ID of issues during migration (#18446)
* FEATURES
* Automatically render wiki TOC (#19873)
* Adding button to link accounts from user settings (#19792)
* Allow set default merge style while creating repo (#19751)
* Auto merge pull requests when all checks succeeded (#9307 & #19648)
* Improve reviewing PR UX (#19612)
* Add support for rendering console output with colors (#19497)
* Add Helm Chart registry (#19406)
* Add Goroutine stack inspector to admin/monitor (#19207)
* RSS/Atom support for Orgs & Repos (#17714 & #19055)
* Add button for issue deletion (#19032)
* Allow to mark files in a PR as viewed (#19007)
* Add Index to comment for migrations and mirroring (#18806)
* Add health check endpoint (#18465)
* Add packagist webhook (#18224)
* Add "Allow edits from maintainer" feature (#18002)
* Add apply-patch, basic revert and cherry-pick functionality (#17902)
* Add Package Registry (#16510)
* Add LDAP group sync to Teams (#16299)
* Pause queues (#15928)
* Added auto-save whitespace behavior if it changed manually (#15566)
* Find files in repo (#15028)
* Provide configuration to allow camo-media proxying (#12802)
* API
* Add endpoint to serve blob or LFS file content (#19689)
* Add endpoint to check if team has repo access (#19540)
* More commit info (#19252)
* Allow to create file on empty repo (#19224)
* Allow removing issues (#18879)
* Add endpoint to query collaborators permission for a repository (#18761)
* Return primary language and repository language stats API URL (#18396)
* Implement http signatures support for the API (#17565)
* ENHANCEMENTS
* Make notification bell more prominent on mobile (#20108, #20236, #20251) (#20269)
* Adjust max-widths for the repository file table (#20243) (#20247)
* Display full name (#20171) (#20246)
* Add dbconsistency checks for Stopwatches (#20010)
* Add fetch.writeCommitGraph to gitconfig (#20006)
* Add fgprof pprof profiler (#20005)
* Move agit dependency (#19998)
* Empty log queue on flush and close (#19994)
* Remove tab/TabName usage where it's not needed (#19973)
* Improve file header on mobile (#19945)
* Move issues related files into models/issues (#19931)
* Add breaking email restrictions checker in doctor (#19903)
* Improve UX on modal for deleting an access token (#19894)
* Add alt text to logo (#19892)
* Move some code into models/git (#19879)
* Remove customized (unmaintained) dropdown, improve aria a11y for dropdown (#19861)
* Make user profile image show full image on mobile (#19840)
* Replace blue button and label classes with primary (#19763)
* Remove fomantic progress module (#19760)
* Allows repo search to match against "owner/repo" pattern strings (#19754)
* Move org functions (#19753)
* Move almost all functions' parameter db.Engine to context.Context (#19748)
* Show source/target branches on PR's list (#19747)
* Use http.StatusTemporaryRedirect(307) when serve avatar directly (#19739)
* Add doctor orphan check for orphaned pull requests without an existing base repo (#19731)
* Make Ctrl+Enter (quick submit) work for issue comment and wiki editor (#19729)
* Update go-chi/cache to utilize Ping() (#19719)
* Improve commit list/view on mobile (#19712)
* Move some repository related code into sub package (#19711)
* Use a better OlderThan for DeleteInactiveUsers (#19693)
* Introduce eslint-plugin-jquery (#19690)
* Tidy up `<head>` template (#19678)
* Calculate filename hash only once (#19654)
* Simplify `IsVendor` (#19626)
* Add "Reference" section to Issue view sidebar (#19609)
* Only set CanColorStdout / CanColorStderr to true if the stdout/stderr is a terminal (#19581)
* Use for a repo action one database transaction (#19576)
* Simplify loops to copy (#19569)
* Added X-Mailer header to outgoing emails (#19562)
* use middleware to open gitRepo (#19559)
* Mute link in diff header (#19556)
* Improve UI on mobile (#19546)
* Fix Pull Request comment filename word breaks (#19535)
* Permalink files In PR diff (#19534)
* PullService lock via pullID (#19520)
* Make repository file list useable on mobile (#19515)
* more context for models (#19511)
* Refactor readme file renderer (#19502)
* By default force vertical tabs on mobile (#19486)
* Github style following followers (#19482)
* Improve action table indices (#19472)
* Use horizontal tabs for repo header on mobile (#19468)
* pass gitRepo down since its used for main repo and wiki (#19461)
* Admin should not delete himself (#19423)
* Use queue instead of memory queue in webhook send service (#19390)
* Simplify the code to get issue count (#19380)
* Add commit status popup to issuelist (#19375)
* Add RSS Feed buttons to Repo, User and Org pages (#19370)
* Add logic to switch between source/rendered on Markdown (#19356)
* Move some helper files out of models (#19355)
* Move access and repo permission to models/perm/access (#19350)
* Disallow selecting the text of buttons (#19330)
* Allow custom redirect for landing page (#19324)
* Remove dependent on session auth for api/v1 routers (#19321)
* Never use /api/v1 from Gitea UI Pages (#19318)
* Remove legacy unmaintained packages, refactor to support change default locale (#19308)
* Move milestone to models/issues/ (#19278)
* Configure OpenSSH log level via Environment in Docker (#19274)
* Move reaction to models/issues/ (#19264)
* Make git.OpenRepository accept Context (#19260)
* Move some issue methods as functions (#19255)
* Show last cron messages on monitor page (#19223)
* New cron task: delete old system notices (#19219)
* Add Redis Sentinel Authentication Support (#19213)
* Add auto logging of goroutine pid label (#19212)
* Set OpenGraph title to DisplayName in profile pages (#19206)
* Add pprof labels in processes and for lifecycles (#19202)
* Let web and API routes have different auth methods group (#19168)
* Move init repository related functions to modules (#19159)
* Feeds: render markdown to html (#19058)
* Allow users to self-request a PR review (#19030)
* Allow render HTML with css/js external links (#19017)
* Fix script compatiable with OpenWrt (#19000)
* Support ignore all santize for external renderer (#18984)
* Add note to GPG key response if user has no keys (#18961)
* Improve Stopwatch behavior (#18930)
* Improve mirror iterator (#18928)
* Uncapitalize errors (#18915)
* Prevent Stats Indexer reporting error if repo dir missing (#18870)
* Refactor SecToTime() function (#18863)
* Replace deprecated String.prototype.substr() with String.prototype.slice() (#18796)
* Move deletebeans into models/db (#18781)
* Fix display time of milestones (#18753)
* Add config option to disable "Update branch by rebase" (#18745)
* Display template path of current page in dev mode (#18717)
* Add number in queue status to monitor page (#18712)
* Change git.cmd to RunWithContext (#18693)
* Refactor i18n, use Locale to provide i18n/translation related functions (#18648)
* Delete old git.NewCommand() and use it as git.NewCommandContext() (#18552)
* Move organization related structs into sub package (#18518)
* Warn at startup if the provided `SCRIPT_TYPE` is not on the PATH (#18467)
* Use `CryptoRandomBytes` instead of `CryptoRandomString` (#18439)
* Use explicit jQuery import, remove unused eslint globals (#18435)
* Allow to filter repositories by language in explore, user and organization repositories lists (#18430)
* Use base32 for 2FA scratch token (#18384)
* Unexport var git.GlobalCommandArgs (#18376)
* Don't underline commit status icon on hover (#18372)
* Always use git command but not os.Command (#18363)
* Switch to non-deprecation setting (#18358)
* Set the LastModified header for raw files (#18356)
* Refactor jwt.StandardClaims to RegisteredClaims (#18344)
* Enable deprecation error for v1.17.0 (#18341)
* Refactor httplib (#18338)
* Limit max-height of CodeMirror editors for issue comment and wiki (#18271)
* Validate migration files (#18203)
* Format with gofumpt (#18184)
* Allow custom default merge message with .gitea/default_merge_message/<merge_style>_TEMPLATE.md (#18177)
* Prettify number of issues (#17760)
* Add a "admin user generate-access-token" subcommand (#17722)
* Custom regexp external issues (#17624)
* Add smtp password to install page (#17564)
* Add config options to hide issue events (#17414)
* Prevent double click new issue/pull/comment button (#16157)
* Show issue assignee on project board (#15232)
* BUGFIXES
* WebAuthn CredentialID field needs to be increased in size (#20530) (#20555)
* Ensure that all unmerged files are merged when conflict checking (#20528) (#20536)
* Stop logging EOFs and exit(1)s in ssh handler (#20476) (#20529)
* Add labels to two buttons that were missing them (#20419) (#20524)
* Fix ROOT_URL detection for URLs without trailing slash (#20502) (#20503)
* Dismiss prior pull reviews if done via web in review dismiss (#20197) (#20407)
* Allow RSA 2047 bit keys (#20272) (#20396)
* Add missing return for when topic isn't found (#20351) (#20395)
* Fix commit status icon when in subdirectory (#20285) (#20385)
* Initialize cron last (#20373) (#20384)
* Set target on create release with existing tag (#20381) (#20382)
* Update xorm.io/xorm to fix a interpreting db column sizes issue on 32bit systems (#20371) (#20372)
* Make sure `repo_dir` is an empty directory or doesn't exist before 'dump-repo' (#20205) (#20370)
* Prevent context deadline error propagation in GetCommitsInfo (#20346) (#20361)
* Correctly handle draft releases without a tag (#20314) (#20335)
* Prevent "empty" scrollbars on Firefox (#20294) (#20308)
* Refactor SSH init code, fix directory creation for TrustedUserCAKeys file (#20299) (#20306)
* Bump goldmark to v1.4.13 (#20300) (#20301)
* Do not create empty ".ssh" directory when loading config (#20289) (#20298)
* Fix NPE when using non-numeric (#20277) (#20278)
* Store read access in access for team repositories (#20275) (#20276)
* EscapeFilter the group dn membership (#20200) (#20254)
* Only show Followers that current user can access (#20220) (#20252)
* Update Bluemonday to v1.0.19 (#20199) (#20209)
* Refix indices on actions table (#20158) (#20198)
* Check if project has the same repository id with issue when assign project to issue (#20133) (#20188)
* Fix remove file on initial comment (#20127) (#20128)
* Catch the error before the response is processed by goth (#20000) (#20102)
* Dashboard feed respect setting.UI.FeedPagingNum again (#20094) (#20099)
* Alter hook_task TEXT fields to LONGTEXT (#20038) (#20041)
* Respond with a 401 on git push when password isn't changed yet (#20026) (#20027)
* Return 404 when tag is broken (#20017) (#20024)
* Alter hook_task TEXT fields to LONGTEXT (#20038) (#20041)
* Respond with a 401 on git push when password isn't changed yet (#20026) (#20027)
* Return 404 when tag is broken (#20017) (#20024)
* Write Commit-Graphs in RepositoryDumper (#20004)
* Use DisplayName() instead of FullName in Oauth Provider (#19991)
* Don't buffer doctor logger (#19982)
* Always try to fetch repo for mirrors (#19975)
* Uppercase first languages letters (#19965)
* Fix cli command restore-repo: "units" should be parsed as StringSlice (#19953)
* Ensure minimum mirror interval is reported on settings page (#19895)
* Exclude Archived repos from Dashboard Milestones (#19882)
* gitconfig: set safe.directory = * (#19870)
* Prevent NPE on update mirror settings (#19864)
* Only return valid stopwatches to the EventSource (#19863)
* Prevent NPE whilst migrating if there is a team request review (#19855)
* Fix inconsistency in doctor output (#19836)
* Fix release tag for webhook (#19830)
* Add title attribute to dependencies in sidebar (#19807)
* Estimate Action Count in Statistics (#19775)
* Do not update user stars numbers unless fix is specified (#19750)
* Improved ref comment link when origin is body/title (#19741)
* Fix nodeinfo caching and prevent NPE if cache non-existent (#19721)
* Fix duplicate entry error when add team member (#19702)
* Fix sending empty notifications (#19589)
* Update image URL for Discord webhook (#19536)
* Don't let repo clone URL overflow (#19517)
* Allow commit status popup on /pulls page (#19507)
* Fix two UI bugs: JS error in imagediff.js, 500 error in diff/compare.tmpl (#19494)
* Fix logging of Transfer API (#19456)
* Fix panic in teams API when requesting members (#19360)
* Refactor CSRF protection modules, make sure CSRF tokens can be up-to-date. (#19337)
* An attempt to sync a non-mirror repo must give 400 (Bad Request) (#19300)
* Move checks for pulls before merge into own function (#19271)
* Fix `contrib/upgrade.sh` (#19222)
* Set the default branch for repositories generated from templates (#19136)
* Fix EasyMDE error when input Enter (#19004)
* Don't clean up hardcoded `tmp` (#18983)
* Delete related notifications on issue deletion too (#18953)
* Fix trace log to show value instead of pointers (#18926)
* Fix behavior or checkbox submission. (#18851)
* Add `ContextUser` (#18798)
* Fix some mirror bugs (#18649)
* Quote MAKE to prevent path expansion with space error (#18622)
* Preserve users if restoring a repository on the same Gitea instance (#18604)
* Fix non-ASCII search on database (#18437)
* Automatically pause queue if index service is unavailable (#15066)
* TESTING
* Allow postgres integration tests to run over unix pipe (#19875)
* Prevent intermittent NPE in queue tests (#19301)
* Add test for importing pull requests in gitea uploader for migrations (#18752)
* Remove redundant comparison in repo dump/restore (#18660)
* More repo dump/restore tests, including pull requests (#18621)
* Add test coverage for original author conversion during migrations (#18506)
* TRANSLATION
* Update issue_no_dependencies description (#19112)
* Refactor webhooks i18n (#18380)
* BUILD
* Use alpine 3.16 (#19797)
* Require node 14.0 (#19451)
* DOCS
* Update documents (git/fomantic/db, etc) (#19868)
* Update the ROOT documentation and error messages (#19832)
* Update document to use FHS `/usr/local/bin/gitea` instead of `/app/...` for Docker (#19794)
* Update documentation to disable duration settings with -1 instead of 0 (#19647)
* Add warning to set SENDMAIL_ARGS to -- (#19102)
* Update nginx reverse proxy docs (#18922)
* Add example to render html files (#18736)
* Make SSH passtrough documentation better (#18687)
* Changelog 1.16.0 & 1.15.11 (#18468 & #18455) (#18470)
* Update the SSH passthrough documentation (#18366)
* Add `contrib/upgrade.sh` (#18286)
* MISC
* Fix aria for logo (#19955)
* In code search, get code unit accessible repos in one (main) query (#19764)
* Add tooltip to pending PR comments (#19662)
* Improve sync performance for pull-mirrors (#19125)
* Improve dashboard's repo list performance (#18963)
* Avoid database lookups for `DescriptionHTML` (#18924)
* Remove CodeMirror dependencies (#18911)
* Disable unnecessary mirroring elements (#18527)
* Disable unnecessary OpenID/OAuth2 elements (#18491)
* Disable unnecessary GitHooks elements (#18485)
* Change some logging levels (#18421)
* Prevent showing webauthn error for every time visiting `/user/settings/security` (#18385)
* Use correct translation key for errors (#18342)
## [1.16.9](https://github.com/go-gitea/gitea/releases/tag/v1.16.9) - 2022-07-12
* SECURITY
@ -160,7 +468,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
* SECURITY
* Git backend ignore replace objects (#18979) (#18980)
* Git backend ignore replace objects (#18979) (#18980)
* ENHANCEMENTS
* Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938)
* BUGFIXES

View file

@ -1,5 +1,5 @@
#Build stage
FROM golang:1.18-alpine3.16 AS build-env
FROM golang:1.19-alpine3.16 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

View file

@ -1,5 +1,5 @@
#Build stage
FROM golang:1.18-alpine3.16 AS build-env
FROM golang:1.19-alpine3.16 AS build-env
ARG GOPROXY
ENV GOPROXY ${GOPROXY:-direct}

View file

@ -23,7 +23,7 @@ SHASUM ?= shasum -a 256
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
COMMA := ,
XGO_VERSION := go-1.18.x
XGO_VERSION := go-1.19.x
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0

View file

@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/doctor"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@ -124,13 +125,18 @@ func runRecreateTable(ctx *cli.Context) error {
}
func runDoctor(ctx *cli.Context) error {
stdCtx, cancel := installSignals()
defer cancel()
// some doctor sub-commands need to use git command
if err := git.InitFull(stdCtx); err != nil {
return err
}
// Silence the default loggers
log.DelNamedLogger("console")
log.DelNamedLogger(log.DEFAULT)
stdCtx, cancel := installSignals()
defer cancel()
// Now setup our own
logFile := ctx.String("log-file")
if !ctx.IsSet("log-file") {

View file

@ -80,7 +80,6 @@ func runPR() {
setting.RunUser = curUser.Username
log.Printf("[PR] Loading fixtures data ...\n")
gitea_git.CheckLFSVersion()
//models.LoadConfigs()
/*
setting.Database.Type = "sqlite3"

View file

@ -698,9 +698,11 @@ ROUTER = console
;; Enable captcha validation for registration
;ENABLE_CAPTCHA = false
;;
;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha
;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha.
;CAPTCHA_TYPE = image
;;
;; Change this to use recaptcha.net or other recaptcha service
;RECAPTCHA_URL = https://www.google.com/recaptcha/
;; Enable recaptcha to use Google's recaptcha service
;; Go to https://www.google.com/recaptcha/admin to sign up for a key
;RECAPTCHA_SECRET =
@ -710,8 +712,13 @@ ROUTER = console
;HCAPTCHA_SECRET =
;HCAPTCHA_SITEKEY =
;;
;; Change this to use recaptcha.net or other recaptcha service
;RECAPTCHA_URL = https://www.google.com/recaptcha/
;; Change this to use demo.mcaptcha.org or your self-hosted mcaptcha.org instance.
;MCAPTCHA_URL = https://demo.mcaptcha.org
;;
;; Go to your configured mCaptcha instance and register a sitekey
;; and use your account's secret.
;MCAPTCHA_SECRET =
;MCAPTCHA_SITEKEY =
;;
;; Default value for KeepEmailPrivate
;; Each new user will get the value of this setting copied into their profile
@ -1083,7 +1090,7 @@ ROUTER = console
;EXPLORE_PAGING_NUM = 20
;;
;; Number of issues that are displayed on one page
;ISSUE_PAGING_NUM = 10
;ISSUE_PAGING_NUM = 20
;;
;; Number of maximum commits displayed in one activity feed
;FEED_MAX_COMMIT_NUM = 5
@ -1496,6 +1503,11 @@ ROUTER = console
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; NOTICE: this section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older,
;; please refer to
;; https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini
;; https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md
;;
;ENABLED = false
;;
;; Buffer length of channel, keep it as it is if you don't know what it is.
@ -1509,12 +1521,12 @@ ROUTER = console
;; - dummy: send email messages to the log as a testing phase.
;; If your provider does not explicitly say which protocol it uses but does provide a port,
;; you can set SMTP_PORT instead and this will be inferred.
;; (Before 1.18, this was controlled via MAILER_TYPE and IS_TLS_ENABLED.)
;; (Before 1.18, see the notice, this was controlled via MAILER_TYPE and IS_TLS_ENABLED.)
;PROTOCOL =
;;
;; Mail server address, e.g. smtp.gmail.com.
;; For smtp+unix, this should be a path to a unix socket instead.
;; (Before 1.18, this was combined with SMTP_PORT as HOST.)
;; (Before 1.18, see the notice, this was combined with SMTP_PORT as HOST.)
;SMTP_ADDR =
;;
;; Mail server port. Common ports are:

View file

@ -20,8 +20,9 @@ params:
website: https://docs.gitea.io
version: 1.16.9
minGoVersion: 1.18
goVersion: 1.18
goVersion: 1.19
minNodeVersion: 14
search: nav
outputs:
home:

View file

@ -172,7 +172,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
## UI (`ui`)
- `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page.
- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues).
- `ISSUE_PAGING_NUM`: **20**: Number of issues that are shown in one page (for all pages that list issues, milestones, projects).
- `MEMBERS_PAGING_NUM`: **20**: Number of members that are shown in organization members.
- `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed.
- `FEED_PAGING_NUM`: **20**: Number of items that are displayed in home feed.
@ -296,8 +296,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`.
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`.
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
- `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path.
- `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data.
- `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev".
@ -438,11 +438,11 @@ Configuration at `[queue]` will set defaults for queues with overrides for indiv
- `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue
- `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create.
- Queues by default come with a dynamically scaling worker pool. The following settings configure this:
- `WORKERS`: **0** (v1.14 and before: **1**): Number of initial workers for the queue.
- `WORKERS`: **0**: Number of initial workers for the queue.
- `MAX_WORKERS`: **10**: Maximum number of worker go-routines for the queue.
- `BLOCK_TIMEOUT`: **1s**: If the queue blocks for this time, boost the number of workers - the `BLOCK_TIMEOUT` will then be doubled before boosting again whilst the boost is ongoing.
- `BOOST_TIMEOUT`: **5m**: Boost workers will timeout after this long.
- `BOOST_WORKERS`: **1** (v1.14 and before: **5**): This many workers will be added to the worker pool if there is a boost.
- `BOOST_WORKERS`: **1**: This many workers will be added to the worker pool if there is a boost.
Gitea creates the following non-unique queues:
@ -579,13 +579,16 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
provided email rather than a generated email.
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also.
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha\]
even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`.
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\]
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
- `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net.
- `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha.
- `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha.
- `MCAPTCHA_SECRET`: **""**: Go to your mCaptcha instance to get a secret for mCaptcha.
- `MCAPTCHA_SITEKEY`: **""**: Go to your mCaptcha instance to get a sitekey for mCaptcha.
- `MCAPTCHA_URL` **https://demo.mcaptcha.org/**: Set the mCaptcha URL.
- `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private.
- `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default.
- `DEFAULT_USER_IS_RESTRICTED`: **false**: Give new users restricted permissions by default
@ -631,7 +634,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
- `QUEUE_LENGTH`: **1000**: Hook task queue length. Use caution when editing this value.
- `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks.
- `ALLOWED_HOST_LIST`: **external**: Since 1.15.7. Default to `*` for 1.15.x, `external` for 1.16 and later. Webhook can only call allowed hosts for security reasons. Comma separated list.
- `ALLOWED_HOST_LIST`: **external**: Webhook can only call allowed hosts for security reasons. Comma separated list.
- Built-in networks:
- `loopback`: 127.0.0.0/8 for IPv4 and ::1/128 for IPv6, localhost is included.
- `private`: RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and RFC 4193 (FC00::/7). Also called LAN/Intranet.
@ -646,6 +649,12 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
## Mailer (`mailer`)
⚠️ This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older,
please refer to
[Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini)
and
[Gitea 1.17 configuration document](https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md)
- `ENABLED`: **false**: Enable to use a mail service.
- `PROTOCOL`: **\<empty\>**: Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
- SMTP family, if your provider does not explicitly say which protocol it uses but does provide a port, you can set SMTP_PORT instead and this will be inferred.

View file

@ -15,7 +15,14 @@ menu:
# 配置说明
这是针对Gitea配置文件的说明你可以了解Gitea的强大配置。需要说明的是你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。
这是针对Gitea配置文件的说明你可以了解Gitea的强大配置。需要说明的是你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。
所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。
如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。
标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。
## ⚠️时效性警告⚠️
此文档的内容可能过于陈旧或者错误,请参考英文文档。
{{< toc >}}

View file

@ -105,6 +105,18 @@ curl -X POST "http://localhost:4000/api/v1/repos/test1/test1/issues" \
As mentioned above, the token used is the same one you would use in
the `token=` string in a GET request.
## Pagination
The API supports pagination. The `page` and `limit` parameters are used to specify the page number and the number of items per page. As well, the `Link` header is returned with the next, previous, and last page links if there are more than one pages. The `x-total-count` is also returned to indicate the total number of items.
```sh
curl -v "http://localhost/api/v1/repos/search?limit=1"
...
< link: <http://localhost/api/v1/repos/search?limit=1&page=2>; rel="next",<http://localhost/api/v1/repos/search?limit=1&page=5252>; rel="last"
...
< x-total-count: 5252
```
## API Guide:
API Reference guide is auto-generated by swagger and available on:

View file

@ -46,7 +46,7 @@ _表格中的符号含义:_
| Git 驱动的集成化 wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 部署令牌 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 仓库写权限令牌 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
| 内置容器 Registry | | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 内置容器 Registry | | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 外部 Git 镜像 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ |
| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? |
| 内置 CI/CD | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
@ -62,7 +62,7 @@ _表格中的符号含义:_
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | | ✓ |
| 组织里程碑 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 细粒度用户角色 (例如 Code, Issues, Wiki) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 提交人的身份验证 | | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
| 提交人的身份验证 | | ✘ | ? | ✓ | ✓ | ✓ | ✘ |
| GPG 签名的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| SSH 签名的提交 | ✓ | ✘ | ✘ | ✘ | ✘ | ? | ? |
| 拒绝未用通过验证的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
@ -71,6 +71,7 @@ _表格中的符号含义:_
| 建立新分支 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 在线代码编辑 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 提交的统计图表 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 模板仓库 | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ |
#### Issue 管理
@ -84,9 +85,9 @@ _表格中的符号含义:_
| 关联的 issues | ✘ | ✘ | | ✘ | ✓ | ✘ | ✘ |
| 私密 issues | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 评论反馈 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 锁定讨论 | | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 锁定讨论 | | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| Issue 批量处理 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
| Issue 看板 | | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| Issue 看板 | | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 从 issues 创建分支 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| Issue 搜索 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 全局 Issue 搜索 | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
@ -108,6 +109,7 @@ _表格中的符号含义:_
| 回退某些 commits 或 merge request | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| Pull/Merge requests 模板 | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 查看 Cherry-picking 的更改 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
| 下载 Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✘ |
#### 第三方集成
@ -124,4 +126,5 @@ _表格中的符号含义:_
| 二次验证 (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 集成 Mattermost/Slack | ✓ | ✓ | | ✓ | ✓ | | ✓ |
| 集成 Discord | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
| 集成 Microsoft Teams | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| 显示外部 CI/CD 的状态 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |

View file

@ -0,0 +1,18 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "Search"
slug: "search"
weight: 4
toc: false
draft: false
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View file

@ -5,12 +5,6 @@ slug: "search"
weight: 4
toc: false
draft: false
menu:
sidebar:
parent: "help"
name: "Search"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"

View file

@ -5,12 +5,6 @@ slug: "search"
weight: 4
toc: false
draft: false
menu:
sidebar:
parent: "help"
name: "Chercher"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"

View file

@ -0,0 +1,18 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "Search"
slug: "search"
weight: 4
toc: false
draft: false
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View file

@ -0,0 +1,18 @@
---
date: "2019-11-12T16:00:00+02:00"
title: "Search"
slug: "search"
weight: 4
toc: false
draft: false
sitemap:
priority : 0.1
layout: "search"
---
This file exists solely to respond to /search URL with the related `search` layout template.
No content shown here is rendered, all content is based in the template layouts/doc/search.html
Setting a very low sitemap priority will tell search engines this is not important content.

View file

@ -5,12 +5,6 @@ slug: "search"
weight: 4
toc: false
draft: false
menu:
sidebar:
parent: "help"
name: "搜索"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"

View file

@ -5,12 +5,6 @@ slug: "search"
weight: 4
toc: false
draft: false
menu:
sidebar:
parent: "help"
name: "搜尋"
weight: 4
identifier: "search"
sitemap:
priority : 0.1
layout: "search"

View file

@ -27,7 +27,7 @@ To authenticate to the Package Registry, you need to provide [custom HTTP header
## Publish a package
To publish a generic package perform a HTTP PUT operation with the package content in the request body.
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
You cannot publish a file with the same name twice to a package. You must delete the existing package version first.
```
PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{file_name}
@ -36,9 +36,9 @@ PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{packa
| Parameter | Description |
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
| `package_version` | The package version, a non-empty string. |
| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). |
| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). |
| `package_version` | The package version, a non-empty string without trailing or leading whitespaces. |
| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). |
Example request using HTTP Basic authentication:
@ -55,7 +55,8 @@ The server reponds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
| ----------------- | ------- |
| `201 Created` | The package has been published. |
| `400 Bad Request` | The package name and/or version are invalid or a package with the same name and version already exist. |
| `400 Bad Request` | The package name and/or version and/or file name are invalid. |
| `409 Conflict` | A file with the same name exist already in the package. |
## Download a package
@ -80,3 +81,67 @@ Example request using HTTP Basic authentication:
curl --user your_username:your_token_or_password \
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
```
The server reponds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
| ----------------- | ------- |
| `200 OK` | Success |
| `404 Not Found` | The package or file was not found. |
## Delete a package
To delete a generic package perform a HTTP DELETE operation. This will delete all files of this version.
```
DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}
```
| Parameter | Description |
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `package_name` | The package name. |
| `package_version` | The package version. |
Example request using HTTP Basic authentication:
```shell
curl --user your_username:your_token_or_password -X DELETE \
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0
```
The server reponds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
| ----------------- | ------- |
| `204 No Content` | Success |
| `404 Not Found` | The package was not found. |
## Delete a package file
To delete a file of a generic package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
```
DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{filename}
```
| Parameter | Description |
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `package_name` | The package name. |
| `package_version` | The package version. |
| `filename` | The filename. |
Example request using HTTP Basic authentication:
```shell
curl --user your_username:your_token_or_password -X DELETE \
https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin
```
The server reponds with the following HTTP Status codes.
| HTTP Status Code | Meaning |
| ----------------- | ------- |
| `204 No Content` | Success |
| `404 Not Found` | The package or file was not found. |

View file

@ -81,6 +81,16 @@ To publish a package simply run:
mvn deploy
```
If you want to publish a prebuild package to the registry, you can use [`mvn deploy:deploy-file`](https://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html):
```shell
mvn deploy:deploy-file -Durl=https://gitea.example.com/api/packages/{owner}/maven -DrepositoryId=gitea -Dfile=/path/to/package.jar
```
| Parameter | Description |
| -------------- | ----------- |
| `owner` | The owner of the package. |
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
## Install a package

View file

@ -67,6 +67,26 @@ npm publish
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
## Unpublish a package
Delete a package by running the following command:
```shell
npm unpublish {package_name}[@{package_version}]
```
| Parameter | Description |
| ----------------- | ----------- |
| `package_name` | The package name. |
| `package_version` | The package version. |
For example:
```shell
npm unpublish @test/test_package
npm unpublish @test/test_package@1.0.0
```
## Install a package
To install a package from the package registry, execute the following command:
@ -113,6 +133,7 @@ The tag name must not be a valid version. All tag names which are parsable as a
npm install
npm ci
npm publish
npm unpublish
npm dist-tag
npm view
```

View file

@ -47,6 +47,8 @@ For example:
dotnet nuget add source --name gitea --username testuser --password password123 https://gitea.example.com/api/packages/testuser/nuget/index.json
```
You can add the source without credentials and use the [`--api-key`](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push) parameter when publishing packages. In this case you need to provide a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}).
## Publish a package
Publish a package by running the following command:

View file

@ -34,6 +34,7 @@ The following package managers are currently supported:
| [Maven]({{< relref "doc/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` |
| [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn` |
| [NuGet]({{< relref "doc/packages/nuget.en-us.md" >}}) | .NET | `nuget` |
| [Pub]({{< relref "doc/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` |
| [PyPI]({{< relref "doc/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` |
| [RubyGems]({{< relref "doc/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` |

View file

@ -0,0 +1,83 @@
---
date: "2022-07-31T00:00:00+00:00"
title: "Pub Packages Repository"
slug: "packages/pub"
draft: false
toc: false
menu:
sidebar:
parent: "packages"
name: "Pub"
weight: 90
identifier: "pub"
---
# Pub Packages Repository
Publish [Pub](https://dart.dev/guides/packages) packages for your user or organization.
**Table of Contents**
{{< toc >}}
## Requirements
To work with the Pub package registry, you need to use the tools [dart](https://dart.dev/tools/dart-tool) and/or [flutter](https://docs.flutter.dev/reference/flutter-cli).
The following examples use dart.
## Configuring the package registry
To register the package registry and provide credentials, execute:
```shell
dart pub token add https://gitea.example.com/api/packages/{owner}/pub
```
| Placeholder | Description |
| ------------ | ----------- |
| `owner` | The owner of the package. |
You need to provide your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}).
## Publish a package
To publish a package, edit the `pubspec.yaml` and add the following line:
```yaml
publish_to: https://gitea.example.com/api/packages/{owner}/pub
```
| Placeholder | Description |
| ------------ | ----------- |
| `owner` | The owner of the package. |
Now you can publish the package by running the following command:
```shell
dart pub publish
```
You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first.
## Install a package
To install a Pub package from the package registry, execute the following command:
```shell
dart pub add {package_name} --hosted-url=https://gitea.example.com/api/packages/{owner}/pub/
```
| Parameter | Description |
| ----------------- | ----------- |
| `owner` | The owner of the package. |
| `package_name` | The package name. |
For example:
```shell
# use latest version
dart pub add mypackage --hosted-url=https://gitea.example.com/api/packages/testuser/pub/
# specify version
dart pub add mypackage:1.0.8 --hosted-url=https://gitea.example.com/api/packages/testuser/pub/
```

View file

@ -8,7 +8,7 @@ menu:
sidebar:
parent: "packages"
name: "PyPI"
weight: 90
weight: 100
identifier: "pypi"
---

View file

@ -8,7 +8,7 @@ menu:
sidebar:
parent: "packages"
name: "RubyGems"
weight: 100
weight: 110
identifier: "rubygems"
---

View file

@ -23,6 +23,12 @@ To update Gitea, download a newer version, stop the old one, perform a backup, a
Every time a Gitea instance starts up, it checks whether a database migration should be run.
If a database migration is required, Gitea will take some time to complete the upgrade and then serve.
## Check the Changelog for breaking changes
To make Gitea better, some breaking changes are unavoidable, especially for big milestone releases.
Before upgrade, please read the [Changelog on Gitea blog](https://blog.gitea.io/)
and check whether the breaking changes affect your Gitea instance.
## Backup for downgrade
Gitea keeps compatibility for patch versions whose first two fields are the same (`a.b.x` -> `a.b.y`),

View file

@ -11,12 +11,6 @@
<div class=" content">
<section class="resume-section p-3 p-lg-5 d-flex flex-column">
<div class="my-auto" >
<form action="{{ "search" | absLangURL }}">
<label>Search:
<input id="search-query" name="s"/>
</label>
</form>
<br/>
<div id="search-results"></div>
</div>
</section>

1
go.mod
View file

@ -5,6 +5,7 @@ go 1.18
require (
code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b
code.gitea.io/sdk/gitea v0.15.1
codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
gitea.com/go-chi/cache v0.2.0
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5

2
go.sum
View file

@ -62,6 +62,8 @@ code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b/go.mod h1:zcNbT/aJE
code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY=
code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M=
code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222 h1:PCW4i+gnQ9XxF8V+nBch3KWdGe4MiP3xXUCA/z0jhHk=
codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM=
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=

View file

@ -16,6 +16,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
@ -171,19 +172,21 @@ func TestAPISearchIssues(t *testing.T) {
token := getUserToken(t, "user2")
link, _ := url.Parse("/api/v1/repos/issues/search")
req := NewRequest(t, "GET", link.String()+"?token="+token)
resp := MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
// as this API was used in the frontend, it uses UI page size
expectedIssueCount := 15 // from the fixtures
if expectedIssueCount > setting.UI.IssuePagingNum {
expectedIssueCount = setting.UI.IssuePagingNum
}
link, _ := url.Parse("/api/v1/repos/issues/search")
query := url.Values{"token": {getUserToken(t, "user1")}}
var apiIssues []*api.Issue
query := url.Values{"token": {token}}
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
req := NewRequest(t, "GET", link.String())
resp := MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
assert.Len(t, apiIssues, expectedIssueCount)
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
before := time.Unix(999307200, 0).Format(time.RFC3339)
@ -211,14 +214,15 @@ func TestAPISearchIssues(t *testing.T) {
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
assert.Len(t, apiIssues, 17)
query.Add("limit", "20")
query.Add("limit", "10")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 17)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 10)
query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}}
link.RawQuery = query.Encode()
@ -266,23 +270,21 @@ func TestAPISearchIssues(t *testing.T) {
func TestAPISearchIssuesWithLabels(t *testing.T) {
defer prepareTestEnv(t)()
token := getUserToken(t, "user1")
// as this API was used in the frontend, it uses UI page size
expectedIssueCount := 15 // from the fixtures
if expectedIssueCount > setting.UI.IssuePagingNum {
expectedIssueCount = setting.UI.IssuePagingNum
}
link, _ := url.Parse("/api/v1/repos/issues/search")
req := NewRequest(t, "GET", link.String()+"?token="+token)
resp := MakeRequest(t, req, http.StatusOK)
query := url.Values{"token": {getUserToken(t, "user1")}}
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
query := url.Values{}
query.Add("token", token)
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
req := NewRequest(t, "GET", link.String())
resp := MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
assert.Len(t, apiIssues, expectedIssueCount)
query.Add("labels", "label1")
link.RawQuery = query.Encode()

View file

@ -276,11 +276,23 @@ func TestPackageContainer(t *testing.T) {
}
}
// Overwrite existing tag
req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag))
addTokenAuthHeader(req, userToken)
MakeRequest(t, req, http.StatusOK)
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount)
// Overwrite existing tag should keep the download count
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent))
addTokenAuthHeader(req, userToken)
req.Header.Set("Content-Type", oci.MediaTypeDockerManifest)
MakeRequest(t, req, http.StatusCreated)
pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag)
assert.NoError(t, err)
assert.EqualValues(t, 1, pv.DownloadCount)
})
t.Run("HeadManifest", func(t *testing.T) {

View file

@ -23,16 +23,16 @@ func TestPackageGeneric(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
packageName := "te-st_pac.kage"
packageVersion := "1.0.3"
packageVersion := "1.0.3-te st"
filename := "fi-le_na.me"
content := []byte{1, 2, 3}
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename)
url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion)
t.Run("Upload", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusCreated)
@ -55,54 +55,139 @@ func TestPackageGeneric(t *testing.T) {
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(len(content)), pb.Size)
})
t.Run("UploadExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
t.Run("Exists", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusConflict)
})
t.Run("Additional", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", url+"/dummy.bin", bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusCreated)
// Check deduplication
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 2)
assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID)
})
t.Run("InvalidParameter", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid+package name", packageVersion, filename), bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, "%20test ", filename), bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inval+id.na me"), bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusBadRequest)
})
})
t.Run("Download", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "GET", url)
checkDownloadCount := func(count int64) {
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
assert.Equal(t, count, pvs[0].DownloadCount)
}
checkDownloadCount(0)
req := NewRequest(t, "GET", url+"/"+filename)
resp := MakeRequest(t, req, http.StatusOK)
assert.Equal(t, content, resp.Body.Bytes())
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
assert.Equal(t, int64(1), pvs[0].DownloadCount)
checkDownloadCount(1)
req = NewRequest(t, "GET", url+"/dummy.bin")
MakeRequest(t, req, http.StatusOK)
checkDownloadCount(2)
t.Run("NotExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "GET", url+"/not.found")
MakeRequest(t, req, http.StatusNotFound)
})
})
t.Run("Delete", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "DELETE", url)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusOK)
t.Run("File", func(t *testing.T) {
defer PrintCurrentTest(t)()
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Empty(t, pvs)
})
req := NewRequest(t, "DELETE", url+"/"+filename)
MakeRequest(t, req, http.StatusUnauthorized)
t.Run("DownloadNotExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
req = NewRequest(t, "DELETE", url+"/"+filename)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNoContent)
req := NewRequest(t, "GET", url)
MakeRequest(t, req, http.StatusNotFound)
})
req = NewRequest(t, "GET", url+"/"+filename)
MakeRequest(t, req, http.StatusNotFound)
t.Run("DeleteNotExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
req = NewRequest(t, "DELETE", url+"/"+filename)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNotFound)
req := NewRequest(t, "DELETE", url)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNotFound)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
t.Run("RemovesVersion", func(t *testing.T) {
defer PrintCurrentTest(t)()
req = NewRequest(t, "DELETE", url+"/dummy.bin")
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNoContent)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Empty(t, pvs)
})
})
t.Run("Version", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content))
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusCreated)
req = NewRequest(t, "DELETE", url)
MakeRequest(t, req, http.StatusUnauthorized)
req = NewRequest(t, "DELETE", url)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNoContent)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric)
assert.NoError(t, err)
assert.Empty(t, pvs)
req = NewRequest(t, "GET", url+"/"+filename)
MakeRequest(t, req, http.StatusNotFound)
req = NewRequest(t, "DELETE", url)
AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusNotFound)
})
})
}

View file

@ -42,6 +42,7 @@ func TestPackageMaven(t *testing.T) {
defer PrintCurrentTest(t)()
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
@ -135,12 +136,14 @@ func TestPackageMaven(t *testing.T) {
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 2)
i := 0
if strings.HasSuffix(pfs[1].Name, ".pom") {
i = 1
for _, pf := range pfs {
if strings.HasSuffix(pf.Name, ".pom") {
assert.Equal(t, filename+".pom", pf.Name)
assert.True(t, pf.IsLead)
} else {
assert.False(t, pf.IsLead)
}
}
assert.Equal(t, filename+".pom", pfs[i].Name)
assert.True(t, pfs[i].IsLead)
})
t.Run("DownloadPOM", func(t *testing.T) {
@ -202,4 +205,13 @@ func TestPackageMaven(t *testing.T) {
assert.Equal(t, checksum, resp.Body.String())
}
})
t.Run("UploadSnapshot", func(t *testing.T) {
snapshotVersion := packageVersion + "-SNAPSHOT"
putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
})
}

View file

@ -36,33 +36,36 @@ func TestPackageNpm(t *testing.T) {
packageDescription := "Test Description"
data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA"
upload := `{
"_id": "` + packageName + `",
"name": "` + packageName + `",
"description": "` + packageDescription + `",
"dist-tags": {
"` + packageTag + `": "` + packageVersion + `"
},
"versions": {
"` + packageVersion + `": {
buildUpload := func(version string) string {
return `{
"_id": "` + packageName + `",
"name": "` + packageName + `",
"version": "` + packageVersion + `",
"description": "` + packageDescription + `",
"author": {
"name": "` + packageAuthor + `"
"dist-tags": {
"` + packageTag + `": "` + version + `"
},
"dist": {
"integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
"shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
"versions": {
"` + version + `": {
"name": "` + packageName + `",
"version": "` + version + `",
"description": "` + packageDescription + `",
"author": {
"name": "` + packageAuthor + `"
},
"dist": {
"integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==",
"shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90"
}
}
},
"_attachments": {
"` + packageName + `-` + version + `.tgz": {
"data": "` + data + `"
}
}
}
},
"_attachments": {
"` + packageName + `-` + packageVersion + `.tgz": {
"data": "` + data + `"
}
}
}`
}`
}
root := fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, url.QueryEscape(packageName))
tagsRoot := fmt.Sprintf("/api/packages/%s/npm/-/package/%s/dist-tags", user.Name, url.QueryEscape(packageName))
@ -71,7 +74,7 @@ func TestPackageNpm(t *testing.T) {
t.Run("Upload", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusCreated)
@ -103,7 +106,7 @@ func TestPackageNpm(t *testing.T) {
t.Run("UploadExists", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload))
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion)))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusBadRequest)
})
@ -219,4 +222,57 @@ func TestPackageNpm(t *testing.T) {
test(t, http.StatusOK, "dummy")
test(t, http.StatusOK, packageTag2)
})
t.Run("Delete", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion+"-dummy")))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusCreated)
req = NewRequest(t, "PUT", root+"/-rev/dummy")
MakeRequest(t, req, http.StatusUnauthorized)
req = NewRequest(t, "PUT", root+"/-rev/dummy")
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusOK)
t.Run("Version", func(t *testing.T) {
defer PrintCurrentTest(t)()
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
assert.NoError(t, err)
assert.Len(t, pvs, 2)
req := NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
MakeRequest(t, req, http.StatusUnauthorized)
req = NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename))
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusOK)
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
})
t.Run("Full", func(t *testing.T) {
defer PrintCurrentTest(t)()
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
req := NewRequest(t, "DELETE", root+"/-rev/dummy")
MakeRequest(t, req, http.StatusUnauthorized)
req = NewRequest(t, "DELETE", root+"/-rev/dummy")
req = addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusOK)
pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm)
assert.NoError(t, err)
assert.Len(t, pvs, 0)
})
})
}

View file

@ -24,9 +24,16 @@ import (
"github.com/stretchr/testify/assert"
)
func addNuGetAPIKeyHeader(request *http.Request, token string) *http.Request {
request.Header.Set("X-NuGet-ApiKey", token)
return request
}
func TestPackageNuGet(t *testing.T) {
defer prepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
token := getUserToken(t, user.Name)
packageName := "test.package"
packageVersion := "1.0.3"
@ -60,6 +67,10 @@ func TestPackageNuGet(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
req = AddBasicAuthHeader(req, user.Name)
MakeRequest(t, req, http.StatusOK)
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
req = addNuGetAPIKeyHeader(req, token)
resp := MakeRequest(t, req, http.StatusOK)
var result nuget.ServiceIndexResponse

View file

@ -0,0 +1,179 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
pub_module "code.gitea.io/gitea/modules/packages/pub"
"github.com/stretchr/testify/assert"
)
func TestPackagePub(t *testing.T) {
defer prepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
token := "Bearer " + getUserToken(t, user.Name)
packageName := "test_package"
packageVersion := "1.0.1"
packageDescription := "Test Description"
filename := fmt.Sprintf("%s.tar.gz", packageVersion)
pubspecContent := `name: ` + packageName + `
version: ` + packageVersion + `
description: ` + packageDescription
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
archive := tar.NewWriter(zw)
archive.WriteHeader(&tar.Header{
Name: "pubspec.yaml",
Mode: 0o600,
Size: int64(len(pubspecContent)),
})
archive.Write([]byte(pubspecContent))
archive.Close()
zw.Close()
content := buf.Bytes()
root := fmt.Sprintf("/api/packages/%s/pub", user.Name)
t.Run("Upload", func(t *testing.T) {
defer PrintCurrentTest(t)()
uploadURL := root + "/api/packages/versions/new"
req := NewRequest(t, "GET", uploadURL)
MakeRequest(t, req, http.StatusUnauthorized)
req = NewRequest(t, "GET", uploadURL)
addTokenAuthHeader(req, token)
resp := MakeRequest(t, req, http.StatusOK)
type UploadRequest struct {
URL string `json:"url"`
Fields map[string]string `json:"fields"`
}
var result UploadRequest
DecodeJSON(t, resp, &result)
assert.Empty(t, result.Fields)
uploadFile := func(t *testing.T, url string, content []byte, expectedStatus int) *httptest.ResponseRecorder {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "dummy.tar.gz")
_, _ = io.Copy(part, bytes.NewReader(content))
_ = writer.Close()
req := NewRequestWithBody(t, "POST", url, body)
req.Header.Add("Content-Type", writer.FormDataContentType())
addTokenAuthHeader(req, token)
return MakeRequest(t, req, expectedStatus)
}
resp = uploadFile(t, result.URL, content, http.StatusNoContent)
req = NewRequest(t, "GET", resp.Header().Get("Location"))
addTokenAuthHeader(req, token)
MakeRequest(t, req, http.StatusOK)
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePub)
assert.NoError(t, err)
assert.Len(t, pvs, 1)
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err)
assert.NotNil(t, pd.SemVer)
assert.IsType(t, &pub_module.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version)
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
assert.NoError(t, err)
assert.Len(t, pfs, 1)
assert.Equal(t, filename, pfs[0].Name)
assert.True(t, pfs[0].IsLead)
pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID)
assert.NoError(t, err)
assert.Equal(t, int64(len(content)), pb.Size)
resp = uploadFile(t, result.URL, content, http.StatusBadRequest)
})
t.Run("Download", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s/%s", root, packageName, packageVersion))
resp := MakeRequest(t, req, http.StatusOK)
type VersionMetadata struct {
Version string `json:"version"`
ArchiveURL string `json:"archive_url"`
Published time.Time `json:"published"`
Pubspec interface{} `json:"pubspec,omitempty"`
}
var result VersionMetadata
DecodeJSON(t, resp, &result)
assert.Equal(t, packageVersion, result.Version)
assert.NotNil(t, result.Pubspec)
req = NewRequest(t, "GET", result.ArchiveURL)
resp = MakeRequest(t, req, http.StatusOK)
assert.Equal(t, content, resp.Body.Bytes())
})
t.Run("EnumeratePackageVersions", func(t *testing.T) {
defer PrintCurrentTest(t)()
req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s", root, packageName))
resp := MakeRequest(t, req, http.StatusOK)
type VersionMetadata struct {
Version string `json:"version"`
ArchiveURL string `json:"archive_url"`
Published time.Time `json:"published"`
Pubspec interface{} `json:"pubspec,omitempty"`
}
type PackageVersions struct {
Name string `json:"name"`
Latest *VersionMetadata `json:"latest"`
Versions []*VersionMetadata `json:"versions"`
}
var result PackageVersions
DecodeJSON(t, resp, &result)
assert.Equal(t, packageName, result.Name)
assert.NotNil(t, result.Latest)
assert.Len(t, result.Versions, 1)
assert.Equal(t, result.Latest.Version, result.Versions[0].Version)
assert.Equal(t, packageVersion, result.Latest.Version)
assert.NotNil(t, result.Latest.Pubspec)
})
}

View file

@ -156,11 +156,6 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string
func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) {
t.Run("LFS", func(t *testing.T) {
defer PrintCurrentTest(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
prefix := "lfs-data-file-"
err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath})
assert.NoError(t, err)
@ -226,7 +221,6 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
git.CheckLFSVersion()
if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
resp := session.MakeRequest(t, req, http.StatusOK)
@ -268,12 +262,9 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
git.CheckLFSVersion()
if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
}
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS))
resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length)
if !testing.Short() {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big))

View file

@ -175,10 +175,9 @@ func initIntegrationTest() {
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
_ = util.RemoveAll(repo_module.LocalCopyPath())
if err := git.InitOnceWithSync(context.Background()); err != nil {
if err := git.InitFull(context.Background()); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err)
}
git.CheckLFSVersion()
setting.InitDBConfig()
if err := storage.Init(); err != nil {
@ -285,7 +284,6 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@ -586,7 +584,6 @@ func resetFixtures(t *testing.T) {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

View file

@ -356,17 +356,17 @@ func TestSearchIssues(t *testing.T) {
session := loginUser(t, "user2")
expectedIssueCount := 15 // from the fixtures
if expectedIssueCount > setting.UI.IssuePagingNum {
expectedIssueCount = setting.UI.IssuePagingNum
}
link, _ := url.Parse("/issues/search")
req := NewRequest(t, "GET", link.String())
resp := session.MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
assert.Len(t, apiIssues, expectedIssueCount)
since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801
before := time.Unix(999307200, 0).Format(time.RFC3339)
@ -394,14 +394,15 @@ func TestSearchIssues(t *testing.T) {
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit
assert.Len(t, apiIssues, 17)
query.Add("limit", "20")
query.Add("limit", "5")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 17)
assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count"))
assert.Len(t, apiIssues, 5)
query = url.Values{"assigned": {"true"}, "state": {"all"}}
link.RawQuery = query.Encode()
@ -449,29 +450,26 @@ func TestSearchIssues(t *testing.T) {
func TestSearchIssuesWithLabels(t *testing.T) {
defer prepareTestEnv(t)()
token := getUserToken(t, "user1")
link, _ := url.Parse("/api/v1/repos/issues/search?token=" + token)
req := NewRequest(t, "GET", link.String())
resp := MakeRequest(t, req, http.StatusOK)
var apiIssues []*api.Issue
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
query := url.Values{
"token": []string{token},
expectedIssueCount := 15 // from the fixtures
if expectedIssueCount > setting.UI.IssuePagingNum {
expectedIssueCount = setting.UI.IssuePagingNum
}
session := loginUser(t, "user1")
link, _ := url.Parse("/issues/search")
query := url.Values{}
var apiIssues []*api.Issue
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
req := NewRequest(t, "GET", link.String())
resp := session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 10)
assert.Len(t, apiIssues, expectedIssueCount)
query.Add("labels", "label1")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@ -479,7 +477,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "label1,label2")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@ -487,7 +485,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "orglabel4")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 1)
@ -496,7 +494,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Add("state", "all")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
@ -504,7 +502,7 @@ func TestSearchIssuesWithLabels(t *testing.T) {
query.Set("labels", "label1,orglabel4")
link.RawQuery = query.Encode()
req = NewRequest(t, "GET", link.String())
resp = MakeRequest(t, req, http.StatusOK)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiIssues)
assert.Len(t, apiIssues, 2)
}

View file

@ -14,7 +14,6 @@ import (
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
@ -83,11 +82,6 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt
func TestGetLFSSmall(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("A very small file\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@ -96,11 +90,6 @@ func TestGetLFSSmall(t *testing.T) {
func TestGetLFSLarge(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := make([]byte, web.GzipMinSize*10)
for i := range content {
content[i] = byte(i % 256)
@ -112,11 +101,6 @@ func TestGetLFSLarge(t *testing.T) {
func TestGetLFSGzip(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
@ -133,11 +117,6 @@ func TestGetLFSGzip(t *testing.T) {
func TestGetLFSZip(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
b := make([]byte, web.GzipMinSize*10)
for i := range b {
b[i] = byte(i % 256)
@ -156,11 +135,6 @@ func TestGetLFSZip(t *testing.T) {
func TestGetLFSRangeNo(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("123456789\n")
resp := storeAndGetLfs(t, &content, nil, http.StatusOK)
@ -169,11 +143,6 @@ func TestGetLFSRangeNo(t *testing.T) {
func TestGetLFSRange(t *testing.T) {
defer prepareTestEnv(t)()
git.CheckLFSVersion()
if !setting.LFS.StartServer {
t.Skip()
return
}
content := []byte("123456789\n")
tests := []struct {

View file

@ -82,8 +82,7 @@ func initMigrationTest(t *testing.T) func() {
}
}
assert.NoError(t, git.InitOnceWithSync(context.Background()))
git.CheckLFSVersion()
assert.NoError(t, git.InitFull(context.Background()))
setting.InitDBConfig()
setting.NewLogServices(true)
return deferFn

View file

@ -56,11 +56,11 @@ func TestPullCreate_CommitStatus(t *testing.T) {
}
statesIcons := map[api.CommitStatusState]string{
api.CommitStatusPending: "circle icon yellow",
api.CommitStatusSuccess: "check icon green",
api.CommitStatusError: "warning icon red",
api.CommitStatusFailure: "remove icon red",
api.CommitStatusWarning: "warning sign icon yellow",
api.CommitStatusPending: "octicon-dot-fill",
api.CommitStatusSuccess: "octicon-check",
api.CommitStatusError: "gitea-exclamation",
api.CommitStatusFailure: "octicon-x",
api.CommitStatusWarning: "gitea-exclamation",
}
testCtx := NewAPITestContext(t, "user1", "repo1")
@ -80,9 +80,9 @@ func TestPullCreate_CommitStatus(t *testing.T) {
assert.NotEmpty(t, commitURL)
assert.EqualValues(t, commitID, path.Base(commitURL))
cls, ok := doc.doc.Find("#commits-table tbody tr td.message i.commit-status").Last().Attr("class")
cls, ok := doc.doc.Find("#commits-table tbody tr td.message .commit-status").Last().Attr("class")
assert.True(t, ok)
assert.EqualValues(t, "commit-status "+statesIcons[status], cls)
assert.Contains(t, cls, statesIcons[status])
}
})
}

View file

@ -55,7 +55,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
doc = NewHTMLParser(t, resp.Body)
// Check if commit status is displayed in message column
sel := doc.doc.Find("#commits-table tbody tr td.message a.commit-statuses-trigger i.commit-status")
sel := doc.doc.Find("#commits-table tbody tr td.message a.commit-statuses-trigger .commit-status")
assert.Equal(t, 1, sel.Length())
for _, class := range classes {
assert.True(t, sel.HasClass(class))
@ -96,21 +96,21 @@ func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRec
}
func TestRepoCommitsWithStatusPending(t *testing.T) {
doTestRepoCommitWithStatus(t, "pending", "circle", "yellow")
doTestRepoCommitWithStatus(t, "pending", "octicon-dot-fill", "yellow")
}
func TestRepoCommitsWithStatusSuccess(t *testing.T) {
doTestRepoCommitWithStatus(t, "success", "check", "green")
doTestRepoCommitWithStatus(t, "success", "octicon-check", "green")
}
func TestRepoCommitsWithStatusError(t *testing.T) {
doTestRepoCommitWithStatus(t, "error", "warning", "red")
doTestRepoCommitWithStatus(t, "error", "gitea-exclamation", "red")
}
func TestRepoCommitsWithStatusFailure(t *testing.T) {
doTestRepoCommitWithStatus(t, "failure", "remove", "red")
doTestRepoCommitWithStatus(t, "failure", "octicon-x", "red")
}
func TestRepoCommitsWithStatusWarning(t *testing.T) {
doTestRepoCommitWithStatus(t, "warning", "warning", "sign", "yellow")
doTestRepoCommitWithStatus(t, "warning", "gitea-exclamation", "yellow")
}

View file

@ -171,9 +171,9 @@ func setAppHelpTemplates() {
}
func adjustHelpTemplate(originalTemplate string) string {
overrided := ""
overridden := ""
if _, ok := os.LookupEnv("GITEA_CUSTOM"); ok {
overrided = "(GITEA_CUSTOM)"
overridden = "(GITEA_CUSTOM)"
}
return fmt.Sprintf(`%s
@ -183,7 +183,7 @@ DEFAULT CONFIGURATION:
AppPath: %s
AppWorkPath: %s
`, originalTemplate, setting.CustomPath, overrided, setting.CustomConf, setting.AppPath, setting.AppWorkPath)
`, originalTemplate, setting.CustomPath, overridden, setting.CustomConf, setting.AppPath, setting.AppWorkPath)
}
func formatBuiltWith() string {

View file

@ -66,11 +66,10 @@ func TestMain(m *testing.M) {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
if err = git.InitOnceWithSync(context.Background()); err != nil {
fmt.Printf("Unable to InitOnceWithSync: %v\n", err)
if err = git.InitFull(context.Background()); err != nil {
fmt.Printf("Unable to InitFull: %v\n", err)
os.Exit(1)
}
git.CheckLFSVersion()
setting.InitDBConfig()
setting.NewLogServices(true)
@ -207,7 +206,6 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)

View file

@ -12,18 +12,17 @@ import (
"xorm.io/xorm/schemas"
)
func addContainerRepositoryProperty(x *xorm.Engine) error {
func addContainerRepositoryProperty(x *xorm.Engine) (err error) {
switch x.Dialect().URI().DBType {
case schemas.SQLITE:
_, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
if err != nil {
return err
}
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
case schemas.MSSQL:
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name + '/' + p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
default:
_, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
if err != nil {
return err
}
_, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?",
packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer)
}
return nil
return err
}

View file

@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/packages/maven"
"code.gitea.io/gitea/modules/packages/npm"
"code.gitea.io/gitea/modules/packages/nuget"
"code.gitea.io/gitea/modules/packages/pub"
"code.gitea.io/gitea/modules/packages/pypi"
"code.gitea.io/gitea/modules/packages/rubygems"
@ -143,6 +144,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
metadata = &npm.Metadata{}
case TypeMaven:
metadata = &maven.Metadata{}
case TypePub:
metadata = &pub.Metadata{}
case TypePyPI:
metadata = &pypi.Metadata{}
case TypeRubyGems:

View file

@ -39,6 +39,7 @@ const (
TypeMaven Type = "maven"
TypeNpm Type = "npm"
TypeNuGet Type = "nuget"
TypePub Type = "pub"
TypePyPI Type = "pypi"
TypeRubyGems Type = "rubygems"
)
@ -62,6 +63,8 @@ func (pt Type) Name() string {
return "npm"
case TypeNuGet:
return "NuGet"
case TypePub:
return "Pub"
case TypePyPI:
return "PyPI"
case TypeRubyGems:
@ -89,6 +92,8 @@ func (pt Type) SVGName() string {
return "gitea-npm"
case TypeNuGet:
return "gitea-nuget"
case TypePub:
return "gitea-pub"
case TypePyPI:
return "gitea-python"
case TypeRubyGems:

View file

@ -170,3 +170,15 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64)
users := make([]*user_model.User, 0, 8)
return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
}
// GetIssuePosters returns all users that have authored an issue/pull request for the given repository
func GetIssuePosters(ctx context.Context, repo *Repository, isPull bool) ([]*user_model.User, error) {
users := make([]*user_model.User, 0, 8)
cond := builder.In("`user`.id",
builder.Select("poster_id").From("issue").Where(
builder.Eq{"repo_id": repo.ID}.
And(builder.Eq{"is_pull": isPull}),
).GroupBy("poster_id"),
)
return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users)
}

View file

@ -120,11 +120,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
fatalTestError("util.CopyDir: %v\n", err)
}
if err = git.InitOnceWithSync(context.Background()); err != nil {
if err = git.InitFull(context.Background()); err != nil {
fatalTestError("git.Init: %v\n", err)
}
git.CheckLFSVersion()
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
fatalTestError("unable to read the new repo root: %v\n", err)
@ -206,8 +204,6 @@ func PrepareTestEnv(t testing.TB) {
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
assert.NoError(t, err)
for _, ownerDir := range ownerDirs {

View file

@ -399,6 +399,10 @@ func CreateWebhook(ctx context.Context, w *Webhook) error {
// CreateWebhooks creates multiple web hooks
func CreateWebhooks(ctx context.Context, ws []*Webhook) error {
// xorm returns err "no element on slice when insert" for empty slices.
if len(ws) == 0 {
return nil
}
for i := 0; i < len(ws); i++ {
ws[i].Type = strings.TrimSpace(ws[i].Type)
}

View file

@ -224,7 +224,7 @@ func (ctx *Context) HTML(status int, name base.TplName) {
ctx.Data["TemplateLoadTimes"] = func() string {
return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms"
}
if err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data); err != nil {
if err := ctx.Render.HTML(ctx.Resp, status, string(name), templates.BaseVars().Merge(ctx.Data)); err != nil {
if status == http.StatusInternalServerError && name == base.TplName("status/500") {
ctx.PlainText(http.StatusInternalServerError, "Unable to find status/500 template")
return

View file

@ -30,9 +30,6 @@ func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*rep
}
func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error {
if err := git.InitOnceWithSync(ctx); err != nil {
return err
}
numRepos := 0
numPRs := 0
numPRsUpdated := 0

View file

@ -190,10 +190,6 @@ func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) err
}
func checkCommitGraph(ctx context.Context, logger log.Logger, autofix bool) error {
if err := git.InitOnceWithSync(ctx); err != nil {
return err
}
numRepos := 0
numNeedUpdate := 0
numWritten := 0

View file

@ -95,14 +95,15 @@ func (c *Command) AddArguments(args ...string) *Command {
return c
}
// RunOpts represents parameters to run the command
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
type RunOpts struct {
Env []string
Timeout time.Duration
Dir string
Stdout, Stderr io.Writer
Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
Env []string
Timeout time.Duration
UseContextTimeout bool
Dir string
Stdout, Stderr io.Writer
Stdin io.Reader
PipelineFunc func(context.Context, context.CancelFunc) error
}
func commonBaseEnvs() []string {
@ -171,7 +172,15 @@ func (c *Command) Run(opts *RunOpts) error {
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir)
}
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
var ctx context.Context
var cancel context.CancelFunc
var finished context.CancelFunc
if opts.UseContextTimeout {
ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
} else {
ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
}
defer finished()
cmd := exec.CommandContext(ctx, c.name, c.args...)

View file

@ -15,7 +15,6 @@ import (
"regexp"
"runtime"
"strings"
"sync"
"time"
"code.gitea.io/gitea/modules/log"
@ -24,8 +23,8 @@ import (
"github.com/hashicorp/go-version"
)
// GitVersionRequired is the minimum Git version required
const GitVersionRequired = "2.0.0"
// RequiredVersion is the minimum Git version required
const RequiredVersion = "2.0.0"
var (
// GitExecutable is the command name of git
@ -43,7 +42,7 @@ var (
// loadGitVersion returns current Git version from shell. Internal usage only.
func loadGitVersion() (*version.Version, error) {
// doesn't need RWMutex because its exec by Init()
// doesn't need RWMutex because it's executed by Init()
if gitVersion != nil {
return gitVersion, nil
}
@ -90,7 +89,7 @@ func SetExecutablePath(path string) error {
return fmt.Errorf("unable to load git version: %w", err)
}
versionRequired, err := version.NewVersion(GitVersionRequired)
versionRequired, err := version.NewVersion(RequiredVersion)
if err != nil {
return err
}
@ -104,7 +103,7 @@ func SetExecutablePath(path string) error {
moreHint = "get git: https://git-scm.com/download/linux and https://ius.io"
}
}
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), GitVersionRequired, moreHint)
return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), RequiredVersion, moreHint)
}
return nil
@ -131,7 +130,7 @@ func checkInit() error {
return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
}
if DefaultContext != nil {
log.Warn("git module has been initialized already, duplicate init should be fixed")
log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it")
}
return nil
}
@ -140,7 +139,7 @@ func checkInit() error {
func HomeDir() string {
if setting.Git.HomePath == "" {
// strict check, make sure the git module is initialized correctly.
// attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users.
// attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers.
// for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules")
return ""
@ -149,14 +148,14 @@ func HomeDir() string {
}
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race
// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too
// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands.
func InitSimple(ctx context.Context) error {
if err := checkInit(); err != nil {
return err
}
DefaultContext = ctx
globalCommandArgs = nil
if setting.Git.Timeout.Default > 0 {
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
@ -165,46 +164,46 @@ func InitSimple(ctx context.Context) error {
return SetExecutablePath(setting.Git.Path)
}
var initOnce sync.Once
// InitOnceWithSync initializes git module with version check and change global variables, sync gitconfig.
// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too),
// otherwise there will be data-race problem at the moment.
func InitOnceWithSync(ctx context.Context) (err error) {
// InitFull initializes git module with version check and change global variables, sync gitconfig.
// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables.
func InitFull(ctx context.Context) (err error) {
if err = checkInit(); err != nil {
return err
}
initOnce.Do(func() {
if err = InitSimple(ctx); err != nil {
return
}
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
}
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
}
// Explicitly disable credential helper, otherwise Git credentials might leak
if CheckGitVersionAtLeast("2.9") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
}
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
})
if err != nil {
return err
if err = InitSimple(ctx); err != nil {
return
}
// when git works with gnupg (commit signing), there should be a stable home for gnupg commands
if _, ok := os.LookupEnv("GNUPGHOME"); !ok {
_ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg"))
}
// Since git wire protocol has been released from git v2.18
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2")
}
// By default partial clones are disabled, enable them from git v2.22
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
}
// Explicitly disable credential helper, otherwise Git credentials might leak
if CheckGitVersionAtLeast("2.9") == nil {
globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=")
}
SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil
if setting.LFS.StartServer {
if CheckGitVersionAtLeast("2.1.2") != nil {
return errors.New("LFS server support requires Git >= 2.1.2")
}
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
}
return syncGitConfig()
}

View file

@ -28,7 +28,7 @@ func testRun(m *testing.M) error {
defer util.RemoveAll(gitHomePath)
setting.Git.HomePath = gitHomePath
if err = InitOnceWithSync(context.Background()); err != nil {
if err = InitFull(context.Background()); err != nil {
return fmt.Errorf("failed to call Init: %w", err)
}

View file

@ -1,31 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package git
import (
"sync"
logger "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
)
var once sync.Once
// CheckLFSVersion will check lfs version, if not satisfied, then disable it.
func CheckLFSVersion() {
if setting.LFS.StartServer {
// Disable LFS client hooks if installed for the current OS user
// Needs at least git v2.1.2
if CheckGitVersionAtLeast("2.1.2") != nil {
setting.LFS.StartServer = false
logger.Error("LFS server support needs at least Git v2.1.2")
} else {
once.Do(func() {
globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=",
"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
})
}
}
}

View file

@ -0,0 +1,27 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package mcaptcha
import (
"context"
"fmt"
"code.gitea.io/gitea/modules/setting"
"codeberg.org/gusted/mcaptcha"
)
func Verify(ctx context.Context, token string) (bool, error) {
valid, err := mcaptcha.Verify(ctx, &mcaptcha.VerifyOpts{
InstanceURL: setting.Service.McaptchaURL,
Sitekey: setting.Service.McaptchaSitekey,
Secret: setting.Service.McaptchaSecret,
Token: token,
})
if err != nil {
return false, fmt.Errorf("wasn't able to verify mCaptcha: %v", err)
}
return valid, nil
}

View file

@ -0,0 +1,154 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pub
import (
"archive/tar"
"compress/gzip"
"errors"
"io"
"regexp"
"strings"
"code.gitea.io/gitea/modules/validation"
"github.com/hashicorp/go-version"
"gopkg.in/yaml.v2"
)
var (
ErrMissingPubspecFile = errors.New("Pubspec file is missing")
ErrPubspecFileTooLarge = errors.New("Pubspec file is too large")
ErrInvalidName = errors.New("Package name is invalid")
ErrInvalidVersion = errors.New("Package version is invalid")
)
var namePattern = regexp.MustCompile(`\A[a-zA-Z_][a-zA-Z0-9_]*\z`)
// https://github.com/dart-lang/pub-dev/blob/4d582302a8d10152a5cd6129f65bf4f4dbca239d/pkg/pub_package_reader/lib/pub_package_reader.dart#L143
const maxPubspecFileSize = 128 * 1024
// Package represents a Pub package
type Package struct {
Name string
Version string
Metadata *Metadata
}
// Metadata represents the metadata of a Pub package
type Metadata struct {
Description string `json:"description,omitempty"`
ProjectURL string `json:"project_url,omitempty"`
RepositoryURL string `json:"repository_url,omitempty"`
DocumentationURL string `json:"documentation_url,omitempty"`
Readme string `json:"readme,omitempty"`
Pubspec interface{} `json:"pubspec"`
}
type pubspecPackage struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Description string `yaml:"description"`
Homepage string `yaml:"homepage"`
Repository string `yaml:"repository"`
Documentation string `yaml:"documentation"`
}
// ParsePackage parses the Pub package file
func ParsePackage(r io.Reader) (*Package, error) {
gzr, err := gzip.NewReader(r)
if err != nil {
return nil, err
}
defer gzr.Close()
var p *Package
var readme string
tr := tar.NewReader(gzr)
for {
hd, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if hd.Typeflag != tar.TypeReg {
continue
}
if hd.Name == "pubspec.yaml" {
if hd.Size > maxPubspecFileSize {
return nil, ErrPubspecFileTooLarge
}
p, err = ParsePubspecMetadata(tr)
if err != nil {
return nil, err
}
} else if strings.ToLower(hd.Name) == "readme.md" {
data, err := io.ReadAll(tr)
if err != nil {
return nil, err
}
readme = string(data)
}
}
if p == nil {
return nil, ErrMissingPubspecFile
}
p.Metadata.Readme = readme
return p, nil
}
// ParsePubspecMetadata parses a Pubspec file to retrieve the metadata of a Pub package
func ParsePubspecMetadata(r io.Reader) (*Package, error) {
buf, err := io.ReadAll(io.LimitReader(r, maxPubspecFileSize))
if err != nil {
return nil, err
}
var p pubspecPackage
if err := yaml.Unmarshal(buf, &p); err != nil {
return nil, err
}
if !namePattern.MatchString(p.Name) {
return nil, ErrInvalidName
}
v, err := version.NewSemver(p.Version)
if err != nil {
return nil, ErrInvalidVersion
}
if !validation.IsValidURL(p.Homepage) {
p.Homepage = ""
}
if !validation.IsValidURL(p.Repository) {
p.Repository = ""
}
var pubspec interface{}
if err := yaml.Unmarshal(buf, &pubspec); err != nil {
return nil, err
}
return &Package{
Name: p.Name,
Version: v.String(),
Metadata: &Metadata{
Description: p.Description,
ProjectURL: p.Homepage,
RepositoryURL: p.Repository,
DocumentationURL: p.Documentation,
Pubspec: pubspec,
},
}, nil
}

View file

@ -0,0 +1,136 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pub
import (
"archive/tar"
"bytes"
"compress/gzip"
"io"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
const (
packageName = "gitea"
packageVersion = "1.0.1"
description = "Package Description"
projectURL = "https://gitea.io"
repositoryURL = "https://gitea.io/gitea/gitea"
documentationURL = "https://docs.gitea.io"
)
const pubspecContent = `name: ` + packageName + `
version: ` + packageVersion + `
description: ` + description + `
homepage: ` + projectURL + `
repository: ` + repositoryURL + `
documentation: ` + documentationURL + `
environment:
sdk: '>=2.16.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
path: '>=1.8.0 <3.0.0'
dev_dependencies:
http: '>=0.13.0'`
func TestParsePackage(t *testing.T) {
createArchive := func(files map[string][]byte) io.Reader {
var buf bytes.Buffer
zw := gzip.NewWriter(&buf)
tw := tar.NewWriter(zw)
for filename, content := range files {
hdr := &tar.Header{
Name: filename,
Mode: 0o600,
Size: int64(len(content)),
}
tw.WriteHeader(hdr)
tw.Write(content)
}
tw.Close()
zw.Close()
return &buf
}
t.Run("MissingPubspecFile", func(t *testing.T) {
data := createArchive(map[string][]byte{"dummy.txt": {}})
pp, err := ParsePackage(data)
assert.Nil(t, pp)
assert.ErrorIs(t, err, ErrMissingPubspecFile)
})
t.Run("PubspecFileTooLarge", func(t *testing.T) {
data := createArchive(map[string][]byte{"pubspec.yaml": make([]byte, 200*1024)})
pp, err := ParsePackage(data)
assert.Nil(t, pp)
assert.ErrorIs(t, err, ErrPubspecFileTooLarge)
})
t.Run("InvalidPubspecFile", func(t *testing.T) {
data := createArchive(map[string][]byte{"pubspec.yaml": {}})
pp, err := ParsePackage(data)
assert.Nil(t, pp)
assert.Error(t, err)
})
t.Run("Valid", func(t *testing.T) {
data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent)})
pp, err := ParsePackage(data)
assert.NoError(t, err)
assert.NotNil(t, pp)
assert.Empty(t, pp.Metadata.Readme)
})
t.Run("ValidWithReadme", func(t *testing.T) {
data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent), "README.md": []byte("readme")})
pp, err := ParsePackage(data)
assert.NoError(t, err)
assert.NotNil(t, pp)
assert.Equal(t, "readme", pp.Metadata.Readme)
})
}
func TestParsePubspecMetadata(t *testing.T) {
t.Run("InvalidName", func(t *testing.T) {
for _, name := range []string{"123abc", "ab-cd"} {
pp, err := ParsePubspecMetadata(strings.NewReader(`name: ` + name))
assert.Nil(t, pp)
assert.ErrorIs(t, err, ErrInvalidName)
}
})
t.Run("InvalidVersion", func(t *testing.T) {
pp, err := ParsePubspecMetadata(strings.NewReader(`name: dummy
version: invalid`))
assert.Nil(t, pp)
assert.ErrorIs(t, err, ErrInvalidVersion)
})
t.Run("Valid", func(t *testing.T) {
pp, err := ParsePubspecMetadata(strings.NewReader(pubspecContent))
assert.NoError(t, err)
assert.NotNil(t, pp)
assert.Equal(t, packageName, pp.Name)
assert.Equal(t, packageVersion, pp.Version)
assert.Equal(t, description, pp.Metadata.Description)
assert.Equal(t, projectURL, pp.Metadata.ProjectURL)
assert.Equal(t, repositoryURL, pp.Metadata.RepositoryURL)
assert.Equal(t, documentationURL, pp.Metadata.DocumentationURL)
assert.NotNil(t, pp.Metadata.Pubspec)
})
}

View file

@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
@ -153,6 +154,10 @@ func createDelegateHooks(repoPath string) (err error) {
}
func checkExecutable(filename string) bool {
// windows has no concept of a executable bit
if runtime.GOOS == "windows" {
return true
}
fileInfo, err := os.Stat(filename)
if err != nil {
return false

View file

@ -47,6 +47,9 @@ var Service = struct {
RecaptchaURL string
HcaptchaSecret string
HcaptchaSitekey string
McaptchaSecret string
McaptchaSitekey string
McaptchaURL string
DefaultKeepEmailPrivate bool
DefaultAllowCreateOrganization bool
DefaultUserIsRestricted bool
@ -133,6 +136,9 @@ func newService() {
Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/")
Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("")
Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("")
Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/")
Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("")
Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("")
Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false)

View file

@ -59,6 +59,7 @@ const (
ImageCaptcha = "image"
ReCaptcha = "recaptcha"
HCaptcha = "hcaptcha"
MCaptcha = "mcaptcha"
)
// settings
@ -262,8 +263,8 @@ var (
}{
ExplorePagingNum: 20,
SitemapPagingNum: 20,
IssuePagingNum: 10,
RepoSearchPagingNum: 10,
IssuePagingNum: 20,
RepoSearchPagingNum: 20,
MembersPagingNum: 20,
FeedMaxCommitNum: 5,
FeedPagingNum: 20,

View file

@ -18,10 +18,22 @@ import (
// 45677465s -> 1 year 6 months
func SecToTime(duration int64) string {
formattedTime := ""
years := duration / (3600 * 24 * 7 * 4 * 12)
months := (duration / (3600 * 24 * 30)) % 12
weeks := (duration / (3600 * 24 * 7)) % 4
days := (duration / (3600 * 24)) % 7
// The following four variables are calculated by taking
// into account the previously calculated variables, this avoids
// pitfalls when using remainders. As that could lead to incorrect
// results when the calculated number equals the quotient number.
remainingDays := duration / (60 * 60 * 24)
years := remainingDays / 365
remainingDays -= years * 365
months := remainingDays * 12 / 365
remainingDays -= months * 365 / 12
weeks := remainingDays / 7
remainingDays -= weeks * 7
days := remainingDays
// The following three variables are calculated without depending
// on the previous calculated variables.
hours := (duration / 3600) % 24
minutes := (duration / 60) % 60
seconds := duration % 60

View file

@ -11,10 +11,21 @@ import (
)
func TestSecToTime(t *testing.T) {
assert.Equal(t, SecToTime(66), "1 minute 6 seconds")
assert.Equal(t, SecToTime(52410), "14 hours 33 minutes")
assert.Equal(t, SecToTime(563418), "6 days 12 hours")
assert.Equal(t, SecToTime(1563418), "2 weeks 4 days")
assert.Equal(t, SecToTime(3937125), "1 month 2 weeks")
assert.Equal(t, SecToTime(45677465), "1 year 5 months")
second := int64(1)
minute := 60 * second
hour := 60 * minute
day := 24 * hour
year := 365 * day
assert.Equal(t, "1 minute 6 seconds", SecToTime(minute+6*second))
assert.Equal(t, "1 hour", SecToTime(hour))
assert.Equal(t, "1 hour", SecToTime(hour+second))
assert.Equal(t, "14 hours 33 minutes", SecToTime(14*hour+33*minute+30*second))
assert.Equal(t, "6 days 12 hours", SecToTime(6*day+12*hour+30*minute+18*second))
assert.Equal(t, "2 weeks 4 days", SecToTime((2*7+4)*day+2*hour+16*minute+58*second))
assert.Equal(t, "4 weeks", SecToTime(4*7*day))
assert.Equal(t, "4 weeks 1 day", SecToTime((4*7+1)*day))
assert.Equal(t, "1 month 2 weeks", SecToTime((6*7+3)*day+13*hour+38*minute+45*second))
assert.Equal(t, "11 months", SecToTime(year-25*day))
assert.Equal(t, "1 year 5 months", SecToTime(year+163*day+10*hour+11*minute+5*second))
}

View file

@ -0,0 +1,101 @@
Creative Commons Attribution 3.0 IGO
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. THE LICENSOR IS NOT NECESSARILY AN INTERGOVERNMENTAL ORGANIZATION (IGO), AS DEFINED IN THE LICENSE BELOW.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("LICENSE"). THE LICENSOR (DEFINED BELOW) HOLDS COPYRIGHT AND OTHER RIGHTS IN THE WORK. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION FOR YOUR ACCEPTANCE AND AGREEMENT TO THE TERMS OF THE LICENSE.
1. Definitions
a. "IGO" means, solely and exclusively for purposes of this License, an organization established by a treaty or other instrument governed by international law and possessing its own international legal personality. Other organizations established to carry out activities across national borders and that accordingly enjoy immunity from legal process are also IGOs for the sole and exclusive purposes of this License. IGOs may include as members, in addition to states, other entities.
b. "Work" means the literary and/or artistic work eligible for copyright protection, whatever may be the mode or form of its expression including digital form, and offered under the terms of this License. It is understood that a database, which by reason of the selection and arrangement of its contents constitutes an intellectual creation, is considered a Work.
c. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License and may be, but is not necessarily, an IGO.
d. "You" means an individual or entity exercising rights under this License.
e. "Reproduce" means to make a copy of the Work in any manner or form, and by any means.
f. "Distribute" means the activity of making publicly available the Work or Adaptation (or copies of the Work or Adaptation), as applicable, by sale, rental, public lending or any other known form of transfer of ownership or possession of the Work or copy of the Work.
g. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
h. "Adaptation" means a work derived from or based upon the Work, or upon the Work and other pre-existing works. Adaptations may include works such as translations, derivative works, or any alterations and arrangements of any kind involving the Work. For purposes of this License, where the Work is a musical work, performance, or phonogram, the synchronization of the Work in timed-relation with a moving image is an Adaptation. For the avoidance of doubt, including the Work in a Collection is not an Adaptation.
i. "Collection" means a collection of literary or artistic works or other works or subject matter other than works listed in Section 1(b) which by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. For the avoidance of doubt, a Collection will not be considered as an Adaptation.
2. Scope of this License. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright protection.
3. License Grant. Subject to the terms and conditions of this License, the Licensor hereby grants You a worldwide, royalty-free, non-exclusive license to exercise the rights in the Work as follows:
a. to Reproduce, Distribute and Publicly Perform the Work, to incorporate the Work into one or more Collections, and to Reproduce, Distribute and Publicly Perform the Work as incorporated in the Collections; and,
b. to create, Reproduce, Distribute and Publicly Perform Adaptations, provided that You clearly label, demarcate or otherwise identify that changes were made to the original Work.
c. For the avoidance of doubt:
i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,
iii. Voluntary License Schemes. To the extent possible, the Licensor waives the right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary licensing scheme.
This License lasts for the duration of the term of the copyright in the Work licensed by the Licensor. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by the Licensor are hereby reserved.
4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work (see section 8(a)). You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from a Licensor You must, to the extent practicable, remove from the Collection any credit (inclusive of any logo, trademark, official mark or official emblem) as required by Section 4(b), as requested. If You create an Adaptation, upon notice from a Licensor You must, to the extent practicable, remove from the Adaptation any credit (inclusive of any logo, trademark, official mark or official emblem) as required by Section 4(b), as requested.
b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) any attributions that the Licensor indicates be associated with the Work as indicated in a copyright notice, (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that the Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation. The credit required by this Section 4(b) may be implemented in any reasonable manner; provided, however, that in the case of an Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributors to the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Licensor or others designated for attribution, of You or Your use of the Work, without the separate, express prior written permission of the Licensor or such others.
c. Except as otherwise agreed in writing by the Licensor, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the honor or reputation of the Licensor where moral rights apply.
5. Representations, Warranties and Disclaimer
THE LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE.
6. Limitation on Liability
IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
a. Subject to the terms and conditions set forth in this License, the license granted here lasts for the duration of the term of the copyright in the Work licensed by the Licensor as stated in Section 3. Notwithstanding the above, the Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated below.
b. If You fail to comply with this License, then this License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. Notwithstanding the foregoing, this License reinstates automatically as of the date the violation is cured, provided it is cured within 30 days of You discovering the violation, or upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 7(b) does not affect any rights the Licensor may have to seek remedies for violations of this License by You.
8. Miscellaneous
a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
b. Each time You Distribute or Publicly Perform an Adaptation, the Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
c. If any provision of this License is invalid or unenforceable, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the Licensor.
e. This License constitutes the entire agreement between You and the Licensor with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. The Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). Interpretation of the scope of the rights granted by the Licensor and the conditions imposed on You under this License, this License, and the rights and conditions set forth herein shall be made with reference to copyright as determined in accordance with general principles of international law, including the above mentioned conventions.
g. Nothing in this License constitutes or may be interpreted as a limitation upon or waiver of any privileges and immunities that may apply to the Licensor or You, including immunity from the legal processes of any jurisdiction, national court or other authority.
h. Where the Licensor is an IGO, any and all disputes arising under this License that cannot be settled amicably shall be resolved in accordance with the following procedure:
i. Pursuant to a notice of mediation communicated by reasonable means by either You or the Licensor to the other, the dispute shall be submitted to non-binding mediation conducted in accordance with rules designated by the Licensor in the copyright notice published with the Work, or if none then in accordance with those communicated in the notice of mediation. The language used in the mediation proceedings shall be English unless otherwise agreed.
ii. If any such dispute has not been settled within 45 days following the date on which the notice of mediation is provided, either You or the Licensor may, pursuant to a notice of arbitration communicated by reasonable means to the other, elect to have the dispute referred to and finally determined by arbitration. The arbitration shall be conducted in accordance with the rules designated by the Licensor in the copyright notice published with the Work, or if none then in accordance with the UNCITRAL Arbitration Rules as then in force. The arbitral tribunal shall consist of a sole arbitrator and the language of the proceedings shall be English unless otherwise agreed. The place of arbitration shall be where the Licensor has its headquarters. The arbitral proceedings shall be conducted remotely (e.g., via telephone conference or written submissions) whenever practicable.
iii. Interpretation of this License in any dispute submitted to mediation or arbitration shall be as set forth in Section 8(f), above.
Creative Commons Notice
Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of the Licensor.
Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.
Creative Commons may be contacted at https://creativecommons.org/.

View file

@ -0,0 +1,8 @@
LICENSE
-------
LZMA SDK is written and placed in the public domain by Igor Pavlov.
Some code in LZMA is based on public domain code from another developers:
1) PPMd var.H (2001): Dmitry Shkarin
2) SHA-256: Wei Dai (Crypto++ library)

View file

@ -0,0 +1,15 @@
LICENSE
-------
LZMA SDK is written and placed in the public domain by Igor Pavlov.
Some code in LZMA SDK is based on public domain code from another developers:
1) PPMd var.H (2001): Dmitry Shkarin
2) SHA-256: Wei Dai (Crypto++ library)
Anyone is free to copy, modify, publish, use, compile, sell, or distribute the
original LZMA SDK code, either in source code form or as a compiled binary, for
any purpose, commercial or non-commercial, and by any means.
LZMA SDK code is compatible with open source licenses, for example, you can
include it to GNU GPL or GNU LGPL code.

61
options/license/NICTA-1.0 Normal file
View file

@ -0,0 +1,61 @@
NICTA Public Software Licence
Version 1.0
Copyright © 2004 National ICT Australia Ltd
All rights reserved.
By this licence, National ICT Australia Ltd (NICTA) grants permission,
free of charge, to any person who obtains a copy of this software
and any associated documentation files ("the Software") to use and
deal with the Software in source code and binary forms without
restriction, with or without modification, and to permit persons
to whom the Software is furnished to do so, provided that the
following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimers.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimers in
the documentation and/or other materials provided with the
distribution.
- The name of NICTA may not be used to endorse or promote products
derived from this Software without specific prior written permission.
EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND
NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY
REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS
OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT
OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR
NOT DISCOVERABLE.
TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL
NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT
LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR
CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS,
OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS;
OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE,
THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
If applicable legislation implies warranties or conditions, or
imposes obligations or liability on NICTA in respect of the Software
that cannot be wholly or partly excluded, restricted or modified,
NICTA's liability is limited, to the full extent permitted by the
applicable legislation, at its option, to:
a. in the case of goods, any one or more of the following:
i. the replacement of the goods or the supply of equivalent goods;
ii. the repair of the goods;
iii. the payment of the cost of replacing the goods or of acquiring
equivalent goods;
iv. the payment of the cost of having the goods repaired; or
b. in the case of services:
i. the supplying of the services again; or
ii. the payment of the cost of having the services supplied
again.

View file

@ -1063,6 +1063,7 @@ normal_view = Normal View
line = line
lines = lines
editor.add_file = Add File
editor.new_file = New File
editor.upload_file = Upload File
editor.edit_file = Edit File
@ -1268,6 +1269,8 @@ issues.filter_milestone = Milestone
issues.filter_milestone_no_select = All milestones
issues.filter_assignee = Assignee
issues.filter_assginee_no_select = All assignees
issues.filter_poster = Author
issues.filter_poster_no_select = All authors
issues.filter_type = Type
issues.filter_type.all_issues = All issues
issues.filter_type.assigned_to_you = Assigned to you
@ -3111,6 +3114,10 @@ npm.dependencies.development = Development Dependencies
npm.dependencies.peer = Peer Dependencies
npm.dependencies.optional = Optional Dependencies
npm.details.tag = Tag
pub.install = To install the package using Dart, run the following command:
pub.documentation = For more information on the Pub registry, see <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">the documentation</a>.
pub.details.repository_site = Repository Site
pub.details.documentation_site = Documentation Site
pypi.requires = Requires Python
pypi.install = To install the package using pip, run the following command:
pypi.documentation = For more information on the PyPI registry, see <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">the documentation</a>.

View file

@ -179,6 +179,8 @@ log_root_path_helper=Archivos de registro se escribirán en este directorio.
optional_title=Configuración opcional
email_title=Configuración de Correo
smtp_addr=Servidor SMTP
smtp_port=Puerto SMTP
smtp_from=Enviar correos electrónicos como
smtp_from_helper=Dirección de correo electrónico que utilizará Gitea. Introduzca una dirección de correo electrónico normal o utilice el formato "Nombre" <email@example.com>.
mailer_user=Nombre de usuario SMTP
@ -1061,6 +1063,7 @@ normal_view=Vista normal
line=línea
lines=líneas
editor.add_file=Añadir archivo
editor.new_file=Nuevo Archivo
editor.upload_file=Subir archivo
editor.edit_file=Editar Archivo
@ -2794,13 +2797,19 @@ config.queue_length=Tamaño de Cola de Envío
config.deliver_timeout=Timeout de Entrega
config.skip_tls_verify=Saltar verificación TLS
config.mailer_config=Configuración del servidor de correo
config.mailer_enabled=Activado
config.mailer_enable_helo=Habilitar HELO
config.mailer_name=Nombre
config.mailer_protocol=Protocolo
config.mailer_smtp_addr=Dirección SMTP
config.mailer_smtp_port=Puerto SMTP
config.mailer_user=Usuario
config.mailer_use_sendmail=Usar Sendmail
config.mailer_sendmail_path=Ruta de Sendmail
config.mailer_sendmail_args=Argumentos adicionales por Sendmail
config.mailer_sendmail_timeout=Tiempo de espera de Sendmail
config.mailer_use_dummy=Dummy
config.test_email_placeholder=Correo electrónico (ej. test@ejemplo.com)
config.send_test_mail=Enviar prueba de correo
config.test_mail_failed=Fallo al enviar correo electrónico de prueba a '%s': %v
@ -3103,6 +3112,10 @@ npm.dependencies.development=Dependencias de desarrollo
npm.dependencies.peer=Dependencias de pares
npm.dependencies.optional=Dependencias opcionales
npm.details.tag=Etiqueta
pub.install=Para instalar el paquete usando Dart, ejecute el siguiente comando:
pub.documentation=Para obtener más información sobre el registro de Pub, consulte <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">la documentación</a>.
pub.details.repository_site=Sitio del repositorio
pub.details.documentation_site=Sitio de documentación
pypi.requires=Requiere Python
pypi.install=Para instalar el paquete usando pip, ejecute el siguiente comando:
pypi.documentation=Para obtener más información sobre el registro PyPI, consulte <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">la documentación</a>.

View file

@ -2,6 +2,7 @@ home=Etusivu
dashboard=Kojelauta
explore=Tutki
help=Apua
logo=Logo
sign_in=Kirjaudu sisään
sign_in_with=Kirjaudu sisään tunnuksilla
sign_out=Kirjaudu ulos
@ -21,16 +22,28 @@ signed_in_as=Kirjautuneena käyttäjänä
enable_javascript=Tämä sivusto toimii paremmin JavaScriptillä.
toc=Sisällysluettelo
licenses=Lisenssit
return_to_gitea=Palaa Giteaan
username=Käyttäjätunnus
email=Sähköpostiosoite
password=Salasana
access_token=Pääsymerkki
re_type=Kirjoita salasana uudelleen
captcha=CAPTCHA
twofa=Kaksivaiheinen todennus
twofa_scratch=Kaksivaiheinen kertakäyttöinen koodi
passcode=Tunnuskoodi
webauthn_insert_key=Aseta turva-avaimesi
webauthn_press_button=Paina turva-avaimesi painiketta…
webauthn_error=Turva-avainta ei voitu lukea.
webauthn_unsupported_browser=Selaimesi ei tällä hetkellä tue WebAuthnia.
webauthn_error_insecure=WebAuthn tukee vain suojattuja yhteyksiä. Testaukseen HTTP:n yli, voit käyttää osoitetta "localhost" tai "127.0.0.1"
webauthn_error_unable_to_process=Palvelin ei pystynyt toteuttamaan kutsua.
webauthn_error_duplicated=Turva-avainta ei ole sallittu tässä pyynnössä. Varmista, ettei avainta ole jo rekisteröity.
webauthn_error_empty=Sinun täytyy asettaa nimi tälle avaimelle.
webauthn_error_timeout=Aikakatkaisu saavutettu ennenkuin avaintasi on voitu lukea. Lataa tämä sivu uudelleen ja yritä uudelleen.
webauthn_reload=Päivitä
repository=Repo
organization=Organisaatio
@ -40,6 +53,7 @@ new_migrate=Uusi migraatio
new_mirror=Uusi peilaus
new_fork=Uusi repositorio
new_org=Uusi organisaatio
new_project=Uusi projekti
manage_org=Ylläpidä organisaatioita
admin_panel=Sivuston ylläpito
account_settings=Tilin asetukset
@ -59,28 +73,47 @@ pull_requests=Pull requestit
issues=Ongelmat
milestones=Merkkipaalut
ok=OK
cancel=Peruuta
save=Tallenna
add=Lisää
add_all=Lisää kaikki
remove=Poista
remove_all=Poista kaikki
edit=Muokkaa
copy=Kopioi
copy_url=Kopioi osoite
copy_branch=Kopioi haaran nimi
copy_success=Kopioitu!
copy_error=Kopiointi epäonnistui
write=Kirjoita
preview=Esikatselu
loading=Ladataan…
step1=Vaihe 1:
step2=Vaihe 2:
error=Virhe
error404=Sivu, jota yrität nähdä, joko <strong>ei löydy</strong> tai <strong>et ole oikeutettu</strong> katsomaan sitä.
never=Ei koskaan
rss_feed=RSS-syöte
[error]
occurred=Virhe tapahtui
report_message=Jos olet varma, että tämä on ongelma Giteassa, etsi ongelmaa <a href="https://github.com/go-gitea/gitea/issues" target="_blank">GitHubista</a> tai avaa uusi ongelma tarvittaessa.
missing_csrf=Virheellinen pyyntö: CSRF-tunnusta ei ole olemassa
invalid_csrf=Virheellinen pyyntö: Virheellinen CSRF-tunniste
not_found=Kohdetta ei löytynyt.
network_error=Verkkovirhe
[startpage]
app_desc=Kivuton, itsehostattu Git-palvelu
install=Helppo asentaa
install_desc=Yksinkertaisesti <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-binary/">aja binääri</a> alustallasi, toimita se <a target="_blank" rel="noopener noreferrer" href="https://github.com/go-gitea/gitea/tree/master/docker">Dockerilla</a>, tai saa se <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/install-from-package/">pakettina</a>.
platform=Alustariippumaton
platform_desc=Gitea käy missä tahansa alustassa, johon <a target="_blank" rel="noopener noreferrer" href="http://golang.org/">Go</a> kykenee kääntämään. Windows, macOS, Linux, ARM, jne. Valitse omasi!
lightweight=Kevyt
@ -92,6 +125,7 @@ license_desc=Mene osoitteeseen <a target="_blank" rel="noopener noreferrer" href
install=Asennus
title=Alkuperäiset asetukset
docker_helper=Jos ajat Giteaa Dockerin sisällä, lue <a target="_blank" rel="noopener noreferrer" href="%s">ohjeet</a> ennen minkään asetuksen muuttamista.
require_db_desc=Gitea tarvitsee toimiakseen MySQL, PostgreSQL, MSSQL, SQLite3 tai TiDB (MySQL protokolla) tietokannan.
db_title=Tietokanta asetukset
db_type=Tietokanta tyyppi
host=Isäntä
@ -99,10 +133,16 @@ user=Käyttäjätunnus
password=Salasana
db_name=Tietokannan nimi
db_helper=Huomautus MySQL-käyttäjille: käytä InnoDB-tallennusmoottoria, ja jos käytät "utf8mb4" merkistöä, InnoDB-version on oltava yli 5.6.
db_schema=Skeema
ssl_mode=SSL
charset=Merkistö
path=Polku
sqlite_helper=SQLite3-tietokannan tiedostopolku.<br>Syötä absoluuttinen polku, jos ajat Giteaa palveluna.
reinstall_error=Yrität asentaa olemassa olevaan Gitea tietokantaan
reinstall_confirm_message=Asentaminen uudelleen olemassa olevalla Gitea-tietokannalla voi aiheuttaa useita ongelmia. Useimmissa tapauksissa sinun pitäisi käyttää olemassa olevia "app.ini" asetuksia Gitean käyttöön. Jos tiedät mitä teet, vahvista seuraavat seikat:
reinstall_confirm_check_1=Tiedot, jotka on salattu SECRET_KEY:llä app.ini:ssä saatetaan menettää: käyttäjät eivät ehkä voi kirjautua sisään 2FA/OTP:lla ja peilit eivät välttämättä toimi oikein. Ruksaamalla tämän vahvistat, että nykyinen app.ini -tiedosto sisältää oikean SECRET_KEY:n.
reinstall_confirm_check_2=Repot ja asetukset saattaa olla tarpeen uudelleensynkronoida. Valitsemalla tämän vahvistat, että uudelleensynkronoit repojen koukut ja authorized_keys -tiedoston manuaalisesti. Varmistat, että repon ja peilin asetukset ovat oikeat.
reinstall_confirm_check_3=Vahvistat, että olet täysin varma siitä, että tämä Gitea toimii oikealla app.ini sijainnilla ja että olet varma, että sinun täytyy asentaa uudelleen. Vahvistat, että tunnustat edellä mainitut riskit.
err_empty_db_path=SQLite3-tietokannan polku ei voi olla tyhjä.
no_admin_and_disable_registration=Et voi kytkeä rekisteröintiä pois luomatta sitä ennen ylläpitotiliä.
err_empty_admin_password=Ylläpitäjän salasana ei voi olla tyhjä.
@ -119,6 +159,7 @@ lfs_path=Git LFS -juuripolku
lfs_path_helper=Git LFS:n ylläpitämät tiedostot tullaan tallentamaan tähän hakemistoon. Jätä tyhjäksi kytkeäksesi toiminnon pois.
run_user=Aja käyttäjänä
run_user_helper=Anna käyttäjätunnus, jona Giteaa ajetaan. Käyttäjällä on oltava oikeudet repositorioiden juuripolkuun.
domain=Palvelimen verkkotunnus
ssh_port=SSH-palvelimen portti
ssh_port_helper=Porttinumero, jossa SSH-palvelimesi kuuntelee. Jätä tyhjäksi kytkeäksesi pois.
http_port=Gitean HTTP-kuunteluportti
@ -150,6 +191,7 @@ openid_signin=Ota OpenID kirjautuminen käyttöön
openid_signin_popup=Ota käyttöön kirjautuminen OpenID:n kautta.
openid_signup=Ota käyttöön OpenID itse-rekisteröinti
openid_signup_popup=Ota käyttöön OpenID-pohjainen käyttäjän itse-rekisteröinti.
enable_captcha=Ota käyttöön CAPTCHA rekisteröityessä
enable_captcha_popup=Pakollinen captcha käyttäjän itse rekisteröityessä.
require_sign_in_view=Vaadi sisäänkirjautuminen sivujen näkemiseksi
require_sign_in_view_popup=Rajoita pääsy vain kirjautuneille käyttäjille. Vierailijat näkevät vain 'kirjaudu sisään' ja rekisteröidy -sivut.
@ -164,22 +206,41 @@ test_git_failed=Epäonnistui testata 'git' komentoa: %v
sqlite3_not_available=Tämä Gitea versio ei tue SQLite3. Lataa virallinen binääriversio kohteesta %s (ei 'gobuild' versio).
invalid_db_setting=Tietokanta-asetukset ovat väärin: %v
invalid_repo_path=Repojen juuri polku on virheellinen: %v
invalid_app_data_path=Sovelluksen datapolku on virheellinen: %v
internal_token_failed=Sisäisen pääsymerkin luonti epäonnistui: %v
save_config_failed=Asetusten tallentaminen epäonnistui: %v
install_success=Tervetuloa! Kiitos kun valitsit Gitean. Pidä hauskaa!
default_keep_email_private=Piilota sähköpostiosoitteet oletuksena
default_enable_timetracking=Ota ajan seuranta oletusarvoisesti käyttöön
default_enable_timetracking_popup=Ota käyttöön uusien repojen aikaseuranta oletusarvoisesti.
no_reply_address=Piilotettu sähköpostin verkkotunnus
no_reply_address_helper=Verkkotunnuksen nimi käyttäjille, joilla on piilotettu sähköpostiosoite. Esimerkiksi käyttäjätunnus 'joe' kirjataan Git nimellä 'joe@noreply.example.org' jos piilotettu sähköpostiosoite on asetettu 'noreply.example.org'.
password_algorithm=Salasanan hajautusalgoritmi
password_algorithm_helper=Aseta salasanan hajautusalgoritmi. Algoritmeillä on eri vaatimukset ja vahvuudet. `argon2`, vaikka sillä on hyvät ominaisuudet, käyttää paljon muistia ja voi olla sopimaton pienille järjestelmille.
[home]
uname_holder=Käyttäjätunnus tai sähköpostiosoite
password_holder=Salasana
switch_dashboard_context=Vaihda kojelaudan kontekstia
my_repos=Repot
show_more_repos=Näytä lisää repoja…
collaborative_repos=Yhteistyö repot
my_orgs=Organisaationi
my_mirrors=Peilini
view_home=Näytä %s
search_repos=Etsi repo…
filter=Muut suodattimet
filter_by_team_repositories=Suodata tiimin repojen mukaan
feed_of=Syöte "%s"
show_archived=Arkistoidut
show_both_archived_unarchived=Näytetään arkistoidut ja arkistoimattomat
show_only_archived=Näytetään vain arkistoidut
show_only_unarchived=Näytetään vain arkistoimattomat
show_private=Yksityinen
show_only_private=Näytetään vain yksityiset
show_only_public=Näytetään vain julkiset
issues.in_your_repos=Repoissasi
@ -189,6 +250,7 @@ users=Käyttäjät
organizations=Organisaatiot
search=Hae
code=Koodi
search.match=Osuma
repo_no_results=Vastaavia repoja ei löydy.
user_no_results=Vastaavia käyttäjiä ei löytynyt.
org_no_results=Ei löytynyt vastaavia organisaatioita.
@ -202,6 +264,7 @@ register_helper_msg=On jo tili? Kirjaudu sisään nyt!
social_register_helper_msg=Onko sinulla jo tili? Linkitä se nyt!
disable_register_prompt=Rekisteröinti on estetty. Ota yhteys ylläpitäjääsi.
disable_register_mail=Sähköpostivahvistus rekisteröinnille on estetty.
remember_me=Muista tämä laite
forgot_password_title=Unohtuiko salasana
forgot_password=Unohtuiko salasana?
sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt.
@ -209,6 +272,7 @@ sign_up_successful=Tilin luonti onnistui.
confirmation_mail_sent_prompt=Uusi varmistussähköposti on lähetetty osoitteeseen <b>%s</b>, ole hyvä ja tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi.
must_change_password=Vaihda salasanasi
allow_password_change=Vaadi käyttäjää vaihtamaan salasanansa (suositeltava)
reset_password_mail_sent_prompt=Varmistussähköposti on lähetetty osoitteeseen <b>%s</b>. Tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi tilin palauttamisen valmiiksi.
active_your_account=Aktivoi tilisi
account_activated=Tili on aktivoitu
prohibit_login=Kirjautuminen estetty
@ -217,9 +281,11 @@ resent_limit_prompt=Olet jo tilannut aktivointisähköpostin hetki sitten. Ole h
has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (<b>%s</b>). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta.
resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi
email_not_associate=Tätä sähköpostiosoitetta ei ole liitetty mihinkään tiliin.
send_reset_mail=Lähetä tilin palautussähköposti
reset_password=Tilin palautus
invalid_code=Vahvistusavain on virheellinen tai vanhentunut.
reset_password_helper=Palauta käyttäjätili
reset_password_wrong_user=Olet kirjautunut sisään nimellä %s, mutta tilin palautuslinkki on tarkoitettu kohteelle %s
password_too_short=Salasanan pituus ei voi olla vähemmän kuin %d merkkiä.
non_local_account=Ei-lokaalit käyttäjät eivät voi päivittää salasanojaan Gitean web-käyttöliittymän kautta.
verify=Vahvista
@ -231,10 +297,12 @@ twofa_scratch_token_incorrect=Kertakäyttökoodisi on virheellinen.
login_userpass=Kirjaudu sisään
login_openid=OpenID
oauth_signup_tab=Rekisteröi uusi tili
oauth_signup_title=Viimeistele tili
oauth_signup_submit=Viimeistele tili
oauth_signin_tab=Linkitä olemassa olevaan tiliin
oauth_signin_title=Kirjaudu sisään valtuuttaaksesi linkitetyn tilin
oauth_signin_submit=Yhdistä tiliin
oauth.signin.error.access_denied=Valtuutuspyyntö on evätty.
openid_connect_submit=Connect
openid_connect_title=Yhdistä olemassaolevaan tiliin
openid_connect_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin täällä.
@ -250,22 +318,38 @@ authorize_title=Valtuutatko "%s" pääsemään tilillesi?
authorization_failed=Käyttöoikeuden varmistus epäonnistui
authorization_failed_desc=Käyttöoikeuden varmistus epäonnistui virheellisen pyynnön takia. Ota yhteyttä sovelluksen ylläpitäjään, jonka olet yrittänyt valtuuttaa.
sspi_auth_failed=SSPI todennus epäonnistui
password_pwned=Valitsemasi salasana on <a target="_blank" rel="noopener noreferrer" href="https://haveibeenpwned.com/Passwords">varastettujen salasanojen luettelossa</a>, joka on aiemmin paljastunut julkisissa tietorikkomuksissa. Yritä uudelleen toisella salasanalla.
[mail]
view_it_on=Näytä %s
link_not_working_do_paste=Eikö toimi? Yritä kopioida ja liittää se selaimeesi.
hi_user_x=Hei <b>%s</b>,
activate_account=Ole hyvä ja aktivoi tilisi
activate_email=Vahvista sähköpostiosoitteesi
activate_email.title=%s, vahvista sähköpostiosoitteesi
register_notify=Tervetuloa Giteaan
register_notify.text_2=Voit nyt kirjautua käyttäjätunnuksella: %s.
reset_password=Palauta käyttäjätili
reset_password.title=%s, olet pyytänyt tilisi palauttamista
register_success=Rekisteröinti onnistui
issue.x_mentioned_you=<b>@%s</b> mainitsi sinut:
issue.action.push_1=<b>@%[1]s</b> työnsi %[3]d commitin kohteeseen %[2]s
issue.action.push_n=<b>@%[1]s</b> työnsi %[3]d committia kohteeseen %[2]s
release.title=Otsikko: %s
release.note=Huomautus:
release.downloads=Lataukset:
release.download.zip=Lähdekoodi (ZIP)
release.download.targz=Lähdekoodi (TAR.GZ)
repo.transfer.to_you=sinä
[modal]
@ -286,6 +370,7 @@ AuthName=Luvan nimi
AdminEmail=Ylläpito sähköposti
NewBranchName=Uuden haaran nimi
CommitSummary=Commitin yhteenveto
CommitMessage=Commitin viesti
CommitChoice=Commitin valinta
TreeName=Tiedostopolku
@ -301,17 +386,24 @@ max_size_error=` täytyy sisältää enintään %s merkkiä.`
email_error=` ei ole kelvollinen sähköpostiosoite.`
include_error=` täytyy sisältää tekstiosa '%s'.`
unknown_error=Tuntematon virhe:
captcha_incorrect=CAPTCHA koodi on virheellinen.
password_not_match=Salasanat eivät täsmää.
lang_select_error=Valitse kieli listalta.
username_been_taken=Käyttäjätunnus on jo varattu.
repo_name_been_taken=Repon nimi on jo käytössä.
repository_force_private=Pakotettu yksityisyys käytössä: yksityisiä repoja ei voida muuttaa julkisiksi.
org_name_been_taken=Organisaation nimi on jo käytössä.
team_name_been_taken=Tiimin nimi on jo varattu.
email_been_used=Sähköpostiosoite on jo käytössä.
email_invalid=Sähköpostiosoite on virheellinen.
openid_been_used=OpenID-osoite '%s' on jo käytössä.
username_password_incorrect=Käyttäjätunnus tai salasana on virheellinen.
password_lowercase_one=Ainakin yksi pieni kirjan
password_uppercase_one=Ainakin yksi iso kirjain
password_digit_one=Ainakin yksi numero
password_special_one=Ainakin yksi erikoismerkki (välimerkki, sulut, lainausmerkit, jne.)
enterred_invalid_org_name=Antamasi organisaation nimi on virheellinen.
enterred_invalid_password=Syöttämäsi salasana oli väärä.
user_not_exist=Käyttäjää ei ole olemassa.
team_not_exist=Tiimiä ei ole olemassa.
@ -332,16 +424,20 @@ repositories=Repot
activity=Julkinen toiminta
followers=Seuraajat
starred=Tähdelliset repot
projects=Projektit
following=Seurataan
follow=Seuraa
unfollow=Lopeta seuraaminen
heatmap.loading=Ladataan lämpökarttaa…
user_bio=Elämäkerta
form.name_reserved=Käyttäjätunnus '%s' on varattu.
form.name_chars_not_allowed=Käyttäjänimi '%s' sisältää virheellisiä merkkejä.
[settings]
profile=Profiili
account=Tili
appearance=Ulkoasu
password=Salasana
security=Turvallisuus
avatar=Profiilikuva
@ -355,8 +451,10 @@ twofa=Kaksivaiheinen todennus
account_link=Linkitetyt tilit
organization=Organisaatiot
uid=Käyttäjä ID
webauthn=Turva-avaimet
public_profile=Julkinen profiili
biography_placeholder=Kerro itsestäsi
profile_desc=Sähköpostiosoitettasi käytetään ilmoituksiin ja muihin toimintoihin.
password_username_disabled=Ei-paikalliset käyttäjät eivät voi muuttaa käyttäjätunnustaan. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään saadaksesi lisätietoa.
full_name=Kokonimi
@ -364,6 +462,9 @@ website=Nettisivut
location=Sijainti
update_theme=Päivitä teema
update_profile=Päivitä profiili
update_language=Päivitä kieli
update_language_not_found=Kieli '%s' ei ole käytettävissä.
update_language_success=Kieli on päivitetty.
update_profile_success=Profiilisi on päivitetty.
change_username=Käyttäjätunnuksesi on muutettu.
change_username_prompt=Huomio: käyttäjätunnuksen muutos muuttaa myös tilisi URL:n.
@ -371,6 +472,23 @@ continue=Jatka
cancel=Peruuta
language=Kieli
ui=Teema
hidden_comment_types=Piilotetut kommenttityypit
comment_type_group_reference=Viittaus
comment_type_group_label=Tunniste
comment_type_group_milestone=Merkkipaalu
comment_type_group_assignee=Osoitettu henkilölle
comment_type_group_title=Otsikko
comment_type_group_branch=Haara
comment_type_group_time_tracking=Ajan seuranta
comment_type_group_deadline=Määräaika
comment_type_group_dependency=Riippuvuus
comment_type_group_lock=Lukituksen tila
comment_type_group_review_request=Arviointipyyntö
comment_type_group_pull_request_push=Lisätyt commitit
comment_type_group_project=Projekti
saved_successfully=Asetuksesi tallennettiin onnistuneesti.
privacy=Yksityisyys
keep_activity_private=Piilota toiminta profiilisivulta
lookup_avatar_by_mail=Hae profiilikuva sähköpostin perusteella
federated_avatar_lookup=Ulkopuolinen profiilikuvan haku
@ -397,17 +515,23 @@ primary=Ensisijainen
activated=Aktivoitu
requires_activation=Vaatii aktivoinnin
primary_email=Tee ensisijainen
activate_email=Lähetä aktivointi
activations_pending=Odottaa aktivointia
delete_email=Poista
email_deletion=Poista sähköpostiosoite
email_deletion_desc=Sähköpostiosoite ja siihen liittyvät tiedot poistetaan tililtäsi. Kyseisen sähköpostiosoitteen sisältävät commitit pysyvät muuttumattomia. Jatketaanko?
email_deletion_success=Sähköpostiosoite on poistettu.
theme_update_success=Teemasi on päivitetty.
theme_update_error=Valittua teemaa ei löydy.
openid_deletion=Poista OpenID-osoite
openid_deletion_success=OpenID-osoite on poistettu.
add_new_email=Lisää uusi sähköpostiosoite
add_new_openid=Lisää uusi OpenID URI
add_email=Lisää sähköpostiosoite
add_openid=Lisää OpenID URI
add_email_success=Uusi sähköpostiosoite on lisätty.
email_preference_set_success=Sähköpostin asetukset on asetettu onnistuneesti.
add_openid_success=Uusi OpenID-osoite on lisätty.
keep_email_private=Piilota sähköpostiosoite
keep_email_private_popup=Sähköpostiosoitteesi on piilotettu muilta käyttäjiltä.
openid_desc=OpenID mahdollistaa todentamisen delegoinnin ulkopuoliselle palvelun tarjoajalle.
@ -421,10 +545,35 @@ ssh_helper=<strong>Tarvitsetko apua?</strong> Tutustu GitHubin oppaaseen <a href
gpg_helper=<strong>Tarvitsetko apua?</strong> Katso GitHubin opas <a href="%s">GPG</a>:stä.
add_new_key=Lisää SSH avain
add_new_gpg_key=Lisää GPG-avain
key_content_ssh_placeholder=Alkaa sanoilla 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', tai 'sk-ssh-ed25519@openssh.com'
key_content_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP PUBLIC KEY BLOCK-----'
ssh_key_name_used=Samanniminen SSH avain on jo olemassa tililläsi.
gpg_key_id_used=Julkinen GPG-avain samalla tunnuksella on jo olemassa.
gpg_no_key_email_found=Tämä GPG-avain ei vastaa mitään tiliisi liitettyä aktivoitua sähköpostiosoitetta. Se voidaan silti lisätä, jos allekirjoitat annetun pääsymerkin.
gpg_key_verified=Vahvistettu avain
gpg_key_verified_long=Avain on vahvistettu pääsymerkillä ja sitä voidaan käyttää todentamaan commitit, jotka vastaavat tämän käyttäjän aktivoituja sähköpostiosoitteita tämän avaimen kaikkien vastaavien identiteettien lisäksi.
gpg_key_verify=Vahvista
gpg_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkille
gpg_token=Pääsymerkki
gpg_token_help=Voit luoda allekirjoituksen käyttäen:
gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig
gpg_token_signature=Panssaroitu GPG-allekirjoitus
key_signature_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP SIGNATURE-----'
verify_gpg_key_success=GPG-avain '%s' on vahvistettu.
ssh_key_verified=Vahvistettu avain
ssh_key_verified_long=Avain on vahvistettu pääsymerkillä ja sitä voidaan käyttää todentamaan commitit, jotka vastaavat tämän käyttäjän aktivoituja sähköpostiosoitteita.
ssh_key_verify=Vahvista
ssh_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkille
ssh_token=Pääsymerkki
ssh_token_help=Voit luoda allekirjoituksen käyttäen:
ssh_token_signature=Panssaroitu SSH-allekirjoitus
key_signature_ssh_placeholder=Alkaa sanoilla '-----BEGIN SSH SIGNATURE-----'
verify_ssh_key_success=SSH avain '%s' on vahvistettu.
subkeys=Aliavaimet
key_id=Avain ID
key_name=Avaimen nimi
key_content=Sisältö
principal_content=Sisältö
add_key_success=SSH-avain '%s' on lisätty.
add_gpg_key_success=GPG-avain '%s' lisättiin.
delete_key=Poista
@ -434,13 +583,22 @@ gpg_key_deletion_desc=GPG-avaimen poistaminen peruuttaa sillä allekirjoitettuje
gpg_key_deletion_success=GPG-avain on poistettu.
add_on=Lisätty
valid_until=Vanhenee
valid_forever=Voimassa ikuisesti
last_used=Käytetty viimeksi
no_activity=Ei viimeaikaista toimintaa
can_read_info=Luku
can_write_info=Kirjoitus
show_openid=Näytä profiilissa
hide_openid=Piilota profiilista
ssh_disabled=SSH pois käytöstä
manage_social=Hallitse liitettyjä sosiaalisia tilejä
manage_access_token=Hallitse pääsymerkkejä
generate_new_token=Luo uusi pääsymerkki
new_token_desc=Pääsymerkkiä käyttävillä sovelluksilla on täysi pääsy tiliisi.
token_name=Pääsymerkin nimi
generate_token=Luo pääsymerkki
generate_token_success=Uusi pääsymerkkisi on nyt luotu. Kopioi se nyt, koska sitä ei näytetä enää uudelleen.
delete_token=Poista
access_token_deletion=Poista pääsymerkki
@ -458,8 +616,15 @@ oauth2_application_edit=Muokkaa
twofa_desc=Kaksivaiheinen todennus parantaa tilisi turvallisuutta.
twofa_is_enrolled=Tilisi <strong>käyttää</strong> kaksivaiheista vahvistusta.
twofa_not_enrolled=Tilisi ei tällä hetkellä käytä kaksivaiheista vahvistusta.
twofa_enroll=Ota kaksivaiheinen vahvistus käyttöön
twofa_disabled=Kaksivaiheinen todennus on otettu pois käytöstä.
scan_this_image=Skannaa tämä kuva tunnistautumissovelluksellasi:
or_enter_secret=Tai kirjoita salainen avain: %s
twofa_enrolled=Tiliisi on otettu käyttöön kaksivaiheinen vahvistus. Ota palautustunnus (%s) talteen turvalliseen paikkaan, sillä se näytetään vain kerran!
webauthn_nickname=Nimimerkki
manage_account_links=Hallitse linkitettyjä tilejä
manage_account_links_desc=Nämä ulkoiset tilit on linkitetty Gitea tiliisi.
@ -475,37 +640,60 @@ delete_prompt=Tämä toiminto poistaa käyttäjätilisi pysyvästi. Toimintoa <s
confirm_delete_account=Varmista poisto
delete_account_title=Poista käyttäjätili
email_notifications.enable=Ota käyttöön sähköposti-ilmoitukset
visibility=Käyttäjän näkyvyys
visibility.public=Julkinen
visibility.public_tooltip=Näkyvissä kaikille käyttäjille
visibility.limited=Rajattu
visibility.private=Yksityinen
[repo]
new_repo_helper=Repo sisältää kaikki projektitiedostot, mukaan lukien revisiohistorian. Onko sinulla repo jo muualla? <a href="%s">Voit siirtää repon.</a>
owner=Omistaja
owner_helper=Jotkin organisaatiot eivät välttämättä näy pudotusvalikossa, koska repojen maksimimäärää on rajoitettu.
repo_name=Repon nimi
repo_name_helper=Hyvä repon nimi on lyhyt, mieleenpainuva ja yksilöllinen.
repo_size=Repon koko
template=Malli
template_select=Valitse malli.
template_helper=Tee reposta mallipohja
visibility=Näkyvyys
visibility_description=Vain omistaja tai organisaation jäsenet, jos heillä on oikeudet, voivat nähdä sen.
visibility_helper=Tee reposta yksityinen
fork_repo=Forkkaa repo
fork_from=Forkkaa lähteestä
fork_visibility_helper=Forkatun repon näkyvyyttä ei voi muuttaa.
clone_in_vsc=Kloonaa VS Codessa
download_zip=Lataa ZIP
download_tar=Lataa TAR.GZ
repo_desc=Kuvaus
repo_lang=Kieli
repo_gitignore_helper=Valitse .gitignore mallit.
issue_labels=Ongelmien tunnisteet
issue_labels_helper=Valitse pohja ongelmien nimilapuille.
license=Lisenssi
license_helper=Valitse lisenssitiedosto.
readme=README
auto_init=Alusta repo (Luo .gitignore, License ja README)
create_repo=Luo repo
default_branch=Oletus branch
mirror_prune=Karsi
watchers=Tarkkailijat
stargazers=Tähtiharrastajat
forks=Haarat
pick_reaction=Valitse reaktiosi
delete_preexisting_label=Poista
desc.private=Yksityinen
desc.public=Julkinen
desc.private_template=Yksityinen malli
desc.public_template=Malli
desc.internal=Sisäinen
template.git_hooks=Git-koukut
template.webhooks=Webkoukut
template.topics=Aiheet
template.avatar=Profiilikuva
template.issue_labels=Ongelmien tunnisteet
@ -521,15 +709,18 @@ migrate_items_pullrequests=Vetopyynnöt
migrate_items_releases=Julkaisut
migrate_repo=Siirrä repo
migrate.clone_address=Migraation / Kloonaa URL osoitteesta
migrate.github_token_desc=Voit laittaa yhden tai useamman pääsymerkin pilkulla erotellen tähän nopeuttaaksesi migraatiota GitHub APIn vauhtirajojen takia. VAROITUS: Tämän ominaisuuden väärinkäyttö voi rikkoa palveluntarjoajan ehtoja ja johtaa tilin estämiseen.
migrate.permission_denied=Sinun ei sallita tuovan paikallisia repoja.
migrate.failed=Siirto epäonnistui: %v
migrate.migrate_items_options=Pääsymerkki vaaditaan lisäkohteiden siirtämiseen
migrate.migrating_failed.error=Virhe: %s
mirror_from=peilaus alkaen
forked_from=forkattu lähteestä
unwatch=Lopeta tarkkailu
watch=Tarkkaile
unstar=Peru ääni
star=Äänestä
unstar=Poista tähti
star=Tähti
download_archive=Lataa varasto
no_desc=Ei kuvausta
@ -549,7 +740,10 @@ labels=Tunnisteet
milestones=Merkkipaalut
commits=Commitit
commit=Commit
releases=Julkaisut
tag=Tagi
released_this=julkaisi tämän
file_raw=Raaka
file_history=Historia
file_view_raw=Näytä raaka
@ -557,6 +751,8 @@ file_permalink=Pysyvä linkki
video_not_supported_in_browser=Selaimesi ei tue HTML5 video-tagia.
audio_not_supported_in_browser=Selaimesi ei tue HTML5 audio-tagia.
blame=Selitys
download_file=Lataa tiedosto
normal_view=Normaali näkymä
line=rivi
lines=rivejä
@ -585,6 +781,7 @@ editor.create_new_branch_np=Luo <strong>uusi haara</strong> tälle commitille.
editor.cancel=Peruuta
editor.filename_cannot_be_empty=Tiedostonimi ei voi olla tyhjä.
editor.filename_is_invalid=Tiedostonnimi on epäkelpo: '%s'.
editor.branch_already_exists=Haara '%s' on jo olemassa tässä repossa.
editor.no_changes_to_show=Ei muutoksia näytettäväksi.
editor.add_subdir=Lisää hakemisto…
editor.unable_to_upload_files=Tiedostojen lataaminen kohteeseen '%s' epäonnistui virheellä: %v
@ -600,9 +797,32 @@ commits.date=Päivämäärä
commits.older=Vanhemmat
commits.newer=Uudemmat
commits.signed_by=Allekirjoittanut
commits.gpg_key_id=GPG avaimen ID
commits.ssh_key_fingerprint=SSH avaimen sormenjälki
projects=Projektit
projects.description_placeholder=Kuvaus
projects.create=Luo projekti
projects.title=Otsikko
projects.new=Uusi projekti
projects.create_success=Projekti '%s' on luotu.
projects.deletion=Poista projekti
projects.deletion_success=Projekti on poistettu.
projects.edit=Muokkaa projektia
projects.modify=Päivitä projekti
projects.edit_success=Projekti '%s' on päivitetty.
projects.type.basic_kanban=Yksinkertainen Kanban
projects.type.uncategorized=Luokittelematon
projects.board.edit=Muokkaa luetteloa
projects.board.new_submit=Lähetä
projects.board.new=Uusi taulu
projects.board.set_default=Aseta oletukseksi
projects.board.delete=Poista taulu
projects.board.color=Väri
projects.open=Avaa
projects.close=Sulje
issues.desc=Ongelmien, tehtävien ja merkkipaalujen hallinta.
issues.filter_milestones=Suodata merkkipaalu
@ -619,12 +839,14 @@ issues.new.closed_milestone=Suljetut merkkipaalut
issues.new.assignees=Käsittelijä
issues.new.clear_assignees=Tyhjennä käsittelijä
issues.new.no_assignees=Ei käsittelijää
issues.choose.blank=Oletus
issues.no_ref=Haaraa/tagia ei määritelty
issues.create=Ilmoita ongelma
issues.new_label=Uusi tunniste
issues.new_label_placeholder=Tunnisteen nimi
issues.new_label_desc_placeholder=Kuvaus
issues.create_label=Luo tunniste
issues.label_templates.helper=Valitse tunnistejoukko
issues.add_milestone_at=`lisäsi tämän merkkipaaluun <b>%s</b> %s`
issues.deleted_milestone=`(poistettu)`
issues.self_assign_at=`itse otti tämän käsittelyyn %s`
@ -640,6 +862,7 @@ issues.filter_type.all_issues=Kaikki ongelmat
issues.filter_type.assigned_to_you=Osoitettu sinulle
issues.filter_type.created_by_you=Ilmoittamasi
issues.filter_type.mentioning_you=Jotka mainitsee sinut
issues.filter_type.review_requested=Arvostelua pyydetty
issues.filter_sort=Lajittele
issues.filter_sort.latest=Uusin
issues.filter_sort.oldest=Vanhin
@ -657,6 +880,7 @@ issues.action_open=Avaa
issues.action_close=Sulje
issues.action_label=Tunniste
issues.action_milestone=Merkkipaalu
issues.action_milestone_no_select=Ei merkkipaalua
issues.opened_by=%[1]s avasi <a href="%[2]s">%[3]s</a>
issues.previous=Edellinen
issues.next=Seuraava
@ -724,9 +948,11 @@ issues.add_time_minutes=Minuuttia
issues.add_time_sum_to_small=Aikaa ei syötetty.
issues.time_spent_from_all_authors=`Käytetty kokonaisaika: %s`
issues.due_date=Määräpäivä
issues.due_date_form=vvvv-kk-pp
issues.due_date_form_edit=Muokkaa
issues.due_date_form_remove=Poista
issues.due_date_not_set=Määräpäivää ei asetettu.
issues.due_date_overdue=Myöhässä
issues.dependency.title=Riippuvuudet
issues.dependency.add=Lisää riippuvuus…
issues.dependency.cancel=Peru
@ -734,6 +960,12 @@ issues.dependency.remove=Poista
issues.dependency.remove_info=Poistä tämä riippuvuus
issues.review.self.approval=Et voi hyväksyä omia vetopyyntöjä.
issues.review.approve=hyväksyi nämä muutokset %s
issues.review.left_comment=jätti kommentin
issues.review.pending=Odottaa
issues.reference_issue.body=Kuvaus
issues.content_history.deleted=poistettu
issues.content_history.edited=muokattu
issues.content_history.created=luotu
pulls.new=Uusi pull pyyntö
@ -775,12 +1007,17 @@ milestones.edit_success=Merkkipaalu '%s' on päivitetty.
milestones.filter_sort.most_issues=Eniten ongelmia
milestones.filter_sort.least_issues=Vähiten ongelmia
signing.wont_sign.always=Commitit ovat aina allekirjoitettuja
wiki=Wiki
wiki.welcome=Tervetuloa Wikiin.
wiki.welcome_desc=Wikissä voit kirjoittaa ja jakaa dokumentaatiota käyttäjien kesken.
wiki.create_first_page=Luo ensimmäinen sivu
wiki.page=Sivu
wiki.filter_page=Suodatin sivu
wiki.new_page=Sivu
wiki.default_commit_message=Kirjoita muistiinpano tästä päivityksestä (valinnainen).
wiki.save_page=Tallenna sivu
wiki.last_commit_info=%s muokkasi tätä sivua %s
wiki.edit_page_button=Muokkaa
@ -813,6 +1050,7 @@ activity.new_issues_count_n=Uutta ongelmaa
activity.new_issue_label=Avoinna
activity.unresolved_conv_label=Auki
activity.published_release_label=Julkaistu
activity.git_stats_pushed_1=on työntänyt
activity.git_stats_file_1=%d tiedosto
activity.git_stats_file_n=%d tiedostoa
activity.git_stats_addition_1=%d lisäys
@ -881,15 +1119,27 @@ settings.discord_username=Käyttäjätunnus
settings.event_create=Luo
settings.event_delete=Poista
settings.event_release_desc=Julkaisu julkaistu, päivitetty tai poistettu varastosta.
settings.event_push=Työnnä
settings.event_repository=Repo
settings.event_issue_comment_desc=Ongelman kommentti luotu, muokattu tai poistettu.
settings.event_pull_request=Vetopyyntö
settings.update_webhook=Päivitä webkoukku
settings.delete_webhook=Poista webkoukku
settings.recent_deliveries=Viimeisimmät toimitukset
settings.hook_type=Koukkutyyppi
settings.slack_token=Pääsymerkki
settings.slack_domain=Verkkotunnus
settings.slack_channel=Kanava
settings.web_hook_name_gitea=Gitea
settings.web_hook_name_gogs=Gogs
settings.web_hook_name_slack=Slack
settings.web_hook_name_discord=Discord
settings.web_hook_name_dingtalk=DingTalk
settings.web_hook_name_telegram=Telegram
settings.web_hook_name_matrix=Matrix
settings.web_hook_name_feishu=Feishu
settings.web_hook_name_larksuite=Lark Suite
settings.web_hook_name_packagist=Packagist
settings.deploy_keys=Deploy avaimet
settings.add_deploy_key=Lisää deploy avain
settings.title=Otsikko
@ -904,12 +1154,20 @@ settings.protect_merge_whitelist_committers_desc=Salli vain listaan merkittyjen
settings.protect_merge_whitelist_users=Lista käyttäjistä joilla yhdistämis-oikeus:
settings.protect_required_approvals=Vaadittavat hyväksynnät:
settings.protect_approvals_whitelist_users=Sallittujen tarkastajien lista:
settings.protect_protected_file_patterns_desc=Suojatut tiedostot, joita ei voi muuttaa suoraan, vaikka käyttäjällä olisi oikeudet lisätä, muokata tai poistaa tiedostoja tässä haarassa. Useita malleja voidaan erottaa puolipisteellä ('\;'). Katso <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> dokumentaatio mallisyntaksille. Esimerkkejä: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
settings.protect_unprotected_file_patterns_desc=Suojaamattomat tiedostot, joita voidaan muuttaa suoraan, jos käyttäjällä on kirjoitusoikeudet, ohittaen push-rajoituksen. Useita kuvioita voidaan erottaa puolipisteellä ('\;'). Katso <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> dokumentaatio kuviosyntaksille. Esimerkkejä: <code>.drone.yml</code>, <code>/docs/**/*.txt</code>.
settings.update_protect_branch_success=Haaran '%s' suojaus on päivitetty.
settings.remove_protected_branch_success=Haaran '%s' suojaus on poistettu käytöstä.
settings.choose_branch=Valitse haara…
settings.no_protected_branch=Suojattuja haaroja ei ole.
settings.edit_protected_branch=Muokkaa
settings.protected_branch_required_approvals_min=Vaadittavat hyväksynnät ei voi olla negatiivinen.
settings.tags=Tagit
settings.tags.protection.pattern=Tagin kuvio
settings.tags.protection.pattern.description=Voit käyttää yhtä nimeä tai glob-kuviota tai säännöllistä lauseketta, joka täsmää useisiin tageihin. Lue lisää <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/protected-tags/">suojatut tagit oppaasta</a>.
settings.bot_token=Botti pääsymerkki
settings.matrix.homeserver_url=Kotipalvelimen URL
settings.matrix.access_token=Pääsymerkki
settings.archive.button=Arkistoi repo
settings.archive.header=Arkistoi tämä repo
settings.lfs=LFS
@ -917,7 +1175,9 @@ settings.lfs_pointers.oid=OID
diff.browse_source=Selaa lähdekoodia
diff.parent=vanhempi
diff.commit=commit
diff.git-notes=Muistiinpanot
diff.options_button=Vertailun asetukset
diff.show_split_view=Jaettu näkymä
diff.show_unified_view=Yhdistetty näkymä
diff.whitespace_button=Tyhjämerkki
@ -937,6 +1197,7 @@ diff.review.comment=Kommentoi
diff.review.approve=Hyväksy
release.releases=Julkaisut
release.tags=Tagit
release.new_release=Uusi julkaisu
release.draft=Työversio
release.prerelease=Esiversio
@ -963,6 +1224,7 @@ release.downloads=Lataukset
branch.name=Haaran nimi
branch.delete_head=Poista
branch.delete=Poista haara '%s'
branch.create_branch=Luo haara <strong>%s</strong>
@ -1002,7 +1264,9 @@ settings.permission=Käyttöoikeudet
settings.visibility=Näkyvyys
settings.visibility.public=Julkinen
settings.visibility.limited=Rajoitettu (näkyvä vain kirjautuneille käyttäjille)
settings.visibility.limited_shortname=Rajattu
settings.visibility.private=Yksityinen (näkyvä vain organisaation jäsenille)
settings.visibility.private_shortname=Yksityinen
settings.update_settings=Päivitä asetukset
settings.delete=Poista organisaatio
@ -1053,6 +1317,7 @@ users=Käyttäjätilit
organizations=Organisaatiot
repositories=Repot
authentication=Todennuslähteet
emails=Käyttäjien sähköpostit
config=Asetukset
notices=Järjestelmän ilmoitukset
monitor=Valvonta
@ -1061,10 +1326,13 @@ last_page=Viimeisin
total=Yhteensä: %d
dashboard.statistic=Yhteenveto
dashboard.operations=Huoltotoimet
dashboard.system_status=Järjestelmän tila
dashboard.operation_name=Toiminnon nimi
dashboard.operation_switch=Vaihda
dashboard.operation_run=Suorita
dashboard.delete_inactive_accounts=Poista kaikki aktivoimattomat käyttäjät
dashboard.delete_repo_archives=Poista kaikki repojen arkistot (ZIP, TAR.GZ, jne..)
dashboard.server_uptime=Palvelimen Uptime
dashboard.current_goroutine=Nykyiset Goroutinet
dashboard.current_memory_usage=Nykyinen muistinkäyttö
@ -1099,23 +1367,38 @@ users.name=Käyttäjätunnus
users.full_name=Kokonimi
users.activated=Aktivoitu
users.admin=Ylläpito
users.restricted=Rajoitettu
users.2fa=2FA
users.repos=Repot
users.created=Luotu
users.last_login=Viimeksi kirjautunut
users.never_login=Ei koskaan kirjautunut
users.edit=Muokkaa
users.auth_source=Todennuslähde
users.local=Paikallinen
users.password_helper=Jätä salasanakenttä tyhjäksi jos haluat pitää sen muuttamattomana.
users.update_profile_success=Käyttäjän tili on päivitetty.
users.edit_account=Muokkaa käyttäjän tiliä
users.max_repo_creation_desc=(Aseta -1 käyttääksesi globaalia oletusrajaa.)
users.is_activated=Käyttäjätili on aktivoitu
users.prohibit_login=Ota sisäänkirjautuminen pois käytöstä
users.is_admin=Ylläpitäjä
users.is_restricted=Rajoitettu tili
users.allow_git_hook=Voi luoda Git koukkuja
users.allow_create_organization=Voi luoda organisaatioita
users.update_profile=Päivitä käyttäjän tili
users.delete_account=Poista käyttäjän tili
users.list_status_filter.is_restricted=Rajoitettu
users.list_status_filter.not_restricted=Ei rajoitettu
emails.email_manage_panel=Käyttäjien sähköpostien hallinta
emails.primary=Ensisijainen
emails.activated=Aktivoitu
emails.filter_sort.email=Sähköposti
emails.filter_sort.email_reverse=Sähköposti (käänteinen)
emails.filter_sort.name=Käyttäjänimi
emails.filter_sort.name_reverse=Käyttäjänimi (käänteinen)
emails.duplicate_active=Tämä sähköpostiosoite on jo käytössä toisella käyttäjällä.
orgs.org_manage_panel=Organisaatioiden hallinta
orgs.name=Nimi
@ -1128,11 +1411,12 @@ repos.owner=Omistaja
repos.name=Nimi
repos.private=Yksityinen
repos.watches=Tarkkailijat
repos.stars=Äänet
repos.stars=Tähdet
repos.forks=Haarat
repos.issues=Ongelmat
repos.size=Koko
packages.owner=Omistaja
@ -1154,12 +1438,14 @@ auths.user_dn=Käyttäjä DN
auths.search_page_size=Sivukoko
auths.filter=Käyttäjäsuodatin
auths.admin_filter=Ylläpitosuodatin
auths.restricted_filter=Rajoitettu suodatin
auths.smtp_auth=SMTP todennustyyppi
auths.smtphost=SMTP isäntä
auths.smtpport=SMTP portti
auths.allowed_domains=Sallitut verkkotunnukset
auths.skip_tls_verify=Ohita TLS tarkistaminen
auths.pam_service_name=PAM palvelun nimi
auths.oauth2_tokenURL=Pääsymerkki URL
auths.enable_auto_register=Ota käyttöön automaattinen rekisteröinti
auths.tips=Vinkit
auths.tips.oauth2.general=OAuth2-autentikointi
@ -1282,6 +1568,8 @@ notices.op=Toiminta
create_repo=luotu repo <a href="%s">%s</a>
rename_repo=uudelleennimetty repo <code>%[1]s</code> nimelle <a href="%[2]s">%[3]s</a>
transfer_repo=siirretty repo <code>%s</code> kohteeseen <a href="%s">%s</a>
push_tag=työnsi tagin <a href="%[2]s">%[3]s</a> kohteeseen <a href="%[1]s">%[4]s</a>
compare_commits_general=Vertaa committeja
[tool]
ago=%s sitten
@ -1321,8 +1609,29 @@ mark_as_unread=Merkitse lukemattomaksi
mark_all_as_read=Merkitse kaikki luetuiksi
[gpg]
error.no_committer_account=Committaajan sähköpostiosoitteeseen ei ole linkitetty tiliä
error.not_signed_commit=Ei allekirjoitettu committi
[units]
[packages]
title=Paketit
desc=Hallitse repon paketteja.
empty=Täällä ei vielä ole paketteja.
empty.documentation=Lisätietoa pakettirekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview">dokumentaatiosta</a>.
filter.type=Tyyppi
filter.type.all=Kaikki
filter.no_result=Suodattimesi ei tuottanut tuloksia.
installation=Asennus
details.author=Tekijä
composer.documentation=Lisätietoa Composer-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/composer/">dokumentaatiosta</a>.
conan.documentation=Lisätietoa Conan-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/conan/">dokumentaatiosta</a>.
container.documentation=Lisätietoa Container-rekisteristä löydät<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/container/">dokumentaatiosta</a>.
generic.documentation=Lisätietoa yleisestä pakettirekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/generic">dokumentaatiosta</a>.
helm.documentation=Lisätietoa Helm-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">dokumentaatiosta</a>.
maven.documentation=Lisätietoa Maven-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/maven/">dokumentaatiosta</a>.
nuget.documentation=Lisätietoa NuGet-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/nuget/">dokumentaatiosta</a>.
npm.documentation=Lisätietoa npm-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/npm/">dokumentaatiosta</a>.
pypi.documentation=Lisätietoa PyPI-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">dokumentaatiosta</a>.
rubygems.documentation=Lisätietoa RubyGems-rekisteristä löydät <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/rubygems/">dokumentaatiosta</a>.

View file

@ -1063,6 +1063,7 @@ normal_view=Vista normale
line=riga
lines=righe
editor.add_file=Aggiungi file
editor.new_file=Nuovo file
editor.upload_file=Carica File
editor.edit_file=Modifica File
@ -1268,6 +1269,8 @@ issues.filter_milestone=Traguardo
issues.filter_milestone_no_select=Tutte le pietre miliari
issues.filter_assignee=Assegnatario
issues.filter_assginee_no_select=Tutte le assegnazioni
issues.filter_poster=Autore
issues.filter_poster_no_select=Tutti gli autori
issues.filter_type=Tipo
issues.filter_type.all_issues=Tutti i problemi
issues.filter_type.assigned_to_you=Assegnati a te
@ -3111,6 +3114,9 @@ npm.dependencies.development=Dipendenze Di Sviluppo
npm.dependencies.peer=Dipendenze Peer
npm.dependencies.optional=Dipendenze Opzionali
npm.details.tag=Tag
pub.install=Per installare il pacchetto utilizzando NuGet, eseguire il seguente comando:
pub.documentation=Per ulteriori informazioni sul registro Pub, consultare <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">la documentazione</a>.
pub.details.repository_site=Sito Repository
pypi.requires=Richiede Python
pypi.install=Per installare il pacchetto usando pip, eseguire il seguente comando:
pypi.documentation=Per ulteriori informazioni sul registro PyPI, consultare <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">la documentazione</a>.

View file

@ -2794,13 +2794,19 @@ config.queue_length=キューの長さ
config.deliver_timeout=送信タイムアウト
config.skip_tls_verify=TLS検証を省略
config.mailer_config=メーラー設定
config.mailer_enabled=有効
config.mailer_enable_helo=HELO有効
config.mailer_name=名称
config.mailer_protocol=プロトコル
config.mailer_smtp_addr=SMTPアドレス
config.mailer_smtp_port=SMTPポート
config.mailer_user=ユーザー
config.mailer_use_sendmail=Sendmailを使う
config.mailer_sendmail_path=Sendmailのパス
config.mailer_sendmail_args=Sendmailの追加引数
config.mailer_sendmail_timeout=Sendmail のタイムアウト
config.mailer_use_dummy=Dummy
config.test_email_placeholder=Email (例 test@example.com)
config.send_test_mail=テストメールを送信
config.test_mail_failed='%s' へのテストメール送信に失敗しました: %v

View file

@ -179,6 +179,8 @@ log_root_path_helper=Žurnalizēšanas faili tiks rakstīti šajā direktorijā.
optional_title=Neobligātie iestatījumi
email_title=E-pastu iestatījumi
smtp_addr=SMTP resursdators
smtp_port=SMTP ports
smtp_from=Nosūtīt e-pastu kā
smtp_from_helper=E-pasta adrese, ko Gitea izmantos. Ievadiet tika e-pasta adrese vai izmantojiet "Vārds" <epasts@domens.lv> formātu.
mailer_user=SMTP lietotāja vārds
@ -798,6 +800,7 @@ email_notifications.enable=Iespējot e-pasta paziņojumus
email_notifications.onmention=Tikai, ja esmu pieminēts
email_notifications.disable=Nesūtīt paziņojumus
email_notifications.submit=Saglabāt sūtīšanas iestatījumus
email_notifications.andyourown=Iekļaut savus paziņojumus
visibility=Lietotāja redzamība
visibility.public=Publisks
@ -860,7 +863,9 @@ default_branch=Noklusējuma atzars
default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana.
mirror_prune=Izmest
mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē
mirror_interval=Spoguļošanas intervāls (derīgas laika vienības ir 'h', 'm', 's'). Norādiet 0, lai atslēgtu periodisku spoguļošanu. (Minimālais intervāls: %s)
mirror_interval_invalid=Nekorekts spoguļošanas intervāls.
mirror_sync_on_commit=Sinhronizēt, kad revīzijas tiek iesūtītas
mirror_address=Spoguļa adrese
mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā.
mirror_address_url_invalid=Norādītais URL nav korekts. Norādiet visas URL daļas korekti.
@ -929,6 +934,7 @@ form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts.
need_auth=Autorizācija
migrate_options=Migrācijas opcijas
migrate_service=Migrācijas serviss
migrate_options_mirror_helper=Šis repozitorijs būs spogulis
migrate_options_lfs=Migrēt LFS failus
migrate_options_lfs_endpoint.label=LFS galapunkts
migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai <a target="_blank" rel="noopener noreferrer" href="%s">noteiktu LFS serveri</a>. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā.
@ -1057,6 +1063,7 @@ normal_view=Parastais skats
line=rinda
lines=rindas
editor.add_file=Pievienot
editor.new_file=Jauna datne
editor.upload_file=Augšupielādēt failu
editor.edit_file=Labot failu
@ -1299,6 +1306,7 @@ issues.previous=Iepriekšējā
issues.next=Nākamā
issues.open_title=Atvērta
issues.closed_title=Slēgta
issues.draft_title=Melnraksts
issues.num_comments=%d komentāri
issues.commented_at=` komentēja <a href="#%s">%s</a>`
issues.delete_comment_confirm=Vai patiešām vēlaties dzēst šo komentāru?
@ -1415,6 +1423,7 @@ issues.due_date_form_remove=Noņemt
issues.due_date_not_writer=Jums ir nepieciešamas rakstīšanas tiesības uz šo repozitoriju, lai mainītu izpildes termiņu.
issues.due_date_not_set=Izpildes termiņš nav uzstādīts.
issues.due_date_added=pievienoja izpildes termiņu %s %s
issues.due_date_modified=mainīja termiņa datumu no %[2]s uz %[1]s %[3]s
issues.due_date_remove=noņēma izpildes termiņu %s %s
issues.due_date_overdue=Nokavēts
issues.due_date_invalid=Datums līdz nav korekts. Izmantojiet formātu 'gggg-mm-dd'.
@ -1526,6 +1535,8 @@ pulls.remove_prefix=Noņemt <strong>%s</strong> prefiksu
pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija.
pulls.files_conflicted=Šīs izmaiņu pieprasījuma izmaiņas konfliktē ar mērķa atzaru.
pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu.
pulls.is_ancestor=Atzars jau ir pilnībā iekļauts mērķā atzarā. Nav izmaiņu, ko sapludināt.
pulls.is_empty=Mērķa atzars jau satur šī atzara izmaiņas. Šī revīzija būs tukša.
pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas.
pulls.required_status_check_missing=Trūkst dažu obligāto pārbaužu.
pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu.
@ -1604,6 +1615,8 @@ pulls.auto_merge_canceled_schedule=Automātiskā sapludināšana šim izmaiņu p
pulls.auto_merge_newly_scheduled_comment=`ieplānoja automātisko sapludināšanu šim izmaiņu pieprasījumam, kad visas pārbaudes būs veiksmīgas %[1]s`
pulls.auto_merge_canceled_schedule_comment=`atcēla automātisko sapludināšanu šim izmaiņu pieprasījumam %[1]s`
pulls.delete.title=Dzēst šo izmaiņu pieprasījumu?
pulls.delete.text=Vai patiešām vēlaties dzēst šo izmaiņu pieprasījumu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei)
milestones.new=Jauns atskaites punkts
milestones.closed=Aizvērts %s
@ -2526,6 +2539,8 @@ users.delete_account=Dzēst lietotāja kontu
users.cannot_delete_self=Nevar izdzēst sevi
users.still_own_repo=Lietotājam pieder repozitoriji, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku.
users.still_has_org=Šis lietotājs ir vienas vai vairāku organizāciju biedrs, lietotāju sākumā ir nepieciešams pamest šīs organizācijas vai viņu no tām ir jāizdzēš.
users.purge=Attīrīt lietotu
users.purge_help=Piespiedu dzēst lietotāju un visus tā repozitorijus, organizācijas un pakotnes. Arī visi lietotāja komentāri tiks dzēsti.
users.still_own_packages=Šim lietotājam pieder viena vai vairākas pakotnes. Tās nepieciešams izdzēst.
users.deletion_success=Lietotāja konts veiksmīgi izdzēsts.
users.reset_2fa=Noņemt 2FA
@ -2782,13 +2797,19 @@ config.queue_length=Rindas garums
config.deliver_timeout=Piegādes noildze
config.skip_tls_verify=Izlaist TLS pārbaudi
config.mailer_config=Pasta sūtītāja konfigurācija
config.mailer_enabled=Iespējota
config.mailer_enable_helo=Iespējot HELO
config.mailer_name=Nosaukums
config.mailer_protocol=Protokols
config.mailer_smtp_addr=SMTP adrese
config.mailer_smtp_port=SMTP ports
config.mailer_user=Lietotājs
config.mailer_use_sendmail=Izmantot Sendmail
config.mailer_sendmail_path=Ceļš līdz sendmail programmai
config.mailer_sendmail_args=Papildus Sendmail komandrindas argumenti
config.mailer_sendmail_timeout=Sendmail noildze
config.mailer_use_dummy=Tukšs
config.test_email_placeholder=E-pasts (piemēram, test@example.com)
config.send_test_mail=Nosūtīt pārbaudes e-pastu
config.test_mail_failed=Neizdevās nosūtīt pārbaudes e-pastu uz '%s': %v
@ -3025,6 +3046,7 @@ title=Pakotnes
desc=Pārvaldīt repozitorija pakotnes.
empty=Pašlaik šeit nav nevienas pakotnes.
empty.documentation=Papildus informācija par pakotņu reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview">dokumentācijā</a>.
empty.repo=Neparādās augšupielādēta pakotne? Apmeklējiet <a href="%[1]s">pakotņu iestatījumus</a>, lai sasaistītu ar repozitoriju.
filter.type=Veids
filter.type.all=Visas
filter.no_result=Pēc norādītajiem kritērijiem nekas netika atrasts.
@ -3090,6 +3112,10 @@ npm.dependencies.development=Izstrādes atkarības
npm.dependencies.peer=Netiešās atkarības
npm.dependencies.optional=Neobligātās atkarības
npm.details.tag=Tags
pub.install=Lai instalētu Dart pakotni, izpildiet sekojošu komandu:
pub.documentation=Papildus informācija par Pub reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">dokumentācijā</a>.
pub.details.repository_site=Repozitorija izmērs
pub.details.documentation_site=Dokumentācijas lapa
pypi.requires=Nepieciešams Python
pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu:
pypi.documentation=Papildus informācija par PyPI reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">dokumentācijā</a>.

View file

@ -1063,6 +1063,7 @@ normal_view=Normale weergave
line=regel
lines=regels
editor.add_file=Bestand toevoegen
editor.new_file=Nieuw bestand
editor.upload_file=Upload bestand
editor.edit_file=Bewerk bestand
@ -1268,6 +1269,8 @@ issues.filter_milestone=Mijlpaal
issues.filter_milestone_no_select=Alle mijlpalen
issues.filter_assignee=Aangewezene
issues.filter_assginee_no_select=Alle toegewezen personen
issues.filter_poster=Auteur
issues.filter_poster_no_select=Alle auteurs
issues.filter_type=Type
issues.filter_type.all_issues=Alle kwesties
issues.filter_type.assigned_to_you=Aan jou toegewezen
@ -1296,6 +1299,11 @@ issues.action_milestone_no_select=Geen mijlpaal
issues.action_assignee=Toegewezene
issues.action_assignee_no_select=Geen verantwoordelijke
issues.opened_by=%[1]s geopend door <a href="%[2]s">%[3]s</a>
pulls.merged_by=door <a href="%[2]s">%[3]s</a> was samengevoegd %[1]s
pulls.merged_by_fake=bij %[2]s is %[1]s samengevoegd
issues.closed_by=door <a href="%[2]s">%[3]s</a> was gesloten %[1]s
issues.opened_by_fake=%[1]s geopend door %[2]s
issues.closed_by_fake=door %[2]s was gesloten %[1]s
issues.previous=Vorige
issues.next=Volgende
issues.open_title=Open
@ -1311,6 +1319,8 @@ issues.context.edit=Bewerken
issues.context.delete=Verwijder
issues.no_content=Er is nog geen inhoud.
issues.close_issue=Sluit
issues.pull_merged_at=`commit samengevoegd <a class="ui sha" href="%[1]s"><code>%[2]s</code></a> in <b>%[3]s</b> %[4]s`
issues.manually_pull_merged_at=`commit <a class="ui sha" href="%[1]s"> handmatig samengevoegd <code>%[2]s</code></a> in <b>%[3]s</b> %[4]s`
issues.close_comment_issue=Reageer en sluit
issues.reopen_issue=Heropen
issues.reopen_comment_issue=Heropen en geef commentaar
@ -1333,6 +1343,7 @@ issues.is_stale=Er zijn wijzigingen aangebracht in deze PR sinds deze beoordelin
issues.remove_request_review=Verwijder beoordelingsverzoek
issues.remove_request_review_block=Kan beoordelingsverzoek niet verwijderen
issues.dismiss_review=Beoordeling afwijzen
issues.dismiss_review_warning=Bent u zeker dat u deze beoordeling wilt afwijzen?
issues.sign_in_require_desc=<a href="%s">Log in</a> om deel te nemen aan deze discussie.
issues.edit=Bewerken
issues.cancel=Annuleren
@ -1406,6 +1417,7 @@ issues.error_modifying_due_date=Deadline aanpassen mislukt.
issues.error_removing_due_date=Deadline verwijderen mislukt.
issues.push_commit_1=toegevoegd %d commit %s
issues.push_commits_n=toegevoegd %d commits %s
issues.force_push_codes=`force-push %[1]s van <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> naar <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s`
issues.due_date_form=jjjj-mm-dd
issues.due_date_form_add=Vervaldatum toevoegen
issues.due_date_form_edit=Bewerk
@ -1426,6 +1438,7 @@ issues.dependency.remove=Verwijder
issues.dependency.remove_info=Verwijder afhankelijkheid
issues.dependency.added_dependency=`voegde een nieuwe afhankelijkheid %s toe `
issues.dependency.removed_dependency=`verwijderde een afhankelijkheid %s`
issues.dependency.pr_closing_blockedby=Het sluiten van deze pull-aanvraag is geblokkeerd door de volgende issues
issues.dependency.issue_closing_blockedby=Het sluiten van dit issue is geblokkeerd door de volgende problemen
issues.dependency.issue_close_blocks=Deze kwestie blokkeert het sluiten van de volgende kwesties
issues.dependency.pr_close_blocks=Deze pull-aanvraag blokkeert het sluiten van de volgende kwesties
@ -1598,6 +1611,8 @@ pulls.auto_merge_newly_scheduled=De pull-verzoek was gepland om samen te voegen
pulls.auto_merge_has_pending_schedule=%[1]s heeft deze pull-verzoek automatisch samengevoegd wanneer alle checks succesvol zijn geweest %[2]s.
pulls.auto_merge_cancel_schedule=Automatisch samenvoegen annuleren
pulls.auto_merge_not_scheduled=Deze pull-aanvraag is niet gepland om automatisch samen te voegen.
pulls.auto_merge_canceled_schedule=De automatisch samenvoegen is geannuleerd voor deze pull-aanvraag.
pulls.delete.title=Deze pull-verzoek verwijderen?
@ -1761,6 +1776,7 @@ settings.hooks=Webhooks
settings.githooks=Git-hooks
settings.basic_settings=Basis instellingen
settings.mirror_settings=Kopie Settings
settings.mirror_settings.mirrored_repository=Gespiegelde repository
settings.mirror_settings.direction=Richting
settings.mirror_settings.direction.pull=Pull
settings.mirror_settings.direction.push=Push
@ -1790,6 +1806,8 @@ settings.tracker_url_format_error=Het URL-formaat van de externe wiki is geen ge
settings.tracker_issue_style=Nummerformaat van de externe kwestie-tracker
settings.tracker_issue_style.numeric=Nummeriek
settings.tracker_issue_style.alphanumeric=Alfanummeriek
settings.tracker_issue_style.regexp=Reguliere expressie
settings.tracker_issue_style.regexp_pattern=Reguliere expressie patroon
settings.tracker_url_format_desc=Gebruik de aanduidingen <code>{user}</code>, <code>{repo}</code> en <code>{index}</code> voor de gebruikersnaam, repositorynaam en kwestie-index.
settings.enable_timetracker=Tijdregistratie inschakelen
settings.allow_only_contributors_to_track_time=Sta alleen bijdragers toe tijdregistratie te gebruiken

View file

@ -1063,6 +1063,7 @@ normal_view=Vista normal
line=linha
lines=linhas
editor.add_file=Adicionar ficheiro
editor.new_file=Novo ficheiro
editor.upload_file=Carregar ficheiro
editor.edit_file=Editar ficheiro
@ -1268,6 +1269,8 @@ issues.filter_milestone=Etapa
issues.filter_milestone_no_select=Todas as etapas
issues.filter_assignee=Encarregado
issues.filter_assginee_no_select=Todos os encarregados
issues.filter_poster=Autor(a)
issues.filter_poster_no_select=Todos os autores
issues.filter_type=Tipo
issues.filter_type.all_issues=Todas as questões
issues.filter_type.assigned_to_you=Atribuídas a si
@ -3111,6 +3114,10 @@ npm.dependencies.development=Dependências de desenvolvimento
npm.dependencies.peer=Dependências de pares
npm.dependencies.optional=Dependências opcionais
npm.details.tag=Etiqueta
pub.install=Para instalar o pacote usando o Dart, execute o seguinte comando:
pub.documentation=Para obter mais informações sobre o registo Pub, consulte <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">a documentação</a>.
pub.details.repository_site=Página web do repositório
pub.details.documentation_site=Página web da documentação
pypi.requires=Requer Python
pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando:
pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">a documentação</a>.

View file

@ -913,8 +913,8 @@ desc.archived=Arşivlenmiş
template.items=Şablon Öğeleri
template.git_content=Git İçeriği (Varsayılan Dal)
template.git_hooks=Git İstekleri
template.git_hooks_tooltip=Eklendikten sonra Git Hooks'u değiştirmek veya kaldırmak mümkün değildir. Bunu yalnızca şablon deposuna güveniyorsanız seçin.
template.git_hooks=Git İstemcileri
template.git_hooks_tooltip=Eklendikten sonra Git İstemcilerini değiştirmek veya kaldırmak mümkün değildir. Bunu yalnızca şablon deposuna güveniyorsanız seçin.
template.webhooks=Web İstemcileri
template.topics=Konular
template.avatar=Profil Resmi
@ -954,6 +954,7 @@ migrate.clone_address_desc=Varolan bir deponun HTTP(S) veya Git 'klonlama' URL's
migrate.github_token_desc=GitHub API hız sınırı nedeniyle göçü hızlandırmak için buraya virgülle ayrılmış bir veya daha fazla erişm anahtarı koyabilirsiniz. UYARI: Bu özelliğin kötüye kullanılması, hizmet sağlayıcının politikasını ihlal edebilir ve hesabın engellenmesine yol açabilir.
migrate.clone_local_path=veya bir yerel sunucu yolu
migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok.
migrate.permission_denied_blocked=İzin verilmeyen sunuculardan içe aktaramazsınız, lütfen yöneticiden ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS ayarlarını kontrol etmesini isteyin.
migrate.invalid_local_path=Yerel yol geçersiz. Mevcut değil veya bir dizin değil.
migrate.invalid_lfs_endpoint=LFS Uç noktası geçerli değil.
migrate.failed=Göç başarısız: %v
@ -1001,6 +1002,7 @@ clone_this_repo=Bu depoyu klonla
create_new_repo_command=Komut satırında yeni bir depo oluşturuluyor
push_exist_repo=Komut satırından mevcut bir depo itiliyor
empty_message=Bu depoda herhangi bir içerik yok.
broken_message=Bu deponun altındaki Git verisi okunamıyor. Bu sunucunun yöneticisiyle bağlantıya geçin veya bu depoyu silin.
code=Kod
code.desc=Kaynak koda, dosyalara, işlemelere ve dallara eriş.
@ -1026,6 +1028,7 @@ release=Sürüm
releases=Sürüm
tag=Etiket
released_this=bu sürümü yayınladı
file.title=%s dalındaki/etiketindeki %s
file_raw=Ham
file_history=Geçmiş
file_view_source=Kaynağı Görüntüle
@ -1044,6 +1047,7 @@ line_unicode=`Bu satırda gizli evrensel kod karakterler var`
escape_control_characters=Kaçış Karakterli
unescape_control_characters=Kaçış Karaktersiz
file_copy_permalink=Kalıcı Bağlantıyı Kopyala
view_git_blame=Git Suç Görüntüle
video_not_supported_in_browser=Tarayıcınız HTML5 'video' etiketini desteklemiyor.
audio_not_supported_in_browser=Tarayıcınız HTML5 'audio' etiketini desteklemiyor.
stored_lfs=Git LFS ile depolandı
@ -1059,6 +1063,7 @@ normal_view=Normal Görünüm
line=satır
lines=satır
editor.add_file=Dosya Ekle
editor.new_file=Yeni dosya
editor.upload_file=Dosya Yükle
editor.edit_file=Dosyayı Düzenle
@ -1121,6 +1126,8 @@ editor.cannot_commit_to_protected_branch=Korunan '%s' dalına işleme yapılamı
editor.no_commit_to_branch=Doğrudan dala işleme yapılamıyor çünkü:
editor.user_no_push_to_branch=Kullanıcı dala gönderemez
editor.require_signed_commit=Dal imzalı bir işleme gerektirir
editor.cherry_pick=%s şunun üzerine cımbızla:
editor.revert=%s şuna geri döndür:
commits.desc=Kaynak kodu değişiklik geçmişine göz atın.
commits.commits=İşleme
@ -1144,6 +1151,7 @@ commits.ssh_key_fingerprint=SSH Anahtar Parmak İzi
commit.actions=Eylemler
commit.revert=Geri Al
commit.revert-header=Geri al: %s
commit.revert-content=Geri almak için dal seçin:
commit.cherry-pick=Cımbızla
commit.cherry-pick-header=Cımbızla: %s
commit.cherry-pick-content=Cımbızlamak için dal seçin:
@ -1185,6 +1193,7 @@ projects.board.deletion_desc=Bir proje panosunun silinmesi, ilgili tüm konular
projects.board.color=Renk
projects.open=
projects.close=Kapat
projects.board.assigned_to=Atanan
issues.desc=Hata raporlarını, görevleri ve kilometre taşlarını yönetmenizi sağlar.
issues.filter_assignees=Atama Süzgeci
@ -1249,6 +1258,9 @@ issues.add_assignee_at=`%[2]s <b>%[1]s</b> tarafından atandı`
issues.remove_assignee_at=`ataması %[2]s <b>%[1]s</b> tarafından kaldırıldı`
issues.remove_self_assignment=`atamalarını kaldırdı %s`
issues.change_title_at=`başlığı <b><strike>%s</strike></b> iken %s olarak <b>%s</b> değiştirdi`
issues.change_ref_at=`<b><strike>%s</strike></b> referans <b>%s</b> %s olarak değiştirildi`
issues.remove_ref_at=`<b>%s</b> referansı %s tarihinde kaldırıldı`
issues.add_ref_at=`<b>%s</b> referansı %s tarihinde eklendi`
issues.delete_branch_at=`<b>%s</b> dalı silindi %s`
issues.filter_label=Etiket
issues.filter_label_exclude=`Etiketleri hariç tutmak için <code>alt</code> + <code>tıkla/enter</code> kullanın`
@ -1257,6 +1269,8 @@ issues.filter_milestone=Kilometre Taşı
issues.filter_milestone_no_select=Tüm kilometre taşları
issues.filter_assignee=Atanan
issues.filter_assginee_no_select=Tüm atananlar
issues.filter_poster=Yazar
issues.filter_poster_no_select=Tüm yazarlar
issues.filter_type=Tür
issues.filter_type.all_issues=Tüm konular
issues.filter_type.assigned_to_you=Size atanan
@ -1276,6 +1290,7 @@ issues.filter_sort.moststars=En çok yıldızlılar
issues.filter_sort.feweststars=En az yıldızlılar
issues.filter_sort.mostforks=En çok çatallananlar
issues.filter_sort.fewestforks=En az çatallananlar
issues.keyword_search_unavailable=Anahtar kelime ile arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin.
issues.action_open=ık
issues.action_close=Kapat
issues.action_label=Etiket
@ -1284,7 +1299,11 @@ issues.action_milestone_no_select=Kilometre Taşı Yok
issues.action_assignee=Atanan
issues.action_assignee_no_select=Atanan yok
issues.opened_by=<a href="%[2]s">%[3]s</a> tarafından %[1]s açıldı
pulls.merged_by=%[1]s <a href="%[2]s">%[3]s</a> tarafından açılan istek birleştirildi
pulls.merged_by_fake=%[2]s tarafından açılan istek %[1]s birleştirildi
issues.closed_by=<a href="%[2]s">%[3]s</a> tarafından %[1]s kapatıldı
issues.opened_by_fake=%[2]s tarafından %[1]s açıldı
issues.closed_by_fake=%[2]s tarafından %[1]s kapatıldı
issues.previous=Önceki
issues.next=Sonraki
issues.open_title=ık
@ -1405,7 +1424,8 @@ issues.due_date_form_edit=Düzenle
issues.due_date_form_remove=Kaldır
issues.due_date_not_writer=Bir konunun bitiş tarihini değiştirmek için depoda yazma hakkınız olmalıdır.
issues.due_date_not_set=Bitiş tarihi atanmadı.
issues.due_date_added=%[2]s %[1]s bitiş tarihini ekledi
issues.due_date_added=bitiş tarihini %s olarak %s ekledi
issues.due_date_modified=bitiş tarihini %[2]s iken %[1]s olarak %[3]s değiştirdi
issues.due_date_remove=%[2]s %[1]s bitiş tarihini kaldırdı
issues.due_date_overdue=Süresi Geçmiş
issues.due_date_invalid=Bitiş tarihi geçersiz veya aralık dışında. Lütfen 'yyyy-aa-gg' biçimini kullanın.
@ -1467,6 +1487,7 @@ issues.content_history.deleted=silindi
issues.content_history.edited=düzenlendi
issues.content_history.created=oluşturuldu
issues.content_history.delete_from_history=Geçmişten kaldır
issues.content_history.delete_from_history_confirm=Geçmişten kaldırılsın mı?
issues.content_history.options=Seçenekler
issues.reference_link=Referans: %s
@ -1477,6 +1498,8 @@ pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir.
pulls.new=Yeni Değişiklik İsteği
pulls.view=Değişiklik İsteği Görüntüle
pulls.compare_changes=Yeni Değişiklik İsteği
pulls.allow_edits_from_maintainers=Bakımcıların düzenlemelerine izin ver
pulls.allow_edits_from_maintainers_desc=Ana dala yazma hakkı olan kullanıcılar bu dala da gönderebilirler
pulls.allow_edits_from_maintainers_err=Güncelleme başarısız oldu
pulls.compare_changes_desc=Birleştirmek için hedef ve kaynak dalı seçin.
pulls.has_viewed_file=Görüldü
@ -1559,7 +1582,10 @@ pulls.rebase_conflict_summary=Hata Mesajı
; </summary><code>%[2]s<br>%[3]s</code></details>
pulls.unrelated_histories=Birleştirme Başarısız: Birleştirme başlığı ve tabanı ortak bir geçmişi paylaşmıyor. İpucu: Farklı bir strateji deneyin
pulls.merge_out_of_date=Birleştirme Başarısız: Birleştirme oluşturulurken, taban güncellendi. İpucu: Tekrar deneyin.
pulls.head_out_of_date=Birleştirme Başarısız: Birleştirme oluşturulurken, ana güncellendi. İpucu: Tekrar deneyin.
pulls.push_rejected=Birleştirme Başarısız Oldu: Gönderme reddedildi. Bu depo için Git İstemcilerini inceleyin.
pulls.push_rejected_summary=Tam Red Mesajı
pulls.push_rejected_no_message=Birleştirme başarısız oldu: Gönderme reddedildi, ancak uzak bir mesaj yoktu.<br>Bu depo için Git İstemcilerini inceleyin
pulls.open_unmerged_pull_exists=`Aynı özelliklere sahip bekleyen bir değişiklik isteği (#%d) olduğundan yeniden açma işlemini gerçekleştiremezsiniz.`
pulls.status_checking=Bazı denetlemeler beklemede
pulls.status_checks_success=Tüm denetlemeler başarılı oldu
@ -1582,9 +1608,17 @@ pulls.merge_instruction_step2_desc=Gitea'daki değişiklikleri ve güncellemeler
pulls.auto_merge_button_when_succeed=(Denetlemeler başarılı olduğunda)
pulls.auto_merge_when_succeed=Tüm denetlemeler başarılı olduğundan otomatik olarak birleştir
pulls.auto_merge_newly_scheduled=Değişiklik İsteği tüm denetlemeler başarılı olduğunda birleştirilecek şekilde ayarlanmış.
pulls.auto_merge_has_pending_schedule=%[1]s, bu değişiklik isteğini tüm denetlemeler başarılı olduğunda %[2]s, otomatik olarak birleşecek şekilde ayarlamış.
pulls.auto_merge_cancel_schedule=Otomatik birleştirmeyi iptal et
pulls.auto_merge_not_scheduled=Bu değişiklik isteği için otomatik birleştirme zamanlanmamış.
pulls.auto_merge_canceled_schedule=Bu değişiklik isteği için otomatik birleştirme iptal edildi.
pulls.auto_merge_newly_scheduled_comment=`bu değişiklik isteği, tüm denetlemeler başarılı olduğunda %[1]s, otomatik olarak birleşecek şekilde ayarlandı`
pulls.auto_merge_canceled_schedule_comment=`bu değişiklik isteğinin, tüm denetlemeler başarılı olduğunda %[1]s, otomatik birleştirmesi iptal edildi`
pulls.delete.title=Bu değişiklik isteği silinsin mi?
pulls.delete.text=Bu değişiklik isteğini gerçekten silmek istiyor musunuz? (Bu işlem tüm içeriği kalıcı olarak silecektir. Arşivde tutma niyetiniz varsa silmek yerine kapatmayı düşünün)
milestones.new=Yeni Kilometre Taşı
milestones.closed=Kapalı %s
@ -1630,6 +1664,7 @@ signing.wont_sign.commitssigned=İlişkili tüm işlemeler imzalanmadığı içi
signing.wont_sign.approved=Değişiklik İsteği onaylanmadığı için birleştirme imzalanmayacak
signing.wont_sign.not_signed_in=Oturum açmadınız
ext_wiki=Harici Vikiye Erişim
ext_wiki.desc=Harici bir wiki'ye bağlantı.
wiki=Wiki
@ -1654,6 +1689,7 @@ wiki.page_already_exists=Aynı isimde bir Wiki sayfası zaten var.
wiki.reserved_page='%s' wiki sayfa adı rezerve edilmiştir.
wiki.pages=Sayfalar
wiki.last_updated=Son güncelleme %s
wiki.page_name_desc=Bu Viki sayfası için bir ad girin. Bazı özel isimler 'Home', '_Sidebar' ve '_Footer' şeklindedir.
activity=Aktivite
activity.period.filter_label=Dönem:
@ -1726,6 +1762,8 @@ search.search_repo=Depo ara
search.fuzzy=Belirsiz
search.match=Eşleştir
search.results="%s" için <a href="%s">%s</a> içinde sonuçları ara
search.code_no_results=Arama teriminizle eşleşen bir kaynak kod bulunamadı.
search.code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin.
settings=Ayarlar
settings.desc=Ayarlar, depo için ayarları yönetebileceğiniz yerdir
@ -1737,7 +1775,7 @@ settings.collaboration.read=Oku
settings.collaboration.owner=Sahibi
settings.collaboration.undefined=Belirsiz
settings.hooks=Web İstemcileri
settings.githooks=Git İstekleri
settings.githooks=Git İstemcileri
settings.basic_settings=Temel Ayarlar
settings.mirror_settings=Yansıma Ayarları
settings.mirror_settings.docs=Projenizi, değişiklikleri başka bir depoya/depodan otomatik olarak gönderecek ve/veya çekecek şekilde ayarlayın. Dallar, etiketler ve işlemeler otomatik olarak senkronize edilecektir. <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/repo-mirror/">Depoları nasıl yansıtrım?</a>
@ -1772,6 +1810,9 @@ settings.tracker_url_format_error=Harici konu izleyici URL biçimi geçerli bir
settings.tracker_issue_style=Harici Konu İzleyici Numara Biçimi
settings.tracker_issue_style.numeric=Sayısal
settings.tracker_issue_style.alphanumeric=Alfanumerik
settings.tracker_issue_style.regexp=Düzenli ifade
settings.tracker_issue_style.regexp_pattern=Düzenli İfade Kalıbı
settings.tracker_issue_style.regexp_pattern_desc=<code>{index}</code> yerine ilk eşleşen grup kullanılacaktır.
settings.tracker_url_format_desc=Kullanıcı adı, depo adı ve yayın dizini için <code>{user}</code>, <code>{repo}</code> ve <code>{index}</code> yer tutucularını kullanın.
settings.enable_timetracker=Zaman Takibini Etkinleştir
settings.allow_only_contributors_to_track_time=Sadece Katkıcılar İçin Zaman Takibine İzin Ver
@ -1783,10 +1824,18 @@ settings.pulls.allow_rebase_merge_commit=Açık birleştirme işlemeleri ile Yen
settings.pulls.allow_squash_commits=İşlemeleri Birleştirmek için Ezmeyi Etkinleştir
settings.pulls.allow_manual_merge=Dİ'yi elle birleştirilmiş olarak işaretlemeyi etkinleştir
settings.pulls.enable_autodetect_manual_merge=Kendiliğinden algılamalı elle birleştirmeyi etkinleştir (Not: Bazı özel durumlarda yanlış kararlar olabilir)
settings.pulls.allow_rebase_update=Değişiklik isteği dalının yeniden yapılandırmayla güncellenmesine izin ver
settings.pulls.default_delete_branch_after_merge=Varsayılan olarak birleştirmeden sonra değişiklik isteği dalını sil
settings.packages_desc=Depo Paket Kütüğünü Etkinleştir
settings.projects_desc=Depo Projelerini Etkinleştir
settings.admin_settings=Yönetici Ayarları
settings.admin_enable_health_check=Depo Sağlık Kontrollerini Etkinleştir (git fsck)
settings.admin_code_indexer=Kod Dizinleyici
settings.admin_stats_indexer=Kod İstatistiği Dizinleyici
settings.admin_indexer_commit_sha=Son Dizinlenen SHA
settings.admin_indexer_unindexed=Dizinlenmemiş
settings.reindex_button=Yeniden Dizinleme Kuyruğuna Ekle
settings.reindex_requested=Yeniden Dizinleme İstendi
settings.admin_enable_close_issues_via_commit_in_any_branch=Varsayılan olmayan bir dalda yapılan bir işlemeyle konuyu kapat
settings.danger_zone=Tehlike Alanı
settings.new_owner_has_same_repo=Yeni sahibin aynı isimde başka bir deposu var. Lütfen farklı bir isim seçin.
@ -1875,6 +1924,9 @@ settings.webhook.response=Cevaplar
settings.webhook.headers=Başlıklar
settings.webhook.payload=İçerik
settings.webhook.body=Gövde
settings.webhook.replay.description=Bu web kancasını tekrar çalıştır.
settings.webhook.delivery.success=Teslim kuyruğuna bir olay eklendi. Teslim geçmişinde görünmesi birkaç saniye alabilir.
settings.githooks_desc=Git İstemcileri Git'in kendisi tarafından desteklenmektedir. Özel işlemler ayarlamak için aşağıdaki istemci dosyalarını düzenleyebilirsiniz.
settings.githook_edit_desc=İstek aktif değilse örnek içerik sunulacaktır. İçeriği boş bırakmak, isteği devre dışı bırakmayı beraberinde getirecektir.
settings.githook_name=İstek İsmi
settings.githook_content=İstek İçeriği
@ -1886,6 +1938,7 @@ settings.content_type=POST İçerik Türü
settings.secret=Gizli
settings.slack_username=Kullanıcı Adı
settings.slack_icon_url=Simge Bağlantısı
settings.slack_color=Renk
settings.discord_username=Kullanıcı adı
settings.discord_icon_url=Simge URL'si
settings.event_desc=Tetikleyici Açık:
@ -1946,6 +1999,7 @@ settings.hook_type=İstek Türü
settings.slack_token=Erişim Anahtarı
settings.slack_domain=Alan Adı
settings.slack_channel=Kanal
settings.add_web_hook_desc=<a target="_blank" rel="noreferrer" href="%s">%s</a> web kancasını deponuza ekleyin.
settings.web_hook_name_gitea=Gitea
settings.web_hook_name_gogs=Gogs
settings.web_hook_name_slack=Slack
@ -2492,6 +2546,18 @@ users.purge_help=Kullanıcıyı ve sahip olduğu herhangi bir depoyu, organizasy
users.still_own_packages=Kullanıcının bir veya daha fazla paketi var. Önce bu paketleri silin.
users.deletion_success=Kullanıcı hesabı silindi.
users.reset_2fa=2FD'yi sıfırla
users.list_status_filter.menu_text=Filtre
users.list_status_filter.reset=Sıfırla
users.list_status_filter.is_active=Etkin
users.list_status_filter.not_active=Etkin değil
users.list_status_filter.is_admin=Yönetici
users.list_status_filter.not_admin=Yönetici Değil
users.list_status_filter.is_restricted=Kısıtlanmış
users.list_status_filter.not_restricted=Kısıtlanmamış
users.list_status_filter.is_prohibit_login=Oturum Açmayı Önle
users.list_status_filter.not_prohibit_login=Oturum Açmaya İzin Ver
users.list_status_filter.is_2fa_enabled=2FA Etkin
users.list_status_filter.not_2fa_enabled=2FA Devre Dışı
emails.email_manage_panel=Kullanıcı E-posta Yönetimi
emails.primary=Birincil
@ -2524,6 +2590,16 @@ repos.forks=Çatallar
repos.issues=Konular
repos.size=Boyut
packages.package_manage_panel=Paket Yönetimi
packages.total_size=Toplam Boyut: %s
packages.owner=Sahibi
packages.creator=Oluşturan
packages.name=İsim
packages.version=Sürüm
packages.type=Tür
packages.repository=Depo
packages.size=Boyut
packages.published=Yayınlandı
defaulthooks=Varsayılan Web İstemcileri
defaulthooks.desc=Web İstemcileri, belirli Gitea olayları tetiklendiğinde otomatik olarak HTTP POST isteklerini sunucuya yapar. Burada tanımlanan Web İstemcileri varsayılandır ve tüm yeni depolara kopyalanır. <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">web istemcileri kılavuzunda</a> daha fazla bilgi edinin.
@ -2567,9 +2643,13 @@ auths.filter=Kullanıcı Filtresi
auths.admin_filter=Yönetici Filtresi
auths.restricted_filter=Kısıtlı Süzgeç
auths.restricted_filter_helper=Hiçbir kullanıcıyı kısıtlı olarak ayarlamamak için boş bırakın. Yönetici Süzgeci ile eşleşmeyen tüm kullanıcıları kısıtlanmış olarak ayarlamak için yıldız işareti ('*') kullanın.
auths.verify_group_membership=LDAP'ta grup üyeliğini doğrula (atlamak için filtreyi boş bırakın)
auths.group_search_base=Grup Arama Tabanı DN
auths.group_attribute_list_users=Kullanıcı Listesi İçeren Grup Özelliği
auths.user_attribute_in_group=Grupta Listelenen Kullanıcı Özelliği
auths.map_group_to_team=LDAP gruplarını Organizasyon takımlarına eşle (atlamak için bu alanı boş bırakın)
auths.map_group_to_team_removal=Eğer kullanıcı ilişkili LDAP grubuna ait değilse, kullanıcıları eşleşmiş takımlardan çıkarın
auths.enable_ldap_groups=LDAP gruplarını etkinleştir
auths.ms_ad_sa=MS AD Arama Nitelikleri
auths.smtp_auth=SMTP Yetkilendirme Türü
auths.smtphost=SMTP Sunucusu
@ -2597,6 +2677,14 @@ auths.oauth2_emailURL=E-posta URL'si
auths.skip_local_two_fa=Yerel 2FA'yı atla
auths.skip_local_two_fa_helper=Bunu seçmediğinizde, 2FA ayarlamış olan yerel kullanıcıların, giriş yapabilmek için 2FA'yı yine de geçmeleri gerekiyor
auths.oauth2_tenant=Kiracı
auths.oauth2_scopes=Ek Kapsamlar
auths.oauth2_required_claim_name=Gerekli Talep İsmi
auths.oauth2_required_claim_name_helper=Bu ismi, bu kaynağa oturum açmayı bu isimdeki talebe sahip kullanıcıların girişiyle sınırlamak için ayarlayın
auths.oauth2_required_claim_value=Gerekli Talep Değeri
auths.oauth2_required_claim_value_helper=Bu değeri, bu kaynağa oturum açmayı bu isimdeki ve değerdeki talebe sahip kullanıcıların girişiyle sınırlamak için ayarlayın
auths.oauth2_group_claim_name=Talep ismi bu kaynak için grup isimlerini sağlıyor. (İsteğe bağlı)
auths.oauth2_admin_group=Yönetici kullanıcıları için Grup Talep değeri. (İsteğe bağlı, yukarıda talep ismine gerek duyar)
auths.oauth2_restricted_group=Kısıtlı kullanıcılar için Grup Talep değeri. (İsteğe bağlı, yukarıda talep ismine gerek duyar)
auths.enable_auto_register=Otomatik Kaydolmayı Etkinleştir
auths.sspi_auto_create_users=Kullanıcıları otomatik olarak oluştur
auths.sspi_auto_create_users_helper=SSPI kimlik doğrulama yönteminin ilk kez oturum açan kullanıcılar için otomatik olarak yeni hesaplar oluşturmasına izin ver
@ -2644,6 +2732,7 @@ config.app_ver=Gitea Sürümü
config.app_url=Gitea Taban URL'si
config.custom_conf=Yapılandırma Dosyası Yolu
config.custom_file_root_path=Özel Dosya Kök Yolu
config.domain=Sunucu Alan Adı
config.offline_mode=Yerel Kip
config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak
config.run_user=Şu Kullanıcı Olarak Çalıştır
@ -2659,6 +2748,7 @@ config.reverse_auth_user=Tersine Yetkilendirme Kullanıcısı
config.ssh_config=SSH Yapılandırması
config.ssh_enabled=Aktif
config.ssh_start_builtin_server=Yerleşik Sunucuyu Kullan
config.ssh_domain=SSH Sunucusu Alan Adı
config.ssh_port=Bağlantı Noktası
config.ssh_listen_port=Port'u Dinle
config.ssh_root_path=Kök Yol
@ -2709,13 +2799,19 @@ config.queue_length=Kuyruk Uzunluğu
config.deliver_timeout=Dağıtım Zaman Aşımı
config.skip_tls_verify=TLS Doğrulamasını Geç
config.mailer_config=Mailer Yapılandırması
config.mailer_enabled=Aktif
config.mailer_enable_helo=HELO'yu etkinleştir
config.mailer_name=İsim
config.mailer_protocol=Protokol
config.mailer_smtp_addr=SMTP Adresi
config.mailer_smtp_port=SMTP Portu
config.mailer_user=Kullanıcı
config.mailer_use_sendmail=Sendmail Kullan
config.mailer_sendmail_path=Sendmail Yolu
config.mailer_sendmail_args=Sendmail İçin İlave Değişkenler
config.mailer_sendmail_timeout=Sendmail Zaman Aşımı
config.mailer_use_dummy=Sahte
config.test_email_placeholder=E-posta (ör. test@example.com)
config.send_test_mail=Test E-postası Gönder
config.test_mail_failed='%s' adresine test e-postası gönderilemedi: %v
@ -2775,12 +2871,16 @@ monitor.next=Sonraki Zaman
monitor.previous=Önceki Zaman
monitor.execute_times=Çalıştırma
monitor.process=Çalışan Süreçler
monitor.stacktrace=Yığın izleme
monitor.goroutines=%d Gorutinleri
monitor.desc=ıklama
monitor.start=Başlangıç Zamanı
monitor.execute_time=Çalıştırma Zamanı
monitor.last_execution_result=Sonuç
monitor.process.cancel=İşlemi iptal et
monitor.process.cancel_desc=Bir işlemi iptal etmek veri kaybına neden olabilir
monitor.process.cancel_notices=İptal et: <strong>%s</strong>?
monitor.process.children=Çocuklar
monitor.queues=Kuyruklar
monitor.queue=Kuyruk: %s
monitor.queue.name=İsim
@ -2788,6 +2888,7 @@ monitor.queue.type=Tür
monitor.queue.exemplar=Örnek Türü
monitor.queue.numberworkers=Çalışan Sayısı
monitor.queue.maxnumberworkers=En Fazla Çalışan Sayısı
monitor.queue.numberinqueue=Kuyruktaki Sayı
monitor.queue.review=Yapılandırmayı İncele
monitor.queue.review_add=Çalışanları İncele/Ekle
monitor.queue.configuration=Başlangıç Yapılandırması
@ -2807,6 +2908,12 @@ monitor.queue.pool.flush.title=Kuyruk Temizleme
monitor.queue.pool.flush.desc=Temizleme, kuyruk boş olduğunda veya zaman aşımına uğradığında sona erecek bir işçi ekler.
monitor.queue.pool.flush.submit=Temizleme İşçisi Ekle
monitor.queue.pool.flush.added=%[1]s için Temizleme İşçisi eklendi
monitor.queue.pool.pause.title=Kuyruğu Duraklat
monitor.queue.pool.pause.desc=Kuyruğun duraklatılması veriyi işlemesini önleyecektir
monitor.queue.pool.pause.submit=Kuyruğu Duraklat
monitor.queue.pool.resume.title=Kuyruğu Sürdür
monitor.queue.pool.resume.desc=Bu kuyruğun çalışmasını sürdür
monitor.queue.pool.resume.submit=Kuyruğu Sürdür
monitor.queue.settings.title=Havuz Ayarları
monitor.queue.settings.desc=Havuzlar, çalışan kuyruğunun engellenmesine yanıt olarak dinamik bir şekilde büyür. Bu değişiklikler mevcut çalışan gruplarını etkilemeyecektir.
@ -2852,18 +2959,34 @@ notices.delete_success=Sistem bildirimleri silindi.
[action]
create_repo=depo <a href="%s">%s</a> oluşturuldu
rename_repo=<code>%[1]s</code> olan depo adını <a href="%[2]s">%[3]s</a> buna çevirdi
commit_repo=<a href="%[1]s">%[4]s</a> deposuna <a href="%[2]s">%[3]s</a> dalını gönderdi
create_issue=`<a href="%[1]s">%[3]s#%[2]s</a> konusunu açtı`
close_issue=`<a href="%[1]s">%[3]s#%[2]s</a> konusunu kapattı`
reopen_issue=`<a href="%[1]s">%[3]s#%[2]s</a> konusunu tekrar açtı`
create_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini oluşturdu`
close_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini kapattı`
reopen_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini yeniden açtı`
comment_issue=`<a href="%[1]s">%[3]s#%[2]s</a> konusuna yorum yaptı`
comment_pull=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğine yorum yaptı`
merge_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini birleştirdi`
transfer_repo=depo <code>%s</code> <a href="%s">%s</a>'a aktarıldı
push_tag=<a href="%[2]s">%[3]s</a> etiketini <a href="%[1]s">%[4]s</a> dalına gönderdi
delete_tag=%[2]s etiketi <a href="%[1]s">%[3]s</a> deposundan silindi
delete_branch=<a href="%[1]s">%[3]s</a> deposundan %[2]s dalı silindi
compare_branch=Karşılaştır
compare_commits=%d işlemeyi karşılaştır
compare_commits_general=İşlemeleri karşılaştır
mirror_sync_push=yansıdan <a href="%[1]s">%[4]s</a> deposundaki <a href="%[2]s">%[3]s</a> dalına işlemeleri eşitledi
mirror_sync_create=<a href="%[2]s">%[3]s</a> yeni referansını, <a href="%[1]s">%[4]s</a> olarak yansıdan eşledi
mirror_sync_delete=<a href="%[1]s">%[3]s</a> adresindeki <code>%[2]s</code> referansını eşitledi ve sildi
approve_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> değişiklik isteğini onayladı`
reject_pull_request=`<a href="%[1]s">%[3]s#%[2]s</a> için değişiklikler önerdi`
publish_release=`<a href="%[1]s">%[3]s</a> deposu için <a href="%[2]s"> "%[4]s" </a> sürümü yayınlandı`
review_dismissed=`<a href="%[1]s">%[3]s#%[2]s</a> için <b>%[4]s</b> yorumunu reddetti`
review_dismissed_reason=Sebep:
create_branch=<a href="%[1]s">%[4]s</a> deposunda <a href="%[2]s">%[3]s</a> dalını oluşturdu
starred_repo=<a href="%[1]s">%[2]s</a> deposuna yıldız bıraktı
watched_repo=<a href="%[1]s">%[2]s</a> deposunu izlemeye başladı
[tool]
ago=%s önce
@ -2924,10 +3047,15 @@ error.unit_not_allowed=Bu depo bölümüne erişme izniniz yok.
title=Paketler
desc=Depo paketlerini yönet.
empty=Henüz hiçbir paket yok.
empty.documentation=Paket kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview">belgeye</a> bakabilirsiniz.
empty.repo=Bir paket yüklediniz ama burada gösterilmiyor mu? <a href="%[1]s">Paket ayarları</a>na gidin ve bu depoya bağlantı verin.
filter.type=Tür
filter.type.all=Tümü
filter.no_result=Filtreniz herhangi bir sonuç döndürmedi.
filter.container.tagged=Etiketlenmiş
filter.container.untagged=Etiketlenmemiş
published_by=%[1]s, <a href="%[2]s">%[3]s</a> tarafından yayınlandı
published_by_in=%[1]s, <a href="%[2]s">%[3]s</a> tarafından <a href="%[4]s"><strong>%[5]s</strong></a> içerisinde yayınlanmış
installation=Kurulum
about=Bu paket hakkında
requirements=Gereksinimler
@ -2941,12 +3069,43 @@ assets=Varlıklar
versions=Sürümler
versions.on=ık
versions.view_all=Tümünü görüntüle
dependency.id=Kimlik
dependency.version=Sürüm
composer.registry=Bu kütüğü <code>~/.composer/config.json</code> dosyasında ayarlayın:
composer.install=Paketi Composer ile kurmak için, şu komutu çalıştırın:
composer.documentation=Composer kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/composer/">belgeye</a> bakabilirsiniz.
composer.dependencies=Bağımlılıklar
composer.dependencies.development=Geliştirme Bağımlılıkları
conan.details.repository=Depo
conan.registry=Bu kütüğü komut satırını kullanarak kurun:
conan.install=Conan ile paket kurmak için aşağıdaki komutu çalıştırın:
conan.documentation=Conan kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/conan/">belgeye</a> bakabilirsiniz.
container.details.type=Görüntü Türü
container.details.platform=Platform
container.details.repository_site=Depo Sitesi
container.details.documentation_site=Belge Sitesi
container.pull=Görüntüyü komut satırını kullanarak çekin:
container.documentation=Taşıyıcı kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/container/">belgeye</a> bakabilirsiniz.
container.multi_arch=İşletim Sistemi / Mimari
container.layers=Görüntü Katmanları
container.labels=Etiketler
container.labels.key=Anahtar
container.labels.value=Değer
generic.download=Paketi komut satırında indirin:
generic.documentation=Genel kütük hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/generic">belgeye</a> bakabilirsiniz.
helm.registry=Bu kütüğü komut satırını kullanarak kurun:
helm.install=Paketi kurmak için, aşağıdaki komutu çalıştırın:
helm.documentation=Helm kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">belgeye</a> bakabilirsiniz.
maven.registry=Bu kütüğü projenizdeki <code>pom.xml</code> dosyasında ayarlayın:
maven.install=Paketi kullanmak için aşağıdaki <code>dependencies</code> parçasını <code>pom.xml</code> dosyasınıza ekleyin:
maven.install2=Komut satırında çalıştırın:
maven.download=Bağımlılığı indirmek için, komut satırında çalıştırın:
maven.documentation=Maven kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/maven/">belgeye</a> bakabilirsiniz.
nuget.registry=Bu kütüğü komut satırını kullanarak kurun:
nuget.install=Paketi NuGet ile kurmak için, şu komutu çalıştırın:
nuget.documentation=NuGet kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/nuget/">belgeye</a> bakabilirsiniz.
nuget.dependency.framework=Hedef Çerçeve
npm.registry=Bu kütüğü projenizdeki <code>.npmrc</code> dosyasında ayarlayın:
npm.install=Paketi npm ile kurmak için, şu komutu çalıştırın:
npm.install2=veya paketi package.json dosyasına ekleyin:
npm.documentation=Npm kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/npm/">belgeye</a> bakabilirsiniz.
@ -2955,6 +3114,10 @@ npm.dependencies.development=Geliştirme Bağımlılıkları
npm.dependencies.peer=Eş Bağımlılıkları
npm.dependencies.optional=İsteğe Bağlı Bağımlılıklar
npm.details.tag=Etiket
pub.install=Paketi Dart ile kurmak için, şu komutu çalıştırın:
pub.documentation=Pub kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">belgeye</a> bakabilirsiniz.
pub.details.repository_site=Depo Sitesi
pub.details.documentation_site=Belge Sitesi
pypi.requires=Gereken Python
pypi.install=Paketi pip ile kurmak için, şu komutu çalıştırın:
pypi.documentation=PyPI kütüğü hakkında daha fazla bilgi için, <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">belgeye</a> bakabilirsiniz.

View file

@ -9,7 +9,7 @@ sign_out=退出
sign_up=注册
link_account=链接账户
register=注册
website=官方网站
website=网站
version=当前版本
powered_by=Powered by %s
page=页面
@ -20,7 +20,7 @@ active_stopwatch=活动时间跟踪器
create_new=创建…
user_profile_and_more=个人信息和配置
signed_in_as=已登录用户
enable_javascript=使用 JavaScript能使本网站更好的工作。
enable_javascript=使用 JavaScript 能使本网站更好的工作。
toc=目录
licenses=许可证
return_to_gitea=返回 Gitea
@ -179,6 +179,8 @@ log_root_path_helper=日志文件将写入此目录。
optional_title=可选设置
email_title=电子邮箱设置
smtp_addr=SMTP 主机地址
smtp_port=SMTP 端口
smtp_from=电子邮件发件人
smtp_from_helper=电子邮件地址 Gitea 将使用。输入一个普通的电子邮件地址或使用 "名称" <email@example.com> 格式。
mailer_user=SMTP 用户名
@ -798,6 +800,7 @@ email_notifications.enable=启用邮件通知
email_notifications.onmention=只在被提到时邮件通知
email_notifications.disable=停用邮件通知
email_notifications.submit=邮件通知设置
email_notifications.andyourown=和您自己的通知
visibility=用户可见性
visibility.public=公开
@ -931,6 +934,7 @@ form.name_pattern_not_allowed=仓库名称中不允许使用模式 "%s"。
need_auth=授权
migrate_options=迁移选项
migrate_service=迁移服务
migrate_options_mirror_helper=该仓库将是一个镜像
migrate_options_lfs=迁移 LFS 文件
migrate_options_lfs_endpoint.label=LFS 网址
migrate_options_lfs_endpoint.description=迁移将尝试使用你的 Git remote 来 <a target="_blank" rel="noopener noreferrer" href="%s">确定 LFS 服务器</a>。如果仓库 LFS 数据存储在其他位置,你还可以指定自定义网址。
@ -1059,6 +1063,7 @@ normal_view=普通视图
line=
lines=
editor.add_file=添加文件
editor.new_file=新建文件
editor.upload_file=上传文件
editor.edit_file=编辑文件
@ -1264,6 +1269,8 @@ issues.filter_milestone=里程碑筛选
issues.filter_milestone_no_select=所有里程碑
issues.filter_assignee=指派人筛选
issues.filter_assginee_no_select=所有指派成员
issues.filter_poster=作者
issues.filter_poster_no_select=所有作者
issues.filter_type=类型筛选
issues.filter_type.all_issues=所有工单
issues.filter_type.assigned_to_you=指派给您的
@ -1418,6 +1425,7 @@ issues.due_date_form_remove=删除
issues.due_date_not_writer=你需要仓库写入权限来修改工单到期时间。
issues.due_date_not_set=未设置到期时间。
issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s
issues.due_date_modified=将到期日从 %[2]s 修改为 %[1]s %[3]s
issues.due_date_remove=于 %[2]s 删除了到期时间 %[1]s
issues.due_date_overdue=过期
issues.due_date_invalid=到期日期无效或超出范围。请使用 'yyyy-mm-dd' 格式。
@ -1529,6 +1537,8 @@ pulls.remove_prefix=删除 <strong>%s</strong> 前缀
pulls.data_broken=此合并请求因为派生仓库信息缺失而中断。
pulls.files_conflicted=此合并请求有变更与目标分支冲突。
pulls.is_checking=正在进行合并冲突检测,请稍后再试。
pulls.is_ancestor=此分支已经包含在目标分支中,没有什么可以合并。
pulls.is_empty=此分支上的更改已经在目标分支上。这将是一个空提交。
pulls.required_status_check_failed=一些必要的检查没有成功
pulls.required_status_check_missing=缺少一些必要的检查。
pulls.required_status_check_administrator=作为管理员,您仍可合并此合并请求
@ -2203,7 +2213,7 @@ release.stable=稳定
release.compare=比较
release.edit=编辑
release.ahead.commits=<strong>%d</strong> 次提交
release.ahead.target=到 %s 自发布后
release.ahead.target=在此版本发布后被加入到 %s
release.source_code=源代码
release.new_subheader=版本发布组织项目的版本。
release.edit_subheader=版本发布组织项目的版本。
@ -2314,7 +2324,7 @@ form.create_org_not_allowed=此账号禁止创建组织
settings=组织设置
settings.options=组织
settings.full_name=组织全名
settings.website=官方网站
settings.website=网站
settings.location=所在地区
settings.permission=权限
settings.repoadminchangeteam=仓库管理员可以添加或移除团队的访问权限
@ -2531,6 +2541,8 @@ users.delete_account=删除帐户
users.cannot_delete_self=你不能删除自己
users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。
users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。
users.purge=清理用户
users.purge_help=强制删除用户和用户拥有的任何仓库、组织和软件包。所有评论也将被删除。
users.still_own_packages=此用户仍然拥有一个或多个软件包。请先删除这些软件包。
users.deletion_success=用户帐户已被删除。
users.reset_2fa=重置两步验证
@ -2787,13 +2799,19 @@ config.queue_length=队列长度
config.deliver_timeout=推送超时
config.skip_tls_verify=跳过 TLS 验证
config.mailer_config=Mailer 配置
config.mailer_enabled=启用服务
config.mailer_enable_helo=启用HELO
config.mailer_name=任务名称
config.mailer_protocol=协议
config.mailer_smtp_addr=SMTP 地址
config.mailer_smtp_port=SMTP 端口
config.mailer_user=发送者帐号
config.mailer_use_sendmail=使用 Sendmail
config.mailer_sendmail_path=Sendmail 路径
config.mailer_sendmail_args=Sendmail 的额外参数
config.mailer_sendmail_timeout=Sendmail 超时
config.mailer_use_dummy=Dummy
config.test_email_placeholder=电子邮址 (例如test@example.com)
config.send_test_mail=发送测试邮件
config.test_mail_failed=发送测试邮件至 '%s' 时失败:%v
@ -3030,6 +3048,7 @@ title=软件包
desc=管理仓库软件包。
empty=还没有软件包。
empty.documentation=关于软件包注册中心的更多信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview"> 文档 </a>。
empty.repo=您上传了一个包,但没有显示在这里吗?转到 <a href="%[1]s">包设置</a> 并将其链接到这个仓库中。
filter.type=类型
filter.type.all=所有
filter.no_result=您的过滤器没有产生任何结果。
@ -3095,6 +3114,10 @@ npm.dependencies.development=开发依赖
npm.dependencies.peer=Peer 依赖
npm.dependencies.optional=可选依赖
npm.details.tag=标签
pub.install=要使用 Dart 安装软件包,请运行以下命令:
pub.documentation=关于 Pub 注册中心的信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pub/">文档</a>。
pub.details.repository_site=仓库站点
pub.details.documentation_site=文档站点
pypi.requires=需要 Python
pypi.install=要使用 pip 安装软件包,请运行以下命令:
pypi.documentation=关于 PyPI 注册中心的信息,请参阅 <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">文档</a>。

1643
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,8 @@
},
"dependencies": {
"@claviska/jquery-minicolors": "2.3.6",
"@primer/octicons": "17.3.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-2",
"@primer/octicons": "17.4.0",
"add-asset-webpack-plugin": "2.0.1",
"css-loader": "6.7.1",
"dropzone": "6.0.0-beta.2",
@ -28,7 +29,7 @@
"monaco-editor-webpack-plugin": "7.0.1",
"pretty-ms": "8.0.0",
"sortablejs": "1.15.0",
"swagger-ui-dist": "4.13.0",
"swagger-ui-dist": "4.13.2",
"tippy.js": "6.3.7",
"tributejs": "5.1.3",
"uint8-to-base64": "0.2.0",
@ -37,22 +38,22 @@
"vue-calendar-heatmap": "0.8.4",
"vue-loader": "15.9.8",
"vue-template-compiler": "2.6.14",
"webpack": "5.73.0",
"webpack": "5.74.0",
"webpack-cli": "4.10.0",
"workbox-routing": "6.5.3",
"workbox-strategies": "6.5.3",
"workbox-routing": "6.5.4",
"workbox-strategies": "6.5.4",
"worker-loader": "3.0.8",
"wrap-ansi": "8.0.1"
},
"devDependencies": {
"@happy-dom/jest-environment": "6.0.4",
"@stoplight/spectral-cli": "6.4.1",
"eslint": "8.20.0",
"@stoplight/spectral-cli": "6.5.0",
"eslint": "8.21.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-sonarjs": "0.13.0",
"eslint-plugin-sonarjs": "0.14.0",
"eslint-plugin-unicorn": "43.0.2",
"eslint-plugin-vue": "9.2.0",
"eslint-plugin-vue": "9.3.0",
"jest": "28.1.3",
"jest-extended": "3.0.1",
"markdownlint-cli": "0.32.1",
@ -60,7 +61,7 @@
"stylelint": "14.9.1",
"stylelint-config-standard": "26.0.0",
"svgo": "2.8.0",
"updates": "13.1.2"
"updates": "13.1.4"
},
"browserslist": [
"defaults",

View file

@ -0,0 +1 @@
<svg viewBox="0 0 449 448" class="svg fontawesome-send" width="16" height="16" aria-hidden="true"><path d="M441 2.8c5.3 3.7 7.8 9.7 6.8 16l-64 384A16 16 0 0 1 368 416c-2 0-4-.5-6-1.3l-113.3-46.2-60.4 73.8c-3 3.7-7.6 5.7-12.3 5.7a16 16 0 0 1-16-16v-87.3L376 80 108.7 311.3 10 270.6a15.8 15.8 0 0 1-2-28.4l416-240c2.5-1.5 5.3-2.3 8-2.3 3.3 0 6.5 1 9 2.8z"/></svg>

After

Width:  |  Height:  |  Size: 361 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 24 24" class="svg gitea-exclamation" width="16" height="16" aria-hidden="true"><path d="M12 15.99a2 2 0 0 0 2-2V2.03a2 2 0 0 0-4 0v11.96a2 2 0 0 0 2 2zm0 7.98a2.5 2.5 0 1 0-2.5-2.5 2.5 2.5 0 0 0 2.5 2.5z"/></svg>

After

Width:  |  Height:  |  Size: 230 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 502.87 502.87" class="svg gitea-pub" width="16" height="16" aria-hidden="true"><defs><radialGradient id="gitea-pub__a" cx="251.42" cy="631.97" r="251.4" gradientTransform="translate(0 -380.56)" gradientUnits="userSpaceOnUse"><stop stop-color="#fff" stop-opacity=".1" offset="0"/><stop stop-color="#fff" stop-opacity="0" offset="1"/></radialGradient><style>.gitea-pub__cls-1{fill:#01579b}.gitea-pub__cls-2{fill:#40c4ff}.gitea-pub__cls-4{fill:#fff;opacity:.2;isolation:isolate}</style></defs><path class="gitea-pub__cls-1" d="m102.56 400.31-86-86C6.32 303.82 0 289 0 274.58c0-6.69 3.77-17.16 6.62-23.15L86 86Z"/><path class="gitea-pub__cls-2" d="m397 102.56-86-86C303.49 9 287.85 0 274.61 0c-11.38 0-22.55 2.29-29.76 6.62L86.07 86ZM205.11 502.87h208.44v-89.32l-155.5-49.65-142.26 49.65z"/><path d="M86 354c0 26.54 3.33 33.05 16.53 46.32l13.23 13.24h297.79L268 248.14 86 86Z" style="fill:#29b6f6"/><path class="gitea-pub__cls-1" d="M350.7 86H86l327.55 327.51h89.32V208.4L397 102.52C382.12 87.62 368.92 86 350.7 86Z"/><path class="gitea-pub__cls-4" d="M105.88 403.6c-13.23-13.27-16.52-26.36-16.52-49.6V89.32L86.07 86v268c0 23.25 0 29.69 19.81 49.61l9.91 9.91Z"/><path style="fill:#263238;opacity:.2;isolation:isolate" d="M499.58 205.11v205.11h-89.32l3.29 3.33h89.32V208.4z"/><path class="gitea-pub__cls-4" d="M397 102.56C380.61 86.14 367.19 86 347.41 86H86.07l3.29 3.29h258.05c9.87 0 34.79-1.66 49.61 13.24Z"/><path d="M499.58 205.11 397 102.56l-86-86C303.49 9 287.85 0 274.61 0c-11.38 0-22.55 2.29-29.76 6.62L86.07 86 6.65 251.43C3.81 257.46 0 267.92 0 274.58c0 14.45 6.36 29.2 16.52 39.7L95.83 393a92.42 92.42 0 0 0 6.73 7.32l3.29 3.29 9.9 9.91 86 86 3.29 3.29h208.4v-89.3h89.32V208.4Z" style="fill:url(#gitea-pub__a);opacity:.2;isolation:isolate"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-cache" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.5 5.724c.241.15.503.286.779.407C4.525 6.68 6.195 7 8 7c1.805 0 3.475-.32 4.722-.869.622-.274 1.172-.62 1.578-1.04.408-.426.7-.965.7-1.591s-.292-1.165-.7-1.59c-.406-.422-.956-.767-1.579-1.041C11.476.32 9.806 0 8 0 6.195 0 4.525.32 3.279.869c-.623.274-1.173.62-1.579 1.04-.408.426-.7.965-.7 1.591v9c0 .626.292 1.165.7 1.59.406.422.956.767 1.579 1.041C4.525 15.68 6.195 16 8 16c.45 0 .89-.02 1.317-.058a.75.75 0 1 0-.134-1.494c-.381.034-.777.052-1.183.052-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707-.224-.233-.282-.418-.282-.551v-2.276c.164.102.334.196.507.28 1.102.543 2.582.89 4.204.975a.75.75 0 0 0 .078-1.498c-1.476-.077-2.746-.392-3.62-.822C2.738 8.7 2.5 8.248 2.5 8V5.724zm0-2.224c0-.133.058-.318.282-.55.227-.237.592-.484 1.1-.708C4.899 1.795 6.354 1.5 8 1.5c1.647 0 3.102.295 4.117.742.51.224.874.47 1.101.707.224.233.282.418.282.551 0 .133-.058.318-.282.55-.227.237-.592.484-1.1.708C11.101 5.205 9.646 5.5 8 5.5c-1.647 0-3.102-.295-4.117-.742-.51-.224-.874-.47-1.101-.707-.224-.233-.282-.418-.282-.551z"/><path d="M14.49 7.582a.375.375 0 0 0-.66-.313l-3.625 4.625a.375.375 0 0 0 .295.606h2.127l-.619 2.922a.375.375 0 0 0 .666.304l3.125-4.125A.375.375 0 0 0 15.5 11h-1.778l.769-3.418z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-checkbox" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.5 2.75a.25.25 0 0 1 .25-.25h10.5a.25.25 0 0 1 .25.25v10.5a.25.25 0 0 1-.25.25H2.75a.25.25 0 0 1-.25-.25V2.75zM2.75 1A1.75 1.75 0 0 0 1 2.75v10.5c0 .966.784 1.75 1.75 1.75h10.5A1.75 1.75 0 0 0 15 13.25V2.75A1.75 1.75 0 0 0 13.25 1H2.75zm9.03 5.28a.75.75 0 0 0-1.06-1.06L6.75 9.19 5.28 7.72a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l4.5-4.5z"/></svg>

After

Width:  |  Height:  |  Size: 481 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-command-palette" width="16" height="16" aria-hidden="true"><path d="m6.354 8.04-4.773 4.773a.75.75 0 1 0 1.061 1.06L7.945 8.57a.75.75 0 0 0 0-1.06L2.642 2.206a.75.75 0 0 0-1.06 1.061L6.353 8.04zM8.75 11.5a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5z"/></svg>

After

Width:  |  Height:  |  Size: 305 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-git-merge-queue" width="16" height="16" aria-hidden="true"><path d="M3.75 4.5a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5z"/><path fill-rule="evenodd" d="M3 7.75a.75.75 0 0 1 1.5 0v2.878a2.251 2.251 0 1 1-1.5 0V7.75zm.75 5.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5z"/><path d="M8.75 5.75a1.25 1.25 0 1 1-2.5 0 1.25 1.25 0 0 1 2.5 0z"/><path fill-rule="evenodd" d="M14.5 8.25a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0zm-1.5 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0z"/></svg>

After

Width:  |  Height:  |  Size: 516 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-paperclip" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M12.212 3.02a1.75 1.75 0 0 0-2.478.003l-5.83 5.83a3.007 3.007 0 0 0-.88 2.127c0 .795.315 1.551.88 2.116.567.567 1.333.89 2.126.89.79 0 1.548-.321 2.116-.89l5.48-5.48a.75.75 0 0 1 1.061 1.06l-5.48 5.48a4.494 4.494 0 0 1-3.177 1.33c-1.2 0-2.345-.487-3.187-1.33a4.485 4.485 0 0 1-1.32-3.177c0-1.195.475-2.341 1.32-3.186l5.83-5.83a3.25 3.25 0 0 1 5.553 2.297c0 .863-.343 1.691-.953 2.301L7.439 12.39a2.01 2.01 0 0 1-1.416.593 2 2 0 0 1-1.412-.593 1.991 1.991 0 0 1 0-2.828l5.48-5.48a.75.75 0 0 1 1.06 1.06l-5.48 5.48a.491.491 0 0 0 0 .707.5.5 0 0 0 .352.154.509.509 0 0 0 .356-.154l5.833-5.827a1.755 1.755 0 0 0 0-2.481z"/></svg>

After

Width:  |  Height:  |  Size: 751 B

View file

@ -1 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-table" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v3.585a.746.746 0 0 1 0 .83v8.085A1.75 1.75 0 0 1 14.25 16H6.309a.748.748 0 0 1-1.118 0H1.75A1.75 1.75 0 0 1 0 14.25V6.165a.746.746 0 0 1 0-.83V1.75zM1.5 6.5v7.75c0 .138.112.25.25.25H5v-8H1.5zM5 5H1.5V1.75a.25.25 0 0 1 .25-.25H5V5zm1.5 1.5v8h7.75a.25.25 0 0 0 .25-.25V6.5h-8zm8-1.5h-8V1.5h7.75a.25.25 0 0 1 .25.25V5z"/></svg>
<svg viewBox="0 0 16 16" class="svg octicon-table" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75zM1.5 6.5v7.75c0 .138.112.25.25.25H5v-8H1.5zM5 5H1.5V1.75a.25.25 0 0 1 .25-.25H5V5zm1.5 1.5v8h7.75a.25.25 0 0 0 .25-.25V6.5h-8zm8-1.5h-8V1.5h7.75a.25.25 0 0 1 .25.25V5z"/></svg>

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 420 B

View file

@ -1 +1 @@
<svg viewBox="0 0 16 16" class="svg octicon-tasklist" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.5 2.75a.25.25 0 0 1 .25-.25h10.5a.25.25 0 0 1 .25.25v10.5a.25.25 0 0 1-.25.25H2.75a.25.25 0 0 1-.25-.25V2.75zM2.75 1A1.75 1.75 0 0 0 1 2.75v10.5c0 .966.784 1.75 1.75 1.75h10.5A1.75 1.75 0 0 0 15 13.25V2.75A1.75 1.75 0 0 0 13.25 1H2.75zm9.03 5.28a.75.75 0 0 0-1.06-1.06L6.75 9.19 5.28 7.72a.75.75 0 0 0-1.06 1.06l2 2a.75.75 0 0 0 1.06 0l4.5-4.5z"/></svg>
<svg viewBox="0 0 16 16" class="svg octicon-tasklist" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M2.5 3.5v3h3v-3h-3zM2 2a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1H2zm4.655 8.595a.75.75 0 0 1 0 1.06L4.03 14.28a.75.75 0 0 1-1.06 0l-1.5-1.5a.75.75 0 1 1 1.06-1.06l.97.97 2.095-2.095a.75.75 0 0 1 1.06 0zM9.75 2.5a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5zm0 5a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5zm0 5a.75.75 0 0 0 0 1.5h5.5a.75.75 0 0 0 0-1.5h-5.5z"/></svg>

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 518 B

View file

@ -21,6 +21,7 @@ import (
"code.gitea.io/gitea/routers/api/packages/maven"
"code.gitea.io/gitea/routers/api/packages/npm"
"code.gitea.io/gitea/routers/api/packages/nuget"
"code.gitea.io/gitea/routers/api/packages/pub"
"code.gitea.io/gitea/routers/api/packages/pypi"
"code.gitea.io/gitea/routers/api/packages/rubygems"
"code.gitea.io/gitea/services/auth"
@ -45,6 +46,7 @@ func Routes() *web.Route {
authMethods := []auth.Method{
&auth.OAuth2{},
&auth.Basic{},
&nuget.Auth{},
&conan.Auth{},
}
if setting.Service.EnableReverseProxyAuth {
@ -155,12 +157,15 @@ func Routes() *web.Route {
})
})
r.Group("/generic", func() {
r.Group("/{packagename}/{packageversion}/{filename}", func() {
r.Get("", generic.DownloadPackageFile)
r.Group("", func() {
r.Put("", generic.UploadPackage)
r.Delete("", generic.DeletePackage)
}, reqPackageAccess(perm.AccessModeWrite))
r.Group("/{packagename}/{packageversion}", func() {
r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage)
r.Group("/{filename}", func() {
r.Get("", generic.DownloadPackageFile)
r.Group("", func() {
r.Put("", generic.UploadPackage)
r.Delete("", generic.DeletePackageFile)
}, reqPackageAccess(perm.AccessModeWrite))
})
})
})
r.Group("/helm", func() {
@ -194,12 +199,26 @@ func Routes() *web.Route {
r.Group("/@{scope}/{id}", func() {
r.Get("", npm.PackageMetadata)
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
r.Group("/-/{version}/{filename}", func() {
r.Get("", npm.DownloadPackageFile)
r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
})
r.Group("/-rev/{revision}", func() {
r.Delete("", npm.DeletePackage)
r.Put("", npm.DeletePreview)
}, reqPackageAccess(perm.AccessModeWrite))
})
r.Group("/{id}", func() {
r.Get("", npm.PackageMetadata)
r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage)
r.Get("/-/{version}/{filename}", npm.DownloadPackageFile)
r.Group("/-/{version}/{filename}", func() {
r.Get("", npm.DownloadPackageFile)
r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion)
})
r.Group("/-rev/{revision}", func() {
r.Delete("", npm.DeletePackage)
r.Put("", npm.DeletePreview)
}, reqPackageAccess(perm.AccessModeWrite))
})
r.Group("/-/package/@{scope}/{id}/dist-tags", func() {
r.Get("", npm.ListPackageTags)
@ -216,6 +235,20 @@ func Routes() *web.Route {
}, reqPackageAccess(perm.AccessModeWrite))
})
})
r.Group("/pub", func() {
r.Group("/api/packages", func() {
r.Group("/versions/new", func() {
r.Get("", pub.RequestUpload)
r.Post("/upload", pub.UploadPackageFile)
r.Get("/finalize/{id}/{version}", pub.FinalizePackage)
}, reqPackageAccess(perm.AccessModeWrite))
r.Group("/{id}", func() {
r.Get("", pub.EnumeratePackageVersions)
r.Get("/files/{version}", pub.DownloadPackageFile)
r.Get("/{version}", pub.PackageVersionMetadata)
})
})
})
r.Group("/pypi", func() {
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)

View file

@ -312,6 +312,9 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met
return nil, err
}
// keep download count on overwrite
_pv.DownloadCount = pv.DownloadCount
if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil {
log.Error("Error inserting package: %v", err)
return nil, err

View file

@ -31,22 +31,16 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
// DownloadPackageFile serves the specific generic package.
func DownloadPackageFile(ctx *context.Context) {
packageName, packageVersion, filename, err := sanitizeParameters(ctx)
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
return
}
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
ctx,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeGeneric,
Name: packageName,
Version: packageVersion,
Name: ctx.Params("packagename"),
Version: ctx.Params("packageversion"),
},
&packages_service.PackageFileInfo{
Filename: filename,
Filename: ctx.Params("filename"),
},
)
if err != nil {
@ -65,9 +59,17 @@ func DownloadPackageFile(ctx *context.Context) {
// UploadPackage uploads the specific generic package.
// Duplicated packages get rejected.
func UploadPackage(ctx *context.Context) {
packageName, packageVersion, filename, err := sanitizeParameters(ctx)
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
packageName := ctx.Params("packagename")
filename := ctx.Params("filename")
if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) {
apiError(ctx, http.StatusBadRequest, errors.New("Invalid package name or filename"))
return
}
packageVersion := ctx.Params("packageversion")
if packageVersion != strings.TrimSpace(packageVersion) {
apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version"))
return
}
@ -88,7 +90,7 @@ func UploadPackage(ctx *context.Context) {
}
defer buf.Close()
_, _, err = packages_service.CreatePackageAndAddFile(
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
&packages_service.PackageCreationInfo{
PackageInfo: packages_service.PackageInfo{
Owner: ctx.Package.Owner,
@ -107,8 +109,8 @@ func UploadPackage(ctx *context.Context) {
},
)
if err != nil {
if err == packages_model.ErrDuplicatePackageVersion {
apiError(ctx, http.StatusBadRequest, err)
if err == packages_model.ErrDuplicatePackageFile {
apiError(ctx, http.StatusConflict, err)
return
}
apiError(ctx, http.StatusInternalServerError, err)
@ -120,19 +122,13 @@ func UploadPackage(ctx *context.Context) {
// DeletePackage deletes the specific generic package.
func DeletePackage(ctx *context.Context) {
packageName, packageVersion, _, err := sanitizeParameters(ctx)
if err != nil {
apiError(ctx, http.StatusBadRequest, err)
return
}
err = packages_service.RemovePackageVersionByNameAndVersion(
err := packages_service.RemovePackageVersionByNameAndVersion(
ctx.Doer,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeGeneric,
Name: packageName,
Version: packageVersion,
Name: ctx.Params("packagename"),
Version: ctx.Params("packageversion"),
},
)
if err != nil {
@ -144,21 +140,50 @@ func DeletePackage(ctx *context.Context) {
return
}
ctx.Status(http.StatusOK)
ctx.Status(http.StatusNoContent)
}
func sanitizeParameters(ctx *context.Context) (string, string, string, error) {
packageName := ctx.Params("packagename")
filename := ctx.Params("filename")
// DeletePackageFile deletes the specific file of a generic package.
func DeletePackageFile(ctx *context.Context) {
pv, pf, err := func() (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.Params("packagename"), ctx.Params("packageversion"))
if err != nil {
return nil, nil, err
}
if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) {
return "", "", "", errors.New("Invalid package name or filename")
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey)
if err != nil {
return nil, nil, err
}
return pv, pf, nil
}()
if err != nil {
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
apiError(ctx, http.StatusNotFound, err)
return
}
apiError(ctx, http.StatusInternalServerError, err)
return
}
packageVersion := strings.TrimSpace(ctx.Params("packageversion"))
if packageVersion == "" {
return "", "", "", errors.New("Invalid package version")
pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
return packageName, packageVersion, filename, nil
if len(pfs) == 1 {
if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
} else {
if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
}
ctx.Status(http.StatusNoContent)
}

Some files were not shown because too many files have changed in this diff Show more