diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 1b0255d198..9f9f6f27d1 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,12 +1,12 @@
{
"name": "Gitea DevContainer",
- "image": "mcr.microsoft.com/devcontainers/go:1.22-bullseye",
+ "image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm",
"features": {
// installs nodejs into container
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
- "ghcr.io/devcontainers/features/git-lfs:1.1.0": {},
+ "ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 265616baed..46efbcb194 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -70,10 +70,11 @@ modifies/go:
- any-glob-to-any-file:
- "**/*.go"
-modifies/js:
+modifies/frontend:
- changed-files:
- any-glob-to-any-file:
- "**/*.js"
+ - "**/*.ts"
- "**/*.vue"
docs-update-needed:
diff --git a/.github/workflows/pull-db-tests.yml b/.github/workflows/pull-db-tests.yml
index 246884f24b..22cb784245 100644
--- a/.github/workflows/pull-db-tests.yml
+++ b/.github/workflows/pull-db-tests.yml
@@ -198,7 +198,9 @@ jobs:
test-mssql:
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
needs: files-changed
- runs-on: ubuntu-latest
+ # specifying the version of ubuntu in use as mssql fails on newer kernels
+ # pending resolution from vendor
+ runs-on: ubuntu-20.04
services:
mssql:
image: mcr.microsoft.com/mssql/server:2017-latest
diff --git a/Dockerfile b/Dockerfile
index 6621dded9d..2a6b1dd6b7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
# Build stage
-FROM docker.io/library/golang:1.22-alpine3.20 AS build-env
+FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
diff --git a/Dockerfile.rootless b/Dockerfile.rootless
index 736cea5d05..26f02205a7 100644
--- a/Dockerfile.rootless
+++ b/Dockerfile.rootless
@@ -1,5 +1,5 @@
# Build stage
-FROM docker.io/library/golang:1.22-alpine3.20 AS build-env
+FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
ARG GOPROXY
ENV GOPROXY=${GOPROXY:-direct}
diff --git a/Makefile b/Makefile
index 0f72f97673..b9e940b248 100644
--- a/Makefile
+++ b/Makefile
@@ -23,12 +23,12 @@ SHASUM ?= shasum -a 256
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
COMMA := ,
-XGO_VERSION := go-1.22.x
+XGO_VERSION := go-1.23.x
AIR_PACKAGE ?= github.com/air-verse/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.7.0
-GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0
-GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.0
+GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
+GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.60.3
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
@@ -179,6 +179,7 @@ TEST_PGSQL_DBNAME ?= testgitea
TEST_PGSQL_USERNAME ?= postgres
TEST_PGSQL_PASSWORD ?= postgres
TEST_PGSQL_SCHEMA ?= gtestschema
+TEST_MINIO_ENDPOINT ?= minio:9000
TEST_MSSQL_HOST ?= mssql:1433
TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa
@@ -574,6 +575,7 @@ generate-ini-pgsql:
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
+ -e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
diff --git a/assets/go-licenses.json b/assets/go-licenses.json
index cebbe468d2..4b78a12030 100644
--- a/assets/go-licenses.json
+++ b/assets/go-licenses.json
@@ -149,6 +149,56 @@
"path": "github.com/anmitsu/go-shlex/LICENSE",
"licenseText": "Copyright (c) anmitsu \u003canmitsu.s@gmail.com\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
},
+ {
+ "name": "github.com/aws/aws-sdk-go-v2",
+ "path": "github.com/aws/aws-sdk-go-v2/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go-v2/credentials",
+ "path": "github.com/aws/aws-sdk-go-v2/credentials/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go-v2/internal/configsources",
+ "path": "github.com/aws/aws-sdk-go-v2/internal/configsources/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2",
+ "path": "github.com/aws/aws-sdk-go-v2/internal/endpoints/v2/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go-v2/internal/sync/singleflight",
+ "path": "github.com/aws/aws-sdk-go-v2/internal/sync/singleflight/LICENSE",
+ "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go-v2/service/codecommit",
+ "path": "github.com/aws/aws-sdk-go-v2/service/codecommit/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go",
+ "path": "github.com/aws/aws-sdk-go/LICENSE.txt",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
+ {
+ "name": "github.com/aws/aws-sdk-go/internal/sync/singleflight",
+ "path": "github.com/aws/aws-sdk-go/internal/sync/singleflight/LICENSE",
+ "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ },
+ {
+ "name": "github.com/aws/smithy-go",
+ "path": "github.com/aws/smithy-go/LICENSE",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n"
+ },
+ {
+ "name": "github.com/aws/smithy-go/internal/sync/singleflight",
+ "path": "github.com/aws/smithy-go/internal/sync/singleflight/LICENSE",
+ "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"
+ },
{
"name": "github.com/aymerick/douceur",
"path": "github.com/aymerick/douceur/LICENSE",
@@ -294,6 +344,11 @@
"path": "github.com/cespare/xxhash/v2/LICENSE.txt",
"licenseText": "Copyright (c) 2016 Caleb Spare\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
},
+ {
+ "name": "github.com/charmbracelet/git-lfs-transfer/transfer",
+ "path": "github.com/charmbracelet/git-lfs-transfer/transfer/LICENSE",
+ "licenseText": "MIT License\n\nCopyright (c) 2022-2023 Charmbracelet, Inc\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
+ },
{
"name": "github.com/chi-middleware/proxy",
"path": "github.com/chi-middleware/proxy/LICENSE",
@@ -414,6 +469,11 @@
"path": "github.com/fxamacker/cbor/v2/LICENSE",
"licenseText": "MIT License\n\nCopyright (c) 2019-present Faye Amacker\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
},
+ {
+ "name": "github.com/git-lfs/pktline",
+ "path": "github.com/git-lfs/pktline/LICENSE.md",
+ "licenseText": "MIT License\n\nCopyright (c) 2014- GitHub, Inc. and Git LFS contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\nNote that Git LFS uses components from other Go modules (included in `vendor/`)\nwhich are under different licenses. See those LICENSE files for details.\n"
+ },
{
"name": "github.com/gliderlabs/ssh",
"path": "github.com/gliderlabs/ssh/LICENSE",
@@ -489,6 +549,11 @@
"path": "github.com/go-git/go-git/v5/LICENSE",
"licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"{}\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright 2018 Sourced Technologies, S.L.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
},
+ {
+ "name": "github.com/go-ini/ini",
+ "path": "github.com/go-ini/ini/LICENSE",
+ "licenseText": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"[]\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n Copyright 2014 Unknwon\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
{
"name": "github.com/go-ldap/ldap/v3",
"path": "github.com/go-ldap/ldap/v3/LICENSE",
@@ -599,6 +664,11 @@
"path": "github.com/google/go-tpm/LICENSE",
"licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
},
+ {
+ "name": "github.com/google/licenseclassifier/v2",
+ "path": "github.com/google/licenseclassifier/v2/LICENSE",
+ "licenseText": "\n Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
+ },
{
"name": "github.com/google/pprof/profile",
"path": "github.com/google/pprof/profile/LICENSE",
@@ -849,6 +919,11 @@
"path": "github.com/modern-go/reflect2/LICENSE",
"licenseText": " Apache License\n Version 2.0, January 2004\n http://www.apache.org/licenses/\n\n TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n 1. Definitions.\n\n \"License\" shall mean the terms and conditions for use, reproduction,\n and distribution as defined by Sections 1 through 9 of this document.\n\n \"Licensor\" shall mean the copyright owner or entity authorized by\n the copyright owner that is granting the License.\n\n \"Legal Entity\" shall mean the union of the acting entity and all\n other entities that control, are controlled by, or are under common\n control with that entity. For the purposes of this definition,\n \"control\" means (i) the power, direct or indirect, to cause the\n direction or management of such entity, whether by contract or\n otherwise, or (ii) ownership of fifty percent (50%) or more of the\n outstanding shares, or (iii) beneficial ownership of such entity.\n\n \"You\" (or \"Your\") shall mean an individual or Legal Entity\n exercising permissions granted by this License.\n\n \"Source\" form shall mean the preferred form for making modifications,\n including but not limited to software source code, documentation\n source, and configuration files.\n\n \"Object\" form shall mean any form resulting from mechanical\n transformation or translation of a Source form, including but\n not limited to compiled object code, generated documentation,\n and conversions to other media types.\n\n \"Work\" shall mean the work of authorship, whether in Source or\n Object form, made available under the License, as indicated by a\n copyright notice that is included in or attached to the work\n (an example is provided in the Appendix below).\n\n \"Derivative Works\" shall mean any work, whether in Source or Object\n form, that is based on (or derived from) the Work and for which the\n editorial revisions, annotations, elaborations, or other modifications\n represent, as a whole, an original work of authorship. For the purposes\n of this License, Derivative Works shall not include works that remain\n separable from, or merely link (or bind by name) to the interfaces of,\n the Work and Derivative Works thereof.\n\n \"Contribution\" shall mean any work of authorship, including\n the original version of the Work and any modifications or additions\n to that Work or Derivative Works thereof, that is intentionally\n submitted to Licensor for inclusion in the Work by the copyright owner\n or by an individual or Legal Entity authorized to submit on behalf of\n the copyright owner. For the purposes of this definition, \"submitted\"\n means any form of electronic, verbal, or written communication sent\n to the Licensor or its representatives, including but not limited to\n communication on electronic mailing lists, source code control systems,\n and issue tracking systems that are managed by, or on behalf of, the\n Licensor for the purpose of discussing and improving the Work, but\n excluding communication that is conspicuously marked or otherwise\n designated in writing by the copyright owner as \"Not a Contribution.\"\n\n \"Contributor\" shall mean Licensor and any individual or Legal Entity\n on behalf of whom a Contribution has been received by Licensor and\n subsequently incorporated within the Work.\n\n 2. Grant of Copyright License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n copyright license to reproduce, prepare Derivative Works of,\n publicly display, publicly perform, sublicense, and distribute the\n Work and such Derivative Works in Source or Object form.\n\n 3. Grant of Patent License. Subject to the terms and conditions of\n this License, each Contributor hereby grants to You a perpetual,\n worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n (except as stated in this section) patent license to make, have made,\n use, offer to sell, sell, import, and otherwise transfer the Work,\n where such license applies only to those patent claims licensable\n by such Contributor that are necessarily infringed by their\n Contribution(s) alone or by combination of their Contribution(s)\n with the Work to which such Contribution(s) was submitted. If You\n institute patent litigation against any entity (including a\n cross-claim or counterclaim in a lawsuit) alleging that the Work\n or a Contribution incorporated within the Work constitutes direct\n or contributory patent infringement, then any patent licenses\n granted to You under this License for that Work shall terminate\n as of the date such litigation is filed.\n\n 4. Redistribution. You may reproduce and distribute copies of the\n Work or Derivative Works thereof in any medium, with or without\n modifications, and in Source or Object form, provided that You\n meet the following conditions:\n\n (a) You must give any other recipients of the Work or\n Derivative Works a copy of this License; and\n\n (b) You must cause any modified files to carry prominent notices\n stating that You changed the files; and\n\n (c) You must retain, in the Source form of any Derivative Works\n that You distribute, all copyright, patent, trademark, and\n attribution notices from the Source form of the Work,\n excluding those notices that do not pertain to any part of\n the Derivative Works; and\n\n (d) If the Work includes a \"NOTICE\" text file as part of its\n distribution, then any Derivative Works that You distribute must\n include a readable copy of the attribution notices contained\n within such NOTICE file, excluding those notices that do not\n pertain to any part of the Derivative Works, in at least one\n of the following places: within a NOTICE text file distributed\n as part of the Derivative Works; within the Source form or\n documentation, if provided along with the Derivative Works; or,\n within a display generated by the Derivative Works, if and\n wherever such third-party notices normally appear. The contents\n of the NOTICE file are for informational purposes only and\n do not modify the License. You may add Your own attribution\n notices within Derivative Works that You distribute, alongside\n or as an addendum to the NOTICE text from the Work, provided\n that such additional attribution notices cannot be construed\n as modifying the License.\n\n You may add Your own copyright statement to Your modifications and\n may provide additional or different license terms and conditions\n for use, reproduction, or distribution of Your modifications, or\n for any such Derivative Works as a whole, provided Your use,\n reproduction, and distribution of the Work otherwise complies with\n the conditions stated in this License.\n\n 5. Submission of Contributions. Unless You explicitly state otherwise,\n any Contribution intentionally submitted for inclusion in the Work\n by You to the Licensor shall be under the terms and conditions of\n this License, without any additional terms or conditions.\n Notwithstanding the above, nothing herein shall supersede or modify\n the terms of any separate license agreement you may have executed\n with Licensor regarding such Contributions.\n\n 6. Trademarks. This License does not grant permission to use the trade\n names, trademarks, service marks, or product names of the Licensor,\n except as required for reasonable and customary use in describing the\n origin of the Work and reproducing the content of the NOTICE file.\n\n 7. Disclaimer of Warranty. Unless required by applicable law or\n agreed to in writing, Licensor provides the Work (and each\n Contributor provides its Contributions) on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n implied, including, without limitation, any warranties or conditions\n of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n PARTICULAR PURPOSE. You are solely responsible for determining the\n appropriateness of using or redistributing the Work and assume any\n risks associated with Your exercise of permissions under this License.\n\n 8. Limitation of Liability. In no event and under no legal theory,\n whether in tort (including negligence), contract, or otherwise,\n unless required by applicable law (such as deliberate and grossly\n negligent acts) or agreed to in writing, shall any Contributor be\n liable to You for damages, including any direct, indirect, special,\n incidental, or consequential damages of any character arising as a\n result of this License or out of the use or inability to use the\n Work (including but not limited to damages for loss of goodwill,\n work stoppage, computer failure or malfunction, or any and all\n other commercial damages or losses), even if such Contributor\n has been advised of the possibility of such damages.\n\n 9. Accepting Warranty or Additional Liability. While redistributing\n the Work or Derivative Works thereof, You may choose to offer,\n and charge a fee for, acceptance of support, warranty, indemnity,\n or other liability obligations and/or rights consistent with this\n License. However, in accepting such obligations, You may act only\n on Your own behalf and on Your sole responsibility, not on behalf\n of any other Contributor, and only if You agree to indemnify,\n defend, and hold each Contributor harmless for any liability\n incurred by, or claims asserted against, such Contributor by reason\n of your accepting any such warranty or additional liability.\n\n END OF TERMS AND CONDITIONS\n\n APPENDIX: How to apply the Apache License to your work.\n\n To apply the Apache License to your work, attach the following\n boilerplate notice, with the fields enclosed by brackets \"[]\"\n replaced with your own identifying information. (Don't include\n the brackets!) The text should be enclosed in the appropriate\n comment syntax for the file format. We also recommend that a\n file or class name and description of purpose be included on the\n same \"printed page\" as the copyright notice for easier\n identification within third-party archives.\n\n Copyright [yyyy] [name of copyright owner]\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
},
+ {
+ "name": "github.com/munnerz/goautoneg",
+ "path": "github.com/munnerz/goautoneg/LICENSE",
+ "licenseText": "Copyright (c) 2011, Open Knowledge Foundation Ltd.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n\n Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in\n the documentation and/or other materials provided with the\n distribution.\n\n Neither the name of the Open Knowledge Foundation Ltd. nor the\n names of its contributors may be used to endorse or promote\n products derived from this software without specific prior written\n permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nHOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ },
{
"name": "github.com/nektos/act/pkg",
"path": "github.com/nektos/act/pkg/LICENSE",
@@ -1142,12 +1217,12 @@
{
"name": "golang.org/x/mod/semver",
"path": "golang.org/x/mod/semver/LICENSE",
- "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
{
"name": "golang.org/x/net",
"path": "golang.org/x/net/LICENSE",
- "licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+ "licenseText": "Copyright 2009 The Go Authors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google LLC nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
{
"name": "golang.org/x/oauth2",
diff --git a/build/generate-licenses.go b/build/generate-licenses.go
index 9a111bc811..66e1d37755 100644
--- a/build/generate-licenses.go
+++ b/build/generate-licenses.go
@@ -1,3 +1,6 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
//go:build ignore
package main
@@ -5,6 +8,8 @@ package main
import (
"archive/tar"
"compress/gzip"
+ "crypto/md5"
+ "encoding/hex"
"flag"
"fmt"
"io"
@@ -15,6 +20,8 @@ import (
"path/filepath"
"strings"
+ "code.gitea.io/gitea/build/license"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/util"
)
@@ -77,7 +84,7 @@ func main() {
}
tr := tar.NewReader(gz)
-
+ aliasesFiles := make(map[string][]string)
for {
hdr, err := tr.Next()
@@ -97,26 +104,73 @@ func main() {
continue
}
- if strings.HasPrefix(filepath.Base(hdr.Name), "README") {
+ fileBaseName := filepath.Base(hdr.Name)
+ licenseName := strings.TrimSuffix(fileBaseName, ".txt")
+
+ if strings.HasPrefix(fileBaseName, "README") {
continue
}
- if strings.HasPrefix(filepath.Base(hdr.Name), "deprecated_") {
+ if strings.HasPrefix(fileBaseName, "deprecated_") {
continue
}
- out, err := os.Create(path.Join(destination, strings.TrimSuffix(filepath.Base(hdr.Name), ".txt")))
+ out, err := os.Create(path.Join(destination, licenseName))
if err != nil {
log.Fatalf("Failed to create new file. %s", err)
}
defer out.Close()
- if _, err := io.Copy(out, tr); err != nil {
+ // some license files have same content, so we need to detect these files and create a convert map into a json file
+ // Later we use this convert map to avoid adding same license content with different license name
+ h := md5.New()
+ // calculate md5 and write file in the same time
+ r := io.TeeReader(tr, h)
+ if _, err := io.Copy(out, r); err != nil {
log.Fatalf("Failed to write new file. %s", err)
} else {
fmt.Printf("Written %s\n", out.Name())
+
+ md5 := hex.EncodeToString(h.Sum(nil))
+ aliasesFiles[md5] = append(aliasesFiles[md5], licenseName)
}
}
+ // generate convert license name map
+ licenseAliases := make(map[string]string)
+ for _, fileNames := range aliasesFiles {
+ if len(fileNames) > 1 {
+ licenseName := license.GetLicenseNameFromAliases(fileNames)
+ if licenseName == "" {
+ // license name should not be empty as expected
+ // if it is empty, we need to rewrite the logic of GetLicenseNameFromAliases
+ log.Fatalf("GetLicenseNameFromAliases: license name is empty")
+ }
+ for _, fileName := range fileNames {
+ licenseAliases[fileName] = licenseName
+ }
+ }
+ }
+ // save convert license name map to file
+ b, err := json.Marshal(licenseAliases)
+ if err != nil {
+ log.Fatalf("Failed to create json bytes. %s", err)
+ }
+
+ licenseAliasesDestination := filepath.Join(destination, "etc", "license-aliases.json")
+ if err := os.MkdirAll(filepath.Dir(licenseAliasesDestination), 0o755); err != nil {
+ log.Fatalf("Failed to create directory for license aliases json file. %s", err)
+ }
+
+ f, err := os.Create(licenseAliasesDestination)
+ if err != nil {
+ log.Fatalf("Failed to create license aliases json file. %s", err)
+ }
+ defer f.Close()
+
+ if _, err = f.Write(b); err != nil {
+ log.Fatalf("Failed to write license aliases json file. %s", err)
+ }
+
fmt.Println("Done")
}
diff --git a/build/license/aliasgenerator.go b/build/license/aliasgenerator.go
new file mode 100644
index 0000000000..7de1e6fbd6
--- /dev/null
+++ b/build/license/aliasgenerator.go
@@ -0,0 +1,41 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package license
+
+import "strings"
+
+func GetLicenseNameFromAliases(fnl []string) string {
+ if len(fnl) == 0 {
+ return ""
+ }
+
+ shortestItem := func(list []string) string {
+ s := list[0]
+ for _, l := range list[1:] {
+ if len(l) < len(s) {
+ s = l
+ }
+ }
+ return s
+ }
+ allHasPrefix := func(list []string, s string) bool {
+ for _, l := range list {
+ if !strings.HasPrefix(l, s) {
+ return false
+ }
+ }
+ return true
+ }
+
+ sl := shortestItem(fnl)
+ slv := strings.Split(sl, "-")
+ var result string
+ for i := len(slv); i >= 0; i-- {
+ result = strings.Join(slv[:i], "-")
+ if allHasPrefix(fnl, result) {
+ return result
+ }
+ }
+ return ""
+}
diff --git a/build/license/aliasgenerator_test.go b/build/license/aliasgenerator_test.go
new file mode 100644
index 0000000000..239181b736
--- /dev/null
+++ b/build/license/aliasgenerator_test.go
@@ -0,0 +1,39 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package license
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGetLicenseNameFromAliases(t *testing.T) {
+ tests := []struct {
+ target string
+ inputs []string
+ }{
+ {
+ // real case which you can find in license-aliases.json
+ target: "AGPL-1.0",
+ inputs: []string{
+ "AGPL-1.0-only",
+ "AGPL-1.0-or-late",
+ },
+ },
+ {
+ target: "",
+ inputs: []string{
+ "APSL-1.0",
+ "AGPL-1.0-only",
+ "AGPL-1.0-or-late",
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ result := GetLicenseNameFromAliases(tt.inputs)
+ assert.Equal(t, result, tt.target)
+ }
+}
diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go
index f328b753d8..106d14b25a 100644
--- a/cmd/admin_user_create.go
+++ b/cmd/admin_user_create.go
@@ -158,7 +158,7 @@ func runCreateUser(c *cli.Context) error {
IsRestricted: restricted,
}
- if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
+ if err := user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
return fmt.Errorf("CreateUser: %w", err)
}
diff --git a/cmd/hook.go b/cmd/hook.go
index e8a8b1f4ad..11d0d072c9 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -542,14 +542,14 @@ Gitea or set your environment appropriately.`, "")
index := bytes.IndexByte(rs.Data, byte(0))
if index >= len(rs.Data) {
- return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
+ return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
if index < 0 {
if len(rs.Data) == 10 && rs.Data[9] == '\n' {
index = 9
} else {
- return fail(ctx, "Protocol: format error", "pkt-line: format error "+fmt.Sprint(rs.Data))
+ return fail(ctx, "Protocol: format error", "pkt-line: format error %s", rs.Data)
}
}
diff --git a/cmd/serv.go b/cmd/serv.go
index 2bfd111061..2d2df8aa23 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -20,8 +20,10 @@ import (
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/perm"
+ "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/lfstransfer"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/pprof"
"code.gitea.io/gitea/modules/private"
@@ -36,7 +38,11 @@ import (
)
const (
- lfsAuthenticateVerb = "git-lfs-authenticate"
+ verbUploadPack = "git-upload-pack"
+ verbUploadArchive = "git-upload-archive"
+ verbReceivePack = "git-receive-pack"
+ verbLfsAuthenticate = "git-lfs-authenticate"
+ verbLfsTransfer = "git-lfs-transfer"
)
// CmdServ represents the available serv sub-command.
@@ -73,12 +79,18 @@ func setup(ctx context.Context, debug bool) {
}
var (
- allowedCommands = map[string]perm.AccessMode{
- "git-upload-pack": perm.AccessModeRead,
- "git-upload-archive": perm.AccessModeRead,
- "git-receive-pack": perm.AccessModeWrite,
- lfsAuthenticateVerb: perm.AccessModeNone,
- }
+ // keep getAccessMode() in sync
+ allowedCommands = container.SetOf(
+ verbUploadPack,
+ verbUploadArchive,
+ verbReceivePack,
+ verbLfsAuthenticate,
+ verbLfsTransfer,
+ )
+ allowedCommandsLfs = container.SetOf(
+ verbLfsAuthenticate,
+ verbLfsTransfer,
+ )
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
)
@@ -124,6 +136,45 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
return nil
}
+func getAccessMode(verb, lfsVerb string) perm.AccessMode {
+ switch verb {
+ case verbUploadPack, verbUploadArchive:
+ return perm.AccessModeRead
+ case verbReceivePack:
+ return perm.AccessModeWrite
+ case verbLfsAuthenticate, verbLfsTransfer:
+ switch lfsVerb {
+ case "upload":
+ return perm.AccessModeWrite
+ case "download":
+ return perm.AccessModeRead
+ }
+ }
+ // should be unreachable
+ return perm.AccessModeNone
+}
+
+func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServCommandResults) (string, error) {
+ now := time.Now()
+ claims := lfs.Claims{
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
+ NotBefore: jwt.NewNumericDate(now),
+ },
+ RepoID: results.RepoID,
+ Op: lfsVerb,
+ UserID: results.UserID,
+ }
+ token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+
+ // Sign and get the complete encoded token as a string using the secret
+ tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
+ if err != nil {
+ return "", fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
+ }
+ return fmt.Sprintf("Bearer %s", tokenString), nil
+}
+
func runServ(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
@@ -143,6 +194,12 @@ func runServ(c *cli.Context) error {
return nil
}
+ defer func() {
+ if err := recover(); err != nil {
+ _ = fail(ctx, "Internal Server Error", "Panic: %v\n%s", err, log.Stack(2))
+ }
+ }()
+
keys := strings.Split(c.Args().First(), "-")
if len(keys) != 2 || keys[0] != "key" {
return fail(ctx, "Key ID format error", "Invalid key argument: %s", c.Args().First())
@@ -189,21 +246,9 @@ func runServ(c *cli.Context) error {
}
verb := words[0]
- repoPath := words[1]
- if repoPath[0] == '/' {
- repoPath = repoPath[1:]
- }
+ repoPath := strings.TrimPrefix(words[1], "/")
var lfsVerb string
- if verb == lfsAuthenticateVerb {
- if !setting.LFS.StartServer {
- return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
- }
-
- if len(words) > 2 {
- lfsVerb = words[2]
- }
- }
rr := strings.SplitN(repoPath, "/", 2)
if len(rr) != 2 {
@@ -240,53 +285,52 @@ func runServ(c *cli.Context) error {
}()
}
- requestedMode, has := allowedCommands[verb]
- if !has {
+ if allowedCommands.Contains(verb) {
+ if allowedCommandsLfs.Contains(verb) {
+ if !setting.LFS.StartServer {
+ return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
+ }
+ if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
+ return fail(ctx, "Unknown git command", "LFS SSH transfer connection denied, pure SSH protocol is disabled")
+ }
+ if len(words) > 2 {
+ lfsVerb = words[2]
+ }
+ }
+ } else {
return fail(ctx, "Unknown git command", "Unknown git command %s", verb)
}
- if verb == lfsAuthenticateVerb {
- if lfsVerb == "upload" {
- requestedMode = perm.AccessModeWrite
- } else if lfsVerb == "download" {
- requestedMode = perm.AccessModeRead
- } else {
- return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
- }
- }
+ requestedMode := getAccessMode(verb, lfsVerb)
results, extra := private.ServCommand(ctx, keyID, username, reponame, requestedMode, verb, lfsVerb)
if extra.HasError() {
return fail(ctx, extra.UserMsg, "ServCommand failed: %s", extra.Error)
}
+ // LFS SSH protocol
+ if verb == verbLfsTransfer {
+ token, err := getLFSAuthToken(ctx, lfsVerb, results)
+ if err != nil {
+ return err
+ }
+ return lfstransfer.Main(ctx, repoPath, lfsVerb, token)
+ }
+
// LFS token authentication
- if verb == lfsAuthenticateVerb {
+ if verb == verbLfsAuthenticate {
url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
- now := time.Now()
- claims := lfs.Claims{
- RegisteredClaims: jwt.RegisteredClaims{
- ExpiresAt: jwt.NewNumericDate(now.Add(setting.LFS.HTTPAuthExpiry)),
- NotBefore: jwt.NewNumericDate(now),
- },
- RepoID: results.RepoID,
- Op: lfsVerb,
- UserID: results.UserID,
- }
- token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
-
- // Sign and get the complete encoded token as a string using the secret
- tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
+ token, err := getLFSAuthToken(ctx, lfsVerb, results)
if err != nil {
- return fail(ctx, "Failed to sign JWT Token", "Failed to sign JWT token: %v", err)
+ return err
}
tokenAuthentication := &git_model.LFSTokenResponse{
Header: make(map[string]string),
Href: url,
}
- tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)
+ tokenAuthentication.Header["Authorization"] = token
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(tokenAuthentication)
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 0f70a1a3d0..7c7a43944f 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -306,6 +306,8 @@ RUN_USER = ; git
;; Enables git-lfs support. true or false, default is false.
;LFS_START_SERVER = false
;;
+;; Enables git-lfs SSH protocol support. true or false, default is false.
+;LFS_ALLOW_PURE_SSH = false
;;
;; LFS authentication secret, change this yourself
;LFS_JWT_SECRET =
@@ -507,6 +509,9 @@ INTERNAL_TOKEN =
;; stemming from cached/logged plain-text API tokens.
;; In future releases, this will become the default behavior
;DISABLE_QUERY_AUTH_TOKEN = false
+;;
+;; On user registration, record the IP address and user agent of the user to help identify potential abuse.
+;; RECORD_USER_SIGNUP_METADATA = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -523,7 +528,8 @@ INTERNAL_TOKEN =
;; HMAC to encode urls with, it **is required** if camo is enabled.
;HMAC_KEY =
;; Set to true to use camo for https too lese only non https urls are proxyed
-;ALLWAYS = false
+;; ALLWAYS is deprecated and will be removed in the future
+;ALWAYS = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1501,6 +1507,8 @@ LEVEL = Info
;; - manage_gpg_keys: a user cannot configure gpg keys
;; - manage_mfa: a user cannot configure mfa devices
;; - manage_credentials: a user cannot configure emails, passwords, or openid
+;; - change_username: a user cannot change their username
+;; - change_full_name: a user cannot change their full name
;;EXTERNAL_USER_DISABLE_FEATURES =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2692,7 +2700,7 @@ LEVEL = Info
;; It's always recommended to use compression when using local disk as log storage if CPU or memory is not a bottleneck.
;; And for object storage services like S3, which is billed for requests, it would cause extra 2 times of get requests for each log view.
;; But it will save storage space and network bandwidth, so it's still recommended to use compression.
-;LOG_COMPRESSION = none
+;LOG_COMPRESSION = zstd
;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
;ARTIFACT_RETENTION_DAYS = 90
;; Timeout to stop the task which have running status, but haven't been updated for a long time
diff --git a/go.mod b/go.mod
index 29126a70bc..d85553ac9f 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,11 @@
module code.gitea.io/gitea
-go 1.22
+go 1.23
+
+// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
+// But some CAs use negative serial number, just relax the check. related:
+// Default TLS cert uses negative serial number #895 https://github.com/microsoft/mssql-docker/issues/895
+godebug x509negativeserial=1
require (
code.gitea.io/actions-proto-go v0.4.0
@@ -23,10 +28,14 @@ require (
github.com/PuerkitoBio/goquery v1.9.2
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2
github.com/alecthomas/chroma/v2 v2.14.0
+ github.com/aws/aws-sdk-go v1.43.21
+ github.com/aws/aws-sdk-go-v2/credentials v1.17.30
+ github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
github.com/blevesearch/bleve/v2 v2.4.2
github.com/buildkite/terminal-to-html/v3 v3.12.1
github.com/caddyserver/certmagic v0.21.3
+ github.com/charmbracelet/git-lfs-transfer v0.2.0
github.com/chi-middleware/proxy v1.1.1
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
github.com/djherbis/buffer v1.2.0
@@ -59,6 +68,7 @@ require (
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-github/v61 v61.0.0
+ github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0
@@ -82,7 +92,7 @@ require (
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.26
github.com/microsoft/go-mssqldb v1.7.2
- github.com/minio/minio-go/v7 v7.0.71
+ github.com/minio/minio-go/v7 v7.0.77
github.com/msteinert/pam v1.2.0
github.com/nektos/act v0.2.63
github.com/niklasfasching/go-org v1.7.0
@@ -112,11 +122,11 @@ require (
github.com/yuin/goldmark-meta v1.1.0
golang.org/x/crypto v0.26.0
golang.org/x/image v0.18.0
- golang.org/x/net v0.26.0
+ golang.org/x/net v0.28.0
golang.org/x/oauth2 v0.21.0
- golang.org/x/sys v0.23.0
+ golang.org/x/sys v0.24.0
golang.org/x/text v0.17.0
- golang.org/x/tools v0.22.0
+ golang.org/x/tools v0.24.0
google.golang.org/grpc v1.62.1
google.golang.org/protobuf v1.34.2
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
@@ -146,6 +156,10 @@ require (
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
+ github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
+ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
+ github.com/aws/smithy-go v1.20.4 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect
@@ -185,6 +199,7 @@ require (
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
+ github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
github.com/go-ap/errors v0.0.0-20240304112515-6077fa9c17b0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect
@@ -192,6 +207,7 @@ require (
github.com/go-faster/errors v0.7.1 // indirect
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
+ github.com/go-ini/ini v1.67.0 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/inflect v0.21.0 // indirect
@@ -249,22 +265,24 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
github.com/mschoch/smat v0.2.0 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
+ github.com/onsi/gomega v1.33.1 // indirect
github.com/paulmach/orb v0.11.1 // indirect
- github.com/pelletier/go-toml/v2 v2.1.1 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_model v0.6.0 // indirect
- github.com/prometheus/common v0.50.0 // indirect
- github.com/prometheus/procfs v0.13.0 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.55.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
github.com/rhysd/actionlint v1.7.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
- github.com/rs/xid v1.5.0 // indirect
+ github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@@ -300,7 +318,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f // indirect
- golang.org/x/mod v0.18.0 // indirect
+ golang.org/x/mod v0.20.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
@@ -313,7 +331,9 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
-replace github.com/nektos/act => gitea.com/gitea/act v0.259.1
+replace github.com/nektos/act => gitea.com/gitea/act v0.261.3
+
+replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0
// TODO: This could be removed after https://github.com/mholt/archiver/pull/396 merged
replace github.com/mholt/archiver/v3 => github.com/anchore/archiver/v3 v3.5.2
diff --git a/go.sum b/go.sum
index db99b632fc..bb185e20c1 100644
--- a/go.sum
+++ b/go.sum
@@ -16,8 +16,10 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
-gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw=
-gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8=
+gitea.com/gitea/act v0.261.3 h1:BhiYpGJQKGq0XMYYICCYAN4KnsEWHyLbA6dxhZwFcV4=
+gitea.com/gitea/act v0.261.3/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
+gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40=
+gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g=
@@ -109,6 +111,20 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aws/aws-sdk-go v1.43.21 h1:E4S2eX3d2gKJyI/ISrcIrSwXwqjIvCK85gtBMt4sAPE=
+github.com/aws/aws-sdk-go v1.43.21/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
+github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
+github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1 h1:mOOALIM4JzhYkq3voCBbmZqmyEVEhHsfasMTbVxLkNs=
+github.com/aws/aws-sdk-go-v2/service/codecommit v1.25.1/go.mod h1:6zf5j3mIUXKM0s2iz5ttR2Qwq+o47D0jotpAyaKgZRA=
+github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
+github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -277,6 +293,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA=
github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 h1:mtDjlmloH7ytdblogrMz1/8Hqua1y8B4ID+bh3rvod0=
+github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
@@ -316,6 +334,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
@@ -421,6 +441,8 @@ github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/licenseclassifier/v2 v2.0.0 h1:1Y57HHILNf4m0ABuMVb6xk4vAJYEUO0gDxNpog0pyeA=
+github.com/google/licenseclassifier/v2 v2.0.0/go.mod h1:cOjbdH0kyC9R22sdQbYsFkto4NGCAc+ZSwbeThazEtM=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8 h1:ASJ/LAqdCHOyMYI+dwNxn7Rd8FscNkMyTr1KZU1JI/M=
github.com/google/pprof v0.0.0-20240618054019-d3b898a103f8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
@@ -504,6 +526,9 @@ github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LF
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jhillyerd/enmime v1.2.0 h1:dIu1IPEymQgoT2dzuB//ttA/xcV40NMPpQtmd4wslHk=
github.com/jhillyerd/enmime v1.2.0/go.mod h1:FRFuUPCLh8PByQv+8xRcLO9QHqaqTqreYhopv5eyk4I=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -586,8 +611,8 @@ github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.0.71 h1:No9XfOKTYi6i0GnBj+WZwD8WP5GZfL7n7GOjRqCdAjA=
-github.com/minio/minio-go/v7 v7.0.71/go.mod h1:4yBA8v80xGA30cfM3fz0DKYMXunWl/AV/6tWEs9ryzo=
+github.com/minio/minio-go/v7 v7.0.77 h1:GaGghJRg9nwDVlNbwYjSDJT1rqltQkBFDsypWX1v3Bw=
+github.com/minio/minio-go/v7 v7.0.77/go.mod h1:AVM3IUN6WwKzmwBxVdjzhH8xq+f57JSbbvzqvUzR6eg=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
@@ -611,6 +636,8 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/msteinert/pam v1.2.0 h1:mYfjlvN2KYs2Pb9G6nb/1f/nPfAttT/Jee5Sq9r3bGE=
github.com/msteinert/pam v1.2.0/go.mod h1:d2n0DCUK8rGecChV3JzvmsDjOY4R7AYbsNxAT+ftQl0=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
@@ -635,8 +662,8 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
-github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@@ -646,8 +673,8 @@ github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
-github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
@@ -666,12 +693,12 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
-github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
-github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
-github.com/prometheus/common v0.50.0 h1:YSZE6aa9+luNa2da6/Tik0q0A5AbR+U003TItK57CPQ=
-github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ=
-github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
-github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
+github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -694,8 +721,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
-github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
+github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -710,6 +737,7 @@ github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jN
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -752,6 +780,7 @@ github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -880,8 +909,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
-golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
+golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -891,6 +920,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
@@ -899,8 +929,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
-golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -948,8 +978,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
-golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -985,8 +1015,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
-golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/models/activities/action.go b/models/activities/action.go
index 532667d495..9b4ffd7725 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -452,13 +452,10 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
actions := make([]*Action, 0, opts.PageSize)
var count int64
+ opts.SetDefaultValues()
if opts.Page < 10 { // TODO: why it's 10 but other values? It's an experience value.
- sess := db.GetEngine(ctx).Where(cond).
- Select("`action`.*"). // this line will avoid select other joined table's columns
- Join("INNER", "repository", "`repository`.id = `action`.repo_id")
-
- opts.SetDefaultValues()
+ sess := db.GetEngine(ctx).Where(cond)
sess = db.SetSessionPagination(sess, &opts)
count, err = sess.Desc("`action`.created_unix").FindAndCount(&actions)
@@ -467,11 +464,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
}
} else {
// First, only query which IDs are necessary, and only then query all actions to speed up the overall query
- sess := db.GetEngine(ctx).Where(cond).
- Select("`action`.id").
- Join("INNER", "repository", "`repository`.id = `action`.repo_id")
-
- opts.SetDefaultValues()
+ sess := db.GetEngine(ctx).Where(cond).Select("`action`.id")
sess = db.SetSessionPagination(sess, &opts)
actionIDs := make([]int64, 0, opts.PageSize)
@@ -481,8 +474,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
count, err = db.GetEngine(ctx).Where(cond).
Table("action").
- Cols("`action`.id").
- Join("INNER", "repository", "`repository`.id = `action`.repo_id").Count()
+ Cols("`action`.id").Count()
if err != nil {
return nil, 0, fmt.Errorf("Count: %w", err)
}
diff --git a/models/activities/action_test.go b/models/activities/action_test.go
index 36a38c7863..e5dee33ae0 100644
--- a/models/activities/action_test.go
+++ b/models/activities/action_test.go
@@ -228,6 +228,8 @@ func TestNotifyWatchers(t *testing.T) {
}
func TestGetFeedsCorrupted(t *testing.T) {
+ // Now we will not check for corrupted data in the feeds
+ // users should run doctor to fix their data
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
@@ -241,8 +243,8 @@ func TestGetFeedsCorrupted(t *testing.T) {
IncludePrivate: true,
})
assert.NoError(t, err)
- assert.Len(t, actions, 0)
- assert.Equal(t, int64(0), count)
+ assert.Len(t, actions, 1)
+ assert.Equal(t, int64(1), count)
}
func TestConsistencyUpdateAction(t *testing.T) {
diff --git a/models/activities/repo_activity.go b/models/activities/repo_activity.go
index ba5e4959f0..3ffad035b7 100644
--- a/models/activities/repo_activity.go
+++ b/models/activities/repo_activity.go
@@ -34,6 +34,7 @@ type ActivityStats struct {
OpenedPRAuthorCount int64
MergedPRs issues_model.PullRequestList
MergedPRAuthorCount int64
+ ActiveIssues issues_model.IssueList
OpenedIssues issues_model.IssueList
OpenedIssueAuthorCount int64
ClosedIssues issues_model.IssueList
@@ -172,7 +173,7 @@ func (stats *ActivityStats) MergedPRPerc() int {
// ActiveIssueCount returns total active issue count
func (stats *ActivityStats) ActiveIssueCount() int {
- return stats.OpenedIssueCount() + stats.ClosedIssueCount()
+ return len(stats.ActiveIssues)
}
// OpenedIssueCount returns open issue count
@@ -285,13 +286,21 @@ func (stats *ActivityStats) FillIssues(ctx context.Context, repoID int64, fromTi
stats.ClosedIssueAuthorCount = count
// New issues
- sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false)
+ sess = newlyCreatedIssues(ctx, repoID, fromTime)
sess.OrderBy("issue.created_unix ASC")
stats.OpenedIssues = make(issues_model.IssueList, 0)
if err = sess.Find(&stats.OpenedIssues); err != nil {
return err
}
+ // Active issues
+ sess = activeIssues(ctx, repoID, fromTime)
+ sess.OrderBy("issue.created_unix ASC")
+ stats.ActiveIssues = make(issues_model.IssueList, 0)
+ if err = sess.Find(&stats.ActiveIssues); err != nil {
+ return err
+ }
+
// Opened issue authors
sess = issuesForActivityStatement(ctx, repoID, fromTime, false, false)
if _, err = sess.Select("count(distinct issue.poster_id) as `count`").Table("issue").Get(&count); err != nil {
@@ -317,6 +326,23 @@ func (stats *ActivityStats) FillUnresolvedIssues(ctx context.Context, repoID int
return sess.Find(&stats.UnresolvedIssues)
}
+func newlyCreatedIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
+ sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
+ And("issue.is_pull = ?", false). // Retain the is_pull check to exclude pull requests
+ And("issue.created_unix >= ?", fromTime.Unix()) // Include all issues created after fromTime
+
+ return sess
+}
+
+func activeIssues(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session {
+ sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
+ And("issue.is_pull = ?", false).
+ And("issue.created_unix >= ?", fromTime.Unix()).
+ Or("issue.closed_unix >= ?", fromTime.Unix())
+
+ return sess
+}
+
func issuesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time, closed, unresolved bool) *xorm.Session {
sess := db.GetEngine(ctx).Where("issue.repo_id = ?", repoID).
And("issue.is_closed = ?", closed)
diff --git a/models/admin/task.go b/models/admin/task.go
index c8bc95f981..10f8e6d570 100644
--- a/models/admin/task.go
+++ b/models/admin/task.go
@@ -179,27 +179,6 @@ func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {
return &task, nil
}
-// GetMigratingTaskByID returns the migrating task by repo's id
-func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) {
- task := Task{
- ID: id,
- DoerID: doerID,
- Type: structs.TaskTypeMigrateRepo,
- }
- has, err := db.GetEngine(ctx).Get(&task)
- if err != nil {
- return nil, nil, err
- } else if !has {
- return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type}
- }
-
- var opts migration.MigrateOptions
- if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil {
- return nil, nil, err
- }
- return &task, &opts, nil
-}
-
// CreateTask creates a task on database
func CreateTask(ctx context.Context, task *Task) error {
return db.Insert(ctx, task)
diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go
index 9c015582f1..28cb8f4e76 100644
--- a/models/asymkey/gpg_key_common.go
+++ b/models/asymkey/gpg_key_common.go
@@ -114,7 +114,7 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) {
return nil, err
}
if block.Type != openpgp.SignatureType {
- return nil, fmt.Errorf("expected '" + openpgp.SignatureType + "', got: " + block.Type)
+ return nil, fmt.Errorf("expected '%s', got: %s", openpgp.SignatureType, block.Type)
}
return block.Body, nil
}
@@ -139,7 +139,7 @@ func tryGetKeyIDFromSignature(sig *packet.Signature) string {
if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
return fmt.Sprintf("%016X", *sig.IssuerKeyId)
}
- if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
+ if len(sig.IssuerFingerprint) > 0 {
return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20])
}
return ""
diff --git a/models/db/sql_postgres_with_schema.go b/models/db/sql_postgres_with_schema.go
index ec63447f6f..64b61b2ef3 100644
--- a/models/db/sql_postgres_with_schema.go
+++ b/models/db/sql_postgres_with_schema.go
@@ -39,7 +39,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// golangci lint is incorrect here - there is no benefit to using driver.ExecerContext here
// and in any case pq does not implement it
- if execer, ok := conn.(driver.Execer); ok { //nolint
+ if execer, ok := conn.(driver.Execer); ok { //nolint:staticcheck
_, err := execer.Exec(`SELECT set_config(
'search_path',
$1 || ',' || current_setting('search_path'),
@@ -64,7 +64,7 @@ func (d *postgresSchemaDriver) Open(name string) (driver.Conn, error) {
// driver.String.ConvertValue will never return err for string
// golangci lint is incorrect here - there is no benefit to using stmt.ExecWithContext here
- _, err = stmt.Exec([]driver.Value{schemaValue}) //nolint
+ _, err = stmt.Exec([]driver.Value{schemaValue}) //nolint:staticcheck
if err != nil {
_ = conn.Close()
return nil, err
diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml
index 74fc716180..8fde386e22 100644
--- a/models/fixtures/comment.yml
+++ b/models/fixtures/comment.yml
@@ -83,3 +83,22 @@
issue_id: 2 # in repo_id 1
review_id: 20
created_unix: 946684810
+
+-
+ id: 10
+ type: 22 # review
+ poster_id: 5
+ issue_id: 3 # in repo_id 1
+ content: "reviewed by user5"
+ review_id: 21
+ created_unix: 946684816
+
+-
+ id: 11
+ type: 27 # review request
+ poster_id: 2
+ issue_id: 3 # in repo_id 1
+ content: "review request for user5"
+ review_id: 22
+ assignee_id: 5
+ created_unix: 946684817
diff --git a/models/fixtures/repo_license.yml b/models/fixtures/repo_license.yml
new file mode 100644
index 0000000000..ca780a73aa
--- /dev/null
+++ b/models/fixtures/repo_license.yml
@@ -0,0 +1 @@
+[] # empty
diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml
index 9adc6c855b..e141593f41 100644
--- a/models/fixtures/repository.yml
+++ b/models/fixtures/repository.yml
@@ -26,7 +26,7 @@
fork_id: 0
is_template: false
template_id: 0
- size: 7597
+ size: 8478
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false
diff --git a/models/fixtures/review.yml b/models/fixtures/review.yml
index ac97e24c2b..0438ceadae 100644
--- a/models/fixtures/review.yml
+++ b/models/fixtures/review.yml
@@ -179,3 +179,22 @@
content: "Review Comment"
updated_unix: 946684810
created_unix: 946684810
+
+-
+ id: 21
+ type: 2
+ reviewer_id: 5
+ issue_id: 3
+ content: "reviewed by user5"
+ commit_id: 4a357436d925b5c974181ff12a994538ddc5a269
+ updated_unix: 946684816
+ created_unix: 946684816
+
+-
+ id: 22
+ type: 4
+ reviewer_id: 5
+ issue_id: 3
+ content: "review request for user5"
+ updated_unix: 946684817
+ created_unix: 946684817
diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go
index 835ea1db52..c4515fd898 100644
--- a/models/issues/issue_project.go
+++ b/models/issues/issue_project.go
@@ -48,12 +48,12 @@ func (issue *Issue) ProjectColumnID(ctx context.Context) int64 {
}
// LoadIssuesFromColumn load issues assigned to this column
-func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueList, error) {
- issueList, err := Issues(ctx, &IssuesOptions{
- ProjectColumnID: b.ID,
- ProjectID: b.ProjectID,
- SortType: "project-column-sorting",
- })
+func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column, opts *IssuesOptions) (IssueList, error) {
+ issueList, err := Issues(ctx, opts.Copy(func(o *IssuesOptions) {
+ o.ProjectColumnID = b.ID
+ o.ProjectID = b.ProjectID
+ o.SortType = "project-column-sorting"
+ }))
if err != nil {
return nil, err
}
@@ -78,10 +78,10 @@ func LoadIssuesFromColumn(ctx context.Context, b *project_model.Column) (IssueLi
}
// LoadIssuesFromColumnList load issues assigned to the columns
-func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList) (map[int64]IssueList, error) {
+func LoadIssuesFromColumnList(ctx context.Context, bs project_model.ColumnList, opts *IssuesOptions) (map[int64]IssueList, error) {
issuesMap := make(map[int64]IssueList, len(bs))
for i := range bs {
- il, err := LoadIssuesFromColumn(ctx, bs[i])
+ il, err := LoadIssuesFromColumn(ctx, bs[i], opts)
if err != nil {
return nil, err
}
diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go
index e9f116bfc6..5948a67d4e 100644
--- a/models/issues/issue_search.go
+++ b/models/issues/issue_search.go
@@ -54,6 +54,19 @@ type IssuesOptions struct { //nolint
User *user_model.User // issues permission scope
}
+// Copy returns a copy of the options.
+// Be careful, it's not a deep copy, so `IssuesOptions.RepoIDs = {...}` is OK while `IssuesOptions.RepoIDs[0] = ...` is not.
+func (o *IssuesOptions) Copy(edit ...func(options *IssuesOptions)) *IssuesOptions {
+ if o == nil {
+ return nil
+ }
+ v := *o
+ for _, e := range edit {
+ e(&v)
+ }
+ return &v
+}
+
// applySorts sort an issues-related session based on the provided
// sortType string
func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 5fe95d56cc..b327ebc625 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -268,6 +268,10 @@ func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) {
return nil
}
+func (pr *PullRequest) IsAgitFlow() bool {
+ return pr.Flow == PullRequestFlowAGit
+}
+
// LoadHeadRepo loads the head repository, pr.HeadRepo will remain nil if it does not exist
// and thus ErrRepoNotExist will never be returned
func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) {
@@ -410,7 +414,7 @@ func (pr *PullRequest) getReviewedByLines(ctx context.Context, writer io.Writer)
// Note: This doesn't page as we only expect a very limited number of reviews
reviews, err := FindLatestReviews(ctx, FindReviewOptions{
- Type: ReviewTypeApprove,
+ Types: []ReviewType{ReviewTypeApprove},
IssueID: pr.IssueID,
OfficialOnly: setting.Repository.PullRequest.DefaultMergeMessageOfficialApproversOnly,
})
diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go
index f80a2284f0..9155ea0834 100644
--- a/models/issues/pull_list.go
+++ b/models/issues/pull_list.go
@@ -26,6 +26,7 @@ type PullRequestsOptions struct {
SortType string
Labels []int64
MilestoneID int64
+ PosterID int64
}
func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) *xorm.Session {
@@ -46,6 +47,10 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR
sess.And("issue.milestone_id=?", opts.MilestoneID)
}
+ if opts.PosterID > 0 {
+ sess.And("issue.poster_id=?", opts.PosterID)
+ }
+
return sess
}
diff --git a/models/issues/review.go b/models/issues/review.go
index 9a08e265ff..8b345e5fd8 100644
--- a/models/issues/review.go
+++ b/models/issues/review.go
@@ -247,7 +247,7 @@ func (r *Review) TooltipContent() string {
}
return "repo.issues.review.official"
case ReviewTypeComment:
- return "repo.issues.review.comment"
+ return "repo.issues.review.commented"
case ReviewTypeReject:
return "repo.issues.review.rejected"
case ReviewTypeRequest:
@@ -389,7 +389,7 @@ func GetCurrentReview(ctx context.Context, reviewer *user_model.User, issue *Iss
return nil, nil
}
reviews, err := FindReviews(ctx, FindReviewOptions{
- Type: ReviewTypePending,
+ Types: []ReviewType{ReviewTypePending},
IssueID: issue.ID,
ReviewerID: reviewer.ID,
})
diff --git a/models/issues/review_list.go b/models/issues/review_list.go
index 0ee28874ec..a5ceb21791 100644
--- a/models/issues/review_list.go
+++ b/models/issues/review_list.go
@@ -92,7 +92,7 @@ func (reviews ReviewList) LoadIssues(ctx context.Context) error {
// FindReviewOptions represent possible filters to find reviews
type FindReviewOptions struct {
db.ListOptions
- Type ReviewType
+ Types []ReviewType
IssueID int64
ReviewerID int64
OfficialOnly bool
@@ -107,8 +107,8 @@ func (opts *FindReviewOptions) toCond() builder.Cond {
if opts.ReviewerID > 0 {
cond = cond.And(builder.Eq{"reviewer_id": opts.ReviewerID})
}
- if opts.Type != ReviewTypeUnknown {
- cond = cond.And(builder.Eq{"type": opts.Type})
+ if len(opts.Types) > 0 {
+ cond = cond.And(builder.In("type", opts.Types))
}
if opts.OfficialOnly {
cond = cond.And(builder.Eq{"official": true})
diff --git a/models/issues/review_test.go b/models/issues/review_test.go
index ac1b84adeb..942121fd8f 100644
--- a/models/issues/review_test.go
+++ b/models/issues/review_test.go
@@ -63,7 +63,7 @@ func TestReviewType_Icon(t *testing.T) {
func TestFindReviews(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
- Type: issues_model.ReviewTypeApprove,
+ Types: []issues_model.ReviewType{issues_model.ReviewTypeApprove},
IssueID: 2,
ReviewerID: 1,
})
@@ -75,7 +75,7 @@ func TestFindReviews(t *testing.T) {
func TestFindLatestReviews(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
reviews, err := issues_model.FindLatestReviews(db.DefaultContext, issues_model.FindReviewOptions{
- Type: issues_model.ReviewTypeApprove,
+ Types: []issues_model.ReviewType{issues_model.ReviewTypeApprove},
IssueID: 11,
})
assert.NoError(t, err)
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index 13551423ce..f99718ead2 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -500,7 +500,7 @@ var migrations = []Migration{
// v259 -> v260
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
- // Gitea 1.20.0 ends at 260
+ // Gitea 1.20.0 ends at v260
// v260 -> v261
NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),
@@ -601,6 +601,8 @@ var migrations = []Migration{
NewMigration("Add metadata column for comment table", v1_23.AddCommentMetaDataColumn),
// v304 -> v305
NewMigration("Add index for release sha1", v1_23.AddIndexForReleaseSha1),
+ // v305 -> v306
+ NewMigration("Add Repository Licenses", v1_23.AddRepositoryLicenses),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_16/v189.go b/models/migrations/v1_16/v189.go
index afd93b0eac..5649645051 100644
--- a/models/migrations/v1_16/v189.go
+++ b/models/migrations/v1_16/v189.go
@@ -83,7 +83,7 @@ func UnwrapLDAPSourceCfg(x *xorm.Engine) error {
if err != nil {
return fmt.Errorf("failed to unmarshal %s: %w", source.Cfg, err)
}
- if wrapped.Source != nil && len(wrapped.Source) > 0 {
+ if len(wrapped.Source) > 0 {
bs, err := json.Marshal(wrapped.Source)
if err != nil {
return err
diff --git a/models/migrations/v1_23/v305.go b/models/migrations/v1_23/v305.go
new file mode 100644
index 0000000000..4d881192b2
--- /dev/null
+++ b/models/migrations/v1_23/v305.go
@@ -0,0 +1,23 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_23 //nolint
+
+import (
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func AddRepositoryLicenses(x *xorm.Engine) error {
+ type RepoLicense struct {
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"UNIQUE(s) NOT NULL"`
+ CommitID string
+ License string `xorm:"VARCHAR(255) UNIQUE(s) NOT NULL"`
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"`
+ }
+
+ return x.Sync(new(RepoLicense))
+}
diff --git a/models/organization/org_user.go b/models/organization/org_user.go
index 5fe3a178d2..1d3b2fab44 100644
--- a/models/organization/org_user.go
+++ b/models/organization/org_user.go
@@ -9,7 +9,9 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
+ "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/log"
"xorm.io/builder"
@@ -112,6 +114,49 @@ func IsUserOrgOwner(ctx context.Context, users user_model.UserList, orgID int64)
return results
}
+// GetOrgAssignees returns all users that have write access and can be assigned to issues
+// of the any repository in the organization.
+func GetOrgAssignees(ctx context.Context, orgID int64) (_ []*user_model.User, err error) {
+ e := db.GetEngine(ctx)
+ userIDs := make([]int64, 0, 10)
+ if err = e.Table("access").
+ Join("INNER", "repository", "`repository`.id = `access`.repo_id").
+ Where("`repository`.owner_id = ? AND `access`.mode >= ?", orgID, perm.AccessModeWrite).
+ Select("user_id").
+ Find(&userIDs); err != nil {
+ return nil, err
+ }
+
+ additionalUserIDs := make([]int64, 0, 10)
+ if err = e.Table("team_user").
+ Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
+ Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id").
+ Join("INNER", "repository", "`repository`.id = `team_repo`.repo_id").
+ Where("`repository`.owner_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))",
+ orgID, perm.AccessModeWrite, perm.AccessModeRead, unit.TypePullRequests).
+ Distinct("`team_user`.uid").
+ Select("`team_user`.uid").
+ Find(&additionalUserIDs); err != nil {
+ return nil, err
+ }
+
+ uniqueUserIDs := make(container.Set[int64])
+ uniqueUserIDs.AddMultiple(userIDs...)
+ uniqueUserIDs.AddMultiple(additionalUserIDs...)
+
+ users := make([]*user_model.User, 0, len(uniqueUserIDs))
+ if len(userIDs) > 0 {
+ if err = e.In("id", uniqueUserIDs.Values()).
+ Where(builder.Eq{"`user`.is_active": true}).
+ OrderBy(user_model.GetOrderByName()).
+ Find(&users); err != nil {
+ return nil, err
+ }
+ }
+
+ return users, nil
+}
+
func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*TeamUser, error) {
if len(users) == 0 {
return nil, nil
diff --git a/models/repo/license.go b/models/repo/license.go
new file mode 100644
index 0000000000..366b4598cc
--- /dev/null
+++ b/models/repo/license.go
@@ -0,0 +1,120 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "context"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/timeutil"
+)
+
+func init() {
+ db.RegisterModel(new(RepoLicense))
+}
+
+type RepoLicense struct { //revive:disable-line:exported
+ ID int64 `xorm:"pk autoincr"`
+ RepoID int64 `xorm:"UNIQUE(s) NOT NULL"`
+ CommitID string
+ License string `xorm:"VARCHAR(255) UNIQUE(s) NOT NULL"`
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX CREATED"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX UPDATED"`
+}
+
+// RepoLicenseList defines a list of repo licenses
+type RepoLicenseList []*RepoLicense //revive:disable-line:exported
+
+func (rll RepoLicenseList) StringList() []string {
+ var licenses []string
+ for _, rl := range rll {
+ licenses = append(licenses, rl.License)
+ }
+ return licenses
+}
+
+// GetRepoLicenses returns the license statistics for a repository
+func GetRepoLicenses(ctx context.Context, repo *Repository) (RepoLicenseList, error) {
+ licenses := make(RepoLicenseList, 0)
+ if err := db.GetEngine(ctx).Where("`repo_id` = ?", repo.ID).Asc("`license`").Find(&licenses); err != nil {
+ return nil, err
+ }
+ return licenses, nil
+}
+
+// UpdateRepoLicenses updates the license statistics for repository
+func UpdateRepoLicenses(ctx context.Context, repo *Repository, commitID string, licenses []string) error {
+ oldLicenses, err := GetRepoLicenses(ctx, repo)
+ if err != nil {
+ return err
+ }
+ for _, license := range licenses {
+ upd := false
+ for _, o := range oldLicenses {
+ // Update already existing license
+ if o.License == license {
+ if _, err := db.GetEngine(ctx).ID(o.ID).Cols("`commit_id`").Update(o); err != nil {
+ return err
+ }
+ upd = true
+ break
+ }
+ }
+ // Insert new license
+ if !upd {
+ if err := db.Insert(ctx, &RepoLicense{
+ RepoID: repo.ID,
+ CommitID: commitID,
+ License: license,
+ }); err != nil {
+ return err
+ }
+ }
+ }
+ // Delete old licenses
+ licenseToDelete := make([]int64, 0, len(oldLicenses))
+ for _, o := range oldLicenses {
+ if o.CommitID != commitID {
+ licenseToDelete = append(licenseToDelete, o.ID)
+ }
+ }
+ if len(licenseToDelete) > 0 {
+ if _, err := db.GetEngine(ctx).In("`id`", licenseToDelete).Delete(&RepoLicense{}); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// CopyLicense Copy originalRepo license information to destRepo (use for forked repo)
+func CopyLicense(ctx context.Context, originalRepo, destRepo *Repository) error {
+ repoLicenses, err := GetRepoLicenses(ctx, originalRepo)
+ if err != nil {
+ return err
+ }
+ if len(repoLicenses) > 0 {
+ newRepoLicenses := make(RepoLicenseList, 0, len(repoLicenses))
+
+ for _, rl := range repoLicenses {
+ newRepoLicense := &RepoLicense{
+ RepoID: destRepo.ID,
+ CommitID: rl.CommitID,
+ License: rl.License,
+ }
+ newRepoLicenses = append(newRepoLicenses, newRepoLicense)
+ }
+ if err := db.Insert(ctx, &newRepoLicenses); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// CleanRepoLicenses will remove all license record of the repo
+func CleanRepoLicenses(ctx context.Context, repo *Repository) error {
+ return db.DeleteBeans(ctx, &RepoLicense{
+ RepoID: repo.ID,
+ })
+}
diff --git a/models/repo/release.go b/models/repo/release.go
index 1643258301..7c66cbc1af 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -234,6 +234,7 @@ type FindReleasesOptions struct {
IsDraft optional.Option[bool]
TagNames []string
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
+ NamePattern optional.Option[string]
}
func (opts FindReleasesOptions) ToConds() builder.Cond {
@@ -261,6 +262,11 @@ func (opts FindReleasesOptions) ToConds() builder.Cond {
cond = cond.And(builder.Eq{"sha1": ""})
}
}
+
+ if opts.NamePattern.Has() && opts.NamePattern.Value() != "" {
+ cond = cond.And(builder.Like{"lower_tag_name", strings.ToLower(opts.NamePattern.Value())})
+ }
+
return cond
}
diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go
index e22d872ae4..1bffadbf0a 100644
--- a/models/repo/repo_list.go
+++ b/models/repo/repo_list.go
@@ -749,7 +749,7 @@ func GetUserRepositories(ctx context.Context, opts *SearchRepoOptions) (Reposito
cond = cond.And(builder.Eq{"is_private": false})
}
- if opts.LowerNames != nil && len(opts.LowerNames) > 0 {
+ if len(opts.LowerNames) > 0 {
cond = cond.And(builder.In("lower_name", opts.LowerNames))
}
diff --git a/models/user/search.go b/models/user/search.go
index 45b051187e..382b6fac2b 100644
--- a/models/user/search.go
+++ b/models/user/search.go
@@ -65,7 +65,19 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
builder.Like{"LOWER(full_name)", lowerKeyword},
)
if opts.SearchByEmail {
- keywordCond = keywordCond.Or(builder.Like{"LOWER(email)", lowerKeyword})
+ var emailCond builder.Cond
+ emailCond = builder.Like{"LOWER(email)", lowerKeyword}
+ if opts.Actor == nil {
+ emailCond = emailCond.And(builder.Eq{"keep_email_private": false})
+ } else if !opts.Actor.IsAdmin {
+ emailCond = emailCond.And(
+ builder.Or(
+ builder.Eq{"keep_email_private": false},
+ builder.Eq{"id": opts.Actor.ID},
+ ),
+ )
+ }
+ keywordCond = keywordCond.Or(emailCond)
}
cond = cond.And(keywordCond)
diff --git a/models/user/setting_keys.go b/models/user/setting_keys.go
index 72b3974eee..3149aae18b 100644
--- a/models/user/setting_keys.go
+++ b/models/user/setting_keys.go
@@ -14,4 +14,8 @@ const (
UserActivityPubPrivPem = "activitypub.priv_pem"
// UserActivityPubPubPem is user's public key
UserActivityPubPubPem = "activitypub.pub_pem"
+ // SignupIP is the IP address that the user signed up with
+ SignupIP = "signup.ip"
+ // SignupUserAgent is the user agent that the user signed up with
+ SignupUserAgent = "signup.user_agent"
)
diff --git a/models/user/user.go b/models/user/user.go
index 2a3c1833b9..d5c4833cde 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -150,6 +150,14 @@ type User struct {
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
}
+// Meta defines the meta information of a user, to be stored in the K/V table
+type Meta struct {
+ // Store the initial registration of the user, to aid in spam prevention
+ // Ensure that one IP isn't creating many accounts (following mediawiki approach)
+ InitialIP string
+ InitialUserAgent string
+}
+
func init() {
db.RegisterModel(new(User))
}
@@ -400,6 +408,10 @@ func (u *User) IsIndividual() bool {
return u.Type == UserTypeIndividual
}
+func (u *User) IsUser() bool {
+ return u.Type == UserTypeIndividual || u.Type == UserTypeBot
+}
+
// IsBot returns whether or not the user is of type bot
func (u *User) IsBot() bool {
return u.Type == UserTypeBot
@@ -615,17 +627,17 @@ type CreateUserOverwriteOptions struct {
}
// CreateUser creates record of a new user.
-func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
- return createUser(ctx, u, false, overwriteDefault...)
+func CreateUser(ctx context.Context, u *User, meta *Meta, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
+ return createUser(ctx, u, meta, false, overwriteDefault...)
}
// AdminCreateUser is used by admins to manually create users
-func AdminCreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
- return createUser(ctx, u, true, overwriteDefault...)
+func AdminCreateUser(ctx context.Context, u *User, meta *Meta, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
+ return createUser(ctx, u, meta, true, overwriteDefault...)
}
// createUser creates record of a new user.
-func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
+func createUser(ctx context.Context, u *User, meta *Meta, createdByAdmin bool, overwriteDefault ...*CreateUserOverwriteOptions) (err error) {
if err = IsUsableUsername(u.Name); err != nil {
return err
}
@@ -745,6 +757,22 @@ func createUser(ctx context.Context, u *User, createdByAdmin bool, overwriteDefa
return err
}
+ if setting.RecordUserSignupMetadata {
+ // insert initial IP and UserAgent
+ if err = SetUserSetting(ctx, u.ID, SignupIP, meta.InitialIP); err != nil {
+ return err
+ }
+
+ // trim user agent string to a reasonable length, if necessary
+ userAgent := strings.TrimSpace(meta.InitialUserAgent)
+ if len(userAgent) > 255 {
+ userAgent = userAgent[:255]
+ }
+ if err = SetUserSetting(ctx, u.ID, SignupUserAgent, userAgent); err != nil {
+ return err
+ }
+ }
+
// insert email address
if err := db.Insert(ctx, &EmailAddress{
UID: u.ID,
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 26cda3f89e..67efb3859f 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -227,7 +227,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
MustChangePassword: false,
}
- err := user_model.CreateUser(db.DefaultContext, user)
+ err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailCharIsNotSupported(err))
}
@@ -241,7 +241,7 @@ func TestCreateUserEmailAlreadyUsed(t *testing.T) {
user.Name = "testuser"
user.LowerName = strings.ToLower(user.Name)
user.ID = 0
- err := user_model.CreateUser(db.DefaultContext, user)
+ err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.Error(t, err)
assert.True(t, user_model.IsErrEmailAlreadyUsed(err))
}
@@ -258,7 +258,7 @@ func TestCreateUserCustomTimestamps(t *testing.T) {
user.ID = 0
user.Email = "unique@example.com"
user.CreatedUnix = creationTimestamp
- err := user_model.CreateUser(db.DefaultContext, user)
+ err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.NoError(t, err)
fetched, err := user_model.GetUserByID(context.Background(), user.ID)
@@ -283,7 +283,7 @@ func TestCreateUserWithoutCustomTimestamps(t *testing.T) {
user.Email = "unique@example.com"
user.CreatedUnix = 0
user.UpdatedUnix = 0
- err := user_model.CreateUser(db.DefaultContext, user)
+ err := user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{})
assert.NoError(t, err)
timestampEnd := time.Now().Unix()
diff --git a/modules/actions/task_state.go b/modules/actions/task_state.go
index 31a74be3fd..1f36e021a5 100644
--- a/modules/actions/task_state.go
+++ b/modules/actions/task_state.go
@@ -18,8 +18,32 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
return fullStepsOfEmptySteps(task)
}
- firstStep := task.Steps[0]
+ // firstStep is the first step that has run or running, not include preStep.
+ // For example,
+ // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): firstStep is step1.
+ // 2. preStep(Success) -> step1(Skipped) -> step2(Success) -> postStep(Success): firstStep is step2.
+ // 3. preStep(Success) -> step1(Running) -> step2(Waiting) -> postStep(Waiting): firstStep is step1.
+ // 4. preStep(Success) -> step1(Skipped) -> step2(Skipped) -> postStep(Skipped): firstStep is nil.
+ // 5. preStep(Success) -> step1(Cancelled) -> step2(Cancelled) -> postStep(Cancelled): firstStep is nil.
+ var firstStep *actions_model.ActionTaskStep
+ // lastHasRunStep is the last step that has run.
+ // For example,
+ // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
+ // 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
+ // 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
+ // So its Stopped is the Started of postStep when there are no more steps to run.
+ var lastHasRunStep *actions_model.ActionTaskStep
+
var logIndex int64
+ for _, step := range task.Steps {
+ if firstStep == nil && (step.Status.HasRun() || step.Status.IsRunning()) {
+ firstStep = step
+ }
+ if step.Status.HasRun() {
+ lastHasRunStep = step
+ }
+ logIndex += step.LogLength
+ }
preStep := &actions_model.ActionTaskStep{
Name: preStepName,
@@ -28,32 +52,17 @@ func FullSteps(task *actions_model.ActionTask) []*actions_model.ActionTaskStep {
Status: actions_model.StatusRunning,
}
- if firstStep.Status.HasRun() || firstStep.Status.IsRunning() {
+ // No step has run or is running, so preStep is equal to the task
+ if firstStep == nil {
+ preStep.Stopped = task.Stopped
+ preStep.Status = task.Status
+ } else {
preStep.LogLength = firstStep.LogIndex
preStep.Stopped = firstStep.Started
preStep.Status = actions_model.StatusSuccess
- } else if task.Status.IsDone() {
- preStep.Stopped = task.Stopped
- preStep.Status = actions_model.StatusFailure
- if task.Status.IsSkipped() {
- preStep.Status = actions_model.StatusSkipped
- }
}
logIndex += preStep.LogLength
- // lastHasRunStep is the last step that has run.
- // For example,
- // 1. preStep(Success) -> step1(Success) -> step2(Running) -> step3(Waiting) -> postStep(Waiting): lastHasRunStep is step1.
- // 2. preStep(Success) -> step1(Success) -> step2(Success) -> step3(Success) -> postStep(Success): lastHasRunStep is step3.
- // 3. preStep(Success) -> step1(Success) -> step2(Failure) -> step3 -> postStep(Waiting): lastHasRunStep is step2.
- // So its Stopped is the Started of postStep when there are no more steps to run.
- var lastHasRunStep *actions_model.ActionTaskStep
- for _, step := range task.Steps {
- if step.Status.HasRun() {
- lastHasRunStep = step
- }
- logIndex += step.LogLength
- }
if lastHasRunStep == nil {
lastHasRunStep = preStep
}
diff --git a/modules/actions/task_state_test.go b/modules/actions/task_state_test.go
index 28213d781b..ff0fd57195 100644
--- a/modules/actions/task_state_test.go
+++ b/modules/actions/task_state_test.go
@@ -137,6 +137,25 @@ func TestFullSteps(t *testing.T) {
{Name: postStepName, Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
},
},
+ {
+ name: "first step is skipped",
+ task: &actions_model.ActionTask{
+ Steps: []*actions_model.ActionTaskStep{
+ {Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+ },
+ Status: actions_model.StatusSuccess,
+ Started: 10000,
+ Stopped: 10100,
+ LogLength: 100,
+ },
+ want: []*actions_model.ActionTaskStep{
+ {Name: preStepName, Status: actions_model.StatusSuccess, LogIndex: 0, LogLength: 10, Started: 10000, Stopped: 10010},
+ {Status: actions_model.StatusSkipped, LogIndex: 0, LogLength: 0, Started: 0, Stopped: 0},
+ {Status: actions_model.StatusSuccess, LogIndex: 10, LogLength: 80, Started: 10010, Stopped: 10090},
+ {Name: postStepName, Status: actions_model.StatusSuccess, LogIndex: 90, LogLength: 10, Started: 10090, Stopped: 10100},
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/modules/cache/context.go b/modules/cache/context.go
index 62bbf5dcba..484cee659a 100644
--- a/modules/cache/context.go
+++ b/modules/cache/context.go
@@ -63,9 +63,9 @@ func (cc *cacheContext) isDiscard() bool {
}
// cacheContextLifetime is the max lifetime of cacheContext.
-// Since cacheContext is used to cache data in a request level context, 10s is enough.
-// If a cacheContext is used more than 10s, it's probably misuse.
-const cacheContextLifetime = 10 * time.Second
+// Since cacheContext is used to cache data in a request level context, 5 minutes is enough.
+// If a cacheContext is used more than 5 minutes, it's probably misuse.
+const cacheContextLifetime = 5 * time.Minute
var timeNow = time.Now
@@ -109,7 +109,8 @@ func WithCacheContext(ctx context.Context) context.Context {
return ctx
}
}
- return context.WithValue(ctx, cacheContextKey, &cacheContext{
+ // FIXME: review the use of this nolint directive
+ return context.WithValue(ctx, cacheContextKey, &cacheContext{ //nolint:staticcheck
data: make(map[any]map[any]any),
created: timeNow(),
})
@@ -131,7 +132,7 @@ func GetContextData(ctx context.Context, tp, key any) any {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
- log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
+ log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return nil
}
return c.Get(tp, key)
@@ -144,7 +145,7 @@ func SetContextData(ctx context.Context, tp, key, value any) {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
- log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
+ log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return
}
c.Put(tp, key, value)
@@ -157,7 +158,7 @@ func RemoveContextData(ctx context.Context, tp, key any) {
if c.Expired() {
// The warning means that the cache context is misused for long-life task,
// it can be resolved with WithNoCacheContext(ctx).
- log.Warn("cache context is expired, may be misused for long-life tasks: %v", c)
+ log.Warn("cache context is expired, is highly likely to be misused for long-life tasks: %v", c)
return
}
c.Delete(tp, key)
diff --git a/modules/cache/context_test.go b/modules/cache/context_test.go
index 5315547865..c01b9e8d84 100644
--- a/modules/cache/context_test.go
+++ b/modules/cache/context_test.go
@@ -45,7 +45,7 @@ func TestWithCacheContext(t *testing.T) {
timeNow = now
}()
timeNow = func() time.Time {
- return now().Add(10 * time.Second)
+ return now().Add(5 * time.Minute)
}
v = GetContextData(ctx, field, "my_config1")
assert.Nil(t, v)
diff --git a/modules/git/log_name_status.go b/modules/git/log_name_status.go
index 9e345f3ee0..1fd58abfcd 100644
--- a/modules/git/log_name_status.go
+++ b/modules/git/log_name_status.go
@@ -114,7 +114,7 @@ type LogNameStatusCommitData struct {
// Next returns the next LogStatusCommitData
func (g *LogNameStatusRepoParser) Next(treepath string, paths2ids map[string]int, changed []bool, maxpathlen int) (*LogNameStatusCommitData, error) {
var err error
- if g.next == nil || len(g.next) == 0 {
+ if len(g.next) == 0 {
g.buffull = false
g.next, err = g.rd.ReadSlice('\x00')
if err != nil {
diff --git a/modules/hostmatcher/http.go b/modules/hostmatcher/http.go
index c743f6efb3..8828902034 100644
--- a/modules/hostmatcher/http.go
+++ b/modules/hostmatcher/http.go
@@ -13,11 +13,7 @@ import (
)
// NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check
-func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx context.Context, network, addr string) (net.Conn, error) {
- return NewDialContextWithProxy(usage, allowList, blockList, nil)
-}
-
-func NewDialContextWithProxy(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
+func NewDialContext(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
// How Go HTTP Client works with redirection:
// transport.RoundTrip URL=http://domain.com, Host=domain.com
// transport.DialContext addrOrHost=domain.com:80
diff --git a/modules/httpcache/httpcache.go b/modules/httpcache/httpcache.go
index 40458dfc33..2c9af94405 100644
--- a/modules/httpcache/httpcache.go
+++ b/modules/httpcache/httpcache.go
@@ -75,7 +75,8 @@ func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag s
w.Header().Set("Etag", etag)
}
if lastModified != nil && !lastModified.IsZero() {
- w.Header().Set("Last-Modified", lastModified.Format(http.TimeFormat))
+ // http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
+ w.Header().Set("Last-Modified", lastModified.UTC().Format(http.TimeFormat))
}
if len(etag) > 0 {
diff --git a/modules/httplib/serve.go b/modules/httplib/serve.go
index 6e147d76f5..2e3e6a7c42 100644
--- a/modules/httplib/serve.go
+++ b/modules/httplib/serve.go
@@ -79,6 +79,7 @@ func ServeSetHeaders(w http.ResponseWriter, opts *ServeHeaderOptions) {
httpcache.SetCacheControlInHeader(header, duration)
if !opts.LastModified.IsZero() {
+ // http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
}
}
diff --git a/modules/httplib/url.go b/modules/httplib/url.go
index 219dfe695c..e3bad1e5fb 100644
--- a/modules/httplib/url.go
+++ b/modules/httplib/url.go
@@ -52,11 +52,6 @@ func getRequestScheme(req *http.Request) string {
return ""
}
-func getForwardedHost(req *http.Request) string {
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
- return req.Header.Get("X-Forwarded-Host")
-}
-
// GuessCurrentAppURL tries to guess the current full app URL (with sub-path) by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
func GuessCurrentAppURL(ctx context.Context) string {
return GuessCurrentHostURL(ctx) + setting.AppSubURL + "/"
@@ -81,11 +76,9 @@ func GuessCurrentHostURL(ctx context.Context) string {
if reqScheme == "" {
return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
}
- reqHost := getForwardedHost(req)
- if reqHost == "" {
- reqHost = req.Host
- }
- return reqScheme + "://" + reqHost
+ // X-Forwarded-Host has many problems: non-standard, not well-defined (X-Forwarded-Port or not), conflicts with Host header.
+ // So do not use X-Forwarded-Host, just use Host header directly.
+ return reqScheme + "://" + req.Host
}
// MakeAbsoluteURL tries to make a link to an absolute URL:
diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go
index 28aaee6e12..fc6c91cd3a 100644
--- a/modules/httplib/url_test.go
+++ b/modules/httplib/url_test.go
@@ -70,7 +70,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
"X-Forwarded-Proto": {"https"},
},
})
- assert.Equal(t, "https://forwarded-host/foo", MakeAbsoluteURL(ctx, "/foo"))
+ assert.Equal(t, "https://user-host/foo", MakeAbsoluteURL(ctx, "/foo"))
}
func TestIsCurrentGiteaSiteURL(t *testing.T) {
@@ -119,5 +119,6 @@ func TestIsCurrentGiteaSiteURL(t *testing.T) {
},
})
assert.True(t, IsCurrentGiteaSiteURL(ctx, "http://localhost:3000"))
- assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host"))
+ assert.True(t, IsCurrentGiteaSiteURL(ctx, "https://user-host"))
+ assert.False(t, IsCurrentGiteaSiteURL(ctx, "https://forwarded-host"))
}
diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go
index 542bdfb501..c17f56d3cf 100644
--- a/modules/indexer/code/bleve/bleve.go
+++ b/modules/indexer/code/bleve/bleve.go
@@ -284,6 +284,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
searchRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10))
}
+ searchRequest.SortBy([]string{"-_score", "UpdatedAt"})
+
result, err := b.inner.Indexer.SearchInContext(ctx, searchRequest)
if err != nil {
return 0, nil, nil, err
diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go
index 0bda180fac..5c01034450 100644
--- a/modules/indexer/code/elasticsearch/elasticsearch.go
+++ b/modules/indexer/code/elasticsearch/elasticsearch.go
@@ -20,6 +20,7 @@ import (
indexer_internal "code.gitea.io/gitea/modules/indexer/internal"
inner_elasticsearch "code.gitea.io/gitea/modules/indexer/internal/elasticsearch"
"code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/typesniffer"
@@ -197,8 +198,33 @@ func (b *Indexer) Index(ctx context.Context, repo *repo_model.Repository, sha st
return nil
}
-// Delete deletes indexes by ids
+// Delete entries by repoId
func (b *Indexer) Delete(ctx context.Context, repoID int64) error {
+ if err := b.doDelete(ctx, repoID); err != nil {
+ // Maybe there is a conflict during the delete operation, so we should retry after a refresh
+ log.Warn("Deletion of entries of repo %v within index %v was erroneus. Trying to refresh index before trying again", repoID, b.inner.VersionedIndexName(), err)
+ if err := b.refreshIndex(ctx); err != nil {
+ return err
+ }
+ if err := b.doDelete(ctx, repoID); err != nil {
+ log.Error("Could not delete entries of repo %v within index %v", repoID, b.inner.VersionedIndexName())
+ return err
+ }
+ }
+ return nil
+}
+
+func (b *Indexer) refreshIndex(ctx context.Context) error {
+ if _, err := b.inner.Client.Refresh(b.inner.VersionedIndexName()).Do(ctx); err != nil {
+ log.Error("Error while trying to refresh index %v", b.inner.VersionedIndexName(), err)
+ return err
+ }
+
+ return nil
+}
+
+// Delete entries by repoId
+func (b *Indexer) doDelete(ctx context.Context, repoID int64) error {
_, err := b.inner.Client.DeleteByQuery(b.inner.VersionedIndexName()).
Query(elastic.NewTermsQuery("repo_id", repoID)).
Do(ctx)
@@ -318,7 +344,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"),
).
- Sort("repo_id", true).
+ Sort("_score", false).
+ Sort("updated_at", true).
From(start).Size(pageSize).
Do(ctx)
if err != nil {
@@ -349,7 +376,8 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
NumOfFragments(0). // return all highting content on fragments
HighlighterType("fvh"),
).
- Sort("repo_id", true).
+ Sort("_score", false).
+ Sort("updated_at", true).
From(start).Size(pageSize).
Do(ctx)
if err != nil {
diff --git a/modules/issue/template/template.go b/modules/issue/template/template.go
index 0a105c723c..a2b9d6b33e 100644
--- a/modules/issue/template/template.go
+++ b/modules/issue/template/template.go
@@ -401,7 +401,7 @@ func (f *valuedField) Render() string {
}
func (f *valuedField) Value() string {
- return strings.TrimSpace(f.Get(fmt.Sprintf("form-field-" + f.ID)))
+ return strings.TrimSpace(f.Get(fmt.Sprintf("form-field-%s", f.ID)))
}
func (f *valuedField) Options() []*valuedOption {
diff --git a/modules/lfstransfer/backend/backend.go b/modules/lfstransfer/backend/backend.go
new file mode 100644
index 0000000000..d4523e1abf
--- /dev/null
+++ b/modules/lfstransfer/backend/backend.go
@@ -0,0 +1,301 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package backend
+
+import (
+ "bytes"
+ "context"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strconv"
+
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/lfs"
+ "code.gitea.io/gitea/modules/setting"
+
+ "github.com/charmbracelet/git-lfs-transfer/transfer"
+)
+
+// Version is the git-lfs-transfer protocol version number.
+const Version = "1"
+
+// Capabilities is a list of Git LFS capabilities supported by this package.
+var Capabilities = []string{
+ "version=" + Version,
+ "locking",
+}
+
+var _ transfer.Backend = &GiteaBackend{}
+
+// GiteaBackend is an adapter between git-lfs-transfer library and Gitea's internal LFS API
+type GiteaBackend struct {
+ ctx context.Context
+ server *url.URL
+ op string
+ token string
+ itoken string
+ logger transfer.Logger
+}
+
+func New(ctx context.Context, repo, op, token string, logger transfer.Logger) (transfer.Backend, error) {
+ // runServ guarantees repo will be in form [owner]/[name].git
+ server, err := url.Parse(setting.LocalURL)
+ if err != nil {
+ return nil, err
+ }
+ server = server.JoinPath("api/internal/repo", repo, "info/lfs")
+ return &GiteaBackend{ctx: ctx, server: server, op: op, token: token, itoken: fmt.Sprintf("Bearer %s", setting.InternalToken), logger: logger}, nil
+}
+
+// Batch implements transfer.Backend
+func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args transfer.Args) ([]transfer.BatchItem, error) {
+ reqBody := lfs.BatchRequest{Operation: g.op}
+ if transfer, ok := args[argTransfer]; ok {
+ reqBody.Transfers = []string{transfer}
+ }
+ if ref, ok := args[argRefname]; ok {
+ reqBody.Ref = &lfs.Reference{Name: ref}
+ }
+ reqBody.Objects = make([]lfs.Pointer, len(pointers))
+ for i := range pointers {
+ reqBody.Objects[i].Oid = pointers[i].Oid
+ reqBody.Objects[i].Size = pointers[i].Size
+ }
+
+ bodyBytes, err := json.Marshal(reqBody)
+ if err != nil {
+ g.logger.Log("json marshal error", err)
+ return nil, err
+ }
+ url := g.server.JoinPath("objects/batch").String()
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeGitLFS,
+ headerContentType: mimeGitLFS,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
+ resp, err := req.Response()
+ if err != nil {
+ g.logger.Log("http request error", err)
+ return nil, err
+ }
+ if resp.StatusCode != http.StatusOK {
+ g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
+ return nil, statusCodeToErr(resp.StatusCode)
+ }
+ defer resp.Body.Close()
+ respBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ g.logger.Log("http read error", err)
+ return nil, err
+ }
+ var respBody lfs.BatchResponse
+ err = json.Unmarshal(respBytes, &respBody)
+ if err != nil {
+ g.logger.Log("json umarshal error", err)
+ return nil, err
+ }
+
+ // rebuild slice, we can't rely on order in resp being the same as req
+ pointers = pointers[:0]
+ opNum := opMap[g.op]
+ for _, obj := range respBody.Objects {
+ pointer := transfer.Pointer{Oid: obj.Pointer.Oid, Size: obj.Pointer.Size}
+ item := transfer.BatchItem{Pointer: pointer, Args: map[string]string{}}
+ switch opNum {
+ case opDownload:
+ if action, ok := obj.Actions[actionDownload]; ok {
+ item.Present = true
+ idMap := obj.Actions
+ idMapBytes, err := json.Marshal(idMap)
+ if err != nil {
+ g.logger.Log("json marshal error", err)
+ return nil, err
+ }
+ idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
+ item.Args[argID] = idMapStr
+ if authHeader, ok := action.Header[headerAuthorisation]; ok {
+ authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
+ item.Args[argToken] = authHeaderB64
+ }
+ if action.ExpiresAt != nil {
+ item.Args[argExpiresAt] = action.ExpiresAt.String()
+ }
+ } else {
+ // must be an error, but the SSH protocol can't propagate individual errors
+ g.logger.Log("object not found", obj.Pointer.Oid, obj.Pointer.Size)
+ item.Present = false
+ }
+ case opUpload:
+ if action, ok := obj.Actions[actionUpload]; ok {
+ item.Present = false
+ idMap := obj.Actions
+ idMapBytes, err := json.Marshal(idMap)
+ if err != nil {
+ g.logger.Log("json marshal error", err)
+ return nil, err
+ }
+ idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
+ item.Args[argID] = idMapStr
+ if authHeader, ok := action.Header[headerAuthorisation]; ok {
+ authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
+ item.Args[argToken] = authHeaderB64
+ }
+ if action.ExpiresAt != nil {
+ item.Args[argExpiresAt] = action.ExpiresAt.String()
+ }
+ } else {
+ item.Present = true
+ }
+ }
+ pointers = append(pointers, item)
+ }
+ return pointers, nil
+}
+
+// Download implements transfer.Backend. The returned reader must be closed by the
+// caller.
+func (g *GiteaBackend) Download(oid string, args transfer.Args) (io.ReadCloser, int64, error) {
+ idMapStr, exists := args[argID]
+ if !exists {
+ return nil, 0, ErrMissingID
+ }
+ idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
+ if err != nil {
+ g.logger.Log("base64 decode error", err)
+ return nil, 0, transfer.ErrCorruptData
+ }
+ idMap := map[string]*lfs.Link{}
+ err = json.Unmarshal(idMapBytes, &idMap)
+ if err != nil {
+ g.logger.Log("json unmarshal error", err)
+ return nil, 0, transfer.ErrCorruptData
+ }
+ action, exists := idMap[actionDownload]
+ if !exists {
+ g.logger.Log("argument id incorrect")
+ return nil, 0, transfer.ErrCorruptData
+ }
+ url := action.Href
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeOctetStream,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodGet, headers, nil)
+ resp, err := req.Response()
+ if err != nil {
+ return nil, 0, err
+ }
+ if resp.StatusCode != http.StatusOK {
+ return nil, 0, statusCodeToErr(resp.StatusCode)
+ }
+ defer resp.Body.Close()
+ respBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, 0, err
+ }
+ respSize := int64(len(respBytes))
+ respBuf := io.NopCloser(bytes.NewBuffer(respBytes))
+ return respBuf, respSize, nil
+}
+
+// StartUpload implements transfer.Backend.
+func (g *GiteaBackend) Upload(oid string, size int64, r io.Reader, args transfer.Args) error {
+ idMapStr, exists := args[argID]
+ if !exists {
+ return ErrMissingID
+ }
+ idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
+ if err != nil {
+ g.logger.Log("base64 decode error", err)
+ return transfer.ErrCorruptData
+ }
+ idMap := map[string]*lfs.Link{}
+ err = json.Unmarshal(idMapBytes, &idMap)
+ if err != nil {
+ g.logger.Log("json unmarshal error", err)
+ return transfer.ErrCorruptData
+ }
+ action, exists := idMap[actionUpload]
+ if !exists {
+ g.logger.Log("argument id incorrect")
+ return transfer.ErrCorruptData
+ }
+ url := action.Href
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerContentType: mimeOctetStream,
+ headerContentLength: strconv.FormatInt(size, 10),
+ }
+ reqBytes, err := io.ReadAll(r)
+ if err != nil {
+ return err
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodPut, headers, reqBytes)
+ resp, err := req.Response()
+ if err != nil {
+ return err
+ }
+ if resp.StatusCode != http.StatusOK {
+ return statusCodeToErr(resp.StatusCode)
+ }
+ return nil
+}
+
+// Verify implements transfer.Backend.
+func (g *GiteaBackend) Verify(oid string, size int64, args transfer.Args) (transfer.Status, error) {
+ reqBody := lfs.Pointer{Oid: oid, Size: size}
+
+ bodyBytes, err := json.Marshal(reqBody)
+ if err != nil {
+ return transfer.NewStatus(transfer.StatusInternalServerError), err
+ }
+ idMapStr, exists := args[argID]
+ if !exists {
+ return transfer.NewStatus(transfer.StatusBadRequest, "missing argument: id"), ErrMissingID
+ }
+ idMapBytes, err := base64.StdEncoding.DecodeString(idMapStr)
+ if err != nil {
+ g.logger.Log("base64 decode error", err)
+ return transfer.NewStatus(transfer.StatusBadRequest, "corrupt argument: id"), transfer.ErrCorruptData
+ }
+ idMap := map[string]*lfs.Link{}
+ err = json.Unmarshal(idMapBytes, &idMap)
+ if err != nil {
+ g.logger.Log("json unmarshal error", err)
+ return transfer.NewStatus(transfer.StatusBadRequest, "corrupt argument: id"), transfer.ErrCorruptData
+ }
+ action, exists := idMap[actionVerify]
+ if !exists {
+ // the server sent no verify action
+ return transfer.SuccessStatus(), nil
+ }
+ url := action.Href
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeGitLFS,
+ headerContentType: mimeGitLFS,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
+ resp, err := req.Response()
+ if err != nil {
+ return transfer.NewStatus(transfer.StatusInternalServerError), err
+ }
+ if resp.StatusCode != http.StatusOK {
+ return transfer.NewStatus(uint32(resp.StatusCode), http.StatusText(resp.StatusCode)), statusCodeToErr(resp.StatusCode)
+ }
+ return transfer.SuccessStatus(), nil
+}
+
+// LockBackend implements transfer.Backend.
+func (g *GiteaBackend) LockBackend(_ transfer.Args) transfer.LockBackend {
+ return newGiteaLockBackend(g)
+}
diff --git a/modules/lfstransfer/backend/lock.go b/modules/lfstransfer/backend/lock.go
new file mode 100644
index 0000000000..f72ffd5b6f
--- /dev/null
+++ b/modules/lfstransfer/backend/lock.go
@@ -0,0 +1,296 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package backend
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strconv"
+ "time"
+
+ "code.gitea.io/gitea/modules/json"
+ lfslock "code.gitea.io/gitea/modules/structs"
+
+ "github.com/charmbracelet/git-lfs-transfer/transfer"
+)
+
+var _ transfer.LockBackend = &giteaLockBackend{}
+
+type giteaLockBackend struct {
+ ctx context.Context
+ g *GiteaBackend
+ server *url.URL
+ token string
+ itoken string
+ logger transfer.Logger
+}
+
+func newGiteaLockBackend(g *GiteaBackend) transfer.LockBackend {
+ server := g.server.JoinPath("locks")
+ return &giteaLockBackend{ctx: g.ctx, g: g, server: server, token: g.token, itoken: g.itoken, logger: g.logger}
+}
+
+// Create implements transfer.LockBackend
+func (g *giteaLockBackend) Create(path, refname string) (transfer.Lock, error) {
+ reqBody := lfslock.LFSLockRequest{Path: path}
+
+ bodyBytes, err := json.Marshal(reqBody)
+ if err != nil {
+ g.logger.Log("json marshal error", err)
+ return nil, err
+ }
+ url := g.server.String()
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeGitLFS,
+ headerContentType: mimeGitLFS,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
+ resp, err := req.Response()
+ if err != nil {
+ g.logger.Log("http request error", err)
+ return nil, err
+ }
+ defer resp.Body.Close()
+ respBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ g.logger.Log("http read error", err)
+ return nil, err
+ }
+ if resp.StatusCode != http.StatusCreated {
+ g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
+ return nil, statusCodeToErr(resp.StatusCode)
+ }
+ var respBody lfslock.LFSLockResponse
+ err = json.Unmarshal(respBytes, &respBody)
+ if err != nil {
+ g.logger.Log("json umarshal error", err)
+ return nil, err
+ }
+
+ if respBody.Lock == nil {
+ g.logger.Log("api returned nil lock")
+ return nil, fmt.Errorf("api returned nil lock")
+ }
+ respLock := respBody.Lock
+ owner := userUnknown
+ if respLock.Owner != nil {
+ owner = respLock.Owner.Name
+ }
+ lock := newGiteaLock(g, respLock.ID, respLock.Path, respLock.LockedAt, owner)
+ return lock, nil
+}
+
+// Unlock implements transfer.LockBackend
+func (g *giteaLockBackend) Unlock(lock transfer.Lock) error {
+ reqBody := lfslock.LFSLockDeleteRequest{}
+
+ bodyBytes, err := json.Marshal(reqBody)
+ if err != nil {
+ g.logger.Log("json marshal error", err)
+ return err
+ }
+ url := g.server.JoinPath(lock.ID(), "unlock").String()
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeGitLFS,
+ headerContentType: mimeGitLFS,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
+ resp, err := req.Response()
+ if err != nil {
+ g.logger.Log("http request error", err)
+ return err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
+ return statusCodeToErr(resp.StatusCode)
+ }
+ // no need to read response
+
+ return nil
+}
+
+// FromPath implements transfer.LockBackend
+func (g *giteaLockBackend) FromPath(path string) (transfer.Lock, error) {
+ v := url.Values{
+ argPath: []string{path},
+ }
+
+ respLocks, _, err := g.queryLocks(v)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(respLocks) == 0 {
+ return nil, transfer.ErrNotFound
+ }
+ return respLocks[0], nil
+}
+
+// FromID implements transfer.LockBackend
+func (g *giteaLockBackend) FromID(id string) (transfer.Lock, error) {
+ v := url.Values{
+ argID: []string{id},
+ }
+
+ respLocks, _, err := g.queryLocks(v)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(respLocks) == 0 {
+ return nil, transfer.ErrNotFound
+ }
+ return respLocks[0], nil
+}
+
+// Range implements transfer.LockBackend
+func (g *giteaLockBackend) Range(cursor string, limit int, iter func(transfer.Lock) error) (string, error) {
+ v := url.Values{
+ argLimit: []string{strconv.FormatInt(int64(limit), 10)},
+ }
+ if cursor != "" {
+ v[argCursor] = []string{cursor}
+ }
+
+ respLocks, cursor, err := g.queryLocks(v)
+ if err != nil {
+ return "", err
+ }
+
+ for _, lock := range respLocks {
+ err := iter(lock)
+ if err != nil {
+ return "", err
+ }
+ }
+ return cursor, nil
+}
+
+func (g *giteaLockBackend) queryLocks(v url.Values) ([]transfer.Lock, string, error) {
+ urlq := g.server.JoinPath() // get a copy
+ urlq.RawQuery = v.Encode()
+ url := urlq.String()
+ headers := map[string]string{
+ headerAuthorisation: g.itoken,
+ headerAuthX: g.token,
+ headerAccept: mimeGitLFS,
+ headerContentType: mimeGitLFS,
+ }
+ req := newInternalRequest(g.ctx, url, http.MethodGet, headers, nil)
+ resp, err := req.Response()
+ if err != nil {
+ g.logger.Log("http request error", err)
+ return nil, "", err
+ }
+ defer resp.Body.Close()
+ respBytes, err := io.ReadAll(resp.Body)
+ if err != nil {
+ g.logger.Log("http read error", err)
+ return nil, "", err
+ }
+ if resp.StatusCode != http.StatusOK {
+ g.logger.Log("http statuscode error", resp.StatusCode, statusCodeToErr(resp.StatusCode))
+ return nil, "", statusCodeToErr(resp.StatusCode)
+ }
+ var respBody lfslock.LFSLockList
+ err = json.Unmarshal(respBytes, &respBody)
+ if err != nil {
+ g.logger.Log("json umarshal error", err)
+ return nil, "", err
+ }
+
+ respLocks := make([]transfer.Lock, 0, len(respBody.Locks))
+ for _, respLock := range respBody.Locks {
+ owner := userUnknown
+ if respLock.Owner != nil {
+ owner = respLock.Owner.Name
+ }
+ lock := newGiteaLock(g, respLock.ID, respLock.Path, respLock.LockedAt, owner)
+ respLocks = append(respLocks, lock)
+ }
+ return respLocks, respBody.Next, nil
+}
+
+var _ transfer.Lock = &giteaLock{}
+
+type giteaLock struct {
+ g *giteaLockBackend
+ id string
+ path string
+ lockedAt time.Time
+ owner string
+}
+
+func newGiteaLock(g *giteaLockBackend, id, path string, lockedAt time.Time, owner string) transfer.Lock {
+ return &giteaLock{g: g, id: id, path: path, lockedAt: lockedAt, owner: owner}
+}
+
+// Unlock implements transfer.Lock
+func (g *giteaLock) Unlock() error {
+ return g.g.Unlock(g)
+}
+
+// ID implements transfer.Lock
+func (g *giteaLock) ID() string {
+ return g.id
+}
+
+// Path implements transfer.Lock
+func (g *giteaLock) Path() string {
+ return g.path
+}
+
+// FormattedTimestamp implements transfer.Lock
+func (g *giteaLock) FormattedTimestamp() string {
+ return g.lockedAt.UTC().Format(time.RFC3339)
+}
+
+// OwnerName implements transfer.Lock
+func (g *giteaLock) OwnerName() string {
+ return g.owner
+}
+
+func (g *giteaLock) CurrentUser() (string, error) {
+ return userSelf, nil
+}
+
+// AsLockSpec implements transfer.Lock
+func (g *giteaLock) AsLockSpec(ownerID bool) ([]string, error) {
+ msgs := []string{
+ fmt.Sprintf("lock %s", g.ID()),
+ fmt.Sprintf("path %s %s", g.ID(), g.Path()),
+ fmt.Sprintf("locked-at %s %s", g.ID(), g.FormattedTimestamp()),
+ fmt.Sprintf("ownername %s %s", g.ID(), g.OwnerName()),
+ }
+ if ownerID {
+ user, err := g.CurrentUser()
+ if err != nil {
+ return nil, fmt.Errorf("error getting current user: %w", err)
+ }
+ who := "theirs"
+ if user == g.OwnerName() {
+ who = "ours"
+ }
+ msgs = append(msgs, fmt.Sprintf("owner %s %s", g.ID(), who))
+ }
+ return msgs, nil
+}
+
+// AsArguments implements transfer.Lock
+func (g *giteaLock) AsArguments() []string {
+ return []string{
+ fmt.Sprintf("id=%s", g.ID()),
+ fmt.Sprintf("path=%s", g.Path()),
+ fmt.Sprintf("locked-at=%s", g.FormattedTimestamp()),
+ fmt.Sprintf("ownername=%s", g.OwnerName()),
+ }
+}
diff --git a/modules/lfstransfer/backend/util.go b/modules/lfstransfer/backend/util.go
new file mode 100644
index 0000000000..126ac00175
--- /dev/null
+++ b/modules/lfstransfer/backend/util.go
@@ -0,0 +1,141 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package backend
+
+import (
+ "context"
+ "crypto/tls"
+ "fmt"
+ "net"
+ "net/http"
+ "time"
+
+ "code.gitea.io/gitea/modules/httplib"
+ "code.gitea.io/gitea/modules/proxyprotocol"
+ "code.gitea.io/gitea/modules/setting"
+
+ "github.com/charmbracelet/git-lfs-transfer/transfer"
+)
+
+// HTTP headers
+const (
+ headerAccept = "Accept"
+ headerAuthorisation = "Authorization"
+ headerAuthX = "X-Auth"
+ headerContentType = "Content-Type"
+ headerContentLength = "Content-Length"
+)
+
+// MIME types
+const (
+ mimeGitLFS = "application/vnd.git-lfs+json"
+ mimeOctetStream = "application/octet-stream"
+)
+
+// SSH protocol action keys
+const (
+ actionDownload = "download"
+ actionUpload = "upload"
+ actionVerify = "verify"
+)
+
+// SSH protocol argument keys
+const (
+ argCursor = "cursor"
+ argExpiresAt = "expires-at"
+ argID = "id"
+ argLimit = "limit"
+ argPath = "path"
+ argRefname = "refname"
+ argToken = "token"
+ argTransfer = "transfer"
+)
+
+// Default username constants
+const (
+ userSelf = "(self)"
+ userUnknown = "(unknown)"
+)
+
+// Operations enum
+const (
+ opNone = iota
+ opDownload
+ opUpload
+)
+
+var opMap = map[string]int{
+ "download": opDownload,
+ "upload": opUpload,
+}
+
+var ErrMissingID = fmt.Errorf("%w: missing id arg", transfer.ErrMissingData)
+
+func statusCodeToErr(code int) error {
+ switch code {
+ case http.StatusBadRequest:
+ return transfer.ErrParseError
+ case http.StatusConflict:
+ return transfer.ErrConflict
+ case http.StatusForbidden:
+ return transfer.ErrForbidden
+ case http.StatusNotFound:
+ return transfer.ErrNotFound
+ case http.StatusUnauthorized:
+ return transfer.ErrUnauthorized
+ default:
+ return fmt.Errorf("server returned status %v: %v", code, http.StatusText(code))
+ }
+}
+
+func newInternalRequest(ctx context.Context, url, method string, headers map[string]string, body []byte) *httplib.Request {
+ req := httplib.NewRequest(url, method).
+ SetContext(ctx).
+ SetTimeout(10*time.Second, 60*time.Second).
+ SetTLSClientConfig(&tls.Config{
+ InsecureSkipVerify: true,
+ })
+
+ if setting.Protocol == setting.HTTPUnix {
+ req.SetTransport(&http.Transport{
+ DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
+ var d net.Dialer
+ conn, err := d.DialContext(ctx, "unix", setting.HTTPAddr)
+ if err != nil {
+ return conn, err
+ }
+ if setting.LocalUseProxyProtocol {
+ if err = proxyprotocol.WriteLocalHeader(conn); err != nil {
+ _ = conn.Close()
+ return nil, err
+ }
+ }
+ return conn, err
+ },
+ })
+ } else if setting.LocalUseProxyProtocol {
+ req.SetTransport(&http.Transport{
+ DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
+ var d net.Dialer
+ conn, err := d.DialContext(ctx, network, address)
+ if err != nil {
+ return conn, err
+ }
+ if err = proxyprotocol.WriteLocalHeader(conn); err != nil {
+ _ = conn.Close()
+ return nil, err
+ }
+ return conn, err
+ },
+ })
+ }
+
+ for k, v := range headers {
+ req.Header(k, v)
+ }
+
+ req.Body(body)
+
+ return req
+}
diff --git a/modules/lfstransfer/logger.go b/modules/lfstransfer/logger.go
new file mode 100644
index 0000000000..517c2d9ba1
--- /dev/null
+++ b/modules/lfstransfer/logger.go
@@ -0,0 +1,21 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package lfstransfer
+
+import (
+ "github.com/charmbracelet/git-lfs-transfer/transfer"
+)
+
+var _ transfer.Logger = (*GiteaLogger)(nil)
+
+// noop logger for passing into transfer
+type GiteaLogger struct{}
+
+func newLogger() transfer.Logger {
+ return &GiteaLogger{}
+}
+
+// Log implements transfer.Logger
+func (g *GiteaLogger) Log(msg string, itms ...any) {
+}
diff --git a/modules/lfstransfer/main.go b/modules/lfstransfer/main.go
new file mode 100644
index 0000000000..a134f50b86
--- /dev/null
+++ b/modules/lfstransfer/main.go
@@ -0,0 +1,42 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package lfstransfer
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "code.gitea.io/gitea/modules/lfstransfer/backend"
+
+ "github.com/charmbracelet/git-lfs-transfer/transfer"
+)
+
+func Main(ctx context.Context, repo, verb, token string) error {
+ logger := newLogger()
+ pktline := transfer.NewPktline(os.Stdin, os.Stdout, logger)
+ giteaBackend, err := backend.New(ctx, repo, verb, token, logger)
+ if err != nil {
+ return err
+ }
+
+ for _, cap := range backend.Capabilities {
+ if err := pktline.WritePacketText(cap); err != nil {
+ logger.Log("error sending capability due to error:", err)
+ }
+ }
+ if err := pktline.WriteFlush(); err != nil {
+ logger.Log("error flushing capabilities:", err)
+ }
+ p := transfer.NewProcessor(pktline, giteaBackend, logger)
+ defer logger.Log("done processing commands")
+ switch verb {
+ case "upload":
+ return p.ProcessCommands(transfer.UploadOperation)
+ case "download":
+ return p.ProcessCommands(transfer.DownloadOperation)
+ default:
+ return fmt.Errorf("unknown operation %q", verb)
+ }
+}
diff --git a/modules/markup/camo.go b/modules/markup/camo.go
index e93797de2b..7e2583469d 100644
--- a/modules/markup/camo.go
+++ b/modules/markup/camo.go
@@ -38,7 +38,7 @@ func camoHandleLink(link string) string {
if setting.Camo.Enabled {
lnkURL, err := url.Parse(link)
if err == nil && lnkURL.IsAbs() && !strings.HasPrefix(link, setting.AppURL) &&
- (setting.Camo.Allways || lnkURL.Scheme != "https") {
+ (setting.Camo.Always || lnkURL.Scheme != "https") {
return CamoEncode(link)
}
}
diff --git a/modules/markup/camo_test.go b/modules/markup/camo_test.go
index ba58835221..3c5d40afa0 100644
--- a/modules/markup/camo_test.go
+++ b/modules/markup/camo_test.go
@@ -28,7 +28,7 @@ func TestCamoHandleLink(t *testing.T) {
"https://image.proxy/eivin43gJwGVIjR9MiYYtFIk0mw/aHR0cDovL3Rlc3RpbWFnZXMub3JnL2ltZy5qcGc",
camoHandleLink("http://testimages.org/img.jpg"))
- setting.Camo.Allways = true
+ setting.Camo.Always = true
assert.Equal(t,
"https://gitea.com/img.jpg",
camoHandleLink("https://gitea.com/img.jpg"))
diff --git a/modules/migration/options.go b/modules/migration/options.go
index 234e72c295..163aa0cfaa 100644
--- a/modules/migration/options.go
+++ b/modules/migration/options.go
@@ -38,4 +38,7 @@ type MigrateOptions struct {
ReleaseAssets bool
MigrateToRepoID int64
MirrorInterval string `json:"mirror_interval"`
+
+ AWSAccessKeyID string
+ AWSSecretAccessKey string
}
diff --git a/modules/packages/composer/metadata.go b/modules/packages/composer/metadata.go
index 2c2e9ebf27..6035eae8ca 100644
--- a/modules/packages/composer/metadata.go
+++ b/modules/packages/composer/metadata.go
@@ -48,6 +48,7 @@ type Metadata struct {
Homepage string `json:"homepage,omitempty"`
License Licenses `json:"license,omitempty"`
Authors []Author `json:"authors,omitempty"`
+ Bin []string `json:"bin,omitempty"`
Autoload map[string]any `json:"autoload,omitempty"`
AutoloadDev map[string]any `json:"autoload-dev,omitempty"`
Extra map[string]any `json:"extra,omitempty"`
diff --git a/modules/queue/base_channel.go b/modules/queue/base_channel.go
index d03c72bdae..dd8ccb15f4 100644
--- a/modules/queue/base_channel.go
+++ b/modules/queue/base_channel.go
@@ -120,7 +120,7 @@ func (q *baseChannel) RemoveAll(ctx context.Context) error {
q.mu.Lock()
defer q.mu.Unlock()
- for q.c != nil && len(q.c) > 0 {
+ for len(q.c) > 0 {
<-q.c
}
diff --git a/modules/repository/license.go b/modules/repository/license.go
index 6ac3547e7b..9da3af84f8 100644
--- a/modules/repository/license.go
+++ b/modules/repository/license.go
@@ -23,7 +23,7 @@ type LicenseValues struct {
func GetLicense(name string, values *LicenseValues) ([]byte, error) {
data, err := options.License(name)
if err != nil {
- return nil, fmt.Errorf("GetRepoInitFile[%s]: %w", name, err)
+ return nil, fmt.Errorf("GetLicense[%s]: %w", name, err)
}
return fillLicensePlaceholder(name, values, data), nil
}
diff --git a/modules/setting/actions.go b/modules/setting/actions.go
index a515b1ca69..913872eaf2 100644
--- a/modules/setting/actions.go
+++ b/modules/setting/actions.go
@@ -62,11 +62,11 @@ func (c logCompression) IsValid() bool {
}
func (c logCompression) IsNone() bool {
- return c == "" || strings.ToLower(string(c)) == "none"
+ return strings.ToLower(string(c)) == "none"
}
func (c logCompression) IsZstd() bool {
- return strings.ToLower(string(c)) == "zstd"
+ return c == "" || strings.ToLower(string(c)) == "zstd"
}
func loadActionsFrom(rootCfg ConfigProvider) error {
diff --git a/modules/setting/admin.go b/modules/setting/admin.go
index ca4e9b1d58..fde291ade9 100644
--- a/modules/setting/admin.go
+++ b/modules/setting/admin.go
@@ -29,4 +29,6 @@ const (
UserFeatureManageGPGKeys = "manage_gpg_keys"
UserFeatureManageMFA = "manage_mfa"
UserFeatureManageCredentials = "manage_credentials"
+ UserFeatureChangeUsername = "change_username"
+ UserFeatureChangeFullName = "change_full_name"
)
diff --git a/modules/setting/camo.go b/modules/setting/camo.go
index 366e9a116c..608ecf8363 100644
--- a/modules/setting/camo.go
+++ b/modules/setting/camo.go
@@ -3,18 +3,28 @@
package setting
-import "code.gitea.io/gitea/modules/log"
+import (
+ "strconv"
+
+ "code.gitea.io/gitea/modules/log"
+)
var Camo = struct {
Enabled bool
ServerURL string `ini:"SERVER_URL"`
HMACKey string `ini:"HMAC_KEY"`
- Allways bool
+ Always bool
}{}
func loadCamoFrom(rootCfg ConfigProvider) {
mustMapSetting(rootCfg, "camo", &Camo)
if Camo.Enabled {
+ oldValue := rootCfg.Section("camo").Key("ALLWAYS").MustString("")
+ if oldValue != "" {
+ log.Warn("camo.ALLWAYS is deprecated, use camo.ALWAYS instead")
+ Camo.Always, _ = strconv.ParseBool(oldValue)
+ }
+
if Camo.ServerURL == "" || Camo.HMACKey == "" {
log.Fatal(`Camo settings require "SERVER_URL" and HMAC_KEY`)
}
diff --git a/modules/setting/lfs.go b/modules/setting/lfs.go
index 2034ef782c..6bdcbed91d 100644
--- a/modules/setting/lfs.go
+++ b/modules/setting/lfs.go
@@ -13,6 +13,7 @@ import (
// LFS represents the configuration for Git LFS
var LFS = struct {
StartServer bool `ini:"LFS_START_SERVER"`
+ AllowPureSSH bool `ini:"LFS_ALLOW_PURE_SSH"`
JWTSecretBytes []byte `ini:"-"`
HTTPAuthExpiry time.Duration `ini:"LFS_HTTP_AUTH_EXPIRY"`
MaxFileSize int64 `ini:"LFS_MAX_FILE_SIZE"`
diff --git a/modules/setting/security.go b/modules/setting/security.go
index 3d7b1f9ce7..3d12fcf8d9 100644
--- a/modules/setting/security.go
+++ b/modules/setting/security.go
@@ -37,6 +37,7 @@ var (
DisableQueryAuthToken bool
CSRFCookieName = "_csrf"
CSRFCookieHTTPOnly = true
+ RecordUserSignupMetadata = false
)
// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set
@@ -164,6 +165,8 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
// TODO: default value should be true in future releases
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)
+ RecordUserSignupMetadata = sec.Key("RECORD_USER_SIGNUP_METADATA").MustBool(false)
+
// warn if the setting is set to false explicitly
if sectionHasDisableQueryAuthToken && !DisableQueryAuthToken {
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")
diff --git a/modules/storage/azureblob.go b/modules/storage/azureblob.go
index 211522c5bb..568227ca47 100644
--- a/modules/storage/azureblob.go
+++ b/modules/storage/azureblob.go
@@ -114,7 +114,7 @@ func convertAzureBlobErr(err error) error {
if !errors.As(err, &respErr) {
return err
}
- return fmt.Errorf(respErr.ErrorCode)
+ return fmt.Errorf("%s", respErr.ErrorCode)
}
// NewAzureBlobStorage returns a azure blob storage
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index 444967c3e7..832ffa8bcc 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -114,6 +114,7 @@ type Repository struct {
MirrorUpdated time.Time `json:"mirror_updated,omitempty"`
RepoTransfer *RepoTransfer `json:"repo_transfer"`
Topics []string `json:"topics"`
+ Licenses []string `json:"licenses"`
}
// CreateRepoOption options when creating repository
@@ -291,15 +292,16 @@ type GitServiceType int
// enumerate all GitServiceType
const (
- NotMigrated GitServiceType = iota // 0 not migrated from external sites
- PlainGitService // 1 plain git service
- GithubService // 2 github.com
- GiteaService // 3 gitea service
- GitlabService // 4 gitlab service
- GogsService // 5 gogs service
- OneDevService // 6 onedev service
- GitBucketService // 7 gitbucket service
- CodebaseService // 8 codebase service
+ NotMigrated GitServiceType = iota // 0 not migrated from external sites
+ PlainGitService // 1 plain git service
+ GithubService // 2 github.com
+ GiteaService // 3 gitea service
+ GitlabService // 4 gitlab service
+ GogsService // 5 gogs service
+ OneDevService // 6 onedev service
+ GitBucketService // 7 gitbucket service
+ CodebaseService // 8 codebase service
+ CodeCommitService // 9 codecommit service
)
// Name represents the service type's name
@@ -325,6 +327,8 @@ func (gt GitServiceType) Title() string {
return "GitBucket"
case CodebaseService:
return "Codebase"
+ case CodeCommitService:
+ return "CodeCommit"
case PlainGitService:
return "Git"
}
@@ -361,6 +365,9 @@ type MigrateRepoOptions struct {
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
MirrorInterval string `json:"mirror_interval"`
+
+ AWSAccessKeyID string `json:"aws_access_key_id"`
+ AWSSecretAccessKey string `json:"aws_secret_access_key"`
}
// TokenAuth represents whether a service type supports token-based auth
@@ -382,6 +389,7 @@ var SupportedFullGitService = []GitServiceType{
OneDevService,
GitBucketService,
CodebaseService,
+ CodeCommitService,
}
// RepoTransfer represents a pending repo transfer
diff --git a/modules/templates/util_avatar.go b/modules/templates/util_avatar.go
index 85832cf264..afc1091516 100644
--- a/modules/templates/util_avatar.go
+++ b/modules/templates/util_avatar.go
@@ -34,7 +34,7 @@ func AvatarHTML(src string, size int, class, name string) template.HTML {
name = "avatar"
}
- return template.HTML(`
`)
+ return template.HTML(`
`)
}
// Avatar renders user avatars. args: user, size (int), class (string)
diff --git a/options/gitignore/Hexo b/options/gitignore/Hexo
new file mode 100644
index 0000000000..570a5e7b5d
--- /dev/null
+++ b/options/gitignore/Hexo
@@ -0,0 +1,14 @@
+# gitignore template for Hexo sites
+# website: https://hexo.io/
+# Recommended: Node.gitignore
+
+# Ignore generated directory
+public/
+
+# Ignore temp files
+tmp/
+.tmp*
+
+# additional files
+db.json
+.deploy*/
diff --git a/options/gitignore/KiCad b/options/gitignore/KiCad
index a63bc0e7f7..59fde34c0e 100644
--- a/options/gitignore/KiCad
+++ b/options/gitignore/KiCad
@@ -16,6 +16,8 @@ _autosave-*
*-save.pro
*-save.kicad_pcb
fp-info-cache
+~*.lck
+\#auto_saved_files#
# Netlist files (exported from Eeschema)
*.net
diff --git a/options/gitignore/ReScript b/options/gitignore/ReScript
new file mode 100644
index 0000000000..b7364c932a
--- /dev/null
+++ b/options/gitignore/ReScript
@@ -0,0 +1,3 @@
+/node_modules/
+/lib/
+.bsb.lock
diff --git a/options/gitignore/Terragrunt b/options/gitignore/Terragrunt
new file mode 100644
index 0000000000..ea4808637f
--- /dev/null
+++ b/options/gitignore/Terragrunt
@@ -0,0 +1,3 @@
+# Ignore the default terragrunt cache directory
+# https://terragrunt.gruntwork.io/docs/features/caching/
+.terragrunt-cache
diff --git a/options/gitignore/Zig b/options/gitignore/Zig
new file mode 100644
index 0000000000..3389c86c99
--- /dev/null
+++ b/options/gitignore/Zig
@@ -0,0 +1,2 @@
+.zig-cache/
+zig-out/
diff --git a/options/license/Boehm-GC-without-fee b/options/license/Boehm-GC-without-fee
new file mode 100644
index 0000000000..354d47017e
--- /dev/null
+++ b/options/license/Boehm-GC-without-fee
@@ -0,0 +1,14 @@
+Copyright (c) 2000
+SWsoft company
+
+Modifications copyright (c) 2001, 2013. Oracle and/or its affiliates.
+All rights reserved.
+
+This material is provided "as is", with absolutely no warranty expressed
+or implied. Any use is at your own risk.
+
+Permission to use or copy this software for any purpose is hereby granted
+without fee, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is granted,
+provided the above notices are retained, and a notice that the code was
+modified is included with the above copyright notice.
diff --git a/options/license/DocBook-Stylesheet b/options/license/DocBook-Stylesheet
new file mode 100644
index 0000000000..e986ed4235
--- /dev/null
+++ b/options/license/DocBook-Stylesheet
@@ -0,0 +1,13 @@
+Copyright 2005 Norman Walsh, Sun Microsystems,
+Inc., and the Organization for the Advancement
+of Structured Information Standards (OASIS).
+
+Release: $Id: db4-upgrade.xsl 8905 2010-09-12 11:47:07Z bobstayton $
+
+Permission to use, copy, modify and distribute this stylesheet
+and its accompanying documentation for any purpose and
+without fee is hereby granted in perpetuity, provided that
+the above copyright notice and this paragraph appear in
+all copies. The copyright holders make no representation
+about the suitability of the schema for any purpose. It
+is provided "as is" without expressed or implied warranty.
diff --git a/options/license/GPL-3.0-389-ds-base-exception b/options/license/GPL-3.0-389-ds-base-exception
new file mode 100644
index 0000000000..52be470c10
--- /dev/null
+++ b/options/license/GPL-3.0-389-ds-base-exception
@@ -0,0 +1,10 @@
+Additional permission under GPLv3 section 7:
+
+If you modify this Program, or any covered work, by
+linking or combining it with OpenSSL, or a modified
+version of OpenSSL licensed under the OpenSSL license
+(https://www.openssl.org/source/license.html), the licensors of this
+Program grant you additional permission to convey the resulting work.
+Corresponding Source for a non-source form of such a combination
+shall include the source code for the parts that are licensed
+under the OpenSSL license as well as that of the covered work.
diff --git a/options/license/MIT-Click b/options/license/MIT-Click
new file mode 100644
index 0000000000..82054edc39
--- /dev/null
+++ b/options/license/MIT-Click
@@ -0,0 +1,30 @@
+Portions of this software are subject to the license below. The relevant
+source files are clearly marked; they refer to this file using the phrase
+"the Click LICENSE file". This license is an MIT license, plus a clause
+(taken from the W3C license) requiring prior written permission to use our
+names in publicity.
+
+===========================================================================
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+The name and trademarks of copyright holders may NOT be used in advertising
+or publicity pertaining to the Software without specific, written prior
+permission. Title to copyright in this Software and any associated
+documentation will at all times remain with copyright holders.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/options/license/Sendmail-Open-Source-1.1 b/options/license/Sendmail-Open-Source-1.1
new file mode 100644
index 0000000000..054f719ee5
--- /dev/null
+++ b/options/license/Sendmail-Open-Source-1.1
@@ -0,0 +1,75 @@
+SENDMAIL OPEN SOURCE LICENSE
+
+The following license terms and conditions apply to this open source
+software ("Software"), unless a different license is obtained directly
+from Sendmail, Inc. ("Sendmail") located at 6475 Christie Ave, Suite 350,
+Emeryville, CA 94608, USA.
+
+Use, modification and redistribution (including distribution of any
+modified or derived work) of the Software in source and binary forms is
+permitted only if each of the following conditions of 1-6 are met:
+
+1. Redistributions of the Software qualify as "freeware" or "open
+ source software" under one of the following terms:
+
+ (a) Redistributions are made at no charge beyond the reasonable
+ cost of materials and delivery; or
+
+ (b) Redistributions are accompanied by a copy of the modified
+ Source Code (on an acceptable machine-readable medium) or by an
+ irrevocable offer to provide a copy of the modified Source Code
+ (on an acceptable machine-readable medium) for up to three years
+ at the cost of materials and delivery. Such redistributions must
+ allow further use, modification, and redistribution of the Source
+ Code under substantially the same terms as this license. For
+ the purposes of redistribution "Source Code" means the complete
+ human-readable, compilable, linkable, and operational source
+ code of the redistributed module(s) including all modifications.
+
+2. Redistributions of the Software Source Code must retain the
+ copyright notices as they appear in each Source Code file, these
+ license terms and conditions, and the disclaimer/limitation of
+ liability set forth in paragraph 6 below. Redistributions of the
+ Software Source Code must also comply with the copyright notices
+ and/or license terms and conditions imposed by contributors on
+ embedded code. The contributors' license terms and conditions
+ and/or copyright notices are contained in the Source Code
+ distribution.
+
+3. Redistributions of the Software in binary form must reproduce the
+ Copyright Notice described below, these license terms and conditions,
+ and the disclaimer/limitation of liability set forth in paragraph
+ 6 below, in the documentation and/or other materials provided with
+ the binary distribution. For the purposes of binary distribution,
+ "Copyright Notice" refers to the following language: "Copyright (c)
+ 1998-2009 Sendmail, Inc. All rights reserved."
+
+4. Neither the name, trademark or logo of Sendmail, Inc. (including
+ without limitation its subsidiaries or affiliates) or its contributors
+ may be used to endorse or promote products, or software or services
+ derived from this Software without specific prior written permission.
+ The name "sendmail" is a registered trademark and service mark of
+ Sendmail, Inc.
+
+5. We reserve the right to cancel this license if you do not comply with
+ the terms. This license is governed by California law and both of us
+ agree that for any dispute arising out of or relating to this Software,
+ that jurisdiction and venue is proper in San Francisco or Alameda
+ counties. These license terms and conditions reflect the complete
+ agreement for the license of the Software (which means this supercedes
+ prior or contemporaneous agreements or representations). If any term
+ or condition under this license is found to be invalid, the remaining
+ terms and conditions still apply.
+
+6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY
+ SENDMAIL AND ITS CONTRIBUTORS "AS IS" WITHOUT WARRANTY OF ANY KIND
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. IN NO EVENT SHALL SENDMAIL
+ OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ WITHOUT LIMITATION NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
diff --git a/options/license/TrustedQSL b/options/license/TrustedQSL
new file mode 100644
index 0000000000..982d4269f6
--- /dev/null
+++ b/options/license/TrustedQSL
@@ -0,0 +1,58 @@
+Copyright (C) 2001-2015 American Radio Relay League, Inc. All rights
+reserved.
+
+Portions (C) 2003-2023 The TrustedQSL Developers. Please see the AUTHORS.txt
+file for contributors.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Any redistribution of source code must retain the above copyright
+notice, this list of conditions and the disclaimer shown in
+Paragraph 5 (below).
+
+2. Redistribution in binary form must reproduce the above copyright
+notice, this list of conditions and the disclaimer shown in
+Paragraph 5 (below) in the documentation and/or other materials
+provided with the distribution.
+
+3. Products derived from or including this software may not use
+"Logbook of the World" or "LoTW" or any other American Radio Relay
+League, Incorporated trademarks or servicemarks in their names
+without prior written permission of the ARRL. See Paragraph 6
+(below) for contact information.
+
+4. Use of this software does not imply endorsement by ARRL of
+products derived from or including this software and vendors may not
+claim such endorsement.
+
+5. Disclaimer: This software is provided "as-is" without
+representation, guarantee or warranty of any kind, either express or
+implied, including but not limited to the implied warranties of
+merchantability or of fitness for a particular purpose. The entire
+risk as to the quality and performance of the software is solely
+with you. Should the software prove defective, you (and not the
+American Radio Relay League, its officers, directors, employees or
+agents) assume the entire cost of all necessary servicing, repair or
+correction. In no event will ARRL be liable to you or to any third
+party for any damages, whether direct or indirect, including lost
+profits, lost savings, or other incidental or consequential damages
+arising out of the use or inability to use such software, regardless
+of whether ARRL has been advised of the possibility of such damages.
+
+6. Contact information:
+
+American Radio Relay League, Inc.
+Attn: Logbook of the World Manager
+225 Main St
+Newington, CT 06111
+voice: 860-594-0200
+fax: 860-594-0259
+email: logbook@arrl.org
+Worldwide Web: www.arrl.org
+
+This software consists of voluntary contributions made by many
+individuals on behalf of the ARRL. More information on the "Logbook
+of The World" project and the ARRL is available from the ARRL Web
+site at www.arrl.org.
diff --git a/options/license/etc/license-aliases.json b/options/license/etc/license-aliases.json
new file mode 100644
index 0000000000..fe2cf2d58e
--- /dev/null
+++ b/options/license/etc/license-aliases.json
@@ -0,0 +1 @@
+{"AGPL-1.0-only":"AGPL-1.0","AGPL-1.0-or-later":"AGPL-1.0","AGPL-3.0-only":"AGPL-3.0","AGPL-3.0-or-later":"AGPL-3.0","CAL-1.0":"CAL-1.0","CAL-1.0-Combined-Work-Exception":"CAL-1.0","GFDL-1.1-invariants-only":"GFDL-1.1","GFDL-1.1-invariants-or-later":"GFDL-1.1","GFDL-1.1-no-invariants-only":"GFDL-1.1","GFDL-1.1-no-invariants-or-later":"GFDL-1.1","GFDL-1.1-only":"GFDL-1.1","GFDL-1.1-or-later":"GFDL-1.1","GFDL-1.2-invariants-only":"GFDL-1.2","GFDL-1.2-invariants-or-later":"GFDL-1.2","GFDL-1.2-no-invariants-only":"GFDL-1.2","GFDL-1.2-no-invariants-or-later":"GFDL-1.2","GFDL-1.2-only":"GFDL-1.2","GFDL-1.2-or-later":"GFDL-1.2","GFDL-1.3-invariants-only":"GFDL-1.3","GFDL-1.3-invariants-or-later":"GFDL-1.3","GFDL-1.3-no-invariants-only":"GFDL-1.3","GFDL-1.3-no-invariants-or-later":"GFDL-1.3","GFDL-1.3-only":"GFDL-1.3","GFDL-1.3-or-later":"GFDL-1.3","GPL-1.0-only":"GPL-1.0","GPL-1.0-or-later":"GPL-1.0","GPL-2.0-only":"GPL-2.0","GPL-2.0-or-later":"GPL-2.0","GPL-3.0-only":"GPL-3.0","GPL-3.0-or-later":"GPL-3.0","LGPL-2.0-only":"LGPL-2.0","LGPL-2.0-or-later":"LGPL-2.0","LGPL-2.1-only":"LGPL-2.1","LGPL-2.1-or-later":"LGPL-2.1","LGPL-3.0-only":"LGPL-3.0","LGPL-3.0-or-later":"LGPL-3.0","MPL-2.0":"MPL-2.0","MPL-2.0-no-copyleft-exception":"MPL-2.0","OFL-1.0":"OFL-1.0","OFL-1.0-RFN":"OFL-1.0","OFL-1.0-no-RFN":"OFL-1.0","OFL-1.1":"OFL-1.1","OFL-1.1-RFN":"OFL-1.1","OFL-1.1-no-RFN":"OFL-1.1"}
\ No newline at end of file
diff --git a/options/license/harbour-exception b/options/license/harbour-exception
new file mode 100644
index 0000000000..25d75e9fc7
--- /dev/null
+++ b/options/license/harbour-exception
@@ -0,0 +1,23 @@
+As a special exception, the Harbour Project gives permission for
+additional uses of the text contained in its release of Harbour.
+
+The exception is that, if you link the Harbour libraries with other
+files to produce an executable, this does not by itself cause the
+resulting executable to be covered by the GNU General Public License.
+Your use of that executable is in no way restricted on account of
+linking the Harbour library code into it.
+
+This exception does not however invalidate any other reasons why
+the executable file might be covered by the GNU General Public License.
+
+This exception applies only to the code released by the Harbour
+Project under the name Harbour. If you copy code from other
+Harbour Project or Free Software Foundation releases into a copy of
+Harbour, as the General Public License permits, the exception does
+not apply to the code that you add in this way. To avoid misleading
+anyone as to the status of such modified files, you must delete
+this exception notice from them.
+
+If you write modifications of your own for Harbour, it is your choice
+whether to permit this exception to apply to your modifications.
+If you do not wish that, delete this exception notice.
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index 271bf11402..2bf2a96880 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -218,8 +218,6 @@ string.desc=Z – A
[error]
occurred=Došlo k chybě
-missing_csrf=Špatný požadavek: Neexistuje CSRF token
-invalid_csrf=Špatný požadavek: Neplatný CSRF token
not_found=CÃl nebyl nalezen.
network_error=Chyba sÃtÄ›
@@ -691,7 +689,6 @@ public_profile=Veřejný profil
biography_placeholder=ŘeknÄ›te nám nÄ›co o sobÄ›! (Můžete použÃt Markdown)
location_placeholder=SdÃlejte svou pÅ™ibližnou polohu s ostatnÃmi
profile_desc=Nastavte, jak bude váš profil zobrazen ostatnÃm uživatelům. VaÅ¡e hlavnà e-mailová adresa bude použita pro oznámenÃ, obnovenà hesla a operace Git.
-password_username_disabled=Externà uživatelé nemohou mÄ›nit svoje uživatelské jméno. Kontaktujte prosÃm svého administrátora pro vÃce detailů.
full_name=Celé jméno
website=Web
location=MÃsto
@@ -1701,7 +1698,6 @@ issues.dependency.add_error_dep_not_same_repo=Oba úkoly musà být ve stejném
issues.review.self.approval=Nemůžete schválit svůj pull request.
issues.review.self.rejection=Nemůžete požadovat zmÄ›ny ve svém vlastnÃm pull requestu.
issues.review.approve=schválil tyto změny %s
-issues.review.comment=Okomentovat
issues.review.dismissed=zamÃtl/a posouzenà od %s %s
issues.review.dismissed_label=ZamÃtnuto
issues.review.left_comment=zanechal komentář
@@ -1726,6 +1722,7 @@ issues.review.hide_resolved=Skrýt vyřešené
issues.review.resolve_conversation=Vyřešit konverzaci
issues.review.un_resolve_conversation=Nevyřešit konverzaci
issues.review.resolved_by=oznaÄil tuto konverzaci jako vyÅ™eÅ¡enou
+issues.review.commented=Okomentovat
issues.assignee.error=Ne vÅ¡ichni zpracovatelé byli pÅ™idáni z důvodu neoÄekávané chyby.
issues.reference_issue.body=Tělo zprávy
issues.content_history.deleted=vymazáno
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 78c9f0b41d..4f011663e8 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -213,8 +213,6 @@ string.desc=Z–A
[error]
occurred=Ein Fehler ist aufgetreten
-missing_csrf=Fehlerhafte Anfrage: Kein CSRF Token verfügbar
-invalid_csrf=Fehlerhafte Anfrage: Ungültiger CSRF Token
not_found=Das Ziel konnte nicht gefunden werden.
network_error=Netzwerkfehler
@@ -685,7 +683,6 @@ public_profile=Öffentliches Profil
biography_placeholder=Erzähle uns ein wenig über Dich selbst! (Du kannst Markdown verwenden)
location_placeholder=Teile Deinen ungefähren Standort mit anderen
profile_desc=Lege fest, wie dein Profil anderen Benutzern angezeigt wird. Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und webbasierte Git-Operationen verwendet.
-password_username_disabled=Benutzer, die nicht von Gitea verwaltet werden können ihren Benutzernamen nicht ändern. Bitte kontaktiere deinen Administrator für mehr Details.
full_name=Vollständiger Name
website=Webseite
location=Standort
@@ -1681,7 +1678,6 @@ issues.dependency.add_error_dep_not_same_repo=Beide Issues müssen sich im selbe
issues.review.self.approval=Du kannst nicht dein eigenen Pull-Request genehmigen.
issues.review.self.rejection=Du kannst keine Änderungen an deinem eigenen Pull-Request anfragen.
issues.review.approve=hat die Änderungen %s genehmigt
-issues.review.comment=Kommentieren
issues.review.dismissed=verwarf %ss Review %s
issues.review.dismissed_label=Verworfen
issues.review.left_comment=hat einen Kommentar hinterlassen
@@ -1706,6 +1702,7 @@ issues.review.hide_resolved=Gelöste ausblenden
issues.review.resolve_conversation=Diskussion als "erledigt" markieren
issues.review.un_resolve_conversation=Diskussion als "nicht-erledigt" markieren
issues.review.resolved_by=markierte diese Unterhaltung als gelöst
+issues.review.commented=Kommentieren
issues.assignee.error=Aufgrund eines unerwarteten Fehlers konnten nicht alle Beauftragten hinzugefügt werden.
issues.reference_issue.body=Beschreibung
issues.content_history.deleted=gelöscht
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index ef314b1392..8a82d9353a 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -184,8 +184,6 @@ string.desc=Z - A
[error]
occurred=ΠαÏουσιάστηκε Îνα σφάλμα
-missing_csrf=Bad Request: δεν υπάÏχει διακÏιτικό CSRF
-invalid_csrf=Λάθος Αίτημα: μη ÎγκυÏο διακÏιτικό CSRF
not_found=Ο Ï€ÏοοÏισμός δεν βÏÎθηκε.
network_error=Σφάλμα δικτÏου
@@ -622,7 +620,6 @@ public_profile=Δημόσιο Î Ïοφίλ
biography_placeholder=Πείτε μας λίγο για τον εαυτό σας! (ΜποÏείτε να γÏάψετε με Markdown)
location_placeholder=ΜοιÏαστείτε την κατά Ï€ÏοσÎγγιση τοποθεσία σας με άλλους
profile_desc=ΕλÎγξτε πώς εμφανίζεται το Ï€Ïοφίλ σας σε άλλους χÏήστες. Η κÏÏια διεÏθυνση email σας θα χÏησιμοποιηθεί για ειδοποιήσεις, ανάκτηση ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης και λειτουÏγίες Git που βασίζονται στο web.
-password_username_disabled=Οι μη τοπικοί χÏήστες δεν επιτÏÎπεται να αλλάξουν το όνομα χÏήστη τους. Επικοινωνήστε με το διαχειÏιστή σας για πεÏισσότεÏες λεπτομÎÏειες.
full_name=ΠλήÏες Όνομα
website=Ιστοσελίδα
location=Τοποθεσία
@@ -1603,7 +1600,6 @@ issues.dependency.add_error_dep_not_same_repo=Και τα δÏο ζητήματ
issues.review.self.approval=Δεν μποÏείτε να εγκÏίνετε το δικό σας pull request.
issues.review.self.rejection=Δεν μποÏείτε να ζητήσετε αλλαγÎÏ‚ στο δικό σας pull request.
issues.review.approve=ενÎκÏινε αυτÎÏ‚ τις αλλαγÎÏ‚ %s
-issues.review.comment=Σχόλιο
issues.review.dismissed=απÎÏÏιψε την αξιολόγηση %s %s
issues.review.dismissed_label=ΑποÏÏίφθηκε
issues.review.left_comment=άφησε Îνα σχόλιο
@@ -1628,6 +1624,7 @@ issues.review.hide_resolved=ΑπόκÏυψη επιλυμÎνων
issues.review.resolve_conversation=Επίλυση συνομιλίας
issues.review.un_resolve_conversation=Ανεπίλυτη συνομιλία
issues.review.resolved_by=σημείωση αυτή την συνομιλία ως επιλυμÎνη
+issues.review.commented=Σχόλιο
issues.assignee.error=Δεν Ï€ÏοστÎθηκαν όλοι οι παÏαλήπτες λόγω απÏοσδόκητου σφάλματος.
issues.reference_issue.body=Σώμα
issues.content_history.deleted=διαγÏάφηκε
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 6c4c641077..aebba54ec0 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -159,6 +159,7 @@ filter.public = Public
filter.private = Private
no_results_found = No results found.
+internal_error_skipped = Internal error occurred but is skipped: %s
[search]
search = Search...
@@ -178,6 +179,8 @@ code_search_by_git_grep = Current code search results are provided by "git grep"
package_kind = Search packages...
project_kind = Search projects...
branch_kind = Search branches...
+tag_kind = Search tags...
+tag_tooltip = Search for matching tags. Use '%' to match any sequence of numbers.
commit_kind = Search commits...
runner_kind = Search runners...
no_results = No matching results found.
@@ -220,8 +223,6 @@ string.desc = Z - A
[error]
occurred = An error occurred
report_message = If you believe that this is a Gitea bug, please search for issues on GitHub or open a new issue if necessary.
-missing_csrf = Bad Request: no CSRF token present
-invalid_csrf = Bad Request: invalid CSRF token
not_found = The target couldn't be found.
network_error = Network error
@@ -583,6 +584,8 @@ invalid_slug_error = `Please provide a valid slug.`
username_been_taken = The username is already taken.
username_change_not_local_user = Non-local users are not allowed to change their username.
+change_username_disabled = Changing username is disabled.
+change_full_name_disabled = Changing full name is disabled.
username_has_not_been_changed = Username has not been changed
slug_been_taken = The slug is already taken.
repo_name_been_taken = The repository name is already used.
@@ -709,7 +712,8 @@ public_profile = Public Profile
biography_placeholder = Tell us a little bit about yourself! (You can use Markdown)
location_placeholder = Share your approximate location with others
profile_desc = Control how your profile is show to other users. Your primary email address will be used for notifications, password recovery and web-based Git operations.
-password_username_disabled = Non-local users are not allowed to change their username. Please contact your site administrator for more details.
+password_username_disabled = You are not allowed to change their username. Please contact your site administrator for more details.
+password_full_name_disabled = You are not allowed to change their full name. Please contact your site administrator for more details.
full_name = Full Name
website = Website
location = Location
@@ -1044,6 +1048,7 @@ issue_labels_helper = Select an issue label set.
license = License
license_helper = Select a license file.
license_helper_desc = A license governs what others can and can't do with your code. Not sure which one is right for your project? See Choose a license.
+multiple_licenses = Multiple Licenses
object_format = Object Format
object_format_helper = Object format of the repository. Cannot be changed later. SHA1 is most compatible.
readme = README
@@ -1181,6 +1186,11 @@ migrate.gogs.description = Migrate data from notabug.org or other Gogs instances
migrate.onedev.description = Migrate data from code.onedev.io or other OneDev instances.
migrate.codebase.description = Migrate data from codebasehq.com.
migrate.gitbucket.description = Migrate data from GitBucket instances.
+migrate.codecommit.description = Migrate data from AWS CodeCommit.
+migrate.codecommit.aws_access_key_id = AWS Access Key ID
+migrate.codecommit.aws_secret_access_key = AWS Secret Access Key
+migrate.codecommit.https_git_credentials_username = HTTPS Git Credentials Username
+migrate.codecommit.https_git_credentials_password = HTTPS Git Credentials Password
migrate.migrating_git = Migrating Git Data
migrate.migrating_topics = Migrating Topics
migrate.migrating_milestones = Migrating Milestones
@@ -1279,7 +1289,6 @@ commit_graph.color = Color
commit.contained_in = This commit is contained in:
commit.contained_in_default_branch = This commit is part of the default branch
commit.load_referencing_branches_and_tags = Load branches and tags referencing this commit
-commit.load_tags_failed = Load tags failed because of internal error
blame = Blame
download_file = Download file
normal_view = Normal View
@@ -1757,7 +1766,7 @@ issues.review.hide_resolved = Hide resolved
issues.review.resolve_conversation = Resolve conversation
issues.review.un_resolve_conversation = Unresolve conversation
issues.review.resolved_by = marked this conversation as resolved
-issues.review.comment = Comment
+issues.review.commented = Comment
issues.review.official = Approved
issues.review.requested = Review pending
issues.review.rejected = Changes requested
@@ -1927,6 +1936,7 @@ pulls.delete.text = Do you really want to delete this pull request? (This will p
pulls.recently_pushed_new_branches = You pushed on branch %[1]s %[2]s
pull.deleted_branch = (deleted):%s
+pull.agit_documentation = Review documentation about AGit
comments.edit.already_changed = Unable to save changes to the comment. It appears the content has already been changed by another user. Please refresh the page and try editing again to avoid overwriting their changes
@@ -2942,6 +2952,7 @@ dashboard.start_schedule_tasks = Start actions schedule tasks
dashboard.sync_branch.started = Branches Sync started
dashboard.sync_tag.started = Tags Sync started
dashboard.rebuild_issue_indexer = Rebuild issue indexer
+dashboard.sync_repo_licenses = Sync repo licenses
users.user_manage_panel = User Account Management
users.new_account = Create User Account
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 5c0384b447..423f74f8b2 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -182,8 +182,6 @@ string.desc=Z - A
[error]
occurred=Ha ocurrido un error
-missing_csrf=Solicitud incorrecta: sin token CSRF
-invalid_csrf=Solicitud incorrecta: el token CSRF no es válido
not_found=El objetivo no pudo ser encontrado.
network_error=Error de red
@@ -619,7 +617,6 @@ public_profile=Perfil público
biography_placeholder=¡Cuéntanos un poco sobre ti mismo! (Puedes usar Markdown)
location_placeholder=Comparte tu ubicación aproximada con otros
profile_desc=Controla cómo se muestra su perfil a otros usuarios. Tu dirección de correo electrónico principal se utilizará para notificaciones, recuperación de contraseña y operaciones de Git basadas en la web.
-password_username_disabled=Usuarios no locales no tienen permitido cambiar su nombre de usuario. Por favor, contacta con el administrador del sistema para más detalles.
full_name=Nombre completo
website=Página web
location=Localización
@@ -1593,7 +1590,6 @@ issues.dependency.add_error_dep_not_same_repo=Ambas incidencias deben estar en e
issues.review.self.approval=No puede aprobar su propio pull request.
issues.review.self.rejection=No puede sugerir cambios en su propio pull request.
issues.review.approve=aprobado estos cambios %s
-issues.review.comment=Comentario
issues.review.dismissed=descartó la revisión de %s %s
issues.review.dismissed_label=Descartado
issues.review.left_comment=dejó un comentario
@@ -1618,6 +1614,7 @@ issues.review.hide_resolved=Ocultar resueltos
issues.review.resolve_conversation=Resolver conversación
issues.review.un_resolve_conversation=Marcar conversación sin resolver
issues.review.resolved_by=ha marcado esta conversación como resuelta
+issues.review.commented=Comentario
issues.assignee.error=No todos los asignados fueron añadidos debido a un error inesperado.
issues.reference_issue.body=Cuerpo
issues.content_history.deleted=borrado
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index b141c7959e..33d72ee7eb 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -118,7 +118,6 @@ filter.private=خصوصی
[filter]
[error]
-missing_csrf=درخواست بد: بلیط CSRF ندارد
[startpage]
app_desc=یک سرویس گیت بی‌درد سر Ùˆ راØت
@@ -492,7 +491,6 @@ account_link=Øساب‌های مرتبط
organization=سازمان ها
public_profile=نمایه عمومی
-password_username_disabled=Øساب‌های غیر Ù…ØÙ„ÛŒ مجاز به تغییر نام کاربری نیستند. لطÙا با مدیر سایت در ارتباط باشید.
full_name=نام کامل
website=تارنما
location=موقعیت مکانی
@@ -1235,7 +1233,6 @@ issues.dependency.add_error_dep_not_same_repo=هر دو موضوع باید از
issues.review.self.approval=شما نمی‌توانید تقاضای واکشی خود را تایید کنید.
issues.review.self.rejection=شما نمی‌توانید تقاضا تغییرات تقاضای واکشی خود را تغییر دهید.
issues.review.approve=این تغییرات را تایید شدند %s
-issues.review.comment=دیدگاه
issues.review.dismissed=بررسی %s %s را رد شده
issues.review.dismissed_label=رها شده
issues.review.left_comment=یک نظر ثبت کرد
@@ -1256,6 +1253,7 @@ issues.review.hide_resolved=مخÙÛŒ کردن ØÙ„ شده ها
issues.review.resolve_conversation=مکالمه را بعنوان ØÙ„ شده علامت گذاری کردن
issues.review.un_resolve_conversation=مکالمه را بعنوان ØÙ„ نشده علامت گذاری کردن
issues.review.resolved_by=علامت گذاری این مکالمه بعنوان ØÙ„ شده
+issues.review.commented=دیدگاه
issues.assignee.error=به دلیل خطای غیرمنتظره همه تکالی٠اضاÙÙ‡ نشد.
issues.reference_issue.body=Body
issues.content_history.deleted=Øذ٠شده
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index 1f8143ad84..d16efb8834 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -133,8 +133,6 @@ filter.private=Yksityinen
[error]
occurred=Virhe tapahtui
-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
@@ -453,7 +451,6 @@ account_link=Linkitetyt tilit
organization=Organisaatiot
public_profile=Julkinen profiili
-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
website=Nettisivut
location=Sijainti
@@ -955,6 +952,7 @@ issues.review.left_comment=jätti kommentin
issues.review.pending=Odottaa
issues.review.show_resolved=Näytä ratkaisu
issues.review.hide_resolved=Piilota ratkaisu
+issues.review.commented=Kommentoi
issues.reference_issue.body=Kuvaus
issues.content_history.deleted=poistettu
issues.content_history.edited=muokattu
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index 4866f931ba..e64c85b7a4 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -31,6 +31,7 @@ username=Nom d'utilisateur
email=Courriel
password=Mot de passe
access_token=Jeton d’accès
+re_type=Confirmez le mot de passe
captcha=CAPTCHA
twofa=Authentification à deux facteurs
twofa_scratch=Code de secours pour l'authentification à deux facteurs
@@ -158,6 +159,7 @@ filter.public=Public
filter.private=Privé
no_results_found=Aucun résultat trouvé.
+internal_error_skipped=Une erreur interne est survenue, mais ignorée : %s
[search]
search=Rechercher…
@@ -176,6 +178,8 @@ code_search_by_git_grep=Les résultats de recherche de code actuels sont fournis
package_kind=Chercher des paquets…
project_kind=Chercher des projets…
branch_kind=Chercher des branches…
+tag_kind=Chercher des étiquettes…
+tag_tooltip=Cherchez des étiquettes correspondantes. Utilisez « % » pour rechercher n’importe quelle suite de nombres.
commit_kind=Chercher des révisions…
runner_kind=Chercher des exécuteurs…
no_results=Aucun résultat correspondant trouvé.
@@ -217,18 +221,20 @@ string.desc=Z - A
[error]
occurred=Une erreur s’est produite
-missing_csrf=Requête incorrecte: aucun jeton CSRF présent
-invalid_csrf=Requête incorrecte : jeton CSRF invalide
+report_message=Si vous pensez qu’il s’agit d’un bug Gitea, veuillez consulter notre board GitHub ou ouvrir un nouveau ticket si nécessaire.
not_found=La cible n'a pu être trouvée.
network_error=Erreur réseau
[startpage]
app_desc=Un service Git auto-hébergé sans prise de tête
install=Facile à installer
+install_desc=Il suffit de lancer l’exécutable adapté à votre plateforme, le déployer avec Docker ou de l’installer depuis un gestionnaire de paquet.
platform=Multi-plateforme
+platform_desc=Gitea tourne partout où Go peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré !
lightweight=Léger
lightweight_desc=Gitea utilise peu de ressources. Il peut même tourner sur un Raspberry Pi très bon marché. Économisez l'énergie de vos serveurs !
license=Open Source
+license_desc=Venez récupérer %[2]s ! Rejoignez-nous en contribuant à rendre ce projet encore meilleur !
[install]
install=Installation
@@ -312,6 +318,7 @@ admin_setting_desc=La création d'un compte administrateur est facultative. Le p
admin_title=Paramètres de compte administrateur
admin_name=Nom d’utilisateur administrateur
admin_password=Mot de passe
+confirm_password=Confirmez le mot de passe
admin_email=Courriel
install_btn_confirm=Installer Gitea
test_git_failed=Le test de la commande "git" a échoué : %v
@@ -450,6 +457,7 @@ authorize_title=Autoriser "%s" à accéder à votre compte ?
authorization_failed=L’autorisation a échoué
authorization_failed_desc=L'autorisation a échoué car nous avons détecté une demande incorrecte. Veuillez contacter le responsable de l'application que vous avez essayé d'autoriser.
sspi_auth_failed=Échec de l'authentification SSPI
+password_pwned=Le mot de passe que vous avez choisi fait partit des mots de passe ayant fuité sur internet. Veuillez réessayer avec un mot de passe différent et considérez remplacer ce mot de passe si vous l’utilisez ailleurs.
password_pwned_err=Impossible d'envoyer la demande à HaveIBeenPwned
last_admin=Vous ne pouvez pas supprimer ce compte car au moins un administrateur est requis.
signin_passkey=Se connecter avec une clé d’identification (passkey)
@@ -533,6 +541,7 @@ UserName=Nom d'utilisateur
RepoName=Nom du dépôt
Email=Courriel
Password=Mot de passe
+Retype=Confirmez le mot de passe
SSHTitle=Nom de la clé SSH
HttpsUrl=URL HTTPS
PayloadUrl=URL des données utiles
@@ -686,15 +695,16 @@ applications=Applications
orgs=Gérer les organisations
repos=Dépôts
delete=Supprimer le compte
+twofa=Authentification à deux facteurs (TOTP)
account_link=Comptes liés
organization=Organisations
uid=UID
+webauthn=Authentification à deux facteurs (Clés de sécurité)
public_profile=Profil public
biography_placeholder=Parlez-nous un peu de vous ! (Vous pouvez utiliser Markdown)
location_placeholder=Partagez votre position approximative avec d'autres personnes
profile_desc=Contrôlez comment votre profil est affiché aux autres utilisateurs. Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et les opérations Git basées sur le Web.
-password_username_disabled=Les utilisateurs externes ne sont pas autorisés à modifier leur nom d'utilisateur. Veuillez contacter l'administrateur de votre site pour plus de détails.
full_name=Nom complet
website=Site Web
location=Localisation
@@ -786,6 +796,7 @@ add_email_success=La nouvelle adresse e-mail a été ajoutée.
email_preference_set_success=L'e-mail de préférence a été défini avec succès.
add_openid_success=La nouvelle adresse OpenID a été ajoutée.
keep_email_private=Cacher l'adresse e-mail
+keep_email_private_popup=Ceci masquera votre adresse e-mail de votre profil, de vos demandes d’ajout et des fichiers modifiés depuis l'interface Web. Les révisions déjà soumises ne seront pas modifiés. Utilisez %s dans les révisions pour les associer à votre compte.
openid_desc=OpenID vous permet de confier l'authentification à une tierce partie.
manage_ssh_keys=Gérer les clés SSH
@@ -924,20 +935,26 @@ revoke_oauth2_grant=Révoquer l'accès
revoke_oauth2_grant_description=La révocation de l'accès à cette application tierce l'empêchera d'accéder à vos données. Vous êtes sûr ?
revoke_oauth2_grant_success=Accès révoqué avec succès.
+twofa_desc=Pour protéger votre compte contre les vols de mot de passes, vous pouvez utiliser un smartphone ou autres appareils pour recevoir un code temporaire à usage unique (TOTP).
twofa_recovery_tip=Si vous perdez votre appareil, vous pourrez utiliser une clé de récupération à usage unique pour obtenir l’accès à votre compte.
twofa_is_enrolled=Votre compte est inscrit à l'authentification à deux facteurs.
twofa_not_enrolled=Votre compte n'est pas inscrit à l'authentification à deux facteurs.
twofa_disable=Désactiver l'authentification à deux facteurs
+twofa_scratch_token_regenerate=Régénérer une clé de secours à usage unique
+twofa_scratch_token_regenerated=Votre clé de secours à usage unique est désormais « %s ». Stockez-la dans un endroit sûr, elle ne sera plus jamais affichée.
twofa_enroll=Activer l'authentification à deux facteurs
twofa_disable_note=Vous pouvez désactiver l'authentification à deux facteurs si nécessaire.
twofa_disable_desc=Désactiver l'authentification à deux facteurs rendra votre compte plus vulnérable. Confirmer ?
+regenerate_scratch_token_desc=Si vous avez égaré votre clé de secours ou avez dû l’utiliser pour vous authentifier, vous pouvez la régénérer.
twofa_disabled=L'authentification à deux facteurs a été désactivée.
scan_this_image=Scannez cette image avec votre application d'authentification :
or_enter_secret=Ou saisissez le code %s
then_enter_passcode=Et entrez le code de passe s'affichant dans l'application :
passcode_invalid=Le mot de passe est invalide. Réessayez.
+twofa_enrolled=L’authentification à deux facteurs a été activée pour votre compte. Gardez votre clé de secours (%s) en lieu sûr, car il ne vous sera montré qu'une seule fois.
twofa_failed_get_secret=Impossible d'obtenir le secret.
+webauthn_desc=Les clefs de sécurité sont des dispositifs matériels contenant des clefs cryptographiques. Elles peuvent être utilisées pour l’authentification à deux facteurs. La clef de sécurité doit supporter le standard WebAuthn Authenticator.
webauthn_register_key=Ajouter une clé de sécurité
webauthn_nickname=Pseudonyme
webauthn_delete_key=Retirer la clé de sécurité
@@ -1082,7 +1099,9 @@ tree_path_not_found_branch=Le chemin %[1]s n’existe pas dans la branche %[2]s.
tree_path_not_found_tag=Le chemin %[1]s n’existe pas dans l’étiquette %[2]s.
transfer.accept=Accepter le transfert
+transfer.accept_desc=Transférer à  « %s »
transfer.reject=Refuser le transfert
+transfer.reject_desc=Annuler le transfert à « %s »
transfer.no_permission_to_accept=Vous n’êtes pas autorisé à accepter ce transfert.
transfer.no_permission_to_reject=Vous n’êtes pas autorisé à rejeter ce transfert.
@@ -1157,6 +1176,11 @@ migrate.gogs.description=Migrer les données depuis notabug.org ou d’autres in
migrate.onedev.description=Migrer les données depuis code.onedev.io ou d’autre instance de OneDev.
migrate.codebase.description=Migrer les données depuis codebasehq.com.
migrate.gitbucket.description=Migrer les données depuis des instances GitBucket.
+migrate.codecommit.description=Migrer les données depuis AWS CodeCommit.
+migrate.codecommit.aws_access_key_id=ID de la clé d’accès AWS
+migrate.codecommit.aws_secret_access_key=Clé d’accès secrète AWS
+migrate.codecommit.https_git_credentials_username=Nom d’utilisateur Git HTTPS
+migrate.codecommit.https_git_credentials_password=Mot de passe Git HTTPS
migrate.migrating_git=Migration des données Git
migrate.migrating_topics=Migration des sujets
migrate.migrating_milestones=Migration des jalons
@@ -1217,6 +1241,7 @@ releases=Publications
tag=Étiquette
released_this=a publié ceci
tagged_this=a étiqueté
+file.title=%s sur %s
file_raw=Brut
file_history=Historique
file_view_source=Voir le code source
@@ -1254,7 +1279,6 @@ commit_graph.color=Couleur
commit.contained_in=Cette révision appartient à :
commit.contained_in_default_branch=Cette révision appartient à la branche par défaut
commit.load_referencing_branches_and_tags=Charger les branches et étiquettes référençant cette révision
-commit.load_tags_failed=Le chargement des étiquettes a échoué à cause d’une erreur interne
blame=Annotations
download_file=Télécharger le fichier
normal_view=Vue normale
@@ -1457,6 +1481,7 @@ issues.remove_labels=a supprimé les labels %s %s.
issues.add_remove_labels=a ajouté le label %s et supprimé %s %s.
issues.add_milestone_at=`a ajouté ça au jalon %s %s.`
issues.add_project_at=`a ajouté ça au projet %s %s.`
+issues.move_to_column_of_project=`a déplacé ça vers %s dans %s sur %s`
issues.change_milestone_at=`a remplacé le jalon %s par %s %s.`
issues.change_project_at=`a remplacé le projet %s par %s %s.`
issues.remove_milestone_at=`a supprimé ça du jalon %s %s.`
@@ -1705,10 +1730,10 @@ issues.dependency.add_error_dep_not_same_repo=Les deux tickets doivent être dan
issues.review.self.approval=Vous ne pouvez approuver vos propres demandes d'ajout.
issues.review.self.rejection=Vous ne pouvez demander de changements sur vos propres demandes de changement.
issues.review.approve=a approuvé ces modifications %s.
-issues.review.comment=Commenter
+issues.review.comment=a évalué %s
issues.review.dismissed=a révoqué l’évaluation de %s %s.
issues.review.dismissed_label=Révoquée
-issues.review.left_comment=laisser un commentaire
+issues.review.left_comment=à laissé un commentaire
issues.review.content.empty=Vous devez laisser un commentaire indiquant le(s) changement(s) demandé(s).
issues.review.reject=a requis les changements %s
issues.review.wait=a été sollicité pour évaluer cette demande d’ajout %s.
@@ -1730,6 +1755,12 @@ issues.review.hide_resolved=Réduire
issues.review.resolve_conversation=Clore la conversation
issues.review.un_resolve_conversation=Rouvrir la conversation
issues.review.resolved_by=a marqué cette conversation comme résolue.
+issues.review.commented=À commenté
+issues.review.official=Approuvée
+issues.review.requested=Évaluation en attente
+issues.review.rejected=Changements demandées
+issues.review.stale=Modifiée depuis la dernière approbation
+issues.review.unofficial=Approbation non comptabilisée
issues.assignee.error=Tous les assignés n'ont pas été ajoutés en raison d'une erreur inattendue.
issues.reference_issue.body=Corps
issues.content_history.deleted=a supprimé
@@ -1803,6 +1834,8 @@ pulls.is_empty=Les changements sur cette branche sont déjà sur la branche cibl
pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi.
pulls.required_status_check_missing=Certains contrôles requis sont manquants.
pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull.
+pulls.blocked_by_approvals=Cette demande d'ajout n’est pas suffisamment approuvée. %d approbations obtenues sur %d.
+pulls.blocked_by_approvals_whitelisted=Cette demande d’ajout n’a pas encore assez d’approbations. %d sur %d approbations de la part des utilisateurs ou équipes sur la liste autorisée.
pulls.blocked_by_rejection=Cette demande d’ajout nécessite des corrections sollicitées par un évaluateur officiel.
pulls.blocked_by_official_review_requests=Cette demande d’ajout a des sollicitations officielles d’évaluation.
pulls.blocked_by_outdated_branch=Cette demande d’ajout est bloquée car elle est obsolète.
@@ -1844,7 +1877,9 @@ pulls.unrelated_histories=Échec de la fusion: La tête de fusion et la base ne
pulls.merge_out_of_date=Échec de la fusion: La base a été mise à jour en cours de fusion. Indice : Réessayez.
pulls.head_out_of_date=Échec de la fusion : L’en-tête a été mis à jour pendant la fusion. Conseil : réessayez.
pulls.has_merged=Échec : La demande d’ajout est déjà fusionnée, vous ne pouvez plus la fusionner, ni modifier sa branche cible.
+pulls.push_rejected=Échec de la fusion : la soumission a été rejetée. Revoyez les déclencheurs Git pour ce dépôt.
pulls.push_rejected_summary=Message de rejet complet
+pulls.push_rejected_no_message=Échec de la fusion : la soumission a été rejetée sans raison. Revoyez les déclencheurs Git pour ce dépôt.
pulls.open_unmerged_pull_exists=`Vous ne pouvez pas rouvrir ceci car la demande d’ajout #%d, en attente, a des propriétés identiques.`
pulls.status_checking=Certains contrôles sont en attente
pulls.status_checks_success=Tous les contrôles ont réussi
@@ -1868,6 +1903,7 @@ pulls.cmd_instruction_checkout_title=Basculer
pulls.cmd_instruction_checkout_desc=Depuis votre dépôt, basculer sur une nouvelle branche et tester des modifications.
pulls.cmd_instruction_merge_title=Fusionner
pulls.cmd_instruction_merge_desc=Fusionner les modifications et mettre à jour sur Gitea.
+pulls.cmd_instruction_merge_warning=Attention : cette opération ne peut pas fusionner la demande d’ajout car la « détection automatique de fusion manuelle » n’a pas été activée
pulls.clear_merge_message=Effacer le message de fusion
pulls.clear_merge_message_hint=Effacer le message de fusion ne supprimera que le message de la révision, mais pas les pieds de révision générés tels que "Co-Authored-By:".
@@ -1889,6 +1925,7 @@ pulls.delete.text=Voulez-vous vraiment supprimer cet demande d'ajout ? (Cela sup
pulls.recently_pushed_new_branches=Vous avez soumis sur la branche %[1]s %[2]s
pull.deleted_branch=(supprimé) : %s
+pull.agit_documentation=Voir la documentation sur AGit
comments.edit.already_changed=Impossible d’enregistrer ce commentaire. Il semble que le contenu ait été modifié par un autre utilisateur. Veuillez rafraîchir la page et réessayer afin d’éviter d’écraser leurs modifications.
@@ -1899,6 +1936,7 @@ milestones.no_due_date=Aucune date d'échéance
milestones.open=Ouvrir
milestones.close=Fermer
milestones.new_subheader=Les jalons peuvent vous aider à organiser vos tickets et à suivre leurs progrès.
+milestones.completeness=%d%% complété
milestones.create=Créer un Jalon
milestones.title=Titre
milestones.desc=Description
@@ -2083,7 +2121,8 @@ settings.push_mirror_sync_in_progress=Versement des changements vers le miroir d
settings.site=Site Web
settings.update_settings=Appliquer
settings.update_mirror_settings=Mettre à jour les paramètres du miroir
-settings.branches.update_default_branch=Changer la Branche par Défaut
+settings.branches.switch_default_branch=Changer la branche par défaut
+settings.branches.update_default_branch=Changer la branche par défaut
settings.branches.add_new_rule=Ajouter une nouvelle règle
settings.advanced_settings=Paramètres avancés
settings.wiki_desc=Activer le wiki du dépôt
@@ -2120,6 +2159,7 @@ settings.pulls.default_delete_branch_after_merge=Supprimer la branche après la
settings.pulls.default_allow_edits_from_maintainers=Autoriser les modifications par les mainteneurs par défaut
settings.releases_desc=Activer les publications du dépôt
settings.packages_desc=Activer le registre des paquets du dépôt
+settings.projects_desc=Activer les projets de dépôt
settings.projects_mode_desc=Mode Projets (type de projets à afficher)
settings.projects_mode_repo=Projets de dépôt uniquement
settings.projects_mode_owner=Projets d’utilisateur ou d’organisation uniquement
@@ -2159,6 +2199,7 @@ settings.transfer_in_progress=Il y a actuellement un transfert en cours. Veuille
settings.transfer_notices_1=- Vous perdrez l'accès à ce dépôt si vous le transférez à un autre utilisateur.
settings.transfer_notices_2=- Vous conserverez l'accès à ce dépôt si vous le transférez à une organisation dont vous êtes (co-)propriétaire.
settings.transfer_notices_3=- Si le dépôt est privé et est transféré à un utilisateur individuel, cette action s'assure que l'utilisateur a au moins la permission de lire (et modifie les permissions si nécessaire).
+settings.transfer_notices_4=- Si le dépôt appartient à une organisation et que vous le transférez à une autre organisation ou personne, vous perdrez les liens entre les tickets du dépôt et le tableau de projet de l’organisation.
settings.transfer_owner=Nouveau propriétaire
settings.transfer_perform=Effectuer le transfert
settings.transfer_started=`Ce dépôt a été marqué pour le transfert et attend la confirmation de "%s"`
@@ -2295,6 +2336,7 @@ settings.event_pull_request_merge=Fusion de demande d'ajout
settings.event_package=Paquet
settings.event_package_desc=Paquet créé ou supprimé.
settings.branch_filter=Filtre de branche
+settings.branch_filter_desc=Liste de branches et motifs globs autorisant la soumission, la création et suppression de branches. Laisser vide ou utiliser *
englobent toutes les branches. Voir la %[2]s. Exemples : master
, {master,release*}
.
settings.authorization_header=En-tête « Authorization »
settings.authorization_header_desc=Si présent, sera ajouté aux requêtes comme en-tête d’authentification. Exemples : %s.
settings.active=Actif
@@ -2340,9 +2382,13 @@ settings.deploy_key_deletion=Supprimer une clef de déploiement
settings.deploy_key_deletion_desc=La suppression d'une clef de déploiement révoque son accès à ce dépôt. Continuer ?
settings.deploy_key_deletion_success=La clé de déploiement a été supprimée.
settings.branches=Branches
+settings.protected_branch=Protection de branche
settings.protected_branch.save_rule=Enregistrer la règle
settings.protected_branch.delete_rule=Supprimer la règle
settings.protected_branch_can_push=Autoriser la soumission ?
+settings.protected_branch_can_push_yes=Vous pouvez soumettre
+settings.protected_branch_can_push_no=Vous ne pouvez pas soumettre
+settings.branch_protection=Paramètres de protection de branches pour la branche %s
settings.protect_this_branch=Activer la protection de branche
settings.protect_this_branch_desc=Empêche les suppressions et limite les poussées et fusions sur cette branche.
settings.protect_disable_push=Désactiver la soumission
@@ -2372,11 +2418,13 @@ settings.protect_merge_whitelist_teams=Équipes autorisées à fusionner :
settings.protect_check_status_contexts=Activer le Contrôle Qualité
settings.protect_status_check_patterns=Motifs de vérification des statuts :
settings.protect_status_check_patterns_desc=Entrez des motifs pour spécifier quelles vérifications doivent réussir avant que des branches puissent être fusionnées. Un motif par ligne. Un motif ne peut être vide.
+settings.protect_check_status_contexts_desc=Exiger le status « succès » avant de fusionner. Quand activée, une branche protégée ne peux accepter que des soumissions ou des fusions ayant le status « succès ». Lorsqu'il n’y a pas de contexte, la dernière révision fait foi.
settings.protect_check_status_contexts_list=Contrôles qualité trouvés au cours de la semaine dernière pour ce dépôt
settings.protect_status_check_matched=Correspondant
settings.protect_invalid_status_check_pattern=Motif de vérification des statuts incorrect : « %s ».
settings.protect_no_valid_status_check_patterns=Aucun motif de vérification des statuts valide.
settings.protect_required_approvals=Minimum d'approbations requis :
+settings.protect_required_approvals_desc=Permet de fusionner les demandes d’ajout lorsque suffisamment d’évaluation sont positives.
settings.protect_approvals_whitelist_enabled=Restreindre les approbations aux utilisateurs ou aux équipes sur liste d’autorisés
settings.protect_approvals_whitelist_enabled_desc=Seuls les évaluations des utilisateurs ou des équipes suivantes compteront dans les approbations requises. Si laissé vide, les évaluations de toute personne ayant un accès en écriture seront comptabilisées à la place.
settings.protect_approvals_whitelist_users=Évaluateurs autorisés :
@@ -2388,12 +2436,18 @@ settings.ignore_stale_approvals_desc=Ignorer les approbations d’anciennes rév
settings.require_signed_commits=Exiger des révisions signées
settings.require_signed_commits_desc=Rejeter les soumissions sur cette branche lorsqu'ils ne sont pas signés ou vérifiables.
settings.protect_branch_name_pattern=Motif de nom de branche protégé
+settings.protect_branch_name_pattern_desc=Motifs de nom de branche protégé. Consultez la documentation pour la syntaxe du motif. Exemples : main
, release/**
settings.protect_patterns=Motifs
settings.protect_protected_file_patterns=Liste des fichiers et motifs protégés
+settings.protect_protected_file_patterns_desc=Liste de fichiers et de motifs, séparés par un point-virgule « ; », qui ne pourront pas être modifiés même si les utilisateurs disposent des droits sur la branche. Consultez la %[2]s. Exemples : .drone.yml ; /docs/**/*.txt
.
settings.protect_unprotected_file_patterns=Liste des fichiers et motifs exclus
+settings.protect_unprotected_file_patterns_desc=Liste de fichiers et de motifs globs, séparés par un point-virgule « ; », qui pourront être modifiés malgré la protection de branche, par les utilisateurs autorisés. Voir la %[2]s. Exemples : .drone.yml ; /docs/**/*.txt
.
+settings.add_protected_branch=Activer la protection
+settings.delete_protected_branch=Désactiver la protection
settings.update_protect_branch_success=La règle de protection de branche "%s" a été mise à jour.
settings.remove_protected_branch_success=La règle de protection de branche "%s" a été retirée.
settings.remove_protected_branch_failed=Impossible de retirer la règle de protection de branche "%s".
+settings.protected_branch_deletion=Désactiver la protection de branche
settings.protected_branch_deletion_desc=Désactiver la protection de branche permet aux utilisateurs ayant accès en écriture de pousser des modifications sur la branche. Continuer ?
settings.block_rejected_reviews=Bloquer la fusion en cas d’évaluations négatives
settings.block_rejected_reviews_desc=La fusion ne sera pas possible lorsque des modifications sont demandées par les évaluateurs officiels, même s'il y a suffisamment d’approbations.
@@ -2403,6 +2457,7 @@ settings.block_outdated_branch=Bloquer la fusion si la demande d'ajout est obsol
settings.block_outdated_branch_desc=La fusion ne sera pas possible lorsque la branche principale est derrière la branche de base.
settings.default_branch_desc=Sélectionnez une branche par défaut pour les demandes de fusion et les révisions :
settings.merge_style_desc=Styles de fusion
+settings.default_merge_style_desc=Méthode de fusion par défaut
settings.choose_branch=Choisissez une branche…
settings.no_protected_branch=Il n'y a pas de branche protégée.
settings.edit_protected_branch=Éditer
@@ -2418,12 +2473,25 @@ settings.tags.protection.allowed.teams=Équipes autorisées
settings.tags.protection.allowed.noone=Personne
settings.tags.protection.create=Protéger l'étiquette
settings.tags.protection.none=Il n'y a pas d'étiquettes protégées.
+settings.tags.protection.pattern.description=Vous pouvez utiliser au choix un nom unique, un motif de glob ou une expression régulière qui correspondra à plusieurs étiquettes. Pour plus d’informations, consultez le guide sur les étiquettes protégées.
settings.bot_token=Jeton de Bot
settings.chat_id=ID de conversation
settings.thread_id=ID du fil
settings.matrix.homeserver_url=URL du serveur d'accueil
settings.matrix.room_id=ID de la salle
settings.matrix.message_type=Type de message
+settings.visibility.private.button=Rendre privé
+settings.visibility.private.text=Rendre le dépôt privé rendra non seulement le dépôt visible uniquement aux membres autorisés, mais peut également rompre la relation entre lui et ses bifurcations, observateurs, et favoris.
+settings.visibility.private.bullet_title=Changer la visibilité en privé :
+settings.visibility.private.bullet_one=Va rendre le dépôt visible uniquement par les membres autorisés
+settings.visibility.private.bullet_two=Peut supprimer la relation avec ses bifurcations, ses observateurs et ses favoris
+settings.visibility.public.button=Rendre public
+settings.visibility.public.text=Rendre le dépôt public rendra le dépôt visible à tout le monde.
+settings.visibility.public.bullet_title=Changer la visibilité en public va :
+settings.visibility.public.bullet_one=Rendre le dépôt visible à tout le monde.
+settings.visibility.success=Visibilité du dépôt changée.
+settings.visibility.error=Une erreur s’est produite en essayant de changer la visibilité du dépôt.
+settings.visibility.fork_error=Impossible de changer la visibilité d’un dépôt bifurqué.
settings.archive.button=Archiver ce dépôt
settings.archive.header=Archiver ce dépôt
settings.archive.text=Archiver un dépôt le place en lecture seule et le cache des tableaux de bord. Personne ne pourra faire de nouvelles révisions, d'ouvrir des tickets ou des demandes d'ajouts (pas même vous!).
@@ -2620,6 +2688,7 @@ tag.create_success=L'étiquette "%s" a été créée.
topic.manage_topics=Gérer les sujets
topic.done=Terminé
+topic.count_prompt=Vous ne pouvez pas sélectionner plus de 25 sujets
topic.format_prompt=Les sujets doivent commencer par un caractère alphanumérique, peuvent inclure des traits d’union « - » et des points « . », et mesurer jusqu'à 35 caractères. Les lettres doivent être en minuscules.
find_file.go_to_file=Aller au fichier
@@ -2786,6 +2855,7 @@ last_page=Dernière
total=Total : %d
settings=Paramètres administrateur
+dashboard.new_version_hint=Gitea %s est maintenant disponible, vous utilisez %s. Consultez le blog pour plus de détails.
dashboard.statistic=Résumé
dashboard.maintenance_operations=Opérations de maintenance
dashboard.system_status=État du système
@@ -2828,6 +2898,7 @@ dashboard.reinit_missing_repos=Réinitialiser tous les dépôts Git manquants po
dashboard.sync_external_users=Synchroniser les données de l’utilisateur externe
dashboard.cleanup_hook_task_table=Nettoyer la table hook_task
dashboard.cleanup_packages=Nettoyer des paquets expirés
+dashboard.cleanup_actions=Nettoyer les reliquats des actions obsolètes
dashboard.server_uptime=Uptime du serveur
dashboard.current_goroutine=Goroutines actuelles
dashboard.current_memory_usage=Utilisation Mémoire actuelle
@@ -2857,9 +2928,15 @@ dashboard.total_gc_time=Pause GC
dashboard.total_gc_pause=Pause GC
dashboard.last_gc_pause=Dernière Pause GC
dashboard.gc_times=Nombres de GC
+dashboard.delete_old_actions=Supprimer toutes les anciennes activités de la base de données
+dashboard.delete_old_actions.started=La suppression des anciennes activités de la base de données a démarré.
dashboard.update_checker=Vérificateur de mise à jour
dashboard.delete_old_system_notices=Supprimer toutes les anciennes observations de la base de données
dashboard.gc_lfs=Épousseter les métaobjets LFS
+dashboard.stop_zombie_tasks=Arrêter les tâches zombies
+dashboard.stop_endless_tasks=Arrêter les tâches interminables
+dashboard.cancel_abandoned_jobs=Annuler les travaux abandonnés
+dashboard.start_schedule_tasks=Démarrer les tâches planifiées
dashboard.sync_branch.started=Début de la synchronisation des branches
dashboard.sync_tag.started=Synchronisation des étiquettes
dashboard.rebuild_issue_indexer=Reconstruire l’indexeur des tickets
@@ -2970,10 +3047,12 @@ packages.size=Taille
packages.published=Publiés
defaulthooks=Déclencheurs web par défaut
+defaulthooks.desc=Les webhooks font automatiquement des requêtes POST HTTP à un serveur spécifié lorsque certains événements Gitea se déclenchent. Ceux créés ici sont par défaut copiés sur tous les nouveaux dépôts. Pour plus d'information, consultez le guide des webhooks.
defaulthooks.add_webhook=Ajouter un déclencheur web par défaut
defaulthooks.update_webhook=Mettre à jour le déclencheur web par défaut
systemhooks=Webhooks système
+systemhooks.desc=Les webhooks font automatiquement des requêtes POST HTTP à un serveur spécifié lorsque certains événements Gitea se déclenchent. Ceux créé ici agiront sur tous les dépôts, ce qui peux impacter les performances du système. Pour plus d’information, consultez le guide des webhooks.
systemhooks.add_webhook=Ajouter un rappel système
systemhooks.update_webhook=Mettre à jour un rappel système
@@ -3068,8 +3147,18 @@ auths.tips=Conseils
auths.tips.oauth2.general=Authentification OAuth2
auths.tips.oauth2.general.tip=Lors de l'enregistrement d'une nouvelle authentification OAuth2, l'URL de rappel/redirection doit être :
auths.tip.oauth2_provider=Fournisseur OAuth2
+auths.tip.bitbucket=Créez un nouveau jeton OAuth sur %s et ajoutez la permission « Compte » → « Lecture ».
auths.tip.nextcloud=`Enregistrez un nouveau consommateur OAuth sur votre instance en utilisant le menu "Paramètres -> Sécurité -> Client OAuth 2.0"`
+auths.tip.dropbox=Créez une nouvelle application sur %s
+auths.tip.facebook=Enregistrez une nouvelle application sur%s et ajoutez le produit « Facebook Login ».
+auths.tip.github=Créez une nouvelle application OAuth sur %s
+auths.tip.gitlab_new=Enregistrez une nouvelle application sur %s
+auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Google (%s)
auths.tip.openid_connect=Utilisez l’URL de découverte OpenID « https://{server}/.well-known/openid-configuration » pour spécifier les points d'accès.
+auths.tip.twitter=Rendez-vous sur %s, créez une application et assurez-vous que l’option « Autoriser l’application à être utilisée avec Twitter Connect » est activée.
+auths.tip.discord=Enregistrer une nouvelle application sur %s
+auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur %s.
+auths.tip.yandex=Créez une nouvelle application sur %s. Sélectionnez les autorisations suivantes dans la section « Yandex.Passport API » : « Accès à l’adresse e-mail », « Accès à l’avatar de l’utilisateur » et « Accès au nom d’utilisateur, prénom, surnom et genre ».
auths.tip.mastodon=Entrez une URL d'instance personnalisée pour l'instance mastodon avec laquelle vous voulez vous authentifier (ou utiliser celle par défaut)
auths.edit=Mettre à jour la source d'authentification
auths.activated=Cette source d'authentification est activée
@@ -3243,6 +3332,8 @@ monitor.start=Heure de démarrage
monitor.execute_time=Heure d'Éxécution
monitor.last_execution_result=Résultat
monitor.process.cancel=Annuler le processus
+monitor.process.cancel_desc=L’annulation d’un processus peut entraîner une perte de données.
+monitor.process.cancel_notices=Annuler : %s ?
monitor.process.children=Enfant
monitor.queues=Files d'attente
@@ -3344,6 +3435,7 @@ raw_minutes=minutes
[dropzone]
default_message=Déposez les fichiers ou cliquez ici pour téléverser.
+invalid_input_type=Vous ne pouvez pas téléverser des fichiers de ce type.
file_too_big=La taille du fichier ({{filesize}} Mo) dépasse la taille maximale ({{maxFilesize}} Mo).
remove_file=Supprimer le fichier
@@ -3615,6 +3707,7 @@ runs.no_workflows.quick_start=Vous découvrez les Actions Gitea ? Consultez la documentation.
runs.no_runs=Le flux de travail n'a pas encore d'exécution.
runs.empty_commit_message=(message de révision vide)
+runs.expire_log_message=Les journaux ont été supprimés car ils étaient trop anciens.
workflow.disable=Désactiver le flux de travail
workflow.disable_success=Le flux de travail « %s » a bien été désactivé.
@@ -3646,6 +3739,7 @@ variables.update.failed=Impossible d’éditer la variable.
variables.update.success=La variable a bien été modifiée.
[projects]
+deleted.display_name=Projet supprimé
type-1.display_name=Projet personnel
type-2.display_name=Projet de dépôt
type-3.display_name=Projet d’organisation
diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini
new file mode 100644
index 0000000000..82209b1b11
--- /dev/null
+++ b/options/locale/locale_ga-IE.ini
@@ -0,0 +1,2992 @@
+home=Baile
+dashboard=Deais
+explore=Iniúch
+help=Cabhair
+logo=Lógó
+sign_in=SÃnigh isteach
+sign_in_with_provider=SÃnigh isteach le %s
+sign_in_or=nó
+sign_out=SÃnigh amach
+sign_up=Cláraigh
+link_account=Cuntas Nasc
+register=Cláraigh
+version=Leagan
+powered_by=Cumhachtaithe ag %s
+page=Leathanach
+template=Teimpléad
+language=Teanga
+notifications=FógraÃ
+active_stopwatch=Rianaitheoir Ama GnÃomhach
+tracked_time_summary=Achoimre ar an am rianaithe bunaithe ar scagairà an liosta eisiúna
+create_new=Cruthaigh...
+user_profile_and_more=PróifÃl agus Socruithe...
+signed_in_as=SÃnithe isteach mar
+enable_javascript=ÉilÃonn JavaScript ar an suÃomh Gréasáin seo.
+toc=Tábla na nÃbhar
+licenses=Ceadúnais
+return_to_gitea=Fill ar Gitea
+more_items=Tuilleadh mÃreanna
+
+username=Ainm úsáideora
+email=Seoladh rÃomhphoist
+password=Pasfhocal
+access_token=Comhartha Rochtana
+re_type=Deimhnigh Pasfhocal
+captcha=CAPTCHA
+twofa=FÃordheimhniú Dhá-Fhachtóir
+twofa_scratch=Cód Scratch Dhá-Fhachtóra
+passcode=Paschód
+
+webauthn_insert_key=Cuir isteach d'eochair slándála
+webauthn_sign_in=Brúigh an cnaipe ar d'eochair slándála. Mura bhfuil aon chnaipe ag d'eochair slándála, cuir isteach é arÃs.
+webauthn_press_button=Brúigh an cnaipe ar d'eochair slándála le do thoil…
+webauthn_use_twofa=Úsáid cód dhá fhachtóir ó do ghuthán
+webauthn_error=Nà fhéadfaà do eochair slándála a léamh.
+webauthn_unsupported_browser=Nà thacaÃonn do bhrabhsálaà le WebAuthn faoi láthair.
+webauthn_error_unknown=Tharla earráid anaithnid. Déan iarracht arÃs.
+webauthn_error_insecure=Nà thacaÃonn WebAuthn ach le naisc slán. Le haghaidh tástála thar HTTP, is féidir leat an bunús “localhost†nó "127.0.0.1" a úsáid
+webauthn_error_unable_to_process=Nà fhéadfadh an freastalaà d'iarratas a phróiseáil.
+webauthn_error_duplicated=Nà cheadaÃtear an eochair slándála don iarratas seo. Déan cinnte le do thoil nach bhfuil an eochair cláraithe cheana féin.
+webauthn_error_empty=Nà mór duit ainm a shocrú don eochair seo.
+webauthn_error_timeout=Sroicheadh an teorainn ama sula bhféadfaà d’eochair a léamh. Athlódáil an leathanach seo, le do thoil, agus déan iarracht arÃs.
+webauthn_reload=Athlódáil
+
+repository=Stór
+organization=EagraÃocht
+mirror=Scáthán
+new_repo=Stór Nua
+new_migrate=Imirce Nua
+new_mirror=Scáthán Nua
+new_fork=Forc Stór Nua
+new_org=EagraÃocht Nua
+new_project=Tionscadal Nua
+new_project_column=Colún Nua
+manage_org=EagraÃochtaà a bhainistiú
+admin_panel=Riarachán Láithreáin
+account_settings=Socruithe Cuntais
+settings=Socruithe
+your_profile=PróifÃl
+your_starred=Réaltaigh
+your_settings=Socruithe
+
+all=Gach
+sources=FoinsÃ
+mirrors=Scátháin
+collaborative=Comhoibritheach
+forks=Forcanna
+
+activities=GnÃomhaÃochtaÃ
+pull_requests=Iarrataà Tarraing
+issues=Saincheisteanna
+milestones=Clocha mÃle
+
+ok=CEART GO LEOR
+cancel=Cealaigh
+retry=Atriail
+rerun=Ath-rith
+rerun_all=Ath-rith na poist go léir
+save=Sábháil
+add=Cuir
+add_all=Cuir Gach
+remove=Bain
+remove_all=Bain Gach
+remove_label_str=Bain mÃr “%sâ€
+edit=Cuir in eagar
+view=Amharc
+test=Tástáil
+
+enabled=Cumasaithe
+disabled=DÃchumasaithe
+locked=Faoi ghlas
+
+copy=Cóipeáil
+copy_url=Cóipeáil URL
+copy_hash=Cóipeáil hais
+copy_content=Cóipeáil ábhair
+copy_branch=Ainm brainse cóipeáil
+copy_success=Cóipeáil!
+copy_error=Theip ar an gcóip
+copy_type_unsupported=Nà féidir an cineál comhaid seo a chóipeáil
+
+write=ScrÃobh
+preview=Réamhamharc
+loading=à lódáil...
+
+error=Earráid
+error404=NÃl an leathanach atá tú ag iarraidh a bhaint amach ann nó nÃl tú údaraithe chun é a fheiceáil.
+go_back=Ar ais
+invalid_data=Sonraà neamhbhailÃ: %v
+
+never=Riamh
+unknown=Anaithnid
+
+rss_feed=Fothú RSS
+
+pin=Bioráin
+unpin=DÃphoráil
+
+artifacts=Déantáin
+confirm_delete_artifact=An bhfuil tú cinnte gur mhaith leat an déantán '%s' a scriosadh?
+
+archived=Cartlann
+
+concept_system_global=Domhanda
+concept_user_individual=Duine aonair
+concept_code_repository=Stóráil
+concept_user_organization=EagraÃocht
+
+show_timestamps=Taispeáin stampaà ama
+show_log_seconds=Taispeáin soicindÃ
+show_full_screen=Taispeáin scáileán iomlán
+download_logs=Ãoslódáil logaÃ
+
+confirm_delete_selected=Deimhnigh chun gach earra roghnaithe a scriosadh?
+
+name=Ainm
+value=Luach
+
+filter=Scagaire
+filter.clear=Scagaire Soiléir
+filter.is_archived=Cartlannaithe
+filter.not_archived=Gan Cartlannaithe
+filter.is_fork=Forcailte
+filter.not_fork=Gan Forcailte
+filter.is_mirror=Scáthánaithe
+filter.not_mirror=Gan Scáthánaithe
+filter.is_template=Teimpléad
+filter.not_template=Gan Teimpléad
+filter.public=PoiblÃ
+filter.private=PrÃobháideach
+
+no_results_found=NÃor aimsÃodh aon torthaÃ.
+internal_error_skipped=Tharla earráid inmheánach ach éirithe as: %s
+
+[search]
+search=Cuardaigh...
+type_tooltip=Cineál cuardaigh
+fuzzy=Doiléir
+fuzzy_tooltip=Cuir san áireamh torthaà a mheaitseálann an téarma cuardaigh go dlúth freisin
+exact=Beacht
+exact_tooltip=Nà chuir san áireamh ach torthaà a mheaitseálann leis an téarma
+repo_kind=Cuardaigh stórtha...
+user_kind=Cuardaigh úsáideoirÃ...
+org_kind=Cuardaigh eagraÃochtaÃ...
+team_kind=Cuardaigh foirne...
+code_kind=Cód cuardaigh...
+code_search_unavailable=NÃl cuardach cód ar fáil faoi láthair. Déan teagmháil le riarthóir an láithreáin.
+code_search_by_git_grep=SoláthraÃonn “git grep†torthaà cuardaigh cód reatha. D'fhéadfadh torthaà nÃos fearr a bheith ann má chuireann riarthóir an láithreáin ar chumas Innéacsaithe
+package_kind=Cuardaigh pacáistÃ...
+project_kind=Cuardaigh tionscadail...
+branch_kind=Cuardaigh brainsÃ...
+tag_kind=Cuardaigh clibeanna...
+tag_tooltip=Cuardaigh clibeanna meaitseála. Úsáid '%' le haon seicheamh uimhreacha a mheaitseáil.
+commit_kind=Cuardaigh tiomáintÃ...
+runner_kind=Cuardaigh reathaithe...
+no_results=NÃl aon torthaà meaitseála le fáil.
+issue_kind=Saincheisteanna cuardaigh...
+pull_kind=Cuardaigh iarratais tarraingthe...
+keyword_search_unavailable=NÃl cuardach de réir eochairfhocal ar fáil faoi láthair. Déan teagmháil le riarthóir an láithreáin.
+
+[aria]
+navbar=Barra Nascleanúint
+footer=Buntásc
+footer.software=Maidir le BogearraÃ
+footer.links=Naisc
+
+[heatmap]
+number_of_contributions_in_the_last_12_months=%s rannÃocaÃochtaà le 12 mhà anuas
+no_contributions=Gan rannÃocaÃochtaÃ
+less=NÃos lú
+more=NÃos mó
+
+[editor]
+buttons.heading.tooltip=Cuir ceannteideal leis
+buttons.bold.tooltip=Cuir téacs trom leis
+buttons.italic.tooltip=Cuir téacs iodálach leis
+buttons.quote.tooltip=Téacs luaigh
+buttons.code.tooltip=Cuir cód leis
+buttons.link.tooltip=Cuir nasc leis
+buttons.list.unordered.tooltip=Cuir liosta piléar leis
+buttons.list.ordered.tooltip=Cuir liosta uimhrithe
+buttons.list.task.tooltip=Cuir liosta tascanna leis
+buttons.mention.tooltip=Luaigh úsáideoir nó foireann
+buttons.ref.tooltip=Déan tagairt d'eisiúint nó iarratas tarraingthe
+buttons.switch_to_legacy.tooltip=Úsáid an eagarthóir oidhreachta ina ionad
+buttons.enable_monospace_font=Cumasaigh cló monospace
+buttons.disable_monospace_font=DÃchumasaigh cló monospace
+
+[filter]
+string.asc=A - Z
+string.desc=Z - A
+
+[error]
+occurred=Tharla earráid
+report_message=Má chreideann tú gur fabht Gitea é seo, déan cuardach le haghaidh ceisteanna ar GitHub nó oscail eagrán nua más gá.
+not_found=Nà raibh an sprioc in ann a fháil.
+network_error=Earráid lÃonra
+
+[startpage]
+app_desc=SeirbhÃs Git gan phian, féin-óstáil
+install=Éasca a shuiteáil
+install_desc=NÃl ort ach rith an dénártha do d'ardán, seol é le Docker, nó faigh pacáilte é.
+platform=Tras-ardán
+platform_desc=Ritheann Gitea áit ar bith is féidir le Go tiomsú le haghaidh: Windows, macOS, Linux, ARM, srl Roghnaigh an ceann is breá leat!
+lightweight=Éadrom
+lightweight_desc=Tá Ãosta riachtanais Ãseal ag Gitea agus is féidir leo rith ar Raspberry Pi saor. Sábháil fuinneamh do mheaisÃn!
+license=Foinse Oscailte
+license_desc=Téigh go bhfaighidh %[2]s! Bà linn trà cur leis chun an tionscadal seo a fheabhsú fós. Ná bÃodh cúthail ort a bheith i do rannpháirtÃ!
+
+[install]
+install=Suiteáil
+title=CumraÃocht Tosaigh
+docker_helper=Má ritheann tú Gitea taobh istigh de Docker, léigh an doiciméadúchán roimh aon socruithe a athrú.
+require_db_desc=ÉilÃonn Gitea MySQL, PostgreSQL, MSSQL, SQLite3 nó TiDB (prótacal MySQL).
+db_title=Socruithe Bunachar SonraÃ
+db_type=Cineál Bunachar SonraÃ
+host=Óstach
+user=Ainm úsáideora
+password=Pasfhocal
+db_name=Ainm Bunachar SonraÃ
+db_schema=Scéim
+db_schema_helper=Fág bán le haghaidh réamhshocraithe bunachar sonraà ("poiblÃ").
+ssl_mode=SSL
+path=Cosán
+sqlite_helper=Conair comhad don bhunachar sonraà SQLite3. Cuir
isteach cosán iomlán má reáchtáil tú Gitea mar sheirbhÃs.
+reinstall_error=Tá tú ag iarraidh a shuiteáil i mbunachar sonraà Gitea atá ann cheana
+reinstall_confirm_message=Is féidir fadhbanna iolracha a bheith ina chúis le hathshuiteáil le bunachar sonraà Gitea I bhformhór na gcásanna, ba chóir duit an "app.ini" atá agat cheana a úsáid chun Gitea a reáchtáil. Má tá a fhios agat cad atá á dhéanamh agat, deimhnigh an méid seo a leanas:
+reinstall_confirm_check_1=Féadfaidh na sonraà criptithe ag an SECRET_KEY i app.ini a chailleadh: b'fhéidir nach mbeidh úsáideoirà in ann logáil isteach le 2FA/OTP & b'fhéidir nach bhfeidhmeoidh scátháin i gceart. Trà an bhosca seo a sheiceáil deimhnÃonn tú go bhfuil an ceart an SECRET_KEY sa chomhad reatha app.ini.
+reinstall_confirm_check_2=B'fhéidir go gcaithfear na stórais agus na socruithe a athshioncronú. Trà an bhosca seo a sheiceáil deimhnÃonn tú go ndéanfaidh tú na crúcaà do na stórálacha agus an chomhad authorized_keys a athshioncronú de láimh. DeimhnÃonn tú go gcinnteoidh tú go bhfuil socruithe stórais agus scátháin ceart.
+reinstall_confirm_check_3=DeimhnÃonn tú go bhfuil tú cinnte go bhfuil an Gitea seo ag rith leis an suÃomh ceart app.ini agus go bhfuil tú cinnte go gcaithfidh tú athshuiteáil. DeimhnÃonn tú go n-admhaÃonn tú na rioscaà thuas.
+err_empty_db_path=Nà féidir cosán bunachar sonraà SQLite3 a bheith folamh.
+no_admin_and_disable_registration=Nà féidir leat féinchlárú úsáideora a dhÃchumasú gan cuntas riarthóra a chruthú.
+err_empty_admin_password=Nà féidir le pasfhocal an riarthóra a bheith folamh.
+err_empty_admin_email=Nà féidir le rÃomhphost an riarthóra a bheith folamh.
+err_admin_name_is_reserved=Riarthóir Tá an t-ainm úsáideora neamhbhailÃ, tá an t-ainm úsáideora curtha in áirithe
+err_admin_name_pattern_not_allowed=Tá ainm úsáideora an riarthóra neamhbhailÃ, meaitseálann an t-ainm úsáideora patrún in áirithe
+err_admin_name_is_invalid=Tá an t-ainm úsáideora Riarthóra neamhbhailÃ
+
+general_title=Socruithe Ginearálta
+app_name=Teideal an tSuÃmh
+app_name_helper=Is féidir leat ainm do chuideachta a iontráil anseo.
+repo_path=Cosán Fréimhe an Stór
+repo_path_helper=Sábhálfar stórais iargúlta Git chuig an eolaire seo.
+lfs_path=Cosán Fréamh Git LFS
+lfs_path_helper=Stórálfar comhaid a rianóidh Git LFS san eolaire seo. Fág folamh le dÃchumasú.
+run_user=Rith mar Ainm Úsáideora
+run_user_helper=An ainm úsáideora an chórais oibriúcháin a ritheann Gitea mar. Tabhair faoi deara go gcaithfidh rochtain a bheith ag an úsáideoir seo ar fhréamhchosán an taisclainne.
+domain=Fearann ​​FreastalaÃ
+domain_helper=Seoladh fearainn nó óstach don fhreastalaÃ.
+ssh_port=Port Freastalaà SSH
+ssh_port_helper=Uimhir chalafoirt éisteann do fhreastalaà SSH air. Fág folamh le dÃchumasú.
+http_port=Port Éisteachta HTTP Gitea
+http_port_helper=Uimhir chalafoirt a éistfidh an freastalaà gréasáin Gitea air.
+app_url=URL Bonn Gitea
+app_url_helper=Seoladh bonn le haghaidh URLanna clóin HTTP(S) agus fógraà rÃomhphoist.
+log_root_path=Cosán Logála
+log_root_path_helper=ScrÃofar comhaid logála chuig an eolaire seo.
+
+optional_title=Socruithe Roghnacha
+email_title=Socruithe rÃomhphoist
+smtp_addr=Óstach SMTP
+smtp_port=Port SMTP
+smtp_from=Seol RÃomhphost Mar
+smtp_from_invalid=Tá an seoladh “Seol RÃomhphost Mar†neamhbhailÃ
+smtp_from_helper=Seoladh rÃomhphoist a úsáidfidh Gitea. Cuir isteach seoladh rÃomhphoist simplà nó úsáid an fhormáid "Ainm" .
+mailer_user=SMTP Ainm úsáideora
+mailer_password=Pasfhocal SMTP
+register_confirm=Deimhniú RÃomhphoist a cheangal le Clárú
+mail_notify=Cumasaigh Fógraà RÃomhphoist
+server_service_title=Socruithe Freastalaà agus SeirbhÃse TrÃú PáirtÃ
+offline_mode=Cumasaigh Mód Ãitiúil
+offline_mode_popup=DÃchumasaigh lÃonraà seachadta ábhair trÃú páirtà agus freastal ar na hacmhainnà go léir go háitiúil.
+disable_gravatar=DÃchumasaigh Gravatar
+disable_gravatar_popup=DÃchumasaigh foinsà abhatár Gravatar agus trÃú páirtÃ. Úsáidfear abhatár réamhshocraithe mura n-uaslódálann úsáideoir abhatár go háitiúil.
+federated_avatar_lookup=Cumasaigh Abhatáir Chónaidhme
+federated_avatar_lookup_popup=Cumasaigh cuardach avatar cónaidhme ag baint úsáide as Libravatar.
+disable_registration=DÃchumasaigh Féin-Chlárú
+disable_registration_popup=DÃchumasaigh féinchlárú úsáideora. Nà bheidh ach riarthóirà in ann cuntais úsáideora nua a chruthú.
+allow_only_external_registration_popup=Ceadaigh Clárú Trà SheirbhÃsà Seachtracha amháin
+openid_signin=Cumasaigh SÃniú isteach OpenID
+openid_signin_popup=Cumasaigh sÃniú isteach úsáideora trà OpenID.
+openid_signup=Cumasaigh Féinchlárú OpenID
+openid_signup_popup=Cumasaigh féinchlárú úsáideora bunaithe ar OpenID.
+enable_captcha=Cumasaigh clárú CAPTCHA
+enable_captcha_popup=TeastaÃonn CAPTCHA le haghaidh féinchlárú úsáideora.
+require_sign_in_view=TeastaÃonn SÃnigh isteach chun Leathanaigh Amharc
+require_sign_in_view_popup=Teorainn a chur ar rochtain leathanaigh d'úsáideoirà sÃnithe isteach. Nà fheicfidh cuairteoirà ach na leathanaigh sÃnithe isteach agus clárúcháin.
+admin_setting_desc=Tá cuntas riarthóra a chruthú roghnach. Beidh an chéad úsáideoir cláraithe ina rialtóir go huathoibrÃoch
+admin_title=Socruithe Cuntas Riarthóra
+admin_name=Ainm Úsáideora an Riarthóra
+admin_password=Pasfhocal
+confirm_password=Deimhnigh Pasfhocal
+admin_email=Seoladh rÃomhphoist
+install_btn_confirm=Suiteáil Gitea
+test_git_failed=Nà féidir ordú 'git' a thástáil: %v
+sqlite3_not_available=Nà thacaÃonn an leagan Gitea seo le SQLite3. Ãoslódáil an leagan dénártha oifigiúil ó %s (nà an leagan 'gobuild').
+invalid_db_setting=Tá na socruithe bunachar sonraà neamhbhailÃ:%v
+invalid_db_table=Tá an tábla bunachar sonraà "%s" neamhbhailÃ: %v
+invalid_repo_path=Tá cosán fréimhe an stór neamhbhailÃ:%v
+invalid_app_data_path=Tá cosán sonraà an aip neamhbhailÃ:%v
+run_user_not_match=Nà hé an t-ainm úsáideora 'rith mar' an t-ainm úsáideora reatha: %s -> %s
+internal_token_failed=Theip ar chomhartha inmheánach a ghiniúint:%v
+secret_key_failed=Theip ar an eochair rúnda a ghiniúint:%v
+save_config_failed=Theip ar chumraÃocht a shábháil:%v
+invalid_admin_setting=Tá socrú cuntas riarthóra neamhbhailÃ: %v
+invalid_log_root_path=Tá an cosán logála neamhbhailÃ:%v
+default_keep_email_private=Folaigh Seoltaà RÃomhphoist de réir Réamhshocrú
+default_keep_email_private_popup=Folaigh seoltaà rÃomhphoist cuntas úsáideora nua de réir réamhshocraithe.
+default_allow_create_organization=Ceadaigh Cruthú EagraÃochtaà de réir Réamhshocrú
+default_allow_create_organization_popup=Lig cuntais úsáideora nua eagraÃochtaà a chruthú de réir réamhshocraithe.
+default_enable_timetracking=Cumasaigh Rianú Ama de réir Réamhshocrú
+default_enable_timetracking_popup=Cumasaigh rianú ama do stórais nua de réir réamhshocraithe.
+no_reply_address=Fearann RÃomhphoist Folaite
+no_reply_address_helper=Ainm fearainn d'úsáideoirà a bhfuil seoladh rÃomhphoist i bhfolach acu. Mar shampla, logálfar an t-ainm úsáideora 'joe' i Git mar 'joe@noreply.example.org' má tá an fearainn rÃomhphoist i bhfolach socraithe go 'noreply.example.org'.
+password_algorithm=Algartam Hais Pasfhocal
+invalid_password_algorithm=Algartam hais pasfhocail neamhbhailÃ
+password_algorithm_helper=Socraigh an algartam hashing pasfhocal. Tá riachtanais agus neart éagsúla ag halgartaim. Tá an algartam argon2 sách slán ach úsáideann sé go leor cuimhne agus d'fhéadfadh sé a bheith mÃchuà do chórais bheaga.
+enable_update_checker=Cumasaigh Seiceoir Nuashonraithe
+enable_update_checker_helper=Seiceálacha ar eisiúintà leagan nua go tréimhsiúil trà nascadh le gitea.io.
+env_config_keys=CumraÃocht Comhshaoil
+env_config_keys_prompt=Cuirfear na hathróga comhshaoil seo a leanas i bhfeidhm ar do chomhad cumraÃochta freisin:
+
+[home]
+nav_menu=Roghchlár Nascleanúint
+uname_holder=Ainm Úsáideora nó Seoladh RÃomhphoist
+password_holder=Pasfhocal
+switch_dashboard_context=Athraigh Comhthéacs an Deais
+my_repos=Stórais
+show_more_repos=Taispeáin nÃos mó stórais...
+collaborative_repos=Stórais ComhoibrÃoch
+my_orgs=Mo EagraÃochtaÃ
+my_mirrors=Mo Scátháin
+view_home=Amharc %s
+filter=Scagairà Eile
+filter_by_team_repositories=Scag de réir stórais foirne
+feed_of=`Fotha de "%s"`
+
+show_archived=Cartlannaithe
+show_both_archived_unarchived=Ag taispeáint idir chartlannaithe agus neamhchartlann
+show_only_archived=Ag taispeáint ach na cartlannaigh
+show_only_unarchived=Ag taispeáint ach na cartlannaigh neamh
+
+show_private=PrÃobháideach
+show_both_private_public=Ag taispeáint poiblà agus prÃobháideach araon
+show_only_private=Ag taispeáint prÃobháideach amháin
+show_only_public=Ag taispeáint poiblà amháin
+
+issues.in_your_repos=I do stórais
+
+[explore]
+repos=Stórais
+users=ÚsáideoirÃ
+organizations=EagraÃochtaÃ
+go_to=Téigh chuig
+code=Cód
+code_last_indexed_at=Innéacsaithe %s is déanaÃ
+relevant_repositories_tooltip=Tá stórais atá forca iad nó nach bhfuil aon ábhar acu, gan aon deilbhÃn, agus gan aon tuairisc i bhfolach.
+relevant_repositories=NÃl ach stórtha ábhartha á dtaispeáint, taispeáin torthaà neamhscagtha.
+
+[auth]
+create_new_account=Cláraigh Cuntas
+already_have_account=An bhfuil cuntas agat cheana féin?
+sign_in_now=SÃnigh isteach anois!
+disable_register_prompt=Tá clárú faoi dhÃchumasú. Téigh i dteagmháil le do riarthóir suÃomh.
+disable_register_mail=Tá deimhniú rÃomhphoist le haghaidh clárú faoi dhÃchum
+manual_activation_only=Déan teagmháil le riarthóir do tsuÃmh chun gnÃomhachtú a chur i gcrÃch.
+remember_me=Cuimhnigh ar an nGléas seo
+remember_me.compromised=NÃl an comhartha logála isteach bailà nÃos mó a d'fhéadfadh cuntas i gcontúirt a léiriú. Seiceáil do chuntas le haghaidh gnÃomhaÃochtaà neamhghnácha.
+forgot_password_title=Dearmad ar an bPasfhocal
+forgot_password=Dearmad ar an bPasfhocal?
+need_account=An bhfuil cuntas ag teastáil uait?
+sign_up_now=Cláraigh anois.
+sign_up_successful=CruthaÃodh cuntas go rathúil. Fáilte romhat!
+confirmation_mail_sent_prompt_ex=Tá rÃomhphost dearbhaithe nua seolta chuig %s. Seiceáil do bhosca isteach laistigh den chéad %s eile chun an próiseas clárúcháin a chur i gcrÃch. Má tá do sheoladh rÃomhphoist clárúcháin mÃcheart, is féidir leat sÃniú isteach arÃs agus é a athrú.
+must_change_password=Nuashonraigh do phasfhocal
+allow_password_change=A cheangal ar an úsáideoir pasfhocal a athrú (molta)
+reset_password_mail_sent_prompt=Seoladh rÃomhphost deimhnithe chu ig %s. Seiceáil do bhosca isteach laistigh den chéad %s eile chun an próiseas aisghabhála cuntais a chrÃochnú.
+active_your_account=GnÃomhachtaigh do chuntas
+account_activated=Cuireadh cuntas gnÃomhachtaithe
+prohibit_login=SÃnigh isteach Toirmiscthe
+prohibit_login_desc=Tá cosc ar do chuntas sÃniú isteach, déan teagmháil le do riarthóir láithreáin le do thoil.
+resent_limit_prompt=D'iarr tú rÃomhphost gnÃomhachtaithe cheana féin le déanaÃ. Fan 3 nóiméad le do thoil agus bain triail as arÃs.
+has_unconfirmed_mail=Dia duit %s, tá seoladh rÃomhphoist neamhdheimhnithe agat (%s). Mura bhfuair tú rÃomhphost dearbhaithe nó mura gcaithfidh tú ceann nua a athsheoladh, cliceáil ar an gcnaipe thÃos le do thoil.
+change_unconfirmed_mail_address=Má tá do sheoladh rÃomhphoist cláraithe mÃcheart, is féidir leat é a athrú anseo agus rÃomhphost dearbhaithe nua a sheoladh arÃs.
+resend_mail=Cliceáil anseo chun do r-phost gnÃomhachtaithe a athshe
+email_not_associate=NÃl baint ag an seoladh rÃomhphoist le haon chuntas.
+send_reset_mail=Seol RÃomhphost Aisghabháil Cuntas
+reset_password=Aisghabháil Cuntas
+invalid_code=Tá do chód deimhnithe neamhbhailà nó tá sé in éag.
+invalid_code_forgot_password=Tá do chód deimhnithe neamhbhailà nó tá sé in éag. Cliceáil anseo chun seisiún nua a thosú.
+invalid_password=Nà mheaitseálann do phasfhocal leis an bhfocal faire a úsáideadh chun an cuntas a chruthú.
+reset_password_helper=Gnóthaigh Cuntas
+reset_password_wrong_user=Tá tú sÃnithe isteach mar %s, ach tá an nasc aisghabhála cuntas i gceist le haghaidh %s
+password_too_short=Nà féidir fad pasfhocal a bheith nÃos lú ná %d carachtair.
+non_local_account=Nà féidir le húsáideoirà neamháitiúla a bhfocal faire a nuashonrú trà chomhéadan gréasáin Gitea.
+verify=FÃoraigh
+scratch_code=Cód Scratch
+use_scratch_code=Úsáid cód scratch
+twofa_scratch_used=D'úsáid tú do chód scratch. Tá tú atreoraithe chuig an leathanach socruithe dhá fhachtóir ionas gur féidir leat clárú do ghléas a bhaint nó cód scratch nua a ghiniúint.
+twofa_passcode_incorrect=Tá do phaschód mÃcheart. Má chuir tú do ghléas mÃchuir tú, bain úsáid as do chód scratch chun sÃniú isteach.
+twofa_scratch_token_incorrect=Tá do chód scratch mÃcheart.
+login_userpass=SÃnigh isteach
+login_openid=OpenID
+oauth_signup_tab=Cláraigh Cuntas Nua
+oauth_signup_title=Comhlánaigh Cuntas Nua
+oauth_signup_submit=Cuntas Comhlánaigh
+oauth_signin_tab=Nasc leis an gCuntas Reatha
+oauth_signin_title=SÃnigh isteach chun Cuntas Nasctha a Údarú
+oauth_signin_submit=Cuntas Nasc
+oauth.signin.error=Bhà earráid ann ag próiseáil an t-iarratas ar údarú. Má leanann an earráid seo, déan teagmháil le riarthóir an láithreáin.
+oauth.signin.error.access_denied=DiúltaÃodh an t-iarratas ar údarú.
+oauth.signin.error.temporarily_unavailable=Theip ar údarú toisc nach bhfuil an fhreastalaà fÃordheimhnithe ar fáil Bain triail as arÃs nÃos déanaÃ.
+oauth_callback_unable_auto_reg=Tá Clárú UathoibrÃoch cumasaithe, ach sheol Soláthraà OAuth2 %[1]s réimsà in easnamh ar ais: %[2]s, nà raibh sé in ann cuntas a chruthú go huathoibrÃoch, cruthaigh nó nasc le cuntas, nó déan teagmháil le riarthóir an tsuÃmh.
+openid_connect_submit=Ceangail
+openid_connect_title=Ceangail le cuntas atá ann cheana
+openid_connect_desc=NÃl an URI OpenID roghnaithe ar eolas. Comhcheangail é le cuntas nua anseo.
+openid_register_title=Cruthaigh cuntas nua
+openid_register_desc=NÃl an URI OpenID roghnaithe ar eolas. Comhcheangail é le cuntas nua anseo.
+openid_signin_desc=Cuir isteach do URI OpenID. Mar shampla: alice.openid.example.org nó https://openid.example.org/alice.
+disable_forgot_password_mail=Tá aisghabháil cuntas dÃchumasaithe toisc nach bhfuil aon rÃomhphost ar bun. Téigh i dteagmháil le do riarthóir suÃomh.
+disable_forgot_password_mail_admin=NÃl aisghabháil cuntas ar fáil ach amháin nuair a bhÃonn rÃomhphost ar bun. Bunaigh rÃomhphost le do thoil chun aisghabháil cuntas a chumasú
+email_domain_blacklisted=Nà féidir leat clárú le do sheoladh rÃomhphoist.
+authorize_application=Údaraigh an Feidhmchlár
+authorize_redirect_notice=Déanfar tú a atreorú chuig %s má údaraÃonn tú an feidhmchlár seo.
+authorize_application_created_by=Chruthaigh %s an feidhmchlár seo.
+authorize_application_description=Má dheonaÃonn tú an rochtain, beidh sé in ann rochtain a fháil agus scrÃobh chuig faisnéis uile do chuntais, lena n-áirÃtear repos prÃobháideacha agus eagraÃochtaÃ.
+authorize_title=Údaraigh "%s" chun rochtain a fháil ar do chuntas?
+authorization_failed=Theip ar údarú
+authorization_failed_desc=Theip ar an údarú toisc gur bhraitheamar iarratas neamhbhailÃ. Téigh i dteagmháil le cothabhálaà an aip a rinne tú iarracht a údarú.
+sspi_auth_failed=Theip ar fhÃordheimhniú SSPI
+password_pwned=Tá an pasfhocal a roghnaigh tú ar liosta na bhfocal faire goidte a nochtadh cheana i sáruithe sonraà poiblÃ. Bain triail eile as le pasfhocal eile agus smaoinigh ar an bpasfhocal seo a athrú áit eile freisin.
+password_pwned_err=Nà fhéadfaà iarratas a chomhlánú ar HaveIBeenPwned
+last_admin=Nà féidir leat an riarachán deireanach a bhaint. Caithfidh riarachán amháin ar a laghad a bheith ann.
+signin_passkey=SÃnigh isteach le passkey
+back_to_sign_in=Ar ais go SÃnigh Isteach
+
+[mail]
+view_it_on=Féach air ar %s
+reply=nó freagra a thabhairt ar an r-phost seo go dÃreach
+link_not_working_do_paste=NÃl ag obair? Bain triail as é a chóipeáil agus a ghreamú le do bhrabh
+hi_user_x=Dia duit %s,
+
+activate_account=GnÃomhachtaigh do chuntas le do thoil
+activate_account.title=%s, gnÃomhachtaigh do chuntas le do thoil
+activate_account.text_1=Dia duit %[1]s, go raibh maith agat as clárú ag %[2]s!
+activate_account.text_2=Cliceáil ar an nasc seo a leanas chun do chuntas a ghnÃomhachtú laistigh de %s:
+
+activate_email=FÃoraigh do sheoladh rÃomhphoist
+activate_email.title=%s, fÃoraigh do sheoladh rÃomhphoist le do thoil
+activate_email.text=Cliceáil ar an nasc seo a leanas le do sheoladh rÃomhphoist a fhÃorú laistigh de %s:
+
+register_notify=Fáilte go dtà %s
+register_notify.title=%[1]s, fáilte go %[2]s
+register_notify.text_1=is é seo do rÃomhphost deimhnithe clárúcháin do %s!
+register_notify.text_2=Is féidir leat logáil isteach anois trà ainm úsáideora: %s.
+register_notify.text_3=Má cruthaÃodh an cuntas seo duit, socraigh do phasfhocal ar dtús.
+
+reset_password=Aisghabháil do chuntas
+reset_password.title=%s, d'iarr tú do chuntas a aisghabháil
+reset_password.text=Cliceáil ar an nasc seo a leanas chun do chuntas a athshlánú laistigh de %s:
+
+register_success=Clárú rathúil
+
+issue_assigned.pull=@%[1]s shann tú don iarratas tarraingthe %[2]s i stór %[3]s.
+issue_assigned.issue=@%[1]s shann tú don eisiúint %[2]s i stór %[3]s.
+
+issue.x_mentioned_you=Luaigh @%s tú:
+issue.action.force_push=Bhrúigh %[1]s an %[2]s go fórsa ó %[3]s go %[4]s.
+issue.action.push_1=Bhrúigh @%[1]s %[3]d tiomáintà go %[2]s
+issue.action.push_n=@%[1]s brúite % [3]d tiomáintà chuig %[2]s
+issue.action.close=@%[1]s dúnta #%[2]d.
+issue.action.reopen=D'athoscail @%[1]s #%[2]d.
+issue.action.merge=Chomhcheangail @%[1]s #%[2]d le %[3]s.
+issue.action.approve=Cheadaigh @%[1]s an t-iarratas tarraingthe seo.
+issue.action.reject=D'iarr @%[1]s athruithe ar an iarratas tarraingthe seo.
+issue.action.review=Rinne @%[1]s trácht ar an iarratas tarraingthe seo.
+issue.action.review_dismissed=Dhiúltaigh @%[1]s an léirmheas deiridh ó %[2]s don iarratas tarraingthe seo.
+issue.action.ready_for_review=Mharcáil @%[1]s an t-iarratas tarraingthe seo réidh lena athbhreithniú.
+issue.action.new=Chruthaigh @%[1]s #%[2]d.
+issue.in_tree_path=I %s:
+
+release.new.subject=Scaoileadh %s i %s
+release.new.text=D'eisigh @%[1]s %[2]s i %[3]s
+release.title=Teideal: %s
+release.note=Nóta:
+release.downloads=Ãoslódálacha:
+release.download.zip=Cód Foinse (ZIP)
+release.download.targz=Cód Foinse (TAR.GZ)
+
+repo.transfer.subject_to=Ba mhaith le %s "%s" a aistriú go %s
+repo.transfer.subject_to_you=Ba mhaith le %s "%s" a aistriú chugat
+repo.transfer.to_you=tú
+repo.transfer.body=Chun glacadh leis nó a dhiúltú tabhair cuairt ar %s nó neamhaird a dhéanamh air.
+
+repo.collaborator.added.subject=Chuir %s le %s tú
+repo.collaborator.added.text=Cuireadh tú leis mar chomhoibritheoir stórais:
+
+team_invite.subject=Tá cuireadh tugtha agat ag %[1]s chun dul le heagraÃocht %[2]s
+team_invite.text_1=Tá cuireadh tugtha ag %[1]s duit chun dul le foireann %[2]s in eagraÃocht %[3]s.
+team_invite.text_2=Cliceáil ar an nasc seo a leanas le do thoil chun dul isteach san fhoireann:
+team_invite.text_3=Nóta: Bhà an cuireadh seo beartaithe do %[1]s. Mura raibh tú ag súil leis an gcuireadh seo, is féidir leat neamhaird a dhéanamh den rÃomhphost seo.
+
+[modal]
+yes=Tá
+no=NÃl
+confirm=Deimhnigh
+cancel=Cealaigh
+modify=Nuashonraigh
+
+[form]
+UserName=Ainm úsáideora
+RepoName=Ainm stórais
+Email=Seoladh rÃomhphoist
+Password=Pasfhocal
+Retype=Deimhnigh Pasfhocal
+SSHTitle=Ainm eochair SSH
+HttpsUrl=URL HTTPS
+PayloadUrl=URL Pálasta
+TeamName=Ainm foirne
+AuthName=Ainm údaraithe
+AdminEmail=RÃomhphost riaracháin
+
+NewBranchName=Ainm brainse nua
+CommitSummary=Achoimre tiomáintÃ
+CommitMessage=Tiomantas teachtaireacht
+CommitChoice=Rogha tiomanta
+TreeName=Cosán comhaid
+Content=Ãbhar
+
+SSPISeparatorReplacement=Deighilteoir
+SSPIDefaultLanguage=Teanga Réamhshocraithe
+
+require_error=` nà féidir a bheith folamh.`
+alpha_dash_error=` nÃor cheart go mbeadh ach carachtair alfauméireacha, daingean ('-') agus béim ('_') ann. `
+alpha_dash_dot_error=` nÃor cheart go mbeadh ach alfa-uimhriúil, dash ('-'), cuir béim ar ('_') agus ponc ('.') carachtair ann.`
+git_ref_name_error=` caithfidh gur ainm tagartha Git dea-chruthaithe é.`
+size_error=` nà mór méid %s.`
+min_size_error=` nà mór go mbeadh carachtar %s ar a laghad ann.`
+max_size_error=` caithfidh `%s carachtar ar a mhéad a bheith ann.`
+email_error=`nà seoladh rÃomhphoist bailà é.`
+url_error=`nà URL bailà é `"%s". `
+include_error=` nà mór fotheaghrán a bheith ann "%s".`
+glob_pattern_error=` tá patrún glob neamhbhailÃ: %s.`
+regex_pattern_error=`tá patrún regex neamhbhailÃ: %s.`
+username_error=` nà féidir ach carachtair alfa-uimhriúla ('0-9', 'a-z', 'A-Z'), dash ('-'), béim ('_') agus ponc ('.') a bheith ann. Nà féidir tús a chur leis ná deireadh a chur le carachtair neamh-alfamanacha, agus tá cosc ​​freisin ar charthanna neamh-alfanuimhriúla i ndiaidh a chéile.`
+invalid_group_team_map_error=` tá mapáil neamhbhailÃ: %s`
+unknown_error=Earráid anaithnid:
+captcha_incorrect=Tá an cód CAPTCHA mÃcheart.
+password_not_match=Nà mheaitseálann na pasfhocail.
+lang_select_error=Roghnaigh teanga ón liosta.
+
+username_been_taken=Tá an t-ainm úsáideora tógtha cheana féin.
+username_change_not_local_user=Nà cheadaÃtear d'úsáideoirà neamháitiúla a n-ainm úsáideora a athrú.
+change_username_disabled=Tá athrú an ainm úsáideora dÃchumasaithe.
+change_full_name_disabled=Tá athrú an ainm iomlán dÃchumasaithe.
+username_has_not_been_changed=NÃor athraÃodh ainm úsáideora
+repo_name_been_taken=Úsáidtear ainm an stór cheana féin.
+repository_force_private=Tá Force Private cumasaithe: nà féidir stórais phrÃobháideacha a dhéanamh poiblÃ.
+repository_files_already_exist=Tá comhaid ann cheana féin don stór seo. Déan teagmháil leis an riarthóir córais.
+repository_files_already_exist.adopt=Tá comhaid ann cheana don stór seo agus nà féidir iad a ghlacadh ach amháin.
+repository_files_already_exist.delete=Tá comhaid ann cheana féin don stór seo. Nà mór duit iad a scriosadh.
+repository_files_already_exist.adopt_or_delete=Tá comhaid ann cheana féin don stór seo. Glac iad nó scrios iad.
+visit_rate_limit=Thug cuairt chianda aghaidh ar theorannú rátaÃ.
+2fa_auth_required=Bhà fÃordheimhniú dhá thoisc ag teastáil ó chianchuairt.
+org_name_been_taken=Tá ainm na heagraÃochta glactha cheana féin.
+team_name_been_taken=Tá ainm na foirne glactha cheana féin.
+team_no_units_error=Ceadaigh rochtain ar chuid stórais amháin ar a laghad.
+email_been_used=Úsáidtear an seoladh rÃomhphoist cheana féin.
+email_invalid=Tá an seoladh rÃomhphoist neamhbhailÃ.
+email_domain_is_not_allowed=Tá réimse rÃomhphoist úsáideora %s ag teacht i gcoitinne le EMAIL_DOMAIN_ALLOWLIST nó EMAIL_DOMAIN_BLOCKLIST. Déan cinnte go bhfuil súil le d'oibrÃocht.
+openid_been_used=Úsáidtear an seoladh OpenID "%s" cheana féin.
+username_password_incorrect=Tá ainm úsáideora nó pasfhocal mÃcheart.
+password_complexity=Nà shásaÃonn pasfhocal ceanglais castachta:
+password_lowercase_one=Carachtar beaga amháin ar a laghad
+password_uppercase_one=Carachtar cás uachtair amháin ar a laghad
+password_digit_one=Digit amháin ar a laghad
+password_special_one=Carachtar speisialta amháin ar a laghad (poncaÃocht, lúibÃnÃ, luachana, srl.)
+enterred_invalid_repo_name=Tá ainm an stórais a chuir tú isteach mÃcheart.
+enterred_invalid_org_name=Tá ainm na heagraÃochta a chuir tú isteach mÃcheart.
+enterred_invalid_owner_name=NÃl ainm an úinéara nua bailÃ.
+enterred_invalid_password=Tá an pasfhocal a chuir tú isteach mÃcheart.
+unset_password=NÃor shocraigh an t-úsáideoir logála isteach an pasfhocal.
+unsupported_login_type=Nà thacaÃtear leis an gcineál logála isteach chun cuntas a scriosadh.
+user_not_exist=NÃl an t-úsáideoir ann.
+team_not_exist=NÃl an fhoireann ann.
+last_org_owner=Nà féidir leat an t-úsáideoir deireanach a bhaint as an bhfoireann 'úinéirÃ'. Caithfidh úinéir amháin ar a laghad a bheith ann d'eagraÃocht.
+cannot_add_org_to_team=Nà féidir eagraÃocht a chur leis mar bhall foirne.
+duplicate_invite_to_team=Tugadh cuireadh don úsáideoir cheana féin mar bhall foirne.
+organization_leave_success=D'fhág tú an eagraÃocht %s go rathúil.
+
+invalid_ssh_key=Nà féidir d'eochair SSH a fhÃorú: %s
+invalid_gpg_key=Nà féidir d'eochair GPG a fhÃorú: %s
+invalid_ssh_principal=PrÃomhoide neamhbhailÃ: %s
+must_use_public_key=Is eochair phrÃobháideach an eochair a sholáthraÃonn tú. Ná uaslódáil d'eochair phrÃobháideach áit ar bith Úsáid d'eochair phoiblà ina ionad.
+unable_verify_ssh_key=Nà féidir an eochair SSH a fhÃorú, seiceáil faoi dhó é le haghaidh botúin.
+auth_failed=Theip ar fhÃordheimhniú:%v
+
+still_own_repo=Tá stór amháin nó nÃos mó ag do chuntas, scriosadh nó aistrigh iad ar dtús.
+still_has_org=Is ball d'eagraÃocht amháin nó nÃos mó é do chuntas, fág iad ar dtús.
+still_own_packages=Tá pacáiste amháin nó nÃos mó ag do chuntas, scrios iad ar dtús.
+org_still_own_repo=Tá stór amháin nó nÃos mó ag an eagraÃocht seo fós, scriosadh nó aistrigh iad ar dtús.
+org_still_own_packages=Tá pacáiste amháin nó nÃos mó ag an eagraÃocht seo fós, scrios iad ar dtús.
+
+target_branch_not_exist=NÃl spriocbhrainse ann.
+target_ref_not_exist=NÃl an sprioctagartha %s ann
+
+admin_cannot_delete_self=Nà féidir leat tú féin a scriosadh nuair is riarachán tú. Bain do phribhléidà riaracháin ar dtús.
+
+[user]
+change_avatar=Athraigh do abhatár…
+joined_on=Cláraigh ar %s
+repositories=Stórais
+activity=GnÃomhaÃocht PhoiblÃ
+followers=LeantóirÃ
+starred=Stórais Réaltaithe
+watched=Stórais Breathnaithe
+code=Cód
+projects=Tionscadail
+overview=Forbhreathnú
+following=Ag leanúint
+follow=Lean
+unfollow=DÃlean
+user_bio=Beathaisnéis
+disabled_public_activity=DhÃchumasaigh an t-úsáideoir seo infheictheacht phoiblà na gnÃomhaÃochta.
+email_visibility.limited=Tá do sheoladh rÃomhphoist le feiceáil do gach úsáideoir fÃordheimhnithe
+email_visibility.private=NÃl do sheoladh rÃomhphoist le feiceáil ach duit féin agus do riarthóirÃ
+show_on_map=Taispeáin an áit seo ar léarscáil
+settings=Socruithe Úsáideora
+
+form.name_reserved=Tá an t-ainm úsáideora "%s" in áirithe.
+form.name_pattern_not_allowed=Nà cheadaÃtear an patrún "%s" in ainm úsáideora.
+form.name_chars_not_allowed=Tá carachtair neamhbhailà in ainm úsáideora "%s".
+
+block.block=Bloc
+block.block.user=Bloc úsáideoir
+block.block.org=Bloc úsáideoir don eagraÃocht
+block.block.failure=Theip ar an úsáideoir a bhac: %s
+block.unblock=DÃbhlocáil
+block.unblock.failure=Theip ar an úsáideoir a dÃbhlocáil: %s
+block.blocked=Chuir tú bac ar an úsáideoir seo.
+block.title=Cuir bac ar úsáideoir
+block.info=Cuireann blocáil úsáideora cosc orthu idirghnÃomhú le stórais, mar shampla iarratais tarraingthe nó saincheisteanna a oscailt nó trácht a dhéanamh orthu. NÃos mó a fhoghlaim faoi bhac úsáideora.
+block.info_1=Cuireann blocáil úsáideora cosc ar na gnÃomhartha seo a leanas ar do chuntas agus ar do stór:
+block.info_2=ag leanúint do chuntas
+block.info_3=seol fógraà chugat ag @mentioning d'ainm úsáideora
+block.info_4=ag tabhairt cuireadh duit mar chomhoibritheoir chuig a stórtha
+block.info_5=ag réaladh, ag forcáil nó ag féachaint ar stórais
+block.info_6=ceisteanna nó iarrataà tarraingthe a oscailt agus trácht
+block.info_7=freagairt ar do chuid tuairimà i saincheisteanna nó iarratais tarraingthe
+block.user_to_block=Úsáideoir chun blocáil
+block.note=Nóta
+block.note.title=Nóta roghnach:
+block.note.info=NÃl an nóta le feiceáil don úsáideoir blocáilte.
+block.note.edit=Cuir nóta in eagar
+block.list=Úsáideoirà blocáilte
+block.list.none=NÃor chuir tú bac ar aon úsáideoirÃ.
+
+[settings]
+profile=PróifÃl
+account=Cuntas
+appearance=Dealramh
+password=Pasfhocal
+security=Slándáil
+avatar=Abhatár
+ssh_gpg_keys=Eochracha SSH/GPG
+social=Cuntais Shóisialta
+applications=Iarratais
+orgs=EagraÃochtaà a bhainistiú
+repos=Stórais
+delete=Scrios Cuntas
+twofa=FÃordheimhniú Dhá Fachtóir (TOTP)
+account_link=Cuntais Nasctha
+organization=EagraÃochtaÃ
+uid=UID
+webauthn=FÃordheimhniú Dhá-Fachtóir (Eochracha Slándála)
+
+public_profile=PróifÃl PhoiblÃ
+biography_placeholder=Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid)
+location_placeholder=Comhroinn do shuÃomh thart le daoine eile
+profile_desc=Rialú conas a thaispeánfar do phróifÃl d'úsáideoirà eile. Úsáidfear do phrÃomhsheoladh rÃomhphoist le haghaidh fógraÃ, aisghabháil pasfhocail agus oibrÃochtaà Git gréasán-bhunaithe.
+password_username_disabled=NÃl cead agat a n-ainm úsáideora a athrú. Déan teagmháil le do riarthóir suÃmh le haghaidh tuilleadh sonraÃ.
+password_full_name_disabled=NÃl cead agat a n-ainm iomlán a athrú. Déan teagmháil le do riarthóir suÃmh le haghaidh tuilleadh sonraÃ.
+full_name=Ainm Iomlán
+website=Láithreán Gréasáin
+location=SuÃomh
+update_theme=Nuashonraigh Téama
+update_profile=Nuashonraigh PróifÃl
+update_language=Nuashonraigh Teanga
+update_language_not_found=NÃl teanga “%s†ar fáil.
+update_language_success=Tá an teanga nuashonraithe.
+update_profile_success=NuashonraÃodh do phróifÃl.
+change_username=Tá d'ainm úsáideora athraithe.
+change_username_prompt=Nóta: AthraÃonn athrú d'ainm úsáideora URL do chuntais freisin.
+change_username_redirect_prompt=Athreoróidh an sean-ainm úsáideora go dtà go n-éilÃonn duine é
+continue=Lean ar aghaidh
+cancel=Cealaigh
+language=Teanga
+ui=Téama
+hidden_comment_types=Cineálacha tráchtaireachta ceilte
+hidden_comment_types_description=Nà thaispeánfar cineálacha tráchta a sheiceáiltear anseo taobh istigh de leathan Cuireann seiceáil “Lipéad†mar shampla baintear gach trácht “{user} cursaÃ/bainte {label}â€.
+hidden_comment_types.ref_tooltip=Tuairimà ina dtagraÃodh an tsaincheist seo ó shaincheiste/coiste eile...
+hidden_comment_types.issue_ref_tooltip=Tuairimà ina n-athraÃonn an t-úsáideoir an brainse/clib a bhaineann leis an tsaincheist
+comment_type_group_reference=Tagairt
+comment_type_group_label=Lipéad
+comment_type_group_milestone=Cloch MhÃle
+comment_type_group_assignee=Sannaitheoir
+comment_type_group_title=Teideal
+comment_type_group_branch=Brainse
+comment_type_group_time_tracking=Rianú Ama
+comment_type_group_deadline=Spriocdháta
+comment_type_group_dependency=Spleáchas
+comment_type_group_lock=Stádas Glas
+comment_type_group_review_request=Iarratas athbhreithnithe
+comment_type_group_pull_request_push=Tiomáintà curtha leis
+comment_type_group_project=Tionscadal
+comment_type_group_issue_ref=Tagairt eisiúna
+saved_successfully=Sábháiltear do shocruithe go rathúil.
+privacy=PrÃobháideacht
+keep_activity_private=Folaigh gnÃomhaÃocht ó leathanach próifÃle
+keep_activity_private_popup=Nà dhéanann an gnÃomhaÃocht le feiceáil ach duit féin agus do na riarthóirÃ
+
+lookup_avatar_by_mail=Cuardaigh Avatar trà Seoladh RÃomhphoist
+federated_avatar_lookup=Cuardach Avatar Cónaidhme
+enable_custom_avatar=Úsáid Avatar Saincheaptha
+choose_new_avatar=Roghnaigh avatar nua
+update_avatar=Nuashonrú Avatar
+delete_current_avatar=Scrios Avatar Reatha
+uploaded_avatar_not_a_image=Nà Ãomhá é an comhad uaslódáilte.
+uploaded_avatar_is_too_big=SáraÃonn méid an chomhaid uaslódáilte (%d KiB) an méid uasta (%d KiB).
+update_avatar_success=Tá do avatar nuashonraithe.
+update_user_avatar_success=NuashonraÃodh avatar an úsáideora.
+
+change_password=Nuashonrú Pasfhocal
+old_password=Pasfhocal Reatha
+new_password=Pasfhocal Nua
+retype_new_password=Deimhnigh Pasfhocal Nua
+password_incorrect=Tá an pasfhocal reatha mÃcheart.
+change_password_success=Tá do phasfhocal nuashonraithe. SÃnigh isteach ag baint úsáide as do phasfhocal nua as seo amach.
+password_change_disabled=Nà féidir le húsáideoirà neamháitiúla a bhfocal faire a nuashonrú trà chomhéadan gréasáin Gitea.
+
+emails=Seoltaà rÃomhphoist
+manage_emails=Bainistigh Seoltaà RÃomhphoist
+manage_themes=Roghnaigh téama réamhshocraithe
+manage_openid=Seoltaà OpenID a bhainistiú
+email_desc=Úsáidfear do phrÃomhsheoladh rÃomhphoist le haghaidh fógraÃ, aisghabháil pasfhocal agus, ar choinnÃoll nach bhfuil sé i bhfolach, oibrÃochtaà Git bunaithe ar an ngréas
+theme_desc=Beidh sé seo do théama réamhshocraithe ar fud an láithreáin.
+theme_colorblindness_help=TacaÃocht Téama Dathdallacht
+theme_colorblindness_prompt=Nà fhaigheann Gitea ach roinnt téamaà le tacaÃocht bhunúsach daille datha, nach bhfuil ach cúpla dathanna sainithe acu. Tá an obair fós ar siúl. D’fhéadfaà tuilleadh feabhsuithe a dhéanamh trà nÃos mó dathanna a shainiú sna comhaid CSS téamaÃ.
+primary=PrÃomhúil
+activated=GnÃomhachtaithe
+requires_activation=ÉilÃonn gnÃomhachtú
+primary_email=Déan prÃomhúil
+activate_email=Seol GnÃomhachtaithe
+activations_pending=GnÃomhartha ar Feitheamh
+can_not_add_email_activations_pending=Tá gnÃomhachtú ar feitheamh, déan iarracht arÃs i gceann cúpla nóiméad más mian leat rÃomhphost nua a chur leis.
+delete_email=Bain
+email_deletion=Bain Seoladh R-phoist
+email_deletion_desc=Bainfear an seoladh rÃomhphoist agus an fhaisnéis ghaolmhar as do chuntas. Nà bheidh na tiomáintà Git a bhaineann leis an seoladh rÃomhphoist seo athraithe. Lean ar aghaidh?
+email_deletion_success=Tá an seoladh rÃomhphoist bainte.
+theme_update_success=NuashonraÃodh do théama.
+theme_update_error=NÃl an téama roghnaithe ann.
+openid_deletion=Bain Seoladh OpenID
+openid_deletion_desc=Cuirfidh an seoladh OpenID seo a bhaint as do chuntas cosc ort sÃniú isteach leis. Lean ar aghaidh?
+openid_deletion_success=Tá an seoladh OpenID bainte.
+add_new_email=Cuir Seoladh RÃomhphoist nua
+add_new_openid=Cuir URI OpenID nua leis
+add_email=Cuir Seoladh R-phoist leis
+add_openid=Cuir OpenID URI
+add_email_confirmation_sent=Seoladh rÃomhphost deimhnithe chuig “%sâ€. Seiceáil do bhosca isteach laistigh den chéad %s eile chun do sheoladh rÃomhphoist a dhearbhú.
+add_email_success=Cuireadh an seoladh rÃomhphoist nua leis.
+email_preference_set_success=SocraÃodh rogha rÃomhphoist go rathúil.
+add_openid_success=Cuireadh an seoladh OpenID nua leis.
+keep_email_private=Folaigh Seoladh rÃomhphoist
+keep_email_private_popup=Folóidh sé seo do sheoladh rÃomhphoist ó do phróifÃl, chomh maith le nuair a dhéanann tú iarratas tarraingthe nó comhad a chur in eagar ag baint úsáide as an gcomhéadan gréasáin. Nà mhodhnófar na tiomáintà a bhrúitear. Úsáid %s i ngealltanais chun iad a cheangal le do chuntas.
+openid_desc=Ligeann OpenID duit fÃordheimhniú a tharmligean chuig soláthraà seachtrach.
+
+manage_ssh_keys=Bainistigh Eochracha SSH
+manage_ssh_principals=Bainistigh PrÃomhoidà Teastas SSH
+manage_gpg_keys=Bainistigh Eochracha GPG
+add_key=Cuir Eochair
+ssh_desc=Tá na heochracha SSH poiblà seo bainteach le do chuntas. CeadaÃonn na heochracha prÃobháideacha comhfhreagracha rochtain iomlán ar do stórtha.
+principal_desc=Tá baint ag na prÃomhoidà deimhnithe SSH seo le do chuntas agus ceadaÃonn siad rochtain iomlán ar do stórtha.
+gpg_desc=Tá na heochracha GPG poiblà seo bainteach le do chuntas. Coinnigh d'eochracha prÃobháideacha sábháilte mar a cheadaÃonn siad gealltanais a fhÃorú.
+ssh_helper=An bhfuil cabhair uait? Féach ar threoir GitHub chun d'eochracha SSH féin a chruthú nó réitigh fadhbanna coitianta a> seans go dtiocfaidh tú ar úsáid SSH.
+gpg_helper=Cabhair uait? Féach ar threoir GitHub faoi GPG.
+add_new_key=Cuir eochair SSH leis
+add_new_gpg_key=Cuir Eochair GPG leis
+key_content_ssh_placeholder=TosaÃonn sé le 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', nó 'sk-ssh-ed25519@openssh.com'
+key_content_gpg_placeholder=TosaÃonn sé le '----- BEGIN PGP POIBLà EOCHAIR BLOC ------ '
+add_new_principal=Cuir PrÃomhoide
+ssh_key_been_used=Cuireadh an eochair SSH seo leis an bhfreastalaà cheana féin.
+ssh_key_name_used=Tá eochair SSH leis an ainm céanna ar do chuntas cheana féin.
+ssh_principal_been_used=Cuireadh an prÃomhoide seo leis an bhfreastalaà cheana féin.
+gpg_key_id_used=Tá eochair GPG poiblà leis an aitheantas céanna ann cheana féin.
+gpg_no_key_email_found=Nà mheaitseálann an eochair GPG seo aon seoladh rÃomhphoist gnÃomhachtaithe a bhaineann le do chuntas. Féadfar é a chur leis fós má shÃnÃonn tú an comhartha a chuirtear ar fáil.
+gpg_key_matched_identities=Aitheantais Meaitseáilte:
+gpg_key_matched_identities_long=Meaitseálann na haitheantais leabaithe san eochair seo na seoltaà rÃomhphoist gnÃomhachtaithe seo a leanas don úsáideoir seo. Is féidir gealltanais a mheaitseálann na seoltaà rÃomhphoist seo a fhÃorú leis an eochair seo.
+gpg_key_verified=Eochair FhÃoraithe
+gpg_key_verified_long=FÃoraÃodh an eochair le heochairchomhartha agus is féidir à a úsáid chun a fhÃorú go bhfuil geallta ag meaitseáil aon seoltaà rÃomhphoist gnÃomhachtaithe don úsáideoir seo chomh maith le haon aitheantas comhoiriúnaithe don eochair seo.
+gpg_key_verify=FÃoraigh
+gpg_invalid_token_signature=Nà mheaitseálann an eochair, an sÃniú agus an comhartha GPG a sholáthraÃtear nó tá an comhartha as dáta.
+gpg_token_required=Nà mór duit sÃniú a sholáthar don chomhartha thÃos
+gpg_token=Comhartha
+gpg_token_help=Is féidir leat sÃniú a ghiniúint ag úsáid:
+gpg_token_signature=SÃniú Armúrtha GPG
+key_signature_gpg_placeholder=TosaÃonn sé le '-----BEGIN SÃNIÚ PGP -----'
+verify_gpg_key_success=Tá eochair GPG “%s†fÃoraithe.
+ssh_key_verified=Eochair FhÃoraithe
+ssh_key_verified_long=FÃoraÃodh an eochair le heochairchomhartha agus is féidir à a úsáid chun a fhÃorú go bhfuil geallta ag teacht le haon seoltaà rÃomhphoist gnÃomhachtaithe don úsáideoir seo.
+ssh_key_verify=FÃoraigh
+ssh_invalid_token_signature=Nà mheaitseálann an eochair, an sÃniú nó an comhartha SSH a sholáthraÃtear nó tá an comhartha as dáta.
+ssh_token_required=Nà mór duit sÃniú a sholáthar don chomhartha thÃos
+ssh_token=Comhartha
+ssh_token_help=Is féidir leat sÃniú a ghiniúint ag úsáid:
+ssh_token_signature=SÃniú armúrtha SSH
+key_signature_ssh_placeholder=TosaÃonn sé le '-----BEGIN SSH SÃNITURE-----'
+verify_ssh_key_success=Tá eochair SSH “%s†fÃoraithe.
+subkeys=Fo-eochracha
+key_id=Eochair ID
+key_name=Ainm Eochair
+key_content=Ãbhar
+principal_content=Ãbhar
+add_key_success=Cuireadh an eochair SSH “%s†leis.
+add_gpg_key_success=Cuireadh an eochair GPG “%s†leis.
+add_principal_success=Cuireadh prÃomhoide an deimhnithe SSH “%s†leis.
+delete_key=Bain
+ssh_key_deletion=Bain Eochair SSH
+gpg_key_deletion=Bain Eochair GPG
+ssh_principal_deletion=Bain PrÃomhoide Teastas SSH
+ssh_key_deletion_desc=Ag baint eochair SSH, cuirtear a rochtain ar do chuntas a chúlghairm. Lean ar aghaidh?
+gpg_key_deletion_desc=Má bhaintear eochair GPG, nà fhÃoraÃtear gealltanais a shÃnigh sé. An leanfaidh tú ar aghaidh?
+ssh_principal_deletion_desc=Cúlghairtear a rochtain ar do chuntas PrÃomhoide Teastas SSH. Lean ar aghaidh?
+ssh_key_deletion_success=Tá an eochair SSH bainte.
+gpg_key_deletion_success=Tá an eochair GPG bainte amach.
+ssh_principal_deletion_success=Tá an prÃomhoide bainte.
+added_on=Cuireadh leis ar %s
+valid_until_date=Bailà go dtà %s
+valid_forever=Bailà go deo
+last_used=Úsáidtear go deireanach ar
+no_activity=Gan gnÃomhaÃocht le déanaÃ
+can_read_info=Léigh
+can_write_info=ScrÃobh
+key_state_desc=Úsáideadh an eochair seo le 7 lá anuas
+token_state_desc=Úsáideadh an comhartha seo le 7 lá anuas
+principal_state_desc=Úsáideadh an prÃomhoide seo le 7 lá anuas
+show_openid=Taispeáin ar phróifÃl
+hide_openid=Folaigh ón bpróifÃl
+ssh_disabled=SSH faoi mhÃchumas
+ssh_signonly=Tá SSH faoi láthair faoi láthair mar sin nà úsáidtear na heochracha seo ach le haghaidh fÃorú sÃnithe tiomanta.
+ssh_externally_managed=Déantar an eochair SSH seo a bhainistiú go seachtrach don úsáideoir seo
+manage_social=Cuntais Shóisialta Ghaolmhara a bhainistiú
+social_desc=Is féidir na cuntais shóisialta seo a úsáid chun sÃniú isteach i do chuntas. Déan cinnte go n-aithnÃonn tú gach ceann acu.
+unbind=DÃnascadh
+unbind_success=Tá an cuntas sóisialta bainte go rathúil.
+
+manage_access_token=Bainistigh Comharthaà Rochtana
+generate_new_token=Gin Comhartha Nua
+tokens_desc=Tugann na comharthaà seo rochtain ar do chuntas ag baint úsáide as an API Gitea.
+token_name=Ainm Comhartha
+generate_token=Gin Comhartha
+generate_token_success=Gintear do chomhartha nua. Cóipeáil é anois mar nà thaispeánfar é arÃs.
+generate_token_name_duplicate=Úsáideadh %s mar ainm feidhmchláir cheana féin. Úsáid ceann nua le do thoil.
+delete_token=Scrios
+access_token_deletion=Scrios Comhartha Rochtana
+access_token_deletion_cancel_action=Cealaigh
+access_token_deletion_confirm_action=Scrios
+access_token_deletion_desc=Cúlghairfear rochtain ar do chuntas le haghaidh feidhmchláir a úsáideann é a scriosadh comhartha. Nà féidir é seo a chur ar ais. Lean ar aghaidh?
+delete_token_success=Tá an comhartha scriosta. NÃl rochtain ag iarratais a úsáideann é ar do chuntas a thuilleadh.
+repo_and_org_access=Rochtain Stórála agus EagraÃochta
+permissions_public_only=Poiblà amháin
+permissions_access_all=Gach (poiblÃ, prÃobháideach agus teoranta)
+select_permissions=Roghnaigh ceadanna
+permission_not_set=NÃl leagtha
+permission_no_access=Gan rochtain
+permission_read=Léigh
+permission_write=Léigh agus ScrÃobh
+access_token_desc=Nà chuireann ceadchomharthaà roghnaithe ach teorainn leis an údarú do na bealaà API comhfhreagracha. Léigh doiciméadúchán chun tuilleadh eolais a fháil.
+at_least_one_permission=Nà mór duit cead amháin ar a laghad a roghnú chun comhartha a chruthú
+permissions_list=Ceadanna:
+
+manage_oauth2_applications=Bainistigh Feidhmchláir OAuth2
+edit_oauth2_application=Cuir Feidhmchlár OAuth2 in eagar
+oauth2_applications_desc=CumasaÃonn feidhmchláir OAuth2 d’fheidhmchlár trÃú páirtà úsáideoirà a fhÃordheimhniú go slán ag an ásc Gitea seo.
+remove_oauth2_application=Bain Feidhmchlár OAuth2
+remove_oauth2_application_desc=Ag baint feidhmchlár OAuth2, cúlghairfear rochtain ar gach comhartha rochtana sÃnithe. Lean ar aghaidh?
+remove_oauth2_application_success=Scriosadh an feidhmchlár.
+create_oauth2_application=Cruthaigh Feidhmchlár OAuth2 nua
+create_oauth2_application_button=Cruthaigh Feidhmchlár
+create_oauth2_application_success=D'éirigh leat feidhmchlár nua OAuth2 a chruthú.
+update_oauth2_application_success=D'éirigh leat an feidhmchlár OAuth2 a nuashonrú.
+oauth2_application_name=Ainm Feidhmchláir
+oauth2_confidential_client=Cliant Rúnda. Roghnaigh le haghaidh aipeanna a choimeádann an rún faoi rún, mar aipeanna gréasáin. Ná roghnaigh le haghaidh aipeanna dúchasacha lena n-áirÃtear aipeanna deisce agus soghluaiste.
+oauth2_skip_secondary_authorization=Scipeáil údarú do chliaint poiblà tar éis rochtain a dheonú D'fhéadfadh sé go mbeadh riosca slándála
+oauth2_redirect_uris=URIs a atreorú. Úsáid lÃne nua do gach URI le do thoil.
+save_application=Sábháil
+oauth2_client_id=ID Cliant
+oauth2_client_secret=Rúnda Cliant
+oauth2_regenerate_secret=Athghin Rún
+oauth2_regenerate_secret_hint=Chaill tú do rún?
+oauth2_client_secret_hint=Nà thaispeánfar an rún arÃs tar éis duit an leathanach seo a fhágáil nó a athnuachan. Déan cinnte le do thoil gur shábháil tú é.
+oauth2_application_edit=Cuir in eagar
+oauth2_application_create_description=Tugann feidhmchláir OAuth2 rochtain d'iarratas trÃú páirtà ar chuntais úsáideora ar an gcás seo.
+oauth2_application_remove_description=Cuirfear feidhmchlár OAuth2 a bhaint cosc air rochtain a fháil ar chuntais úsáideora údaraithe ar an gcás seo. Lean ar aghaidh?
+oauth2_application_locked=RéamhchláraÃonn Gitea roinnt feidhmchlár OAuth2 ar thosú má tá sé cumasaithe i gcumraÃocht. Chun iompar gan choinne a chosc, nà féidir iad seo a chur in eagar ná a bhaint. Féach do thoil do dhoiciméadú OAuth2 le haghaidh tuilleadh faisnéise.
+
+authorized_oauth2_applications=Feidhmchláir Údaraithe OAuth2
+authorized_oauth2_applications_description=Tá rochtain tugtha agat ar do chuntas pearsanta Gitea ar na feidhmchláir trÃú páirtà seo. Cúlghairm rochtain d'iarratais nach bhfuil uait a thuilleadh.
+revoke_key=Cúlghairm
+revoke_oauth2_grant=Rochtain a chúlghairm
+revoke_oauth2_grant_description=Cuirfidh rochtain ar an bhfeidhmchlár trÃú páirtà seo a chúlghairm cosc ar an bhfeidhmchlár seo rochtain An bhfuil tú cinnte?
+revoke_oauth2_grant_success=Cúlghairtear rochtain go rathúil.
+
+twofa_desc=Chun do chuntas a chosaint ar goid pasfhocal, is féidir leat fón cliste nó gléas eile a úsáid chun pasfhocail aon-uaire bunaithe ar am (“TOTPâ€) a fháil.
+twofa_recovery_tip=Má chailleann tú do ghléas, beidh tú in ann eochair aisghabhála aonúsáide a úsáid chun rochtain ar do chuntas a fháil ar ais.
+twofa_is_enrolled=Tá do chuntas cláraithe i bhfÃord heimhniú dhá fhachtóir faoi láthair.
+twofa_not_enrolled=NÃl do chuntas cláraithe faoi láthair i bhfÃordheimhniú dhá fhachtóir.
+twofa_disable=DÃchumasaigh FÃordheimhniú Dhá-Fachtóir
+twofa_scratch_token_regenerate=Athghin Eochair Aisghabhála Aonúsáide
+twofa_scratch_token_regenerated=Is é %s d'eochair aisghabhála aonúsáide anois. Stóráil é in áit shábháilte, mar nà thaispeánfar é arÃs.
+twofa_enroll=Cláraigh le FÃordheimhniú Dhá-Fachtóir
+twofa_disable_note=Is féidir leat fÃordheimhniú dhá fhachtóir a dhÃchumasú más gá.
+twofa_disable_desc=Má dhÃchumasaÃtear fÃordheimhniú dhá fhachtóir beidh do chuntas chomh slán. Lean ar aghaidh?
+regenerate_scratch_token_desc=Má chuir tú d'eochair aisghabhála mÃchuir tú nó má d'úsáid tú é cheana féin chun sÃniú isteach, is féidir leat é a athshocrú anseo.
+twofa_disabled=Tá fÃordheimhniú dhá fhachtóir dÃchumasaithe.
+scan_this_image=Scan an Ãomhá seo le d'fheidhmchlár fÃordheimhnithe:
+or_enter_secret=Nó cuir isteach an rún: %s
+then_enter_passcode=Agus cuir isteach an paschód a léirÃtear san fheidhmchlár:
+passcode_invalid=Tá an pascód mÃcheart. Bain triail as arÃs.
+twofa_enrolled=Tá do chuntas cláraithe go rathúil. Stóráil d'eochair aisghabhála aonúsáide (%s) in áit shábháilte, mar nà thaispeánfar é arÃs.
+twofa_failed_get_secret=Theip ar rún a fháil.
+
+webauthn_desc=Is feistà crua-earraà iad eochracha slándála ina bhfuil eochracha cripte Is féidir iad a úsáid le haghaidh fÃordheimhniú dhá fhachtóir. Caithfidh eochracha slándála tacú le caigh deán FÃordheimhnithe WebAuthn
+webauthn_register_key=Cuir Eochair Slándála
+webauthn_nickname=Leasainm
+webauthn_delete_key=Bain Eochair Slándála
+webauthn_delete_key_desc=Má bhaineann tú eochair slándála nà féidir leat sÃniú leis a thuilleadh. Lean ar aghaidh?
+webauthn_key_loss_warning=Má chailleann tú d'eochracha slándála, caillfidh tú rochtain ar do chuntas.
+webauthn_alternative_tip=B'fhéidir gur mhaith leat modh fÃordheimhnithe breise a chumrú.
+
+manage_account_links=Bainistigh Cuntais Nasctha
+manage_account_links_desc=Tá na cuntais sheachtracha seo nasctha le do chuntas Gitea.
+account_links_not_available=NÃl aon chuntais sheachtracha nasctha le do chuntas Gitea faoi láthair.
+link_account=Cuntas Nasc
+remove_account_link=Bain Cuntas Nasctha
+remove_account_link_desc=Ag baint cuntas nasctha, cuirfear a rochtain ar do chuntas Gitea a chúlghairm. Lean ar aghaidh?
+remove_account_link_success=Tá an cuntas nasctha bainte amach.
+
+hooks.desc=Cuir crúcaà gréasán leis a spreagfar do gach stór ar leatsa iad.
+
+orgs_none=NÃl tú ina bhall d'aon eagraÃochtaÃ.
+repos_none=NÃl aon stórais agat.
+
+delete_account=Scrios Do Cuntas
+delete_prompt=Scriosfaidh an oibrÃocht seo do chuntas úsáideora go buan. Nà FÉIDIR é a chealú.
+delete_with_all_comments=Tá do chuntas nÃos óige ná %s. Chun tuairimà taibhse a sheachaint, scriosfar gach trácht saincheistea/PR leis.
+confirm_delete_account=Deimhnigh scriosadh
+delete_account_title=Scrios Cuntas Úsáide
+delete_account_desc=An bhfuil tú cinnte gur mhaith leat an cuntas úsáideora seo a scriosadh go buan?
+
+email_notifications.enable=Cumasaigh Fógraà RÃomhphoist
+email_notifications.onmention=RÃomhphost amháin ar luaigh
+email_notifications.disable=DÃchumasaigh Fógraà RÃomhphoist
+email_notifications.submit=Socraigh rogha rÃomhphoist
+email_notifications.andyourown=Agus Do Fógraà Féin
+
+visibility=Infheictheacht úsáideora
+visibility.public=PoiblÃ
+visibility.public_tooltip=Infheicthe do gach duine
+visibility.limited=Teoranta
+visibility.limited_tooltip=Infheicthe ach d'úsáideoirà fÃordheimhnithe
+visibility.private=PrÃobháideach
+visibility.private_tooltip=Nà fheictear ach do bhaill d'eagraÃochtaà a chuaigh tú isteach
+
+[repo]
+new_repo_helper=Tá gach comhad tionscadail i stór, lena n-áirÃtear stair athbhreithnithe. Ceana féin ag óstáil ceann in áit eile Stórlann aistrithe.
+owner=Úinéir
+owner_helper=B'fhéidir nach dtaispeánfar roinnt eagraÃochtaà sa anuas mar gheall ar theorainn uasta comhaireamh stórais.
+repo_name=Ainm Stórais
+repo_name_helper=Úsáideann dea-ainmneacha stórtha eochairfhocail ghearr, i gcuimhne agus uathúla.
+repo_size=Méid an Stóras
+template=Teimpléad
+template_select=Roghnaigh teimpléad.
+template_helper=Déan teimpléad den stóras
+template_description=Ligeann stórais teimpléid d'úsáideoirà stórais nua a ghiniúint leis an struchtúr eolaire céanna, comhaid agus socruithe roghnacha.
+visibility=Infheictheacht
+visibility_description=Nà bheidh ach an t-úinéir nó baill na heagraÃochta má tá cearta acu in ann é a fheiceáil.
+visibility_helper=Déan stóras prÃobháideach
+visibility_helper_forced=Cuireann riarthóir do shuÃomh iallach ar stórais nua a bheith prÃobháideach.
+visibility_fork_helper=(Beidh tionchar ag athrú seo ar gach forc.)
+clone_helper=TeastaÃonn cabhair ó chlónáil? Tabhair cuairt ar Cabhair.
+fork_repo=Stóras Forc
+fork_from=Forc ó
+already_forked=Tá tú tar éis %s a fhoirceann
+fork_to_different_account=Forc chuig cuntas difriúil
+fork_visibility_helper=Nà féidir infheictheacht stór forcailte a athrú.
+fork_branch=Brainse le clónú chuig an bhforc
+all_branches=Gach brainse
+fork_no_valid_owners=Nà féidir an stór seo a fhorcáil toisc nach bhfuil úinéirà bailà ann.
+fork.blocked_user=Nà féidir an stór a fhorcáil toisc go bhfuil úinéir an stórais bac ort.
+use_template=Úsáid an teimpléad seo
+open_with_editor=Oscail le %s
+download_zip=Ãoslódáil ZIP
+download_tar=Ãoslódáil TAR.GZ
+download_bundle=Ãoslódáil BUNDLE
+generate_repo=Cruthaigh Stóras
+generate_from=Gin Ó
+repo_desc=Cur sÃos
+repo_desc_helper=Cuir isteach tuairisc ghearr (roghnach)
+repo_lang=Teanga
+repo_gitignore_helper=Roghnaigh teimpléid .gitignore.
+repo_gitignore_helper_desc=Roghnaigh na comhaid nach bhfuil le rianú ó liosta teimpléid do theangacha coitianta. Cuirtear déantáin tipiciúla a ghineann uirlisà tógála gach teanga san áireamh ar.gitignore de réir réamhshocraithe.
+issue_labels=Lipéid Eisiúna
+issue_labels_helper=Roghnaigh tacar lipéad eisiúna.
+license=Ceadúnas
+license_helper=Roghnaigh comhad ceadúnais.
+license_helper_desc=RialaÃonn ceadúnas cad is féidir agus nach féidir le daoine eile a dhéanamh le do chód. NÃl mé cinnte cé acu ceann atá ceart do do thionscadal? Féach Roghnaigh ceadúnas.
+multiple_licenses=Ceadúnais Iolracha
+object_format=Formáid Oibiacht
+object_format_helper=Formáid oibiacht an stór. Nà féidir é a athrú nÃos déanaÃ. Is é SHA1 an comhoiriúnacht is fearr.
+readme=README
+readme_helper=Roghnaigh comhad teimpléad README.
+readme_helper_desc=Seo an áit inar féidir leat cur sÃos iomlán a scrÃobh do thionscadal.
+auto_init=Taisce a thionscnamh (Cuireann sé .gitignore, Ceadúnas agus README)
+trust_model_helper=Roghnaigh múnla iontaobhais le haghaidh fÃorú Is iad na roghanna féideartha:
+trust_model_helper_collaborator=Comhoibritheoir: SÃnithe muinÃn ag comhoibrithe
+trust_model_helper_committer=Gealltóir: Iontaobhais sÃnithe a mheaitseálann na gealltoirÃ
+trust_model_helper_collaborator_committer=Comhoibritheo+Coiteoir: SÃnithe iontaobhais ag comhoibritheoirà a mheaitseann leis an gealltóir
+trust_model_helper_default=Réamhshocrú: Úsáid an tsamhail iontaobhais réamhshocraithe don tsuiteáil seo
+create_repo=Cruthaigh Stóras
+default_branch=Branse Réamhshocraithe
+default_branch_label=réamhshocraithe
+default_branch_helper=Is é an brainse réamhshocraithe an bunbhrainse d'iarratais tarraingthe agus gealltanna cód.
+mirror_prune=Prúnáil
+mirror_prune_desc=Bain tagairtà cianrianaithe atá as feidhm
+mirror_interval=Eatramh Scátháin (is iad aonaid ama bailà ná 'h', 'm', 's'). 0 chun sioncrónú tréimhsiúil a dhÃchumasú. (Eatraimh Ãosta: %s)
+mirror_interval_invalid=NÃl an eatramh scátháin bailÃ.
+mirror_sync=sioncronaithe
+mirror_sync_on_commit=Sioncrónaigh nuair a bhrúitear geallúintÃ
+mirror_address=Clón Ó URL
+mirror_address_desc=Cuir aon dhintiúir riachtanacha sa chuid Údaraithe.
+mirror_address_url_invalid=Tá an URL curtha ar fáil neamhbhailÃ. Caithfidh tú gach comhpháirt den url a éalú i gceart.
+mirror_address_protocol_invalid=Tá an URL curtha ar fáil neamhbhailÃ. Nà féidir ach suÃomhanna http (s)://nó git://a úsáid le haghaidh scátháin.
+mirror_lfs=Stóráil Comhad Móra (LFS)
+mirror_lfs_desc=GnÃomhachtaigh scáthú sonraà LFS.
+mirror_lfs_endpoint=CrÃochphointe LFS
+mirror_lfs_endpoint_desc=Déanfaidh Sync iarracht an url clónála a úsáid chun an freastalaà LFS a chinneadh. Is féidir leat crÃochphointe saincheaptha a shonrú freisin má tá na sonraà LFS stórtha stóráilte áit éigin eile.
+mirror_last_synced=Sincronaithe Deireanach
+mirror_password_placeholder=(Gan athrú)
+mirror_password_blank_placeholder=(Neamhshocraithe)
+mirror_password_help=Athraigh ainm úsáideora chun pasfhocal stóráilte a scriosadh.
+watchers=BreathnóirÃ
+stargazers=RéalteoirÃ
+stars_remove_warning=Bainfidh sé seo na réaltaà go léir ón stóras seo.
+forks=Forcanna
+stars=RéaltaÃ
+reactions_more=agus %d nÃos mó
+unit_disabled=Tá an chuid stórais seo dÃchumasaithe ag riarthóir an láithreáin.
+language_other=Eile
+adopt_search=Iontráil ainm úsáideora chun stórais neamhghlactha a chuardach... (fág bán chun gach rud a fháil)
+adopt_preexisting_label=Glacadh le Comhaid
+adopt_preexisting=Glac le comhaid atá ann cheana
+adopt_preexisting_content=Cruthaigh stór ó %s
+adopt_preexisting_success=Comhaid ghlacadh agus stór cruthaithe ó %s
+delete_preexisting_label=Scrios
+delete_preexisting=Scrios comhaid atá ann cheana
+delete_preexisting_content=Scrios comhaid i %s
+delete_preexisting_success=Scriosta comhaid neamhghlactha i %s
+blame_prior=Féach ar an milleán roimh an athrú seo
+blame.ignore_revs=Ag déanamh neamhairde de leasuithe i .git-blame-ignore-revs. Cliceáil anseo chun seachaint agus an gnáth-amharc milleán a fheiceáil.
+blame.ignore_revs.failed=Theip ar neamhaird a dhéanamh ar leasuithe i .git-blame-ignore-revs.
+author_search_tooltip=Taispeánann 30 úsáideoir ar a mhéad
+
+tree_path_not_found_commit=NÃl cosán %[1]s ann i dtiomantas %[2]s
+tree_path_not_found_branch=NÃl cosán %[1]s ann i mbrainse %[2]s
+tree_path_not_found_tag=NÃl cosán %[1]s ann i gclib %[2]s
+
+transfer.accept=Glac le hAistriú
+transfer.accept_desc=Aistriú chuig “%sâ€
+transfer.reject=Diúltaigh aistriú
+transfer.reject_desc=`Cealaigh aistriú chuig "%s"`
+transfer.no_permission_to_accept=NÃl cead agat glacadh leis an aistriú seo.
+transfer.no_permission_to_reject=NÃl cead agat an aistriú seo a dhiúltú.
+
+desc.private=PrÃobháideach
+desc.public=PoiblÃ
+desc.template=Teimpléad
+desc.internal=Inmheánach
+desc.archived=Cartlannaithe
+desc.sha256=SHA256
+
+template.items=MÃreanna Teimpléad
+template.git_content=Ãbhar Git (Brainse Réamhshocraithe)
+template.git_hooks=Crúcanna Git
+template.git_hooks_tooltip=Faoi láthair nà féidir leat Git Hooks a mhodhnú nó a bhaint nuair a chuirtear leis. Roghnaigh é seo ach amháin má tá muinÃn agat as an stóras teimpléid.
+template.webhooks=Crúcaà gréasáin
+template.topics=TopaicÃ
+template.avatar=Abhatár
+template.issue_labels=Lipéid Eisiúna
+template.one_item=Nà mór mÃr teimpléad amháin ar a laghad a roghnú
+template.invalid=Nà mór stór teimpléad a roghnú
+
+archive.title=Tá an stóras seo i gcartlann. Is féidir leat comhaid a fheiceáil agus iad a chlónáil, ach nà féidir leat ceisteanna a bhrú ná a oscailt ná iarratais a tharraingt.
+archive.title_date=Tá an stóras seo cartlannaithe ar %s. Is féidir leat comhaid a fheiceáil agus é a chlónú, ach nà féidir leat saincheisteanna a bhrú nó a oscailt ná iarratais a tharraingt.
+archive.issue.nocomment=Tá an stóras seo i gcartlann. Nà féidir leat trácht a dhéanamh ar shaincheisteanna.
+archive.pull.nocomment=Tá an stóras seo i gcartlann. Nà féidir leat trácht a dhéanamh ar iarratais tarraingthe.
+
+form.reach_limit_of_creation_1=Tá úinéir an stóras tar éis teorainn de %d stóras a bhaint amach cheana féin.
+form.reach_limit_of_creation_n=Tá úinéir an stórais tar éis teorainn de %d stórtha a bhaint amach cheana féin.
+form.name_reserved=Tá ainm an stór "%s" in áirithe.
+form.name_pattern_not_allowed=Nà cheadaÃtear an patrún "%s" in ainm stór.
+
+need_auth=Údarú
+migrate_options=Roghanna Imirce
+migrate_service=SeirbhÃs Imirce
+migrate_options_mirror_helper=Beidh an stóras seo ina scáthán
+migrate_options_lfs=Aimirce comhaid LFS
+migrate_options_lfs_endpoint.label=CrÃochphointe LFS
+migrate_options_lfs_endpoint.description=Déanfaidh imirce iarracht do chianda Git a úsáid chun freastalaà LFS a chinneadh. Is féidir leat crÃochphointe saincheaptha a shonrú freisin má tá na sonraà LFS stórtha stóráilte áit éigin eile.
+migrate_options_lfs_endpoint.description.local=TacaÃtear le cosán freastalaà áitiúil freisin.
+migrate_options_lfs_endpoint.placeholder=Má fhágtar bán, dÃorthófar an crÃochphointe ón URL clóin
+migrate_items=MÃreanna Imirce
+migrate_items_wiki=Wiki
+migrate_items_milestones=Clocha mÃle
+migrate_items_labels=Lipéid
+migrate_items_issues=Saincheisteanna
+migrate_items_pullrequests=Iarrataà Tarraing
+migrate_items_merge_requests=Iarrataà Cumaisc
+migrate_items_releases=EisiúintÃ
+migrate_repo=Stóras Imirc
+migrate.clone_address=Aimirce/ Clón Ó URL
+migrate.clone_address_desc=An URL 'clón' HTTP(S) nó Git de stóras atá ann cheana
+migrate.github_token_desc=Is féidir leat comhartha amháin nó nÃos mó a chur le camóg scartha anseo chun imirce a dhéanamh nÃos gasta mar gheall ar theorainn ráta API GitHub. RABHADH: D'fhéadfadh mÃ-úsáid na ngné seo beartas an sholáthraà seirbhÃse a shárú agus blocáil cuntais a bheith mar thoradh air.
+migrate.clone_local_path=nó cosán freastalaà áitiúil
+migrate.permission_denied=Nà cheadaÃtear duit stórais áitiúla a iompórtáil.
+migrate.permission_denied_blocked=Nà féidir leat allmhairiú ó óstaigh neamh-cheadaithe, iarr ar an riarachán socruithe ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS a sheiceáil le do thoil.
+migrate.invalid_local_path=Tá an cosán áitiúil neamhbhailÃ. NÃl sé ann nó nà eolaire é.
+migrate.invalid_lfs_endpoint=NÃl an crÃochphointe LFS bailÃ.
+migrate.failed=Theip ar an imirce:% v
+migrate.migrate_items_options=TeastaÃonn Comhartha Rochtana chun mÃreanna breise a aistriú
+migrated_from=AistrÃodh ó %[2]s
+migrated_from_fake=Aistrithe ó %[1]s
+migrate.migrate=Aistrigh Ó %s
+migrate.migrating=Ag aistriú ó %s ...
+migrate.migrating_failed=Theip ar aistriú ó %s.
+migrate.migrating_failed.error=Theip ar aistriú: %s
+migrate.migrating_failed_no_addr=Theip ar an imirce.
+migrate.github.description=Aistrigh sonraà ó github.com nó ó chásanna GitHub eile.
+migrate.git.description=Aistrigh stór amháin ó aon seirbhÃs Git.
+migrate.gitlab.description=Aistrigh sonraà ó gitlab.com nó ó chásanna GitLab eile.
+migrate.gitea.description=Aistrigh sonraà ó gitea.com nó ó chásanna Gitea eile.
+migrate.gogs.description=Aistrigh sonraà ó notabug.org nó ó chásanna eile de chuid Gogs.
+migrate.onedev.description=Aistrigh sonraà ó code.onedev.io nó ó chásanna OneDev eile.
+migrate.codebase.description=Aistrigh sonraà ó codebasehq.com.
+migrate.gitbucket.description=Aistrigh sonraà ó chásanna GitBucket.
+migrate.codecommit.description=Aistrigh sonraà ó AWS CodeCommit.
+migrate.codecommit.aws_access_key_id=ID Eochair Rochtana AWS
+migrate.codecommit.aws_secret_access_key=Eochair Rochtana Rúnda AWS
+migrate.codecommit.https_git_credentials_username=Ainm Úsáideora HTTPS Git Dintiúir
+migrate.codecommit.https_git_credentials_password=Pasfhocal Dintiúir Git HTTPS
+migrate.migrating_git=Sonraà Git a Aimirce
+migrate.migrating_topics=Ãbhair Imirce
+migrate.migrating_milestones=Clocha MÃle a Imirce
+migrate.migrating_labels=Lipéid Imirce
+migrate.migrating_releases=Eisiúintà Imirce
+migrate.migrating_issues=Saincheisteanna Imirce
+migrate.migrating_pulls=Iarratais Tarraingthe á n-Imirce
+migrate.cancel_migrating_title=Cealaigh Imirce
+migrate.cancel_migrating_confirm=Ar mhaith leat an imirce seo a chealú?
+
+mirror_from=scáthán de
+forked_from=forcailte ó
+generated_from=a ghintear ó
+fork_from_self=Nà féidir leat stóras atá agat a fhorcáil.
+fork_guest_user=SÃnigh isteach chun an stóras seo a fhorc.
+watch_guest_user=SÃnigh isteach chun féachaint ar an stór seo.
+star_guest_user=SÃnigh isteach chun an stóras seo a réalú.
+unwatch=DÃfhéachaint
+watch=Fhéachaint
+unstar=Bain Réalta
+star=Réalta
+fork=Forc
+action.blocked_user=Nà féidir gnÃomh a dhéanamh toisc go bhfuil úinéir an stórais bac ort.
+download_archive=Ãoslódáil Stóras
+more_operations=Tuilleadh oibrÃochtaÃ
+
+quick_guide=Treoir Tapa
+clone_this_repo=Clóin an stóras seo
+cite_this_repo=Luaigh an stóras seo
+create_new_repo_command=Stóras nua a chruthú ar an lÃne ordaithe
+push_exist_repo=Stóras atá ann cheana a bhrú ón lÃne ordaithe
+empty_message=NÃl aon ábhar sa stóras seo.
+broken_message=Nà féidir na sonraà Git atá mar bhunús leis an stóras seo a léamh. Déan teagmháil le riarthóir an chás seo nó scrios an stóras seo.
+
+code=Cód
+code.desc=Rochtain ar chód foinse, comhaid, gealltanais agus brainsÃ.
+branch=Brainse
+tree=Crann
+clear_ref=`Tagairt reatha soiléir`
+filter_branch_and_tag=Scagaire brainse nó clib
+find_tag=Aimsigh clib
+branches=BrainsÃ
+tags=Clibeanna
+issues=Saincheisteanna
+pulls=Iarratais Tarraingthe
+projects=Tionscadail
+packages=PacáistÃ
+actions=GnÃomhartha
+labels=Lipéid
+org_labels_desc=Lipéid ar leibhéal eagraÃochta is féidir a úsáid le gach stóras faoin eagraÃocht seo
+org_labels_desc_manage=bainistigh
+
+milestones=Clocha mÃle
+commits=TiomáintÃ
+commit=Tiomantas
+release=Scaoileadh
+releases=Scaoileann
+tag=Clib
+released_this=scaoileadh seo
+tagged_this=clib seo
+file.title=%s ag %s
+file_raw=Amh
+file_history=Stair
+file_view_source=Féach Foinse
+file_view_rendered=Amharc Rindreáilte
+file_view_raw=Amharc Amh
+file_permalink=Buan-nasc
+file_too_large=Tá an comhad ró-mhór le taispeáint.
+file_is_empty=Tá an comhad folamh.
+code_preview_line_from_to=LÃnte %[1]d go %[2]d i %[3]s
+code_preview_line_in=LÃne %[1]d i %[2]s
+invisible_runes_header=`Tá carachtair Unicode dofheicthe sa chomhad seo `
+invisible_runes_description=`Tá carachtair dofheicthe Unicode sa chomhad seo nach féidir a idirdhealú do dhaoine ach d'fhéadfadh rÃomhaire iad a phróiseáil ar bhealach difriúil. Má cheapann tú go bhfuil sé seo d'aon ghnó, is féidir leat neamhaird a dhéanamh go sábháilte don rabhadh seo Úsáid an cnaipe Escape chun iad a nochtadh. `
+ambiguous_runes_header=`Tá carachtair Unicode débhrÃoch sa chomhad seo `
+ambiguous_runes_description=`Tá carachtair Unicode sa chomhad seo a d'fhéadfadh a bheith mearbhall le carachtair eile. Má cheapann tú go bhfuil sé seo d'aon ghnó, is féidir leat neamhaird a dhéanamh go sábháilte don rabhadh seo Úsáid an cnaipe Escape chun iad a nochtadh. `
+invisible_runes_line=`Tá carachtair unicode dofheicthe ag an lÃne seo `
+ambiguous_runes_line=`Tá carachtair unicode débhrÃoch ag an lÃne seo `
+ambiguous_character=Is féidir `%[1]c [U+%04[1]X] a mheascadh le %[2]c [U+%04[2]X]`
+
+escape_control_characters=Éalú
+unescape_control_characters=DÃ-Éalú
+file_copy_permalink=Cóipeáil Buan-nasc
+view_git_blame=Féach ar Git Blame
+video_not_supported_in_browser=Nà thacaÃonn do bhrabhsálaà leis an gclib 'video' HTML5.
+audio_not_supported_in_browser=Nà thacaÃonn do bhrabhsálaà leis an gclib 'audio' HTML5.
+stored_lfs=Stóráilte le Git LFS
+symbolic_link=Nasc siombalach
+executable_file=Comhad Infheidhmithe
+vendored=DÃoltóra
+generated=Gintear
+commit_graph=Graf Tiomantas
+commit_graph.select=Roghnaigh brainsÃ
+commit_graph.hide_pr_refs=Folaigh Iarrataà Tarraing
+commit_graph.monochrome=Mona
+commit_graph.color=Dath
+commit.contained_in=Tá an tiomantas seo le fáil i:
+commit.contained_in_default_branch=Tá an tiomantas seo mar chuid den bhrainse réamhshocraithe
+commit.load_referencing_branches_and_tags=Luchtaigh brainsà agus clibeanna a thagraÃonn an tiomantas
+blame=An milleán
+download_file=Ãoslódáil comhad
+normal_view=Amharc Gnáth
+line=lÃne
+lines=lÃnte
+from_comment=(trácht)
+
+editor.add_file=Cuir Comhad
+editor.new_file=Comhad Nua
+editor.upload_file=Uaslódáil Comhad
+editor.edit_file=Cuir Comhad in eagar
+editor.preview_changes=Athruithe Réamhamhar
+editor.cannot_edit_lfs_files=Nà féidir comhaid LFS a chur in eagar sa chomhéadan gréasáin.
+editor.cannot_edit_non_text_files=Nà féidir comhaid dhénártha a chur in eagar sa chomhéadan gréasáin.
+editor.edit_this_file=Cuir Comhad in eagar
+editor.this_file_locked=Tá an comhad faoi ghlas
+editor.must_be_on_a_branch=Caithfidh tú a bheith ar bhrainse chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo.
+editor.fork_before_edit=Nà mór duit an stór seo a fhorcáil chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo.
+editor.delete_this_file=Scrios Comhad
+editor.must_have_write_access=Caithfidh rochtain scrÃofa a bheith agat chun athruithe a dhéanamh nó a mholadh ar an gcomhad seo.
+editor.file_delete_success=Tá an comhad "%s" scriosta.
+editor.name_your_file=Ainmnigh do chomhad…
+editor.filename_help=Cuir eolaire leis trÃna ainm a chlóscrÃobh ina dhiaidh sin le slash ('/'). Bain eolaire trà backspace a chlóscrÃobh ag tús an réimse ionchuir.
+editor.or=nó
+editor.cancel_lower=Cealaigh
+editor.commit_signed_changes=Tiomantas Athruithe SÃnithe
+editor.commit_changes=Athruithe a Tiomantas
+editor.add_tmpl=Cuir '{filename}' leis
+editor.add=Cuir %s leis
+editor.update=Nuashonraigh %s
+editor.delete=Scrios %s
+editor.patch=Cuir paiste i bhfeidh
+editor.patching=Paisteáil:
+editor.fail_to_apply_patch=Nà féidir paiste "%s" a chur i bhfeidhm
+editor.new_patch=Paiste Nua
+editor.commit_message_desc=Cuir cur sÃos leathnaithe roghnach leis…
+editor.signoff_desc=Cuir leantóir sÃnithe ag an gcoiteoir ag deireadh na teachtaireachta logála tiomanta.
+editor.commit_directly_to_this_branch=Tiomanta go dÃreach chuig an mbrainse %s.
+editor.create_new_branch=Cruthaigh brainse nua don ghealltanas seo agus cuir tús le hiarratas tarraingthe.
+editor.create_new_branch_np=Cruthaigh brainse nua don tiomantas seo.
+editor.propose_file_change=Athrú comhad a mholadh
+editor.new_branch_name=Ainmnigh an brainse nua don gealltanas seo
+editor.new_branch_name_desc=Ainm brainse nua…
+editor.cancel=Cealaigh
+editor.filename_cannot_be_empty=Nà féidir ainm an chomhaid a bheith folamh.
+editor.filename_is_invalid=Tá ainm an chomhaid neamhbhailÃ: "%s".
+editor.branch_does_not_exist=NÃl brainse "%s" ann sa stóras seo.
+editor.branch_already_exists=Tá brainse "%s" ann cheana féin sa stóras seo.
+editor.directory_is_a_file=Úsáidtear ainm eolaire "%s" cheana féin mar ainm comhaid sa stóras seo.
+editor.file_is_a_symlink=Is nasc siombalach é `"%s". Nà féidir naisc shiombalacha a chur in eagar san eagarthóir gréasáin`
+editor.filename_is_a_directory=Úsáidtear ainm comhaid "%s" cheana féin mar ainm eolaire sa stóras seo.
+editor.file_editing_no_longer_exists=NÃl an comhad atá á chur in eagar, "%s", ann sa stóras seo a thuilleadh.
+editor.file_deleting_no_longer_exists=NÃl an comhad atá á scriosadh, "%s", ann sa stóras seo a thuilleadh.
+editor.file_changed_while_editing=Tá athrú tagtha ar ábhar an chomhad ó thosaigh tú ag eagarthóireacht Cliceáil anseo chun iad a fheiceáil nó Athru ithe a Tiomantas arÃs chun iad a fhorscrÃobh.
+editor.file_already_exists=Tá comhad darb ainm "%s" ann cheana féin sa stóras seo.
+editor.commit_id_not_matching=Nà mheaitseálann an ID Tiomanta leis an ID nuair a thosaigh tú ag eagarthóireacht. Tiomanta isteach i mbrainse paiste agus ansin cumaisc.
+editor.push_out_of_date=Is cosúil go bhfuil an brú as dáta.
+editor.commit_empty_file_header=Tiomantas comhad folamh
+editor.commit_empty_file_text=Tá an comhad atá tú ar tà tiomantas folamh. Ar aghaidh?
+editor.no_changes_to_show=NÃl aon athruithe le taispeáint.
+editor.fail_to_update_file=Theip ar nuashonrú/cruthú comhad "%s".
+editor.fail_to_update_file_summary=Teachtaireacht Earráide:
+editor.push_rejected_no_message=Dhiúltaigh an freastalaà an t-athrú gan teachtaireacht. Seiceáil Git Hooks le do thoil.
+editor.push_rejected=Dhiúltaigh an freastalaà an t-athrú. Seiceáil Git Hooks le do thoil.
+editor.push_rejected_summary=Teachtaireacht Diúltaithe Iomlán:
+editor.add_subdir=Cuir eolaire leis…
+editor.unable_to_upload_files=Theip ar uaslódáil comhaid go "%s" le hearráid: %v
+editor.upload_file_is_locked=Tá comhad "%s" faoi ghlas ag %s.
+editor.upload_files_to_dir=`Uaslódáil comhaid go "%s"`
+editor.cannot_commit_to_protected_branch=Nà féidir gealltanas a thabhairt don bhrainse faoi chosaint "%s".
+editor.no_commit_to_branch=Nà féidir tiomantas a thabhairt go dÃreach don bhrainse mar:
+editor.user_no_push_to_branch=Nà féidir leis an úsáideoir brúigh go dtà an brainse
+editor.require_signed_commit=ÉilÃonn an Brainse tiomantas sÃnithe
+editor.cherry_pick=Roghnaigh silÃnà %s ar:
+editor.revert=Fill %s ar:
+
+commits.desc=Brabhsáil stair athraithe cód foinse.
+commits.commits=TiomáintÃ
+commits.no_commits=NÃl aon ghealltanas i gcoiteann. Tá stair iomlán difriúil ag "%s" agus "%s".
+commits.nothing_to_compare=Tá na brainsà seo cothrom.
+commits.search.tooltip=Is féidir eochairfhocail a réamhfhostú le “údar:â€, “committer:â€, “after:â€, nó “before:â€, e.g. "fill an t-údar:Alice roimh: 2019-01-13".
+commits.search_branch=An Brainse seo
+commits.search_all=Gach Brainse
+commits.author=Údar
+commits.message=Teachtaireacht
+commits.date=Dáta
+commits.older=NÃos sine
+commits.newer=NÃos nuaÃ
+commits.signed_by=SÃnithe ag
+commits.signed_by_untrusted_user=SÃnithe ag úsáideoir neamhiontaofa
+commits.signed_by_untrusted_user_unmatched=SÃnithe ag úsáideoir neamhiontaofa nach bhfuil ag teacht leis an gcoiste
+commits.gpg_key_id=GPG Eochair ID
+commits.ssh_key_fingerprint=Méarloirg Eochair SSH
+commits.view_path=Féach ag an bpointe seo sa stair
+
+commit.operations=OibrÃochtaÃ
+commit.revert=Téigh ar ais
+commit.revert-header=Téigh ar ais: %s
+commit.revert-content=Roghnaigh brainse chun filleadh ar:
+commit.cherry-pick=Roghnaigh silÃnÃ
+commit.cherry-pick-header=Roghnaigh silÃnÃ: %s
+commit.cherry-pick-content=Roghnaigh brainse chun silÃnà a phiocadh air:
+
+commitstatus.error=Earráid
+commitstatus.failure=Teip
+commitstatus.pending=Ar feitheamh
+commitstatus.success=Rath
+
+ext_issues=Rochtain ar Saincheisteanna Seachtracha
+ext_issues.desc=Nasc le rianaitheoir saincheisteanna seachtrach.
+
+projects.desc=Saincheisteanna a bhainistiú agus tionscadail a tharraingt isteach.
+projects.description=Cur sÃos (roghnach)
+projects.description_placeholder=Cur sÃos
+projects.create=Cruthaigh Tionscadal
+projects.title=Teideal
+projects.new=Tionscadal Nua
+projects.new_subheader=Déan do chuid oibre a chomhordú, a rianú agus a nuashonrú in aon áit amháin, ionas go bhfanann na tionscadail trédhearcach agus de réir sceidil.
+projects.create_success=Tá an tionscadal "%s" cruthaithe.
+projects.deletion=Scrios tionscadal
+projects.deletion_desc=Má scriostar tionscadal, bainfear de gach saincheist a bhaineann leis é. Lean ort?
+projects.deletion_success=Tá an tionscadal scriosta.
+projects.edit=Cuir Tionscadal in Eagar
+projects.edit_subheader=EagraÃonn tionscadail saincheisteanna agus rianaÃonn siad dul chun cinn.
+projects.modify=Cuir Tionscadal in Eagar
+projects.edit_success=Tá an tionscadal "%s" nuashonraithe.
+projects.type.none=NÃl aon
+projects.type.basic_kanban=Bunúsach Kanban
+projects.type.bug_triage=Triáiseáil Fabht
+projects.template.desc=Teimpléad
+projects.template.desc_helper=Roghnaigh teimpléad tionscadail chun tosú
+projects.column.edit=Cuir Colún in eagar
+projects.column.edit_title=Ainm
+projects.column.new_title=Ainm
+projects.column.new_submit=Cruthaigh Colún
+projects.column.new=Colún Nua
+projects.column.set_default=Socraigh Réamhshocrú
+projects.column.set_default_desc=Socraigh an colún seo mar réamhshocrú le haghaidh saincheisteanna agus tarraingtà gan chatagóir
+projects.column.delete=Scrios Colún
+projects.column.deletion_desc=Ag scriosadh colún tionscadail aistrÃonn gach saincheist ghaolmhar chuig an gcolún. Lean ar aghaidh?
+projects.column.color=Dath
+projects.open=Oscailte
+projects.close=Dún
+projects.column.assigned_to=Sannta do
+projects.card_type.desc=Réamhamharcanna Cárta
+projects.card_type.images_and_text=Ãomhánna agus Téacs
+projects.card_type.text_only=Téacs Amháin
+
+issues.desc=Eagraigh tuarascálacha fabht, tascanna agus cloch mhÃle.
+issues.filter_assignees=Scagaire Sannaitheoir
+issues.filter_milestones=Cloch MhÃle Scagaire
+issues.filter_projects=Tionscadal Scagaire
+issues.filter_labels=Lipéad Scagaire
+issues.filter_reviewers=Athbhreithneoir Scagaire
+issues.new=Eagrán Nua
+issues.new.title_empty=Nà féidir leis an teideal a bheith folamh
+issues.new.labels=Lipéid
+issues.new.no_label=Gan Lipéad
+issues.new.clear_labels=Lipéid shoiléir
+issues.new.projects=Tionscadail
+issues.new.clear_projects=Tionscadail soiléire
+issues.new.no_projects=Gan aon tionscadal
+issues.new.open_projects=Tionscadail Oscailte
+issues.new.closed_projects=Tionscadail Dúnta
+issues.new.no_items=Gan aon earraÃ
+issues.new.milestone=Cloch MhÃle
+issues.new.no_milestone=Gan Chloch MhÃle
+issues.new.clear_milestone=Cloch MhÃle soiléir
+issues.new.open_milestone=Clocha MÃle Oscailte
+issues.new.closed_milestone=Clocha MÃle Dúnta
+issues.new.assignees=SannaitheoirÃ
+issues.new.clear_assignees=Ceannaitheoirà soiléir
+issues.new.no_assignees=Gan aon SannaitheoirÃ
+issues.new.no_reviewers=Gan athbhreithnithe
+issues.new.blocked_user=Nà féidir saincheist a chruthú toisc go bhfuil úinéir an stórais bac ort.
+issues.edit.already_changed=Nà féidir athruithe a shábháil ar an tsaincheist. DealraÃonn sé gur athraigh úsáideoir eile an t-ábhar cheana féin. Athnuachan an leathanach agus déan iarracht eagarthóireacht arÃs chun a gcuid athruithe a sheachaint
+issues.edit.blocked_user=Nà féidir ábhar a chur in eagar toisc go bhfuil an póstaer nó úinéir an stórais bac ort.
+issues.choose.get_started=Faigh Tosaigh
+issues.choose.open_external_link=Oscailte
+issues.choose.blank=Réamhshocrú
+issues.choose.blank_about=Cruthaigh saincheist ó theimpléad réamhshocraithe.
+issues.choose.ignore_invalid_templates=Rinneadh neamhaird ar theimpléid
+issues.choose.invalid_templates=%v teimpléad neamhbhail(Ã) aimsÃodh
+issues.choose.invalid_config=Tá earráidà sa chumraÃocht eisiúint:
+issues.no_ref=NÃl aon Brainse/Clib Sonraithe
+issues.create=Cruthaigh Saincheist
+issues.new_label=Lipéad Nua
+issues.new_label_placeholder=Ainm lipéad
+issues.new_label_desc_placeholder=Cur sÃos
+issues.create_label=Cruthaigh Lipéad
+issues.label_templates.title=Luchtaigh sraith réamhshainithe lipéid
+issues.label_templates.info=NÃl aon lipéid ann fós. Cruthaigh lipéad le 'Lipéad Nua' nó bain úsáid as tacar lipéad réamhshainithe:
+issues.label_templates.helper=Roghnaigh tacar lipéad
+issues.label_templates.use=Úsáid Sraith Lipéad
+issues.label_templates.fail_to_load_file=Theip ar lódáil an chomhaid teimpléid lipéid "%s": %v
+issues.add_label=cuireadh an lipéad %s %s leis
+issues.add_labels=cuireadh na %s lipéid %s
+issues.remove_label=bainte an %s lipéad %s
+issues.remove_labels=bainte na %s lipéid %s
+issues.add_remove_labels=chuir %s leis agus bhain %s lipéid %s
+issues.add_milestone_at=`chuir seo leis an gcloch mhÃle %s %s`
+issues.add_project_at=`chuir seo leis an tionscadal %s %s`
+issues.move_to_column_of_project=`aistrigh sé seo chuig %s i %s ar %s`
+issues.change_milestone_at=`mionathraithe an chloch mhÃle ó %s go %s %s`
+issues.change_project_at=`mionathraithe an tionscadal ó %s go %s %s`
+issues.remove_milestone_at=` bhain seo den %schloch mhÃle %s`
+issues.remove_project_at=`bhain sé seo den %san tionscadal %s`
+issues.deleted_milestone=`(scriosta)`
+issues.deleted_project=`(scriosta)`
+issues.self_assign_at=`féin-shannta an %s seo`
+issues.add_assignee_at=`a shannadh ag %s %s`
+issues.remove_assignee_at=`a bhà gan shannadh ag %s %s`
+issues.remove_self_assignment=`bhain siad a sannadh %s`
+issues.change_title_at=`athraigh an teideal ó %s go %s %s`
+issues.change_ref_at=`tagairt athraithe ó %s go %s %s`
+issues.remove_ref_at=`bhaint an tagairt %s %s`
+issues.add_ref_at=`Cuireadh an tagairt %s %s leis`
+issues.delete_branch_at=`brainse scriosta %s %s`
+issues.filter_label=Lipéad
+issues.filter_label_exclude=`Úsáid alt
+ cliceáil/iontráil
chun lipéid a eisiamh`
+issues.filter_label_no_select=Gach lipéad
+issues.filter_label_select_no_label=Gan lipéad
+issues.filter_milestone=Cloch MhÃle
+issues.filter_milestone_all=Gach cloch mhÃle
+issues.filter_milestone_none=Gan aon clocha mhÃle
+issues.filter_milestone_open=Clocha mhÃle oscailte
+issues.filter_milestone_closed=Clocha mhÃle dúnta
+issues.filter_project=Tionscadal
+issues.filter_project_all=Gach tionscadal
+issues.filter_project_none=Gan aon tionscadal
+issues.filter_assignee=Sannaitheoir
+issues.filter_assginee_no_select=Gach sannaithe
+issues.filter_assginee_no_assignee=Gan sannaitheoir
+issues.filter_poster=Údar
+issues.filter_poster_no_select=Gach údair
+issues.filter_type=Cineál
+issues.filter_type.all_issues=Gach saincheist
+issues.filter_type.assigned_to_you=Sannta duit
+issues.filter_type.created_by_you=Cruthaithe agat
+issues.filter_type.mentioning_you=Ag tagairt duit
+issues.filter_type.review_requested=Athbhreithniú iarrtha
+issues.filter_type.reviewed_by_you=Athbhreithnithe agat
+issues.filter_sort=Sórtáil
+issues.filter_sort.latest=Is nuaÃ
+issues.filter_sort.oldest=Is sine
+issues.filter_sort.recentupdate=Nuashonraithe le déanaÃ
+issues.filter_sort.leastupdate=Is lú a nuashonraÃodh le déanaÃ
+issues.filter_sort.mostcomment=Is mó a bhfuil tráchtanna air
+issues.filter_sort.leastcomment=Is lú a bhfuil tráchtanna air
+issues.filter_sort.nearduedate=An dáta dlite is gaire
+issues.filter_sort.farduedate=An dáta dlite is faide
+issues.filter_sort.moststars=An lÃon réaltaà is mó
+issues.filter_sort.feweststars=An lÃon réaltaà is lú
+issues.filter_sort.mostforks=An lÃon forcanna is mó
+issues.filter_sort.fewestforks=An lÃon forcanna is lú
+issues.action_open=Oscailte
+issues.action_close=Dún
+issues.action_label=Lipéad
+issues.action_milestone=Cloch MhÃle
+issues.action_milestone_no_select=Gan Chloch MhÃle
+issues.action_assignee=Sannaitheoir
+issues.action_assignee_no_select=Gan sannaitheoir
+issues.action_check=Seiceáil/DÃsheiceáil
+issues.action_check_all=Seiceáil/DÃsheiceáil gach mireanna
+issues.opened_by=oscail %[1]s le %[3]s
+pulls.merged_by=le %[3]s cumasc %[1]s
+pulls.merged_by_fake=le %[2]s a chumasc %[1]s
+issues.closed_by=le dúnadh %[3]s %[1]s
+issues.opened_by_fake=oscail %[1]s le %[2]s
+issues.closed_by_fake=faoi ​​%[2]s dúnadh %[1]s
+issues.previous=Roimhe Seo
+issues.next=Ar Aghaidh
+issues.open_title=Oscailte
+issues.closed_title=Dúnta
+issues.draft_title=Dréacht
+issues.num_comments_1=%d trácht
+issues.num_comments=%d tráchtanna
+issues.commented_at=`trácht %s `
+issues.delete_comment_confirm=An bhfuil tú cinnte gur mhaith leat an trácht seo a scriosadh?
+issues.context.copy_link=Cóipeáil Nasc
+issues.context.quote_reply=Luaigh Freagra
+issues.context.reference_issue=Tagairt in Eagrán Nua
+issues.context.edit=Cuir in eagar
+issues.context.delete=Scrios
+issues.no_content=NÃl aon tuairisc ar fáil.
+issues.close=Dún Eagrán
+issues.comment_pull_merged_at=cumasc tiomantas %[1]s le %[2]s %[3]s
+issues.comment_manually_pull_merged_at=cumasc tiomantas %[1]s le %[2]s %[3]s
+issues.close_comment_issue=Dún le trácht
+issues.reopen_issue=Athoscail
+issues.reopen_comment_issue=Athoscail le trácht
+issues.create_comment=Trácht
+issues.comment.blocked_user=Nà féidir trácht a chruthú nó a chur in eagar toisc go bhfuil an tráchtaire nó úinéir an stórais bac ort.
+issues.closed_at=`dhún an cheist seo %[2]s`
+issues.reopened_at=`athoscail an t-eagrán seo %[2]s`
+issues.commit_ref_at=`rinne tagairt don cheist seo ó ghealltanas %[2]s`
+issues.ref_issue_from=`rinne dagairt don cheist seo %[4]s %[2]s`
+issues.ref_pull_from=`rinne dagairt don iarratas tarraingthe seo %[4]s %[ 2]s`
+issues.ref_closing_from=`rinne dagairt d'iarratas tarraingthe %[4]s a dhúnfaidh an cheist seo %[2]s`
+issues.ref_reopening_from=`rinne dagairt d'iarratas tarraingthe %[4]s a athosclóidh an cheist seo %[2]s`
+issues.ref_closed_from=`dhún an cheist seo %[4]s %[2]s`
+issues.ref_reopened_from=`d'athoscail an eagrán seo %[4]s %[2]s`
+issues.ref_from=`ó %[1]s`
+issues.author=Údar
+issues.author_helper=Is é an t-úsáideoir seo an t-údar.
+issues.role.owner=Úinéir
+issues.role.owner_helper=Is é an t-úsáideoir seo úinéir an stór seo.
+issues.role.member=Comhalta
+issues.role.member_helper=Is ball den eagraÃocht é an t-úsáideoir seo a bhfuil an stór seo ina úinéireacht.
+issues.role.collaborator=Comhoibritheoir
+issues.role.collaborator_helper=Tugadh cuireadh don úsáideoir seo comhoibriú ar an stóras.
+issues.role.first_time_contributor=Cuiditheoir den chéad uair
+issues.role.first_time_contributor_helper=Seo é an chéad uair a chuir an t-úsáideoir seo leis an stóras.
+issues.role.contributor=Cuiditheoir
+issues.role.contributor_helper=Tá an t-úsáideoir seo tiomanta don stóras roimhe seo.
+issues.re_request_review=Athiarraigh athbhreithniú
+issues.is_stale=Rinneadh athruithe ar an PR seo ón athbhreithniú seo
+issues.remove_request_review=Bain iarratas athbhreithni
+issues.remove_request_review_block=Nà féidir iarratas athbhreithnithe a bhaint
+issues.dismiss_review=DÃbhe Athbhreithnithe
+issues.dismiss_review_warning=An bhfuil tú cinnte gur mhaith leat an athbhreithnithe seo a dhÃbhe?
+issues.sign_in_require_desc=SÃnigh isteach chun dul isteach sa chomhrá seo.
+issues.edit=Cuir in eagar
+issues.cancel=Cealaigh
+issues.save=Sábháil
+issues.label_title=Ainm
+issues.label_description=Cur sÃos
+issues.label_color=Dath
+issues.label_exclusive=Eisiach
+issues.label_archive=Lipéad Cartlann
+issues.label_archived_filter=Taispeáin lipéid cartlainne
+issues.label_archive_tooltip=Eisiatar lipéid chartlainne de réir réamhshocraithe ó na moltaà nuair a dhéantar cuardach de réir lipéid.
+issues.label_exclusive_desc=Ainmnigh an lipéad scope/item
chun é a dhéanamh comheisiatach le lipéid scope/
eile.
+issues.label_exclusive_warning=Bainfear aon lipéid scóipe contrártha le linn eagarthóireacht a dhéanamh ar lipéid iarratais eisiúna nó tarraingthe.
+issues.label_count=%d lipéid
+issues.label_open_issues=%d saincheisteanna oscailte/iarratais tarraing
+issues.label_edit=Cuir in eagar
+issues.label_delete=Scrios
+issues.label_modify=Cuir Lipéad in Eagar
+issues.label_deletion=Scrios Lipéad
+issues.label_deletion_desc=Baineann lipéad a scriosadh é ó gach saincheist. Lean ar aghaidh?
+issues.label_deletion_success=Tá an lipéad scriosta.
+issues.label.filter_sort.alphabetically=AibÃtreach
+issues.label.filter_sort.reverse_alphabetically=Aisiompú in ord aibÃtre
+issues.label.filter_sort.by_size=Méid is lú
+issues.label.filter_sort.reverse_by_size=Méid is mó
+issues.num_participants=%d Rannpháirtithe
+issues.attachment.open_tab=`Cliceáil chun "%s" a fheiceáil i gcluaisÃn nua`
+issues.attachment.download=`Cliceáil chun "%s" a Ãoslódáil
+issues.subscribe=Liostáil
+issues.unsubscribe=DÃliostáil
+issues.unpin_issue=Bain pionna an t-eagrán
+issues.max_pinned=Nà féidir leat nÃos mó saincheisteanna a phionadh
+issues.pin_comment=phionnáil an %s seo
+issues.unpin_comment=bain pionna an %s seo
+issues.lock=Cuir glas ar an gcomhrá
+issues.unlock=DÃghlasáil comhrá
+issues.lock.unknown_reason=Nà féidir fadhb a ghlasáil le cúis anaithnid.
+issues.lock_duplicate=Nà féidir saincheist a ghlasáil faoi dhó.
+issues.unlock_error=Nà féidir saincheist nach bhfuil glasáilte a dhÃghlasáil.
+issues.lock_with_reason=curtha ar ceal mar %s agus comhrá teoranta do chomhoibrithe %s
+issues.lock_no_reason=comhrá faoi ghlas agus teoranta do chomhoibrithe %s
+issues.unlock_comment=an comhrá seo a dhÃghlasáil %s
+issues.lock_confirm=Glas
+issues.unlock_confirm=DÃghlasáil
+issues.lock.notice_1=- Nà féidir le húsáideoirà eile tuairimà nua a chur leis an gceist seo.
+issues.lock.notice_2=- Is féidir leatsa agus le comhoibrithe eile a bhfuil rochtain acu ar an stór seo fós tuairimà a fhágáil a fheiceann daoine eile.
+issues.lock.notice_3=- Is féidir leat an tsaincheist seo a dhÃghlasáil arÃs sa todhchaÃ.
+issues.unlock.notice_1=- Bheadh gach duine in ann trácht a dhéanamh ar an gceist seo arÃs.
+issues.unlock.notice_2=- Is féidir leat an tsaincheist seo a ghlasáil arÃs sa todhchaà i gcónaÃ.
+issues.lock.reason=Cúis le glasáil
+issues.lock.title=Glas comhrá ar an gceist seo.
+issues.unlock.title=DÃghlasáil comhrá ar an gceist seo.
+issues.comment_on_locked=Nà féidir leat trácht a dhéanamh ar shaincheist faoi ghlas.
+issues.delete=Scrios
+issues.delete.title=Scrios an t-eagrán seo?
+issues.delete.text=An bhfuil tú cinnte gur mhaith leat an cheist seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann)
+issues.tracker=Rianaitheoir Ama
+issues.start_tracking_short=Tosaigh Uaineoir
+issues.start_tracking=Rianú Am Tosaigh
+issues.start_tracking_history=`thosaigh sé ag obair %s`
+issues.tracker_auto_close=Stopfar ama go huathoibrÃoch nuair a dhúnfar an tsaincheist seo
+issues.tracking_already_started=`Tá tús curtha agat cheana féin ag rianú ama ar eagrán eile!`
+issues.stop_tracking=Stop Uaineadóir
+issues.stop_tracking_history=`stop sé ag obair %s`
+issues.cancel_tracking=Caith amach
+issues.cancel_tracking_history=`rianú ama curtha ar ceal %s`
+issues.add_time=Láimh Cuir Am leis
+issues.del_time=Scrios an log ama seo
+issues.add_time_short=Cuir Am leis
+issues.add_time_cancel=Cealaigh
+issues.add_time_history=`am caite curtha leis %s`
+issues.del_time_history=`an t-am caite scriosta %s`
+issues.add_time_hours=Uaireanta
+issues.add_time_minutes=Miontuairi
+issues.add_time_sum_to_small=NÃor iontráilÃodh aon am.
+issues.time_spent_total=An t-am iomlán a chaitear
+issues.time_spent_from_all_authors=`Am Iomlán Caitear: %s`
+issues.due_date=Dáta dlite
+issues.invalid_due_date_format=Nà mór 'bbbb-mm-ll' a bheith i bhformáid an dáta dlite.
+issues.error_modifying_due_date=Theip ar an dáta dlite a mhodhnú.
+issues.error_removing_due_date=Theip ar an dáta dlite a bhaint.
+issues.push_commit_1=Cuir %d gealltanas %s leis
+issues.push_commits_n=cuireadh %d tiomantas %s leis
+issues.force_push_codes=`bhrú i bhfeidhm %[1]s ó %[2]s
go %[4]s
%[6]s`
+issues.force_push_compare=Déan comparáid
+issues.due_date_form=bbbb-mm-ll
+issues.due_date_form_add=Cuir dáta dlite leis
+issues.due_date_form_edit=Cuir in eagar
+issues.due_date_form_remove=Bain
+issues.due_date_not_writer=Nà mór duit rochtain scrÃofa ar an stór seo d'fhonn dáta dlite eisiúna a nuashonrú.
+issues.due_date_not_set=NÃl aon dáta dlite socraithe.
+issues.due_date_added=cuireadh an dáta dlite %s %s
+issues.due_date_modified=d'athraigh an dáta dlite ó %[2]s go %[1]s %[3]s
+issues.due_date_remove=bainte an dáta dlite %s %s
+issues.due_date_overdue=Thar téarma
+issues.due_date_invalid=Tá an dáta dlite neamhbhailà nó lasmuigh den raon. Úsáid an fhormáid 'bbbb-mm-ll' le do thoil.
+issues.dependency.title=SpleithiúlachtaÃ
+issues.dependency.issue_no_dependencies=NÃl aon spleáchais leagtha sÃos.
+issues.dependency.pr_no_dependencies=NÃl aon spleáchais leagtha sÃos.
+issues.dependency.no_permission_1=NÃl cead agat spleáchas %d a léamh
+issues.dependency.no_permission_n=NÃl cead agat spleáchais %d a léamh
+issues.dependency.no_permission.can_remove=NÃl cead agat an spleáchas seo a léamh ach is féidir leis an spleáchas seo a bhaint
+issues.dependency.add=Cuir spleáchas leis…
+issues.dependency.cancel=Cealaigh
+issues.dependency.remove=Bain
+issues.dependency.remove_info=Bain an spleáchas seo
+issues.dependency.added_dependency=`cuireadh spleáchas nua %s`
+issues.dependency.removed_dependency=`bainte spleáchas %s`
+issues.dependency.pr_closing_blockedby=Cuireann na saincheisteanna seo a leanas bac ar an iarratas tarraingte seo a dhúnadh
+issues.dependency.issue_closing_blockedby=Tá na saincheisteanna seo a leanas bac ar dhúnadh an cheist seo
+issues.dependency.issue_close_blocks=Cuireann an tsaincheist seo bac ar dhúnadh na saincheisteanna
+issues.dependency.pr_close_blocks=Cuireann an iarratas tarraingthe seo bac ar dhúnadh na saincheisteanna
+issues.dependency.issue_close_blocked=Nà mór duit gach saincheist a chuireann bac ar an gceist seo a dhúnadh sular féidir leat é a dhúnadh.
+issues.dependency.issue_batch_close_blocked=Nà féidir saincheisteanna a roghnaÃonn tú a dhúnadh, toisc go bhfuil spleáchais oscailte fós ag eisiúint #%d
+issues.dependency.pr_close_blocked=Nà mór duit gach saincheist a bhlocálann an iarratas tarraingthe seo a dhúnadh sula féidir leat é a chumasc.
+issues.dependency.blocks_short=Bloic
+issues.dependency.blocked_by_short=Ag brath ar
+issues.dependency.remove_header=Bain spleáchas
+issues.dependency.issue_remove_text=Bainfidh sé seo an spleáchas ón gceist seo. Lean ar aghaidh?
+issues.dependency.pr_remove_text=Bainfidh sé seo an spleáchas ón iarratas tarraingthe seo. Lean ar aghaidh?
+issues.dependency.setting=Cumasaigh spleáchais le haghaidh Saincheisteanna agus Iarrataà Tar
+issues.dependency.add_error_same_issue=Nà féidir leat ceist a dhéanamh ag brath air féin.
+issues.dependency.add_error_dep_issue_not_exist=NÃl saincheist spleách ann.
+issues.dependency.add_error_dep_not_exist=Nà bhÃonn spleáchas ann.
+issues.dependency.add_error_dep_exists=Tá spleáchas ann cheana féin.
+issues.dependency.add_error_cannot_create_circular=Nà féidir leat spleáchas a chruthú le dhá shaincheist a chuireann bac ar a chéile.
+issues.dependency.add_error_dep_not_same_repo=Caithfidh an dá shaincheist a bheith sa stór céanna.
+issues.review.self.approval=Nà féidir leat d'iarratas tarraingthe féin a cheadú.
+issues.review.self.rejection=Nà féidir leat athruithe a iarraidh ar d'iarratas tarraingthe féin.
+issues.review.approve=ceadaigh na hathruithe seo %s
+issues.review.comment=athbhreithnithe %s
+issues.review.dismissed=dhiúltaigh athbhreithniú %s ó %s
+issues.review.dismissed_label=Dhiúltaigh
+issues.review.left_comment=d'fhág trácht
+issues.review.content.empty=Nà mór duit trácht a fhágáil a léirÃonn an t-athrú (Ã) iarrtha.
+issues.review.reject=athruithe iarrtha %s
+issues.review.wait=iarradh athbhreithniú %s
+issues.review.add_review_request=athbhreithniú iarrtha ó %s %s
+issues.review.remove_review_request=iarratas athbhreithnithe bainte le haghaidh %s %s
+issues.review.remove_review_request_self=dhiúltaigh %s a athbhreithniú
+issues.review.pending=Ar feitheamh
+issues.review.pending.tooltip=NÃl an nóta tráchta seo le feiceáil ag úsáideoirà eile faoi láthair. Chun do thuairimà ar feitheamh a chur isteach, roghnaigh "%s" -> "%s/%s/%s" ag barr an leathanaigh.
+issues.review.review=Léirmheas
+issues.review.reviewers=LéirmheasóirÃ
+issues.review.outdated=As dáta
+issues.review.outdated_description=Tá athrú tagtha ar ábhar ó rinneadh an trácht seo
+issues.review.option.show_outdated_comments=Taispeáin tráchtanna atá as dáta
+issues.review.option.hide_outdated_comments=Folaigh tráchtanna atá as dáta
+issues.review.show_outdated=Taispeáin as dáta
+issues.review.hide_outdated=Folaigh as dáta
+issues.review.show_resolved=Taispeáin réitithe
+issues.review.hide_resolved=Folaigh réitithe
+issues.review.resolve_conversation=Réitigh comhrá
+issues.review.un_resolve_conversation=Comhrá gan réiteach
+issues.review.resolved_by=mharcáil an comhrá seo mar réitigh
+issues.review.commented=Trácht
+issues.review.official=Ceadaithe
+issues.review.requested=Athbhreithniú ar feitheamh
+issues.review.rejected=Athruithe iarrtha
+issues.review.stale=Nuashonraithe ó faomhadh
+issues.review.unofficial=Ceadú gan áireamh
+issues.assignee.error=NÃor cuireadh gach sannaà leis mar gheall ar earráid gan choinne.
+issues.reference_issue.body=Comhlacht
+issues.content_history.deleted=scriosta
+issues.content_history.edited=curtha in eagar
+issues.content_history.created=cruthaithe
+issues.content_history.delete_from_history=Scrios ón stair
+issues.content_history.delete_from_history_confirm=Scrios ón stair?
+issues.content_history.options=Roghanna
+issues.reference_link=Tagairt: %s
+
+compare.compare_base=bonn
+compare.compare_head=déan comparáid
+
+pulls.desc=Cumasaigh iarratais tarraingthe agus athbhreithnithe cód.
+pulls.new=Iarratas Tarraingthe Nua
+pulls.new.blocked_user=Nà féidir iarratas tarraingthe a chruthú toisc go bhfuil úinéir an stórais bac ort.
+pulls.new.must_collaborator=Caithfidh tú a bheith ina chomhoibritheoir chun iarratas tarraingthe a chruthú.
+pulls.edit.already_changed=Nà féidir athruithe a shábháil ar an iarratas tarraingthe. DealraÃonn sé gur athraigh úsáideoir eile an t-ábhar cheana féin. Athnuachan an leathanach agus déan iarracht eagarthóireacht arÃs chun a gcuid athruithe a sheachaint
+pulls.view=Féach ar Iarratas Tarraing
+pulls.compare_changes=Iarratas Tarraingthe Nua
+pulls.allow_edits_from_maintainers=Ceadaigh eagarthóirà ó chothabhálaÃ
+pulls.allow_edits_from_maintainers_desc=Is féidir le húsáideoirà a bhfuil rochtain scrÃofa acu ar an mbunbhrainse brú chuig an bhrainse
+pulls.allow_edits_from_maintainers_err=Theip ar nuashonrú
+pulls.compare_changes_desc=Roghnaigh an brainse le cumasc isteach agus an brainse le tarraingt uaidh.
+pulls.has_viewed_file=Breathnaithe
+pulls.has_changed_since_last_review=Athraithe ó d'athbhreithniú deire
+pulls.viewed_files_label=BreathnaÃodh ar %[1]d / %[2]d comhaid
+pulls.expand_files=Leathnaigh gach comhaid
+pulls.collapse_files=Laghdaigh gach comhaid
+pulls.compare_base=cumaisc isteach
+pulls.compare_compare=tarraing ó
+pulls.switch_comparison_type=Athraigh cineál comparáide
+pulls.switch_head_and_base=Athraigh ceann agus bonn
+pulls.filter_branch=Brainse scagaire
+pulls.show_all_commits=Taispeáin gach gealltanas
+pulls.show_changes_since_your_last_review=Taispeáin athruithe ón léirmheas deiridh
+pulls.showing_only_single_commit=Ag taispeáint athruithe tiomantais %[1]s amháin
+pulls.showing_specified_commit_range=Ag taispeáint athruithe idir %[1]s..%[2]s
+pulls.select_commit_hold_shift_for_range=Roghnaigh tiomantas. Coinnigh shift + cliceáil chun raon a roghnú
+pulls.review_only_possible_for_full_diff=Nà féidir athbhreithniú a dhéanamh ach amháin nuair a bhreathnaÃtear ar an difrÃocht iomlán
+pulls.filter_changes_by_commit=Scagaigh de réir tiomantas
+pulls.nothing_to_compare=Tá na brainsà seo cothrom. Nà gá iarratas tarraingthe a chruthú.
+pulls.nothing_to_compare_have_tag=Tá an brainse/clib roghnaithe cothrom.
+pulls.nothing_to_compare_and_allow_empty_pr=Tá na brainsà seo cothrom. Beidh an PR seo folamh.
+pulls.has_pull_request=`Tá iarratas tarraingthe idir na brainsà seo ann cheana: %[2]s#%[3]d`
+pulls.create=Cruthaigh Iarratas Tarraing
+pulls.title_desc=ag iarraidh %[1]d gealltanas a chumasc ó %[2]s
go %[3]s
+pulls.merged_title_desc=cumasc %[1]d tiomantas ó %[2]s
go %[3]s
%[4]s
+pulls.change_target_branch_at=`athraigh an spriocbhrainse ó %s go %s %s`
+pulls.tab_conversation=Comhrá
+pulls.tab_commits=TiomáintÃ
+pulls.tab_files=Comhaid Athraithe
+pulls.reopen_to_merge=Athoscail an t-iarratas tarraingthe seo le do thoil chun cumasc a dhéanamh.
+pulls.cant_reopen_deleted_branch=Nà féidir an t-iarratas tarraingthe seo a athoscailt toisc gur scriosadh an brainse.
+pulls.merged=Cumaiscthe
+pulls.merged_success=D'éirigh leis an iarratas tarraingthe a chumasc agus a dhúnadh
+pulls.closed=Iarratas tarraingthe dúnta
+pulls.manually_merged=Cumaisc de láimh
+pulls.merged_info_text=Is féidir an brainse %s a scriosadh anois.
+pulls.is_closed=Tá an t-iarratas tarraingthe dúnta.
+pulls.title_wip_desc=`Tosaigh an teideal le %s chun an t-iarratas tarraingthe a chosc ó chumasc de thaisme.`
+pulls.cannot_merge_work_in_progress=Tá an t-iarratas tarraingthe seo marcáilte mar obair atá ar siúl.
+pulls.still_in_progress=Fós ar siúl?
+pulls.add_prefix=Cuir réimÃr %s leis
+pulls.remove_prefix=Bain an réimÃr %s
+pulls.data_broken=Tá an t-iarratas tarraingthe seo briste mar gheall ar fhaisnéis forc a bheith in easnamh.
+pulls.files_conflicted=Tá athruithe ag an iarratas tarraingthe seo atá contrártha leis an spriocbhrainse.
+pulls.is_checking=Tá seiceáil coinbhleachta cumaisc ar siúl. Bain triail eile as i gceann cúpla nóiméad.
+pulls.is_ancestor=Tá an brainse seo san áireamh cheana féin sa spriocbhrainse. NÃl aon rud le cumasc.
+pulls.is_empty=Tá na hathruithe ar an mbrainse seo ar an spriocbhrainse cheana féin. Is tiomantas folamh é seo.
+pulls.required_status_check_failed=NÃor éirigh le roinnt seiceálacha riachtanacha.
+pulls.required_status_check_missing=Tá roinnt seiceanna riachtanacha ar iarraidh.
+pulls.required_status_check_administrator=Mar riarthóir, féadfaidh tú an t-iarratas tarraingthe seo a chumasc fós.
+pulls.blocked_by_approvals=NÃl go leor ceadaithe ag an iarraidh tarraingthe seo fós. DeonaÃodh %d den fhaomhadh %d.
+pulls.blocked_by_approvals_whitelisted=NÃl go leor ceaduithe riachtanacha ag an iarratas tarraingte seo go fóill. %d de %d faomhadh tugtha ó úsáideoirà nó foirne ar an liosta ceadaithe.
+pulls.blocked_by_rejection=Tá athruithe ag athbhreithneoir oifigiúil ag an iarratas tarraingthe seo.
+pulls.blocked_by_official_review_requests=Tá iarratais ar athbhreithniú oifigiúil ag an iarratas tarraingte seo.
+pulls.blocked_by_outdated_branch=Tá bac ar an iarratas tarraingte seo toisc go bhfuil sé as dáta.
+pulls.blocked_by_changed_protected_files_1=Cuirtear bac ar an iarratas tarraingthe seo toisc go n-athraÃonn sé comhad cosanta:
+pulls.blocked_by_changed_protected_files_n=Tá bac ar an iarratas tarraingthe seo toisc go n-athraÃonn sé comhaid chosanta:
+pulls.can_auto_merge_desc=Is féidir an t-iarratas tarraingt seo a chumasc go huathoibrÃoch.
+pulls.cannot_auto_merge_desc=Nà féidir an t-iarratas tarraingthe seo a chumasc go huathoibrÃoch mar gheall ar choinbhleachtaÃ.
+pulls.cannot_auto_merge_helper=Cumaisc de láimh chun na coinbhleachtaà a réiteach.
+pulls.num_conflicting_files_1=Comhad contrártha %d
+pulls.num_conflicting_files_n=%d comhaid contrártha
+pulls.approve_count_1=%d ceadú
+pulls.approve_count_n=%d faomhadh
+pulls.reject_count_1=%d iarratas athraithe
+pulls.reject_count_n=%d iarratas ar athrú
+pulls.waiting_count_1=%d athbhreithniú feithimh
+pulls.waiting_count_n=%d athbhreithnithe feithimh
+pulls.wrong_commit_id=caithfidh comhad id a bheith ina id tiomanta ar an spriocbhrainse
+
+pulls.no_merge_desc=Nà féidir an t-iarratas tarraingthe seo a chumasc toisc go bhfuil gach rogha cumaisc stór dÃchumasaithe.
+pulls.no_merge_helper=Cumasaigh roghanna cumaisc i socruithe an stór nó cumasc an t-iarratas tarraingthe de láimh.
+pulls.no_merge_wip=Nà féidir an t-iarratas tarraingthe seo a chumasc toisc go bhfuil sé marcáilte mar obair atá ar siúl é.
+pulls.no_merge_not_ready=NÃl an t-iarratas tarraingthe seo réidh le cumasc, seiceáil stádas athbhreithnithe agus seiceálacha stádais.
+pulls.no_merge_access=NÃl tú údaraithe chun an t-iarratas tarraingthe seo a chumasc.
+pulls.merge_pull_request=Cruthaigh tiomantas cumaisc
+pulls.rebase_merge_pull_request=Athbhunaigh ansin go tapa ar aghaidh
+pulls.rebase_merge_commit_pull_request=Rebase ansin cruthaigh tiomantas cumaisc
+pulls.squash_merge_pull_request=Cruthaigh tiomantas scuaise
+pulls.fast_forward_only_merge_pull_request=Go tapa ar aghaidh amháin
+pulls.merge_manually=Cumaisc de láimh
+pulls.merge_commit_id=ID an tiomantis cumaisc
+pulls.require_signed_wont_sign=ÉilÃonn an bhrainse tiomáintà shÃnithe, ach nà shÃnÃfear an cumasc seo
+
+pulls.invalid_merge_option=Nà féidir leat an rogha cumaisc seo a úsáid don iarratas tarraingthe seo.
+pulls.merge_conflict=Theip ar Cumaisc: Bhà coinbhleacht ann agus é ag cumasc. Leid: Bain triail as straitéis dhifriúil
+pulls.merge_conflict_summary=Teachtaireacht Earráide
+pulls.rebase_conflict=Theip ar Chumasc: Bhà coinbhleacht ann agus tiomantas á athbhunú: %[1]s. Leid: Bain triail as straitéis eile
+pulls.rebase_conflict_summary=Teachtaireacht Earráide
+pulls.unrelated_histories=Theip ar Cumaisc: Nà roinneann an ceann cumaisc agus an bonn stair choiteann. Leid: Bain triail as straitéis dhifriúil
+pulls.merge_out_of_date=Theip ar Cumaisc: Agus an cumaisc á ghiniúint, nuashonraÃodh an bonn. Leid: Bain triail as arÃs.
+pulls.head_out_of_date=Theip ar Cumaisc: Agus an cumaisc á ghiniúint, nuashonraÃodh an ceann. Leid: Bain triail as arÃs.
+pulls.has_merged=Theip ar: CumaisÃodh an t-iarratas tarraingthe, nà féidir leat a chumasc arÃs nó an spriocbhrainse a athrú.
+pulls.push_rejected=Theip ar Brúigh: DiúltaÃodh don bhrú. Déan athbhreithniú ar na Git Hooks don stór seo.
+pulls.push_rejected_summary=Teachtaireacht Diúltaithe Iomlán
+pulls.push_rejected_no_message=Theip ar Brúigh: DiúltaÃodh don bhrú ach nà raibh aon teachtaireacht iargúlta ann. Déan athbhreithniú ar Git Hooks don stór seo
+pulls.open_unmerged_pull_exists=`Nà féidir leat oibrÃocht athoscailte a dhéanamh toisc go bhfuil iarratas tarraingthe ar feitheamh (#%d) le hairÃonna comhionanna. `
+pulls.status_checking=Tá roinnt seiceála ar feitheamh
+pulls.status_checks_success=D'éirigh le gach seiceáil
+pulls.status_checks_warning=Thuairiscigh roinnt seiceálacha rabhaidh
+pulls.status_checks_failure=Theip ar roinnt seiceálacha
+pulls.status_checks_error=Thug roinnt seiceálacha earráidÃ
+pulls.status_checks_requested=Riachtanach
+pulls.status_checks_details=SonraÃ
+pulls.status_checks_hide_all=Folaigh gach seiceáil
+pulls.status_checks_show_all=Taispeáin gach seiceáil
+pulls.update_branch=Nuashonrú brainse trà chumasc
+pulls.update_branch_rebase=Nuashonraigh an bhrainse trà athbhunú
+pulls.update_branch_success=Bhà nuashonrú brainse rathúil
+pulls.update_not_allowed=Nà cheadaÃtear duit brainse a nuashonrú
+pulls.outdated_with_base_branch=Tá an brainse seo as dáta leis an mbunbhrainse
+pulls.close=Dún Iarratas Tarraing
+pulls.closed_at=`dhún an t-iarratas tarraingthe seo %[2]s`
+pulls.reopened_at=`athoscail an t-iarratas tarraingthe seo %[2]s`
+pulls.cmd_instruction_hint=`Féach ar treoracha na lÃne ordaithe.`
+pulls.cmd_instruction_checkout_title=Seiceáil
+pulls.cmd_instruction_checkout_desc=Ó stór tionscadail, seiceáil brainse nua agus déan tástáil ar na hathruithe.
+pulls.cmd_instruction_merge_title=Cumaisc
+pulls.cmd_instruction_merge_desc=Cumaisc na hathruithe agus nuashonrú ar Gitea.
+pulls.cmd_instruction_merge_warning=Rabhadh: Nà féidir leis an oibrÃocht seo an t-iarratas tarraingthe a chumasc toisc nach raibh "cumasc láimhe uathoibrÃoch" cumasaithe
+pulls.clear_merge_message=Glan an teachtaireacht chumaisc
+pulls.clear_merge_message_hint=Má imrÃtear an teachtaireacht chumaisc nà bhainfear ach ábhar na teachtaireachta tiomanta agus coimeádfar leantóirà git ginte ar nós "Co-Authored-By …".
+
+pulls.auto_merge_button_when_succeed=(Nuair a éirÃonn le seiceálacha)
+pulls.auto_merge_when_succeed=Cumaisc uathoibrÃoch nuair a éirÃonn
+pulls.auto_merge_newly_scheduled=Bhà an t-iarratas tarraingt sceidealta le cumasc nuair a éirÃonn le gach seiceáil.
+pulls.auto_merge_has_pending_schedule=Bhà an t-iarratas tarraingthe seo sceidealaithe ag %[1]s chun cumasc uathoibrÃoch a dhéanamh nuair a éirÃonn le gach seiceáil %[2]s.
+
+pulls.auto_merge_cancel_schedule=Cealaigh cumasc uathoibrÃoch
+pulls.auto_merge_not_scheduled=NÃl an t-iarratas tarraingthe seo sceidealaithe le cumasc go huathoibrÃoch.
+pulls.auto_merge_canceled_schedule=CealaÃodh an cumaisc uathoibrÃoch don iarratas tarraingthe seo.
+
+pulls.auto_merge_newly_scheduled_comment=`sceidealta an t-iarratas tarraingthe seo le cumasc uathoibrithe nuair a éirÃonn le gach seiceáil %[1]s`
+pulls.auto_merge_canceled_schedule_comment=`curtha ar ceal uathchumasc leis an iarratas tarraingthe seo nuair a éirÃonn le gach seiceáil %[1]s`
+
+pulls.delete.title=Scrios an t-iarratas tarraingthe seo?
+pulls.delete.text=An bhfuil tú cinnte gur mhaith leat an t-iarratas tarraingthe seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann)
+
+pulls.recently_pushed_new_branches=Bhrúigh tú ar bhrainse %[1]s %[2]s
+
+pull.deleted_branch=(scriosta): %s
+pull.agit_documentation=Déan athbhreithniú ar dhoiciméid faoi AGit
+
+comments.edit.already_changed=Nà féidir athruithe a shábháil ar an trácht. DealraÃonn sé gur athraigh úsáideoir eile an t-ábhar cheana féin. Athnuachan an leathanach agus déan iarracht eagarthóireacht arÃs chun a gcuid athruithe a sheachaint
+
+milestones.new=Cloch MhÃle Nua
+milestones.closed=Dúnta %s
+milestones.update_ago=Nuashonraithe %s
+milestones.no_due_date=Gan dáta dlite
+milestones.open=Oscailte
+milestones.close=Dún
+milestones.new_subheader=Is féidir le clocha mÃle cabhrú leat ceisteanna a eagrú agus a ndul chun cinn a rianú.
+milestones.completeness=%d%% CrÃochnaithe
+milestones.create=Cruthaigh Cloch MhÃle
+milestones.title=Teideal
+milestones.desc=Cur sÃos
+milestones.due_date=Dáta dlite (roghnach)
+milestones.clear=Glan
+milestones.invalid_due_date_format=Caithfidh formáid dáta dlite a bheith 'bbbb-mm-ll'.
+milestones.create_success=CruthaÃodh an chloch mhÃle "%s".
+milestones.edit=Cuir Cloch MhÃle in eagar
+milestones.edit_subheader=EagraÃonn Garspriocanna saincheisteanna agus rianaÃtear dul chun cinn.
+milestones.cancel=Cealaigh
+milestones.modify=Nuashonraigh Cloch MhÃle
+milestones.edit_success=NuashonraÃodh cloch mhÃle "%s".
+milestones.deletion=Scrios Cloch MhÃle
+milestones.deletion_desc=Cuireann scriosadh cloch mhÃle é as gach saincheist ghaolmhar. Lean ar aghaidh?
+milestones.deletion_success=Tá an chloch mhÃle scriosta.
+milestones.filter_sort.name=Ainm
+milestones.filter_sort.earliest_due_data=An dáta dlite is luaithe
+milestones.filter_sort.latest_due_date=An dáta dlite is déanaÃ
+milestones.filter_sort.least_complete=Is lú crÃochnaithe
+milestones.filter_sort.most_complete=Is mó crÃochnaithe
+milestones.filter_sort.most_issues=Saincheisteanna is mó
+milestones.filter_sort.least_issues=Saincheisteanna is lú
+
+signing.will_sign=SÃneofar an gealltanas seo le heochair "%s".
+signing.wont_sign.error=Bhà earráid ann agus tú ag seiceáil an féidir an tiomantas a shÃniú.
+signing.wont_sign.nokey=NÃl aon eochair ar fáil chun an tiomantas seo a shÃniú.
+signing.wont_sign.never=Nà shÃnÃtear tiomáintà riamh.
+signing.wont_sign.always=SÃnÃtear tiomáintà i gcónaÃ.
+signing.wont_sign.pubkey=Nà shÃnÃofar an tiomantas toisc nach bhfuil eochair phoiblà agat a bhaineann le do chuntas.
+signing.wont_sign.twofa=Caithfidh fÃordheimhniú dhá-fhachtóir a bheith agat chun tiomáintà a shÃniú.
+signing.wont_sign.parentsigned=NÃ shÃnÃofar an tiomantas toisc nach bhfuil an tiomantas tuismitheora sÃnithe.
+signing.wont_sign.basesigned=NÃ shÃnÃfear an cumasc toisc nach bhfuil an tiomantas bunaithe sÃnithe.
+signing.wont_sign.headsigned=NÃ shÃnÃfear an cumasc toisc nach bhfuil an tiomantas ceann sÃnithe.
+signing.wont_sign.commitssigned=Nà shÃnÃfear an cumasc toisc nach bhfuil na tiomáintà gaolmhara go léir sÃnithe.
+signing.wont_sign.approved=NÃ shÃnÃofar an cumaisc toisc nach bhfuil an PR ceadaithe.
+signing.wont_sign.not_signed_in=NÃl tú sÃnithe isteach.
+
+ext_wiki=Rochtain ar Vicà Seachtrach
+ext_wiki.desc=Nasc le vicà seachtrach.
+
+wiki=VicÃ
+wiki.welcome=Fáilte go dtà an VicÃ.
+wiki.welcome_desc=Ligeann an vicà duit cáipéisÃocht a scrÃobh agus a roinnt le comhoibrithe.
+wiki.desc=ScrÃobh agus roinn cáipéisÃocht le comhoibrithe.
+wiki.create_first_page=Cruthaigh an Chéad Leathanach
+wiki.page=Leathanach
+wiki.filter_page=Leathanach scagaire
+wiki.new_page=Leathanach
+wiki.page_title=Teideal an leathanaigh
+wiki.page_content=Ãbhar an leathanaigh
+wiki.default_commit_message=ScrÃobh nóta faoin nuashonrú leathanaigh seo (roghnach).
+wiki.save_page=Sábháil Leathanach
+wiki.last_commit_info=Cuireadh %s an leathanach seo in eagar %s
+wiki.edit_page_button=Cuir in eagar
+wiki.new_page_button=Leathanach Nua
+wiki.file_revision=Athbhreithniú Leathanach
+wiki.wiki_page_revisions=Athbhreithnithe Leathanach VicÃ
+wiki.back_to_wiki=Ar ais go leathanach vicÃ
+wiki.delete_page_button=Scrios Leathanach
+wiki.delete_page_notice_1=Nà féidir leathanach vicà "%s" a scriosadh. Lean ort?
+wiki.page_already_exists=Tá leathanach vicà leis an ainm céanna ann cheana féin.
+wiki.reserved_page=Tá an t-ainm leathanaigh vicà "%s" in áirithe.
+wiki.pages=Leathanaigh
+wiki.last_updated=Nuashonraithe deireanach %s
+wiki.page_name_desc=Cuir isteach ainm don leathanach Vicà seo. Is iad roinnt ainmneacha speisialta: 'Baile', '_Sidebar' agus '_Footer'.
+wiki.original_git_entry_tooltip=Féach ar an gcomhad bunaidh Git in ionad nasc cairdiúil a úsáid.
+
+activity=GnÃomhaÃocht
+activity.navbar.pulse=Cuisle
+activity.navbar.code_frequency=MinicÃocht Cód
+activity.navbar.contributors=Rannpháirtithe
+activity.navbar.recent_commits=Tiomáintà le déanaÃ
+activity.period.filter_label=Tréimhse:
+activity.period.daily=1 lá
+activity.period.halfweekly=3 lá
+activity.period.weekly=1 seachtain
+activity.period.monthly=1 mhÃ
+activity.period.quarterly=3 mhÃ
+activity.period.semiyearly=6 mhÃ
+activity.period.yearly=1 bhliain
+activity.overview=Forbhreathnú
+activity.active_prs_count_1=%d Iarratas Tarraingthe GnÃomhach
+activity.active_prs_count_n=%d Iarratais Tharraing GhnÃomhach
+activity.merged_prs_count_1=Iarratas Tarraing Cumaisc
+activity.merged_prs_count_n=Iarratais Tharraing Chomhcheangail
+activity.opened_prs_count_1=Iarratas Tarraing Beartaithe
+activity.opened_prs_count_n=Iarratais Tarraing Beartaithe
+activity.title.user_1=%d úsáideoir
+activity.title.user_n=%d úsáideoirÃ
+activity.title.prs_1=Iarratas tarraing %d
+activity.title.prs_n=%d Iarratais Tarraing
+activity.title.prs_merged_by=%s a chumasc ag %s
+activity.title.prs_opened_by=%s arna mholadh ag %s
+activity.merged_prs_label=Cumaiscthe
+activity.opened_prs_label=Molta
+activity.active_issues_count_1=%d Eagrán GnÃomhach
+activity.active_issues_count_n=%d Ceisteanna GnÃomhacha
+activity.closed_issues_count_1=Saincheist Dúnta
+activity.closed_issues_count_n=Saincheisteanna Dúnta
+activity.title.issues_1=Saincheist %d
+activity.title.issues_n=Saincheisteanna %d
+activity.title.issues_closed_from=%s dúnta ó %s
+activity.title.issues_created_by=%s cruthaithe ag %s
+activity.closed_issue_label=Dúnta
+activity.new_issues_count_1=Eagrán Nua
+activity.new_issues_count_n=Saincheisteanna Nua
+activity.new_issue_label=OsclaÃodh
+activity.title.unresolved_conv_1=%d Comhrá Neamhréitithe
+activity.title.unresolved_conv_n=%d Comhráite Neamhréitithe
+activity.unresolved_conv_desc=NÃor réitÃodh na saincheisteanna agus na hiarratais tarraingthe seo le déanaà fós.
+activity.unresolved_conv_label=Oscailte
+activity.title.releases_1=Scaoileadh %d
+activity.title.releases_n=Eisiúintà %d
+activity.title.releases_published_by=%s foilsithe ag %s
+activity.published_release_label=Foilsithe
+activity.no_git_activity=NÃor rinneadh aon ghnÃomhaÃocht tiomanta sa tréimhse seo.
+activity.git_stats_exclude_merges=Gan cumaisc a áireamh,
+activity.git_stats_author_1=%d údar
+activity.git_stats_author_n=%d údair
+activity.git_stats_pushed_1=tá sé brúite
+activity.git_stats_pushed_n=tá brú orthu
+activity.git_stats_commit_1=%d tiomantas
+activity.git_stats_commit_n=%d tiomáintÃ
+activity.git_stats_push_to_branch=chuig %s agus
+activity.git_stats_push_to_all_branches=chuig gach brainse.
+activity.git_stats_on_default_branch=Ar %s,
+activity.git_stats_file_1=%d comhad
+activity.git_stats_file_n=%d comhaid
+activity.git_stats_files_changed_1=tá athrú tagtha
+activity.git_stats_files_changed_n=tá athraithe
+activity.git_stats_additions=agus tá ann
+activity.git_stats_addition_1=%d breisiú
+activity.git_stats_addition_n=%d breiseanna
+activity.git_stats_and_deletions=agus
+activity.git_stats_deletion_1=%d scriosadh
+activity.git_stats_deletion_n=%d scriosta
+
+contributors.contribution_type.filter_label=Cineál rannÃocaÃochta:
+contributors.contribution_type.commits=TiomáintÃ
+contributors.contribution_type.additions=Breiseanna
+contributors.contribution_type.deletions=Scriosadh
+
+settings=Socruithe
+settings.desc=Is é socruithe an áit ar féidir leat na socruithe don stóras a bhainistiú
+settings.options=Stóras
+settings.collaboration=ComhoibritheoirÃ
+settings.collaboration.admin=Riarthóir
+settings.collaboration.write=ScrÃobh
+settings.collaboration.read=Léigh
+settings.collaboration.owner=Úinéir
+settings.collaboration.undefined=Neamhshainithe
+settings.hooks=Crúcaà Gréasán
+settings.githooks=Crúcanna Git
+settings.basic_settings=Socruithe Bunúsacha
+settings.mirror_settings=Socruithe Scáthán
+settings.mirror_settings.docs=Cuir do stóras ar bun chun tiomáintÃ, clibeanna agus brainsà a shioncronú go huathoibrÃoch le stóras eile.
+settings.mirror_settings.docs.disabled_pull_mirror.instructions=Socraigh do thionscadal chun tiomáintÃ, clibeanna agus brainsà a bhrú go huathoibrÃoch chuig stóras eile. Tá scátháin tarraingthe dÃchumasaithe ag riarthóir do shuÃomh.
+settings.mirror_settings.docs.disabled_push_mirror.instructions=Socraigh do thionscadal chun tiomáintÃ, clibeanna agus brainsà a tharraingt go huathoibrÃoch ó stóras eile.
+settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=Faoi láthair, nà féidir é seo a dhéanamh ach sa roghchlár "Imirce Nua". Le haghaidh tuilleadh eolais, téigh i gcomhairle le do thoil:
+settings.mirror_settings.docs.disabled_push_mirror.info=Chuir riarthóir do shuÃomh faoi dhÃchumasú scátháin bhrú.
+settings.mirror_settings.docs.no_new_mirrors=Tá do stóras ag teacht le hathruithe chuig nó ó stóras eile. Cuimhnigh le do thoil nach féidir leat scátháin nua a chruthú faoi láthair.
+settings.mirror_settings.docs.can_still_use=Cé nach féidir leat scátháin atá ann cheana a mhodhnú nó cinn nua a chruthú, féadfaidh tú do scáthán atá ann cheana a úsáid fós.
+settings.mirror_settings.docs.pull_mirror_instructions=Chun scáthán tarraingthe a shocrú, téigh i gcomhairle le do thoil:
+settings.mirror_settings.docs.more_information_if_disabled=Is féidir leat tuilleadh eolais a fháil faoi scátháin bhrú agus tarraingthe anseo:
+settings.mirror_settings.docs.doc_link_title=Conas is féidir liom na stórtha a scáthánú?
+settings.mirror_settings.docs.doc_link_pull_section=an chuid "Ag tarraingt ó stóras" den doiciméadú.
+settings.mirror_settings.docs.pulling_remote_title=Ag tarraingt ó stóras cianda
+settings.mirror_settings.mirrored_repository=Stóras scátháin
+settings.mirror_settings.pushed_repository=Stóras brúite
+settings.mirror_settings.direction=Treo
+settings.mirror_settings.direction.pull=Tarraingt
+settings.mirror_settings.direction.push=Brúigh
+settings.mirror_settings.last_update=Nuashonrú deireanach
+settings.mirror_settings.push_mirror.none=NÃl aon scátháin bhrú cumraithe
+settings.mirror_settings.push_mirror.remote_url=URL Stóras Cianda Git
+settings.mirror_settings.push_mirror.add=Cuir Scáthán Brúigh leis
+settings.mirror_settings.push_mirror.edit_sync_time=Eagar eatramh sioncronaithe scátháin
+
+settings.sync_mirror=Sioncronaigh Anois
+settings.pull_mirror_sync_in_progress=Athruithe a tharraingt ón iargúlta %s i láthair na huaire.
+settings.push_mirror_sync_in_progress=Athruithe a bhrú ar an iargúlta %s i láthair na huaire.
+settings.site=Láithreán Gréasáin
+settings.update_settings=Nuashonrú Socruithe
+settings.update_mirror_settings=Nuashonraigh Socruithe Scátháin
+settings.branches.switch_default_branch=Athraigh Brainse Réamhshocraithe
+settings.branches.update_default_branch=An Brainse Réamhshocraithe a nuashonrú
+settings.branches.add_new_rule=Cuir Riail Nua leis
+settings.advanced_settings=Ardsocruithe
+settings.wiki_desc=Cumasaigh Stór VicÃ
+settings.use_internal_wiki=Úsáid Vicà Insuite
+settings.default_wiki_branch_name=Ainm Brainse Réamhshocraithe VicÃ
+settings.default_wiki_everyone_access=Cead Rochtana Réamhshocraithe d'úsáideoirà sÃnithe isteach:
+settings.failed_to_change_default_wiki_branch=Theip ar an brainse réamhshocraithe vicà a athrú.
+settings.use_external_wiki=Úsáid Vicà Seachtrach
+settings.external_wiki_url=URL Vicà Seachtrach
+settings.external_wiki_url_error=Nà URL bailà é URL seachtrach vicÃ.
+settings.external_wiki_url_desc=AtreoraÃtear cuairteoirà chuig an URL wiki seachtrach agus iad ag cliceáil ar an gcluaisÃn wiki.
+settings.issues_desc=Cumasaigh Rianóir Saincheist Stórais
+settings.use_internal_issue_tracker=Úsáid Rianóir Saincheist Ionsuite
+settings.use_external_issue_tracker=Úsáid Rianaire Eisiúint Sheachtrach
+settings.external_tracker_url=URL Rianaithe Saincheisteanna Seachtrach
+settings.external_tracker_url_error=Nà URL bailà é an URL rianaitheora saincheisteanna seachtrach.
+settings.external_tracker_url_desc=Déantar cuairteoirà a atreorú chuig an URL rianaithe eisiúintà seachtracha nuair a chliceálann siad ar an táb saincheisteanna.
+settings.tracker_url_format=Formáid URL Rianaithe Saincheist Seachtrach
+settings.tracker_url_format_error=Nà URL bailà é an fhormáid URL rianaitheora saincheisteanna seachtrach.
+settings.tracker_issue_style=Formáid Uimhir Rianaithe Saincheisteanna
+settings.tracker_issue_style.numeric=Uimhriúil
+settings.tracker_issue_style.alphanumeric=Alfauméireacha
+settings.tracker_issue_style.regexp=Léiriú Rialta
+settings.tracker_issue_style.regexp_pattern=Patrún Léirithe Rialta
+settings.tracker_issue_style.regexp_pattern_desc=Úsáidfear an chéad ghrúpa a gabhadh in ionad {index}
.
+settings.tracker_url_format_desc=Úsáid na sealbhóirà áite {user}
, {repo}
agus {index}
le haghaidh an ainm úsáideora, an t-ainm stórtha agus an t-innéacs eisiúna.
+settings.enable_timetracker=Cumasaigh Rianú Ama
+settings.allow_only_contributors_to_track_time=Lig do Rannpháirtithe Amach Am a Rianú
+settings.pulls_desc=Cumasaigh Iarratais Tarraingthe Stóras
+settings.pulls.ignore_whitespace=Déan neamhaird de spás bán le haghaidh coinbhleachtaÃ
+settings.pulls.enable_autodetect_manual_merge=Cumasaigh cumasc láimhe autodetector (Nóta: I roinnt cásanna speisialta, is féidir mÃbhreithiúnais tarlú)
+settings.pulls.allow_rebase_update=Cumasaigh brainse iarratais tarraingthe a nuashonrú trà athbhunú
+settings.pulls.default_delete_branch_after_merge=Scrios brainse an iarratais tarraingthe tar éis cumasc de réir réamhshocraithe
+settings.pulls.default_allow_edits_from_maintainers=Ceadaigh eagarthóirà ó chothabhálaà de réir réamhshocraithe
+settings.releases_desc=Cumasaigh Eisiúintà Stórais
+settings.packages_desc=Cumasaigh Clárlann na bPacáistà Taisclainne
+settings.projects_desc=Cumasaigh Tionscadail
+settings.projects_mode_desc=Mód Tionscadail (cé na cineálacha tionscadail le taispeáint)
+settings.projects_mode_repo=Tionscadail stórais amháin
+settings.projects_mode_owner=Tionscadail úsáideora nó org amháin
+settings.projects_mode_all=Gach tionscadal
+settings.actions_desc=Cumasaigh GnÃomhartha Taiscthe
+settings.admin_settings=Socruithe Riarthóra
+settings.admin_enable_health_check=Cumasaigh Seiceálacha Sláinte Stórais (git fsck)
+settings.admin_code_indexer=Innéacsaitheoir Cód
+settings.admin_stats_indexer=Innéacsóir Staitisticà Cód
+settings.admin_indexer_commit_sha=SHA Innéacsaithe Deiridh
+settings.admin_indexer_unindexed=Neamh-innéacsaithe
+settings.reindex_button=Cuir le Scuaine Reindex
+settings.reindex_requested=Athinnéacsú Iarrtha
+settings.admin_enable_close_issues_via_commit_in_any_branch=Saincheist a dhúnadh trà ghealltanas a rinneadh i mbrainse neamh-mhainneachtana
+settings.danger_zone=Crios Contúirte
+settings.new_owner_has_same_repo=Tá stóras leis an ainm céanna ag an úinéir nua cheana féin. Roghnaigh ainm eile le do thoil.
+settings.convert=Tiontaigh go Stóras Rialta
+settings.convert_desc=Is féidir leat an scáthán seo a thiontú ina stór rialta. Nà féidir é seo a chur ar ais.
+settings.convert_notices_1=Déanfaidh an oibrÃocht seo an scáthán a thiontú ina stóras rialta agus nà féidir é a chur ar ais.
+settings.convert_confirm=Tiontaigh Stóras
+settings.convert_succeed=Tá an scáthán tiontaithe ina stóras rialta.
+settings.convert_fork=Tiontaigh go Stóras Rialta
+settings.convert_fork_desc=Is féidir leat an forc seo a thiontú ina stóras rialta. Nà féidir é seo a chur ar ais.
+settings.convert_fork_notices_1=Déanfaidh an oibrÃocht seo an forc a thiontú ina stóras rialta agus nà féidir é a chur ar ais.
+settings.convert_fork_confirm=Tiontaigh Stóras
+settings.convert_fork_succeed=Tá an forc tiontaithe ina stóras rialta.
+settings.transfer=Úinéireacht Aistrithe
+settings.transfer.rejected=DiúltaÃodh d'aistriú stóras.
+settings.transfer.success=D'éirigh le haistriú stóras.
+settings.transfer.blocked_user=Nà féidir an stóras a aistriú toisc go bhfuil bac á chur ort ag an úinéir nua.
+settings.transfer_abort=Cealaigh aistriú
+settings.transfer_abort_invalid=Nà féidir leat aistriú stóras nach bhfuil ann a chealú.
+settings.transfer_abort_success=Cuireadh an t-aistriú stóras chuig %s ar ceal go rathúil.
+settings.transfer_desc=Aistrigh an stóras seo chuig úsáideoir nó chuig eagraÃocht a bhfuil cearta riarthóra agat ina leith.
+settings.transfer_form_title=Cuir isteach ainm an stóras mar dhearbhú:
+settings.transfer_in_progress=Tá aistriú leanúnach ann faoi láthair. Cealaigh é más mian leat an stóras seo a aistriú chuig úsáideoir eile.
+settings.transfer_notices_1=- Caillfidh tú rochtain ar an stóras má aistrÃonn tú é chuig úsáideoir aonair.
+settings.transfer_notices_2=- Coimeádfaidh tú rochtain ar an stóras má aistrÃonn tú é chuig eagraÃocht a bhfuil (comh)úinéir agat.
+settings.transfer_notices_3=- Má tá an stóras prÃobháideach agus má aistrÃtear é chuig úsáideoir aonair, cinnteoidh an gnÃomh seo go bhfuil ar a laghad cead léite ag an úsáideoir (agus athraÃonn sé ceadanna más gá).
+settings.transfer_notices_4=- Más le heagraÃocht an stóras, agus má aistrÃonn tú chuig eagraÃocht nó duine aonair eile é, caillfidh tú na naisc idir saincheisteanna an taisclainne agus bord tionscadail na heagraÃochta.
+settings.transfer_owner=Úinéir nua
+settings.transfer_perform=Déan Aistriú
+settings.transfer_started=`Tá an stóras seo marcáilte le haistriú agus tá sé ag fanacht le deimhniú ó "%s"`
+settings.transfer_succeed=Tá an stóras aistrithe.
+settings.signing_settings=Socruithe FÃoraithe SÃnithe
+settings.trust_model=Samhail Iontaobhas SÃnithe
+settings.trust_model.default=Múnla Iontaobhais Réamhshocraithe
+settings.trust_model.default.desc=Úsáid an tsamhail iontaobhais stórais réamhshocraithe don suiteáil
+settings.trust_model.collaborator=Comhoibritheoir
+settings.trust_model.collaborator.long=Comhoibritheoir: SÃnithe muinÃn ag comhoibrithe
+settings.trust_model.collaborator.desc=Déanfar sÃnithe bailà ó chomhoibritheoirà an stóras seo a mharcáil mar 'iontaofa' – (cibé acu a mheaitseálann siad an tiomnóir nó nach bhfuil). Seachas sin, marcálfar sÃnithe bailà mar 'neamhiontaofa' má mheaitseálann an sÃniú an tiomnóir agus mar 'neamh-mheaitseáilte' mura bhfuil.
+settings.trust_model.committer=Coimisitheoir
+settings.trust_model.committer.long=Gealltóir: SÃnithe iontaobhais a mheaitseálann na coimitheoirà (Meaitseálann sé seo le GitHub agus cuirfidh sé iallach ar Gitea gealltanais sÃnithe Gitea a bheith mar an tiomnóir)
+settings.trust_model.committer.desc=Nà mharcálfar "muinÃn" ar shÃnithe bailà ach amháin má mheaitseálann siad leis an gcoiste, nó déanfar iad a mharcáil "gan mheaitseáil". Cuireann sé seo iachall ar Gitea a bheith mar an tiomnóir ar ghealltanais sÃnithe agus an fÃor-chimisteoir marcáilte mar Comhúdar: agus Co-tiomanta ag: leantóir sa chimiú. Caithfidh an eochair réamhshocraithe Gitea a bheith ag teacht le hÚsáideoir sa bhunachar sonraÃ.
+settings.trust_model.collaboratorcommitter=Comhoibritheo+Coimiteoir
+settings.trust_model.collaboratorcommitter.long=ComhoibrÃ+Coiste: sÃnithe muinÃne ó chomhoibrithe a mheaitseálann an tiomnóir
+settings.trust_model.collaboratorcommitter.desc=Déanfar sÃnithe bailà ó chomhoibritheoirà ar an stór seo a mharcáil "muinÃn" má mheaitseálann siad leis an gcoiste. Seachas sin, marcálfar "neamhiontaofa" ar shÃnithe bailà má mheaitseálann an sÃniú leis an gcoiste agus "gan mheaitseáil" ar shlà eile. Cuirfidh sé seo iallach ar Gitea a mharcáil mar an tiomnóir ar ghealltanais shÃnithe agus an fÃor-choiste a bheith marcáilte mar Comhúdaraithe Ag: agus Comhthiomanta Ag: leantóir sa ghealltanas. Caithfidh an eochair réamhshocraithe Gitea a bheith ag teacht le hÚsáideoir sa bhunachar sonraÃ.
+settings.wiki_delete=Scrios Sonraà VicÃ
+settings.wiki_delete_desc=Tá sonraà wiki stóras a scriosadh buan agus nà féidir iad a chur ar ais.
+settings.wiki_delete_notices_1=- Scriosfaidh agus dÃchumasóidh sé seo an stóras vicà do %s go buan.
+settings.confirm_wiki_delete=Scrios Sonraà VicÃ
+settings.wiki_deletion_success=Scriosadh sonraà vicà an stórais.
+settings.delete=Scrios an Stóras seo
+settings.delete_desc=Tá scriosadh stóras buan agus nà féidir é a chealú.
+settings.delete_notices_1=- Nà FÉIDIR an oibrÃocht seo a chealú.
+settings.delete_notices_2=- Scriosfaidh an oibrÃocht seo stór %s go buan lena n-áirÃtear cód, ceisteanna, nótaà tráchta, sonraà vicà agus socruithe comhoibrithe.
+settings.delete_notices_fork_1=- Beidh forcanna den stóras seo neamhspleách tar éis iad a scriosadh.
+settings.deletion_success=Tá an stóras scriosta.
+settings.update_settings_success=NuashonraÃodh na socruithe stóras.
+settings.update_settings_no_unit=Ba cheart go gceadódh an stóras idirghnÃomhú de chineál éigin ar a laghad.
+settings.confirm_delete=Scrios Stóras
+settings.add_collaborator=Cuir Comhoibritheoir leis
+settings.add_collaborator_success=Cuireadh an comhoibritheoir leis.
+settings.add_collaborator_inactive_user=Nà féidir úsáideoir neamhghnÃomhach a chur mar chomhoibritheoir.
+settings.add_collaborator_owner=Nà féidir úinéir a chur leis mar chomhoibritheoir.
+settings.add_collaborator_duplicate=Tá an comhoibrà curtha leis an stóras seo cheana féin.
+settings.add_collaborator.blocked_user=Cuireann úinéir an stóras bac ar an gcomhoibritheoir nó a mhalairt.
+settings.delete_collaborator=Bain
+settings.collaborator_deletion=Bain Comhoibritheoir
+settings.collaborator_deletion_desc=Má dhéantar comhoibrà a bhaint, déanfar a rochtain ar an stóras seo a chúlghairm. Lean ort?
+settings.remove_collaborator_success=Tá an comhoibritheoir bainte.
+settings.org_not_allowed_to_be_collaborator=Nà féidir eagraÃochtaà a chur leis mar chomhoibritheoir.
+settings.change_team_access_not_allowed=Tá rochtain foirne a athrú don stóras teoranta d'úinéir eagraÃochta
+settings.team_not_in_organization=NÃl an fhoireann san eagraÃocht chéanna leis an stóras
+settings.teams=Foirne
+settings.add_team=Cuir Foireann leis
+settings.add_team_duplicate=Tá an stóras ag an bhfoireann cheana féin
+settings.add_team_success=Tá rochtain ag an bhfoireann anois ar an stóras.
+settings.change_team_permission_tip=Tá cead na foirne socraithe ar leathanach socraithe foirne agus nà féidir é a athrú in aghaidh an stóras
+settings.delete_team_tip=Tá rochtain ag an bhfoireann seo ar gach stórais agus nà féidir à a bhaint
+settings.remove_team_success=Tá rochtain na foirne ar an stóras bainte amach.
+settings.add_webhook=Cuir Crúca Gréasán leis
+settings.add_webhook.invalid_channel_name=Nà féidir ainm cainéal Crúca Gréasán a bheith folamh agus nà féidir ach carachtar # a bheith ann.
+settings.hooks_desc=Déanann Crúcaà Gréasán iarratais HTTP POST go huathoibrÃoch chuig freastalaà nuair a chuireann imeachtaà áirithe Gitea tús. Léigh tuilleadh sa treoirleabhair gréasáin.
+settings.webhook_deletion=Bain Crúca Gréasán
+settings.webhook_deletion_desc=Scriostar a shocruithe agus a stair seachadta a bhaineann le Crúca Gréasán a bhaint. Lean ar aghaidh?
+settings.webhook_deletion_success=Tá an Crúca Gréasán bainte amach.
+settings.webhook.test_delivery=Seachadadh Tástála
+settings.webhook.test_delivery_desc=Déan tástáil ar an Crúca Gréasán seo le himeacht bhréige.
+settings.webhook.test_delivery_desc_disabled=Chun an Crúca Gréasán seo a thástáil le himeacht bhréige, gnÃomhachtaigh é.
+settings.webhook.request=Iarratas
+settings.webhook.response=Freagra
+settings.webhook.headers=Ceanntásca
+settings.webhook.payload=Ãbhar
+settings.webhook.body=Comhlacht
+settings.webhook.replay.description=Seinn an Crúca Gréasán seo arÃs.
+settings.webhook.replay.description_disabled=Chun an Crúca Gréasán seo a athsheinm, gnÃomhachtaigh é.
+settings.webhook.delivery.success=Cuireadh imeacht leis an scuaine seachadta. D'fhéadfadh sé cúpla soicind a thógáil sula dtaispeántar sé sa stair seachadta.
+settings.githooks_desc=Tá Git Crúcaà faoi thiomáint ag Git féin. Is féidir leat comhaid crúca a chur in eagar thÃos chun oibrÃochtaà saincheaptha a shocrú.
+settings.githook_edit_desc=Mura bhfuil an hook neamhghnÃomhach, cuirfear ábhar samplach i láthair. Má fhágann tú ábhar go luach folamh dÃchumasófar an crúca seo.
+settings.githook_name=Ainm Crúca
+settings.githook_content=Ãbhar Crúca
+settings.update_githook=Nuashonraigh Crúca
+settings.add_webhook_desc=Seolfaidh Gitea iarratais POST
le cineál ábhar sonraithe chuig an spriocURL. Léigh tuilleadh sa treoir Crúcaà Gréasán.
+settings.payload_url=URL spriocdhÃrithe
+settings.http_method=Modh HTTP
+settings.content_type=Cineál Ãbhar POST
+settings.secret=Rúnda
+settings.slack_username=Ainm úsáideora
+settings.slack_icon_url=URL deilbhÃn
+settings.slack_color=Dath
+settings.discord_username=Ainm úsáideora
+settings.discord_icon_url=URL deilbhÃn
+settings.event_desc=Truicear Ar:
+settings.event_push_only=Imeachtaà Brúigh
+settings.event_send_everything=Gach Imeacht
+settings.event_choose=Imeachtaà Saincheaptha…
+settings.event_header_repository=Imeachtaà Stóras
+settings.event_create=Cruthaigh
+settings.event_create_desc=CruthaÃodh brainse nó clib.
+settings.event_delete=Scrios
+settings.event_delete_desc=Brainse nó clib scriosta.
+settings.event_fork=Forc
+settings.event_fork_desc=Forcadh stóras.
+settings.event_wiki=VicÃ
+settings.event_wiki_desc=Leathanach Vicà cruthaithe, athainmnithe, curtha in eagar nó scriosta.
+settings.event_release=Scaoileadh
+settings.event_release_desc=Scaoileadh foilsithe, nuashonraithe nó scriosta i stóras.
+settings.event_push=Brúigh
+settings.event_force_push=Fórsa Brúigh
+settings.event_push_desc=Brúigh Git chuig stóras.
+settings.event_repository=Stóras
+settings.event_repository_desc=Stóras a cruthaÃodh nó a scriosadh.
+settings.event_header_issue=Imeachtaà Eisiúint
+settings.event_issues=Saincheisteanna
+settings.event_issues_desc=OsclaÃodh, dúnadh, athosclaÃodh nó cuireadh an cheist in eagar.
+settings.event_issue_assign=Saincheist Sannaithe
+settings.event_issue_assign_desc=Eisiúint sannta nó neamhshannta.
+settings.event_issue_label=Eisiúint Lipéadaithe
+settings.event_issue_label_desc=Lipéid eisiúna nuashonraithe nó glanta.
+settings.event_issue_milestone=Clocha MÃle Saincheiste
+settings.event_issue_milestone_desc=Clocha MÃle Saincheiste nó Clocha MÃle de-Saincheiste.
+settings.event_issue_comment=Trácht Eisiúna
+settings.event_issue_comment_desc=Trácht eisiúna cruthaithe, curtha in eagar nó a scriosadh.
+settings.event_header_pull_request=Tarraingt Imeachtaà Iarratas
+settings.event_pull_request=Iarratas Tarraingthe
+settings.event_pull_request_desc=Iarratas tarraingthe oscailte, dúnta, athoscailte nó curtha in eagar.
+settings.event_pull_request_assign=Iarratas Tarraingthe Sannta
+settings.event_pull_request_assign_desc=Iarratas tarraingthe sannta nó neamhshannta.
+settings.event_pull_request_label=Iarratas Tarraingthe Lipéadaithe
+settings.event_pull_request_label_desc=Tarraing lipéid iarratais nuashonraithe nó glanta.
+settings.event_pull_request_milestone=Iarratas Tarraing Cloch MhÃle
+settings.event_pull_request_milestone_desc=Iarratas tarraing clocha mÃle nó dÃ-chlocha mÃle.
+settings.event_pull_request_comment=Trácht ar Iarratas Tarraingthe
+settings.event_pull_request_comment_desc=Trácht ar iarratas tarraingthe cruthaithe, curtha in eagar, nó scriosta.
+settings.event_pull_request_review=Iarratas Tarraingthe Athbhreithnithe
+settings.event_pull_request_review_desc=Tarraing iarratas ceadaithe, diúltaithe nó trácht athbhreithnithe.
+settings.event_pull_request_sync=Iarratas Tarraing Sincronaithe
+settings.event_pull_request_sync_desc=Tarraing iarratas sioncrónaithe.
+settings.event_pull_request_review_request=Iarratas ar Athbhreithniú Tarraingthe Iarrtha
+settings.event_pull_request_review_request_desc=Tarraing athbhreithniú iarratais iarrtha nó baineadh iarratas athbhreithnithe.
+settings.event_pull_request_approvals=Ceaduithe Iarratais Tarraing
+settings.event_pull_request_merge=Cumaisc Iarratas Tarraing
+settings.event_package=Pacáiste
+settings.event_package_desc=Pacáiste a cruthaÃodh nó a scriosadh i stóras.
+settings.branch_filter=Scagaire brainse
+settings.branch_filter_desc=Liosta bán brainse le haghaidh brú, cruthú brainse agus imeachtaà scriosta brainse, sonraithe mar phatrún glob. Má tá sé folamh nó *
, tuairiscÃtear imeachtaà do gach brainse. Féach %[2]s doiciméadú le haghaidh comhréire. SamplaÃ: máistir
, {master,release*}
.
+settings.authorization_header=Ceanntásc Údaraithe
+settings.authorization_header_desc=Cuirfear san áireamh mar cheanntásc údaraithe d'iarratais nuair a bheidh ann SamplaÃ: %s.
+settings.active=GnÃomhach
+settings.active_helper=Seolfar faisnéis faoi imeachtaà spreagtha chuig an URL Crúca Gréasán seo.
+settings.add_hook_success=Cuireadh an Crúca Gréasán leis.
+settings.update_webhook=Nuashonraigh Crúca Gréasán
+settings.update_hook_success=NuashonraÃodh an Crúca Gréasán.
+settings.delete_webhook=Bain Crúca Gréasán
+settings.recent_deliveries=Seachadtaà le déana
+settings.hook_type=Cineál Crúca
+settings.slack_token=Comhartha
+settings.slack_domain=Fearann
+settings.slack_channel=Cainéal
+settings.add_web_hook_desc=Comhtháthaigh %s isteach i do stóras.
+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=Teileagram
+settings.web_hook_name_matrix=MaitrÃs
+settings.web_hook_name_msteams=Microsoft Teams
+settings.web_hook_name_feishu_or_larksuite=Feishu / Lark Suite
+settings.web_hook_name_feishu=Feishu
+settings.web_hook_name_larksuite=Lark Suite
+settings.web_hook_name_wechatwork=WeCom (Wechat Work)
+settings.web_hook_name_packagist=Packagist
+settings.packagist_username=Ainm úsáideora Pacagist
+settings.packagist_api_token=Comhartha API
+settings.packagist_package_url=URL pacáiste Packagist
+settings.deploy_keys=Eochracha a imscaradh
+settings.add_deploy_key=Cuir Eochair Imscartha leis
+settings.deploy_key_desc=Tá rochtain tarraingthe léite amháin ag eochracha imscartha ar an stóras.
+settings.is_writable=Cumasaigh Rochtain ScrÃobh
+settings.is_writable_info=Lig don eochair imlonnaithe seo a bhrú chuig an stóras.
+settings.no_deploy_keys=NÃl aon eochracha imscartha ann fós.
+settings.title=Teideal
+settings.deploy_key_content=Ãbhar
+settings.key_been_used=Tá eochair imscartha le hábhar comhionann in úsáid cheana féin.
+settings.key_name_used=Tá eochair imscartha leis an ainm céanna ann cheana féin.
+settings.add_key_success=Tá an eochair imlonnaithe "%s" curtha leis.
+settings.deploy_key_deletion=Bain Eochair Imlonnaithe
+settings.deploy_key_deletion_desc=Ag baint eochair imscartha, cuirfear a rochtain ar an stóras seo a chúlghairm. Lean ar aghaidh?
+settings.deploy_key_deletion_success=Tá an eochair imscartha bainte amach.
+settings.branches=BrainsÃ
+settings.protected_branch=Cosaint Brainse
+settings.protected_branch.save_rule=Sábháil Riail
+settings.protected_branch.delete_rule=Scrios Riail
+settings.protected_branch_can_push=Ceadaigh bhrú?
+settings.protected_branch_can_push_yes=Is féidir leat a bhrú
+settings.protected_branch_can_push_no=Nà féidir leat a bhrú
+settings.branch_protection=Rialacha Cosanta Brainse do Bhrainse '%s'
+settings.protect_this_branch=Cumasaigh Cosaint Brainse
+settings.protect_this_branch_desc=Cosc ar scriosadh agus cuireann sé srian le Git a bhrú agus a chumasc go dtà an brainse.
+settings.protect_disable_push=DÃchumasaigh Brúigh
+settings.protect_disable_push_desc=Nà cheadfar aon bhrú chuig an mbrainse seo.
+settings.protect_disable_force_push=DÃchumasaigh Fórsa Brú
+settings.protect_disable_force_push_desc=Nà cheadfar aon fhórsa a bhrú chuig an mbrainse seo.
+settings.protect_enable_push=Cumasaigh Brúigh
+settings.protect_enable_push_desc=Beidh cead ag aon duine a bhfuil rochtain scrÃofa aige/aici brú chuig an mbrainse seo (ach gan brú a bhrú).
+settings.protect_enable_force_push_all=Cumasaigh Fórsa Brúigh
+settings.protect_enable_force_push_all_desc=Beidh cead ag duine ar bith a bhfuil rochtain brú aige brú a chur ar an mbrainse seo.
+settings.protect_enable_force_push_allowlist=Brú Fórsa Srianta ón Liosta Ceadaithe
+settings.protect_enable_force_push_allowlist_desc=Nà cheadófar ach d’úsáideoirà liostaithe nó foirne a bhfuil rochtain bhrú acu brú a chur ar an mbrainse seo.
+settings.protect_enable_merge=Cumasaigh Cumaisc
+settings.protect_enable_merge_desc=Beidh cead ag aon duine a bhfuil rochtain scrÃofa aige na hiarratais tarraingte a chumasc leis an mbrainse seo.
+settings.protect_whitelist_committers=Brú Srianta ón Liosta Ceadaithe
+settings.protect_whitelist_committers_desc=Nà bheidh cead ach úsáideoirà nó foirne liostaithe ceadaithe brú chuig an mbrainse seo (ach gan brú a chur i bhfeidhm).
+settings.protect_whitelist_deploy_keys=Eochracha imscartha ón Liosta Ceadaithe le rochtain scrÃofa chun brú.
+settings.protect_whitelist_users=Úsáideoirà ar an Liosta Ceadaithe chun brú a dhéanamh:
+settings.protect_whitelist_teams=Foirne ar an Liosta Ceadaithe chun brú a dhéanamh:
+settings.protect_force_push_allowlist_users=Úsáideoirà ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh:
+settings.protect_force_push_allowlist_teams=Foirne ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh:
+settings.protect_force_push_allowlist_deploy_keys=Eochracha imscaradh le rochtain brú ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh.
+settings.protect_merge_whitelist_committers=Cumasaigh Liosta Ceadaithe Cumaisc
+settings.protect_merge_whitelist_committers_desc=Nà lig ach d'úsáideoirà nó d'fhoirne liostaithe iarratais tarraingthe isteach sa bhrainse seo a chumasc.
+settings.protect_merge_whitelist_users=Úsáideoirà ar an Liosta Ceadaithe le haghaidh cumasc:
+settings.protect_merge_whitelist_teams=Foirne ar an Liosta Ceadaithe le haghaidh cumasc:
+settings.protect_check_status_contexts=Cumasaigh Seiceáil Stádas
+settings.protect_status_check_patterns=Patrúin seiceála stádais:
+settings.protect_status_check_patterns_desc=Iontráil patrúin chun a shonrú cé na seiceálacha stádais a chaithfidh pas a fháil sular féidir brainsà a chumasc le brainse a chomhoibrÃonn leis an riail seo. SonraÃonn gach lÃne patrún. Nà féidir patrúin a bheith folamh.
+settings.protect_check_status_contexts_desc=A cheangal ar sheiceálacha stádais pas a fháil roimh chumasc. Nuair a bheidh sé cumasaithe, nà mór gealltanais a bhrú ar dtús chuig brainse eile, ansin iad a chumasc nó a bhrú go dÃreach chuig brainse a thagann leis an riail seo tar éis do sheiceálacha stádais a bheith caite. Mura ndéantar comhthéacs ar bith a mheaitseáil, nà mór go n-éireodh leis an ngealltanas deiridh beag beann ar an gcomhthéacs.
+settings.protect_check_status_contexts_list=Seiceálacha stádais a fuarthas sa tseachtain seo caite don stóras seo
+settings.protect_status_check_matched=Comhoiriúnach
+settings.protect_invalid_status_check_pattern=Patrún seiceála stádais neamhbhailÃ: "%s".
+settings.protect_no_valid_status_check_patterns=Gan aon phatrúin seiceála stádais bailÃ.
+settings.protect_required_approvals=Ceaduithe riachtanacha:
+settings.protect_required_approvals_desc=Ná lig ach iarratas tarraingthe a chumasc le go leor ceaduithe riachtanacha. Tá ceaduithe riachtanacha ó úsáideoirà nó foirne atá ar an liosta ceadaithe nó ó aon duine a bhfuil rochtain scrÃofa acu.
+settings.protect_approvals_whitelist_enabled=Ceaduithe a theorannú le húsáideoirà nó foirne liostaithe
+settings.protect_approvals_whitelist_enabled_desc=Nà dhéanfar ach léirmheasanna ó úsáideoirà nó foirne ceadaithe a áireamh chuig na formheasanna riachtanacha. Gan liosta ceadaithe formheasa, áireofar léirmheasanna ó aon duine a bhfuil rochtain scrÃofa acu ar na ceaduithe riachtanacha.
+settings.protect_approvals_whitelist_users=Léirmheastóirà ón Liosta Ceadaithe:
+settings.protect_approvals_whitelist_teams=Foirne ar an Liosta Ceadaithe le haghaidh athbhreithnithe:
+settings.dismiss_stale_approvals=Déan seancheaduithe a dhÃbhe
+settings.dismiss_stale_approvals_desc=Nuair a bhrúitear gealltanais nua a athraÃonn ábhar an iarratais tarraingthe chuig an mbrainse, déanfar sean-cheaduithe a dhÃchur.
+settings.ignore_stale_approvals=Déan neamhaird de sheancheaduithe
+settings.ignore_stale_approvals_desc=Ná cuir faomhadh a rinneadh ar ghealltanais nÃos sine (athbhreithnithe seanchaite) san áireamh i dtreo cé mhéad faomhadh atá ag an PR. Nà bhaineann le hábhar má dhéantar athbhreithnithe seanchaite a dhÃbhe cheana féin.
+settings.require_signed_commits=Ceangaltais SÃnithe a cheangal
+settings.require_signed_commits_desc=Diúltaigh brú chuig an mbrainse seo má tá siad neamhshÃnithe nó neamh-fhÃoraithe.
+settings.protect_branch_name_pattern=Patrún Ainm Brainse Cosanta
+settings.protect_branch_name_pattern_desc=Patrúin ainmneacha brainse faoi chosaint. Féach an cháipéisÃocht le haghaidh comhréire patrún. SamplaÃ: prÃomh, scaoileadh/**
+settings.protect_patterns=Patrúin
+settings.protect_protected_file_patterns=Patrúin comhaid faoi chosaint (scartha ag baint úsáide as leathchóilÃn ';'):
+settings.protect_protected_file_patterns_desc=Nà cheadaÃtear comhaid chosanta a athrú go dÃreach fiú má tá cearta ag an úsáideoir comhaid sa bhrainse seo a chur leis, a chur in eagar nó a scriosadh. Is féidir patrúin iolracha a dheighilt trà úsáid a bhaint as leathstad (';'). Féach ar %[2]s do chomhréir phatrúin. SamplaÃ: .drone.yml
, /docs/**/*.txt
.
+settings.protect_unprotected_file_patterns=Patrúin comhaid gan chosaint (scartha ag baint úsáide as leathchóilÃn ';'):
+settings.protect_unprotected_file_patterns_desc=Comhaid gan chosaint a cheadaÃtear a athrú go dÃreach má tá rochtain scrÃofa ag an úsáideoir, ag seachaint srianadh brú. Is féidir patrúin iolracha a dheighilt trà úsáid a bhaint as leathstad (';'). Féach ar %[2]s do chomhréir phatrúin. SamplaÃ: .drone.yml
, /docs/**/*.txt
.
+settings.add_protected_branch=Cumasaigh cosaint
+settings.delete_protected_branch=DÃchumasaigh cosaint
+settings.update_protect_branch_success=Tá cosaint brainse don riail "%s" nuashonraithe.
+settings.remove_protected_branch_success=Baineadh cosaint brainse don riail "%s".
+settings.remove_protected_branch_failed=Theip ar riail cosanta brainse "%s" a bhaint.
+settings.protected_branch_deletion=Scrios Cosaint Brainse
+settings.protected_branch_deletion_desc=Ligeann cosaint brainse a dhÃchumasú d'úsáideoirà a bhfuil cead scrÃofa acu brú chuig an mbrainse. Lean ar aghaidh?
+settings.block_rejected_reviews=Cuir bac ar chumasc ar léirmheasanna diúltaithe
+settings.block_rejected_reviews_desc=Nà bheidh cumasc indéanta nuair a iarrann athbhreithnithe oifigiúla athruithe, fiú má tá go leor ceadaithe ann.
+settings.block_on_official_review_requests=Cuir bac ar chumasc ar iarratais ar athbhreithniú oifigiúil
+settings.block_on_official_review_requests_desc=Nà bheidh sé indéanta cumasc nuair a bhÃonn iarratais oifigiúla ar athbhreithniú aige, fiú má tá go leor ceadaithe ann.
+settings.block_outdated_branch=Cuir bac ar chumasc má tá an t-iarratas tarraingthe as dáta
+settings.block_outdated_branch_desc=Nà bheidh cumasc indéanta nuair a bhÃonn ceannbhrainse taobh thiar de bhronnbhrainse.
+settings.default_branch_desc=Roghnaigh brainse stóras réamhshocraithe le haghaidh iarratas tarraingte agus geallann an cód:
+settings.merge_style_desc=StÃleanna Cumaisc
+settings.default_merge_style_desc=StÃl Cumaisc Réamhshocraithe
+settings.choose_branch=Roghnaigh brainse…
+settings.no_protected_branch=NÃl aon bhrainsà cosanta ann.
+settings.edit_protected_branch=Cuir in eagar
+settings.protected_branch_required_rule_name=Ainm riail riachtanach
+settings.protected_branch_duplicate_rule_name=Ainm riail dúblach
+settings.protected_branch_required_approvals_min=Nà féidir ceaduithe riachtanacha a bheith diúltach.
+settings.tags=Clibeanna
+settings.tags.protection=Cosaint Clib
+settings.tags.protection.pattern=Patrún Clib
+settings.tags.protection.allowed=Ceadaithe
+settings.tags.protection.allowed.users=Úsáideoirà ceadaithe
+settings.tags.protection.allowed.teams=Foirne ceadaithe
+settings.tags.protection.allowed.noone=NÃl aon duine
+settings.tags.protection.create=Clib a chosaint
+settings.tags.protection.none=NÃl aon chlibeanna cosanta ann.
+settings.tags.protection.pattern.description=Is féidir leat ainm amháin nó patrún glob nó slonn rialta a úsáid chun clibeanna iolracha a mheaitseáil. Léigh tuilleadh sa treoir na gclibeanna cosanta.
+settings.bot_token=Comhartha Bota
+settings.chat_id=ID Comhrá
+settings.thread_id=ID Snáithe
+settings.matrix.homeserver_url=URL sheirbhÃse baile
+settings.matrix.room_id=ID seomra
+settings.matrix.message_type=Cineál teachtaireachta
+settings.visibility.private.button=Déan PrÃobháideach
+settings.visibility.private.text=Nà amháin go gcuirfidh an infheictheacht a athrú go prÃobháideach an repo infheicthe amháin do bhaill cheadaithe ach féadfaidh sé an gaol idir é agus forcanna, féachadóirà agus réaltaà a bhaint.
+settings.visibility.private.bullet_title=An infheictheacht a athrú go toil phrÃobháide
+settings.visibility.private.bullet_one=Déan an stóras infheicthe do chomhaltaà ceadaithe amháin.
+settings.visibility.private.bullet_two=B’fhéidir go mbainfear an gaol idir é agus forcanna, faireoirÃ, agus réaltaÃ.
+settings.visibility.public.button=Déan PoiblÃ
+settings.visibility.public.text=Má athraÃonn an infheictheacht don phobal, beidh an stóras le feiceáil do dhuine ar bith.
+settings.visibility.public.bullet_title=Athróidh an infheictheacht go poiblÃ:
+settings.visibility.public.bullet_one=Déan an repo le feiceáil do dhuine ar bith.
+settings.visibility.success=Athraigh infheictheacht stóras.
+settings.visibility.error=Tharla earráid agus tú ag iarraidh infheictheacht an stóras a athrú.
+settings.visibility.fork_error=Nà féidir infheictheacht stóras forcáilte a athrú.
+settings.archive.button=Cartlann Stóras
+settings.archive.header=Cartlann an Stóras seo
+settings.archive.text=Má dhéantar an stóras a chartlannú, beidh sé léite go hiomlán amháin. Beidh sé i bhfolach ón bpainéal. Aon duine (nà fiú tú!) beidh siad in ann tiomantas nua a dhéanamh, nó aon saincheisteanna nó iarratais a tharraingt a oscailt.
+settings.archive.success=Rinneadh an stóras a chartlannú go rathúil.
+settings.archive.error=Tharla earráid agus tú ag iarraidh an stóras a chartlannú. Féach an logáil le haghaidh tuilleadh sonraÃ.
+settings.archive.error_ismirror=Nà féidir leat stóras scátháin a chartlannú.
+settings.archive.branchsettings_unavailable=NÃl socruithe brainse ar fáil má tá an stóras i gcartlann.
+settings.archive.tagsettings_unavailable=NÃl socruithe clibeanna ar fáil má tá an stóras i gcartlann.
+settings.archive.mirrors_unavailable=NÃl scátháin ar fáil má tá an stóras i gcartlann.
+settings.unarchive.button=Stóras gan cartlann
+settings.unarchive.header=DÃchartlannaigh an stóras seo
+settings.unarchive.text=Beidh an stóras a dhÃcheangal ag athghairm a chumas chun tiomanta agus brúigh a fháil, chomh maith le fadhbanna nua agus iarratais tarraing.
+settings.unarchive.success=Rinneadh an stóras a dhÃchartlann go rathúil.
+settings.unarchive.error=Tharla earráid agus tú ag iarraidh an stóras a dhÃchartlannú. Féach an logáil le haghaidh tuilleadh sonraÃ.
+settings.update_avatar_success=NuashonraÃodh avatar an stóras.
+settings.lfs=LFS
+settings.lfs_filelist=Comhaid LFS a stóráiltear sa stóras seo
+settings.lfs_no_lfs_files=NÃl aon chomhaid LFS stóráilte sa stóras seo
+settings.lfs_findcommits=Aimsigh gealltanais
+settings.lfs_lfs_file_no_commits=NÃor aimsÃodh aon ghealltanais don chomhad LFS seo
+settings.lfs_noattribute=NÃl an tréith inghlasáilte sa bhrainse réamhshocraithe ag an gcosán seo
+settings.lfs_delete=Scrios comhad LFS le OID %s
+settings.lfs_delete_warning=D'fhéadfadh earráidà 'nÃl réad ann 'ar an tseiceáil a bheith ina chúis le comhad LFS a scriosadh. An bhfuil tú cinnte?
+settings.lfs_findpointerfiles=Faigh comhaid pointeora
+settings.lfs_locks=Glais
+settings.lfs_invalid_locking_path=Cosan neamhbhailÃ: %s
+settings.lfs_invalid_lock_directory=Nà féidir eolaire a ghlasáil: %s
+settings.lfs_lock_already_exists=Tá an glas ann cheana féin: %s
+settings.lfs_lock=Glas
+settings.lfs_lock_path=Cosán comhad le haghaidh glasáil...
+settings.lfs_locks_no_locks=Gan Glais
+settings.lfs_lock_file_no_exist=NÃl an comhad faoi ghlas sa bhrainse réamhshocraithe
+settings.lfs_force_unlock=DÃghlasáil Fórsa
+settings.lfs_pointers.found=AimsÃodh %d pointeoir(Ã) blob - %d bainteach, %d neamhghaolmhar (%d in easnamh ón siopa)
+settings.lfs_pointers.sha=SHA Blob
+settings.lfs_pointers.oid=OID
+settings.lfs_pointers.inRepo=I Stóras
+settings.lfs_pointers.exists=Ann sa siopa
+settings.lfs_pointers.accessible=Inrochtana don Úsáideoir
+settings.lfs_pointers.associateAccessible=Comhlach %d OID inrochtana
+settings.rename_branch_failed_exist=Nà féidir brainse a athainmniú toisc go bhfuil spriocbhrainse %s ann.
+settings.rename_branch_failed_not_exist=Nà féidir brainse %s a athainmniú toisc nach bhfuil sé ann.
+settings.rename_branch_success=AinmnÃodh brainse %s go rathúil go %s.
+settings.rename_branch_from=sean-ainm brainse
+settings.rename_branch_to=ainm brainse nua
+settings.rename_branch=Athainmnigh brainse
+
+diff.browse_source=Brabhsáil Foinse
+diff.parent=tuismitheoir
+diff.commit=tiomantas
+diff.git-notes=NótaÃ
+diff.data_not_available=NÃl Ãbhar DifrÃochtaà Ar Fáil
+diff.options_button=Roghanna Diff
+diff.show_diff_stats=Taispeáin StaitisticÃ
+diff.download_patch=Ãoslódáil an comhad paiste
+diff.download_diff=Ãoslódáil Comhad Diff
+diff.show_split_view=Amharc Scoilt
+diff.show_unified_view=Amharc Aontaithe
+diff.whitespace_button=Spás bán
+diff.whitespace_show_everything=Taispeáin gach athrú
+diff.whitespace_ignore_all_whitespace=Déan neamhaird de spás bán nuair a dhéantar comparáid idir lÃnte
+diff.whitespace_ignore_amount_changes=Déan neamhaird de athruithe ar an méid spás bán
+diff.whitespace_ignore_at_eol=Déan neamhaird ar athruithe ar spás bán ag EOL
+diff.stats_desc=D'athraigh %d comhad le %d breiseanna agus %d scriosta
+diff.stats_desc_file=%d athruithe: %d breiseanna agus scriosadh %d
+diff.bin=BRUSCAIR
+diff.bin_not_shown=Nà thaispeántar comhad dénártha.
+diff.view_file=Féach ar an gComhad
+diff.file_before=Roimhe
+diff.file_after=Tar éis
+diff.file_image_width=Leithead
+diff.file_image_height=Airde
+diff.file_byte_size=Méid
+diff.file_suppressed=Tá difrÃocht comhad cosc orthu toisc go bhfuil sé ró-mhór
+diff.file_suppressed_line_too_long=Cuirtear difrÃocht comhad faoi chois toisc go bhfuil lÃne amháin nó nÃos mó rófhada
+diff.too_many_files=NÃor taispeánadh roinnt comhad mar go bhfuil an iomarca comhad athraithe sa difrÃocht seo
+diff.show_more=Taispeáin Tuilleadh
+diff.load=DifrÃocht Luchtaigh
+diff.generated=a ghintear
+diff.vendored=curtha ar fáil
+diff.comment.add_line_comment=Cuir trácht lÃne leis
+diff.comment.placeholder=Fág trácht
+diff.comment.markdown_info=TacaÃtear le stÃliú le marcáil.
+diff.comment.add_single_comment=Cuir trácht aonair leis
+diff.comment.add_review_comment=Cuir trácht leis
+diff.comment.start_review=Tosaigh athbhreithniú
+diff.comment.reply=Freagra
+diff.review=Léirmheas
+diff.review.header=Cuir isteach léirmheas
+diff.review.placeholder=Trácht athbhreithnithe
+diff.review.comment=Trácht
+diff.review.approve=Ceadú
+diff.review.self_reject=Nà féidir le húdair iarratais tarraing athruithe a iarraidh ar a n-iarratas tarraingthe
+diff.review.reject=Iarr athruithe
+diff.review.self_approve=Nà féidir le húdair iarratais tarraing a n-iarratas tarraingthe féin a chead
+diff.committed_by=tiomanta ag
+diff.protected=Cosanta
+diff.image.side_by_side=Taobh le Taobh
+diff.image.swipe=Scaoil
+diff.image.overlay=Forleagan
+diff.has_escaped=Tá carachtair Unicode i bhfolach ag an lÃne seo
+diff.show_file_tree=Taispeáin crann comhad
+diff.hide_file_tree=Folaigh crann comhad
+
+releases.desc=Rian leaganacha tionscadal agus Ãoslódálacha.
+release.releases=EisiúintÃ
+release.detail=Sonraà eisithe
+release.tags=Clibeanna
+release.new_release=Scaoileadh Nua
+release.draft=Dréacht
+release.prerelease=Réamh-eisiúint
+release.stable=CobhsaÃ
+release.compare=Déan comparáid
+release.edit=cuir in eagar
+release.ahead.commits=Geallann %d
+release.ahead.target=go %s ón scaoileadh seo
+tag.ahead.target=chuig %s ón gclib seo
+release.source_code=Cód Foinse
+release.new_subheader=EagraÃonn eiseachtaà leaganacha tionscadail
+release.edit_subheader=EagraÃonn eisiúintà leaganacha tionscadal.
+release.tag_name=Ainm chlib
+release.target=Sprioc
+release.tag_helper=Roghnaigh clib atá ann cheana nó cruthaigh clib nua.
+release.tag_helper_new=Clib nua. Cruthófar an chlib seo ón sprioc.
+release.tag_helper_existing=Clib atá ann cheana.
+release.title=Teideal scaoileadh
+release.title_empty=Nà féidir leis an teideal a bheith folamh.
+release.message=Déan cur sÃos ar an eisiúint seo
+release.prerelease_desc=Marcáil mar Réamh-eisiúint
+release.prerelease_helper=Marcáil an scaoileadh seo mÃ-oiriúnach le húsáid táirgeachta.
+release.cancel=Cealaigh
+release.publish=Foilsigh Eisiúint
+release.save_draft=Sábháil Dréacht
+release.edit_release=Eisiúint Nuashonraithe
+release.delete_release=Scrios Scaoilte
+release.delete_tag=Scrios Clib
+release.deletion=Scrios Scaoilte
+release.deletion_desc=Nà bhÃonn scaoileadh ag scriosadh ach é ó Gitea. Nà dhéanfaidh sé difear do chlib Git, ar ábhar do stóras nó ar a stair. Lean ar aghaidh?
+release.deletion_success=Tá an scaoileadh scriosta.
+release.deletion_tag_desc=Scriosfar an chlib seo ón stóras. Nà athraÃtear inneachar agus stair na stórtha. Lean ort?
+release.deletion_tag_success=Tá an chlib scriosta.
+release.tag_name_already_exist=Tá eisiúint leis an ainm clib seo ann cheana féin.
+release.tag_name_invalid=NÃl ainm an chlib bailÃ.
+release.tag_name_protected=Tá ainm an chlib cosanta.
+release.tag_already_exist=Tá an t-ainm clib seo ann cheana féin.
+release.downloads=Ãoslódálacha
+release.download_count=Ãoslódálacha: %s
+release.add_tag_msg=Úsáid teideal agus ábhar an eisiúna mar theachtaireacht chlibe.
+release.add_tag=Cruthaigh Clib Amháin
+release.releases_for=Eisiúintà do %s
+release.tags_for=Clibeanna do %s
+
+branch.name=Ainm Brainse
+branch.already_exists=Tá brainse leis an ainm "%s" ann cheana féin.
+branch.delete_head=Scrios
+branch.delete=`Scrios Brainse "%s"`
+branch.delete_html=Scrios Brainse
+branch.delete_desc=Tá brainse a scriosadh buan. Cé go bhféadfadh an brainse scriosta leanúint ar aghaidh ag bheith ann ar feadh tréimhse ghearr sula mbaintear à i ndáirÃre, Nà FÉIDIR é a dhÃchur i bhformhór Lean ar aghaidh?
+branch.deletion_success=Tá brainse "%s" scriosta.
+branch.deletion_failed=Theip ar scriosadh brainse "%s".
+branch.delete_branch_has_new_commits=Nà féidir brainse “%s†a scriosadh toisc go bhfuil tiomáintà nua curtha leis tar éis a chumasc.
+branch.create_branch=Cruthaigh brainse %s
+branch.create_from=`ó "%s"`
+branch.create_success=Tá brainse "%s" cruthaithe.
+branch.branch_already_exists=Tá brainse "%s" sa stóras seo cheana.
+branch.branch_name_conflict=Tagann an t-ainm brainse "%s" leis an mbrainse "%s" atá ann cheana féin.
+branch.tag_collision=Nà féidir brainse "%s" a chruthú mar tá clib leis an ainm céanna sa stóras cheana féin.
+branch.deleted_by=Scriosta ag %s
+branch.restore_success=Tá brainse "%s" curtha ar ais.
+branch.restore_failed=Theip ar chur ar ais brainse "%s".
+branch.protected_deletion_failed=Tá brainse "%s" cosanta. Nà féidir é a scriosadh.
+branch.default_deletion_failed=Is é brainse "%s" an brainse réamhshocraithe. Nà féidir é a scriosadh.
+branch.restore=`Athchóirigh Brainse "%s"`
+branch.download=`Brainse Ãosluchtaithe "%s"`
+branch.rename=`Athainmnigh Brainse "%s"`
+branch.included_desc=Tá an brainse seo mar chuid den bhrainse réamhshocraithe
+branch.included=San áireamh
+branch.create_new_branch=Cruthaigh brainse ón mbrainse:
+branch.confirm_create_branch=Cruthaigh brainse
+branch.warning_rename_default_branch=Tá tú ag athainmniú an bhrainse réamhshocraithe.
+branch.rename_branch_to=Athainmnigh "%s" go:
+branch.confirm_rename_branch=Athainmnigh brainse
+branch.create_branch_operation=Cruthaigh brainse
+branch.new_branch=Cruthaigh brainse nua
+branch.new_branch_from=`Cruthaigh brainse nua ó "%s"`
+branch.renamed=AinmnÃodh brainse %s go %s.
+
+tag.create_tag=Cruthaigh clib %s
+tag.create_tag_operation=Cruthaigh clib
+tag.confirm_create_tag=Cruthaigh clib
+tag.create_tag_from=`Cruthaigh clib nua ó "%s"`
+
+tag.create_success=Tá clib "%s" cruthaithe.
+
+topic.manage_topics=Bainistigh topaicÃ
+topic.done=Déanta
+topic.count_prompt=Nà féidir leat nÃos mó ná 25 topaicà a roghnú
+topic.format_prompt=Nà mór do thopaicà tosú le litir nó uimhir, is féidir daiseanna ('-') agus poncanna ('.') a áireamh, a bheith suas le 35 carachtar ar fad. Nà mór litreacha a bheith i litreacha beaga.
+
+find_file.go_to_file=Téigh go dtà an comhad
+find_file.no_matching=NÃl aon chomhad meaitseála le fáil
+
+error.csv.too_large=Nà féidir an comhad seo a rinneadh toisc go bhfuil sé ró-mhór.
+error.csv.unexpected=Nà féidir an comhad seo a rindreáil toisc go bhfuil carachtar ann gan súil leis i lÃne %d agus i gcolún %d.
+error.csv.invalid_field_count=Nà féidir an comhad seo a rindreáil toisc go bhfuil lÃon mÃcheart réimsà i lÃne %d.
+error.broken_git_hook=Is cosúil go bhfuil crúcaà git den stór seo briste. Lean an doiciméadúchán chun iad a cheartú, ansin brúigh roinnt gealltanas chun an stádas a athnuachan.
+
+[graphs]
+component_loading=à lódáil %s...
+component_loading_failed=Nà fhéadfaà %s a luchtú
+component_loading_info=Seans go dtógfaidh sé seo beagán…
+component_failed_to_load=Tharla earráid gan choinne.
+code_frequency.what=minicÃocht cód
+contributors.what=rannÃocaÃochtaÃ
+recent_commits.what=tiomantáin le déanaÃ
+
+[org]
+org_name_holder=Ainm na hEagraÃochta
+org_full_name_holder=Ainm iomlán na hEagraÃochta
+org_name_helper=Ba cheart go mbeadh ainmneacha eagraÃochta gearr agus i gcuimhne.
+create_org=Cruthaigh EagraÃocht
+repo_updated=Nuashonraithe
+members=ComhaltaÃ
+teams=Foirne
+code=Cód
+lower_members=comhaltaÃ
+lower_repositories=stórais
+create_new_team=Foireann Nua
+create_team=Cruthaigh Foireann
+org_desc=Cur sÃos
+team_name=Ainm Foirne
+team_desc=Cur sÃos
+team_name_helper=Ba chóir go mbeadh ainmneacha foirne gearr agus i gcuimhne.
+team_desc_helper=Déan cur sÃos ar chuspóir nó ról na foirne.
+team_access_desc=Rochtain stórais
+team_permission_desc=Cead
+team_unit_desc=Ceadaigh Rochtain ar Rannóga Stóras
+team_unit_disabled=(DÃchumasaithe)
+
+form.name_reserved=Tá an t-ainm eagraÃochta "%s" curtha in áirithe.
+form.name_pattern_not_allowed=Nà cheadaÃtear an patrún "%s" in ainm eagraÃochta.
+form.create_org_not_allowed=NÃl cead agat eagraÃocht a chruthú.
+
+settings=Socruithe
+settings.options=EagraÃocht
+settings.full_name=Ainm Iomlán
+settings.email=RÃomhphost Teagmhála
+settings.website=Láithreán Gréasáin
+settings.location=SuÃomh
+settings.permission=Ceadanna
+settings.repoadminchangeteam=Is féidir le riarthóir an stórais rochtain d'fhoirne a chur leis agus a bhaint
+settings.visibility=Infheictheacht
+settings.visibility.public=PoiblÃ
+settings.visibility.limited=Teoranta (Infheicthe d'úsáideoirà fÃordheimhnithe amháin)
+settings.visibility.limited_shortname=Teoranta
+settings.visibility.private=PrÃobháideach (Infheicthe amháin do bhaill eagraÃochta)
+settings.visibility.private_shortname=PrÃobháideach
+
+settings.update_settings=Nuashonrú Socruithe
+settings.update_setting_success=NuashonraÃodh socruithe eagraÃochta.
+settings.change_orgname_prompt=Nóta: Athróidh ainm na heagraÃochta ag athrú URL d'eagraÃochta agus saorfar an sean-ainm.
+settings.change_orgname_redirect_prompt=Déanfaidh an sean-ainm a atreorú go dtà go n-éilÃtear é.
+settings.update_avatar_success=NuashonraÃodh avatar na heagraÃochta.
+settings.delete=Scrios EagraÃocht
+settings.delete_account=Scrios an EagraÃocht seo
+settings.delete_prompt=Bainfear an eagraÃocht go buan. Nà FÉIDIR é seo a chealú!
+settings.confirm_delete_account=Deimhnigh scriosadh
+settings.delete_org_title=Scrios EagraÃocht
+settings.delete_org_desc=Scriosfar an eagraÃocht seo go buan. Lean ar aghaidh?
+settings.hooks_desc=Cuir crúcaà gréasán in leis a spreagfar do gach stóras faoin eagraÃocht seo.
+
+settings.labels_desc=Cuir lipéid leis ar féidir iad a úsáid ar shaincheisteanna do gach stóras faoin eagraÃocht seo.
+
+members.membership_visibility=Infheictheacht BallraÃochta:
+members.public=Infheicthe
+members.public_helper=dhéanamh i bhfolach
+members.private=I bhfolach
+members.private_helper=a dhéanamh le feiceáil
+members.member_role=Ról Comhalta:
+members.owner=Úinéir
+members.member=Comhalta
+members.remove=Bain
+members.remove.detail=Bain %[1]s de %[2]s?
+members.leave=Fágáil
+members.leave.detail=Fág %s?
+members.invite_desc=Cuir ball nua le %s:
+members.invite_now=Tabhair cuireadh Anois
+
+teams.join=BÃgÃ
+teams.leave=Fág
+teams.leave.detail=Fág %s?
+teams.can_create_org_repo=Cruthaigh stórais
+teams.can_create_org_repo_helper=Is féidir le baill stóras nua a chruthú san eagraÃocht. Gheobhaidh an cruthaitheoir rochtain riarthóra ar an stóras nua.
+teams.none_access=Gan Rochtain
+teams.none_access_helper=Nà féidir le baill aon ghnÃomhaÃocht eile a fheiceáil nó a dhéanamh ar an aonad seo. NÃl aon éifeacht aige ar stórais phoiblÃ.
+teams.general_access=Rochtain Ginearálta
+teams.general_access_helper=Déanfar ceadanna baill a chinneadh ag an tábla ceadanna thÃos.
+teams.read_access=Léigh
+teams.read_access_helper=Is féidir le baill stórais foirne a fheiceáil agus a chlónáil.
+teams.write_access=ScrÃobh
+teams.write_access_helper=Is féidir le baill léamh agus brú chuig stórais foirne.
+teams.admin_access=Rochtain Riarthóra
+teams.admin_access_helper=Is féidir le baill tarraingt agus brú chuig stórais foirne agus comhoibritheoirà a chur leo.
+teams.no_desc=NÃl aon tuairisc ag an bhfoireann seo
+teams.settings=Socruithe
+teams.owners_permission_desc=Tá rochtain iomlán ag úinéirà ar gach stórais agus tá rochtain ag an riarthóir ar an eagraÃocht.
+teams.members=Baill Foirne
+teams.update_settings=Nuashonrú Socruithe
+teams.delete_team=Scrios Foireann
+teams.add_team_member=Cuir Comhalta Foirne leis
+teams.invite_team_member=Tabhair cuireadh chuig %s
+teams.invite_team_member.list=Cuirà ar Feitheamh
+teams.delete_team_title=Scrios Foireann
+teams.delete_team_desc=Cúlghairtear rochtain stórais óna baill a scriosadh foirne. Lean ar aghaidh?
+teams.delete_team_success=Tá an fhoireann scriosta.
+teams.read_permission_desc=DeonaÃonn an fhoireann seo rochtain Léamh: is féidir le baill stórtha foirne a fheiceáil agus a chlónáil.
+teams.write_permission_desc=Tugann an fhoireann seo rochtain do ScrÃobh: is féidir le baill léamh ó stórtha foirne agus iad a bhrú chucu.
+teams.admin_permission_desc=Tugann an fhoireann seo rochtain do Riarachán: is féidir le baill léamh ó stórtha foirne, brú chucu agus cur leo.
+teams.create_repo_permission_desc=Ina theannta sin, tugann an fhoireann seo cead Cruthaigh Stóras: is féidir le baill stórtha nua a chruthú san eagraÃocht.
+teams.repositories=Stórais Foirne
+teams.remove_all_repos_title=Bain gach stórais foirne
+teams.remove_all_repos_desc=Bainfidh sé seo gach stórais ón bhfoireann.
+teams.add_all_repos_title=Cuir gach stórais leis
+teams.add_all_repos_desc=Cuirfidh sé seo stórais uile na heagraÃochta leis an bhfoireann.
+teams.add_nonexistent_repo=NÃl an stóras atá tú ag iarraidh a chur leis ann, cruthaigh é ar dtús.
+teams.add_duplicate_users=Is ball foirne é an úsáideoir cheana féin.
+teams.repos.none=Nà raibh rochtain ag an bhfoireann seo ar aon stóras.
+teams.members.none=NÃl aon bhaill ar an bhfoireann seo.
+teams.members.blocked_user=Nà féidir an t-úsáideoir a chur leis toisc go bhfuil an eagraÃocht bac air.
+teams.specific_repositories=Stórais Sonrach
+teams.specific_repositories_helper=Nà bheidh rochtain ag comhaltaà ach ar stórtha a cuireadh leis an bhfoireann go sainráite. Nà bhainfear na stórtha a cuireadh leis cheana le Gach stóras go huathoibrÃoch trà é seo a roghnú.
+teams.all_repositories=Gach stórais
+teams.all_repositories_helper=Tá rochtain ag an bhfoireann ar gach stórais. Má roghnaÃonn sé seo, cuirfear na stórais go léir atá ann cheana leis an bhfoireann.
+teams.all_repositories_read_permission_desc=Tugann an fhoireann seo rochtain do Léamh ar gach stórais: is féidir le baill amharc ar stórais agus iad a chlónáil.
+teams.all_repositories_write_permission_desc=Tugann an fhoireann seo rochtain do ScrÃobh ar gach stórais: is féidir le baill léamh ó stórais agus iad a bhrú chucu.
+teams.all_repositories_admin_permission_desc=Tugann an fhoireann seo rochtain Riarthóra ar gach stóras: is féidir le comhaltaà léamh, brú a dhéanamh agus comhoibritheoirà a chur le stórtha.
+teams.invite.title=Tugadh cuireadh duit dul isteach i bhfoireann %s san eagraÃocht %s.
+teams.invite.by=Ar cuireadh ó %s
+teams.invite.description=Cliceáil ar an gcnaipe thÃos le do thoil chun dul isteach san fhoireann.
+
+[admin]
+maintenance=Cothabháil
+dashboard=Deais
+self_check=Féin-sheiceáil
+identity_access=Féiniúlacht & Rochtain
+users=Cuntais Úsáideora
+organizations=EagraÃochtaÃ
+assets=Sócmhainnà Cód
+repositories=Stórais
+hooks=Crúcaà Gréasán
+integrations=Comhtháthaithe
+authentication=Foinsà FÃordheimhnithe
+emails=RÃomhphoist ÚsáideoirÃ
+config=CumraÃocht
+config_summary=Achoimre
+config_settings=Socruithe
+notices=Fógraà Córais
+monitor=Monatóireacht
+first_page=Ar dtús
+last_page=Deiridh
+total=Iomlán: %d
+settings=Socruithe Riaracháin
+
+dashboard.new_version_hint=Tá Gitea %s ar fáil anois, tá %s á rith agat. Seiceáil an blag le haghaidh tuilleadh sonraÃ.
+dashboard.statistic=Achoimre
+dashboard.maintenance_operations=OibrÃochtaà Cothabháil
+dashboard.system_status=Stádas an Chórais
+dashboard.operation_name=Ainm OibrÃochta
+dashboard.operation_switch=Athraigh
+dashboard.operation_run=Rith
+dashboard.clean_unbind_oauth=Glan naisc OAuth neamhcheangailte
+dashboard.clean_unbind_oauth_success=Scriosadh gach nasc OAuth neamhcheangailte.
+dashboard.task.started=Tasc Tosaigh: %[1]s
+dashboard.task.process=Tasc: %[1]s
+dashboard.task.cancelled=Tasc: %[1]s cealaithe: %[3]s
+dashboard.task.error=Earráid sa Tasc: %[1]s: %[3]s
+dashboard.task.finished=Tasc: Tá %[1]s tosaithe ag %[2]s crÃochnaithe
+dashboard.task.unknown=Tasc anaithnid: %[1]s
+dashboard.cron.started=Cron tosaithe: %[1]s
+dashboard.cron.process=Cron: %[1]s
+dashboard.cron.cancelled=Cron: %[1]s cealaithe: %[3]s
+dashboard.cron.error=Earráid i gCron: %s: %[3]s
+dashboard.cron.finished=Cron: %[1]s crÃochnaithe
+dashboard.delete_inactive_accounts=Scrios gach cuntas neamhghnÃomhach
+dashboard.delete_inactive_accounts.started=Tasc scriostha gach cuntas neamhghnÃomhachtaithe tosaithe.
+dashboard.delete_repo_archives=Scrios gach cartlann stórais (ZIP, TAR.GZ, srl.)
+dashboard.delete_repo_archives.started=Scrios gach tasc cartlann stórais a thosaigh.
+dashboard.delete_missing_repos=Scrios gach stóras atá in easnamh ar a gcuid comhad Git
+dashboard.delete_missing_repos.started=Scrios gach stóras atá in easnamh ar a dtasc comhaid Git a thosaigh.
+dashboard.delete_generated_repository_avatars=Scrios abhatáranna stórtha ginte
+dashboard.sync_repo_branches=Sync brainsà caillte ó shonraà git go bunachair sonraÃ
+dashboard.sync_repo_tags=Clibeanna sioncraigh ó shonraà git go bunachar sonraÃ
+dashboard.update_mirrors=Scátháin a nuashonrú
+dashboard.sync_repo_licenses=Sioncronaigh ceadúnais repo
+
+users.full_name=Ainm Iomlán
+users.list_status_filter.is_active=GnÃomhach
+
+
+orgs.teams=Foirne
+
+repos.owner=Úinéir
+
+packages.owner=Úinéir
+
+defaulthooks=Réamhshocraithe Crúcaà Gréasán
+defaulthooks.desc=Déanann Crúcaà Gréasán iarratais HTTP POST go huathoibrÃoch chuig freastalaà nuair a chuireann imeachtaà áirithe Gitea tús. Is mainneachtainà iad na cuacha gréasáin a shainÃtear anseo agus déanfar iad a chóipeáil isteach i ngach stórais nua. Léigh tuilleadh sa treoir chúca Crúcaà Gréasán.
+defaulthooks.add_webhook=Cuir Crúca Gréasán Réamhshocraithe leis
+defaulthooks.update_webhook=Nuashonraigh Réamhshocrú Crúca Gréasán
+
+systemhooks=Córas Crúcaà Gréasán
+systemhooks.desc=Déanann Crúcaà Gréasán iarratais HTTP POST go huathoibrÃoch chuig freastalaà nuair a chuireann imeachtaà áirithe Gitea tús. GnÃomhóidh na Crúcaà Gréasán atá sainithe anseo ar gach stóras ar an gcóras, mar sin déan machnamh ar aon impleachtaà feidhmÃochta a d’fhéadfadh a bheith aige seo. Léigh tuilleadh sa treoir chúca gréasáin.
+systemhooks.add_webhook=Cuir Crúca Gréasán Córas leis
+systemhooks.update_webhook=Nuashonraigh Córas Crúca Gréasán
+
+auths.updated=Nuashonraithe
+auths.domain=Fearann
+
+
+
+
+
+
+config.webhook_config=CumraÃocht Crúca Gréasán
+
+
+
+
+
+
+
+
+
+
+monitor.desc=Cur sÃos
+
+monitor.queue.settings.submit=Nuashonrú Socruithe
+
+notices.system_notice_list=Fógraà Córais
+notices.operations=OibrÃochtaÃ
+notices.desc=Cur sÃos
+
+
+[action]
+
+[tool]
+
+[dropzone]
+
+[notification]
+
+[gpg]
+
+[units]
+
+[packages]
+alpine.repository.branches=BrainsÃ
+alpine.repository.repositories=Stórais
+
+[secrets]
+
+[actions]
+
+
+
+runners.description=Cur sÃos
+runners.task_list.run=Rith
+runners.task_list.commit=Tiomantas
+runners.status.active=GnÃomhach
+runners.reset_registration_token=Athshocraigh comhartha clár
+runners.reset_registration_token_success=D'éirigh le hathshocrú comhartha clárúcháin an dara háit
+
+runs.all_workflows=Gach Sreafaà Oibre
+runs.commit=Tiomantas
+runs.scheduled=Sceidealaithe
+runs.pushed_by=bhrú ag
+runs.invalid_workflow_helper=Tá comhad cumraÃochta sreabhadh oibre nebhailÃ. Seiceáil do chomhad cumraithe le do thoil: %s
+
+
+
+
+[projects]
+type-3.display_name=Tionscadal Eagrúcháin
+
+[git.filemode]
+changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
+directory=Eolaire
+normal_file=Comhad gnáth
+executable_file=Comhad infheidhmithe
+symbolic_link=Nasc siombalach
+submodule=Fo-mhodúl
+
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index 6f057dc4c8..69f0e6eab7 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -397,7 +397,6 @@ account_link=Kapcsolt fiókok
organization=Szervezetek
public_profile=Nyilvános profil
-password_username_disabled=A nem helyi felhasználóknak nem engedélyezett, hogy megváltoztassák a felhasználói nevüket. Kérjük lépjen kapcsolatba a helyi rendszergazdájával további információkért.
full_name=Teljes név
website=Webhely
location=Hely
@@ -901,13 +900,13 @@ issues.dependency.add_error_dep_issue_not_exist=Függő hibajegy nem létezik.
issues.dependency.add_error_dep_not_exist=A függőség nem létezik.
issues.dependency.add_error_dep_exists=A függőség már létezik.
issues.dependency.add_error_dep_not_same_repo=Mindkét hibajegynek ugyanabban a tárolóban kell lennie.
-issues.review.comment=Hozzászólás
issues.review.reject=%s változtatások kérése
issues.review.pending=Függőben
issues.review.review=Értékelés
issues.review.reviewers=Véleményezők
issues.review.show_outdated=Elavultak mutatása
issues.review.hide_outdated=Elavultak elrejtése
+issues.review.commented=Hozzászólás
issues.assignee.error=Nem minden megbÃzott lett hozzáadva egy nem várt hiba miatt.
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index 94c60979a8..d1b4166e16 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -317,7 +317,6 @@ account_link=Akun Tertaut
organization=Organisasi
public_profile=Profil Publik
-password_username_disabled=Pengguna non-lokal tidak diizinkan untuk mengubah nama pengguna mereka. Silakan hubungi administrator sistem anda untuk lebih lanjut.
full_name=Nama Lengkap
website=Situs Web
location=Lokasi
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 01219b16c4..0bd4ba6894 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -129,8 +129,6 @@ filter.public=Opinbert
[error]
occurred=Villa kom upp
-missing_csrf=Slæm beiðni: enginn CSRF lykill
-invalid_csrf=Slæm beiðni: ógildur CSRF lykill
not_found=Markmiðið fannst ekki.
network_error=Netkerfisvilla
@@ -430,7 +428,6 @@ account_link=Tengdir Reikningar
organization=Stofnanir
public_profile=Opinber NotandasÃða
-password_username_disabled=Notendum utan staðarins er ekki heimilt að breyta notendanafni sÃnu. Vinsamlegast hafðu samband við sÃðustjórann þinn til að fá frekari upplýsingar.
full_name=Fullt Nafn
website=VefsÃða
location=Staðsetning
@@ -850,13 +847,13 @@ issues.dependency.remove_header=Fjarlægja Kröfu
issues.dependency.add_error_dep_not_exist=Krafa er ekki til.
issues.dependency.add_error_dep_exists=Krafa er nú þegar til.
issues.review.approve=samþykkti þessar breytingar %s
-issues.review.comment=Senda Ummæli
issues.review.dismissed_label=Hunsað
issues.review.left_comment=gerði ummæli
issues.review.pending=à bið
issues.review.outdated=Úrelt
issues.review.show_outdated=Sýna úrelt
issues.review.hide_outdated=Fela úreld
+issues.review.commented=Senda Ummæli
issues.reference_issue.body=Meginmál
issues.content_history.deleted=eytt
issues.content_history.edited=breytt
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index 1f7fe7939c..d82215622f 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -135,8 +135,6 @@ filter.private=Privati
[error]
occurred=Si è verificato un errore
-missing_csrf=Richiesta errata: nessun token CSRF presente
-invalid_csrf=Richiesta errata: token CSRF non valido
not_found=Il bersaglio non è stato trovato.
network_error=Errore di rete
@@ -518,7 +516,6 @@ account_link=Account collegati
organization=Organizzazioni
public_profile=Profilo pubblico
-password_username_disabled=Gli utenti non locali non hanno il permesso di cambiare il proprio nome utente. per maggiori dettagli si prega di contattare l'amministratore del sito.
full_name=Nome Completo
website=Sito web
location=Posizione
@@ -1331,7 +1328,6 @@ issues.dependency.add_error_dep_not_same_repo=Entrambi i problemi devono essere
issues.review.self.approval=Non puoi approvare la tua pull request.
issues.review.self.rejection=Non puoi richiedere modifiche sulla tua pull request.
issues.review.approve=hanno approvato queste modifiche %s
-issues.review.comment=Commentare
issues.review.dismissed=recensione %s di %s respinta
issues.review.dismissed_label=Respinta
issues.review.left_comment=lascia un commento
@@ -1352,6 +1348,7 @@ issues.review.hide_resolved=Nascondi risolte
issues.review.resolve_conversation=Risolvi la conversazione
issues.review.un_resolve_conversation=Segnala la conversazione come non risolta
issues.review.resolved_by=ha contrassegnato questa conversazione come risolta
+issues.review.commented=Commentare
issues.assignee.error=Non tutte le assegnazioni sono state aggiunte a causa di un errore imprevisto.
issues.reference_issue.body=Corpo
issues.content_history.deleted=eliminato
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index ea5a95c6a1..973c1b3761 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -159,6 +159,7 @@ filter.public=公開
filter.private=プライベート
no_results_found=見ã¤ã‹ã‚Šã¾ã›ã‚“。
+internal_error_skipped=内部エラーãŒç™ºç”Ÿã—ã¾ã—ãŸãŒã‚¹ã‚ップã•ã‚Œã¾ã—ãŸ: %s
[search]
search=検索…
@@ -177,6 +178,8 @@ code_search_by_git_grep=ç¾åœ¨ã®ã‚³ãƒ¼ãƒ‰æ¤œç´¢ã¯ "git grep" ã«ã‚ˆã£ã¦è¡Œ
package_kind=パッケージを検索...
project_kind=プãƒã‚¸ã‚§ã‚¯ãƒˆã‚’検索...
branch_kind=ブランãƒã‚’検索...
+tag_kind=タグを検索...
+tag_tooltip=一致ã™ã‚‹ã‚¿ã‚°ã‚’検索ã—ã¾ã™ã€‚ä»»æ„ã®ã‚·ãƒ¼ã‚±ãƒ³ã‚¹ã«ä¸€è‡´ã•ã›ã‚‹ã«ã¯ '%' を使用ã—ã¦ãã ã•ã„。
commit_kind=コミットを検索...
runner_kind=ランナーを検索...
no_results=一致ã™ã‚‹çµæžœãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ
@@ -218,18 +221,20 @@ string.desc=Z - A
[error]
occurred=エラーãŒç™ºç”Ÿã—ã¾ã—ãŸ
-missing_csrf=ä¸æ£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ: CSRFトークンãŒã‚ã‚Šã¾ã›ã‚“
-invalid_csrf=ä¸æ£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ: CSRFトークンãŒç„¡åŠ¹ã§ã™
+report_message=Gitea ã®ãƒã‚°ãŒç–‘ã‚ã‚Œã‚‹å ´åˆã¯ã€GitHubã§Issueを検索ã—ã¦ã€è¦‹ã¤ã‹ã‚‰ãªã‘ã‚Œã°æ–°ã—ã„Issueを作æˆã—ã¦ãã ã•ã„。
not_found=ターゲットãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚
network_error=ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¨ãƒ©ãƒ¼
[startpage]
app_desc=自分ã§ç«‹ã¦ã‚‹ã€è¶…ç°¡å˜ Git サービス
install=ç°¡å˜ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«
+install_desc=シンプルã«ã€ãƒ—ラットフォームã«å¿œã˜ã¦ãƒã‚¤ãƒŠãƒªã‚’実行ã—ãŸã‚Šã€Dockerã§å‹•ã‹ã—ãŸã‚Šã€ãƒ‘ッケージを使ã†ã ã‘。
platform=クãƒã‚¹ãƒ—ラットフォーãƒ
+platform_desc=Giteaã¯GoãŒã‚³ãƒ³ãƒ‘イルå¯èƒ½ãªã‚らゆる環境ã§å‹•ãã¾ã™: Windowsã€macOSã€Linuxã€ARMãªã©ã€‚ ã‚ãªãŸã®å¥½ããªã‚‚ã®ã‚’é¸ã‚“ã§ãã ã•ã„!
lightweight=軽é‡
lightweight_desc=Gitea ã®æœ€å°å‹•ä½œè¦ä»¶ã¯å°ã•ã„ãŸã‚ã€å®‰ä¾¡ãª Raspberry Pi ã§ã‚‚å‹•ãã¾ã™ã€‚エãƒãƒ«ã‚®ãƒ¼ã‚’節約ã—ã¾ã—ょã†!
license=オープンソース
+license_desc=Go get %[2]s! ã“ã®ãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆã‚’ã•ã‚‰ã«å‘上ã•ã›ã‚‹ãŸã‚ã€ãœã²è²¢çŒ®ã—ã¦å‚åŠ ã—ã¦ãã ã•ã„。 貢献者ã«ãªã‚‹ã“ã¨ã‚’æ¥ãšã‹ã—ãŒã‚‰ãªã„ã§!
[install]
install=インストール
@@ -452,6 +457,7 @@ authorize_title=`"%s"ã«ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯
authorization_failed=èªå¯å¤±æ•—
authorization_failed_desc=無効ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’検出ã—ãŸãŸã‚èªå¯ãŒå¤±æ•—ã—ã¾ã—ãŸã€‚ èªå¯ã—よã†ã¨ã—ãŸã‚¢ãƒ—リã®é–‹ç™ºè€…ã«é€£çµ¡ã—ã¦ãã ã•ã„。
sspi_auth_failed=SSPIèªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸ
+password_pwned=ã‚ãªãŸãŒé¸æŠžã—ãŸãƒ‘スワードã¯ã€éŽåŽ»ã®æƒ…å ±æ¼æ´©äº‹ä»¶ã§æµå‡ºã—ãŸç›—ã¾ã‚ŒãŸãƒ‘スワードã®ãƒªã‚¹ãƒˆã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚ 別ã®ãƒ‘スワードã§ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ãã ã•ã„。 ã¾ãŸä»–ã®ç™»éŒ²ã§ã‚‚ã“ã®ãƒ‘スワードã‹ã‚‰ã®å¤‰æ›´ã‚’検討ã—ã¦ãã ã•ã„。
password_pwned_err=HaveIBeenPwnedã¸ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’完了ã§ãã¾ã›ã‚“ã§ã—ãŸ
last_admin=最後ã®ç®¡ç†è€…ã¯å‰Šé™¤ã§ãã¾ã›ã‚“。少ãªãã¨ã‚‚一人ã®ç®¡ç†è€…ãŒå¿…è¦ã§ã™ã€‚
signin_passkey=パスã‚ーã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³
@@ -699,7 +705,6 @@ public_profile=公開プãƒãƒ•ã‚£ãƒ¼ãƒ«
biography_placeholder=自己紹介ã—ã¦ãã ã•ã„ï¼(Markdownを使ã†ã“ã¨ãŒã§ãã¾ã™)
location_placeholder=ãŠãŠã‚ˆãã®å ´æ‰€ã‚’ä»–ã®äººã¨å…±æœ‰
profile_desc=ã‚ãªãŸã®ãƒ—ãƒãƒ•ã‚£ãƒ¼ãƒ«ãŒä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã©ã®ã‚ˆã†ã«è¡¨ç¤ºã•ã‚Œã‚‹ã‹ã‚’制御ã—ã¾ã™ã€‚ã‚ãªãŸã®ãƒ—ライマリメールアドレスã¯ã€é€šçŸ¥ã€ãƒ‘スワードã®å›žå¾©ã€Webベースã®Gitæ“作ã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚
-password_username_disabled=éžãƒãƒ¼ã‚«ãƒ«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼åã¯å¤‰æ›´ã§ãã¾ã›ã‚“。詳細ã¯ã‚µã‚¤ãƒˆç®¡ç†è€…ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。
full_name=フルãƒãƒ¼ãƒ
website=Webサイト
location=å ´æ‰€
@@ -921,6 +926,7 @@ oauth2_client_secret_hint=ã“ã®ãƒšãƒ¼ã‚¸ã‹ã‚‰ç§»å‹•ã—ãŸã‚Šãƒšãƒ¼ã‚¸ã‚’æ›´æ–°
oauth2_application_edit=編集
oauth2_application_create_description=OAuth2アプリケーションã§ã€ã‚µãƒ¼ãƒ‰ãƒ‘ーティアプリケーションãŒã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ä¸Šã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚
oauth2_application_remove_description=OAuth2アプリケーションを削除ã™ã‚‹ã¨ã€ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ä¸Šã®è¨±å¯ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒã§ããªããªã‚Šã¾ã™ã€‚ 続行ã—ã¾ã™ã‹ï¼Ÿ
+oauth2_application_locked=è¨å®šã§æœ‰åŠ¹ã«ã•ã‚ŒãŸå ´åˆã€Giteaã¯èµ·å‹•æ™‚ã«ã„ãã¤ã‹ã®OAuth2アプリケーションを事å‰ç™»éŒ²ã—ã¾ã™ã€‚ 想定ã•ã‚Œã¦ã„ãªã„動作を防ããŸã‚ã€ã“れらã¯ç·¨é›†ã‚‚削除もã§ãã¾ã›ã‚“。 詳細ã«ã¤ã„ã¦ã¯OAuth2ã®ãƒ‰ã‚ュメントをå‚ç…§ã—ã¦ãã ã•ã„。
authorized_oauth2_applications=許å¯æ¸ˆã¿OAuth2アプリケーション
authorized_oauth2_applications_description=ã“れらã®ã‚µãƒ¼ãƒ‰ãƒ‘ーティ アプリケーションã«ã€ã‚ãªãŸã®Giteaアカウントã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã—ã¦ã„ã¾ã™ã€‚ ä¸è¦ã«ãªã£ãŸã‚¢ãƒ—リケーションã¯ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’å–り消ã™ã‚ˆã†ã«ã—ã¦ãã ã•ã„。
@@ -948,6 +954,7 @@ passcode_invalid=パスコードãŒé–“é•ã£ã¦ã„ã¾ã™ã€‚ å†åº¦ãŠè©¦ã—ã
twofa_enrolled=ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯æ£å¸¸ã«ç™»éŒ²ã•ã‚Œã¾ã—ãŸã€‚ 一回é™ã‚Šã®ãƒªã‚«ãƒãƒªã‚ー (%s) ã¯å®‰å…¨ãªå ´æ‰€ã«ä¿å˜ã—ã¦ãã ã•ã„。 ã“ã‚Œã¯äºŒåº¦ã¨è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。
twofa_failed_get_secret=シークレットãŒå–å¾—ã§ãã¾ã›ã‚“。
+webauthn_desc=ã‚»ã‚ュリティã‚ーã¯æš—å·åŒ–ã‚ーを内蔵ã™ã‚‹ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ ・ デãƒã‚¤ã‚¹ã§ã™ã€‚ 2è¦ç´ èªè¨¼ã«ä½¿ç”¨ã§ãã¾ã™ã€‚ ã‚»ã‚ュリティã‚ーã¯WebAuthn Authenticatorè¦æ ¼ã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
webauthn_register_key=ã‚»ã‚ュリティã‚ーを追åŠ
webauthn_nickname=ニックãƒãƒ¼ãƒ
webauthn_delete_key=ã‚»ã‚ュリティã‚ーã®ç™»éŒ²è§£é™¤
@@ -969,7 +976,7 @@ orgs_none=ã‚ãªãŸã¯ã©ã®çµ„ç¹”ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã‚‚ã‚ã‚Šã¾ã›ã‚“。
repos_none=ã‚ãªãŸã¯ãƒªãƒã‚¸ãƒˆãƒªã‚’所有ã—ã¦ã„ã¾ã›ã‚“。
delete_account=アカウントを削除
-delete_prompt=ã“ã®æ“作ã«ã‚ˆã‚Šã€ã‚ãªãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯æ’ä¹…çš„ã«æŠ¹æ¶ˆã•ã‚Œã¾ã™ã€‚ å–り消ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。
+delete_prompt=ã“ã®æ“作ã«ã‚ˆã‚Šã€ã‚ãªãŸã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯æ’ä¹…çš„ã«æŠ¹æ¶ˆã•ã‚Œã¾ã™ã€‚ å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。
delete_with_all_comments=ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯ä½œæˆã‹ã‚‰ã¾ã %s 経éŽã—ã¦ã„ã¾ã›ã‚“。 幽霊コメント回é¿ã®ãŸã‚ã€ã‚¤ã‚·ãƒ¥ãƒ¼ã‚„PRã®ã™ã¹ã¦ã®ã‚³ãƒ¡ãƒ³ãƒˆã¯ä¸€ç·’ã«å‰Šé™¤ã•ã‚Œã¾ã™ã€‚
confirm_delete_account=削除ã®ç¶šè¡Œ
delete_account_title=ユーザーアカウントã®å‰Šé™¤
@@ -1032,6 +1039,7 @@ issue_labels_helper=イシューã®ãƒ©ãƒ™ãƒ«ã‚»ãƒƒãƒˆã‚’é¸æŠž
license=ライセンス
license_helper=ライセンス ファイルをé¸æŠžã—ã¦ãã ã•ã„。
license_helper_desc=ライセンスã«ã‚ˆã‚Šã€ä»–人ãŒã‚ãªãŸã®ã‚³ãƒ¼ãƒ‰ã«å¯¾ã—ã¦ä½•ãŒã§ãã¦ä½•ãŒã§ããªã„ã®ã‹ã‚’è¦å®šã—ã¾ã™ã€‚ ã©ã‚ŒãŒãƒ—ãƒã‚¸ã‚§ã‚¯ãƒˆã«ãµã•ã‚ã—ã„ã‹è¿·ã£ã¦ã„ã¾ã™ã‹ï¼Ÿ ライセンスé¸æŠžã‚µã‚¤ãƒˆ も確èªã—ã¦ã¿ã¦ãã ã•ã„。
+multiple_licenses=複数ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹
object_format=オブジェクトã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆ
object_format_helper=リãƒã‚¸ãƒˆãƒªã®ã‚ªãƒ–ジェクトフォーマット。後ã§å¤‰æ›´ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。SHA1 ã¯æœ€ã‚‚互æ›æ€§ãŒã‚ã‚Šã¾ã™ã€‚
readme=README
@@ -1092,7 +1100,9 @@ tree_path_not_found_branch=パス %[1]s ã¯ãƒ–ランム%[2]s ã«å˜åœ¨ã—ã¾ã›
tree_path_not_found_tag=パス %[1]s ã¯ã‚¿ã‚° %[2]s ã«å˜åœ¨ã—ã¾ã›ã‚“
transfer.accept=移転を承èª
+transfer.accept_desc=`"%s" ã«ç§»è»¢`
transfer.reject=移転を拒å¦
+transfer.reject_desc=`"%s" ã¸ã®ç§»è»¢ã‚’ã‚ャンセル`
transfer.no_permission_to_accept=ã“ã®ç§»è»¢ã‚’承èªã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。
transfer.no_permission_to_reject=ã“ã®ç§»è»¢ã‚’æ‹’å¦ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。
@@ -1167,6 +1177,11 @@ migrate.gogs.description=notabug.org ã‚„ãã®ä»–ã® Gogs インスタンスã‹
migrate.onedev.description=code.onedev.io ã‚„ãã®ä»–ã® OneDev インスタンスã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’移行ã—ã¾ã™ã€‚
migrate.codebase.description=codebasehq.com ã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’移行ã—ã¾ã™ã€‚
migrate.gitbucket.description=GitBucket インスタンスã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’移行ã—ã¾ã™ã€‚
+migrate.codecommit.description=AWS CodeCommitã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’移行ã—ã¾ã™ã€‚
+migrate.codecommit.aws_access_key_id=AWS アクセスã‚ー ID
+migrate.codecommit.aws_secret_access_key=AWSシークレットアクセスã‚ー
+migrate.codecommit.https_git_credentials_username=HTTPS Git èªè¨¼æƒ…å ± ユーザーå
+migrate.codecommit.https_git_credentials_password=HTTPS Git èªè¨¼æƒ…å ± パスワード
migrate.migrating_git=Gitデータ移行ä¸
migrate.migrating_topics=トピック移行ä¸
migrate.migrating_milestones=マイルストーン移行ä¸
@@ -1227,6 +1242,7 @@ releases=リリース
tag=ã‚¿ã‚°
released_this=ãŒã“れをリリース
tagged_this=ãŒã‚¿ã‚°ä»˜ã‘
+file.title=%s at %s
file_raw=Raw
file_history=å±¥æ´
file_view_source=ソースを表示
@@ -1243,6 +1259,7 @@ ambiguous_runes_header=ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«ã¯æ›–昧(ambiguous)ãªUnicodeæ–‡å—
ambiguous_runes_description=ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«ã¯ã€ä»–ã®æ–‡å—ã¨è¦‹é–“é•ãˆã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹Unicodeæ–‡å—ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚ ãã‚ŒãŒæ„図的ãªã‚‚ã®ã¨è€ƒãˆã‚‰ã‚Œã‚‹å ´åˆã¯ã€ã“ã®è¦å‘Šã‚’無視ã—ã¦æ§‹ã„ã¾ã›ã‚“。 ãれらã®æ–‡å—を表示ã™ã‚‹ã«ã¯ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ボタンを使用ã—ã¾ã™ã€‚
invisible_runes_line=`ã“ã®è¡Œã«ã¯ä¸å¯è¦–ã®Unicodeæ–‡å—ãŒã‚ã‚Šã¾ã™`
ambiguous_runes_line=`ã“ã®è¡Œã«ã¯æ›–昧(ambiguous)ãªUnicodeæ–‡å—ãŒã‚ã‚Šã¾ã™`
+ambiguous_character=`%[1]c [U+%04[1]X] 㯠%[2]c [U+%04[2]X] ã¨æ··åŒã™ã‚‹ãŠãã‚ŒãŒã‚ã‚Šã¾ã™`
escape_control_characters=エスケープ
unescape_control_characters=エスケープ解除
@@ -1263,7 +1280,6 @@ commit_graph.color=カラー
commit.contained_in=ã“ã®ã‚³ãƒŸãƒƒãƒˆãŒå«ã¾ã‚Œã¦ã„ã‚‹ã®ã¯:
commit.contained_in_default_branch=ã“ã®ã‚³ãƒŸãƒƒãƒˆã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒ–ランãƒã«å«ã¾ã‚Œã¦ã„ã¾ã™
commit.load_referencing_branches_and_tags=ã“ã®ã‚³ãƒŸãƒƒãƒˆã‚’å‚ç…§ã—ã¦ã„るブランãƒã‚„ã‚¿ã‚°ã‚’å–å¾—
-commit.load_tags_failed=内部エラーã«ã‚ˆã‚Šã‚¿ã‚°ã®èªã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ
blame=Blame
download_file=ファイルをダウンãƒãƒ¼ãƒ‰
normal_view=通常表示
@@ -1715,7 +1731,7 @@ issues.dependency.add_error_dep_not_same_repo=両方ã¨ã‚‚åŒã˜ãƒªãƒã‚¸ãƒˆãƒª
issues.review.self.approval=自分ã®ãƒ—ルリクエストを承èªã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
issues.review.self.rejection=自分ã®ãƒ—ルリクエストã«å¯¾ã—ã¦ä¿®æ£ã‚’è¦æ±‚ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
issues.review.approve=ãŒå¤‰æ›´ã‚’æ‰¿èª %s
-issues.review.comment=コメント
+issues.review.comment=ãŒãƒ¬ãƒ“ュー %s
issues.review.dismissed=㌠%s ã®ãƒ¬ãƒ“ãƒ¥ãƒ¼ã‚’æ£„å´ %s
issues.review.dismissed_label=棄å´
issues.review.left_comment=ãŒã‚³ãƒ¡ãƒ³ãƒˆ
@@ -1740,6 +1756,12 @@ issues.review.hide_resolved=解決済ã¿ã‚’éš ã™
issues.review.resolve_conversation=解決済ã¿ã«ã™ã‚‹
issues.review.un_resolve_conversation=未解決ã«ã™ã‚‹
issues.review.resolved_by=ãŒã“ã®ä¼šè©±ã‚’解決済ã¿ã«ã—ã¾ã—ãŸ
+issues.review.commented=コメント
+issues.review.official=承èªæ¸ˆã¿
+issues.review.requested=レビュー待ã¡
+issues.review.rejected=変更è¦è«‹æ¸ˆã¿
+issues.review.stale=承èªå¾Œã«æ›´æ–°ã•ã‚Œã¾ã—ãŸ
+issues.review.unofficial=カウントã•ã‚Œãªã„承èª
issues.assignee.error=予期ã—ãªã„エラーã«ã‚ˆã‚Šã€ä¸€éƒ¨ã®æ‹…å½“è€…ã‚’è¿½åŠ ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚
issues.reference_issue.body=内容
issues.content_history.deleted=削除ã—ã¾ã—ãŸ
@@ -1813,6 +1835,8 @@ pulls.is_empty=ã“ã®ãƒ–ランãƒã®å¤‰æ›´ã¯æ—¢ã«ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ–ランãƒ
pulls.required_status_check_failed=ã„ãã¤ã‹ã®å¿…è¦ãªã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒã‚§ãƒƒã‚¯ãŒæˆåŠŸã—ã¦ã„ã¾ã›ã‚“。
pulls.required_status_check_missing=å¿…è¦ãªãƒã‚§ãƒƒã‚¯ãŒã„ãã¤ã‹æŠœã‘ã¦ã„ã¾ã™ã€‚
pulls.required_status_check_administrator=管ç†è€…ã§ã‚ã‚‹ãŸã‚ã€ã“ã®ãƒ—ルリクエストをマージã™ã‚‹ã“ã¨ã¯å¯èƒ½ã§ã™ã€‚
+pulls.blocked_by_approvals=ã“ã®ãƒ—ルリクエストã¯ã¾ã å¿…è¦ãªæ‰¿èªæ•°ã‚’満ãŸã—ã¦ã„ã¾ã›ã‚“。 å…¬å¼ã®æ‰¿èªã‚’ %[1]d / %[2]d å¾—ã¦ã„ã¾ã™ã€‚
+pulls.blocked_by_approvals_whitelisted=ã“ã®ãƒ—ルリクエストã¯ã¾ã å¿…è¦ãªæ‰¿èªæ•°ã‚’満ãŸã—ã¦ã„ã¾ã›ã‚“。 許å¯ãƒªã‚¹ãƒˆã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¾ãŸã¯ãƒãƒ¼ãƒ ã‹ã‚‰ã®æ‰¿èªã‚’ %[1]d / %[2]d å¾—ã¦ã„ã¾ã™ã€‚
pulls.blocked_by_rejection=ã“ã®ãƒ—ルリクエストã¯å…¬å¼ãƒ¬ãƒ“ューアã«ã‚ˆã‚Šå¤‰æ›´è¦è«‹ã•ã‚Œã¦ã„ã¾ã™ã€‚
pulls.blocked_by_official_review_requests=ã“ã®ãƒ—ルリクエストã«ã¯å…¬å¼ãƒ¬ãƒ“ューä¾é ¼ãŒã‚ã‚Šã¾ã™ã€‚
pulls.blocked_by_outdated_branch=ã“ã®ãƒ—ルリクエストã¯é…ã‚Œã®ãŸã‚ブãƒãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™ã€‚
@@ -1854,7 +1878,9 @@ pulls.unrelated_histories=マージ失敗: マージHEADã¨ãƒ™ãƒ¼ã‚¹ã«ã¯å…±é€š
pulls.merge_out_of_date=マージ失敗: マージã®ç”Ÿæˆä¸ã«ãƒ™ãƒ¼ã‚¹ãŒæ›´æ–°ã•ã‚Œã¾ã—ãŸã€‚ ヒント: ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ã¿ã¦ãã ã•ã„
pulls.head_out_of_date=マージ失敗: マージã®ç”Ÿæˆä¸ã« head ãŒæ›´æ–°ã•ã‚Œã¾ã—ãŸã€‚ ヒント: ã‚‚ã†ä¸€åº¦è©¦ã—ã¦ã¿ã¦ãã ã•ã„
pulls.has_merged=失敗: プルリクエストã¯ãƒžãƒ¼ã‚¸ã•ã‚Œã¦ã„ã¾ã—ãŸã€‚å†åº¦ãƒžãƒ¼ã‚¸ã—ãŸã‚Šã€ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ–ランãƒã‚’変更ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。
+pulls.push_rejected=プッシュ失敗: プッシュã¯æ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚ ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã®Gitフックを見直ã—ã¦ãã ã•ã„。
pulls.push_rejected_summary=æ‹’å¦ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸å…¨ä½“:
+pulls.push_rejected_no_message=プッシュ失敗: プッシュã¯æ‹’å¦ã•ã‚Œã¾ã—ãŸãŒã€ãƒªãƒ¢ãƒ¼ãƒˆã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒã‚ã‚Šã¾ã›ã‚“。ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã®Gitフックを見直ã—ã¦ãã ã•ã„
pulls.open_unmerged_pull_exists=`åŒã˜æ¡ä»¶ã®ãƒ—ルリクエスト (#%d) ãŒæœªå‡¦ç†ã®ãŸã‚ã€å†ã‚ªãƒ¼ãƒ—ンã¯ã§ãã¾ã›ã‚“。`
pulls.status_checking=ã„ãã¤ã‹ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒã‚§ãƒƒã‚¯ãŒå¾…æ©Ÿä¸ã§ã™
pulls.status_checks_success=ステータスãƒã‚§ãƒƒã‚¯ã¯ã™ã¹ã¦æˆåŠŸã—ã¾ã—ãŸ
@@ -1900,6 +1926,7 @@ pulls.delete.text=本当ã«ã“ã®ãƒ—ルリクエストを削除ã—ã¾ã™ã‹? (
pulls.recently_pushed_new_branches=%[2]s ã€ã‚ãªãŸã¯ãƒ–ランム%[1]s ã«ãƒ—ッシュã—ã¾ã—ãŸ
pull.deleted_branch=(削除済ã¿):%s
+pull.agit_documentation=AGitã«é–¢ã™ã‚‹ãƒ‰ã‚ュメントを確èªã™ã‚‹
comments.edit.already_changed=コメントã®å¤‰æ›´ã‚’ä¿å˜ã§ãã¾ã›ã‚“。 ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ˆã£ã¦å†…容ãŒã™ã§ã«å¤‰æ›´ã•ã‚Œã¦ã„るよã†ã§ã™ã€‚ 変更を上書ãã—ãªã„よã†ã«ã™ã‚‹ãŸã‚ã€ãƒšãƒ¼ã‚¸ã‚’æ›´æ–°ã—ã¦ã‹ã‚‰ã‚‚ã†ä¸€åº¦ç·¨é›†ã—ã¦ãã ã•ã„
@@ -1910,6 +1937,7 @@ milestones.no_due_date=期日ãªã—
milestones.open=オープン
milestones.close=クãƒãƒ¼ã‚º
milestones.new_subheader=マイルストーンを使ã†ã¨ã‚¤ã‚·ãƒ¥ãƒ¼ã®æ•´ç†ã‚„進æ—確èªãŒã—ã‚„ã™ããªã‚Šã¾ã™ã€‚
+milestones.completeness=%d%%消化
milestones.create=マイルストーンを作æˆ
milestones.title=タイトル
milestones.desc=説明
@@ -2309,6 +2337,7 @@ settings.event_pull_request_merge=プルリクエストã®ãƒžãƒ¼ã‚¸
settings.event_package=パッケージ
settings.event_package_desc=リãƒã‚¸ãƒˆãƒªã«ãƒ‘ッケージãŒä½œæˆã¾ãŸã¯å‰Šé™¤ã•ã‚ŒãŸã¨ã。
settings.branch_filter=ブランムフィルター
+settings.branch_filter_desc=プッシュã€ãƒ–ランãƒä½œæˆã€ãƒ–ランãƒå‰Šé™¤ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’通知ã™ã‚‹ãƒ–ランãƒã‚’ã€globパターンã§æŒ‡å®šã™ã‚‹ãƒ›ãƒ¯ã‚¤ãƒˆãƒªã‚¹ãƒˆã§ã™ã€‚ 空ã‹*
ã®ã¨ãã¯ã€ã™ã¹ã¦ã®ãƒ–ランãƒã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’通知ã—ã¾ã™ã€‚ 文法ã«ã¤ã„ã¦ã¯ %[2]s ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 例: master
〠{master,release*}
settings.authorization_header=Authorizationヘッダー
settings.authorization_header_desc=入力ã—ãŸå ´åˆã€ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«Authorizationヘッダーã¨ã—ã¦ä»˜åŠ ã—ã¾ã™ã€‚ 例: %s
settings.active=有効
@@ -2359,6 +2388,7 @@ settings.protected_branch.save_rule=ルールをä¿å˜
settings.protected_branch.delete_rule=ルールを削除
settings.protected_branch_can_push=プッシュを許å¯ã™ã‚‹
settings.protected_branch_can_push_yes=プッシュã§ãã¾ã™
+settings.protected_branch_can_push_no=プッシュã§ãã¾ã›ã‚“
settings.branch_protection=ブランム'%s' ã®ä¿è·ãƒ«ãƒ¼ãƒ«
settings.protect_this_branch=ブランãƒã®ä¿è·ã‚’有効ã«ã™ã‚‹
settings.protect_this_branch_desc=ブランãƒã®å‰Šé™¤ã‚’防ãŽã€ãƒ–ランãƒã¸ã®ãƒ—ッシュやマージを制é™ã—ã¾ã™ã€‚
@@ -2395,6 +2425,7 @@ settings.protect_status_check_matched=マッãƒ
settings.protect_invalid_status_check_pattern=`ä¸æ£ãªã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒã‚§ãƒƒã‚¯ãƒ‘ターン: "%s"`
settings.protect_no_valid_status_check_patterns=有効ãªã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ãƒã‚§ãƒƒã‚¯ãƒ‘ターンãŒã‚ã‚Šã¾ã›ã‚“。
settings.protect_required_approvals=å¿…è¦ãªæ‰¿èªæ•°:
+settings.protect_required_approvals_desc=å¿…è¦ãªæ‰¿èªæ•°ã‚’満ãŸã—ãŸãƒ—ルリクエストã—ã‹ãƒžãƒ¼ã‚¸ã§ããªã„よã†ã«ã—ã¾ã™ã€‚ å¿…è¦ã¨ãªã‚‹æ‰¿èªã¨ã¯ã€è¨±å¯ãƒªã‚¹ãƒˆã«ã‚るユーザーやãƒãƒ¼ãƒ ã€ã‚‚ã—ãã¯æ›¸ãè¾¼ã¿æ¨©é™ã‚’æŒã¤èª°ã‹ã‹ã‚‰ã®ã‚‚ã®ã§ã™ã€‚
settings.protect_approvals_whitelist_enabled=許å¯ãƒªã‚¹ãƒˆã«ç™»éŒ²ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚„ãƒãƒ¼ãƒ ã«æ‰¿èªã‚’制é™
settings.protect_approvals_whitelist_enabled_desc=許å¯ãƒªã‚¹ãƒˆã«ç™»éŒ²ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã¾ãŸã¯ãƒãƒ¼ãƒ ã«ã‚ˆã‚‹ãƒ¬ãƒ“ューã®ã¿ã‚’ã€å¿…è¦ãªæ‰¿èªæ•°ã«ã‚«ã‚¦ãƒ³ãƒˆã—ã¾ã™ã€‚ 承èªã®è¨±å¯ãƒªã‚¹ãƒˆãŒç„¡ã„å ´åˆã¯ã€æ›¸ãè¾¼ã¿æ¨©é™ã‚’æŒã¤äººã«ã‚ˆã‚‹ãƒ¬ãƒ“ューを必è¦ãªæ‰¿èªæ•°ã«ã‚«ã‚¦ãƒ³ãƒˆã—ã¾ã™ã€‚
settings.protect_approvals_whitelist_users=許å¯ãƒªã‚¹ãƒˆã«å«ã‚るレビューア:
@@ -2406,9 +2437,12 @@ settings.ignore_stale_approvals_desc=å¤ã„コミットã«å¯¾ã—ã¦è¡Œã‚ã‚ŒãŸ
settings.require_signed_commits=コミット署åå¿…é ˆ
settings.require_signed_commits_desc=ç½²åã•ã‚Œã¦ã„ãªã„å ´åˆã€ã¾ãŸã¯ç½²åãŒæ¤œè¨¼ã§ããªã‹ã£ãŸå ´åˆã¯ã€ã“ã®ãƒ–ランãƒã¸ã®ãƒ—ッシュを拒å¦ã—ã¾ã™ã€‚
settings.protect_branch_name_pattern=ä¿è·ãƒ–ランãƒåã®ãƒ‘ターン
+settings.protect_branch_name_pattern_desc=ä¿è·ãƒ–ランãƒåã®ãƒ‘ターン。書ãæ–¹ã«ã¤ã„ã¦ã¯ ドã‚ュメント ã‚’å‚ç…§ã—ã¦ãã ã•ã„。例: main, release/**
settings.protect_patterns=パターン
settings.protect_protected_file_patterns=ä¿è·ã•ã‚Œã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã®ãƒ‘ターン (セミコãƒãƒ³';'ã§åŒºåˆ‡ã‚‹):
+settings.protect_protected_file_patterns_desc=ä¿è·ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã¯ã€ã“ã®ãƒ–ランãƒã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’è¿½åŠ ãƒ»ç·¨é›†ãƒ»å‰Šé™¤ã™ã‚‹æ¨©é™ã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã§ã‚ã£ã¦ã‚‚ã€ç›´æŽ¥å¤‰æ›´ã™ã‚‹ã“ã¨ãŒã§ããªããªã‚Šã¾ã™ã€‚ セミコãƒãƒ³(';')ã§åŒºåˆ‡ã£ã¦è¤‡æ•°ã®ãƒ‘ターンを指定ã§ãã¾ã™ã€‚ パターンã®æ–‡æ³•ã«ã¤ã„ã¦ã¯ %[2]s ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 例: .drone.yml
, /docs/**/*.txt
settings.protect_unprotected_file_patterns=ä¿è·ã—ãªã„ファイルã®ãƒ‘ターン (セミコãƒãƒ³';'ã§åŒºåˆ‡ã‚‹):
+settings.protect_unprotected_file_patterns_desc=ä¿è·ã—ãªã„ファイルã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«æ›¸ãè¾¼ã¿æ¨©é™ãŒã‚ã‚Œã°ãƒ—ッシュ制é™ã‚’ãƒã‚¤ãƒ‘スã—ã¦ç›´æŽ¥å¤‰æ›´ã§ãã¾ã™ã€‚ セミコãƒãƒ³(';')ã§åŒºåˆ‡ã£ã¦è¤‡æ•°ã®ãƒ‘ターンを指定ã§ãã¾ã™ã€‚ パターンã®æ–‡æ³•ã«ã¤ã„ã¦ã¯ %[2]s ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 例: .drone.yml
, /docs/**/*.txt
settings.add_protected_branch=ä¿è·ã‚’有効ã«ã™ã‚‹
settings.delete_protected_branch=ä¿è·ã‚’無効ã«ã™ã‚‹
settings.update_protect_branch_success=ルール "%s" ã«å¯¾ã™ã‚‹ãƒ–ランãƒä¿è·ã‚’æ›´æ–°ã—ã¾ã—ãŸã€‚
@@ -2440,6 +2474,7 @@ settings.tags.protection.allowed.teams=許å¯ã™ã‚‹ãƒãƒ¼ãƒ
settings.tags.protection.allowed.noone=ãªã—
settings.tags.protection.create=ã‚¿ã‚°ã‚’ä¿è·
settings.tags.protection.none=ã‚¿ã‚°ã¯ä¿è·ã•ã‚Œã¦ã„ã¾ã›ã‚“。
+settings.tags.protection.pattern.description=ã²ã¨ã¤ã®ã‚¿ã‚°åã‹ã€è¤‡æ•°ã®ã‚¿ã‚°ã«ãƒžãƒƒãƒã™ã‚‹globパターンã¾ãŸã¯æ£è¦è¡¨ç¾ã‚’使用ã§ãã¾ã™ã€‚ 詳ã—ãã¯ã‚¿ã‚°ã®ä¿è·ã‚¬ã‚¤ãƒ‰ ã‚’ã”覧ãã ã•ã„。
settings.bot_token=Botトークン
settings.chat_id=ãƒãƒ£ãƒƒãƒˆID
settings.thread_id=スレッドID
@@ -2654,6 +2689,7 @@ tag.create_success=ã‚¿ã‚° "%s" を作æˆã—ã¾ã—ãŸã€‚
topic.manage_topics=トピックã®ç®¡ç†
topic.done=完了
+topic.count_prompt=é¸æŠžã§ãã‚‹ã®ã¯25トピックã¾ã§ã§ã™ã€‚
topic.format_prompt=トピックåã¯è‹±å—ã¾ãŸã¯æ•°å—ã§å§‹ã‚ã€ãƒ€ãƒƒã‚·ãƒ¥('-')やドット('.')ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚最大35æ–‡å—ã¾ã§ã§ã™ã€‚æ–‡å—ã¯å°æ–‡å—ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。
find_file.go_to_file=ファイルã¸ç§»å‹•
@@ -2722,7 +2758,7 @@ settings.change_orgname_redirect_prompt=å¤ã„åå‰ã¯ã€å†ä½¿ç”¨ã•ã‚Œã¦ã„
settings.update_avatar_success=組織ã®ã‚¢ãƒã‚¿ãƒ¼ã‚’æ›´æ–°ã—ã¾ã—ãŸã€‚
settings.delete=組織を削除
settings.delete_account=ã“ã®çµ„織を削除
-settings.delete_prompt=組織ã¯æ’ä¹…çš„ã«å‰Šé™¤ã•ã‚Œã€å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。 続行ã—ã¾ã™ã‹ï¼Ÿ
+settings.delete_prompt=組織ã¯æ’ä¹…çš„ã«å‰Šé™¤ã•ã‚Œã¾ã™ã€‚ å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“ï¼
settings.confirm_delete_account=削除を確èª
settings.delete_org_title=組織ã®å‰Šé™¤
settings.delete_org_desc=組織をæ’ä¹…çš„ã«å‰Šé™¤ã—ã¾ã™ã€‚ 続行ã—ã¾ã™ã‹ï¼Ÿ
@@ -2751,6 +2787,7 @@ teams.leave.detail=%s ã‹ã‚‰è„±é€€ã—ã¾ã™ã‹ï¼Ÿ
teams.can_create_org_repo=リãƒã‚¸ãƒˆãƒªã‚’作æˆ
teams.can_create_org_repo_helper=メンãƒãƒ¼ã¯çµ„ç¹”ã®ãƒªãƒã‚¸ãƒˆãƒªã‚’æ–°ãŸã«ä½œæˆã§ãã¾ã™ã€‚作æˆè€…ã«ã¯æ–°ã—ã„リãƒã‚¸ãƒˆãƒªã®ç®¡ç†è€…権é™ãŒä¸Žãˆã‚‰ã‚Œã¾ã™ã€‚
teams.none_access=アクセスãªã—
+teams.none_access_helper=メンãƒãƒ¼ã¯ã€ã“ã®ãƒ¦ãƒ‹ãƒƒãƒˆã‚’表示ã—ãŸã‚Šä»–ã®æ“作を行ã†ã“ã¨ã¯ã§ãã¾ã›ã‚“。 公開リãƒã‚¸ãƒˆãƒªã«ã¯é©ç”¨ã•ã‚Œã¾ã›ã‚“。
teams.general_access=一般的ãªã‚¢ã‚¯ã‚»ã‚¹
teams.general_access_helper=メンãƒãƒ¼ã®æ¨©é™ã¯ä¸‹è¨˜ã®æ¨©é™ãƒ†ãƒ¼ãƒ–ルã§æ±ºå®šã•ã‚Œã¾ã™ã€‚
teams.read_access=èªã¿å–ã‚Š
@@ -2819,6 +2856,7 @@ last_page=最後
total=åˆè¨ˆ: %d
settings=管ç†è¨å®š
+dashboard.new_version_hint=Gitea %s ãŒå…¥æ‰‹å¯èƒ½ã«ãªã‚Šã¾ã—ãŸã€‚ ç¾åœ¨å®Ÿè¡Œã—ã¦ã„ã‚‹ã®ã¯ %s ã§ã™ã€‚ 詳細㯠ブãƒã‚° を確èªã—ã¦ãã ã•ã„。
dashboard.statistic=サマリー
dashboard.maintenance_operations=メンテナンスæ“作
dashboard.system_status=システム状æ³
@@ -2903,6 +2941,7 @@ dashboard.start_schedule_tasks=Actionsスケジュールタスクを開始
dashboard.sync_branch.started=ブランãƒã®åŒæœŸã‚’開始ã—ã¾ã—ãŸ
dashboard.sync_tag.started=ã‚¿ã‚°ã®åŒæœŸã‚’開始ã—ã¾ã—ãŸ
dashboard.rebuild_issue_indexer=イシューインデクサーã®å†æ§‹ç¯‰
+dashboard.sync_repo_licenses=リãƒã‚¸ãƒˆãƒªãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã®åŒæœŸ
users.user_manage_panel=ユーザーアカウント管ç†
users.new_account=ユーザーアカウントを作æˆ
@@ -3010,10 +3049,12 @@ packages.size=サイズ
packages.published=é…布
defaulthooks=デフォルトWebhook
+defaulthooks.desc=Webhookã¯ã€ç‰¹å®šã®GiteaイベントãŒç™ºç”Ÿã—ãŸã¨ãã«ã€ã‚µãƒ¼ãƒãƒ¼ã«HTTP POSTリクエストを自動的ã«é€ä¿¡ã™ã‚‹ã‚‚ã®ã§ã™ã€‚ ã“ã“ã§å®šç¾©ã—ãŸWebhookã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã¨ãªã‚Šã€å…¨ã¦ã®æ–°è¦ãƒªãƒã‚¸ãƒˆãƒªã«ã‚³ãƒ”ーã•ã‚Œã¾ã™ã€‚ 詳ã—ãã¯Webhooksガイドをã”覧下ã•ã„。
defaulthooks.add_webhook=デフォルトWebhookã®è¿½åŠ
defaulthooks.update_webhook=デフォルトWebhookã®æ›´æ–°
systemhooks=システムWebhook
+systemhooks.desc=Webhookã¯ã€ç‰¹å®šã®GiteaイベントãŒç™ºç”Ÿã—ãŸã¨ãã«ã€ã‚µãƒ¼ãƒãƒ¼ã«HTTP POSTリクエストを自動的ã«é€ä¿¡ã™ã‚‹ã‚‚ã®ã§ã™ã€‚ ã“ã“ã§å®šç¾©ã—ãŸWebhookã¯ã€ã‚·ã‚¹ãƒ†ãƒ 内ã®ã™ã¹ã¦ã®ãƒªãƒã‚¸ãƒˆãƒªã§å‘¼ã³å‡ºã•ã‚Œã¾ã™ã€‚ ãã®ãŸã‚ã€ãƒ‘フォーマンスã«åŠã¼ã™å½±éŸ¿ã‚’考慮ã—ãŸã†ãˆã§è¨å®šã—ã¦ãã ã•ã„。 詳ã—ãã¯Webhooksガイドをã”覧下ã•ã„。
systemhooks.add_webhook=システムWebhookを追åŠ
systemhooks.update_webhook=システムWebhookを更新
@@ -3108,8 +3149,18 @@ auths.tips=ヒント
auths.tips.oauth2.general=OAuth2èªè¨¼
auths.tips.oauth2.general.tip=æ–°ã—ã„OAuth2èªè¨¼ã‚’登録ã™ã‚‹ã¨ãã¯ã€ã‚³ãƒ¼ãƒ«ãƒãƒƒã‚¯/リダイレクトURLã¯ä»¥ä¸‹ã«ãªã‚Šã¾ã™:
auths.tip.oauth2_provider=OAuth2プãƒãƒã‚¤ãƒ€ãƒ¼
+auths.tip.bitbucket=æ–°ã—ã„OAuthコンシューマーを %s ã‹ã‚‰ç™»éŒ²ã—ã€"アカウント" ã« "èªã¿å–ã‚Š" 権é™ã‚’è¿½åŠ ã—ã¦ãã ã•ã„。
auths.tip.nextcloud=æ–°ã—ã„OAuthコンシューマーをã€ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ãƒ¡ãƒ‹ãƒ¥ãƒ¼ "Settings -> Security -> OAuth 2.0 client" ã‹ã‚‰ç™»éŒ²ã—ã¦ãã ã•ã„。
+auths.tip.dropbox=æ–°ã—ã„アプリケーションを %s ã‹ã‚‰ç™»éŒ²ã—ã¦ãã ã•ã„。
+auths.tip.facebook=æ–°ã—ã„アプリケーションを %s ã§ç™»éŒ²ã—ã€"Facebook Login"ã‚’è¿½åŠ ã—ã¦ãã ã•ã„。
+auths.tip.github=æ–°ã—ã„OAuthアプリケーションを %s ã‹ã‚‰ç™»éŒ²ã—ã¦ãã ã•ã„。
+auths.tip.gitlab_new=æ–°ã—ã„アプリケーションを %s ã‹ã‚‰ç™»éŒ²ã—ã¦ãã ã•ã„。
+auths.tip.google_plus=OAuth2ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆè³‡æ ¼æƒ…å ±ã‚’ã€Google APIコンソール %s ã‹ã‚‰å–å¾—ã—ã¦ãã ã•ã„。
auths.tip.openid_connect=OpenID Connect Discoveryã®URL "https://{server}/.well-known/openid-configuration" をエンドãƒã‚¤ãƒ³ãƒˆã¨ã—ã¦æŒ‡å®šã—ã¦ãã ã•ã„
+auths.tip.twitter=%s ã¸ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã‚¢ãƒ—リケーションを作æˆã—ã€â€œAllow this application to be used to Sign in with Twitterâ€ã‚ªãƒ—ションを有効ã«ã—ã¦ãã ã•ã„。
+auths.tip.discord=æ–°ã—ã„アプリケーションを %s ã‹ã‚‰ç™»éŒ²ã—ã¦ãã ã•ã„。
+auths.tip.gitea=æ–°ã—ã„OAuthアプリケーションを登録ã—ã¦ãã ã•ã„。 利用ガイド㯠%s ã«ã‚ã‚Šã¾ã™
+auths.tip.yandex=`%s ã§æ–°ã—ã„アプリケーションを作æˆã—ã¦ãã ã•ã„。 "Yandex.Passport API" セクションã§æ¬¡ã®é …目を許å¯ã—ã¾ã™: "Access to email address"ã€"Access to user avatar"ã€"Access to username, first name and surname, gender"`
auths.tip.mastodon=èªè¨¼ã—ãŸã„Mastodonインスタンスã®ã‚«ã‚¹ã‚¿ãƒ URLを入力ã—ã¦ãã ã•ã„ (入力ã—ãªã„å ´åˆã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®URLを使用ã—ã¾ã™)
auths.edit=èªè¨¼ã‚½ãƒ¼ã‚¹ã®ç·¨é›†
auths.activated=èªè¨¼ã‚½ãƒ¼ã‚¹ã¯ã‚¢ã‚¯ãƒ†ã‚£ãƒ™ãƒ¼ãƒˆæ¸ˆã¿
@@ -3275,6 +3326,7 @@ monitor.next=次回
monitor.previous=å‰å›ž
monitor.execute_times=実行回数
monitor.process=実行ä¸ã®ãƒ—ãƒã‚»ã‚¹
+monitor.stacktrace=スタックトレース
monitor.processes_count=%d プãƒã‚»ã‚¹
monitor.download_diagnosis_report=診æ–レãƒãƒ¼ãƒˆã‚’ダウンãƒãƒ¼ãƒ‰
monitor.desc=説明
@@ -3282,6 +3334,8 @@ monitor.start=開始日時
monitor.execute_time=実行時間
monitor.last_execution_result=çµæžœ
monitor.process.cancel=処ç†ã‚’ã‚ャンセル
+monitor.process.cancel_desc=処ç†ã‚’ã‚ャンセルã™ã‚‹ã¨ãƒ‡ãƒ¼ã‚¿ãŒå¤±ã‚れるå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™
+monitor.process.cancel_notices=ã‚ャンセル: %s?
monitor.process.children=åプãƒã‚»ã‚¹
monitor.queues=ã‚ュー
@@ -3383,6 +3437,7 @@ raw_minutes=分
[dropzone]
default_message=ファイルをã“ã“ã«ãƒ‰ãƒãƒƒãƒ—ã€ã¾ãŸã¯ã“ã“をクリックã—ã¦ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰
+invalid_input_type=ã“ã®ç¨®é¡žã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã‚¢ãƒƒãƒ—ãƒãƒ¼ãƒ‰ã§ãã¾ã›ã‚“。
file_too_big=アップãƒãƒ¼ãƒ‰ã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã®ã‚µã‚¤ã‚º ({{filesize}} MB) ã¯ã€æœ€å¤§ã‚µã‚¤ã‚º ({{maxFilesize}} MB) を超ãˆã¦ã„ã¾ã™ã€‚
remove_file=ファイル削除
@@ -3530,6 +3585,7 @@ settings.link=ã“ã®ãƒ‘ッケージをリãƒã‚¸ãƒˆãƒªã«ãƒªãƒ³ã‚¯
settings.link.description=パッケージをリãƒã‚¸ãƒˆãƒªã«ãƒªãƒ³ã‚¯ã™ã‚‹ã¨ã€ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ‘ッケージリストã«è¡¨ç¤ºã•ã‚Œã‚‹ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚
settings.link.select=リãƒã‚¸ãƒˆãƒªã‚’é¸æŠž
settings.link.button=リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ³ã‚¯ã‚’æ›´æ–°
+settings.link.success=リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ³ã‚¯ãŒæ£å¸¸ã«æ›´æ–°ã•ã‚Œã¾ã—ãŸã€‚
settings.link.error=リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ³ã‚¯ã®æ›´æ–°ã«å¤±æ•—ã—ã¾ã—ãŸã€‚
settings.delete=パッケージ削除
settings.delete.description=パッケージã®å‰Šé™¤ã¯æ’ä¹…çš„ã§å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。
diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini
index ef11284b08..91c5b24ab5 100644
--- a/options/locale/locale_ko-KR.ini
+++ b/options/locale/locale_ko-KR.ini
@@ -375,7 +375,6 @@ account_link=ì—°ê²°ëœ ê³„ì •
organization=ì¡°ì§
public_profile=공개 프로필
-password_username_disabled=로컬 사용ìžê°€ ì•„ë‹Œ 경우 ì‚¬ìš©ìž ì´ë¦„ ë³€ê²½ì„ í• ìˆ˜ 없습니다. ìžì„¸í•œ ë‚´ìš©ì€ ê´€ë¦¬ìžì—게 문ì˜í•´ì£¼ì„¸ìš”.
full_name=성명
website=웹 사ì´íŠ¸
location=위치
@@ -818,12 +817,12 @@ issues.dependency.add_error_dep_not_same_repo=ë‘ ì´ìŠˆëŠ” ê°™ì€ ë ˆí¬ì§€í†
issues.review.self.approval=ìžì‹ ì˜ í’€ 리퀘스트를 승ì¸í• 수 없습니다.
issues.review.self.rejection=ìžì‹ ì˜ í’€ ë¦¬í€˜ìŠ¤íŠ¸ì— ëŒ€í•œ ë³€ê²½ì„ ìš”ì²í• 수 없습니다.
issues.review.approve="ì´ ë³€ê²½ì‚¬í•ì„ 승ì¸í•˜ì˜€ìŠµë‹ˆë‹¤. %s"
-issues.review.comment=댓글
issues.review.pending=보류
issues.review.review=ê²€í†
issues.review.reviewers=리뷰어
issues.review.show_outdated=ì˜¤ëž˜ëœ ë‚´ì— ë³´ê¸°
issues.review.hide_outdated=ì˜¤ëž˜ëœ ë‚´ì— ìˆ¨ê¸°ê¸°
+issues.review.commented=댓글
pulls.new=새 풀 리퀘스트
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index ee7ab1192c..ee6f3911b0 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -187,8 +187,6 @@ string.desc=Z - A
[error]
occurred=Radusies kļūda
-missing_csrf=Kļūdains pieprasījums: netika iesūtīta drošības pilnvara
-invalid_csrf=Kļūdains pieprasījums: iesūtīta kļūdaina drošības pilnvara
not_found=Pieprasītie dati netika atrasti.
network_error=Tīkla kļūda
@@ -625,7 +623,6 @@ public_profile=Publiskais profils
biography_placeholder=PastÄsti mums mazliet par sevi! (Var izmantot Markdown)
location_placeholder=KopÄ«got savu aptuveno atraÅ¡anÄs vietu ar citiem
profile_desc=NorÄdÄ«t, kÄ profils tiek attÄ“lots citiem lietotÄjiem. PrimÄrÄ e-pasta adrese tiks izmantota paziņojumiem, paroles atjaunoÅ¡anai un Git tÄ«mekļa darbÄ«bÄm.
-password_username_disabled=Ne-lokÄliem lietotÄjiem nav atļauts mainÄ«t savu lietotÄja vÄrdu. Sazinieties ar sistÄ“mas administratoru, lai uzzinÄtu sÄ«kÄk.
full_name=Pilns vÄrds
website=MÄjas lapa
location=AtraÅ¡anÄs vieta
@@ -1609,7 +1606,6 @@ issues.dependency.add_error_dep_not_same_repo=AbÄm problÄ“mÄm ir jÄbÅ«t no vi
issues.review.self.approval=Nevar apstiprinÄt savu izmaiņu pieprasÄ«jumi.
issues.review.self.rejection=Nevar pieprasīt izmaiņas savam izmaiņu pieprasījumam.
issues.review.approve=apstiprinÄja izmaiņas %s
-issues.review.comment=Komentēt
issues.review.dismissed=atmeta %s recenziju %s
issues.review.dismissed_label=Atmesta
issues.review.left_comment=atstÄja komentÄru
@@ -1634,6 +1630,7 @@ issues.review.hide_resolved=PaslÄ“pt atrisinÄto
issues.review.resolve_conversation=AtrisinÄt sarunu
issues.review.un_resolve_conversation=Atcelt sarunas atrisinÄjumu
issues.review.resolved_by=atzÄ«mÄ“ja sarunu kÄ atrisinÄtu
+issues.review.commented=Komentēt
issues.assignee.error=Ne visi atbildÄ«gie tika pievienoti, jo radÄs neparedzÄ“ta kļūda.
issues.reference_issue.body=Saturs
issues.content_history.deleted=dzēsts
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 5de274da2b..1540cf095b 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -134,8 +134,6 @@ filter.private=Prive
[error]
occurred=Er is een fout opgetreden
-missing_csrf=Foutief verzoek: geen CSRF-token aanwezig
-invalid_csrf=Verkeerd verzoek: ongeldig CSRF-token
not_found=Het doel kon niet worden gevonden.
network_error=Netwerk fout
@@ -517,7 +515,6 @@ account_link=Gekoppelde Accounts
organization=Organisaties
public_profile=Openbaar profiel
-password_username_disabled=Niet-lokale gebruikers kunnen hun gebruikersnaam niet veranderen. Neem contact op met de sitebeheerder voor meer details.
full_name=Volledige naam
website=Website
location=Locatie
@@ -1328,7 +1325,6 @@ issues.dependency.add_error_dep_not_same_repo=Beide kwesties moeten in dezelfde
issues.review.self.approval=Je kan je eigen pull-aanvraag niet goedkeuren.
issues.review.self.rejection=Je kan geen wijzigingen aanvragen op je eigen pull-aanvraag.
issues.review.approve=heeft deze veranderingen %s goedgekeurd
-issues.review.comment=Opmerking
issues.review.dismissed=%s's beoordeling afgewezen %s
issues.review.dismissed_label=Afgewezen
issues.review.left_comment=heeft een reactie achtergelaten
@@ -1349,6 +1345,7 @@ issues.review.hide_resolved=Verbergen afgehandeld
issues.review.resolve_conversation=Gesprek oplossen
issues.review.un_resolve_conversation=Gesprek niet oplossen
issues.review.resolved_by=markeerde dit gesprek als opgelost
+issues.review.commented=Opmerking
issues.assignee.error=Niet alle aangewezen personen zijn toegevoegd vanwege een onverwachte fout.
issues.reference_issue.body=Inhoud
issues.content_history.deleted=verwijderd
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index 88e54fc3be..22bdf1bbac 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -131,8 +131,6 @@ filter.private=Prywatne
[error]
occurred=Wystąpił błąd
-missing_csrf=Błędne żądanie: brak tokenu CSRF
-invalid_csrf=Błędne żądanie: nieprawidłowy token CSRF
not_found=Nie można odnaleźć celu.
network_error=BÅ‚Ä…d sieci
@@ -502,7 +500,6 @@ account_link=PowiÄ…zane Konta
organization=Organizacje
public_profile=Profil publiczny
-password_username_disabled=Użytkownicy nielokalni nie mogą zmieniać swoich nazw. Aby uzyskać więcej informacji, skontaktuj się z administratorem strony.
full_name=ImiÄ™ i nazwisko
website=Strona
location=Lokalizacja
@@ -1220,7 +1217,6 @@ issues.dependency.add_error_dep_not_same_repo=Oba zgłoszenia muszą być w tym
issues.review.self.approval=Nie możesz zatwierdzić swojego własnego Pull Requesta.
issues.review.self.rejection=Nie możesz zażądać zmian w swoim własnym Pull Requeście.
issues.review.approve=zatwierdza te zmiany %s
-issues.review.comment=Skomentuj
issues.review.dismissed_label=Odrzucony
issues.review.left_comment=zostawił komentarz
issues.review.content.empty=Musisz pozostawić komentarz o pożądanej zmianie/zmianach.
@@ -1240,6 +1236,7 @@ issues.review.hide_resolved=Ukryj rozwiÄ…zane
issues.review.resolve_conversation=Rozwiąż dyskusję
issues.review.un_resolve_conversation=Oznacz dyskusję jako nierozstrzygniętą
issues.review.resolved_by=oznaczył(-a) tę rozmowę jako rozwiązaną
+issues.review.commented=Skomentuj
issues.assignee.error=Nie udało się dodać wszystkich wybranych osób do przypisanych przez nieoczekiwany błąd.
issues.reference_issue.body=Treść
issues.content_history.edited=edytowano
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index e172aa0a01..bb185d3de6 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -184,8 +184,6 @@ string.desc=Z - A
[error]
occurred=Ocorreu um erro
-missing_csrf=Pedido inválido: não tem token CSRF presente
-invalid_csrf=Requisição Inválida: token CSRF inválido
not_found=Não foi possÃvel encontrar o destino.
network_error=Erro de rede
@@ -624,7 +622,6 @@ public_profile=Perfil público
biography_placeholder=Conte-nos um pouco sobre você! (Você pode usar Markdown)
location_placeholder=Compartilhe sua localização aproximada com outras pessoas
profile_desc=Controle como o seu perfil é exibido para outros usuários. Seu endereço de e-mail principal será usado para notificações, recuperação de senha e operações do Git baseadas na Web.
-password_username_disabled=Usuários não-locais não podem alterar seus nomes de usuário. Por favor contate o administrador do site para mais informações.
full_name=Nome completo
website=Site
location=Localização
@@ -1599,7 +1596,6 @@ issues.dependency.add_error_dep_not_same_repo=Ambas as issues devem estar no mes
issues.review.self.approval=Você não pode aprovar o seu próprio pull request.
issues.review.self.rejection=Você não pode solicitar alterações em seu próprio pull request.
issues.review.approve=aprovou estas alterações %s
-issues.review.comment=Comentar
issues.review.dismissed=rejeitou a revisão de %s %s
issues.review.dismissed_label=Rejeitada
issues.review.left_comment=deixou um comentário
@@ -1624,6 +1620,7 @@ issues.review.hide_resolved=Ocultar resolvidas
issues.review.resolve_conversation=Resolver conversa
issues.review.un_resolve_conversation=Conversa não resolvida
issues.review.resolved_by=marcou esta conversa como resolvida
+issues.review.commented=Comentar
issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado.
issues.reference_issue.body=Conteúdo
issues.content_history.deleted=excluÃdo
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index dd79cb7758..41531f7b3d 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -159,6 +159,7 @@ filter.public=Público
filter.private=Privado
no_results_found=Não foram encontrados quaisquer resultados.
+internal_error_skipped=Ocorreu um erro interno mas foi ignorado: %s
[search]
search=Pesquisar...
@@ -177,6 +178,8 @@ code_search_by_git_grep=Os resultados da pesquisa no código-fonte neste momento
package_kind=Pesquisar pacotes...
project_kind=Pesquisar planeamentos...
branch_kind=Pesquisar ramos...
+tag_kind=Pesquisar etiquetas...
+tag_tooltip=Pesquisar etiquetas correspondentes. Use '%' para corresponder a qualquer sequência de números.
commit_kind=Pesquisar cometimentos...
runner_kind=Pesquisar executores...
no_results=Não foram encontrados resultados correspondentes.
@@ -218,18 +221,20 @@ string.desc=Z - A
[error]
occurred=Ocorreu um erro
-missing_csrf=Pedido inválido: não há código CSRF
-invalid_csrf=Pedido inválido: código CSRF inválido
+report_message=Se acredita tratar-se de um erro do Gitea, procure questões relacionadas no GitHub ou abra uma nova questão, se necessário.
not_found=Não foi possÃvel encontrar o destino.
network_error=Erro de rede
[startpage]
app_desc=Um serviço Git auto-hospedado e fácil de usar
install=Fácil de instalar
+install_desc=Corra, simplesmente, o ficheiro binário executável para a sua plataforma, despache-o com o Docker, ou obtenha-o sob a forma de pacote.
platform=Multiplataforma
+platform_desc=Gitea corre em qualquer plataforma onde possa compilar em linguagem Go: Windows, macOS, Linux, ARM, etc. Escolha a sua preferida!
lightweight=Leve
lightweight_desc=Gitea requer poucos recursos e pode correr num simples Raspberry Pi. Economize a energia da sua máquina!
license=Código aberto
+license_desc=Vá buscar %[2]s! Junte-se a nós dando a sua contribuição para tornar este programa ainda melhor. Não se acanhe e contribua!
[install]
install=Instalação
@@ -402,6 +407,7 @@ reset_password_mail_sent_prompt=Foi enviado um email de confirmação para %s
active_your_account=Ponha a sua conta em funcionamento
account_activated=A conta foi posta em funcionamento
prohibit_login=InÃcio de sessão proibido
+prohibit_login_desc=A sua conta está proibida de iniciar sessão. Contacte o administrador.
resent_limit_prompt=Já fez um pedido recentemente para enviar um email para pôr a conta em funcionamento. Espere 3 minutos e tente novamente.
has_unconfirmed_mail=Olá %s, tem um endereço de email não confirmado (%s). Se não recebeu um email de confirmação ou precisa de o voltar a enviar, clique no botão abaixo.
change_unconfirmed_mail_address=Se o seu endereço de email estiver errado, pode mudá-lo aqui e enviar um novo email de confirmação.
@@ -413,6 +419,7 @@ invalid_code=O seu código de confirmação é inválido ou expirou.
invalid_code_forgot_password=O seu código de confirmação é inválido ou já expirou. Clique aqui para iniciar uma nova sessão.
invalid_password=A sua senha não corresponde à senha que foi usada para criar a conta.
reset_password_helper=Recuperar conta
+reset_password_wrong_user=Tem conta iniciada como %s, mas a ligação de recuperação de conta é para %s
password_too_short=O tamanho da senha não pode ser inferior a %d caracteres.
non_local_account=Os utilizadores não-locais não podem alterar a sua senha através da interface web do Gitea.
verify=Validar
@@ -448,7 +455,9 @@ authorize_application_created_by=Esta aplicação foi criada por %s.
authorize_application_description=Se conceder acesso, a aplicação terá privilégios para alterar toda a informação da conta, incluindo repositórios e organizações privados.
authorize_title=Autorizar o acesso de "%s" Ã sua conta?
authorization_failed=A autorização falhou
+authorization_failed_desc=A autorização falhou porque encontrámos um pedido inválido. Entre em contacto com o responsável pela aplicação que tentou autorizar.
sspi_auth_failed=Falhou a autenticação SSPI
+password_pwned=A senha que escolheu está numa lista de senhas roubadas anteriormente expostas em fugas de dados públicas. Tente novamente com uma senha diferente e considere também mudar esta senha nos outros sÃtios.
password_pwned_err=Não foi possÃvel completar o pedido ao HaveIBeenPwned
last_admin=Não pode remover o último administrador. Tem que existir pelo menos um administrador.
signin_passkey=Iniciar sessão com uma passkey
@@ -466,6 +475,7 @@ activate_account.text_1=Olá %[1]s, obrigado por se registar em %[2]s!
activate_account.text_2=Clique, por favor, na ligação seguinte para activar a sua conta dentro de %s:
activate_email=Valide o seu endereço de email
+activate_email.title=%s, por favor valide o seu endereço de email
activate_email.text=Por favor clique na seguinte ligação para validar o seu endereço de email dentro de %s:
register_notify=Bem-vindo(a) a %s
@@ -570,6 +580,8 @@ lang_select_error=Escolha um idioma da lista.
username_been_taken=O nome de utilizador já foi tomado.
username_change_not_local_user=Utilizadores que não são locais não têm permissão para mudar o nome de utilizador.
+change_username_disabled=Alterar o nome de utilizador está desabilitado.
+change_full_name_disabled=Alterar o nome completo está desabilitado.
username_has_not_been_changed=O nome de utilizador não foi modificado
repo_name_been_taken=O nome do repositório já foi usado.
repository_force_private=Forçar Privado está habilitado: repositórios privados não podem ser tornados públicos.
@@ -685,15 +697,18 @@ applications=Aplicações
orgs=Gerir organizações
repos=Repositórios
delete=Eliminar a conta
+twofa=Autenticação em dois passos (TOTP)
account_link=Contas vinculadas
organization=Organizações
uid=UID
+webauthn=Autenticação em dois passos (Chaves de Segurança)
public_profile=Perfil público
biography_placeholder=Conte-nos um pouco sobre si! (Pode usar Markdown)
location_placeholder=Partilhe a sua localização aproximada com outros
profile_desc=Controle como o seu perfil é apresentado aos outros utilizadores. O seu endereço de email principal será usado para notificações, recuperação de senha e operações Git baseadas na web.
-password_username_disabled=Utilizadores não-locais não podem mudar os seus nomes de utilizador. Entre em contacto com o administrador do sÃtio saber para mais detalhes.
+password_username_disabled=Não tem permissão para alterar os nomes de utilizador deles/delas. Entre em contacto com o administrador para saber mais detalhes.
+password_full_name_disabled=Não tem permissão para alterar o nome completo deles/delas. Entre em contacto com o administrador para saber mais detalhes.
full_name=Nome completo
website=SÃtio web
location=Localização
@@ -705,6 +720,7 @@ update_language_success=O idioma foi modificado.
update_profile_success=O seu perfil foi modificado.
change_username=O seu nome de utilizador foi modificado.
change_username_prompt=Note: Mudar o seu nome de utilizador também muda o URL da sua conta.
+change_username_redirect_prompt=O antigo nome de utilizador, enquanto ninguém o reivindicar, irá reencaminhar para o novo.
continue=Continuar
cancel=Cancelar
language=Idioma
@@ -784,6 +800,7 @@ add_email_success=O novo endereço de email foi adicionado.
email_preference_set_success=As preferências relativas ao email foram definidas com sucesso.
add_openid_success=O novo endereço OpenID foi adicionado.
keep_email_private=Ocultar endereço de email
+keep_email_private_popup=Isto irá ocultar o seu endereço de email no seu perfil, assim como quando fizer um pedido de integração ou editar um ficheiro usando a interface web. Cometimentos enviados não serão modificados. Utilize %s nos cometimentos para os associar à sua conta.
openid_desc=O OpenID permite delegar a autenticação num fornecedor externo.
manage_ssh_keys=Gerir chaves SSH
@@ -898,6 +915,8 @@ remove_oauth2_application_desc=Remover uma aplicação OAuth2 irá revogar o ace
remove_oauth2_application_success=A aplicação foi eliminada.
create_oauth2_application=Criar uma nova aplicação OAuth2
create_oauth2_application_button=Criar aplicação
+create_oauth2_application_success=Criou com sucesso uma nova aplicação OAuth2.
+update_oauth2_application_success=Modificou com sucesso a aplicação OAuth2.
oauth2_application_name=Nome da aplicação
oauth2_confidential_client=Cliente confidencial. Escolha esta opção para aplicações que mantêm o segredo confidencial, tais como aplicações web. Não escolha esta opção para aplicações nativas, incluindo aplicações para computador e aplicações móveis.
oauth2_skip_secondary_authorization=Saltar a autorização para clientes públicos depois de lhes ceder acesso uma vez. Pode representar um risco de segurança.
@@ -910,6 +929,8 @@ oauth2_regenerate_secret_hint=Perdeu o seu segredo?
oauth2_client_secret_hint=O segredo não voltará a ser mostrado depois de sair ou refrescar esta página. Certifique-se de que o guardou.
oauth2_application_edit=Editar
oauth2_application_create_description=As aplicações OAuth2 dão à sua aplicação de terceiros acesso a contas de utilizador nesta instância.
+oauth2_application_remove_description=A remoção de uma aplicação OAuth2 impedi-la-á de aceder a contas de utilizador autorizadas nesta instância. Quer continuar?
+oauth2_application_locked=O Gitea pré-regista algumas aplicações OAuth2 no arranque, se forem habilitadas na configuração. Para evitar comportamentos inesperados, estas não podem ser editadas nem removidas. Consulte a documentação sobre o OAuth2 para obter mais informações.
authorized_oauth2_applications=Aplicações OAuth2 autorizadas
authorized_oauth2_applications_description=Concedeu acesso à sua conta pessoal do Gitea a estas aplicações de terceiros. Por favor, revogue o acesso às aplicações que já não precisa.
@@ -918,20 +939,26 @@ revoke_oauth2_grant=Revogar acesso
revoke_oauth2_grant_description=Revogar o acesso desta aplicação de terceiros impedi-la-á de aceder aos seus dados. Tem a certeza?
revoke_oauth2_grant_success=Acesso revogado com sucesso.
+twofa_desc=Para proteger a sua conta contra o roubo de senhas, pode usar um telemóvel ou outro dispositivo para recerber um código de utilização única baseado no tempo ("TOTP").
twofa_recovery_tip=Se perder o seu dispositivo, poderá usar uma chave de recuperação de utilização única para voltar a ter acesso à sua conta.
twofa_is_enrolled=A autenticação em dois passos está neste momento habilitada na sua conta.
twofa_not_enrolled=A autenticação em dois passos não está neste momento habilitada na sua conta.
twofa_disable=Desabilitar autenticação em dois passos
+twofa_scratch_token_regenerate=Voltar a gerar o código de recuperação de utilização única
+twofa_scratch_token_regenerated=O seu código de recuperação de utilização única agora é %s. Guarde-o num lugar seguro, uma vez que nunca mais vai ser mostrado.
twofa_enroll=Habilitar autenticação em dois passos
twofa_disable_note=Pode desabilitar a autenticação em dois passos, se for necessário.
twofa_disable_desc=Desabilitar a autenticação em dois passos tornará a sua conta menos segura. Quer continuar?
+regenerate_scratch_token_desc=Se perdeu o seu código de recuperação ou já o usou para iniciar uma sessão, pode restaurá-lo aqui.
twofa_disabled=A autenticação em dois passos foi desabilitada.
scan_this_image=Digitalize esta imagem com a sua aplicação de autenticação:
or_enter_secret=Ou insira o segredo: %s
then_enter_passcode=E insira o código apresentado na aplicação:
passcode_invalid=O código está errado. Tente de novo.
+twofa_enrolled=A sua conta foi registada com sucesso. Guarde o seu código de recuperação de utilização única (%s) num lugar seguro, uma vez que não vai ser mostrado novamente.
twofa_failed_get_secret=Falhou a obtenção do segredo.
+webauthn_desc=Chaves de segurança são dispositivos de hardware contendo chaves criptográficas. Podem ser usadas para autenticação em dois passos. As chaves de segurança têm de suportar o standard Autenticador WebAuthn.
webauthn_register_key=Adicionar chave de segurança
webauthn_nickname=Apelido
webauthn_delete_key=Remover chave de segurança
@@ -969,10 +996,12 @@ visibility=Visibilidade do utilizador
visibility.public=Pública
visibility.public_tooltip=VisÃvel para todos
visibility.limited=Limitada
+visibility.limited_tooltip=VisÃvel apenas para utilizadores autenticados
visibility.private=Privada
visibility.private_tooltip=VisÃvel apenas para membros das organizações a que se associou
[repo]
+new_repo_helper=Um repositório contém todos os ficheiros do trabalho, incluindo o histórico das revisões. Já tem um hospedado noutro sÃtio? Migre o repositório.
owner=Proprietário(a)
owner_helper=Algumas organizações podem não aparecer na lista suspensa devido a um limite máximo de contagem de repositórios.
repo_name=Nome do repositório
@@ -984,6 +1013,7 @@ template_helper=Fazer do repositório um modelo
template_description=Repositórios modelo permitem que os utilizadores gerem novos repositórios com a mesma estrutura de pastas, ficheiros e configurações opcionais.
visibility=Visibilidade
visibility_description=Somente o proprietário ou os membros da organização, se tiverem direitos, poderão vê-lo.
+visibility_helper=Tornar o repositório privado
visibility_helper_forced=O administrador obriga a que os repositórios novos sejam privados.
visibility_fork_helper=(alterar este parâmetro irá alterar também todas as derivações)
clone_helper=Precisa de ajuda para clonar? Visite a Ajuda.
@@ -1013,6 +1043,7 @@ issue_labels_helper=Escolha um conjunto de rótulos para as questões.
license=Licença
license_helper=Escolha um ficheiro de licença.
license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu trabalho? Veja: Escolher uma licença.
+multiple_licenses=Múltiplas licenças
object_format=Formato dos elementos
object_format_helper=Formato dos elementos do repositório. Não poderá ser alterado mais tarde. SHA1 é o mais compatÃvel.
readme=README
@@ -1036,6 +1067,8 @@ mirror_sync=sincronizado
mirror_sync_on_commit=Sincronizar quando forem enviados cometimentos
mirror_address=Clonar a partir do URL
mirror_address_desc=Coloque, na secção de autorização, as credenciais que, eventualmente, sejam necessárias.
+mirror_address_url_invalid=O URL fornecido é inválido. Tem que codificar adequadamente todos os componentes do URL.
+mirror_address_protocol_invalid=O URL fornecido é inválido. Só se pode replicar a partir de endereços http(s):// ou git://.
mirror_lfs=Armazenamento de Ficheiros Grandes (LFS)
mirror_lfs_desc=Habilitar a réplica de dados LFS.
mirror_lfs_endpoint=Destino LFS
@@ -1071,7 +1104,9 @@ tree_path_not_found_branch=A localização %[1]s não existe no ramo %[2]s
tree_path_not_found_tag=A localização %[1]s não existe na etiqueta %[2]s
transfer.accept=Aceitar transferência
+transfer.accept_desc=`Transferir para "%s"`
transfer.reject=Rejeitar transferência
+transfer.reject_desc=`Cancelar transferência para "%s"`
transfer.no_permission_to_accept=Você não tem permissão para aceitar esta transferência.
transfer.no_permission_to_reject=Você não tem permissão para rejeitar esta transferência.
@@ -1093,6 +1128,8 @@ template.issue_labels=Rótulos das questões
template.one_item=Tem que escolher pelo menos um item do modelo
template.invalid=Tem que escolher um repositório modelo
+archive.title=Este repositório está arquivado. Pode ver os seus ficheiros e cloná-lo, mas não pode fazer envios para o repositório nem lançar questões ou fazer pedidos de integração.
+archive.title_date=Este repositório foi arquivado em %s. Pode ver os ficheiros e cloná-lo, mas não pode fazer envios ou abrir questões ou pedidos de integração.
archive.issue.nocomment=Este repositório está arquivado. Não pode comentar nas questões.
archive.pull.nocomment=Este repositório está arquivado. Não pode comentar nos pedidos de integração.
@@ -1144,6 +1181,11 @@ migrate.gogs.description=Migrar dados de notabug.org ou de outras instâncias do
migrate.onedev.description=Migrar dados de code.onedev.io ou de outras instâncias do OneDev.
migrate.codebase.description=Migrar dados de codebasehq.com.
migrate.gitbucket.description=Migrar dados de instâncias do GitBucket.
+migrate.codecommit.description=Migrar dados de AWS CodeCommit.
+migrate.codecommit.aws_access_key_id=ID da chave de acesso AWS
+migrate.codecommit.aws_secret_access_key=Chave de acesso secreto AWS
+migrate.codecommit.https_git_credentials_username=Nome de utilizador das credenciais Git para HTTPS
+migrate.codecommit.https_git_credentials_password=Senha das credenciais Git para HTTPS
migrate.migrating_git=Migrando dados Git
migrate.migrating_topics=Migrando tópicos
migrate.migrating_milestones=Migrando etapas
@@ -1204,6 +1246,7 @@ releases=Lançamentos
tag=Etiqueta
released_this=lançou isto
tagged_this=etiquetou isto
+file.title=%s em %s
file_raw=Em bruto
file_history=Histórico
file_view_source=Ver código-fonte
@@ -1220,6 +1263,7 @@ ambiguous_runes_header=`Este ficheiro contém caracteres Unicode ambÃguos`
ambiguous_runes_description=`Este ficheiro contém caracteres Unicode que podem ser confundidos com outros caracteres. Se acha que é intencional, pode ignorar este aviso com segurança. Use o botão Revelar para os mostrar.`
invisible_runes_line=`Esta linha tem caracteres unicode invisÃveis`
ambiguous_runes_line=`Esta linha tem caracteres unicode ambÃguos`
+ambiguous_character=`%[1]c [U+%04[1]X] pode confundir-se com %[2]c [U+%04[2]X]`
escape_control_characters=Revelar
unescape_control_characters=Esconder
@@ -1240,7 +1284,6 @@ commit_graph.color=Colorido
commit.contained_in=Este cometimento está contido em:
commit.contained_in_default_branch=Este cometimento é parte do ramo principal
commit.load_referencing_branches_and_tags=Carregar ramos e etiquetas que referenciem este cometimento
-commit.load_tags_failed=O carregamento das etiquetas falhou por causa de um erro interno
blame=Responsabilidade
download_file=Descarregar ficheiro
normal_view=Vista normal
@@ -1380,6 +1423,7 @@ projects.column.new=Nova coluna
projects.column.set_default=Tornar predefinida
projects.column.set_default_desc=Definir esta coluna como a predefinida para questões e pedidos de integração não categorizados
projects.column.delete=Eliminar coluna
+projects.column.deletion_desc=Eliminar uma coluna de um planeamento faz com que todas as questões que nela constam sejam movidas para a coluna predefinida. Continuar?
projects.column.color=Colorido
projects.open=Abrir
projects.close=Fechar
@@ -1461,6 +1505,7 @@ issues.delete_branch_at=`eliminou o ramo %s %s`
issues.filter_label=Rótulo
issues.filter_label_exclude=`Use alt
+ clique/enter
para excluir rótulos`
issues.filter_label_no_select=Todos os rótulos
+issues.filter_label_select_no_label=Sem rótulo
issues.filter_milestone=Etapa
issues.filter_milestone_all=Todas as etapas
issues.filter_milestone_none=Sem etapas
@@ -1625,6 +1670,7 @@ issues.tracking_already_started=`Você já iniciou a contagem de tempo documentação para ver os detalhes da sintaxe. Exemplos: main
, {main,release*}
.
settings.authorization_header=Cabeçalho de Autorização
settings.authorization_header_desc=Será incluÃdo como cabeçalho de autorização para pedidos, quando estiver presente. Exemplos: %s.
settings.active=Em funcionamento
@@ -2325,6 +2392,7 @@ settings.protected_branch.save_rule=Guardar regra
settings.protected_branch.delete_rule=Eliminar regra
settings.protected_branch_can_push=Permitir envios?
settings.protected_branch_can_push_yes=Pode enviar
+settings.protected_branch_can_push_no=Não pode enviar
settings.branch_protection=Regras de salvaguarda do ramo '%s'
settings.protect_this_branch=Habilitar salvaguarda do ramo
settings.protect_this_branch_desc=Impede a eliminação e restringe envios e integrações do Git no ramo.
@@ -2355,11 +2423,13 @@ settings.protect_merge_whitelist_teams=Equipas com permissão para executar inte
settings.protect_check_status_contexts=Habilitar verificação de estado
settings.protect_status_check_patterns=Padrões de verificação de estado:
settings.protect_status_check_patterns_desc=Insira padrões para especificar que verificações de estado têm de passar antes que os ramos possam ser integrados num ramo correspondente a esta regra. Cada linha especifÃca um padrão. Os padrões não podem estar em branco.
+settings.protect_check_status_contexts_desc=Exigir que as verificações de estado passem antes de ser aplicada a integração. Quando habilitado, os cometimentos primeiro têm de ser enviados para outro ramo, depois integrados ou enviados imediatamente para um ramo que corresponda a esta regra, após terem passado as verificações de estado. Se não houver correspondência com quaisquer contextos, o último cometimento tem que ser bem sucedido, independentemente do contexto.
settings.protect_check_status_contexts_list=Verificações de estado encontradas na última semana para este repositório
settings.protect_status_check_matched=Correspondido
settings.protect_invalid_status_check_pattern=Padrão de verificação de estado inválido: "%s".
settings.protect_no_valid_status_check_patterns=Não existem padrões de verificação de estado válidos.
settings.protect_required_approvals=Aprovações necessárias:
+settings.protect_required_approvals_desc=Permitir somente a integração constante de pedidos que tenham aprovações exigidas suficientes. Aprovações exigidas são as dos utilizadores ou das equipas ou de qualquer pessoa que esteja na lista de permissão com acesso de escrita.
settings.protect_approvals_whitelist_enabled=Restringir aprovações a utilizadores ou equipas da lista de permissão
settings.protect_approvals_whitelist_enabled_desc=Somente as revisões dos utilizadores ou equipas da lista de permissão irão contar para as aprovações necessárias. Se não houver uma lista de permissão de aprovações, revisões de qualquer pessoa com acesso de escrita contam para as aprovações necessárias.
settings.protect_approvals_whitelist_users=Revisores com permissão:
@@ -2371,14 +2441,18 @@ settings.ignore_stale_approvals_desc=Não contar as aprovações feitas em comet
settings.require_signed_commits=Exigir cometimentos assinados
settings.require_signed_commits_desc=Rejeitar envios para este ramo que não estejam assinados ou que não sejam validáveis.
settings.protect_branch_name_pattern=Padrão do nome do ramo protegido
+settings.protect_branch_name_pattern_desc=Padrões de nomes de ramos protegidos. Consulte a documentação para ver a sintaxe dos padrões. Exemplos: main, release/**
settings.protect_patterns=Padrões
settings.protect_protected_file_patterns=Padrões de ficheiros protegidos (separados com ponto e vÃrgula ';'):
+settings.protect_protected_file_patterns_desc=Ficheiros protegidos não podem ser modificados imediatamente, mesmo que o utilizador tenha direitos para adicionar, editar ou eliminar ficheiros neste ramo. Múltiplos padrões podem ser separados com ponto e vÃrgula (';'). Veja a documentação %[2]s para ver a sintaxe. Exemplos: .drone.yml
, /docs/**/*.txt
.
settings.protect_unprotected_file_patterns=Padrões de ficheiros desprotegidos (separados com ponto e vÃrgula ';'):
+settings.protect_unprotected_file_patterns_desc=Ficheiros desprotegidos que podem ser modificados imediatamente se o utilizador tiver direitos de escrita, contornando a restrição no envio. Padrões múltiplos podem ser separados com ponto e vÃrgula (';'). Veja a documentação %[2]s para ver a sintaxe. Exemplos: .drone.yml
, /docs/**/*.txt
.
settings.add_protected_branch=Habilitar salvaguarda
settings.delete_protected_branch=Desabilitar salvaguarda
settings.update_protect_branch_success=A salvaguarda do ramo "%s" foi modificada.
settings.remove_protected_branch_success=A salvaguarda do ramo "%s" foi removida.
settings.remove_protected_branch_failed=A remoção da regra "%s" de salvaguarda do ramo falhou.
+settings.protected_branch_deletion=Eliminar salvaguarda do ramo
settings.protected_branch_deletion_desc=Desabilitar a salvaguarda do ramo irá permitir que os utilizadores que tenham permissão de escrita enviem para o ramo. Quer continuar?
settings.block_rejected_reviews=Bloquear a integração quando há revisões rejeitadas
settings.block_rejected_reviews_desc=A integração não será possÃvel quando as modificações forem pedidas pelos revisores oficiais, mesmo que haja aprovações suficientes.
@@ -2404,6 +2478,7 @@ settings.tags.protection.allowed.teams=Equipas com permissão
settings.tags.protection.allowed.noone=Ninguém
settings.tags.protection.create=Proteger etiqueta
settings.tags.protection.none=Não há etiquetas protegidas.
+settings.tags.protection.pattern.description=Pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias etiquetas. Para mais informações leia o guia das etiquetas protegidas.
settings.bot_token=Código do bot
settings.chat_id=ID do diálogo
settings.thread_id=ID da discussão
@@ -2431,6 +2506,11 @@ settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sid
settings.archive.branchsettings_unavailable=As configurações dos ramos não estão disponÃveis quando o repositório está arquivado.
settings.archive.tagsettings_unavailable=As configurações sobre etiquetas não estão disponÃveis quando o repositório está arquivado.
settings.archive.mirrors_unavailable=As réplicas não estão disponÃveis se o repositório estiver arquivado.
+settings.unarchive.button=Desarquivar repositório
+settings.unarchive.header=Desarquivar este repositório
+settings.unarchive.text=Desarquivar o repositório irá restaurar a capacidade de receber cometimentos e envios, assim como novas questões e pedidos de integração.
+settings.unarchive.success=O repositório foi desarquivado com sucesso.
+settings.unarchive.error=Ocorreu um erro enquanto decorria o processo de desarquivar o repositório. Veja os registos para obter mais detalhes.
settings.update_avatar_success=O avatar do repositório foi modificado.
settings.lfs=LFS
settings.lfs_filelist=Ficheiros LFS armazenados neste repositório
@@ -2492,6 +2572,7 @@ diff.file_image_height=Altura
diff.file_byte_size=Tamanho
diff.file_suppressed=A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
diff.file_suppressed_line_too_long=A apresentação das diferenças entre ficheiros foi suprimida porque há linhas demasiado longas
+diff.too_many_files=Alguns ficheiros não foram mostrados porque foram modificados demasiados ficheiros neste diff
diff.show_more=Mostrar mais
diff.load=Carregar diff
diff.generated=gerado
@@ -2612,6 +2693,7 @@ tag.create_success=A etiqueta "%s" foi criada.
topic.manage_topics=Gerir tópicos
topic.done=ConcluÃdo
+topic.count_prompt=Não pode escolher mais do que 25 tópicos
topic.format_prompt=Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') ou pontos ('.') e podem ter até 35 caracteres. As letras têm que ser minúsculas.
find_file.go_to_file=Ir para o ficheiro
@@ -2751,6 +2833,7 @@ teams.all_repositories_helper=A equipa tem acesso a todos os repositórios. Esco
teams.all_repositories_read_permission_desc=Esta equipa atribui o acesso de leitura a todos os repositórios: os seus membros podem ver e clonar os repositórios.
teams.all_repositories_write_permission_desc=Esta equipa atribui o acesso de escrita a todos os repositórios: os seus membros podem ler de, e enviar para os repositórios.
teams.all_repositories_admin_permission_desc=Esta equipa atribui o acesso de administração a todos os repositórios: os seus membros podem ler de, enviar para, e adicionar colaboradores aos repositórios.
+teams.invite.title=Foi-lhe feito um convite para se juntar à equipa %s na organização%s.
teams.invite.by=Convidado(a) por %s
teams.invite.description=Clique no botão abaixo para se juntar à equipa.
@@ -2777,6 +2860,7 @@ last_page=Última
total=total: %d
settings=Configurações de administração
+dashboard.new_version_hint=O Gitea %s está disponÃvel, você está a correr a versão %s. Verifique o blog para mais detalhes.
dashboard.statistic=Resumo
dashboard.maintenance_operations=Operações de manutenção
dashboard.system_status=Estado do sistema
@@ -2787,6 +2871,7 @@ dashboard.clean_unbind_oauth=Limpar conexões OAuth não vinculadas
dashboard.clean_unbind_oauth_success=Todas as conexões OAuth não vinculadas foram eliminadas.
dashboard.task.started=Tarefa iniciada: %[1]s
dashboard.task.process=Tarefa: %[1]s
+dashboard.task.cancelled=Tarefa: %[1]s cancelada: %[3]s
dashboard.task.error=Erro na tarefa: %[1]s: %[3]s
dashboard.task.finished=Tarefa: %[1]s iniciada por %[2]s foi concluÃda
dashboard.task.unknown=Tarefa desconhecida: %[1]s
@@ -2860,6 +2945,7 @@ dashboard.start_schedule_tasks=Iniciar tarefas de agendamento das operações
dashboard.sync_branch.started=Sincronização de ramos iniciada
dashboard.sync_tag.started=Sincronização de etiquetas iniciada
dashboard.rebuild_issue_indexer=Reconstruir indexador de questões
+dashboard.sync_repo_licenses=Sincronizar licenças do repositório
users.user_manage_panel=Gestão das contas de utilizadores
users.new_account=Criar conta de utilizador
@@ -2930,6 +3016,7 @@ emails.updated=Email modificado
emails.not_updated=Falhou a modificação do endereço de email solicitado: %v
emails.duplicate_active=Este endereço de email já está a ser usado por outro utilizador.
emails.change_email_header=Modificar propriedades do email
+emails.change_email_text=Tem a certeza que quer modificar este endereço de email?
emails.delete=Eliminar email
emails.delete_desc=Tem a certeza que quer eliminar este endereço de email?
emails.deletion_success=O endereço de email foi eliminado.
@@ -2966,10 +3053,12 @@ packages.size=Tamanho
packages.published=Publicado
defaulthooks=Automatismos web predefinidos
+defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os predefinidos e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web.
defaulthooks.add_webhook=Adicionar automatismo web predefinido
defaulthooks.update_webhook=Modificar automatismo web predefinido
systemhooks=Automatismos web do sistema
+systemhooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui irão operar em todos os repositórios deste sistema, por isso tenha em consideração quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de automatismos web.
systemhooks.add_webhook=Adicionar automatismo web do sistema
systemhooks.update_webhook=Modificar automatismo web do sistema
@@ -3064,8 +3153,18 @@ auths.tips=Dicas
auths.tips.oauth2.general=Autenticação OAuth2
auths.tips.oauth2.general.tip=Ao registar uma nova autenticação OAuth2, o URL da ligação de retorno ou do reencaminhamento deve ser:
auths.tip.oauth2_provider=Fornecedor OAuth2
+auths.tip.bitbucket=Registe um novo consumidor de OAuth em %s e adicione a permissão 'Account' - 'Read'
auths.tip.nextcloud=`Registe um novo consumidor OAuth na sua instância usando o seguinte menu "Configurações → Segurança → Cliente OAuth 2.0"`
+auths.tip.dropbox=Crie uma nova aplicação em %s
+auths.tip.facebook=`Registe uma nova aplicação em %s e adicione o produto "Facebook Login"`
+auths.tip.github=Registe uma nova aplicação OAuth em %s
+auths.tip.gitlab_new=Registe uma nova aplicação em %s
+auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola do Google API em %s
auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID "https://{server}/.well-known/openid-configuration" para especificar os extremos
+auths.tip.twitter=`Vá a %s, crie uma aplicação e certifique-se de que está habilitada a opção "Allow this application to be used to Sign in with Twitter"`
+auths.tip.discord=Registe uma nova aplicação em %s
+auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em %s
+auths.tip.yandex=`Crie uma nova aplicação em %s. Escolha as seguintes permissões da secção "Yandex.Passport API": "Acesso ao endereço de email", "Acesso ao avatar do utilizador" e "Acesso ao nome de utilizador, nome e sobrenome, género"`
auths.tip.mastodon=Insira o URL de uma instância personalizada para a instância do mastodon com que se pretende autenticar (ou então use a predefinida)
auths.edit=Editar fonte de autenticação
auths.activated=Esta fonte de autenticação está em funcionamento
@@ -3231,6 +3330,7 @@ monitor.next=Próxima execução
monitor.previous=Execução anterior
monitor.execute_times=Execuções
monitor.process=Processos em execução
+monitor.stacktrace=VestÃgios da pilha
monitor.processes_count=%d processos
monitor.download_diagnosis_report=Descarregar relatório de diagnóstico
monitor.desc=Descrição
@@ -3238,6 +3338,8 @@ monitor.start=InÃcio
monitor.execute_time=Tempo de execução
monitor.last_execution_result=Resultado
monitor.process.cancel=Cancelar processo
+monitor.process.cancel_desc=Cancelar um processo pode resultar na perda de dados
+monitor.process.cancel_notices=Cancelar: %s?
monitor.process.children=Descendentes
monitor.queues=Filas
@@ -3339,6 +3441,7 @@ raw_minutes=minutos
[dropzone]
default_message=Largue os ficheiros aqui ou clique aqui para os carregar.
+invalid_input_type=Não pode carregar ficheiros deste tipo.
file_too_big=O tamanho do ficheiro ({{filesize}} MB) excede o tamanho máximo de ({{maxFilesize}} MB).
remove_file=Remover ficheiro
@@ -3486,6 +3589,7 @@ settings.link=Vincular este pacote a um repositório
settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório.
settings.link.select=Escolha o repositório
settings.link.button=Modificar vÃnculo ao repositório
+settings.link.success=A ligação ao repositório foi modificada com sucesso.
settings.link.error=Falhou a modificação do vÃnculo ao repositório.
settings.delete=Eliminar pacote
settings.delete.description=Eliminar o pacote é permanente e não pode ser desfeito.
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index 20e82273cb..7fd73f9d83 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -182,8 +182,6 @@ string.desc=Я - Ð
[error]
occurred=Произошла ошибка
-missing_csrf=Ðекорректный запроÑ: отÑутÑтвует токен CSRF
-invalid_csrf=Ðекорректный запроÑ: неверный токен CSRF
not_found=Цель не найдена.
network_error=Ошибка Ñети
@@ -620,7 +618,6 @@ public_profile=Открытый профиль
biography_placeholder=РаÑÑкажите немного о Ñебе! (Можно иÑпользовать Markdown)
location_placeholder=ПоделитеÑÑŒ Ñвоим приблизительным меÑтоположением Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸
profile_desc=Контролируйте, как ваш профиль будет отображатьÑÑ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ пользователÑм. Ваш оÑновной Ð°Ð´Ñ€ÐµÑ Ñлектронной почты будет иÑпользоватьÑÑ Ð´Ð»Ñ ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ð¹, воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð¸ веб-операций Git.
-password_username_disabled=Ðелокальным пользователÑм запрещено изменение их имени пользователÑ. Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÐµÐµ подробной информации обратитеÑÑŒ к админиÑтратору Ñайта.
full_name=Ð˜Ð¼Ñ Ð¸ фамилиÑ
website=Веб-Ñайт
location=МеÑтоположение
@@ -1578,7 +1575,6 @@ issues.dependency.add_error_dep_not_same_repo=Обе задачи должны
issues.review.self.approval=Ð’Ñ‹ не можете одобрить ÑобÑтвенный Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние.
issues.review.self.rejection=Ðевозможно запрашивать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñвоего запроÑа на ÑлиÑние.
issues.review.approve=одобрил(а) Ñти Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ %s
-issues.review.comment=Комментировать
issues.review.dismissed=отклонен отзыв %s %s
issues.review.dismissed_label=Отклонено
issues.review.left_comment=оÑтавил комментарий
@@ -1602,6 +1598,7 @@ issues.review.hide_resolved=Скрыть разрешенные
issues.review.resolve_conversation=Покинуть диалог
issues.review.un_resolve_conversation=Ðезавершённый разговор
issues.review.resolved_by=пометить Ñтот разговор как разрешённый
+issues.review.commented=Комментировать
issues.assignee.error=Ðе вÑе Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¸ добавлены из-за непредвиденной ошибки.
issues.reference_issue.body=Тело
issues.content_history.deleted=удалено
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 077a4014e8..4d64c46e6e 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -118,7 +118,6 @@ filter.private=පෞද්ගලික
[filter]
[error]
-missing_csrf=නරක ඉල්ලීම: CSRF ටà·à¶šà¶±à·Š නොමà·à¶
[startpage]
app_desc=වේදනà·à¶šà·à¶»à·“, ස්වයං-à·ƒà¶à·Šà¶šà·à¶»à¶š Git සේවà·à·€à¶šà·Š
@@ -481,7 +480,6 @@ account_link=සම්බන්ධිචගිණුම්
organization=සංවිධà·à¶±
public_profile=ප්â€à¶»à·ƒà·’ද්ධ පà·à¶à·’කඩ
-password_username_disabled=දේà·à·“ය නොවන පරිà·à·“ලකයින්ට ඔවුන්ගේ පරිà·à·“ලක නà·à¶¸à¶º වෙනස් කිරීමට අවසර නà·à¶. à·€à·à¶©à·’ විස්à¶à¶» සඳහ෠කරුණà·à¶šà¶» ඔබේ වෙබ් අඩවිය පරිපà·à¶½à¶š අමà¶à¶±à·Šà¶±.
full_name=සම්පූර්ණ නම
website=වියමන අඩවිය
location=ස්ථà·à¶±à¶º
@@ -1200,7 +1198,6 @@ issues.dependency.add_error_dep_not_same_repo=මෙම ගà·à¶§à·…à·” දෙ
issues.review.self.approval=ඔබ ඔබේ ම අදින්න ඉල්ලීම අනුමචකළ නොහà·à¶š.
issues.review.self.rejection=ඔබ ඔබේ ම අදින්න ඉල්ලීම මචවෙනස්කම් ඉල්ල෠සිටිය නොහà·à¶š.
issues.review.approve=මෙම වෙනස්කම් අනුමච%s
-issues.review.comment=අදහස
issues.review.dismissed=%sà·„à·’ සමà·à¶½à·à¶ නය %sප්රà¶à·’ක්ෂේප කරන ලද
issues.review.dismissed_label=බà·à·„à·à¶»
issues.review.left_comment=අදහසක් à·„à·à¶»à¶œà·’යà·
@@ -1221,6 +1218,7 @@ issues.review.hide_resolved=විසඳ෠සඟවන්න
issues.review.resolve_conversation=සංවà·à¶¯à¶º විසඳන්න
issues.review.un_resolve_conversation=නොවිසඳිය à·„à·à¶šà·’ සංවà·à¶¯à¶º
issues.review.resolved_by=මෙම සංවà·à¶¯à¶º විසඳ෠ඇà¶à·’ පරිදි සලකුණු කර ඇà¶
+issues.review.commented=අදහස
issues.assignee.error=අනපේක්ෂිචදà·à·‚යක් à·„à·šà¶à·”වෙන් සියලුම ඇසිග්නස් එකà¶à·” නොකළේය.
issues.reference_issue.body=à·à¶»à·“රය
issues.content_history.deleted=මක෠දà·à¶¸à·–
diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini
index d27dfa83bc..a964b526af 100644
--- a/options/locale/locale_sk-SK.ini
+++ b/options/locale/locale_sk-SK.ini
@@ -181,8 +181,6 @@ string.desc=Z - A
[error]
occurred=Vyskytla sa chyba
-missing_csrf=Nesprávna žiadosÅ¥: neprÃtomný CSFR token
-invalid_csrf=Nesprávna žiadosť: nesprávny CSFR token
not_found=Nebolo možné nájsť cieľ.
network_error=Chyba siete
@@ -585,7 +583,6 @@ account_link=Prepojené úÄty
organization=Organizácie
public_profile=Verejný profil
-password_username_disabled=Externà použÃvatelia nemôžu meniÅ¥ svoje použÃvateľské meno. Kontaktujte, prosÃm, svojho administrátora kvôli detailom.
full_name=Celé meno
website=Webová stránka
location=Miesto
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index 34c70ab422..2993828c22 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -418,7 +418,6 @@ account_link=Länkade Konton
organization=Organisationer
public_profile=Offentlig profil
-password_username_disabled=Externa användare kan inte ändra sitt användarnamn. Kontakta din webbadministratör för mera information.
full_name=Fullständigt namn
website=Webbplats
location=Plats
@@ -1039,7 +1038,6 @@ issues.dependency.add_error_dep_not_same_repo=Båda ärendena måste vara i samm
issues.review.self.approval=Du kan inte godkänna din egen pull-begäran.
issues.review.self.rejection=Du kan inte begära ändringar för din egna pull-förfrågan.
issues.review.approve=godkände dessa ändringar %s
-issues.review.comment=Kommentar
issues.review.left_comment=lämnade en kommentar
issues.review.content.empty=Du måste skriva en kommentar som anger de önskade ändringarna.
issues.review.reject=begärda ändringar %s
@@ -1056,6 +1054,7 @@ issues.review.show_resolved=Visa löst
issues.review.hide_resolved=Dölj löst
issues.review.resolve_conversation=Lös konversation
issues.review.resolved_by=markerade denna konversation som löst
+issues.review.commented=Kommentar
issues.assignee.error=Inte alla tilldelade har lagts till på grund av ett oväntat fel.
issues.content_history.options=Alternativ
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index d388e79c27..3c719f84ba 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -218,8 +218,6 @@ string.desc=Z - A
[error]
occurred=Bir hata oluÅŸtu
-missing_csrf=Hatalı İstek: CSRF anahtarı yok
-invalid_csrf=Hatalı İstek: geçersiz CSRF erişim anahtarı
not_found=Hedef bulunamadı.
network_error=Ağ hatası
@@ -696,7 +694,6 @@ public_profile=Herkese Açık Profil
biography_placeholder=Bize kendiniz hakkında birşeyler söyleyin! (Markdown kullanabilirsiniz)
location_placeholder=Yaklaşık konumunuzu başkalarıyla paylaşın
profile_desc=Profilinizin başkalarına nasıl gösterildiğini yönetin. Ana e-posta adresiniz bildirimler, parola kurtarma ve web tabanlı Git işlemleri için kullanılacaktır.
-password_username_disabled=Yerel olmayan kullanıcılara kullanıcı adlarını değiştirme izni verilmemiştir. Daha fazla bilgi edinmek için lütfen site yöneticisi ile iletişime geçiniz.
full_name=Ad Soyad
website=Web Sitesi
location=Konum
@@ -1704,7 +1701,6 @@ issues.dependency.add_error_dep_not_same_repo=Her iki konu da aynı depoda olmal
issues.review.self.approval=Kendi değişiklik isteğinizi onaylayamazsınız.
issues.review.self.rejection=Kendi deÄŸiÅŸiklik isteÄŸinizde deÄŸiÅŸiklik isteyemezsiniz.
issues.review.approve=%s bu değişiklikleri onayladı
-issues.review.comment=Yorum Yap
issues.review.dismissed=%s incelemesini %s reddetti
issues.review.dismissed_label=Reddedildi
issues.review.left_comment=bir yorum yaptı
@@ -1729,6 +1725,7 @@ issues.review.hide_resolved=Çözülenleri gizle
issues.review.resolve_conversation=Konuşmayı çöz
issues.review.un_resolve_conversation=Konuşmayı çözme
issues.review.resolved_by=bu konuşmayı çözümlenmiş olarak işaretledi
+issues.review.commented=Yorum Yap
issues.assignee.error=Beklenmeyen bir hata nedeniyle tüm atananlar eklenmedi.
issues.reference_issue.body=Gövde
issues.content_history.deleted=silindi
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index b8b7a29037..d94d11207b 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -120,7 +120,6 @@ filter.private=Приватний
[error]
occurred=СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°
-missing_csrf=Ðекоректний запит: токен CSRF не задано
network_error=Помилка мережі
[startpage]
@@ -495,7 +494,6 @@ account_link=Прив'Ñзані облікові запиÑи
organization=Організації
public_profile=ЗагальнодоÑтупний профіль
-password_username_disabled=Ðелокальним кориÑтувачам заборонено змінювати ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача. Щоб отримати докладнішу інформацію, зв'ÑжітьÑÑ Ð· адмініÑтратором Ñайту.
full_name=Повне ім'Ñ
website=Веб-Ñайт
location=МіÑцезнаходженнÑ
@@ -1245,7 +1243,6 @@ issues.dependency.add_error_dep_not_same_repo=Обидві задачі пови
issues.review.self.approval=Ви не можете Ñхвалити влаÑний пулл-реквеÑÑ‚.
issues.review.self.rejection=Ви не можете надіÑлати запит на зміну на влаÑний пулл-реквеÑÑ‚.
issues.review.approve=зміни затверджено %s
-issues.review.comment=Коментар
issues.review.dismissed=відхилено відгук %s %s
issues.review.dismissed_label=Відхилено
issues.review.left_comment=додав коментар
@@ -1266,6 +1263,7 @@ issues.review.hide_resolved=Приховати вирішене
issues.review.resolve_conversation=Завершити обговореннÑ
issues.review.un_resolve_conversation=Поновити обговореннÑ
issues.review.resolved_by=позначив Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ð¼
+issues.review.commented=Коментар
issues.assignee.error=Додано не вÑÑ–Ñ… виконавців через непередбачену помилку.
issues.reference_issue.body=Тіло
issues.content_history.deleted=видалено
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 223277b540..3be7b044e9 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -217,8 +217,6 @@ string.desc=Z - A
[error]
occurred=å‘生了一个错误
-missing_csrf=错误的请求:没有 CSRF 令牌
-invalid_csrf=é”™è¯¯çš„è¯·æ±‚ï¼šæ— æ•ˆçš„ CSRF 令牌
not_found=找ä¸åˆ°ç›®æ ‡ã€‚
network_error=网络错误
@@ -688,7 +686,6 @@ public_profile=公开信æ¯
biography_placeholder=å‘Šè¯‰æˆ‘ä»¬ä¸€ç‚¹æ‚¨è‡ªå·±ï¼ (您å¯ä»¥ä½¿ç”¨Markdown)
location_placeholder=ä¸Žä»–äººåˆ†äº«ä½ çš„å¤§æ¦‚ä½ç½®
profile_desc=控制您的个人资料对其他用户的显示方å¼ã€‚您的主è¦ç”µå邮件地å€å°†ç”¨äºŽé€šçŸ¥ã€å¯†ç æ¢å¤å’ŒåŸºäºŽç½‘页界é¢çš„ Git æ“作
-password_username_disabled=ä¸å…许éžæœ¬åœ°ç”¨æˆ·æ›´æ”¹ä»–们的用户å。更多详情请è”系您的系统管ç†å‘˜ã€‚
full_name=自定义å称
website=个人网站
location=所在地区
@@ -1692,7 +1689,6 @@ issues.dependency.add_error_dep_not_same_repo=这两个工å•å¿…须在åŒä¸€ä»“
issues.review.self.approval=您ä¸èƒ½æ‰¹å‡†æ‚¨è‡ªå·±çš„åˆå¹¶è¯·æ±‚。
issues.review.self.rejection=您ä¸èƒ½è¯·æ±‚对您自己的åˆå¹¶è¯·æ±‚进行更改。
issues.review.approve=于 %s 批准æ¤åˆå¹¶è¯·æ±‚
-issues.review.comment=评论
issues.review.dismissed=于 %[2]s å–消了 %[1]s 的评审
issues.review.dismissed_label=å·²å–消
issues.review.left_comment=留下了一æ¡è¯„论
@@ -1717,6 +1713,7 @@ issues.review.hide_resolved=éšè—已解决的
issues.review.resolve_conversation=已解决问题
issues.review.un_resolve_conversation=未解决问题
issues.review.resolved_by=æ ‡è®°é—®é¢˜ä¸ºå·²è§£å†³
+issues.review.commented=评论
issues.assignee.error=å› ä¸ºæœªçŸ¥åŽŸå› ï¼Œå¹¶éžæ‰€æœ‰çš„指派都æˆåŠŸã€‚
issues.reference_issue.body=内容
issues.content_history.deleted=åˆ é™¤äºŽ
@@ -1790,6 +1787,8 @@ pulls.is_empty=æ¤åˆ†æ”¯ä¸Šçš„更改已ç»åœ¨ç›®æ ‡åˆ†æ”¯ä¸Šã€‚这将是一个
pulls.required_status_check_failed=一些必è¦çš„检查没有æˆåŠŸ
pulls.required_status_check_missing=缺少一些必è¦çš„检查。
pulls.required_status_check_administrator=作为管ç†å‘˜ï¼Œæ‚¨ä»å¯åˆå¹¶æ¤åˆå¹¶è¯·æ±‚
+pulls.blocked_by_approvals=æ¤åˆå¹¶è¯·æ±‚还没有足够的批准。已获批准数 %d 个,需获批准数 %d 个。
+pulls.blocked_by_approvals_whitelisted=æ¤åˆå¹¶è¯·æ±‚还没有足够的批准。%[2]d ä¸çš„ %[1]d 个已由å…许åå•ä¸çš„用户或团队批准。
pulls.blocked_by_rejection=æ¤åˆå¹¶è¯·æ±‚æœ‰å®˜æ–¹å®¡æ ¸å‘˜è¯·æ±‚çš„æ›´æ”¹ã€‚
pulls.blocked_by_official_review_requests=æ¤åˆå¹¶è¯·æ±‚需è¦å®˜æ–¹è¯„审。
pulls.blocked_by_outdated_branch=æ¤åˆå¹¶è¯·æ±‚å› è¿‡æœŸè€Œè¢«é˜»æ¢ã€‚
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index 2eb03fa84c..d755f64dcd 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -167,8 +167,6 @@ string.desc=Z - A
[error]
occurred=發生錯誤
-missing_csrf=錯誤的請求:未æä¾› CSRF token
-invalid_csrf=錯誤的請求:無效的 CSRF token
not_found=找ä¸åˆ°ç›®æ¨™ã€‚
network_error=網路錯誤
@@ -585,7 +583,6 @@ account_link=已連çµå¸³è™Ÿ
organization=組織
public_profile=公開的個人資料
-password_username_disabled=éžæœ¬åœ°ä½¿ç”¨è€…ä¸å…許更改他們的帳號。詳細資訊請è¯çµ¡æ‚¨çš„系統管ç†å“¡ã€‚
full_name=å…¨å
website=個人網站
location=所在地å€
@@ -1467,7 +1464,6 @@ issues.dependency.add_error_dep_not_same_repo=這兩個å•é¡Œå¿…é ˆåœ¨åŒä¸€å€‹
issues.review.self.approval=您ä¸èƒ½æ ¸å¯è‡ªå·±çš„åˆä½µè«‹æ±‚。
issues.review.self.rejection=您ä¸èƒ½å°è‡ªå·±çš„åˆä½µè«‹æ±‚æ出請求變更。
issues.review.approve=æ ¸å¯äº†é€™äº›è®Šæ›´ %s
-issues.review.comment=留言
issues.review.dismissed=å–消 %s çš„å¯©æ ¸ %s
issues.review.dismissed_label=å·²å–消
issues.review.left_comment=留下了回應
@@ -1488,6 +1484,7 @@ issues.review.hide_resolved=éš±è—已解決
issues.review.resolve_conversation=解決å°è©±
issues.review.un_resolve_conversation=å–消解決å°è©±
issues.review.resolved_by=標記了æ¤å°è©±ç‚ºå·²è§£æ±º
+issues.review.commented=留言
issues.assignee.error=å› ç‚ºæœªé 期的錯誤,未能æˆåŠŸåŠ å…¥æ‰€æœ‰è² è²¬äººã€‚
issues.reference_issue.body=內容
issues.content_history.deleted=刪除
diff --git a/package-lock.json b/package-lock.json
index e0e83b60ec..ca001b2939 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,7 +29,7 @@
"esbuild-loader": "4.2.2",
"escape-goat": "4.0.0",
"fast-glob": "3.3.2",
- "htmx.org": "2.0.2",
+ "htmx.org": "2.0.3",
"idiomorph": "0.3.0",
"jquery": "3.7.1",
"katex": "0.16.11",
@@ -10548,10 +10548,9 @@
}
},
"node_modules/htmx.org": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.2.tgz",
- "integrity": "sha512-eUPIpQaWKKstX393XNCRCMJTrqPzikh36Y9RceqsUZLTtlFjFaVDgwZLUsrFk8J2uzZxkkfiy0TE359j2eN6hA==",
- "license": "0BSD"
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.3.tgz",
+ "integrity": "sha512-AeoJUAjkCVVajbfKX+3sVQBTCt8Ct4lif1T+z/tptTXo8+8yyq3QIMQQe/IT+R8ssfrO1I0DeX4CAronzCL6oA=="
},
"node_modules/human-signals": {
"version": "5.0.0",
diff --git a/package.json b/package.json
index d188e99a30..015dfc67a6 100644
--- a/package.json
+++ b/package.json
@@ -28,7 +28,7 @@
"esbuild-loader": "4.2.2",
"escape-goat": "4.0.0",
"fast-glob": "3.3.2",
- "htmx.org": "2.0.2",
+ "htmx.org": "2.0.3",
"idiomorph": "0.3.0",
"jquery": "3.7.1",
"katex": "0.16.11",
diff --git a/public/assets/img/svg/gitea-codecommit.svg b/public/assets/img/svg/gitea-codecommit.svg
new file mode 100644
index 0000000000..b44847d9e1
--- /dev/null
+++ b/public/assets/img/svg/gitea-codecommit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go
index 3d1a3891d9..cf48da12aa 100644
--- a/routers/api/actions/artifacts_chunks.go
+++ b/routers/api/actions/artifacts_chunks.go
@@ -123,6 +123,54 @@ func listChunksByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chun
return chunksMap, nil
}
+func listChunksByRunIDV4(st storage.ObjectStorage, runID, artifactID int64, blist *BlockList) ([]*chunkFileItem, error) {
+ storageDir := fmt.Sprintf("tmpv4%d", runID)
+ var chunks []*chunkFileItem
+ chunkMap := map[string]*chunkFileItem{}
+ dummy := &chunkFileItem{}
+ for _, name := range blist.Latest {
+ chunkMap[name] = dummy
+ }
+ if err := st.IterateObjects(storageDir, func(fpath string, obj storage.Object) error {
+ baseName := filepath.Base(fpath)
+ if !strings.HasPrefix(baseName, "block-") {
+ return nil
+ }
+ // when read chunks from storage, it only contains storage dir and basename,
+ // no matter the subdirectory setting in storage config
+ item := chunkFileItem{Path: storageDir + "/" + baseName, ArtifactID: artifactID}
+ var size int64
+ var b64chunkName string
+ if _, err := fmt.Sscanf(baseName, "block-%d-%d-%s", &item.RunID, &size, &b64chunkName); err != nil {
+ return fmt.Errorf("parse content range error: %v", err)
+ }
+ rchunkName, err := base64.URLEncoding.DecodeString(b64chunkName)
+ if err != nil {
+ return fmt.Errorf("failed to parse chunkName: %v", err)
+ }
+ chunkName := string(rchunkName)
+ item.End = item.Start + size - 1
+ if _, ok := chunkMap[chunkName]; ok {
+ chunkMap[chunkName] = &item
+ }
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+ for i, name := range blist.Latest {
+ chunk, ok := chunkMap[name]
+ if !ok || chunk.Path == "" {
+ return nil, fmt.Errorf("missing Chunk (%d/%d): %s", i, len(blist.Latest), name)
+ }
+ chunks = append(chunks, chunk)
+ if i > 0 {
+ chunk.Start = chunkMap[blist.Latest[i-1]].End + 1
+ chunk.End += chunk.Start
+ }
+ }
+ return chunks, nil
+}
+
func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int64, artifactName string) error {
// read all db artifacts by name
artifacts, err := db.Find[actions.ActionArtifact](ctx, actions.FindArtifactsOptions{
@@ -230,7 +278,7 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
rawChecksum := hash.Sum(nil)
actualChecksum := hex.EncodeToString(rawChecksum)
if !strings.HasSuffix(checksum, actualChecksum) {
- return fmt.Errorf("update artifact error checksum is invalid")
+ return fmt.Errorf("update artifact error checksum is invalid %v vs %v", checksum, actualChecksum)
}
}
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
index e78ed7a0c2..9e463cceeb 100644
--- a/routers/api/actions/artifactsv4.go
+++ b/routers/api/actions/artifactsv4.go
@@ -24,8 +24,15 @@ package actions
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=block
// 1.3. Continue Upload Zip Content to Blobstorage (unauthenticated request), repeat until everything is uploaded
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=appendBlock
-// 1.4. Unknown xml payload to Blobstorage (unauthenticated request), ignored for now
+// 1.4. BlockList xml payload to Blobstorage (unauthenticated request)
+// Files of about 800MB are parallel in parallel and / or out of order, this file is needed to enshure the correct order
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=blockList
+// Request
+//
+//
+// blockId1
+// blockId2
+//
// 1.5. FinalizeArtifact
// Post: /twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact
// Request
@@ -82,6 +89,7 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
+ "encoding/xml"
"fmt"
"io"
"net/http"
@@ -152,31 +160,34 @@ func ArtifactsV4Routes(prefix string) *web.Router {
return m
}
-func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID int64) []byte {
+func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID, artifactID int64) []byte {
mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
mac.Write([]byte(endp))
mac.Write([]byte(expires))
mac.Write([]byte(artifactName))
mac.Write([]byte(fmt.Sprint(taskID)))
+ mac.Write([]byte(fmt.Sprint(artifactID)))
return mac.Sum(nil)
}
-func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID int64) string {
+func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID, artifactID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(r.prefix, "/") +
- "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID)
+ "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID, artifactID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + fmt.Sprint(taskID) + "&artifactID=" + fmt.Sprint(artifactID)
return uploadURL
}
func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) {
rawTaskID := ctx.Req.URL.Query().Get("taskID")
+ rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
sig := ctx.Req.URL.Query().Get("sig")
expires := ctx.Req.URL.Query().Get("expires")
artifactName := ctx.Req.URL.Query().Get("artifactName")
dsig, _ := base64.URLEncoding.DecodeString(sig)
taskID, _ := strconv.ParseInt(rawTaskID, 10, 64)
+ artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
- expecedsig := r.buildSignature(endp, expires, artifactName, taskID)
+ expecedsig := r.buildSignature(endp, expires, artifactName, taskID, artifactID)
if !hmac.Equal(dsig, expecedsig) {
log.Error("Error unauthorized")
ctx.Error(http.StatusUnauthorized, "Error unauthorized")
@@ -271,6 +282,8 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
return
}
artifact.ContentEncoding = ArtifactV4ContentEncoding
+ artifact.FileSize = 0
+ artifact.FileCompressedSize = 0
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
log.Error("Error UpdateArtifactByID: %v", err)
ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
@@ -279,7 +292,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
respData := CreateArtifactResponse{
Ok: true,
- SignedUploadUrl: r.buildArtifactURL(ctx, "UploadArtifact", artifactName, ctx.ActionTask.ID),
+ SignedUploadUrl: r.buildArtifactURL(ctx, "UploadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID),
}
r.sendProtbufBody(ctx, &respData)
}
@@ -293,38 +306,77 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
comp := ctx.Req.URL.Query().Get("comp")
switch comp {
case "block", "appendBlock":
- // get artifact by name
- artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
- if err != nil {
- log.Error("Error artifact not found: %v", err)
- ctx.Error(http.StatusNotFound, "Error artifact not found")
- return
- }
+ blockid := ctx.Req.URL.Query().Get("blockid")
+ if blockid == "" {
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.Error(http.StatusNotFound, "Error artifact not found")
+ return
+ }
- if comp == "block" {
- artifact.FileSize = 0
- artifact.FileCompressedSize = 0
+ _, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID)
+ if err != nil {
+ log.Error("Error runner api getting task: task is not running")
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ return
+ }
+ artifact.FileCompressedSize += ctx.Req.ContentLength
+ artifact.FileSize += ctx.Req.ContentLength
+ if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
+ log.Error("Error UpdateArtifactByID: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
+ return
+ }
+ } else {
+ _, err := r.fs.Save(fmt.Sprintf("tmpv4%d/block-%d-%d-%s", task.Job.RunID, task.Job.RunID, ctx.Req.ContentLength, base64.URLEncoding.EncodeToString([]byte(blockid))), ctx.Req.Body, -1)
+ if err != nil {
+ log.Error("Error runner api getting task: task is not running")
+ ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ return
+ }
}
-
- _, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID)
+ ctx.JSON(http.StatusCreated, "appended")
+ case "blocklist":
+ rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
+ artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
+ _, err := r.fs.Save(fmt.Sprintf("tmpv4%d/%d-%d-blocklist", task.Job.RunID, task.Job.RunID, artifactID), ctx.Req.Body, -1)
if err != nil {
log.Error("Error runner api getting task: task is not running")
ctx.Error(http.StatusInternalServerError, "Error runner api getting task: task is not running")
return
}
- artifact.FileCompressedSize += ctx.Req.ContentLength
- artifact.FileSize += ctx.Req.ContentLength
- if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
- log.Error("Error UpdateArtifactByID: %v", err)
- ctx.Error(http.StatusInternalServerError, "Error UpdateArtifactByID")
- return
- }
- ctx.JSON(http.StatusCreated, "appended")
- case "blocklist":
ctx.JSON(http.StatusCreated, "created")
}
}
+type BlockList struct {
+ Latest []string `xml:"Latest"`
+}
+
+type Latest struct {
+ Value string `xml:",chardata"`
+}
+
+func (r *artifactV4Routes) readBlockList(runID, artifactID int64) (*BlockList, error) {
+ blockListName := fmt.Sprintf("tmpv4%d/%d-%d-blocklist", runID, runID, artifactID)
+ s, err := r.fs.Open(blockListName)
+ if err != nil {
+ return nil, err
+ }
+
+ xdec := xml.NewDecoder(s)
+ blockList := &BlockList{}
+ err = xdec.Decode(blockList)
+
+ delerr := r.fs.Delete(blockListName)
+ if delerr != nil {
+ log.Warn("Failed to delete blockList %s: %v", blockListName, delerr)
+ }
+ return blockList, err
+}
+
func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
var req FinalizeArtifactRequest
@@ -343,18 +395,34 @@ func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
ctx.Error(http.StatusNotFound, "Error artifact not found")
return
}
- chunkMap, err := listChunksByRunID(r.fs, runID)
+
+ var chunks []*chunkFileItem
+ blockList, err := r.readBlockList(runID, artifact.ID)
if err != nil {
- log.Error("Error merge chunks: %v", err)
- ctx.Error(http.StatusInternalServerError, "Error merge chunks")
- return
- }
- chunks, ok := chunkMap[artifact.ID]
- if !ok {
- log.Error("Error merge chunks")
- ctx.Error(http.StatusInternalServerError, "Error merge chunks")
- return
+ log.Warn("Failed to read BlockList, fallback to old behavior: %v", err)
+ chunkMap, err := listChunksByRunID(r.fs, runID)
+ if err != nil {
+ log.Error("Error merge chunks: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+ chunks, ok = chunkMap[artifact.ID]
+ if !ok {
+ log.Error("Error merge chunks")
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+ } else {
+ chunks, err = listChunksByRunIDV4(r.fs, runID, artifact.ID, blockList)
+ if err != nil {
+ log.Error("Error merge chunks: %v", err)
+ ctx.Error(http.StatusInternalServerError, "Error merge chunks")
+ return
+ }
+ artifact.FileSize = chunks[len(chunks)-1].End + 1
+ artifact.FileCompressedSize = chunks[len(chunks)-1].End + 1
}
+
checksum := ""
if req.Hash != nil {
checksum = req.Hash.Value
@@ -455,7 +523,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
}
}
if respData.SignedUrl == "" {
- respData.SignedUrl = r.buildArtifactURL(ctx, "DownloadArtifact", artifactName, ctx.ActionTask.ID)
+ respData.SignedUrl = r.buildArtifactURL(ctx, "DownloadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID)
}
r.sendProtbufBody(ctx, &respData)
}
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 0f42e8f59e..d17e4875b1 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -63,6 +63,20 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin")
return
}
+
+ // check if scope only applies to public resources
+ publicOnly, err := scope.PublicOnly()
+ if err != nil {
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
+ return
+ }
+
+ if publicOnly {
+ if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages")
+ return
+ }
+ }
}
}
diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go
index 1486e83c57..343705990a 100644
--- a/routers/api/packages/maven/maven.go
+++ b/routers/api/packages/maven/maven.go
@@ -20,6 +20,7 @@ import (
"strings"
packages_model "code.gitea.io/gitea/models/packages"
+ "code.gitea.io/gitea/modules/globallock"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
@@ -114,7 +115,9 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
xmlMetadataWithHeader := append([]byte(xml.Header), xmlMetadata...)
latest := pds[len(pds)-1]
- ctx.Resp.Header().Set("Last-Modified", latest.Version.CreatedUnix.Format(http.TimeFormat))
+ // http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
+ lastModifed := latest.Version.CreatedUnix.AsTime().UTC().Format(http.TimeFormat)
+ ctx.Resp.Header().Set("Last-Modified", lastModifed)
ext := strings.ToLower(filepath.Ext(params.Filename))
if isChecksumExtension(ext) {
@@ -223,6 +226,10 @@ func servePackageFile(ctx *context.Context, params parameters, serveContent bool
helper.ServePackageFile(ctx, s, u, pf, opts)
}
+func mavenPkgNameKey(packageName string) string {
+ return "pkg_maven_" + packageName
+}
+
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
func UploadPackageFile(ctx *context.Context) {
params, err := extractPathParameters(ctx)
@@ -241,6 +248,14 @@ func UploadPackageFile(ctx *context.Context) {
packageName := params.GroupID + "-" + params.ArtifactID
+ // for the same package, only one upload at a time
+ releaser, err := globallock.Lock(ctx, mavenPkgNameKey(packageName))
+ if err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+ defer releaser()
+
buf, err := packages_module.CreateHashedBufferFromReader(ctx.Req.Body)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index 3e2fefc6da..b0f40084da 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -133,7 +133,7 @@ func CreateUser(ctx *context.APIContext) {
u.UpdatedUnix = u.CreatedUnix
}
- if err := user_model.AdminCreateUser(ctx, u, overwriteDefault); err != nil {
+ if err := user_model.AdminCreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
if user_model.IsErrUserAlreadyExist(err) ||
user_model.IsErrEmailAlreadyUsed(err) ||
db.IsErrNameReserved(err) ||
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index be67ec1695..883e694e44 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -235,6 +235,62 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.APIContext)
}
}
+func checkTokenPublicOnly() func(ctx *context.APIContext) {
+ return func(ctx *context.APIContext) {
+ if !ctx.PublicOnly {
+ return
+ }
+
+ requiredScopeCategories, ok := ctx.Data["requiredScopeCategories"].([]auth_model.AccessTokenScopeCategory)
+ if !ok || len(requiredScopeCategories) == 0 {
+ return
+ }
+
+ // public Only permission check
+ switch {
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository):
+ if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryIssue):
+ if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public issues")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization):
+ if ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
+ return
+ }
+ if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryUser):
+ if ctx.ContextUser != nil && ctx.ContextUser.IsUser() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public users")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryActivityPub):
+ if ctx.ContextUser != nil && ctx.ContextUser.IsUser() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public activitypub")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryNotification):
+ if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public notifications")
+ return
+ }
+ case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryPackage):
+ if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages")
+ return
+ }
+ }
+ }
+}
+
// if a token is being used for auth, we check that it contains the required scope
// if a token is not being used, reqToken will enforce other sign in methods
func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeCategory) func(ctx *context.APIContext) {
@@ -250,9 +306,6 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
return
}
- ctx.Data["ApiTokenScopePublicRepoOnly"] = false
- ctx.Data["ApiTokenScopePublicOrgOnly"] = false
-
// use the http method to determine the access level
requiredScopeLevel := auth_model.Read
if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" {
@@ -261,6 +314,18 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
// get the required scope for the given access level and category
requiredScopes := auth_model.GetRequiredScopes(requiredScopeLevel, requiredScopeCategories...)
+ allow, err := scope.HasScope(requiredScopes...)
+ if err != nil {
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error())
+ return
+ }
+
+ if !allow {
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
+ return
+ }
+
+ ctx.Data["requiredScopeCategories"] = requiredScopeCategories
// check if scope only applies to public resources
publicOnly, err := scope.PublicOnly()
@@ -269,21 +334,8 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
return
}
- // this context is used by the middleware in the specific route
- ctx.Data["ApiTokenScopePublicRepoOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository)
- ctx.Data["ApiTokenScopePublicOrgOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization)
-
- allow, err := scope.HasScope(requiredScopes...)
- if err != nil {
- ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error())
- return
- }
-
- if allow {
- return
- }
-
- ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
+ // assign to true so that those searching should only filter public repositories/users/organizations
+ ctx.PublicOnly = publicOnly
}
}
@@ -295,25 +347,6 @@ func reqToken() func(ctx *context.APIContext) {
return
}
- if true == ctx.Data["IsApiToken"] {
- publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"]
- publicOrg, pubOrgExists := ctx.Data["ApiTokenScopePublicOrgOnly"]
-
- if pubRepoExists && publicRepo.(bool) &&
- ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
- ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
- return
- }
-
- if pubOrgExists && publicOrg.(bool) &&
- ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic {
- ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
- return
- }
-
- return
- }
-
if ctx.IsSigned {
return
}
@@ -879,11 +912,11 @@ func Routes() *web.Router {
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
- }, context.UserAssignmentAPI())
+ }, context.UserAssignmentAPI(), checkTokenPublicOnly())
m.Group("/user-id/{user-id}", func() {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
- }, context.UserIDAssignmentAPI())
+ }, context.UserIDAssignmentAPI(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
}
@@ -939,7 +972,7 @@ func Routes() *web.Router {
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
m.Get("/activities/feeds", user.ListUserActivityFeeds)
- }, context.UserAssignmentAPI(), individualPermsChecker)
+ }, context.UserAssignmentAPI(), checkTokenPublicOnly(), individualPermsChecker)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
// Users (requires user scope)
@@ -957,7 +990,7 @@ func Routes() *web.Router {
m.Get("/starred", user.GetStarredRepos)
m.Get("/subscriptions", user.GetWatchedRepos)
- }, context.UserAssignmentAPI())
+ }, context.UserAssignmentAPI(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
// Users (requires user scope)
@@ -1044,7 +1077,7 @@ func Routes() *web.Router {
m.Get("", user.IsStarring)
m.Put("", user.Star)
m.Delete("", user.Unstar)
- }, repoAssignment())
+ }, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
m.Get("/times", repo.ListMyTrackedTimes)
m.Get("/stopwatches", repo.GetStopwatches)
@@ -1069,18 +1102,20 @@ func Routes() *web.Router {
m.Get("", user.CheckUserBlock)
m.Put("", user.BlockUser)
m.Delete("", user.UnblockUser)
- }, context.UserAssignmentAPI())
+ }, context.UserAssignmentAPI(), checkTokenPublicOnly())
})
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
// Repositories (requires repo scope, org scope)
m.Post("/org/{org}/repos",
+ // FIXME: we need org in context
tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization, auth_model.AccessTokenScopeCategoryRepository),
reqToken(),
bind(api.CreateRepoOption{}),
repo.CreateOrgRepoDeprecated)
// requires repo scope
+ // FIXME: Don't expose repository id outside of the system
m.Combo("/repositories/{id}", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(repo.GetByID)
// Repos (requires repo scope)
@@ -1286,6 +1321,8 @@ func Routes() *web.Router {
m.Group("/{ref}", func() {
m.Get("/status", repo.GetCombinedCommitStatusByRef)
m.Get("/statuses", repo.GetCommitStatusesByRef)
+ }, context.ReferencesGitRepo())
+ m.Group("/{sha}", func() {
m.Get("/pull", repo.GetCommitPullRequest)
}, context.ReferencesGitRepo())
}, reqRepoReader(unit.TypeCode))
@@ -1325,13 +1362,14 @@ func Routes() *web.Router {
m.Get("/issue_config", context.ReferencesGitRepo(), repo.GetIssueConfig)
m.Get("/issue_config/validate", context.ReferencesGitRepo(), repo.ValidateIssueConfig)
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
+ m.Get("/licenses", reqRepoReader(unit.TypeCode), repo.GetLicenses)
m.Get("/activities/feeds", repo.ListRepoActivityFeeds)
m.Get("/new_pin_allowed", repo.AreNewIssuePinsAllowed)
m.Group("/avatar", func() {
m.Post("", bind(api.UpdateRepoAvatarOption{}), repo.UpdateAvatar)
m.Delete("", repo.DeleteAvatar)
}, reqAdmin(), reqToken())
- }, repoAssignment())
+ }, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
// Notifications (requires notifications scope)
@@ -1340,7 +1378,7 @@ func Routes() *web.Router {
m.Combo("/notifications", reqToken()).
Get(notify.ListRepoNotifications).
Put(notify.ReadRepoNotifications)
- }, repoAssignment())
+ }, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification))
// Issue (requires issue scope)
@@ -1454,7 +1492,7 @@ func Routes() *web.Router {
Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
})
- }, repoAssignment())
+ }, repoAssignment(), checkTokenPublicOnly())
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
@@ -1465,14 +1503,14 @@ func Routes() *web.Router {
m.Get("/files", reqToken(), packages.ListPackageFiles)
})
m.Get("/", reqToken(), packages.ListPackages)
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly())
// Organizations
m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
m.Group("/users/{username}/orgs", func() {
m.Get("", reqToken(), org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI(), checkTokenPublicOnly())
m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
m.Group("/orgs/{org}", func() {
@@ -1530,7 +1568,7 @@ func Routes() *web.Router {
m.Delete("", org.UnblockUser)
})
}, reqToken(), reqOrgOwnership())
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true))
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true), checkTokenPublicOnly())
m.Group("/teams/{teamid}", func() {
m.Combo("").Get(reqToken(), org.GetTeam).
Patch(reqToken(), reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam).
@@ -1550,7 +1588,7 @@ func Routes() *web.Router {
Get(reqToken(), org.GetTeamRepo)
})
m.Get("/activities/feeds", org.ListTeamActivityFeeds)
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership(), checkTokenPublicOnly())
m.Group("/admin", func() {
m.Group("/cron", func() {
diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go
index e848d95181..9e58746272 100644
--- a/routers/api/v1/org/org.go
+++ b/routers/api/v1/org/org.go
@@ -191,7 +191,7 @@ func GetAll(ctx *context.APIContext) {
// "$ref": "#/responses/OrganizationList"
vMode := []api.VisibleType{api.VisibleTypePublic}
- if ctx.IsSigned {
+ if ctx.IsSigned && !ctx.PublicOnly {
vMode = append(vMode, api.VisibleTypeLimited)
if ctx.Doer.IsAdmin {
vMode = append(vMode, api.VisibleTypePrivate)
diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go
index cec7c3d534..788c75fab2 100644
--- a/routers/api/v1/repo/commits.go
+++ b/routers/api/v1/repo/commits.go
@@ -325,11 +325,11 @@ func DownloadCommitDiffOrPatch(ctx *context.APIContext) {
}
}
-// GetCommitPullRequest returns the pull request of the commit
+// GetCommitPullRequest returns the merged pull request of the commit
func GetCommitPullRequest(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/commits/{sha}/pull repository repoGetCommitPullRequest
// ---
- // summary: Get the pull request of the commit
+ // summary: Get the merged pull request of the commit
// produces:
// - application/json
// parameters:
@@ -354,7 +354,7 @@ func GetCommitPullRequest(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- pr, err := issues_model.GetPullRequestByMergedCommit(ctx, ctx.Repo.Repository.ID, ctx.PathParam(":sha"))
+ pr, err := issues_model.GetPullRequestByMergedCommit(ctx, ctx.Repo.Repository.ID, ctx.PathParam("sha"))
if err != nil {
if issues_model.IsErrPullRequestNotExist(err) {
ctx.Error(http.StatusNotFound, "GetPullRequestByMergedCommit", err)
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index c53eb07190..d8c39b0f69 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -149,7 +149,7 @@ func SearchIssues(ctx *context.APIContext) {
Actor: ctx.Doer,
}
if ctx.IsSigned {
- opts.Private = true
+ opts.Private = !ctx.PublicOnly
opts.AllLimited = true
}
if ctx.FormString("owner") != "" {
@@ -833,10 +833,16 @@ func EditIssue(ctx *context.APIContext) {
if (form.Deadline != nil || form.RemoveDeadline != nil) && canWrite {
var deadlineUnix timeutil.TimeStamp
- if (form.RemoveDeadline == nil || !*form.RemoveDeadline) && !form.Deadline.IsZero() {
- deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
- 23, 59, 59, 0, form.Deadline.Location())
- deadlineUnix = timeutil.TimeStamp(deadline.Unix())
+ if form.RemoveDeadline == nil || !*form.RemoveDeadline {
+ if form.Deadline == nil {
+ ctx.Error(http.StatusBadRequest, "", "The due_date cannot be empty")
+ return
+ }
+ if !form.Deadline.IsZero() {
+ deadline := time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
+ 23, 59, 59, 0, form.Deadline.Location())
+ deadlineUnix = timeutil.TimeStamp(deadline.Unix())
+ }
}
if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil {
diff --git a/routers/api/v1/repo/license.go b/routers/api/v1/repo/license.go
new file mode 100644
index 0000000000..8a6bdfd42f
--- /dev/null
+++ b/routers/api/v1/repo/license.go
@@ -0,0 +1,51 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "net/http"
+
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/services/context"
+)
+
+// GetLicenses returns licenses
+func GetLicenses(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/licenses repository repoGetLicenses
+ // ---
+ // summary: Get repo licenses
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repo
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repo
+ // type: string
+ // required: true
+ // responses:
+ // "404":
+ // "$ref": "#/responses/notFound"
+ // "200":
+ // "$ref": "#/responses/LicensesList"
+
+ licenses, err := repo_model.GetRepoLicenses(ctx, ctx.Repo.Repository)
+ if err != nil {
+ log.Error("GetRepoLicenses failed: %v", err)
+ ctx.InternalServerError(err)
+ return
+ }
+
+ resp := make([]string, len(licenses))
+ for i := range licenses {
+ resp[i] = licenses[i].License
+ }
+
+ ctx.JSON(http.StatusOK, resp)
+}
diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go
index 14c8c01f4e..dcbd8f3dd5 100644
--- a/routers/api/v1/repo/migrate.go
+++ b/routers/api/v1/repo/migrate.go
@@ -169,6 +169,10 @@ func Migrate(ctx *context.APIContext) {
opts.PullRequests = false
opts.Releases = false
}
+ if gitServiceType == api.CodeCommitService {
+ opts.AWSAccessKeyID = form.AWSAccessKeyID
+ opts.AWSSecretAccessKey = form.AWSSecretAccessKey
+ }
repo, err := repo_service.CreateRepositoryDirectly(ctx, ctx.Doer, repoOwner, repo_service.CreateRepoOptions{
Name: opts.RepoName,
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index de67057fdd..34ebcb42d5 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -52,56 +52,79 @@ func ListPullRequests(ctx *context.APIContext) {
// parameters:
// - name: owner
// in: path
- // description: owner of the repo
+ // description: Owner of the repo
// type: string
// required: true
// - name: repo
// in: path
- // description: name of the repo
+ // description: Name of the repo
// type: string
// required: true
// - name: state
// in: query
- // description: "State of pull request: open or closed (optional)"
+ // description: State of pull request
// type: string
- // enum: [closed, open, all]
+ // enum: [open, closed, all]
+ // default: open
// - name: sort
// in: query
- // description: "Type of sort"
+ // description: Type of sort
// type: string
// enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority]
// - name: milestone
// in: query
- // description: "ID of the milestone"
+ // description: ID of the milestone
// type: integer
// format: int64
// - name: labels
// in: query
- // description: "Label IDs"
+ // description: Label IDs
// type: array
// collectionFormat: multi
// items:
// type: integer
// format: int64
+ // - name: poster
+ // in: query
+ // description: Filter by pull request author
+ // type: string
// - name: page
// in: query
- // description: page number of results to return (1-based)
+ // description: Page number of results to return (1-based)
// type: integer
+ // minimum: 1
+ // default: 1
// - name: limit
// in: query
- // description: page size of results
+ // description: Page size of results
// type: integer
+ // minimum: 0
// responses:
// "200":
// "$ref": "#/responses/PullRequestList"
// "404":
// "$ref": "#/responses/notFound"
+ // "500":
+ // "$ref": "#/responses/error"
labelIDs, err := base.StringsToInt64s(ctx.FormStrings("labels"))
if err != nil {
ctx.Error(http.StatusInternalServerError, "PullRequests", err)
return
}
+ var posterID int64
+ if posterStr := ctx.FormString("poster"); posterStr != "" {
+ poster, err := user_model.GetUserByName(ctx, posterStr)
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ ctx.Error(http.StatusBadRequest, "Poster not found", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
+ }
+ return
+ }
+ posterID = poster.ID
+ }
listOptions := utils.GetListOptions(ctx)
prs, maxResults, err := issues_model.PullRequests(ctx, ctx.Repo.Repository.ID, &issues_model.PullRequestsOptions{
ListOptions: listOptions,
@@ -109,6 +132,7 @@ func ListPullRequests(ctx *context.APIContext) {
SortType: ctx.FormTrim("sort"),
Labels: labelIDs,
MilestoneID: ctx.FormInt64("milestone"),
+ PosterID: posterID,
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "PullRequests", err)
@@ -766,7 +790,7 @@ func EditPullRequest(ctx *context.APIContext) {
// update allow edits
if form.AllowMaintainerEdit != nil {
if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, *form.AllowMaintainerEdit); err != nil {
- if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) {
+ if errors.Is(err, pull_service.ErrUserHasNoPermissionForAction) {
ctx.Error(http.StatusForbidden, "SetAllowEdits", fmt.Sprintf("SetAllowEdits: %s", err))
return
}
@@ -1124,9 +1148,20 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
// Check if current user has fork of repository or in the same repository.
headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID)
if headRepo == nil && !isSameRepo {
- log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
- ctx.NotFound("GetForkedRepo")
- return nil, nil, nil, "", ""
+ err := baseRepo.GetBaseRepo(ctx)
+ if err != nil {
+ ctx.Error(http.StatusInternalServerError, "GetBaseRepo", err)
+ return nil, nil, nil, "", ""
+ }
+
+ // Check if baseRepo's base repository is the same as headUser's repository.
+ if baseRepo.BaseRepo == nil || baseRepo.BaseRepo.OwnerID != headUser.ID {
+ log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
+ ctx.NotFound("GetBaseRepo")
+ return nil, nil, nil, "", ""
+ }
+ // Assign headRepo so it can be used below.
+ headRepo = baseRepo.BaseRepo
}
var headGitRepo *git.Repository
diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go
index c2e4966498..34bbaf5600 100644
--- a/routers/api/v1/repo/pull_review.go
+++ b/routers/api/v1/repo/pull_review.go
@@ -83,7 +83,6 @@ func ListPullReviews(ctx *context.APIContext) {
opts := issues_model.FindReviewOptions{
ListOptions: utils.GetListOptions(ctx),
- Type: issues_model.ReviewTypeUnknown,
IssueID: pr.IssueID,
}
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index ef587f6274..478bdbd797 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/git"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
@@ -251,6 +252,8 @@ func CreateRelease(ctx *context.APIContext) {
ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err)
} else if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusUnprocessableEntity, "ProtectedTagName", err)
+ } else if git.IsErrNotExist(err) {
+ ctx.Error(http.StatusNotFound, "ErrNotExist", fmt.Errorf("target \"%v\" not found: %w", rel.Target, err))
} else {
ctx.Error(http.StatusInternalServerError, "CreateRelease", err)
}
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 1bcec8fcf7..4638e2ba5c 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -129,6 +129,11 @@ func Search(ctx *context.APIContext) {
// "422":
// "$ref": "#/responses/validationError"
+ private := ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private"))
+ if ctx.PublicOnly {
+ private = false
+ }
+
opts := &repo_model.SearchRepoOptions{
ListOptions: utils.GetListOptions(ctx),
Actor: ctx.Doer,
@@ -138,7 +143,7 @@ func Search(ctx *context.APIContext) {
TeamID: ctx.FormInt64("team_id"),
TopicOnly: ctx.FormBool("topic"),
Collaborate: optional.None[bool](),
- Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")),
+ Private: private,
Template: optional.None[bool](),
StarredByID: ctx.FormInt64("starredBy"),
IncludeDescription: ctx.FormBool("includeDesc"),
@@ -731,6 +736,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
}
// Default branch only updated if changed and exist or the repository is empty
+ updateRepoLicense := false
if opts.DefaultBranch != nil && repo.DefaultBranch != *opts.DefaultBranch && (repo.IsEmpty || ctx.Repo.GitRepo.IsBranchExist(*opts.DefaultBranch)) {
if !repo.IsEmpty {
if err := gitrepo.SetDefaultBranch(ctx, ctx.Repo.Repository, *opts.DefaultBranch); err != nil {
@@ -739,6 +745,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
return err
}
}
+ updateRepoLicense = true
}
repo.DefaultBranch = *opts.DefaultBranch
}
@@ -748,6 +755,15 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
return err
}
+ if updateRepoLicense {
+ if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{
+ RepoID: ctx.Repo.Repository.ID,
+ }); err != nil {
+ ctx.Error(http.StatusInternalServerError, "AddRepoToLicenseUpdaterQueue", err)
+ return err
+ }
+ }
+
log.Trace("Repository basic settings updated: %s/%s", owner.Name, repo.Name)
return nil
}
diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go
index 345835f9a5..b9d2a0217c 100644
--- a/routers/api/v1/swagger/repo.go
+++ b/routers/api/v1/swagger/repo.go
@@ -359,6 +359,13 @@ type swaggerLanguageStatistics struct {
Body map[string]int64 `json:"body"`
}
+// LicensesList
+// swagger:response LicensesList
+type swaggerLicensesList struct {
+ // in: body
+ Body []string `json:"body"`
+}
+
// CombinedStatus
// swagger:response CombinedStatus
type swaggerCombinedStatus struct {
diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go
index 5c28dd878d..9583bb548c 100644
--- a/routers/api/v1/user/app.go
+++ b/routers/api/v1/user/app.go
@@ -118,6 +118,10 @@ func CreateAccessToken(ctx *context.APIContext) {
ctx.Error(http.StatusBadRequest, "AccessTokenScope.Normalize", fmt.Errorf("invalid access token scope provided: %w", err))
return
}
+ if scope == "" {
+ ctx.Error(http.StatusBadRequest, "AccessTokenScope", "access token must have a scope")
+ return
+ }
t.Scope = scope
if err := auth_model.NewAccessToken(ctx, t); err != nil {
@@ -129,6 +133,7 @@ func CreateAccessToken(ctx *context.APIContext) {
Token: t.Token,
ID: t.ID,
TokenLastEight: t.TokenLastEight,
+ Scopes: t.Scope.StringSlice(),
})
}
diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go
index fedad87fc4..a9011427fb 100644
--- a/routers/api/v1/user/user.go
+++ b/routers/api/v1/user/user.go
@@ -9,6 +9,7 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -67,12 +68,18 @@ func Search(ctx *context.APIContext) {
maxResults = 1
users = []*user_model.User{user_model.NewActionsUser()}
default:
+ var visible []structs.VisibleType
+ if ctx.PublicOnly {
+ visible = []structs.VisibleType{structs.VisibleTypePublic}
+ }
users, maxResults, err = user_model.SearchUsers(ctx, &user_model.SearchUserOptions{
- Actor: ctx.Doer,
- Keyword: ctx.FormTrim("q"),
- UID: uid,
- Type: user_model.UserTypeIndividual,
- ListOptions: listOptions,
+ Actor: ctx.Doer,
+ Keyword: ctx.FormTrim("q"),
+ UID: uid,
+ Type: user_model.UserTypeIndividual,
+ SearchByEmail: true,
+ Visible: visible,
+ ListOptions: listOptions,
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]any{
diff --git a/routers/init.go b/routers/init.go
index e21f763c1e..2091f5967a 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -47,6 +47,7 @@ import (
markup_service "code.gitea.io/gitea/services/markup"
repo_migrations "code.gitea.io/gitea/services/migrations"
mirror_service "code.gitea.io/gitea/services/mirror"
+ "code.gitea.io/gitea/services/oauth2_provider"
pull_service "code.gitea.io/gitea/services/pull"
release_service "code.gitea.io/gitea/services/release"
repo_service "code.gitea.io/gitea/services/repository"
@@ -144,7 +145,7 @@ func InitWebInstalled(ctx context.Context) {
log.Info("ORM engine initialization successful!")
mustInit(system.Init)
mustInitCtx(ctx, oauth2.Init)
-
+ mustInitCtx(ctx, oauth2_provider.Init)
mustInit(release_service.Init)
mustInitCtx(ctx, models.Init)
@@ -172,6 +173,8 @@ func InitWebInstalled(ctx context.Context) {
actions_service.Init()
+ mustInit(repo_service.InitLicenseClassifier)
+
// Finally start up the cron
cron.NewContext(ctx)
}
diff --git a/routers/install/install.go b/routers/install/install.go
index fde8b37ed5..e420d36da5 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -554,7 +554,7 @@ func SubmitInstall(ctx *context.Context) {
IsActive: optional.Some(true),
}
- if err = user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
+ if err = user_model.CreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
if !user_model.IsErrUserAlreadyExist(err) {
setting.InstallLock = false
ctx.Data["Err_AdminName"] = true
diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go
index 7be909f955..03c19c8ff4 100644
--- a/routers/private/default_branch.go
+++ b/routers/private/default_branch.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/private"
gitea_context "code.gitea.io/gitea/services/context"
+ repo_service "code.gitea.io/gitea/services/repository"
)
// SetDefaultBranch updates the default branch
@@ -36,5 +37,15 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) {
})
return
}
+
+ if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{
+ RepoID: ctx.Repo.Repository.ID,
+ }); err != nil {
+ ctx.JSON(http.StatusInternalServerError, private.Response{
+ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err),
+ })
+ return
+ }
+
ctx.PlainText(http.StatusOK, "success")
}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index 2d1688523c..5c01216356 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -278,10 +278,19 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
branch := refFullName.BranchName()
- // If our branch is the default branch of an unforked repo - there's no PR to create or refer to
- if !repo.IsFork && branch == baseRepo.DefaultBranch {
- results = append(results, private.HookPostReceiveBranchResult{})
- continue
+ if branch == baseRepo.DefaultBranch {
+ if err := repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{
+ RepoID: repo.ID,
+ }); err != nil {
+ ctx.JSON(http.StatusInternalServerError, private.Response{Err: err.Error()})
+ return
+ }
+
+ // If our branch is the default branch of an unforked repo - there's no PR to create or refer to
+ if !repo.IsFork {
+ results = append(results, private.HookPostReceiveBranchResult{})
+ continue
+ }
}
pr, err := issues_model.GetUnmergedPullRequest(ctx, repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch, issues_model.PullRequestFlowGithub)
diff --git a/routers/private/internal.go b/routers/private/internal.go
index 61e604b7a9..f9adff388c 100644
--- a/routers/private/internal.go
+++ b/routers/private/internal.go
@@ -12,7 +12,9 @@ import (
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
+ "code.gitea.io/gitea/routers/common"
"code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/lfs"
"gitea.com/go-chi/binding"
chi_middleware "github.com/go-chi/chi/v5/middleware"
@@ -46,6 +48,14 @@ func bind[T any](_ T) any {
}
}
+// SwapAuthToken swaps Authorization header with X-Auth header
+func swapAuthToken(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ req.Header.Set("Authorization", req.Header.Get("X-Auth"))
+ next.ServeHTTP(w, req)
+ })
+}
+
// Routes registers all internal APIs routes to web application.
// These APIs will be invoked by internal commands for example `gitea serv` and etc.
func Routes() *web.Router {
@@ -80,5 +90,25 @@ func Routes() *web.Router {
r.Post("/restore_repo", RestoreRepo)
r.Post("/actions/generate_actions_runner_token", GenerateActionsRunnerToken)
+ r.Group("/repo/{username}/{reponame}", func() {
+ r.Group("/info/lfs", func() {
+ r.Post("/objects/batch", lfs.CheckAcceptMediaType, lfs.BatchHandler)
+ r.Put("/objects/{oid}/{size}", lfs.UploadHandler)
+ r.Get("/objects/{oid}/{filename}", lfs.DownloadHandler)
+ r.Get("/objects/{oid}", lfs.DownloadHandler)
+ r.Post("/verify", lfs.CheckAcceptMediaType, lfs.VerifyHandler)
+ r.Group("/locks", func() {
+ r.Get("/", lfs.GetListLockHandler)
+ r.Post("/", lfs.PostLockHandler)
+ r.Post("/verify", lfs.VerifyLockHandler)
+ r.Post("/{lid}/unlock", lfs.UnLockHandler)
+ }, lfs.CheckAcceptMediaType)
+ r.Any("/*", func(ctx *context.Context) {
+ ctx.NotFound("", nil)
+ })
+ }, swapAuthToken)
+ }, common.Sessioner(), context.Contexter())
+ // end "/repo/{username}/{reponame}": git (LFS) API mirror
+
return r
}
diff --git a/routers/private/serv.go b/routers/private/serv.go
index dbb28cc2bb..4dd7d06fb3 100644
--- a/routers/private/serv.go
+++ b/routers/private/serv.go
@@ -136,16 +136,15 @@ func ServCommand(ctx *context.PrivateContext) {
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
repoExist = false
- for _, verb := range ctx.FormStrings("verb") {
- if verb == "git-upload-pack" {
- // User is fetching/cloning a non-existent repository
- log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
- ctx.JSON(http.StatusNotFound, private.Response{
- UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
- })
- return
- }
+ if mode == perm.AccessModeRead {
+ // User is fetching/cloning a non-existent repository
+ log.Warn("Failed authentication attempt (cannot find repository: %s/%s) from %s", results.OwnerName, results.RepoName, ctx.RemoteAddr())
+ ctx.JSON(http.StatusNotFound, private.Response{
+ UserMsg: fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
+ })
+ return
}
+ // else fallthrough (push-to-create may kick in below)
} else {
log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
ctx.JSON(http.StatusInternalServerError, private.Response{
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index 34bb1dfe26..48ff8ea04b 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -177,7 +177,7 @@ func NewUserPost(ctx *context.Context) {
u.MustChangePassword = form.MustChangePassword
}
- if err := user_model.AdminCreateUser(ctx, u, overwriteDefault); err != nil {
+ if err := user_model.AdminCreateUser(ctx, u, &user_model.Meta{}, overwriteDefault); err != nil {
switch {
case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index f295cf039f..5cbe2f5388 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -228,12 +228,12 @@ func SignInPost(ctx *context.Context) {
if err != nil {
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
- log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
+ log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrEmailAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
- log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
+ log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrUserProhibitLogin(err) {
- log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
+ log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
} else if user_model.IsErrUserInactive(err) {
@@ -241,7 +241,7 @@ func SignInPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
ctx.HTML(http.StatusOK, TplActivate)
} else {
- log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
+ log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
}
@@ -541,7 +541,11 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any
// createUserInContext creates a user and handles errors within a given context.
// Optionally a template can be specified.
func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
- if err := user_model.CreateUser(ctx, u, overwrites); err != nil {
+ meta := &user_model.Meta{
+ InitialIP: ctx.RemoteAddr(),
+ InitialUserAgent: ctx.Req.UserAgent(),
+ }
+ if err := user_model.CreateUser(ctx, u, meta, overwrites); err != nil {
if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
var user *user_model.User
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index c61a0a6240..ccbb3bebf1 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -4,878 +4,34 @@
package auth
import (
- go_context "context"
"errors"
"fmt"
"html"
- "html/template"
"io"
"net/http"
- "net/url"
"sort"
"strings"
"code.gitea.io/gitea/models/auth"
- org_model "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
auth_module "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/container"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/timeutil"
- "code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
- auth_service "code.gitea.io/gitea/services/auth"
source_service "code.gitea.io/gitea/services/auth/source"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/externalaccount"
- "code.gitea.io/gitea/services/forms"
user_service "code.gitea.io/gitea/services/user"
- "gitea.com/go-chi/binding"
- "github.com/golang-jwt/jwt/v5"
"github.com/markbates/goth"
"github.com/markbates/goth/gothic"
go_oauth2 "golang.org/x/oauth2"
)
-const (
- tplGrantAccess base.TplName = "user/auth/grant"
- tplGrantError base.TplName = "user/auth/grant_error"
-)
-
-// TODO move error and responses to SDK or models
-
-// AuthorizeErrorCode represents an error code specified in RFC 6749
-// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
-type AuthorizeErrorCode string
-
-const (
- // ErrorCodeInvalidRequest represents the according error in RFC 6749
- ErrorCodeInvalidRequest AuthorizeErrorCode = "invalid_request"
- // ErrorCodeUnauthorizedClient represents the according error in RFC 6749
- ErrorCodeUnauthorizedClient AuthorizeErrorCode = "unauthorized_client"
- // ErrorCodeAccessDenied represents the according error in RFC 6749
- ErrorCodeAccessDenied AuthorizeErrorCode = "access_denied"
- // ErrorCodeUnsupportedResponseType represents the according error in RFC 6749
- ErrorCodeUnsupportedResponseType AuthorizeErrorCode = "unsupported_response_type"
- // ErrorCodeInvalidScope represents the according error in RFC 6749
- ErrorCodeInvalidScope AuthorizeErrorCode = "invalid_scope"
- // ErrorCodeServerError represents the according error in RFC 6749
- ErrorCodeServerError AuthorizeErrorCode = "server_error"
- // ErrorCodeTemporaryUnavailable represents the according error in RFC 6749
- ErrorCodeTemporaryUnavailable AuthorizeErrorCode = "temporarily_unavailable"
-)
-
-// AuthorizeError represents an error type specified in RFC 6749
-// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
-type AuthorizeError struct {
- ErrorCode AuthorizeErrorCode `json:"error" form:"error"`
- ErrorDescription string
- State string
-}
-
-// Error returns the error message
-func (err AuthorizeError) Error() string {
- return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
-}
-
-// AccessTokenErrorCode represents an error code specified in RFC 6749
-// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
-type AccessTokenErrorCode string
-
-const (
- // AccessTokenErrorCodeInvalidRequest represents an error code specified in RFC 6749
- AccessTokenErrorCodeInvalidRequest AccessTokenErrorCode = "invalid_request"
- // AccessTokenErrorCodeInvalidClient represents an error code specified in RFC 6749
- AccessTokenErrorCodeInvalidClient = "invalid_client"
- // AccessTokenErrorCodeInvalidGrant represents an error code specified in RFC 6749
- AccessTokenErrorCodeInvalidGrant = "invalid_grant"
- // AccessTokenErrorCodeUnauthorizedClient represents an error code specified in RFC 6749
- AccessTokenErrorCodeUnauthorizedClient = "unauthorized_client"
- // AccessTokenErrorCodeUnsupportedGrantType represents an error code specified in RFC 6749
- AccessTokenErrorCodeUnsupportedGrantType = "unsupported_grant_type"
- // AccessTokenErrorCodeInvalidScope represents an error code specified in RFC 6749
- AccessTokenErrorCodeInvalidScope = "invalid_scope"
-)
-
-// AccessTokenError represents an error response specified in RFC 6749
-// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
-type AccessTokenError struct {
- ErrorCode AccessTokenErrorCode `json:"error" form:"error"`
- ErrorDescription string `json:"error_description"`
-}
-
-// Error returns the error message
-func (err AccessTokenError) Error() string {
- return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
-}
-
-// errCallback represents a oauth2 callback error
-type errCallback struct {
- Code string
- Description string
-}
-
-func (err errCallback) Error() string {
- return err.Description
-}
-
-// TokenType specifies the kind of token
-type TokenType string
-
-const (
- // TokenTypeBearer represents a token type specified in RFC 6749
- TokenTypeBearer TokenType = "bearer"
- // TokenTypeMAC represents a token type specified in RFC 6749
- TokenTypeMAC = "mac"
-)
-
-// AccessTokenResponse represents a successful access token response
-// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2
-type AccessTokenResponse struct {
- AccessToken string `json:"access_token"`
- TokenType TokenType `json:"token_type"`
- ExpiresIn int64 `json:"expires_in"`
- RefreshToken string `json:"refresh_token"`
- IDToken string `json:"id_token,omitempty"`
-}
-
-func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) {
- if setting.OAuth2.InvalidateRefreshTokens {
- if err := grant.IncreaseCounter(ctx); err != nil {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidGrant,
- ErrorDescription: "cannot increase the grant counter",
- }
- }
- }
- // generate access token to access the API
- expirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.AccessTokenExpirationTime)
- accessToken := &oauth2.Token{
- GrantID: grant.ID,
- Type: oauth2.TypeAccessToken,
- RegisteredClaims: jwt.RegisteredClaims{
- ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
- },
- }
- signedAccessToken, err := accessToken.SignToken(serverKey)
- if err != nil {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot sign token",
- }
- }
-
- // generate refresh token to request an access token after it expired later
- refreshExpirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.RefreshTokenExpirationTime * 60 * 60).AsTime()
- refreshToken := &oauth2.Token{
- GrantID: grant.ID,
- Counter: grant.Counter,
- Type: oauth2.TypeRefreshToken,
- RegisteredClaims: jwt.RegisteredClaims{
- ExpiresAt: jwt.NewNumericDate(refreshExpirationDate),
- },
- }
- signedRefreshToken, err := refreshToken.SignToken(serverKey)
- if err != nil {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot sign token",
- }
- }
-
- // generate OpenID Connect id_token
- signedIDToken := ""
- if grant.ScopeContains("openid") {
- app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID)
- if err != nil {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot find application",
- }
- }
- user, err := user_model.GetUserByID(ctx, grant.UserID)
- if err != nil {
- if user_model.IsErrUserNotExist(err) {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot find user",
- }
- }
- log.Error("Error loading user: %v", err)
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "server error",
- }
- }
-
- idToken := &oauth2.OIDCToken{
- RegisteredClaims: jwt.RegisteredClaims{
- ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
- Issuer: setting.AppURL,
- Audience: []string{app.ClientID},
- Subject: fmt.Sprint(grant.UserID),
- },
- Nonce: grant.Nonce,
- }
- if grant.ScopeContains("profile") {
- idToken.Name = user.GetDisplayName()
- idToken.PreferredUsername = user.Name
- idToken.Profile = user.HTMLURL()
- idToken.Picture = user.AvatarLink(ctx)
- idToken.Website = user.Website
- idToken.Locale = user.Language
- idToken.UpdatedAt = user.UpdatedUnix
- }
- if grant.ScopeContains("email") {
- idToken.Email = user.Email
- idToken.EmailVerified = user.IsActive
- }
- if grant.ScopeContains("groups") {
- groups, err := getOAuthGroupsForUser(ctx, user)
- if err != nil {
- log.Error("Error getting groups: %v", err)
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "server error",
- }
- }
- idToken.Groups = groups
- }
-
- signedIDToken, err = idToken.SignToken(clientKey)
- if err != nil {
- return nil, &AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot sign token",
- }
- }
- }
-
- return &AccessTokenResponse{
- AccessToken: signedAccessToken,
- TokenType: TokenTypeBearer,
- ExpiresIn: setting.OAuth2.AccessTokenExpirationTime,
- RefreshToken: signedRefreshToken,
- IDToken: signedIDToken,
- }, nil
-}
-
-type userInfoResponse struct {
- Sub string `json:"sub"`
- Name string `json:"name"`
- Username string `json:"preferred_username"`
- Email string `json:"email"`
- Picture string `json:"picture"`
- Groups []string `json:"groups"`
-}
-
-// InfoOAuth manages request for userinfo endpoint
-func InfoOAuth(ctx *context.Context) {
- if ctx.Doer == nil || ctx.Data["AuthedMethod"] != (&auth_service.OAuth2{}).Name() {
- ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
- ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
- return
- }
-
- response := &userInfoResponse{
- Sub: fmt.Sprint(ctx.Doer.ID),
- Name: ctx.Doer.FullName,
- Username: ctx.Doer.Name,
- Email: ctx.Doer.Email,
- Picture: ctx.Doer.AvatarLink(ctx),
- }
-
- groups, err := getOAuthGroupsForUser(ctx, ctx.Doer)
- if err != nil {
- ctx.ServerError("Oauth groups for user", err)
- return
- }
- response.Groups = groups
-
- ctx.JSON(http.StatusOK, response)
-}
-
-// returns a list of "org" and "org:team" strings,
-// that the given user is a part of.
-func getOAuthGroupsForUser(ctx go_context.Context, user *user_model.User) ([]string, error) {
- orgs, err := org_model.GetUserOrgsList(ctx, user)
- if err != nil {
- return nil, fmt.Errorf("GetUserOrgList: %w", err)
- }
-
- var groups []string
- for _, org := range orgs {
- groups = append(groups, org.Name)
- teams, err := org.LoadTeams(ctx)
- if err != nil {
- return nil, fmt.Errorf("LoadTeams: %w", err)
- }
- for _, team := range teams {
- if team.IsMember(ctx, user.ID) {
- groups = append(groups, org.Name+":"+team.LowerName)
- }
- }
- }
- return groups, nil
-}
-
-func parseBasicAuth(ctx *context.Context) (username, password string, err error) {
- authHeader := ctx.Req.Header.Get("Authorization")
- if authType, authData, ok := strings.Cut(authHeader, " "); ok && strings.EqualFold(authType, "Basic") {
- return base.BasicAuthDecode(authData)
- }
- return "", "", errors.New("invalid basic authentication")
-}
-
-// IntrospectOAuth introspects an oauth token
-func IntrospectOAuth(ctx *context.Context) {
- clientIDValid := false
- if clientID, clientSecret, err := parseBasicAuth(ctx); err == nil {
- app, err := auth.GetOAuth2ApplicationByClientID(ctx, clientID)
- if err != nil && !auth.IsErrOauthClientIDInvalid(err) {
- // this is likely a database error; log it and respond without details
- log.Error("Error retrieving client_id: %v", err)
- ctx.Error(http.StatusInternalServerError)
- return
- }
- clientIDValid = err == nil && app.ValidateClientSecret([]byte(clientSecret))
- }
- if !clientIDValid {
- ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm=""`)
- ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
- return
- }
-
- var response struct {
- Active bool `json:"active"`
- Scope string `json:"scope,omitempty"`
- Username string `json:"username,omitempty"`
- jwt.RegisteredClaims
- }
-
- form := web.GetForm(ctx).(*forms.IntrospectTokenForm)
- token, err := oauth2.ParseToken(form.Token, oauth2.DefaultSigningKey)
- if err == nil {
- grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID)
- if err == nil && grant != nil {
- app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID)
- if err == nil && app != nil {
- response.Active = true
- response.Scope = grant.Scope
- response.Issuer = setting.AppURL
- response.Audience = []string{app.ClientID}
- response.Subject = fmt.Sprint(grant.UserID)
- }
- if user, err := user_model.GetUserByID(ctx, grant.UserID); err == nil {
- response.Username = user.Name
- }
- }
- }
-
- ctx.JSON(http.StatusOK, response)
-}
-
-// AuthorizeOAuth manages authorize requests
-func AuthorizeOAuth(ctx *context.Context) {
- form := web.GetForm(ctx).(*forms.AuthorizationForm)
- errs := binding.Errors{}
- errs = form.Validate(ctx.Req, errs)
- if len(errs) > 0 {
- errstring := ""
- for _, e := range errs {
- errstring += e.Error() + "\n"
- }
- ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occurred during validation: %s", errstring))
- return
- }
-
- app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
- if err != nil {
- if auth.IsErrOauthClientIDInvalid(err) {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeUnauthorizedClient,
- ErrorDescription: "Client ID not registered",
- State: form.State,
- }, "")
- return
- }
- ctx.ServerError("GetOAuth2ApplicationByClientID", err)
- return
- }
-
- var user *user_model.User
- if app.UID != 0 {
- user, err = user_model.GetUserByID(ctx, app.UID)
- if err != nil {
- ctx.ServerError("GetUserByID", err)
- return
- }
- }
-
- if !app.ContainsRedirectURI(form.RedirectURI) {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeInvalidRequest,
- ErrorDescription: "Unregistered Redirect URI",
- State: form.State,
- }, "")
- return
- }
-
- if form.ResponseType != "code" {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeUnsupportedResponseType,
- ErrorDescription: "Only code response type is supported.",
- State: form.State,
- }, form.RedirectURI)
- return
- }
-
- // pkce support
- switch form.CodeChallengeMethod {
- case "S256":
- case "plain":
- if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallengeMethod); err != nil {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeServerError,
- ErrorDescription: "cannot set code challenge method",
- State: form.State,
- }, form.RedirectURI)
- return
- }
- if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallenge); err != nil {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeServerError,
- ErrorDescription: "cannot set code challenge",
- State: form.State,
- }, form.RedirectURI)
- return
- }
- // Here we're just going to try to release the session early
- if err := ctx.Session.Release(); err != nil {
- // we'll tolerate errors here as they *should* get saved elsewhere
- log.Error("Unable to save changes to the session: %v", err)
- }
- case "":
- // "Authorization servers SHOULD reject authorization requests from native apps that don't use PKCE by returning an error message"
- // https://datatracker.ietf.org/doc/html/rfc8252#section-8.1
- if !app.ConfidentialClient {
- // "the authorization endpoint MUST return the authorization error response with the "error" value set to "invalid_request""
- // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeInvalidRequest,
- ErrorDescription: "PKCE is required for public clients",
- State: form.State,
- }, form.RedirectURI)
- return
- }
- default:
- // "If the server supporting PKCE does not support the requested transformation, the authorization endpoint MUST return the authorization error response with "error" value set to "invalid_request"."
- // https://www.rfc-editor.org/rfc/rfc7636#section-4.4.1
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeInvalidRequest,
- ErrorDescription: "unsupported code challenge method",
- State: form.State,
- }, form.RedirectURI)
- return
- }
-
- grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
-
- // Redirect if user already granted access and the application is confidential or trusted otherwise
- // I.e. always require authorization for untrusted public clients as recommended by RFC 6749 Section 10.2
- if (app.ConfidentialClient || app.SkipSecondaryAuthorization) && grant != nil {
- code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
- redirect, err := code.GenerateRedirectURI(form.State)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
- // Update nonce to reflect the new session
- if len(form.Nonce) > 0 {
- err := grant.SetNonce(ctx, form.Nonce)
- if err != nil {
- log.Error("Unable to update nonce: %v", err)
- }
- }
- ctx.Redirect(redirect.String())
- return
- }
-
- // show authorize page to grant access
- ctx.Data["Application"] = app
- ctx.Data["RedirectURI"] = form.RedirectURI
- ctx.Data["State"] = form.State
- ctx.Data["Scope"] = form.Scope
- ctx.Data["Nonce"] = form.Nonce
- if user != nil {
- ctx.Data["ApplicationCreatorLinkHTML"] = template.HTML(fmt.Sprintf(`@%s`, html.EscapeString(user.HomeLink()), html.EscapeString(user.Name)))
- } else {
- ctx.Data["ApplicationCreatorLinkHTML"] = template.HTML(fmt.Sprintf(`%s`, html.EscapeString(setting.AppSubURL+"/"), html.EscapeString(setting.AppName)))
- }
- ctx.Data["ApplicationRedirectDomainHTML"] = template.HTML("" + html.EscapeString(form.RedirectURI) + "")
- // TODO document SESSION <=> FORM
- err = ctx.Session.Set("client_id", app.ClientID)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- log.Error(err.Error())
- return
- }
- err = ctx.Session.Set("redirect_uri", form.RedirectURI)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- log.Error(err.Error())
- return
- }
- err = ctx.Session.Set("state", form.State)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- log.Error(err.Error())
- return
- }
- // Here we're just going to try to release the session early
- if err := ctx.Session.Release(); err != nil {
- // we'll tolerate errors here as they *should* get saved elsewhere
- log.Error("Unable to save changes to the session: %v", err)
- }
- ctx.HTML(http.StatusOK, tplGrantAccess)
-}
-
-// GrantApplicationOAuth manages the post request submitted when a user grants access to an application
-func GrantApplicationOAuth(ctx *context.Context) {
- form := web.GetForm(ctx).(*forms.GrantApplicationForm)
- if ctx.Session.Get("client_id") != form.ClientID || ctx.Session.Get("state") != form.State ||
- ctx.Session.Get("redirect_uri") != form.RedirectURI {
- ctx.Error(http.StatusBadRequest)
- return
- }
-
- if !form.Granted {
- handleAuthorizeError(ctx, AuthorizeError{
- State: form.State,
- ErrorDescription: "the request is denied",
- ErrorCode: ErrorCodeAccessDenied,
- }, form.RedirectURI)
- return
- }
-
- app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
- if err != nil {
- ctx.ServerError("GetOAuth2ApplicationByClientID", err)
- return
- }
- grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
- if grant == nil {
- grant, err = app.CreateGrant(ctx, ctx.Doer.ID, form.Scope)
- if err != nil {
- handleAuthorizeError(ctx, AuthorizeError{
- State: form.State,
- ErrorDescription: "cannot create grant for user",
- ErrorCode: ErrorCodeServerError,
- }, form.RedirectURI)
- return
- }
- } else if grant.Scope != form.Scope {
- handleAuthorizeError(ctx, AuthorizeError{
- State: form.State,
- ErrorDescription: "a grant exists with different scope",
- ErrorCode: ErrorCodeServerError,
- }, form.RedirectURI)
- return
- }
-
- if len(form.Nonce) > 0 {
- err := grant.SetNonce(ctx, form.Nonce)
- if err != nil {
- log.Error("Unable to update nonce: %v", err)
- }
- }
-
- var codeChallenge, codeChallengeMethod string
- codeChallenge, _ = ctx.Session.Get("CodeChallenge").(string)
- codeChallengeMethod, _ = ctx.Session.Get("CodeChallengeMethod").(string)
-
- code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, codeChallenge, codeChallengeMethod)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
- redirect, err := code.GenerateRedirectURI(form.State)
- if err != nil {
- handleServerError(ctx, form.State, form.RedirectURI)
- return
- }
- ctx.Redirect(redirect.String(), http.StatusSeeOther)
-}
-
-// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
-func OIDCWellKnown(ctx *context.Context) {
- ctx.Data["SigningKey"] = oauth2.DefaultSigningKey
- ctx.JSONTemplate("user/auth/oidc_wellknown")
-}
-
-// OIDCKeys generates the JSON Web Key Set
-func OIDCKeys(ctx *context.Context) {
- jwk, err := oauth2.DefaultSigningKey.ToJWK()
- if err != nil {
- log.Error("Error converting signing key to JWK: %v", err)
- ctx.Error(http.StatusInternalServerError)
- return
- }
-
- jwk["use"] = "sig"
-
- jwks := map[string][]map[string]string{
- "keys": {
- jwk,
- },
- }
-
- ctx.Resp.Header().Set("Content-Type", "application/json")
- enc := json.NewEncoder(ctx.Resp)
- if err := enc.Encode(jwks); err != nil {
- log.Error("Failed to encode representation as json. Error: %v", err)
- }
-}
-
-// AccessTokenOAuth manages all access token requests by the client
-func AccessTokenOAuth(ctx *context.Context) {
- form := *web.GetForm(ctx).(*forms.AccessTokenForm)
- // if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header
- if form.ClientID == "" || form.ClientSecret == "" {
- authHeader := ctx.Req.Header.Get("Authorization")
- if authType, authData, ok := strings.Cut(authHeader, " "); ok && strings.EqualFold(authType, "Basic") {
- clientID, clientSecret, err := base.BasicAuthDecode(authData)
- if err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot parse basic auth header",
- })
- return
- }
- // validate that any fields present in the form match the Basic auth header
- if form.ClientID != "" && form.ClientID != clientID {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "client_id in request body inconsistent with Authorization header",
- })
- return
- }
- form.ClientID = clientID
- if form.ClientSecret != "" && form.ClientSecret != clientSecret {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "client_secret in request body inconsistent with Authorization header",
- })
- return
- }
- form.ClientSecret = clientSecret
- }
- }
-
- serverKey := oauth2.DefaultSigningKey
- clientKey := serverKey
- if serverKey.IsSymmetric() {
- var err error
- clientKey, err = oauth2.CreateJWTSigningKey(serverKey.SigningMethod().Alg(), []byte(form.ClientSecret))
- if err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "Error creating signing key",
- })
- return
- }
- }
-
- switch form.GrantType {
- case "refresh_token":
- handleRefreshToken(ctx, form, serverKey, clientKey)
- case "authorization_code":
- handleAuthorizationCode(ctx, form, serverKey, clientKey)
- default:
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnsupportedGrantType,
- ErrorDescription: "Only refresh_token or authorization_code grant type is supported",
- })
- }
-}
-
-func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, serverKey, clientKey oauth2.JWTSigningKey) {
- app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
- if err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidClient,
- ErrorDescription: fmt.Sprintf("cannot load client with client id: %q", form.ClientID),
- })
- return
- }
- // "The authorization server MUST ... require client authentication for confidential clients"
- // https://datatracker.ietf.org/doc/html/rfc6749#section-6
- if app.ConfidentialClient && !app.ValidateClientSecret([]byte(form.ClientSecret)) {
- errorDescription := "invalid client secret"
- if form.ClientSecret == "" {
- errorDescription = "invalid empty client secret"
- }
- // "invalid_client ... Client authentication failed"
- // https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidClient,
- ErrorDescription: errorDescription,
- })
- return
- }
-
- token, err := oauth2.ParseToken(form.RefreshToken, serverKey)
- if err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "unable to parse refresh token",
- })
- return
- }
- // get grant before increasing counter
- grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID)
- if err != nil || grant == nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidGrant,
- ErrorDescription: "grant does not exist",
- })
- return
- }
-
- // check if token got already used
- if setting.OAuth2.InvalidateRefreshTokens && (grant.Counter != token.Counter || token.Counter == 0) {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "token was already used",
- })
- log.Warn("A client tried to use a refresh token for grant_id = %d was used twice!", grant.ID)
- return
- }
- accessToken, tokenErr := newAccessTokenResponse(ctx, grant, serverKey, clientKey)
- if tokenErr != nil {
- handleAccessTokenError(ctx, *tokenErr)
- return
- }
- ctx.JSON(http.StatusOK, accessToken)
-}
-
-func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, serverKey, clientKey oauth2.JWTSigningKey) {
- app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
- if err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidClient,
- ErrorDescription: fmt.Sprintf("cannot load client with client id: '%s'", form.ClientID),
- })
- return
- }
- if app.ConfidentialClient && !app.ValidateClientSecret([]byte(form.ClientSecret)) {
- errorDescription := "invalid client secret"
- if form.ClientSecret == "" {
- errorDescription = "invalid empty client secret"
- }
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: errorDescription,
- })
- return
- }
- if form.RedirectURI != "" && !app.ContainsRedirectURI(form.RedirectURI) {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "unexpected redirect URI",
- })
- return
- }
- authorizationCode, err := auth.GetOAuth2AuthorizationByCode(ctx, form.Code)
- if err != nil || authorizationCode == nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "client is not authorized",
- })
- return
- }
- // check if code verifier authorizes the client, PKCE support
- if !authorizationCode.ValidateCodeChallenge(form.CodeVerifier) {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "failed PKCE code challenge",
- })
- return
- }
- // check if granted for this application
- if authorizationCode.Grant.ApplicationID != app.ID {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidGrant,
- ErrorDescription: "invalid grant",
- })
- return
- }
- // remove token from database to deny duplicate usage
- if err := authorizationCode.Invalidate(ctx); err != nil {
- handleAccessTokenError(ctx, AccessTokenError{
- ErrorCode: AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot proceed your request",
- })
- }
- resp, tokenErr := newAccessTokenResponse(ctx, authorizationCode.Grant, serverKey, clientKey)
- if tokenErr != nil {
- handleAccessTokenError(ctx, *tokenErr)
- return
- }
- // send successful response
- ctx.JSON(http.StatusOK, resp)
-}
-
-func handleAccessTokenError(ctx *context.Context, acErr AccessTokenError) {
- ctx.JSON(http.StatusBadRequest, acErr)
-}
-
-func handleServerError(ctx *context.Context, state, redirectURI string) {
- handleAuthorizeError(ctx, AuthorizeError{
- ErrorCode: ErrorCodeServerError,
- ErrorDescription: "A server error occurred",
- State: state,
- }, redirectURI)
-}
-
-func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirectURI string) {
- if redirectURI == "" {
- log.Warn("Authorization failed: %v", authErr.ErrorDescription)
- ctx.Data["Error"] = authErr
- ctx.HTML(http.StatusBadRequest, tplGrantError)
- return
- }
- redirect, err := url.Parse(redirectURI)
- if err != nil {
- ctx.ServerError("url.Parse", err)
- return
- }
- q := redirect.Query()
- q.Set("error", string(authErr.ErrorCode))
- q.Set("error_description", authErr.ErrorDescription)
- q.Set("state", authErr.State)
- redirect.RawQuery = q.Encode()
- ctx.Redirect(redirect.String(), http.StatusSeeOther)
-}
-
// SignInOAuth handles the OAuth2 login buttons
func SignInOAuth(ctx *context.Context) {
provider := ctx.PathParam(":provider")
diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go
new file mode 100644
index 0000000000..29827b062d
--- /dev/null
+++ b/routers/web/auth/oauth2_provider.go
@@ -0,0 +1,666 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package auth
+
+import (
+ "errors"
+ "fmt"
+ "html"
+ "html/template"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "code.gitea.io/gitea/models/auth"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/web"
+ auth_service "code.gitea.io/gitea/services/auth"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/forms"
+ "code.gitea.io/gitea/services/oauth2_provider"
+
+ "gitea.com/go-chi/binding"
+ jwt "github.com/golang-jwt/jwt/v5"
+)
+
+const (
+ tplGrantAccess base.TplName = "user/auth/grant"
+ tplGrantError base.TplName = "user/auth/grant_error"
+)
+
+// TODO move error and responses to SDK or models
+
+// AuthorizeErrorCode represents an error code specified in RFC 6749
+// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
+type AuthorizeErrorCode string
+
+const (
+ // ErrorCodeInvalidRequest represents the according error in RFC 6749
+ ErrorCodeInvalidRequest AuthorizeErrorCode = "invalid_request"
+ // ErrorCodeUnauthorizedClient represents the according error in RFC 6749
+ ErrorCodeUnauthorizedClient AuthorizeErrorCode = "unauthorized_client"
+ // ErrorCodeAccessDenied represents the according error in RFC 6749
+ ErrorCodeAccessDenied AuthorizeErrorCode = "access_denied"
+ // ErrorCodeUnsupportedResponseType represents the according error in RFC 6749
+ ErrorCodeUnsupportedResponseType AuthorizeErrorCode = "unsupported_response_type"
+ // ErrorCodeInvalidScope represents the according error in RFC 6749
+ ErrorCodeInvalidScope AuthorizeErrorCode = "invalid_scope"
+ // ErrorCodeServerError represents the according error in RFC 6749
+ ErrorCodeServerError AuthorizeErrorCode = "server_error"
+ // ErrorCodeTemporaryUnavailable represents the according error in RFC 6749
+ ErrorCodeTemporaryUnavailable AuthorizeErrorCode = "temporarily_unavailable"
+)
+
+// AuthorizeError represents an error type specified in RFC 6749
+// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
+type AuthorizeError struct {
+ ErrorCode AuthorizeErrorCode `json:"error" form:"error"`
+ ErrorDescription string
+ State string
+}
+
+// Error returns the error message
+func (err AuthorizeError) Error() string {
+ return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
+}
+
+// errCallback represents a oauth2 callback error
+type errCallback struct {
+ Code string
+ Description string
+}
+
+func (err errCallback) Error() string {
+ return err.Description
+}
+
+type userInfoResponse struct {
+ Sub string `json:"sub"`
+ Name string `json:"name"`
+ Username string `json:"preferred_username"`
+ Email string `json:"email"`
+ Picture string `json:"picture"`
+ Groups []string `json:"groups"`
+}
+
+// InfoOAuth manages request for userinfo endpoint
+func InfoOAuth(ctx *context.Context) {
+ if ctx.Doer == nil || ctx.Data["AuthedMethod"] != (&auth_service.OAuth2{}).Name() {
+ ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
+ ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
+ return
+ }
+
+ response := &userInfoResponse{
+ Sub: fmt.Sprint(ctx.Doer.ID),
+ Name: ctx.Doer.FullName,
+ Username: ctx.Doer.Name,
+ Email: ctx.Doer.Email,
+ Picture: ctx.Doer.AvatarLink(ctx),
+ }
+
+ groups, err := oauth2_provider.GetOAuthGroupsForUser(ctx, ctx.Doer)
+ if err != nil {
+ ctx.ServerError("Oauth groups for user", err)
+ return
+ }
+ response.Groups = groups
+
+ ctx.JSON(http.StatusOK, response)
+}
+
+func parseBasicAuth(ctx *context.Context) (username, password string, err error) {
+ authHeader := ctx.Req.Header.Get("Authorization")
+ if authType, authData, ok := strings.Cut(authHeader, " "); ok && strings.EqualFold(authType, "Basic") {
+ return base.BasicAuthDecode(authData)
+ }
+ return "", "", errors.New("invalid basic authentication")
+}
+
+// IntrospectOAuth introspects an oauth token
+func IntrospectOAuth(ctx *context.Context) {
+ clientIDValid := false
+ if clientID, clientSecret, err := parseBasicAuth(ctx); err == nil {
+ app, err := auth.GetOAuth2ApplicationByClientID(ctx, clientID)
+ if err != nil && !auth.IsErrOauthClientIDInvalid(err) {
+ // this is likely a database error; log it and respond without details
+ log.Error("Error retrieving client_id: %v", err)
+ ctx.Error(http.StatusInternalServerError)
+ return
+ }
+ clientIDValid = err == nil && app.ValidateClientSecret([]byte(clientSecret))
+ }
+ if !clientIDValid {
+ ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm=""`)
+ ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
+ return
+ }
+
+ var response struct {
+ Active bool `json:"active"`
+ Scope string `json:"scope,omitempty"`
+ Username string `json:"username,omitempty"`
+ jwt.RegisteredClaims
+ }
+
+ form := web.GetForm(ctx).(*forms.IntrospectTokenForm)
+ token, err := oauth2_provider.ParseToken(form.Token, oauth2_provider.DefaultSigningKey)
+ if err == nil {
+ grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID)
+ if err == nil && grant != nil {
+ app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID)
+ if err == nil && app != nil {
+ response.Active = true
+ response.Scope = grant.Scope
+ response.Issuer = setting.AppURL
+ response.Audience = []string{app.ClientID}
+ response.Subject = fmt.Sprint(grant.UserID)
+ }
+ if user, err := user_model.GetUserByID(ctx, grant.UserID); err == nil {
+ response.Username = user.Name
+ }
+ }
+ }
+
+ ctx.JSON(http.StatusOK, response)
+}
+
+// AuthorizeOAuth manages authorize requests
+func AuthorizeOAuth(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.AuthorizationForm)
+ errs := binding.Errors{}
+ errs = form.Validate(ctx.Req, errs)
+ if len(errs) > 0 {
+ errstring := ""
+ for _, e := range errs {
+ errstring += e.Error() + "\n"
+ }
+ ctx.ServerError("AuthorizeOAuth: Validate: ", fmt.Errorf("errors occurred during validation: %s", errstring))
+ return
+ }
+
+ app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
+ if err != nil {
+ if auth.IsErrOauthClientIDInvalid(err) {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeUnauthorizedClient,
+ ErrorDescription: "Client ID not registered",
+ State: form.State,
+ }, "")
+ return
+ }
+ ctx.ServerError("GetOAuth2ApplicationByClientID", err)
+ return
+ }
+
+ var user *user_model.User
+ if app.UID != 0 {
+ user, err = user_model.GetUserByID(ctx, app.UID)
+ if err != nil {
+ ctx.ServerError("GetUserByID", err)
+ return
+ }
+ }
+
+ if !app.ContainsRedirectURI(form.RedirectURI) {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeInvalidRequest,
+ ErrorDescription: "Unregistered Redirect URI",
+ State: form.State,
+ }, "")
+ return
+ }
+
+ if form.ResponseType != "code" {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeUnsupportedResponseType,
+ ErrorDescription: "Only code response type is supported.",
+ State: form.State,
+ }, form.RedirectURI)
+ return
+ }
+
+ // pkce support
+ switch form.CodeChallengeMethod {
+ case "S256":
+ case "plain":
+ if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallengeMethod); err != nil {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeServerError,
+ ErrorDescription: "cannot set code challenge method",
+ State: form.State,
+ }, form.RedirectURI)
+ return
+ }
+ if err := ctx.Session.Set("CodeChallengeMethod", form.CodeChallenge); err != nil {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeServerError,
+ ErrorDescription: "cannot set code challenge",
+ State: form.State,
+ }, form.RedirectURI)
+ return
+ }
+ // Here we're just going to try to release the session early
+ if err := ctx.Session.Release(); err != nil {
+ // we'll tolerate errors here as they *should* get saved elsewhere
+ log.Error("Unable to save changes to the session: %v", err)
+ }
+ case "":
+ // "Authorization servers SHOULD reject authorization requests from native apps that don't use PKCE by returning an error message"
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-8.1
+ if !app.ConfidentialClient {
+ // "the authorization endpoint MUST return the authorization error response with the "error" value set to "invalid_request""
+ // https://datatracker.ietf.org/doc/html/rfc7636#section-4.4.1
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeInvalidRequest,
+ ErrorDescription: "PKCE is required for public clients",
+ State: form.State,
+ }, form.RedirectURI)
+ return
+ }
+ default:
+ // "If the server supporting PKCE does not support the requested transformation, the authorization endpoint MUST return the authorization error response with "error" value set to "invalid_request"."
+ // https://www.rfc-editor.org/rfc/rfc7636#section-4.4.1
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeInvalidRequest,
+ ErrorDescription: "unsupported code challenge method",
+ State: form.State,
+ }, form.RedirectURI)
+ return
+ }
+
+ grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+
+ // Redirect if user already granted access and the application is confidential or trusted otherwise
+ // I.e. always require authorization for untrusted public clients as recommended by RFC 6749 Section 10.2
+ if (app.ConfidentialClient || app.SkipSecondaryAuthorization) && grant != nil {
+ code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+ redirect, err := code.GenerateRedirectURI(form.State)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+ // Update nonce to reflect the new session
+ if len(form.Nonce) > 0 {
+ err := grant.SetNonce(ctx, form.Nonce)
+ if err != nil {
+ log.Error("Unable to update nonce: %v", err)
+ }
+ }
+ ctx.Redirect(redirect.String())
+ return
+ }
+
+ // show authorize page to grant access
+ ctx.Data["Application"] = app
+ ctx.Data["RedirectURI"] = form.RedirectURI
+ ctx.Data["State"] = form.State
+ ctx.Data["Scope"] = form.Scope
+ ctx.Data["Nonce"] = form.Nonce
+ if user != nil {
+ ctx.Data["ApplicationCreatorLinkHTML"] = template.HTML(fmt.Sprintf(`@%s`, html.EscapeString(user.HomeLink()), html.EscapeString(user.Name)))
+ } else {
+ ctx.Data["ApplicationCreatorLinkHTML"] = template.HTML(fmt.Sprintf(`%s`, html.EscapeString(setting.AppSubURL+"/"), html.EscapeString(setting.AppName)))
+ }
+ ctx.Data["ApplicationRedirectDomainHTML"] = template.HTML("" + html.EscapeString(form.RedirectURI) + "")
+ // TODO document SESSION <=> FORM
+ err = ctx.Session.Set("client_id", app.ClientID)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ log.Error(err.Error())
+ return
+ }
+ err = ctx.Session.Set("redirect_uri", form.RedirectURI)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ log.Error(err.Error())
+ return
+ }
+ err = ctx.Session.Set("state", form.State)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ log.Error(err.Error())
+ return
+ }
+ // Here we're just going to try to release the session early
+ if err := ctx.Session.Release(); err != nil {
+ // we'll tolerate errors here as they *should* get saved elsewhere
+ log.Error("Unable to save changes to the session: %v", err)
+ }
+ ctx.HTML(http.StatusOK, tplGrantAccess)
+}
+
+// GrantApplicationOAuth manages the post request submitted when a user grants access to an application
+func GrantApplicationOAuth(ctx *context.Context) {
+ form := web.GetForm(ctx).(*forms.GrantApplicationForm)
+ if ctx.Session.Get("client_id") != form.ClientID || ctx.Session.Get("state") != form.State ||
+ ctx.Session.Get("redirect_uri") != form.RedirectURI {
+ ctx.Error(http.StatusBadRequest)
+ return
+ }
+
+ if !form.Granted {
+ handleAuthorizeError(ctx, AuthorizeError{
+ State: form.State,
+ ErrorDescription: "the request is denied",
+ ErrorCode: ErrorCodeAccessDenied,
+ }, form.RedirectURI)
+ return
+ }
+
+ app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
+ if err != nil {
+ ctx.ServerError("GetOAuth2ApplicationByClientID", err)
+ return
+ }
+ grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+ if grant == nil {
+ grant, err = app.CreateGrant(ctx, ctx.Doer.ID, form.Scope)
+ if err != nil {
+ handleAuthorizeError(ctx, AuthorizeError{
+ State: form.State,
+ ErrorDescription: "cannot create grant for user",
+ ErrorCode: ErrorCodeServerError,
+ }, form.RedirectURI)
+ return
+ }
+ } else if grant.Scope != form.Scope {
+ handleAuthorizeError(ctx, AuthorizeError{
+ State: form.State,
+ ErrorDescription: "a grant exists with different scope",
+ ErrorCode: ErrorCodeServerError,
+ }, form.RedirectURI)
+ return
+ }
+
+ if len(form.Nonce) > 0 {
+ err := grant.SetNonce(ctx, form.Nonce)
+ if err != nil {
+ log.Error("Unable to update nonce: %v", err)
+ }
+ }
+
+ var codeChallenge, codeChallengeMethod string
+ codeChallenge, _ = ctx.Session.Get("CodeChallenge").(string)
+ codeChallengeMethod, _ = ctx.Session.Get("CodeChallengeMethod").(string)
+
+ code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, codeChallenge, codeChallengeMethod)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+ redirect, err := code.GenerateRedirectURI(form.State)
+ if err != nil {
+ handleServerError(ctx, form.State, form.RedirectURI)
+ return
+ }
+ ctx.Redirect(redirect.String(), http.StatusSeeOther)
+}
+
+// OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities
+func OIDCWellKnown(ctx *context.Context) {
+ ctx.Data["SigningKey"] = oauth2_provider.DefaultSigningKey
+ ctx.JSONTemplate("user/auth/oidc_wellknown")
+}
+
+// OIDCKeys generates the JSON Web Key Set
+func OIDCKeys(ctx *context.Context) {
+ jwk, err := oauth2_provider.DefaultSigningKey.ToJWK()
+ if err != nil {
+ log.Error("Error converting signing key to JWK: %v", err)
+ ctx.Error(http.StatusInternalServerError)
+ return
+ }
+
+ jwk["use"] = "sig"
+
+ jwks := map[string][]map[string]string{
+ "keys": {
+ jwk,
+ },
+ }
+
+ ctx.Resp.Header().Set("Content-Type", "application/json")
+ enc := json.NewEncoder(ctx.Resp)
+ if err := enc.Encode(jwks); err != nil {
+ log.Error("Failed to encode representation as json. Error: %v", err)
+ }
+}
+
+// AccessTokenOAuth manages all access token requests by the client
+func AccessTokenOAuth(ctx *context.Context) {
+ form := *web.GetForm(ctx).(*forms.AccessTokenForm)
+ // if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header
+ if form.ClientID == "" || form.ClientSecret == "" {
+ authHeader := ctx.Req.Header.Get("Authorization")
+ if authType, authData, ok := strings.Cut(authHeader, " "); ok && strings.EqualFold(authType, "Basic") {
+ clientID, clientSecret, err := base.BasicAuthDecode(authData)
+ if err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot parse basic auth header",
+ })
+ return
+ }
+ // validate that any fields present in the form match the Basic auth header
+ if form.ClientID != "" && form.ClientID != clientID {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "client_id in request body inconsistent with Authorization header",
+ })
+ return
+ }
+ form.ClientID = clientID
+ if form.ClientSecret != "" && form.ClientSecret != clientSecret {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "client_secret in request body inconsistent with Authorization header",
+ })
+ return
+ }
+ form.ClientSecret = clientSecret
+ }
+ }
+
+ serverKey := oauth2_provider.DefaultSigningKey
+ clientKey := serverKey
+ if serverKey.IsSymmetric() {
+ var err error
+ clientKey, err = oauth2_provider.CreateJWTSigningKey(serverKey.SigningMethod().Alg(), []byte(form.ClientSecret))
+ if err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "Error creating signing key",
+ })
+ return
+ }
+ }
+
+ switch form.GrantType {
+ case "refresh_token":
+ handleRefreshToken(ctx, form, serverKey, clientKey)
+ case "authorization_code":
+ handleAuthorizationCode(ctx, form, serverKey, clientKey)
+ default:
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnsupportedGrantType,
+ ErrorDescription: "Only refresh_token or authorization_code grant type is supported",
+ })
+ }
+}
+
+func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, serverKey, clientKey oauth2_provider.JWTSigningKey) {
+ app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
+ if err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidClient,
+ ErrorDescription: fmt.Sprintf("cannot load client with client id: %q", form.ClientID),
+ })
+ return
+ }
+ // "The authorization server MUST ... require client authentication for confidential clients"
+ // https://datatracker.ietf.org/doc/html/rfc6749#section-6
+ if app.ConfidentialClient && !app.ValidateClientSecret([]byte(form.ClientSecret)) {
+ errorDescription := "invalid client secret"
+ if form.ClientSecret == "" {
+ errorDescription = "invalid empty client secret"
+ }
+ // "invalid_client ... Client authentication failed"
+ // https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidClient,
+ ErrorDescription: errorDescription,
+ })
+ return
+ }
+
+ token, err := oauth2_provider.ParseToken(form.RefreshToken, serverKey)
+ if err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: "unable to parse refresh token",
+ })
+ return
+ }
+ // get grant before increasing counter
+ grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID)
+ if err != nil || grant == nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidGrant,
+ ErrorDescription: "grant does not exist",
+ })
+ return
+ }
+
+ // check if token got already used
+ if setting.OAuth2.InvalidateRefreshTokens && (grant.Counter != token.Counter || token.Counter == 0) {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: "token was already used",
+ })
+ log.Warn("A client tried to use a refresh token for grant_id = %d was used twice!", grant.ID)
+ return
+ }
+ accessToken, tokenErr := oauth2_provider.NewAccessTokenResponse(ctx, grant, serverKey, clientKey)
+ if tokenErr != nil {
+ handleAccessTokenError(ctx, *tokenErr)
+ return
+ }
+ ctx.JSON(http.StatusOK, accessToken)
+}
+
+func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, serverKey, clientKey oauth2_provider.JWTSigningKey) {
+ app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID)
+ if err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidClient,
+ ErrorDescription: fmt.Sprintf("cannot load client with client id: '%s'", form.ClientID),
+ })
+ return
+ }
+ if app.ConfidentialClient && !app.ValidateClientSecret([]byte(form.ClientSecret)) {
+ errorDescription := "invalid client secret"
+ if form.ClientSecret == "" {
+ errorDescription = "invalid empty client secret"
+ }
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: errorDescription,
+ })
+ return
+ }
+ if form.RedirectURI != "" && !app.ContainsRedirectURI(form.RedirectURI) {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: "unexpected redirect URI",
+ })
+ return
+ }
+ authorizationCode, err := auth.GetOAuth2AuthorizationByCode(ctx, form.Code)
+ if err != nil || authorizationCode == nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: "client is not authorized",
+ })
+ return
+ }
+ // check if code verifier authorizes the client, PKCE support
+ if !authorizationCode.ValidateCodeChallenge(form.CodeVerifier) {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeUnauthorizedClient,
+ ErrorDescription: "failed PKCE code challenge",
+ })
+ return
+ }
+ // check if granted for this application
+ if authorizationCode.Grant.ApplicationID != app.ID {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidGrant,
+ ErrorDescription: "invalid grant",
+ })
+ return
+ }
+ // remove token from database to deny duplicate usage
+ if err := authorizationCode.Invalidate(ctx); err != nil {
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot proceed your request",
+ })
+ }
+ resp, tokenErr := oauth2_provider.NewAccessTokenResponse(ctx, authorizationCode.Grant, serverKey, clientKey)
+ if tokenErr != nil {
+ handleAccessTokenError(ctx, *tokenErr)
+ return
+ }
+ // send successful response
+ ctx.JSON(http.StatusOK, resp)
+}
+
+func handleAccessTokenError(ctx *context.Context, acErr oauth2_provider.AccessTokenError) {
+ ctx.JSON(http.StatusBadRequest, acErr)
+}
+
+func handleServerError(ctx *context.Context, state, redirectURI string) {
+ handleAuthorizeError(ctx, AuthorizeError{
+ ErrorCode: ErrorCodeServerError,
+ ErrorDescription: "A server error occurred",
+ State: state,
+ }, redirectURI)
+}
+
+func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirectURI string) {
+ if redirectURI == "" {
+ log.Warn("Authorization failed: %v", authErr.ErrorDescription)
+ ctx.Data["Error"] = authErr
+ ctx.HTML(http.StatusBadRequest, tplGrantError)
+ return
+ }
+ redirect, err := url.Parse(redirectURI)
+ if err != nil {
+ ctx.ServerError("url.Parse", err)
+ return
+ }
+ q := redirect.Query()
+ q.Set("error", string(authErr.ErrorCode))
+ q.Set("error_description", authErr.ErrorDescription)
+ q.Set("state", authErr.State)
+ redirect.RawQuery = q.Encode()
+ ctx.Redirect(redirect.String(), http.StatusSeeOther)
+}
diff --git a/routers/web/auth/oauth_test.go b/routers/web/auth/oauth_test.go
index 4339d9d1eb..78af97fa9c 100644
--- a/routers/web/auth/oauth_test.go
+++ b/routers/web/auth/oauth_test.go
@@ -11,22 +11,22 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/services/auth/source/oauth2"
+ "code.gitea.io/gitea/services/oauth2_provider"
"github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
)
-func createAndParseToken(t *testing.T, grant *auth.OAuth2Grant) *oauth2.OIDCToken {
- signingKey, err := oauth2.CreateJWTSigningKey("HS256", make([]byte, 32))
+func createAndParseToken(t *testing.T, grant *auth.OAuth2Grant) *oauth2_provider.OIDCToken {
+ signingKey, err := oauth2_provider.CreateJWTSigningKey("HS256", make([]byte, 32))
assert.NoError(t, err)
assert.NotNil(t, signingKey)
- response, terr := newAccessTokenResponse(db.DefaultContext, grant, signingKey, signingKey)
+ response, terr := oauth2_provider.NewAccessTokenResponse(db.DefaultContext, grant, signingKey, signingKey)
assert.Nil(t, terr)
assert.NotNil(t, response)
- parsedToken, err := jwt.ParseWithClaims(response.IDToken, &oauth2.OIDCToken{}, func(token *jwt.Token) (any, error) {
+ parsedToken, err := jwt.ParseWithClaims(response.IDToken, &oauth2_provider.OIDCToken{}, func(token *jwt.Token) (any, error) {
assert.NotNil(t, token.Method)
assert.Equal(t, signingKey.SigningMethod().Alg(), token.Method.Alg())
return signingKey.VerifyKey(), nil
@@ -34,7 +34,7 @@ func createAndParseToken(t *testing.T, grant *auth.OAuth2Grant) *oauth2.OIDCToke
assert.NoError(t, err)
assert.True(t, parsedToken.Valid)
- oidcToken, ok := parsedToken.Claims.(*oauth2.OIDCToken)
+ oidcToken, ok := parsedToken.Claims.(*oauth2_provider.OIDCToken)
assert.True(t, ok)
assert.NotNil(t, oidcToken)
diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go
index 66760d31db..2a5434b414 100644
--- a/routers/web/org/projects.go
+++ b/routers/web/org/projects.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
+ org_model "code.gitea.io/gitea/models/organization"
project_model "code.gitea.io/gitea/models/project"
attachment_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
@@ -333,7 +334,29 @@ func ViewProject(ctx *context.Context) {
return
}
- issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns)
+ var labelIDs []int64
+ // 1,-2 means including label 1 and excluding label 2
+ // 0 means issues with no label
+ // blank means labels will not be filtered for issues
+ selectLabels := ctx.FormString("labels")
+ if selectLabels == "" {
+ ctx.Data["AllLabels"] = true
+ } else if selectLabels == "0" {
+ ctx.Data["NoLabel"] = true
+ }
+ if len(selectLabels) > 0 {
+ labelIDs, err = base.StringsToInt64s(strings.Split(selectLabels, ","))
+ if err != nil {
+ ctx.Flash.Error(ctx.Tr("invalid_data", selectLabels), true)
+ }
+ }
+
+ assigneeID := ctx.FormInt64("assignee")
+
+ issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns, &issues_model.IssuesOptions{
+ LabelIDs: labelIDs,
+ AssigneeID: assigneeID,
+ })
if err != nil {
ctx.ServerError("LoadIssuesOfColumns", err)
return
@@ -372,6 +395,46 @@ func ViewProject(ctx *context.Context) {
}
}
+ // TODO: Add option to filter also by repository specific labels
+ labels, err := issues_model.GetLabelsByOrgID(ctx, project.OwnerID, "", db.ListOptions{})
+ if err != nil {
+ ctx.ServerError("GetLabelsByOrgID", err)
+ return
+ }
+
+ // Get the exclusive scope for every label ID
+ labelExclusiveScopes := make([]string, 0, len(labelIDs))
+ for _, labelID := range labelIDs {
+ foundExclusiveScope := false
+ for _, label := range labels {
+ if label.ID == labelID || label.ID == -labelID {
+ labelExclusiveScopes = append(labelExclusiveScopes, label.ExclusiveScope())
+ foundExclusiveScope = true
+ break
+ }
+ }
+ if !foundExclusiveScope {
+ labelExclusiveScopes = append(labelExclusiveScopes, "")
+ }
+ }
+
+ for _, l := range labels {
+ l.LoadSelectedLabelsAfterClick(labelIDs, labelExclusiveScopes)
+ }
+ ctx.Data["Labels"] = labels
+ ctx.Data["NumLabels"] = len(labels)
+
+ // Get assignees.
+ assigneeUsers, err := org_model.GetOrgAssignees(ctx, project.OwnerID)
+ if err != nil {
+ ctx.ServerError("GetRepoAssignees", err)
+ return
+ }
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
+
+ ctx.Data["SelectLabels"] = selectLabels
+ ctx.Data["AssigneeID"] = assigneeID
+
project.RenderedContent = templates.RenderMarkdownToHtml(ctx, project.Description)
ctx.Data["LinkedPRs"] = linkedPrsMap
ctx.Data["PageIsViewProjects"] = true
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index 63cf3e948a..f5fb056494 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -23,7 +23,7 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/routers/web/repo"
+ shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -252,7 +252,7 @@ func List(ctx *context.Context) {
ctx.ServerError("GetActors", err)
return
}
- ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx.Doer, actors)
+ ctx.Data["Actors"] = shared_user.MakeSelfOnTop(ctx.Doer, actors)
ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx)
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index 4897a5f4fc..4a62237838 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -89,7 +89,7 @@ func Branches(ctx *context.Context) {
pager := context.NewPagination(int(branchesCount), pageSize, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
-
+ ctx.Data["LicenseFileName"] = repo_service.LicenseFileName
ctx.HTML(http.StatusOK, tplBranch)
}
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index c91d5fad05..0e4e10bf50 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -29,7 +29,7 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/gitdiff"
- git_service "code.gitea.io/gitea/services/repository"
+ repo_service "code.gitea.io/gitea/services/repository"
)
const (
@@ -90,7 +90,7 @@ func Commits(ctx *context.Context) {
commitsTagsMap, err := repo_model.FindTagsByCommitIDs(ctx, ctx.Repo.Repository.ID, commitIDs...)
if err != nil {
log.Error("FindTagsByCommitIDs: %v", err)
- ctx.Flash.Error(ctx.Tr("repo.commit.load_tags_failed"))
+ ctx.Flash.Error(ctx.Tr("internal_error_skipped", "FindTagsByCommitIDs"))
} else {
ctx.Data["CommitsTagsMap"] = commitsTagsMap
}
@@ -101,7 +101,7 @@ func Commits(ctx *context.Context) {
pager := context.NewPagination(int(commitsCount), pageSize, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
-
+ ctx.Data["LicenseFileName"] = repo_service.LicenseFileName
ctx.HTML(http.StatusOK, tplCommits)
}
@@ -218,6 +218,8 @@ func SearchCommits(ctx *context.Context) {
}
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
+ ctx.Data["RefName"] = ctx.Repo.RefName
+ ctx.Data["LicenseFileName"] = repo_service.LicenseFileName
ctx.HTML(http.StatusOK, tplCommits)
}
@@ -263,12 +265,12 @@ func FileHistory(ctx *context.Context) {
pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
-
+ ctx.Data["LicenseFileName"] = repo_service.LicenseFileName
ctx.HTML(http.StatusOK, tplCommits)
}
func LoadBranchesAndTags(ctx *context.Context) {
- response, err := git_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.PathParam("sha"))
+ response, err := repo_service.LoadBranchesAndTags(ctx, ctx.Repo, ctx.PathParam("sha"))
if err == nil {
ctx.JSON(http.StatusOK, response)
return
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 4ff86b5a66..9396115b0d 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -317,7 +317,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b
case git.EntryModeBlob:
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form)
default:
- ctx.Error(http.StatusInternalServerError, err.Error())
+ ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", fileErr.Path), tplEditFile, &form)
}
} else {
ctx.Error(http.StatusInternalServerError, err.Error())
diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go
index bb85df1a86..ee1ec1fd0c 100644
--- a/routers/web/repo/githttp.go
+++ b/routers/web/repo/githttp.go
@@ -395,7 +395,8 @@ func (h *serviceHandler) sendFile(ctx *context.Context, contentType, file string
ctx.Resp.Header().Set("Content-Type", contentType)
ctx.Resp.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size()))
- ctx.Resp.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat))
+ // http.TimeFormat required a UTC time, refer to https://pkg.go.dev/net/http#TimeFormat
+ ctx.Resp.Header().Set("Last-Modified", fi.ModTime().UTC().Format(http.TimeFormat))
http.ServeFile(ctx.Resp, ctx.Req, reqFile)
}
diff --git a/routers/web/repo/helper.go b/routers/web/repo/helper.go
index 5e1e116018..ed6216fa5c 100644
--- a/routers/web/repo/helper.go
+++ b/routers/web/repo/helper.go
@@ -5,25 +5,11 @@ package repo
import (
"net/url"
- "sort"
- "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/services/context"
)
-func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
- if doer != nil {
- sort.Slice(users, func(i, j int) bool {
- if users[i].ID == users[j].ID {
- return false
- }
- return users[i].ID == doer.ID // if users[i] is self, put it before others, so less=true
- })
- }
- return users
-}
-
func HandleGitError(ctx *context.Context, msg string, err error) {
if git.IsErrNotExist(err) {
refType := ""
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index fd6abe04fe..507b5af9d9 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -49,6 +49,7 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/utils"
+ shared_user "code.gitea.io/gitea/routers/web/shared/user"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/context/upload"
@@ -360,7 +361,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
ctx.ServerError("GetRepoAssignees", err)
return
}
- ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
handleTeamMentions(ctx)
if ctx.Written() {
@@ -466,6 +467,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
ctx.Data["AssigneeID"] = assigneeID
ctx.Data["PosterID"] = posterID
ctx.Data["Keyword"] = keyword
+ ctx.Data["IsShowClosed"] = isShowClosed
switch {
case isShowClosed.Value():
ctx.Data["State"] = "closed"
@@ -580,7 +582,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R
ctx.ServerError("GetRepoAssignees", err)
return
}
- ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
handleTeamMentions(ctx)
}
@@ -3771,7 +3773,7 @@ func issuePosters(ctx *context.Context, isPullList bool) {
}
}
- posters = MakeSelfOnTop(ctx.Doer, posters)
+ posters = shared_user.MakeSelfOnTop(ctx.Doer, posters)
resp := &userSearchResponse{}
resp.Results = make([]*userSearchInfo, len(posters))
diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go
index 97b0c425ea..3eaf05f383 100644
--- a/routers/web/repo/migrate.go
+++ b/routers/web/repo/migrate.go
@@ -15,6 +15,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -231,6 +232,10 @@ func MigratePost(ctx *context.Context) {
opts.PullRequests = false
opts.Releases = false
}
+ if form.Service == structs.CodeCommitService {
+ opts.AWSAccessKeyID = form.AWSAccessKeyID
+ opts.AWSSecretAccessKey = form.AWSSecretAccessKey
+ }
err = repo_model.CheckCreateRepository(ctx, ctx.Doer, ctxUser, opts.RepoName, false)
if err != nil {
@@ -284,3 +289,40 @@ func MigrateCancelPost(ctx *context.Context) {
}
ctx.Redirect(ctx.Repo.Repository.Link())
}
+
+// MigrateStatus returns migrate task's status
+func MigrateStatus(ctx *context.Context) {
+ task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID)
+ if err != nil {
+ if admin_model.IsErrTaskDoesNotExist(err) {
+ ctx.JSON(http.StatusNotFound, map[string]any{
+ "err": "task does not exist or you do not have access to this task",
+ })
+ return
+ }
+ log.Error("GetMigratingTask: %v", err)
+ ctx.JSON(http.StatusInternalServerError, map[string]any{
+ "err": http.StatusText(http.StatusInternalServerError),
+ })
+ return
+ }
+
+ message := task.Message
+
+ if task.Message != "" && task.Message[0] == '{' {
+ // assume message is actually a translatable string
+ var translatableMessage admin_model.TranslatableMessage
+ if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
+ translatableMessage = admin_model.TranslatableMessage{
+ Format: "migrate.migrating_failed.error",
+ Args: []any{task.Message},
+ }
+ }
+ message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
+ }
+
+ ctx.JSON(http.StatusOK, map[string]any{
+ "status": task.Status,
+ "message": message,
+ })
+}
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index aac8997d62..664ea7eb76 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
+ shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
project_service "code.gitea.io/gitea/services/projects"
@@ -313,7 +314,29 @@ func ViewProject(ctx *context.Context) {
return
}
- issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns)
+ var labelIDs []int64
+ // 1,-2 means including label 1 and excluding label 2
+ // 0 means issues with no label
+ // blank means labels will not be filtered for issues
+ selectLabels := ctx.FormString("labels")
+ if selectLabels == "" {
+ ctx.Data["AllLabels"] = true
+ } else if selectLabels == "0" {
+ ctx.Data["NoLabel"] = true
+ }
+ if len(selectLabels) > 0 {
+ labelIDs, err = base.StringsToInt64s(strings.Split(selectLabels, ","))
+ if err != nil {
+ ctx.Flash.Error(ctx.Tr("invalid_data", selectLabels), true)
+ }
+ }
+
+ assigneeID := ctx.FormInt64("assignee")
+
+ issuesMap, err := issues_model.LoadIssuesFromColumnList(ctx, columns, &issues_model.IssuesOptions{
+ LabelIDs: labelIDs,
+ AssigneeID: assigneeID,
+ })
if err != nil {
ctx.ServerError("LoadIssuesOfColumns", err)
return
@@ -353,6 +376,55 @@ func ViewProject(ctx *context.Context) {
}
ctx.Data["LinkedPRs"] = linkedPrsMap
+ labels, err := issues_model.GetLabelsByRepoID(ctx, project.RepoID, "", db.ListOptions{})
+ if err != nil {
+ ctx.ServerError("GetLabelsByRepoID", err)
+ return
+ }
+
+ if ctx.Repo.Owner.IsOrganization() {
+ orgLabels, err := issues_model.GetLabelsByOrgID(ctx, ctx.Repo.Owner.ID, "", db.ListOptions{})
+ if err != nil {
+ ctx.ServerError("GetLabelsByOrgID", err)
+ return
+ }
+
+ labels = append(labels, orgLabels...)
+ }
+
+ // Get the exclusive scope for every label ID
+ labelExclusiveScopes := make([]string, 0, len(labelIDs))
+ for _, labelID := range labelIDs {
+ foundExclusiveScope := false
+ for _, label := range labels {
+ if label.ID == labelID || label.ID == -labelID {
+ labelExclusiveScopes = append(labelExclusiveScopes, label.ExclusiveScope())
+ foundExclusiveScope = true
+ break
+ }
+ }
+ if !foundExclusiveScope {
+ labelExclusiveScopes = append(labelExclusiveScopes, "")
+ }
+ }
+
+ for _, l := range labels {
+ l.LoadSelectedLabelsAfterClick(labelIDs, labelExclusiveScopes)
+ }
+ ctx.Data["Labels"] = labels
+ ctx.Data["NumLabels"] = len(labels)
+
+ // Get assignees.
+ assigneeUsers, err := repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository)
+ if err != nil {
+ ctx.ServerError("GetRepoAssignees", err)
+ return
+ }
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
+
+ ctx.Data["SelectLabels"] = selectLabels
+ ctx.Data["AssigneeID"] = assigneeID
+
project.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
Links: markup.Links{
Base: ctx.Repo.RepoLink,
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index e001e872aa..ced0bbc15a 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -34,6 +34,7 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/utils"
+ shared_user "code.gitea.io/gitea/routers/web/shared/user"
asymkey_service "code.gitea.io/gitea/services/asymkey"
"code.gitea.io/gitea/services/automerge"
"code.gitea.io/gitea/services/context"
@@ -163,7 +164,19 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch
}
ctx.Data["BaseTarget"] = pull.BaseBranch
- ctx.Data["HeadBranchLink"] = pull.GetHeadBranchLink(ctx)
+ headBranchLink := ""
+ if pull.Flow == issues_model.PullRequestFlowGithub {
+ b, err := git_model.GetBranch(ctx, ctx.Repo.Repository.ID, pull.HeadBranch)
+ switch {
+ case err == nil:
+ if !b.IsDeleted {
+ headBranchLink = pull.GetHeadBranchLink(ctx)
+ }
+ case !git_model.IsErrBranchNotExist(err):
+ log.Error("GetBranch: %v", err)
+ }
+ }
+ ctx.Data["HeadBranchLink"] = headBranchLink
ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink(ctx)
}
@@ -825,7 +838,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.ServerError("GetRepoAssignees", err)
return
}
- ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
handleTeamMentions(ctx)
if ctx.Written() {
@@ -1625,7 +1638,7 @@ func SetAllowEdits(ctx *context.Context) {
}
if err := pull_service.SetAllowEdits(ctx, ctx.Doer, pr, form.AllowMaintainerEdit); err != nil {
- if errors.Is(pull_service.ErrUserHasNoPermissionForAction, err) {
+ if errors.Is(err, pull_service.ErrUserHasNoPermissionForAction) {
ctx.Error(http.StatusForbidden)
return
}
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 85c7828f2e..566a82316f 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -26,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/web/feed"
+ shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/context/upload"
"code.gitea.io/gitea/services/forms"
@@ -213,6 +214,8 @@ func TagsList(ctx *context.Context) {
ctx.Data["HideBranchesInDropdown"] = true
ctx.Data["CanCreateRelease"] = ctx.Repo.CanWrite(unit.TypeReleases) && !ctx.Repo.Repository.IsArchived
+ namePattern := ctx.FormTrim("q")
+
listOptions := db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: ctx.FormInt("limit"),
@@ -232,6 +235,7 @@ func TagsList(ctx *context.Context) {
IncludeTags: true,
HasSha1: optional.Some(true),
RepoID: ctx.Repo.Repository.ID,
+ NamePattern: optional.Some(namePattern),
}
releases, err := db.Find[repo_model.Release](ctx, opts)
@@ -240,14 +244,21 @@ func TagsList(ctx *context.Context) {
return
}
- ctx.Data["Releases"] = releases
+ count, err := db.Count[repo_model.Release](ctx, opts)
+ if err != nil {
+ ctx.ServerError("GetReleasesByRepoID", err)
+ return
+ }
- numTags := ctx.Data["NumTags"].(int64)
- pager := context.NewPagination(int(numTags), opts.PageSize, opts.Page, 5)
+ ctx.Data["Keyword"] = namePattern
+ ctx.Data["Releases"] = releases
+ ctx.Data["TagCount"] = count
+
+ pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager
-
ctx.Data["PageIsViewCode"] = !ctx.Repo.Repository.UnitEnabled(ctx, unit.TypeReleases)
+
ctx.HTML(http.StatusOK, tplTagsList)
}
@@ -278,7 +289,6 @@ func releasesOrTagsFeed(ctx *context.Context, isReleasesOnly bool, formatType st
// SingleRelease renders a single release's page
func SingleRelease(ctx *context.Context) {
ctx.Data["PageIsReleaseList"] = true
- ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
writeAccess := ctx.Repo.CanWrite(unit.TypeReleases)
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
@@ -370,7 +380,7 @@ func NewRelease(ctx *context.Context) {
ctx.ServerError("GetRepoAssignees", err)
return
}
- ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
upload.AddUploadContext(ctx, "release")
@@ -559,7 +569,7 @@ func EditRelease(ctx *context.Context) {
ctx.ServerError("GetRepoAssignees", err)
return
}
- ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers)
+ ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
ctx.HTML(http.StatusOK, tplReleaseNew)
}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 5e67386457..9769117609 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -8,6 +8,7 @@ import (
"bytes"
gocontext "context"
"encoding/base64"
+ "errors"
"fmt"
"html/template"
"image"
@@ -50,6 +51,7 @@ import (
"code.gitea.io/gitea/routers/web/feed"
"code.gitea.io/gitea/services/context"
issue_service "code.gitea.io/gitea/services/issue"
+ repo_service "code.gitea.io/gitea/services/repository"
files_service "code.gitea.io/gitea/services/repository/files"
"github.com/nektos/act/pkg/model"
@@ -739,7 +741,7 @@ func checkHomeCodeViewable(ctx *context.Context) {
}
}
- ctx.NotFound("Home", fmt.Errorf(ctx.Locale.TrString("units.error.no_unit_allowed_repo")))
+ ctx.NotFound("Home", errors.New(ctx.Locale.TrString("units.error.no_unit_allowed_repo")))
}
func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
@@ -1076,6 +1078,7 @@ func renderHomeCode(ctx *context.Context) {
ctx.Data["TreeLink"] = treeLink
ctx.Data["TreeNames"] = treeNames
ctx.Data["BranchLink"] = branchLink
+ ctx.Data["LicenseFileName"] = repo_service.LicenseFileName
ctx.HTML(http.StatusOK, tplRepoHome)
}
diff --git a/routers/web/shared/user/helper.go b/routers/web/shared/user/helper.go
new file mode 100644
index 0000000000..6186b9b9ff
--- /dev/null
+++ b/routers/web/shared/user/helper.go
@@ -0,0 +1,22 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package user
+
+import (
+ "sort"
+
+ "code.gitea.io/gitea/models/user"
+)
+
+func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User {
+ if doer != nil {
+ sort.Slice(users, func(i, j int) bool {
+ if users[i].ID == users[j].ID {
+ return false
+ }
+ return users[i].ID == doer.ID // if users[i] is self, put it before others, so less=true
+ })
+ }
+ return users
+}
diff --git a/routers/web/repo/helper_test.go b/routers/web/shared/user/helper_test.go
similarity index 97%
rename from routers/web/repo/helper_test.go
rename to routers/web/shared/user/helper_test.go
index 978758e77f..ccdf536c13 100644
--- a/routers/web/repo/helper_test.go
+++ b/routers/web/shared/user/helper_test.go
@@ -1,7 +1,7 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-package repo
+package user
import (
"testing"
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 2ecc2cc8d1..2b16142f6d 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -730,7 +730,7 @@ func UsernameSubRoute(ctx *context.Context) {
// check view permissions
if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
- ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
+ ctx.NotFound("user", fmt.Errorf("%s", ctx.ContextUser.Name))
return false
}
return true
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index 5748ce45ab..d0abf603c3 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -54,7 +54,7 @@ func OwnerProfile(ctx *context.Context) {
func userProfile(ctx *context.Context) {
// check view permissions
if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) {
- ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
+ ctx.NotFound("user", fmt.Errorf("%s", ctx.ContextUser.Name))
return
}
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index 554f6cd6ce..3b051c9b5f 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -69,6 +69,11 @@ func ProfilePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.UpdateProfileForm)
if form.Name != "" {
+ if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureChangeUsername) {
+ ctx.Flash.Error(ctx.Tr("user.form.change_username_disabled"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings")
+ return
+ }
if err := user_service.RenameUser(ctx, ctx.Doer, form.Name); err != nil {
switch {
case user_model.IsErrUserIsNotLocal(err):
@@ -91,7 +96,6 @@ func ProfilePost(ctx *context.Context) {
}
opts := &user_service.UpdateOptions{
- FullName: optional.Some(form.FullName),
KeepEmailPrivate: optional.Some(form.KeepEmailPrivate),
Description: optional.Some(form.Description),
Website: optional.Some(form.Website),
@@ -99,6 +103,16 @@ func ProfilePost(ctx *context.Context) {
Visibility: optional.Some(form.Visibility),
KeepActivityPrivate: optional.Some(form.KeepActivityPrivate),
}
+
+ if form.FullName != "" {
+ if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureChangeFullName) {
+ ctx.Flash.Error(ctx.Tr("user.form.change_full_name_disabled"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings")
+ return
+ }
+ opts.FullName = optional.Some(form.FullName)
+ }
+
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
ctx.ServerError("UpdateUser", err)
return
diff --git a/routers/web/user/task.go b/routers/web/user/task.go
deleted file mode 100644
index 475ef16212..0000000000
--- a/routers/web/user/task.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package user
-
-import (
- "net/http"
- "strconv"
-
- admin_model "code.gitea.io/gitea/models/admin"
- "code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/services/context"
-)
-
-// TaskStatus returns task's status
-func TaskStatus(ctx *context.Context) {
- task, opts, err := admin_model.GetMigratingTaskByID(ctx, ctx.PathParamInt64("task"), ctx.Doer.ID)
- if err != nil {
- if admin_model.IsErrTaskDoesNotExist(err) {
- ctx.JSON(http.StatusNotFound, map[string]any{
- "error": "task `" + strconv.FormatInt(ctx.PathParamInt64("task"), 10) + "` does not exist",
- })
- return
- }
- ctx.JSON(http.StatusInternalServerError, map[string]any{
- "err": err,
- })
- return
- }
-
- message := task.Message
-
- if task.Message != "" && task.Message[0] == '{' {
- // assume message is actually a translatable string
- var translatableMessage admin_model.TranslatableMessage
- if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
- translatableMessage = admin_model.TranslatableMessage{
- Format: "migrate.migrating_failed.error",
- Args: []any{task.Message},
- }
- }
- message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
- }
-
- ctx.JSON(http.StatusOK, map[string]any{
- "status": task.Status,
- "message": message,
- "repo-id": task.RepoID,
- "repo-name": opts.RepoName,
- "start": task.StartTime,
- "end": task.EndTime,
- })
-}
diff --git a/routers/web/web.go b/routers/web/web.go
index e9d05ec8b8..0be8d68a5c 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -129,6 +129,8 @@ func webAuth(authMethod auth_service.Method) func(*context.Context) {
// ensure the session uid is deleted
_ = ctx.Session.Delete("uid")
}
+
+ ctx.Csrf.PrepareForSessionUser(ctx)
}
}
@@ -667,7 +669,6 @@ func registerRoutes(m *web.Router) {
m.Get("/forgot_password", auth.ForgotPasswd)
m.Post("/forgot_password", auth.ForgotPasswdPost)
m.Post("/logout", auth.SignOut)
- m.Get("/task/{task}", reqSignIn, user.TaskStatus)
m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
m.Get("/search", ignExploreSignIn, user.Search)
m.Group("/oauth2", func() {
@@ -1050,6 +1051,13 @@ func registerRoutes(m *web.Router) {
}, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
// end "/{username}/-": packages, projects, code
+ m.Group("/{username}/{reponame}/-", func() {
+ m.Group("/migrate", func() {
+ m.Get("/status", repo.MigrateStatus)
+ })
+ }, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
+ // end "/{username}/{reponame}/-": migrate
+
m.Group("/{username}/{reponame}/settings", func() {
m.Group("", func() {
m.Combo("").Get(repo_setting.Settings).
@@ -1077,9 +1085,7 @@ func registerRoutes(m *web.Router) {
m.Combo("/edit").Get(repo_setting.SettingsProtectedBranch).
Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.SettingsProtectedBranchPost)
m.Post("/{id}/delete", repo_setting.DeleteProtectedBranchRulePost)
- }, repo.MustBeNotEmpty)
-
- m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo_setting.RenameBranchPost)
+ })
m.Group("/tags", func() {
m.Get("", repo_setting.ProtectedTags)
@@ -1312,6 +1318,7 @@ func registerRoutes(m *web.Router) {
}, web.Bind(forms.NewBranchForm{}))
m.Post("/delete", repo.DeleteBranchPost)
m.Post("/restore", repo.RestoreBranchPost)
+ m.Post("/rename", web.Bind(forms.RenameBranchForm{}), repo_setting.RenameBranchPost)
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 0030ef9a91..b21d889d03 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -43,7 +43,8 @@ func withMethod(ctx context.Context, method string) context.Context {
return ctx
}
}
- return context.WithValue(ctx, methodCtxKey, method)
+ // FIXME: review the use of this nolint directive
+ return context.WithValue(ctx, methodCtxKey, method) //nolint:staticcheck
}
// getMethod gets the notification method that this context currently executes.
diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go
index 46d8510143..523998a634 100644
--- a/services/auth/oauth2.go
+++ b/services/auth/oauth2.go
@@ -17,7 +17,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web/middleware"
- "code.gitea.io/gitea/services/auth/source/oauth2"
+ "code.gitea.io/gitea/services/oauth2_provider"
)
// Ensure the struct implements the interface.
@@ -31,7 +31,7 @@ func CheckOAuthAccessToken(ctx context.Context, accessToken string) int64 {
if !strings.Contains(accessToken, ".") {
return 0
}
- token, err := oauth2.ParseToken(accessToken, oauth2.DefaultSigningKey)
+ token, err := oauth2_provider.ParseToken(accessToken, oauth2_provider.DefaultSigningKey)
if err != nil {
log.Trace("oauth2.ParseToken: %v", err)
return 0
@@ -40,7 +40,7 @@ func CheckOAuthAccessToken(ctx context.Context, accessToken string) int64 {
if grant, err = auth_model.GetOAuth2GrantByID(ctx, token.GrantID); err != nil || grant == nil {
return 0
}
- if token.Type != oauth2.TypeAccessToken {
+ if token.Kind != oauth2_provider.KindAccessToken {
return 0
}
if token.ExpiresAt.Before(time.Now()) || token.IssuedAt.After(time.Now()) {
diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go
index b6aeb0aed2..36b4ef68f4 100644
--- a/services/auth/reverseproxy.go
+++ b/services/auth/reverseproxy.go
@@ -164,7 +164,7 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User {
IsActive: optional.Some(true),
}
- if err := user_model.CreateUser(req.Context(), user, &overwriteDefault); err != nil {
+ if err := user_model.CreateUser(req.Context(), user, &user_model.Meta{}, &overwriteDefault); err != nil {
// FIXME: should I create a system notice?
log.Error("CreateUser: %v", err)
return nil
diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go
index 6ebd3ea50a..01cb743720 100644
--- a/services/auth/source/ldap/source_authenticate.go
+++ b/services/auth/source/ldap/source_authenticate.go
@@ -89,7 +89,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u
IsActive: optional.Some(true),
}
- err := user_model.CreateUser(ctx, user, overwriteDefault)
+ err := user_model.CreateUser(ctx, user, &user_model.Meta{}, overwriteDefault)
if err != nil {
return user, err
}
diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go
index 2a95326b9e..a6d6d2a0f2 100644
--- a/services/auth/source/ldap/source_sync.go
+++ b/services/auth/source/ldap/source_sync.go
@@ -129,7 +129,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
IsActive: optional.Some(true),
}
- err = user_model.CreateUser(ctx, usr, overwriteDefault)
+ err = user_model.CreateUser(ctx, usr, &user_model.Meta{}, overwriteDefault)
if err != nil {
log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err)
}
diff --git a/services/auth/source/oauth2/init.go b/services/auth/source/oauth2/init.go
index 5c25681548..313f375281 100644
--- a/services/auth/source/oauth2/init.go
+++ b/services/auth/source/oauth2/init.go
@@ -30,10 +30,6 @@ const ProviderHeaderKey = "gitea-oauth2-provider"
// Init initializes the oauth source
func Init(ctx context.Context) error {
- if err := InitSigningKey(); err != nil {
- return err
- }
-
// Lock our mutex
gothRWMutex.Lock()
diff --git a/services/auth/source/oauth2/source_sync_test.go b/services/auth/source/oauth2/source_sync_test.go
index e2f04bcb25..25408e8727 100644
--- a/services/auth/source/oauth2/source_sync_test.go
+++ b/services/auth/source/oauth2/source_sync_test.go
@@ -36,7 +36,7 @@ func TestSource(t *testing.T) {
Email: "external@example.com",
}
- err := user_model.CreateUser(context.Background(), user, &user_model.CreateUserOverwriteOptions{})
+ err := user_model.CreateUser(context.Background(), user, &user_model.Meta{}, &user_model.CreateUserOverwriteOptions{})
assert.NoError(t, err)
e := &user_model.ExternalLoginUser{
diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go
index addd1bd2c9..6fd02dc29f 100644
--- a/services/auth/source/pam/source_authenticate.go
+++ b/services/auth/source/pam/source_authenticate.go
@@ -63,7 +63,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u
IsActive: optional.Some(true),
}
- if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil {
+ if err := user_model.CreateUser(ctx, user, &user_model.Meta{}, overwriteDefault); err != nil {
return user, err
}
diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go
index 1f0a61c789..b2e94933a6 100644
--- a/services/auth/source/smtp/source_authenticate.go
+++ b/services/auth/source/smtp/source_authenticate.go
@@ -79,7 +79,7 @@ func (source *Source) Authenticate(ctx context.Context, user *user_model.User, u
IsActive: optional.Some(true),
}
- if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil {
+ if err := user_model.CreateUser(ctx, user, &user_model.Meta{}, overwriteDefault); err != nil {
return user, err
}
diff --git a/services/auth/sspi.go b/services/auth/sspi.go
index 64a127e97a..7f8a03a4c6 100644
--- a/services/auth/sspi.go
+++ b/services/auth/sspi.go
@@ -176,7 +176,7 @@ func (s *SSPI) newUser(ctx context.Context, username string, cfg *sspi.Source) (
KeepEmailPrivate: optional.Some(true),
EmailNotificationsPreference: &emailNotificationPreference,
}
- if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil {
+ if err := user_model.CreateUser(ctx, user, &user_model.Meta{}, overwriteDefault); err != nil {
return nil, err
}
diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go
index ed7a0141b9..a1ee204882 100644
--- a/services/automerge/automerge.go
+++ b/services/automerge/automerge.go
@@ -288,7 +288,7 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
}
if err := pull_service.CheckPullMergeable(ctx, doer, &perm, pr, pull_service.MergeCheckTypeGeneral, false); err != nil {
- if errors.Is(pull_service.ErrUserNotAllowedToMerge, err) {
+ if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
log.Info("%-v was scheduled to automerge by an unauthorized user", pr)
return
}
diff --git a/services/context/api.go b/services/context/api.go
index 84da526e74..00cfd6afd9 100644
--- a/services/context/api.go
+++ b/services/context/api.go
@@ -35,9 +35,10 @@ type APIContext struct {
ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer
- Repo *Repository
- Org *APIOrganization
- Package *Package
+ Repo *Repository
+ Org *APIOrganization
+ Package *Package
+ PublicOnly bool // Whether the request is for a public endpoint
}
func init() {
diff --git a/services/context/context.go b/services/context/context.go
index 69b65cbddb..42f7c3d9d1 100644
--- a/services/context/context.go
+++ b/services/context/context.go
@@ -138,10 +138,8 @@ func Contexter() func(next http.Handler) http.Handler {
csrfOpts := CsrfOptions{
Secret: hex.EncodeToString(setting.GetGeneralTokenSigningSecret()),
Cookie: setting.CSRFCookieName,
- SetCookie: true,
Secure: setting.SessionConfig.Secure,
CookieHTTPOnly: setting.CSRFCookieHTTPOnly,
- Header: "X-Csrf-Token",
CookieDomain: setting.SessionConfig.Domain,
CookiePath: setting.SessionConfig.CookiePath,
SameSite: setting.SessionConfig.SameSite,
@@ -167,7 +165,7 @@ func Contexter() func(next http.Handler) http.Handler {
ctx.Base.AppendContextValue(WebContextKey, ctx)
ctx.Base.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo })
- ctx.Csrf = PrepareCSRFProtector(csrfOpts, ctx)
+ ctx.Csrf = NewCSRFProtector(csrfOpts)
// Get the last flash message from cookie
lastFlashCookie := middleware.GetSiteCookie(ctx.Req, CookieNameFlash)
@@ -204,8 +202,6 @@ func Contexter() func(next http.Handler) http.Handler {
ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions)
ctx.Data["SystemConfig"] = setting.Config()
- ctx.Data["CsrfToken"] = ctx.Csrf.GetToken()
- ctx.Data["CsrfTokenHtml"] = template.HTML(``)
// FIXME: do we really always need these setting? There should be someway to have to avoid having to always set these
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
diff --git a/services/context/csrf.go b/services/context/csrf.go
index 9b0dc2923b..9b66d613e3 100644
--- a/services/context/csrf.go
+++ b/services/context/csrf.go
@@ -20,64 +20,42 @@
package context
import (
- "encoding/base32"
- "fmt"
+ "html/template"
"net/http"
"strconv"
"time"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/modules/web/middleware"
+)
+
+const (
+ CsrfHeaderName = "X-Csrf-Token"
+ CsrfFormName = "_csrf"
)
// CSRFProtector represents a CSRF protector and is used to get the current token and validate the token.
type CSRFProtector interface {
- // GetHeaderName returns HTTP header to search for token.
- GetHeaderName() string
- // GetFormName returns form value to search for token.
- GetFormName() string
- // GetToken returns the token.
- GetToken() string
- // Validate validates the token in http context.
+ // PrepareForSessionUser prepares the csrf protector for the current session user.
+ PrepareForSessionUser(ctx *Context)
+ // Validate validates the csrf token in http context.
Validate(ctx *Context)
- // DeleteCookie deletes the cookie
+ // DeleteCookie deletes the csrf cookie
DeleteCookie(ctx *Context)
}
type csrfProtector struct {
opt CsrfOptions
- // Token generated to pass via header, cookie, or hidden form value.
- Token string
- // This value must be unique per user.
- ID string
-}
-
-// GetHeaderName returns the name of the HTTP header for csrf token.
-func (c *csrfProtector) GetHeaderName() string {
- return c.opt.Header
-}
-
-// GetFormName returns the name of the form value for csrf token.
-func (c *csrfProtector) GetFormName() string {
- return c.opt.Form
-}
-
-// GetToken returns the current token. This is typically used
-// to populate a hidden form in an HTML template.
-func (c *csrfProtector) GetToken() string {
- return c.Token
+ // id must be unique per user.
+ id string
+ // token is the valid one which wil be used by end user and passed via header, cookie, or hidden form value.
+ token string
}
// CsrfOptions maintains options to manage behavior of Generate.
type CsrfOptions struct {
// The global secret value used to generate Tokens.
Secret string
- // HTTP header used to set and get token.
- Header string
- // Form value used to set and get token.
- Form string
// Cookie value used to set and get token.
Cookie string
// Cookie domain.
@@ -87,103 +65,64 @@ type CsrfOptions struct {
CookieHTTPOnly bool
// SameSite set the cookie SameSite type
SameSite http.SameSite
- // Key used for getting the unique ID per user.
- SessionKey string
- // oldSessionKey saves old value corresponding to SessionKey.
- oldSessionKey string
- // If true, send token via X-Csrf-Token header.
- SetHeader bool
- // If true, send token via _csrf cookie.
- SetCookie bool
// Set the Secure flag to true on the cookie.
Secure bool
- // Disallow Origin appear in request header.
- Origin bool
- // Cookie lifetime. Default is 0
- CookieLifeTime int
+ // sessionKey is the key used for getting the unique ID per user.
+ sessionKey string
+ // oldSessionKey saves old value corresponding to sessionKey.
+ oldSessionKey string
}
-func prepareDefaultCsrfOptions(opt CsrfOptions) CsrfOptions {
- if opt.Secret == "" {
- randBytes, err := util.CryptoRandomBytes(8)
- if err != nil {
- // this panic can be handled by the recover() in http handlers
- panic(fmt.Errorf("failed to generate random bytes: %w", err))
- }
- opt.Secret = base32.StdEncoding.EncodeToString(randBytes)
- }
- if opt.Header == "" {
- opt.Header = "X-Csrf-Token"
- }
- if opt.Form == "" {
- opt.Form = "_csrf"
- }
- if opt.Cookie == "" {
- opt.Cookie = "_csrf"
- }
- if opt.CookiePath == "" {
- opt.CookiePath = "/"
- }
- if opt.SessionKey == "" {
- opt.SessionKey = "uid"
- }
- if opt.CookieLifeTime == 0 {
- opt.CookieLifeTime = int(CsrfTokenTimeout.Seconds())
- }
-
- opt.oldSessionKey = "_old_" + opt.SessionKey
- return opt
-}
-
-func newCsrfCookie(c *csrfProtector, value string) *http.Cookie {
+func newCsrfCookie(opt *CsrfOptions, value string) *http.Cookie {
return &http.Cookie{
- Name: c.opt.Cookie,
+ Name: opt.Cookie,
Value: value,
- Path: c.opt.CookiePath,
- Domain: c.opt.CookieDomain,
- MaxAge: c.opt.CookieLifeTime,
- Secure: c.opt.Secure,
- HttpOnly: c.opt.CookieHTTPOnly,
- SameSite: c.opt.SameSite,
+ Path: opt.CookiePath,
+ Domain: opt.CookieDomain,
+ MaxAge: int(CsrfTokenTimeout.Seconds()),
+ Secure: opt.Secure,
+ HttpOnly: opt.CookieHTTPOnly,
+ SameSite: opt.SameSite,
}
}
-// PrepareCSRFProtector returns a CSRFProtector to be used for every request.
-// Additionally, depending on options set, generated tokens will be sent via Header and/or Cookie.
-func PrepareCSRFProtector(opt CsrfOptions, ctx *Context) CSRFProtector {
- opt = prepareDefaultCsrfOptions(opt)
- x := &csrfProtector{opt: opt}
-
- if opt.Origin && len(ctx.Req.Header.Get("Origin")) > 0 {
- return x
+func NewCSRFProtector(opt CsrfOptions) CSRFProtector {
+ if opt.Secret == "" {
+ panic("CSRF secret is empty but it must be set") // it shouldn't happen because it is always set in code
}
+ opt.Cookie = util.IfZero(opt.Cookie, "_csrf")
+ opt.CookiePath = util.IfZero(opt.CookiePath, "/")
+ opt.sessionKey = "uid"
+ opt.oldSessionKey = "_old_" + opt.sessionKey
+ return &csrfProtector{opt: opt}
+}
- x.ID = "0"
- uidAny := ctx.Session.Get(opt.SessionKey)
- if uidAny != nil {
+func (c *csrfProtector) PrepareForSessionUser(ctx *Context) {
+ c.id = "0"
+ if uidAny := ctx.Session.Get(c.opt.sessionKey); uidAny != nil {
switch uidVal := uidAny.(type) {
case string:
- x.ID = uidVal
+ c.id = uidVal
case int64:
- x.ID = strconv.FormatInt(uidVal, 10)
+ c.id = strconv.FormatInt(uidVal, 10)
default:
log.Error("invalid uid type in session: %T", uidAny)
}
}
- oldUID := ctx.Session.Get(opt.oldSessionKey)
- uidChanged := oldUID == nil || oldUID.(string) != x.ID
- cookieToken := ctx.GetSiteCookie(opt.Cookie)
+ oldUID := ctx.Session.Get(c.opt.oldSessionKey)
+ uidChanged := oldUID == nil || oldUID.(string) != c.id
+ cookieToken := ctx.GetSiteCookie(c.opt.Cookie)
needsNew := true
if uidChanged {
- _ = ctx.Session.Set(opt.oldSessionKey, x.ID)
+ _ = ctx.Session.Set(c.opt.oldSessionKey, c.id)
} else if cookieToken != "" {
// If cookie token presents, re-use existing unexpired token, else generate a new one.
if issueTime, ok := ParseCsrfToken(cookieToken); ok {
dur := time.Since(issueTime) // issueTime is not a monotonic-clock, the server time may change a lot to an early time.
if dur >= -CsrfTokenRegenerationInterval && dur <= CsrfTokenRegenerationInterval {
- x.Token = cookieToken
+ c.token = cookieToken
needsNew = false
}
}
@@ -191,42 +130,33 @@ func PrepareCSRFProtector(opt CsrfOptions, ctx *Context) CSRFProtector {
if needsNew {
// FIXME: actionId.
- x.Token = GenerateCsrfToken(x.opt.Secret, x.ID, "POST", time.Now())
- if opt.SetCookie {
- cookie := newCsrfCookie(x, x.Token)
- ctx.Resp.Header().Add("Set-Cookie", cookie.String())
- }
+ c.token = GenerateCsrfToken(c.opt.Secret, c.id, "POST", time.Now())
+ cookie := newCsrfCookie(&c.opt, c.token)
+ ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}
- if opt.SetHeader {
- ctx.Resp.Header().Add(opt.Header, x.Token)
- }
- return x
+ ctx.Data["CsrfToken"] = c.token
+ ctx.Data["CsrfTokenHtml"] = template.HTML(``)
}
func (c *csrfProtector) validateToken(ctx *Context, token string) {
- if !ValidCsrfToken(token, c.opt.Secret, c.ID, "POST", time.Now()) {
+ if !ValidCsrfToken(token, c.opt.Secret, c.id, "POST", time.Now()) {
c.DeleteCookie(ctx)
- if middleware.IsAPIPath(ctx.Req) {
- // currently, there should be no access to the APIPath with CSRF token. because templates shouldn't use the `/api/` endpoints.
- http.Error(ctx.Resp, "Invalid CSRF token.", http.StatusBadRequest)
- } else {
- ctx.Flash.Error(ctx.Tr("error.invalid_csrf"))
- ctx.Redirect(setting.AppSubURL + "/")
- }
+ // currently, there should be no access to the APIPath with CSRF token. because templates shouldn't use the `/api/` endpoints.
+ // FIXME: distinguish what the response is for: HTML (web page) or JSON (fetch)
+ http.Error(ctx.Resp, "Invalid CSRF token.", http.StatusBadRequest)
}
}
// Validate should be used as a per route middleware. It attempts to get a token from an "X-Csrf-Token"
// HTTP header and then a "_csrf" form value. If one of these is found, the token will be validated.
-// If this validation fails, custom Error is sent in the reply.
-// If neither a header nor form value is found, http.StatusBadRequest is sent.
+// If this validation fails, http.StatusBadRequest is sent.
func (c *csrfProtector) Validate(ctx *Context) {
- if token := ctx.Req.Header.Get(c.GetHeaderName()); token != "" {
+ if token := ctx.Req.Header.Get(CsrfHeaderName); token != "" {
c.validateToken(ctx, token)
return
}
- if token := ctx.Req.FormValue(c.GetFormName()); token != "" {
+ if token := ctx.Req.FormValue(CsrfFormName); token != "" {
c.validateToken(ctx, token)
return
}
@@ -234,9 +164,7 @@ func (c *csrfProtector) Validate(ctx *Context) {
}
func (c *csrfProtector) DeleteCookie(ctx *Context) {
- if c.opt.SetCookie {
- cookie := newCsrfCookie(c, "")
- cookie.MaxAge = -1
- ctx.Resp.Header().Add("Set-Cookie", cookie.String())
- }
+ cookie := newCsrfCookie(&c.opt, "")
+ cookie.MaxAge = -1
+ ctx.Resp.Header().Add("Set-Cookie", cookie.String())
}
diff --git a/services/context/repo.go b/services/context/repo.go
index e0d3a0bfd3..0072b63b7c 100644
--- a/services/context/repo.go
+++ b/services/context/repo.go
@@ -404,6 +404,13 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
ctx.Data["PushMirrors"] = pushMirrors
ctx.Data["RepoName"] = ctx.Repo.Repository.Name
ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
+
+ repoLicenses, err := repo_model.GetRepoLicenses(ctx, ctx.Repo.Repository)
+ if err != nil {
+ ctx.ServerError("GetRepoLicenses", err)
+ return
+ }
+ ctx.Data["DetectedRepoLicenses"] = repoLicenses.StringList()
}
// RepoAssignment returns a middleware to handle repository assignment
@@ -607,7 +614,10 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
}
}
- isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/")
+ isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink ||
+ ctx.Link == ctx.Repo.RepoLink+"/settings" ||
+ strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") ||
+ ctx.Link == ctx.Repo.RepoLink+"/-/migrate/status"
// Disable everything when the repo is being created
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
diff --git a/services/convert/convert.go b/services/convert/convert.go
index d70c1b940a..041d553e98 100644
--- a/services/convert/convert.go
+++ b/services/convert/convert.go
@@ -485,6 +485,7 @@ func ToLFSLock(ctx context.Context, l *git_model.LFSLock) *api.LFSLock {
// ToChangedFile convert a gitdiff.DiffFile to api.ChangedFile
func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit string) *api.ChangedFile {
status := "changed"
+ previousFilename := ""
if f.IsDeleted {
status = "deleted"
} else if f.IsCreated {
@@ -493,23 +494,21 @@ func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit stri
status = "copied"
} else if f.IsRenamed && f.Type == gitdiff.DiffFileRename {
status = "renamed"
+ previousFilename = f.OldName
} else if f.Addition == 0 && f.Deletion == 0 {
status = "unchanged"
}
file := &api.ChangedFile{
- Filename: f.GetDiffFileName(),
- Status: status,
- Additions: f.Addition,
- Deletions: f.Deletion,
- Changes: f.Addition + f.Deletion,
- HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
- ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
- RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
- }
-
- if status == "rename" {
- file.PreviousFilename = f.OldName
+ Filename: f.GetDiffFileName(),
+ Status: status,
+ Additions: f.Addition,
+ Deletions: f.Deletion,
+ Changes: f.Addition + f.Deletion,
+ PreviousFilename: previousFilename,
+ HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
+ ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
+ RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
}
return file
diff --git a/services/convert/repository.go b/services/convert/repository.go
index 751260a45d..e026d0f440 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -175,6 +175,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
language = repo.PrimaryLanguage.Language
}
+ repoLicenses, err := repo_model.GetRepoLicenses(ctx, repo)
+ if err != nil {
+ return nil
+ }
+
repoAPIURL := repo.APIURL()
return &api.Repository{
@@ -238,6 +243,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
RepoTransfer: transfer,
Topics: repo.Topics,
ObjectFormatName: repo.ObjectFormatName,
+ Licenses: repoLicenses.StringList(),
}
}
diff --git a/services/convert/utils.go b/services/convert/utils.go
index cdce60831c..5e9d32cc8e 100644
--- a/services/convert/utils.go
+++ b/services/convert/utils.go
@@ -36,6 +36,8 @@ func ToGitServiceType(value string) structs.GitServiceType {
return structs.OneDevService
case "gitbucket":
return structs.GitBucketService
+ case "codecommit":
+ return structs.CodeCommitService
default:
return structs.PlainGitService
}
diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go
index 2a213ae515..fb5938745e 100644
--- a/services/cron/tasks_basic.go
+++ b/services/cron/tasks_basic.go
@@ -156,6 +156,16 @@ func registerCleanupPackages() {
})
}
+func registerSyncRepoLicenses() {
+ RegisterTaskFatal("sync_repo_licenses", &BaseConfig{
+ Enabled: false,
+ RunAtStart: false,
+ Schedule: "@annually",
+ }, func(ctx context.Context, _ *user_model.User, config Config) error {
+ return repo_service.SyncRepoLicenses(ctx)
+ })
+}
+
func initBasicTasks() {
if setting.Mirror.Enabled {
registerUpdateMirrorTask()
@@ -172,4 +182,5 @@ func initBasicTasks() {
if setting.Packages.Enabled {
registerCleanupPackages()
}
+ registerSyncRepoLicenses()
}
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index a2c2af3fac..988e479a48 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -79,6 +79,9 @@ type MigrateRepoForm struct {
PullRequests bool `json:"pull_requests"`
Releases bool `json:"releases"`
MirrorInterval string `json:"mirror_interval"`
+
+ AWSAccessKeyID string `json:"aws_access_key_id"`
+ AWSSecretAccessKey string `json:"aws_secret_access_key"`
}
// Validate validates the fields
diff --git a/services/mailer/incoming/incoming_handler.go b/services/mailer/incoming/incoming_handler.go
index dc0b539822..38a234eac1 100644
--- a/services/mailer/incoming/incoming_handler.go
+++ b/services/mailer/incoming/incoming_handler.go
@@ -82,43 +82,40 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u
return nil
}
+ attachmentIDs := make([]string, 0, len(content.Attachments))
+ if setting.Attachment.Enabled {
+ for _, attachment := range content.Attachments {
+ a, err := attachment_service.UploadAttachment(ctx, bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{
+ Name: attachment.Name,
+ UploaderID: doer.ID,
+ RepoID: issue.Repo.ID,
+ })
+ if err != nil {
+ if upload.IsErrFileTypeForbidden(err) {
+ log.Info("Skipping disallowed attachment type: %s", attachment.Name)
+ continue
+ }
+ return err
+ }
+ attachmentIDs = append(attachmentIDs, a.UUID)
+ }
+ }
+
+ if content.Content == "" && len(attachmentIDs) == 0 {
+ return nil
+ }
+
switch r := ref.(type) {
case *issues_model.Issue:
- attachmentIDs := make([]string, 0, len(content.Attachments))
- if setting.Attachment.Enabled {
- for _, attachment := range content.Attachments {
- a, err := attachment_service.UploadAttachment(ctx, bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{
- Name: attachment.Name,
- UploaderID: doer.ID,
- RepoID: issue.Repo.ID,
- })
- if err != nil {
- if upload.IsErrFileTypeForbidden(err) {
- log.Info("Skipping disallowed attachment type: %s", attachment.Name)
- continue
- }
- return err
- }
- attachmentIDs = append(attachmentIDs, a.UUID)
- }
- }
-
- if content.Content == "" && len(attachmentIDs) == 0 {
- return nil
- }
-
- _, err = issue_service.CreateIssueComment(ctx, doer, issue.Repo, issue, content.Content, attachmentIDs)
+ _, err := issue_service.CreateIssueComment(ctx, doer, issue.Repo, issue, content.Content, attachmentIDs)
if err != nil {
return fmt.Errorf("CreateIssueComment failed: %w", err)
}
case *issues_model.Comment:
comment := r
- if content.Content == "" {
- return nil
- }
-
- if comment.Type == issues_model.CommentTypeCode {
+ switch comment.Type {
+ case issues_model.CommentTypeCode:
_, err := pull_service.CreateCodeComment(
ctx,
doer,
@@ -130,11 +127,16 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u
false, // not pending review but a single review
comment.ReviewID,
"",
- nil,
+ attachmentIDs,
)
if err != nil {
return fmt.Errorf("CreateCodeComment failed: %w", err)
}
+ default:
+ _, err := issue_service.CreateIssueComment(ctx, doer, issue.Repo, issue, content.Content, attachmentIDs)
+ if err != nil {
+ return fmt.Errorf("CreateIssueComment failed: %w", err)
+ }
}
}
return nil
diff --git a/services/migrations/codecommit.go b/services/migrations/codecommit.go
new file mode 100644
index 0000000000..ccda62fc3d
--- /dev/null
+++ b/services/migrations/codecommit.go
@@ -0,0 +1,269 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package migrations
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+
+ git_module "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ base "code.gitea.io/gitea/modules/migration"
+ "code.gitea.io/gitea/modules/structs"
+
+ "github.com/aws/aws-sdk-go-v2/credentials"
+ "github.com/aws/aws-sdk-go-v2/service/codecommit"
+ "github.com/aws/aws-sdk-go-v2/service/codecommit/types"
+ "github.com/aws/aws-sdk-go/aws"
+)
+
+var (
+ _ base.Downloader = &CodeCommitDownloader{}
+ _ base.DownloaderFactory = &CodeCommitDownloaderFactory{}
+)
+
+func init() {
+ RegisterDownloaderFactory(&CodeCommitDownloaderFactory{})
+}
+
+// CodeCommitDownloaderFactory defines a codecommit downloader factory
+type CodeCommitDownloaderFactory struct{}
+
+// New returns a Downloader related to this factory according MigrateOptions
+func (c *CodeCommitDownloaderFactory) New(ctx context.Context, opts base.MigrateOptions) (base.Downloader, error) {
+ u, err := url.Parse(opts.CloneAddr)
+ if err != nil {
+ return nil, err
+ }
+
+ hostElems := strings.Split(u.Host, ".")
+ if len(hostElems) != 4 {
+ return nil, fmt.Errorf("cannot get the region from clone URL")
+ }
+ region := hostElems[1]
+
+ pathElems := strings.Split(u.Path, "/")
+ if len(pathElems) == 0 {
+ return nil, fmt.Errorf("cannot get the repo name from clone URL")
+ }
+ repoName := pathElems[len(pathElems)-1]
+
+ baseURL := u.Scheme + "://" + u.Host
+
+ return NewCodeCommitDownloader(ctx, repoName, baseURL, opts.AWSAccessKeyID, opts.AWSSecretAccessKey, region), nil
+}
+
+// GitServiceType returns the type of git service
+func (c *CodeCommitDownloaderFactory) GitServiceType() structs.GitServiceType {
+ return structs.CodeCommitService
+}
+
+func NewCodeCommitDownloader(ctx context.Context, repoName, baseURL, accessKeyID, secretAccessKey, region string) *CodeCommitDownloader {
+ downloader := CodeCommitDownloader{
+ ctx: ctx,
+ repoName: repoName,
+ baseURL: baseURL,
+ codeCommitClient: codecommit.New(codecommit.Options{
+ Credentials: credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, ""),
+ Region: region,
+ }),
+ }
+
+ return &downloader
+}
+
+// CodeCommitDownloader implements a downloader for AWS CodeCommit
+type CodeCommitDownloader struct {
+ base.NullDownloader
+ ctx context.Context
+ codeCommitClient *codecommit.Client
+ repoName string
+ baseURL string
+ allPullRequestIDs []string
+}
+
+// SetContext set context
+func (c *CodeCommitDownloader) SetContext(ctx context.Context) {
+ c.ctx = ctx
+}
+
+// GetRepoInfo returns a repository information
+func (c *CodeCommitDownloader) GetRepoInfo() (*base.Repository, error) {
+ output, err := c.codeCommitClient.GetRepository(c.ctx, &codecommit.GetRepositoryInput{
+ RepositoryName: aws.String(c.repoName),
+ })
+ if err != nil {
+ return nil, err
+ }
+ repoMeta := output.RepositoryMetadata
+
+ repo := &base.Repository{
+ Name: *repoMeta.RepositoryName,
+ Owner: *repoMeta.AccountId,
+ IsPrivate: true, // CodeCommit repos are always private
+ CloneURL: *repoMeta.CloneUrlHttp,
+ }
+ if repoMeta.DefaultBranch != nil {
+ repo.DefaultBranch = *repoMeta.DefaultBranch
+ }
+ if repoMeta.RepositoryDescription != nil {
+ repo.DefaultBranch = *repoMeta.RepositoryDescription
+ }
+ return repo, nil
+}
+
+// GetComments returns comments of an issue or PR
+func (c *CodeCommitDownloader) GetComments(commentable base.Commentable) ([]*base.Comment, bool, error) {
+ var (
+ nextToken *string
+ comments []*base.Comment
+ )
+
+ for {
+ resp, err := c.codeCommitClient.GetCommentsForPullRequest(c.ctx, &codecommit.GetCommentsForPullRequestInput{
+ NextToken: nextToken,
+ PullRequestId: aws.String(strconv.FormatInt(commentable.GetForeignIndex(), 10)),
+ })
+ if err != nil {
+ return nil, false, err
+ }
+
+ for _, prComment := range resp.CommentsForPullRequestData {
+ for _, ccComment := range prComment.Comments {
+ comment := &base.Comment{
+ IssueIndex: commentable.GetForeignIndex(),
+ PosterName: c.getUsernameFromARN(*ccComment.AuthorArn),
+ Content: *ccComment.Content,
+ Created: *ccComment.CreationDate,
+ Updated: *ccComment.LastModifiedDate,
+ }
+ comments = append(comments, comment)
+ }
+ }
+
+ nextToken = resp.NextToken
+ if nextToken == nil {
+ break
+ }
+ }
+
+ return comments, true, nil
+}
+
+// GetPullRequests returns pull requests according page and perPage
+func (c *CodeCommitDownloader) GetPullRequests(page, perPage int) ([]*base.PullRequest, bool, error) {
+ allPullRequestIDs, err := c.getAllPullRequestIDs()
+ if err != nil {
+ return nil, false, err
+ }
+
+ startIndex := (page - 1) * perPage
+ endIndex := page * perPage
+ if endIndex > len(allPullRequestIDs) {
+ endIndex = len(allPullRequestIDs)
+ }
+ batch := allPullRequestIDs[startIndex:endIndex]
+
+ prs := make([]*base.PullRequest, 0, len(batch))
+ for _, id := range batch {
+ output, err := c.codeCommitClient.GetPullRequest(c.ctx, &codecommit.GetPullRequestInput{
+ PullRequestId: aws.String(id),
+ })
+ if err != nil {
+ return nil, false, err
+ }
+ orig := output.PullRequest
+ number, err := strconv.ParseInt(*orig.PullRequestId, 10, 64)
+ if err != nil {
+ log.Error("CodeCommit pull request id is not a number: %s", *orig.PullRequestId)
+ continue
+ }
+ if len(orig.PullRequestTargets) == 0 {
+ log.Error("CodeCommit pull request does not contain targets", *orig.PullRequestId)
+ continue
+ }
+ target := orig.PullRequestTargets[0]
+ pr := &base.PullRequest{
+ Number: number,
+ Title: *orig.Title,
+ PosterName: c.getUsernameFromARN(*orig.AuthorArn),
+ Content: *orig.Description,
+ State: "open",
+ Created: *orig.CreationDate,
+ Updated: *orig.LastActivityDate,
+ Merged: target.MergeMetadata.IsMerged,
+ Head: base.PullRequestBranch{
+ Ref: strings.TrimPrefix(*target.SourceReference, git_module.BranchPrefix),
+ SHA: *target.SourceCommit,
+ RepoName: c.repoName,
+ },
+ Base: base.PullRequestBranch{
+ Ref: strings.TrimPrefix(*target.DestinationReference, git_module.BranchPrefix),
+ SHA: *target.DestinationCommit,
+ RepoName: c.repoName,
+ },
+ ForeignIndex: number,
+ }
+
+ if orig.PullRequestStatus == types.PullRequestStatusEnumClosed {
+ pr.State = "closed"
+ pr.Closed = orig.LastActivityDate
+ }
+
+ _ = CheckAndEnsureSafePR(pr, c.baseURL, c)
+ prs = append(prs, pr)
+ }
+
+ return prs, len(prs) < perPage, nil
+}
+
+// FormatCloneURL add authentication into remote URLs
+func (c *CodeCommitDownloader) FormatCloneURL(opts MigrateOptions, remoteAddr string) (string, error) {
+ u, err := url.Parse(remoteAddr)
+ if err != nil {
+ return "", err
+ }
+ u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword)
+ return u.String(), nil
+}
+
+func (c *CodeCommitDownloader) getAllPullRequestIDs() ([]string, error) {
+ if len(c.allPullRequestIDs) > 0 {
+ return c.allPullRequestIDs, nil
+ }
+
+ var (
+ nextToken *string
+ prIDs []string
+ )
+
+ for {
+ output, err := c.codeCommitClient.ListPullRequests(c.ctx, &codecommit.ListPullRequestsInput{
+ RepositoryName: aws.String(c.repoName),
+ NextToken: nextToken,
+ })
+ if err != nil {
+ return nil, err
+ }
+ prIDs = append(prIDs, output.PullRequestIds...)
+ nextToken = output.NextToken
+ if nextToken == nil {
+ break
+ }
+ }
+
+ c.allPullRequestIDs = prIDs
+ return c.allPullRequestIDs, nil
+}
+
+func (c *CodeCommitDownloader) getUsernameFromARN(arn string) string {
+ parts := strings.Split(arn, "/")
+ if len(parts) > 0 {
+ return parts[len(parts)-1]
+ }
+ return ""
+}
diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go
index c9b9248098..f2379dadf8 100644
--- a/services/migrations/gitea_uploader_test.go
+++ b/services/migrations/gitea_uploader_test.go
@@ -26,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
+ repo_service "code.gitea.io/gitea/services/repository"
"github.com/stretchr/testify/assert"
)
@@ -302,6 +303,8 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
toRepoName := "migrated"
uploader := NewGiteaLocalUploader(context.Background(), fromRepoOwner, fromRepoOwner.Name, toRepoName)
uploader.gitServiceType = structs.GiteaService
+
+ assert.NoError(t, repo_service.Init(context.Background()))
assert.NoError(t, uploader.CreateRepo(&base.Repository{
Description: "description",
OriginalURL: fromRepo.RepoPath(),
diff --git a/services/migrations/http_client.go b/services/migrations/http_client.go
index 9e3caec191..0b997e08f4 100644
--- a/services/migrations/http_client.go
+++ b/services/migrations/http_client.go
@@ -24,6 +24,6 @@ func NewMigrationHTTPTransport() *http.Transport {
return &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Migrations.SkipTLSVerify},
Proxy: proxy.Proxy(),
- DialContext: hostmatcher.NewDialContext("migration", allowList, blockList),
+ DialContext: hostmatcher.NewDialContext("migration", allowList, blockList, setting.Proxy.ProxyURLFixed),
}
}
diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go
index 21bdc68e73..d0ad6d0139 100644
--- a/services/migrations/migrate.go
+++ b/services/migrations/migrate.go
@@ -499,9 +499,5 @@ func Init() error {
// TODO: at the moment, if ALLOW_LOCALNETWORKS=false, ALLOWED_DOMAINS=domain.com, and domain.com has IP 127.0.0.1, then it's still allowed.
// if we want to block such case, the private&loopback should be added to the blockList when ALLOW_LOCALNETWORKS=false
- if setting.Proxy.Enabled && setting.Proxy.ProxyURLFixed != nil {
- allowList.AppendPattern(setting.Proxy.ProxyURLFixed.Host)
- }
-
return nil
}
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index 9f7ffb29c9..654a50d11e 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
notify_service "code.gitea.io/gitea/services/notify"
+ repo_service "code.gitea.io/gitea/services/repository"
)
// gitShortEmptySha Git short empty SHA
@@ -559,6 +560,14 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
}
}
+ // Update License
+ if err = repo_service.AddRepoToLicenseUpdaterQueue(&repo_service.LicenseUpdaterOptions{
+ RepoID: m.Repo.ID,
+ }); err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to add repo to license updater queue: %v", m.Repo, err)
+ return false
+ }
+
log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo)
return true
diff --git a/services/oauth2_provider/access_token.go b/services/oauth2_provider/access_token.go
new file mode 100644
index 0000000000..00c960caf2
--- /dev/null
+++ b/services/oauth2_provider/access_token.go
@@ -0,0 +1,214 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package oauth2_provider //nolint
+
+import (
+ "context"
+ "fmt"
+
+ auth "code.gitea.io/gitea/models/auth"
+ org_model "code.gitea.io/gitea/models/organization"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
+
+ "github.com/golang-jwt/jwt/v5"
+)
+
+// AccessTokenErrorCode represents an error code specified in RFC 6749
+// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+type AccessTokenErrorCode string
+
+const (
+ // AccessTokenErrorCodeInvalidRequest represents an error code specified in RFC 6749
+ AccessTokenErrorCodeInvalidRequest AccessTokenErrorCode = "invalid_request"
+ // AccessTokenErrorCodeInvalidClient represents an error code specified in RFC 6749
+ AccessTokenErrorCodeInvalidClient = "invalid_client"
+ // AccessTokenErrorCodeInvalidGrant represents an error code specified in RFC 6749
+ AccessTokenErrorCodeInvalidGrant = "invalid_grant"
+ // AccessTokenErrorCodeUnauthorizedClient represents an error code specified in RFC 6749
+ AccessTokenErrorCodeUnauthorizedClient = "unauthorized_client"
+ // AccessTokenErrorCodeUnsupportedGrantType represents an error code specified in RFC 6749
+ AccessTokenErrorCodeUnsupportedGrantType = "unsupported_grant_type"
+ // AccessTokenErrorCodeInvalidScope represents an error code specified in RFC 6749
+ AccessTokenErrorCodeInvalidScope = "invalid_scope"
+)
+
+// AccessTokenError represents an error response specified in RFC 6749
+// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
+type AccessTokenError struct {
+ ErrorCode AccessTokenErrorCode `json:"error" form:"error"`
+ ErrorDescription string `json:"error_description"`
+}
+
+// Error returns the error message
+func (err AccessTokenError) Error() string {
+ return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
+}
+
+// TokenType specifies the kind of token
+type TokenType string
+
+const (
+ // TokenTypeBearer represents a token type specified in RFC 6749
+ TokenTypeBearer TokenType = "bearer"
+ // TokenTypeMAC represents a token type specified in RFC 6749
+ TokenTypeMAC = "mac"
+)
+
+// AccessTokenResponse represents a successful access token response
+// https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2
+type AccessTokenResponse struct {
+ AccessToken string `json:"access_token"`
+ TokenType TokenType `json:"token_type"`
+ ExpiresIn int64 `json:"expires_in"`
+ RefreshToken string `json:"refresh_token"`
+ IDToken string `json:"id_token,omitempty"`
+}
+
+func NewAccessTokenResponse(ctx context.Context, grant *auth.OAuth2Grant, serverKey, clientKey JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) {
+ if setting.OAuth2.InvalidateRefreshTokens {
+ if err := grant.IncreaseCounter(ctx); err != nil {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidGrant,
+ ErrorDescription: "cannot increase the grant counter",
+ }
+ }
+ }
+ // generate access token to access the API
+ expirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.AccessTokenExpirationTime)
+ accessToken := &Token{
+ GrantID: grant.ID,
+ Kind: KindAccessToken,
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
+ },
+ }
+ signedAccessToken, err := accessToken.SignToken(serverKey)
+ if err != nil {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot sign token",
+ }
+ }
+
+ // generate refresh token to request an access token after it expired later
+ refreshExpirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.RefreshTokenExpirationTime * 60 * 60).AsTime()
+ refreshToken := &Token{
+ GrantID: grant.ID,
+ Counter: grant.Counter,
+ Kind: KindRefreshToken,
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(refreshExpirationDate),
+ },
+ }
+ signedRefreshToken, err := refreshToken.SignToken(serverKey)
+ if err != nil {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot sign token",
+ }
+ }
+
+ // generate OpenID Connect id_token
+ signedIDToken := ""
+ if grant.ScopeContains("openid") {
+ app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID)
+ if err != nil {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot find application",
+ }
+ }
+ user, err := user_model.GetUserByID(ctx, grant.UserID)
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot find user",
+ }
+ }
+ log.Error("Error loading user: %v", err)
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "server error",
+ }
+ }
+
+ idToken := &OIDCToken{
+ RegisteredClaims: jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(expirationDate.AsTime()),
+ Issuer: setting.AppURL,
+ Audience: []string{app.ClientID},
+ Subject: fmt.Sprint(grant.UserID),
+ },
+ Nonce: grant.Nonce,
+ }
+ if grant.ScopeContains("profile") {
+ idToken.Name = user.GetDisplayName()
+ idToken.PreferredUsername = user.Name
+ idToken.Profile = user.HTMLURL()
+ idToken.Picture = user.AvatarLink(ctx)
+ idToken.Website = user.Website
+ idToken.Locale = user.Language
+ idToken.UpdatedAt = user.UpdatedUnix
+ }
+ if grant.ScopeContains("email") {
+ idToken.Email = user.Email
+ idToken.EmailVerified = user.IsActive
+ }
+ if grant.ScopeContains("groups") {
+ groups, err := GetOAuthGroupsForUser(ctx, user)
+ if err != nil {
+ log.Error("Error getting groups: %v", err)
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "server error",
+ }
+ }
+ idToken.Groups = groups
+ }
+
+ signedIDToken, err = idToken.SignToken(clientKey)
+ if err != nil {
+ return nil, &AccessTokenError{
+ ErrorCode: AccessTokenErrorCodeInvalidRequest,
+ ErrorDescription: "cannot sign token",
+ }
+ }
+ }
+
+ return &AccessTokenResponse{
+ AccessToken: signedAccessToken,
+ TokenType: TokenTypeBearer,
+ ExpiresIn: setting.OAuth2.AccessTokenExpirationTime,
+ RefreshToken: signedRefreshToken,
+ IDToken: signedIDToken,
+ }, nil
+}
+
+// returns a list of "org" and "org:team" strings,
+// that the given user is a part of.
+func GetOAuthGroupsForUser(ctx context.Context, user *user_model.User) ([]string, error) {
+ orgs, err := org_model.GetUserOrgsList(ctx, user)
+ if err != nil {
+ return nil, fmt.Errorf("GetUserOrgList: %w", err)
+ }
+
+ var groups []string
+ for _, org := range orgs {
+ groups = append(groups, org.Name)
+ teams, err := org.LoadTeams(ctx)
+ if err != nil {
+ return nil, fmt.Errorf("LoadTeams: %w", err)
+ }
+ for _, team := range teams {
+ if team.IsMember(ctx, user.ID) {
+ groups = append(groups, org.Name+":"+team.LowerName)
+ }
+ }
+ }
+ return groups, nil
+}
diff --git a/services/oauth2_provider/init.go b/services/oauth2_provider/init.go
new file mode 100644
index 0000000000..e5958099a6
--- /dev/null
+++ b/services/oauth2_provider/init.go
@@ -0,0 +1,19 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package oauth2_provider //nolint
+
+import (
+ "context"
+
+ "code.gitea.io/gitea/modules/setting"
+)
+
+// Init initializes the oauth source
+func Init(ctx context.Context) error {
+ if !setting.OAuth2.Enabled {
+ return nil
+ }
+
+ return InitSigningKey()
+}
diff --git a/services/auth/source/oauth2/jwtsigningkey.go b/services/oauth2_provider/jwtsigningkey.go
similarity index 99%
rename from services/auth/source/oauth2/jwtsigningkey.go
rename to services/oauth2_provider/jwtsigningkey.go
index 070fffe60f..6c668db463 100644
--- a/services/auth/source/oauth2/jwtsigningkey.go
+++ b/services/oauth2_provider/jwtsigningkey.go
@@ -1,7 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-package oauth2
+package oauth2_provider //nolint
import (
"crypto/ecdsa"
diff --git a/services/auth/source/oauth2/token.go b/services/oauth2_provider/token.go
similarity index 83%
rename from services/auth/source/oauth2/token.go
rename to services/oauth2_provider/token.go
index 3405619d3f..b71b11906e 100644
--- a/services/auth/source/oauth2/token.go
+++ b/services/oauth2_provider/token.go
@@ -1,7 +1,7 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
-package oauth2
+package oauth2_provider //nolint
import (
"fmt"
@@ -12,29 +12,22 @@ import (
"github.com/golang-jwt/jwt/v5"
)
-// ___________ __
-// \__ ___/___ | | __ ____ ____
-// | | / _ \| |/ // __ \ / \
-// | |( <_> ) <\ ___/| | \
-// |____| \____/|__|_ \\___ >___| /
-// \/ \/ \/
-
// Token represents an Oauth grant
-// TokenType represents the type of token for an oauth application
-type TokenType int
+// TokenKind represents the type of token for an oauth application
+type TokenKind int
const (
- // TypeAccessToken is a token with short lifetime to access the api
- TypeAccessToken TokenType = 0
- // TypeRefreshToken is token with long lifetime to refresh access tokens obtained by the client
- TypeRefreshToken = iota
+ // KindAccessToken is a token with short lifetime to access the api
+ KindAccessToken TokenKind = 0
+ // KindRefreshToken is token with long lifetime to refresh access tokens obtained by the client
+ KindRefreshToken = iota
)
// Token represents a JWT token used to authenticate a client
type Token struct {
GrantID int64 `json:"gnt"`
- Type TokenType `json:"tt"`
+ Kind TokenKind `json:"tt"`
Counter int64 `json:"cnt,omitempty"`
jwt.RegisteredClaims
}
diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go
index bc342e53ab..a7d196c15c 100644
--- a/services/packages/rpm/repository.go
+++ b/services/packages/rpm/repository.go
@@ -13,7 +13,6 @@ import (
"errors"
"fmt"
"io"
- "net/url"
"strings"
"time"
@@ -438,7 +437,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
Archive: pd.FileMetadata.ArchiveSize,
},
Location: Location{
- Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(packageVersion), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture))),
+ Href: fmt.Sprintf("package/%s/%s/%s/%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture, pd.Package.Name, packageVersion, pd.FileMetadata.Architecture),
},
Format: Format{
License: pd.VersionMetadata.License,
diff --git a/services/pull/pull.go b/services/pull/pull.go
index 154ff6c5c6..bab4e49998 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -995,6 +995,8 @@ type CommitInfo struct {
}
// GetPullCommits returns all commits on given pull request and the last review commit sha
+// Attention: The last review commit sha must be from the latest review whose commit id is not empty.
+// So the type of the latest review cannot be "ReviewTypeRequest".
func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]CommitInfo, string, error) {
pull := issue.PullRequest
@@ -1040,7 +1042,11 @@ func GetPullCommits(ctx *gitea_context.Context, issue *issues_model.Issue) ([]Co
lastreview, err := issues_model.FindLatestReviews(ctx, issues_model.FindReviewOptions{
IssueID: issue.ID,
ReviewerID: ctx.Doer.ID,
- Type: issues_model.ReviewTypeUnknown,
+ Types: []issues_model.ReviewType{
+ issues_model.ReviewTypeApprove,
+ issues_model.ReviewTypeComment,
+ issues_model.ReviewTypeReject,
+ },
})
if err != nil && !issues_model.IsErrReviewNotExist(err) {
diff --git a/services/pull/review.go b/services/pull/review.go
index 3d5eca779f..78723a58ae 100644
--- a/services/pull/review.go
+++ b/services/pull/review.go
@@ -348,7 +348,7 @@ func DismissApprovalReviews(ctx context.Context, doer *user_model.User, pull *is
reviews, err := issues_model.FindReviews(ctx, issues_model.FindReviewOptions{
ListOptions: db.ListOptionsAll,
IssueID: pull.IssueID,
- Type: issues_model.ReviewTypeApprove,
+ Types: []issues_model.ReviewType{issues_model.ReviewTypeApprove},
Dismissed: optional.Some(false),
})
if err != nil {
diff --git a/services/release/release.go b/services/release/release.go
index 399fdc79c0..5c021404b8 100644
--- a/services/release/release.go
+++ b/services/release/release.go
@@ -65,7 +65,7 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
commit, err := gitRepo.GetCommit(rel.Target)
if err != nil {
- return false, fmt.Errorf("createTag::GetCommit[%v]: %w", rel.Target, err)
+ return false, err
}
if len(msg) > 0 {
diff --git a/services/repository/branch.go b/services/repository/branch.go
index 7fc9993077..67df4363e4 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -483,13 +483,12 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
}
rawBranch, err := git_model.GetBranch(ctx, repo.ID, branchName)
- if err != nil {
+ if err != nil && !git_model.IsErrBranchNotExist(err) {
return fmt.Errorf("GetBranch: %vc", err)
}
- if rawBranch.IsDeleted {
- return nil
- }
+ // database branch record not exist or it's a deleted branch
+ notExist := git_model.IsErrBranchNotExist(err) || rawBranch.IsDeleted
commit, err := gitRepo.GetBranchCommit(branchName)
if err != nil {
@@ -497,8 +496,10 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
}
if err := db.WithTx(ctx, func(ctx context.Context) error {
- if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
- return err
+ if !notExist {
+ if err := git_model.AddDeletedBranch(ctx, repo.ID, branchName, doer.ID); err != nil {
+ return err
+ }
}
return gitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
@@ -611,6 +612,14 @@ func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitR
return err
}
+ if !repo.IsEmpty {
+ if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{
+ RepoID: repo.ID,
+ }); err != nil {
+ log.Error("AddRepoToLicenseUpdaterQueue: %v", err)
+ }
+ }
+
notify_service.ChangeDefaultBranch(ctx, repo)
return nil
diff --git a/services/repository/create.go b/services/repository/create.go
index 971793bcc6..282b2d3e58 100644
--- a/services/repository/create.go
+++ b/services/repository/create.go
@@ -303,6 +303,25 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
rollbackRepo.OwnerID = u.ID
return fmt.Errorf("CreateRepository(git update-server-info): %w", err)
}
+
+ // update licenses
+ var licenses []string
+ if len(opts.License) > 0 {
+ licenses = append(licenses, ConvertLicenseName(opts.License))
+
+ stdout, _, err := git.NewCommand(ctx, "rev-parse", "HEAD").
+ SetDescription(fmt.Sprintf("CreateRepository(git rev-parse HEAD): %s", repoPath)).
+ RunStdString(&git.RunOpts{Dir: repoPath})
+ if err != nil {
+ log.Error("CreateRepository(git rev-parse HEAD) in %v: Stdout: %s\nError: %v", repo, stdout, err)
+ rollbackRepo = repo
+ rollbackRepo.OwnerID = u.ID
+ return fmt.Errorf("CreateRepository(git rev-parse HEAD): %w", err)
+ }
+ if err := repo_model.UpdateRepoLicenses(ctx, repo, stdout, licenses); err != nil {
+ return err
+ }
+ }
return nil
}); err != nil {
if rollbackRepo != nil {
diff --git a/services/repository/delete.go b/services/repository/delete.go
index cd779b05c3..e580833140 100644
--- a/services/repository/delete.go
+++ b/services/repository/delete.go
@@ -140,6 +140,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
&git_model.Branch{RepoID: repoID},
&git_model.LFSLock{RepoID: repoID},
&repo_model.LanguageStat{RepoID: repoID},
+ &repo_model.RepoLicense{RepoID: repoID},
&issues_model.Milestone{RepoID: repoID},
&repo_model.Mirror{RepoID: repoID},
&activities_model.Notification{RepoID: repoID},
diff --git a/services/repository/fork.go b/services/repository/fork.go
index f074fd1082..e114555679 100644
--- a/services/repository/fork.go
+++ b/services/repository/fork.go
@@ -198,6 +198,9 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork
if err := repo_model.CopyLanguageStat(ctx, opts.BaseRepo, repo); err != nil {
log.Error("Copy language stat from oldRepo failed: %v", err)
}
+ if err := repo_model.CopyLicense(ctx, opts.BaseRepo, repo); err != nil {
+ return nil, err
+ }
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil {
diff --git a/services/repository/license.go b/services/repository/license.go
new file mode 100644
index 0000000000..2453be3c87
--- /dev/null
+++ b/services/repository/license.go
@@ -0,0 +1,205 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/container"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/gitrepo"
+ "code.gitea.io/gitea/modules/graceful"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/options"
+ "code.gitea.io/gitea/modules/queue"
+
+ licenseclassifier "github.com/google/licenseclassifier/v2"
+)
+
+var (
+ classifier *licenseclassifier.Classifier
+ LicenseFileName = "LICENSE"
+ licenseAliases map[string]string
+
+ // licenseUpdaterQueue represents a queue to handle update repo licenses
+ licenseUpdaterQueue *queue.WorkerPoolQueue[*LicenseUpdaterOptions]
+)
+
+func AddRepoToLicenseUpdaterQueue(opts *LicenseUpdaterOptions) error {
+ if opts == nil {
+ return nil
+ }
+ return licenseUpdaterQueue.Push(opts)
+}
+
+func loadLicenseAliases() error {
+ if licenseAliases != nil {
+ return nil
+ }
+
+ data, err := options.AssetFS().ReadFile("license", "etc", "license-aliases.json")
+ if err != nil {
+ return err
+ }
+ err = json.Unmarshal(data, &licenseAliases)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func ConvertLicenseName(name string) string {
+ if err := loadLicenseAliases(); err != nil {
+ return name
+ }
+
+ v, ok := licenseAliases[name]
+ if ok {
+ return v
+ }
+ return name
+}
+
+func InitLicenseClassifier() error {
+ // threshold should be 0.84~0.86 or the test will be failed
+ classifier = licenseclassifier.NewClassifier(.85)
+ licenseFiles, err := options.AssetFS().ListFiles("license", true)
+ if err != nil {
+ return err
+ }
+
+ existLicense := make(container.Set[string])
+ if len(licenseFiles) > 0 {
+ for _, licenseFile := range licenseFiles {
+ licenseName := ConvertLicenseName(licenseFile)
+ if existLicense.Contains(licenseName) {
+ continue
+ }
+ existLicense.Add(licenseName)
+ data, err := options.License(licenseFile)
+ if err != nil {
+ return err
+ }
+ classifier.AddContent("License", licenseFile, licenseName, data)
+ }
+ }
+ return nil
+}
+
+type LicenseUpdaterOptions struct {
+ RepoID int64
+}
+
+func repoLicenseUpdater(items ...*LicenseUpdaterOptions) []*LicenseUpdaterOptions {
+ ctx := graceful.GetManager().ShutdownContext()
+
+ for _, opts := range items {
+ repo, err := repo_model.GetRepositoryByID(ctx, opts.RepoID)
+ if err != nil {
+ log.Error("repoLicenseUpdater [%d] failed: GetRepositoryByID: %v", opts.RepoID, err)
+ continue
+ }
+ if repo.IsEmpty {
+ continue
+ }
+
+ gitRepo, err := gitrepo.OpenRepository(ctx, repo)
+ if err != nil {
+ log.Error("repoLicenseUpdater [%d] failed: OpenRepository: %v", opts.RepoID, err)
+ continue
+ }
+ defer gitRepo.Close()
+
+ commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch)
+ if err != nil {
+ log.Error("repoLicenseUpdater [%d] failed: GetBranchCommit: %v", opts.RepoID, err)
+ continue
+ }
+ if err = UpdateRepoLicenses(ctx, repo, commit); err != nil {
+ log.Error("repoLicenseUpdater [%d] failed: updateRepoLicenses: %v", opts.RepoID, err)
+ }
+ }
+ return nil
+}
+
+func SyncRepoLicenses(ctx context.Context) error {
+ log.Trace("Doing: SyncRepoLicenses")
+
+ if err := db.Iterate(
+ ctx,
+ nil,
+ func(ctx context.Context, repo *repo_model.Repository) error {
+ select {
+ case <-ctx.Done():
+ return db.ErrCancelledf("before sync repo licenses for %s", repo.FullName())
+ default:
+ }
+ return AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID})
+ },
+ ); err != nil {
+ log.Trace("Error: SyncRepoLicenses: %v", err)
+ return err
+ }
+
+ log.Trace("Finished: SyncReposLicenses")
+ return nil
+}
+
+// UpdateRepoLicenses will update repository licenses col if license file exists
+func UpdateRepoLicenses(ctx context.Context, repo *repo_model.Repository, commit *git.Commit) error {
+ if commit == nil {
+ return nil
+ }
+
+ b, err := commit.GetBlobByPath(LicenseFileName)
+ if err != nil && !git.IsErrNotExist(err) {
+ return fmt.Errorf("GetBlobByPath: %w", err)
+ }
+
+ if git.IsErrNotExist(err) {
+ return repo_model.CleanRepoLicenses(ctx, repo)
+ }
+
+ licenses := make([]string, 0)
+ if b != nil {
+ r, err := b.DataAsync()
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+
+ licenses, err = detectLicense(r)
+ if err != nil {
+ return fmt.Errorf("detectLicense: %w", err)
+ }
+ }
+ return repo_model.UpdateRepoLicenses(ctx, repo, commit.ID.String(), licenses)
+}
+
+// detectLicense returns the licenses detected by the given content buff
+func detectLicense(r io.Reader) ([]string, error) {
+ if r == nil {
+ return nil, nil
+ }
+
+ matches, err := classifier.MatchFrom(r)
+ if err != nil {
+ return nil, err
+ }
+ if len(matches.Matches) > 0 {
+ results := make(container.Set[string], len(matches.Matches))
+ for _, r := range matches.Matches {
+ if r.MatchType == "License" && !results.Contains(r.Variant) {
+ results.Add(r.Variant)
+ }
+ }
+ return results.Values(), nil
+ }
+ return nil, nil
+}
diff --git a/services/repository/license_test.go b/services/repository/license_test.go
new file mode 100644
index 0000000000..39e9738145
--- /dev/null
+++ b/services/repository/license_test.go
@@ -0,0 +1,73 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+
+ repo_module "code.gitea.io/gitea/modules/repository"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_detectLicense(t *testing.T) {
+ type DetectLicenseTest struct {
+ name string
+ arg string
+ want []string
+ }
+
+ tests := []DetectLicenseTest{
+ {
+ name: "empty",
+ arg: "",
+ want: nil,
+ },
+ {
+ name: "no detected license",
+ arg: "Copyright (c) 2023 Gitea",
+ want: nil,
+ },
+ }
+
+ repo_module.LoadRepoConfig()
+ err := loadLicenseAliases()
+ assert.NoError(t, err)
+ for _, licenseName := range repo_module.Licenses {
+ license, err := repo_module.GetLicense(licenseName, &repo_module.LicenseValues{
+ Owner: "Gitea",
+ Email: "teabot@gitea.io",
+ Repo: "gitea",
+ Year: "2024",
+ })
+ assert.NoError(t, err)
+
+ tests = append(tests, DetectLicenseTest{
+ name: fmt.Sprintf("single license test: %s", licenseName),
+ arg: string(license),
+ want: []string{ConvertLicenseName(licenseName)},
+ })
+ }
+
+ err = InitLicenseClassifier()
+ assert.NoError(t, err)
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ license, err := detectLicense(strings.NewReader(tt.arg))
+ assert.NoError(t, err)
+ assert.Equal(t, tt.want, license)
+ })
+ }
+
+ result, err := detectLicense(strings.NewReader(tests[2].arg + tests[3].arg + tests[4].arg))
+ assert.NoError(t, err)
+ t.Run("multiple licenses test", func(t *testing.T) {
+ assert.Equal(t, 3, len(result))
+ assert.Contains(t, result, tests[2].want[0])
+ assert.Contains(t, result, tests[3].want[0])
+ assert.Contains(t, result, tests[4].want[0])
+ })
+}
diff --git a/services/repository/migrate.go b/services/repository/migrate.go
index 2e901791b4..c627b46fab 100644
--- a/services/repository/migrate.go
+++ b/services/repository/migrate.go
@@ -172,6 +172,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
return repo, fmt.Errorf("StoreMissingLfsObjectsInRepository: %w", err)
}
}
+
+ // Update repo license
+ if err := AddRepoToLicenseUpdaterQueue(&LicenseUpdaterOptions{RepoID: repo.ID}); err != nil {
+ log.Error("Failed to add repo to license updater queue: %v", err)
+ }
}
ctx, committer, err := db.TxContext(ctx)
diff --git a/services/repository/push.go b/services/repository/push.go
index f27e6a58dd..8b81588c07 100644
--- a/services/repository/push.go
+++ b/services/repository/push.go
@@ -320,8 +320,9 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
}
releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
- RepoID: repo.ID,
- TagNames: tags,
+ RepoID: repo.ID,
+ TagNames: tags,
+ IncludeTags: true,
})
if err != nil {
return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
@@ -382,12 +383,12 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
rel, has := relMap[lowerTag]
+ parts := strings.SplitN(tag.Message, "\n", 2)
+ note := ""
+ if len(parts) > 1 {
+ note = parts[1]
+ }
if !has {
- parts := strings.SplitN(tag.Message, "\n", 2)
- note := ""
- if len(parts) > 1 {
- note = parts[1]
- }
rel = &repo_model.Release{
RepoID: repo.ID,
Title: parts[0],
@@ -408,10 +409,11 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
newReleases = append(newReleases, rel)
} else {
+ rel.Title = parts[0]
+ rel.Note = note
rel.Sha1 = commit.ID.String()
rel.CreatedUnix = timeutil.TimeStamp(createdAt.Unix())
rel.NumCommits = commitsCount
- rel.IsDraft = false
if rel.IsTag && author != nil {
rel.PublisherID = author.ID
}
diff --git a/services/repository/repository.go b/services/repository/repository.go
index 5306e7d45c..59b4491132 100644
--- a/services/repository/repository.go
+++ b/services/repository/repository.go
@@ -18,6 +18,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
@@ -96,6 +97,12 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN
// Init start repository service
func Init(ctx context.Context) error {
+ licenseUpdaterQueue = queue.CreateUniqueQueue(graceful.GetManager().ShutdownContext(), "repo_license_updater", repoLicenseUpdater)
+ if licenseUpdaterQueue == nil {
+ return fmt.Errorf("unable to create repo_license_updater queue")
+ }
+ go graceful.GetManager().RunWithCancel(licenseUpdaterQueue)
+
if err := repo_module.LoadRepoConfig(); err != nil {
return err
}
diff --git a/services/user/user_test.go b/services/user/user_test.go
index bd6019a14f..cd0f597501 100644
--- a/services/user/user_test.go
+++ b/services/user/user_test.go
@@ -92,7 +92,7 @@ func TestCreateUser(t *testing.T) {
MustChangePassword: false,
}
- assert.NoError(t, user_model.CreateUser(db.DefaultContext, user))
+ assert.NoError(t, user_model.CreateUser(db.DefaultContext, user, &user_model.Meta{}))
assert.NoError(t, DeleteUser(db.DefaultContext, user, false))
}
@@ -177,7 +177,7 @@ func TestCreateUser_Issue5882(t *testing.T) {
for _, v := range tt {
setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation
- assert.NoError(t, user_model.CreateUser(db.DefaultContext, v.user))
+ assert.NoError(t, user_model.CreateUser(db.DefaultContext, v.user, &user_model.Meta{}))
u, err := user_model.GetUserByEmail(db.DefaultContext, v.user.Email)
assert.NoError(t, err)
diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go
index b2c0a73784..4707602cdf 100644
--- a/services/webhook/deliver.go
+++ b/services/webhook/deliver.go
@@ -303,7 +303,7 @@ func Init() error {
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
Proxy: webhookProxy(allowedHostMatcher),
- DialContext: hostmatcher.NewDialContextWithProxy("webhook", allowedHostMatcher, nil, setting.Webhook.ProxyURLFixed),
+ DialContext: hostmatcher.NewDialContext("webhook", allowedHostMatcher, nil, setting.Webhook.ProxyURLFixed),
},
}
diff --git a/services/webhook/discord.go b/services/webhook/discord.go
index f27b39dac3..59e87a7e1f 100644
--- a/services/webhook/discord.go
+++ b/services/webhook/discord.go
@@ -11,6 +11,7 @@ import (
"net/url"
"strconv"
"strings"
+ "unicode/utf8"
webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
@@ -154,8 +155,14 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) {
var text string
// for each commit, generate attachment text
for i, commit := range p.Commits {
- text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL,
- strings.TrimRight(commit.Message, "\r\n"), commit.Author.Name)
+ // limit the commit message display to just the summary, otherwise it would be hard to read
+ message := strings.TrimRight(strings.SplitN(commit.Message, "\n", 1)[0], "\r")
+
+ // a limit of 50 is set because GitHub does the same
+ if utf8.RuneCountInString(message) > 50 {
+ message = fmt.Sprintf("%.47s...", message)
+ }
+ text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, message, commit.Author.Name)
// add linebreak to each commit but the last
if i < len(p.Commits)-1 {
text += "\n"
diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go
index c04b95383b..fbb4b24ef1 100644
--- a/services/webhook/discord_test.go
+++ b/services/webhook/discord_test.go
@@ -80,6 +80,20 @@ func TestDiscordPayload(t *testing.T) {
assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
})
+ t.Run("PushWithLongCommitMessage", func(t *testing.T) {
+ p := pushTestMultilineCommitMessagePayload()
+
+ pl, err := dc.Push(p)
+ require.NoError(t, err)
+
+ assert.Len(t, pl.Embeds, 1)
+ assert.Equal(t, "[test/repo:test] 2 new commits", pl.Embeds[0].Title)
+ assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary âš ï¸âš ï¸âš ï¸âš ï¸ containing ä½ å¥½... - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) This is a commit summary âš ï¸âš ï¸âš ï¸âš ï¸ containing ä½ å¥½... - user1", pl.Embeds[0].Description)
+ assert.Equal(t, p.Sender.UserName, pl.Embeds[0].Author.Name)
+ assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.Embeds[0].Author.URL)
+ assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
+ })
+
t.Run("Issue", func(t *testing.T) {
p := issueTestPayload()
diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go
index fc6e7140e7..d6a77c9442 100644
--- a/services/webhook/general_test.go
+++ b/services/webhook/general_test.go
@@ -64,9 +64,17 @@ func forkTestPayload() *api.ForkPayload {
}
func pushTestPayload() *api.PushPayload {
+ return pushTestPayloadWithCommitMessage("commit message")
+}
+
+func pushTestMultilineCommitMessagePayload() *api.PushPayload {
+ return pushTestPayloadWithCommitMessage("This is a commit summary âš ï¸âš ï¸âš ï¸âš ï¸ containing ä½ å¥½ âš ï¸âš ï¸ï¸\n\nThis is the message body.")
+}
+
+func pushTestPayloadWithCommitMessage(message string) *api.PushPayload {
commit := &api.PayloadCommit{
ID: "2020558fe2e34debb818a514715839cabd25e778",
- Message: "commit message",
+ Message: message,
URL: "http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778",
Author: &api.PayloadUser{
Name: "user1",
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 4c09a9d588..a0a85d85af 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -44,7 +44,7 @@ parts:
source: .
stage-packages: [ git, sqlite3, openssh-client ]
build-packages: [ git, libpam0g-dev, libsqlite3-dev, build-essential]
- build-snaps: [ go/1.22/stable, node/20/stable ]
+ build-snaps: [ go/1.23/stable, node/20/stable ]
build-environment:
- LDFLAGS: ""
override-pull: |
diff --git a/templates/projects/view.tmpl b/templates/projects/view.tmpl
index 584462d2a2..f5c1bb7670 100644
--- a/templates/projects/view.tmpl
+++ b/templates/projects/view.tmpl
@@ -3,6 +3,82 @@
{{.Project.Title}}
+
+
+
{{if $canWriteProject}}