mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-21 09:48:58 +02:00
Compare commits
118 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
486d274be6 | ||
|
ab3d2a944c | ||
|
12bfa9e83d | ||
|
dd661e92df | ||
|
0b31272c7e | ||
|
ec0c418719 | ||
|
6dc19fc29a | ||
|
9f1baa7d18 | ||
|
e13deb7a16 | ||
|
e5c1b8b632 | ||
|
e931b62f33 | ||
|
81ee93e5bc | ||
|
053f9186bc | ||
|
68fcdb6122 | ||
|
14ca309c39 | ||
|
4aba42519d | ||
|
9adf175df0 | ||
|
c3fa2a8729 | ||
|
89dfed32e0 | ||
|
d5062d0c27 | ||
|
90e9e79232 | ||
|
c6467edcb1 | ||
|
5d5b695527 | ||
|
0af7a7b79f | ||
|
9339661078 | ||
|
1e69f085d6 | ||
|
0bfccd8ecf | ||
|
534b9b35dd | ||
|
dbadc59b56 | ||
|
a57e2c4bc3 | ||
|
acd4e10990 | ||
|
0a1df294c8 | ||
|
52a964d1fc | ||
|
d3dbe0d9ce | ||
|
cdbbdbef06 | ||
|
79f555d465 | ||
|
ae2b795693 | ||
|
d1fdbf46bd | ||
|
f27a75564a | ||
|
958d0db4f4 | ||
|
4c2441ba5d | ||
|
6f5f0be9e3 | ||
|
23d2d224c2 | ||
|
a43d829de8 | ||
|
8ab1363fef | ||
|
178fd90852 | ||
|
b39f7a37d1 | ||
|
b9ed8fceff | ||
|
e6ce72b14a | ||
|
2eecd58bbe | ||
|
64b9b21790 | ||
|
3290aff964 | ||
|
7ed1e8987e | ||
|
f10e909fce | ||
|
a3b25436f2 | ||
|
b947bc4363 | ||
|
18dc41d6f8 | ||
|
bf5d00074d | ||
|
fb4e9f92f9 | ||
|
468d1919b5 | ||
|
1b788946a7 | ||
|
e8646ad1d8 | ||
|
29dc9c784e | ||
|
b1cc4bf77f | ||
|
d35161ceb8 | ||
|
8defca6d39 | ||
|
fac434da0a | ||
|
e18eae7129 | ||
|
c60bc26fd3 | ||
|
bacc69db83 | ||
|
c5da032193 | ||
|
3ace45c118 | ||
|
5d6c5ce71a | ||
|
7baa6fa47c | ||
|
f9a0b077a7 | ||
|
d3317ebabe | ||
|
e9481e1da3 | ||
|
8965c068e9 | ||
|
eaaa158df3 | ||
|
f5498421c4 | ||
|
a6a14c9a92 | ||
|
d0ec1788b8 | ||
|
c1202f1b57 | ||
|
1162cbccc0 | ||
|
038990e0ff | ||
|
03ff09870d | ||
|
8bf4f2cc8f | ||
|
21731c1370 | ||
|
a0e272d95a | ||
|
47537a8361 | ||
|
d018c1b4b1 | ||
|
d2cbe2fba0 | ||
|
d6233c25b5 | ||
|
2bf2d00c8a | ||
|
9bd56a8ba0 | ||
|
a1dc3c9bd1 | ||
|
47ee84d1f3 | ||
|
89f1df033a | ||
|
94b67f1967 | ||
|
0a9a84df11 | ||
|
cdac263bb8 | ||
|
a5c7df7a4c | ||
|
6d738fecc4 | ||
|
38cc7453e2 | ||
|
b44175c071 | ||
|
947358dffe | ||
|
be1090cb2d | ||
|
c8f3402841 | ||
|
a3a95a0b67 | ||
|
ed527b664d | ||
|
e4717d426e | ||
|
16f15d2f7b | ||
|
b3f5196241 | ||
|
6c5f0af45d | ||
|
c95cb7c7e2 | ||
|
6747e3e0eb | ||
|
a12b5b3640 | ||
|
834dad8cef |
@ -1,17 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "Gitea DevContainer",
|
"name": "Gitea DevContainer",
|
||||||
"image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
|
"image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
|
||||||
"containerEnv": {
|
|
||||||
// override "local" from packaged version
|
|
||||||
"GOTOOLCHAIN": "auto"
|
|
||||||
},
|
|
||||||
"features": {
|
"features": {
|
||||||
// installs nodejs into container
|
// installs nodejs into container
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "lts"
|
"version": "20"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
|
"ghcr.io/devcontainers/features/git-lfs:1.2.2": {},
|
||||||
"ghcr.io/jsburckhardt/devcontainer-features/uv:1": {},
|
"ghcr.io/devcontainers-extra/features/poetry:2": {},
|
||||||
"ghcr.io/devcontainers/features/python:1": {
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
"version": "3.12"
|
"version": "3.12"
|
||||||
},
|
},
|
||||||
|
@ -36,6 +36,15 @@ _testmain.go
|
|||||||
coverage.all
|
coverage.all
|
||||||
cpu.out
|
cpu.out
|
||||||
|
|
||||||
|
/modules/migration/bindata.go
|
||||||
|
/modules/migration/bindata.go.hash
|
||||||
|
/modules/options/bindata.go
|
||||||
|
/modules/options/bindata.go.hash
|
||||||
|
/modules/public/bindata.go
|
||||||
|
/modules/public/bindata.go.hash
|
||||||
|
/modules/templates/bindata.go
|
||||||
|
/modules/templates/bindata.go.hash
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
@ -91,7 +91,6 @@ module.exports = {
|
|||||||
plugins: ['@vitest/eslint-plugin'],
|
plugins: ['@vitest/eslint-plugin'],
|
||||||
globals: vitestPlugin.environments.env.globals,
|
globals: vitestPlugin.environments.env.globals,
|
||||||
rules: {
|
rules: {
|
||||||
'github/unescaped-html-literal': [0],
|
|
||||||
'@vitest/consistent-test-filename': [0],
|
'@vitest/consistent-test-filename': [0],
|
||||||
'@vitest/consistent-test-it': [0],
|
'@vitest/consistent-test-it': [0],
|
||||||
'@vitest/expect-expect': [0],
|
'@vitest/expect-expect': [0],
|
||||||
@ -326,7 +325,6 @@ module.exports = {
|
|||||||
'@typescript-eslint/no-unnecessary-type-arguments': [0],
|
'@typescript-eslint/no-unnecessary-type-arguments': [0],
|
||||||
'@typescript-eslint/no-unnecessary-type-assertion': [2],
|
'@typescript-eslint/no-unnecessary-type-assertion': [2],
|
||||||
'@typescript-eslint/no-unnecessary-type-constraint': [2],
|
'@typescript-eslint/no-unnecessary-type-constraint': [2],
|
||||||
'@typescript-eslint/no-unnecessary-type-conversion': [2],
|
|
||||||
'@typescript-eslint/no-unsafe-argument': [0],
|
'@typescript-eslint/no-unsafe-argument': [0],
|
||||||
'@typescript-eslint/no-unsafe-assignment': [0],
|
'@typescript-eslint/no-unsafe-assignment': [0],
|
||||||
'@typescript-eslint/no-unsafe-call': [0],
|
'@typescript-eslint/no-unsafe-call': [0],
|
||||||
@ -425,7 +423,7 @@ module.exports = {
|
|||||||
'github/no-useless-passive': [2],
|
'github/no-useless-passive': [2],
|
||||||
'github/prefer-observers': [2],
|
'github/prefer-observers': [2],
|
||||||
'github/require-passive-events': [2],
|
'github/require-passive-events': [2],
|
||||||
'github/unescaped-html-literal': [2],
|
'github/unescaped-html-literal': [0],
|
||||||
'grouped-accessor-pairs': [2],
|
'grouped-accessor-pairs': [2],
|
||||||
'guard-for-in': [0],
|
'guard-for-in': [0],
|
||||||
'id-blacklist': [0],
|
'id-blacklist': [0],
|
||||||
@ -484,7 +482,7 @@ module.exports = {
|
|||||||
'max-nested-callbacks': [0],
|
'max-nested-callbacks': [0],
|
||||||
'max-params': [0],
|
'max-params': [0],
|
||||||
'max-statements': [0],
|
'max-statements': [0],
|
||||||
'multiline-comment-style': [0],
|
'multiline-comment-style': [2, 'separate-lines'],
|
||||||
'new-cap': [0],
|
'new-cap': [0],
|
||||||
'no-alert': [0],
|
'no-alert': [0],
|
||||||
'no-array-constructor': [0], // handled by @typescript-eslint/no-array-constructor
|
'no-array-constructor': [0], // handled by @typescript-eslint/no-array-constructor
|
||||||
@ -646,7 +644,7 @@ module.exports = {
|
|||||||
'no-multi-str': [2],
|
'no-multi-str': [2],
|
||||||
'no-negated-condition': [0],
|
'no-negated-condition': [0],
|
||||||
'no-nested-ternary': [0],
|
'no-nested-ternary': [0],
|
||||||
'no-new-func': [0], // handled by @typescript-eslint/no-implied-eval
|
'no-new-func': [2],
|
||||||
'no-new-native-nonconstructor': [2],
|
'no-new-native-nonconstructor': [2],
|
||||||
'no-new-object': [2],
|
'no-new-object': [2],
|
||||||
'no-new-symbol': [2],
|
'no-new-symbol': [2],
|
||||||
|
12
.github/labeler.yml
vendored
12
.github/labeler.yml
vendored
@ -61,7 +61,7 @@ modifies/dependencies:
|
|||||||
- "package.json"
|
- "package.json"
|
||||||
- "package-lock.json"
|
- "package-lock.json"
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
- "uv.lock"
|
- "poetry.lock"
|
||||||
- "go.mod"
|
- "go.mod"
|
||||||
- "go.sum"
|
- "go.sum"
|
||||||
|
|
||||||
@ -81,13 +81,3 @@ docs-update-needed:
|
|||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- "custom/conf/app.example.ini"
|
- "custom/conf/app.example.ini"
|
||||||
|
|
||||||
topic/code-linting:
|
|
||||||
- changed-files:
|
|
||||||
- any-glob-to-any-file:
|
|
||||||
- ".eslintrc.cjs"
|
|
||||||
- ".golangci.yml"
|
|
||||||
- ".markdownlint.yaml"
|
|
||||||
- ".spectral.yaml"
|
|
||||||
- ".yamllint.yaml"
|
|
||||||
- "stylelint.config.js"
|
|
||||||
|
3
.github/workflows/files-changed.yml
vendored
3
.github/workflows/files-changed.yml
vendored
@ -77,7 +77,7 @@ jobs:
|
|||||||
- "tools/lint-templates-*.js"
|
- "tools/lint-templates-*.js"
|
||||||
- "templates/**/*.tmpl"
|
- "templates/**/*.tmpl"
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
- "uv.lock"
|
- "poetry.lock"
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
- "Dockerfile"
|
- "Dockerfile"
|
||||||
@ -98,3 +98,4 @@ jobs:
|
|||||||
- "**/*.yaml"
|
- "**/*.yaml"
|
||||||
- ".yamllint.yaml"
|
- ".yamllint.yaml"
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
|
- "poetry.lock"
|
||||||
|
20
.github/workflows/pull-compliance.yml
vendored
20
.github/workflows/pull-compliance.yml
vendored
@ -32,13 +32,15 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: astral-sh/setup-uv@v6
|
- uses: actions/setup-python@v5
|
||||||
- run: uv python install 3.12
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
|
- run: pip install poetry
|
||||||
- run: make deps-py
|
- run: make deps-py
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
- run: make lint-templates
|
- run: make lint-templates
|
||||||
@ -49,8 +51,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: astral-sh/setup-uv@v6
|
- uses: actions/setup-python@v5
|
||||||
- run: uv python install 3.12
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
- run: pip install poetry
|
||||||
- run: make deps-py
|
- run: make deps-py
|
||||||
- run: make lint-yaml
|
- run: make lint-yaml
|
||||||
|
|
||||||
@ -62,7 +66,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
@ -133,7 +137,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
@ -182,7 +186,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
|
2
.github/workflows/pull-e2e-tests.yml
vendored
2
.github/workflows/pull-e2e-tests.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend frontend deps-backend
|
- run: make deps-frontend frontend deps-backend
|
||||||
|
2
.github/workflows/release-nightly.yml
vendored
2
.github/workflows/release-nightly.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend deps-backend
|
- run: make deps-frontend deps-backend
|
||||||
|
2
.github/workflows/release-tag-rc.yml
vendored
2
.github/workflows/release-tag-rc.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend deps-backend
|
- run: make deps-frontend deps-backend
|
||||||
|
2
.github/workflows/release-tag-version.yml
vendored
2
.github/workflows/release-tag-version.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 22
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: package-lock.json
|
cache-dependency-path: package-lock.json
|
||||||
- run: make deps-frontend deps-backend
|
- run: make deps-frontend deps-backend
|
||||||
|
15
.gitignore
vendored
15
.gitignore
vendored
@ -22,9 +22,6 @@ _test
|
|||||||
.vscode
|
.vscode
|
||||||
__debug_bin*
|
__debug_bin*
|
||||||
|
|
||||||
# Visual Studio
|
|
||||||
/.vs/
|
|
||||||
|
|
||||||
*.cgo1.go
|
*.cgo1.go
|
||||||
*.cgo2.c
|
*.cgo2.c
|
||||||
_cgo_defun.c
|
_cgo_defun.c
|
||||||
@ -109,15 +106,3 @@ prime/
|
|||||||
|
|
||||||
# Manpage
|
# Manpage
|
||||||
/man
|
/man
|
||||||
|
|
||||||
# Ignore AI/LLM instruction files
|
|
||||||
/.claude/
|
|
||||||
/.cursorrules
|
|
||||||
/.cursor/
|
|
||||||
/.goosehints
|
|
||||||
/.windsurfrules
|
|
||||||
/.github/copilot-instructions.md
|
|
||||||
/AGENT.md
|
|
||||||
/CLAUDE.md
|
|
||||||
/llms.txt
|
|
||||||
|
|
||||||
|
@ -45,13 +45,7 @@ linters:
|
|||||||
desc: do not use the ini package, use gitea's config system instead
|
desc: do not use the ini package, use gitea's config system instead
|
||||||
- pkg: gitea.com/go-chi/cache
|
- pkg: gitea.com/go-chi/cache
|
||||||
desc: do not use the go-chi cache package, use gitea's cache system
|
desc: do not use the go-chi cache package, use gitea's cache system
|
||||||
nolintlint:
|
|
||||||
allow-unused: false
|
|
||||||
require-explanation: true
|
|
||||||
require-specific: true
|
|
||||||
gocritic:
|
gocritic:
|
||||||
enabled-checks:
|
|
||||||
- equalFold
|
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
- ifElseChain
|
- ifElseChain
|
||||||
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
|
- singleCaseSwitch # Every time this occurred in the code, there was no other way.
|
||||||
@ -89,10 +83,6 @@ linters:
|
|||||||
- name: unreachable-code
|
- name: unreachable-code
|
||||||
- name: var-declaration
|
- name: var-declaration
|
||||||
- name: var-naming
|
- name: var-naming
|
||||||
arguments:
|
|
||||||
- [] # AllowList - do not remove as args for the rule are positional and won't work without lists first
|
|
||||||
- [] # DenyList
|
|
||||||
- - skip-package-name-checks: true # supress errors from underscore in migration packages
|
|
||||||
staticcheck:
|
staticcheck:
|
||||||
checks:
|
checks:
|
||||||
- all
|
- all
|
||||||
|
3
.ignore
3
.ignore
@ -1,6 +1,9 @@
|
|||||||
*.min.css
|
*.min.css
|
||||||
*.min.js
|
*.min.js
|
||||||
/assets/*.json
|
/assets/*.json
|
||||||
|
/modules/options/bindata.go
|
||||||
|
/modules/public/bindata.go
|
||||||
|
/modules/templates/bindata.go
|
||||||
/options/gitignore
|
/options/gitignore
|
||||||
/options/license
|
/options/license
|
||||||
/public/assets
|
/public/assets
|
||||||
|
60
CHANGELOG.md
60
CHANGELOG.md
@ -4,6 +4,66 @@ This changelog goes through the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
been added to each release, please refer to the [blog](https://blog.gitea.com).
|
||||||
|
|
||||||
|
## [1.24.3](https://github.com/go-gitea/gitea/releases/tag/1.24.3) - 2025-07-15
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix form property assignment edge case (#35073) (#35078)
|
||||||
|
* Improve submodule relative path handling (#35056) (#35075)
|
||||||
|
* Fix incorrect comment diff hunk parsing, fix github asset ID nil panic (#35046) (#35055)
|
||||||
|
* Fix updating user visibility (#35036) (#35044)
|
||||||
|
* Support base64-encoded agit push options (#35037) (#35041)
|
||||||
|
* Make submodule link work with relative path (#35034) (#35038)
|
||||||
|
* Fix bug when displaying git user avatar in commits list (#35006)
|
||||||
|
* Fix API response for swagger spec (#35029)
|
||||||
|
* Start automerge check again after the conflict check and the schedule (#34988) (#35002)
|
||||||
|
* Fix the response format for actions/workflows (#35009) (#35016)
|
||||||
|
* Fix repo settings and protocol log problems (#35012) (#35013)
|
||||||
|
* Fix project images scroll (#34971) (#34972)
|
||||||
|
* Mark old reviews as stale on agit pr updates (#34933) (#34965)
|
||||||
|
* Fix git graph page (#34948) (#34949)
|
||||||
|
* Don't send trigger for a pending review's comment create/update/delete (#34928) (#34939)
|
||||||
|
* Fix some log and UI problems (#34863) (#34868)
|
||||||
|
* Fix archive API (#34853) (#34857)
|
||||||
|
* Ignore force pushes for changed files in a PR review (#34837) (#34843)
|
||||||
|
* Fix SSH LFS timeout (#34838) (#34842)
|
||||||
|
* Fix team permissions (#34827) (#34836)
|
||||||
|
* Fix job status aggregation logic (#34823) (#34835)
|
||||||
|
* Fix issue filter (#34914) (#34915)
|
||||||
|
* Fix typo in pull request merge warning message text (#34899) (#34903)
|
||||||
|
* Support the open-icon of folder (#34168) (#34896)
|
||||||
|
* Optimize flex layout of release attachment area (#34885) (#34886)
|
||||||
|
* Fix the issue of abnormal interface when there is no issue-item on the project page (#34791) (#34880)
|
||||||
|
* Skip updating timestamp when sync branch (#34875)
|
||||||
|
* Fix required contexts and commit status matching bug (#34815) (#34829)
|
||||||
|
|
||||||
|
## [1.24.2](https://github.com/go-gitea/gitea/releases/tag/1.24.2) - 2025-06-20
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix container range bug (#34795) (#34796)
|
||||||
|
* Upgrade chi to v5.2.2 (#34798) (#34799)
|
||||||
|
* BUILD
|
||||||
|
* Bump poetry feature to new url for dev container (#34787) (#34790)
|
||||||
|
|
||||||
|
## [1.24.1](https://github.com/go-gitea/gitea/releases/tag/1.24.1) - 2025-06-18
|
||||||
|
|
||||||
|
* ENHANCEMENTS
|
||||||
|
* Improve alignment of commit status icon on commit page (#34750) (#34757)
|
||||||
|
* Support title and body query parameters for new PRs (#34537) (#34752)
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* When using rules to delete packages, remove unclean bugs (#34632) (#34761)
|
||||||
|
* Fix ghost user in feeds when pushing in an actions, it should be gitea-actions (#34703) (#34756)
|
||||||
|
* Prevent double markdown link brackets when pasting URL (#34745) (#34748)
|
||||||
|
* Prevent duplicate form submissions when creating forks (#34714) (#34735)
|
||||||
|
* Fix markdown wrap (#34697) (#34702)
|
||||||
|
* Fix pull requests API convert panic when head repository is deleted. (#34685) (#34687)
|
||||||
|
* Fix commit message rendering and some UI problems (#34680) (#34683)
|
||||||
|
* Fix container range bug (#34725) (#34732)
|
||||||
|
* Fix incorrect cli default values (#34765) (#34766)
|
||||||
|
* Fix dropdown filter (#34708) (#34711)
|
||||||
|
* Hide href attribute of a tag if there is no target_url (#34556) (#34684)
|
||||||
|
* Fix tag target (#34781) #34783
|
||||||
|
|
||||||
## [1.24.0](https://github.com/go-gitea/gitea/releases/tag/1.24.0) - 2025-05-26
|
## [1.24.0](https://github.com/go-gitea/gitea/releases/tag/1.24.0) - 2025-05-26
|
||||||
|
|
||||||
* BREAKING
|
* BREAKING
|
||||||
|
@ -30,7 +30,7 @@ These are the values to which people in the Gitea community should aspire.
|
|||||||
- **Be constructive.**
|
- **Be constructive.**
|
||||||
- Avoid derailing: stay on topic; if you want to talk about something else, start a new conversation.
|
- Avoid derailing: stay on topic; if you want to talk about something else, start a new conversation.
|
||||||
- Avoid unconstructive criticism: don't merely decry the current state of affairs; offer—or at least solicit—suggestions as to how things may be improved.
|
- Avoid unconstructive criticism: don't merely decry the current state of affairs; offer—or at least solicit—suggestions as to how things may be improved.
|
||||||
- Avoid snarking (pithy, unproductive, sniping comments).
|
- Avoid snarking (pithy, unproductive, sniping comments)
|
||||||
- Avoid discussing potentially offensive or sensitive issues; this all too often leads to unnecessary conflict.
|
- Avoid discussing potentially offensive or sensitive issues; this all too often leads to unnecessary conflict.
|
||||||
- Avoid microaggressions (brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults to a person or group).
|
- Avoid microaggressions (brief and commonplace verbal, behavioral and environmental indignities that communicate hostile, derogatory or negative slights and insults to a person or group).
|
||||||
- **Be responsible.**
|
- **Be responsible.**
|
||||||
@ -42,7 +42,7 @@ People are complicated. You should expect to be misunderstood and to misundersta
|
|||||||
|
|
||||||
### Our Pledge
|
### Our Pledge
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
### Our Standards
|
### Our Standards
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ be reviewed by two maintainers and must pass the automatic tests.
|
|||||||
## Releasing Gitea
|
## Releasing Gitea
|
||||||
|
|
||||||
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
|
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
|
||||||
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
|
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody against in about serval hours.
|
||||||
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
|
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
|
||||||
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
|
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
|
||||||
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
|
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
|
FROM docker.io/library/golang:1.24-alpine3.22 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-direct}
|
ENV GOPROXY=${GOPROXY:-direct}
|
||||||
@ -39,6 +39,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
|||||||
/tmp/local/etc/s6/.s6-svscan/* \
|
/tmp/local/etc/s6/.s6-svscan/* \
|
||||||
/go/src/code.gitea.io/gitea/gitea \
|
/go/src/code.gitea.io/gitea/gitea \
|
||||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.22
|
FROM docker.io/library/alpine:3.22
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
@ -82,3 +83,4 @@ CMD ["/usr/bin/s6-svscan", "/etc/s6"]
|
|||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
COPY --from=build-env /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||||
|
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.25-alpine3.22 AS build-env
|
FROM docker.io/library/golang:1.24-alpine3.22 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-direct}
|
ENV GOPROXY=${GOPROXY:-direct}
|
||||||
@ -37,6 +37,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
|
|||||||
/tmp/local/usr/local/bin/gitea \
|
/tmp/local/usr/local/bin/gitea \
|
||||||
/go/src/code.gitea.io/gitea/gitea \
|
/go/src/code.gitea.io/gitea/gitea \
|
||||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.22
|
FROM docker.io/library/alpine:3.22
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
@ -51,7 +52,6 @@ RUN apk --no-cache add \
|
|||||||
git \
|
git \
|
||||||
curl \
|
curl \
|
||||||
gnupg \
|
gnupg \
|
||||||
openssh-keygen \
|
|
||||||
&& rm -rf /var/cache/apk/*
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
RUN addgroup \
|
RUN addgroup \
|
||||||
@ -71,6 +71,7 @@ RUN chown git:git /var/lib/gitea /etc/gitea
|
|||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/environment-to-ini /usr/local/bin/environment-to-ini
|
||||||
|
COPY --from=build-env /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete /etc/profile.d/gitea_bash_autocomplete.sh
|
||||||
|
|
||||||
# git:git
|
# git:git
|
||||||
USER 1000:1000
|
USER 1000:1000
|
||||||
|
@ -36,7 +36,9 @@ a1012112796 <1012112796@qq.com> (@a1012112796)
|
|||||||
Karl Heinz Marbaise <kama@soebes.de> (@khmarbaise)
|
Karl Heinz Marbaise <kama@soebes.de> (@khmarbaise)
|
||||||
Norwin Roosen <git@nroo.de> (@noerw)
|
Norwin Roosen <git@nroo.de> (@noerw)
|
||||||
Kyle Dumont <kdumontnu@gmail.com> (@kdumontnu)
|
Kyle Dumont <kdumontnu@gmail.com> (@kdumontnu)
|
||||||
|
Patrick Schratz <patrick.schratz@gmail.com> (@pat-s)
|
||||||
Janis Estelmann <admin@oldschoolhack.me> (@KN4CK3R)
|
Janis Estelmann <admin@oldschoolhack.me> (@KN4CK3R)
|
||||||
|
Steven Kriegler <sk.bunsenbrenner@gmail.com> (@justusbunsi)
|
||||||
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
Jimmy Praet <jimmy.praet@telenet.be> (@jpraet)
|
||||||
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
Leon Hofmeister <dev.lh@web.de> (@delvh)
|
||||||
Wim <wim@42.be> (@42wim)
|
Wim <wim@42.be> (@42wim)
|
||||||
@ -62,4 +64,3 @@ Rowan Bohde <rowan.bohde@gmail.com> (@bohde)
|
|||||||
hiifong <i@hiif.ong> (@hiifong)
|
hiifong <i@hiif.ong> (@hiifong)
|
||||||
metiftikci <metiftikci@hotmail.com> (@metiftikci)
|
metiftikci <metiftikci@hotmail.com> (@metiftikci)
|
||||||
Christopher Homberger <christopher.homberger@web.de> (@ChristopherHX)
|
Christopher Homberger <christopher.homberger@web.de> (@ChristopherHX)
|
||||||
Tobias Balle-Petersen <tobiasbp@gmail.com> (@tobiasbp)
|
|
||||||
|
79
Makefile
79
Makefile
@ -23,21 +23,20 @@ SHASUM ?= shasum -a 256
|
|||||||
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
|
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
|
||||||
COMMA := ,
|
COMMA := ,
|
||||||
|
|
||||||
XGO_VERSION := go-1.25.x
|
XGO_VERSION := go-1.24.x
|
||||||
|
|
||||||
AIR_PACKAGE ?= github.com/air-verse/air@v1
|
AIR_PACKAGE ?= github.com/air-verse/air@v1
|
||||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
|
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.1
|
||||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.4.0
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.0.2
|
||||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12
|
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.12
|
||||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.7.0
|
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.32.3
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
|
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1
|
||||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
||||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
|
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1
|
||||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.20.0
|
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.17.1
|
||||||
GOPLS_MODERNIZE_PACKAGE ?= golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@v0.20.0
|
|
||||||
|
|
||||||
DOCKER_IMAGE ?= gitea/gitea
|
DOCKER_IMAGE ?= gitea/gitea
|
||||||
DOCKER_TAG ?= latest
|
DOCKER_TAG ?= latest
|
||||||
@ -48,17 +47,6 @@ ifeq ($(HAS_GO), yes)
|
|||||||
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CGO_ENABLED ?= 0
|
|
||||||
ifneq (,$(findstring sqlite,$(TAGS))$(findstring pam,$(TAGS)))
|
|
||||||
CGO_ENABLED = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
STATIC ?=
|
|
||||||
EXTLDFLAGS ?=
|
|
||||||
ifneq ($(STATIC),)
|
|
||||||
EXTLDFLAGS = -extldflags "-static"
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(GOOS),windows)
|
ifeq ($(GOOS),windows)
|
||||||
IS_WINDOWS := yes
|
IS_WINDOWS := yes
|
||||||
else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows)
|
else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows)
|
||||||
@ -92,6 +80,7 @@ ifeq ($(RACE_ENABLED),true)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
STORED_VERSION_FILE := VERSION
|
STORED_VERSION_FILE := VERSION
|
||||||
|
HUGO_VERSION ?= 0.111.3
|
||||||
|
|
||||||
GITHUB_REF_TYPE ?= branch
|
GITHUB_REF_TYPE ?= branch
|
||||||
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
GITHUB_REF_NAME ?= $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
@ -131,7 +120,8 @@ WEBPACK_CONFIGS := webpack.config.js tailwind.config.js
|
|||||||
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
|
WEBPACK_DEST := public/assets/js/index.js public/assets/css/index.css
|
||||||
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts
|
WEBPACK_DEST_ENTRIES := public/assets/js public/assets/css public/assets/fonts
|
||||||
|
|
||||||
BINDATA_DEST_WILDCARD := modules/migration/bindata.* modules/public/bindata.* modules/options/bindata.* modules/templates/bindata.*
|
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
||||||
|
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
||||||
|
|
||||||
GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go
|
GENERATED_GO_DEST := modules/charset/invisible_gen.go modules/charset/ambiguous_gen.go
|
||||||
|
|
||||||
@ -159,8 +149,14 @@ SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US
|
|||||||
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
|
||||||
|
|
||||||
GO_SOURCES := $(wildcard *.go)
|
GO_SOURCES := $(wildcard *.go)
|
||||||
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go")
|
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go)
|
||||||
GO_SOURCES += $(GENERATED_GO_DEST)
|
GO_SOURCES += $(GENERATED_GO_DEST)
|
||||||
|
GO_SOURCES_NO_BINDATA := $(GO_SOURCES)
|
||||||
|
|
||||||
|
ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
|
||||||
|
GO_SOURCES += $(BINDATA_DEST)
|
||||||
|
GENERATED_GO_DEST += $(BINDATA_DEST)
|
||||||
|
endif
|
||||||
|
|
||||||
# Force installation of playwright dependencies by setting this flag
|
# Force installation of playwright dependencies by setting this flag
|
||||||
ifdef DEPS_PLAYWRIGHT
|
ifdef DEPS_PLAYWRIGHT
|
||||||
@ -230,7 +226,7 @@ clean-all: clean ## delete backend, frontend and integration files
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: ## delete backend and integration files
|
clean: ## delete backend and integration files
|
||||||
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST_WILDCARD) \
|
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
|
||||||
integrations*.test \
|
integrations*.test \
|
||||||
e2e*.test \
|
e2e*.test \
|
||||||
tests/integration/gitea-integration-* \
|
tests/integration/gitea-integration-* \
|
||||||
@ -241,7 +237,7 @@ clean: ## delete backend and integration files
|
|||||||
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
||||||
|
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt: ## format the Go and template code
|
fmt: ## format the Go code
|
||||||
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||||
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
||||||
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
||||||
@ -260,19 +256,6 @@ fmt-check: fmt
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
.PHONY: fix
|
|
||||||
fix: ## apply automated fixes to Go code
|
|
||||||
$(GO) run $(GOPLS_MODERNIZE_PACKAGE) -fix ./...
|
|
||||||
|
|
||||||
.PHONY: fix-check
|
|
||||||
fix-check: fix
|
|
||||||
@diff=$$(git diff --color=always $(GO_SOURCES)); \
|
|
||||||
if [ -n "$$diff" ]; then \
|
|
||||||
echo "Please run 'make fix' and commit the result:"; \
|
|
||||||
printf "%s" "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: $(TAGS_EVIDENCE)
|
.PHONY: $(TAGS_EVIDENCE)
|
||||||
$(TAGS_EVIDENCE):
|
$(TAGS_EVIDENCE):
|
||||||
@mkdir -p $(MAKE_EVIDENCE_DIR)
|
@mkdir -p $(MAKE_EVIDENCE_DIR)
|
||||||
@ -285,7 +268,7 @@ endif
|
|||||||
.PHONY: generate-swagger
|
.PHONY: generate-swagger
|
||||||
generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
|
generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
|
||||||
|
|
||||||
$(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT)
|
$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC_INPUT)
|
||||||
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
|
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
|
||||||
|
|
||||||
.PHONY: swagger-check
|
.PHONY: swagger-check
|
||||||
@ -312,7 +295,7 @@ checks: checks-frontend checks-backend ## run various consistency checks
|
|||||||
checks-frontend: lockfile-check svg-check ## check frontend files
|
checks-frontend: lockfile-check svg-check ## check frontend files
|
||||||
|
|
||||||
.PHONY: checks-backend
|
.PHONY: checks-backend
|
||||||
checks-backend: tidy-check swagger-check fmt-check fix-check swagger-validate security-check ## check backend files
|
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-frontend lint-backend lint-spell ## lint everything
|
lint: lint-frontend lint-backend lint-spell ## lint everything
|
||||||
@ -390,7 +373,7 @@ lint-go-gitea-vet: ## lint go files with gitea-vet
|
|||||||
.PHONY: lint-go-gopls
|
.PHONY: lint-go-gopls
|
||||||
lint-go-gopls: ## lint go files with gopls
|
lint-go-gopls: ## lint go files with gopls
|
||||||
@echo "Running gopls check..."
|
@echo "Running gopls check..."
|
||||||
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES)
|
@GO=$(GO) GOPLS_PACKAGE=$(GOPLS_PACKAGE) tools/lint-go-gopls.sh $(GO_SOURCES_NO_BINDATA)
|
||||||
|
|
||||||
.PHONY: lint-editorconfig
|
.PHONY: lint-editorconfig
|
||||||
lint-editorconfig:
|
lint-editorconfig:
|
||||||
@ -404,11 +387,11 @@ lint-actions: ## lint action workflow files
|
|||||||
.PHONY: lint-templates
|
.PHONY: lint-templates
|
||||||
lint-templates: .venv node_modules ## lint template files
|
lint-templates: .venv node_modules ## lint template files
|
||||||
@node tools/lint-templates-svg.js
|
@node tools/lint-templates-svg.js
|
||||||
@uv run --frozen djlint $(shell find templates -type f -iname '*.tmpl')
|
@poetry run djlint $(shell find templates -type f -iname '*.tmpl')
|
||||||
|
|
||||||
.PHONY: lint-yaml
|
.PHONY: lint-yaml
|
||||||
lint-yaml: .venv ## lint yaml files
|
lint-yaml: .venv ## lint yaml files
|
||||||
@uv run --frozen yamllint -s .
|
@poetry run yamllint -s .
|
||||||
|
|
||||||
.PHONY: watch
|
.PHONY: watch
|
||||||
watch: ## watch everything and continuously rebuild
|
watch: ## watch everything and continuously rebuild
|
||||||
@ -757,10 +740,7 @@ security-check:
|
|||||||
go run $(GOVULNCHECK_PACKAGE) -show color ./...
|
go run $(GOVULNCHECK_PACKAGE) -show color ./...
|
||||||
|
|
||||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
|
||||||
$(error pam support set via TAGS doesn't support static builds)
|
|
||||||
endif
|
|
||||||
CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
|
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
|
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
|
||||||
@ -836,15 +816,14 @@ deps-tools: ## install tool dependencies
|
|||||||
$(GO) install $(GOVULNCHECK_PACKAGE) & \
|
$(GO) install $(GOVULNCHECK_PACKAGE) & \
|
||||||
$(GO) install $(ACTIONLINT_PACKAGE) & \
|
$(GO) install $(ACTIONLINT_PACKAGE) & \
|
||||||
$(GO) install $(GOPLS_PACKAGE) & \
|
$(GO) install $(GOPLS_PACKAGE) & \
|
||||||
$(GO) install $(GOPLS_MODERNIZE_PACKAGE) & \
|
|
||||||
wait
|
wait
|
||||||
|
|
||||||
node_modules: package-lock.json
|
node_modules: package-lock.json
|
||||||
npm install --no-save
|
npm install --no-save
|
||||||
@touch node_modules
|
@touch node_modules
|
||||||
|
|
||||||
.venv: uv.lock
|
.venv: poetry.lock
|
||||||
uv sync
|
poetry install
|
||||||
@touch .venv
|
@touch .venv
|
||||||
|
|
||||||
.PHONY: update
|
.PHONY: update
|
||||||
@ -862,8 +841,8 @@ update-js: node-check | node_modules ## update js dependencies
|
|||||||
.PHONY: update-py
|
.PHONY: update-py
|
||||||
update-py: node-check | node_modules ## update py dependencies
|
update-py: node-check | node_modules ## update py dependencies
|
||||||
npx updates -u -f pyproject.toml
|
npx updates -u -f pyproject.toml
|
||||||
rm -rf .venv uv.lock
|
rm -rf .venv poetry.lock
|
||||||
uv sync
|
poetry install
|
||||||
@touch .venv
|
@touch .venv
|
||||||
|
|
||||||
.PHONY: webpack
|
.PHONY: webpack
|
||||||
|
@ -80,9 +80,9 @@ Expected workflow is: Fork -> Patch -> Push -> Pull Request
|
|||||||
|
|
||||||
[](https://translate.gitea.com)
|
[](https://translate.gitea.com)
|
||||||
|
|
||||||
Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language, ask one of the managers in the Crowdin project to add a new language there.
|
Translations are done through [Crowdin](https://translate.gitea.com). If you want to translate to a new language ask one of the managers in the Crowdin project to add a new language there.
|
||||||
|
|
||||||
You can also just create an issue for adding a language or ask on Discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty, but we hope to fill it as questions pop up.
|
You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
|
||||||
|
|
||||||
Get more information from [documentation](https://docs.gitea.com/contributing/localization).
|
Get more information from [documentation](https://docs.gitea.com/contributing/localization).
|
||||||
|
|
||||||
|
54
SECURITY.md
54
SECURITY.md
@ -14,12 +14,12 @@ Please **DO NOT** file a public issue, instead send your report privately to `se
|
|||||||
|
|
||||||
Due to the sensitive nature of security information, you can use the below GPG public key to encrypt your mail body.
|
Due to the sensitive nature of security information, you can use the below GPG public key to encrypt your mail body.
|
||||||
|
|
||||||
The PGP key is valid until July 4, 2026.
|
The PGP key is valid until July 9, 2025.
|
||||||
|
|
||||||
```
|
```
|
||||||
Key ID: 6FCD2D5B
|
Key ID: 6FCD2D5B
|
||||||
Key Type: RSA
|
Key Type: RSA
|
||||||
Expires: 7/4/2026
|
Expires: 7/9/2025
|
||||||
Key Size: 4096/4096
|
Key Size: 4096/4096
|
||||||
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
|
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
|
||||||
```
|
```
|
||||||
@ -42,18 +42,18 @@ lzpAjnN9/KLtQroutrm+Ft0mdjDiJUeFVl1cOHDhoyfCsQh62HumoyZoZvqzQd6e
|
|||||||
AbN11nq6aViMe2Q3je1AbiBnRnQSHxt1Tc8X4IshO3MQK1Sk7oPI6LA5oQARAQAB
|
AbN11nq6aViMe2Q3je1AbiBnRnQSHxt1Tc8X4IshO3MQK1Sk7oPI6LA5oQARAQAB
|
||||||
tCJHaXRlYSBTZWN1cml0eSA8c2VjdXJpdHlAZ2l0ZWEuaW8+iQJXBBMBCABBAhsD
|
tCJHaXRlYSBTZWN1cml0eSA8c2VjdXJpdHlAZ2l0ZWEuaW8+iQJXBBMBCABBAhsD
|
||||||
BQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAFiEEPeA9HhRKfwaTWZncqv0jgW/N
|
BQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAFiEEPeA9HhRKfwaTWZncqv0jgW/N
|
||||||
LVsFAmhoHmkFCQeT6esACgkQqv0jgW/NLVuFLRAAmjBQSKRAgs2bFIEj7HLAbDp4
|
LVsFAmaMse0FCQW4fW8ACgkQqv0jgW/NLVtXLg/+PF4G9Jhlui15BTNlEBJAV2P/
|
||||||
f+XkdH+GsT3jRPOZ9QZgmtM+TfoE4yNgIVfOl+s4RdjM/W4QzqZuPQ55hbEHd056
|
1QlAV2krk0fP7tykn0FR9RfGIfVV/kwC1f+ouosYPQDDevl9LWdUIM+g94DtNo2o
|
||||||
cJmm7B+6GsHFcdrPmh65sOCEIyh4+t45dUfeWpFsDPqm9j1UHXAJQIpB8vDEVAPH
|
7ACpcL3morvt5lVGpIZHL8TbX0qmFRXL/pB/cB+K6IwYvh2mrbp2zH+r4SCRyFYq
|
||||||
t+3wLCk8GMPJs1o5tIyMmaO23ngvkwn8eG7KgY+rp2PzObrb5g7ppci0ILzILkrp
|
BjgXYFTI1MylJ1ShAjU6Z+m3oJ+2xs5LzHS0X6zkTjzA2Zl4zQzciQ9T+wJcE7Zi
|
||||||
HVjZsEfUWRgSVF7LuU5ppqDKrlcqwUpQq6n3kGMZcLrCp6ACKP04TBmTfUxNwdL7
|
HXdM1+YMF8KGNP8J9Rpug5oNDJ98lgZirRY7c3A/1xmYBiPnULwuuymdqEZO7l70
|
||||||
I0N7apI2Pbct9T1Gv/lYAUFWyU2c3gh/EBLbO6BukaLOFRQHrtNfdJV/YnMPlcXr
|
SeAlE1RWYX8kbOBnBb/KY4XwE3Vic1oEzc9DiPWVH1ElX86WNNsFzuyULiwoBoWg
|
||||||
LUJjK9K4eAH9DsrZqrisz/LthsC2BaNIN3KRMTk5YTYgmIh8GXzSgihORmtDFELC
|
pqZGhL9x1p5+46RGQSDczsHM7YGVtfYOiDo2PAVrmwsT0BnXnK8Oe3YIkvmUPEJu
|
||||||
RroID3pTuS0zjXh+wpY9GuPTh7UW23p42Daxca4fAT4k5EclvDRUrL21xMopPMiL
|
OkLt0Z6A5n8pz8zhQzuApwBsK4ncJ8zTCpvz/pfKKqZC/Vnoh3gKGhDGvOZ+b5IJ
|
||||||
HuNdELz4FVchRTy05PjzKVyjVInDNojE2KUxnjxZDzYJ6aT/g+coD5yfntYm8BEj
|
0kUTe2JsbnwFixDUMDtacQ1op8XOyLoLVmgqLn0+Pws4XPBlMof2bioFir3yHKnP
|
||||||
+ZzL0ndZES54hzKLpv7zwBQwFzam68clZYmDPILOPTflQDfpGEWmJK4undFU5obz
|
gNchsF1agrlSIo5GA8u4ga+IlCSfvFIKrl7+cxacKcJYt/vbOU5KcvVJI5EtHKCG
|
||||||
ZsQRz0R3ulspChATbZxO0d5LX2obLpKO9X3b5VoO1KF+R8Vjw1Y0KxrNZ6rIcfqH
|
xfHjHY2ah1Qww7SxW6IXiRZZzPpsL2mBM2CD7N3qh9bV2s27wxYCdUodsIZbiyHe
|
||||||
Z50QVQKSe9dm08K0ON+5Ag0EYrVn/gEQALrFLQjCR3GjuHSindz0rd3Fnx/t7Sen
|
oWPzfBnkmiAN8KlZxHm5Ag0EYrVn/gEQALrFLQjCR3GjuHSindz0rd3Fnx/t7Sen
|
||||||
T+p07yCSSoSlmnJHCQmwh4vfg1blyz0zZ4vkIhtpHsEgc+ZAG+WQXSsJ2iRz+eSN
|
T+p07yCSSoSlmnJHCQmwh4vfg1blyz0zZ4vkIhtpHsEgc+ZAG+WQXSsJ2iRz+eSN
|
||||||
GwoOQl4XC3n+QWkc1ws+btr48+6UqXIQU+F8TPQyx/PIgi2nZXJB7f5+mjCqsk46
|
GwoOQl4XC3n+QWkc1ws+btr48+6UqXIQU+F8TPQyx/PIgi2nZXJB7f5+mjCqsk46
|
||||||
XvH4nTr4kJjuqMSR/++wvre2qNQRa/q/dTsK0OaN/mJsdX6Oi+aGNaQJUhIG7F+E
|
XvH4nTr4kJjuqMSR/++wvre2qNQRa/q/dTsK0OaN/mJsdX6Oi+aGNaQJUhIG7F+E
|
||||||
@ -65,19 +65,19 @@ s+GsP9I3cmWWQcKYxWHtE8xTXnNCVPFZQj2nwhJzae8ypfOtulBRA3dUKWGKuDH/
|
|||||||
axFENhUsT397aOU3qkP/od4a64JyNIEo4CTTSPVeWd7njsGqli2U3A4xL2CcyYvt
|
axFENhUsT397aOU3qkP/od4a64JyNIEo4CTTSPVeWd7njsGqli2U3A4xL2CcyYvt
|
||||||
D/MWcMBGEoLSNTswwKdom4FaJpn5KThnK/T0bQcmJblJhoCtppXisbexZnCpuS0x
|
D/MWcMBGEoLSNTswwKdom4FaJpn5KThnK/T0bQcmJblJhoCtppXisbexZnCpuS0x
|
||||||
Zdlm2T14KJ3LABEBAAGJAjwEGAEIACYCGwwWIQQ94D0eFEp/BpNZmdyq/SOBb80t
|
Zdlm2T14KJ3LABEBAAGJAjwEGAEIACYCGwwWIQQ94D0eFEp/BpNZmdyq/SOBb80t
|
||||||
WwUCaGgeJAUJB5PppgAKCRCq/SOBb80tW/NWEACB6Jrf0gWlk7e+hNCdnbM0ZVWU
|
WwUCZoyyjQUJBbh+DwAKCRCq/SOBb80tW18XD/9MXztmf01MT+1kZdBouZ/7Rp/7
|
||||||
f2sHNFfXxxsdhpcDgKbNHtkZb8nZgv8AX+5fTtUwMVa3vKcdw30xFiIM5N7cCIPV
|
9kuqo//B1G+RXau4oFtPqb67kNe2WaIc3u5B73PUHsMf3i6z4ib2KbMhZZerLn0O
|
||||||
vg/5z5BtfEaitnabEUG2iiVDIy8IHXIcK10rX+7BosA3QDl2PsiBHwyi5G13lRk8
|
dRglcuPeNWmsASY3dH/XVG0cT0zvvWegagd12TJEl3Vs+7XNrOw4cwDj9L1+GH9m
|
||||||
zGTSNDuOalug33h5/lr2dPigamkq74Aoy29q8Rjad6GfWHipL2bFimgtY+Zdi0BH
|
kSt4uaANWn/6a3RvMRhiVEYuNwhAzcKaactPmYqrLJgoVLbRSDkgyHaMQ2jKgLxk
|
||||||
NLk4EJXxj1SgVx5dtkQzWJReBA5M+FQ4QYQZBO+f4TDoOLmjui152uhkoLBQbGAa
|
ifS/fvluGV0ub2Po6DJiqfRpd1tDvPhe9y1+r1WFDZsOcvTcZUfSt/7dXMGfqGu0
|
||||||
WWJFTVxm0bG5MXloEL3gA8DfU7XDwuW/sHJC5pBko8RpQViooOhckMepZV3Y83DK
|
2daVFlfeSXSALrDE5uc0UxodHCpP3sqRYDZevGLBRaaTkIjYXG/+N898+7K5WJF4
|
||||||
bwLYa3JmPgj2rEv4993dvrJbQhpGd082HOxOsllCs8pgNq1SnXpWYfcGTgGKC3ts
|
xXOLWxM2cwGkG7eC9pugcDnBp9XlF7O+GBiZ05JUe5flXDQFZ+h3exjopu6KHF1B
|
||||||
U8YZUUJUQ7mi2L8Tv3ix20c9EiGmA30JAmA8eZTC3cWup91ZkkVBFRml2czTXajd
|
RnzNy8LC0UKb+AuvRIOLV92a9Q9wGWU/jaVDu6nZ0umAeuSzxiHoDsonm0Fl9QAz
|
||||||
RWZ6GbHV5503ueDQcB8yBVgF3CSixs67+dGSbD3p86OqGrjAcJzM5TFbNKcnGLdE
|
2/xCokebuoeLrEK7R2af3X86mqq3sVO4ax+HPYChzOaVQBiHUW/TAldWcldYYphR
|
||||||
kGbZpNwAISy750lXzXKmyrh5RTCeTOQerbwCMBvHZO+HAevA/LXDTw2OAiSIQlP5
|
/e2WsbmQfvCRtz/bZfo+aUVnrHNjzVMtF2SszdVmA/04Y8pS28MqtuRqhm5DPOOd
|
||||||
sYA4sFYLQ30OAkgJcmdp/pSgVj/erNtSN07ClrOpDb/uFpQymO6K2h0Pst3feNVK
|
g1YeUywK5jRZ1twyo1kzJEFPLaoeaXaycsR1PMVBW0Urik5mrR/pOWq7PPoZoKb2
|
||||||
9M2VbqL9C51z/wyHLg==
|
lXYLE8bwkuQTmsyL1g==
|
||||||
=SfZA
|
=9i7d
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
|
||||||
```
|
```
|
||||||
|
16
assets/go-licenses.json
generated
16
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
11
build.go
11
build.go
@ -5,10 +5,19 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// Libraries that are included to vendor utilities used during Makefile build.
|
// Libraries that are included to vendor utilities used during build.
|
||||||
// These libraries will not be included in a normal compilation.
|
// These libraries will not be included in a normal compilation.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
// for embed
|
||||||
|
_ "github.com/shurcooL/vfsgen"
|
||||||
|
|
||||||
|
// for cover merge
|
||||||
|
_ "golang.org/x/tools/cover"
|
||||||
|
|
||||||
// for vet
|
// for vet
|
||||||
_ "code.gitea.io/gitea-vet"
|
_ "code.gitea.io/gitea-vet"
|
||||||
|
|
||||||
|
// for swagger
|
||||||
|
_ "github.com/go-swagger/go-swagger/cmd/swagger"
|
||||||
)
|
)
|
||||||
|
@ -6,22 +6,87 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/assetfs"
|
"github.com/shurcooL/vfsgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func needsUpdate(dir, filename string) (bool, []byte) {
|
||||||
if len(os.Args) != 3 {
|
needRegen := false
|
||||||
fmt.Println("usage: ./generate-bindata {local-directory} {bindata-filename}")
|
_, err := os.Stat(filename)
|
||||||
os.Exit(1)
|
if err != nil {
|
||||||
|
needRegen = true
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, filename := os.Args[1], os.Args[2]
|
oldHash, err := os.ReadFile(filename + ".hash")
|
||||||
fmt.Printf("generating bindata for %s to %s\n", dir, filename)
|
if err != nil {
|
||||||
if err := assetfs.GenerateEmbedBindata(dir, filename); err != nil {
|
oldHash = []byte{}
|
||||||
fmt.Printf("failed: %s\n", err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasher := sha1.New()
|
||||||
|
|
||||||
|
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := d.Info()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, _ = hasher.Write([]byte(d.Name()))
|
||||||
|
_, _ = hasher.Write([]byte(info.ModTime().String()))
|
||||||
|
_, _ = hasher.Write([]byte(strconv.FormatInt(info.Size(), 16)))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return true, oldHash
|
||||||
|
}
|
||||||
|
|
||||||
|
newHash := hasher.Sum([]byte{})
|
||||||
|
|
||||||
|
if bytes.Compare(oldHash, newHash) != 0 {
|
||||||
|
return true, newHash
|
||||||
|
}
|
||||||
|
|
||||||
|
return needRegen, newHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 4 {
|
||||||
|
log.Fatal("Insufficient number of arguments. Need: directory packageName filename")
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, packageName, filename := os.Args[1], os.Args[2], os.Args[3]
|
||||||
|
var useGlobalModTime bool
|
||||||
|
if len(os.Args) == 5 {
|
||||||
|
useGlobalModTime, _ = strconv.ParseBool(os.Args[4])
|
||||||
|
}
|
||||||
|
|
||||||
|
update, newHash := needsUpdate(dir, filename)
|
||||||
|
|
||||||
|
if !update {
|
||||||
|
fmt.Printf("bindata for %s already up-to-date\n", packageName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("generating bindata for %s\n", packageName)
|
||||||
|
var fsTemplates http.FileSystem = http.Dir(dir)
|
||||||
|
err := vfsgen.Generate(fsTemplates, vfsgen.Options{
|
||||||
|
PackageName: packageName,
|
||||||
|
BuildTags: "bindata",
|
||||||
|
VariableName: "Assets",
|
||||||
|
Filename: filename,
|
||||||
|
UseGlobalModTime: useGlobalModTime,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v\n", err)
|
||||||
|
}
|
||||||
|
_ = os.WriteFile(filename+".hash", newHash, 0o666)
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,7 +17,7 @@ var (
|
|||||||
CmdActions = &cli.Command{
|
CmdActions = &cli.Command{
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "Manage Gitea Actions",
|
Usage: "Manage Gitea Actions",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdActionsGenRunnerToken,
|
subcmdActionsGenRunnerToken,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -39,7 +38,10 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
|
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
scope := c.String("scope")
|
scope := c.String("scope")
|
||||||
|
43
cmd/admin.go
43
cmd/admin.go
@ -15,7 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -23,7 +23,7 @@ var (
|
|||||||
CmdAdmin = &cli.Command{
|
CmdAdmin = &cli.Command{
|
||||||
Name: "admin",
|
Name: "admin",
|
||||||
Usage: "Perform common administrative operations",
|
Usage: "Perform common administrative operations",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdUser,
|
subcmdUser,
|
||||||
subcmdRepoSyncReleases,
|
subcmdRepoSyncReleases,
|
||||||
subcmdRegenerate,
|
subcmdRegenerate,
|
||||||
@ -41,7 +41,7 @@ var (
|
|||||||
subcmdRegenerate = &cli.Command{
|
subcmdRegenerate = &cli.Command{
|
||||||
Name: "regenerate",
|
Name: "regenerate",
|
||||||
Usage: "Regenerate specific files",
|
Usage: "Regenerate specific files",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
microcmdRegenHooks,
|
microcmdRegenHooks,
|
||||||
microcmdRegenKeys,
|
microcmdRegenKeys,
|
||||||
},
|
},
|
||||||
@ -50,15 +50,15 @@ var (
|
|||||||
subcmdAuth = &cli.Command{
|
subcmdAuth = &cli.Command{
|
||||||
Name: "auth",
|
Name: "auth",
|
||||||
Usage: "Modify external auth providers",
|
Usage: "Modify external auth providers",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
microcmdAuthAddOauth(),
|
microcmdAuthAddOauth,
|
||||||
microcmdAuthUpdateOauth(),
|
microcmdAuthUpdateOauth,
|
||||||
microcmdAuthAddLdapBindDn(),
|
microcmdAuthAddLdapBindDn,
|
||||||
microcmdAuthUpdateLdapBindDn(),
|
microcmdAuthUpdateLdapBindDn,
|
||||||
microcmdAuthAddLdapSimpleAuth(),
|
microcmdAuthAddLdapSimpleAuth,
|
||||||
microcmdAuthUpdateLdapSimpleAuth(),
|
microcmdAuthUpdateLdapSimpleAuth,
|
||||||
microcmdAuthAddSMTP(),
|
microcmdAuthAddSMTP,
|
||||||
microcmdAuthUpdateSMTP(),
|
microcmdAuthUpdateSMTP,
|
||||||
microcmdAuthList,
|
microcmdAuthList,
|
||||||
microcmdAuthDelete,
|
microcmdAuthDelete,
|
||||||
},
|
},
|
||||||
@ -70,9 +70,9 @@ var (
|
|||||||
Action: runSendMail,
|
Action: runSendMail,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "title",
|
Name: "title",
|
||||||
Usage: "a title of a message",
|
Usage: `a title of a message`,
|
||||||
Required: true,
|
Value: "",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "content",
|
Name: "content",
|
||||||
@ -86,16 +86,17 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func idFlag() *cli.Int64Flag {
|
idFlag = &cli.Int64Flag{
|
||||||
return &cli.Int64Flag{
|
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Usage: "ID of authentication source",
|
Usage: "ID of authentication source",
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
|
func runRepoSyncReleases(_ *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -106,7 +107,7 @@ func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
|
|||||||
|
|
||||||
log.Trace("Synchronizing repository releases (this may take a while)")
|
log.Trace("Synchronizing repository releases (this may take a while)")
|
||||||
for page := 1; ; page++ {
|
for page := 1; ; page++ {
|
||||||
repos, count, err := repo_model.SearchRepositoryByName(ctx, repo_model.SearchRepoOptions{
|
repos, count, err := repo_model.SearchRepositoryByName(ctx, &repo_model.SearchRepoOptions{
|
||||||
ListOptions: db.ListOptions{
|
ListOptions: db.ListOptions{
|
||||||
PageSize: repo_model.RepositoryListDefaultPageSize,
|
PageSize: repo_model.RepositoryListDefaultPageSize,
|
||||||
Page: page,
|
Page: page,
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -14,14 +13,14 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
auth_service "code.gitea.io/gitea/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
microcmdAuthDelete = &cli.Command{
|
microcmdAuthDelete = &cli.Command{
|
||||||
Name: "delete",
|
Name: "delete",
|
||||||
Usage: "Delete specific auth source",
|
Usage: "Delete specific auth source",
|
||||||
Flags: []cli.Flag{idFlag()},
|
Flags: []cli.Flag{idFlag},
|
||||||
Action: runDeleteAuth,
|
Action: runDeleteAuth,
|
||||||
}
|
}
|
||||||
microcmdAuthList = &cli.Command{
|
microcmdAuthList = &cli.Command{
|
||||||
@ -57,7 +56,10 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runListAuth(ctx context.Context, c *cli.Command) error {
|
func runListAuth(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -88,11 +90,14 @@ func runListAuth(ctx context.Context, c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteAuth(ctx context.Context, c *cli.Command) error {
|
func runDeleteAuth(c *cli.Context) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/auth/source/ldap"
|
"code.gitea.io/gitea/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@ -24,8 +24,8 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func commonLdapCLIFlags() []cli.Flag {
|
var (
|
||||||
return []cli.Flag{
|
commonLdapCLIFlags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Usage: "Authentication name.",
|
Usage: "Authentication name.",
|
||||||
@ -103,10 +103,8 @@ func commonLdapCLIFlags() []cli.Flag {
|
|||||||
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
|
Usage: "The attribute of the user’s LDAP record containing the user’s avatar.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func ldapBindDnCLIFlags() []cli.Flag {
|
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
|
||||||
return append(commonLdapCLIFlags(),
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "bind-dn",
|
Name: "bind-dn",
|
||||||
Usage: "The DN to bind to the LDAP server with when searching for the user.",
|
Usage: "The DN to bind to the LDAP server with when searching for the user.",
|
||||||
@ -159,59 +157,49 @@ func ldapBindDnCLIFlags() []cli.Flag {
|
|||||||
Name: "group-team-map-removal",
|
Name: "group-team-map-removal",
|
||||||
Usage: "Remove users from synchronized teams if user does not belong to corresponding LDAP group",
|
Usage: "Remove users from synchronized teams if user does not belong to corresponding LDAP group",
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
func ldapSimpleAuthCLIFlags() []cli.Flag {
|
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
|
||||||
return append(commonLdapCLIFlags(),
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "user-dn",
|
Name: "user-dn",
|
||||||
Usage: "The user's DN.",
|
Usage: "The user's DN.",
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthAddLdapBindDn() *cli.Command {
|
microcmdAuthAddLdapBindDn = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "add-ldap",
|
Name: "add-ldap",
|
||||||
Usage: "Add new LDAP (via Bind DN) authentication source",
|
Usage: "Add new LDAP (via Bind DN) authentication source",
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().addLdapBindDn(ctx, cmd)
|
return newAuthService().addLdapBindDn(c)
|
||||||
},
|
},
|
||||||
Flags: ldapBindDnCLIFlags(),
|
Flags: ldapBindDnCLIFlags,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthUpdateLdapBindDn() *cli.Command {
|
microcmdAuthUpdateLdapBindDn = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "update-ldap",
|
Name: "update-ldap",
|
||||||
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
Usage: "Update existing LDAP (via Bind DN) authentication source",
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().updateLdapBindDn(ctx, cmd)
|
return newAuthService().updateLdapBindDn(c)
|
||||||
},
|
},
|
||||||
Flags: append([]cli.Flag{idFlag()}, ldapBindDnCLIFlags()...),
|
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthAddLdapSimpleAuth() *cli.Command {
|
microcmdAuthAddLdapSimpleAuth = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "add-ldap-simple",
|
Name: "add-ldap-simple",
|
||||||
Usage: "Add new LDAP (simple auth) authentication source",
|
Usage: "Add new LDAP (simple auth) authentication source",
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().addLdapSimpleAuth(ctx, cmd)
|
return newAuthService().addLdapSimpleAuth(c)
|
||||||
},
|
},
|
||||||
Flags: ldapSimpleAuthCLIFlags(),
|
Flags: ldapSimpleAuthCLIFlags,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthUpdateLdapSimpleAuth() *cli.Command {
|
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "update-ldap-simple",
|
Name: "update-ldap-simple",
|
||||||
Usage: "Update existing LDAP (simple auth) authentication source",
|
Usage: "Update existing LDAP (simple auth) authentication source",
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().updateLdapSimpleAuth(ctx, cmd)
|
return newAuthService().updateLdapSimpleAuth(c)
|
||||||
},
|
},
|
||||||
Flags: append([]cli.Flag{idFlag()}, ldapSimpleAuthCLIFlags()...),
|
Flags: append([]cli.Flag{idFlag}, ldapSimpleAuthCLIFlags...),
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
// newAuthService creates a service with default functions.
|
// newAuthService creates a service with default functions.
|
||||||
func newAuthService() *authService {
|
func newAuthService() *authService {
|
||||||
@ -224,7 +212,7 @@ func newAuthService() *authService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseAuthSourceLdap assigns values on authSource according to command line flags.
|
// parseAuthSourceLdap assigns values on authSource according to command line flags.
|
||||||
func parseAuthSourceLdap(c *cli.Command, authSource *auth.Source) {
|
func parseAuthSourceLdap(c *cli.Context, authSource *auth.Source) {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
authSource.Name = c.String("name")
|
authSource.Name = c.String("name")
|
||||||
}
|
}
|
||||||
@ -244,7 +232,7 @@ func parseAuthSourceLdap(c *cli.Command, authSource *auth.Source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseLdapConfig assigns values on config according to command line flags.
|
// parseLdapConfig assigns values on config according to command line flags.
|
||||||
func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
|
func parseLdapConfig(c *cli.Context, config *ldap.Source) error {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
config.Name = c.String("name")
|
config.Name = c.String("name")
|
||||||
}
|
}
|
||||||
@ -257,7 +245,7 @@ func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
|
|||||||
if c.IsSet("security-protocol") {
|
if c.IsSet("security-protocol") {
|
||||||
p, ok := findLdapSecurityProtocolByName(c.String("security-protocol"))
|
p, ok := findLdapSecurityProtocolByName(c.String("security-protocol"))
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unknown security protocol name: %s", c.String("security-protocol"))
|
return fmt.Errorf("Unknown security protocol name: %s", c.String("security-protocol"))
|
||||||
}
|
}
|
||||||
config.SecurityProtocol = p
|
config.SecurityProtocol = p
|
||||||
}
|
}
|
||||||
@ -349,27 +337,32 @@ func findLdapSecurityProtocolByName(name string) (ldap.SecurityProtocol, bool) {
|
|||||||
|
|
||||||
// getAuthSource gets the login source by its id defined in the command line flags.
|
// getAuthSource gets the login source by its id defined in the command line flags.
|
||||||
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
|
// It returns an error if the id is not set, does not match any source or if the source is not of expected type.
|
||||||
func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authType auth.Type) (*auth.Source, error) {
|
func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, authType auth.Type) (*auth.Source, error) {
|
||||||
if err := argsSet(c, "id"); err != nil {
|
if err := argsSet(c, "id"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
authSource, err := a.getAuthSourceByID(ctx, c.Int64("id"))
|
authSource, err := a.getAuthSourceByID(ctx, c.Int64("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if authSource.Type != authType {
|
if authSource.Type != authType {
|
||||||
return nil, fmt.Errorf("invalid authentication type. expected: %s, actual: %s", authType.String(), authSource.Type.String())
|
return nil, fmt.Errorf("Invalid authentication type. expected: %s, actual: %s", authType.String(), authSource.Type.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
return authSource, nil
|
return authSource, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
|
// addLdapBindDn adds a new LDAP via Bind DN authentication source.
|
||||||
func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error {
|
func (a *authService) addLdapBindDn(c *cli.Context) error {
|
||||||
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
|
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-search-base", "user-filter", "email-attribute"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -391,7 +384,10 @@ func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
|
// updateLdapBindDn updates a new LDAP via Bind DN authentication source.
|
||||||
func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) error {
|
func (a *authService) updateLdapBindDn(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -410,11 +406,14 @@ func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
|
||||||
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil {
|
if err := argsSet(c, "name", "security-protocol", "host", "port", "user-dn", "user-filter", "email-attribute"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -436,7 +435,10 @@ func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,17 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/auth"
|
"code.gitea.io/gitea/models/auth"
|
||||||
"code.gitea.io/gitea/modules/test"
|
|
||||||
"code.gitea.io/gitea/services/auth/source/ldap"
|
"code.gitea.io/gitea/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddLdapBindDn(t *testing.T) {
|
func TestAddLdapBindDn(t *testing.T) {
|
||||||
// Mock cli functions to do not exit on error
|
// Mock cli functions to do not exit on error
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
osExiter := cli.OsExiter
|
||||||
|
defer func() { cli.OsExiter = osExiter }()
|
||||||
|
cli.OsExiter = func(code int) {}
|
||||||
|
|
||||||
// Test cases
|
// Test cases
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -134,7 +135,7 @@ func TestAddLdapBindDn(t *testing.T) {
|
|||||||
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
|
"--user-filter", "(memberOf=cn=user-group,ou=example,dc=domain,dc=org)",
|
||||||
"--email-attribute", "mail",
|
"--email-attribute", "mail",
|
||||||
},
|
},
|
||||||
errMsg: "unknown security protocol name: zzzzz",
|
errMsg: "Unknown security protocol name: zzzzz",
|
||||||
},
|
},
|
||||||
// case 3
|
// case 3
|
||||||
{
|
{
|
||||||
@ -238,13 +239,12 @@ func TestAddLdapBindDn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.Command{
|
app := cli.NewApp()
|
||||||
Flags: microcmdAuthAddLdapBindDn().Flags,
|
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
||||||
Action: service.addLdapBindDn,
|
app.Action = service.addLdapBindDn
|
||||||
}
|
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(t.Context(), c.args)
|
err := app.Run(c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
@ -256,7 +256,9 @@ func TestAddLdapBindDn(t *testing.T) {
|
|||||||
|
|
||||||
func TestAddLdapSimpleAuth(t *testing.T) {
|
func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
// Mock cli functions to do not exit on error
|
// Mock cli functions to do not exit on error
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
osExiter := cli.OsExiter
|
||||||
|
defer func() { cli.OsExiter = osExiter }()
|
||||||
|
cli.OsExiter = func(code int) {}
|
||||||
|
|
||||||
// Test cases
|
// Test cases
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -346,12 +348,12 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
|||||||
"--name", "ldap (simple auth) source",
|
"--name", "ldap (simple auth) source",
|
||||||
"--security-protocol", "zzzzz",
|
"--security-protocol", "zzzzz",
|
||||||
"--host", "ldap-server",
|
"--host", "ldap-server",
|
||||||
"--port", "1234",
|
"--port", "123",
|
||||||
"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
|
"--user-filter", "(&(objectClass=posixAccount)(cn=%s))",
|
||||||
"--email-attribute", "mail",
|
"--email-attribute", "mail",
|
||||||
"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
|
"--user-dn", "cn=%s,ou=Users,dc=domain,dc=org",
|
||||||
},
|
},
|
||||||
errMsg: "unknown security protocol name: zzzzz",
|
errMsg: "Unknown security protocol name: zzzzz",
|
||||||
},
|
},
|
||||||
// case 3
|
// case 3
|
||||||
{
|
{
|
||||||
@ -468,13 +470,12 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := &cli.Command{
|
app := cli.NewApp()
|
||||||
Flags: microcmdAuthAddLdapSimpleAuth().Flags,
|
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
||||||
Action: service.addLdapSimpleAuth,
|
app.Action = service.addLdapSimpleAuth
|
||||||
}
|
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(t.Context(), c.args)
|
err := app.Run(c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
@ -486,7 +487,9 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
|||||||
|
|
||||||
func TestUpdateLdapBindDn(t *testing.T) {
|
func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
// Mock cli functions to do not exit on error
|
// Mock cli functions to do not exit on error
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
osExiter := cli.OsExiter
|
||||||
|
defer func() { cli.OsExiter = osExiter }()
|
||||||
|
cli.OsExiter = func(code int) {}
|
||||||
|
|
||||||
// Test cases
|
// Test cases
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -861,7 +864,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||||||
"--id", "1",
|
"--id", "1",
|
||||||
"--security-protocol", "xxxxx",
|
"--security-protocol", "xxxxx",
|
||||||
},
|
},
|
||||||
errMsg: "unknown security protocol name: xxxxx",
|
errMsg: "Unknown security protocol name: xxxxx",
|
||||||
},
|
},
|
||||||
// case 22
|
// case 22
|
||||||
{
|
{
|
||||||
@ -880,7 +883,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||||||
Type: auth.OAuth2,
|
Type: auth.OAuth2,
|
||||||
Cfg: &ldap.Source{},
|
Cfg: &ldap.Source{},
|
||||||
},
|
},
|
||||||
errMsg: "invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2",
|
errMsg: "Invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2",
|
||||||
},
|
},
|
||||||
// case 24
|
// case 24
|
||||||
{
|
{
|
||||||
@ -944,12 +947,12 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.Command{
|
app := cli.NewApp()
|
||||||
Flags: microcmdAuthUpdateLdapBindDn().Flags,
|
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
||||||
Action: service.updateLdapBindDn,
|
app.Action = service.updateLdapBindDn
|
||||||
}
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(t.Context(), c.args)
|
err := app.Run(c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
@ -961,7 +964,9 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||||||
|
|
||||||
func TestUpdateLdapSimpleAuth(t *testing.T) {
|
func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
// Mock cli functions to do not exit on error
|
// Mock cli functions to do not exit on error
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
osExiter := cli.OsExiter
|
||||||
|
defer func() { cli.OsExiter = osExiter }()
|
||||||
|
cli.OsExiter = func(code int) {}
|
||||||
|
|
||||||
// Test cases
|
// Test cases
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -1252,7 +1257,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
|||||||
"--id", "1",
|
"--id", "1",
|
||||||
"--security-protocol", "xxxxx",
|
"--security-protocol", "xxxxx",
|
||||||
},
|
},
|
||||||
errMsg: "unknown security protocol name: xxxxx",
|
errMsg: "Unknown security protocol name: xxxxx",
|
||||||
},
|
},
|
||||||
// case 18
|
// case 18
|
||||||
{
|
{
|
||||||
@ -1271,7 +1276,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
|||||||
Type: auth.PAM,
|
Type: auth.PAM,
|
||||||
Cfg: &ldap.Source{},
|
Cfg: &ldap.Source{},
|
||||||
},
|
},
|
||||||
errMsg: "invalid authentication type. expected: LDAP (simple auth), actual: PAM",
|
errMsg: "Invalid authentication type. expected: LDAP (simple auth), actual: PAM",
|
||||||
},
|
},
|
||||||
// case 20
|
// case 20
|
||||||
{
|
{
|
||||||
@ -1332,12 +1337,12 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.Command{
|
app := cli.NewApp()
|
||||||
Flags: microcmdAuthUpdateLdapSimpleAuth().Flags,
|
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
||||||
Action: service.updateLdapSimpleAuth,
|
app.Action = service.updateLdapSimpleAuth
|
||||||
}
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(t.Context(), c.args)
|
err := app.Run(c.args)
|
||||||
if c.errMsg != "" {
|
if c.errMsg != "" {
|
||||||
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
assert.EqualError(t, err, c.errMsg, "case %d: error should match", n)
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -13,11 +12,11 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func oauthCLIFlags() []cli.Flag {
|
var (
|
||||||
return []cli.Flag{
|
oauthCLIFlags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
@ -87,14 +86,6 @@ func oauthCLIFlags() []cli.Flag {
|
|||||||
Value: nil,
|
Value: nil,
|
||||||
Usage: "Scopes to request when to authenticate against this OAuth2 source",
|
Usage: "Scopes to request when to authenticate against this OAuth2 source",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "ssh-public-key-claim-name",
|
|
||||||
Usage: "Claim name that provides SSH public keys",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "full-name-claim-name",
|
|
||||||
Usage: "Claim name that provides user's full name",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "required-claim-name",
|
Name: "required-claim-name",
|
||||||
Value: "",
|
Value: "",
|
||||||
@ -130,34 +121,23 @@ func oauthCLIFlags() []cli.Flag {
|
|||||||
Usage: "Activate automatic team membership removal depending on groups",
|
Usage: "Activate automatic team membership removal depending on groups",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthAddOauth() *cli.Command {
|
microcmdAuthAddOauth = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "add-oauth",
|
||||||
Name: "add-oauth",
|
Usage: "Add new Oauth authentication source",
|
||||||
Usage: "Add new Oauth authentication source",
|
Action: runAddOauth,
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Flags: oauthCLIFlags,
|
||||||
return newAuthService().runAddOauth(ctx, cmd)
|
|
||||||
},
|
|
||||||
Flags: oauthCLIFlags(),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthUpdateOauth() *cli.Command {
|
microcmdAuthUpdateOauth = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "update-oauth",
|
||||||
Name: "update-oauth",
|
Usage: "Update existing Oauth authentication source",
|
||||||
Usage: "Update existing Oauth authentication source",
|
Action: runUpdateOauth,
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
||||||
return newAuthService().runUpdateOauth(ctx, cmd)
|
|
||||||
},
|
|
||||||
Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{&cli.Int64Flag{
|
|
||||||
Name: "id",
|
|
||||||
Usage: "ID of authentication source",
|
|
||||||
}}, oauthCLIFlags()[1:]...)...),
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func parseOAuth2Config(c *cli.Command) *oauth2.Source {
|
func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||||
var customURLMapping *oauth2.CustomURLMapping
|
var customURLMapping *oauth2.CustomURLMapping
|
||||||
if c.IsSet("use-custom-urls") {
|
if c.IsSet("use-custom-urls") {
|
||||||
customURLMapping = &oauth2.CustomURLMapping{
|
customURLMapping = &oauth2.CustomURLMapping{
|
||||||
@ -185,13 +165,14 @@ func parseOAuth2Config(c *cli.Command) *oauth2.Source {
|
|||||||
RestrictedGroup: c.String("restricted-group"),
|
RestrictedGroup: c.String("restricted-group"),
|
||||||
GroupTeamMap: c.String("group-team-map"),
|
GroupTeamMap: c.String("group-team-map"),
|
||||||
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
|
GroupTeamMapRemoval: c.Bool("group-team-map-removal"),
|
||||||
SSHPublicKeyClaimName: c.String("ssh-public-key-claim-name"),
|
|
||||||
FullNameClaimName: c.String("full-name-claim-name"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authService) runAddOauth(ctx context.Context, c *cli.Command) error {
|
func runAddOauth(c *cli.Context) error {
|
||||||
if err := a.initDB(ctx); err != nil {
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +184,7 @@ func (a *authService) runAddOauth(ctx context.Context, c *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.createAuthSource(ctx, &auth_model.Source{
|
return auth_model.CreateSource(ctx, &auth_model.Source{
|
||||||
Type: auth_model.OAuth2,
|
Type: auth_model.OAuth2,
|
||||||
Name: c.String("name"),
|
Name: c.String("name"),
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
@ -212,16 +193,19 @@ func (a *authService) runAddOauth(ctx context.Context, c *cli.Command) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error {
|
func runUpdateOauth(c *cli.Context) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
source, err := a.getAuthSourceByID(ctx, c.Int64("id"))
|
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -278,12 +262,6 @@ func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error
|
|||||||
if c.IsSet("group-team-map-removal") {
|
if c.IsSet("group-team-map-removal") {
|
||||||
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
|
oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal")
|
||||||
}
|
}
|
||||||
if c.IsSet("ssh-public-key-claim-name") {
|
|
||||||
oAuth2Config.SSHPublicKeyClaimName = c.String("ssh-public-key-claim-name")
|
|
||||||
}
|
|
||||||
if c.IsSet("full-name-claim-name") {
|
|
||||||
oAuth2Config.FullNameClaimName = c.String("full-name-claim-name")
|
|
||||||
}
|
|
||||||
|
|
||||||
// update custom URL mapping
|
// update custom URL mapping
|
||||||
customURLMapping := &oauth2.CustomURLMapping{}
|
customURLMapping := &oauth2.CustomURLMapping{}
|
||||||
@ -318,5 +296,5 @@ func (a *authService) runUpdateOauth(ctx context.Context, c *cli.Command) error
|
|||||||
oAuth2Config.CustomURLMapping = customURLMapping
|
oAuth2Config.CustomURLMapping = customURLMapping
|
||||||
source.Cfg = oAuth2Config
|
source.Cfg = oAuth2Config
|
||||||
source.TwoFactorPolicy = util.Iif(c.Bool("skip-local-2fa"), "skip", "")
|
source.TwoFactorPolicy = util.Iif(c.Bool("skip-local-2fa"), "skip", "")
|
||||||
return a.updateAuthSource(ctx, source)
|
return auth_model.UpdateSource(ctx, source)
|
||||||
}
|
}
|
||||||
|
@ -1,343 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
|
||||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAddOauth(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
source *auth_model.Source
|
|
||||||
errMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "valid config",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--provider", "github",
|
|
||||||
"--key", "some_key",
|
|
||||||
"--secret", "some_secret",
|
|
||||||
},
|
|
||||||
source: &auth_model.Source{
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Scopes: []string{},
|
|
||||||
Provider: "github",
|
|
||||||
ClientID: "some_key",
|
|
||||||
ClientSecret: "some_secret",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with openid connect",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--provider", "openidConnect",
|
|
||||||
"--key", "some_key",
|
|
||||||
"--secret", "some_secret",
|
|
||||||
"--auto-discover-url", "https://example.com",
|
|
||||||
},
|
|
||||||
source: &auth_model.Source{
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Scopes: []string{},
|
|
||||||
Provider: "openidConnect",
|
|
||||||
ClientID: "some_key",
|
|
||||||
ClientSecret: "some_secret",
|
|
||||||
OpenIDConnectAutoDiscoveryURL: "https://example.com",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with options",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--provider", "gitlab",
|
|
||||||
"--key", "some_key",
|
|
||||||
"--secret", "some_secret",
|
|
||||||
"--use-custom-urls", "true",
|
|
||||||
"--custom-token-url", "https://example.com/token",
|
|
||||||
"--custom-auth-url", "https://example.com/auth",
|
|
||||||
"--custom-profile-url", "https://example.com/profile",
|
|
||||||
"--custom-email-url", "https://example.com/email",
|
|
||||||
"--custom-tenant-id", "some_tenant",
|
|
||||||
"--icon-url", "https://example.com/icon",
|
|
||||||
"--scopes", "scope1,scope2",
|
|
||||||
"--skip-local-2fa", "true",
|
|
||||||
"--required-claim-name", "claim_name",
|
|
||||||
"--required-claim-value", "claim_value",
|
|
||||||
"--group-claim-name", "group_name",
|
|
||||||
"--admin-group", "admin",
|
|
||||||
"--restricted-group", "restricted",
|
|
||||||
"--group-team-map", `{"group1": [1,2]}`,
|
|
||||||
"--group-team-map-removal=true",
|
|
||||||
"--ssh-public-key-claim-name", "attr_ssh_pub_key",
|
|
||||||
"--full-name-claim-name", "attr_full_name",
|
|
||||||
},
|
|
||||||
source: &auth_model.Source{
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Provider: "gitlab",
|
|
||||||
ClientID: "some_key",
|
|
||||||
ClientSecret: "some_secret",
|
|
||||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
|
||||||
TokenURL: "https://example.com/token",
|
|
||||||
AuthURL: "https://example.com/auth",
|
|
||||||
ProfileURL: "https://example.com/profile",
|
|
||||||
EmailURL: "https://example.com/email",
|
|
||||||
Tenant: "some_tenant",
|
|
||||||
},
|
|
||||||
IconURL: "https://example.com/icon",
|
|
||||||
Scopes: []string{"scope1", "scope2"},
|
|
||||||
RequiredClaimName: "claim_name",
|
|
||||||
RequiredClaimValue: "claim_value",
|
|
||||||
GroupClaimName: "group_name",
|
|
||||||
AdminGroup: "admin",
|
|
||||||
RestrictedGroup: "restricted",
|
|
||||||
GroupTeamMap: `{"group1": [1,2]}`,
|
|
||||||
GroupTeamMapRemoval: true,
|
|
||||||
SSHPublicKeyClaimName: "attr_ssh_pub_key",
|
|
||||||
FullNameClaimName: "attr_full_name",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "skip",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
var createdSource *auth_model.Source
|
|
||||||
a := &authService{
|
|
||||||
initDB: func(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
createAuthSource: func(ctx context.Context, source *auth_model.Source) error {
|
|
||||||
createdSource = source
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
app := &cli.Command{
|
|
||||||
Flags: microcmdAuthAddOauth().Flags,
|
|
||||||
Action: a.runAddOauth,
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"oauth-test"}
|
|
||||||
args = append(args, tc.args...)
|
|
||||||
|
|
||||||
err := app.Run(t.Context(), args)
|
|
||||||
|
|
||||||
if tc.errMsg != "" {
|
|
||||||
assert.EqualError(t, err, tc.errMsg)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tc.source, createdSource)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateOauth(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
id int64
|
|
||||||
existingAuthSource *auth_model.Source
|
|
||||||
authSource *auth_model.Source
|
|
||||||
errMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "missing id",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
},
|
|
||||||
errMsg: "--id flag is missing",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config",
|
|
||||||
id: 1,
|
|
||||||
existingAuthSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "old name",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Provider: "github",
|
|
||||||
ClientID: "old_key",
|
|
||||||
ClientSecret: "old_secret",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
args: []string{
|
|
||||||
"--id", "1",
|
|
||||||
"--name", "test",
|
|
||||||
"--provider", "gitlab",
|
|
||||||
"--key", "new_key",
|
|
||||||
"--secret", "new_secret",
|
|
||||||
},
|
|
||||||
authSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Provider: "gitlab",
|
|
||||||
ClientID: "new_key",
|
|
||||||
ClientSecret: "new_secret",
|
|
||||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with options",
|
|
||||||
id: 1,
|
|
||||||
existingAuthSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "old name",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Provider: "gitlab",
|
|
||||||
ClientID: "old_key",
|
|
||||||
ClientSecret: "old_secret",
|
|
||||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
|
||||||
TokenURL: "https://old.example.com/token",
|
|
||||||
AuthURL: "https://old.example.com/auth",
|
|
||||||
ProfileURL: "https://old.example.com/profile",
|
|
||||||
EmailURL: "https://old.example.com/email",
|
|
||||||
Tenant: "old_tenant",
|
|
||||||
},
|
|
||||||
IconURL: "https://old.example.com/icon",
|
|
||||||
Scopes: []string{"old_scope1", "old_scope2"},
|
|
||||||
RequiredClaimName: "old_claim_name",
|
|
||||||
RequiredClaimValue: "old_claim_value",
|
|
||||||
GroupClaimName: "old_group_name",
|
|
||||||
AdminGroup: "old_admin",
|
|
||||||
RestrictedGroup: "old_restricted",
|
|
||||||
GroupTeamMap: `{"old_group1": [1,2]}`,
|
|
||||||
GroupTeamMapRemoval: true,
|
|
||||||
SSHPublicKeyClaimName: "old_ssh_pub_key",
|
|
||||||
FullNameClaimName: "old_full_name",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
args: []string{
|
|
||||||
"--id", "1",
|
|
||||||
"--name", "test",
|
|
||||||
"--provider", "github",
|
|
||||||
"--key", "new_key",
|
|
||||||
"--secret", "new_secret",
|
|
||||||
"--use-custom-urls", "true",
|
|
||||||
"--custom-token-url", "https://example.com/token",
|
|
||||||
"--custom-auth-url", "https://example.com/auth",
|
|
||||||
"--custom-profile-url", "https://example.com/profile",
|
|
||||||
"--custom-email-url", "https://example.com/email",
|
|
||||||
"--custom-tenant-id", "new_tenant",
|
|
||||||
"--icon-url", "https://example.com/icon",
|
|
||||||
"--scopes", "scope1,scope2",
|
|
||||||
"--skip-local-2fa=true",
|
|
||||||
"--required-claim-name", "claim_name",
|
|
||||||
"--required-claim-value", "claim_value",
|
|
||||||
"--group-claim-name", "group_name",
|
|
||||||
"--admin-group", "admin",
|
|
||||||
"--restricted-group", "restricted",
|
|
||||||
"--group-team-map", `{"group1": [1,2]}`,
|
|
||||||
"--group-team-map-removal=false",
|
|
||||||
"--ssh-public-key-claim-name", "new_ssh_pub_key",
|
|
||||||
"--full-name-claim-name", "new_full_name",
|
|
||||||
},
|
|
||||||
authSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
Provider: "github",
|
|
||||||
ClientID: "new_key",
|
|
||||||
ClientSecret: "new_secret",
|
|
||||||
CustomURLMapping: &oauth2.CustomURLMapping{
|
|
||||||
TokenURL: "https://example.com/token",
|
|
||||||
AuthURL: "https://example.com/auth",
|
|
||||||
ProfileURL: "https://example.com/profile",
|
|
||||||
EmailURL: "https://example.com/email",
|
|
||||||
Tenant: "new_tenant",
|
|
||||||
},
|
|
||||||
IconURL: "https://example.com/icon",
|
|
||||||
Scopes: []string{"scope1", "scope2"},
|
|
||||||
RequiredClaimName: "claim_name",
|
|
||||||
RequiredClaimValue: "claim_value",
|
|
||||||
GroupClaimName: "group_name",
|
|
||||||
AdminGroup: "admin",
|
|
||||||
RestrictedGroup: "restricted",
|
|
||||||
GroupTeamMap: `{"group1": [1,2]}`,
|
|
||||||
GroupTeamMapRemoval: false,
|
|
||||||
SSHPublicKeyClaimName: "new_ssh_pub_key",
|
|
||||||
FullNameClaimName: "new_full_name",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "skip",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
a := &authService{
|
|
||||||
initDB: func(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth_model.Source, error) {
|
|
||||||
return &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.OAuth2,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &oauth2.Source{
|
|
||||||
CustomURLMapping: &oauth2.CustomURLMapping{},
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "skip",
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
updateAuthSource: func(ctx context.Context, source *auth_model.Source) error {
|
|
||||||
assert.Equal(t, tc.authSource, source)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
app := &cli.Command{
|
|
||||||
Flags: microcmdAuthUpdateOauth().Flags,
|
|
||||||
Action: a.runUpdateOauth,
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"oauth-test"}
|
|
||||||
args = append(args, tc.args...)
|
|
||||||
|
|
||||||
err := app.Run(t.Context(), args)
|
|
||||||
|
|
||||||
if tc.errMsg != "" {
|
|
||||||
assert.EqualError(t, err, tc.errMsg)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,271 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
|
||||||
"code.gitea.io/gitea/services/auth/source/smtp"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAddSMTP(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
source *auth_model.Source
|
|
||||||
errMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "missing name",
|
|
||||||
args: []string{
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
},
|
|
||||||
errMsg: "name must be set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing host",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--port", "25",
|
|
||||||
},
|
|
||||||
errMsg: "host must be set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing port",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
},
|
|
||||||
errMsg: "port must be set",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
},
|
|
||||||
source: &auth_model.Source{
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "PLAIN",
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 25,
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with options",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
"--auth-type", "LOGIN",
|
|
||||||
"--force-smtps",
|
|
||||||
"--skip-verify",
|
|
||||||
"--helo-hostname", "example.com",
|
|
||||||
"--disable-helo=true",
|
|
||||||
"--allowed-domains", "example.com,example.org",
|
|
||||||
"--skip-local-2fa",
|
|
||||||
"--active=false",
|
|
||||||
},
|
|
||||||
source: &auth_model.Source{
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: false,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "LOGIN",
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 25,
|
|
||||||
ForceSMTPS: true,
|
|
||||||
SkipVerify: true,
|
|
||||||
HeloHostname: "example.com",
|
|
||||||
DisableHelo: true,
|
|
||||||
AllowedDomains: "example.com,example.org",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "skip",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
a := &authService{
|
|
||||||
initDB: func(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
createAuthSource: func(ctx context.Context, source *auth_model.Source) error {
|
|
||||||
assert.Equal(t, tc.source, source)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := &cli.Command{
|
|
||||||
Flags: microcmdAuthAddSMTP().Flags,
|
|
||||||
Action: a.runAddSMTP,
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"smtp-test"}
|
|
||||||
args = append(args, tc.args...)
|
|
||||||
|
|
||||||
t.Log(args)
|
|
||||||
err := cmd.Run(t.Context(), args)
|
|
||||||
|
|
||||||
if tc.errMsg != "" {
|
|
||||||
assert.EqualError(t, err, tc.errMsg)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateSMTP(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
existingAuthSource *auth_model.Source
|
|
||||||
authSource *auth_model.Source
|
|
||||||
errMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "missing id",
|
|
||||||
args: []string{
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
},
|
|
||||||
errMsg: "--id flag is missing",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config",
|
|
||||||
existingAuthSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "old name",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "PLAIN",
|
|
||||||
Host: "old host",
|
|
||||||
Port: 26,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
args: []string{
|
|
||||||
"--id", "1",
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
},
|
|
||||||
authSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "PLAIN",
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 25,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with options",
|
|
||||||
existingAuthSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "old name",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "PLAIN",
|
|
||||||
Host: "old host",
|
|
||||||
Port: 26,
|
|
||||||
HeloHostname: "old.example.com",
|
|
||||||
AllowedDomains: "old.example.com",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "",
|
|
||||||
},
|
|
||||||
args: []string{
|
|
||||||
"--id", "1",
|
|
||||||
"--name", "test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--port", "25",
|
|
||||||
"--auth-type", "LOGIN",
|
|
||||||
"--force-smtps",
|
|
||||||
"--skip-verify",
|
|
||||||
"--helo-hostname", "example.com",
|
|
||||||
"--disable-helo",
|
|
||||||
"--allowed-domains", "example.com,example.org",
|
|
||||||
"--skip-local-2fa",
|
|
||||||
"--active=false",
|
|
||||||
},
|
|
||||||
authSource: &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: false,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "LOGIN",
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 25,
|
|
||||||
ForceSMTPS: true,
|
|
||||||
SkipVerify: true,
|
|
||||||
HeloHostname: "example.com",
|
|
||||||
DisableHelo: true,
|
|
||||||
AllowedDomains: "example.com,example.org",
|
|
||||||
},
|
|
||||||
TwoFactorPolicy: "skip",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
a := &authService{
|
|
||||||
initDB: func(ctx context.Context) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth_model.Source, error) {
|
|
||||||
return &auth_model.Source{
|
|
||||||
ID: 1,
|
|
||||||
Type: auth_model.SMTP,
|
|
||||||
Name: "test",
|
|
||||||
IsActive: true,
|
|
||||||
Cfg: &smtp.Source{
|
|
||||||
Auth: "PLAIN",
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
updateAuthSource: func(ctx context.Context, source *auth_model.Source) error {
|
|
||||||
assert.Equal(t, tc.authSource, source)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
app := &cli.Command{
|
|
||||||
Flags: microcmdAuthUpdateSMTP().Flags,
|
|
||||||
Action: a.runUpdateSMTP,
|
|
||||||
}
|
|
||||||
args := []string{"smtp-tests"}
|
|
||||||
args = append(args, tc.args...)
|
|
||||||
|
|
||||||
err := app.Run(t.Context(), args)
|
|
||||||
|
|
||||||
if tc.errMsg != "" {
|
|
||||||
assert.EqualError(t, err, tc.errMsg)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -12,11 +11,11 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/services/auth/source/smtp"
|
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func smtpCLIFlags() []cli.Flag {
|
var (
|
||||||
return []cli.Flag{
|
smtpCLIFlags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
@ -68,34 +67,23 @@ func smtpCLIFlags() []cli.Flag {
|
|||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthUpdateSMTP() *cli.Command {
|
microcmdAuthAddSMTP = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "add-smtp",
|
||||||
Name: "update-smtp",
|
Usage: "Add new SMTP authentication source",
|
||||||
Usage: "Update existing SMTP authentication source",
|
Action: runAddSMTP,
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Flags: smtpCLIFlags,
|
||||||
return newAuthService().runUpdateSMTP(ctx, cmd)
|
|
||||||
},
|
|
||||||
Flags: append(smtpCLIFlags()[:1], append([]cli.Flag{&cli.Int64Flag{
|
|
||||||
Name: "id",
|
|
||||||
Usage: "ID of authentication source",
|
|
||||||
}}, smtpCLIFlags()[1:]...)...),
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthAddSMTP() *cli.Command {
|
microcmdAuthUpdateSMTP = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "update-smtp",
|
||||||
Name: "add-smtp",
|
Usage: "Update existing SMTP authentication source",
|
||||||
Usage: "Add new SMTP authentication source",
|
Action: runUpdateSMTP,
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
|
||||||
return newAuthService().runAddSMTP(ctx, cmd)
|
|
||||||
},
|
|
||||||
Flags: smtpCLIFlags(),
|
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error {
|
func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||||
if c.IsSet("auth-type") {
|
if c.IsSet("auth-type") {
|
||||||
conf.Auth = c.String("auth-type")
|
conf.Auth = c.String("auth-type")
|
||||||
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"}
|
||||||
@ -128,8 +116,11 @@ func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authService) runAddSMTP(ctx context.Context, c *cli.Command) error {
|
func runAddSMTP(c *cli.Context) error {
|
||||||
if err := a.initDB(ctx); err != nil {
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +148,7 @@ func (a *authService) runAddSMTP(ctx context.Context, c *cli.Command) error {
|
|||||||
smtpConfig.Auth = "PLAIN"
|
smtpConfig.Auth = "PLAIN"
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.createAuthSource(ctx, &auth_model.Source{
|
return auth_model.CreateSource(ctx, &auth_model.Source{
|
||||||
Type: auth_model.SMTP,
|
Type: auth_model.SMTP,
|
||||||
Name: c.String("name"),
|
Name: c.String("name"),
|
||||||
IsActive: active,
|
IsActive: active,
|
||||||
@ -166,16 +157,19 @@ func (a *authService) runAddSMTP(ctx context.Context, c *cli.Command) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authService) runUpdateSMTP(ctx context.Context, c *cli.Command) error {
|
func runUpdateSMTP(c *cli.Context) error {
|
||||||
if !c.IsSet("id") {
|
if !c.IsSet("id") {
|
||||||
return errors.New("--id flag is missing")
|
return errors.New("--id flag is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
source, err := a.getAuthSourceByID(ctx, c.Int64("id"))
|
source, err := auth_model.GetSourceByID(ctx, c.Int64("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -196,5 +190,5 @@ func (a *authService) runUpdateSMTP(ctx context.Context, c *cli.Command) error {
|
|||||||
|
|
||||||
source.Cfg = smtpConfig
|
source.Cfg = smtpConfig
|
||||||
source.TwoFactorPolicy = util.Iif(c.Bool("skip-local-2fa"), "skip", "")
|
source.TwoFactorPolicy = util.Iif(c.Bool("skip-local-2fa"), "skip", "")
|
||||||
return a.updateAuthSource(ctx, source)
|
return auth_model.UpdateSource(ctx, source)
|
||||||
}
|
}
|
@ -4,13 +4,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
repo_service "code.gitea.io/gitea/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -27,14 +25,20 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
func runRegenerateHooks(_ *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRegenerateKeys(ctx context.Context, _ *cli.Command) error {
|
func runRegenerateKeys(_ *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,18 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var subcmdUser = &cli.Command{
|
var subcmdUser = &cli.Command{
|
||||||
Name: "user",
|
Name: "user",
|
||||||
Usage: "Modify users",
|
Usage: "Modify users",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
microcmdUserCreate(),
|
microcmdUserCreate,
|
||||||
microcmdUserList,
|
microcmdUserList,
|
||||||
microcmdUserChangePassword(),
|
microcmdUserChangePassword,
|
||||||
microcmdUserDelete(),
|
microcmdUserDelete,
|
||||||
microcmdUserGenerateAccessToken,
|
microcmdUserGenerateAccessToken,
|
||||||
microcmdUserMustChangePassword(),
|
microcmdUserMustChangePassword,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
@ -14,41 +13,44 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
user_service "code.gitea.io/gitea/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserChangePassword() *cli.Command {
|
var microcmdUserChangePassword = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "change-password",
|
||||||
Name: "change-password",
|
Usage: "Change a user's password",
|
||||||
Usage: "Change a user's password",
|
Action: runChangePassword,
|
||||||
Action: runChangePassword,
|
Flags: []cli.Flag{
|
||||||
Flags: []cli.Flag{
|
&cli.StringFlag{
|
||||||
&cli.StringFlag{
|
Name: "username",
|
||||||
Name: "username",
|
Aliases: []string{"u"},
|
||||||
Aliases: []string{"u"},
|
Value: "",
|
||||||
Usage: "The user to change password for",
|
Usage: "The user to change password for",
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "password",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Usage: "New password to set for user",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "User must change password (can be disabled by --must-change-password=false)",
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New password to set for user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "User must change password (can be disabled by --must-change-password=false)",
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runChangePassword(ctx context.Context, c *cli.Command) error {
|
func runChangePassword(c *cli.Context) error {
|
||||||
if !setting.IsInTesting {
|
if err := argsSet(c, "username", "password"); err != nil {
|
||||||
if err := initDB(ctx); err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(ctx); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := user_model.GetUserByName(ctx, c.String("username"))
|
user, err := user_model.GetUserByName(ctx, c.String("username"))
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChangePasswordCommand(t *testing.T) {
|
|
||||||
ctx := t.Context()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
|
||||||
}()
|
|
||||||
|
|
||||||
t.Run("change password successfully", func(t *testing.T) {
|
|
||||||
// defer func() {
|
|
||||||
// require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
|
||||||
// }()
|
|
||||||
// Prepare test user
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
err := microcmdUserCreate().Run(ctx, []string{"create", "--username", "testuser", "--email", "testuser@gitea.local", "--random-password"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// load test user
|
|
||||||
userBase := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
|
|
||||||
// Change the password
|
|
||||||
err = microcmdUserChangePassword().Run(ctx, []string{"change-password", "--username", "testuser", "--password", "newpassword"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Verify the password has been changed
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.NotEqual(t, userBase.Passwd, user.Passwd)
|
|
||||||
assert.NotEqual(t, userBase.Salt, user.Salt)
|
|
||||||
|
|
||||||
// Additional check for must-change-password flag
|
|
||||||
require.NoError(t, microcmdUserChangePassword().Run(ctx, []string{"change-password", "--username", "testuser", "--password", "anotherpassword", "--must-change-password=false"}))
|
|
||||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.False(t, user.MustChangePassword)
|
|
||||||
|
|
||||||
require.NoError(t, microcmdUserChangePassword().Run(ctx, []string{"change-password", "--username", "testuser", "--password", "yetanotherpassword", "--must-change-password"}))
|
|
||||||
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.True(t, user.MustChangePassword)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("failure cases", func(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
expectedErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "user does not exist",
|
|
||||||
args: []string{"change-password", "--username", "nonexistentuser", "--password", "newpassword"},
|
|
||||||
expectedErr: "user does not exist",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing username",
|
|
||||||
args: []string{"change-password", "--password", "newpassword"},
|
|
||||||
expectedErr: `"username" not set`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "missing password",
|
|
||||||
args: []string{"change-password", "--username", "testuser"},
|
|
||||||
expectedErr: `"password" not set`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "too short password",
|
|
||||||
args: []string{"change-password", "--username", "testuser", "--password", "1"},
|
|
||||||
expectedErr: "password is not long enough",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
err := microcmdUserChangePassword().Run(ctx, tc.args)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), tc.expectedErr)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@ -16,95 +16,87 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserCreate() *cli.Command {
|
var microcmdUserCreate = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "create",
|
||||||
Name: "create",
|
Usage: "Create a new user in database",
|
||||||
Usage: "Create a new user in database",
|
Action: runCreateUser,
|
||||||
Action: runCreateUser,
|
Flags: []cli.Flag{
|
||||||
MutuallyExclusiveFlags: []cli.MutuallyExclusiveFlags{
|
&cli.StringFlag{
|
||||||
{
|
Name: "name",
|
||||||
Flags: [][]cli.Flag{
|
Usage: "Username. DEPRECATED: use username instead",
|
||||||
{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "name",
|
|
||||||
Usage: "Username. DEPRECATED: use username instead",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "username",
|
|
||||||
Usage: "Username",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
&cli.StringFlag{
|
||||||
&cli.StringFlag{
|
Name: "username",
|
||||||
Name: "user-type",
|
Usage: "Username",
|
||||||
Usage: "Set user's type: individual or bot",
|
|
||||||
Value: "individual",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "password",
|
|
||||||
Usage: "User password",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Usage: "User email address",
|
|
||||||
Required: true,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "admin",
|
|
||||||
Usage: "User is an admin",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "random-password",
|
|
||||||
Usage: "Generate a random password for the user",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)",
|
|
||||||
HideDefault: true,
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "random-password-length",
|
|
||||||
Usage: "Length of the random password to be generated",
|
|
||||||
Value: 12,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "access-token",
|
|
||||||
Usage: "Generate access token for the user",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-name",
|
|
||||||
Usage: `Name of the generated access token`,
|
|
||||||
Value: "gitea-admin",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-scopes",
|
|
||||||
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
||||||
Value: "all",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "restricted",
|
|
||||||
Usage: "Make a restricted user account",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "fullname",
|
|
||||||
Usage: `The full, human-readable name of the user`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
&cli.StringFlag{
|
||||||
|
Name: "user-type",
|
||||||
|
Usage: "Set user's type: individual or bot",
|
||||||
|
Value: "individual",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "User password",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Usage: "User email address",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "admin",
|
||||||
|
Usage: "User is an admin",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "random-password",
|
||||||
|
Usage: "Generate a random password for the user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "User must change password after initial login, defaults to true for all users except the first one (can be disabled by --must-change-password=false)",
|
||||||
|
DisableDefaultText: true,
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "random-password-length",
|
||||||
|
Usage: "Length of the random password to be generated",
|
||||||
|
Value: 12,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "access-token",
|
||||||
|
Usage: "Generate access token for the user",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-name",
|
||||||
|
Usage: `Name of the generated access token`,
|
||||||
|
Value: "gitea-admin",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-scopes",
|
||||||
|
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
||||||
|
Value: "all",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "restricted",
|
||||||
|
Usage: "Make a restricted user account",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "fullname",
|
||||||
|
Usage: `The full, human-readable name of the user`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreateUser(ctx context.Context, c *cli.Command) error {
|
func runCreateUser(c *cli.Context) error {
|
||||||
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
|
// this command highly depends on the many setting options (create org, visibility, etc.), so it must have a full setting load first
|
||||||
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
// duplicate setting loading should be safe at the moment, but it should be refactored & improved in the future.
|
||||||
setting.LoadSettings()
|
setting.LoadSettings()
|
||||||
|
|
||||||
|
if err := argsSet(c, "email"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
userTypes := map[string]user_model.UserType{
|
userTypes := map[string]user_model.UserType{
|
||||||
"individual": user_model.UserTypeIndividual,
|
"individual": user_model.UserTypeIndividual,
|
||||||
"bot": user_model.UserTypeBot,
|
"bot": user_model.UserTypeBot,
|
||||||
@ -121,6 +113,12 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
|
|||||||
return errors.New("password can only be set for individual users")
|
return errors.New("password can only be set for individual users")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.IsSet("name") && c.IsSet("username") {
|
||||||
|
return errors.New("cannot set both --name and --username flags")
|
||||||
|
}
|
||||||
|
if !c.IsSet("name") && !c.IsSet("username") {
|
||||||
|
return errors.New("one of --name or --username flags must be set")
|
||||||
|
}
|
||||||
|
|
||||||
if c.IsSet("password") && c.IsSet("random-password") {
|
if c.IsSet("password") && c.IsSet("random-password") {
|
||||||
return errors.New("cannot set both -random-password and -password flags")
|
return errors.New("cannot set both -random-password and -password flags")
|
||||||
@ -131,12 +129,16 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
|
|||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
} else {
|
} else {
|
||||||
username = c.String("name")
|
username = c.String("name")
|
||||||
_, _ = fmt.Fprintf(c.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx := c.Context
|
||||||
if !setting.IsInTesting {
|
if !setting.IsInTesting {
|
||||||
// FIXME: need to refactor the "initDB" related code later
|
// FIXME: need to refactor the "installSignals/initDB" related code later
|
||||||
// it doesn't make sense to call it in (almost) every command action function
|
// it doesn't make sense to call it in (almost) every command action function
|
||||||
|
var cancel context.CancelFunc
|
||||||
|
ctx, cancel = installSignals()
|
||||||
|
defer cancel()
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAdminUserCreate(t *testing.T) {
|
func TestAdminUserCreate(t *testing.T) {
|
||||||
|
app := NewMainApp(AppVersion{})
|
||||||
|
|
||||||
reset := func() {
|
reset := func() {
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
|
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
|
||||||
@ -29,9 +31,8 @@ func TestAdminUserCreate(t *testing.T) {
|
|||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
MustChangePassword bool
|
MustChangePassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
createCheck := func(name, args string) check {
|
createCheck := func(name, args string) check {
|
||||||
require.NoError(t, microcmdUserCreate().Run(t.Context(), strings.Fields(fmt.Sprintf("create --username %s --email %s@gitea.local %s --password foobar", name, name, args))))
|
require.NoError(t, app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s --password foobar", name, name, args))))
|
||||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
|
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: name})
|
||||||
return check{IsAdmin: u.IsAdmin, MustChangePassword: u.MustChangePassword}
|
return check{IsAdmin: u.IsAdmin, MustChangePassword: u.MustChangePassword}
|
||||||
}
|
}
|
||||||
@ -50,7 +51,7 @@ func TestAdminUserCreate(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
createUser := func(name string, args ...string) error {
|
createUser := func(name string, args ...string) error {
|
||||||
return microcmdUserCreate().Run(t.Context(), append([]string{"create", "--username", name, "--email", name + "@gitea.local"}, args...))
|
return app.Run(append([]string{"./gitea", "admin", "user", "create", "--username", name, "--email", name + "@gitea.local"}, args...))
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("UserType", func(t *testing.T) {
|
t.Run("UserType", func(t *testing.T) {
|
||||||
|
@ -4,56 +4,53 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
user_service "code.gitea.io/gitea/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserDelete() *cli.Command {
|
var microcmdUserDelete = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "delete",
|
||||||
Name: "delete",
|
Usage: "Delete specific user by id, name or email",
|
||||||
Usage: "Delete specific user by id, name or email",
|
Flags: []cli.Flag{
|
||||||
Flags: []cli.Flag{
|
&cli.Int64Flag{
|
||||||
&cli.Int64Flag{
|
Name: "id",
|
||||||
Name: "id",
|
Usage: "ID of user of the user to delete",
|
||||||
Usage: "ID of user of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "username",
|
|
||||||
Aliases: []string{"u"},
|
|
||||||
Usage: "Username of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Email of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "purge",
|
|
||||||
Usage: "Purge user, all their repositories, organizations and comments",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Action: runDeleteUser,
|
&cli.StringFlag{
|
||||||
}
|
Name: "username",
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Username of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Email of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "purge",
|
||||||
|
Usage: "Purge user, all their repositories, organizations and comments",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: runDeleteUser,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteUser(ctx context.Context, c *cli.Command) error {
|
func runDeleteUser(c *cli.Context) error {
|
||||||
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
|
if !c.IsSet("id") && !c.IsSet("username") && !c.IsSet("email") {
|
||||||
return errors.New("You must provide the id, username or email of a user to delete")
|
return errors.New("You must provide the id, username or email of a user to delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.IsInTesting {
|
ctx, cancel := installSignals()
|
||||||
if err := initDB(ctx); err != nil {
|
defer cancel()
|
||||||
return err
|
|
||||||
}
|
if err := initDB(ctx); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := storage.Init(); err != nil {
|
if err := storage.Init(); err != nil {
|
||||||
@ -73,11 +70,11 @@ func runDeleteUser(ctx context.Context, c *cli.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c.IsSet("username") && user.LowerName != strings.ToLower(strings.TrimSpace(c.String("username"))) {
|
if c.IsSet("username") && user.LowerName != strings.ToLower(strings.TrimSpace(c.String("username"))) {
|
||||||
return fmt.Errorf("the user %s who has email %s does not match the provided username %s", user.Name, c.String("email"), c.String("username"))
|
return fmt.Errorf("The user %s who has email %s does not match the provided username %s", user.Name, c.String("email"), c.String("username"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.IsSet("id") && user.ID != c.Int64("id") {
|
if c.IsSet("id") && user.ID != c.Int64("id") {
|
||||||
return fmt.Errorf("the user %s does not match the provided id %d", user.Name, c.Int64("id"))
|
return fmt.Errorf("The user %s does not match the provided id %d", user.Name, c.Int64("id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
return user_service.DeleteUser(ctx, user, c.Bool("purge"))
|
return user_service.DeleteUser(ctx, user, c.Bool("purge"))
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAdminUserDelete(t *testing.T) {
|
|
||||||
ctx := t.Context()
|
|
||||||
defer func() {
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &auth_model.AccessToken{}))
|
|
||||||
}()
|
|
||||||
|
|
||||||
setupTestUser := func(t *testing.T) {
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
err := microcmdUserCreate().Run(t.Context(), []string{"create", "--username", "testuser", "--email", "testuser@gitea.local", "--random-password"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("delete user by id", func(t *testing.T) {
|
|
||||||
setupTestUser(t)
|
|
||||||
|
|
||||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
err := microcmdUserDelete().Run(ctx, []string{"delete-test", "--id", strconv.FormatInt(u.ID, 10)})
|
|
||||||
require.NoError(t, err)
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
})
|
|
||||||
t.Run("delete user by username", func(t *testing.T) {
|
|
||||||
setupTestUser(t)
|
|
||||||
|
|
||||||
err := microcmdUserDelete().Run(ctx, []string{"delete-test", "--username", "testuser"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
})
|
|
||||||
t.Run("delete user by email", func(t *testing.T) {
|
|
||||||
setupTestUser(t)
|
|
||||||
|
|
||||||
err := microcmdUserDelete().Run(ctx, []string{"delete-test", "--email", "testuser@gitea.local"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
})
|
|
||||||
t.Run("delete user by all 3 attributes", func(t *testing.T) {
|
|
||||||
setupTestUser(t)
|
|
||||||
|
|
||||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
err := microcmdUserDelete().Run(ctx, []string{"delete", "--id", strconv.FormatInt(u.ID, 10), "--username", "testuser", "--email", "testuser@gitea.local"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAdminUserDeleteFailure(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
expectedErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "no user to delete",
|
|
||||||
args: []string{"delete", "--username", "nonexistentuser"},
|
|
||||||
expectedErr: "user does not exist",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "user exists but provided username does not match",
|
|
||||||
args: []string{"delete", "--email", "testuser@gitea.local", "--username", "wrongusername"},
|
|
||||||
expectedErr: "the user testuser who has email testuser@gitea.local does not match the provided username wrongusername",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "user exists but provided id does not match",
|
|
||||||
args: []string{"delete", "--username", "testuser", "--id", "999"},
|
|
||||||
expectedErr: "the user testuser does not match the provided id 999",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no required flags are provided",
|
|
||||||
args: []string{"delete"},
|
|
||||||
expectedErr: "You must provide the id, username or email of a user to delete",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
ctx := t.Context()
|
|
||||||
if strings.Contains(tc.name, "user exists") {
|
|
||||||
unittest.AssertNotExistsBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
err := microcmdUserCreate().Run(t.Context(), []string{"create", "--username", "testuser", "--email", "testuser@gitea.local", "--random-password"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := microcmdUserDelete().Run(ctx, tc.args)
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Contains(t, err.Error(), tc.expectedErr)
|
|
||||||
})
|
|
||||||
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.EmailAddress{}))
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &auth_model.AccessToken{}))
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,14 +4,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
auth_model "code.gitea.io/gitea/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserGenerateAccessToken = &cli.Command{
|
var microcmdUserGenerateAccessToken = &cli.Command{
|
||||||
@ -42,11 +41,14 @@ var microcmdUserGenerateAccessToken = &cli.Command{
|
|||||||
Action: runGenerateAccessToken,
|
Action: runGenerateAccessToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
|
func runGenerateAccessToken(c *cli.Context) error {
|
||||||
if !c.IsSet("username") {
|
if !c.IsSet("username") {
|
||||||
return errors.New("you must provide a username to generate a token for")
|
return errors.New("you must provide a username to generate a token for")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserList = &cli.Command{
|
var microcmdUserList = &cli.Command{
|
||||||
@ -26,7 +25,10 @@ var microcmdUserList = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListUsers(ctx context.Context, c *cli.Command) error {
|
func runListUsers(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,41 +4,40 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserMustChangePassword() *cli.Command {
|
var microcmdUserMustChangePassword = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "must-change-password",
|
||||||
Name: "must-change-password",
|
Usage: "Set the must change password flag for the provided users or all users",
|
||||||
Usage: "Set the must change password flag for the provided users or all users",
|
Action: runMustChangePassword,
|
||||||
Action: runMustChangePassword,
|
Flags: []cli.Flag{
|
||||||
Flags: []cli.Flag{
|
&cli.BoolFlag{
|
||||||
&cli.BoolFlag{
|
Name: "all",
|
||||||
Name: "all",
|
Aliases: []string{"A"},
|
||||||
Aliases: []string{"A"},
|
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
||||||
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "exclude",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Do not change the must-change-password flag for these users",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "unset",
|
|
||||||
Usage: "Instead of setting the must-change-password flag, unset it",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
&cli.StringSliceFlag{
|
||||||
|
Name: "exclude",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Do not change the must-change-password flag for these users",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "unset",
|
||||||
|
Usage: "Instead of setting the must-change-password flag, unset it",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
func runMustChangePassword(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() == 0 && !c.IsSet("all") {
|
if c.NArg() == 0 && !c.IsSet("all") {
|
||||||
return errors.New("either usernames or --all must be provided")
|
return errors.New("either usernames or --all must be provided")
|
||||||
}
|
}
|
||||||
@ -47,10 +46,8 @@ func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
|||||||
all := c.Bool("all")
|
all := c.Bool("all")
|
||||||
exclude := c.StringSlice("exclude")
|
exclude := c.StringSlice("exclude")
|
||||||
|
|
||||||
if !setting.IsInTesting {
|
if err := initDB(ctx); err != nil {
|
||||||
if err := initDB(ctx); err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := user_model.SetMustChangePassword(ctx, all, mustChangePassword, c.Args().Slice(), exclude)
|
n, err := user_model.SetMustChangePassword(ctx, all, mustChangePassword, c.Args().Slice(), exclude)
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMustChangePassword(t *testing.T) {
|
|
||||||
defer func() {
|
|
||||||
require.NoError(t, db.TruncateBeans(db.DefaultContext, &user_model.User{}))
|
|
||||||
}()
|
|
||||||
err := microcmdUserCreate().Run(t.Context(), []string{"create", "--username", "testuser", "--email", "testuser@gitea.local", "--random-password"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
err = microcmdUserCreate().Run(t.Context(), []string{"create", "--username", "testuserexclude", "--email", "testuserexclude@gitea.local", "--random-password"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
// Reset password change flag
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--all", "--unset"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.False(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.False(t, testUserExclude.MustChangePassword)
|
|
||||||
|
|
||||||
// Make all users change password
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--all"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.True(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.True(t, testUserExclude.MustChangePassword)
|
|
||||||
|
|
||||||
// Reset password change flag but exclude all tested users
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--all", "--unset", "--exclude", "testuser,testuserexclude"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.True(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.True(t, testUserExclude.MustChangePassword)
|
|
||||||
|
|
||||||
// Reset password change flag by listing multiple users
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--unset", "testuser", "testuserexclude"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.False(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.False(t, testUserExclude.MustChangePassword)
|
|
||||||
|
|
||||||
// Exclude a user from all user
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--all", "--exclude", "testuserexclude"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.True(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.False(t, testUserExclude.MustChangePassword)
|
|
||||||
|
|
||||||
// Unset a flag for single user
|
|
||||||
err = microcmdUserMustChangePassword().Run(t.Context(), []string{"change-test", "--unset", "testuser"})
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuser"})
|
|
||||||
assert.False(t, testUser.MustChangePassword)
|
|
||||||
testUserExclude = unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "testuserexclude"})
|
|
||||||
assert.False(t, testUserExclude.MustChangePassword)
|
|
||||||
}
|
|
128
cmd/cert.go
128
cmd/cert.go
@ -6,7 +6,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -14,7 +13,6 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
@ -22,59 +20,47 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdCert represents the available cert sub-command.
|
// CmdCert represents the available cert sub-command.
|
||||||
func cmdCert() *cli.Command {
|
var CmdCert = &cli.Command{
|
||||||
return &cli.Command{
|
Name: "cert",
|
||||||
Name: "cert",
|
Usage: "Generate self-signed certificate",
|
||||||
Usage: "Generate self-signed certificate",
|
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
|
||||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||||
Action: runCert,
|
Action: runCert,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "host",
|
Name: "host",
|
||||||
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
Value: "",
|
||||||
Required: true,
|
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "ecdsa-curve",
|
|
||||||
Value: "",
|
|
||||||
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "rsa-bits",
|
|
||||||
Value: 3072,
|
|
||||||
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "start-date",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
|
||||||
},
|
|
||||||
&cli.DurationFlag{
|
|
||||||
Name: "duration",
|
|
||||||
Value: 365 * 24 * time.Hour,
|
|
||||||
Usage: "Duration that certificate is valid for",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "ca",
|
|
||||||
Usage: "whether this cert should be its own Certificate Authority",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "out",
|
|
||||||
Value: "cert.pem",
|
|
||||||
Usage: "Path to the file where there certificate will be saved",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "keyout",
|
|
||||||
Value: "key.pem",
|
|
||||||
Usage: "Path to the file where there certificate key will be saved",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
&cli.StringFlag{
|
||||||
|
Name: "ecdsa-curve",
|
||||||
|
Value: "",
|
||||||
|
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "rsa-bits",
|
||||||
|
Value: 3072,
|
||||||
|
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "start-date",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
||||||
|
},
|
||||||
|
&cli.DurationFlag{
|
||||||
|
Name: "duration",
|
||||||
|
Value: 365 * 24 * time.Hour,
|
||||||
|
Usage: "Duration that certificate is valid for",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "ca",
|
||||||
|
Usage: "whether this cert should be its own Certificate Authority",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicKey(priv any) any {
|
func publicKey(priv any) any {
|
||||||
@ -103,7 +89,11 @@ func pemBlockForKey(priv any) *pem.Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCert(_ context.Context, c *cli.Command) error {
|
func runCert(c *cli.Context) error {
|
||||||
|
if err := argsSet(c, "host"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var priv any
|
var priv any
|
||||||
var err error
|
var err error
|
||||||
switch c.String("ecdsa-curve") {
|
switch c.String("ecdsa-curve") {
|
||||||
@ -118,17 +108,17 @@ func runCert(_ context.Context, c *cli.Command) error {
|
|||||||
case "P521":
|
case "P521":
|
||||||
priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unrecognized elliptic curve: %q", c.String("ecdsa-curve"))
|
log.Fatalf("Unrecognized elliptic curve: %q", c.String("ecdsa-curve"))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate private key: %w", err)
|
log.Fatalf("Failed to generate private key: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var notBefore time.Time
|
var notBefore time.Time
|
||||||
if startDate := c.String("start-date"); startDate != "" {
|
if startDate := c.String("start-date"); startDate != "" {
|
||||||
notBefore, err = time.Parse("Jan 2 15:04:05 2006", startDate)
|
notBefore, err = time.Parse("Jan 2 15:04:05 2006", startDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse creation date %w", err)
|
log.Fatalf("Failed to parse creation date: %v", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notBefore = time.Now()
|
notBefore = time.Now()
|
||||||
@ -139,7 +129,7 @@ func runCert(_ context.Context, c *cli.Command) error {
|
|||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to generate serial number: %w", err)
|
log.Fatalf("Failed to generate serial number: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
template := x509.Certificate{
|
template := x509.Certificate{
|
||||||
@ -156,8 +146,8 @@ func runCert(_ context.Context, c *cli.Command) error {
|
|||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts := strings.SplitSeq(c.String("host"), ",")
|
hosts := strings.Split(c.String("host"), ",")
|
||||||
for h := range hosts {
|
for _, h := range hosts {
|
||||||
if ip := net.ParseIP(h); ip != nil {
|
if ip := net.ParseIP(h); ip != nil {
|
||||||
template.IPAddresses = append(template.IPAddresses, ip)
|
template.IPAddresses = append(template.IPAddresses, ip)
|
||||||
} else {
|
} else {
|
||||||
@ -172,35 +162,35 @@ func runCert(_ context.Context, c *cli.Command) error {
|
|||||||
|
|
||||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
|
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create certificate: %w", err)
|
log.Fatalf("Failed to create certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
certOut, err := os.Create(c.String("out"))
|
certOut, err := os.Create("cert.pem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for writing: %w", c.String("keyout"), err)
|
log.Fatalf("Failed to open cert.pem for writing: %v", err)
|
||||||
}
|
}
|
||||||
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to encode certificate: %w", err)
|
log.Fatalf("Failed to encode certificate: %v", err)
|
||||||
}
|
}
|
||||||
err = certOut.Close()
|
err = certOut.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to write cert: %w", err)
|
log.Fatalf("Failed to write cert: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(c.Writer, "Written cert to %s\n", c.String("out"))
|
log.Println("Written cert.pem")
|
||||||
|
|
||||||
keyOut, err := os.OpenFile(c.String("keyout"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open %s for writing: %w", c.String("keyout"), err)
|
log.Fatalf("Failed to open key.pem for writing: %v", err)
|
||||||
}
|
}
|
||||||
err = pem.Encode(keyOut, pemBlockForKey(priv))
|
err = pem.Encode(keyOut, pemBlockForKey(priv))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to encode key: %w", err)
|
log.Fatalf("Failed to encode key: %v", err)
|
||||||
}
|
}
|
||||||
err = keyOut.Close()
|
err = keyOut.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to write key: %w", err)
|
log.Fatalf("Failed to write key: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(c.Writer, "Written key to %s\n", c.String("keyout"))
|
log.Println("Written key.pem")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
123
cmd/cert_test.go
123
cmd/cert_test.go
@ -1,123 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCertCommand(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "RSA cert generation",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--rsa-bits", "2048",
|
|
||||||
"--duration", "1h",
|
|
||||||
"--start-date", "Jan 1 00:00:00 2024",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ECDSA cert generation",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--ecdsa-curve", "P256",
|
|
||||||
"--duration", "1h",
|
|
||||||
"--start-date", "Jan 1 00:00:00 2024",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "mixed host, certificate authority",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost,127.0.0.1",
|
|
||||||
"--duration", "1h",
|
|
||||||
"--start-date", "Jan 1 00:00:00 2024",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.name, func(t *testing.T) {
|
|
||||||
app := cmdCert()
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
|
|
||||||
certFile := filepath.Join(tempDir, "cert.pem")
|
|
||||||
keyFile := filepath.Join(tempDir, "key.pem")
|
|
||||||
|
|
||||||
err := app.Run(t.Context(), append(c.args, "--out", certFile, "--keyout", keyFile))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
assert.FileExists(t, certFile)
|
|
||||||
assert.FileExists(t, keyFile)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCertCommandFailures(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
name string
|
|
||||||
args []string
|
|
||||||
errMsg string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Start Date Parsing failure",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--start-date", "invalid-date",
|
|
||||||
},
|
|
||||||
errMsg: "parsing time",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Unknown curve",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--ecdsa-curve", "invalid-curve",
|
|
||||||
},
|
|
||||||
errMsg: "unrecognized elliptic curve",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Key generation failure",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
"--host", "localhost",
|
|
||||||
"--rsa-bits", "invalid-bits",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Missing parameters",
|
|
||||||
args: []string{
|
|
||||||
"cert-test",
|
|
||||||
},
|
|
||||||
errMsg: `"host" not set`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.name, func(t *testing.T) {
|
|
||||||
app := cmdCert()
|
|
||||||
tempDir := t.TempDir()
|
|
||||||
|
|
||||||
certFile := filepath.Join(tempDir, "cert.pem")
|
|
||||||
keyFile := filepath.Join(tempDir, "key.pem")
|
|
||||||
err := app.Run(t.Context(), append(c.args, "--out", certFile, "--keyout", keyFile))
|
|
||||||
require.Error(t, err)
|
|
||||||
if c.errMsg != "" {
|
|
||||||
assert.ErrorContains(t, err, c.errMsg)
|
|
||||||
}
|
|
||||||
assert.NoFileExists(t, certFile)
|
|
||||||
assert.NoFileExists(t, keyFile)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
25
cmd/cmd.go
25
cmd/cmd.go
@ -18,19 +18,20 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// argsSet checks that all the required arguments are set. args is a list of
|
// argsSet checks that all the required arguments are set. args is a list of
|
||||||
// arguments that must be set in the passed Context.
|
// arguments that must be set in the passed Context.
|
||||||
func argsSet(c *cli.Command, args ...string) error {
|
func argsSet(c *cli.Context, args ...string) error {
|
||||||
for _, a := range args {
|
for _, a := range args {
|
||||||
if !c.IsSet(a) {
|
if !c.IsSet(a) {
|
||||||
return errors.New(a + " is not set")
|
return errors.New(a + " is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Value(a) == nil {
|
if util.IsEmptyString(c.String(a)) {
|
||||||
return errors.New(a + " is required")
|
return errors.New(a + " is required")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,7 +109,7 @@ func setupConsoleLogger(level log.Level, colorize bool, out io.Writer) {
|
|||||||
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
log.GetManager().GetLogger(log.DEFAULT).ReplaceAllWriters(writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalBool(c *cli.Command, name string) bool {
|
func globalBool(c *cli.Context, name string) bool {
|
||||||
for _, ctx := range c.Lineage() {
|
for _, ctx := range c.Lineage() {
|
||||||
if ctx.Bool(name) {
|
if ctx.Bool(name) {
|
||||||
return true
|
return true
|
||||||
@ -119,8 +120,8 @@ func globalBool(c *cli.Command, name string) bool {
|
|||||||
|
|
||||||
// PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout.
|
// PrepareConsoleLoggerLevel by default, use INFO level for console logger, but some sub-commands (for git/ssh protocol) shouldn't output any log to stdout.
|
||||||
// Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever.
|
// Any log appears in git stdout pipe will break the git protocol, eg: client can't push and hangs forever.
|
||||||
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cli.Command) (context.Context, error) {
|
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error {
|
||||||
return func(ctx context.Context, c *cli.Command) (context.Context, error) {
|
return func(c *cli.Context) error {
|
||||||
level := defaultLevel
|
level := defaultLevel
|
||||||
if globalBool(c, "quiet") {
|
if globalBool(c, "quiet") {
|
||||||
level = log.FATAL
|
level = log.FATAL
|
||||||
@ -129,16 +130,6 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl
|
|||||||
level = log.TRACE
|
level = log.TRACE
|
||||||
}
|
}
|
||||||
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
||||||
return ctx, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValidDefaultSubCommand(cmd *cli.Command) (string, bool) {
|
|
||||||
// Dirty patch for urfave/cli's strange design.
|
|
||||||
// "./gitea bad-cmd" should not start the web server.
|
|
||||||
rootArgs := cmd.Root().Args().Slice()
|
|
||||||
if len(rootArgs) != 0 && rootArgs[0] != cmd.Name {
|
|
||||||
return rootArgs[0], false
|
|
||||||
}
|
|
||||||
return "", true
|
|
||||||
}
|
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
// Copyright 2025 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDefaultCommand(t *testing.T) {
|
|
||||||
test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) {
|
|
||||||
called := false
|
|
||||||
cmd := &cli.Command{
|
|
||||||
DefaultCommand: "test",
|
|
||||||
Commands: []*cli.Command{
|
|
||||||
{
|
|
||||||
Name: "test",
|
|
||||||
Action: func(ctx context.Context, command *cli.Command) error {
|
|
||||||
retName, retValid := isValidDefaultSubCommand(command)
|
|
||||||
assert.Equal(t, expectedRetName, retName)
|
|
||||||
assert.Equal(t, expectedRetValid, retValid)
|
|
||||||
called = true
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.NoError(t, cmd.Run(t.Context(), args))
|
|
||||||
assert.True(t, called)
|
|
||||||
}
|
|
||||||
test(t, []string{"./gitea"}, "", true)
|
|
||||||
test(t, []string{"./gitea", "test"}, "", true)
|
|
||||||
test(t, []string{"./gitea", "other"}, "other", false)
|
|
||||||
}
|
|
18
cmd/docs.go
18
cmd/docs.go
@ -4,13 +4,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
cli_docs "github.com/urfave/cli-docs/v3"
|
"github.com/urfave/cli/v2"
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDocs represents the available docs sub-command.
|
// CmdDocs represents the available docs sub-command.
|
||||||
@ -32,16 +30,16 @@ var CmdDocs = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDocs(_ context.Context, cmd *cli.Command) error {
|
func runDocs(ctx *cli.Context) error {
|
||||||
docs, err := cli_docs.ToMarkdown(cmd.Root())
|
docs, err := ctx.App.ToMarkdown()
|
||||||
if cmd.Bool("man") {
|
if ctx.Bool("man") {
|
||||||
docs, err = cli_docs.ToMan(cmd.Root())
|
docs, err = ctx.App.ToMan()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cmd.Bool("man") {
|
if !ctx.Bool("man") {
|
||||||
// Clean up markdown. The following bug was fixed in v2, but is present in v1.
|
// Clean up markdown. The following bug was fixed in v2, but is present in v1.
|
||||||
// It affects markdown output (even though the issue is referring to man pages)
|
// It affects markdown output (even though the issue is referring to man pages)
|
||||||
// https://github.com/urfave/cli/issues/1040
|
// https://github.com/urfave/cli/issues/1040
|
||||||
@ -53,8 +51,8 @@ func runDocs(_ context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out := os.Stdout
|
out := os.Stdout
|
||||||
if cmd.String("output") != "" {
|
if ctx.String("output") != "" {
|
||||||
fi, err := os.Create(cmd.String("output"))
|
fi, err := os.Create(ctx.String("output"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/services/doctor"
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ var CmdDoctor = &cli.Command{
|
|||||||
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
||||||
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
||||||
|
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
cmdDoctorCheck,
|
cmdDoctorCheck,
|
||||||
cmdRecreateTable,
|
cmdRecreateTable,
|
||||||
cmdDoctorConvert,
|
cmdDoctorConvert,
|
||||||
@ -93,13 +93,16 @@ You should back-up your database before doing this and ensure that your database
|
|||||||
Action: runRecreateTable,
|
Action: runRecreateTable,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
|
func runRecreateTable(ctx *cli.Context) error {
|
||||||
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// Redirect the default golog to here
|
// Redirect the default golog to here
|
||||||
golog.SetFlags(0)
|
golog.SetFlags(0)
|
||||||
golog.SetPrefix("")
|
golog.SetPrefix("")
|
||||||
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
||||||
|
|
||||||
debug := cmd.Bool("debug")
|
debug := ctx.Bool("debug")
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
setting.LoadDBSetting()
|
setting.LoadDBSetting()
|
||||||
|
|
||||||
@ -110,15 +113,15 @@ func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setting.Database.LogSQL = debug
|
setting.Database.LogSQL = debug
|
||||||
if err := db.InitEngine(ctx); err != nil {
|
if err := db.InitEngine(stdCtx); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
|
fmt.Println("Check if you are using the right config file. You can use a --config directive to specify one.")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
args := cmd.Args()
|
args := ctx.Args()
|
||||||
names := make([]string, 0, cmd.NArg())
|
names := make([]string, 0, ctx.NArg())
|
||||||
for i := 0; i < cmd.NArg(); i++ {
|
for i := 0; i < ctx.NArg(); i++ {
|
||||||
names = append(names, args.Get(i))
|
names = append(names, args.Get(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +131,7 @@ func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
recreateTables := migrate_base.RecreateTables(beans...)
|
recreateTables := migrate_base.RecreateTables(beans...)
|
||||||
|
|
||||||
return db.InitEngineWithMigration(ctx, func(ctx context.Context, x *xorm.Engine) error {
|
return db.InitEngineWithMigration(stdCtx, func(ctx context.Context, x *xorm.Engine) error {
|
||||||
if err := migrations.EnsureUpToDate(ctx, x); err != nil {
|
if err := migrations.EnsureUpToDate(ctx, x); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -136,11 +139,11 @@ func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDoctorDefaultLogger(cmd *cli.Command, colorize bool) {
|
func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
||||||
// Silence the default loggers
|
// Silence the default loggers
|
||||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
logFile := cmd.String("log-file")
|
logFile := ctx.String("log-file")
|
||||||
switch logFile {
|
switch logFile {
|
||||||
case "":
|
case "":
|
||||||
return // if no doctor log-file is set, do not show any log from default logger
|
return // if no doctor log-file is set, do not show any log from default logger
|
||||||
@ -158,20 +161,23 @@ func setupDoctorDefaultLogger(cmd *cli.Command, colorize bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorCheck(ctx context.Context, cmd *cli.Command) error {
|
func runDoctorCheck(ctx *cli.Context) error {
|
||||||
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
colorize := log.CanColorStdout
|
colorize := log.CanColorStdout
|
||||||
if cmd.IsSet("color") {
|
if ctx.IsSet("color") {
|
||||||
colorize = cmd.Bool("color")
|
colorize = ctx.Bool("color")
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDoctorDefaultLogger(cmd, colorize)
|
setupDoctorDefaultLogger(ctx, colorize)
|
||||||
|
|
||||||
// Finally redirect the default golang's log to here
|
// Finally redirect the default golang's log to here
|
||||||
golog.SetFlags(0)
|
golog.SetFlags(0)
|
||||||
golog.SetPrefix("")
|
golog.SetPrefix("")
|
||||||
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
golog.SetOutput(log.LoggerToWriter(log.GetLogger(log.DEFAULT).Info))
|
||||||
|
|
||||||
if cmd.IsSet("list") {
|
if ctx.IsSet("list") {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
||||||
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
|
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
|
||||||
doctor.SortChecks(doctor.Checks)
|
doctor.SortChecks(doctor.Checks)
|
||||||
@ -189,12 +195,12 @@ func runDoctorCheck(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var checks []*doctor.Check
|
var checks []*doctor.Check
|
||||||
if cmd.Bool("all") {
|
if ctx.Bool("all") {
|
||||||
checks = make([]*doctor.Check, len(doctor.Checks))
|
checks = make([]*doctor.Check, len(doctor.Checks))
|
||||||
copy(checks, doctor.Checks)
|
copy(checks, doctor.Checks)
|
||||||
} else if cmd.IsSet("run") {
|
} else if ctx.IsSet("run") {
|
||||||
addDefault := cmd.Bool("default")
|
addDefault := ctx.Bool("default")
|
||||||
runNamesSet := container.SetOf(cmd.StringSlice("run")...)
|
runNamesSet := container.SetOf(ctx.StringSlice("run")...)
|
||||||
for _, check := range doctor.Checks {
|
for _, check := range doctor.Checks {
|
||||||
if (addDefault && check.IsDefault) || runNamesSet.Contains(check.Name) {
|
if (addDefault && check.IsDefault) || runNamesSet.Contains(check.Name) {
|
||||||
checks = append(checks, check)
|
checks = append(checks, check)
|
||||||
@ -211,5 +217,5 @@ func runDoctorCheck(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return doctor.RunChecks(ctx, colorize, cmd.Bool("fix"), checks)
|
return doctor.RunChecks(stdCtx, colorize, ctx.Bool("fix"), checks)
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdDoctorConvert represents the available convert sub-command.
|
// cmdDoctorConvert represents the available convert sub-command.
|
||||||
@ -22,8 +21,11 @@ var cmdDoctorConvert = &cli.Command{
|
|||||||
Action: runDoctorConvert,
|
Action: runDoctorConvert,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorConvert(ctx context.Context, cmd *cli.Command) error {
|
func runDoctorConvert(ctx *cli.Context) error {
|
||||||
if err := initDB(ctx); err != nil {
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(stdCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"code.gitea.io/gitea/services/doctor"
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDoctorRun(t *testing.T) {
|
func TestDoctorRun(t *testing.T) {
|
||||||
@ -22,13 +22,12 @@ func TestDoctorRun(t *testing.T) {
|
|||||||
|
|
||||||
SkipDatabaseInitialization: true,
|
SkipDatabaseInitialization: true,
|
||||||
})
|
})
|
||||||
app := &cli.Command{
|
app := cli.NewApp()
|
||||||
Commands: []*cli.Command{cmdDoctorCheck},
|
app.Commands = []*cli.Command{cmdDoctorCheck}
|
||||||
}
|
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
||||||
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "no-such"})
|
err = app.Run([]string{"./gitea", "check", "--run", "no-such"})
|
||||||
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check,no-such"})
|
err = app.Run([]string{"./gitea", "check", "--run", "test-check,no-such"})
|
||||||
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
}
|
}
|
||||||
|
36
cmd/dump.go
36
cmd/dump.go
@ -5,7 +5,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -21,7 +20,7 @@ import (
|
|||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"gitea.com/go-chi/session"
|
||||||
"github.com/mholt/archiver/v3"
|
"github.com/mholt/archiver/v3"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDump represents the available dump sub-command.
|
// CmdDump represents the available dump sub-command.
|
||||||
@ -102,17 +101,17 @@ func fatal(format string, args ...any) {
|
|||||||
log.Fatal(format, args...)
|
log.Fatal(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDump(ctx context.Context, cmd *cli.Command) error {
|
func runDump(ctx *cli.Context) error {
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
quite := cmd.Bool("quiet")
|
quite := ctx.Bool("quiet")
|
||||||
verbose := cmd.Bool("verbose")
|
verbose := ctx.Bool("verbose")
|
||||||
if verbose && quite {
|
if verbose && quite {
|
||||||
fatal("Option --quiet and --verbose cannot both be set")
|
fatal("Option --quiet and --verbose cannot both be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
// outFileName is either "-" or a file name (will be made absolute)
|
// outFileName is either "-" or a file name (will be made absolute)
|
||||||
outFileName, outType := dump.PrepareFileNameAndType(cmd.String("file"), cmd.String("type"))
|
outFileName, outType := dump.PrepareFileNameAndType(ctx.String("file"), ctx.String("type"))
|
||||||
if outType == "" {
|
if outType == "" {
|
||||||
fatal("Invalid output type")
|
fatal("Invalid output type")
|
||||||
}
|
}
|
||||||
@ -137,7 +136,10 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
setting.DisableLoggerInit()
|
setting.DisableLoggerInit()
|
||||||
setting.LoadSettings() // cannot access session settings otherwise
|
setting.LoadSettings() // cannot access session settings otherwise
|
||||||
|
|
||||||
err := db.InitEngine(ctx)
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err := db.InitEngine(stdCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -163,7 +165,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
dumper.GlobalExcludeAbsPath(outFileName)
|
dumper.GlobalExcludeAbsPath(outFileName)
|
||||||
|
|
||||||
if cmd.IsSet("skip-repository") && cmd.Bool("skip-repository") {
|
if ctx.IsSet("skip-repository") && ctx.Bool("skip-repository") {
|
||||||
log.Info("Skip dumping local repositories")
|
log.Info("Skip dumping local repositories")
|
||||||
} else {
|
} else {
|
||||||
log.Info("Dumping local repositories... %s", setting.RepoRootPath)
|
log.Info("Dumping local repositories... %s", setting.RepoRootPath)
|
||||||
@ -171,7 +173,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
fatal("Failed to include repositories: %v", err)
|
fatal("Failed to include repositories: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.IsSet("skip-lfs-data") && cmd.Bool("skip-lfs-data") {
|
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") {
|
||||||
log.Info("Skip dumping LFS data")
|
log.Info("Skip dumping LFS data")
|
||||||
} else if !setting.LFS.StartServer {
|
} else if !setting.LFS.StartServer {
|
||||||
log.Info("LFS isn't enabled. Skip dumping LFS data")
|
log.Info("LFS isn't enabled. Skip dumping LFS data")
|
||||||
@ -186,12 +188,12 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.Bool("skip-db") {
|
if ctx.Bool("skip-db") {
|
||||||
// Ensure that we don't dump the database file that may reside in setting.AppDataPath or elsewhere.
|
// Ensure that we don't dump the database file that may reside in setting.AppDataPath or elsewhere.
|
||||||
dumper.GlobalExcludeAbsPath(setting.Database.Path)
|
dumper.GlobalExcludeAbsPath(setting.Database.Path)
|
||||||
log.Info("Skipping database")
|
log.Info("Skipping database")
|
||||||
} else {
|
} else {
|
||||||
tmpDir := cmd.String("tempdir")
|
tmpDir := ctx.String("tempdir")
|
||||||
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
|
if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
|
||||||
fatal("Path does not exist: %s", tmpDir)
|
fatal("Path does not exist: %s", tmpDir)
|
||||||
}
|
}
|
||||||
@ -207,7 +209,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
targetDBType := cmd.String("database")
|
targetDBType := ctx.String("database")
|
||||||
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
|
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
|
||||||
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
||||||
} else {
|
} else {
|
||||||
@ -228,7 +230,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
fatal("Failed to include specified app.ini: %v", err)
|
fatal("Failed to include specified app.ini: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.IsSet("skip-custom-dir") && cmd.Bool("skip-custom-dir") {
|
if ctx.IsSet("skip-custom-dir") && ctx.Bool("skip-custom-dir") {
|
||||||
log.Info("Skipping custom directory")
|
log.Info("Skipping custom directory")
|
||||||
} else {
|
} else {
|
||||||
customDir, err := os.Stat(setting.CustomPath)
|
customDir, err := os.Stat(setting.CustomPath)
|
||||||
@ -261,7 +263,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
excludes = append(excludes, opts.ProviderConfig)
|
excludes = append(excludes, opts.ProviderConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.IsSet("skip-index") && cmd.Bool("skip-index") {
|
if ctx.IsSet("skip-index") && ctx.Bool("skip-index") {
|
||||||
excludes = append(excludes, setting.Indexer.RepoPath)
|
excludes = append(excludes, setting.Indexer.RepoPath)
|
||||||
excludes = append(excludes, setting.Indexer.IssuePath)
|
excludes = append(excludes, setting.Indexer.IssuePath)
|
||||||
}
|
}
|
||||||
@ -276,7 +278,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.IsSet("skip-attachment-data") && cmd.Bool("skip-attachment-data") {
|
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") {
|
||||||
log.Info("Skip dumping attachment data")
|
log.Info("Skip dumping attachment data")
|
||||||
} else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error {
|
} else if err := storage.Attachments.IterateObjects("", func(objPath string, object storage.Object) error {
|
||||||
info, err := object.Stat()
|
info, err := object.Stat()
|
||||||
@ -288,7 +290,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
fatal("Failed to dump attachments: %v", err)
|
fatal("Failed to dump attachments: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmd.IsSet("skip-package-data") && cmd.Bool("skip-package-data") {
|
if ctx.IsSet("skip-package-data") && ctx.Bool("skip-package-data") {
|
||||||
log.Info("Skip dumping package data")
|
log.Info("Skip dumping package data")
|
||||||
} else if !setting.Packages.Enabled {
|
} else if !setting.Packages.Enabled {
|
||||||
log.Info("Packages isn't enabled. Skip dumping package data")
|
log.Info("Packages isn't enabled. Skip dumping package data")
|
||||||
@ -305,7 +307,7 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
// Doesn't check if LogRootPath exists before processing --skip-log intentionally,
|
// Doesn't check if LogRootPath exists before processing --skip-log intentionally,
|
||||||
// ensuring that it's clear the dump is skipped whether the directory's initialized
|
// ensuring that it's clear the dump is skipped whether the directory's initialized
|
||||||
// yet or not.
|
// yet or not.
|
||||||
if cmd.IsSet("skip-log") && cmd.Bool("skip-log") {
|
if ctx.IsSet("skip-log") && ctx.Bool("skip-log") {
|
||||||
log.Info("Skip dumping log files")
|
log.Info("Skip dumping log files")
|
||||||
} else {
|
} else {
|
||||||
isExist, err := util.IsExist(setting.Log.RootPath)
|
isExist, err := util.IsExist(setting.Log.RootPath)
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
"code.gitea.io/gitea/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
"code.gitea.io/gitea/services/migrations"
|
"code.gitea.io/gitea/services/migrations"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDumpRepository represents the available dump repository sub-command.
|
// CmdDumpRepository represents the available dump repository sub-command.
|
||||||
@ -79,13 +79,16 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
func runDumpRepository(ctx *cli.Context) error {
|
||||||
setupConsoleLogger(log.INFO, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.INFO, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
setting.DisableLoggerInit()
|
setting.DisableLoggerInit()
|
||||||
setting.LoadSettings() // cannot access skip_tls_verify settings otherwise
|
setting.LoadSettings() // cannot access skip_tls_verify settings otherwise
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(stdCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,8 +105,8 @@ func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
serviceType structs.GitServiceType
|
serviceType structs.GitServiceType
|
||||||
cloneAddr = cmd.String("clone_addr")
|
cloneAddr = ctx.String("clone_addr")
|
||||||
serviceStr = cmd.String("git_service")
|
serviceStr = ctx.String("git_service")
|
||||||
)
|
)
|
||||||
|
|
||||||
if strings.HasPrefix(strings.ToLower(cloneAddr), "https://github.com/") {
|
if strings.HasPrefix(strings.ToLower(cloneAddr), "https://github.com/") {
|
||||||
@ -121,13 +124,13 @@ func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
|||||||
opts := base.MigrateOptions{
|
opts := base.MigrateOptions{
|
||||||
GitServiceType: serviceType,
|
GitServiceType: serviceType,
|
||||||
CloneAddr: cloneAddr,
|
CloneAddr: cloneAddr,
|
||||||
AuthUsername: cmd.String("auth_username"),
|
AuthUsername: ctx.String("auth_username"),
|
||||||
AuthPassword: cmd.String("auth_password"),
|
AuthPassword: ctx.String("auth_password"),
|
||||||
AuthToken: cmd.String("auth_token"),
|
AuthToken: ctx.String("auth_token"),
|
||||||
RepoName: cmd.String("repo_name"),
|
RepoName: ctx.String("repo_name"),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cmd.String("units")) == 0 {
|
if len(ctx.String("units")) == 0 {
|
||||||
opts.Wiki = true
|
opts.Wiki = true
|
||||||
opts.Issues = true
|
opts.Issues = true
|
||||||
opts.Milestones = true
|
opts.Milestones = true
|
||||||
@ -137,8 +140,8 @@ func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
|||||||
opts.PullRequests = true
|
opts.PullRequests = true
|
||||||
opts.ReleaseAssets = true
|
opts.ReleaseAssets = true
|
||||||
} else {
|
} else {
|
||||||
units := strings.SplitSeq(cmd.String("units"), ",")
|
units := strings.Split(ctx.String("units"), ",")
|
||||||
for unit := range units {
|
for _, unit := range units {
|
||||||
switch strings.ToLower(strings.TrimSpace(unit)) {
|
switch strings.ToLower(strings.TrimSpace(unit)) {
|
||||||
case "":
|
case "":
|
||||||
continue
|
continue
|
||||||
@ -166,7 +169,7 @@ func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
|||||||
|
|
||||||
// the repo_dir will be removed if error occurs in DumpRepository
|
// the repo_dir will be removed if error occurs in DumpRepository
|
||||||
// make sure the directory doesn't exist or is empty, prevent from deleting user files
|
// make sure the directory doesn't exist or is empty, prevent from deleting user files
|
||||||
repoDir := cmd.String("repo_dir")
|
repoDir := ctx.String("repo_dir")
|
||||||
if exists, err := util.IsExist(repoDir); err != nil {
|
if exists, err := util.IsExist(repoDir); err != nil {
|
||||||
return fmt.Errorf("unable to stat repo_dir %q: %w", repoDir, err)
|
return fmt.Errorf("unable to stat repo_dir %q: %w", repoDir, err)
|
||||||
} else if exists {
|
} else if exists {
|
||||||
@ -181,7 +184,7 @@ func runDumpRepository(ctx context.Context, cmd *cli.Command) error {
|
|||||||
if err := migrations.DumpRepository(
|
if err := migrations.DumpRepository(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
repoDir,
|
repoDir,
|
||||||
cmd.String("owner_name"),
|
ctx.String("owner_name"),
|
||||||
opts,
|
opts,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
log.Fatal("Failed to dump repository: %v", err)
|
log.Fatal("Failed to dump repository: %v", err)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -20,7 +19,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdEmbedded represents the available extract sub-command.
|
// CmdEmbedded represents the available extract sub-command.
|
||||||
@ -29,7 +28,7 @@ var (
|
|||||||
Name: "embedded",
|
Name: "embedded",
|
||||||
Usage: "Extract embedded resources",
|
Usage: "Extract embedded resources",
|
||||||
Description: "A command for extracting embedded resources, like templates and images",
|
Description: "A command for extracting embedded resources, like templates and images",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdList,
|
subcmdList,
|
||||||
subcmdView,
|
subcmdView,
|
||||||
subcmdExtract,
|
subcmdExtract,
|
||||||
@ -101,7 +100,7 @@ type assetFile struct {
|
|||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initEmbeddedExtractor(c *cli.Command) error {
|
func initEmbeddedExtractor(c *cli.Context) error {
|
||||||
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.ERROR, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
patterns, err := compileCollectPatterns(c.Args().Slice())
|
patterns, err := compileCollectPatterns(c.Args().Slice())
|
||||||
@ -116,31 +115,31 @@ func initEmbeddedExtractor(c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runList(_ context.Context, c *cli.Command) error {
|
func runList(c *cli.Context) error {
|
||||||
if err := runListDo(c); err != nil {
|
if err := runListDo(c); err != nil {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runView(_ context.Context, c *cli.Command) error {
|
func runView(c *cli.Context) error {
|
||||||
if err := runViewDo(c); err != nil {
|
if err := runViewDo(c); err != nil {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtract(_ context.Context, c *cli.Command) error {
|
func runExtract(c *cli.Context) error {
|
||||||
if err := runExtractDo(c); err != nil {
|
if err := runExtractDo(c); err != nil {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListDo(c *cli.Command) error {
|
func runListDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -152,7 +151,7 @@ func runListDo(c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runViewDo(c *cli.Command) error {
|
func runViewDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -175,7 +174,7 @@ func runViewDo(c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtractDo(c *cli.Command) error {
|
func runExtractDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -217,7 +216,7 @@ func runExtractDo(c *cli.Command) error {
|
|||||||
for _, a := range matchedAssetFiles {
|
for _, a := range matchedAssetFiles {
|
||||||
if err := extractAsset(destdir, a, overwrite, rename); err != nil {
|
if err := extractAsset(destdir, a, overwrite, rename); err != nil {
|
||||||
// Non-fatal error
|
// Non-fatal error
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%s: %v\n", a.path, err)
|
fmt.Fprintf(os.Stderr, "%s: %v", a.path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +271,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectAssetFilesByPattern(c *cli.Command, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
func collectAssetFilesByPattern(c *cli.Context, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
||||||
fs := assetfs.Layered(layer)
|
fs := assetfs.Layered(layer)
|
||||||
files, err := fs.ListAllFiles(".", true)
|
files, err := fs.ListAllFiles(".", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -295,14 +294,16 @@ func collectAssetFilesByPattern(c *cli.Command, globs []glob.Glob, path string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compileCollectPatterns(args []string) (_ []glob.Glob, err error) {
|
func compileCollectPatterns(args []string) ([]glob.Glob, error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
args = []string{"**"}
|
args = []string{"**"}
|
||||||
}
|
}
|
||||||
pat := make([]glob.Glob, len(args))
|
pat := make([]glob.Glob, len(args))
|
||||||
for i := range args {
|
for i := range args {
|
||||||
if pat[i], err = glob.Compile(args[i], '/'); err != nil {
|
if g, err := glob.Compile(args[i], '/'); err != nil {
|
||||||
return nil, fmt.Errorf("invalid glob patterh %q: %w", args[i], err)
|
return nil, fmt.Errorf("'%s': Invalid glob pattern: %w", args[i], err)
|
||||||
|
} else { //nolint:revive
|
||||||
|
pat[i] = g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pat, nil
|
return pat, nil
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -20,7 +19,7 @@ var (
|
|||||||
CmdGenerate = &cli.Command{
|
CmdGenerate = &cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Usage: "Generate Gitea's secrets/keys/tokens",
|
Usage: "Generate Gitea's secrets/keys/tokens",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdSecret,
|
subcmdSecret,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -28,7 +27,7 @@ var (
|
|||||||
subcmdSecret = &cli.Command{
|
subcmdSecret = &cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Usage: "Generate a secret token",
|
Usage: "Generate a secret token",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
microcmdGenerateInternalToken,
|
microcmdGenerateInternalToken,
|
||||||
microcmdGenerateLfsJwtSecret,
|
microcmdGenerateLfsJwtSecret,
|
||||||
microcmdGenerateSecretKey,
|
microcmdGenerateSecretKey,
|
||||||
@ -55,7 +54,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runGenerateInternalToken(_ context.Context, c *cli.Command) error {
|
func runGenerateInternalToken(c *cli.Context) error {
|
||||||
internalToken, err := generate.NewInternalToken()
|
internalToken, err := generate.NewInternalToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -70,7 +69,7 @@ func runGenerateInternalToken(_ context.Context, c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateLfsJwtSecret(_ context.Context, c *cli.Command) error {
|
func runGenerateLfsJwtSecret(c *cli.Context) error {
|
||||||
_, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
|
_, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -85,7 +84,7 @@ func runGenerateLfsJwtSecret(_ context.Context, c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateSecretKey(_ context.Context, c *cli.Command) error {
|
func runGenerateSecretKey(c *cli.Context) error {
|
||||||
secretKey, err := generate.NewSecretKey()
|
secretKey, err := generate.NewSecretKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
27
cmd/hook.go
27
cmd/hook.go
@ -20,7 +20,7 @@ import (
|
|||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -32,10 +32,9 @@ var (
|
|||||||
CmdHook = &cli.Command{
|
CmdHook = &cli.Command{
|
||||||
Name: "hook",
|
Name: "hook",
|
||||||
Usage: "(internal) Should only be called by Git",
|
Usage: "(internal) Should only be called by Git",
|
||||||
Hidden: true, // internal commands shouldn't be visible
|
|
||||||
Description: "Delegate commands to corresponding Git hooks",
|
Description: "Delegate commands to corresponding Git hooks",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdHookPreReceive,
|
subcmdHookPreReceive,
|
||||||
subcmdHookUpdate,
|
subcmdHookUpdate,
|
||||||
subcmdHookPostReceive,
|
subcmdHookPostReceive,
|
||||||
@ -162,10 +161,12 @@ func (n *nilWriter) WriteString(s string) (int, error) {
|
|||||||
return len(s), nil
|
return len(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPreReceive(ctx context.Context, c *cli.Command) error {
|
func runHookPreReceive(c *cli.Context) error {
|
||||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
@ -291,7 +292,7 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
|
|
||||||
// runHookUpdate avoid to do heavy operations on update hook because it will be
|
// runHookUpdate avoid to do heavy operations on update hook because it will be
|
||||||
// invoked for every ref update which does not like pre-receive and post-receive
|
// invoked for every ref update which does not like pre-receive and post-receive
|
||||||
func runHookUpdate(_ context.Context, c *cli.Command) error {
|
func runHookUpdate(c *cli.Context) error {
|
||||||
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
if isInternal, _ := strconv.ParseBool(os.Getenv(repo_module.EnvIsInternal)); isInternal {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -308,12 +309,15 @@ func runHookUpdate(_ context.Context, c *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
func runHookPostReceive(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
// First of all run update-server-info no matter what
|
// First of all run update-server-info no matter what
|
||||||
if _, _, err := git.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil {
|
if _, _, err := git.NewCommand("update-server-info").RunStdString(ctx, nil); err != nil {
|
||||||
return fmt.Errorf("failed to call 'git update-server-info': %w", err)
|
return fmt.Errorf("Failed to call 'git update-server-info': %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now if we're an internal don't do anything else
|
// Now if we're an internal don't do anything else
|
||||||
@ -481,7 +485,7 @@ func hookPrintResult(output, isCreate bool, branch, url string) {
|
|||||||
func pushOptions() map[string]string {
|
func pushOptions() map[string]string {
|
||||||
opts := make(map[string]string)
|
opts := make(map[string]string)
|
||||||
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
|
if pushCount, err := strconv.Atoi(os.Getenv(private.GitPushOptionCount)); err == nil {
|
||||||
for idx := range pushCount {
|
for idx := 0; idx < pushCount; idx++ {
|
||||||
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
|
opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx))
|
||||||
kv := strings.SplitN(opt, "=", 2)
|
kv := strings.SplitN(opt, "=", 2)
|
||||||
if len(kv) == 2 {
|
if len(kv) == 2 {
|
||||||
@ -492,7 +496,10 @@ func pushOptions() map[string]string {
|
|||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookProcReceive(ctx context.Context, c *cli.Command) error {
|
func runHookProcReceive(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
@ -733,7 +740,7 @@ func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType)
|
|||||||
|
|
||||||
// read prefix
|
// read prefix
|
||||||
lengthBytes := make([]byte, 4)
|
lengthBytes := make([]byte, 4)
|
||||||
for i := range 4 {
|
for i := 0; i < 4; i++ {
|
||||||
lengthBytes[i], err = in.ReadByte()
|
lengthBytes[i], err = in.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err)
|
||||||
|
11
cmd/keys.go
11
cmd/keys.go
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@ -12,14 +11,13 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdKeys represents the available keys sub-command
|
// CmdKeys represents the available keys sub-command
|
||||||
var CmdKeys = &cli.Command{
|
var CmdKeys = &cli.Command{
|
||||||
Name: "keys",
|
Name: "keys",
|
||||||
Usage: "(internal) Should only be called by SSH server",
|
Usage: "(internal) Should only be called by SSH server",
|
||||||
Hidden: true, // internal commands shouldn't not be visible
|
|
||||||
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Action: runKeys,
|
Action: runKeys,
|
||||||
@ -51,7 +49,7 @@ var CmdKeys = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKeys(ctx context.Context, c *cli.Command) error {
|
func runKeys(c *cli.Context) error {
|
||||||
if !c.IsSet("username") {
|
if !c.IsSet("username") {
|
||||||
return errors.New("No username provided")
|
return errors.New("No username provided")
|
||||||
}
|
}
|
||||||
@ -70,6 +68,9 @@ func runKeys(ctx context.Context, c *cli.Command) error {
|
|||||||
return errors.New("No key type and content provided")
|
return errors.New("No key type and content provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
|
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
|
||||||
@ -77,6 +78,6 @@ func runKeys(ctx context.Context, c *cli.Command) error {
|
|||||||
if extra.Error != nil {
|
if extra.Error != nil {
|
||||||
return extra.Error
|
return extra.Error
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(c.Root().Writer, strings.TrimSpace(authorizedString.Text))
|
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,24 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runSendMail(ctx context.Context, c *cli.Command) error {
|
func runSendMail(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
|
if err := argsSet(c, "title"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
subject := c.String("title")
|
subject := c.String("title")
|
||||||
confirmSkiped := c.Bool("force")
|
confirmSkiped := c.Bool("force")
|
||||||
body := c.String("content")
|
body := c.String("content")
|
||||||
|
183
cmd/main.go
183
cmd/main.go
@ -4,40 +4,36 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cliHelpPrinterOld = cli.HelpPrinter
|
// cmdHelp is our own help subcommand with more information
|
||||||
|
// Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
|
||||||
func init() {
|
func cmdHelp() *cli.Command {
|
||||||
cli.HelpPrinter = cliHelpPrinterNew
|
c := &cli.Command{
|
||||||
}
|
Name: "help",
|
||||||
|
Aliases: []string{"h"},
|
||||||
// cliHelpPrinterNew helps to print "DEFAULT CONFIGURATION" for the following cases ( "-c" can apper in any position):
|
Usage: "Shows a list of commands or help for one command",
|
||||||
// * ./gitea -c /dev/null -h
|
ArgsUsage: "[command]",
|
||||||
// * ./gitea -c help /dev/null help
|
Action: func(c *cli.Context) (err error) {
|
||||||
// * ./gitea help -c /dev/null
|
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
|
||||||
// * ./gitea help -c /dev/null web
|
targetCmdIdx := 0
|
||||||
// * ./gitea help web -c /dev/null
|
if c.Command.Name == "help" {
|
||||||
// * ./gitea web help -c /dev/null
|
targetCmdIdx = 1
|
||||||
// * ./gitea web -h -c /dev/null
|
}
|
||||||
func cliHelpPrinterNew(out io.Writer, templ string, data any) {
|
if lineage[targetCmdIdx+1].Command != nil {
|
||||||
cmd, _ := data.(*cli.Command)
|
err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
|
||||||
if cmd != nil {
|
} else {
|
||||||
prepareWorkPathAndCustomConf(cmd)
|
err = cli.ShowAppHelp(c)
|
||||||
}
|
}
|
||||||
cliHelpPrinterOld(out, templ, data)
|
_, _ = fmt.Fprintf(c.App.Writer, `
|
||||||
if setting.CustomConf != "" {
|
|
||||||
_, _ = fmt.Fprintf(out, `
|
|
||||||
DEFAULT CONFIGURATION:
|
DEFAULT CONFIGURATION:
|
||||||
AppPath: %s
|
AppPath: %s
|
||||||
WorkPath: %s
|
WorkPath: %s
|
||||||
@ -45,71 +41,94 @@ DEFAULT CONFIGURATION:
|
|||||||
ConfigFile: %s
|
ConfigFile: %s
|
||||||
|
|
||||||
`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
|
`, setting.AppPath, setting.AppWorkPath, setting.CustomPath, setting.CustomConf)
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func appGlobalFlags() []cli.Flag {
|
||||||
|
return []cli.Flag{
|
||||||
|
// make the builtin flags at the top
|
||||||
|
cli.HelpFlag,
|
||||||
|
|
||||||
|
// shared configuration flags, they are for global and for each sub-command at the same time
|
||||||
|
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
||||||
|
// keep in mind that the short flags like "-C", "-c" and "-w" are globally polluted, they can't be used for sub-commands anymore.
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "custom-path",
|
||||||
|
Aliases: []string{"C"},
|
||||||
|
Usage: "Set custom path (defaults to '{WorkPath}/custom')",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Value: setting.CustomConf,
|
||||||
|
Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "work-path",
|
||||||
|
Aliases: []string{"w"},
|
||||||
|
Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
|
func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) {
|
||||||
originBefore := originCmd.Before
|
command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
|
||||||
originCmd.Before = func(ctx context.Context, cmd *cli.Command) (context.Context, error) {
|
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
||||||
prepareWorkPathAndCustomConf(cmd)
|
command.HideHelp = true
|
||||||
if originBefore != nil {
|
if command.Name != "help" {
|
||||||
return originBefore(ctx, cmd)
|
command.Subcommands = append(command.Subcommands, cmdHelp())
|
||||||
|
}
|
||||||
|
for i := range command.Subcommands {
|
||||||
|
prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
||||||
|
// It can't use "Before", because each level's sub-command's Before will be called one by one, so the "init" would be done multiple times
|
||||||
|
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error {
|
||||||
|
return func(ctx *cli.Context) error {
|
||||||
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
|
// from children to parent, check the global flags
|
||||||
|
for _, curCtx := range ctx.Lineage() {
|
||||||
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
|
args.WorkPath = curCtx.String("work-path")
|
||||||
|
}
|
||||||
|
if curCtx.IsSet("custom-path") && args.CustomPath == "" {
|
||||||
|
args.CustomPath = curCtx.String("custom-path")
|
||||||
|
}
|
||||||
|
if curCtx.IsSet("config") && args.CustomConf == "" {
|
||||||
|
args.CustomConf = curCtx.String("config")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ctx, nil
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
|
if ctx.Bool("help") || action == nil {
|
||||||
|
// the default behavior of "urfave/cli": "nil action" means "show help"
|
||||||
|
return cmdHelp().Action(ctx)
|
||||||
|
}
|
||||||
|
return action(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareWorkPathAndCustomConf tries to prepare the work path, custom path and custom config from various inputs:
|
|
||||||
// command line flags, environment variables, config file
|
|
||||||
func prepareWorkPathAndCustomConf(cmd *cli.Command) {
|
|
||||||
var args setting.ArgWorkPathAndCustomConf
|
|
||||||
if cmd.IsSet("work-path") {
|
|
||||||
args.WorkPath = cmd.String("work-path")
|
|
||||||
}
|
|
||||||
if cmd.IsSet("custom-path") {
|
|
||||||
args.CustomPath = cmd.String("custom-path")
|
|
||||||
}
|
|
||||||
if cmd.IsSet("config") {
|
|
||||||
args.CustomConf = cmd.String("config")
|
|
||||||
}
|
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AppVersion struct {
|
type AppVersion struct {
|
||||||
Version string
|
Version string
|
||||||
Extra string
|
Extra string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainApp(appVer AppVersion) *cli.Command {
|
func NewMainApp(appVer AppVersion) *cli.App {
|
||||||
app := &cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Name = "gitea" // must be lower-cased because it appears in the "USAGE" section like "gitea doctor [command [command options]]"
|
app.Name = "Gitea"
|
||||||
|
app.HelpName = "gitea"
|
||||||
app.Usage = "A painless self-hosted Git service"
|
app.Usage = "A painless self-hosted Git service"
|
||||||
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
|
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
|
||||||
app.Version = appVer.Version + appVer.Extra
|
app.Version = appVer.Version + appVer.Extra
|
||||||
app.EnableShellCompletion = true
|
app.EnableBashCompletion = true
|
||||||
app.Flags = []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
// these sub-commands need to use config file
|
||||||
Name: "work-path",
|
|
||||||
Aliases: []string{"w"},
|
|
||||||
TakesFile: true,
|
|
||||||
Usage: "Set Gitea's working path (defaults to the Gitea's binary directory)",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "config",
|
|
||||||
Aliases: []string{"c"},
|
|
||||||
TakesFile: true,
|
|
||||||
Value: setting.CustomConf,
|
|
||||||
Usage: "Set custom config file (defaults to '{WorkPath}/custom/conf/app.ini')",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "custom-path",
|
|
||||||
Aliases: []string{"C"},
|
|
||||||
TakesFile: true,
|
|
||||||
Usage: "Set custom path (defaults to '{WorkPath}/custom')",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// these sub-commands need to use a config file
|
|
||||||
subCmdWithConfig := []*cli.Command{
|
subCmdWithConfig := []*cli.Command{
|
||||||
|
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||||
CmdWeb,
|
CmdWeb,
|
||||||
CmdServ,
|
CmdServ,
|
||||||
CmdHook,
|
CmdHook,
|
||||||
@ -128,18 +147,20 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
|||||||
|
|
||||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||||
subCmdStandalone := []*cli.Command{
|
subCmdStandalone := []*cli.Command{
|
||||||
cmdCert(),
|
CmdCert,
|
||||||
CmdGenerate,
|
CmdGenerate,
|
||||||
CmdDocs,
|
CmdDocs,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we should eventually drop the default command,
|
|
||||||
// but not sure whether it would break Windows users who used to double-click the EXE to run.
|
|
||||||
app.DefaultCommand = CmdWeb.Name
|
app.DefaultCommand = CmdWeb.Name
|
||||||
|
|
||||||
|
globalFlags := appGlobalFlags()
|
||||||
|
app.Flags = append(app.Flags, cli.VersionFlag)
|
||||||
|
app.Flags = append(app.Flags, globalFlags...)
|
||||||
|
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
||||||
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
||||||
for i := range subCmdWithConfig {
|
for i := range subCmdWithConfig {
|
||||||
prepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
|
prepareSubcommandWithConfig(subCmdWithConfig[i], globalFlags)
|
||||||
}
|
}
|
||||||
app.Commands = append(app.Commands, subCmdWithConfig...)
|
app.Commands = append(app.Commands, subCmdWithConfig...)
|
||||||
app.Commands = append(app.Commands, subCmdStandalone...)
|
app.Commands = append(app.Commands, subCmdStandalone...)
|
||||||
@ -148,10 +169,8 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
|||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMainApp(app *cli.Command, args ...string) error {
|
func RunMainApp(app *cli.App, args ...string) error {
|
||||||
ctx, cancel := installSignals()
|
err := app.Run(args)
|
||||||
defer cancel()
|
|
||||||
err := app.Run(ctx, args)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -17,7 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
@ -28,10 +27,10 @@ func makePathOutput(workPath, customPath, customConf string) string {
|
|||||||
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestApp(testCmdAction cli.ActionFunc) *cli.Command {
|
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
|
||||||
app := NewMainApp(AppVersion{})
|
app := NewMainApp(AppVersion{})
|
||||||
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
||||||
prepareSubcommandWithGlobalFlags(testCmd)
|
prepareSubcommandWithConfig(testCmd, appGlobalFlags())
|
||||||
app.Commands = append(app.Commands, testCmd)
|
app.Commands = append(app.Commands, testCmd)
|
||||||
app.DefaultCommand = testCmd.Name
|
app.DefaultCommand = testCmd.Name
|
||||||
return app
|
return app
|
||||||
@ -43,7 +42,7 @@ type runResult struct {
|
|||||||
ExitCode int
|
ExitCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
|
func runTestApp(app *cli.App, args ...string) (runResult, error) {
|
||||||
outBuf := new(strings.Builder)
|
outBuf := new(strings.Builder)
|
||||||
errBuf := new(strings.Builder)
|
errBuf := new(strings.Builder)
|
||||||
app.Writer = outBuf
|
app.Writer = outBuf
|
||||||
@ -66,7 +65,7 @@ func TestCliCmd(t *testing.T) {
|
|||||||
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
||||||
|
|
||||||
cli.CommandHelpTemplate = "(command help template)"
|
cli.CommandHelpTemplate = "(command help template)"
|
||||||
cli.RootCommandHelpTemplate = "(app help template)"
|
cli.AppHelpTemplate = "(app help template)"
|
||||||
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
@ -74,56 +73,12 @@ func TestCliCmd(t *testing.T) {
|
|||||||
cmd string
|
cmd string
|
||||||
exp string
|
exp string
|
||||||
}{
|
}{
|
||||||
// help commands
|
// main command help
|
||||||
{
|
|
||||||
cmd: "./gitea -h",
|
|
||||||
exp: "DEFAULT CONFIGURATION:",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
cmd: "./gitea help",
|
cmd: "./gitea help",
|
||||||
exp: "DEFAULT CONFIGURATION:",
|
exp: "DEFAULT CONFIGURATION:",
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea help -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null test-cmd -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -c /dev/null -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -h -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null test-cmd help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -c /dev/null help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd help -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
// parse paths
|
// parse paths
|
||||||
{
|
{
|
||||||
cmd: "./gitea test-cmd",
|
cmd: "./gitea test-cmd",
|
||||||
@ -154,12 +109,12 @@ func TestCliCmd(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app := newTestApp(func(ctx *cli.Context) error {
|
||||||
|
_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.cmd, func(t *testing.T) {
|
t.Run(c.cmd, func(t *testing.T) {
|
||||||
app := newTestApp(func(ctx context.Context, cmd *cli.Command) error {
|
|
||||||
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
for k, v := range c.env {
|
for k, v := range c.env {
|
||||||
t.Setenv(k, v)
|
t.Setenv(k, v)
|
||||||
}
|
}
|
||||||
@ -173,28 +128,28 @@ func TestCliCmd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
func TestCliCmdError(t *testing.T) {
|
||||||
app := newTestApp(func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") })
|
app := newTestApp(func(ctx *cli.Context) error { return errors.New("normal error") })
|
||||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
r, err := runTestApp(app, "./gitea", "test-cmd")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) })
|
app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 2, r.ExitCode)
|
assert.Equal(t, 2, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
assert.Equal(t, "exit error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return nil })
|
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
|
||||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
assert.Empty(t, r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
||||||
|
|
||||||
app = newTestApp(func(ctx context.Context, cmd *cli.Command) error { return nil })
|
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -19,7 +18,7 @@ var (
|
|||||||
Name: "manager",
|
Name: "manager",
|
||||||
Usage: "Manage the running gitea process",
|
Usage: "Manage the running gitea process",
|
||||||
Description: "This is a command for managing the running gitea process",
|
Description: "This is a command for managing the running gitea process",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdShutdown,
|
subcmdShutdown,
|
||||||
subcmdRestart,
|
subcmdRestart,
|
||||||
subcmdReloadTemplates,
|
subcmdReloadTemplates,
|
||||||
@ -109,31 +108,46 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runShutdown(ctx context.Context, c *cli.Command) error {
|
func runShutdown(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
extra := private.Shutdown(ctx)
|
extra := private.Shutdown(ctx)
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestart(ctx context.Context, c *cli.Command) error {
|
func runRestart(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
extra := private.Restart(ctx)
|
extra := private.Restart(ctx)
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReloadTemplates(ctx context.Context, c *cli.Command) error {
|
func runReloadTemplates(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
extra := private.ReloadTemplates(ctx)
|
extra := private.ReloadTemplates(ctx)
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFlushQueues(ctx context.Context, c *cli.Command) error {
|
func runFlushQueues(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
|
extra := private.FlushQueues(ctx, c.Duration("timeout"), c.Bool("non-blocking"))
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runProcesses(ctx context.Context, c *cli.Command) error {
|
func runProcesses(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
|
extra := private.Processes(ctx, os.Stdout, c.Bool("flat"), c.Bool("no-system"), c.Bool("stacktraces"), c.Bool("json"), c.String("cancel"))
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@ -12,7 +11,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -61,7 +60,7 @@ var (
|
|||||||
subcmdLogging = &cli.Command{
|
subcmdLogging = &cli.Command{
|
||||||
Name: "logging",
|
Name: "logging",
|
||||||
Usage: "Adjust logging commands",
|
Usage: "Adjust logging commands",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "pause",
|
Name: "pause",
|
||||||
Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)",
|
Usage: "Pause logging (Gitea will buffer logs up to a certain point and will drop them after that point)",
|
||||||
@ -105,7 +104,7 @@ var (
|
|||||||
}, {
|
}, {
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "Add a logger",
|
Usage: "Add a logger",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Usage: "Add a file logger",
|
Usage: "Add a file logger",
|
||||||
@ -193,7 +192,10 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
func runRemoveLogger(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
logger := c.String("logger")
|
logger := c.String("logger")
|
||||||
if len(logger) == 0 {
|
if len(logger) == 0 {
|
||||||
@ -205,7 +207,10 @@ func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
|||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddConnLogger(ctx context.Context, c *cli.Command) error {
|
func runAddConnLogger(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
vals := map[string]any{}
|
vals := map[string]any{}
|
||||||
mode := "conn"
|
mode := "conn"
|
||||||
@ -229,10 +234,13 @@ func runAddConnLogger(ctx context.Context, c *cli.Command) error {
|
|||||||
if c.IsSet("reconnect-on-message") {
|
if c.IsSet("reconnect-on-message") {
|
||||||
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
vals["reconnectOnMsg"] = c.Bool("reconnect-on-message")
|
||||||
}
|
}
|
||||||
return commonAddLogger(ctx, c, mode, vals)
|
return commonAddLogger(c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddFileLogger(ctx context.Context, c *cli.Command) error {
|
func runAddFileLogger(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
vals := map[string]any{}
|
vals := map[string]any{}
|
||||||
mode := "file"
|
mode := "file"
|
||||||
@ -259,10 +267,10 @@ func runAddFileLogger(ctx context.Context, c *cli.Command) error {
|
|||||||
if c.IsSet("compression-level") {
|
if c.IsSet("compression-level") {
|
||||||
vals["compressionLevel"] = c.Int("compression-level")
|
vals["compressionLevel"] = c.Int("compression-level")
|
||||||
}
|
}
|
||||||
return commonAddLogger(ctx, c, mode, vals)
|
return commonAddLogger(c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[string]any) error {
|
func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
||||||
if len(c.String("level")) > 0 {
|
if len(c.String("level")) > 0 {
|
||||||
vals["level"] = log.LevelFromString(c.String("level")).String()
|
vals["level"] = log.LevelFromString(c.String("level")).String()
|
||||||
}
|
}
|
||||||
@ -289,33 +297,46 @@ func commonAddLogger(ctx context.Context, c *cli.Command, mode string, vals map[
|
|||||||
if c.IsSet("writer") {
|
if c.IsSet("writer") {
|
||||||
writer = c.String("writer")
|
writer = c.String("writer")
|
||||||
}
|
}
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
extra := private.AddLogger(ctx, logger, writer, mode, vals)
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runPauseLogging(ctx context.Context, c *cli.Command) error {
|
func runPauseLogging(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
userMsg := private.PauseLogging(ctx)
|
userMsg := private.PauseLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runResumeLogging(ctx context.Context, c *cli.Command) error {
|
func runResumeLogging(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
userMsg := private.ResumeLogging(ctx)
|
userMsg := private.ResumeLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error {
|
func runReleaseReopenLogging(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
userMsg := private.ReleaseReopenLogging(ctx)
|
userMsg := private.ReleaseReopenLogging(ctx)
|
||||||
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
_, _ = fmt.Fprintln(os.Stdout, userMsg)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSetLogSQL(ctx context.Context, c *cli.Command) error {
|
func runSetLogSQL(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/services/versioned_migration"
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrate represents the available migrate sub-command.
|
// CmdMigrate represents the available migrate sub-command.
|
||||||
@ -22,8 +22,11 @@ var CmdMigrate = &cli.Command{
|
|||||||
Action: runMigrate,
|
Action: runMigrate,
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrate(ctx context.Context, c *cli.Command) error {
|
func runMigrate(ctx *cli.Context) error {
|
||||||
if err := initDB(ctx); err != nil {
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(stdCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/services/versioned_migration"
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrateStorage represents the available migrate storage sub-command.
|
// CmdMigrateStorage represents the available migrate storage sub-command.
|
||||||
@ -213,8 +213,11 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrateStorage(ctx context.Context, cmd *cli.Command) error {
|
func runMigrateStorage(ctx *cli.Context) error {
|
||||||
if err := initDB(ctx); err != nil {
|
stdCtx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := initDB(stdCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,51 +238,51 @@ func runMigrateStorage(ctx context.Context, cmd *cli.Command) error {
|
|||||||
|
|
||||||
var dstStorage storage.ObjectStorage
|
var dstStorage storage.ObjectStorage
|
||||||
var err error
|
var err error
|
||||||
switch strings.ToLower(cmd.String("storage")) {
|
switch strings.ToLower(ctx.String("storage")) {
|
||||||
case "":
|
case "":
|
||||||
fallthrough
|
fallthrough
|
||||||
case string(setting.LocalStorageType):
|
case string(setting.LocalStorageType):
|
||||||
p := cmd.String("path")
|
p := ctx.String("path")
|
||||||
if p == "" {
|
if p == "" {
|
||||||
log.Fatal("Path must be given when storage is local")
|
log.Fatal("Path must be given when storage is local")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dstStorage, err = storage.NewLocalStorage(
|
dstStorage, err = storage.NewLocalStorage(
|
||||||
ctx,
|
stdCtx,
|
||||||
&setting.Storage{
|
&setting.Storage{
|
||||||
Path: p,
|
Path: p,
|
||||||
})
|
})
|
||||||
case string(setting.MinioStorageType):
|
case string(setting.MinioStorageType):
|
||||||
dstStorage, err = storage.NewMinioStorage(
|
dstStorage, err = storage.NewMinioStorage(
|
||||||
ctx,
|
stdCtx,
|
||||||
&setting.Storage{
|
&setting.Storage{
|
||||||
MinioConfig: setting.MinioStorageConfig{
|
MinioConfig: setting.MinioStorageConfig{
|
||||||
Endpoint: cmd.String("minio-endpoint"),
|
Endpoint: ctx.String("minio-endpoint"),
|
||||||
AccessKeyID: cmd.String("minio-access-key-id"),
|
AccessKeyID: ctx.String("minio-access-key-id"),
|
||||||
SecretAccessKey: cmd.String("minio-secret-access-key"),
|
SecretAccessKey: ctx.String("minio-secret-access-key"),
|
||||||
Bucket: cmd.String("minio-bucket"),
|
Bucket: ctx.String("minio-bucket"),
|
||||||
Location: cmd.String("minio-location"),
|
Location: ctx.String("minio-location"),
|
||||||
BasePath: cmd.String("minio-base-path"),
|
BasePath: ctx.String("minio-base-path"),
|
||||||
UseSSL: cmd.Bool("minio-use-ssl"),
|
UseSSL: ctx.Bool("minio-use-ssl"),
|
||||||
InsecureSkipVerify: cmd.Bool("minio-insecure-skip-verify"),
|
InsecureSkipVerify: ctx.Bool("minio-insecure-skip-verify"),
|
||||||
ChecksumAlgorithm: cmd.String("minio-checksum-algorithm"),
|
ChecksumAlgorithm: ctx.String("minio-checksum-algorithm"),
|
||||||
BucketLookUpType: cmd.String("minio-bucket-lookup-type"),
|
BucketLookUpType: ctx.String("minio-bucket-lookup-type"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
case string(setting.AzureBlobStorageType):
|
case string(setting.AzureBlobStorageType):
|
||||||
dstStorage, err = storage.NewAzureBlobStorage(
|
dstStorage, err = storage.NewAzureBlobStorage(
|
||||||
ctx,
|
stdCtx,
|
||||||
&setting.Storage{
|
&setting.Storage{
|
||||||
AzureBlobConfig: setting.AzureBlobStorageConfig{
|
AzureBlobConfig: setting.AzureBlobStorageConfig{
|
||||||
Endpoint: cmd.String("azureblob-endpoint"),
|
Endpoint: ctx.String("azureblob-endpoint"),
|
||||||
AccountName: cmd.String("azureblob-account-name"),
|
AccountName: ctx.String("azureblob-account-name"),
|
||||||
AccountKey: cmd.String("azureblob-account-key"),
|
AccountKey: ctx.String("azureblob-account-key"),
|
||||||
Container: cmd.String("azureblob-container"),
|
Container: ctx.String("azureblob-container"),
|
||||||
BasePath: cmd.String("azureblob-base-path"),
|
BasePath: ctx.String("azureblob-base-path"),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported storage type: %s", cmd.String("storage"))
|
return fmt.Errorf("unsupported storage type: %s", ctx.String("storage"))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -296,14 +299,14 @@ func runMigrateStorage(ctx context.Context, cmd *cli.Command) error {
|
|||||||
"actions-artifacts": migrateActionsArtifacts,
|
"actions-artifacts": migrateActionsArtifacts,
|
||||||
}
|
}
|
||||||
|
|
||||||
tp := strings.ToLower(cmd.String("type"))
|
tp := strings.ToLower(ctx.String("type"))
|
||||||
if m, ok := migratedMethods[tp]; ok {
|
if m, ok := migratedMethods[tp]; ok {
|
||||||
if err := m(ctx, dstStorage); err != nil {
|
if err := m(stdCtx, dstStorage); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("%s files have successfully been copied to the new storage.", tp)
|
log.Info("%s files have successfully been copied to the new storage.", tp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("unsupported storage: %s", cmd.String("type"))
|
return fmt.Errorf("unsupported storage: %s", ctx.String("type"))
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,12 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdRestoreRepository represents the available restore a repository sub-command.
|
// CmdRestoreRepository represents the available restore a repository sub-command.
|
||||||
@ -49,7 +48,10 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestoreRepository(ctx context.Context, c *cli.Command) error {
|
func runRestoreRepository(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
var units []string
|
var units []string
|
||||||
if s := c.String("units"); s != "" {
|
if s := c.String("units"); s != "" {
|
||||||
|
10
cmd/serv.go
10
cmd/serv.go
@ -33,7 +33,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/kballard/go-shellquote"
|
"github.com/kballard/go-shellquote"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdServ represents the available serv sub-command.
|
// CmdServ represents the available serv sub-command.
|
||||||
@ -41,7 +41,6 @@ var CmdServ = &cli.Command{
|
|||||||
Name: "serv",
|
Name: "serv",
|
||||||
Usage: "(internal) Should only be called by SSH shell",
|
Usage: "(internal) Should only be called by SSH shell",
|
||||||
Description: "Serv provides access auth for repositories",
|
Description: "Serv provides access auth for repositories",
|
||||||
Hidden: true, // Internal commands shouldn't be visible in help
|
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Action: runServ,
|
Action: runServ,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
@ -153,7 +152,10 @@ func getLFSAuthToken(ctx context.Context, lfsVerb string, results *private.ServC
|
|||||||
return "Bearer " + tokenString, nil
|
return "Bearer " + tokenString, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServ(ctx context.Context, c *cli.Command) error {
|
func runServ(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
// FIXME: This needs to internationalised
|
// FIXME: This needs to internationalised
|
||||||
setup(ctx, c.Bool("debug"))
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
@ -213,7 +215,7 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
|||||||
if git.DefaultFeatures().SupportProcReceive {
|
if git.DefaultFeatures().SupportProcReceive {
|
||||||
// for AGit Flow
|
// for AGit Flow
|
||||||
if cmd == "ssh_info" {
|
if cmd == "ssh_info" {
|
||||||
fmt.Print(`{"type":"agit","version":1}`)
|
fmt.Print(`{"type":"gitea","version":1}`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
cmd/web.go
32
cmd/web.go
@ -28,7 +28,7 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/install"
|
"code.gitea.io/gitea/routers/install"
|
||||||
|
|
||||||
"github.com/felixge/fgprof"
|
"github.com/felixge/fgprof"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PIDFile could be set from build tag
|
// PIDFile could be set from build tag
|
||||||
@ -130,19 +130,19 @@ func showWebStartupMessage(msg string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstall(cmd *cli.Command) error {
|
func serveInstall(ctx *cli.Context) error {
|
||||||
showWebStartupMessage("Prepare to run install page")
|
showWebStartupMessage("Prepare to run install page")
|
||||||
|
|
||||||
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
||||||
|
|
||||||
// Flag for port number in case first time run conflict
|
// Flag for port number in case first time run conflict
|
||||||
if cmd.IsSet("port") {
|
if ctx.IsSet("port") {
|
||||||
if err := setPort(cmd.String("port")); err != nil {
|
if err := setPort(ctx.String("port")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cmd.IsSet("install-port") {
|
if ctx.IsSet("install-port") {
|
||||||
if err := setPort(cmd.String("install-port")); err != nil {
|
if err := setPort(ctx.String("install-port")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ func serveInstall(cmd *cli.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstalled(c *cli.Command) error {
|
func serveInstalled(ctx *cli.Context) error {
|
||||||
setting.InitCfgProvider(setting.CustomConf)
|
setting.InitCfgProvider(setting.CustomConf)
|
||||||
setting.LoadCommonSettings()
|
setting.LoadCommonSettings()
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
@ -218,8 +218,8 @@ func serveInstalled(c *cli.Command) error {
|
|||||||
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
|
setting.AppDataTempDir("").RemoveOutdated(3 * 24 * time.Hour)
|
||||||
|
|
||||||
// Override the provided port number within the configuration
|
// Override the provided port number within the configuration
|
||||||
if c.IsSet("port") {
|
if ctx.IsSet("port") {
|
||||||
if err := setPort(c.String("port")); err != nil {
|
if err := setPort(ctx.String("port")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,17 +244,13 @@ func servePprof() {
|
|||||||
finished()
|
finished()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb(_ context.Context, cmd *cli.Command) error {
|
func runWeb(ctx *cli.Context) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
if panicked := recover(); panicked != nil {
|
if panicked := recover(); panicked != nil {
|
||||||
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
log.Fatal("PANIC: %v\n%s", panicked, log.Stack(2))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if subCmdName, valid := isValidDefaultSubCommand(cmd); !valid {
|
|
||||||
return fmt.Errorf("unknown command: %s", subCmdName)
|
|
||||||
}
|
|
||||||
|
|
||||||
managerCtx, cancel := context.WithCancel(context.Background())
|
managerCtx, cancel := context.WithCancel(context.Background())
|
||||||
graceful.InitManager(managerCtx)
|
graceful.InitManager(managerCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -266,12 +262,12 @@ func runWeb(_ context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set pid file setting
|
// Set pid file setting
|
||||||
if cmd.IsSet("pid") {
|
if ctx.IsSet("pid") {
|
||||||
createPIDFile(cmd.String("pid"))
|
createPIDFile(ctx.String("pid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.InstallLock {
|
if !setting.InstallLock {
|
||||||
if err := serveInstall(cmd); err != nil {
|
if err := serveInstall(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -282,7 +278,7 @@ func runWeb(_ context.Context, cmd *cli.Command) error {
|
|||||||
go servePprof()
|
go servePprof()
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveInstalled(cmd)
|
return serveInstalled(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPort(port string) error {
|
func setPort(port string) error {
|
||||||
|
@ -23,6 +23,12 @@ func NoHTTPRedirector() {
|
|||||||
graceful.GetManager().InformCleanup()
|
graceful.GetManager().InformCleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoMainListener tells our cleanup routine that we will not be using a possibly provided listener
|
||||||
|
// for our main HTTP/HTTPS service
|
||||||
|
func NoMainListener() {
|
||||||
|
graceful.GetManager().InformCleanup()
|
||||||
|
}
|
||||||
|
|
||||||
// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
|
// NoInstallListener tells our cleanup routine that we will not be using a possibly provided listener
|
||||||
// for our install HTTP/HTTPS service
|
// for our install HTTP/HTTPS service
|
||||||
func NoInstallListener() {
|
func NoInstallListener() {
|
||||||
|
17
contrib/autocompletion/README
Normal file
17
contrib/autocompletion/README
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Bash and Zsh completion
|
||||||
|
=======================
|
||||||
|
|
||||||
|
From within the gitea root run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source contrib/autocompletion/bash_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
or for zsh run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source contrib/autocompletion/zsh_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
These scripts will check if gitea is on the path and if so add autocompletion for `gitea`. Or if not autocompletion will work for `./gitea`.
|
||||||
|
If gitea has been installed as a different program pass in the `PROG` environment variable to set the correct program name.
|
30
contrib/autocompletion/bash_autocomplete
Executable file
30
contrib/autocompletion/bash_autocomplete
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# Heavily inspired by https://github.com/urfave/cli
|
||||||
|
|
||||||
|
_cli_bash_autocomplete() {
|
||||||
|
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
|
||||||
|
local cur opts base
|
||||||
|
COMPREPLY=()
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
if [[ "$cur" == "-"* ]]; then
|
||||||
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
|
||||||
|
else
|
||||||
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||||
|
fi
|
||||||
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "$PROG" ] && [ ! "$(command -v gitea &> /dev/null)" ] ; then
|
||||||
|
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete gitea
|
||||||
|
elif [ -z "$PROG" ]; then
|
||||||
|
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete ./gitea
|
||||||
|
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PWD/gitea"
|
||||||
|
else
|
||||||
|
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete "$PROG"
|
||||||
|
unset PROG
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
30
contrib/autocompletion/zsh_autocomplete
Normal file
30
contrib/autocompletion/zsh_autocomplete
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#compdef ${PROG:=gitea}
|
||||||
|
|
||||||
|
|
||||||
|
# Heavily inspired by https://github.com/urfave/cli
|
||||||
|
|
||||||
|
_cli_zsh_autocomplete() {
|
||||||
|
|
||||||
|
local -a opts
|
||||||
|
local cur
|
||||||
|
cur=${words[-1]}
|
||||||
|
if [[ "$cur" == "-"* ]]; then
|
||||||
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
|
||||||
|
else
|
||||||
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${opts[1]}" != "" ]]; then
|
||||||
|
_describe 'values' opts
|
||||||
|
else
|
||||||
|
_files
|
||||||
|
fi
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z $PROG ] ; then
|
||||||
|
compdef _cli_zsh_autocomplete gitea
|
||||||
|
else
|
||||||
|
compdef _cli_zsh_autocomplete $(basename $PROG)
|
||||||
|
fi
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright 2023 The Gitea Authors. All rights reserved.
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
//nolint:forbidigo // use of print functions is allowed in cli
|
//nolint:forbidigo
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -12,19 +12,21 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/google/go-github/v71/github"
|
"github.com/google/go-github/v71/github"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultVersion = "v1.18" // to backport to
|
const defaultVersion = "v1.18" // to backport to
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := &cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Name = "backport"
|
app.Name = "backport"
|
||||||
app.Usage = "Backport provided PR-number on to the current or previous released version"
|
app.Usage = "Backport provided PR-number on to the current or previous released version"
|
||||||
app.Description = `Backport will look-up the PR in Gitea's git log and attempt to cherry-pick it on the current version`
|
app.Description = `Backport will look-up the PR in Gitea's git log and attempt to cherry-pick it on the current version`
|
||||||
@ -89,7 +91,7 @@ func main() {
|
|||||||
Usage: "Set this flag to continue from a git cherry-pick that has broken",
|
Usage: "Set this flag to continue from a git cherry-pick that has broken",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cli.RootCommandHelpTemplate = `NAME:
|
cli.AppHelpTemplate = `NAME:
|
||||||
{{.Name}} - {{.Usage}}
|
{{.Name}} - {{.Usage}}
|
||||||
USAGE:
|
USAGE:
|
||||||
{{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
{{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
@ -103,12 +105,16 @@ OPTIONS:
|
|||||||
`
|
`
|
||||||
|
|
||||||
app.Action = runBackport
|
app.Action = runBackport
|
||||||
if err := app.Run(context.Background(), os.Args); err != nil {
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBackport(ctx context.Context, c *cli.Command) error {
|
func runBackport(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
continuing := c.Bool("continue")
|
continuing := c.Bool("continue")
|
||||||
|
|
||||||
var pr string
|
var pr string
|
||||||
@ -337,8 +343,8 @@ func determineRemote(ctx context.Context, forkUser string) (string, string, erro
|
|||||||
fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out))
|
fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out))
|
||||||
return "", "", fmt.Errorf("unable to determine forked remote: %w", err)
|
return "", "", fmt.Errorf("unable to determine forked remote: %w", err)
|
||||||
}
|
}
|
||||||
lines := strings.SplitSeq(string(out), "\n")
|
lines := strings.Split(string(out), "\n")
|
||||||
for line := range lines {
|
for _, line := range lines {
|
||||||
fields := strings.Split(line, "\t")
|
fields := strings.Split(line, "\t")
|
||||||
name, remote := fields[0], fields[1]
|
name, remote := fields[0], fields[1]
|
||||||
// only look at pushers
|
// only look at pushers
|
||||||
@ -356,12 +362,12 @@ func determineRemote(ctx context.Context, forkUser string) (string, string, erro
|
|||||||
if !strings.Contains(remote, forkUser) {
|
if !strings.Contains(remote, forkUser) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if after, ok := strings.CutPrefix(remote, "git@github.com:"); ok {
|
if strings.HasPrefix(remote, "git@github.com:") {
|
||||||
forkUser = after
|
forkUser = strings.TrimPrefix(remote, "git@github.com:")
|
||||||
} else if after, ok := strings.CutPrefix(remote, "https://github.com/"); ok {
|
} else if strings.HasPrefix(remote, "https://github.com/") {
|
||||||
forkUser = after
|
forkUser = strings.TrimPrefix(remote, "https://github.com/")
|
||||||
} else if after, ok := strings.CutPrefix(remote, "https://www.github.com/"); ok {
|
} else if strings.HasPrefix(remote, "https://www.github.com/") {
|
||||||
forkUser = after
|
forkUser = strings.TrimPrefix(remote, "https://www.github.com/")
|
||||||
} else if forkUser == "" {
|
} else if forkUser == "" {
|
||||||
return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote)
|
return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote)
|
||||||
}
|
}
|
||||||
@ -454,3 +460,25 @@ func determineSHAforPR(ctx context.Context, prStr, accessToken string) (string,
|
|||||||
|
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func installSignals() (context.Context, context.CancelFunc) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
go func() {
|
||||||
|
// install notify
|
||||||
|
signalChannel := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(
|
||||||
|
signalChannel,
|
||||||
|
syscall.SIGINT,
|
||||||
|
syscall.SIGTERM,
|
||||||
|
)
|
||||||
|
select {
|
||||||
|
case <-signalChannel:
|
||||||
|
case <-ctx.Done():
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
signal.Reset()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ctx, cancel
|
||||||
|
}
|
||||||
|
@ -4,17 +4,16 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Name = "environment-to-ini"
|
app.Name = "environment-to-ini"
|
||||||
app.Usage = "Use provided environment to update configuration ini"
|
app.Usage = "Use provided environment to update configuration ini"
|
||||||
app.Description = `As a helper to allow docker users to update the gitea configuration
|
app.Description = `As a helper to allow docker users to update the gitea configuration
|
||||||
@ -73,13 +72,13 @@ func main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Action = runEnvironmentToIni
|
app.Action = runEnvironmentToIni
|
||||||
err := app.Run(context.Background(), os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
log.Fatal("Failed to run app with %s: %v", os.Args, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runEnvironmentToIni(_ context.Context, c *cli.Command) error {
|
func runEnvironmentToIni(c *cli.Context) error {
|
||||||
// the config system may change the environment variables, so get a copy first, to be used later
|
// the config system may change the environment variables, so get a copy first, to be used later
|
||||||
env := append([]string{}, os.Environ()...)
|
env := append([]string{}, os.Environ()...)
|
||||||
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
setting.InitWorkPathAndCfgProvider(os.Getenv, setting.ArgWorkPathAndCustomConf{
|
||||||
|
@ -85,7 +85,7 @@ fi
|
|||||||
# confirm update
|
# confirm update
|
||||||
echo "Checking currently installed version..."
|
echo "Checking currently installed version..."
|
||||||
current=$(giteacmd --version | cut -d ' ' -f 3)
|
current=$(giteacmd --version | cut -d ' ' -f 3)
|
||||||
[[ "$current" == "$giteaversion" ]] && echo "$current is already installed, stopping." && exit 0
|
[[ "$current" == "$giteaversion" ]] && echo "$current is already installed, stopping." && exit 1
|
||||||
if [[ -z "${no_confirm:-}" ]]; then
|
if [[ -z "${no_confirm:-}" ]]; then
|
||||||
echo "Make sure to read the changelog first: https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md"
|
echo "Make sure to read the changelog first: https://github.com/go-gitea/gitea/blob/main/CHANGELOG.md"
|
||||||
echo "Are you ready to update Gitea from ${current} to ${giteaversion}? (y/N)"
|
echo "Are you ready to update Gitea from ${current} to ${giteaversion}? (y/N)"
|
||||||
|
@ -186,13 +186,17 @@ RUN_USER = ; git
|
|||||||
;; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off.
|
;; If you intend to use the AuthorizedPrincipalsCommand functionality then you should turn this off.
|
||||||
;SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true
|
;SSH_CREATE_AUTHORIZED_PRINCIPALS_FILE = true
|
||||||
;;
|
;;
|
||||||
;; For the builtin SSH server, choose the supported ciphers/key-exchange-algorithms/MACs for SSH connections.
|
;; For the built-in SSH server, choose the ciphers to support for SSH connections,
|
||||||
;; The supported names are listed in https://github.com/golang/crypto/blob/master/ssh/common.go.
|
;; for system SSH this setting has no effect
|
||||||
;; Leave them empty to use the Golang crypto's recommended default values.
|
;SSH_SERVER_CIPHERS = chacha20-poly1305@openssh.com, aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, aes256-gcm@openssh.com
|
||||||
;; For system SSH (non-builtin SSH server), this setting has no effect.
|
;;
|
||||||
;SSH_SERVER_CIPHERS =
|
;; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections,
|
||||||
;SSH_SERVER_KEY_EXCHANGES =
|
;; for system SSH this setting has no effect
|
||||||
;SSH_SERVER_MACS =
|
;SSH_SERVER_KEY_EXCHANGES = curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
|
||||||
|
;;
|
||||||
|
;; For the built-in SSH server, choose the MACs to support for SSH connections,
|
||||||
|
;; for system SSH this setting has no effect
|
||||||
|
;SSH_SERVER_MACS = hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1
|
||||||
;;
|
;;
|
||||||
;; For the built-in SSH server, choose the keypair to offer as the host key
|
;; For the built-in SSH server, choose the keypair to offer as the host key
|
||||||
;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
|
;; The private key should be at SSH_SERVER_HOST_KEY and the public SSH_SERVER_HOST_KEY.pub
|
||||||
@ -1186,24 +1190,17 @@ LEVEL = Info
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; GPG or SSH key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey
|
;; GPG key to use to sign commits, Defaults to the default - that is the value of git config --get user.signingkey
|
||||||
;; Depending on the value of SIGNING_FORMAT this is either:
|
|
||||||
;; - openpgp: the GPG key ID
|
|
||||||
;; - ssh: the path to the ssh public key "/path/to/key.pub": where "/path/to/key" is the private key, use ssh-keygen -t ed25519 to generate a new key pair without password
|
|
||||||
;; run in the context of the RUN_USER
|
;; run in the context of the RUN_USER
|
||||||
;; Switch to none to stop signing completely
|
;; Switch to none to stop signing completely
|
||||||
;SIGNING_KEY = default
|
;SIGNING_KEY = default
|
||||||
;;
|
;;
|
||||||
;; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer and the signing format.
|
;; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer.
|
||||||
;; These should match a publicized name and email address for the key. (When SIGNING_KEY is default these are set to
|
;; These should match a publicized name and email address for the key. (When SIGNING_KEY is default these are set to
|
||||||
;; the results of git config --get user.name, git config --get user.email and git config --default openpgp --get gpg.format respectively and can only be overridden
|
;; the results of git config --get user.name and git config --get user.email respectively and can only be overridden
|
||||||
;; by setting the SIGNING_KEY ID to the correct ID.)
|
;; by setting the SIGNING_KEY ID to the correct ID.)
|
||||||
;SIGNING_NAME =
|
;SIGNING_NAME =
|
||||||
;SIGNING_EMAIL =
|
;SIGNING_EMAIL =
|
||||||
;; SIGNING_FORMAT can be one of:
|
|
||||||
;; - openpgp (default): use GPG to sign commits
|
|
||||||
;; - ssh: use SSH to sign commits
|
|
||||||
;SIGNING_FORMAT = openpgp
|
|
||||||
;;
|
;;
|
||||||
;; Sets the default trust model for repositories. Options are: collaborator, committer, collaboratorcommitter
|
;; Sets the default trust model for repositories. Options are: collaborator, committer, collaboratorcommitter
|
||||||
;DEFAULT_TRUST_MODEL = collaborator
|
;DEFAULT_TRUST_MODEL = collaborator
|
||||||
@ -1230,13 +1227,6 @@ LEVEL = Info
|
|||||||
;; - commitssigned: require that all the commits in the head branch are signed.
|
;; - commitssigned: require that all the commits in the head branch are signed.
|
||||||
;; - approved: only sign when merging an approved pr to a protected branch
|
;; - approved: only sign when merging an approved pr to a protected branch
|
||||||
;MERGES = pubkey, twofa, basesigned, commitssigned
|
;MERGES = pubkey, twofa, basesigned, commitssigned
|
||||||
;;
|
|
||||||
;; Determines which additional ssh keys are trusted for all signed commits regardless of the user
|
|
||||||
;; This is useful for ssh signing key rotation.
|
|
||||||
;; Exposes the provided SIGNING_NAME and SIGNING_EMAIL as the signer, regardless of the SIGNING_FORMAT value.
|
|
||||||
;; Multiple keys should be comma separated.
|
|
||||||
;; E.g."ssh-<algorithm> <key>". or "ssh-<algorithm> <key1>, ssh-<algorithm> <key2>".
|
|
||||||
;TRUSTED_SSH_KEYS =
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755186698,
|
"lastModified": 1747179050,
|
||||||
"narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
|
"narHash": "sha256-qhFMmDkeJX9KJwr5H32f1r7Prs7XbQWtO0h3V0a0rFY=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
|
"rev": "adaa24fbf46737f3f1b5497bf64bae750f82942e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
73
flake.nix
73
flake.nix
@ -11,58 +11,33 @@
|
|||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.default =
|
devShells.default = pkgs.mkShell {
|
||||||
with pkgs;
|
buildInputs = with pkgs; [
|
||||||
let
|
# generic
|
||||||
# only bump toolchain versions here
|
git
|
||||||
go = go_1_25;
|
git-lfs
|
||||||
nodejs = nodejs_24;
|
gnumake
|
||||||
python3 = python312;
|
gnused
|
||||||
|
gnutar
|
||||||
|
gzip
|
||||||
|
|
||||||
# Platform-specific dependencies
|
# frontend
|
||||||
linuxOnlyInputs = lib.optionals pkgs.stdenv.isLinux [
|
nodejs_22
|
||||||
glibc.static
|
|
||||||
];
|
|
||||||
|
|
||||||
linuxOnlyEnv = lib.optionalAttrs pkgs.stdenv.isLinux {
|
# linting
|
||||||
CFLAGS = "-I${glibc.static.dev}/include";
|
python312
|
||||||
LDFLAGS = "-L ${glibc.static}/lib";
|
poetry
|
||||||
};
|
|
||||||
in
|
|
||||||
pkgs.mkShell (
|
|
||||||
{
|
|
||||||
buildInputs = [
|
|
||||||
# generic
|
|
||||||
git
|
|
||||||
git-lfs
|
|
||||||
gnumake
|
|
||||||
gnused
|
|
||||||
gnutar
|
|
||||||
gzip
|
|
||||||
zip
|
|
||||||
|
|
||||||
# frontend
|
# backend
|
||||||
nodejs
|
go_1_24
|
||||||
|
gofumpt
|
||||||
# linting
|
sqlite
|
||||||
python3
|
];
|
||||||
uv
|
shellHook = ''
|
||||||
|
export GO="${pkgs.go_1_24}/bin/go"
|
||||||
# backend
|
export GOROOT="${pkgs.go_1_24}/share/go"
|
||||||
go
|
'';
|
||||||
gofumpt
|
};
|
||||||
sqlite
|
|
||||||
]
|
|
||||||
++ linuxOnlyInputs;
|
|
||||||
|
|
||||||
GO = "${go}/bin/go";
|
|
||||||
GOROOT = "${go}/share/go";
|
|
||||||
|
|
||||||
TAGS = "sqlite sqlite_unlock_notify";
|
|
||||||
STATIC = "true";
|
|
||||||
}
|
|
||||||
// linuxOnlyEnv
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
71
go.mod
71
go.mod
@ -1,6 +1,6 @@
|
|||||||
module code.gitea.io/gitea
|
module code.gitea.io/gitea
|
||||||
|
|
||||||
go 1.24.6
|
go 1.24
|
||||||
|
|
||||||
// rfc5280 said: "The serial number is an integer assigned by the CA to each certificate."
|
// 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:
|
// But some CAs use negative serial number, just relax the check. related:
|
||||||
@ -27,7 +27,7 @@ require (
|
|||||||
github.com/ProtonMail/go-crypto v1.2.0
|
github.com/ProtonMail/go-crypto v1.2.0
|
||||||
github.com/PuerkitoBio/goquery v1.10.3
|
github.com/PuerkitoBio/goquery v1.10.3
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
||||||
github.com/alecthomas/chroma/v2 v2.20.0
|
github.com/alecthomas/chroma/v2 v2.17.0
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.67
|
||||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.2
|
github.com/aws/aws-sdk-go-v2/service/codecommit v1.28.2
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||||
@ -60,6 +60,7 @@ require (
|
|||||||
github.com/go-ldap/ldap/v3 v3.4.11
|
github.com/go-ldap/ldap/v3 v3.4.11
|
||||||
github.com/go-redsync/redsync/v4 v4.13.0
|
github.com/go-redsync/redsync/v4 v4.13.0
|
||||||
github.com/go-sql-driver/mysql v1.9.2
|
github.com/go-sql-driver/mysql v1.9.2
|
||||||
|
github.com/go-swagger/go-swagger v0.31.0
|
||||||
github.com/go-webauthn/webauthn v0.12.3
|
github.com/go-webauthn/webauthn v0.12.3
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||||
@ -91,7 +92,7 @@ require (
|
|||||||
github.com/minio/minio-go/v7 v7.0.91
|
github.com/minio/minio-go/v7 v7.0.91
|
||||||
github.com/msteinert/pam v1.2.0
|
github.com/msteinert/pam v1.2.0
|
||||||
github.com/nektos/act v0.2.63
|
github.com/nektos/act v0.2.63
|
||||||
github.com/niklasfasching/go-org v1.8.0
|
github.com/niklasfasching/go-org v1.7.0
|
||||||
github.com/olivere/elastic/v7 v7.0.32
|
github.com/olivere/elastic/v7 v7.0.32
|
||||||
github.com/opencontainers/go-digest v1.0.0
|
github.com/opencontainers/go-digest v1.0.0
|
||||||
github.com/opencontainers/image-spec v1.1.1
|
github.com/opencontainers/image-spec v1.1.1
|
||||||
@ -104,12 +105,12 @@ require (
|
|||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||||
github.com/sassoftware/go-rpmutils v0.4.0
|
github.com/sassoftware/go-rpmutils v0.4.0
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||||
|
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/tstranex/u2f v1.0.0
|
github.com/tstranex/u2f v1.0.0
|
||||||
github.com/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
github.com/urfave/cli-docs/v3 v3.0.0-alpha6
|
github.com/urfave/cli/v2 v2.27.6
|
||||||
github.com/urfave/cli/v3 v3.3.3
|
|
||||||
github.com/wneessen/go-mail v0.6.2
|
github.com/wneessen/go-mail v0.6.2
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
github.com/yohcop/openid-go v1.0.1
|
github.com/yohcop/openid-go v1.0.1
|
||||||
@ -117,13 +118,14 @@ require (
|
|||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
gitlab.com/gitlab-org/api/client-go v0.127.0
|
gitlab.com/gitlab-org/api/client-go v0.127.0
|
||||||
golang.org/x/crypto v0.39.0
|
golang.org/x/crypto v0.37.0
|
||||||
golang.org/x/image v0.26.0
|
golang.org/x/image v0.26.0
|
||||||
golang.org/x/net v0.40.0
|
golang.org/x/net v0.39.0
|
||||||
golang.org/x/oauth2 v0.29.0
|
golang.org/x/oauth2 v0.29.0
|
||||||
golang.org/x/sync v0.15.0
|
golang.org/x/sync v0.13.0
|
||||||
golang.org/x/sys v0.33.0
|
golang.org/x/sys v0.32.0
|
||||||
golang.org/x/text v0.26.0
|
golang.org/x/text v0.24.0
|
||||||
|
golang.org/x/tools v0.32.0
|
||||||
google.golang.org/grpc v1.72.0
|
google.golang.org/grpc v1.72.0
|
||||||
google.golang.org/protobuf v1.36.6
|
google.golang.org/protobuf v1.36.6
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
@ -131,7 +133,7 @@ require (
|
|||||||
mvdan.cc/xurls/v2 v2.6.0
|
mvdan.cc/xurls/v2 v2.6.0
|
||||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||||
xorm.io/builder v0.3.13
|
xorm.io/builder v0.3.13
|
||||||
xorm.io/xorm v1.3.10
|
xorm.io/xorm v1.3.9
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -141,11 +143,15 @@ require (
|
|||||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
|
||||||
github.com/DataDog/zstd v1.5.7 // indirect
|
github.com/DataDog/zstd v1.5.7 // indirect
|
||||||
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||||
|
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
|
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // 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.36.3 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||||
@ -180,7 +186,7 @@ require (
|
|||||||
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
||||||
github.com/couchbase/gomemcached v0.3.3 // indirect
|
github.com/couchbase/gomemcached v0.3.3 // indirect
|
||||||
github.com/couchbase/goutils v0.1.2 // indirect
|
github.com/couchbase/goutils v0.1.2 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||||
@ -188,6 +194,7 @@ require (
|
|||||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||||
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
|
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||||
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
|
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
|
||||||
github.com/go-ap/errors v0.0.0-20250409143711-5686c11ae650 // indirect
|
github.com/go-ap/errors v0.0.0-20250409143711-5686c11ae650 // indirect
|
||||||
@ -196,6 +203,18 @@ require (
|
|||||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // 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-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // 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.1 // indirect
|
||||||
|
github.com/go-openapi/inflect v0.21.2 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/loads v0.22.0 // indirect
|
||||||
|
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||||
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.1 // indirect
|
||||||
|
github.com/go-openapi/validate v0.24.0 // indirect
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
github.com/go-webauthn/x v0.1.20 // indirect
|
github.com/go-webauthn/x v0.1.20 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||||
@ -209,6 +228,7 @@ require (
|
|||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/go-tpm v0.9.3 // indirect
|
github.com/google/go-tpm v0.9.3 // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
|
github.com/gorilla/handlers v1.5.2 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
@ -216,9 +236,12 @@ require (
|
|||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
github.com/jessevdk/go-flags v1.6.1 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/libdns/libdns v1.0.0-beta.1 // indirect
|
github.com/libdns/libdns v1.0.0-beta.1 // indirect
|
||||||
github.com/mailru/easyjson v0.9.0 // indirect
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
github.com/markbates/going v1.0.3 // indirect
|
github.com/markbates/going v1.0.3 // indirect
|
||||||
@ -229,15 +252,19 @@ require (
|
|||||||
github.com/miekg/dns v1.1.65 // indirect
|
github.com/miekg/dns v1.1.65 // indirect
|
||||||
github.com/minio/crc64nvme v1.0.1 // indirect
|
github.com/minio/crc64nvme v1.0.1 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/nwaples/rardecode v1.1.3 // 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/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
@ -246,11 +273,22 @@ require (
|
|||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
github.com/rhysd/actionlint v1.7.7 // indirect
|
github.com/rhysd/actionlint v1.7.7 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/rs/xid v1.6.0 // indirect
|
github.com/rs/xid v1.6.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||||
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.14.0 // indirect
|
||||||
|
github.com/spf13/cast v1.7.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
github.com/spf13/viper v1.20.1 // indirect
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||||
github.com/unknwon/com v1.0.1 // indirect
|
github.com/unknwon/com v1.0.1 // indirect
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
@ -258,17 +296,18 @@ require (
|
|||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
github.com/zeebo/assert v1.3.0 // indirect
|
github.com/zeebo/assert v1.3.0 // indirect
|
||||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||||
go.etcd.io/bbolt v1.4.0 // indirect
|
go.etcd.io/bbolt v1.4.0 // indirect
|
||||||
|
go.mongodb.org/mongo-driver v1.17.3 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
go.uber.org/zap/exp v0.3.0 // indirect
|
go.uber.org/zap/exp v0.3.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
golang.org/x/mod v0.25.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/time v0.11.0 // indirect
|
golang.org/x/time v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.33.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
@ -276,7 +315,9 @@ require (
|
|||||||
|
|
||||||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||||
|
|
||||||
replace github.com/nektos/act => gitea.com/gitea/act v0.261.6
|
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
|
||||||
|
|
||||||
|
replace github.com/nektos/act => gitea.com/gitea/act v0.261.4
|
||||||
|
|
||||||
// TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why
|
// TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why
|
||||||
replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0
|
replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0
|
||||||
|
139
go.sum
139
go.sum
@ -14,8 +14,8 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
|||||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
gitea.com/gitea/act v0.261.6 h1:CjZwKOyejonNFDmsXOw3wGm5Vet573hHM6VMLsxtvPY=
|
gitea.com/gitea/act v0.261.4 h1:Tf9eLlvsYFtKcpuxlMvf9yT3g4Hshb2Beqw6C1STuH8=
|
||||||
gitea.com/gitea/act v0.261.6/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
gitea.com/gitea/act v0.261.4/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 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40=
|
||||||
gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits=
|
gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits=
|
||||||
gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4=
|
gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4=
|
||||||
@ -62,6 +62,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||||||
github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE=
|
github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE=
|
||||||
github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||||
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
|
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
|
||||||
|
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||||
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
||||||
|
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
|
||||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||||
@ -78,11 +84,11 @@ github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3/go.mod h1:hMNtySovKkn2
|
|||||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||||
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
|
||||||
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
|
github.com/alecthomas/chroma/v2 v2.17.0 h1:3r2Cgk+nXNICMBxIFGnTRTbQFUwMiLisW+9uos0TtUI=
|
||||||
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
|
github.com/alecthomas/chroma/v2 v2.17.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||||
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/anchore/archiver/v3 v3.5.2 h1:Bjemm2NzuRhmHy3m0lRe5tNoClB9A4zYyDV58PaB6aA=
|
github.com/anchore/archiver/v3 v3.5.2 h1:Bjemm2NzuRhmHy3m0lRe5tNoClB9A4zYyDV58PaB6aA=
|
||||||
@ -97,6 +103,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW
|
|||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
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-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM=
|
||||||
@ -215,8 +223,8 @@ github.com/couchbase/goutils v0.1.2 h1:gWr8B6XNWPIhfalHNog3qQKfGiYyh4K4VhO3P2o9B
|
|||||||
github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE=
|
github.com/couchbase/goutils v0.1.2/go.mod h1:h89Ek/tiOxxqjz30nPPlwZdQbdB8BwgnuBxeoUe/ViE=
|
||||||
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
|
||||||
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
@ -266,8 +274,12 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
|||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
|
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
|
||||||
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
@ -313,6 +325,28 @@ 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-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
|
||||||
|
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
|
||||||
|
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
|
||||||
|
github.com/go-openapi/errors v0.22.1 h1:kslMRRnK7NCb/CvR1q1VWuEQCEIsBGn5GgKD9e+HYhU=
|
||||||
|
github.com/go-openapi/errors v0.22.1/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0=
|
||||||
|
github.com/go-openapi/inflect v0.21.2 h1:0gClGlGcxifcJR56zwvhaOulnNgnhc4qTAkob5ObnSM=
|
||||||
|
github.com/go-openapi/inflect v0.21.2/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
|
github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
|
||||||
|
github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
|
||||||
|
github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ=
|
||||||
|
github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
|
||||||
|
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
||||||
|
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||||
|
github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
|
||||||
|
github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
|
||||||
|
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||||
|
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||||
|
github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
|
||||||
|
github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
|
github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI=
|
||||||
@ -323,9 +357,13 @@ github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkv
|
|||||||
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
|
github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ=
|
||||||
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||||
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||||
|
github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc=
|
||||||
|
github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
|
||||||
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/go-webauthn/webauthn v0.12.3 h1:hHQl1xkUuabUU9uS+ISNCMLs9z50p9mDUZI/FmkayNE=
|
github.com/go-webauthn/webauthn v0.12.3 h1:hHQl1xkUuabUU9uS+ISNCMLs9z50p9mDUZI/FmkayNE=
|
||||||
github.com/go-webauthn/webauthn v0.12.3/go.mod h1:4JRe8Z3W7HIw8NGEWn2fnUwecoDzkkeach/NnvhkqGY=
|
github.com/go-webauthn/webauthn v0.12.3/go.mod h1:4JRe8Z3W7HIw8NGEWn2fnUwecoDzkkeach/NnvhkqGY=
|
||||||
github.com/go-webauthn/x v0.1.20 h1:brEBDqfiPtNNCdS/peu8gARtq8fIPsHz0VzpPjGvgiw=
|
github.com/go-webauthn/x v0.1.20 h1:brEBDqfiPtNNCdS/peu8gARtq8fIPsHz0VzpPjGvgiw=
|
||||||
@ -408,6 +446,8 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
|
|||||||
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
|
||||||
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
|
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
|
||||||
github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
||||||
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
||||||
@ -457,6 +497,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
|
|||||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
|
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
|
||||||
|
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
||||||
github.com/jhillyerd/enmime v1.3.0 h1:LV5kzfLidiOr8qRGIpYYmUZCnhrPbcFAnAFUnWn99rw=
|
github.com/jhillyerd/enmime v1.3.0 h1:LV5kzfLidiOr8qRGIpYYmUZCnhrPbcFAnAFUnWn99rw=
|
||||||
github.com/jhillyerd/enmime v1.3.0/go.mod h1:6c6jg5HdRRV2FtvVL69LjiX1M8oE0xDX9VEhV3oy4gs=
|
github.com/jhillyerd/enmime v1.3.0/go.mod h1:6c6jg5HdRRV2FtvVL69LjiX1M8oE0xDX9VEhV3oy4gs=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@ -498,6 +540,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
|||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ=
|
github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ=
|
||||||
github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
|
github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 h1:F/3FfGmKdiKFa8kL3YrpZ7pe9H4l4AzA1pbaOUnRvPI=
|
||||||
|
github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0/go.mod h1:JEfTc3+2DF9Z4PXhLLvXL42zexJyh8rIq3OzUj/0rAk=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
@ -533,10 +577,14 @@ 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/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc=
|
github.com/minio/minio-go/v7 v7.0.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc=
|
||||||
github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
|
github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
|
||||||
|
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=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||||
|
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@ -551,14 +599,16 @@ 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/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 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/niklasfasching/go-org v1.8.0 h1:WyGLaajLLp8JbQzkmapZ1y0MOzKuKV47HkZRloi+HGY=
|
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
||||||
github.com/niklasfasching/go-org v1.8.0/go.mod h1:e2A9zJs7cdONrEGs3gvxCcaAEpwwPNPG7csDpXckMNg=
|
github.com/niklasfasching/go-org v1.7.0/go.mod h1:WuVm4d45oePiE0eX25GqTDQIt/qPW1T9DGkRscqLW5o=
|
||||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
|
||||||
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
|
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||||
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||||
@ -579,6 +629,8 @@ github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJw
|
|||||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
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.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||||
@ -622,6 +674,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
|||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||||
@ -629,6 +682,8 @@ 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 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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
|
||||||
|
github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
|
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
|
||||||
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||||
@ -637,6 +692,10 @@ github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLS
|
|||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
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 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
|
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs=
|
||||||
|
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
@ -648,12 +707,22 @@ github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYl
|
|||||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
|
||||||
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||||
|
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||||
|
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||||
|
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
||||||
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
|
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
|
||||||
@ -676,9 +745,13 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
|||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203 h1:QVqDTf3h2WHt08YuiTGPZLls0Wq99X9bWd0Q5ZSBesM=
|
||||||
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
github.com/stvp/tempredis v0.0.0-20181119212430-b82af8480203/go.mod h1:oqN97ltKNihBbwlX8dLpwxCl3+HnXKV/R0e+sRLd9C8=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
|
||||||
|
github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
|
||||||
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
|
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
|
||||||
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
|
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
@ -688,10 +761,8 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
|||||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
||||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||||
github.com/urfave/cli-docs/v3 v3.0.0-alpha6 h1:w/l/N0xw1rO/aHRIGXJ0lDwwYFOzilup1qGvIytP3BI=
|
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
||||||
github.com/urfave/cli-docs/v3 v3.0.0-alpha6/go.mod h1:p7Z4lg8FSTrPB9GTaNyTrK3ygffHZcK3w0cU2VE+mzU=
|
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
|
|
||||||
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
@ -711,6 +782,8 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ
|
|||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||||
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
|
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
|
||||||
@ -736,6 +809,8 @@ gitlab.com/gitlab-org/api/client-go v0.127.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAj
|
|||||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
|
||||||
|
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
@ -760,8 +835,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
|
|||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||||
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
||||||
@ -775,8 +850,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@ -794,8 +869,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -811,8 +886,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -845,8 +920,8 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -858,8 +933,8 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
|||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@ -871,8 +946,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@ -885,8 +960,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -955,5 +1030,5 @@ strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3
|
|||||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
|
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
|
||||||
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
|
||||||
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||||
xorm.io/xorm v1.3.10 h1:yR83hTT4mKIPyA/lvWFTzS35xjLwkiYnwdw0Qupeh0o=
|
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
|
||||||
xorm.io/xorm v1.3.10/go.mod h1:Lo7hmsFF0F0GbDE7ubX5ZKa+eCf0eCuiJAUG3oI5cxQ=
|
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=
|
||||||
|
2
main.go
2
main.go
@ -21,7 +21,7 @@ import (
|
|||||||
_ "code.gitea.io/gitea/modules/markup/markdown"
|
_ "code.gitea.io/gitea/modules/markup/markdown"
|
||||||
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// these flags will be set by the build flags
|
// these flags will be set by the build flags
|
||||||
|
@ -16,7 +16,6 @@ import (
|
|||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@ -166,17 +165,6 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err
|
|||||||
return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
|
return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (run *ActionRun) GetWorkflowRunEventPayload() (*api.WorkflowRunPayload, error) {
|
|
||||||
if run.Event == webhook_module.HookEventWorkflowRun {
|
|
||||||
var payload api.WorkflowRunPayload
|
|
||||||
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &payload, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("event %s is not a workflow run event", run.Event)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (run *ActionRun) IsSchedule() bool {
|
func (run *ActionRun) IsSchedule() bool {
|
||||||
return run.ScheduleID > 0
|
return run.ScheduleID > 0
|
||||||
}
|
}
|
||||||
@ -282,81 +270,86 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
|
|||||||
// InsertRun inserts a run
|
// InsertRun inserts a run
|
||||||
// The title will be cut off at 255 characters if it's longer than 255 characters.
|
// The title will be cut off at 255 characters if it's longer than 255 characters.
|
||||||
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
|
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
run.Index = index
|
||||||
|
run.Title = util.EllipsisDisplayString(run.Title, 255)
|
||||||
|
|
||||||
|
if err := db.Insert(ctx, run); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if run.Repo == nil {
|
||||||
|
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
run.Index = index
|
run.Repo = repo
|
||||||
run.Title = util.EllipsisDisplayString(run.Title, 255)
|
}
|
||||||
|
|
||||||
if err := db.Insert(ctx, run); err != nil {
|
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
runJobs := make([]*ActionRunJob, 0, len(jobs))
|
||||||
|
var hasWaiting bool
|
||||||
|
for _, v := range jobs {
|
||||||
|
id, job := v.Job()
|
||||||
|
needs := job.Needs()
|
||||||
|
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
payload, _ := v.Marshal()
|
||||||
if run.Repo == nil {
|
status := StatusWaiting
|
||||||
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
|
if len(needs) > 0 || run.NeedApproval {
|
||||||
if err != nil {
|
status = StatusBlocked
|
||||||
return err
|
} else {
|
||||||
}
|
hasWaiting = true
|
||||||
run.Repo = repo
|
|
||||||
}
|
}
|
||||||
|
job.Name = util.EllipsisDisplayString(job.Name, 255)
|
||||||
|
runJobs = append(runJobs, &ActionRunJob{
|
||||||
|
RunID: run.ID,
|
||||||
|
RepoID: run.RepoID,
|
||||||
|
OwnerID: run.OwnerID,
|
||||||
|
CommitSHA: run.CommitSHA,
|
||||||
|
IsForkPullRequest: run.IsForkPullRequest,
|
||||||
|
Name: job.Name,
|
||||||
|
WorkflowPayload: payload,
|
||||||
|
JobID: id,
|
||||||
|
Needs: needs,
|
||||||
|
RunsOn: job.RunsOn(),
|
||||||
|
Status: status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err := db.Insert(ctx, runJobs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
|
// if there is a job in the waiting status, increase tasks version.
|
||||||
|
if hasWaiting {
|
||||||
|
if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
runJobs := make([]*ActionRunJob, 0, len(jobs))
|
return committer.Commit()
|
||||||
var hasWaiting bool
|
|
||||||
for _, v := range jobs {
|
|
||||||
id, job := v.Job()
|
|
||||||
needs := job.Needs()
|
|
||||||
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
payload, _ := v.Marshal()
|
|
||||||
status := StatusWaiting
|
|
||||||
if len(needs) > 0 || run.NeedApproval {
|
|
||||||
status = StatusBlocked
|
|
||||||
} else {
|
|
||||||
hasWaiting = true
|
|
||||||
}
|
|
||||||
job.Name = util.EllipsisDisplayString(job.Name, 255)
|
|
||||||
runJobs = append(runJobs, &ActionRunJob{
|
|
||||||
RunID: run.ID,
|
|
||||||
RepoID: run.RepoID,
|
|
||||||
OwnerID: run.OwnerID,
|
|
||||||
CommitSHA: run.CommitSHA,
|
|
||||||
IsForkPullRequest: run.IsForkPullRequest,
|
|
||||||
Name: job.Name,
|
|
||||||
WorkflowPayload: payload,
|
|
||||||
JobID: id,
|
|
||||||
Needs: needs,
|
|
||||||
RunsOn: job.RunsOn(),
|
|
||||||
Status: status,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if err := db.Insert(ctx, runJobs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is a job in the waiting status, increase tasks version.
|
|
||||||
if hasWaiting {
|
|
||||||
if err := IncreaseTaskVersion(ctx, run.OwnerID, run.RepoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRunByRepoAndID(ctx context.Context, repoID, runID int64) (*ActionRun, error) {
|
func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) {
|
||||||
var run ActionRun
|
var run ActionRun
|
||||||
has, err := db.GetEngine(ctx).Where("id=? AND repo_id=?", runID, repoID).Get(&run)
|
has, err := db.GetEngine(ctx).Where("id=?", id).Get(&run)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return nil, fmt.Errorf("run with id %d: %w", runID, util.ErrNotExist)
|
return nil, fmt.Errorf("run with id %d: %w", id, util.ErrNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &run, nil
|
return &run, nil
|
||||||
@ -427,10 +420,17 @@ func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
|
|||||||
|
|
||||||
if run.Status != 0 || slices.Contains(cols, "status") {
|
if run.Status != 0 || slices.Contains(cols, "status") {
|
||||||
if run.RepoID == 0 {
|
if run.RepoID == 0 {
|
||||||
setting.PanicInDevOrTesting("RepoID should not be 0")
|
run, err = GetRunByID(ctx, run.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err = run.LoadRepo(ctx); err != nil {
|
if run.Repo == nil {
|
||||||
return err
|
repo, err := repo_model.GetRepositoryByID(ctx, run.RepoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
run.Repo = repo
|
||||||
}
|
}
|
||||||
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
|
if err := updateRepoRunsNumbers(ctx, run.Repo); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -51,7 +51,7 @@ func (job *ActionRunJob) Duration() time.Duration {
|
|||||||
|
|
||||||
func (job *ActionRunJob) LoadRun(ctx context.Context) error {
|
func (job *ActionRunJob) LoadRun(ctx context.Context) error {
|
||||||
if job.Run == nil {
|
if job.Run == nil {
|
||||||
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
|
run, err := GetRunByID(ctx, job.RunID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
|
|||||||
{
|
{
|
||||||
// Other goroutines may aggregate the status of the run and update it too.
|
// Other goroutines may aggregate the status of the run and update it too.
|
||||||
// So we need load the run and its jobs before updating the run.
|
// So we need load the run and its jobs before updating the run.
|
||||||
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
|
run, err := GetRunByID(ctx, job.RunID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -187,10 +187,10 @@ func AggregateJobStatus(jobs []*ActionRunJob) Status {
|
|||||||
return StatusCancelled
|
return StatusCancelled
|
||||||
case hasRunning:
|
case hasRunning:
|
||||||
return StatusRunning
|
return StatusRunning
|
||||||
case hasWaiting:
|
|
||||||
return StatusWaiting
|
|
||||||
case hasFailure:
|
case hasFailure:
|
||||||
return StatusFailure
|
return StatusFailure
|
||||||
|
case hasWaiting:
|
||||||
|
return StatusWaiting
|
||||||
case hasBlocked:
|
case hasBlocked:
|
||||||
return StatusBlocked
|
return StatusBlocked
|
||||||
default:
|
default:
|
||||||
|
@ -80,31 +80,22 @@ type FindRunJobOptions struct {
|
|||||||
func (opts FindRunJobOptions) ToConds() builder.Cond {
|
func (opts FindRunJobOptions) ToConds() builder.Cond {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
if opts.RunID > 0 {
|
if opts.RunID > 0 {
|
||||||
cond = cond.And(builder.Eq{"`action_run_job`.run_id": opts.RunID})
|
cond = cond.And(builder.Eq{"run_id": opts.RunID})
|
||||||
}
|
}
|
||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 {
|
||||||
cond = cond.And(builder.Eq{"`action_run_job`.repo_id": opts.RepoID})
|
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||||
|
}
|
||||||
|
if opts.OwnerID > 0 {
|
||||||
|
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||||
}
|
}
|
||||||
if opts.CommitSHA != "" {
|
if opts.CommitSHA != "" {
|
||||||
cond = cond.And(builder.Eq{"`action_run_job`.commit_sha": opts.CommitSHA})
|
cond = cond.And(builder.Eq{"commit_sha": opts.CommitSHA})
|
||||||
}
|
}
|
||||||
if len(opts.Statuses) > 0 {
|
if len(opts.Statuses) > 0 {
|
||||||
cond = cond.And(builder.In("`action_run_job`.status", opts.Statuses))
|
cond = cond.And(builder.In("status", opts.Statuses))
|
||||||
}
|
}
|
||||||
if opts.UpdatedBefore > 0 {
|
if opts.UpdatedBefore > 0 {
|
||||||
cond = cond.And(builder.Lt{"`action_run_job`.updated": opts.UpdatedBefore})
|
cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore})
|
||||||
}
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindRunJobOptions) ToJoins() []db.JoinFunc {
|
|
||||||
if opts.OwnerID > 0 {
|
|
||||||
return []db.JoinFunc{
|
|
||||||
func(sess db.Engine) error {
|
|
||||||
sess.Join("INNER", "repository", "repository.id = repo_id AND repository.owner_id = ?", opts.OwnerID)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -64,7 +64,7 @@ func TestAggregateJobStatus(t *testing.T) {
|
|||||||
{[]Status{StatusFailure, StatusSuccess}, StatusFailure},
|
{[]Status{StatusFailure, StatusSuccess}, StatusFailure},
|
||||||
{[]Status{StatusFailure, StatusSkipped}, StatusFailure},
|
{[]Status{StatusFailure, StatusSkipped}, StatusFailure},
|
||||||
{[]Status{StatusFailure, StatusCancelled}, StatusCancelled},
|
{[]Status{StatusFailure, StatusCancelled}, StatusCancelled},
|
||||||
{[]Status{StatusFailure, StatusWaiting}, StatusWaiting},
|
{[]Status{StatusFailure, StatusWaiting}, StatusFailure},
|
||||||
{[]Status{StatusFailure, StatusRunning}, StatusRunning},
|
{[]Status{StatusFailure, StatusRunning}, StatusRunning},
|
||||||
{[]Status{StatusFailure, StatusBlocked}, StatusFailure},
|
{[]Status{StatusFailure, StatusBlocked}, StatusFailure},
|
||||||
|
|
||||||
|
@ -72,50 +72,39 @@ type FindRunOptions struct {
|
|||||||
TriggerEvent webhook_module.HookEventType
|
TriggerEvent webhook_module.HookEventType
|
||||||
Approved bool // not util.OptionalBool, it works only when it's true
|
Approved bool // not util.OptionalBool, it works only when it's true
|
||||||
Status []Status
|
Status []Status
|
||||||
CommitSHA string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindRunOptions) ToConds() builder.Cond {
|
func (opts FindRunOptions) ToConds() builder.Cond {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 {
|
||||||
cond = cond.And(builder.Eq{"`action_run`.repo_id": opts.RepoID})
|
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||||
|
}
|
||||||
|
if opts.OwnerID > 0 {
|
||||||
|
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||||
}
|
}
|
||||||
if opts.WorkflowID != "" {
|
if opts.WorkflowID != "" {
|
||||||
cond = cond.And(builder.Eq{"`action_run`.workflow_id": opts.WorkflowID})
|
cond = cond.And(builder.Eq{"workflow_id": opts.WorkflowID})
|
||||||
}
|
}
|
||||||
if opts.TriggerUserID > 0 {
|
if opts.TriggerUserID > 0 {
|
||||||
cond = cond.And(builder.Eq{"`action_run`.trigger_user_id": opts.TriggerUserID})
|
cond = cond.And(builder.Eq{"trigger_user_id": opts.TriggerUserID})
|
||||||
}
|
}
|
||||||
if opts.Approved {
|
if opts.Approved {
|
||||||
cond = cond.And(builder.Gt{"`action_run`.approved_by": 0})
|
cond = cond.And(builder.Gt{"approved_by": 0})
|
||||||
}
|
}
|
||||||
if len(opts.Status) > 0 {
|
if len(opts.Status) > 0 {
|
||||||
cond = cond.And(builder.In("`action_run`.status", opts.Status))
|
cond = cond.And(builder.In("status", opts.Status))
|
||||||
}
|
}
|
||||||
if opts.Ref != "" {
|
if opts.Ref != "" {
|
||||||
cond = cond.And(builder.Eq{"`action_run`.ref": opts.Ref})
|
cond = cond.And(builder.Eq{"ref": opts.Ref})
|
||||||
}
|
}
|
||||||
if opts.TriggerEvent != "" {
|
if opts.TriggerEvent != "" {
|
||||||
cond = cond.And(builder.Eq{"`action_run`.trigger_event": opts.TriggerEvent})
|
cond = cond.And(builder.Eq{"trigger_event": opts.TriggerEvent})
|
||||||
}
|
|
||||||
if opts.CommitSHA != "" {
|
|
||||||
cond = cond.And(builder.Eq{"`action_run`.commit_sha": opts.CommitSHA})
|
|
||||||
}
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindRunOptions) ToJoins() []db.JoinFunc {
|
|
||||||
if opts.OwnerID > 0 {
|
|
||||||
return []db.JoinFunc{func(sess db.Engine) error {
|
|
||||||
sess.Join("INNER", "repository", "repository.id = repo_id AND repository.owner_id = ?", opts.OwnerID)
|
|
||||||
return nil
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts FindRunOptions) ToOrders() string {
|
func (opts FindRunOptions) ToOrders() string {
|
||||||
return "`action_run`.`id` DESC"
|
return "`id` DESC"
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusInfo struct {
|
type StatusInfo struct {
|
||||||
|
@ -56,54 +56,65 @@ func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
// Begin transaction
|
||||||
// Loop through each schedule row
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
for _, row := range rows {
|
if err != nil {
|
||||||
row.Title = util.EllipsisDisplayString(row.Title, 255)
|
return err
|
||||||
// Create new schedule row
|
}
|
||||||
if err := db.Insert(ctx, row); err != nil {
|
defer committer.Close()
|
||||||
|
|
||||||
|
// Loop through each schedule row
|
||||||
|
for _, row := range rows {
|
||||||
|
row.Title = util.EllipsisDisplayString(row.Title, 255)
|
||||||
|
// Create new schedule row
|
||||||
|
if err = db.Insert(ctx, row); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through each schedule spec and create a new spec row
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
for _, spec := range row.Specs {
|
||||||
|
specRow := &ActionScheduleSpec{
|
||||||
|
RepoID: row.RepoID,
|
||||||
|
ScheduleID: row.ID,
|
||||||
|
Spec: spec,
|
||||||
|
}
|
||||||
|
// Parse the spec and check for errors
|
||||||
|
schedule, err := specRow.Parse()
|
||||||
|
if err != nil {
|
||||||
|
continue // skip to the next spec if there's an error
|
||||||
|
}
|
||||||
|
|
||||||
|
specRow.Next = timeutil.TimeStamp(schedule.Next(now).Unix())
|
||||||
|
|
||||||
|
// Insert the new schedule spec row
|
||||||
|
if err = db.Insert(ctx, specRow); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop through each schedule spec and create a new spec row
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
for _, spec := range row.Specs {
|
|
||||||
specRow := &ActionScheduleSpec{
|
|
||||||
RepoID: row.RepoID,
|
|
||||||
ScheduleID: row.ID,
|
|
||||||
Spec: spec,
|
|
||||||
}
|
|
||||||
// Parse the spec and check for errors
|
|
||||||
schedule, err := specRow.Parse()
|
|
||||||
if err != nil {
|
|
||||||
continue // skip to the next spec if there's an error
|
|
||||||
}
|
|
||||||
|
|
||||||
specRow.Next = timeutil.TimeStamp(schedule.Next(now).Unix())
|
|
||||||
|
|
||||||
// Insert the new schedule spec row
|
|
||||||
if err = db.Insert(ctx, specRow); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
}
|
||||||
})
|
|
||||||
|
// Commit transaction
|
||||||
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
|
func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
|
if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
|
||||||
})
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) {
|
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) ([]*ActionRunJob, error) {
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
package actions
|
package actions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/translation"
|
"code.gitea.io/gitea/modules/translation"
|
||||||
|
|
||||||
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
|
||||||
@ -90,7 +88,12 @@ func (s Status) IsBlocked() bool {
|
|||||||
|
|
||||||
// In returns whether s is one of the given statuses
|
// In returns whether s is one of the given statuses
|
||||||
func (s Status) In(statuses ...Status) bool {
|
func (s Status) In(statuses ...Status) bool {
|
||||||
return slices.Contains(statuses, s)
|
for _, v := range statuses {
|
||||||
|
if s == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Status) AsResult() runnerv1.Result {
|
func (s Status) AsResult() runnerv1.Result {
|
||||||
|
@ -278,13 +278,14 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
|
|||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedWorkflows, err := jobparser.Parse(job.WorkflowPayload)
|
var workflowJob *jobparser.Job
|
||||||
if err != nil {
|
if gots, err := jobparser.Parse(job.WorkflowPayload); err != nil {
|
||||||
return nil, false, fmt.Errorf("parse workflow of job %d: %w", job.ID, err)
|
return nil, false, fmt.Errorf("parse workflow of job %d: %w", job.ID, err)
|
||||||
} else if len(parsedWorkflows) != 1 {
|
} else if len(gots) != 1 {
|
||||||
return nil, false, fmt.Errorf("workflow of job %d: not single workflow", job.ID)
|
return nil, false, fmt.Errorf("workflow of job %d: not single workflow", job.ID)
|
||||||
|
} else { //nolint:revive
|
||||||
|
_, workflowJob = gots[0].Job()
|
||||||
}
|
}
|
||||||
_, workflowJob := parsedWorkflows[0].Job()
|
|
||||||
|
|
||||||
if _, err := e.Insert(task); err != nil {
|
if _, err := e.Insert(task); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
@ -352,70 +353,78 @@ func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.Task
|
|||||||
stepStates[v.Id] = v
|
stepStates[v.Id] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.WithTx2(ctx, func(ctx context.Context) (*ActionTask, error) {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
e := db.GetEngine(ctx)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
task := &ActionTask{}
|
e := db.GetEngine(ctx)
|
||||||
if has, err := e.ID(state.Id).Get(task); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, util.ErrNotExist
|
|
||||||
} else if runnerID != task.RunnerID {
|
|
||||||
return nil, errors.New("invalid runner for task")
|
|
||||||
}
|
|
||||||
|
|
||||||
if task.Status.IsDone() {
|
task := &ActionTask{}
|
||||||
// the state is final, do nothing
|
if has, err := e.ID(state.Id).Get(task); err != nil {
|
||||||
return task, nil
|
return nil, err
|
||||||
}
|
} else if !has {
|
||||||
|
return nil, util.ErrNotExist
|
||||||
// state.Result is not unspecified means the task is finished
|
} else if runnerID != task.RunnerID {
|
||||||
if state.Result != runnerv1.Result_RESULT_UNSPECIFIED {
|
return nil, errors.New("invalid runner for task")
|
||||||
task.Status = Status(state.Result)
|
}
|
||||||
task.Stopped = timeutil.TimeStamp(state.StoppedAt.AsTime().Unix())
|
|
||||||
if err := UpdateTask(ctx, task, "status", "stopped"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if _, err := UpdateRunJob(ctx, &ActionRunJob{
|
|
||||||
ID: task.JobID,
|
|
||||||
Status: task.Status,
|
|
||||||
Stopped: task.Stopped,
|
|
||||||
}, nil); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Force update ActionTask.Updated to avoid the task being judged as a zombie task
|
|
||||||
task.Updated = timeutil.TimeStampNow()
|
|
||||||
if err := UpdateTask(ctx, task, "updated"); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := task.LoadAttributes(ctx); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, step := range task.Steps {
|
|
||||||
var result runnerv1.Result
|
|
||||||
if v, ok := stepStates[step.Index]; ok {
|
|
||||||
result = v.Result
|
|
||||||
step.LogIndex = v.LogIndex
|
|
||||||
step.LogLength = v.LogLength
|
|
||||||
step.Started = convertTimestamp(v.StartedAt)
|
|
||||||
step.Stopped = convertTimestamp(v.StoppedAt)
|
|
||||||
}
|
|
||||||
if result != runnerv1.Result_RESULT_UNSPECIFIED {
|
|
||||||
step.Status = Status(result)
|
|
||||||
} else if step.Started != 0 {
|
|
||||||
step.Status = StatusRunning
|
|
||||||
}
|
|
||||||
if _, err := e.ID(step.ID).Update(step); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if task.Status.IsDone() {
|
||||||
|
// the state is final, do nothing
|
||||||
return task, nil
|
return task, nil
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// state.Result is not unspecified means the task is finished
|
||||||
|
if state.Result != runnerv1.Result_RESULT_UNSPECIFIED {
|
||||||
|
task.Status = Status(state.Result)
|
||||||
|
task.Stopped = timeutil.TimeStamp(state.StoppedAt.AsTime().Unix())
|
||||||
|
if err := UpdateTask(ctx, task, "status", "stopped"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := UpdateRunJob(ctx, &ActionRunJob{
|
||||||
|
ID: task.JobID,
|
||||||
|
Status: task.Status,
|
||||||
|
Stopped: task.Stopped,
|
||||||
|
}, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Force update ActionTask.Updated to avoid the task being judged as a zombie task
|
||||||
|
task.Updated = timeutil.TimeStampNow()
|
||||||
|
if err := UpdateTask(ctx, task, "updated"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := task.LoadAttributes(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, step := range task.Steps {
|
||||||
|
var result runnerv1.Result
|
||||||
|
if v, ok := stepStates[step.Index]; ok {
|
||||||
|
result = v.Result
|
||||||
|
step.LogIndex = v.LogIndex
|
||||||
|
step.LogLength = v.LogLength
|
||||||
|
step.Started = convertTimestamp(v.StartedAt)
|
||||||
|
step.Stopped = convertTimestamp(v.StoppedAt)
|
||||||
|
}
|
||||||
|
if result != runnerv1.Result_RESULT_UNSPECIFIED {
|
||||||
|
step.Status = Status(result)
|
||||||
|
} else if step.Started != 0 {
|
||||||
|
step.Status = StatusRunning
|
||||||
|
}
|
||||||
|
if _, err := e.ID(step.ID).Update(step); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := committer.Commit(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return task, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func StopTask(ctx context.Context, taskID int64, status Status) error {
|
func StopTask(ctx context.Context, taskID int64, status Status) error {
|
||||||
|
@ -48,7 +48,6 @@ func (tasks TaskList) LoadAttributes(ctx context.Context) error {
|
|||||||
type FindTaskOptions struct {
|
type FindTaskOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
RepoID int64
|
RepoID int64
|
||||||
JobID int64
|
|
||||||
OwnerID int64
|
OwnerID int64
|
||||||
CommitSHA string
|
CommitSHA string
|
||||||
Status Status
|
Status Status
|
||||||
@ -62,9 +61,6 @@ func (opts FindTaskOptions) ToConds() builder.Cond {
|
|||||||
if opts.RepoID > 0 {
|
if opts.RepoID > 0 {
|
||||||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||||
}
|
}
|
||||||
if opts.JobID > 0 {
|
|
||||||
cond = cond.And(builder.Eq{"job_id": opts.JobID})
|
|
||||||
}
|
|
||||||
if opts.OwnerID > 0 {
|
if opts.OwnerID > 0 {
|
||||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||||
}
|
}
|
||||||
|
@ -73,29 +73,33 @@ func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
|
func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
// 1. increase global
|
if err != nil {
|
||||||
if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
|
return err
|
||||||
log.Error("IncreaseTasksVersionByScope(Global): %v", err)
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
// 1. increase global
|
||||||
|
if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil {
|
||||||
|
log.Error("IncreaseTasksVersionByScope(Global): %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. increase owner
|
||||||
|
if ownerID > 0 {
|
||||||
|
if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil {
|
||||||
|
log.Error("IncreaseTasksVersionByScope(Owner): %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. increase owner
|
// 3. increase repo
|
||||||
if ownerID > 0 {
|
if repoID > 0 {
|
||||||
if err := increaseTasksVersionByScope(ctx, ownerID, 0); err != nil {
|
if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil {
|
||||||
log.Error("IncreaseTasksVersionByScope(Owner): %v", err)
|
log.Error("IncreaseTasksVersionByScope(Repo): %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 3. increase repo
|
return committer.Commit()
|
||||||
if repoID > 0 {
|
|
||||||
if err := increaseTasksVersionByScope(ctx, 0, repoID); err != nil {
|
|
||||||
log.Error("IncreaseTasksVersionByScope(Repo): %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -82,22 +82,3 @@ func calculateDuration(started, stopped timeutil.TimeStamp, status Status) time.
|
|||||||
}
|
}
|
||||||
return timeSince(s).Truncate(time.Second)
|
return timeSince(s).Truncate(time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
// best effort function to convert an action schedule to action run, to be used in GenerateGiteaContext
|
|
||||||
func (s *ActionSchedule) ToActionRun() *ActionRun {
|
|
||||||
return &ActionRun{
|
|
||||||
Title: s.Title,
|
|
||||||
RepoID: s.RepoID,
|
|
||||||
Repo: s.Repo,
|
|
||||||
OwnerID: s.OwnerID,
|
|
||||||
WorkflowID: s.WorkflowID,
|
|
||||||
TriggerUserID: s.TriggerUserID,
|
|
||||||
TriggerUser: s.TriggerUser,
|
|
||||||
Ref: s.Ref,
|
|
||||||
CommitSHA: s.CommitSHA,
|
|
||||||
Event: s.Event,
|
|
||||||
EventPayload: s.EventPayload,
|
|
||||||
Created: s.Created,
|
|
||||||
Updated: s.Updated,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"slices"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -126,7 +125,12 @@ func (at ActionType) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (at ActionType) InActions(actions ...string) bool {
|
func (at ActionType) InActions(actions ...string) bool {
|
||||||
return slices.Contains(actions, at.String())
|
for _, action := range actions {
|
||||||
|
if action == at.String() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action represents user operation type and other information to
|
// Action represents user operation type and other information to
|
||||||
|
@ -70,9 +70,17 @@ func (opts FindNotificationOptions) ToOrders() string {
|
|||||||
// for each watcher, or updates it if already exists
|
// for each watcher, or updates it if already exists
|
||||||
// receiverID > 0 just send to receiver, else send to all watcher
|
// receiverID > 0 just send to receiver, else send to all watcher
|
||||||
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
return createOrUpdateIssueNotifications(ctx, issueID, commentID, notificationAuthorID, receiverID)
|
if err != nil {
|
||||||
})
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
if err := createOrUpdateIssueNotifications(ctx, issueID, commentID, notificationAuthorID, receiverID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
|
||||||
@ -200,7 +208,10 @@ func (nl NotificationList) LoadRepos(ctx context.Context) (repo_model.Repository
|
|||||||
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
|
repos := make(map[int64]*repo_model.Repository, len(repoIDs))
|
||||||
left := len(repoIDs)
|
left := len(repoIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := min(left, db.DefaultMaxInSize)
|
limit := db.DefaultMaxInSize
|
||||||
|
if left < limit {
|
||||||
|
limit = left
|
||||||
|
}
|
||||||
rows, err := db.GetEngine(ctx).
|
rows, err := db.GetEngine(ctx).
|
||||||
In("id", repoIDs[:limit]).
|
In("id", repoIDs[:limit]).
|
||||||
Rows(new(repo_model.Repository))
|
Rows(new(repo_model.Repository))
|
||||||
@ -271,7 +282,10 @@ func (nl NotificationList) LoadIssues(ctx context.Context) ([]int, error) {
|
|||||||
issues := make(map[int64]*issues_model.Issue, len(issueIDs))
|
issues := make(map[int64]*issues_model.Issue, len(issueIDs))
|
||||||
left := len(issueIDs)
|
left := len(issueIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := min(left, db.DefaultMaxInSize)
|
limit := db.DefaultMaxInSize
|
||||||
|
if left < limit {
|
||||||
|
limit = left
|
||||||
|
}
|
||||||
rows, err := db.GetEngine(ctx).
|
rows, err := db.GetEngine(ctx).
|
||||||
In("id", issueIDs[:limit]).
|
In("id", issueIDs[:limit]).
|
||||||
Rows(new(issues_model.Issue))
|
Rows(new(issues_model.Issue))
|
||||||
@ -363,7 +377,10 @@ func (nl NotificationList) LoadUsers(ctx context.Context) ([]int, error) {
|
|||||||
users := make(map[int64]*user_model.User, len(userIDs))
|
users := make(map[int64]*user_model.User, len(userIDs))
|
||||||
left := len(userIDs)
|
left := len(userIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := min(left, db.DefaultMaxInSize)
|
limit := db.DefaultMaxInSize
|
||||||
|
if left < limit {
|
||||||
|
limit = left
|
||||||
|
}
|
||||||
rows, err := db.GetEngine(ctx).
|
rows, err := db.GetEngine(ctx).
|
||||||
In("id", userIDs[:limit]).
|
In("id", userIDs[:limit]).
|
||||||
Rows(new(user_model.User))
|
Rows(new(user_model.User))
|
||||||
@ -411,7 +428,10 @@ func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) {
|
|||||||
comments := make(map[int64]*issues_model.Comment, len(commentIDs))
|
comments := make(map[int64]*issues_model.Comment, len(commentIDs))
|
||||||
left := len(commentIDs)
|
left := len(commentIDs)
|
||||||
for left > 0 {
|
for left > 0 {
|
||||||
limit := min(left, db.DefaultMaxInSize)
|
limit := db.DefaultMaxInSize
|
||||||
|
if left < limit {
|
||||||
|
limit = left
|
||||||
|
}
|
||||||
rows, err := db.GetEngine(ctx).
|
rows, err := db.GetEngine(ctx).
|
||||||
In("id", commentIDs[:limit]).
|
In("id", commentIDs[:limit]).
|
||||||
Rows(new(issues_model.Comment))
|
Rows(new(issues_model.Comment))
|
||||||
|
@ -139,7 +139,10 @@ func GetActivityStatsTopAuthors(ctx context.Context, repo *repo_model.Repository
|
|||||||
return v[i].Commits > v[j].Commits
|
return v[i].Commits > v[j].Commits
|
||||||
})
|
})
|
||||||
|
|
||||||
cnt := min(count, len(v))
|
cnt := count
|
||||||
|
if cnt > len(v) {
|
||||||
|
cnt = len(v)
|
||||||
|
}
|
||||||
|
|
||||||
return v[:cnt], nil
|
return v[:cnt], nil
|
||||||
}
|
}
|
||||||
|
@ -17,16 +17,13 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
"code.gitea.io/gitea/modules/optional"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Statistic contains the database statistics
|
// Statistic contains the database statistics
|
||||||
type Statistic struct {
|
type Statistic struct {
|
||||||
Counter struct {
|
Counter struct {
|
||||||
UsersActive, UsersNotActive,
|
User, Org, PublicKey,
|
||||||
Org, PublicKey,
|
|
||||||
Repo, Watch, Star, Access,
|
Repo, Watch, Star, Access,
|
||||||
Issue, IssueClosed, IssueOpen,
|
Issue, IssueClosed, IssueOpen,
|
||||||
Comment, Oauth, Follow,
|
Comment, Oauth, Follow,
|
||||||
@ -56,20 +53,8 @@ type IssueByRepositoryCount struct {
|
|||||||
// GetStatistic returns the database statistics
|
// GetStatistic returns the database statistics
|
||||||
func GetStatistic(ctx context.Context) (stats Statistic) {
|
func GetStatistic(ctx context.Context) (stats Statistic) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
stats.Counter.User = user_model.CountUsers(ctx, nil)
|
||||||
// Number of active users
|
stats.Counter.Org, _ = db.Count[organization.Organization](ctx, organization.FindOrgOptions{IncludePrivate: true})
|
||||||
usersActiveOpts := user_model.CountUserFilter{
|
|
||||||
IsActive: optional.Some(true),
|
|
||||||
}
|
|
||||||
stats.Counter.UsersActive = user_model.CountUsers(ctx, &usersActiveOpts)
|
|
||||||
|
|
||||||
// Number of inactive users
|
|
||||||
usersNotActiveOpts := user_model.CountUserFilter{
|
|
||||||
IsActive: optional.Some(false),
|
|
||||||
}
|
|
||||||
stats.Counter.UsersNotActive = user_model.CountUsers(ctx, &usersNotActiveOpts)
|
|
||||||
|
|
||||||
stats.Counter.Org, _ = db.Count[organization.Organization](ctx, organization.FindOrgOptions{IncludeVisibility: structs.VisibleTypePrivate})
|
|
||||||
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
|
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
|
||||||
stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{})
|
stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{})
|
||||||
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
|
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
|
||||||
|
@ -228,10 +228,17 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
|
|||||||
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
_, err = deleteGPGKey(ctx, key.KeyID)
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
})
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
if _, err = deleteGPGKey(ctx, key.KeyID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindGPGKeyWithSubKeys(ctx context.Context, keyID string) ([]*GPGKey, error) {
|
func FindGPGKeyWithSubKeys(ctx context.Context, keyID string) ([]*GPGKey, error) {
|
||||||
|
@ -15,6 +15,25 @@ import (
|
|||||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// __________________ ________ ____ __.
|
||||||
|
// / _____/\______ \/ _____/ | |/ _|____ ___.__.
|
||||||
|
// / \ ___ | ___/ \ ___ | <_/ __ < | |
|
||||||
|
// \ \_\ \| | \ \_\ \ | | \ ___/\___ |
|
||||||
|
// \______ /|____| \______ / |____|__ \___ > ____|
|
||||||
|
// \/ \/ \/ \/\/
|
||||||
|
// _________ .__ __
|
||||||
|
// \_ ___ \ ____ _____ _____ |__|/ |_
|
||||||
|
// / \ \/ / _ \ / \ / \| \ __\
|
||||||
|
// \ \___( <_> ) Y Y \ Y Y \ || |
|
||||||
|
// \______ /\____/|__|_| /__|_| /__||__|
|
||||||
|
// \/ \/ \/
|
||||||
|
// ____ ____ .__ _____.__ __ .__
|
||||||
|
// \ \ / /___________|__|/ ____\__| ____ _____ _/ |_|__| ____ ____
|
||||||
|
// \ Y // __ \_ __ \ \ __\| |/ ___\\__ \\ __\ |/ _ \ / \
|
||||||
|
// \ /\ ___/| | \/ || | | \ \___ / __ \| | | ( <_> ) | \
|
||||||
|
// \___/ \___ >__| |__||__| |__|\___ >____ /__| |__|\____/|___| /
|
||||||
|
// \/ \/ \/ \/
|
||||||
|
|
||||||
// This file provides functions relating commit verification
|
// This file provides functions relating commit verification
|
||||||
|
|
||||||
// CommitVerification represents a commit validation of signature
|
// CommitVerification represents a commit validation of signature
|
||||||
@ -22,8 +41,8 @@ type CommitVerification struct {
|
|||||||
Verified bool
|
Verified bool
|
||||||
Warning bool
|
Warning bool
|
||||||
Reason string
|
Reason string
|
||||||
SigningUser *user_model.User // if Verified, then SigningUser is non-nil
|
SigningUser *user_model.User
|
||||||
CommittingUser *user_model.User // if Verified, then CommittingUser is non-nil
|
CommittingUser *user_model.User
|
||||||
SigningEmail string
|
SigningEmail string
|
||||||
SigningKey *GPGKey
|
SigningKey *GPGKey
|
||||||
SigningSSHKey *PublicKey
|
SigningSSHKey *PublicKey
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user