mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-07-01 06:30:19 +00:00
Compare commits
64 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c72fd88d35 | ||
|
16484c72ec | ||
|
006d9c060e | ||
|
f067db8f8e | ||
|
d3c6ab538e | ||
|
eed84d72b6 | ||
|
ff4f2bcf07 | ||
|
dc0d4fb3ad | ||
|
673eccf51f | ||
|
ed87ecd17f | ||
|
e9f0e96a27 | ||
|
55df95b1be | ||
|
aa8fa7f7e9 | ||
|
a821eb9e0f | ||
|
bdef19f62b | ||
|
f13147a019 | ||
|
1ca805933f | ||
|
da267ab00e | ||
|
fe55ddcdaf | ||
|
738ec94b8f | ||
|
a4cb898335 | ||
|
4a30f59e6e | ||
|
723fa1c966 | ||
|
661028623c | ||
|
5a54ce0fbc | ||
|
5bb61cf6c2 | ||
|
5d7953def4 | ||
|
5816106de5 | ||
|
c5601e9399 | ||
|
1d15e243e4 | ||
|
97220d1ce9 | ||
|
44a5cd3b7a | ||
|
6a9fb3dbbc | ||
|
fe07c90636 | ||
|
4215476cee | ||
|
e837350319 | ||
|
bc6c0b610b | ||
|
b067d0df6e | ||
|
c5bfe77873 | ||
|
b2241c3939 | ||
|
a4396782b5 | ||
|
55cff9cfb4 | ||
|
5ffe4e54e1 | ||
|
9147665e2c | ||
|
5395eea338 | ||
|
973bc33a5f | ||
|
722ea4179c | ||
|
9ebdc09939 | ||
|
308810cdd1 | ||
|
ecdb814dd8 | ||
|
64d8854222 | ||
|
a4e8594643 | ||
|
43c35fb3d3 | ||
|
50104993d2 | ||
|
fdf641ddce | ||
|
6bcdfd6efb | ||
|
7bc4f4976e | ||
|
52da8aab7e | ||
|
49625aac60 | ||
|
fa8d75b3e5 | ||
|
1d1e0ced3e | ||
|
e153e21177 | ||
|
e286457990 | ||
|
0a6a6d351d |
1360 changed files with 17515 additions and 37223 deletions
|
@ -13,13 +13,6 @@ forgejo.org/models
|
||||||
IsErrSHANotFound
|
IsErrSHANotFound
|
||||||
IsErrMergeDivergingFastForwardOnly
|
IsErrMergeDivergingFastForwardOnly
|
||||||
|
|
||||||
forgejo.org/models/activities
|
|
||||||
GetActivityByID
|
|
||||||
NewFederatedUserActivity
|
|
||||||
CreateUserActivity
|
|
||||||
GetFollowingFeeds
|
|
||||||
FederatedUserActivity.loadActor
|
|
||||||
|
|
||||||
forgejo.org/models/auth
|
forgejo.org/models/auth
|
||||||
WebAuthnCredentials
|
WebAuthnCredentials
|
||||||
|
|
||||||
|
@ -27,7 +20,6 @@ forgejo.org/models/db
|
||||||
TruncateBeans
|
TruncateBeans
|
||||||
InTransaction
|
InTransaction
|
||||||
DumpTables
|
DumpTables
|
||||||
GetTableNames
|
|
||||||
|
|
||||||
forgejo.org/models/dbfs
|
forgejo.org/models/dbfs
|
||||||
file.renameTo
|
file.renameTo
|
||||||
|
@ -62,17 +54,9 @@ forgejo.org/models/user
|
||||||
IsErrExternalLoginUserAlreadyExist
|
IsErrExternalLoginUserAlreadyExist
|
||||||
IsErrExternalLoginUserNotExist
|
IsErrExternalLoginUserNotExist
|
||||||
NewFederatedUser
|
NewFederatedUser
|
||||||
NewFederatedUserFollower
|
|
||||||
IsErrUserSettingIsNotExist
|
IsErrUserSettingIsNotExist
|
||||||
GetUserAllSettings
|
GetUserAllSettings
|
||||||
DeleteUserSetting
|
DeleteUserSetting
|
||||||
GetFederatedUser
|
|
||||||
GetFederatedUserByUserID
|
|
||||||
UpdateFederatedUser
|
|
||||||
GetFollowersForUser
|
|
||||||
AddFollower
|
|
||||||
RemoveFollower
|
|
||||||
IsFollowingAp
|
|
||||||
|
|
||||||
forgejo.org/modules/activitypub
|
forgejo.org/modules/activitypub
|
||||||
NewContext
|
NewContext
|
||||||
|
@ -103,24 +87,12 @@ forgejo.org/modules/eventsource
|
||||||
Event.String
|
Event.String
|
||||||
|
|
||||||
forgejo.org/modules/forgefed
|
forgejo.org/modules/forgefed
|
||||||
NewForgeFollowFromAp
|
|
||||||
NewForgeFollow
|
|
||||||
ForgeFollow.MarshalJSON
|
|
||||||
ForgeFollow.UnmarshalJSON
|
|
||||||
ForgeFollow.Validate
|
|
||||||
NewForgeUndoLike
|
NewForgeUndoLike
|
||||||
ForgeUndoLike.UnmarshalJSON
|
ForgeUndoLike.UnmarshalJSON
|
||||||
ForgeUndoLike.Validate
|
ForgeUndoLike.Validate
|
||||||
NewForgeUserActivityFromAp
|
|
||||||
NewForgeUserActivity
|
|
||||||
ForgeUserActivity.Validate
|
|
||||||
NewPersonIDFromModel
|
|
||||||
GetItemByType
|
GetItemByType
|
||||||
JSONUnmarshalerFn
|
JSONUnmarshalerFn
|
||||||
NotEmpty
|
NotEmpty
|
||||||
NewForgeUserActivityNoteFromAp
|
|
||||||
newNote
|
|
||||||
ForgeUserActivityNote.Validate
|
|
||||||
ToRepository
|
ToRepository
|
||||||
OnRepository
|
OnRepository
|
||||||
|
|
||||||
|
@ -216,14 +188,10 @@ forgejo.org/modules/translation
|
||||||
MockLocale.Tr
|
MockLocale.Tr
|
||||||
MockLocale.TrN
|
MockLocale.TrN
|
||||||
MockLocale.TrPluralString
|
MockLocale.TrPluralString
|
||||||
MockLocale.TrPluralStringAllForms
|
|
||||||
MockLocale.TrSize
|
MockLocale.TrSize
|
||||||
MockLocale.HasKey
|
MockLocale.HasKey
|
||||||
MockLocale.PrettyNumber
|
MockLocale.PrettyNumber
|
||||||
|
|
||||||
forgejo.org/modules/translation/localeiter
|
|
||||||
IterateMessagesContent
|
|
||||||
|
|
||||||
forgejo.org/modules/util
|
forgejo.org/modules/util
|
||||||
OptionalArg
|
OptionalArg
|
||||||
|
|
||||||
|
@ -232,7 +200,6 @@ forgejo.org/modules/util/filebuffer
|
||||||
|
|
||||||
forgejo.org/modules/validation
|
forgejo.org/modules/validation
|
||||||
IsErrNotValid
|
IsErrNotValid
|
||||||
ValidateIDExists
|
|
||||||
|
|
||||||
forgejo.org/modules/web
|
forgejo.org/modules/web
|
||||||
RouteMock
|
RouteMock
|
||||||
|
@ -243,6 +210,9 @@ forgejo.org/modules/zstd
|
||||||
Writer.Write
|
Writer.Write
|
||||||
Writer.Close
|
Writer.Close
|
||||||
|
|
||||||
|
forgejo.org/routers/web
|
||||||
|
NotFound
|
||||||
|
|
||||||
forgejo.org/routers/web/org
|
forgejo.org/routers/web/org
|
||||||
MustEnableProjects
|
MustEnableProjects
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
"features": {
|
"features": {
|
||||||
// installs nodejs into container
|
// installs nodejs into container
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "22"
|
"version": "20"
|
||||||
|
},
|
||||||
|
"ghcr.io/devcontainers/features/git-lfs:1.2.3": {},
|
||||||
|
"ghcr.io/devcontainers-contrib/features/poetry:2": {},
|
||||||
|
"ghcr.io/devcontainers/features/python:1": {
|
||||||
|
"version": "3.12"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/git-lfs:1.2.5": {},
|
|
||||||
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
|
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
|
|
|
@ -37,9 +37,13 @@ coverage.all
|
||||||
coverage/
|
coverage/
|
||||||
cpu.out
|
cpu.out
|
||||||
|
|
||||||
|
/modules/migration/bindata.go
|
||||||
/modules/migration/bindata.go.hash
|
/modules/migration/bindata.go.hash
|
||||||
|
/modules/options/bindata.go
|
||||||
/modules/options/bindata.go.hash
|
/modules/options/bindata.go.hash
|
||||||
|
/modules/public/bindata.go
|
||||||
/modules/public/bindata.go.hash
|
/modules/public/bindata.go.hash
|
||||||
|
/modules/templates/bindata.go
|
||||||
/modules/templates/bindata.go.hash
|
/modules/templates/bindata.go.hash
|
||||||
|
|
||||||
*.db
|
*.db
|
||||||
|
|
|
@ -12,9 +12,6 @@ insert_final_newline = true
|
||||||
[{*.{go,tmpl,html},Makefile,go.mod}]
|
[{*.{go,tmpl,html},Makefile,go.mod}]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|
||||||
[go.*]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
[templates/custom/*.tmpl]
|
[templates/custom/*.tmpl]
|
||||||
insert_final_newline = false
|
insert_final_newline = false
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
**NOTE: If your issue is a security concern, please email <security@forgejo.org> ([security.txt](https://forgejo.org/.well-known/security.txt)) instead of opening a public issue.**
|
**NOTE: If your issue is a security concern, please email <security@forgejo.org> (GPG: `A4676E79`) instead of opening a public issue.**
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
|
|
|
@ -6,7 +6,7 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
**NOTE: If your issue is a security concern, please email <security@forgejo.org> ([security.txt](https://forgejo.org/.well-known/security.txt)) instead of opening a public issue.**
|
**NOTE: If your issue is a security concern, please email <security@forgejo.org> (GPG: `A4676E79`) instead of opening a public issue.**
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
|
|
2
.forgejo/testdata/build-release/Dockerfile
vendored
2
.forgejo/testdata/build-release/Dockerfile
vendored
|
@ -1,4 +1,4 @@
|
||||||
FROM data.forgejo.org/oci/alpine:3.22
|
FROM data.forgejo.org/oci/alpine:3.21
|
||||||
ARG RELEASE_VERSION=unkown
|
ARG RELEASE_VERSION=unkown
|
||||||
LABEL maintainer="contact@forgejo.org" \
|
LABEL maintainer="contact@forgejo.org" \
|
||||||
org.opencontainers.image.version="${RELEASE_VERSION}"
|
org.opencontainers.image.version="${RELEASE_VERSION}"
|
||||||
|
|
|
@ -18,7 +18,7 @@ runs:
|
||||||
- name: install packages
|
- name: install packages
|
||||||
run: |
|
run: |
|
||||||
apt-get update -qq
|
apt-get update -qq
|
||||||
apt-get -q install --allow-downgrades -qq -y ${PACKAGES}
|
apt-get -q install -qq -y ${PACKAGES}
|
||||||
env:
|
env:
|
||||||
PACKAGES: ${{inputs.packages}}
|
PACKAGES: ${{inputs.packages}}
|
||||||
- name: remove temporary package list to prevent using it in other steps
|
- name: remove temporary package list to prevent using it in other steps
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
#
|
|
||||||
# Install the minimal version of Git supported by Forgejo
|
|
||||||
#
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: install git and git-lfs
|
|
||||||
run: |
|
|
||||||
set -x
|
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
apt-get update -qq
|
|
||||||
apt-get -q install -y -qq curl ca-certificates
|
|
||||||
|
|
||||||
curl -sS -o /tmp/git-man.deb http://archive.ubuntu.com/ubuntu/pool/main/g/git/git-man_2.34.1-1ubuntu1_all.deb
|
|
||||||
curl -sS -o /tmp/git.deb https://archive.ubuntu.com/ubuntu/pool/main/g/git/git_2.34.1-1ubuntu1_amd64.deb
|
|
||||||
curl -sS -o /tmp/git-lfs.deb https://archive.ubuntu.com/ubuntu/pool/universe/g/git-lfs/git-lfs_3.0.2-1_amd64.deb
|
|
||||||
|
|
||||||
apt-get -q install --allow-downgrades -y -qq /tmp/git-man.deb
|
|
||||||
apt-get -q install --allow-downgrades -y -qq /tmp/git.deb
|
|
||||||
apt-get -q install --allow-downgrades -y -qq /tmp/git-lfs.deb
|
|
|
@ -47,7 +47,7 @@ jobs:
|
||||||
cat <<'EOF'
|
cat <<'EOF'
|
||||||
${{ toJSON(github) }}
|
${{ toJSON(github) }}
|
||||||
EOF
|
EOF
|
||||||
- uses: https://data.forgejo.org/actions/git-backporting@v4.8.5
|
- uses: https://data.forgejo.org/actions/git-backporting@v4.8.4
|
||||||
with:
|
with:
|
||||||
target-branch-pattern: "^backport/(?<target>(v.*))$"
|
target-branch-pattern: "^backport/(?<target>(v.*))$"
|
||||||
strategy: ort
|
strategy: ort
|
||||||
|
|
|
@ -164,7 +164,7 @@ jobs:
|
||||||
|
|
||||||
- name: build container & release
|
- name: build container & release
|
||||||
if: ${{ secrets.TOKEN != '' }}
|
if: ${{ secrets.TOKEN != '' }}
|
||||||
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.4
|
||||||
with:
|
with:
|
||||||
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
||||||
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
||||||
|
@ -183,7 +183,7 @@ jobs:
|
||||||
|
|
||||||
- name: build rootless container
|
- name: build rootless container
|
||||||
if: ${{ secrets.TOKEN != '' }}
|
if: ${{ secrets.TOKEN != '' }}
|
||||||
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.4
|
||||||
with:
|
with:
|
||||||
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
||||||
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
||||||
|
|
|
@ -31,7 +31,7 @@ jobs:
|
||||||
|| contains(toJSON(github.event.pull_request.labels), 'test/manual')
|
|| contains(toJSON(github.event.pull_request.labels), 'test/manual')
|
||||||
)
|
)
|
||||||
run: |
|
run: |
|
||||||
echo "A team member must set the label to either 'present', 'not-needed' or 'manual'."
|
echo "Test label must be set to either 'present', 'not-needed' or 'manual'."
|
||||||
exit 1
|
exit 1
|
||||||
- name: Missing manual test instructions
|
- name: Missing manual test instructions
|
||||||
if: >
|
if: >
|
||||||
|
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
- uses: https://data.forgejo.org/actions/checkout@v4
|
- uses: https://data.forgejo.org/actions/checkout@v4
|
||||||
|
|
||||||
- name: copy & sign
|
- name: copy & sign
|
||||||
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.5
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.4
|
||||||
with:
|
with:
|
||||||
from-forgejo: ${{ vars.FORGEJO }}
|
from-forgejo: ${{ vars.FORGEJO }}
|
||||||
to-forgejo: ${{ vars.FORGEJO }}
|
to-forgejo: ${{ vars.FORGEJO }}
|
||||||
|
|
|
@ -4,9 +4,6 @@ on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '@daily'
|
- cron: '@daily'
|
||||||
|
|
||||||
env:
|
|
||||||
RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-notes:
|
release-notes:
|
||||||
if: vars.ROLE == 'forgejo-coding'
|
if: vars.ROLE == 'forgejo-coding'
|
||||||
|
@ -32,5 +29,5 @@ jobs:
|
||||||
set -x
|
set -x
|
||||||
curl -sS $GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do
|
curl -sS $GITHUB_SERVER_URL/api/v1/repos/$GITHUB_REPOSITORY/milestones?state=open | jq -r '.[] | .title' | while read forgejo version ; do
|
||||||
milestone="$forgejo $version"
|
milestone="$forgejo $version"
|
||||||
go run code.forgejo.org/forgejo/release-notes-assistant@$RNA_VERSION --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version
|
go run code.forgejo.org/forgejo/release-notes-assistant@v1.1.1 --config .release-notes-assistant.yaml --storage milestone --storage-location "$milestone" --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} release $version
|
||||||
done
|
done
|
||||||
|
|
|
@ -7,9 +7,6 @@ on:
|
||||||
- synchronize
|
- synchronize
|
||||||
- labeled
|
- labeled
|
||||||
|
|
||||||
env:
|
|
||||||
RNA_VERSION: v1.2.5 # renovate: datasource=gitea-releases depName=forgejo/release-notes-assistant registryUrl=https://code.forgejo.org
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-notes:
|
release-notes:
|
||||||
if: ( vars.ROLE == 'forgejo-coding' ) && contains(github.event.pull_request.labels.*.name, 'worth a release-note')
|
if: ( vars.ROLE == 'forgejo-coding' ) && contains(github.event.pull_request.labels.*.name, 'worth a release-note')
|
||||||
|
@ -41,4 +38,4 @@ jobs:
|
||||||
|
|
||||||
- name: release-notes-assistant preview
|
- name: release-notes-assistant preview
|
||||||
run: |
|
run: |
|
||||||
go run code.forgejo.org/forgejo/release-notes-assistant@$RNA_VERSION --config .release-notes-assistant.yaml --storage pr --storage-location ${{ github.event.pull_request.number }} --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} preview ${{ github.event.pull_request.number }}
|
go run code.forgejo.org/forgejo/release-notes-assistant@v1.1.1 --config .release-notes-assistant.yaml --storage pr --storage-location ${{ github.event.pull_request.number }} --forgejo-url $GITHUB_SERVER_URL --repository $GITHUB_REPOSITORY --token ${{ secrets.RELEASE_NOTES_ASSISTANT_TOKEN }} preview ${{ github.event.pull_request.number }}
|
||||||
|
|
|
@ -20,7 +20,7 @@ env:
|
||||||
RENOVATE_REPOSITORIES: ${{ github.repository }}
|
RENOVATE_REPOSITORIES: ${{ github.repository }}
|
||||||
# fix because 10.0.0-58-7e1df53+gitea-1.22.0 < 10.0.0 for semver
|
# fix because 10.0.0-58-7e1df53+gitea-1.22.0 < 10.0.0 for semver
|
||||||
# and codeberg api returns such versions from `git describe --tags`
|
# and codeberg api returns such versions from `git describe --tags`
|
||||||
# RENOVATE_X_PLATFORM_VERSION: 10.0.0+gitea-1.22.0 currently not needed
|
RENOVATE_X_PLATFORM_VERSION: 10.0.0+gitea-1.22.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
renovate:
|
renovate:
|
||||||
|
@ -28,7 +28,7 @@ jobs:
|
||||||
|
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: data.forgejo.org/renovate/renovate:41.17.2
|
image: data.forgejo.org/renovate/renovate:39.212.0
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Load renovate repo cache
|
- name: Load renovate repo cache
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
#
|
|
||||||
# Additional integration tests designed to run once a day when
|
|
||||||
# `mirror.yml` pushes to https://codeberg.org/forgejo-integration/forgejo
|
|
||||||
# and send a notification via email should they fail.
|
|
||||||
#
|
|
||||||
# For debug purposes:
|
|
||||||
#
|
|
||||||
# - uncomment [on].pull_request
|
|
||||||
# - swap 'forgejo-integration' and 'forgejo-coding'
|
|
||||||
# - open a pull request at https://codeberg.org/forgejo/forgejo and fix things
|
|
||||||
# - swap 'forgejo-integration' and 'forgejo-coding'
|
|
||||||
# - comment [on].pull_request
|
|
||||||
#
|
|
||||||
|
|
||||||
name: testing-integration
|
|
||||||
|
|
||||||
on:
|
|
||||||
# pull_request:
|
|
||||||
push:
|
|
||||||
tags: 'v[0-9]+.[0-9]+.*'
|
|
||||||
branches:
|
|
||||||
- 'forgejo'
|
|
||||||
- 'v*/forgejo'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-unit:
|
|
||||||
# if: vars.ROLE == 'forgejo-coding'
|
|
||||||
if: vars.ROLE == 'forgejo-integration'
|
|
||||||
runs-on: docker
|
|
||||||
container:
|
|
||||||
image: 'data.forgejo.org/oci/node:22-bookworm'
|
|
||||||
options: --tmpfs /tmp:exec,noatime
|
|
||||||
steps:
|
|
||||||
- uses: https://data.forgejo.org/actions/checkout@v4
|
|
||||||
- uses: ./.forgejo/workflows-composite/setup-env
|
|
||||||
- name: install git 2.34.1 and git-lfs 3.0.2
|
|
||||||
uses: ./.forgejo/workflows-composite/install-minimum-git-version
|
|
||||||
- uses: ./.forgejo/workflows-composite/build-backend
|
|
||||||
- run: |
|
|
||||||
su forgejo -c 'make test-backend test-check'
|
|
||||||
timeout-minutes: 120
|
|
||||||
env:
|
|
||||||
RACE_ENABLED: 'true'
|
|
||||||
TAGS: bindata
|
|
||||||
test-sqlite:
|
|
||||||
# if: vars.ROLE == 'forgejo-coding'
|
|
||||||
if: vars.ROLE == 'forgejo-integration'
|
|
||||||
runs-on: docker
|
|
||||||
container:
|
|
||||||
image: 'data.forgejo.org/oci/node:22-bookworm'
|
|
||||||
options: --tmpfs /tmp:exec,noatime
|
|
||||||
steps:
|
|
||||||
- uses: https://data.forgejo.org/actions/checkout@v4
|
|
||||||
- uses: ./.forgejo/workflows-composite/setup-env
|
|
||||||
- name: install git 2.34.1 and git-lfs 3.0.2
|
|
||||||
uses: ./.forgejo/workflows-composite/install-minimum-git-version
|
|
||||||
- uses: ./.forgejo/workflows-composite/build-backend
|
|
||||||
- run: |
|
|
||||||
su forgejo -c 'make test-sqlite-migration test-sqlite'
|
|
||||||
timeout-minutes: 120
|
|
||||||
env:
|
|
||||||
TAGS: sqlite sqlite_unlock_notify
|
|
||||||
RACE_ENABLED: true
|
|
||||||
TEST_TAGS: sqlite sqlite_unlock_notify
|
|
||||||
USE_REPO_TEST_DIR: 1
|
|
|
@ -91,7 +91,6 @@ jobs:
|
||||||
RACE_ENABLED: 'true'
|
RACE_ENABLED: 'true'
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
TEST_ELASTICSEARCH_URL: http://elasticsearch:9200
|
TEST_ELASTICSEARCH_URL: http://elasticsearch:9200
|
||||||
TEST_MINIO_ENDPOINT: minio:9000
|
|
||||||
test-e2e:
|
test-e2e:
|
||||||
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing'
|
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing'
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
|
@ -115,14 +114,9 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
su forgejo -c 'make deps-frontend frontend'
|
su forgejo -c 'make deps-frontend frontend'
|
||||||
- uses: ./.forgejo/workflows-composite/build-backend
|
- uses: ./.forgejo/workflows-composite/build-backend
|
||||||
- name: Decide to run all tests
|
|
||||||
id: run-all
|
|
||||||
if: contains(github.event.pull_request.labels.*.name, 'run-all-playwright-tests') || contains(github.event.pull_request.title, 'playwright')
|
|
||||||
run: |
|
|
||||||
echo "all=1" >> "$GITHUB_OUTPUT"
|
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
uses: https://data.forgejo.org/tj-actions/changed-files@v46
|
uses: https://data.forgejo.org/tj-actions/changed-files@v45
|
||||||
with:
|
with:
|
||||||
separator: '\n'
|
separator: '\n'
|
||||||
- run: |
|
- run: |
|
||||||
|
@ -132,7 +126,6 @@ jobs:
|
||||||
USE_REPO_TEST_DIR: 1
|
USE_REPO_TEST_DIR: 1
|
||||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
CHANGED_FILES: ${{steps.changed-files.outputs.all_changed_files}}
|
CHANGED_FILES: ${{steps.changed-files.outputs.all_changed_files}}
|
||||||
RUN_ALL: ${{steps.run-all.all}}
|
|
||||||
- name: Upload test artifacts on failure
|
- name: Upload test artifacts on failure
|
||||||
if: failure()
|
if: failure()
|
||||||
uses: https://data.forgejo.org/forgejo/upload-artifact@v4
|
uses: https://data.forgejo.org/forgejo/upload-artifact@v4
|
||||||
|
|
187
.golangci.yml
187
.golangci.yml
|
@ -1,9 +1,7 @@
|
||||||
version: "2"
|
|
||||||
output:
|
|
||||||
sort-order:
|
|
||||||
- file
|
|
||||||
linters:
|
linters:
|
||||||
default: none
|
enable-all: false
|
||||||
|
disable-all: true
|
||||||
|
fast: false
|
||||||
enable:
|
enable:
|
||||||
- bidichk
|
- bidichk
|
||||||
- depguard
|
- depguard
|
||||||
|
@ -11,37 +9,37 @@ linters:
|
||||||
- errcheck
|
- errcheck
|
||||||
- forbidigo
|
- forbidigo
|
||||||
- gocritic
|
- gocritic
|
||||||
|
- gofmt
|
||||||
|
- gofumpt
|
||||||
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- nakedret
|
- nakedret
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- revive
|
- revive
|
||||||
- staticcheck
|
- staticcheck
|
||||||
|
- stylecheck
|
||||||
- testifylint
|
- testifylint
|
||||||
|
- typecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
|
||||||
- unused
|
- unused
|
||||||
|
- unparam
|
||||||
- usetesting
|
- usetesting
|
||||||
- wastedassign
|
- wastedassign
|
||||||
settings:
|
|
||||||
depguard:
|
run:
|
||||||
rules:
|
timeout: 10m
|
||||||
main:
|
|
||||||
deny:
|
output:
|
||||||
- pkg: encoding/json
|
sort-results: true
|
||||||
desc: use gitea's modules/json instead of encoding/json
|
sort-order: [file]
|
||||||
- pkg: github.com/unknwon/com
|
show-stats: true
|
||||||
desc: use gitea's util and replacements
|
|
||||||
- pkg: io/ioutil
|
linters-settings:
|
||||||
desc: use os or io instead
|
stylecheck:
|
||||||
- pkg: golang.org/x/exp
|
checks: ["all", "-ST1005", "-ST1003"]
|
||||||
desc: it's experimental and unreliable
|
nakedret:
|
||||||
- pkg: forgejo.org/modules/git/internal
|
max-func-lines: 0
|
||||||
desc: do not use the internal package, use AddXxx function instead
|
|
||||||
- pkg: gopkg.in/ini.v1
|
|
||||||
desc: do not use the ini package, use gitea's config system instead
|
|
||||||
- pkg: github.com/minio/sha256-simd
|
|
||||||
desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528
|
|
||||||
gocritic:
|
gocritic:
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
- ifElseChain
|
- ifElseChain
|
||||||
|
@ -81,85 +79,72 @@ linters:
|
||||||
- name: var-naming
|
- name: var-naming
|
||||||
- name: redefines-builtin-id
|
- name: redefines-builtin-id
|
||||||
disabled: true
|
disabled: true
|
||||||
staticcheck:
|
gofumpt:
|
||||||
checks:
|
extra-rules: true
|
||||||
- all
|
depguard:
|
||||||
|
rules:
|
||||||
|
main:
|
||||||
|
deny:
|
||||||
|
- pkg: encoding/json
|
||||||
|
desc: use gitea's modules/json instead of encoding/json
|
||||||
|
- pkg: github.com/unknwon/com
|
||||||
|
desc: use gitea's util and replacements
|
||||||
|
- pkg: io/ioutil
|
||||||
|
desc: use os or io instead
|
||||||
|
- pkg: golang.org/x/exp
|
||||||
|
desc: it's experimental and unreliable
|
||||||
|
- pkg: forgejo.org/modules/git/internal
|
||||||
|
desc: do not use the internal package, use AddXxx function instead
|
||||||
|
- pkg: gopkg.in/ini.v1
|
||||||
|
desc: do not use the ini package, use gitea's config system instead
|
||||||
|
- pkg: github.com/minio/sha256-simd
|
||||||
|
desc: use crypto/sha256 instead, see https://codeberg.org/forgejo/forgejo/pulls/1528
|
||||||
testifylint:
|
testifylint:
|
||||||
disable:
|
disable:
|
||||||
- go-require
|
- go-require
|
||||||
exclusions:
|
|
||||||
generated: lax
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
- std-error-handling
|
|
||||||
rules:
|
|
||||||
- linters:
|
|
||||||
- nolintlint
|
|
||||||
path: models/db/sql_postgres_with_schema.go
|
|
||||||
- linters:
|
|
||||||
- dupl
|
|
||||||
- errcheck
|
|
||||||
- gocyclo
|
|
||||||
- gosec
|
|
||||||
- staticcheck
|
|
||||||
- unparam
|
|
||||||
path: _test\.go
|
|
||||||
- linters:
|
|
||||||
- dupl
|
|
||||||
- errcheck
|
|
||||||
- gocyclo
|
|
||||||
- gosec
|
|
||||||
path: models/migrations/v
|
|
||||||
- linters:
|
|
||||||
- forbidigo
|
|
||||||
path: cmd
|
|
||||||
- linters:
|
|
||||||
- dupl
|
|
||||||
text: (?i)webhook
|
|
||||||
- linters:
|
|
||||||
- gocritic
|
|
||||||
text: (?i)`ID' should not be capitalized
|
|
||||||
- linters:
|
|
||||||
- deadcode
|
|
||||||
- unused
|
|
||||||
text: (?i)swagger
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: (?i)argument x is overwritten before first use
|
|
||||||
- linters:
|
|
||||||
- gocritic
|
|
||||||
text: '(?i)commentFormatting: put a space between `//` and comment text'
|
|
||||||
- linters:
|
|
||||||
- gocritic
|
|
||||||
text: '(?i)exitAfterDefer:'
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "(ST1005|ST1003|QF1001):"
|
|
||||||
paths:
|
|
||||||
- node_modules
|
|
||||||
- public
|
|
||||||
- web_src
|
|
||||||
- third_party$
|
|
||||||
- builtin$
|
|
||||||
- examples$
|
|
||||||
issues:
|
issues:
|
||||||
max-issues-per-linter: 0
|
max-issues-per-linter: 0
|
||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
formatters:
|
exclude-dirs: [node_modules, public, web_src]
|
||||||
enable:
|
exclude-case-sensitive: true
|
||||||
- gofmt
|
exclude-rules:
|
||||||
- gofumpt
|
- path: models/db/sql_postgres_with_schema.go
|
||||||
settings:
|
linters:
|
||||||
gofumpt:
|
- nolintlint
|
||||||
extra-rules: true
|
- path: _test\.go
|
||||||
exclusions:
|
linters:
|
||||||
generated: lax
|
- gocyclo
|
||||||
paths:
|
- errcheck
|
||||||
- node_modules
|
- dupl
|
||||||
- public
|
- gosec
|
||||||
- web_src
|
- unparam
|
||||||
- third_party$
|
- staticcheck
|
||||||
- builtin$
|
- path: models/migrations/v
|
||||||
- examples$
|
linters:
|
||||||
|
- gocyclo
|
||||||
|
- errcheck
|
||||||
|
- dupl
|
||||||
|
- gosec
|
||||||
|
- path: cmd
|
||||||
|
linters:
|
||||||
|
- forbidigo
|
||||||
|
- text: "webhook"
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
- text: "`ID' should not be capitalized"
|
||||||
|
linters:
|
||||||
|
- gocritic
|
||||||
|
- text: "swagger"
|
||||||
|
linters:
|
||||||
|
- unused
|
||||||
|
- deadcode
|
||||||
|
- text: "argument x is overwritten before first use"
|
||||||
|
linters:
|
||||||
|
- staticcheck
|
||||||
|
- text: "commentFormatting: put a space between `//` and comment text"
|
||||||
|
linters:
|
||||||
|
- gocritic
|
||||||
|
- text: "exitAfterDefer:"
|
||||||
|
linters:
|
||||||
|
- gocritic
|
||||||
|
|
17
BSDmakefile
17
BSDmakefile
|
@ -36,6 +36,10 @@ GARGS = "--no-print-directory"
|
||||||
JARG = -j$(.MAKE.JOBS)
|
JARG = -j$(.MAKE.JOBS)
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
# bmake prefers out-of-source builds and tries to cd into ./obj (among others)
|
||||||
|
# where possible. GNU Make doesn't, so override that value.
|
||||||
|
.OBJDIR: ./
|
||||||
|
|
||||||
# The GNU convention is to use the lowercased `prefix` variable/macro to
|
# The GNU convention is to use the lowercased `prefix` variable/macro to
|
||||||
# specify the installation directory. Humor them.
|
# specify the installation directory. Humor them.
|
||||||
GPREFIX =
|
GPREFIX =
|
||||||
|
@ -44,12 +48,11 @@ GPREFIX =
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.BEGIN: .SILENT
|
.BEGIN: .SILENT
|
||||||
which $(GMAKE) >/dev/null || (printf "Error: GNU Make is required!\n\n" 1>&2 && false)
|
which $(GMAKE) || (printf "Error: GNU Make is required!\n\n" 1>&2 && false)
|
||||||
|
|
||||||
.PHONY: EMPTY
|
.PHONY: FRC
|
||||||
EMPTY: .SILENT
|
$(.TARGETS): FRC
|
||||||
$(GMAKE) $(GPREFIX) $(GARGS) $(JARG)
|
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||||
|
|
||||||
.PHONY: $(.TARGETS)
|
.DONE .DEFAULT: .SILENT
|
||||||
$(.TARGETS): .SILENT
|
$(GMAKE) $(GPREFIX) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||||
$(GMAKE) $(GPREFIX) $(GARGS) $(JARG) $@
|
|
||||||
|
|
|
@ -9,11 +9,10 @@
|
||||||
# Files related to frontend development.
|
# Files related to frontend development.
|
||||||
|
|
||||||
# Javascript and CSS code.
|
# Javascript and CSS code.
|
||||||
web_src/.* @beowulf @gusted
|
web_src/.* @caesar @crystal @gusted
|
||||||
web_src/css/.* @0ko
|
|
||||||
|
|
||||||
# HTML templates used by the backend.
|
# HTML templates used by the backend.
|
||||||
templates/.* @beowulf @gusted
|
templates/.* @caesar @crystal @gusted
|
||||||
## the issue sidebar was touched by fnetx
|
## the issue sidebar was touched by fnetx
|
||||||
templates/repo/issue/view_content/sidebar.* @fnetx
|
templates/repo/issue/view_content/sidebar.* @fnetx
|
||||||
|
|
||||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,9 +1,9 @@
|
||||||
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.21 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
ENV GOPROXY=${GOPROXY:-direct}
|
||||||
|
|
||||||
ARG RELEASE_VERSION
|
ARG RELEASE_VERSION
|
||||||
ARG TAGS="sqlite sqlite_unlock_notify"
|
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
|
@ -33,10 +33,10 @@ RUN apk --no-cache add build-base git nodejs npm
|
||||||
COPY . ${GOPATH}/src/forgejo.org
|
COPY . ${GOPATH}/src/forgejo.org
|
||||||
WORKDIR ${GOPATH}/src/forgejo.org
|
WORKDIR ${GOPATH}/src/forgejo.org
|
||||||
|
|
||||||
RUN make clean-no-bindata
|
RUN make clean
|
||||||
RUN make frontend
|
RUN make frontend
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
||||||
RUN LDFLAGS="-buildid=" make FORGEJO_GENERATE_SKIP_HASH=true RELEASE_VERSION=$RELEASE_VERSION GOFLAGS="-trimpath" go-check generate-backend static-executable && xx-verify gitea
|
RUN LDFLAGS="-buildid=" make RELEASE_VERSION=$RELEASE_VERSION GOFLAGS="-trimpath" go-check generate-backend static-executable && xx-verify gitea
|
||||||
|
|
||||||
# Copy local files
|
# Copy local files
|
||||||
COPY docker/root /tmp/local
|
COPY docker/root /tmp/local
|
||||||
|
@ -51,7 +51,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
||||||
/go/src/forgejo.org/environment-to-ini
|
/go/src/forgejo.org/environment-to-ini
|
||||||
RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM data.forgejo.org/oci/alpine:3.22
|
FROM data.forgejo.org/oci/alpine:3.21
|
||||||
ARG RELEASE_VERSION
|
ARG RELEASE_VERSION
|
||||||
LABEL maintainer="contact@forgejo.org" \
|
LABEL maintainer="contact@forgejo.org" \
|
||||||
org.opencontainers.image.authors="Forgejo" \
|
org.opencontainers.image.authors="Forgejo" \
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/xx AS xx
|
||||||
|
|
||||||
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.21 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
ENV GOPROXY=${GOPROXY:-direct}
|
||||||
|
|
||||||
ARG RELEASE_VERSION
|
ARG RELEASE_VERSION
|
||||||
ARG TAGS="sqlite sqlite_unlock_notify"
|
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
|
@ -33,10 +33,10 @@ RUN apk --no-cache add build-base git nodejs npm
|
||||||
COPY . ${GOPATH}/src/forgejo.org
|
COPY . ${GOPATH}/src/forgejo.org
|
||||||
WORKDIR ${GOPATH}/src/forgejo.org
|
WORKDIR ${GOPATH}/src/forgejo.org
|
||||||
|
|
||||||
RUN make clean-no-bindata
|
RUN make clean
|
||||||
RUN make frontend
|
RUN make frontend
|
||||||
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
RUN go build contrib/environment-to-ini/environment-to-ini.go && xx-verify environment-to-ini
|
||||||
RUN make FORGEJO_GENERATE_SKIP_HASH=true RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea
|
RUN make RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea
|
||||||
|
|
||||||
# Copy local files
|
# Copy local files
|
||||||
COPY docker/rootless /tmp/local
|
COPY docker/rootless /tmp/local
|
||||||
|
@ -49,7 +49,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
|
||||||
/go/src/forgejo.org/environment-to-ini
|
/go/src/forgejo.org/environment-to-ini
|
||||||
RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/forgejo.org/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM data.forgejo.org/oci/alpine:3.22
|
FROM data.forgejo.org/oci/alpine:3.21
|
||||||
ARG RELEASE_VERSION
|
ARG RELEASE_VERSION
|
||||||
LABEL maintainer="contact@forgejo.org" \
|
LABEL maintainer="contact@forgejo.org" \
|
||||||
org.opencontainers.image.authors="Forgejo" \
|
org.opencontainers.image.authors="Forgejo" \
|
||||||
|
|
146
Makefile
146
Makefile
|
@ -37,17 +37,19 @@ endif
|
||||||
XGO_VERSION := go-1.21.x
|
XGO_VERSION := go-1.21.x
|
||||||
|
|
||||||
AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go
|
AIR_PACKAGE ?= github.com/air-verse/air@v1 # renovate: datasource=go
|
||||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.3.0 # renovate: datasource=go
|
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.2.1 # renovate: datasource=go
|
||||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0 # renovate: datasource=go
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 # renovate: datasource=go
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.7 # renovate: datasource=go
|
||||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go
|
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 # renovate: datasource=go
|
||||||
|
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.6.0 # renovate: datasource=go
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.31.0 # renovate: datasource=go
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go
|
GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.6.0 # renovate: datasource=go
|
||||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasource=go
|
||||||
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go
|
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.31.0 # renovate: datasource=go
|
||||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go
|
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go
|
||||||
RENOVATE_NPM_PACKAGE ?= renovate@41.17.2 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
|
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.18.1 # renovate: datasource=go
|
||||||
|
RENOVATE_NPM_PACKAGE ?= renovate@39.212.0 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
|
||||||
|
|
||||||
# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/
|
# https://github.com/disposable-email-domains/disposable-email-domains/commits/main/
|
||||||
DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ...
|
DISPOSABLE_EMAILS_SHA ?= 0c27e671231d27cf66370034d7f6818037416989 # renovate: ...
|
||||||
|
@ -90,22 +92,29 @@ else
|
||||||
FORGEJO_VERSION_API ?= $(GITEA_VERSION)+${GITEA_COMPATIBILITY}
|
FORGEJO_VERSION_API ?= $(GITEA_VERSION)+${GITEA_COMPATIBILITY}
|
||||||
else
|
else
|
||||||
# drop the "g" prefix prepended by git describe to the commit hash
|
# drop the "g" prefix prepended by git describe to the commit hash
|
||||||
FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always 2>/dev/null | sed 's/^v//' | sed 's/\-g/-/')
|
FORGEJO_VERSION ?= $(shell git describe --exclude '*-test' --tags --always | sed 's/^v//' | sed 's/\-g/-/')+${GITEA_COMPATIBILITY}
|
||||||
ifneq ($(FORGEJO_VERSION),)
|
|
||||||
ifeq ($(findstring $(GITEA_COMPATIBILITY),$(FORGEJO_VERSION)),)
|
|
||||||
FORGEJO_VERSION := $(FORGEJO_VERSION)+$(GITEA_COMPATIBILITY)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
FORGEJO_VERSION_MAJOR=$(shell echo $(FORGEJO_VERSION) | sed -e 's/\..*//')
|
FORGEJO_VERSION_MAJOR=$(shell echo $(FORGEJO_VERSION) | sed -e 's/\..*//')
|
||||||
FORGEJO_VERSION_MINOR=$(shell echo $(FORGEJO_VERSION) | sed -E -e 's/^([0-9]+\.[0-9]+).*/\1/')
|
FORGEJO_VERSION_MINOR=$(shell echo $(FORGEJO_VERSION) | sed -E -e 's/^([0-9]+\.[0-9]+).*/\1/')
|
||||||
|
|
||||||
|
show-version-full:
|
||||||
|
@echo ${FORGEJO_VERSION}
|
||||||
|
|
||||||
|
show-version-major:
|
||||||
|
@echo ${FORGEJO_VERSION_MAJOR}
|
||||||
|
|
||||||
|
show-version-minor:
|
||||||
|
@echo ${FORGEJO_VERSION_MINOR}
|
||||||
|
|
||||||
RELEASE_VERSION ?= ${FORGEJO_VERSION}
|
RELEASE_VERSION ?= ${FORGEJO_VERSION}
|
||||||
VERSION ?= ${RELEASE_VERSION}
|
VERSION ?= ${RELEASE_VERSION}
|
||||||
|
|
||||||
FORGEJO_VERSION_API ?= ${FORGEJO_VERSION}
|
FORGEJO_VERSION_API ?= ${FORGEJO_VERSION}
|
||||||
|
|
||||||
|
show-version-api:
|
||||||
|
@echo ${FORGEJO_VERSION_API}
|
||||||
|
|
||||||
# Strip binaries by default to reduce size, allow overriding for debugging
|
# Strip binaries by default to reduce size, allow overriding for debugging
|
||||||
STRIP ?= 1
|
STRIP ?= 1
|
||||||
ifeq ($(STRIP),1)
|
ifeq ($(STRIP),1)
|
||||||
|
@ -128,7 +137,7 @@ 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 := modules/migration/bindata.go modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
BINDATA_DEST := modules/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
||||||
BINDATA_HASH := $(addsuffix .hash,$(BINDATA_DEST))
|
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
|
||||||
|
@ -212,22 +221,31 @@ help:
|
||||||
@echo " - deps-frontend install frontend dependencies"
|
@echo " - deps-frontend install frontend dependencies"
|
||||||
@echo " - deps-backend install backend dependencies"
|
@echo " - deps-backend install backend dependencies"
|
||||||
@echo " - deps-tools install tool dependencies"
|
@echo " - deps-tools install tool dependencies"
|
||||||
|
@echo " - deps-py install python dependencies"
|
||||||
@echo " - lint lint everything"
|
@echo " - lint lint everything"
|
||||||
@echo " - lint-fix lint everything and fix issues"
|
@echo " - lint-fix lint everything and fix issues"
|
||||||
@echo " - lint-frontend lint frontend files"
|
@echo " - lint-frontend lint frontend files"
|
||||||
@echo " - lint-frontend-fix lint frontend files and fix issues"
|
@echo " - lint-frontend-fix lint frontend files and fix issues"
|
||||||
@echo " - lint-backend lint backend files"
|
@echo " - lint-backend lint backend files"
|
||||||
@echo " - lint-backend-fix lint backend files and fix issues"
|
@echo " - lint-backend-fix lint backend files and fix issues"
|
||||||
|
@echo " - lint-codespell lint typos"
|
||||||
|
@echo " - lint-codespell-fix lint typos and fix them automatically"
|
||||||
|
@echo " - lint-codespell-fix-i lint typos and fix them interactively"
|
||||||
@echo " - lint-go lint go files"
|
@echo " - lint-go lint go files"
|
||||||
@echo " - lint-go-fix lint go files and fix issues"
|
@echo " - lint-go-fix lint go files and fix issues"
|
||||||
@echo " - lint-go-vet lint go files with vet"
|
@echo " - lint-go-vet lint go files with vet"
|
||||||
|
@echo " - lint-go-gopls lint go files with gopls"
|
||||||
@echo " - lint-js lint js files"
|
@echo " - lint-js lint js files"
|
||||||
@echo " - lint-js-fix lint js files and fix issues"
|
@echo " - lint-js-fix lint js files and fix issues"
|
||||||
@echo " - lint-css lint css files"
|
@echo " - lint-css lint css files"
|
||||||
@echo " - lint-css-fix lint css files and fix issues"
|
@echo " - lint-css-fix lint css files and fix issues"
|
||||||
@echo " - lint-md lint markdown files"
|
@echo " - lint-md lint markdown files"
|
||||||
@echo " - lint-swagger lint swagger files"
|
@echo " - lint-swagger lint swagger files"
|
||||||
|
@echo " - lint-templates lint template files"
|
||||||
@echo " - lint-renovate lint renovate files"
|
@echo " - lint-renovate lint renovate files"
|
||||||
|
@echo " - lint-yaml lint yaml files"
|
||||||
|
@echo " - lint-spell lint spelling"
|
||||||
|
@echo " - lint-spell-fix lint spelling and fix issues"
|
||||||
@echo " - checks run various consistency checks"
|
@echo " - checks run various consistency checks"
|
||||||
@echo " - checks-frontend check frontend files"
|
@echo " - checks-frontend check frontend files"
|
||||||
@echo " - checks-backend check backend files"
|
@echo " - checks-backend check backend files"
|
||||||
|
@ -258,30 +276,6 @@ help:
|
||||||
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
|
@echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite"
|
||||||
@echo " - reproduce-build\#version build a reproducible binary for the specified release version"
|
@echo " - reproduce-build\#version build a reproducible binary for the specified release version"
|
||||||
|
|
||||||
.PHONY: verify-version
|
|
||||||
verify-version:
|
|
||||||
ifeq ($(FORGEJO_VERSION),)
|
|
||||||
@echo "Error: Could not determine FORGEJO_VERSION; version file $(STORED_VERSION_FILE) not present and no suitable git tag found"
|
|
||||||
@echo 'In most cases this likely means you forgot to fetch git tags, you can fix this by executing `git fetch --tags`. If this is not possible and this is part of a custom build process, then you can set a specific version by writing it to $(STORED_VERSION_FILE) (This must be a semver compatible version).'
|
|
||||||
@false
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: show-version-full
|
|
||||||
show-version-full: verify-version
|
|
||||||
@echo ${FORGEJO_VERSION}
|
|
||||||
|
|
||||||
.PHONY: show-version-major
|
|
||||||
show-version-major: verify-version
|
|
||||||
@echo ${FORGEJO_VERSION_MAJOR}
|
|
||||||
|
|
||||||
.PHONY: show-version-minor
|
|
||||||
show-version-minor: verify-version
|
|
||||||
@echo ${FORGEJO_VERSION_MINOR}
|
|
||||||
|
|
||||||
.PHONY: show-version-api
|
|
||||||
show-version-api: verify-version
|
|
||||||
@echo ${FORGEJO_VERSION_API}
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# Check system and environment requirements
|
# Check system and environment requirements
|
||||||
###
|
###
|
||||||
|
@ -323,12 +317,8 @@ clean-all: clean
|
||||||
rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
|
rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: clean-no-bindata
|
clean:
|
||||||
rm -rf $(BINDATA_DEST) $(BINDATA_HASH)
|
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
|
||||||
|
|
||||||
.PHONY: clean-no-bindata
|
|
||||||
clean-no-bindata:
|
|
||||||
rm -rf $(EXECUTABLE) $(DIST) \
|
|
||||||
integrations*.test \
|
integrations*.test \
|
||||||
e2e*.test \
|
e2e*.test \
|
||||||
tests/integration/gitea-integration-* \
|
tests/integration/gitea-integration-* \
|
||||||
|
@ -411,10 +401,10 @@ checks-frontend: lockfile-check svg-check
|
||||||
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check
|
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-frontend lint-backend
|
lint: lint-frontend lint-backend lint-spell
|
||||||
|
|
||||||
.PHONY: lint-fix
|
.PHONY: lint-fix
|
||||||
lint-fix: lint-frontend-fix lint-backend-fix
|
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix
|
||||||
|
|
||||||
.PHONY: lint-frontend
|
.PHONY: lint-frontend
|
||||||
lint-frontend: lint-js lint-css
|
lint-frontend: lint-js lint-css
|
||||||
|
@ -428,6 +418,18 @@ lint-backend: lint-go lint-go-vet lint-editorconfig lint-renovate lint-locale li
|
||||||
.PHONY: lint-backend-fix
|
.PHONY: lint-backend-fix
|
||||||
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig lint-disposable-emails-fix
|
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig lint-disposable-emails-fix
|
||||||
|
|
||||||
|
.PHONY: lint-codespell
|
||||||
|
lint-codespell: deps-py
|
||||||
|
@poetry run codespell
|
||||||
|
|
||||||
|
.PHONY: lint-codespell-fix
|
||||||
|
lint-codespell-fix: deps-py
|
||||||
|
@poetry run codespell -w
|
||||||
|
|
||||||
|
.PHONY: lint-codespell-fix-i
|
||||||
|
lint-codespell-fix-i: deps-py
|
||||||
|
@poetry run codespell -w -i 3 -C 2
|
||||||
|
|
||||||
.PHONY: lint-js
|
.PHONY: lint-js
|
||||||
lint-js: node_modules
|
lint-js: node_modules
|
||||||
npx eslint --color --max-warnings=0
|
npx eslint --color --max-warnings=0
|
||||||
|
@ -450,8 +452,8 @@ lint-swagger: node_modules
|
||||||
|
|
||||||
.PHONY: lint-renovate
|
.PHONY: lint-renovate
|
||||||
lint-renovate: node_modules
|
lint-renovate: node_modules
|
||||||
npx --yes --package $(RENOVATE_NPM_PACKAGE) -- renovate-config-validator > .lint-renovate 2>&1 || true
|
npx --yes --package $(RENOVATE_NPM_PACKAGE) -- renovate-config-validator --strict > .lint-renovate 2>&1 || true
|
||||||
@if grep --quiet --extended-regexp -e '^( ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi
|
@if grep --quiet --extended-regexp -e '^( WARN:|ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi
|
||||||
@rm .lint-renovate
|
@rm .lint-renovate
|
||||||
|
|
||||||
.PHONY: lint-locale
|
.PHONY: lint-locale
|
||||||
|
@ -460,12 +462,20 @@ lint-locale:
|
||||||
|
|
||||||
.PHONY: lint-locale-usage
|
.PHONY: lint-locale-usage
|
||||||
lint-locale-usage:
|
lint-locale-usage:
|
||||||
$(GO) run build/lint-locale-usage/lint-locale-usage.go
|
$(GO) run build/lint-locale-usage/lint-locale-usage.go --allow-missing-msgids
|
||||||
|
|
||||||
.PHONY: lint-md
|
.PHONY: lint-md
|
||||||
lint-md: node_modules
|
lint-md: node_modules
|
||||||
npx markdownlint docs *.md
|
npx markdownlint docs *.md
|
||||||
|
|
||||||
|
.PHONY: lint-spell
|
||||||
|
lint-spell: lint-codespell
|
||||||
|
@go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES)
|
||||||
|
|
||||||
|
.PHONY: lint-spell-fix
|
||||||
|
lint-spell-fix: lint-codespell-fix
|
||||||
|
@go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES)
|
||||||
|
|
||||||
RUN_DEADCODE = $(GO) run $(DEADCODE_PACKAGE) -generated=false -f='{{println .Path}}{{range .Funcs}}{{printf "\t%s\n" .Name}}{{end}}{{println}}' -test forgejo.org
|
RUN_DEADCODE = $(GO) run $(DEADCODE_PACKAGE) -generated=false -f='{{println .Path}}{{range .Funcs}}{{printf "\t%s\n" .Name}}{{end}}{{println}}' -test forgejo.org
|
||||||
|
|
||||||
.PHONY: lint-go
|
.PHONY: lint-go
|
||||||
|
@ -485,6 +495,11 @@ lint-go-vet:
|
||||||
@echo "Running go vet..."
|
@echo "Running go vet..."
|
||||||
@$(GO) vet ./...
|
@$(GO) vet ./...
|
||||||
|
|
||||||
|
.PHONY: lint-go-gopls
|
||||||
|
lint-go-gopls:
|
||||||
|
@echo "Running gopls check..."
|
||||||
|
@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:
|
||||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows
|
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates .forgejo/workflows
|
||||||
|
@ -497,9 +512,18 @@ lint-disposable-emails:
|
||||||
lint-disposable-emails-fix:
|
lint-disposable-emails-fix:
|
||||||
$(GO) run build/generate-disposable-email.go -r $(DISPOSABLE_EMAILS_SHA)
|
$(GO) run build/generate-disposable-email.go -r $(DISPOSABLE_EMAILS_SHA)
|
||||||
|
|
||||||
|
.PHONY: lint-templates
|
||||||
|
lint-templates: .venv node_modules
|
||||||
|
@node tools/lint-templates-svg.js
|
||||||
|
@poetry run djlint $(shell find templates -type f -iname '*.tmpl')
|
||||||
|
|
||||||
|
.PHONY: lint-yaml
|
||||||
|
lint-yaml: .venv
|
||||||
|
@poetry run yamllint -s .
|
||||||
|
|
||||||
.PHONY: security-check
|
.PHONY: security-check
|
||||||
security-check:
|
security-check:
|
||||||
go run $(GOVULNCHECK_PACKAGE) -show color ./...
|
go run $(GOVULNCHECK_PACKAGE) ./...
|
||||||
|
|
||||||
###
|
###
|
||||||
# Development and testing targets
|
# Development and testing targets
|
||||||
|
@ -553,7 +577,7 @@ test-check:
|
||||||
|
|
||||||
.PHONY: test\#%
|
.PHONY: test\#%
|
||||||
test\#%:
|
test\#%:
|
||||||
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
|
@echo "Running go test with -tags '$(TEST_TAGS)'..."
|
||||||
@$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
@$(GOTEST) $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
|
@ -792,7 +816,7 @@ check: test
|
||||||
###
|
###
|
||||||
|
|
||||||
.PHONY: install $(TAGS_PREREQ)
|
.PHONY: install $(TAGS_PREREQ)
|
||||||
install: $(wildcard *.go) | verify-version
|
install: $(wildcard *.go)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)'
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
@ -820,13 +844,13 @@ generate-go: $(TAGS_PREREQ)
|
||||||
merge-locales:
|
merge-locales:
|
||||||
@echo "NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY"
|
@echo "NOT NEEDED: THIS IS A NOOP AS OF Forgejo 7.0 BUT KEPT FOR BACKWARD COMPATIBILITY"
|
||||||
|
|
||||||
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ) | verify-version
|
$(EXECUTABLE): $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $@
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $@
|
||||||
|
|
||||||
forgejo: $(EXECUTABLE)
|
forgejo: $(EXECUTABLE)
|
||||||
ln -f $(EXECUTABLE) forgejo
|
ln -f $(EXECUTABLE) forgejo
|
||||||
|
|
||||||
static-executable: $(GO_SOURCES) $(TAGS_PREREQ) | verify-version
|
static-executable: $(GO_SOURCES) $(TAGS_PREREQ)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -o $(EXECUTABLE)
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -o $(EXECUTABLE)
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
|
@ -839,18 +863,18 @@ $(DIST_DIRS):
|
||||||
mkdir -p $(DIST_DIRS)
|
mkdir -p $(DIST_DIRS)
|
||||||
|
|
||||||
.PHONY: release-linux
|
.PHONY: release-linux
|
||||||
release-linux: | $(DIST_DIRS) verify-version
|
release-linux: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out forgejo-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out forgejo-$(VERSION) .
|
||||||
ifeq ($(CI),true)
|
ifeq ($(CI),true)
|
||||||
cp /build/* $(DIST)/binaries
|
cp /build/* $(DIST)/binaries
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: release-darwin
|
.PHONY: release-darwin
|
||||||
release-darwin: | $(DIST_DIRS) verify-version
|
release-darwin: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||||
|
|
||||||
.PHONY: release-freebsd
|
.PHONY: release-freebsd
|
||||||
release-freebsd: | $(DIST_DIRS) verify-version
|
release-freebsd: | $(DIST_DIRS)
|
||||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'freebsd/amd64' -out gitea-$(VERSION) .
|
||||||
|
|
||||||
.PHONY: release-copy
|
.PHONY: release-copy
|
||||||
|
@ -904,7 +928,10 @@ reproduce-build\#%:
|
||||||
###
|
###
|
||||||
|
|
||||||
.PHONY: deps
|
.PHONY: deps
|
||||||
deps: deps-frontend deps-backend deps-tools
|
deps: deps-frontend deps-backend deps-tools deps-py
|
||||||
|
|
||||||
|
.PHONY: deps-py
|
||||||
|
deps-py: .venv
|
||||||
|
|
||||||
.PHONY: deps-frontend
|
.PHONY: deps-frontend
|
||||||
deps-frontend: node_modules
|
deps-frontend: node_modules
|
||||||
|
@ -920,11 +947,13 @@ deps-tools:
|
||||||
$(GO) install $(GOFUMPT_PACKAGE)
|
$(GO) install $(GOFUMPT_PACKAGE)
|
||||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||||
$(GO) install $(GXZ_PACKAGE)
|
$(GO) install $(GXZ_PACKAGE)
|
||||||
|
$(GO) install $(MISSPELL_PACKAGE)
|
||||||
$(GO) install $(SWAGGER_PACKAGE)
|
$(GO) install $(SWAGGER_PACKAGE)
|
||||||
$(GO) install $(XGO_PACKAGE)
|
$(GO) install $(XGO_PACKAGE)
|
||||||
$(GO) install $(GO_LICENSES_PACKAGE)
|
$(GO) install $(GO_LICENSES_PACKAGE)
|
||||||
$(GO) install $(GOVULNCHECK_PACKAGE)
|
$(GO) install $(GOVULNCHECK_PACKAGE)
|
||||||
$(GO) install $(GOMOCK_PACKAGE)
|
$(GO) install $(GOMOCK_PACKAGE)
|
||||||
|
$(GO) install $(GOPLS_PACKAGE)
|
||||||
|
|
||||||
node_modules: package-lock.json
|
node_modules: package-lock.json
|
||||||
npm install --no-save
|
npm install --no-save
|
||||||
|
@ -988,7 +1017,8 @@ generate-gomock:
|
||||||
|
|
||||||
.PHONY: generate-images
|
.PHONY: generate-images
|
||||||
generate-images: | node_modules
|
generate-images: | node_modules
|
||||||
node tools/generate-images.js
|
npm install --no-save fabric@6 imagemin-zopfli@7
|
||||||
|
node tools/generate-images.js $(TAGS)
|
||||||
|
|
||||||
.PHONY: generate-manpage
|
.PHONY: generate-manpage
|
||||||
generate-manpage:
|
generate-manpage:
|
||||||
|
|
|
@ -15,6 +15,11 @@ Our promise: **Independent Free/Libre Software forever!**
|
||||||
|
|
||||||
## What does Forgejo offer?
|
## What does Forgejo offer?
|
||||||
|
|
||||||
|
<!-- If you want to know what Forgejo is like,
|
||||||
|
you can check out public instances,
|
||||||
|
e.g. [Codeberg.org](https://codeberg.org).
|
||||||
|
-->
|
||||||
|
|
||||||
If you like any of the following, Forgejo is literally meant for you:
|
If you like any of the following, Forgejo is literally meant for you:
|
||||||
|
|
||||||
- Lightweight: Forgejo can easily be hosted on nearly **every machine**.
|
- Lightweight: Forgejo can easily be hosted on nearly **every machine**.
|
||||||
|
|
60
assets/go-licenses.json
generated
60
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
14
build.go
Normal file
14
build.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//go:build vendor
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// Libraries that are included to vendor utilities used during build.
|
||||||
|
// These libraries will not be included in a normal compilation.
|
||||||
|
|
||||||
|
import (
|
||||||
|
// for embed
|
||||||
|
_ "github.com/shurcooL/vfsgen"
|
||||||
|
)
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
// SPDX-License-Identifier: MIT
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
//go:build ignore
|
//go:build ignore
|
||||||
|
|
||||||
|
@ -8,40 +7,30 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha256"
|
"crypto/sha1"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/fs"
|
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/shurcooL/vfsgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
func fileExists(filename string) bool {
|
|
||||||
_, err := os.Stat(filename)
|
|
||||||
if err == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func needsUpdate(dir, filename string) (bool, []byte) {
|
func needsUpdate(dir, filename string) (bool, []byte) {
|
||||||
needRegen := !fileExists(filename)
|
needRegen := false
|
||||||
|
_, err := os.Stat(filename)
|
||||||
|
if err != nil {
|
||||||
|
needRegen = true
|
||||||
|
}
|
||||||
|
|
||||||
oldHash, err := os.ReadFile(filename + ".hash")
|
oldHash, err := os.ReadFile(filename + ".hash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oldHash = []byte{}
|
oldHash = []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher := sha256.New()
|
hasher := sha1.New()
|
||||||
|
|
||||||
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
|
err = filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -62,7 +51,7 @@ func needsUpdate(dir, filename string) (bool, []byte) {
|
||||||
|
|
||||||
newHash := hasher.Sum([]byte{})
|
newHash := hasher.Sum([]byte{})
|
||||||
|
|
||||||
if !bytes.Equal(oldHash, newHash) {
|
if bytes.Compare(oldHash, newHash) != 0 {
|
||||||
return true, newHash
|
return true, newHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,280 +69,24 @@ func main() {
|
||||||
useGlobalModTime, _ = strconv.ParseBool(os.Args[4])
|
useGlobalModTime, _ = strconv.ParseBool(os.Args[4])
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.Getenv("FORGEJO_GENERATE_SKIP_HASH") == "true" && fileExists(filename) {
|
|
||||||
fmt.Printf("bindata %s already exists and FORGEJO_GENERATE_SKIP_HASH=true\n", packageName)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
update, newHash := needsUpdate(dir, filename)
|
update, newHash := needsUpdate(dir, filename)
|
||||||
|
|
||||||
if !update {
|
if !update {
|
||||||
fmt.Printf("bindata %s already exists and the checksum is a match\n", packageName)
|
fmt.Printf("bindata for %s already up-to-date\n", packageName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("generating bindata for %s\n", packageName)
|
fmt.Printf("generating bindata for %s\n", packageName)
|
||||||
|
var fsTemplates http.FileSystem = http.Dir(dir)
|
||||||
root, err := os.OpenRoot(dir)
|
err := vfsgen.Generate(fsTemplates, vfsgen.Options{
|
||||||
|
PackageName: packageName,
|
||||||
|
BuildTags: "bindata",
|
||||||
|
VariableName: "Assets",
|
||||||
|
Filename: filename,
|
||||||
|
UseGlobalModTime: useGlobalModTime,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatalf("%v\n", err)
|
||||||
}
|
|
||||||
|
|
||||||
out, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer out.Close()
|
|
||||||
|
|
||||||
if err := generate(root.FS(), packageName, useGlobalModTime, out); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
}
|
||||||
_ = os.WriteFile(filename+".hash", newHash, 0o666)
|
_ = os.WriteFile(filename+".hash", newHash, 0o666)
|
||||||
}
|
}
|
||||||
|
|
||||||
type file struct {
|
|
||||||
Path string
|
|
||||||
Name string
|
|
||||||
UncompressedSize int
|
|
||||||
CompressedData []byte
|
|
||||||
UncompressedData []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type direntry struct {
|
|
||||||
Name string
|
|
||||||
IsDir bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func generate(fsRoot fs.FS, packageName string, globalTime bool, output io.Writer) error {
|
|
||||||
enc, err := zstd.NewWriter(nil, zstd.WithEncoderLevel(zstd.SpeedBestCompression))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
files := []file{}
|
|
||||||
|
|
||||||
dirs := map[string][]direntry{}
|
|
||||||
|
|
||||||
if err := fs.WalkDir(fsRoot, ".", func(filePath string, d fs.DirEntry, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.IsDir() {
|
|
||||||
entries, err := fs.ReadDir(fsRoot, filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
dirEntries := make([]direntry, 0, len(entries))
|
|
||||||
for _, entry := range entries {
|
|
||||||
dirEntries = append(dirEntries, direntry{Name: entry.Name(), IsDir: entry.IsDir()})
|
|
||||||
}
|
|
||||||
dirs[filePath] = dirEntries
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err := fs.ReadFile(fsRoot, filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dst := enc.EncodeAll(src, nil)
|
|
||||||
if len(dst) < len(src) {
|
|
||||||
files = append(files, file{
|
|
||||||
Path: filePath,
|
|
||||||
Name: path.Base(filePath),
|
|
||||||
UncompressedSize: len(src),
|
|
||||||
CompressedData: dst,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
files = append(files, file{
|
|
||||||
Path: filePath,
|
|
||||||
Name: path.Base(filePath),
|
|
||||||
UncompressedData: src,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return generatedTmpl.Execute(output, map[string]any{
|
|
||||||
"Packagename": packageName,
|
|
||||||
"GlobalTime": globalTime,
|
|
||||||
"Files": files,
|
|
||||||
"Dirs": dirs,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
var generatedTmpl = template.Must(template.New("").Parse(`// Code generated by efs-gen. DO NOT EDIT.
|
|
||||||
|
|
||||||
//go:build bindata
|
|
||||||
|
|
||||||
package {{.Packagename}}
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"time"
|
|
||||||
"io"
|
|
||||||
"io/fs"
|
|
||||||
|
|
||||||
"github.com/klauspost/compress/zstd"
|
|
||||||
)
|
|
||||||
|
|
||||||
type normalFile struct {
|
|
||||||
name string
|
|
||||||
content []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type compressedFile struct {
|
|
||||||
name string
|
|
||||||
uncompressedSize int64
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var files = map[string]any{
|
|
||||||
{{- range .Files}}
|
|
||||||
"{{.Path}}": {{if .CompressedData}}compressedFile{"{{.Name}}", {{.UncompressedSize}}, []byte({{printf "%+q" .CompressedData}})}{{else}}normalFile{"{{.Name}}", []byte({{printf "%+q" .UncompressedData}})}{{end}},
|
|
||||||
{{- end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
var dirs = map[string][]fs.DirEntry{
|
|
||||||
{{- range $key, $entry := .Dirs}}
|
|
||||||
"{{$key}}": {
|
|
||||||
{{- range $entry}}
|
|
||||||
direntry{"{{.Name}}", {{.IsDir}}},
|
|
||||||
{{- end}}
|
|
||||||
},
|
|
||||||
{{- end}}
|
|
||||||
}
|
|
||||||
|
|
||||||
type assets struct{}
|
|
||||||
|
|
||||||
var Assets = assets{}
|
|
||||||
|
|
||||||
func (a assets) Open(name string) (fs.File, error) {
|
|
||||||
f, ok := files[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch f := f.(type) {
|
|
||||||
case normalFile:
|
|
||||||
return file{name: f.name, size: int64(len(f.content)), data: bytes.NewReader(f.content)}, nil
|
|
||||||
case compressedFile:
|
|
||||||
r, _ := zstd.NewReader(bytes.NewReader(f.data))
|
|
||||||
return &compressFile{name: f.name, size: f.uncompressedSize, data: r, content: f.data}, nil
|
|
||||||
default:
|
|
||||||
panic("unknown file type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a assets) ReadDir(name string) ([]fs.DirEntry, error) {
|
|
||||||
d, ok := dirs[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
|
||||||
}
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type file struct {
|
|
||||||
name string
|
|
||||||
size int64
|
|
||||||
data io.ReadSeeker
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ io.ReadSeeker = (*file)(nil)
|
|
||||||
|
|
||||||
func (f file) Stat() (fs.FileInfo, error) {
|
|
||||||
return fileinfo{name: f.name, size: f.size}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f file) Read(p []byte) (int, error) {
|
|
||||||
return f.data.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f file) Seek(offset int64, whence int) (int64, error) {
|
|
||||||
return f.data.Seek(offset, whence)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f file) Close() error { return nil }
|
|
||||||
|
|
||||||
type compressFile struct {
|
|
||||||
name string
|
|
||||||
size int64
|
|
||||||
data *zstd.Decoder
|
|
||||||
content []byte
|
|
||||||
zstdPos int64
|
|
||||||
seekPos int64
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ io.ReadSeeker = (*compressFile)(nil)
|
|
||||||
|
|
||||||
func (f *compressFile) Stat() (fs.FileInfo, error) {
|
|
||||||
return fileinfo{name: f.name, size: f.size}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *compressFile) Read(p []byte) (int, error) {
|
|
||||||
if f.zstdPos > f.seekPos {
|
|
||||||
if err := f.data.Reset(bytes.NewReader(f.content)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
f.zstdPos = 0
|
|
||||||
}
|
|
||||||
if f.zstdPos < f.seekPos {
|
|
||||||
if _, err := io.CopyN(io.Discard, f.data, f.seekPos - f.zstdPos); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
f.zstdPos = f.seekPos
|
|
||||||
}
|
|
||||||
n, err := f.data.Read(p)
|
|
||||||
f.zstdPos += int64(n)
|
|
||||||
f.seekPos = f.zstdPos
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *compressFile) Seek(offset int64, whence int) (int64, error) {
|
|
||||||
switch whence {
|
|
||||||
case io.SeekStart:
|
|
||||||
f.seekPos = 0 + offset
|
|
||||||
case io.SeekCurrent:
|
|
||||||
f.seekPos += offset
|
|
||||||
case io.SeekEnd:
|
|
||||||
f.seekPos = f.size + offset
|
|
||||||
}
|
|
||||||
return f.seekPos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *compressFile) Close() error {
|
|
||||||
f.data.Close()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *compressFile) ZstdBytes() []byte { return f.content }
|
|
||||||
|
|
||||||
type fileinfo struct {
|
|
||||||
name string
|
|
||||||
size int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f fileinfo) Name() string { return f.name }
|
|
||||||
func (f fileinfo) Size() int64 { return f.size }
|
|
||||||
func (f fileinfo) Mode() fs.FileMode { return 0o444 }
|
|
||||||
func (f fileinfo) ModTime() time.Time { return {{if .GlobalTime}}GlobalModTime(f.name){{else}}time.Unix(0, 0){{end}} }
|
|
||||||
func (f fileinfo) IsDir() bool { return false }
|
|
||||||
func (f fileinfo) Sys() any { return nil }
|
|
||||||
|
|
||||||
type direntry struct {
|
|
||||||
name string
|
|
||||||
isDir bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d direntry) Name() string { return d.name }
|
|
||||||
func (d direntry) IsDir() bool { return d.isDir }
|
|
||||||
func (d direntry) Type() fs.FileMode {
|
|
||||||
if d.isDir {
|
|
||||||
return 0o755 | fs.ModeDir
|
|
||||||
}
|
|
||||||
return 0o444
|
|
||||||
}
|
|
||||||
func (direntry) Info() (fs.FileInfo, error) { return nil, fs.ErrNotExist }
|
|
||||||
`))
|
|
||||||
|
|
|
@ -18,14 +18,16 @@ import (
|
||||||
tmplParser "text/template/parse"
|
tmplParser "text/template/parse"
|
||||||
|
|
||||||
"forgejo.org/modules/container"
|
"forgejo.org/modules/container"
|
||||||
|
"forgejo.org/modules/locale"
|
||||||
fjTemplates "forgejo.org/modules/templates"
|
fjTemplates "forgejo.org/modules/templates"
|
||||||
"forgejo.org/modules/translation/localeiter"
|
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// this works by first gathering all valid source string IDs from `en-US` reference files
|
// this works by first gathering all valid source string IDs from `en-US` reference files
|
||||||
// and then checking if all used source strings are actually defined
|
// and then checking if all used source strings are actually defined
|
||||||
|
|
||||||
|
type OnMsgidHandler func(fset *token.FileSet, pos token.Pos, msgid string)
|
||||||
|
|
||||||
type LocatedError struct {
|
type LocatedError struct {
|
||||||
Location string
|
Location string
|
||||||
Kind string
|
Kind string
|
||||||
|
@ -47,24 +49,8 @@ func (e LocatedError) Error() string {
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitLocaleTrFunctions() map[string][]uint {
|
func isLocaleTrFunction(funcname string) bool {
|
||||||
ret := make(map[string][]uint)
|
return funcname == "Tr" || funcname == "TrN"
|
||||||
|
|
||||||
f0 := []uint{0}
|
|
||||||
ret["Tr"] = f0
|
|
||||||
ret["TrString"] = f0
|
|
||||||
ret["TrHTML"] = f0
|
|
||||||
|
|
||||||
ret["TrPluralString"] = []uint{1}
|
|
||||||
ret["TrN"] = []uint{1, 2}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
OnMsgid func(fset *token.FileSet, pos token.Pos, msgid string)
|
|
||||||
OnUnexpectedInvoke func(fset *token.FileSet, pos token.Pos, funcname string, argc int)
|
|
||||||
LocaleTrFunctions map[string][]uint
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the `Handle*File` functions follow the following calling convention:
|
// the `Handle*File` functions follow the following calling convention:
|
||||||
|
@ -72,7 +58,7 @@ type Handler struct {
|
||||||
// * `src` is either `nil` (then the function invokes `ReadFile` to read the file)
|
// * `src` is either `nil` (then the function invokes `ReadFile` to read the file)
|
||||||
// or the contents of the file as {`[]byte`, or a `string`}
|
// or the contents of the file as {`[]byte`, or a `string`}
|
||||||
|
|
||||||
func (handler Handler) HandleGoFile(fname string, src any) error {
|
func (omh OnMsgidHandler) HandleGoFile(fname string, src any) error {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
node, err := goParser.ParseFile(fset, fname, src, goParser.SkipObjectResolution)
|
node, err := goParser.ParseFile(fset, fname, src, goParser.SkipObjectResolution)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -84,47 +70,31 @@ func (handler Handler) HandleGoFile(fname string, src any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ast.Inspect(node, func(n ast.Node) bool {
|
ast.Inspect(node, func(n ast.Node) bool {
|
||||||
// search for function calls of the form `anything.Tr(any-string-lit, ...)`
|
// search for function calls of the form `anything.Tr(any-string-lit)`
|
||||||
|
|
||||||
call, ok := n.(*ast.CallExpr)
|
call, ok := n.(*ast.CallExpr)
|
||||||
if !ok || len(call.Args) < 1 {
|
if !ok || len(call.Args) != 1 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
funSel, ok := call.Fun.(*ast.SelectorExpr)
|
funSel, ok := call.Fun.(*ast.SelectorExpr)
|
||||||
if !ok {
|
if (!ok) || !isLocaleTrFunction(funSel.Sel.Name) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
ltf, ok := handler.LocaleTrFunctions[funSel.Sel.Name]
|
argLit, ok := call.Args[0].(*ast.BasicLit)
|
||||||
if !ok {
|
if (!ok) || argLit.Kind != token.STRING {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var gotUnexpectedInvoke *int
|
|
||||||
|
|
||||||
for _, argNum := range ltf {
|
|
||||||
if len(call.Args) >= int(argNum+1) {
|
|
||||||
argLit, ok := call.Args[int(argNum)].(*ast.BasicLit)
|
|
||||||
if !ok || argLit.Kind != token.STRING {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract string content
|
// extract string content
|
||||||
arg, err := strconv.Unquote(argLit.Value)
|
arg, err := strconv.Unquote(argLit.Value)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
// found interesting strings
|
return true
|
||||||
handler.OnMsgid(fset, argLit.ValuePos, arg)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
argc := len(call.Args)
|
|
||||||
gotUnexpectedInvoke = &argc
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if gotUnexpectedInvoke != nil {
|
// found interesting string
|
||||||
handler.OnUnexpectedInvoke(fset, funSel.Sel.NamePos, funSel.Sel.Name, *gotUnexpectedInvoke)
|
omh(fset, argLit.ValuePos, arg)
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
@ -133,33 +103,33 @@ func (handler Handler) HandleGoFile(fname string, src any) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// derived from source: modules/templates/scopedtmpl/scopedtmpl.go, L169-L213
|
// derived from source: modules/templates/scopedtmpl/scopedtmpl.go, L169-L213
|
||||||
func (handler Handler) handleTemplateNode(fset *token.FileSet, node tmplParser.Node) {
|
func (omh OnMsgidHandler) handleTemplateNode(fset *token.FileSet, node tmplParser.Node) {
|
||||||
switch node.Type() {
|
switch node.Type() {
|
||||||
case tmplParser.NodeAction:
|
case tmplParser.NodeAction:
|
||||||
handler.handleTemplatePipeNode(fset, node.(*tmplParser.ActionNode).Pipe)
|
omh.handleTemplatePipeNode(fset, node.(*tmplParser.ActionNode).Pipe)
|
||||||
case tmplParser.NodeList:
|
case tmplParser.NodeList:
|
||||||
nodeList := node.(*tmplParser.ListNode)
|
nodeList := node.(*tmplParser.ListNode)
|
||||||
handler.handleTemplateFileNodes(fset, nodeList.Nodes)
|
omh.handleTemplateFileNodes(fset, nodeList.Nodes)
|
||||||
case tmplParser.NodePipe:
|
case tmplParser.NodePipe:
|
||||||
handler.handleTemplatePipeNode(fset, node.(*tmplParser.PipeNode))
|
omh.handleTemplatePipeNode(fset, node.(*tmplParser.PipeNode))
|
||||||
case tmplParser.NodeTemplate:
|
case tmplParser.NodeTemplate:
|
||||||
handler.handleTemplatePipeNode(fset, node.(*tmplParser.TemplateNode).Pipe)
|
omh.handleTemplatePipeNode(fset, node.(*tmplParser.TemplateNode).Pipe)
|
||||||
case tmplParser.NodeIf:
|
case tmplParser.NodeIf:
|
||||||
nodeIf := node.(*tmplParser.IfNode)
|
nodeIf := node.(*tmplParser.IfNode)
|
||||||
handler.handleTemplateBranchNode(fset, nodeIf.BranchNode)
|
omh.handleTemplateBranchNode(fset, nodeIf.BranchNode)
|
||||||
case tmplParser.NodeRange:
|
case tmplParser.NodeRange:
|
||||||
nodeRange := node.(*tmplParser.RangeNode)
|
nodeRange := node.(*tmplParser.RangeNode)
|
||||||
handler.handleTemplateBranchNode(fset, nodeRange.BranchNode)
|
omh.handleTemplateBranchNode(fset, nodeRange.BranchNode)
|
||||||
case tmplParser.NodeWith:
|
case tmplParser.NodeWith:
|
||||||
nodeWith := node.(*tmplParser.WithNode)
|
nodeWith := node.(*tmplParser.WithNode)
|
||||||
handler.handleTemplateBranchNode(fset, nodeWith.BranchNode)
|
omh.handleTemplateBranchNode(fset, nodeWith.BranchNode)
|
||||||
|
|
||||||
case tmplParser.NodeCommand:
|
case tmplParser.NodeCommand:
|
||||||
nodeCommand := node.(*tmplParser.CommandNode)
|
nodeCommand := node.(*tmplParser.CommandNode)
|
||||||
|
|
||||||
handler.handleTemplateFileNodes(fset, nodeCommand.Args)
|
omh.handleTemplateFileNodes(fset, nodeCommand.Args)
|
||||||
|
|
||||||
if len(nodeCommand.Args) < 2 {
|
if len(nodeCommand.Args) != 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,66 +138,54 @@ func (handler Handler) handleTemplateNode(fset *token.FileSet, node tmplParser.N
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeIdent, ok := nodeChain.Node.(*tmplParser.IdentifierNode)
|
nodeString, ok := nodeCommand.Args[1].(*tmplParser.StringNode)
|
||||||
if !ok || nodeIdent.Ident != "ctx" || len(nodeChain.Field) != 2 || nodeChain.Field[0] != "Locale" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ltf, ok := handler.LocaleTrFunctions[nodeChain.Field[1]]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var gotUnexpectedInvoke *int
|
nodeIdent, ok := nodeChain.Node.(*tmplParser.IdentifierNode)
|
||||||
|
if !ok || nodeIdent.Ident != "ctx" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, argNum := range ltf {
|
if len(nodeChain.Field) != 2 || nodeChain.Field[0] != "Locale" || !isLocaleTrFunction(nodeChain.Field[1]) {
|
||||||
if len(nodeCommand.Args) >= int(argNum+2) {
|
return
|
||||||
nodeString, ok := nodeCommand.Args[int(argNum+1)].(*tmplParser.StringNode)
|
}
|
||||||
if ok {
|
|
||||||
// found interesting strings
|
// found interesting string
|
||||||
// the column numbers are a bit "off", but much better than nothing
|
// the column numbers are a bit "off", but much better than nothing
|
||||||
handler.OnMsgid(fset, token.Pos(nodeString.Pos), nodeString.Text)
|
omh(fset, token.Pos(nodeString.Pos), nodeString.Text)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
argc := len(nodeCommand.Args) - 1
|
|
||||||
gotUnexpectedInvoke = &argc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if gotUnexpectedInvoke != nil {
|
|
||||||
handler.OnUnexpectedInvoke(fset, token.Pos(nodeChain.Pos), nodeChain.Field[1], *gotUnexpectedInvoke)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler Handler) handleTemplatePipeNode(fset *token.FileSet, pipeNode *tmplParser.PipeNode) {
|
func (omh OnMsgidHandler) handleTemplatePipeNode(fset *token.FileSet, pipeNode *tmplParser.PipeNode) {
|
||||||
if pipeNode == nil {
|
if pipeNode == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we can't pass `pipeNode.Cmds` to handleTemplateFileNodes due to incompatible argument types
|
// NOTE: we can't pass `pipeNode.Cmds` to handleTemplateFileNodes due to incompatible argument types
|
||||||
for _, node := range pipeNode.Cmds {
|
for _, node := range pipeNode.Cmds {
|
||||||
handler.handleTemplateNode(fset, node)
|
omh.handleTemplateNode(fset, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler Handler) handleTemplateBranchNode(fset *token.FileSet, branchNode tmplParser.BranchNode) {
|
func (omh OnMsgidHandler) handleTemplateBranchNode(fset *token.FileSet, branchNode tmplParser.BranchNode) {
|
||||||
handler.handleTemplatePipeNode(fset, branchNode.Pipe)
|
omh.handleTemplatePipeNode(fset, branchNode.Pipe)
|
||||||
handler.handleTemplateFileNodes(fset, branchNode.List.Nodes)
|
omh.handleTemplateFileNodes(fset, branchNode.List.Nodes)
|
||||||
if branchNode.ElseList != nil {
|
if branchNode.ElseList != nil {
|
||||||
handler.handleTemplateFileNodes(fset, branchNode.ElseList.Nodes)
|
omh.handleTemplateFileNodes(fset, branchNode.ElseList.Nodes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler Handler) handleTemplateFileNodes(fset *token.FileSet, nodes []tmplParser.Node) {
|
func (omh OnMsgidHandler) handleTemplateFileNodes(fset *token.FileSet, nodes []tmplParser.Node) {
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
handler.handleTemplateNode(fset, node)
|
omh.handleTemplateNode(fset, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (handler Handler) HandleTemplateFile(fname string, src any) error {
|
func (omh OnMsgidHandler) HandleTemplateFile(fname string, src any) error {
|
||||||
var tmplContent []byte
|
var tmplContent []byte
|
||||||
switch src2 := src.(type) {
|
switch src2 := src.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
|
@ -264,7 +222,7 @@ func (handler Handler) HandleTemplateFile(fname string, src any) error {
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler.handleTemplateFileNodes(fset, tmplParsed.Root.Nodes)
|
omh.handleTemplateFileNodes(fset, tmplParsed.Tree.Root.Nodes)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +258,10 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
msgids := make(container.Set[string])
|
msgids := make(container.Set[string])
|
||||||
|
onMsgid := func(trKey, trValue string) error {
|
||||||
|
msgids[trKey] = struct{}{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
localeFile := filepath.Join(filepath.Join("options", "locale"), "locale_en-US.ini")
|
localeFile := filepath.Join(filepath.Join("options", "locale"), "locale_en-US.ini")
|
||||||
localeContent, err := os.ReadFile(localeFile)
|
localeContent, err := os.ReadFile(localeFile)
|
||||||
|
@ -308,10 +270,7 @@ func main() {
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = localeiter.IterateMessagesContent(localeContent, func(trKey, trValue string) error {
|
if err = locale.IterateMessagesContent(localeContent, onMsgid); err != nil {
|
||||||
msgids[trKey] = struct{}{}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error())
|
fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error())
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
@ -323,30 +282,19 @@ func main() {
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := localeiter.IterateMessagesNextContent(localeContent, func(trKey, pluralForm, trValue string) error {
|
if err := locale.IterateMessagesNextContent(localeContent, onMsgid); err != nil {
|
||||||
// ignore plural form
|
|
||||||
msgids[trKey] = struct{}{}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error())
|
fmt.Printf("%s:\tERROR: %s\n", localeFile, err.Error())
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
gotAnyMsgidError := false
|
gotAnyMsgidError := false
|
||||||
|
|
||||||
handler := Handler{
|
omh := OnMsgidHandler(func(fset *token.FileSet, pos token.Pos, msgid string) {
|
||||||
OnMsgid: func(fset *token.FileSet, pos token.Pos, msgid string) {
|
|
||||||
if !msgids.Contains(msgid) {
|
if !msgids.Contains(msgid) {
|
||||||
gotAnyMsgidError = true
|
gotAnyMsgidError = true
|
||||||
fmt.Printf("%s:\tmissing msgid: %s\n", fset.Position(pos).String(), msgid)
|
fmt.Printf("%s:\tmissing msgid: %s\n", fset.Position(pos).String(), msgid)
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
OnUnexpectedInvoke: func(fset *token.FileSet, pos token.Pos, funcname string, argc int) {
|
|
||||||
gotAnyMsgidError = true
|
|
||||||
fmt.Printf("%s:\tunexpected invocation of %s with %d arguments\n", fset.Position(pos).String(), funcname, argc)
|
|
||||||
},
|
|
||||||
LocaleTrFunctions: InitLocaleTrFunctions(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := filepath.WalkDir(".", func(fpath string, d fs.DirEntry, err error) error {
|
if err := filepath.WalkDir(".", func(fpath string, d fs.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -360,15 +308,15 @@ func main() {
|
||||||
if name == "docker" || name == ".git" || name == "node_modules" {
|
if name == "docker" || name == ".git" || name == "node_modules" {
|
||||||
return fs.SkipDir
|
return fs.SkipDir
|
||||||
}
|
}
|
||||||
} else if name == "bindata.go" || fpath == "modules/translation/i18n/i18n_test.go" {
|
} else if name == "bindata.go" {
|
||||||
// skip false positives
|
// skip false positives
|
||||||
} else if strings.HasSuffix(name, ".go") {
|
} else if strings.HasSuffix(name, ".go") {
|
||||||
onError(handler.HandleGoFile(fpath, nil))
|
onError(omh.HandleGoFile(fpath, nil))
|
||||||
} else if strings.HasSuffix(name, ".tmpl") {
|
} else if strings.HasSuffix(name, ".tmpl") {
|
||||||
if strings.HasPrefix(fpath, "tests") && strings.HasSuffix(name, ".ini.tmpl") {
|
if strings.HasPrefix(fpath, "tests") && strings.HasSuffix(name, ".ini.tmpl") {
|
||||||
// skip false positives
|
// skip false positives
|
||||||
} else {
|
} else {
|
||||||
onError(handler.HandleTemplateFile(fpath, nil))
|
onError(omh.HandleTemplateFile(fpath, nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -11,39 +11,33 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildHandler(ret *[]string) Handler {
|
|
||||||
return Handler{
|
|
||||||
OnMsgid: func(fset *token.FileSet, pos token.Pos, msgid string) {
|
|
||||||
*ret = append(*ret, msgid)
|
|
||||||
},
|
|
||||||
OnUnexpectedInvoke: func(fset *token.FileSet, pos token.Pos, funcname string, argc int) {},
|
|
||||||
LocaleTrFunctions: InitLocaleTrFunctions(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleGoFileWrapped(t *testing.T, fname, src string) []string {
|
func HandleGoFileWrapped(t *testing.T, fname, src string) []string {
|
||||||
var ret []string
|
var ret []string
|
||||||
handler := buildHandler(&ret)
|
omh := OnMsgidHandler(func(fset *token.FileSet, pos token.Pos, msgid string) {
|
||||||
require.NoError(t, handler.HandleGoFile(fname, src))
|
ret = append(ret, msgid)
|
||||||
|
})
|
||||||
|
require.NoError(t, omh.HandleGoFile(fname, src))
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleTemplateFileWrapped(t *testing.T, fname, src string) []string {
|
func HandleTemplateFileWrapped(t *testing.T, fname, src string) []string {
|
||||||
var ret []string
|
var ret []string
|
||||||
handler := buildHandler(&ret)
|
omh := OnMsgidHandler(func(fset *token.FileSet, pos token.Pos, msgid string) {
|
||||||
require.NoError(t, handler.HandleTemplateFile(fname, src))
|
ret = append(ret, msgid)
|
||||||
|
})
|
||||||
|
require.NoError(t, omh.HandleTemplateFile(fname, src))
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUsagesParser(t *testing.T) {
|
func TestUsagesParser(t *testing.T) {
|
||||||
t.Run("go, simple", func(t *testing.T) {
|
t.Run("go, simple", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.EqualValues(t,
|
||||||
[]string{"what.an.example"},
|
[]string{"what.an.example"},
|
||||||
HandleGoFileWrapped(t, "<g1>", "package main\nfunc Render(ctx *context.Context) string { return ctx.Tr(\"what.an.example\"); }\n"))
|
HandleGoFileWrapped(t, "<g1>", "package main\nfunc Render(ctx *context.Context) string { return ctx.Tr(\"what.an.example\"); }\n"))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("template, simple", func(t *testing.T) {
|
t.Run("template, simple", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.EqualValues(t,
|
||||||
[]string{"what.an.example"},
|
[]string{"what.an.example"},
|
||||||
HandleTemplateFileWrapped(t, "<t1>", "{{ ctx.Locale.Tr \"what.an.example\" }}\n"))
|
HandleTemplateFileWrapped(t, "<t1>", "{{ ctx.Locale.Tr \"what.an.example\" }}\n"))
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"forgejo.org/modules/translation/localeiter"
|
"forgejo.org/modules/locale"
|
||||||
|
|
||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
"github.com/sergi/go-diff/diffmatchpatch"
|
"github.com/sergi/go-diff/diffmatchpatch"
|
||||||
|
@ -52,7 +52,7 @@ func initBlueMondayPolicy() {
|
||||||
policy.AllowAttrs("id").Matching(positionalPlaceholderRe).OnElements("code")
|
policy.AllowAttrs("id").Matching(positionalPlaceholderRe).OnElements("code")
|
||||||
|
|
||||||
// Allowed elements with no attributes. Must be a recognized tagname.
|
// Allowed elements with no attributes. Must be a recognized tagname.
|
||||||
policy.AllowElements("strong", "br", "b", "strike", "code", "i", "kbd")
|
policy.AllowElements("strong", "br", "b", "strike", "code", "i")
|
||||||
|
|
||||||
// TODO: Remove <c> in `actions.workflow.dispatch.trigger_found`.
|
// TODO: Remove <c> in `actions.workflow.dispatch.trigger_found`.
|
||||||
policy.AllowNoAttrs().OnElements("c")
|
policy.AllowNoAttrs().OnElements("c")
|
||||||
|
@ -100,7 +100,7 @@ func checkValue(trKey, value string) []string {
|
||||||
func checkLocaleContent(localeContent []byte) []string {
|
func checkLocaleContent(localeContent []byte) []string {
|
||||||
errors := []string{}
|
errors := []string{}
|
||||||
|
|
||||||
if err := localeiter.IterateMessagesContent(localeContent, func(trKey, trValue string) error {
|
if err := locale.IterateMessagesContent(localeContent, func(trKey, trValue string) error {
|
||||||
errors = append(errors, checkValue(trKey, trValue)...)
|
errors = append(errors, checkValue(trKey, trValue)...)
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -113,12 +113,8 @@ func checkLocaleContent(localeContent []byte) []string {
|
||||||
func checkLocaleNextContent(localeContent []byte) []string {
|
func checkLocaleNextContent(localeContent []byte) []string {
|
||||||
errors := []string{}
|
errors := []string{}
|
||||||
|
|
||||||
if err := localeiter.IterateMessagesNextContent(localeContent, func(trKey, pluralForm, trValue string) error {
|
if err := locale.IterateMessagesNextContent(localeContent, func(trKey, trValue string) error {
|
||||||
fullKey := trKey
|
errors = append(errors, checkValue(trKey, trValue)...)
|
||||||
if pluralForm != "" {
|
|
||||||
fullKey = trKey + "." + pluralForm
|
|
||||||
}
|
|
||||||
errors = append(errors, checkValue(fullKey, trValue)...)
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -15,9 +15,9 @@ func TestLocalizationPolicy(t *testing.T) {
|
||||||
t.Run("Remove tags", func(t *testing.T) {
|
t.Run("Remove tags", func(t *testing.T) {
|
||||||
assert.Empty(t, checkLocaleContent([]byte(`hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "<user> added/removed <label>" comments.`)))
|
assert.Empty(t, checkLocaleContent([]byte(`hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "<user> added/removed <label>" comments.`)))
|
||||||
|
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<not-an-allowed-key> <label>"`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<not-an-allowed-key> <label>"`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<user@example.com>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<user@example.com> <email@example.com>"`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<user@example.com>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<user@example.com> <email@example.com>"`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<tag>\x1b[0m REPLACED-TAG \x1b[31m</tag>\x1b[0m"}, checkLocaleContent([]byte(`key = "<tag> <email@example.com> </tag>"`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<tag>\x1b[0m REPLACED-TAG \x1b[31m</tag>\x1b[0m"}, checkLocaleContent([]byte(`key = "<tag> <email@example.com> </tag>"`)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Specific exception", func(t *testing.T) {
|
t.Run("Specific exception", func(t *testing.T) {
|
||||||
|
@ -25,11 +25,11 @@ func TestLocalizationPolicy(t *testing.T) {
|
||||||
assert.Empty(t, checkLocaleContent([]byte(`pulls.title_desc_one = wants to merge %[1]d commit from <code>%[2]s</code> into <code id="%[4]s">%[3]s</code>`)))
|
assert.Empty(t, checkLocaleContent([]byte(`pulls.title_desc_one = wants to merge %[1]d commit from <code>%[2]s</code> into <code id="%[4]s">%[3]s</code>`)))
|
||||||
assert.Empty(t, checkLocaleContent([]byte(`editor.commit_directly_to_this_branch = Commit directly to the <strong class="%[2]s">%[1]s</strong> branch.`)))
|
assert.Empty(t, checkLocaleContent([]byte(`editor.commit_directly_to_this_branch = Commit directly to the <strong class="%[2]s">%[1]s</strong> branch.`)))
|
||||||
|
|
||||||
assert.Equal(t, []string{"workflow.dispatch.trigger_found: This workflow has a \x1b[31m<d>\x1b[0mworkflow_dispatch\x1b[31m</d>\x1b[0m event trigger."}, checkLocaleContent([]byte(`workflow.dispatch.trigger_found = This workflow has a <d>workflow_dispatch</d> event trigger.`)))
|
assert.EqualValues(t, []string{"workflow.dispatch.trigger_found: This workflow has a \x1b[31m<d>\x1b[0mworkflow_dispatch\x1b[31m</d>\x1b[0m event trigger."}, checkLocaleContent([]byte(`workflow.dispatch.trigger_found = This workflow has a <d>workflow_dispatch</d> event trigger.`)))
|
||||||
assert.Equal(t, []string{"key: <code\x1b[31m id=\"branch_targe\"\x1b[0m>%[3]s</code>"}, checkLocaleContent([]byte(`key = <code id="branch_targe">%[3]s</code>`)))
|
assert.EqualValues(t, []string{"key: <code\x1b[31m id=\"branch_targe\"\x1b[0m>%[3]s</code>"}, checkLocaleContent([]byte(`key = <code id="branch_targe">%[3]s</code>`)))
|
||||||
assert.Equal(t, []string{"key: <a\x1b[31m class=\"ui sh\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="ui sh" href="%[3]s">`)))
|
assert.EqualValues(t, []string{"key: <a\x1b[31m class=\"ui sh\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="ui sh" href="%[3]s">`)))
|
||||||
assert.Equal(t, []string{"key: <a\x1b[31m class=\"js-click-me\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="js-click-me" href="%[3]s">`)))
|
assert.EqualValues(t, []string{"key: <a\x1b[31m class=\"js-click-me\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="js-click-me" href="%[3]s">`)))
|
||||||
assert.Equal(t, []string{"key: <strong\x1b[31m class=\"branch-target\"\x1b[0m>%[1]s</strong>"}, checkLocaleContent([]byte(`key = <strong class="branch-target">%[1]s</strong>`)))
|
assert.EqualValues(t, []string{"key: <strong\x1b[31m class=\"branch-target\"\x1b[0m>%[1]s</strong>"}, checkLocaleContent([]byte(`key = <strong class="branch-target">%[1]s</strong>`)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("General safe tags", func(t *testing.T) {
|
t.Run("General safe tags", func(t *testing.T) {
|
||||||
|
@ -37,9 +37,8 @@ func TestLocalizationPolicy(t *testing.T) {
|
||||||
assert.Empty(t, checkLocaleContent([]byte("teams.specific_repositories_helper = Members will only have access to repositories explicitly added to the team. Selecting this <strong>will not</strong> automatically remove repositories already added with <i>All repositories</i>.")))
|
assert.Empty(t, checkLocaleContent([]byte("teams.specific_repositories_helper = Members will only have access to repositories explicitly added to the team. Selecting this <strong>will not</strong> automatically remove repositories already added with <i>All repositories</i>.")))
|
||||||
assert.Empty(t, checkLocaleContent([]byte("sqlite_helper = File path for the SQLite3 database.<br>Enter an absolute path if you run Forgejo as a service.")))
|
assert.Empty(t, checkLocaleContent([]byte("sqlite_helper = File path for the SQLite3 database.<br>Enter an absolute path if you run Forgejo as a service.")))
|
||||||
assert.Empty(t, checkLocaleContent([]byte("hi_user_x = Hi <b>%s</b>,")))
|
assert.Empty(t, checkLocaleContent([]byte("hi_user_x = Hi <b>%s</b>,")))
|
||||||
assert.Empty(t, checkLocaleContent([]byte("key = Press <kbd>Shift</kbd>")))
|
|
||||||
|
|
||||||
assert.Equal(t, []string{"error404: The page you are trying to reach either <strong\x1b[31m title='aaa'\x1b[0m>does not exist</strong> or <strong>you are not authorized</strong> to view it."}, checkLocaleContent([]byte("error404 = The page you are trying to reach either <strong title='aaa'>does not exist</strong> or <strong>you are not authorized</strong> to view it.")))
|
assert.EqualValues(t, []string{"error404: The page you are trying to reach either <strong\x1b[31m title='aaa'\x1b[0m>does not exist</strong> or <strong>you are not authorized</strong> to view it."}, checkLocaleContent([]byte("error404 = The page you are trying to reach either <strong title='aaa'>does not exist</strong> or <strong>you are not authorized</strong> to view it.")))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("<a>", func(t *testing.T) {
|
t.Run("<a>", func(t *testing.T) {
|
||||||
|
@ -48,20 +47,20 @@ func TestLocalizationPolicy(t *testing.T) {
|
||||||
assert.Empty(t, checkLocaleContent([]byte(`webauthn_desc = Security keys are hardware devices containing cryptographic keys. They can be used for two-factor authentication. Security keys must support the <a rel="noreferrer" target="_blank" href="%s">WebAuthn Authenticator</a> standard.`)))
|
assert.Empty(t, checkLocaleContent([]byte(`webauthn_desc = Security keys are hardware devices containing cryptographic keys. They can be used for two-factor authentication. Security keys must support the <a rel="noreferrer" target="_blank" href="%s">WebAuthn Authenticator</a> standard.`)))
|
||||||
assert.Empty(t, checkLocaleContent([]byte("issues.closed_at = `closed this issue <a id=\"%[1]s\" href=\"#%[1]s\">%[2]s</a>`")))
|
assert.Empty(t, checkLocaleContent([]byte("issues.closed_at = `closed this issue <a id=\"%[1]s\" href=\"#%[1]s\">%[2]s</a>`")))
|
||||||
|
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"https://example.com\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com">`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"javascript:alert('1')\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="javascript:alert('1')">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"javascript:alert('1')\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="javascript:alert('1')">`)))
|
||||||
assert.Equal(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m download\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" download>`)))
|
assert.EqualValues(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m download\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" download>`)))
|
||||||
assert.Equal(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m target=\"_self\"\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" target="_self">`)))
|
assert.EqualValues(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m target=\"_self\"\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" target="_self">`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"https://example.com/%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/%s">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com/%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/%s">`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"https://example.com/?q=%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/?q=%s">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com/?q=%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/?q=%s">`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"%s/open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s/open-redirect">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"%s/open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s/open-redirect">`)))
|
||||||
assert.Equal(t, []string{"key: \x1b[31m<a href=\"%s?q=open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s?q=open-redirect">`)))
|
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"%s?q=open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s?q=open-redirect">`)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Escaped HTML characters", func(t *testing.T) {
|
t.Run("Escaped HTML characters", func(t *testing.T) {
|
||||||
assert.Empty(t, checkLocaleContent([]byte("activity.git_stats_push_to_branch = `إلى %s و\"`")))
|
assert.Empty(t, checkLocaleContent([]byte("activity.git_stats_push_to_branch = `إلى %s و\"`")))
|
||||||
|
|
||||||
assert.Equal(t, []string{"key: و\x1b[31m \x1b[0m\x1b[32m\u00a0\x1b[0m"}, checkLocaleContent([]byte(`key = و `)))
|
assert.EqualValues(t, []string{"key: و\x1b[31m \x1b[0m\x1b[32m\u00a0\x1b[0m"}, checkLocaleContent([]byte(`key = و `)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +75,7 @@ func TestNextLocalizationPolicy(t *testing.T) {
|
||||||
}
|
}
|
||||||
}`)))
|
}`)))
|
||||||
|
|
||||||
assert.Equal(t, []string{"settings.hidden_comment_types_description: \"\x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG\""}, checkLocaleNextContent([]byte(`{
|
assert.EqualValues(t, []string{"settings.hidden_comment_types_description: \"\x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG\""}, checkLocaleNextContent([]byte(`{
|
||||||
"settings": {
|
"settings": {
|
||||||
"hidden_comment_types_description": "\"<not-an-allowed-key> <label>\""
|
"hidden_comment_types_description": "\"<not-an-allowed-key> <label>\""
|
||||||
}
|
}
|
||||||
|
@ -88,20 +87,8 @@ func TestNextLocalizationPolicy(t *testing.T) {
|
||||||
"settings.hidden_comment_types_description": "Comment types checked here will not be shown inside issue pages. Checking \"Label\" for example removes all \"<user> added/removed <label>\" comments."
|
"settings.hidden_comment_types_description": "Comment types checked here will not be shown inside issue pages. Checking \"Label\" for example removes all \"<user> added/removed <label>\" comments."
|
||||||
}`)))
|
}`)))
|
||||||
|
|
||||||
assert.Equal(t, []string{"settings.hidden_comment_types_description: \"\x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG\""}, checkLocaleNextContent([]byte(`{
|
assert.EqualValues(t, []string{"settings.hidden_comment_types_description: \"\x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG\""}, checkLocaleNextContent([]byte(`{
|
||||||
"settings.hidden_comment_types_description": "\"<not-an-allowed-key> <label>\""
|
"settings.hidden_comment_types_description": "\"<not-an-allowed-key> <label>\""
|
||||||
}`)))
|
}`)))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Plural form", func(t *testing.T) {
|
|
||||||
assert.Equal(t, []string{"repo.pulls.title_desc: key = \x1b[31m<a href=\"https://example.com\">\x1b[0m"}, checkLocaleNextContent([]byte(`{"repo.pulls.title_desc": {
|
|
||||||
"few": "key = <a href=\"%s\">",
|
|
||||||
"other": "key = <a href=\"https://example.com\">"
|
|
||||||
}}`)))
|
|
||||||
|
|
||||||
assert.Equal(t, []string{"repo.pulls.title_desc.few: key = \x1b[31m<a href=\"https://example.com\">\x1b[0m"}, checkLocaleNextContent([]byte(`{"repo.pulls.title_desc": {
|
|
||||||
"few": "key = <a href=\"https://example.com\">",
|
|
||||||
"other": "key = <a href=\"%s\">"
|
|
||||||
}}`)))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
52
build/update-locales.sh
Executable file
52
build/update-locales.sh
Executable file
|
@ -0,0 +1,52 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# this script runs in alpine image which only has `sh` shell
|
||||||
|
|
||||||
|
set +e
|
||||||
|
if sed --version 2>/dev/null | grep -q GNU; then
|
||||||
|
SED_INPLACE="sed -i"
|
||||||
|
else
|
||||||
|
SED_INPLACE="sed -i ''"
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -f ./options/locale/locale_en-US.ini ]; then
|
||||||
|
echo "please run this script in the root directory of the project"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv ./options/locale/locale_en-US.ini ./options/
|
||||||
|
|
||||||
|
# the "ini" library for locale has many quirks, its behavior is different from Crowdin.
|
||||||
|
# see i18n_test.go for more details
|
||||||
|
|
||||||
|
# this script helps to unquote the Crowdin outputs for the quirky ini library
|
||||||
|
# * find all `key="...\"..."` lines
|
||||||
|
# * remove the leading quote
|
||||||
|
# * remove the trailing quote
|
||||||
|
# * unescape the quotes
|
||||||
|
# * eg: key="...\"..." => key=..."...
|
||||||
|
$SED_INPLACE -r -e '/^[-.A-Za-z0-9_]+[ ]*=[ ]*".*"$/ {
|
||||||
|
s/^([-.A-Za-z0-9_]+)[ ]*=[ ]*"/\1=/
|
||||||
|
s/"$//
|
||||||
|
s/\\"/"/g
|
||||||
|
}' ./options/locale/*.ini
|
||||||
|
|
||||||
|
# * if the escaped line is incomplete like `key="...` or `key=..."`, quote it with backticks
|
||||||
|
# * eg: key="... => key=`"...`
|
||||||
|
# * eg: key=..." => key=`..."`
|
||||||
|
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*(".*[^"])$/\1=`\2`/' ./options/locale/*.ini
|
||||||
|
$SED_INPLACE -r -e 's/^([-.A-Za-z0-9_]+)[ ]*=[ ]*([^"].*")$/\1=`\2`/' ./options/locale/*.ini
|
||||||
|
|
||||||
|
# Remove translation under 25% of en_us
|
||||||
|
baselines=$(wc -l "./options/locale_en-US.ini" | cut -d" " -f1)
|
||||||
|
baselines=$((baselines / 4))
|
||||||
|
for filename in ./options/locale/*.ini; do
|
||||||
|
lines=$(wc -l "$filename" | cut -d" " -f1)
|
||||||
|
if [ $lines -lt $baselines ]; then
|
||||||
|
echo "Removing $filename: $lines/$baselines"
|
||||||
|
rm "$filename"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
mv ./options/locale_en-US.ini ./options/locale/
|
|
@ -4,28 +4,25 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// CmdActions represents the available actions sub-commands.
|
// CmdActions represents the available actions sub-commands.
|
||||||
func cmdActions() *cli.Command {
|
CmdActions = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "Manage Forgejo Actions",
|
Usage: "Manage Forgejo Actions",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdActionsGenRunnerToken(),
|
subcmdActionsGenRunnerToken,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdActionsGenRunnerToken() *cli.Command {
|
subcmdActionsGenRunnerToken = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "generate-runner-token",
|
Name: "generate-runner-token",
|
||||||
Usage: "Generate a new token for a runner to use to register with the server",
|
Usage: "Generate a new token for a runner to use to register with the server",
|
||||||
Action: runGenerateActionsRunnerToken,
|
Action: runGenerateActionsRunnerToken,
|
||||||
|
@ -39,10 +36,10 @@ func subcmdActionsGenRunnerToken() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
|
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
68
cmd/admin.go
68
cmd/admin.go
|
@ -15,64 +15,56 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
repo_module "forgejo.org/modules/repository"
|
repo_module "forgejo.org/modules/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// CmdAdmin represents the available admin sub-command.
|
// CmdAdmin represents the available admin sub-command.
|
||||||
func cmdAdmin() *cli.Command {
|
CmdAdmin = &cli.Command{
|
||||||
return &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,
|
||||||
subcmdAuth(),
|
subcmdAuth,
|
||||||
subcmdSendMail(),
|
subcmdSendMail,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdRepoSyncReleases() *cli.Command {
|
subcmdRepoSyncReleases = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "repo-sync-releases",
|
Name: "repo-sync-releases",
|
||||||
Usage: "Synchronize repository releases with tags",
|
Usage: "Synchronize repository releases with tags",
|
||||||
Action: runRepoSyncReleases,
|
Action: runRepoSyncReleases,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdRegenerate() *cli.Command {
|
subcmdRegenerate = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "regenerate",
|
Name: "regenerate",
|
||||||
Usage: "Regenerate specific files",
|
Usage: "Regenerate specific files",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
microcmdRegenHooks,
|
microcmdRegenHooks,
|
||||||
microcmdRegenKeys,
|
microcmdRegenKeys,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdAuth() *cli.Command {
|
subcmdAuth = &cli.Command{
|
||||||
return &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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdSendMail() *cli.Command {
|
subcmdSendMail = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "sendmail",
|
Name: "sendmail",
|
||||||
Usage: "Send a message to all users",
|
Usage: "Send a message to all users",
|
||||||
Action: runSendMail,
|
Action: runSendMail,
|
||||||
|
@ -94,17 +86,15 @@ func subcmdSendMail() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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(ctx context.Context, _ *cli.Command) error {
|
func runRepoSyncReleases(_ *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -14,20 +13,17 @@ import (
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
auth_service "forgejo.org/services/auth"
|
auth_service "forgejo.org/services/auth"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdAuthDelete() *cli.Command {
|
var (
|
||||||
return &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{
|
||||||
|
|
||||||
func microcmdAuthList() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List auth sources",
|
Usage: "List auth sources",
|
||||||
Action: runListAuth,
|
Action: runListAuth,
|
||||||
|
@ -58,10 +54,10 @@ func microcmdAuthList() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func runListAuth(ctx context.Context, c *cli.Command) error {
|
func runListAuth(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -85,7 +81,7 @@ func runListAuth(ctx context.Context, c *cli.Command) error {
|
||||||
|
|
||||||
// loop through each source and print
|
// loop through each source and print
|
||||||
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
|
w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags)
|
||||||
fmt.Fprint(w, "ID\tName\tType\tEnabled\n")
|
fmt.Fprintf(w, "ID\tName\tType\tEnabled\n")
|
||||||
for _, source := range authSources {
|
for _, source := range authSources {
|
||||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
|
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive)
|
||||||
}
|
}
|
||||||
|
@ -94,12 +90,12 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"forgejo.org/models/auth"
|
"forgejo.org/models/auth"
|
||||||
"forgejo.org/services/auth/source/ldap"
|
"forgejo.org/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -23,8 +23,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.",
|
||||||
|
@ -102,10 +102,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.",
|
||||||
|
@ -130,59 +128,49 @@ func ldapBindDnCLIFlags() []cli.Flag {
|
||||||
Name: "page-size",
|
Name: "page-size",
|
||||||
Usage: "Search page size.",
|
Usage: "Search page size.",
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
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, cli *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().addLdapBindDn(ctx, cli)
|
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, cli *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().updateLdapBindDn(ctx, cli)
|
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, cli *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().addLdapSimpleAuth(ctx, cli)
|
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, cli *cli.Command) error {
|
Action: func(c *cli.Context) error {
|
||||||
return newAuthService().updateLdapSimpleAuth(ctx, cli)
|
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 {
|
||||||
|
@ -195,7 +183,7 @@ func newAuthService() *authService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAuthSource assigns values on authSource according to command line flags.
|
// parseAuthSource assigns values on authSource according to command line flags.
|
||||||
func parseAuthSource(c *cli.Command, authSource *auth.Source) {
|
func parseAuthSource(c *cli.Context, authSource *auth.Source) {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
authSource.Name = c.String("name")
|
authSource.Name = c.String("name")
|
||||||
}
|
}
|
||||||
|
@ -214,7 +202,7 @@ func parseAuthSource(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")
|
||||||
}
|
}
|
||||||
|
@ -301,7 +289,7 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -319,12 +307,12 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, authTyp
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -348,8 +336,8 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -370,12 +358,12 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -399,8 +387,8 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
|
|
@ -8,17 +8,18 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"forgejo.org/models/auth"
|
"forgejo.org/models/auth"
|
||||||
"forgejo.org/modules/test"
|
|
||||||
"forgejo.org/services/auth/source/ldap"
|
"forgejo.org/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"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 {
|
||||||
|
@ -215,22 +216,22 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
assert.FailNow(t, "should not call updateAuthSource", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call updateAuthSource", n)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
||||||
assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Flags = microcmdAuthAddLdapBindDn().Flags
|
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
||||||
app.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 {
|
||||||
|
@ -242,7 +243,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 {
|
||||||
|
@ -444,22 +447,22 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
assert.FailNow(t, "should not call updateAuthSource", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call updateAuthSource", n)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
getAuthSourceByID: func(ctx context.Context, id int64) (*auth.Source, error) {
|
||||||
assert.FailNow(t, "should not call getAuthSourceByID", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call getAuthSourceByID", n)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Flags = microcmdAuthAddLdapSimpleAuth().Flags
|
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
||||||
app.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 {
|
||||||
|
@ -471,7 +474,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 {
|
||||||
|
@ -893,7 +898,7 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
assert.FailNow(t, "should not call createAuthSource", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call createAuthSource", n)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
|
@ -915,12 +920,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()
|
||||||
app.Flags = microcmdAuthUpdateLdapBindDn().Flags
|
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
||||||
app.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 {
|
||||||
|
@ -932,7 +937,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 {
|
||||||
|
@ -1281,7 +1288,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
createAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
assert.FailNow(t, "should not call createAuthSource", "case: %d", n)
|
assert.FailNow(t, "case %d: should not call createAuthSource", n)
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
updateAuthSource: func(ctx context.Context, authSource *auth.Source) error {
|
||||||
|
@ -1303,12 +1310,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()
|
||||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth().Flags
|
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
||||||
app.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"
|
||||||
|
@ -12,11 +11,11 @@ import (
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
"forgejo.org/services/auth/source/oauth2"
|
"forgejo.org/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: "",
|
||||||
|
@ -121,27 +120,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: runAddOauth,
|
||||||
Flags: oauthCLIFlags(),
|
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: runUpdateOauth,
|
||||||
Flags: append(oauthCLIFlags()[:1], append([]cli.Flag{idFlag()}, oauthCLIFlags()[1:]...)...),
|
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func parseOAuth2Config(_ context.Context, 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{
|
||||||
|
@ -173,15 +168,15 @@ func parseOAuth2Config(_ context.Context, c *cli.Command) *oauth2.Source {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddOauth(ctx context.Context, c *cli.Command) error {
|
func runAddOauth(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := parseOAuth2Config(ctx, c)
|
config := parseOAuth2Config(c)
|
||||||
if config.Provider == "openidConnect" {
|
if config.Provider == "openidConnect" {
|
||||||
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
|
||||||
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
|
||||||
|
@ -197,12 +192,12 @@ func runAddOauth(ctx context.Context, c *cli.Command) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -12,11 +11,11 @@ import (
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
"forgejo.org/services/auth/source/smtp"
|
"forgejo.org/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: "",
|
||||||
|
@ -72,27 +71,23 @@ func smtpCLIFlags() []cli.Flag {
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdAuthAddSMTP() *cli.Command {
|
microcmdAuthAddSMTP = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "add-smtp",
|
Name: "add-smtp",
|
||||||
Usage: "Add new SMTP authentication source",
|
Usage: "Add new SMTP authentication source",
|
||||||
Action: runAddSMTP,
|
Action: runAddSMTP,
|
||||||
Flags: smtpCLIFlags(),
|
Flags: smtpCLIFlags,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func microcmdAuthUpdateSMTP() *cli.Command {
|
microcmdAuthUpdateSMTP = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "update-smtp",
|
Name: "update-smtp",
|
||||||
Usage: "Update existing SMTP authentication source",
|
Usage: "Update existing SMTP authentication source",
|
||||||
Action: runUpdateSMTP,
|
Action: runUpdateSMTP,
|
||||||
Flags: append(smtpCLIFlags()[:1], append([]cli.Flag{idFlag()}, smtpCLIFlags()[1:]...)...),
|
Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
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 +123,8 @@ func parseSMTPConfig(c *cli.Command, conf *smtp.Source) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddSMTP(ctx context.Context, c *cli.Command) error {
|
func runAddSMTP(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -168,12 +163,12 @@ func runAddSMTP(ctx context.Context, c *cli.Command) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,13 +4,11 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
asymkey_model "forgejo.org/models/asymkey"
|
asymkey_model "forgejo.org/models/asymkey"
|
||||||
"forgejo.org/modules/graceful"
|
"forgejo.org/modules/graceful"
|
||||||
repo_service "forgejo.org/services/repository"
|
repo_service "forgejo.org/services/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -27,8 +25,8 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
func runRegenerateHooks(_ *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -37,8 +35,8 @@ func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
||||||
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,21 +4,18 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func subcmdUser() *cli.Command {
|
var subcmdUser = &cli.Command{
|
||||||
return &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,
|
||||||
microcmdUserResetMFA(),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -14,11 +13,10 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
user_service "forgejo.org/services/user"
|
user_service "forgejo.org/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,
|
||||||
|
@ -42,14 +40,13 @@ func microcmdUserChangePassword() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runChangePassword(ctx context.Context, c *cli.Command) error {
|
func runChangePassword(c *cli.Context) error {
|
||||||
if err := argsSet(c, "username", "password"); err != nil {
|
if err := argsSet(c, "username", "password"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
|
@ -16,11 +14,10 @@ import (
|
||||||
"forgejo.org/modules/optional"
|
"forgejo.org/modules/optional"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/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,
|
||||||
|
@ -53,6 +50,7 @@ func microcmdUserCreate() *cli.Command {
|
||||||
Name: "must-change-password",
|
Name: "must-change-password",
|
||||||
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
||||||
Value: true,
|
Value: true,
|
||||||
|
DisableDefaultText: true,
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "random-password-length",
|
Name: "random-password-length",
|
||||||
|
@ -63,29 +61,14 @@ func microcmdUserCreate() *cli.Command {
|
||||||
Name: "access-token",
|
Name: "access-token",
|
||||||
Usage: "Generate access token for the user",
|
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{
|
&cli.BoolFlag{
|
||||||
Name: "restricted",
|
Name: "restricted",
|
||||||
Usage: "Make a restricted user account",
|
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()
|
||||||
|
@ -110,10 +93,10 @@ 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.Fprint(c.Root().ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -167,7 +150,6 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
|
||||||
IsAdmin: isAdmin,
|
IsAdmin: isAdmin,
|
||||||
MustChangePassword: mustChangePassword,
|
MustChangePassword: mustChangePassword,
|
||||||
Visibility: visibility,
|
Visibility: visibility,
|
||||||
FullName: c.String("fullname"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||||
|
@ -175,40 +157,23 @@ func runCreateUser(ctx context.Context, c *cli.Command) error {
|
||||||
IsRestricted: restricted,
|
IsRestricted: restricted,
|
||||||
}
|
}
|
||||||
|
|
||||||
var accessTokenName string
|
|
||||||
var accessTokenScope auth_model.AccessTokenScope
|
|
||||||
if c.IsSet("access-token") {
|
|
||||||
accessTokenName = strings.TrimSpace(c.String("access-token-name"))
|
|
||||||
if accessTokenName == "" {
|
|
||||||
return errors.New("access-token-name cannot be empty")
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
accessTokenScope, err = auth_model.AccessTokenScope(c.String("access-token-scopes")).Normalize()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid access token scope provided: %w", err)
|
|
||||||
}
|
|
||||||
if !accessTokenScope.HasPermissionScope() {
|
|
||||||
return errors.New("access token does not have any permission")
|
|
||||||
}
|
|
||||||
} else if c.IsSet("access-token-name") || c.IsSet("access-token-scopes") {
|
|
||||||
return errors.New("access-token-name and access-token-scopes flags are only valid when access-token flag is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
// arguments should be prepared before creating the user & access token, in case there is anything wrong
|
|
||||||
|
|
||||||
// create the user
|
|
||||||
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
|
if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil {
|
||||||
return fmt.Errorf("CreateUser: %w", err)
|
return fmt.Errorf("CreateUser: %w", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("New user '%s' has been successfully created!\n", username)
|
|
||||||
|
|
||||||
// create the access token
|
if c.Bool("access-token") {
|
||||||
if accessTokenScope != "" {
|
t := &auth_model.AccessToken{
|
||||||
t := &auth_model.AccessToken{Name: accessTokenName, UID: u.ID, Scope: accessTokenScope}
|
Name: "gitea-admin",
|
||||||
|
UID: u.ID,
|
||||||
|
}
|
||||||
|
|
||||||
if err := auth_model.NewAccessToken(ctx, t); err != nil {
|
if err := auth_model.NewAccessToken(ctx, t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Access token was successfully created... %s\n", t.Token)
|
fmt.Printf("Access token was successfully created... %s\n", t.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("New user '%s' has been successfully created!\n", username)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -13,11 +12,10 @@ import (
|
||||||
"forgejo.org/modules/storage"
|
"forgejo.org/modules/storage"
|
||||||
user_service "forgejo.org/services/user"
|
user_service "forgejo.org/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{
|
||||||
|
@ -42,14 +40,13 @@ func microcmdUserDelete() *cli.Command {
|
||||||
},
|
},
|
||||||
Action: runDeleteUser,
|
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,18 +4,16 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserGenerateAccessToken() *cli.Command {
|
var microcmdUserGenerateAccessToken = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "generate-access-token",
|
Name: "generate-access-token",
|
||||||
Usage: "Generate an access token for a specific user",
|
Usage: "Generate an access token for a specific user",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -36,20 +34,19 @@ func microcmdUserGenerateAccessToken() *cli.Command {
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "scopes",
|
Name: "scopes",
|
||||||
Value: "all",
|
Value: "",
|
||||||
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
Usage: "Comma separated list of scopes to apply to access token",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -80,9 +77,6 @@ func runGenerateAccessToken(ctx context.Context, c *cli.Command) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid access token scope provided: %w", err)
|
return fmt.Errorf("invalid access token scope provided: %w", err)
|
||||||
}
|
}
|
||||||
if !accessTokenScope.HasPermissionScope() {
|
|
||||||
return errors.New("access token does not have any permission")
|
|
||||||
}
|
|
||||||
t.Scope = accessTokenScope
|
t.Scope = accessTokenScope
|
||||||
|
|
||||||
// create the token
|
// create the token
|
||||||
|
|
|
@ -4,18 +4,16 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func microcmdUserList() *cli.Command {
|
var microcmdUserList = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List users",
|
Usage: "List users",
|
||||||
Action: runListUsers,
|
Action: runListUsers,
|
||||||
|
@ -26,10 +24,9 @@ func microcmdUserList() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runListUsers(ctx context.Context, c *cli.Command) error {
|
func runListUsers(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -44,7 +41,7 @@ func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0)
|
||||||
|
|
||||||
if c.IsSet("admin") {
|
if c.IsSet("admin") {
|
||||||
fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\n")
|
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n")
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
if u.IsAdmin {
|
if u.IsAdmin {
|
||||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive)
|
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive)
|
||||||
|
@ -52,7 +49,7 @@ func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
||||||
fmt.Fprint(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
|
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,15 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
|
||||||
"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,
|
||||||
|
@ -35,10 +33,9 @@ func microcmdUserMustChangePassword() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
func runMustChangePassword(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() == 0 && !c.IsSet("all") {
|
if c.NArg() == 0 && !c.IsSet("all") {
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
|
||||||
user_model "forgejo.org/models/user"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func microcmdUserResetMFA() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "reset-mfa",
|
|
||||||
Usage: "Remove all two-factor authentication configurations for a user",
|
|
||||||
Action: runResetMFA,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "username",
|
|
||||||
Aliases: []string{"u"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "The user to update",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runResetMFA(ctx context.Context, c *cli.Command) error {
|
|
||||||
if err := argsSet(c, "username"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := installSignals(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := user_model.GetUserByName(ctx, c.String("username"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
webAuthnList, err := auth_model.GetWebAuthnCredentialsByUID(ctx, user.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, credential := range webAuthnList {
|
|
||||||
if _, err := auth_model.DeleteCredential(ctx, credential.ID, user.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tfaModes, err := auth_model.GetTwoFactorByUID(ctx, user.ID)
|
|
||||||
if err == nil && tfaModes != nil {
|
|
||||||
if err := auth_model.DeleteTwoFactorByID(ctx, tfaModes.ID, user.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, is := err.(auth_model.ErrTwoFactorNotEnrolled); !is {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("%s's two-factor authentication settings have been removed!\n", user.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -21,12 +20,11 @@ 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.
|
||||||
|
@ -64,7 +62,6 @@ Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func publicKey(priv any) any {
|
func publicKey(priv any) any {
|
||||||
switch k := priv.(type) {
|
switch k := priv.(type) {
|
||||||
|
@ -92,7 +89,7 @@ func pemBlockForKey(priv any) *pem.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCert(ctx context.Context, c *cli.Command) error {
|
func runCert(c *cli.Context) error {
|
||||||
if err := argsSet(c, "host"); err != nil {
|
if err := argsSet(c, "host"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
24
cmd/cmd.go
24
cmd/cmd.go
|
@ -20,23 +20,21 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/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 s, ok := c.Value(a).(string); ok {
|
if util.IsEmptyString(c.String(a)) {
|
||||||
if util.IsEmptyString(s) {
|
|
||||||
return errors.New(a + " is required")
|
return errors.New(a + " is required")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,8 +73,8 @@ If this is the intended configuration file complete the [database] section.`, se
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func installSignals(ctx context.Context) (context.Context, context.CancelFunc) {
|
func installSignals() (context.Context, context.CancelFunc) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
go func() {
|
go func() {
|
||||||
// install notify
|
// install notify
|
||||||
signalChannel := make(chan os.Signal, 1)
|
signalChannel := make(chan os.Signal, 1)
|
||||||
|
@ -111,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
|
||||||
|
@ -122,16 +120,16 @@ 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(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(*cli.Context) error {
|
||||||
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
return func(c *cli.Context) error {
|
||||||
level := defaultLevel
|
level := defaultLevel
|
||||||
if globalBool(cli, "quiet") {
|
if globalBool(c, "quiet") {
|
||||||
level = log.FATAL
|
level = log.FATAL
|
||||||
}
|
}
|
||||||
if globalBool(cli, "debug") || globalBool(cli, "verbose") {
|
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
cmd/docs.go
Normal file
65
cmd/docs.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CmdDocs represents the available docs sub-command.
|
||||||
|
var CmdDocs = &cli.Command{
|
||||||
|
Name: "docs",
|
||||||
|
Usage: "Output CLI documentation",
|
||||||
|
Description: "A command to output Forgejo's CLI documentation, optionally to a file.",
|
||||||
|
Action: runDocs,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "man",
|
||||||
|
Usage: "Output man pages instead",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "output",
|
||||||
|
Aliases: []string{"o"},
|
||||||
|
Usage: "Path to output to instead of stdout (will overwrite if exists)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func runDocs(ctx *cli.Context) error {
|
||||||
|
docs, err := ctx.App.ToMarkdown()
|
||||||
|
if ctx.Bool("man") {
|
||||||
|
docs, err = ctx.App.ToMan()
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.Bool("man") {
|
||||||
|
// 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)
|
||||||
|
// https://github.com/urfave/cli/issues/1040
|
||||||
|
firstHashtagIndex := strings.Index(docs, "#")
|
||||||
|
|
||||||
|
if firstHashtagIndex > 0 {
|
||||||
|
docs = docs[firstHashtagIndex:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out := os.Stdout
|
||||||
|
if ctx.String("output") != "" {
|
||||||
|
fi, err := os.Create(ctx.String("output"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fi.Close()
|
||||||
|
out = fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = fmt.Fprintln(out, docs)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
golog "log"
|
golog "log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -20,26 +19,24 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/services/doctor"
|
"forgejo.org/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDoctor represents the available doctor sub-command.
|
// CmdDoctor represents the available doctor sub-command.
|
||||||
func cmdDoctor() *cli.Command {
|
var CmdDoctor = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "doctor",
|
Name: "doctor",
|
||||||
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 Forgejo 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 Forgejo 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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func cmdDoctorCheck() *cli.Command {
|
var cmdDoctorCheck = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "check",
|
Name: "check",
|
||||||
Usage: "Diagnose and optionally fix problems",
|
Usage: "Diagnose and optionally fix problems",
|
||||||
Description: "A command to diagnose problems with the current Forgejo 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 Forgejo instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
||||||
|
@ -76,10 +73,8 @@ func cmdDoctorCheck() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func cmdRecreateTable() *cli.Command {
|
var cmdRecreateTable = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "recreate-table",
|
Name: "recreate-table",
|
||||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||||
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
||||||
|
@ -96,10 +91,9 @@ This command will cause Xorm to recreate tables, copying over the data and delet
|
||||||
You should back-up your database before doing this and ensure that your database is up-to-date first.`,
|
You should back-up your database before doing this and ensure that your database is up-to-date first.`,
|
||||||
Action: runRecreateTable,
|
Action: runRecreateTable,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
func runRecreateTable(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Redirect the default golog to here
|
// Redirect the default golog to here
|
||||||
|
@ -126,7 +120,7 @@ func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
|
|
||||||
args := ctx.Args()
|
args := ctx.Args()
|
||||||
names := make([]string, 0, ctx.NArg())
|
names := make([]string, 0, ctx.NArg())
|
||||||
for i := range ctx.NArg() {
|
for i := 0; i < ctx.NArg(); i++ {
|
||||||
names = append(names, args.Get(i))
|
names = append(names, args.Get(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,31 +130,24 @@ func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
}
|
}
|
||||||
recreateTables := migrate_base.RecreateTables(beans...)
|
recreateTables := migrate_base.RecreateTables(beans...)
|
||||||
|
|
||||||
return db.InitEngineWithMigration(stdCtx, func(x db.Engine) error {
|
return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
|
||||||
engine, err := db.GetMasterEngine(x)
|
if err := migrations.EnsureUpToDate(x); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return recreateTables(x)
|
||||||
if err := migrations.EnsureUpToDate(engine); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return recreateTables(engine)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDoctorDefaultLogger(ctx *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 := ctx.String("log-file")
|
logFile := ctx.String("log-file")
|
||||||
switch logFile {
|
if logFile == "" {
|
||||||
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
|
||||||
case "-":
|
} else if logFile == "-" {
|
||||||
setupConsoleLogger(log.TRACE, colorize, os.Stdout)
|
setupConsoleLogger(log.TRACE, colorize, os.Stdout)
|
||||||
default:
|
} else {
|
||||||
logFile, _ = filepath.Abs(logFile)
|
logFile, _ = filepath.Abs(logFile)
|
||||||
writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}}
|
writeMode := log.WriterMode{Level: log.TRACE, WriterOption: log.WriterFileOption{FileName: logFile}}
|
||||||
writer, err := log.NewEventWriter("console-to-file", "file", writeMode)
|
writer, err := log.NewEventWriter("console-to-file", "file", writeMode)
|
||||||
|
@ -172,8 +159,8 @@ func setupDoctorDefaultLogger(ctx *cli.Command, colorize bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorCheck(stdCtx context.Context, ctx *cli.Command) error {
|
func runDoctorCheck(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
colorize := log.CanColorStdout
|
colorize := log.CanColorStdout
|
||||||
|
|
|
@ -4,28 +4,25 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/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.
|
||||||
func cmdDoctorConvert() *cli.Command {
|
var cmdDoctorConvert = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "convert",
|
Name: "convert",
|
||||||
Usage: "Convert the database",
|
Usage: "Convert the database",
|
||||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||||
Action: runDoctorConvert,
|
Action: runDoctorConvert,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runDoctorConvert(stdCtx context.Context, ctx *cli.Command) error {
|
func runDoctorConvert(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"forgejo.org/services/doctor"
|
"forgejo.org/services/doctor"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDoctorRun(t *testing.T) {
|
func TestDoctorRun(t *testing.T) {
|
||||||
|
@ -22,12 +22,12 @@ func TestDoctorRun(t *testing.T) {
|
||||||
|
|
||||||
SkipDatabaseInitialization: true,
|
SkipDatabaseInitialization: true,
|
||||||
})
|
})
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Commands = []*cli.Command{cmdDoctorCheck()}
|
app.Commands = []*cli.Command{cmdDoctorCheck}
|
||||||
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
|
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "no-such"})
|
err = app.Run([]string{"./gitea", "check", "--run", "no-such"})
|
||||||
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
require.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"})
|
||||||
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
}
|
}
|
||||||
|
|
38
cmd/dump.go
38
cmd/dump.go
|
@ -5,8 +5,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -24,7 +22,7 @@ import (
|
||||||
|
|
||||||
"code.forgejo.org/go-chi/session"
|
"code.forgejo.org/go-chi/session"
|
||||||
"github.com/mholt/archiver/v3"
|
"github.com/mholt/archiver/v3"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
|
func addReader(w archiver.Writer, r io.ReadCloser, info os.FileInfo, customName string, verbose bool) error {
|
||||||
|
@ -85,10 +83,6 @@ func (o *outputType) Set(value string) error {
|
||||||
return fmt.Errorf("allowed values are %s", o.Join())
|
return fmt.Errorf("allowed values are %s", o.Join())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *outputType) Get() any {
|
|
||||||
return o.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o outputType) String() string {
|
func (o outputType) String() string {
|
||||||
if o.selected == "" {
|
if o.selected == "" {
|
||||||
return o.Default
|
return o.Default
|
||||||
|
@ -102,8 +96,7 @@ var outputTypeEnum = &outputType{
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmdDump represents the available dump sub-command.
|
// CmdDump represents the available dump sub-command.
|
||||||
func cmdDump() *cli.Command {
|
var CmdDump = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "dump",
|
Name: "dump",
|
||||||
Usage: "Dump Forgejo files and database",
|
Usage: "Dump Forgejo files and database",
|
||||||
Description: `Dump compresses all related files and database into zip file.
|
Description: `Dump compresses all related files and database into zip file.
|
||||||
|
@ -129,6 +122,7 @@ It can be used for backup and capture Forgejo server image to send to maintainer
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "tempdir",
|
Name: "tempdir",
|
||||||
Aliases: []string{"t"},
|
Aliases: []string{"t"},
|
||||||
|
Value: os.TempDir(),
|
||||||
Usage: "Temporary dir path",
|
Usage: "Temporary dir path",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
|
@ -177,14 +171,13 @@ It can be used for backup and capture Forgejo server image to send to maintainer
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func fatal(format string, args ...any) {
|
func fatal(format string, args ...any) {
|
||||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||||
log.Fatal(format, args...)
|
log.Fatal(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDump(stdCtx context.Context, ctx *cli.Command) error {
|
func runDump(ctx *cli.Context) error {
|
||||||
var file *os.File
|
var file *os.File
|
||||||
fileName := ctx.String("file")
|
fileName := ctx.String("file")
|
||||||
outType := ctx.String("type")
|
outType := ctx.String("type")
|
||||||
|
@ -220,16 +213,16 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
|
|
||||||
if !setting.InstallLock {
|
if !setting.InstallLock {
|
||||||
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
||||||
return errors.New("forgejo is not initialized")
|
return fmt.Errorf("forgejo is not initialized")
|
||||||
}
|
}
|
||||||
setting.LoadSettings() // cannot access session settings otherwise
|
setting.LoadSettings() // cannot access session settings otherwise
|
||||||
|
|
||||||
verbose := ctx.Bool("verbose")
|
verbose := ctx.Bool("verbose")
|
||||||
if verbose && ctx.Bool("quiet") {
|
if verbose && ctx.Bool("quiet") {
|
||||||
return errors.New("--quiet and --verbose cannot both be set")
|
return fmt.Errorf("--quiet and --verbose cannot both be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
err := db.InitEngine(stdCtx)
|
err := db.InitEngine(stdCtx)
|
||||||
|
@ -295,31 +288,18 @@ func runDump(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpDir := ctx.String("tempdir")
|
tmpDir := ctx.String("tempdir")
|
||||||
if tmpDir == "" {
|
|
||||||
tmpDir, err = os.MkdirTemp("", "forgejo-dump-*")
|
|
||||||
if err != nil {
|
|
||||||
fatal("Failed to create temporary directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := util.Remove(tmpDir); err != nil {
|
|
||||||
log.Warn("Failed to remove temporary directory: %s: Error: %v", tmpDir, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbDump, err := os.CreateTemp(tmpDir, "forgejo-db.sql")
|
dbDump, err := os.CreateTemp(tmpDir, "forgejo-db.sql")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatal("Failed to create temporary file: %v", err)
|
fatal("Failed to create tmp file: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = dbDump.Close()
|
_ = dbDump.Close()
|
||||||
if err := util.Remove(dbDump.Name()); err != nil {
|
if err := util.Remove(dbDump.Name()); err != nil {
|
||||||
log.Warn("Failed to remove temporary database file: %s: Error: %v", dbDump.Name(), err)
|
log.Warn("Failed to remove temporary file: %s: Error: %v", dbDump.Name(), err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,11 @@ import (
|
||||||
"forgejo.org/services/convert"
|
"forgejo.org/services/convert"
|
||||||
"forgejo.org/services/migrations"
|
"forgejo.org/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.
|
||||||
func cmdDumpRepository() *cli.Command {
|
var CmdDumpRepository = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "dump-repo",
|
Name: "dump-repo",
|
||||||
Usage: "Dump the repository from git/github/gitea/gitlab",
|
Usage: "Dump the repository from git/github/gitea/gitlab",
|
||||||
Description: "This is a command for dumping the repository data.",
|
Description: "This is a command for dumping the repository data.",
|
||||||
|
@ -79,15 +78,9 @@ wiki, issues, labels, releases, release_assets, milestones, pull_requests, comme
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error {
|
func runDumpRepository(ctx *cli.Context) error {
|
||||||
setupConsoleLogger(log.INFO, log.CanColorStderr, os.Stderr)
|
stdCtx, cancel := installSignals()
|
||||||
|
|
||||||
// setting.DisableLoggerInit()
|
|
||||||
setting.LoadSettings() // cannot access skip_tls_verify settings otherwise
|
|
||||||
|
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -20,25 +19,23 @@ import (
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/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.
|
||||||
func cmdEmbedded() *cli.Command {
|
var (
|
||||||
return &cli.Command{
|
CmdEmbedded = &cli.Command{
|
||||||
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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdList() *cli.Command {
|
subcmdList = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Usage: "List files matching the given pattern",
|
Usage: "List files matching the given pattern",
|
||||||
Action: runList,
|
Action: runList,
|
||||||
|
@ -50,10 +47,8 @@ func subcmdList() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdView() *cli.Command {
|
subcmdView = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "view",
|
Name: "view",
|
||||||
Usage: "View a file matching the given pattern",
|
Usage: "View a file matching the given pattern",
|
||||||
Action: runView,
|
Action: runView,
|
||||||
|
@ -65,10 +60,8 @@ func subcmdView() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdExtract() *cli.Command {
|
subcmdExtract = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "extract",
|
Name: "extract",
|
||||||
Usage: "Extract resources",
|
Usage: "Extract resources",
|
||||||
Action: runExtract,
|
Action: runExtract,
|
||||||
|
@ -97,9 +90,9 @@ func subcmdExtract() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var matchedAssetFiles []assetFile
|
matchedAssetFiles []assetFile
|
||||||
|
)
|
||||||
|
|
||||||
type assetFile struct {
|
type assetFile struct {
|
||||||
fs *assetfs.LayeredFS
|
fs *assetfs.LayeredFS
|
||||||
|
@ -107,7 +100,7 @@ type assetFile struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initEmbeddedExtractor(_ context.Context, 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())
|
||||||
|
@ -122,32 +115,32 @@ func initEmbeddedExtractor(_ context.Context, c *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runList(ctx context.Context, c *cli.Command) error {
|
func runList(c *cli.Context) error {
|
||||||
if err := runListDo(ctx, 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(ctx context.Context, c *cli.Command) error {
|
func runView(c *cli.Context) error {
|
||||||
if err := runViewDo(ctx, 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(ctx context.Context, c *cli.Command) error {
|
func runExtract(c *cli.Context) error {
|
||||||
if err := runExtractDo(ctx, 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(ctx context.Context, c *cli.Command) error {
|
func runListDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +151,8 @@ func runListDo(ctx context.Context, c *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runViewDo(ctx context.Context, c *cli.Command) error {
|
func runViewDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,8 +174,8 @@ func runViewDo(ctx context.Context, c *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtractDo(ctx context.Context, c *cli.Command) error {
|
func runExtractDo(c *cli.Context) error {
|
||||||
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
if err := initEmbeddedExtractor(c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,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 {
|
||||||
|
|
|
@ -6,7 +6,6 @@ package forgejo
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -17,14 +16,14 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
private_routers "forgejo.org/routers/private"
|
private_routers "forgejo.org/routers/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CmdActions(ctx context.Context) *cli.Command {
|
func CmdActions(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "Commands for managing Forgejo Actions",
|
Usage: "Commands for managing Forgejo Actions",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
SubcmdActionsGenerateRunnerToken(ctx),
|
SubcmdActionsGenerateRunnerToken(ctx),
|
||||||
SubcmdActionsGenerateRunnerSecret(ctx),
|
SubcmdActionsGenerateRunnerSecret(ctx),
|
||||||
SubcmdActionsRegister(ctx),
|
SubcmdActionsRegister(ctx),
|
||||||
|
@ -37,7 +36,7 @@ func SubcmdActionsGenerateRunnerToken(ctx context.Context) *cli.Command {
|
||||||
Name: "generate-runner-token",
|
Name: "generate-runner-token",
|
||||||
Usage: "Generate a new token for a runner to use to register with the server",
|
Usage: "Generate a new token for a runner to use to register with the server",
|
||||||
Before: prepareWorkPathAndCustomConf(ctx),
|
Before: prepareWorkPathAndCustomConf(ctx),
|
||||||
Action: RunGenerateActionsRunnerToken,
|
Action: func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) },
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "scope",
|
Name: "scope",
|
||||||
|
@ -53,7 +52,7 @@ func SubcmdActionsGenerateRunnerSecret(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "generate-secret",
|
Name: "generate-secret",
|
||||||
Usage: "Generate a secret suitable for input to the register subcommand",
|
Usage: "Generate a secret suitable for input to the register subcommand",
|
||||||
Action: RunGenerateSecret,
|
Action: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
Name: "register",
|
Name: "register",
|
||||||
Usage: "Idempotent registration of a runner using a shared secret",
|
Usage: "Idempotent registration of a runner using a shared secret",
|
||||||
Before: prepareWorkPathAndCustomConf(ctx),
|
Before: prepareWorkPathAndCustomConf(ctx),
|
||||||
Action: RunRegister,
|
Action: func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) },
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
|
@ -106,26 +105,26 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSecret(ctx context.Context, cli *cli.Command) (string, error) {
|
func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) {
|
||||||
if cli.IsSet("secret") {
|
if cliCtx.IsSet("secret") {
|
||||||
return cli.String("secret"), nil
|
return cliCtx.String("secret"), nil
|
||||||
}
|
}
|
||||||
if cli.IsSet("secret-stdin") {
|
if cliCtx.IsSet("secret-stdin") {
|
||||||
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
buf, err := io.ReadAll(ContextGetStdin(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
}
|
}
|
||||||
if cli.IsSet("secret-file") {
|
if cliCtx.IsSet("secret-file") {
|
||||||
path := cli.String("secret-file")
|
path := cliCtx.String("secret-file")
|
||||||
buf, err := os.ReadFile(path)
|
buf, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buf), nil
|
return string(buf), nil
|
||||||
}
|
}
|
||||||
return "", errors.New("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
return "", fmt.Errorf("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSecret(secret string) error {
|
func validateSecret(secret string) error {
|
||||||
|
@ -139,18 +138,18 @@ func validateSecret(secret string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabels(cli *cli.Command) (*[]string, error) {
|
func getLabels(cliCtx *cli.Context) (*[]string, error) {
|
||||||
if !cli.Bool("keep-labels") {
|
if !cliCtx.Bool("keep-labels") {
|
||||||
lblValue := strings.Split(cli.String("labels"), ",")
|
lblValue := strings.Split(cliCtx.String("labels"), ",")
|
||||||
return &lblValue, nil
|
return &lblValue, nil
|
||||||
}
|
}
|
||||||
if cli.String("labels") != "" {
|
if cliCtx.String("labels") != "" {
|
||||||
return nil, errors.New("--labels and --keep-labels should not be used together")
|
return nil, fmt.Errorf("--labels and --keep-labels should not be used together")
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunRegister(ctx context.Context, cli *cli.Command) error {
|
func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -162,17 +161,17 @@ func RunRegister(ctx context.Context, cli *cli.Command) error {
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
secret, err := readSecret(ctx, cli)
|
secret, err := readSecret(ctx, cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := validateSecret(secret); err != nil {
|
if err := validateSecret(secret); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
scope := cli.String("scope")
|
scope := cliCtx.String("scope")
|
||||||
name := cli.String("name")
|
name := cliCtx.String("name")
|
||||||
version := cli.String("version")
|
version := cliCtx.String("version")
|
||||||
labels, err := getLabels(cli)
|
labels, err := getLabels(cliCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -210,7 +209,7 @@ func RunRegister(ctx context.Context, cli *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateSecret(ctx context.Context, cli *cli.Command) error {
|
func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
runner := actions_model.ActionRunner{}
|
runner := actions_model.ActionRunner{}
|
||||||
if err := runner.GenerateToken(); err != nil {
|
if err := runner.GenerateToken(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -221,7 +220,7 @@ func RunGenerateSecret(ctx context.Context, cli *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error {
|
func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -230,7 +229,7 @@ func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
scope := cli.String("scope")
|
scope := cliCtx.String("scope")
|
||||||
|
|
||||||
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
package forgejo
|
package forgejo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"forgejo.org/services/context"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestActions_getLabels(t *testing.T) {
|
func TestActions_getLabels(t *testing.T) {
|
||||||
|
@ -53,21 +54,21 @@ func TestActions_getLabels(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := SubcmdActionsRegister(t.Context()).Flags
|
flags := SubcmdActionsRegister(context.Context{}).Flags
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) {
|
t.Run(fmt.Sprintf("args: %v", c.args), func(t *testing.T) {
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
var result *resultType
|
var result *resultType
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Flags = flags
|
app.Flags = flags
|
||||||
app.Action = func(_ context.Context, ctx *cli.Command) error {
|
app.Action = func(ctx *cli.Context) error {
|
||||||
labels, err := getLabels(ctx)
|
labels, err := getLabels(ctx)
|
||||||
result = &resultType{labels, err}
|
result = &resultType{labels, err}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
_ = app.Run(t.Context(), c.args)
|
_ = app.Run(c.args)
|
||||||
|
|
||||||
// Test the results
|
// Test the results
|
||||||
require.NotNil(t, result)
|
require.NotNil(t, result)
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
f3_cmd "code.forgejo.org/f3/gof3/v3/cmd"
|
f3_cmd "code.forgejo.org/f3/gof3/v3/cmd"
|
||||||
f3_logger "code.forgejo.org/f3/gof3/v3/logger"
|
f3_logger "code.forgejo.org/f3/gof3/v3/logger"
|
||||||
f3_util "code.forgejo.org/f3/gof3/v3/util"
|
f3_util "code.forgejo.org/f3/gof3/v3/util"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CmdF3(ctx context.Context) *cli.Command {
|
func CmdF3(ctx context.Context) *cli.Command {
|
||||||
|
@ -28,21 +28,21 @@ func CmdF3(ctx context.Context) *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "f3",
|
Name: "f3",
|
||||||
Usage: "F3",
|
Usage: "F3",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
SubcmdF3Mirror(ctx),
|
SubcmdF3Mirror(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
||||||
mirrorCmd := f3_cmd.CreateCmdMirror()
|
mirrorCmd := f3_cmd.CreateCmdMirror(ctx)
|
||||||
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
||||||
f3Action := mirrorCmd.Action
|
f3Action := mirrorCmd.Action
|
||||||
mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { return runMirror(ctx, cli, f3Action) }
|
mirrorCmd.Action = func(c *cli.Context) error { return runMirror(ctx, c, f3Action) }
|
||||||
return mirrorCmd
|
return mirrorCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error {
|
func runMirror(ctx context.Context, c *cli.Context, action cli.ActionFunc) error {
|
||||||
setting.LoadF3Setting()
|
setting.LoadF3Setting()
|
||||||
if !setting.F3.Enabled {
|
if !setting.F3.Enabled {
|
||||||
return errors.New("F3 is disabled, it is not ready to be used and is only present for development purposes")
|
return errors.New("F3 is disabled, it is not ready to be used and is only present for development purposes")
|
||||||
|
@ -69,7 +69,7 @@ func runMirror(ctx context.Context, c *cli.Command, action cli.ActionFunc) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := action(ctx, c)
|
err := action(c)
|
||||||
if panicError, ok := err.(f3_util.PanicError); ok {
|
if panicError, ok := err.(f3_util.PanicError); ok {
|
||||||
log.Debug("F3 Stack trace\n%s", panicError.Stack())
|
log.Debug("F3 Stack trace\n%s", panicError.Stack())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type key int
|
type key int
|
||||||
|
@ -34,7 +34,7 @@ func CmdForgejo(ctx context.Context) *cli.Command {
|
||||||
Name: "forgejo-cli",
|
Name: "forgejo-cli",
|
||||||
Usage: "Forgejo CLI",
|
Usage: "Forgejo CLI",
|
||||||
Flags: []cli.Flag{},
|
Flags: []cli.Flag{},
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
CmdActions(ctx),
|
CmdActions(ctx),
|
||||||
CmdF3(ctx),
|
CmdF3(ctx),
|
||||||
},
|
},
|
||||||
|
@ -147,12 +147,12 @@ func handleCliResponseExtra(ctx context.Context, extra private.ResponseExtra) er
|
||||||
return cli.Exit(extra.Error, 1)
|
return cli.Exit(extra.Error, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
func prepareWorkPathAndCustomConf(ctx context.Context) func(c *cli.Context) error {
|
||||||
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
return func(c *cli.Context) error {
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
var args setting.ArgWorkPathAndCustomConf
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
// from children to parent, check the global flags
|
// from children to parent, check the global flags
|
||||||
for _, curCtx := range cli.Lineage() {
|
for _, curCtx := range c.Lineage() {
|
||||||
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
args.WorkPath = curCtx.String("work-path")
|
args.WorkPath = curCtx.String("work-path")
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,6 @@ func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context,
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
}
|
}
|
||||||
return ctx, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,65 +5,56 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"forgejo.org/modules/generate"
|
"forgejo.org/modules/generate"
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// CmdGenerate represents the available generate sub-command.
|
// CmdGenerate represents the available generate sub-command.
|
||||||
func cmdGenerate() *cli.Command {
|
CmdGenerate = &cli.Command{
|
||||||
return &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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdSecret() *cli.Command {
|
subcmdSecret = &cli.Command{
|
||||||
return &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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdGenerateInternalToken() *cli.Command {
|
microcmdGenerateInternalToken = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "INTERNAL_TOKEN",
|
Name: "INTERNAL_TOKEN",
|
||||||
Usage: "Generate a new INTERNAL_TOKEN",
|
Usage: "Generate a new INTERNAL_TOKEN",
|
||||||
Action: runGenerateInternalToken,
|
Action: runGenerateInternalToken,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdGenerateLfsJwtSecret() *cli.Command {
|
microcmdGenerateLfsJwtSecret = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "JWT_SECRET",
|
Name: "JWT_SECRET",
|
||||||
Aliases: []string{"LFS_JWT_SECRET"},
|
Aliases: []string{"LFS_JWT_SECRET"},
|
||||||
Usage: "Generate a new JWT_SECRET",
|
Usage: "Generate a new JWT_SECRET",
|
||||||
Action: runGenerateLfsJwtSecret,
|
Action: runGenerateLfsJwtSecret,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func microcmdGenerateSecretKey() *cli.Command {
|
microcmdGenerateSecretKey = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "SECRET_KEY",
|
Name: "SECRET_KEY",
|
||||||
Usage: "Generate a new SECRET_KEY",
|
Usage: "Generate a new SECRET_KEY",
|
||||||
Action: runGenerateSecretKey,
|
Action: runGenerateSecretKey,
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func runGenerateInternalToken(ctx 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
|
||||||
|
@ -72,25 +63,28 @@ func runGenerateInternalToken(ctx context.Context, c *cli.Command) error {
|
||||||
fmt.Printf("%s", internalToken)
|
fmt.Printf("%s", internalToken)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Println()
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateLfsJwtSecret(ctx context.Context, c *cli.Command) error {
|
func runGenerateLfsJwtSecret(c *cli.Context) error {
|
||||||
_, jwtSecretBase64 := generate.NewJwtSecret()
|
_, jwtSecretBase64, err := generate.NewJwtSecret()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("%s", jwtSecretBase64)
|
fmt.Printf("%s", jwtSecretBase64)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Print("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateSecretKey(ctx 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
|
||||||
|
@ -99,7 +93,7 @@ func runGenerateSecretKey(ctx context.Context, c *cli.Command) error {
|
||||||
fmt.Printf("%s", secretKey)
|
fmt.Printf("%s", secretKey)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Print("\n")
|
fmt.Printf("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
84
cmd/hook.go
84
cmd/hook.go
|
@ -21,31 +21,29 @@ import (
|
||||||
repo_module "forgejo.org/modules/repository"
|
repo_module "forgejo.org/modules/repository"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hookBatchSize = 30
|
hookBatchSize = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// CmdHook represents the available hooks sub-command.
|
// CmdHook represents the available hooks sub-command.
|
||||||
func cmdHook() *cli.Command {
|
CmdHook = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "hook",
|
Name: "hook",
|
||||||
Usage: "(internal) Should only be called by Git",
|
Usage: "(internal) Should only be called by Git",
|
||||||
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,
|
||||||
subcmdHookProcReceive(),
|
subcmdHookProcReceive,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdHookPreReceive() *cli.Command {
|
subcmdHookPreReceive = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "pre-receive",
|
Name: "pre-receive",
|
||||||
Usage: "Delegate pre-receive Git hook",
|
Usage: "Delegate pre-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -56,10 +54,7 @@ func subcmdHookPreReceive() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
subcmdHookUpdate = &cli.Command{
|
||||||
|
|
||||||
func subcmdHookUpdate() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "update",
|
Name: "update",
|
||||||
Usage: "Delegate update Git hook",
|
Usage: "Delegate update Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -70,10 +65,7 @@ func subcmdHookUpdate() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
subcmdHookPostReceive = &cli.Command{
|
||||||
|
|
||||||
func subcmdHookPostReceive() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "post-receive",
|
Name: "post-receive",
|
||||||
Usage: "Delegate post-receive Git hook",
|
Usage: "Delegate post-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -84,11 +76,8 @@ func subcmdHookPostReceive() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Note: new hook since git 2.29
|
// Note: new hook since git 2.29
|
||||||
func subcmdHookProcReceive() *cli.Command {
|
subcmdHookProcReceive = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "proc-receive",
|
Name: "proc-receive",
|
||||||
Usage: "Delegate proc-receive Git hook",
|
Usage: "Delegate proc-receive Git hook",
|
||||||
Description: "This command should only be called by Git",
|
Description: "This command should only be called by Git",
|
||||||
|
@ -99,7 +88,7 @@ func subcmdHookProcReceive() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
type delayWriter struct {
|
type delayWriter struct {
|
||||||
internal io.Writer
|
internal io.Writer
|
||||||
|
@ -172,14 +161,14 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||||
|
@ -231,6 +220,11 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
supportProcReceive := false
|
||||||
|
if git.CheckGitVersionAtLeast("2.29") == nil {
|
||||||
|
supportProcReceive = true
|
||||||
|
}
|
||||||
|
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
// TODO: support news feeds for wiki
|
// TODO: support news feeds for wiki
|
||||||
if isWiki {
|
if isWiki {
|
||||||
|
@ -248,12 +242,15 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
total++
|
total++
|
||||||
lastline++
|
lastline++
|
||||||
|
|
||||||
// All references should be checked because permission check was delayed.
|
// If the ref is a branch or tag, check if it's protected
|
||||||
|
// if supportProcReceive all ref should be checked because
|
||||||
|
// permission check was delayed
|
||||||
|
if supportProcReceive || refFullName.IsBranch() || refFullName.IsTag() {
|
||||||
oldCommitIDs[count] = oldCommitID
|
oldCommitIDs[count] = oldCommitID
|
||||||
newCommitIDs[count] = newCommitID
|
newCommitIDs[count] = newCommitID
|
||||||
refFullNames[count] = refFullName
|
refFullNames[count] = refFullName
|
||||||
count++
|
count++
|
||||||
fmt.Fprint(out, "*")
|
fmt.Fprintf(out, "*")
|
||||||
|
|
||||||
if count >= hookBatchSize {
|
if count >= hookBatchSize {
|
||||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||||
|
@ -268,8 +265,11 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
count = 0
|
count = 0
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(out, ".")
|
||||||
|
}
|
||||||
if lastline >= hookBatchSize {
|
if lastline >= hookBatchSize {
|
||||||
fmt.Fprint(out, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
return fail(ctx, extra.UserMsg, "HookPreReceive(last) failed: %v", extra.Error)
|
||||||
}
|
}
|
||||||
} else if lastline > 0 {
|
} else if lastline > 0 {
|
||||||
fmt.Fprint(out, "\n")
|
fmt.Fprintf(out, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
||||||
|
@ -294,13 +294,13 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update
|
// runHookUpdate process the update hook: https://git-scm.com/docs/githooks#update
|
||||||
func runHookUpdate(ctx context.Context, c *cli.Command) error {
|
func runHookUpdate(c *cli.Context) error {
|
||||||
// Now if we're an internal don't do anything else
|
// Now if we're an internal don't do anything else
|
||||||
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() != 3 {
|
if c.NArg() != 3 {
|
||||||
|
@ -326,11 +326,11 @@ func runHookUpdate(ctx context.Context, c *cli.Command) error {
|
||||||
return fail(ctx, fmt.Sprintf("The modification of %s is skipped as it's an internal reference.", refFullName), "")
|
return fail(ctx, fmt.Sprintf("The modification of %s is skipped as it's an internal reference.", refFullName), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
func runHookPostReceive(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
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(ctx, "update-server-info").RunStdString(nil); err != nil {
|
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
|
||||||
|
@ -402,7 +402,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(out, ".")
|
fmt.Fprintf(out, ".")
|
||||||
oldCommitIDs[count] = string(fields[0])
|
oldCommitIDs[count] = string(fields[0])
|
||||||
newCommitIDs[count] = string(fields[1])
|
newCommitIDs[count] = string(fields[1])
|
||||||
refFullNames[count] = git.RefName(fields[2])
|
refFullNames[count] = git.RefName(fields[2])
|
||||||
|
@ -490,11 +490,11 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookProcReceive(ctx context.Context, c *cli.Command) error {
|
func runHookProcReceive(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
|
||||||
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
|
||||||
|
@ -505,6 +505,10 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if git.CheckGitVersionAtLeast("2.29") != nil {
|
||||||
|
return fail(ctx, "No proc-receive support", "current git version doesn't support proc-receive.")
|
||||||
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
repoUser := os.Getenv(repo_module.EnvRepoUsername)
|
||||||
repoName := os.Getenv(repo_module.EnvRepoName)
|
repoName := os.Getenv(repo_module.EnvRepoName)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Capture what's being written into a standard file descriptor.
|
// Capture what's being written into a standard file descriptor.
|
||||||
|
@ -134,14 +134,14 @@ func TestDelayWriter(t *testing.T) {
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
defer test.MockVariableValue(&setting.LocalURL, ts.URL+"/")()
|
||||||
|
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Commands = []*cli.Command{subcmdHookPreReceive()}
|
app.Commands = []*cli.Command{subcmdHookPreReceive}
|
||||||
|
|
||||||
t.Run("Should delay", func(t *testing.T) {
|
t.Run("Should delay", func(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Millisecond*500)()
|
||||||
finish := captureOutput(t, os.Stdout)
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"})
|
err = app.Run([]string{"./forgejo", "pre-receive"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
out := finish()
|
out := finish()
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func TestDelayWriter(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
defer test.MockVariableValue(&setting.Git.VerbosePushDelay, time.Second*5)()
|
||||||
finish := captureOutput(t, os.Stdout)
|
finish := captureOutput(t, os.Stdout)
|
||||||
|
|
||||||
err = app.Run(t.Context(), []string{"./forgejo", "pre-receive"})
|
err = app.Run([]string{"./forgejo", "pre-receive"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
out := finish()
|
out := finish()
|
||||||
|
|
||||||
|
@ -163,15 +163,15 @@ func TestDelayWriter(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunHookUpdate(t *testing.T) {
|
func TestRunHookUpdate(t *testing.T) {
|
||||||
app := cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Commands = []*cli.Command{subcmdHookUpdate()}
|
app.Commands = []*cli.Command{subcmdHookUpdate}
|
||||||
|
|
||||||
t.Run("Removal of internal reference", func(t *testing.T) {
|
t.Run("Removal of internal reference", func(t *testing.T) {
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
defer test.MockVariableValue(&cli.OsExiter, func(code int) {})()
|
||||||
defer test.MockVariableValue(&setting.IsProd, false)()
|
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||||
finish := captureOutput(t, os.Stderr)
|
finish := captureOutput(t, os.Stderr)
|
||||||
|
|
||||||
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
out := finish()
|
out := finish()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func TestRunHookUpdate(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.IsProd, false)()
|
defer test.MockVariableValue(&setting.IsProd, false)()
|
||||||
finish := captureOutput(t, os.Stderr)
|
finish := captureOutput(t, os.Stderr)
|
||||||
|
|
||||||
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
err := app.Run([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
||||||
out := finish()
|
out := finish()
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
@ -191,12 +191,12 @@ func TestRunHookUpdate(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Removal of branch", func(t *testing.T) {
|
t.Run("Removal of branch", func(t *testing.T) {
|
||||||
err := app.Run(t.Context(), []string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run([]string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Not enough arguments", func(t *testing.T) {
|
t.Run("Not enough arguments", func(t *testing.T) {
|
||||||
err := app.Run(t.Context(), []string{"./forgejo", "update"})
|
err := app.Run([]string{"./forgejo", "update"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
15
cmd/keys.go
15
cmd/keys.go
|
@ -4,7 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,12 +11,11 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/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
|
||||||
func cmdKeys() *cli.Command {
|
var CmdKeys = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "keys",
|
Name: "keys",
|
||||||
Usage: "(internal) Should only be called by SSH server",
|
Usage: "(internal) Should only be called by SSH server",
|
||||||
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
||||||
|
@ -50,9 +48,8 @@ func 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")
|
||||||
}
|
}
|
||||||
|
@ -71,16 +68,16 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
|
authorizedString, extra := private.AuthorizedPublicKeyByContent(ctx, content)
|
||||||
// do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
|
// do not use handleCliResponseExtra or cli.NewExitError, if it exists immediately, it breaks some tests like Test_CmdKeys
|
||||||
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,17 +4,16 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
107
cmd/main.go
107
cmd/main.go
|
@ -14,7 +14,7 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdHelp is our own help subcommand with more information
|
// cmdHelp is our own help subcommand with more information
|
||||||
|
@ -25,18 +25,18 @@ func cmdHelp() *cli.Command {
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
ArgsUsage: "[command]",
|
ArgsUsage: "[command]",
|
||||||
Action: func(ctx context.Context, c *cli.Command) (err error) {
|
Action: func(c *cli.Context) (err error) {
|
||||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Forgejo
|
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
|
||||||
targetCmdIdx := 0
|
targetCmdIdx := 0
|
||||||
if c.Name == "help" {
|
if c.Command.Name == "help" {
|
||||||
targetCmdIdx = 1
|
targetCmdIdx = 1
|
||||||
}
|
}
|
||||||
if targetCmdIdx+1 < len(lineage) {
|
if lineage[targetCmdIdx+1].Command != nil {
|
||||||
err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1], lineage[targetCmdIdx].Name)
|
err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
|
||||||
} else {
|
} else {
|
||||||
err = cli.ShowAppHelp(c)
|
err = cli.ShowAppHelp(c)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(c.Root().Writer, `
|
_, _ = fmt.Fprintf(c.App.Writer, `
|
||||||
DEFAULT CONFIGURATION:
|
DEFAULT CONFIGURATION:
|
||||||
AppPath: %s
|
AppPath: %s
|
||||||
WorkPath: %s
|
WorkPath: %s
|
||||||
|
@ -77,25 +77,25 @@ func appGlobalFlags() []cli.Flag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareSubcommandWithConfig(command *cli.Command, globalFlags func() []cli.Flag) {
|
func prepareSubcommandWithConfig(command *cli.Command, globalFlags []cli.Flag) {
|
||||||
command.Flags = append(globalFlags(), command.Flags...)
|
command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
|
||||||
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
command.Action = prepareWorkPathAndCustomConf(command.Action)
|
||||||
command.HideHelp = true
|
command.HideHelp = true
|
||||||
if command.Name != "help" {
|
if command.Name != "help" {
|
||||||
command.Commands = append(command.Commands, cmdHelp())
|
command.Subcommands = append(command.Subcommands, cmdHelp())
|
||||||
}
|
}
|
||||||
for i := range command.Commands {
|
for i := range command.Subcommands {
|
||||||
prepareSubcommandWithConfig(command.Commands[i], globalFlags)
|
prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareWorkPathAndCustomConf wraps the Action to prepare the work path and custom config
|
// 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
|
// 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(_ context.Context, _ *cli.Command) error {
|
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context) error {
|
||||||
return func(ctx context.Context, cli *cli.Command) error {
|
return func(ctx *cli.Context) error {
|
||||||
var args setting.ArgWorkPathAndCustomConf
|
var args setting.ArgWorkPathAndCustomConf
|
||||||
// from children to parent, check the global flags
|
// from children to parent, check the global flags
|
||||||
for _, curCtx := range cli.Lineage() {
|
for _, curCtx := range ctx.Lineage() {
|
||||||
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
if curCtx.IsSet("work-path") && args.WorkPath == "" {
|
||||||
args.WorkPath = curCtx.String("work-path")
|
args.WorkPath = curCtx.String("work-path")
|
||||||
}
|
}
|
||||||
|
@ -107,24 +107,24 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
if cli.Bool("help") || action == nil {
|
if ctx.Bool("help") || action == nil {
|
||||||
// the default behavior of "urfave/cli": "nil action" means "show help"
|
// the default behavior of "urfave/cli": "nil action" means "show help"
|
||||||
return cmdHelp().Action(ctx, cli)
|
return cmdHelp().Action(ctx)
|
||||||
}
|
}
|
||||||
return action(ctx, cli)
|
return action(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainApp(version, versionExtra string) *cli.Command {
|
func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
path, err := os.Executable()
|
path, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
executable := filepath.Base(path)
|
executable := filepath.Base(path)
|
||||||
|
|
||||||
subCmdsStandalone := make([]*cli.Command, 0, 10)
|
var subCmdsStandalone []*cli.Command = make([]*cli.Command, 0, 10)
|
||||||
subCmdWithConfig := make([]*cli.Command, 0, 10)
|
var subCmdWithConfig []*cli.Command = make([]*cli.Command, 0, 10)
|
||||||
globalFlags := func() []cli.Flag { return []cli.Flag{} }
|
var globalFlags []cli.Flag = make([]cli.Flag, 0, 10)
|
||||||
|
|
||||||
//
|
//
|
||||||
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
||||||
|
@ -133,16 +133,14 @@ func NewMainApp(version, versionExtra string) *cli.Command {
|
||||||
if executable == "forgejo-cli" {
|
if executable == "forgejo-cli" {
|
||||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdActions(context.Background()))
|
||||||
subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background()))
|
subCmdWithConfig = append(subCmdWithConfig, forgejo.CmdF3(context.Background()))
|
||||||
globalFlags = func() []cli.Flag {
|
globalFlags = append(globalFlags, []cli.Flag{
|
||||||
return []cli.Flag{
|
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "quiet",
|
Name: "quiet",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "verbose",
|
Name: "verbose",
|
||||||
},
|
},
|
||||||
}
|
}...)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
||||||
|
@ -151,54 +149,55 @@ func NewMainApp(version, versionExtra string) *cli.Command {
|
||||||
// binary and rename it to forgejo if they want.
|
// binary and rename it to forgejo if they want.
|
||||||
//
|
//
|
||||||
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
subCmdsStandalone = append(subCmdsStandalone, forgejo.CmdForgejo(context.Background()))
|
||||||
subCmdWithConfig = append(subCmdWithConfig, cmdActions())
|
subCmdWithConfig = append(subCmdWithConfig, CmdActions)
|
||||||
}
|
}
|
||||||
|
|
||||||
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags)
|
return innerNewMainApp(version, versionExtra, subCmdsStandalone, subCmdWithConfig, globalFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs func() []cli.Flag) *cli.Command {
|
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs []cli.Flag) *cli.App {
|
||||||
app := &cli.Command{}
|
app := cli.NewApp()
|
||||||
app.Name = "forgejo"
|
app.HelpName = "forgejo"
|
||||||
|
app.Name = "Forgejo"
|
||||||
app.Usage = "Beyond coding. We forge."
|
app.Usage = "Beyond coding. We forge."
|
||||||
app.Description = `By default, forgejo will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
app.Description = `By default, forgejo will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
||||||
app.Version = version + versionExtra
|
app.Version = version + versionExtra
|
||||||
app.EnableShellCompletion = true
|
app.EnableBashCompletion = true
|
||||||
|
|
||||||
// these sub-commands need to use config file
|
// these sub-commands need to use 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"
|
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||||
cmdWeb(),
|
CmdWeb,
|
||||||
cmdServ(),
|
CmdServ,
|
||||||
cmdHook(),
|
CmdHook,
|
||||||
cmdKeys(),
|
CmdKeys,
|
||||||
cmdDump(),
|
CmdDump,
|
||||||
cmdAdmin(),
|
CmdAdmin,
|
||||||
cmdMigrate(),
|
CmdMigrate,
|
||||||
cmdDoctor(),
|
CmdDoctor,
|
||||||
cmdManager(),
|
CmdManager,
|
||||||
cmdEmbedded(),
|
CmdEmbedded,
|
||||||
cmdMigrateStorage(),
|
CmdMigrateStorage,
|
||||||
cmdDumpRepository(),
|
CmdDumpRepository,
|
||||||
cmdRestoreRepository(),
|
CmdRestoreRepository,
|
||||||
}
|
}
|
||||||
|
|
||||||
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
subCmdWithConfig = append(subCmdWithConfig, subCmdWithConfigArgs...)
|
||||||
|
|
||||||
// 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,
|
||||||
}
|
}
|
||||||
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
subCmdStandalone = append(subCmdStandalone, subCmdsStandaloneArgs...)
|
||||||
|
|
||||||
app.DefaultCommand = cmdWeb().Name
|
app.DefaultCommand = CmdWeb.Name
|
||||||
|
|
||||||
globalFlags := func() []cli.Flag {
|
globalFlags := appGlobalFlags()
|
||||||
return append(appGlobalFlags(), globalFlagsArgs()...)
|
globalFlags = append(globalFlags, globalFlagsArgs...)
|
||||||
}
|
|
||||||
app.Flags = append(app.Flags, cli.VersionFlag)
|
app.Flags = append(app.Flags, cli.VersionFlag)
|
||||||
app.Flags = append(app.Flags, globalFlags()...)
|
app.Flags = append(app.Flags, globalFlags...)
|
||||||
app.HideHelp = true // use our own help action to show helps (with more information like default config)
|
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 {
|
||||||
|
@ -211,8 +210,8 @@ func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmd
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMainApp(app *cli.Command, args ...string) error {
|
func RunMainApp(app *cli.App, args ...string) error {
|
||||||
err := app.Run(context.Background(), args)
|
err := app.Run(args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -221,7 +220,7 @@ func RunMainApp(app *cli.Command, args ...string) error {
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(app.Root().ErrWriter, "Command error: %v\n", err)
|
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -18,7 +16,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -29,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 func(_ context.Context, ctx *cli.Command) error) *cli.Command {
|
func newTestApp(testCmdAction func(ctx *cli.Context) error) *cli.App {
|
||||||
app := NewMainApp("version", "version-extra")
|
app := NewMainApp("version", "version-extra")
|
||||||
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
testCmd := &cli.Command{Name: "test-cmd", Action: testCmdAction}
|
||||||
prepareSubcommandWithConfig(testCmd, appGlobalFlags)
|
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
|
||||||
|
@ -44,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
|
||||||
|
@ -67,6 +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.AppHelpTemplate = "(app help template)"
|
||||||
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
@ -110,17 +109,12 @@ func TestCliCmd(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
app := newTestApp(func(ctx *cli.Context) error {
|
||||||
t.Run(c.cmd, func(t *testing.T) {
|
_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
||||||
defer test.MockProtect(&setting.AppWorkPath)()
|
|
||||||
defer test.MockProtect(&setting.CustomPath)()
|
|
||||||
defer test.MockProtect(&setting.CustomConf)()
|
|
||||||
|
|
||||||
app := newTestApp(func(_ context.Context, ctx *cli.Command) error {
|
|
||||||
_, _ = fmt.Fprint(ctx.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.cmd, func(t *testing.T) {
|
||||||
for k, v := range c.env {
|
for k, v := range c.env {
|
||||||
t.Setenv(k, v)
|
t.Setenv(k, v)
|
||||||
}
|
}
|
||||||
|
@ -128,37 +122,37 @@ func TestCliCmd(t *testing.T) {
|
||||||
r, err := runTestApp(app, args...)
|
r, err := runTestApp(app, args...)
|
||||||
require.NoError(t, err, c.cmd)
|
require.NoError(t, err, c.cmd)
|
||||||
assert.NotEmpty(t, c.exp, c.cmd)
|
assert.NotEmpty(t, c.exp, c.cmd)
|
||||||
assert.Contains(t, r.Stdout, c.exp, c.cmd+"\n"+r.Stdout)
|
assert.Contains(t, r.Stdout, c.exp, c.cmd)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
func TestCliCmdError(t *testing.T) {
|
||||||
app := newTestApp(func(_ context.Context, ctx *cli.Command) error { return errors.New("normal error") })
|
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
|
||||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
r, err := runTestApp(app, "./gitea", "test-cmd")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Equal(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(_ context.Context, ctx *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")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 2, r.ExitCode)
|
assert.Equal(t, 2, r.ExitCode)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Equal(t, "", r.Stdout)
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
assert.Equal(t, "exit error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(_ context.Context, ctx *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")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stdout)
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Equal(t, "", r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
||||||
|
|
||||||
app = newTestApp(func(_ context.Context, ctx *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")
|
||||||
require.NoError(t, err)
|
require.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
|
||||||
assert.Empty(t, r.Stdout)
|
assert.Equal(t, "", r.Stdout)
|
||||||
assert.Empty(t, r.Stderr)
|
assert.Equal(t, "", r.Stderr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,34 +4,30 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
// CmdManager represents the manager command
|
// CmdManager represents the manager command
|
||||||
func cmdManager() *cli.Command {
|
CmdManager = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "manager",
|
Name: "manager",
|
||||||
Usage: "Manage the running forgejo process",
|
Usage: "Manage the running forgejo process",
|
||||||
Description: "This is a command for managing the running forgejo process",
|
Description: "This is a command for managing the running forgejo process",
|
||||||
Commands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdShutdown(),
|
subcmdShutdown,
|
||||||
subcmdRestart(),
|
subcmdRestart,
|
||||||
subcmdReloadTemplates(),
|
subcmdReloadTemplates,
|
||||||
subcmdFlushQueues(),
|
subcmdFlushQueues,
|
||||||
subcmdLogging(),
|
subcmdLogging,
|
||||||
subCmdProcesses(),
|
subCmdProcesses,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
subcmdShutdown = &cli.Command{
|
||||||
|
|
||||||
func subcmdShutdown() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "shutdown",
|
Name: "shutdown",
|
||||||
Usage: "Gracefully shutdown the running process",
|
Usage: "Gracefully shutdown the running process",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -41,10 +37,7 @@ func subcmdShutdown() *cli.Command {
|
||||||
},
|
},
|
||||||
Action: runShutdown,
|
Action: runShutdown,
|
||||||
}
|
}
|
||||||
}
|
subcmdRestart = &cli.Command{
|
||||||
|
|
||||||
func subcmdRestart() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "restart",
|
Name: "restart",
|
||||||
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
|
Usage: "Gracefully restart the running process - (not implemented for windows servers)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -54,10 +47,7 @@ func subcmdRestart() *cli.Command {
|
||||||
},
|
},
|
||||||
Action: runRestart,
|
Action: runRestart,
|
||||||
}
|
}
|
||||||
}
|
subcmdReloadTemplates = &cli.Command{
|
||||||
|
|
||||||
func subcmdReloadTemplates() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "reload-templates",
|
Name: "reload-templates",
|
||||||
Usage: "Reload template files in the running process",
|
Usage: "Reload template files in the running process",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
@ -67,10 +57,7 @@ func subcmdReloadTemplates() *cli.Command {
|
||||||
},
|
},
|
||||||
Action: runReloadTemplates,
|
Action: runReloadTemplates,
|
||||||
}
|
}
|
||||||
}
|
subcmdFlushQueues = &cli.Command{
|
||||||
|
|
||||||
func subcmdFlushQueues() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "flush-queues",
|
Name: "flush-queues",
|
||||||
Usage: "Flush queues in the running process",
|
Usage: "Flush queues in the running process",
|
||||||
Action: runFlushQueues,
|
Action: runFlushQueues,
|
||||||
|
@ -89,10 +76,7 @@ func subcmdFlushQueues() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
subCmdProcesses = &cli.Command{
|
||||||
|
|
||||||
func subCmdProcesses() *cli.Command {
|
|
||||||
return &cli.Command{
|
|
||||||
Name: "processes",
|
Name: "processes",
|
||||||
Usage: "Display running processes within the current process",
|
Usage: "Display running processes within the current process",
|
||||||
Action: runProcesses,
|
Action: runProcesses,
|
||||||
|
@ -122,49 +106,49 @@ func subCmdProcesses() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func runShutdown(ctx context.Context, c *cli.Command) error {
|
func runShutdown(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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,11 +11,11 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func defaultLoggingFlags() []cli.Flag {
|
var (
|
||||||
return []cli.Flag{
|
defaultLoggingFlags = []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "logger",
|
Name: "logger",
|
||||||
Usage: `Logger name - will default to "default"`,
|
Usage: `Logger name - will default to "default"`,
|
||||||
|
@ -57,13 +56,11 @@ func defaultLoggingFlags() []cli.Flag {
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func subcmdLogging() *cli.Command {
|
subcmdLogging = &cli.Command{
|
||||||
return &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 (Forgejo will buffer logs up to a certain point and will drop them after that point)",
|
Usage: "Pause logging (Forgejo will buffer logs up to a certain point and will drop them after that point)",
|
||||||
|
@ -107,11 +104,11 @@ func subcmdLogging() *cli.Command {
|
||||||
}, {
|
}, {
|
||||||
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",
|
||||||
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "filename",
|
Name: "filename",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
|
@ -155,7 +152,7 @@ func subcmdLogging() *cli.Command {
|
||||||
}, {
|
}, {
|
||||||
Name: "conn",
|
Name: "conn",
|
||||||
Usage: "Add a net conn logger",
|
Usage: "Add a net conn logger",
|
||||||
Flags: append(defaultLoggingFlags(), []cli.Flag{
|
Flags: append(defaultLoggingFlags, []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "reconnect-on-message",
|
Name: "reconnect-on-message",
|
||||||
Aliases: []string{"R"},
|
Aliases: []string{"R"},
|
||||||
|
@ -196,13 +193,13 @@ func subcmdLogging() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
func runRemoveLogger(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"))
|
||||||
logger := c.String("logger")
|
logger := c.String("logger")
|
||||||
if len(logger) == 0 {
|
if len(logger) == 0 {
|
||||||
logger = log.DEFAULT
|
logger = log.DEFAULT
|
||||||
|
@ -213,11 +210,11 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"))
|
||||||
vals := map[string]any{}
|
vals := map[string]any{}
|
||||||
mode := "conn"
|
mode := "conn"
|
||||||
vals["net"] = "tcp"
|
vals["net"] = "tcp"
|
||||||
|
@ -240,14 +237,14 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"))
|
||||||
vals := map[string]any{}
|
vals := map[string]any{}
|
||||||
mode := "file"
|
mode := "file"
|
||||||
if c.IsSet("filename") {
|
if c.IsSet("filename") {
|
||||||
|
@ -273,10 +270,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()
|
||||||
}
|
}
|
||||||
|
@ -303,47 +300,47 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
extra := private.SetLogSQL(ctx, !c.Bool("off"))
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
|
|
|
@ -11,21 +11,19 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrate represents the available migrate sub-command.
|
// CmdMigrate represents the available migrate sub-command.
|
||||||
func cmdMigrate() *cli.Command {
|
var CmdMigrate = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "migrate",
|
Name: "migrate",
|
||||||
Usage: "Migrate the database",
|
Usage: "Migrate the database",
|
||||||
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
||||||
Action: runMigrate,
|
Action: runMigrate,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runMigrate(stdCtx context.Context, ctx *cli.Command) error {
|
func runMigrate(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
@ -38,13 +36,7 @@ func runMigrate(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
if err := db.InitEngineWithMigration(context.Background(), func(dbEngine db.Engine) error {
|
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
||||||
masterEngine, err := db.GetMasterEngine(dbEngine)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return migrations.Migrate(masterEngine)
|
|
||||||
}); err != nil {
|
|
||||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,11 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/storage"
|
"forgejo.org/modules/storage"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v2"
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrateStorage represents the available migrate storage sub-command.
|
// CmdMigrateStorage represents the available migrate storage sub-command.
|
||||||
func cmdMigrateStorage() *cli.Command {
|
var CmdMigrateStorage = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "migrate-storage",
|
Name: "migrate-storage",
|
||||||
Usage: "Migrate the storage",
|
Usage: "Migrate the storage",
|
||||||
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
||||||
|
@ -97,7 +95,6 @@ func cmdMigrateStorage() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
return db.Iterate(ctx, nil, func(ctx context.Context, attach *repo_model.Attachment) error {
|
return db.Iterate(ctx, nil, func(ctx context.Context, attach *repo_model.Attachment) error {
|
||||||
|
@ -184,8 +181,8 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error {
|
func runMigrateStorage(ctx *cli.Context) error {
|
||||||
stdCtx, cancel := installSignals(stdCtx)
|
stdCtx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
@ -198,9 +195,7 @@ func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
if err := db.InitEngineWithMigration(context.Background(), func(e db.Engine) error {
|
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
||||||
return migrations.Migrate(e.(*xorm.Engine))
|
|
||||||
}); err != nil {
|
|
||||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,8 @@ func TestMigratePackages(t *testing.T) {
|
||||||
entries, err := os.ReadDir(p)
|
entries, err := os.ReadDir(p)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, entries, 2)
|
assert.Len(t, entries, 2)
|
||||||
assert.Equal(t, "01", entries[0].Name())
|
assert.EqualValues(t, "01", entries[0].Name())
|
||||||
assert.Equal(t, "tmp", entries[1].Name())
|
assert.EqualValues(t, "tmp", entries[1].Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMigrateActionsArtifacts(t *testing.T) {
|
func TestMigrateActionsArtifacts(t *testing.T) {
|
||||||
|
|
|
@ -4,18 +4,16 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/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.
|
||||||
func cmdRestoreRepository() *cli.Command {
|
var CmdRestoreRepository = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "restore-repo",
|
Name: "restore-repo",
|
||||||
Usage: "Restore the repository from disk",
|
Usage: "Restore the repository from disk",
|
||||||
Description: "This is a command for restoring the repository data.",
|
Description: "This is a command for restoring the repository data.",
|
||||||
|
@ -49,10 +47,9 @@ 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(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
28
cmd/serv.go
28
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,8 +41,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdServ represents the available serv sub-command.
|
// CmdServ represents the available serv sub-command.
|
||||||
func cmdServ() *cli.Command {
|
var CmdServ = &cli.Command{
|
||||||
return &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",
|
||||||
|
@ -57,26 +56,22 @@ func cmdServ() *cli.Command {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func setup(ctx context.Context, debug, gitNeeded bool) {
|
func setup(ctx context.Context, debug bool) {
|
||||||
if debug {
|
if debug {
|
||||||
setupConsoleLogger(log.TRACE, false, os.Stderr)
|
setupConsoleLogger(log.TRACE, false, os.Stderr)
|
||||||
} else {
|
} else {
|
||||||
setupConsoleLogger(log.FATAL, false, os.Stderr)
|
setupConsoleLogger(log.FATAL, false, os.Stderr)
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
// Sanity check to ensure path is not relative, see: https://github.com/go-gitea/gitea/pull/19317
|
|
||||||
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
||||||
_ = fail(ctx, "Unable to access repository path", "Unable to access repository path %q, err: %v", setting.RepoRootPath, err)
|
_ = fail(ctx, "Unable to access repository path", "Unable to access repository path %q, err: %v", setting.RepoRootPath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if gitNeeded {
|
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
|
_ = fail(ctx, "Failed to init git", "Failed to init git, err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
allowedCommands = map[string]perm.AccessMode{
|
allowedCommands = map[string]perm.AccessMode{
|
||||||
|
@ -133,12 +128,12 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServ(ctx context.Context, c *cli.Command) error {
|
func runServ(c *cli.Context) error {
|
||||||
ctx, cancel := installSignals(ctx)
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// FIXME: This needs to internationalised
|
// FIXME: This needs to internationalised
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"))
|
||||||
|
|
||||||
if setting.SSH.Disabled {
|
if setting.SSH.Disabled {
|
||||||
fmt.Println("Forgejo: SSH has been disabled")
|
fmt.Println("Forgejo: SSH has been disabled")
|
||||||
|
@ -193,11 +188,13 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(words) < 2 {
|
if len(words) < 2 {
|
||||||
|
if git.CheckGitVersionAtLeast("2.29") == nil {
|
||||||
// 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
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
return fail(ctx, "Too few arguments", "Too few arguments in cmd: %s", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,12 +253,11 @@ func runServ(ctx context.Context, c *cli.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if verb == lfsAuthenticateVerb {
|
if verb == lfsAuthenticateVerb {
|
||||||
switch lfsVerb {
|
if lfsVerb == "upload" {
|
||||||
case "upload":
|
|
||||||
requestedMode = perm.AccessModeWrite
|
requestedMode = perm.AccessModeWrite
|
||||||
case "download":
|
} else if lfsVerb == "download" {
|
||||||
requestedMode = perm.AccessModeRead
|
requestedMode = perm.AccessModeRead
|
||||||
default:
|
} else {
|
||||||
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
return fail(ctx, "Unknown LFS verb", "Unknown lfs verb %s", lfsVerb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
23
cmd/web.go
23
cmd/web.go
|
@ -26,15 +26,14 @@ import (
|
||||||
"forgejo.org/routers/install"
|
"forgejo.org/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
|
||||||
var PIDFile = "/run/gitea.pid"
|
var PIDFile = "/run/gitea.pid"
|
||||||
|
|
||||||
// CmdWeb represents the available web sub-command.
|
// CmdWeb represents the available web sub-command.
|
||||||
func cmdWeb() *cli.Command {
|
var CmdWeb = &cli.Command{
|
||||||
return &cli.Command{
|
|
||||||
Name: "web",
|
Name: "web",
|
||||||
Usage: "Start the Forgejo web server",
|
Usage: "Start the Forgejo web server",
|
||||||
Description: `The Forgejo web server is the only thing you need to run,
|
Description: `The Forgejo web server is the only thing you need to run,
|
||||||
|
@ -70,7 +69,6 @@ and it takes care of all the other things for you`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func runHTTPRedirector() {
|
func runHTTPRedirector() {
|
||||||
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: HTTP Redirector", process.SystemProcessType, true)
|
_, _, finished := process.GetManager().AddTypedContext(graceful.GetManager().HammerContext(), "Web: HTTP Redirector", process.SystemProcessType, true)
|
||||||
|
@ -130,7 +128,7 @@ func showWebStartupMessage(msg string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstall(_ context.Context, ctx *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())
|
||||||
|
@ -163,7 +161,7 @@ func serveInstall(_ context.Context, ctx *cli.Command) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstalled(_ context.Context, ctx *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()
|
||||||
|
@ -200,6 +198,9 @@ func serveInstalled(_ context.Context, ctx *cli.Command) error {
|
||||||
for fn := range publicFilesSet.Seq() {
|
for fn := range publicFilesSet.Seq() {
|
||||||
log.Error("Found legacy public asset %q in CustomPath. Please move it to %s/public/assets/%s", fn, setting.CustomPath, fn)
|
log.Error("Found legacy public asset %q in CustomPath. Please move it to %s/public/assets/%s", fn, setting.CustomPath, fn)
|
||||||
}
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(setting.CustomPath, "robots.txt")); err == nil {
|
||||||
|
log.Error(`Found legacy public asset "robots.txt" in CustomPath. Please move it to %s/public/robots.txt`, setting.CustomPath)
|
||||||
|
}
|
||||||
|
|
||||||
routers.InitWebInstalled(graceful.GetManager().HammerContext())
|
routers.InitWebInstalled(graceful.GetManager().HammerContext())
|
||||||
|
|
||||||
|
@ -235,7 +236,7 @@ func servePprof() {
|
||||||
finished()
|
finished()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb(ctx context.Context, cli *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))
|
||||||
|
@ -253,12 +254,12 @@ func runWeb(ctx context.Context, cli *cli.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set pid file setting
|
// Set pid file setting
|
||||||
if cli.IsSet("pid") {
|
if ctx.IsSet("pid") {
|
||||||
createPIDFile(cli.String("pid"))
|
createPIDFile(ctx.String("pid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.InstallLock {
|
if !setting.InstallLock {
|
||||||
if err := serveInstall(ctx, cli); err != nil {
|
if err := serveInstall(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -269,7 +270,7 @@ func runWeb(ctx context.Context, cli *cli.Command) error {
|
||||||
go servePprof()
|
go servePprof()
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveInstalled(ctx, cli)
|
return serveInstalled(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPort(port string) error {
|
func setPort(port string) error {
|
||||||
|
|
|
@ -54,8 +54,8 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||||
altTLSALPNPort = p
|
altTLSALPNPort = p
|
||||||
}
|
}
|
||||||
|
|
||||||
certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
magic := certmagic.NewDefault()
|
||||||
|
magic.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||||
// Try to use private CA root if provided, otherwise defaults to system's trust
|
// Try to use private CA root if provided, otherwise defaults to system's trust
|
||||||
var certPool *x509.CertPool
|
var certPool *x509.CertPool
|
||||||
if setting.AcmeCARoot != "" {
|
if setting.AcmeCARoot != "" {
|
||||||
|
@ -65,8 +65,7 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||||
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
|
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{
|
||||||
certmagic.DefaultACME = certmagic.ACMEIssuer{
|
|
||||||
CA: setting.AcmeURL,
|
CA: setting.AcmeURL,
|
||||||
TrustedRoots: certPool,
|
TrustedRoots: certPool,
|
||||||
Email: setting.AcmeEmail,
|
Email: setting.AcmeEmail,
|
||||||
|
@ -76,11 +75,7 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||||
ListenHost: setting.HTTPAddr,
|
ListenHost: setting.HTTPAddr,
|
||||||
AltTLSALPNPort: altTLSALPNPort,
|
AltTLSALPNPort: altTLSALPNPort,
|
||||||
AltHTTPPort: altHTTPPort,
|
AltHTTPPort: altHTTPPort,
|
||||||
}
|
})
|
||||||
|
|
||||||
magic := certmagic.NewDefault()
|
|
||||||
|
|
||||||
myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME)
|
|
||||||
|
|
||||||
magic.Issuers = []certmagic.Issuer{myACME}
|
magic.Issuers = []certmagic.Issuer{myACME}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#! /bin/bash
|
||||||
# Heavily inspired by https://github.com/urfave/cli
|
# Heavily inspired by https://github.com/urfave/cli
|
||||||
|
|
||||||
_cli_bash_autocomplete() {
|
_cli_bash_autocomplete() {
|
||||||
|
@ -6,9 +7,9 @@ _cli_bash_autocomplete() {
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
if [[ "$cur" == "-"* ]]; then
|
if [[ "$cur" == "-"* ]]; then
|
||||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-shell-completion )
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
|
||||||
else
|
else
|
||||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-shell-completion )
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
||||||
fi
|
fi
|
||||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -9,9 +9,9 @@ _cli_zsh_autocomplete() {
|
||||||
local cur
|
local cur
|
||||||
cur=${words[-1]}
|
cur=${words[-1]}
|
||||||
if [[ "$cur" == "-"* ]]; then
|
if [[ "$cur" == "-"* ]]; then
|
||||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-shell-completion)}")
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
|
||||||
else
|
else
|
||||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-shell-completion)}")
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${opts[1]}" != "" ]]; then
|
if [[ "${opts[1]}" != "" ]]; then
|
||||||
|
|
41
contrib/backport/README
Normal file
41
contrib/backport/README
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
`backport`
|
||||||
|
==========
|
||||||
|
|
||||||
|
`backport` is a command to help create backports of PRs. It backports a
|
||||||
|
provided PR from main on to a released version.
|
||||||
|
|
||||||
|
It will create a backport branch, cherry-pick the PR's merge commit, adjust
|
||||||
|
the commit message and then push this back up to your fork's remote.
|
||||||
|
|
||||||
|
The default version will read from `docs/config.yml`. You can override this
|
||||||
|
using the option `--version`.
|
||||||
|
|
||||||
|
The upstream branches will be fetched, using the remote `origin`. This can
|
||||||
|
be overridden using `--upstream`, and fetching can be avoided using
|
||||||
|
`--no-fetch`.
|
||||||
|
|
||||||
|
By default the branch created will be called `backport-$PR-$VERSION`. You
|
||||||
|
can override this using the option `--backport-branch`. This branch will
|
||||||
|
be created from `--release-branch` which is `release/$(VERSION)`
|
||||||
|
by default and will be pulled from `$(UPSTREAM)`.
|
||||||
|
|
||||||
|
The merge-commit as determined by the github API will be used as the SHA to
|
||||||
|
cherry-pick. You can override this using `--cherry-pick`.
|
||||||
|
|
||||||
|
The commit message will be amended to add the `Backport` header.
|
||||||
|
`--no-amend-message` can be set to stop this from happening.
|
||||||
|
|
||||||
|
If cherry-pick is successful the backported branch will be pushed up to your
|
||||||
|
fork using your remote. These will be determined using `git remote -v`. You
|
||||||
|
can set your fork name using `--fork-user` and your remote name using
|
||||||
|
`--remote`. You can avoid pushing using `--no-push`.
|
||||||
|
|
||||||
|
If the push is successful, `xdg-open` will be called to open a backport url.
|
||||||
|
You can stop this using `--no-xdg-open`.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install contrib/backport/backport.go
|
||||||
|
```
|
474
contrib/backport/backport.go
Normal file
474
contrib/backport/backport.go
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
//nolint:forbidigo
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v64/github"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultVersion = "v1.18" // to backport to
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "backport"
|
||||||
|
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.ArgsUsage = "<PR-to-backport>"
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "version",
|
||||||
|
Usage: "Version branch to backport on to",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "upstream",
|
||||||
|
Value: "origin",
|
||||||
|
Usage: "Upstream remote for the Gitea upstream",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "release-branch",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Release branch to backport on. Will default to release/<version>",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "cherry-pick",
|
||||||
|
Usage: "SHA to cherry-pick as backport",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "backport-branch",
|
||||||
|
Usage: "Backport branch to backport on to (default: backport-<pr>-<version>",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "remote",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Remote for your fork of the Gitea upstream",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "fork-user",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Forked user name on Github",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "no-fetch",
|
||||||
|
Usage: "Set this flag to prevent fetch of remote branches",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "no-amend-message",
|
||||||
|
Usage: "Set this flag to prevent automatic amendment of the commit message",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "no-push",
|
||||||
|
Usage: "Set this flag to prevent pushing the backport up to your fork",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "no-xdg-open",
|
||||||
|
Usage: "Set this flag to not use xdg-open to open the PR URL",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "continue",
|
||||||
|
Usage: "Set this flag to continue from a git cherry-pick that has broken",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cli.AppHelpTemplate = `NAME:
|
||||||
|
{{.Name}} - {{.Usage}}
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}} {{if .VisibleFlags}}[options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
{{if len .Authors}}
|
||||||
|
AUTHOR:
|
||||||
|
{{range .Authors}}{{ . }}{{end}}
|
||||||
|
{{end}}{{if .Commands}}
|
||||||
|
OPTIONS:
|
||||||
|
{{range .VisibleFlags}}{{.}}
|
||||||
|
{{end}}{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
app.Action = runBackport
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to backport: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runBackport(c *cli.Context) error {
|
||||||
|
ctx, cancel := installSignals()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
continuing := c.Bool("continue")
|
||||||
|
|
||||||
|
var pr string
|
||||||
|
|
||||||
|
version := c.String("version")
|
||||||
|
if version == "" && continuing {
|
||||||
|
// determine version from current branch name
|
||||||
|
var err error
|
||||||
|
pr, version, err = readCurrentBranch(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if version == "" {
|
||||||
|
version = readVersion()
|
||||||
|
}
|
||||||
|
if version == "" {
|
||||||
|
version = defaultVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream := c.String("upstream")
|
||||||
|
if upstream == "" {
|
||||||
|
upstream = "origin"
|
||||||
|
}
|
||||||
|
|
||||||
|
forkUser := c.String("fork-user")
|
||||||
|
remote := c.String("remote")
|
||||||
|
if remote == "" && !c.Bool("--no-push") {
|
||||||
|
var err error
|
||||||
|
remote, forkUser, err = determineRemote(ctx, forkUser)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upstreamReleaseBranch := c.String("release-branch")
|
||||||
|
if upstreamReleaseBranch == "" {
|
||||||
|
upstreamReleaseBranch = path.Join("release", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
localReleaseBranch := path.Join(upstream, upstreamReleaseBranch)
|
||||||
|
|
||||||
|
args := c.Args().Slice()
|
||||||
|
if len(args) == 0 && pr == "" {
|
||||||
|
return fmt.Errorf("no PR number provided\nProvide a PR number to backport")
|
||||||
|
} else if len(args) != 1 && pr == "" {
|
||||||
|
return fmt.Errorf("multiple PRs provided %v\nOnly a single PR can be backported at a time", args)
|
||||||
|
}
|
||||||
|
if pr == "" {
|
||||||
|
pr = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
backportBranch := c.String("backport-branch")
|
||||||
|
if backportBranch == "" {
|
||||||
|
backportBranch = "backport-" + pr + "-" + version
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch)
|
||||||
|
|
||||||
|
sha := c.String("cherry-pick")
|
||||||
|
if sha == "" {
|
||||||
|
var err error
|
||||||
|
sha, err = determineSHAforPR(ctx, pr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if sha == "" {
|
||||||
|
return fmt.Errorf("unable to determine sha for cherry-pick of %s", pr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bool("no-fetch") {
|
||||||
|
if err := fetchRemoteAndMain(ctx, upstream, upstreamReleaseBranch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !continuing {
|
||||||
|
if err := checkoutBackportBranch(ctx, backportBranch, localReleaseBranch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cherrypick(ctx, sha); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bool("no-amend-message") {
|
||||||
|
if err := amendCommit(ctx, pr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bool("no-push") {
|
||||||
|
url := "https://github.com/go-gitea/gitea/compare/" + upstreamReleaseBranch + "..." + forkUser + ":" + backportBranch
|
||||||
|
|
||||||
|
if err := gitPushUp(ctx, remote, backportBranch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.Bool("no-xdg-open") {
|
||||||
|
if err := xdgOpen(ctx, url); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("* Navigate to %s to open PR\n", url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func xdgOpen(ctx context.Context, url string) error {
|
||||||
|
fmt.Printf("* `xdg-open %s`\n", url)
|
||||||
|
out, err := exec.CommandContext(ctx, "xdg-open", url).Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s", string(out))
|
||||||
|
return fmt.Errorf("unable to xdg-open to %s: %w", url, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitPushUp(ctx context.Context, remote, backportBranch string) error {
|
||||||
|
fmt.Printf("* `git push -u %s %s`\n", remote, backportBranch)
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "push", "-u", remote, backportBranch).Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s", string(out))
|
||||||
|
return fmt.Errorf("unable to push up to %s: %w", remote, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func amendCommit(ctx context.Context, pr string) error {
|
||||||
|
fmt.Printf("* Amending commit to prepend `Backport #%s` to body\n", pr)
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "log", "-1", "--pretty=format:%B").Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s", string(out))
|
||||||
|
return fmt.Errorf("unable to get last log message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.SplitN(string(out), "\n", 2)
|
||||||
|
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return fmt.Errorf("unable to interpret log message:\n%s", string(out))
|
||||||
|
}
|
||||||
|
subject, body := parts[0], parts[1]
|
||||||
|
if !strings.HasSuffix(subject, " (#"+pr+")") {
|
||||||
|
subject = subject + " (#" + pr + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err = exec.CommandContext(ctx, "git", "commit", "--amend", "-m", subject+"\n\nBackport #"+pr+"\n"+body).Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s", string(out))
|
||||||
|
return fmt.Errorf("unable to amend last log message: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cherrypick(ctx context.Context, sha string) error {
|
||||||
|
// Check if a CHERRY_PICK_HEAD exists
|
||||||
|
if _, err := os.Stat(".git/CHERRY_PICK_HEAD"); err == nil {
|
||||||
|
// Assume that we are in the middle of cherry-pick - continue it
|
||||||
|
fmt.Println("* Attempting git cherry-pick --continue")
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "cherry-pick", "--continue").Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "git cherry-pick --continue failed:\n%s\n", string(out))
|
||||||
|
return fmt.Errorf("unable to continue cherry-pick: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("* Attempting git cherry-pick %s\n", sha)
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "cherry-pick", sha).Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "git cherry-pick %s failed:\n%s\n", sha, string(out))
|
||||||
|
return fmt.Errorf("git cherry-pick %s failed: %w", sha, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkoutBackportBranch(ctx context.Context, backportBranch, releaseBranch string) error {
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to check current branch %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBranch := strings.TrimSpace(string(out))
|
||||||
|
fmt.Printf("* Current branch is %s\n", currentBranch)
|
||||||
|
if currentBranch == backportBranch {
|
||||||
|
fmt.Printf("* Current branch is %s - not checking out\n", currentBranch)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := exec.CommandContext(ctx, "git", "rev-list", "-1", backportBranch).Output(); err == nil {
|
||||||
|
fmt.Printf("* Branch %s already exists. Checking it out...\n", backportBranch)
|
||||||
|
return exec.CommandContext(ctx, "git", "checkout", "-f", backportBranch).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("* `git checkout -b %s %s`\n", backportBranch, releaseBranch)
|
||||||
|
return exec.CommandContext(ctx, "git", "checkout", "-b", backportBranch, releaseBranch).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchRemoteAndMain(ctx context.Context, remote, releaseBranch string) error {
|
||||||
|
fmt.Printf("* `git fetch %s main`\n", remote)
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "fetch", remote, "main").Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(string(out))
|
||||||
|
return fmt.Errorf("unable to fetch %s from %s: %w", "main", remote, err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
fmt.Printf("* `git fetch %s %s`\n", remote, releaseBranch)
|
||||||
|
out, err = exec.CommandContext(ctx, "git", "fetch", remote, releaseBranch).Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(string(out))
|
||||||
|
return fmt.Errorf("unable to fetch %s from %s: %w", releaseBranch, remote, err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(out))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func determineRemote(ctx context.Context, forkUser string) (string, string, error) {
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "remote", "-v").Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to list git remotes:\n%s\n", string(out))
|
||||||
|
return "", "", fmt.Errorf("unable to determine forked remote: %w", err)
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(out), "\n")
|
||||||
|
for _, line := range lines {
|
||||||
|
fields := strings.Split(line, "\t")
|
||||||
|
name, remote := fields[0], fields[1]
|
||||||
|
// only look at pushers
|
||||||
|
if !strings.HasSuffix(remote, " (push)") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// only look at github.com pushes
|
||||||
|
if !strings.Contains(remote, "github.com") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// ignore go-gitea/gitea
|
||||||
|
if strings.Contains(remote, "go-gitea/gitea") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.Contains(remote, forkUser) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(remote, "git@github.com:") {
|
||||||
|
forkUser = strings.TrimPrefix(remote, "git@github.com:")
|
||||||
|
} else if strings.HasPrefix(remote, "https://github.com/") {
|
||||||
|
forkUser = strings.TrimPrefix(remote, "https://github.com/")
|
||||||
|
} else if strings.HasPrefix(remote, "https://www.github.com/") {
|
||||||
|
forkUser = strings.TrimPrefix(remote, "https://www.github.com/")
|
||||||
|
} else if forkUser == "" {
|
||||||
|
return "", "", fmt.Errorf("unable to extract forkUser from remote %s: %s", name, remote)
|
||||||
|
}
|
||||||
|
idx := strings.Index(forkUser, "/")
|
||||||
|
if idx >= 0 {
|
||||||
|
forkUser = forkUser[:idx]
|
||||||
|
}
|
||||||
|
return name, forkUser, nil
|
||||||
|
}
|
||||||
|
return "", "", fmt.Errorf("unable to find appropriate remote in:\n%s", string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCurrentBranch(ctx context.Context) (pr, version string, err error) {
|
||||||
|
out, err := exec.CommandContext(ctx, "git", "branch", "--show-current").Output()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read current git branch:\n%s\n", string(out))
|
||||||
|
return "", "", fmt.Errorf("unable to read current git branch: %w", err)
|
||||||
|
}
|
||||||
|
parts := strings.Split(strings.TrimSpace(string(out)), "-")
|
||||||
|
|
||||||
|
if len(parts) != 3 || parts[0] != "backport" {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to continue from git branch:\n%s\n", string(out))
|
||||||
|
return "", "", fmt.Errorf("unable to continue from git branch:\n%s", string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts[1], parts[2], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readVersion() string {
|
||||||
|
bs, err := os.ReadFile("docs/config.yaml")
|
||||||
|
if err != nil {
|
||||||
|
if err == os.ErrNotExist {
|
||||||
|
log.Println("`docs/config.yaml` not present")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type params struct {
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
type docConfig struct {
|
||||||
|
Params params
|
||||||
|
}
|
||||||
|
dc := &docConfig{}
|
||||||
|
if err := yaml.Unmarshal(bs, dc); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Unable to read `docs/config.yaml`: %v\n", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if dc.Params.Version == "" {
|
||||||
|
fmt.Fprintf(os.Stderr, "No version in `docs/config.yaml`")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
version := dc.Params.Version
|
||||||
|
if version[0] != 'v' {
|
||||||
|
version = "v" + version
|
||||||
|
}
|
||||||
|
|
||||||
|
split := strings.SplitN(version, ".", 3)
|
||||||
|
|
||||||
|
return strings.Join(split[:2], ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
|
||||||
|
prNum, err := strconv.Atoi(prStr)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := github.NewClient(http.DefaultClient)
|
||||||
|
|
||||||
|
pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pr.Merged == nil || !*pr.Merged {
|
||||||
|
return "", fmt.Errorf("PR #%d is not yet merged - cannot determine sha to backport", prNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pr.MergeCommitSHA != nil {
|
||||||
|
return *pr.MergeCommitSHA, 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
|
||||||
|
}
|
|
@ -1,35 +1,34 @@
|
||||||
Environment To Ini
|
Environment To Ini
|
||||||
==================
|
==================
|
||||||
|
|
||||||
This tool allows defining Forgejo's entire configuration via environment
|
Multiple docker users have requested that the Gitea docker is changed
|
||||||
variables, mostly geared towards usage in Docker.
|
to permit arbitrary configuration via environment variables.
|
||||||
|
|
||||||
Forgejo needs to use an INI file for configuration because the running
|
Gitea needs to use an ini file for configuration because the running
|
||||||
environment that starts the container may not be the same as the one used
|
environment that starts the docker may not be the same as that used
|
||||||
by the hooks. An INI file also gives a good default and means that
|
by the hooks. An ini file also gives a good default and means that
|
||||||
users do not have to provide the entire set of environment variables.
|
users do not have to completely provide a full environment.
|
||||||
|
|
||||||
With those caveats above, this command provides a generic way of
|
With those caveats above, this command provides a generic way of
|
||||||
converting suitably structured environment variables into any ini
|
converting suitably structured environment variables into any ini
|
||||||
value.
|
value.
|
||||||
|
|
||||||
When run, `environment-to-ini` will write the config files based on the
|
To use the command is very simple just run it and the default gitea
|
||||||
environment variables provided.
|
app.ini will be rewritten to take account of the variables provided,
|
||||||
Check with the `-h` flag for several options to alter this behaviour.
|
however there are various options to give slightly different
|
||||||
|
behavior and these can be interrogated with the `-h` option.
|
||||||
|
|
||||||
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME"
|
The environment variables should be of the form:
|
||||||
will be mapped to the ini section "[section_name]" and the key
|
|
||||||
"KEY_NAME" with the value as provided.
|
|
||||||
|
|
||||||
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE"
|
GITEA__SECTION_NAME__KEY_NAME
|
||||||
will be mapped to the ini section "[section_name]" and the key
|
|
||||||
"KEY_NAME" with the value loaded from the specified file.
|
Note, SECTION_NAME in the notation above is case-insensitive.
|
||||||
|
|
||||||
Environment variables are usually restricted to a reduced character
|
Environment variables are usually restricted to a reduced character
|
||||||
set "0-9A-Z_" - in order to allow the setting of sections with
|
set "0-9A-Z_" - in order to allow the setting of sections with
|
||||||
characters outside of that set, they should be escaped as following:
|
characters outside of that set, they should be escaped as following:
|
||||||
"_0X2E_" for ".". The entire section and key names can be escaped as
|
"_0X2E_" for "." and "_0X2D_" for "-". The entire section and key names
|
||||||
a UTF8 byte string if necessary. E.g. to configure:
|
can be escaped as a UTF8 byte string if necessary. E.g. to configure:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
|
@ -39,8 +38,8 @@ a UTF8 byte string if necessary. E.g. to configure:
|
||||||
...
|
...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false"
|
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
|
||||||
and "FORGEJO__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
|
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
|
||||||
on the configuration cheat sheet.
|
on the configuration cheat sheet.
|
||||||
|
|
||||||
To build locally, run:
|
To build locally, run:
|
||||||
|
|
|
@ -4,17 +4,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/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 forgejo configuration
|
app.Description = `As a helper to allow docker users to update the forgejo 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(ctx 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{
|
||||||
|
|
|
@ -408,7 +408,7 @@ local addIssueLabelsOverrides(labels) =
|
||||||
regex: '',
|
regex: '',
|
||||||
type: 'query',
|
type: 'query',
|
||||||
multi: true,
|
multi: true,
|
||||||
allValue: '.+',
|
allValue: '.+'
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.addTemplate(
|
.addTemplate(
|
||||||
|
@ -423,7 +423,7 @@ local addIssueLabelsOverrides(labels) =
|
||||||
regex: '',
|
regex: '',
|
||||||
type: 'query',
|
type: 'query',
|
||||||
multi: true,
|
multi: true,
|
||||||
allValue: '.+',
|
allValue: '.+'
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.addTemplate(
|
.addTemplate(
|
||||||
|
|
|
@ -183,7 +183,7 @@ RUN_USER = ; git
|
||||||
;;
|
;;
|
||||||
;; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections,
|
;; For the built-in SSH server, choose the key exchange algorithms to support for SSH connections,
|
||||||
;; for system SSH this setting has no effect
|
;; for system SSH this setting has no effect
|
||||||
;SSH_SERVER_KEY_EXCHANGES = mlkem768x25519-sha256, curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
|
;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 the built-in SSH server, choose the MACs to support for SSH connections,
|
||||||
;; for system SSH this setting has no effect
|
;; for system SSH this setting has no effect
|
||||||
|
@ -1025,10 +1025,6 @@ LEVEL = Info
|
||||||
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
|
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
|
||||||
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
|
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
|
||||||
;;
|
;;
|
||||||
;; Comma separated list of default mirror repo units.
|
|
||||||
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
|
|
||||||
;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages
|
|
||||||
;;
|
|
||||||
;; Prefix archive files by placing them in a directory named after the repository
|
;; Prefix archive files by placing them in a directory named after the repository
|
||||||
;PREFIX_ARCHIVE_FILES = true
|
;PREFIX_ARCHIVE_FILES = true
|
||||||
;;
|
;;
|
||||||
|
@ -1135,6 +1131,9 @@ LEVEL = Info
|
||||||
;; Add co-authored-by and co-committed-by trailers if committer does not match author
|
;; Add co-authored-by and co-committed-by trailers if committer does not match author
|
||||||
;ADD_CO_COMMITTER_TRAILERS = true
|
;ADD_CO_COMMITTER_TRAILERS = true
|
||||||
;;
|
;;
|
||||||
|
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
|
||||||
|
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
||||||
|
;;
|
||||||
;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
||||||
;RETARGET_CHILDREN_ON_MERGE = true
|
;RETARGET_CHILDREN_ON_MERGE = true
|
||||||
|
|
||||||
|
@ -1164,13 +1163,9 @@ LEVEL = Info
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; Signing format that Forgejo should use, openpgp uses GPG and ssh uses OpenSSH.
|
|
||||||
;FORMAT = openpgp
|
|
||||||
;;
|
|
||||||
;; GPG 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
|
||||||
;; 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
|
||||||
;; If `FORMAT` is set to **ssh** this should be set to an absolute path to an public OpenSSH key.
|
|
||||||
;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.
|
;; If a SIGNING_KEY ID is provided and is not set to default, use the provided Name and Email address as the signer.
|
||||||
|
@ -1576,15 +1571,6 @@ LEVEL = Info
|
||||||
;; - manage_gpg_keys: a user cannot configure gpg keys
|
;; - manage_gpg_keys: a user cannot configure gpg keys
|
||||||
;;EXTERNAL_USER_DISABLE_FEATURES =
|
;;EXTERNAL_USER_DISABLE_FEATURES =
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;[moderation]
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; When true enables moderation capabilities; default is false.
|
|
||||||
;; If enabled it will be possible for users to report abusive content (new actions are added in the UI and /report_abuse route will be enabled) and a new Moderation section will be added to Admin settings where the reports can be reviewed.
|
|
||||||
;ENABLED = false
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;[openid]
|
;[openid]
|
||||||
|
@ -2454,7 +2440,7 @@ LEVEL = Info
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
|
;; Set the maximum number of characters in a mermaid source. (Set to -1 to disable limits)
|
||||||
;MERMAID_MAX_SOURCE_CHARACTERS = 50000
|
;MERMAID_MAX_SOURCE_CHARACTERS = 5000
|
||||||
;; Set the maximum number of lines allowed for a filepreview. (Set to -1 to disable limits; set to 0 to disable the feature)
|
;; Set the maximum number of lines allowed for a filepreview. (Set to -1 to disable limits; set to 0 to disable the feature)
|
||||||
;FILEPREVIEW_MAX_LINES = 50
|
;FILEPREVIEW_MAX_LINES = 50
|
||||||
|
|
||||||
|
|
|
@ -31,21 +31,6 @@ if [ -e /data/ssh/ssh_host_ecdsa_cert ]; then
|
||||||
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"}
|
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_cert"}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# In case someone wants to sign the `{keyname}.pub` key by `ssh-keygen -s ca -I identity ...` to
|
|
||||||
# make use of the ssh-key certificate authority feature (see ssh-keygen CERTIFICATES section),
|
|
||||||
# the generated key file name is `{keyname}-cert.pub`
|
|
||||||
if [ -e /data/ssh/ssh_host_ed25519_key-cert.pub ]; then
|
|
||||||
SSH_ED25519_CERT=${SSH_ED25519_CERT:-"/data/ssh/ssh_host_ed25519_key-cert.pub"}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e /data/ssh/ssh_host_rsa_key-cert.pub ]; then
|
|
||||||
SSH_RSA_CERT=${SSH_RSA_CERT:-"/data/ssh/ssh_host_rsa_key-cert.pub"}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e /data/ssh/ssh_host_ecdsa_key-cert.pub ]; then
|
|
||||||
SSH_ECDSA_CERT=${SSH_ECDSA_CERT:-"/data/ssh/ssh_host_ecdsa_key-cert.pub"}
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d /etc/ssh ]; then
|
if [ -d /etc/ssh ]; then
|
||||||
SSH_PORT=${SSH_PORT:-"22"} \
|
SSH_PORT=${SSH_PORT:-"22"} \
|
||||||
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \
|
SSH_LISTEN_PORT=${SSH_LISTEN_PORT:-"${SSH_PORT}"} \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments';
|
import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments';
|
||||||
import stylisticEslintPlugin from '@stylistic/eslint-plugin';
|
import stylisticEslintPluginJs from '@stylistic/eslint-plugin-js';
|
||||||
import vitest from '@vitest/eslint-plugin';
|
import vitest from '@vitest/eslint-plugin';
|
||||||
import arrayFunc from 'eslint-plugin-array-func';
|
import arrayFunc from 'eslint-plugin-array-func';
|
||||||
import eslintPluginImportX from 'eslint-plugin-import-x';
|
import eslintPluginImportX from 'eslint-plugin-import-x';
|
||||||
|
@ -26,7 +26,7 @@ export default tseslint.config(
|
||||||
{
|
{
|
||||||
plugins: {
|
plugins: {
|
||||||
'@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments,
|
'@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments,
|
||||||
'@stylistic': stylisticEslintPlugin,
|
'@stylistic/js': stylisticEslintPluginJs,
|
||||||
'@vitest': vitest,
|
'@vitest': vitest,
|
||||||
'array-func': arrayFunc,
|
'array-func': arrayFunc,
|
||||||
'no-jquery': noJquery,
|
'no-jquery': noJquery,
|
||||||
|
@ -69,62 +69,62 @@ export default tseslint.config(
|
||||||
'@eslint-community/eslint-comments/no-unused-enable': [2],
|
'@eslint-community/eslint-comments/no-unused-enable': [2],
|
||||||
'@eslint-community/eslint-comments/no-use': [0],
|
'@eslint-community/eslint-comments/no-use': [0],
|
||||||
'@eslint-community/eslint-comments/require-description': [0],
|
'@eslint-community/eslint-comments/require-description': [0],
|
||||||
'@stylistic/array-bracket-newline': [0],
|
'@stylistic/js/array-bracket-newline': [0],
|
||||||
'@stylistic/array-bracket-spacing': [2, 'never'],
|
'@stylistic/js/array-bracket-spacing': [2, 'never'],
|
||||||
'@stylistic/array-element-newline': [0],
|
'@stylistic/js/array-element-newline': [0],
|
||||||
'@stylistic/arrow-parens': [2, 'always'],
|
'@stylistic/js/arrow-parens': [2, 'always'],
|
||||||
|
|
||||||
'@stylistic/arrow-spacing': [2, {
|
'@stylistic/js/arrow-spacing': [2, {
|
||||||
before: true,
|
before: true,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/block-spacing': [0],
|
'@stylistic/js/block-spacing': [0],
|
||||||
|
|
||||||
'@stylistic/brace-style': [2, '1tbs', {
|
'@stylistic/js/brace-style': [2, '1tbs', {
|
||||||
allowSingleLine: true,
|
allowSingleLine: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/comma-dangle': [2, 'always-multiline'],
|
'@stylistic/js/comma-dangle': [2, 'always-multiline'],
|
||||||
|
|
||||||
'@stylistic/comma-spacing': [2, {
|
'@stylistic/js/comma-spacing': [2, {
|
||||||
before: false,
|
before: false,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/comma-style': [2, 'last'],
|
'@stylistic/js/comma-style': [2, 'last'],
|
||||||
'@stylistic/computed-property-spacing': [2, 'never'],
|
'@stylistic/js/computed-property-spacing': [2, 'never'],
|
||||||
'@stylistic/dot-location': [2, 'property'],
|
'@stylistic/js/dot-location': [2, 'property'],
|
||||||
'@stylistic/eol-last': [2],
|
'@stylistic/js/eol-last': [2],
|
||||||
'@stylistic/function-call-spacing': [2, 'never'],
|
'@stylistic/js/function-call-spacing': [2, 'never'],
|
||||||
'@stylistic/function-call-argument-newline': [0],
|
'@stylistic/js/function-call-argument-newline': [0],
|
||||||
'@stylistic/function-paren-newline': [0],
|
'@stylistic/js/function-paren-newline': [0],
|
||||||
'@stylistic/generator-star-spacing': [0],
|
'@stylistic/js/generator-star-spacing': [0],
|
||||||
'@stylistic/implicit-arrow-linebreak': [0],
|
'@stylistic/js/implicit-arrow-linebreak': [0],
|
||||||
|
|
||||||
'@stylistic/indent': [2, 2, {
|
'@stylistic/js/indent': [2, 2, {
|
||||||
ignoreComments: true,
|
ignoreComments: true,
|
||||||
SwitchCase: 1,
|
SwitchCase: 1,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/key-spacing': [2],
|
'@stylistic/js/key-spacing': [2],
|
||||||
'@stylistic/keyword-spacing': [2],
|
'@stylistic/js/keyword-spacing': [2],
|
||||||
'@stylistic/linebreak-style': [2, 'unix'],
|
'@stylistic/js/linebreak-style': [2, 'unix'],
|
||||||
'@stylistic/lines-around-comment': [0],
|
'@stylistic/js/lines-around-comment': [0],
|
||||||
'@stylistic/lines-between-class-members': [0],
|
'@stylistic/js/lines-between-class-members': [0],
|
||||||
'@stylistic/max-len': [0],
|
'@stylistic/js/max-len': [0],
|
||||||
'@stylistic/max-statements-per-line': [0],
|
'@stylistic/js/max-statements-per-line': [0],
|
||||||
'@stylistic/multiline-ternary': [0],
|
'@stylistic/js/multiline-ternary': [0],
|
||||||
'@stylistic/new-parens': [2],
|
'@stylistic/js/new-parens': [2],
|
||||||
'@stylistic/newline-per-chained-call': [0],
|
'@stylistic/js/newline-per-chained-call': [0],
|
||||||
'@stylistic/no-confusing-arrow': [0],
|
'@stylistic/js/no-confusing-arrow': [0],
|
||||||
'@stylistic/no-extra-parens': [0],
|
'@stylistic/js/no-extra-parens': [0],
|
||||||
'@stylistic/no-extra-semi': [2],
|
'@stylistic/js/no-extra-semi': [2],
|
||||||
'@stylistic/no-floating-decimal': [0],
|
'@stylistic/js/no-floating-decimal': [0],
|
||||||
'@stylistic/no-mixed-operators': [0],
|
'@stylistic/js/no-mixed-operators': [0],
|
||||||
'@stylistic/no-mixed-spaces-and-tabs': [2],
|
'@stylistic/js/no-mixed-spaces-and-tabs': [2],
|
||||||
|
|
||||||
'@stylistic/no-multi-spaces': [2, {
|
'@stylistic/js/no-multi-spaces': [2, {
|
||||||
ignoreEOLComments: true,
|
ignoreEOLComments: true,
|
||||||
|
|
||||||
exceptions: {
|
exceptions: {
|
||||||
|
@ -132,60 +132,60 @@ export default tseslint.config(
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/no-multiple-empty-lines': [2, {
|
'@stylistic/js/no-multiple-empty-lines': [2, {
|
||||||
max: 1,
|
max: 1,
|
||||||
maxEOF: 0,
|
maxEOF: 0,
|
||||||
maxBOF: 0,
|
maxBOF: 0,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/no-tabs': [2],
|
'@stylistic/js/no-tabs': [2],
|
||||||
'@stylistic/no-trailing-spaces': [2],
|
'@stylistic/js/no-trailing-spaces': [2],
|
||||||
'@stylistic/no-whitespace-before-property': [2],
|
'@stylistic/js/no-whitespace-before-property': [2],
|
||||||
'@stylistic/nonblock-statement-body-position': [2],
|
'@stylistic/js/nonblock-statement-body-position': [2],
|
||||||
'@stylistic/object-curly-newline': [0],
|
'@stylistic/js/object-curly-newline': [0],
|
||||||
'@stylistic/object-curly-spacing': [2, 'never'],
|
'@stylistic/js/object-curly-spacing': [2, 'never'],
|
||||||
'@stylistic/object-property-newline': [0],
|
'@stylistic/js/object-property-newline': [0],
|
||||||
'@stylistic/one-var-declaration-per-line': [0],
|
'@stylistic/js/one-var-declaration-per-line': [0],
|
||||||
'@stylistic/operator-linebreak': [2, 'after'],
|
'@stylistic/js/operator-linebreak': [2, 'after'],
|
||||||
'@stylistic/padded-blocks': [2, 'never'],
|
'@stylistic/js/padded-blocks': [2, 'never'],
|
||||||
'@stylistic/padding-line-between-statements': [0],
|
'@stylistic/js/padding-line-between-statements': [0],
|
||||||
'@stylistic/quote-props': [0],
|
'@stylistic/js/quote-props': [0],
|
||||||
|
|
||||||
'@stylistic/quotes': [2, 'single', {
|
'@stylistic/js/quotes': [2, 'single', {
|
||||||
avoidEscape: true,
|
avoidEscape: true,
|
||||||
allowTemplateLiterals: true,
|
allowTemplateLiterals: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/rest-spread-spacing': [2, 'never'],
|
'@stylistic/js/rest-spread-spacing': [2, 'never'],
|
||||||
|
|
||||||
'@stylistic/semi': [2, 'always', {
|
'@stylistic/js/semi': [2, 'always', {
|
||||||
omitLastInOneLineBlock: true,
|
omitLastInOneLineBlock: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/semi-spacing': [2, {
|
'@stylistic/js/semi-spacing': [2, {
|
||||||
before: false,
|
before: false,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/semi-style': [2, 'last'],
|
'@stylistic/js/semi-style': [2, 'last'],
|
||||||
'@stylistic/space-before-blocks': [2, 'always'],
|
'@stylistic/js/space-before-blocks': [2, 'always'],
|
||||||
|
|
||||||
'@stylistic/space-before-function-paren': [2, {
|
'@stylistic/js/space-before-function-paren': [2, {
|
||||||
anonymous: 'ignore',
|
anonymous: 'ignore',
|
||||||
named: 'never',
|
named: 'never',
|
||||||
asyncArrow: 'always',
|
asyncArrow: 'always',
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/space-in-parens': [2, 'never'],
|
'@stylistic/js/space-in-parens': [2, 'never'],
|
||||||
'@stylistic/space-infix-ops': [2],
|
'@stylistic/js/space-infix-ops': [2],
|
||||||
'@stylistic/space-unary-ops': [2],
|
'@stylistic/js/space-unary-ops': [2],
|
||||||
'@stylistic/spaced-comment': [2, 'always'],
|
'@stylistic/js/spaced-comment': [2, 'always'],
|
||||||
'@stylistic/switch-colon-spacing': [2],
|
'@stylistic/js/switch-colon-spacing': [2],
|
||||||
'@stylistic/template-curly-spacing': [2, 'never'],
|
'@stylistic/js/template-curly-spacing': [2, 'never'],
|
||||||
'@stylistic/template-tag-spacing': [2, 'never'],
|
'@stylistic/js/template-tag-spacing': [2, 'never'],
|
||||||
'@stylistic/wrap-iife': [2, 'inside'],
|
'@stylistic/js/wrap-iife': [2, 'inside'],
|
||||||
'@stylistic/wrap-regex': [0],
|
'@stylistic/js/wrap-regex': [0],
|
||||||
'@stylistic/yield-star-spacing': [2, 'after'],
|
'@stylistic/js/yield-star-spacing': [2, 'after'],
|
||||||
'accessor-pairs': [2],
|
'accessor-pairs': [2],
|
||||||
|
|
||||||
'array-callback-return': [2, {
|
'array-callback-return': [2, {
|
||||||
|
@ -318,9 +318,8 @@ export default tseslint.config(
|
||||||
'no-jquery/no-data': [0],
|
'no-jquery/no-data': [0],
|
||||||
'no-jquery/no-deferred': [2],
|
'no-jquery/no-deferred': [2],
|
||||||
'no-jquery/no-delegate': [2],
|
'no-jquery/no-delegate': [2],
|
||||||
'no-jquery/no-done-fail': [2],
|
|
||||||
'no-jquery/no-each-collection': [0],
|
'no-jquery/no-each-collection': [0],
|
||||||
'no-jquery/no-each-util': [2],
|
'no-jquery/no-each-util': [0],
|
||||||
'no-jquery/no-each': [0],
|
'no-jquery/no-each': [0],
|
||||||
'no-jquery/no-error-shorthand': [2],
|
'no-jquery/no-error-shorthand': [2],
|
||||||
'no-jquery/no-error': [2],
|
'no-jquery/no-error': [2],
|
||||||
|
@ -332,7 +331,6 @@ export default tseslint.config(
|
||||||
'no-jquery/no-find-collection': [0],
|
'no-jquery/no-find-collection': [0],
|
||||||
'no-jquery/no-find-util': [2],
|
'no-jquery/no-find-util': [2],
|
||||||
'no-jquery/no-find': [0],
|
'no-jquery/no-find': [0],
|
||||||
'no-jquery/no-fx': [2],
|
|
||||||
'no-jquery/no-fx-interval': [2],
|
'no-jquery/no-fx-interval': [2],
|
||||||
'no-jquery/no-global-eval': [2],
|
'no-jquery/no-global-eval': [2],
|
||||||
'no-jquery/no-global-selector': [0],
|
'no-jquery/no-global-selector': [0],
|
||||||
|
@ -352,7 +350,7 @@ export default tseslint.config(
|
||||||
'no-jquery/no-live': [2],
|
'no-jquery/no-live': [2],
|
||||||
'no-jquery/no-load-shorthand': [2],
|
'no-jquery/no-load-shorthand': [2],
|
||||||
'no-jquery/no-load': [2],
|
'no-jquery/no-load': [2],
|
||||||
'no-jquery/no-map-collection': [2],
|
'no-jquery/no-map-collection': [0],
|
||||||
'no-jquery/no-map-util': [2],
|
'no-jquery/no-map-util': [2],
|
||||||
'no-jquery/no-map': [2],
|
'no-jquery/no-map': [2],
|
||||||
'no-jquery/no-merge': [2],
|
'no-jquery/no-merge': [2],
|
||||||
|
@ -376,12 +374,12 @@ export default tseslint.config(
|
||||||
'no-jquery/no-selector-prop': [2],
|
'no-jquery/no-selector-prop': [2],
|
||||||
'no-jquery/no-serialize': [2],
|
'no-jquery/no-serialize': [2],
|
||||||
'no-jquery/no-size': [2],
|
'no-jquery/no-size': [2],
|
||||||
'no-jquery/no-sizzle': [2],
|
'no-jquery/no-sizzle': [0],
|
||||||
'no-jquery/no-slide': [2],
|
'no-jquery/no-slide': [2],
|
||||||
'no-jquery/no-sub': [2],
|
'no-jquery/no-sub': [2],
|
||||||
'no-jquery/no-support': [2],
|
'no-jquery/no-support': [2],
|
||||||
'no-jquery/no-text': [0],
|
'no-jquery/no-text': [0],
|
||||||
'no-jquery/no-trigger': [2],
|
'no-jquery/no-trigger': [0],
|
||||||
'no-jquery/no-trim': [2],
|
'no-jquery/no-trim': [2],
|
||||||
'no-jquery/no-type': [2],
|
'no-jquery/no-type': [2],
|
||||||
'no-jquery/no-unique': [2],
|
'no-jquery/no-unique': [2],
|
||||||
|
@ -746,6 +744,7 @@ export default tseslint.config(
|
||||||
'unicorn/no-array-callback-reference': [0],
|
'unicorn/no-array-callback-reference': [0],
|
||||||
'unicorn/no-array-for-each': [2],
|
'unicorn/no-array-for-each': [2],
|
||||||
'unicorn/no-array-method-this-argument': [2],
|
'unicorn/no-array-method-this-argument': [2],
|
||||||
|
'unicorn/no-array-push-push': [2],
|
||||||
'unicorn/no-array-reduce': [2],
|
'unicorn/no-array-reduce': [2],
|
||||||
'unicorn/no-await-expression-member': [0],
|
'unicorn/no-await-expression-member': [0],
|
||||||
'unicorn/no-await-in-promise-methods': [2],
|
'unicorn/no-await-in-promise-methods': [2],
|
||||||
|
@ -758,6 +757,7 @@ export default tseslint.config(
|
||||||
'unicorn/no-invalid-fetch-options': [2],
|
'unicorn/no-invalid-fetch-options': [2],
|
||||||
'unicorn/no-invalid-remove-event-listener': [2],
|
'unicorn/no-invalid-remove-event-listener': [2],
|
||||||
'unicorn/no-keyword-prefix': [0],
|
'unicorn/no-keyword-prefix': [0],
|
||||||
|
'unicorn/no-length-as-slice-end': [2],
|
||||||
'unicorn/no-lonely-if': [2],
|
'unicorn/no-lonely-if': [2],
|
||||||
'unicorn/no-magic-array-flat-depth': [0],
|
'unicorn/no-magic-array-flat-depth': [0],
|
||||||
'unicorn/no-named-default': [2],
|
'unicorn/no-named-default': [2],
|
||||||
|
@ -774,11 +774,8 @@ export default tseslint.config(
|
||||||
'unicorn/no-thenable': [2],
|
'unicorn/no-thenable': [2],
|
||||||
'unicorn/no-this-assignment': [2],
|
'unicorn/no-this-assignment': [2],
|
||||||
'unicorn/no-typeof-undefined': [2],
|
'unicorn/no-typeof-undefined': [2],
|
||||||
'unicorn/no-unnecessary-array-flat-depth': [2],
|
|
||||||
'unicorn/no-unnecessary-array-splice-count': [2],
|
|
||||||
'unicorn/no-unnecessary-await': [2],
|
'unicorn/no-unnecessary-await': [2],
|
||||||
'unicorn/no-unnecessary-polyfills': [2],
|
'unicorn/no-unnecessary-polyfills': [2],
|
||||||
'unicorn/no-unnecessary-slice-end': [2],
|
|
||||||
'unicorn/no-unreadable-array-destructuring': [0],
|
'unicorn/no-unreadable-array-destructuring': [0],
|
||||||
'unicorn/no-unreadable-iife': [2],
|
'unicorn/no-unreadable-iife': [2],
|
||||||
'unicorn/no-unused-properties': [2],
|
'unicorn/no-unused-properties': [2],
|
||||||
|
@ -809,7 +806,6 @@ export default tseslint.config(
|
||||||
'unicorn/prefer-event-target': [2],
|
'unicorn/prefer-event-target': [2],
|
||||||
'unicorn/prefer-export-from': [0],
|
'unicorn/prefer-export-from': [0],
|
||||||
'unicorn/prefer-global-this': [0],
|
'unicorn/prefer-global-this': [0],
|
||||||
'unicorn/prefer-import-meta-properties': [2],
|
|
||||||
'unicorn/prefer-includes': [2],
|
'unicorn/prefer-includes': [2],
|
||||||
'unicorn/prefer-json-parse-buffer': [0],
|
'unicorn/prefer-json-parse-buffer': [0],
|
||||||
'unicorn/prefer-keyboard-event-key': [2],
|
'unicorn/prefer-keyboard-event-key': [2],
|
||||||
|
@ -832,7 +828,6 @@ export default tseslint.config(
|
||||||
'unicorn/prefer-regexp-test': [2],
|
'unicorn/prefer-regexp-test': [2],
|
||||||
'unicorn/prefer-set-has': [0],
|
'unicorn/prefer-set-has': [0],
|
||||||
'unicorn/prefer-set-size': [2],
|
'unicorn/prefer-set-size': [2],
|
||||||
'unicorn/prefer-single-call': [2],
|
|
||||||
'unicorn/prefer-spread': [0],
|
'unicorn/prefer-spread': [0],
|
||||||
'unicorn/prefer-string-raw': [0],
|
'unicorn/prefer-string-raw': [0],
|
||||||
'unicorn/prefer-string-replace-all': [0],
|
'unicorn/prefer-string-replace-all': [0],
|
||||||
|
|
6
flake.lock
generated
6
flake.lock
generated
|
@ -20,11 +20,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1749285348,
|
"lastModified": 1733392399,
|
||||||
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
|
"narHash": "sha256-kEsTJTUQfQFIJOcLYFt/RvNxIK653ZkTBIs4DG+cBns=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
|
"rev": "d0797a04b81caeae77bcff10a9dde78bc17f5661",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
35
flake.nix
35
flake.nix
|
@ -3,20 +3,39 @@
|
||||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
outputs =
|
outputs = {
|
||||||
{
|
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
flake-utils.lib.eachDefaultSystem (
|
flake-utils.lib.eachDefaultSystem (
|
||||||
system:
|
system: let
|
||||||
let
|
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in
|
in {
|
||||||
{
|
devShells.default = pkgs.mkShell {
|
||||||
devShells.default = import ./shell.nix { inherit pkgs; };
|
buildInputs = with pkgs; [
|
||||||
formatter = pkgs.nixfmt-rfc-style;
|
# generic
|
||||||
|
git
|
||||||
|
git-lfs
|
||||||
|
gnumake
|
||||||
|
gnused
|
||||||
|
gnutar
|
||||||
|
gzip
|
||||||
|
|
||||||
|
# frontend
|
||||||
|
nodejs_20
|
||||||
|
|
||||||
|
# linting
|
||||||
|
python312
|
||||||
|
poetry
|
||||||
|
|
||||||
|
# backend
|
||||||
|
gofumpt
|
||||||
|
sqlite
|
||||||
|
go
|
||||||
|
gopls
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
126
go.mod
126
go.mod
|
@ -2,33 +2,32 @@ module forgejo.org
|
||||||
|
|
||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
toolchain go1.24.4
|
toolchain go1.24.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.forgejo.org/f3/gof3/v3 v3.11.0
|
code.forgejo.org/f3/gof3/v3 v3.10.6
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251
|
||||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0
|
|
||||||
code.forgejo.org/forgejo/levelqueue v1.0.0
|
code.forgejo.org/forgejo/levelqueue v1.0.0
|
||||||
code.forgejo.org/forgejo/reply v1.0.2
|
code.forgejo.org/forgejo/reply v1.0.2
|
||||||
code.forgejo.org/go-chi/binding v1.0.1
|
code.forgejo.org/go-chi/binding v1.0.0
|
||||||
code.forgejo.org/go-chi/cache v1.0.1
|
code.forgejo.org/go-chi/cache v1.0.0
|
||||||
code.forgejo.org/go-chi/captcha v1.0.2
|
code.forgejo.org/go-chi/captcha v1.0.1
|
||||||
code.forgejo.org/go-chi/session v1.0.2
|
code.forgejo.org/go-chi/session v1.0.1
|
||||||
code.gitea.io/actions-proto-go v0.4.0
|
code.gitea.io/actions-proto-go v0.4.0
|
||||||
code.gitea.io/sdk/gitea v0.21.0
|
code.gitea.io/sdk/gitea v0.20.0
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||||
connectrpc.com/connect v1.18.1
|
connectrpc.com/connect v1.17.0
|
||||||
github.com/42wim/httpsig v1.2.3
|
github.com/42wim/httpsig v1.2.2
|
||||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
|
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||||
github.com/ProtonMail/go-crypto v1.3.0
|
github.com/ProtonMail/go-crypto v1.1.6
|
||||||
github.com/PuerkitoBio/goquery v1.10.3
|
github.com/PuerkitoBio/goquery v1.10.2
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2
|
||||||
github.com/alecthomas/chroma/v2 v2.18.0
|
github.com/alecthomas/chroma/v2 v2.15.0
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb
|
||||||
github.com/blevesearch/bleve/v2 v2.5.2
|
github.com/blevesearch/bleve/v2 v2.5.2
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.16.8
|
github.com/buildkite/terminal-to-html/v3 v3.16.8
|
||||||
github.com/caddyserver/certmagic v0.23.0
|
github.com/caddyserver/certmagic v0.22.2
|
||||||
github.com/chi-middleware/proxy v1.1.1
|
github.com/chi-middleware/proxy v1.1.1
|
||||||
github.com/djherbis/buffer v1.2.0
|
github.com/djherbis/buffer v1.2.0
|
||||||
github.com/djherbis/nio/v3 v3.0.1
|
github.com/djherbis/nio/v3 v3.0.1
|
||||||
|
@ -37,37 +36,37 @@ require (
|
||||||
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3
|
github.com/editorconfig/editorconfig-core-go/v2 v2.6.3
|
||||||
github.com/emersion/go-imap v1.2.1
|
github.com/emersion/go-imap v1.2.1
|
||||||
github.com/felixge/fgprof v0.9.5
|
github.com/felixge/fgprof v0.9.5
|
||||||
github.com/fsnotify/fsnotify v1.9.0
|
github.com/fsnotify/fsnotify v1.8.0
|
||||||
github.com/gliderlabs/ssh v0.3.8
|
github.com/gliderlabs/ssh v0.3.8
|
||||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||||
github.com/go-chi/chi/v5 v5.2.2
|
github.com/go-chi/chi/v5 v5.2.0
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-co-op/gocron v1.37.0
|
github.com/go-co-op/gocron v1.37.0
|
||||||
github.com/go-enry/go-enry/v2 v2.9.2
|
github.com/go-enry/go-enry/v2 v2.9.2
|
||||||
github.com/go-git/go-git/v5 v5.13.2
|
github.com/go-git/go-git/v5 v5.13.2
|
||||||
github.com/go-ldap/ldap/v3 v3.4.6
|
github.com/go-ldap/ldap/v3 v3.4.6
|
||||||
github.com/go-openapi/spec v0.21.0
|
github.com/go-openapi/spec v0.20.14
|
||||||
github.com/go-sql-driver/mysql v1.9.3
|
github.com/go-sql-driver/mysql v1.9.1
|
||||||
github.com/go-webauthn/webauthn v0.13.0
|
github.com/go-webauthn/webauthn v0.12.2
|
||||||
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
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/google/go-github/v64 v64.0.0
|
github.com/google/go-github/v64 v64.0.0
|
||||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5
|
github.com/google/pprof v0.0.0-20241017200806-017d972448fc
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/feeds v1.2.0
|
github.com/gorilla/feeds v1.2.0
|
||||||
github.com/gorilla/sessions v1.4.0
|
github.com/gorilla/sessions v1.4.0
|
||||||
github.com/hashicorp/go-version v1.7.0
|
github.com/hashicorp/go-version v1.7.0
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7
|
github.com/hashicorp/golang-lru/v2 v2.0.7
|
||||||
github.com/huandu/xstrings v1.5.0
|
github.com/huandu/xstrings v1.5.0
|
||||||
github.com/inbucket/html2text v0.9.0
|
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
|
||||||
github.com/jhillyerd/enmime/v2 v2.2.0
|
github.com/jhillyerd/enmime/v2 v2.1.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
github.com/klauspost/compress v1.18.0
|
github.com/klauspost/compress v1.17.11
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10
|
github.com/klauspost/cpuid/v2 v2.2.10
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/markbates/goth v1.80.0
|
github.com/markbates/goth v1.80.0
|
||||||
|
@ -76,36 +75,38 @@ require (
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0
|
github.com/meilisearch/meilisearch-go v0.31.0
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/minio/minio-go/v7 v7.0.94
|
github.com/minio/minio-go/v7 v7.0.88
|
||||||
github.com/msteinert/pam/v2 v2.1.0
|
github.com/msteinert/pam/v2 v2.1.0
|
||||||
github.com/nektos/act v0.2.52
|
github.com/nektos/act v0.2.52
|
||||||
github.com/niklasfasching/go-org v1.9.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
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.21.1
|
github.com/prometheus/client_golang v1.21.1
|
||||||
github.com/redis/go-redis/v9 v9.8.0
|
github.com/redis/go-redis/v9 v9.7.3
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
||||||
github.com/sergi/go-diff v1.4.0
|
github.com/sassoftware/go-rpmutils v0.4.0
|
||||||
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||||
|
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92
|
||||||
github.com/stretchr/testify v1.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/ulikunitz/xz v0.5.12
|
github.com/ulikunitz/xz v0.5.12
|
||||||
github.com/urfave/cli/v3 v3.3.3
|
github.com/urfave/cli/v2 v2.27.6
|
||||||
github.com/valyala/fastjson v1.6.4
|
github.com/valyala/fastjson v1.6.4
|
||||||
github.com/yohcop/openid-go v1.0.1
|
github.com/yohcop/openid-go v1.0.1
|
||||||
github.com/yuin/goldmark v1.7.12
|
github.com/yuin/goldmark v1.7.8
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
gitlab.com/gitlab-org/api/client-go v0.130.1
|
gitlab.com/gitlab-org/api/client-go v0.126.0
|
||||||
go.uber.org/mock v0.5.2
|
go.uber.org/mock v0.5.0
|
||||||
golang.org/x/crypto v0.39.0
|
golang.org/x/crypto v0.36.0
|
||||||
golang.org/x/image v0.27.0
|
golang.org/x/image v0.25.0
|
||||||
golang.org/x/net v0.41.0
|
golang.org/x/net v0.38.0
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.28.0
|
||||||
golang.org/x/sync v0.15.0
|
golang.org/x/sync v0.12.0
|
||||||
golang.org/x/sys v0.33.0
|
golang.org/x/sys v0.31.0
|
||||||
golang.org/x/text v0.26.0
|
golang.org/x/text v0.23.0
|
||||||
google.golang.org/protobuf v1.36.4
|
google.golang.org/protobuf v1.36.4
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
|
@ -120,6 +121,7 @@ require (
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
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/DataDog/zstd v1.5.5 // 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
|
||||||
|
@ -146,19 +148,20 @@ require (
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
|
||||||
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
|
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1 // indirect
|
github.com/boombuler/barcode v1.0.1 // indirect
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudflare/circl v1.6.1 // indirect
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
github.com/cyphar/filepath-securejoin v0.3.6 // 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
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||||
|
@ -167,19 +170,19 @@ require (
|
||||||
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-git/go-billy/v5 v5.6.2 // indirect
|
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||||
github.com/go-openapi/swag v0.23.1 // indirect
|
github.com/go-openapi/swag v0.22.7 // indirect
|
||||||
github.com/go-webauthn/x v0.1.21 // 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.1 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
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.5 // 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/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
|
||||||
|
@ -189,12 +192,12 @@ require (
|
||||||
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/libdns/libdns v1.0.0-beta.1 // indirect
|
github.com/libdns/libdns v0.2.3 // 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
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mholt/acmez/v3 v3.1.2 // indirect
|
github.com/mholt/acmez/v3 v3.1.1 // indirect
|
||||||
github.com/miekg/dns v1.1.63 // indirect
|
github.com/miekg/dns v1.1.63 // 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
|
||||||
|
@ -205,11 +208,8 @@ require (
|
||||||
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/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
|
||||||
github.com/olekukonko/tablewriter v1.0.7 // indirect
|
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
@ -221,13 +221,15 @@ require (
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
github.com/rogpeppe/go-internal v1.13.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/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.0 // indirect
|
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/tinylib/msgp v1.3.0 // indirect
|
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // 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
|
||||||
|
@ -235,16 +237,18 @@ require (
|
||||||
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/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.10.0 // indirect
|
||||||
golang.org/x/tools v0.34.0 // indirect
|
golang.org/x/tools v0.31.0 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
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 => code.forgejo.org/forgejo/act v1.28.0
|
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
|
||||||
|
|
||||||
|
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.25.1
|
||||||
|
|
||||||
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
|
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
|
||||||
|
|
||||||
|
|
250
go.sum
250
go.sum
|
@ -1,15 +1,13 @@
|
||||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||||
code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE=
|
code.forgejo.org/f3/gof3/v3 v3.10.6 h1:Ru/Iz+pqM8IPi7atUHE7+q7v3O3DRbYgMFqrFTsO1m8=
|
||||||
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
|
code.forgejo.org/f3/gof3/v3 v3.10.6/go.mod h1:K6lQCWQIyN/5rjP/OJL9fMA6fd++satndE20w/I6Kss=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
|
||||||
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
|
||||||
code.forgejo.org/forgejo/act v1.28.0 h1:96njNC7C1YNyjWq5OWvLZMF/nw0PMthzIA8Nwbnn7jo=
|
code.forgejo.org/forgejo/act v1.25.1 h1:T0CsN9iEWIyJzIbmMHMM9pl1KHzmI41q8mtepqVqdCc=
|
||||||
code.forgejo.org/forgejo/act v1.28.0/go.mod h1:dFuiwAmD5vyrzecysHB2kL/GM3wRpoVPl+WdbCTC8Bs=
|
code.forgejo.org/forgejo/act v1.25.1/go.mod h1:tSg5CAHnXp4WLNkMa2e9AEDSujMxKzNM4bF2pvvRCYQ=
|
||||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
|
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
|
||||||
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M=
|
|
||||||
code.forgejo.org/forgejo/go-rpmutils v1.0.0/go.mod h1:cg+VbgLXfrDPza9T+kBsMb3TVmmzPN4XseT6gDGLSUk=
|
|
||||||
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA=
|
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:RArF5AsF9LH4nEoJxqRxcP5r8hhRfWcId84G82YbqzA=
|
||||||
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
code.forgejo.org/forgejo/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||||
code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/UfU/XgPpLuE=
|
code.forgejo.org/forgejo/levelqueue v1.0.0 h1:9krYpU6BM+j/1Ntj6m+VCAIu0UNnne1/UfU/XgPpLuE=
|
||||||
|
@ -18,43 +16,45 @@ code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCd
|
||||||
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
|
code.forgejo.org/forgejo/reply v1.0.2/go.mod h1:RyZUfzQLc+fuLIGjTSQWDAJWPiL4WtKXB/FifT5fM7U=
|
||||||
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA=
|
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616 h1:kEZL84+02jY9RxXM4zHBWZ3Fml0B09cmP1LGkDsCfIA=
|
||||||
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
code.forgejo.org/forgejo/ssh v0.0.0-20241211213324-5fc306ca0616/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
|
||||||
code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY=
|
code.forgejo.org/go-chi/binding v1.0.0 h1:EIDJtk9brK7WsT7rvS/D4cxX8XlnhY3LMy8ex1jeHu0=
|
||||||
code.forgejo.org/go-chi/binding v1.0.1/go.mod h1:oTFFDg/dkwFbmVuusiULB1OlrIJM95cOGK7Nc3GYcoo=
|
code.forgejo.org/go-chi/binding v1.0.0/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E=
|
||||||
code.forgejo.org/go-chi/cache v1.0.1 h1:w6IsDcPbeEnEYZn7M2HJe3/3/Ehtcw/72VjcVK7+lBw=
|
code.forgejo.org/go-chi/cache v1.0.0 h1:akLfGxNlHcacmtutovNtYFSTMsbdcp5MGjAEsP4pxnE=
|
||||||
code.forgejo.org/go-chi/cache v1.0.1/go.mod h1:K3aQSyRIN4xiuqV1kanfQ6O4ToDpzDpY3bNOyGjFe3U=
|
code.forgejo.org/go-chi/cache v1.0.0/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk=
|
||||||
code.forgejo.org/go-chi/captcha v1.0.2 h1:vyHDPXkpjDv8bLO9NqtWzZayzstD/WpJ5xwEkAaqZGQ=
|
code.forgejo.org/go-chi/captcha v1.0.1 h1:/oe1fvGOpdyyeGijg3oMYNOYLvEovNvp79Y3gLe3qbk=
|
||||||
code.forgejo.org/go-chi/captcha v1.0.2/go.mod h1:lxiPLcJ76UCZHoH31/Wbum4GUi2NgjfFZLrJkKv1lLE=
|
code.forgejo.org/go-chi/captcha v1.0.1/go.mod h1:6EbjSVVa7WoZFENgwK/hLAJZq+HBXtgRsjnIngILC8Y=
|
||||||
code.forgejo.org/go-chi/session v1.0.2 h1:pG+AXre9L9VXJmTaADXkmeEPuRalhmBXyv6tG2Rvjcc=
|
code.forgejo.org/go-chi/session v1.0.1 h1:RNkcJQZJBqlvJoIFXSth87b3kMFZLDBA18VcitD+Z0Y=
|
||||||
code.forgejo.org/go-chi/session v1.0.2/go.mod h1:HnEGyBny7WPzCiVLP2vzL5ssma+3gCSl/vLpuVNYrqc=
|
code.forgejo.org/go-chi/session v1.0.1/go.mod h1:y69sjS984wc7k4xyu77yNE5HKeSlBoQW8VSGdsK7RAs=
|
||||||
code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
||||||
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
||||||
code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
|
code.gitea.io/sdk/gitea v0.20.0 h1:Zm/QDwwZK1awoM4AxdjeAQbxolzx2rIP8dDfmKu+KoU=
|
||||||
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
|
code.gitea.io/sdk/gitea v0.20.0/go.mod h1:faouBHC/zyx5wLgjmRKR62ydyvMzwWf3QnU0bH7Cw6U=
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtfU9vS6QJBg77pUvbEb6StRdZO8t1bEY=
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 h1:TXbikPqa7YRtfU9vS6QJBg77pUvbEb6StRdZO8t1bEY=
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM=
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM=
|
||||||
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
|
connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk=
|
||||||
connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
|
connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/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/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||||
github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
|
github.com/42wim/httpsig v1.2.2 h1:ofAYoHUNs/MJOLqQ8hIxeyz2QxOz8qdSVvp3PX/oPgA=
|
||||||
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
|
github.com/42wim/httpsig v1.2.2/go.mod h1:P/UYo7ytNBFwc+dg35IubuAUIs8zj5zzFIgUCEl55WY=
|
||||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920 h1:mWAVGlovzUfREJBhm0GwJnDNu21yRrL9QH9NIzAU3rg=
|
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps=
|
||||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920/go.mod h1:zWxcT7BIWOe05xVJL0VMvO/PJ6RpoCux10heb77H6Q8=
|
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU=
|
||||||
github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U=
|
github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U=
|
||||||
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo=
|
github.com/6543/go-version v1.3.1/go.mod h1:oqFAHCwtLVUTLdhQmVZWYvaHXTdsbB4SY85at64SQEo=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
|
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
|
||||||
|
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||||
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=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||||
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
|
||||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
|
||||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
||||||
github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
|
github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0=
|
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2 h1:cSXom2MoKJ9KPPw29RoZtHvUETY4F4n/kXl8m9btnQ0=
|
||||||
|
@ -62,8 +62,8 @@ github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.2/go.mod h1:JitQWJ8JuV4Y
|
||||||
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.18.0 h1:6h53Q4hW83SuF+jcsp7CVhLsMozzvQvO8HBbKQW+gn4=
|
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
|
||||||
github.com/alecthomas/chroma/v2 v2.18.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
|
||||||
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
|
||||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
|
@ -126,16 +126,16 @@ github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/w
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.16.8 h1:QN/daUob6cmK8GcdKnwn9+YTlPr1vNj+oeAIiJK6fPc=
|
github.com/buildkite/terminal-to-html/v3 v3.16.8 h1:QN/daUob6cmK8GcdKnwn9+YTlPr1vNj+oeAIiJK6fPc=
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.16.8/go.mod h1:+k1KVKROZocrTLsEQ9PEf9A+8+X8uaVV5iO1ZIOwKYM=
|
github.com/buildkite/terminal-to-html/v3 v3.16.8/go.mod h1:+k1KVKROZocrTLsEQ9PEf9A+8+X8uaVV5iO1ZIOwKYM=
|
||||||
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=
|
github.com/caddyserver/certmagic v0.22.2 h1:qzZURXlrxwR5m25/jpvVeEyJHeJJMvAwe5zlMufOTQk=
|
||||||
github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4=
|
github.com/caddyserver/certmagic v0.22.2/go.mod h1:hbqE7BnkjhX5IJiFslPmrSeobSeZvI6ux8tyxhsd6qs=
|
||||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||||
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
|
||||||
|
@ -152,6 +152,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
|
||||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||||
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||||
|
@ -171,8 +173,8 @@ github.com/djherbis/nio/v3 v3.0.1/go.mod h1:Ng4h80pbZFMla1yKzm61cF0tqqilXZYrogmW
|
||||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4=
|
||||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
|
||||||
|
@ -192,16 +194,16 @@ github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTe
|
||||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
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/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/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.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI=
|
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9 h1:j2TrkUG/NATGi/EQS+MvEoF79CxiRUmT16ErFroNcKI=
|
||||||
|
@ -213,8 +215,8 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||||
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||||
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
|
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
|
||||||
|
@ -237,23 +239,23 @@ 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.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
|
github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
|
github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc=
|
||||||
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||||
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||||
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||||
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||||
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
|
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
|
||||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8=
|
||||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0=
|
||||||
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
|
||||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||||
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.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
|
||||||
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
github.com/go-webauthn/webauthn v0.13.0 h1:cJIL1/1l+22UekVhipziAaSgESJxokYkowUqAIsWs0Y=
|
github.com/go-webauthn/webauthn v0.12.2 h1:yLaNPgBUEXDQtWnOjhsGhMMCEWbXwjg/aNkC8riJQI8=
|
||||||
github.com/go-webauthn/webauthn v0.13.0/go.mod h1:Oy9o2o79dbLKRPZWWgRIOdtBGAhKnDIaBp2PFkICRHs=
|
github.com/go-webauthn/webauthn v0.12.2/go.mod h1:Q8SZPPj4sZ469fNTcQXxRpzJOdb30jQrn/36FX8jilA=
|
||||||
github.com/go-webauthn/x v0.1.21 h1:nFbckQxudvHEJn2uy1VEi713MeSpApoAv9eRqsb9AdQ=
|
github.com/go-webauthn/x v0.1.20 h1:brEBDqfiPtNNCdS/peu8gARtq8fIPsHz0VzpPjGvgiw=
|
||||||
github.com/go-webauthn/x v0.1.21/go.mod h1:sEYohtg1zL4An1TXIUIQ5csdmoO+WO0R4R2pGKaHYKA=
|
github.com/go-webauthn/x v0.1.20/go.mod h1:n/gAc8ssZJGATM0qThE+W+vfgXiMedsWi3wf/C4lld0=
|
||||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
|
@ -265,9 +267,8 @@ github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7w
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
@ -301,14 +302,14 @@ github.com/google/go-github/v64 v64.0.0 h1:4G61sozmY3eiPAjjoOHponXDBONm+utovTKby
|
||||||
github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo=
|
github.com/google/go-github/v64 v64.0.0/go.mod h1:xB3vqMQNdHzilXBiO2I+M7iEFtHf+DP/omBOv6tQzVo=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/go-tpm v0.9.5 h1:ocUmnDebX54dnW+MQWGQRbdaAcJELsa6PqZhJ48KwVU=
|
github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc=
|
||||||
github.com/google/go-tpm v0.9.5/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 h1:xhMrHhTJ6zxu3gA4enFM9MLn9AY7613teCdFnlUVbSQ=
|
github.com/google/pprof v0.0.0-20241017200806-017d972448fc h1:NGyrhhFhwvRAZg02jnYVg3GBQy0qGBKmFQJwaPmpmxs=
|
||||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
|
github.com/google/pprof v0.0.0-20241017200806-017d972448fc/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
@ -341,12 +342,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
|
||||||
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
|
||||||
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||||
github.com/inbucket/html2text v0.9.0 h1:ULJmVcBEMAcmLE+/rN815KG1Fx6+a4HhbUxiDiN+qks=
|
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
|
||||||
github.com/inbucket/html2text v0.9.0/go.mod h1:QDaumzl+/OzlSVbNohhmg+yAy5pKjUjzCKW2BMvztKE=
|
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jhillyerd/enmime/v2 v2.2.0 h1:Pe35MB96eZK5Q0XjlvPftOgWypQpd1gcbfJKAt7rsB8=
|
github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0=
|
||||||
github.com/jhillyerd/enmime/v2 v2.2.0/go.mod h1:SOBXlCemjhiV2DvHhAKnJiWrtJGS/Ffuw4Iy7NjBTaI=
|
github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
@ -357,8 +358,8 @@ github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4
|
||||||
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
|
@ -380,8 +381,10 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
|
||||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
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 v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8=
|
||||||
github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
github.com/libdns/libdns v0.2.3/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/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=
|
||||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
|
@ -389,18 +392,20 @@ github.com/markbates/going v1.0.3 h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE
|
||||||
github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o=
|
github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o=
|
||||||
github.com/markbates/goth v1.80.0 h1:NnvatczZDzOs1hn9Ug+dVYf2Viwwkp/ZDX5K+GLjan8=
|
github.com/markbates/goth v1.80.0 h1:NnvatczZDzOs1hn9Ug+dVYf2Viwwkp/ZDX5K+GLjan8=
|
||||||
github.com/markbates/goth v1.80.0/go.mod h1:4/GYHo+W6NWisrMPZnq0Yr2Q70UntNLn7KXEFhrIdAY=
|
github.com/markbates/goth v1.80.0/go.mod h1:4/GYHo+W6NWisrMPZnq0Yr2Q70UntNLn7KXEFhrIdAY=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||||
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY=
|
github.com/meilisearch/meilisearch-go v0.31.0 h1:yZRhY1qJqdH8h6GFZALGtkDLyj8f9v5aJpsNMyrUmnY=
|
||||||
github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g=
|
github.com/meilisearch/meilisearch-go v0.31.0/go.mod h1:aNtyuwurDg/ggxQIcKqWH6G9g2ptc8GyY7PLY4zMn/g=
|
||||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
github.com/mholt/acmez/v3 v3.1.1 h1:Jh+9uKHkPxUJdxM16q5mOr+G2V0aqkuFtNA28ihCxhQ=
|
||||||
github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
github.com/mholt/acmez/v3 v3.1.1/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
||||||
|
@ -409,8 +414,8 @@ github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY
|
||||||
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
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.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM=
|
github.com/minio/minio-go/v7 v7.0.88 h1:v8MoIJjwYxOkehp+eiLIuvXk87P2raUtoU5klrAAshs=
|
||||||
github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
|
github.com/minio/minio-go/v7 v7.0.88/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg=
|
||||||
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/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=
|
||||||
|
@ -426,20 +431,16 @@ github.com/msteinert/pam/v2 v2.1.0 h1:er5F9TKV5nGFuTt12ubtqPHEUdeBwReP7vd3wovidG
|
||||||
github.com/msteinert/pam/v2 v2.1.0/go.mod h1:KT28NNIcDFf3PcBmNI2mIGO4zZJ+9RSs/At2PB3IDVc=
|
github.com/msteinert/pam/v2 v2.1.0/go.mod h1:KT28NNIcDFf3PcBmNI2mIGO4zZJ+9RSs/At2PB3IDVc=
|
||||||
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.9.0 h1:4/Sr68Qx06hjC9MVDB/4etGP67JionLHGscLMOClpnk=
|
github.com/niklasfasching/go-org v1.7.0 h1:vyMdcMWWTe/XmANk19F4k8XGBYg0GQ/gJGMimOjGMek=
|
||||||
github.com/niklasfasching/go-org v1.9.0/go.mod h1:ZAGFFkWvUQcpazmi/8nHqwvARpr1xpb+Es67oUGX/48=
|
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/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
|
||||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
|
||||||
github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
|
|
||||||
github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
|
|
||||||
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
|
||||||
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
@ -457,8 +458,6 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I
|
||||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
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/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
|
|
||||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
|
||||||
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.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
@ -480,8 +479,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
|
||||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw=
|
github.com/rhysd/actionlint v1.6.27 h1:xxwe8YmveBcC8lydW6GoHMGmB6H/MTqUU60F2p10wjw=
|
||||||
|
@ -497,11 +496,17 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||||
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
|
github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg=
|
||||||
|
github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI=
|
||||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
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=
|
||||||
|
@ -525,14 +530,12 @@ 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/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.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
|
|
||||||
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
|
|
||||||
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
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/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
|
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
||||||
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
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/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
@ -541,6 +544,8 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
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/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=
|
||||||
|
@ -548,8 +553,8 @@ github.com/yohcop/openid-go v1.0.1/go.mod h1:b/AvD03P0KHj4yuihb+VtLD6bYYgsy0zqBz
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY=
|
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||||
github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
|
||||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||||
|
@ -558,8 +563,8 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
||||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||||
gitlab.com/gitlab-org/api/client-go v0.130.1 h1:1xF5C5Zq3sFeNg3PzS2z63oqrxifne3n/OnbI7nptRc=
|
gitlab.com/gitlab-org/api/client-go v0.126.0 h1:VV5TdkF6pMbEdFGvbR2CwEgJwg6qdg1u3bj5eD2tiWk=
|
||||||
gitlab.com/gitlab-org/api/client-go v0.130.1/go.mod h1:ZhSxLAWadqP6J9lMh40IAZOlOxBLPRh7yFOXR/bMJWM=
|
gitlab.com/gitlab-org/api/client-go v0.126.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
|
||||||
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.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
@ -567,8 +572,8 @@ 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=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
@ -585,20 +590,20 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
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.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.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=
|
||||||
|
@ -614,10 +619,10 @@ 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.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.28.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=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -627,8 +632,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.12.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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -647,6 +652,7 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -654,8 +660,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.31.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=
|
||||||
|
@ -665,8 +671,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
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.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||||
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=
|
||||||
|
@ -677,10 +683,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
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.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
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=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
@ -688,8 +694,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.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||||
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=
|
||||||
|
|
2
main.go
2
main.go
|
@ -21,7 +21,7 @@ import (
|
||||||
_ "forgejo.org/modules/markup/markdown"
|
_ "forgejo.org/modules/markup/markdown"
|
||||||
_ "forgejo.org/modules/markup/orgmode"
|
_ "forgejo.org/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
|
||||||
|
|
38
manifest.scm
38
manifest.scm
|
@ -1,38 +0,0 @@
|
||||||
;;; Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
||||||
;;; SPDX-License-Identifier: MIT
|
|
||||||
;;;
|
|
||||||
;;; Commentary:
|
|
||||||
;;;
|
|
||||||
;;; This is a GNU Guix manifest that can be used to create a
|
|
||||||
;;; development environment to build and test Forgejo.
|
|
||||||
;;;
|
|
||||||
;;; The following is a usage example to create a containerized
|
|
||||||
;;; environment, with HOME shared for the Go cache and the network
|
|
||||||
;;; made available to fetch required Go and Node dependencies.
|
|
||||||
;;;
|
|
||||||
#|
|
|
||||||
guix shell -CNF --share=$HOME -m manifest.scm
|
|
||||||
export GOTOOLCHAIN=local # to use the Go binary from Guix
|
|
||||||
export CC=gcc CGO_ENABLED=1
|
|
||||||
export TAGS="timetzdata sqlite sqlite_unlock_notify"
|
|
||||||
make clean
|
|
||||||
make -j$(nproc)
|
|
||||||
make test -j$(nproc) # run unit tests
|
|
||||||
make test-sqlite -j$(nproc) # run integration tests
|
|
||||||
make watch # run an instance/rebuild on changes
|
|
||||||
|#
|
|
||||||
(specifications->manifest
|
|
||||||
(list "bash-minimal"
|
|
||||||
"coreutils"
|
|
||||||
"findutils"
|
|
||||||
"gcc-toolchain"
|
|
||||||
"git" ;libpcre support is required
|
|
||||||
"git-lfs"
|
|
||||||
"gnupg"
|
|
||||||
"go"
|
|
||||||
"grep"
|
|
||||||
"make"
|
|
||||||
"node"
|
|
||||||
"nss-certs"
|
|
||||||
"openssh"
|
|
||||||
"sed"))
|
|
|
@ -24,9 +24,9 @@ func TestActions_RegisterRunner_Token(t *testing.T) {
|
||||||
version := "v1.2.3"
|
version := "v1.2.3"
|
||||||
runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, &labels, name, version)
|
runner, err := RegisterRunner(db.DefaultContext, ownerID, repoID, token, &labels, name, version)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, name, runner.Name)
|
assert.EqualValues(t, name, runner.Name)
|
||||||
|
|
||||||
assert.Equal(t, 1, subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))), "the token cannot be verified with the same method as routers/api/actions/runner/interceptor.go as of 8228751c55d6a4263f0fec2932ca16181c09c97d")
|
assert.EqualValues(t, 1, subtle.ConstantTimeCompare([]byte(runner.TokenHash), []byte(auth_model.HashToken(token, runner.TokenSalt))), "the token cannot be verified with the same method as routers/api/actions/runner/interceptor.go as of 8228751c55d6a4263f0fec2932ca16181c09c97d")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestActions_RegisterRunner_TokenUpdate tests that a token's secret is updated
|
// TestActions_RegisterRunner_TokenUpdate tests that a token's secret is updated
|
||||||
|
@ -73,19 +73,19 @@ func TestActions_RegisterRunner_CreateWithLabels(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that the returned record has been updated, except for the labels
|
// Check that the returned record has been updated, except for the labels
|
||||||
assert.Equal(t, ownerID, runner.OwnerID)
|
assert.EqualValues(t, ownerID, runner.OwnerID)
|
||||||
assert.Equal(t, repoID, runner.RepoID)
|
assert.EqualValues(t, repoID, runner.RepoID)
|
||||||
assert.Equal(t, name, runner.Name)
|
assert.EqualValues(t, name, runner.Name)
|
||||||
assert.Equal(t, version, runner.Version)
|
assert.EqualValues(t, version, runner.Version)
|
||||||
assert.Equal(t, labelsCopy, runner.AgentLabels)
|
assert.EqualValues(t, labelsCopy, runner.AgentLabels)
|
||||||
|
|
||||||
// Check that whatever is in the DB has been updated, except for the labels
|
// Check that whatever is in the DB has been updated, except for the labels
|
||||||
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID})
|
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID})
|
||||||
assert.Equal(t, ownerID, after.OwnerID)
|
assert.EqualValues(t, ownerID, after.OwnerID)
|
||||||
assert.Equal(t, repoID, after.RepoID)
|
assert.EqualValues(t, repoID, after.RepoID)
|
||||||
assert.Equal(t, name, after.Name)
|
assert.EqualValues(t, name, after.Name)
|
||||||
assert.Equal(t, version, after.Version)
|
assert.EqualValues(t, version, after.Version)
|
||||||
assert.Equal(t, labelsCopy, after.AgentLabels)
|
assert.EqualValues(t, labelsCopy, after.AgentLabels)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestActions_RegisterRunner_CreateWithoutLabels(t *testing.T) {
|
func TestActions_RegisterRunner_CreateWithoutLabels(t *testing.T) {
|
||||||
|
@ -100,19 +100,19 @@ func TestActions_RegisterRunner_CreateWithoutLabels(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that the returned record has been updated, except for the labels
|
// Check that the returned record has been updated, except for the labels
|
||||||
assert.Equal(t, ownerID, runner.OwnerID)
|
assert.EqualValues(t, ownerID, runner.OwnerID)
|
||||||
assert.Equal(t, repoID, runner.RepoID)
|
assert.EqualValues(t, repoID, runner.RepoID)
|
||||||
assert.Equal(t, name, runner.Name)
|
assert.EqualValues(t, name, runner.Name)
|
||||||
assert.Equal(t, version, runner.Version)
|
assert.EqualValues(t, version, runner.Version)
|
||||||
assert.Equal(t, []string{}, runner.AgentLabels)
|
assert.EqualValues(t, []string{}, runner.AgentLabels)
|
||||||
|
|
||||||
// Check that whatever is in the DB has been updated, except for the labels
|
// Check that whatever is in the DB has been updated, except for the labels
|
||||||
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID})
|
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: runner.ID})
|
||||||
assert.Equal(t, ownerID, after.OwnerID)
|
assert.EqualValues(t, ownerID, after.OwnerID)
|
||||||
assert.Equal(t, repoID, after.RepoID)
|
assert.EqualValues(t, repoID, after.RepoID)
|
||||||
assert.Equal(t, name, after.Name)
|
assert.EqualValues(t, name, after.Name)
|
||||||
assert.Equal(t, version, after.Version)
|
assert.EqualValues(t, version, after.Version)
|
||||||
assert.Equal(t, []string{}, after.AgentLabels)
|
assert.EqualValues(t, []string{}, after.AgentLabels)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestActions_RegisterRunner_UpdateWithLabels(t *testing.T) {
|
func TestActions_RegisterRunner_UpdateWithLabels(t *testing.T) {
|
||||||
|
@ -132,19 +132,19 @@ func TestActions_RegisterRunner_UpdateWithLabels(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that the returned record has been updated
|
// Check that the returned record has been updated
|
||||||
assert.Equal(t, newOwnerID, runner.OwnerID)
|
assert.EqualValues(t, newOwnerID, runner.OwnerID)
|
||||||
assert.Equal(t, newRepoID, runner.RepoID)
|
assert.EqualValues(t, newRepoID, runner.RepoID)
|
||||||
assert.Equal(t, newName, runner.Name)
|
assert.EqualValues(t, newName, runner.Name)
|
||||||
assert.Equal(t, newVersion, runner.Version)
|
assert.EqualValues(t, newVersion, runner.Version)
|
||||||
assert.Equal(t, labelsCopy, runner.AgentLabels)
|
assert.EqualValues(t, labelsCopy, runner.AgentLabels)
|
||||||
|
|
||||||
// Check that whatever is in the DB has been updated
|
// Check that whatever is in the DB has been updated
|
||||||
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID})
|
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID})
|
||||||
assert.Equal(t, newOwnerID, after.OwnerID)
|
assert.EqualValues(t, newOwnerID, after.OwnerID)
|
||||||
assert.Equal(t, newRepoID, after.RepoID)
|
assert.EqualValues(t, newRepoID, after.RepoID)
|
||||||
assert.Equal(t, newName, after.Name)
|
assert.EqualValues(t, newName, after.Name)
|
||||||
assert.Equal(t, newVersion, after.Version)
|
assert.EqualValues(t, newVersion, after.Version)
|
||||||
assert.Equal(t, labelsCopy, after.AgentLabels)
|
assert.EqualValues(t, labelsCopy, after.AgentLabels)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestActions_RegisterRunner_UpdateWithoutLabels(t *testing.T) {
|
func TestActions_RegisterRunner_UpdateWithoutLabels(t *testing.T) {
|
||||||
|
@ -162,17 +162,17 @@ func TestActions_RegisterRunner_UpdateWithoutLabels(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Check that the returned record has been updated, except for the labels
|
// Check that the returned record has been updated, except for the labels
|
||||||
assert.Equal(t, newOwnerID, runner.OwnerID)
|
assert.EqualValues(t, newOwnerID, runner.OwnerID)
|
||||||
assert.Equal(t, newRepoID, runner.RepoID)
|
assert.EqualValues(t, newRepoID, runner.RepoID)
|
||||||
assert.Equal(t, newName, runner.Name)
|
assert.EqualValues(t, newName, runner.Name)
|
||||||
assert.Equal(t, newVersion, runner.Version)
|
assert.EqualValues(t, newVersion, runner.Version)
|
||||||
assert.Equal(t, before.AgentLabels, runner.AgentLabels)
|
assert.EqualValues(t, before.AgentLabels, runner.AgentLabels)
|
||||||
|
|
||||||
// Check that whatever is in the DB has been updated, except for the labels
|
// Check that whatever is in the DB has been updated, except for the labels
|
||||||
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID})
|
after := unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: recordID})
|
||||||
assert.Equal(t, newOwnerID, after.OwnerID)
|
assert.EqualValues(t, newOwnerID, after.OwnerID)
|
||||||
assert.Equal(t, newRepoID, after.RepoID)
|
assert.EqualValues(t, newRepoID, after.RepoID)
|
||||||
assert.Equal(t, newName, after.Name)
|
assert.EqualValues(t, newName, after.Name)
|
||||||
assert.Equal(t, newVersion, after.Version)
|
assert.EqualValues(t, newVersion, after.Version)
|
||||||
assert.Equal(t, before.AgentLabels, after.AgentLabels)
|
assert.EqualValues(t, before.AgentLabels, after.AgentLabels)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ func TestMain(m *testing.M) {
|
||||||
unittest.MainTest(m, &unittest.TestOptions{
|
unittest.MainTest(m, &unittest.TestOptions{
|
||||||
FixtureFiles: []string{
|
FixtureFiles: []string{
|
||||||
"action_runner.yml",
|
"action_runner.yml",
|
||||||
"repository.yml",
|
|
||||||
"action_runner_token.yml",
|
"action_runner_token.yml",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,6 @@ package actions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -55,7 +54,6 @@ type ActionRun struct {
|
||||||
PreviousDuration time.Duration
|
PreviousDuration time.Duration
|
||||||
Created timeutil.TimeStamp `xorm:"created"`
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
Updated timeutil.TimeStamp `xorm:"updated"`
|
Updated timeutil.TimeStamp `xorm:"updated"`
|
||||||
NotifyEmail bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -187,9 +185,77 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CancelPreviousJobs cancels all previous jobs of the same repository, reference, workflow, and event.
|
||||||
|
// It's useful when a new run is triggered, and all previous runs needn't be continued anymore.
|
||||||
|
func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error {
|
||||||
|
// Find all runs in the specified repository, reference, and workflow with non-final status
|
||||||
|
runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
|
||||||
|
RepoID: repoID,
|
||||||
|
Ref: ref,
|
||||||
|
WorkflowID: workflowID,
|
||||||
|
TriggerEvent: event,
|
||||||
|
Status: []Status{StatusRunning, StatusWaiting, StatusBlocked},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no runs found, there's no need to proceed with cancellation, so return nil.
|
||||||
|
if total == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each found run and cancel its associated jobs.
|
||||||
|
for _, run := range runs {
|
||||||
|
// Find all jobs associated with the current run.
|
||||||
|
jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{
|
||||||
|
RunID: run.ID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over each job and attempt to cancel it.
|
||||||
|
for _, job := range jobs {
|
||||||
|
// Skip jobs that are already in a terminal state (completed, cancelled, etc.).
|
||||||
|
status := job.Status
|
||||||
|
if status.IsDone() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the job has no associated task (probably an error), set its status to 'Cancelled' and stop it.
|
||||||
|
if job.TaskID == 0 {
|
||||||
|
job.Status = StatusCancelled
|
||||||
|
job.Stopped = timeutil.TimeStampNow()
|
||||||
|
|
||||||
|
// Update the job's status and stopped time in the database.
|
||||||
|
n, err := UpdateRunJob(ctx, job, builder.Eq{"task_id": 0}, "status", "stopped")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the update affected 0 rows, it means the job has changed in the meantime, so we need to try again.
|
||||||
|
if n == 0 {
|
||||||
|
return fmt.Errorf("job has changed, try again")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with the next job.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the job has an associated task, try to stop the task, effectively cancelling the job.
|
||||||
|
if err := StopTask(ctx, job.TaskID, StatusCancelled); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return nil to indicate successful cancellation of all running and waiting jobs.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
// We don't have to send the ActionRunNowDone notification here because there are no runs that start in a not done status.
|
|
||||||
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
|
func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error {
|
||||||
ctx, commiter, err := db.TxContext(ctx)
|
ctx, commiter, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -224,38 +290,29 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork
|
||||||
var hasWaiting bool
|
var hasWaiting bool
|
||||||
for _, v := range jobs {
|
for _, v := range jobs {
|
||||||
id, job := v.Job()
|
id, job := v.Job()
|
||||||
status := StatusFailure
|
needs := job.Needs()
|
||||||
payload := []byte{}
|
|
||||||
needs := []string{}
|
|
||||||
name := run.Title
|
|
||||||
runsOn := []string{}
|
|
||||||
if job != nil {
|
|
||||||
needs = job.Needs()
|
|
||||||
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
payload, _ = v.Marshal()
|
payload, _ := v.Marshal()
|
||||||
|
status := StatusWaiting
|
||||||
if len(needs) > 0 || run.NeedApproval {
|
if len(needs) > 0 || run.NeedApproval {
|
||||||
status = StatusBlocked
|
status = StatusBlocked
|
||||||
} else {
|
} else {
|
||||||
status = StatusWaiting
|
|
||||||
hasWaiting = true
|
hasWaiting = true
|
||||||
}
|
}
|
||||||
name, _ = util.SplitStringAtByteN(job.Name, 255)
|
job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
|
||||||
runsOn = job.RunsOn()
|
|
||||||
}
|
|
||||||
runJobs = append(runJobs, &ActionRunJob{
|
runJobs = append(runJobs, &ActionRunJob{
|
||||||
RunID: run.ID,
|
RunID: run.ID,
|
||||||
RepoID: run.RepoID,
|
RepoID: run.RepoID,
|
||||||
OwnerID: run.OwnerID,
|
OwnerID: run.OwnerID,
|
||||||
CommitSHA: run.CommitSHA,
|
CommitSHA: run.CommitSHA,
|
||||||
IsForkPullRequest: run.IsForkPullRequest,
|
IsForkPullRequest: run.IsForkPullRequest,
|
||||||
Name: name,
|
Name: job.Name,
|
||||||
WorkflowPayload: payload,
|
WorkflowPayload: payload,
|
||||||
JobID: id,
|
JobID: id,
|
||||||
Needs: needs,
|
Needs: needs,
|
||||||
RunsOn: runsOn,
|
RunsOn: job.RunsOn(),
|
||||||
Status: status,
|
Status: status,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -284,18 +341,6 @@ func GetLatestRun(ctx context.Context, repoID int64) (*ActionRun, error) {
|
||||||
return &run, nil
|
return &run, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRunBefore returns the last run that completed a given timestamp (not inclusive).
|
|
||||||
func GetRunBefore(ctx context.Context, repoID int64, timestamp timeutil.TimeStamp) (*ActionRun, error) {
|
|
||||||
var run ActionRun
|
|
||||||
has, err := db.GetEngine(ctx).Where("repo_id=? AND stopped IS NOT NULL AND stopped<?", repoID, timestamp).OrderBy("stopped DESC").Limit(1).Get(&run)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, fmt.Errorf("run before: %w", util.ErrNotExist)
|
|
||||||
}
|
|
||||||
return &run, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetLatestRunForBranchAndWorkflow(ctx context.Context, repoID int64, branch, workflowFile, event string) (*ActionRun, error) {
|
func GetLatestRunForBranchAndWorkflow(ctx context.Context, repoID int64, branch, workflowFile, event string) (*ActionRun, error) {
|
||||||
var run ActionRun
|
var run ActionRun
|
||||||
q := db.GetEngine(ctx).Where("repo_id=?", repoID).And("workflow_id=?", workflowFile)
|
q := db.GetEngine(ctx).Where("repo_id=?", repoID).And("workflow_id=?", workflowFile)
|
||||||
|
@ -344,9 +389,7 @@ func GetRunByIndex(ctx context.Context, repoID, index int64) (*ActionRun, error)
|
||||||
// UpdateRun updates a run.
|
// UpdateRun updates a run.
|
||||||
// It requires the inputted run has Version set.
|
// It requires the inputted run has Version set.
|
||||||
// It will return error if the version is not matched (it means the run has been changed after loaded).
|
// It will return error if the version is not matched (it means the run has been changed after loaded).
|
||||||
// All calls to UpdateRunWithoutNotification that change run.Status from a not done status to a done status must call the ActionRunNowDone notification channel.
|
func UpdateRun(ctx context.Context, run *ActionRun, cols ...string) error {
|
||||||
// Use the wrapper function UpdateRun instead.
|
|
||||||
func UpdateRunWithoutNotification(ctx context.Context, run *ActionRun, cols ...string) error {
|
|
||||||
sess := db.GetEngine(ctx).ID(run.ID)
|
sess := db.GetEngine(ctx).ID(run.ID)
|
||||||
if len(cols) > 0 {
|
if len(cols) > 0 {
|
||||||
sess.Cols(cols...)
|
sess.Cols(cols...)
|
||||||
|
@ -357,7 +400,7 @@ func UpdateRunWithoutNotification(ctx context.Context, run *ActionRun, cols ...s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if affected == 0 {
|
if affected == 0 {
|
||||||
return errors.New("run has changed")
|
return fmt.Errorf("run has changed")
|
||||||
// It's impossible that the run is not found, since Gitea never deletes runs.
|
// It's impossible that the run is not found, since Gitea never deletes runs.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,7 @@ func GetRunJobsByRunID(ctx context.Context, runID int64) ([]*ActionRunJob, error
|
||||||
return jobs, nil
|
return jobs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// All calls to UpdateRunJobWithoutNotification that change run.Status for any run from a not done status to a done status must call the ActionRunNowDone notification channel.
|
func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) {
|
||||||
// Use the wrapper function UpdateRunJob instead.
|
|
||||||
func UpdateRunJobWithoutNotification(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) {
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
sess := e.ID(job.ID)
|
sess := e.ID(job.ID)
|
||||||
|
@ -156,8 +154,7 @@ func UpdateRunJobWithoutNotification(ctx context.Context, job *ActionRunJob, con
|
||||||
if run.Stopped.IsZero() && run.Status.IsDone() {
|
if run.Stopped.IsZero() && run.Status.IsDone() {
|
||||||
run.Stopped = timeutil.TimeStampNow()
|
run.Stopped = timeutil.TimeStampNow()
|
||||||
}
|
}
|
||||||
// As the caller has to ensure the ActionRunNowDone notification is sent we can ignore doing so here.
|
if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil {
|
||||||
if err := UpdateRunWithoutNotification(ctx, run, "status", "started", "stopped"); err != nil {
|
|
||||||
return 0, fmt.Errorf("update run %d: %w", run.ID, err)
|
return 0, fmt.Errorf("update run %d: %w", run.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,6 @@ type FindRunJobOptions struct {
|
||||||
CommitSHA string
|
CommitSHA string
|
||||||
Statuses []Status
|
Statuses []Status
|
||||||
UpdatedBefore timeutil.TimeStamp
|
UpdatedBefore timeutil.TimeStamp
|
||||||
Events []string // []webhook_module.HookEventType
|
|
||||||
RunNumber int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindRunJobOptions) ToConds() builder.Cond {
|
func (opts FindRunJobOptions) ToConds() builder.Cond {
|
||||||
|
@ -78,11 +76,5 @@ func (opts FindRunJobOptions) ToConds() builder.Cond {
|
||||||
if opts.UpdatedBefore > 0 {
|
if opts.UpdatedBefore > 0 {
|
||||||
cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore})
|
cond = cond.And(builder.Lt{"updated": opts.UpdatedBefore})
|
||||||
}
|
}
|
||||||
if len(opts.Events) > 0 {
|
|
||||||
cond = cond.And(builder.In("event", opts.Events))
|
|
||||||
}
|
|
||||||
if opts.RunNumber > 0 {
|
|
||||||
cond = cond.And(builder.Eq{"`index`": opts.RunNumber})
|
|
||||||
}
|
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package actions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"forgejo.org/models/db"
|
|
||||||
"forgejo.org/models/unittest"
|
|
||||||
"forgejo.org/modules/timeutil"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetRunBefore(t *testing.T) {
|
|
||||||
require.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
// this repo is part of the test database requiring loading "repository.yml" in main_test.go
|
|
||||||
var repoID int64 = 1
|
|
||||||
|
|
||||||
workflowID := "test_workflow"
|
|
||||||
|
|
||||||
// third completed run
|
|
||||||
time1, err := time.Parse(time.RFC3339, "2024-07-31T15:47:55+08:00")
|
|
||||||
require.NoError(t, err)
|
|
||||||
timeutil.MockSet(time1)
|
|
||||||
run1 := ActionRun{
|
|
||||||
ID: 1,
|
|
||||||
Index: 1,
|
|
||||||
RepoID: repoID,
|
|
||||||
Stopped: timeutil.TimeStampNow(),
|
|
||||||
WorkflowID: workflowID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// fourth completed run
|
|
||||||
time2, err := time.Parse(time.RFC3339, "2024-08-31T15:47:55+08:00")
|
|
||||||
require.NoError(t, err)
|
|
||||||
timeutil.MockSet(time2)
|
|
||||||
run2 := ActionRun{
|
|
||||||
ID: 2,
|
|
||||||
Index: 2,
|
|
||||||
RepoID: repoID,
|
|
||||||
Stopped: timeutil.TimeStampNow(),
|
|
||||||
WorkflowID: workflowID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// second completed run
|
|
||||||
time3, err := time.Parse(time.RFC3339, "2024-07-31T15:47:54+08:00")
|
|
||||||
require.NoError(t, err)
|
|
||||||
timeutil.MockSet(time3)
|
|
||||||
run3 := ActionRun{
|
|
||||||
ID: 3,
|
|
||||||
Index: 3,
|
|
||||||
RepoID: repoID,
|
|
||||||
Stopped: timeutil.TimeStampNow(),
|
|
||||||
WorkflowID: workflowID,
|
|
||||||
}
|
|
||||||
|
|
||||||
// first completed run
|
|
||||||
time4, err := time.Parse(time.RFC3339, "2024-06-30T15:47:54+08:00")
|
|
||||||
require.NoError(t, err)
|
|
||||||
timeutil.MockSet(time4)
|
|
||||||
run4 := ActionRun{
|
|
||||||
ID: 4,
|
|
||||||
Index: 4,
|
|
||||||
RepoID: repoID,
|
|
||||||
Stopped: timeutil.TimeStampNow(),
|
|
||||||
WorkflowID: workflowID,
|
|
||||||
}
|
|
||||||
require.NoError(t, db.Insert(db.DefaultContext, &run1))
|
|
||||||
runBefore, err := GetRunBefore(db.DefaultContext, repoID, run1.Stopped)
|
|
||||||
// there is no run before run1
|
|
||||||
require.Error(t, err)
|
|
||||||
require.Nil(t, runBefore)
|
|
||||||
|
|
||||||
// now there is only run3 before run1
|
|
||||||
require.NoError(t, db.Insert(db.DefaultContext, &run3))
|
|
||||||
runBefore, err = GetRunBefore(db.DefaultContext, repoID, run1.Stopped)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, run3.ID, runBefore.ID)
|
|
||||||
|
|
||||||
// there still is only run3 before run1
|
|
||||||
require.NoError(t, db.Insert(db.DefaultContext, &run2))
|
|
||||||
runBefore, err = GetRunBefore(db.DefaultContext, repoID, run1.Stopped)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, run3.ID, runBefore.ID)
|
|
||||||
|
|
||||||
// run4 is further away from run1
|
|
||||||
require.NoError(t, db.Insert(db.DefaultContext, &run4))
|
|
||||||
runBefore, err = GetRunBefore(db.DefaultContext, repoID, run1.Stopped)
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, run3.ID, runBefore.ID)
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue