mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-09-15 18:56:59 +00:00
Merge branch 'forgejo' into timeout-config-to-remove-resolved-reports
This commit is contained in:
commit
7d03d7dd1e
632 changed files with 19250 additions and 6456 deletions
|
@ -13,6 +13,13 @@ 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
|
||||||
|
|
||||||
|
@ -54,9 +61,17 @@ 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
|
||||||
|
@ -87,12 +102,24 @@ 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
|
||||||
|
|
||||||
|
@ -204,6 +231,7 @@ 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
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "22"
|
"version": "22"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/git-lfs:1.2.3": {},
|
"ghcr.io/devcontainers/features/git-lfs:1.2.4": {},
|
||||||
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
|
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
|
|
|
@ -37,13 +37,9 @@ 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
|
||||||
|
|
|
@ -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> (GPG: `A4676E79`) instead of opening a public issue.**
|
**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.**
|
||||||
- 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> (GPG: `A4676E79`) instead of opening a public issue.**
|
**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.**
|
||||||
- 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.21
|
FROM data.forgejo.org/oci/alpine:3.22
|
||||||
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 -qq -y ${PACKAGES}
|
apt-get -q install --allow-downgrades -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
|
||||||
|
|
|
@ -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.4
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5
|
||||||
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.4
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/build@v5.3.5
|
||||||
with:
|
with:
|
||||||
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
forgejo: "${{ env.GITHUB_SERVER_URL }}"
|
||||||
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
owner: "${{ env.GITHUB_REPOSITORY_OWNER }}"
|
||||||
|
|
|
@ -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.4
|
uses: https://data.forgejo.org/forgejo/forgejo-build-publish/publish@v5.3.5
|
||||||
with:
|
with:
|
||||||
from-forgejo: ${{ vars.FORGEJO }}
|
from-forgejo: ${{ vars.FORGEJO }}
|
||||||
to-forgejo: ${{ vars.FORGEJO }}
|
to-forgejo: ${{ vars.FORGEJO }}
|
||||||
|
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
|
|
||||||
runs-on: docker
|
runs-on: docker
|
||||||
container:
|
container:
|
||||||
image: data.forgejo.org/renovate/renovate:40.11.19
|
image: data.forgejo.org/renovate/renovate:41.1.4
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Load renovate repo cache
|
- name: Load renovate repo cache
|
||||||
|
|
71
.forgejo/workflows/testing-integration.yml
Normal file
71
.forgejo/workflows/testing-integration.yml
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#
|
||||||
|
# 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.30
|
||||||
|
uses: ./.forgejo/workflows-composite/apt-install-from
|
||||||
|
with:
|
||||||
|
packages: git/bullseye git-lfs/bullseye
|
||||||
|
release: bullseye
|
||||||
|
- 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.30
|
||||||
|
uses: ./.forgejo/workflows-composite/apt-install-from
|
||||||
|
with:
|
||||||
|
packages: git/bullseye git-lfs/bullseye
|
||||||
|
release: bullseye
|
||||||
|
- 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,6 +91,7 @@ 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
|
||||||
|
@ -114,6 +115,11 @@ 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@v46
|
||||||
|
@ -126,6 +132,7 @@ 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
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
# Javascript and CSS code.
|
# Javascript and CSS code.
|
||||||
web_src/.* @beowulf @gusted
|
web_src/.* @beowulf @gusted
|
||||||
|
web_src/css/.* @0ko
|
||||||
|
|
||||||
# HTML templates used by the backend.
|
# HTML templates used by the backend.
|
||||||
templates/.* @beowulf @gusted
|
templates/.* @beowulf @gusted
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
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.21 AS build-env
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
||||||
|
@ -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
|
RUN make clean-no-bindata
|
||||||
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 RELEASE_VERSION=$RELEASE_VERSION GOFLAGS="-trimpath" go-check generate-backend static-executable && xx-verify gitea
|
RUN LDFLAGS="-buildid=" make FORGEJO_GENERATE_SKIP_HASH=true 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.21
|
FROM data.forgejo.org/oci/alpine:3.22
|
||||||
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,6 +1,6 @@
|
||||||
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.21 AS build-env
|
FROM --platform=$BUILDPLATFORM data.forgejo.org/oci/golang:1.24-alpine3.22 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
ENV GOPROXY=${GOPROXY:-https://proxy.golang.org,direct}
|
||||||
|
@ -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
|
RUN make clean-no-bindata
|
||||||
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 RELEASE_VERSION=$RELEASE_VERSION go-check generate-backend static-executable && xx-verify gitea
|
RUN make FORGEJO_GENERATE_SKIP_HASH=true 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.21
|
FROM data.forgejo.org/oci/alpine:3.22
|
||||||
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" \
|
||||||
|
|
30
Makefile
30
Makefile
|
@ -37,19 +37,17 @@ 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.2.1 # renovate: datasource=go
|
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.3.0 # renovate: datasource=go
|
||||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.0 # renovate: datasource=go
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.8.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/v2/cmd/golangci-lint@v2.1.6 # 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.32.0 # renovate: datasource=go
|
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.34.0 # renovate: datasource=go
|
||||||
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.1 # renovate: datasource=go
|
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.5.2 # renovate: datasource=go
|
||||||
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.18.1 # renovate: datasource=go
|
RENOVATE_NPM_PACKAGE ?= renovate@41.1.4 # renovate: datasource=docker packageName=data.forgejo.org/renovate/renovate
|
||||||
RENOVATE_NPM_PACKAGE ?= renovate@40.11.19 # 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: ...
|
||||||
|
@ -130,7 +128,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/public/bindata.go modules/options/bindata.go modules/templates/bindata.go
|
BINDATA_DEST := modules/migration/bindata.go 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
|
||||||
|
@ -223,7 +221,6 @@ help:
|
||||||
@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"
|
||||||
|
@ -326,8 +323,12 @@ clean-all: clean
|
||||||
rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
|
rm -rf $(WEBPACK_DEST_ENTRIES) node_modules
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean: clean-no-bindata
|
||||||
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \
|
rm -rf $(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-* \
|
||||||
|
@ -484,11 +485,6 @@ 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
|
||||||
|
@ -557,7 +553,7 @@ test-check:
|
||||||
|
|
||||||
.PHONY: test\#%
|
.PHONY: test\#%
|
||||||
test\#%:
|
test\#%:
|
||||||
@echo "Running go test with -tags '$(TEST_TAGS)'..."
|
@echo "Running go test with $(GOTESTFLAGS) -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
|
||||||
|
@ -924,13 +920,11 @@ 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
|
||||||
|
|
46
assets/go-licenses.json
generated
46
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
14
build.go
14
build.go
|
@ -1,14 +0,0 @@
|
||||||
// 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,5 +1,6 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// SPDX-License-Identifier: MIT
|
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
//go:build ignore
|
//go:build ignore
|
||||||
|
|
||||||
|
@ -7,30 +8,40 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/sha1"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"github.com/shurcooL/vfsgen"
|
"github.com/klauspost/compress/zstd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func needsUpdate(dir, filename string) (bool, []byte) {
|
func fileExists(filename string) bool {
|
||||||
needRegen := false
|
|
||||||
_, err := os.Stat(filename)
|
_, err := os.Stat(filename)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
needRegen = true
|
return true
|
||||||
}
|
}
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func needsUpdate(dir, filename string) (bool, []byte) {
|
||||||
|
needRegen := !fileExists(filename)
|
||||||
|
|
||||||
oldHash, err := os.ReadFile(filename + ".hash")
|
oldHash, err := os.ReadFile(filename + ".hash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
oldHash = []byte{}
|
oldHash = []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher := sha1.New()
|
hasher := sha256.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 {
|
||||||
|
@ -51,7 +62,7 @@ func needsUpdate(dir, filename string) (bool, []byte) {
|
||||||
|
|
||||||
newHash := hasher.Sum([]byte{})
|
newHash := hasher.Sum([]byte{})
|
||||||
|
|
||||||
if bytes.Compare(oldHash, newHash) != 0 {
|
if !bytes.Equal(oldHash, newHash) {
|
||||||
return true, newHash
|
return true, newHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,24 +80,280 @@ func main() {
|
||||||
useGlobalModTime, _ = strconv.ParseBool(os.Args[4])
|
useGlobalModTime, _ = strconv.ParseBool(os.Args[4])
|
||||||
}
|
}
|
||||||
|
|
||||||
update, newHash := needsUpdate(dir, filename)
|
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)
|
||||||
if !update {
|
if !update {
|
||||||
fmt.Printf("bindata for %s already up-to-date\n", packageName)
|
fmt.Printf("bindata %s already exists and the checksum is a match\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)
|
|
||||||
err := vfsgen.Generate(fsTemplates, vfsgen.Options{
|
root, err := os.OpenRoot(dir)
|
||||||
PackageName: packageName,
|
|
||||||
BuildTags: "bindata",
|
|
||||||
VariableName: "Assets",
|
|
||||||
Filename: filename,
|
|
||||||
UseGlobalModTime: useGlobalModTime,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("%v\n", err)
|
log.Fatal(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 }
|
||||||
|
`))
|
||||||
|
|
|
@ -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")
|
policy.AllowElements("strong", "br", "b", "strike", "code", "i", "kbd")
|
||||||
|
|
||||||
// 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")
|
||||||
|
|
|
@ -37,6 +37,7 @@ 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.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.")))
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,25 +4,28 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdActionsGenRunnerToken,
|
subcmdActionsGenRunnerToken(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdActionsGenRunnerToken = &cli.Command{
|
func 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,
|
||||||
|
@ -36,10 +39,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runGenerateActionsRunnerToken(c *cli.Context) error {
|
func runGenerateActionsRunnerToken(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
70
cmd/admin.go
70
cmd/admin.go
|
@ -15,56 +15,64 @@ 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdUser,
|
subcmdUser(),
|
||||||
subcmdRepoSyncReleases,
|
subcmdRepoSyncReleases(),
|
||||||
subcmdRegenerate,
|
subcmdRegenerate(),
|
||||||
subcmdAuth,
|
subcmdAuth(),
|
||||||
subcmdSendMail,
|
subcmdSendMail(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdRepoSyncReleases = &cli.Command{
|
func 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,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdRegenerate = &cli.Command{
|
func subcmdRegenerate() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "regenerate",
|
Name: "regenerate",
|
||||||
Usage: "Regenerate specific files",
|
Usage: "Regenerate specific files",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdRegenHooks,
|
microcmdRegenHooks,
|
||||||
microcmdRegenKeys,
|
microcmdRegenKeys,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdAuth = &cli.Command{
|
func subcmdAuth() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "auth",
|
Name: "auth",
|
||||||
Usage: "Modify external auth providers",
|
Usage: "Modify external auth providers",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdAuthAddOauth,
|
microcmdAuthAddOauth(),
|
||||||
microcmdAuthUpdateOauth,
|
microcmdAuthUpdateOauth(),
|
||||||
microcmdAuthAddLdapBindDn,
|
microcmdAuthAddLdapBindDn(),
|
||||||
microcmdAuthUpdateLdapBindDn,
|
microcmdAuthUpdateLdapBindDn(),
|
||||||
microcmdAuthAddLdapSimpleAuth,
|
microcmdAuthAddLdapSimpleAuth(),
|
||||||
microcmdAuthUpdateLdapSimpleAuth,
|
microcmdAuthUpdateLdapSimpleAuth(),
|
||||||
microcmdAuthAddSMTP,
|
microcmdAuthAddSMTP(),
|
||||||
microcmdAuthUpdateSMTP,
|
microcmdAuthUpdateSMTP(),
|
||||||
microcmdAuthList,
|
microcmdAuthList(),
|
||||||
microcmdAuthDelete,
|
microcmdAuthDelete(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdSendMail = &cli.Command{
|
func 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,
|
||||||
|
@ -86,15 +94,17 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
idFlag = &cli.Int64Flag{
|
func idFlag() *cli.Int64Flag {
|
||||||
|
return &cli.Int64Flag{
|
||||||
Name: "id",
|
Name: "id",
|
||||||
Usage: "ID of authentication source",
|
Usage: "ID of authentication source",
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runRepoSyncReleases(_ *cli.Context) error {
|
func runRepoSyncReleases(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -13,17 +14,20 @@ 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func microcmdAuthDelete() *cli.Command {
|
||||||
microcmdAuthDelete = &cli.Command{
|
return &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,
|
||||||
|
@ -54,10 +58,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runListAuth(c *cli.Context) error {
|
func runListAuth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -81,7 +85,7 @@ func runListAuth(c *cli.Context) 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.Fprintf(w, "ID\tName\tType\tEnabled\n")
|
fmt.Fprint(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)
|
||||||
}
|
}
|
||||||
|
@ -90,12 +94,12 @@ func runListAuth(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteAuth(c *cli.Context) error {
|
func runDeleteAuth(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
@ -23,8 +23,8 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func commonLdapCLIFlags() []cli.Flag {
|
||||||
commonLdapCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Usage: "Authentication name.",
|
Usage: "Authentication name.",
|
||||||
|
@ -102,8 +102,10 @@ var (
|
||||||
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.",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ldapBindDnCLIFlags = append(commonLdapCLIFlags,
|
func ldapBindDnCLIFlags() []cli.Flag {
|
||||||
|
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.",
|
||||||
|
@ -128,49 +130,59 @@ var (
|
||||||
Name: "page-size",
|
Name: "page-size",
|
||||||
Usage: "Search page size.",
|
Usage: "Search page size.",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags,
|
func ldapSimpleAuthCLIFlags() []cli.Flag {
|
||||||
|
return append(commonLdapCLIFlags(),
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "user-dn",
|
Name: "user-dn",
|
||||||
Usage: "The user's DN.",
|
Usage: "The user's DN.",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddLdapBindDn = &cli.Command{
|
func 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(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().addLdapBindDn(c)
|
return newAuthService().addLdapBindDn(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: ldapBindDnCLIFlags,
|
Flags: ldapBindDnCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateLdapBindDn = &cli.Command{
|
func 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(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().updateLdapBindDn(c)
|
return newAuthService().updateLdapBindDn(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...),
|
Flags: append([]cli.Flag{idFlag()}, ldapBindDnCLIFlags()...),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddLdapSimpleAuth = &cli.Command{
|
func 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(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().addLdapSimpleAuth(c)
|
return newAuthService().addLdapSimpleAuth(ctx, cli)
|
||||||
},
|
},
|
||||||
Flags: ldapSimpleAuthCLIFlags,
|
Flags: ldapSimpleAuthCLIFlags(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateLdapSimpleAuth = &cli.Command{
|
func 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(c *cli.Context) error {
|
Action: func(ctx context.Context, cli *cli.Command) error {
|
||||||
return newAuthService().updateLdapSimpleAuth(c)
|
return newAuthService().updateLdapSimpleAuth(ctx, cli)
|
||||||
},
|
},
|
||||||
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 {
|
||||||
|
@ -183,7 +195,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.Context, authSource *auth.Source) {
|
func parseAuthSource(c *cli.Command, authSource *auth.Source) {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
authSource.Name = c.String("name")
|
authSource.Name = c.String("name")
|
||||||
}
|
}
|
||||||
|
@ -202,7 +214,7 @@ func parseAuthSource(c *cli.Context, 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.Context, config *ldap.Source) error {
|
func parseLdapConfig(c *cli.Command, config *ldap.Source) error {
|
||||||
if c.IsSet("name") {
|
if c.IsSet("name") {
|
||||||
config.Name = c.String("name")
|
config.Name = c.String("name")
|
||||||
}
|
}
|
||||||
|
@ -289,7 +301,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.Context, authType auth.Type) (*auth.Source, error) {
|
func (a *authService) getAuthSource(ctx context.Context, c *cli.Command, 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
|
||||||
}
|
}
|
||||||
|
@ -307,12 +319,12 @@ func (a *authService) getAuthSource(ctx context.Context, c *cli.Context, 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(c *cli.Context) error {
|
func (a *authService) addLdapBindDn(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -336,8 +348,8 @@ func (a *authService) addLdapBindDn(c *cli.Context) 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(c *cli.Context) error {
|
func (a *authService) updateLdapBindDn(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -358,12 +370,12 @@ func (a *authService) updateLdapBindDn(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
// addLdapSimpleAuth adds a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
|
func (a *authService) addLdapSimpleAuth(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
@ -387,8 +399,8 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source.
|
||||||
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
|
func (a *authService) updateLdapSimpleAuth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := a.initDB(ctx); err != nil {
|
if err := a.initDB(ctx); err != nil {
|
||||||
|
|
|
@ -13,7 +13,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAddLdapBindDn(t *testing.T) {
|
func TestAddLdapBindDn(t *testing.T) {
|
||||||
|
@ -225,12 +225,12 @@ func TestAddLdapBindDn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthAddLdapBindDn.Flags
|
app.Flags = microcmdAuthAddLdapBindDn().Flags
|
||||||
app.Action = service.addLdapBindDn
|
app.Action = service.addLdapBindDn
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), 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 {
|
||||||
|
@ -454,12 +454,12 @@ func TestAddLdapSimpleAuth(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthAddLdapSimpleAuth.Flags
|
app.Flags = microcmdAuthAddLdapSimpleAuth().Flags
|
||||||
app.Action = service.addLdapSimpleAuth
|
app.Action = service.addLdapSimpleAuth
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), 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 {
|
||||||
|
@ -915,12 +915,12 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthUpdateLdapBindDn.Flags
|
app.Flags = microcmdAuthUpdateLdapBindDn().Flags
|
||||||
app.Action = service.updateLdapBindDn
|
app.Action = service.updateLdapBindDn
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), 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 {
|
||||||
|
@ -1303,12 +1303,12 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a copy of command to test
|
// Create a copy of command to test
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags
|
app.Flags = microcmdAuthUpdateLdapSimpleAuth().Flags
|
||||||
app.Action = service.updateLdapSimpleAuth
|
app.Action = service.updateLdapSimpleAuth
|
||||||
|
|
||||||
// Run it
|
// Run it
|
||||||
err := app.Run(c.args)
|
err := app.Run(t.Context(), 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,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -11,11 +12,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func oauthCLIFlags() []cli.Flag {
|
||||||
oauthCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
@ -120,23 +121,27 @@ var (
|
||||||
Usage: "Activate automatic team membership removal depending on groups",
|
Usage: "Activate automatic team membership removal depending on groups",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddOauth = &cli.Command{
|
func 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(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateOauth = &cli.Command{
|
func 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(c *cli.Context) *oauth2.Source {
|
func parseOAuth2Config(_ context.Context, c *cli.Command) *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{
|
||||||
|
@ -168,15 +173,15 @@ func parseOAuth2Config(c *cli.Context) *oauth2.Source {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddOauth(c *cli.Context) error {
|
func runAddOauth(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := parseOAuth2Config(c)
|
config := parseOAuth2Config(ctx, 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") {
|
||||||
|
@ -192,12 +197,12 @@ func runAddOauth(c *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpdateOauth(c *cli.Context) error {
|
func runUpdateOauth(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -11,11 +12,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func smtpCLIFlags() []cli.Flag {
|
||||||
smtpCLIFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
@ -71,23 +72,27 @@ var (
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthAddSMTP = &cli.Command{
|
func 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(),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdAuthUpdateSMTP = &cli.Command{
|
func 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.Context, conf *smtp.Source) error {
|
func parseSMTPConfig(c *cli.Command, 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"}
|
||||||
|
@ -123,8 +128,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddSMTP(c *cli.Context) error {
|
func runAddSMTP(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -163,12 +168,12 @@ func runAddSMTP(c *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpdateSMTP(c *cli.Context) error {
|
func runUpdateSMTP(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,11 +4,13 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -25,8 +27,8 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func runRegenerateHooks(_ *cli.Context) error {
|
func runRegenerateHooks(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -35,8 +37,8 @@ func runRegenerateHooks(_ *cli.Context) error {
|
||||||
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext())
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRegenerateKeys(_ *cli.Context) error {
|
func runRegenerateKeys(ctx context.Context, _ *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,18 +4,21 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var subcmdUser = &cli.Command{
|
func subcmdUser() *cli.Command {
|
||||||
Name: "user",
|
return &cli.Command{
|
||||||
Usage: "Modify users",
|
Name: "user",
|
||||||
Subcommands: []*cli.Command{
|
Usage: "Modify users",
|
||||||
microcmdUserCreate,
|
Commands: []*cli.Command{
|
||||||
microcmdUserList,
|
microcmdUserCreate(),
|
||||||
microcmdUserChangePassword,
|
microcmdUserList(),
|
||||||
microcmdUserDelete,
|
microcmdUserChangePassword(),
|
||||||
microcmdUserGenerateAccessToken,
|
microcmdUserDelete(),
|
||||||
microcmdUserMustChangePassword,
|
microcmdUserGenerateAccessToken(),
|
||||||
},
|
microcmdUserMustChangePassword(),
|
||||||
|
microcmdUserResetMFA(),
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -13,40 +14,42 @@ 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserChangePassword = &cli.Command{
|
func microcmdUserChangePassword() *cli.Command {
|
||||||
Name: "change-password",
|
return &cli.Command{
|
||||||
Usage: "Change a user's password",
|
Name: "change-password",
|
||||||
Action: runChangePassword,
|
Usage: "Change a user's password",
|
||||||
Flags: []cli.Flag{
|
Action: runChangePassword,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "username",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"u"},
|
Name: "username",
|
||||||
Value: "",
|
Aliases: []string{"u"},
|
||||||
Usage: "The user to change password for",
|
Value: "",
|
||||||
|
Usage: "The user to change password for",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New password to set for user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "User must change password",
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "password",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New password to set for user",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "User must change password",
|
|
||||||
Value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runChangePassword(c *cli.Context) error {
|
func runChangePassword(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -15,75 +16,76 @@ import (
|
||||||
"forgejo.org/modules/optional"
|
"forgejo.org/modules/optional"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserCreate = &cli.Command{
|
func microcmdUserCreate() *cli.Command {
|
||||||
Name: "create",
|
return &cli.Command{
|
||||||
Usage: "Create a new user in database",
|
Name: "create",
|
||||||
Action: runCreateUser,
|
Usage: "Create a new user in database",
|
||||||
Flags: []cli.Flag{
|
Action: runCreateUser,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "name",
|
&cli.StringFlag{
|
||||||
Usage: "Username. DEPRECATED: use username instead",
|
Name: "name",
|
||||||
|
Usage: "Username. DEPRECATED: use username instead",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Usage: "Username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Usage: "User password",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Usage: "User email address",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "admin",
|
||||||
|
Usage: "User is an admin",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "random-password",
|
||||||
|
Usage: "Generate a random password for the user",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "must-change-password",
|
||||||
|
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
||||||
|
Value: true,
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "random-password-length",
|
||||||
|
Usage: "Length of the random password to be generated",
|
||||||
|
Value: 12,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "access-token",
|
||||||
|
Usage: "Generate access token for the user",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-name",
|
||||||
|
Usage: `Name of the generated access token`,
|
||||||
|
Value: "gitea-admin",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "access-token-scopes",
|
||||||
|
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
||||||
|
Value: "all",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "restricted",
|
||||||
|
Usage: "Make a restricted user account",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "fullname",
|
||||||
|
Usage: `The full, human-readable name of the user`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "username",
|
|
||||||
Usage: "Username",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "password",
|
|
||||||
Usage: "User password",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Usage: "User email address",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "admin",
|
|
||||||
Usage: "User is an admin",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "random-password",
|
|
||||||
Usage: "Generate a random password for the user",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "must-change-password",
|
|
||||||
Usage: "Set this option to false to prevent forcing the user to change their password after initial login",
|
|
||||||
Value: true,
|
|
||||||
DisableDefaultText: true,
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "random-password-length",
|
|
||||||
Usage: "Length of the random password to be generated",
|
|
||||||
Value: 12,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "access-token",
|
|
||||||
Usage: "Generate access token for the user",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-name",
|
|
||||||
Usage: `Name of the generated access token`,
|
|
||||||
Value: "gitea-admin",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "access-token-scopes",
|
|
||||||
Usage: `Scopes of the generated access token, comma separated. Examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
||||||
Value: "all",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "restricted",
|
|
||||||
Usage: "Make a restricted user account",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "fullname",
|
|
||||||
Usage: `The full, human-readable name of the user`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCreateUser(c *cli.Context) error {
|
func runCreateUser(ctx context.Context, c *cli.Command) 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()
|
||||||
|
@ -108,10 +110,10 @@ func runCreateUser(c *cli.Context) error {
|
||||||
username = c.String("username")
|
username = c.String("username")
|
||||||
} else {
|
} else {
|
||||||
username = c.String("name")
|
username = c.String("name")
|
||||||
_, _ = fmt.Fprintf(c.App.ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
_, _ = fmt.Fprint(c.Root().ErrWriter, "--name flag is deprecated. Use --username instead.\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -12,41 +13,43 @@ 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserDelete = &cli.Command{
|
func microcmdUserDelete() *cli.Command {
|
||||||
Name: "delete",
|
return &cli.Command{
|
||||||
Usage: "Delete specific user by id, name or email",
|
Name: "delete",
|
||||||
Flags: []cli.Flag{
|
Usage: "Delete specific user by id, name or email",
|
||||||
&cli.Int64Flag{
|
Flags: []cli.Flag{
|
||||||
Name: "id",
|
&cli.Int64Flag{
|
||||||
Usage: "ID of user of the user to delete",
|
Name: "id",
|
||||||
|
Usage: "ID of user of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Username of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "email",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Email of the user to delete",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "purge",
|
||||||
|
Usage: "Purge user, all their repositories, organizations and comments",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
Action: runDeleteUser,
|
||||||
Name: "username",
|
}
|
||||||
Aliases: []string{"u"},
|
|
||||||
Usage: "Username of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "email",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Email of the user to delete",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "purge",
|
|
||||||
Usage: "Purge user, all their repositories, organizations and comments",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runDeleteUser,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDeleteUser(c *cli.Context) error {
|
func runDeleteUser(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,49 +4,52 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserGenerateAccessToken = &cli.Command{
|
func microcmdUserGenerateAccessToken() *cli.Command {
|
||||||
Name: "generate-access-token",
|
return &cli.Command{
|
||||||
Usage: "Generate an access token for a specific user",
|
Name: "generate-access-token",
|
||||||
Flags: []cli.Flag{
|
Usage: "Generate an access token for a specific user",
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "username",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"u"},
|
Name: "username",
|
||||||
Usage: "Username",
|
Aliases: []string{"u"},
|
||||||
|
Usage: "Username",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "token-name",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "Token name",
|
||||||
|
Value: "gitea-admin",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "raw",
|
||||||
|
Usage: "Display only the token value",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "scopes",
|
||||||
|
Value: "all",
|
||||||
|
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
Action: runGenerateAccessToken,
|
||||||
Name: "token-name",
|
}
|
||||||
Aliases: []string{"t"},
|
|
||||||
Usage: "Token name",
|
|
||||||
Value: "gitea-admin",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "raw",
|
|
||||||
Usage: "Display only the token value",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "scopes",
|
|
||||||
Value: "all",
|
|
||||||
Usage: `Comma separated list of scopes to apply to access token, examples: "all", "public-only,read:issue", "write:repository,write:user"`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: runGenerateAccessToken,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateAccessToken(c *cli.Context) error {
|
func runGenerateAccessToken(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
|
|
@ -4,29 +4,32 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserList = &cli.Command{
|
func microcmdUserList() *cli.Command {
|
||||||
Name: "list",
|
return &cli.Command{
|
||||||
Usage: "List users",
|
Name: "list",
|
||||||
Action: runListUsers,
|
Usage: "List users",
|
||||||
Flags: []cli.Flag{
|
Action: runListUsers,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "admin",
|
&cli.BoolFlag{
|
||||||
Usage: "List only admin users",
|
Name: "admin",
|
||||||
|
Usage: "List only admin users",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListUsers(c *cli.Context) error {
|
func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(ctx); err != nil {
|
if err := initDB(ctx); err != nil {
|
||||||
|
@ -41,7 +44,7 @@ func runListUsers(c *cli.Context) 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.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n")
|
fmt.Fprint(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)
|
||||||
|
@ -49,7 +52,7 @@ func runListUsers(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
||||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
fmt.Fprint(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,38 +4,41 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var microcmdUserMustChangePassword = &cli.Command{
|
func microcmdUserMustChangePassword() *cli.Command {
|
||||||
Name: "must-change-password",
|
return &cli.Command{
|
||||||
Usage: "Set the must change password flag for the provided users or all users",
|
Name: "must-change-password",
|
||||||
Action: runMustChangePassword,
|
Usage: "Set the must change password flag for the provided users or all users",
|
||||||
Flags: []cli.Flag{
|
Action: runMustChangePassword,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "all",
|
&cli.BoolFlag{
|
||||||
Aliases: []string{"A"},
|
Name: "all",
|
||||||
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
Aliases: []string{"A"},
|
||||||
|
Usage: "All users must change password, except those explicitly excluded with --exclude",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "exclude",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Usage: "Do not change the must-change-password flag for these users",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "unset",
|
||||||
|
Usage: "Instead of setting the must-change-password flag, unset it",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
}
|
||||||
Name: "exclude",
|
|
||||||
Aliases: []string{"e"},
|
|
||||||
Usage: "Do not change the must-change-password flag for these users",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "unset",
|
|
||||||
Usage: "Instead of setting the must-change-password flag, unset it",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMustChangePassword(c *cli.Context) error {
|
func runMustChangePassword(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() == 0 && !c.IsSet("all") {
|
if c.NArg() == 0 && !c.IsSet("all") {
|
||||||
|
|
73
cmd/admin_user_reset_mfa.go
Normal file
73
cmd/admin_user_reset_mfa.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// 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
|
||||||
|
}
|
77
cmd/cert.go
77
cmd/cert.go
|
@ -6,6 +6,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
@ -20,47 +21,49 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdCert represents the available cert sub-command.
|
// CmdCert represents the available cert sub-command.
|
||||||
var CmdCert = &cli.Command{
|
func cmdCert() *cli.Command {
|
||||||
Name: "cert",
|
return &cli.Command{
|
||||||
Usage: "Generate self-signed certificate",
|
Name: "cert",
|
||||||
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
Usage: "Generate self-signed certificate",
|
||||||
|
Description: `Generate a self-signed X.509 certificate for a TLS server.
|
||||||
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
Outputs to 'cert.pem' and 'key.pem' and will overwrite existing files.`,
|
||||||
Action: runCert,
|
Action: runCert,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "host",
|
Name: "host",
|
||||||
Value: "",
|
Value: "",
|
||||||
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
Usage: "Comma-separated hostnames and IPs to generate a certificate for",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "ecdsa-curve",
|
||||||
|
Value: "",
|
||||||
|
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "rsa-bits",
|
||||||
|
Value: 3072,
|
||||||
|
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "start-date",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
||||||
|
},
|
||||||
|
&cli.DurationFlag{
|
||||||
|
Name: "duration",
|
||||||
|
Value: 365 * 24 * time.Hour,
|
||||||
|
Usage: "Duration that certificate is valid for",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "ca",
|
||||||
|
Usage: "whether this cert should be its own Certificate Authority",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "ecdsa-curve",
|
|
||||||
Value: "",
|
|
||||||
Usage: "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521",
|
|
||||||
},
|
|
||||||
&cli.IntFlag{
|
|
||||||
Name: "rsa-bits",
|
|
||||||
Value: 3072,
|
|
||||||
Usage: "Size of RSA key to generate. Ignored if --ecdsa-curve is set",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "start-date",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Creation date formatted as Jan 1 15:04:05 2011",
|
|
||||||
},
|
|
||||||
&cli.DurationFlag{
|
|
||||||
Name: "duration",
|
|
||||||
Value: 365 * 24 * time.Hour,
|
|
||||||
Usage: "Duration that certificate is valid for",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "ca",
|
|
||||||
Usage: "whether this cert should be its own Certificate Authority",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func publicKey(priv any) any {
|
func publicKey(priv any) any {
|
||||||
|
@ -89,7 +92,7 @@ func pemBlockForKey(priv any) *pem.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCert(c *cli.Context) error {
|
func runCert(ctx context.Context, c *cli.Command) error {
|
||||||
if err := argsSet(c, "host"); err != nil {
|
if err := argsSet(c, "host"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
26
cmd/cmd.go
26
cmd/cmd.go
|
@ -20,19 +20,21 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.Context, args ...string) error {
|
func argsSet(c *cli.Command, 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 util.IsEmptyString(c.String(a)) {
|
if s, ok := c.Value(a).(string); ok {
|
||||||
return errors.New(a + " is required")
|
if util.IsEmptyString(s) {
|
||||||
|
return errors.New(a + " is required")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -73,8 +75,8 @@ If this is the intended configuration file complete the [database] section.`, se
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func installSignals() (context.Context, context.CancelFunc) {
|
func installSignals(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
go func() {
|
go func() {
|
||||||
// install notify
|
// install notify
|
||||||
signalChannel := make(chan os.Signal, 1)
|
signalChannel := make(chan os.Signal, 1)
|
||||||
|
@ -109,7 +111,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.Context, name string) bool {
|
func globalBool(c *cli.Command, 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
|
||||||
|
@ -120,16 +122,16 @@ func globalBool(c *cli.Context, 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(*cli.Context) error {
|
func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
return func(c *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
level := defaultLevel
|
level := defaultLevel
|
||||||
if globalBool(c, "quiet") {
|
if globalBool(cli, "quiet") {
|
||||||
level = log.FATAL
|
level = log.FATAL
|
||||||
}
|
}
|
||||||
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
if globalBool(cli, "debug") || globalBool(cli, "verbose") {
|
||||||
level = log.TRACE
|
level = log.TRACE
|
||||||
}
|
}
|
||||||
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
||||||
return nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
cmd/docs.go
65
cmd/docs.go
|
@ -1,65 +0,0 @@
|
||||||
// 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
|
|
||||||
}
|
|
129
cmd/doctor.go
129
cmd/doctor.go
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
golog "log"
|
golog "log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,80 +20,86 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/services/doctor"
|
"forgejo.org/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDoctor represents the available doctor sub-command.
|
// CmdDoctor represents the available doctor sub-command.
|
||||||
var CmdDoctor = &cli.Command{
|
func cmdDoctor() *cli.Command {
|
||||||
Name: "doctor",
|
return &cli.Command{
|
||||||
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
Name: "doctor",
|
||||||
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.",
|
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.",
|
||||||
|
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
cmdDoctorCheck,
|
cmdDoctorCheck(),
|
||||||
cmdRecreateTable,
|
cmdRecreateTable(),
|
||||||
cmdDoctorConvert,
|
cmdDoctorConvert(),
|
||||||
},
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdDoctorCheck = &cli.Command{
|
func cmdDoctorCheck() *cli.Command {
|
||||||
Name: "check",
|
return &cli.Command{
|
||||||
Usage: "Diagnose and optionally fix problems",
|
Name: "check",
|
||||||
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.",
|
Usage: "Diagnose and optionally fix problems",
|
||||||
Action: runDoctorCheck,
|
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.",
|
||||||
Flags: []cli.Flag{
|
Action: runDoctorCheck,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "list",
|
&cli.BoolFlag{
|
||||||
Usage: "List the available checks",
|
Name: "list",
|
||||||
|
Usage: "List the available checks",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "default",
|
||||||
|
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "run",
|
||||||
|
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "all",
|
||||||
|
Usage: "Run all the available checks",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "fix",
|
||||||
|
Usage: "Automatically fix what we can",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "log-file",
|
||||||
|
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "color",
|
||||||
|
Aliases: []string{"H"},
|
||||||
|
Usage: "Use color for outputted information",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "default",
|
|
||||||
Usage: "Run the default checks (if neither --run or --all is set, this is the default behaviour)",
|
|
||||||
},
|
|
||||||
&cli.StringSliceFlag{
|
|
||||||
Name: "run",
|
|
||||||
Usage: "Run the provided checks - (if --default is set, the default checks will also run)",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "all",
|
|
||||||
Usage: "Run all the available checks",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "fix",
|
|
||||||
Usage: "Automatically fix what we can",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "log-file",
|
|
||||||
Usage: `Name of the log file (no verbose log output by default). Set to "-" to output to stdout`,
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "color",
|
|
||||||
Aliases: []string{"H"},
|
|
||||||
Usage: "Use color for outputted information",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdRecreateTable = &cli.Command{
|
func cmdRecreateTable() *cli.Command {
|
||||||
Name: "recreate-table",
|
return &cli.Command{
|
||||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
Name: "recreate-table",
|
||||||
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||||
Flags: []cli.Flag{
|
ArgsUsage: "[TABLE]... : (TABLEs to recreate - leave blank for all)",
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "debug",
|
&cli.BoolFlag{
|
||||||
Usage: "Print SQL commands sent",
|
Name: "debug",
|
||||||
|
Usage: "Print SQL commands sent",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns.
|
||||||
Description: `The database definitions Forgejo uses change across versions, sometimes changing default values and leaving old unused columns.
|
|
||||||
|
|
||||||
This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
|
This command will cause Xorm to recreate tables, copying over the data and deleting the old table.
|
||||||
|
|
||||||
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(ctx *cli.Context) error {
|
func runRecreateTable(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Redirect the default golog to here
|
// Redirect the default golog to here
|
||||||
|
@ -143,7 +150,7 @@ func runRecreateTable(ctx *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
func setupDoctorDefaultLogger(ctx *cli.Command, colorize bool) {
|
||||||
// Silence the default loggers
|
// Silence the default loggers
|
||||||
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
setupConsoleLogger(log.FATAL, log.CanColorStderr, os.Stderr)
|
||||||
|
|
||||||
|
@ -165,8 +172,8 @@ func setupDoctorDefaultLogger(ctx *cli.Context, colorize bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorCheck(ctx *cli.Context) error {
|
func runDoctorCheck(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
colorize := log.CanColorStdout
|
colorize := log.CanColorStdout
|
||||||
|
|
|
@ -4,25 +4,28 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdDoctorConvert represents the available convert sub-command.
|
// cmdDoctorConvert represents the available convert sub-command.
|
||||||
var cmdDoctorConvert = &cli.Command{
|
func cmdDoctorConvert() *cli.Command {
|
||||||
Name: "convert",
|
return &cli.Command{
|
||||||
Usage: "Convert the database",
|
Name: "convert",
|
||||||
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
Usage: "Convert the database",
|
||||||
Action: runDoctorConvert,
|
Description: "A command to convert an existing MySQL database from utf8 to utf8mb4",
|
||||||
|
Action: runDoctorConvert,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDoctorConvert(ctx *cli.Context) error {
|
func runDoctorConvert(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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.NewApp()
|
app := cli.Command{}
|
||||||
app.Commands = []*cli.Command{cmdDoctorCheck}
|
app.Commands = []*cli.Command{cmdDoctorCheck()}
|
||||||
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
err := app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = app.Run([]string{"./gitea", "check", "--run", "no-such"})
|
err = app.Run(t.Context(), []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([]string{"./gitea", "check", "--run", "test-check,no-such"})
|
err = app.Run(t.Context(), []string{"./gitea", "check", "--run", "test-check,no-such"})
|
||||||
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
require.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
}
|
}
|
||||||
|
|
160
cmd/dump.go
160
cmd/dump.go
|
@ -5,6 +5,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -22,7 +24,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -83,6 +85,10 @@ 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
|
||||||
|
@ -96,79 +102,81 @@ var outputTypeEnum = &outputType{
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmdDump represents the available dump sub-command.
|
// CmdDump represents the available dump sub-command.
|
||||||
var CmdDump = &cli.Command{
|
func cmdDump() *cli.Command {
|
||||||
Name: "dump",
|
return &cli.Command{
|
||||||
Usage: "Dump Forgejo files and database",
|
Name: "dump",
|
||||||
Description: `Dump compresses all related files and database into zip file.
|
Usage: "Dump Forgejo files and database",
|
||||||
|
Description: `Dump compresses all related files and database into zip file.
|
||||||
It can be used for backup and capture Forgejo server image to send to maintainer`,
|
It can be used for backup and capture Forgejo server image to send to maintainer`,
|
||||||
Action: runDump,
|
Action: runDump,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "file",
|
Name: "file",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()),
|
Value: fmt.Sprintf("forgejo-dump-%d.zip", time.Now().Unix()),
|
||||||
Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.",
|
Usage: "Name of the dump file which will be created. Supply '-' for stdout. See type for available types.",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "verbose",
|
||||||
|
Aliases: []string{"V"},
|
||||||
|
Usage: "Show process details",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "quiet",
|
||||||
|
Aliases: []string{"q"},
|
||||||
|
Usage: "Only display warnings and errors",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "tempdir",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "Temporary dir path",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "database",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-repository",
|
||||||
|
Aliases: []string{"R"},
|
||||||
|
Usage: "Skip repositories",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-log",
|
||||||
|
Aliases: []string{"L"},
|
||||||
|
Usage: "Skip logs",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-custom-dir",
|
||||||
|
Usage: "Skip custom directory",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-lfs-data",
|
||||||
|
Usage: "Skip LFS data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-attachment-data",
|
||||||
|
Usage: "Skip attachment data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-package-data",
|
||||||
|
Usage: "Skip package data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-index",
|
||||||
|
Usage: "Skip bleve index data",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "skip-repo-archives",
|
||||||
|
Usage: "Skip repository archives",
|
||||||
|
},
|
||||||
|
&cli.GenericFlag{
|
||||||
|
Name: "type",
|
||||||
|
Value: outputTypeEnum,
|
||||||
|
Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "verbose",
|
|
||||||
Aliases: []string{"V"},
|
|
||||||
Usage: "Show process details",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "quiet",
|
|
||||||
Aliases: []string{"q"},
|
|
||||||
Usage: "Only display warnings and errors",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "tempdir",
|
|
||||||
Aliases: []string{"t"},
|
|
||||||
Usage: "Temporary dir path",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "database",
|
|
||||||
Aliases: []string{"d"},
|
|
||||||
Usage: "Specify the database SQL syntax: sqlite3, mysql, postgres",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-repository",
|
|
||||||
Aliases: []string{"R"},
|
|
||||||
Usage: "Skip repositories",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-log",
|
|
||||||
Aliases: []string{"L"},
|
|
||||||
Usage: "Skip logs",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-custom-dir",
|
|
||||||
Usage: "Skip custom directory",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-lfs-data",
|
|
||||||
Usage: "Skip LFS data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-attachment-data",
|
|
||||||
Usage: "Skip attachment data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-package-data",
|
|
||||||
Usage: "Skip package data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-index",
|
|
||||||
Usage: "Skip bleve index data",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "skip-repo-archives",
|
|
||||||
Usage: "Skip repository archives",
|
|
||||||
},
|
|
||||||
&cli.GenericFlag{
|
|
||||||
Name: "type",
|
|
||||||
Value: outputTypeEnum,
|
|
||||||
Usage: fmt.Sprintf("Dump output format: %s", outputTypeEnum.Join()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fatal(format string, args ...any) {
|
func fatal(format string, args ...any) {
|
||||||
|
@ -176,7 +184,7 @@ func fatal(format string, args ...any) {
|
||||||
log.Fatal(format, args...)
|
log.Fatal(format, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDump(ctx *cli.Context) error {
|
func runDump(stdCtx context.Context, ctx *cli.Command) 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")
|
||||||
|
@ -212,16 +220,16 @@ func runDump(ctx *cli.Context) 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 fmt.Errorf("forgejo is not initialized")
|
return errors.New("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 fmt.Errorf("--quiet and --verbose cannot both be set")
|
return errors.New("--quiet and --verbose cannot both be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
err := db.InitEngine(stdCtx)
|
err := db.InitEngine(stdCtx)
|
||||||
|
|
112
cmd/dump_repo.go
112
cmd/dump_repo.go
|
@ -19,68 +19,70 @@ import (
|
||||||
"forgejo.org/services/convert"
|
"forgejo.org/services/convert"
|
||||||
"forgejo.org/services/migrations"
|
"forgejo.org/services/migrations"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdDumpRepository represents the available dump repository sub-command.
|
// CmdDumpRepository represents the available dump repository sub-command.
|
||||||
var CmdDumpRepository = &cli.Command{
|
func cmdDumpRepository() *cli.Command {
|
||||||
Name: "dump-repo",
|
return &cli.Command{
|
||||||
Usage: "Dump the repository from git/github/gitea/gitlab",
|
Name: "dump-repo",
|
||||||
Description: "This is a command for dumping the repository data.",
|
Usage: "Dump the repository from git/github/gitea/gitlab",
|
||||||
Action: runDumpRepository,
|
Description: "This is a command for dumping the repository data.",
|
||||||
Flags: []cli.Flag{
|
Action: runDumpRepository,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "git_service",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "git_service",
|
||||||
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
Value: "",
|
||||||
},
|
Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_dir",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"r"},
|
Name: "repo_dir",
|
||||||
Value: "./data",
|
Aliases: []string{"r"},
|
||||||
Usage: "Repository dir path to store the data",
|
Value: "./data",
|
||||||
},
|
Usage: "Repository dir path to store the data",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "clone_addr",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "clone_addr",
|
||||||
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
Value: "",
|
||||||
},
|
Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_username",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_username",
|
||||||
Usage: "The username to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The username to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_password",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_password",
|
||||||
Usage: "The password to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The password to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "auth_token",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "auth_token",
|
||||||
Usage: "The personal token to visit the clone_addr",
|
Value: "",
|
||||||
},
|
Usage: "The personal token to visit the clone_addr",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "owner_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "owner_name",
|
||||||
Usage: "The data will be stored on a directory with owner name if not empty",
|
Value: "",
|
||||||
},
|
Usage: "The data will be stored on a directory with owner name if not empty",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "repo_name",
|
||||||
Usage: "The data will be stored on a directory with repository name if not empty",
|
Value: "",
|
||||||
},
|
Usage: "The data will be stored on a directory with repository name if not empty",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "units",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "units",
|
||||||
Usage: `Which items will be migrated, one or more units should be separated as comma.
|
Value: "",
|
||||||
|
Usage: `Which items will be migrated, one or more units should be separated as comma.
|
||||||
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDumpRepository(ctx *cli.Context) error {
|
func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -19,23 +20,25 @@ import (
|
||||||
"forgejo.org/modules/util"
|
"forgejo.org/modules/util"
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdEmbedded represents the available extract sub-command.
|
// CmdEmbedded represents the available extract sub-command.
|
||||||
var (
|
func cmdEmbedded() *cli.Command {
|
||||||
CmdEmbedded = &cli.Command{
|
return &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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdList,
|
subcmdList(),
|
||||||
subcmdView,
|
subcmdView(),
|
||||||
subcmdExtract,
|
subcmdExtract(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdList = &cli.Command{
|
func 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,
|
||||||
|
@ -47,8 +50,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdView = &cli.Command{
|
func 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,
|
||||||
|
@ -60,8 +65,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdExtract = &cli.Command{
|
func subcmdExtract() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "extract",
|
Name: "extract",
|
||||||
Usage: "Extract resources",
|
Usage: "Extract resources",
|
||||||
Action: runExtract,
|
Action: runExtract,
|
||||||
|
@ -90,9 +97,9 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
matchedAssetFiles []assetFile
|
var matchedAssetFiles []assetFile
|
||||||
)
|
|
||||||
|
|
||||||
type assetFile struct {
|
type assetFile struct {
|
||||||
fs *assetfs.LayeredFS
|
fs *assetfs.LayeredFS
|
||||||
|
@ -100,7 +107,7 @@ type assetFile struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initEmbeddedExtractor(c *cli.Context) error {
|
func initEmbeddedExtractor(_ context.Context, c *cli.Command) 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())
|
||||||
|
@ -115,32 +122,32 @@ func initEmbeddedExtractor(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runList(c *cli.Context) error {
|
func runList(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runListDo(c); err != nil {
|
if err := runListDo(ctx, 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(c *cli.Context) error {
|
func runView(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runViewDo(c); err != nil {
|
if err := runViewDo(ctx, 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(c *cli.Context) error {
|
func runExtract(ctx context.Context, c *cli.Command) error {
|
||||||
if err := runExtractDo(c); err != nil {
|
if err := runExtractDo(ctx, c); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runListDo(c *cli.Context) error {
|
func runListDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,8 +158,8 @@ func runListDo(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runViewDo(c *cli.Context) error {
|
func runViewDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,8 +181,8 @@ func runViewDo(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runExtractDo(c *cli.Context) error {
|
func runExtractDo(ctx context.Context, c *cli.Command) error {
|
||||||
if err := initEmbeddedExtractor(c); err != nil {
|
if err := initEmbeddedExtractor(ctx, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +278,7 @@ func extractAsset(d string, a assetFile, overwrite, rename bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectAssetFilesByPattern(c *cli.Context, globs []glob.Glob, path string, layer *assetfs.Layer) {
|
func collectAssetFilesByPattern(c *cli.Command, 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,6 +6,7 @@ package forgejo
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -16,14 +17,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
SubcmdActionsGenerateRunnerToken(ctx),
|
SubcmdActionsGenerateRunnerToken(ctx),
|
||||||
SubcmdActionsGenerateRunnerSecret(ctx),
|
SubcmdActionsGenerateRunnerSecret(ctx),
|
||||||
SubcmdActionsRegister(ctx),
|
SubcmdActionsRegister(ctx),
|
||||||
|
@ -36,7 +37,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: func(cliCtx *cli.Context) error { return RunGenerateActionsRunnerToken(ctx, cliCtx) },
|
Action: RunGenerateActionsRunnerToken,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "scope",
|
Name: "scope",
|
||||||
|
@ -52,7 +53,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: func(cliCtx *cli.Context) error { return RunGenerateSecret(ctx, cliCtx) },
|
Action: RunGenerateSecret,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +62,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: func(cliCtx *cli.Context) error { return RunRegister(ctx, cliCtx) },
|
Action: RunRegister,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
|
@ -105,26 +106,26 @@ func SubcmdActionsRegister(ctx context.Context) *cli.Command {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSecret(ctx context.Context, cliCtx *cli.Context) (string, error) {
|
func readSecret(ctx context.Context, cli *cli.Command) (string, error) {
|
||||||
if cliCtx.IsSet("secret") {
|
if cli.IsSet("secret") {
|
||||||
return cliCtx.String("secret"), nil
|
return cli.String("secret"), nil
|
||||||
}
|
}
|
||||||
if cliCtx.IsSet("secret-stdin") {
|
if cli.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 cliCtx.IsSet("secret-file") {
|
if cli.IsSet("secret-file") {
|
||||||
path := cliCtx.String("secret-file")
|
path := cli.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 "", fmt.Errorf("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
return "", errors.New("at least one of the --secret, --secret-stdin, --secret-file options is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateSecret(secret string) error {
|
func validateSecret(secret string) error {
|
||||||
|
@ -138,18 +139,18 @@ func validateSecret(secret string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLabels(cliCtx *cli.Context) (*[]string, error) {
|
func getLabels(cli *cli.Command) (*[]string, error) {
|
||||||
if !cliCtx.Bool("keep-labels") {
|
if !cli.Bool("keep-labels") {
|
||||||
lblValue := strings.Split(cliCtx.String("labels"), ",")
|
lblValue := strings.Split(cli.String("labels"), ",")
|
||||||
return &lblValue, nil
|
return &lblValue, nil
|
||||||
}
|
}
|
||||||
if cliCtx.String("labels") != "" {
|
if cli.String("labels") != "" {
|
||||||
return nil, fmt.Errorf("--labels and --keep-labels should not be used together")
|
return nil, errors.New("--labels and --keep-labels should not be used together")
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
func RunRegister(ctx context.Context, cli *cli.Command) error {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -161,17 +162,17 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
}
|
}
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
secret, err := readSecret(ctx, cliCtx)
|
secret, err := readSecret(ctx, cli)
|
||||||
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 := cliCtx.String("scope")
|
scope := cli.String("scope")
|
||||||
name := cliCtx.String("name")
|
name := cli.String("name")
|
||||||
version := cliCtx.String("version")
|
version := cli.String("version")
|
||||||
labels, err := getLabels(cliCtx)
|
labels, err := getLabels(cli)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -209,7 +210,7 @@ func RunRegister(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
func RunGenerateSecret(ctx context.Context, cli *cli.Command) 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
|
||||||
|
@ -220,7 +221,7 @@ func RunGenerateSecret(ctx context.Context, cliCtx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) error {
|
func RunGenerateActionsRunnerToken(ctx context.Context, cli *cli.Command) error {
|
||||||
if !ContextGetNoInit(ctx) {
|
if !ContextGetNoInit(ctx) {
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = installSignals(ctx)
|
ctx, cancel = installSignals(ctx)
|
||||||
|
@ -229,7 +230,7 @@ func RunGenerateActionsRunnerToken(ctx context.Context, cliCtx *cli.Context) err
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
||||||
scope := cliCtx.String("scope")
|
scope := cli.String("scope")
|
||||||
|
|
||||||
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
|
||||||
if extra.HasError() {
|
if extra.HasError() {
|
||||||
|
|
|
@ -4,14 +4,13 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestActions_getLabels(t *testing.T) {
|
func TestActions_getLabels(t *testing.T) {
|
||||||
|
@ -54,21 +53,21 @@ func TestActions_getLabels(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
flags := SubcmdActionsRegister(context.Context{}).Flags
|
flags := SubcmdActionsRegister(t.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.NewApp()
|
app := cli.Command{}
|
||||||
app.Flags = flags
|
app.Flags = flags
|
||||||
app.Action = func(ctx *cli.Context) error {
|
app.Action = func(_ context.Context, ctx *cli.Command) 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(c.args)
|
_ = app.Run(t.Context(), 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
SubcmdF3Mirror(ctx),
|
SubcmdF3Mirror(ctx),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
func SubcmdF3Mirror(ctx context.Context) *cli.Command {
|
||||||
mirrorCmd := f3_cmd.CreateCmdMirror(ctx)
|
mirrorCmd := f3_cmd.CreateCmdMirror()
|
||||||
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
mirrorCmd.Before = prepareWorkPathAndCustomConf(ctx)
|
||||||
f3Action := mirrorCmd.Action
|
f3Action := mirrorCmd.Action
|
||||||
mirrorCmd.Action = func(c *cli.Context) error { return runMirror(ctx, c, f3Action) }
|
mirrorCmd.Action = func(ctx context.Context, cli *cli.Command) error { return runMirror(ctx, cli, f3Action) }
|
||||||
return mirrorCmd
|
return mirrorCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMirror(ctx context.Context, c *cli.Context, action cli.ActionFunc) error {
|
func runMirror(ctx context.Context, c *cli.Command, 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.Context, action cli.ActionFunc) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := action(c)
|
err := action(ctx, 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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{},
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*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(c *cli.Context) error {
|
func prepareWorkPathAndCustomConf(ctx context.Context) func(ctx context.Context, cli *cli.Command) (context.Context, error) {
|
||||||
return func(c *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) (context.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 c.Lineage() {
|
for _, curCtx := range cli.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(c *cli.Context) erro
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
}
|
}
|
||||||
return nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,56 +5,65 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdSecret,
|
subcmdSecret(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdSecret = &cli.Command{
|
func subcmdSecret() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
Usage: "Generate a secret token",
|
Usage: "Generate a secret token",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
microcmdGenerateInternalToken,
|
microcmdGenerateInternalToken(),
|
||||||
microcmdGenerateLfsJwtSecret,
|
microcmdGenerateLfsJwtSecret(),
|
||||||
microcmdGenerateSecretKey,
|
microcmdGenerateSecretKey(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateInternalToken = &cli.Command{
|
func 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,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateLfsJwtSecret = &cli.Command{
|
func 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,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
microcmdGenerateSecretKey = &cli.Command{
|
func 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(c *cli.Context) error {
|
func runGenerateInternalToken(ctx context.Context, c *cli.Command) error {
|
||||||
internalToken, err := generate.NewInternalToken()
|
internalToken, err := generate.NewInternalToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -63,25 +72,25 @@ func runGenerateInternalToken(c *cli.Context) error {
|
||||||
fmt.Printf("%s", internalToken)
|
fmt.Printf("%s", internalToken)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Printf("\n")
|
fmt.Println()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateLfsJwtSecret(c *cli.Context) error {
|
func runGenerateLfsJwtSecret(ctx context.Context, c *cli.Command) error {
|
||||||
_, jwtSecretBase64 := generate.NewJwtSecret()
|
_, jwtSecretBase64 := generate.NewJwtSecret()
|
||||||
|
|
||||||
fmt.Printf("%s", jwtSecretBase64)
|
fmt.Printf("%s", jwtSecretBase64)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Printf("\n")
|
fmt.Print("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGenerateSecretKey(c *cli.Context) error {
|
func runGenerateSecretKey(ctx context.Context, c *cli.Command) error {
|
||||||
secretKey, err := generate.NewSecretKey()
|
secretKey, err := generate.NewSecretKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -90,7 +99,7 @@ func runGenerateSecretKey(c *cli.Context) error {
|
||||||
fmt.Printf("%s", secretKey)
|
fmt.Printf("%s", secretKey)
|
||||||
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||||
fmt.Printf("\n")
|
fmt.Print("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
67
cmd/hook.go
67
cmd/hook.go
|
@ -21,29 +21,31 @@ 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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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),
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
subcmdHookPreReceive,
|
subcmdHookPreReceive(),
|
||||||
subcmdHookUpdate,
|
subcmdHookUpdate(),
|
||||||
subcmdHookPostReceive,
|
subcmdHookPostReceive(),
|
||||||
subcmdHookProcReceive,
|
subcmdHookProcReceive(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdHookPreReceive = &cli.Command{
|
func 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",
|
||||||
|
@ -54,7 +56,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
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",
|
||||||
|
@ -65,7 +70,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
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",
|
||||||
|
@ -76,8 +84,11 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Note: new hook since git 2.29
|
}
|
||||||
subcmdHookProcReceive = &cli.Command{
|
|
||||||
|
// Note: new hook since git 2.29
|
||||||
|
func 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",
|
||||||
|
@ -88,7 +99,7 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
type delayWriter struct {
|
type delayWriter struct {
|
||||||
internal io.Writer
|
internal io.Writer
|
||||||
|
@ -161,11 +172,11 @@ func (n *nilWriter) WriteString(s string) (int, error) {
|
||||||
return len(s), nil
|
return len(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookPreReceive(c *cli.Context) error {
|
func runHookPreReceive(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -247,7 +258,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
newCommitIDs[count] = newCommitID
|
newCommitIDs[count] = newCommitID
|
||||||
refFullNames[count] = refFullName
|
refFullNames[count] = refFullName
|
||||||
count++
|
count++
|
||||||
fmt.Fprintf(out, "*")
|
fmt.Fprint(out, "*")
|
||||||
|
|
||||||
if count >= hookBatchSize {
|
if count >= hookBatchSize {
|
||||||
fmt.Fprintf(out, " Checking %d references\n", count)
|
fmt.Fprintf(out, " Checking %d references\n", count)
|
||||||
|
@ -263,10 +274,10 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(out, ".")
|
fmt.Fprint(out, ".")
|
||||||
}
|
}
|
||||||
if lastline >= hookBatchSize {
|
if lastline >= hookBatchSize {
|
||||||
fmt.Fprintf(out, "\n")
|
fmt.Fprint(out, "\n")
|
||||||
lastline = 0
|
lastline = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,7 +294,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.Fprintf(out, "\n")
|
fmt.Fprint(out, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
fmt.Fprintf(out, "Checked %d references in total\n", total)
|
||||||
|
@ -291,13 +302,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(c *cli.Context) error {
|
func runHookUpdate(ctx context.Context, c *cli.Command) 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, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if c.NArg() != 3 {
|
if c.NArg() != 3 {
|
||||||
|
@ -323,8 +334,8 @@ func runHookUpdate(c *cli.Context) 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(c *cli.Context) error {
|
func runHookPostReceive(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -399,7 +410,7 @@ Forgejo or set your environment appropriately.`, "")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintf(out, ".")
|
fmt.Fprint(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])
|
||||||
|
@ -487,8 +498,8 @@ func hookPrintResults(results []private.HookPostReceiveBranchResult) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHookProcReceive(c *cli.Context) error {
|
func runHookProcReceive(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
|
|
@ -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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.NewApp()
|
app := cli.Command{}
|
||||||
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([]string{"./forgejo", "pre-receive"})
|
err = app.Run(t.Context(), []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([]string{"./forgejo", "pre-receive"})
|
err = app.Run(t.Context(), []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.NewApp()
|
app := cli.Command{}
|
||||||
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([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run(t.Context(), []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([]string{"./forgejo", "update", "refs/pull/1/head", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000001"})
|
err := app.Run(t.Context(), []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([]string{"./forgejo", "update", "refs/head/main", "0a51ae26bc73c47e2f754560c40904cf14ed51a9", "0000000000000000000000000000000000000000"})
|
err := app.Run(t.Context(), []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([]string{"./forgejo", "update"})
|
err := app.Run(t.Context(), []string{"./forgejo", "update"})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
73
cmd/keys.go
73
cmd/keys.go
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -11,45 +12,47 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdKeys represents the available keys sub-command
|
// CmdKeys represents the available keys sub-command
|
||||||
var CmdKeys = &cli.Command{
|
func cmdKeys() *cli.Command {
|
||||||
Name: "keys",
|
return &cli.Command{
|
||||||
Usage: "(internal) Should only be called by SSH server",
|
Name: "keys",
|
||||||
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
Usage: "(internal) Should only be called by SSH server",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Description: "Queries the Forgejo database to get the authorized command for a given ssh key fingerprint",
|
||||||
Action: runKeys,
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Flags: []cli.Flag{
|
Action: runKeys,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "expected",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"e"},
|
Name: "expected",
|
||||||
Value: "git",
|
Aliases: []string{"e"},
|
||||||
Usage: "Expected user for whom provide key commands",
|
Value: "git",
|
||||||
|
Usage: "Expected user for whom provide key commands",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "username",
|
||||||
|
Aliases: []string{"u"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Username trying to log in by SSH",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "type",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "content",
|
||||||
|
Aliases: []string{"k"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "username",
|
|
||||||
Aliases: []string{"u"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Username trying to log in by SSH",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "type",
|
|
||||||
Aliases: []string{"t"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "content",
|
|
||||||
Aliases: []string{"k"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runKeys(c *cli.Context) error {
|
func runKeys(ctx context.Context, c *cli.Command) error {
|
||||||
if !c.IsSet("username") {
|
if !c.IsSet("username") {
|
||||||
return errors.New("No username provided")
|
return errors.New("No username provided")
|
||||||
}
|
}
|
||||||
|
@ -68,7 +71,7 @@ func runKeys(c *cli.Context) error {
|
||||||
return errors.New("No key type and content provided")
|
return errors.New("No key type and content provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), true)
|
setup(ctx, c.Bool("debug"), true)
|
||||||
|
@ -78,6 +81,6 @@ func runKeys(c *cli.Context) error {
|
||||||
if extra.Error != nil {
|
if extra.Error != nil {
|
||||||
return extra.Error
|
return extra.Error
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(c.App.Writer, strings.TrimSpace(authorizedString.Text))
|
_, _ = fmt.Fprintln(c.Root().Writer, strings.TrimSpace(authorizedString.Text))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,17 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func runSendMail(c *cli.Context) error {
|
func runSendMail(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
115
cmd/main.go
115
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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(c *cli.Context) (err error) {
|
Action: func(ctx context.Context, c *cli.Command) (err error) {
|
||||||
lineage := c.Lineage() // The order is from child to parent: help, doctor, Gitea, {Command:nil}
|
lineage := c.Lineage() // The order is from child to parent: help, doctor, Forgejo
|
||||||
targetCmdIdx := 0
|
targetCmdIdx := 0
|
||||||
if c.Command.Name == "help" {
|
if c.Name == "help" {
|
||||||
targetCmdIdx = 1
|
targetCmdIdx = 1
|
||||||
}
|
}
|
||||||
if lineage[targetCmdIdx+1].Command != nil {
|
if targetCmdIdx+1 < len(lineage) {
|
||||||
err = cli.ShowCommandHelp(lineage[targetCmdIdx+1], lineage[targetCmdIdx].Command.Name)
|
err = cli.ShowCommandHelp(ctx, lineage[targetCmdIdx+1], lineage[targetCmdIdx].Name)
|
||||||
} else {
|
} else {
|
||||||
err = cli.ShowAppHelp(c)
|
err = cli.ShowAppHelp(c)
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(c.App.Writer, `
|
_, _ = fmt.Fprintf(c.Root().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 []cli.Flag) {
|
func prepareSubcommandWithConfig(command *cli.Command, globalFlags func() []cli.Flag) {
|
||||||
command.Flags = append(append([]cli.Flag{}, globalFlags...), command.Flags...)
|
command.Flags = append(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.Subcommands = append(command.Subcommands, cmdHelp())
|
command.Commands = append(command.Commands, cmdHelp())
|
||||||
}
|
}
|
||||||
for i := range command.Subcommands {
|
for i := range command.Commands {
|
||||||
prepareSubcommandWithConfig(command.Subcommands[i], globalFlags)
|
prepareSubcommandWithConfig(command.Commands[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(ctx *cli.Context) error {
|
func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(_ context.Context, _ *cli.Command) error {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx context.Context, cli *cli.Command) 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 ctx.Lineage() {
|
for _, curCtx := range cli.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,15 +107,15 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
setting.InitWorkPathAndCommonConfig(os.Getenv, args)
|
||||||
if ctx.Bool("help") || action == nil {
|
if cli.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)
|
return cmdHelp().Action(ctx, cli)
|
||||||
}
|
}
|
||||||
return action(ctx)
|
return action(ctx, cli)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainApp(version, versionExtra string) *cli.App {
|
func NewMainApp(version, versionExtra string) *cli.Command {
|
||||||
path, err := os.Executable()
|
path, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -124,7 +124,7 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
|
|
||||||
subCmdsStandalone := make([]*cli.Command, 0, 10)
|
subCmdsStandalone := make([]*cli.Command, 0, 10)
|
||||||
subCmdWithConfig := make([]*cli.Command, 0, 10)
|
subCmdWithConfig := make([]*cli.Command, 0, 10)
|
||||||
globalFlags := make([]cli.Flag, 0, 10)
|
globalFlags := func() []cli.Flag { return []cli.Flag{} }
|
||||||
|
|
||||||
//
|
//
|
||||||
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
// If the executable is forgejo-cli, provide a Forgejo specific CLI
|
||||||
|
@ -133,14 +133,16 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
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 = append(globalFlags, []cli.Flag{
|
globalFlags = func() []cli.Flag {
|
||||||
&cli.BoolFlag{
|
return []cli.Flag{
|
||||||
Name: "quiet",
|
&cli.BoolFlag{
|
||||||
},
|
Name: "quiet",
|
||||||
&cli.BoolFlag{
|
},
|
||||||
Name: "verbose",
|
&cli.BoolFlag{
|
||||||
},
|
Name: "verbose",
|
||||||
}...)
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
// Otherwise provide a Gitea compatible CLI which includes Forgejo
|
||||||
|
@ -149,55 +151,54 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
// 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 []cli.Flag) *cli.App {
|
func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmdWithConfigArgs []*cli.Command, globalFlagsArgs func() []cli.Flag) *cli.Command {
|
||||||
app := cli.NewApp()
|
app := &cli.Command{}
|
||||||
app.HelpName = "forgejo"
|
app.Name = "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.EnableBashCompletion = true
|
app.EnableShellCompletion = 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 := appGlobalFlags()
|
globalFlags := func() []cli.Flag {
|
||||||
globalFlags = append(globalFlags, globalFlagsArgs...)
|
return append(appGlobalFlags(), 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 {
|
||||||
|
@ -210,8 +211,8 @@ func innerNewMainApp(version, versionExtra string, subCmdsStandaloneArgs, subCmd
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunMainApp(app *cli.App, args ...string) error {
|
func RunMainApp(app *cli.Command, args ...string) error {
|
||||||
err := app.Run(args)
|
err := app.Run(context.Background(), args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -220,7 +221,7 @@ func RunMainApp(app *cli.App, args ...string) error {
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
_, _ = fmt.Fprintf(app.Root().ErrWriter, "Command error: %v\n", err)
|
||||||
cli.OsExiter(1)
|
cli.OsExiter(1)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -16,7 +18,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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
@ -27,10 +29,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(ctx *cli.Context) error) *cli.App {
|
func newTestApp(testCmdAction func(_ context.Context, ctx *cli.Command) error) *cli.Command {
|
||||||
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
|
||||||
|
@ -42,7 +44,7 @@ type runResult struct {
|
||||||
ExitCode int
|
ExitCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestApp(app *cli.App, args ...string) (runResult, error) {
|
func runTestApp(app *cli.Command, 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
|
||||||
|
@ -65,7 +67,6 @@ 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 {
|
||||||
|
@ -109,12 +110,17 @@ func TestCliCmd(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
app := newTestApp(func(ctx *cli.Context) error {
|
|
||||||
_, _ = fmt.Fprint(ctx.App.Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.cmd, func(t *testing.T) {
|
t.Run(c.cmd, func(t *testing.T) {
|
||||||
|
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
|
||||||
|
})
|
||||||
|
|
||||||
for k, v := range c.env {
|
for k, v := range c.env {
|
||||||
t.Setenv(k, v)
|
t.Setenv(k, v)
|
||||||
}
|
}
|
||||||
|
@ -122,34 +128,34 @@ 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)
|
assert.Contains(t, r.Stdout, c.exp, c.cmd+"\n"+r.Stdout)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
func TestCliCmdError(t *testing.T) {
|
||||||
app := newTestApp(func(ctx *cli.Context) error { return fmt.Errorf("normal error") })
|
app := newTestApp(func(_ context.Context, ctx *cli.Command) error { return errors.New("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.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return cli.Exit("exit error", 2) })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) 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.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
assert.Equal(t, "exit error\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) 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.Stdout)
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
||||||
assert.Empty(t, r.Stderr) // the cli package's strange behavior, the error message is not in stderr ....
|
assert.Empty(t, r.Stdout)
|
||||||
|
|
||||||
app = newTestApp(func(ctx *cli.Context) error { return nil })
|
app = newTestApp(func(_ context.Context, ctx *cli.Command) 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
|
||||||
|
|
|
@ -4,30 +4,34 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
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",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*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{
|
||||||
|
@ -37,7 +41,10 @@ var (
|
||||||
},
|
},
|
||||||
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{
|
||||||
|
@ -47,7 +54,10 @@ var (
|
||||||
},
|
},
|
||||||
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{
|
||||||
|
@ -57,7 +67,10 @@ var (
|
||||||
},
|
},
|
||||||
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,
|
||||||
|
@ -76,7 +89,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
@ -106,10 +122,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runShutdown(c *cli.Context) error {
|
func runShutdown(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -117,8 +133,8 @@ func runShutdown(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestart(c *cli.Context) error {
|
func runRestart(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -126,8 +142,8 @@ func runRestart(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReloadTemplates(c *cli.Context) error {
|
func runReloadTemplates(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -135,8 +151,8 @@ func runReloadTemplates(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFlushQueues(c *cli.Context) error {
|
func runFlushQueues(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -144,8 +160,8 @@ func runFlushQueues(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runProcesses(c *cli.Context) error {
|
func runProcesses(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,11 +12,11 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/private"
|
"forgejo.org/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func defaultLoggingFlags() []cli.Flag {
|
||||||
defaultLoggingFlags = []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "logger",
|
Name: "logger",
|
||||||
Usage: `Logger name - will default to "default"`,
|
Usage: `Logger name - will default to "default"`,
|
||||||
|
@ -56,11 +57,13 @@ var (
|
||||||
Name: "debug",
|
Name: "debug",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subcmdLogging = &cli.Command{
|
func subcmdLogging() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
Name: "logging",
|
Name: "logging",
|
||||||
Usage: "Adjust logging commands",
|
Usage: "Adjust logging commands",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*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)",
|
||||||
|
@ -104,11 +107,11 @@ var (
|
||||||
}, {
|
}, {
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "Add a logger",
|
Usage: "Add a logger",
|
||||||
Subcommands: []*cli.Command{
|
Commands: []*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"},
|
||||||
|
@ -152,7 +155,7 @@ var (
|
||||||
}, {
|
}, {
|
||||||
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"},
|
||||||
|
@ -193,10 +196,10 @@ var (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
func runRemoveLogger(c *cli.Context) error {
|
func runRemoveLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -210,8 +213,8 @@ func runRemoveLogger(c *cli.Context) error {
|
||||||
return handleCliResponseExtra(extra)
|
return handleCliResponseExtra(extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddConnLogger(c *cli.Context) error {
|
func runAddConnLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -237,11 +240,11 @@ func runAddConnLogger(c *cli.Context) 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(c, mode, vals)
|
return commonAddLogger(ctx, c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runAddFileLogger(c *cli.Context) error {
|
func runAddFileLogger(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -270,10 +273,10 @@ func runAddFileLogger(c *cli.Context) 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(c, mode, vals)
|
return commonAddLogger(ctx, c, mode, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
func commonAddLogger(ctx context.Context, c *cli.Command, 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()
|
||||||
}
|
}
|
||||||
|
@ -300,15 +303,15 @@ func commonAddLogger(c *cli.Context, mode string, vals map[string]any) error {
|
||||||
if c.IsSet("writer") {
|
if c.IsSet("writer") {
|
||||||
writer = c.String("writer")
|
writer = c.String("writer")
|
||||||
}
|
}
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
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(c *cli.Context) error {
|
func runPauseLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -317,8 +320,8 @@ func runPauseLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runResumeLogging(c *cli.Context) error {
|
func runResumeLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -327,8 +330,8 @@ func runResumeLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runReleaseReopenLogging(c *cli.Context) error {
|
func runReleaseReopenLogging(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
@ -337,8 +340,8 @@ func runReleaseReopenLogging(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runSetLogSQL(c *cli.Context) error {
|
func runSetLogSQL(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
setup(ctx, c.Bool("debug"), false)
|
setup(ctx, c.Bool("debug"), false)
|
||||||
|
|
||||||
|
|
|
@ -11,19 +11,21 @@ import (
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrate represents the available migrate sub-command.
|
// CmdMigrate represents the available migrate sub-command.
|
||||||
var CmdMigrate = &cli.Command{
|
func cmdMigrate() *cli.Command {
|
||||||
Name: "migrate",
|
return &cli.Command{
|
||||||
Usage: "Migrate the database",
|
Name: "migrate",
|
||||||
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
Usage: "Migrate the database",
|
||||||
Action: runMigrate,
|
Description: "This is a command for migrating the database, so that you can run 'forgejo admin user create' before starting the server.",
|
||||||
|
Action: runMigrate,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrate(ctx *cli.Context) error {
|
func runMigrate(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -22,79 +22,81 @@ import (
|
||||||
"forgejo.org/modules/setting"
|
"forgejo.org/modules/setting"
|
||||||
"forgejo.org/modules/storage"
|
"forgejo.org/modules/storage"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdMigrateStorage represents the available migrate storage sub-command.
|
// CmdMigrateStorage represents the available migrate storage sub-command.
|
||||||
var CmdMigrateStorage = &cli.Command{
|
func cmdMigrateStorage() *cli.Command {
|
||||||
Name: "migrate-storage",
|
return &cli.Command{
|
||||||
Usage: "Migrate the storage",
|
Name: "migrate-storage",
|
||||||
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
Usage: "Migrate the storage",
|
||||||
Action: runMigrateStorage,
|
Description: "Copies stored files from storage configured in app.ini to parameter-configured storage",
|
||||||
Flags: []cli.Flag{
|
Action: runMigrateStorage,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "type",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"t"},
|
Name: "type",
|
||||||
Value: "",
|
Aliases: []string{"t"},
|
||||||
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
|
Value: "",
|
||||||
|
Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages', 'actions-log', 'actions-artifacts'",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "storage",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New storage type: local (default) or minio",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "path",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Value: "",
|
||||||
|
Usage: "New storage placement if store is local (leave blank for default)",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-endpoint",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage endpoint",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-access-key-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage accessKeyID",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-secret-access-key",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage secretAccessKey",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-bucket",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage bucket",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-location",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage location to create bucket",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-base-path",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio storage base path on the bucket",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "minio-use-ssl",
|
||||||
|
Usage: "Enable SSL for minio",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "minio-insecure-skip-verify",
|
||||||
|
Usage: "Skip SSL verification",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "minio-checksum-algorithm",
|
||||||
|
Value: "",
|
||||||
|
Usage: "Minio checksum algorithm (default/md5)",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "storage",
|
|
||||||
Aliases: []string{"s"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New storage type: local (default) or minio",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "path",
|
|
||||||
Aliases: []string{"p"},
|
|
||||||
Value: "",
|
|
||||||
Usage: "New storage placement if store is local (leave blank for default)",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-endpoint",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage endpoint",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-access-key-id",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage accessKeyID",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-secret-access-key",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage secretAccessKey",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-bucket",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage bucket",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-location",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage location to create bucket",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-base-path",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio storage base path on the bucket",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "minio-use-ssl",
|
|
||||||
Usage: "Enable SSL for minio",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "minio-insecure-skip-verify",
|
|
||||||
Usage: "Skip SSL verification",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "minio-checksum-algorithm",
|
|
||||||
Value: "",
|
|
||||||
Usage: "Minio checksum algorithm (default/md5)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||||
|
@ -182,8 +184,8 @@ func migrateActionsArtifacts(ctx context.Context, dstStorage storage.ObjectStora
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMigrateStorage(ctx *cli.Context) error {
|
func runMigrateStorage(stdCtx context.Context, ctx *cli.Command) error {
|
||||||
stdCtx, cancel := installSignals()
|
stdCtx, cancel := installSignals(stdCtx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := initDB(stdCtx); err != nil {
|
if err := initDB(stdCtx); err != nil {
|
||||||
|
|
|
@ -4,52 +4,55 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdRestoreRepository represents the available restore a repository sub-command.
|
// CmdRestoreRepository represents the available restore a repository sub-command.
|
||||||
var CmdRestoreRepository = &cli.Command{
|
func cmdRestoreRepository() *cli.Command {
|
||||||
Name: "restore-repo",
|
return &cli.Command{
|
||||||
Usage: "Restore the repository from disk",
|
Name: "restore-repo",
|
||||||
Description: "This is a command for restoring the repository data.",
|
Usage: "Restore the repository from disk",
|
||||||
Action: runRestoreRepository,
|
Description: "This is a command for restoring the repository data.",
|
||||||
Flags: []cli.Flag{
|
Action: runRestoreRepository,
|
||||||
&cli.StringFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "repo_dir",
|
&cli.StringFlag{
|
||||||
Aliases: []string{"r"},
|
Name: "repo_dir",
|
||||||
Value: "./data",
|
Aliases: []string{"r"},
|
||||||
Usage: "Repository dir path to restore from",
|
Value: "./data",
|
||||||
},
|
Usage: "Repository dir path to restore from",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "owner_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "owner_name",
|
||||||
Usage: "Restore destination owner name",
|
Value: "",
|
||||||
},
|
Usage: "Restore destination owner name",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "repo_name",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "repo_name",
|
||||||
Usage: "Restore destination repository name",
|
Value: "",
|
||||||
},
|
Usage: "Restore destination repository name",
|
||||||
&cli.StringFlag{
|
},
|
||||||
Name: "units",
|
&cli.StringFlag{
|
||||||
Value: "",
|
Name: "units",
|
||||||
Usage: `Which items will be restored, one or more units should be separated as comma.
|
Value: "",
|
||||||
|
Usage: `Which items will be restored, one or more units should be separated as comma.
|
||||||
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "validation",
|
||||||
|
Usage: "Sanity check the content of the files before trying to load them",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "validation",
|
|
||||||
Usage: "Sanity check the content of the files before trying to load them",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRestoreRepository(c *cli.Context) error {
|
func runRestoreRepository(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
|
36
cmd/serv.go
36
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,20 +41,22 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdServ represents the available serv sub-command.
|
// CmdServ represents the available serv sub-command.
|
||||||
var CmdServ = &cli.Command{
|
func cmdServ() *cli.Command {
|
||||||
Name: "serv",
|
return &cli.Command{
|
||||||
Usage: "(internal) Should only be called by SSH shell",
|
Name: "serv",
|
||||||
Description: "Serv provides access auth for repositories",
|
Usage: "(internal) Should only be called by SSH shell",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Description: "Serv provides access auth for repositories",
|
||||||
Action: runServ,
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Flags: []cli.Flag{
|
Action: runServ,
|
||||||
&cli.BoolFlag{
|
Flags: []cli.Flag{
|
||||||
Name: "enable-pprof",
|
&cli.BoolFlag{
|
||||||
|
Name: "enable-pprof",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
}
|
||||||
Name: "debug",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(ctx context.Context, debug, gitNeeded bool) {
|
func setup(ctx context.Context, debug, gitNeeded bool) {
|
||||||
|
@ -131,8 +133,8 @@ func handleCliResponseExtra(extra private.ResponseExtra) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServ(c *cli.Context) error {
|
func runServ(ctx context.Context, c *cli.Command) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// FIXME: This needs to internationalised
|
// FIXME: This needs to internationalised
|
||||||
|
@ -194,7 +196,7 @@ func runServ(c *cli.Context) error {
|
||||||
if git.CheckGitVersionAtLeast("2.29") == nil {
|
if git.CheckGitVersionAtLeast("2.29") == nil {
|
||||||
// for AGit Flow
|
// for AGit Flow
|
||||||
if cmd == "ssh_info" {
|
if cmd == "ssh_info" {
|
||||||
fmt.Print(`{"type":"gitea","version":1}`)
|
fmt.Print(`{"type":"agit","version":1}`)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
84
cmd/web.go
84
cmd/web.go
|
@ -26,48 +26,50 @@ import (
|
||||||
"forgejo.org/routers/install"
|
"forgejo.org/routers/install"
|
||||||
|
|
||||||
"github.com/felixge/fgprof"
|
"github.com/felixge/fgprof"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.
|
||||||
var CmdWeb = &cli.Command{
|
func cmdWeb() *cli.Command {
|
||||||
Name: "web",
|
return &cli.Command{
|
||||||
Usage: "Start the Forgejo web server",
|
Name: "web",
|
||||||
Description: `The Forgejo web server is the only thing you need to run,
|
Usage: "Start the Forgejo web server",
|
||||||
|
Description: `The Forgejo web server is the only thing you need to run,
|
||||||
and it takes care of all the other things for you`,
|
and it takes care of all the other things for you`,
|
||||||
Before: PrepareConsoleLoggerLevel(log.INFO),
|
Before: PrepareConsoleLoggerLevel(log.INFO),
|
||||||
Action: runWeb,
|
Action: runWeb,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "port",
|
Name: "port",
|
||||||
Aliases: []string{"p"},
|
Aliases: []string{"p"},
|
||||||
Value: "3000",
|
Value: "3000",
|
||||||
Usage: "Temporary port number to prevent conflict",
|
Usage: "Temporary port number to prevent conflict",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "install-port",
|
||||||
|
Value: "3000",
|
||||||
|
Usage: "Temporary port number to run the install page on to prevent conflict",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "pid",
|
||||||
|
Aliases: []string{"P"},
|
||||||
|
Value: PIDFile,
|
||||||
|
Usage: "Custom pid file path",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "quiet",
|
||||||
|
Aliases: []string{"q"},
|
||||||
|
Usage: "Only display Fatal logging errors until logging is set-up",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "verbose",
|
||||||
|
Usage: "Set initial logging to TRACE level until logging is properly set-up",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
}
|
||||||
Name: "install-port",
|
|
||||||
Value: "3000",
|
|
||||||
Usage: "Temporary port number to run the install page on to prevent conflict",
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "pid",
|
|
||||||
Aliases: []string{"P"},
|
|
||||||
Value: PIDFile,
|
|
||||||
Usage: "Custom pid file path",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "quiet",
|
|
||||||
Aliases: []string{"q"},
|
|
||||||
Usage: "Only display Fatal logging errors until logging is set-up",
|
|
||||||
},
|
|
||||||
&cli.BoolFlag{
|
|
||||||
Name: "verbose",
|
|
||||||
Usage: "Set initial logging to TRACE level until logging is properly set-up",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func runHTTPRedirector() {
|
func runHTTPRedirector() {
|
||||||
|
@ -128,7 +130,7 @@ func showWebStartupMessage(msg string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstall(ctx *cli.Context) error {
|
func serveInstall(_ context.Context, ctx *cli.Command) error {
|
||||||
showWebStartupMessage("Prepare to run install page")
|
showWebStartupMessage("Prepare to run install page")
|
||||||
|
|
||||||
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
routers.InitWebInstallPage(graceful.GetManager().HammerContext())
|
||||||
|
@ -161,7 +163,7 @@ func serveInstall(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func serveInstalled(ctx *cli.Context) error {
|
func serveInstalled(_ context.Context, ctx *cli.Command) error {
|
||||||
setting.InitCfgProvider(setting.CustomConf)
|
setting.InitCfgProvider(setting.CustomConf)
|
||||||
setting.LoadCommonSettings()
|
setting.LoadCommonSettings()
|
||||||
setting.MustInstalled()
|
setting.MustInstalled()
|
||||||
|
@ -233,7 +235,7 @@ func servePprof() {
|
||||||
finished()
|
finished()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWeb(ctx *cli.Context) error {
|
func runWeb(ctx context.Context, cli *cli.Command) 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))
|
||||||
|
@ -251,12 +253,12 @@ func runWeb(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set pid file setting
|
// Set pid file setting
|
||||||
if ctx.IsSet("pid") {
|
if cli.IsSet("pid") {
|
||||||
createPIDFile(ctx.String("pid"))
|
createPIDFile(cli.String("pid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !setting.InstallLock {
|
if !setting.InstallLock {
|
||||||
if err := serveInstall(ctx); err != nil {
|
if err := serveInstall(ctx, cli); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -267,7 +269,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
go servePprof()
|
go servePprof()
|
||||||
}
|
}
|
||||||
|
|
||||||
return serveInstalled(ctx)
|
return serveInstalled(ctx, cli)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPort(port string) error {
|
func setPort(port string) error {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#! /bin/bash
|
|
||||||
# Heavily inspired by https://github.com/urfave/cli
|
# Heavily inspired by https://github.com/urfave/cli
|
||||||
|
|
||||||
_cli_bash_autocomplete() {
|
_cli_bash_autocomplete() {
|
||||||
|
@ -7,9 +6,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-bash-completion )
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-shell-completion )
|
||||||
else
|
else
|
||||||
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
|
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-shell-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-bash-completion)}")
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-shell-completion)}")
|
||||||
else
|
else
|
||||||
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
|
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-shell-completion)}")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${opts[1]}" != "" ]]; then
|
if [[ "${opts[1]}" != "" ]]; then
|
||||||
|
|
|
@ -1,45 +1,46 @@
|
||||||
Environment To Ini
|
Environment To Ini
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Multiple docker users have requested that the Gitea docker is changed
|
This tool allows defining Forgejo's entire configuration via environment
|
||||||
to permit arbitrary configuration via environment variables.
|
variables, mostly geared towards usage in Docker.
|
||||||
|
|
||||||
Gitea needs to use an ini file for configuration because the running
|
Forgejo needs to use an INI file for configuration because the running
|
||||||
environment that starts the docker may not be the same as that used
|
environment that starts the container may not be the same as the one 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 completely provide a full environment.
|
users do not have to provide the entire set of environment variables.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
To use the command is very simple just run it and the default gitea
|
When run, `environment-to-ini` will write the config files based on the
|
||||||
app.ini will be rewritten to take account of the variables provided,
|
environment variables provided.
|
||||||
however there are various options to give slightly different
|
Check with the `-h` flag for several options to alter this behaviour.
|
||||||
behavior and these can be interrogated with the `-h` option.
|
|
||||||
|
|
||||||
The environment variables should be of the form:
|
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME"
|
||||||
|
will be mapped to the ini section "[section_name]" and the key
|
||||||
|
"KEY_NAME" with the value as provided.
|
||||||
|
|
||||||
GITEA__SECTION_NAME__KEY_NAME
|
Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE"
|
||||||
|
will be mapped to the ini section "[section_name]" and the key
|
||||||
Note, SECTION_NAME in the notation above is case-insensitive.
|
"KEY_NAME" with the value loaded from the specified file.
|
||||||
|
|
||||||
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 "." and "_0X2D_" for "-". The entire section and key names
|
"_0X2E_" for ".". The entire section and key names can be escaped as
|
||||||
can be escaped as a UTF8 byte string if necessary. E.g. to configure:
|
a UTF8 byte string if necessary. E.g. to configure:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
...
|
...
|
||||||
[log.console]
|
[log.console]
|
||||||
COLORIZE=false
|
COLORIZE=false
|
||||||
STDERR=true
|
STDERR=true
|
||||||
...
|
...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
|
You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false"
|
||||||
and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
|
and "FORGEJO__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,16 +4,17 @@
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.Command{}
|
||||||
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
|
||||||
|
@ -72,13 +73,13 @@ func main() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Action = runEnvironmentToIni
|
app.Action = runEnvironmentToIni
|
||||||
err := app.Run(os.Args)
|
err := app.Run(context.Background(), 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(c *cli.Context) error {
|
func runEnvironmentToIni(ctx context.Context, c *cli.Command) 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 = curve25519-sha256, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521, diffie-hellman-group14-sha256, diffie-hellman-group14-sha1
|
;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
|
||||||
;;
|
;;
|
||||||
;; 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,6 +1025,10 @@ 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
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments';
|
import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments';
|
||||||
import stylisticEslintPluginJs from '@stylistic/eslint-plugin-js';
|
import stylisticEslintPlugin from '@stylistic/eslint-plugin';
|
||||||
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/js': stylisticEslintPluginJs,
|
'@stylistic': stylisticEslintPlugin,
|
||||||
'@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/js/array-bracket-newline': [0],
|
'@stylistic/array-bracket-newline': [0],
|
||||||
'@stylistic/js/array-bracket-spacing': [2, 'never'],
|
'@stylistic/array-bracket-spacing': [2, 'never'],
|
||||||
'@stylistic/js/array-element-newline': [0],
|
'@stylistic/array-element-newline': [0],
|
||||||
'@stylistic/js/arrow-parens': [2, 'always'],
|
'@stylistic/arrow-parens': [2, 'always'],
|
||||||
|
|
||||||
'@stylistic/js/arrow-spacing': [2, {
|
'@stylistic/arrow-spacing': [2, {
|
||||||
before: true,
|
before: true,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/block-spacing': [0],
|
'@stylistic/block-spacing': [0],
|
||||||
|
|
||||||
'@stylistic/js/brace-style': [2, '1tbs', {
|
'@stylistic/brace-style': [2, '1tbs', {
|
||||||
allowSingleLine: true,
|
allowSingleLine: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/comma-dangle': [2, 'always-multiline'],
|
'@stylistic/comma-dangle': [2, 'always-multiline'],
|
||||||
|
|
||||||
'@stylistic/js/comma-spacing': [2, {
|
'@stylistic/comma-spacing': [2, {
|
||||||
before: false,
|
before: false,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/comma-style': [2, 'last'],
|
'@stylistic/comma-style': [2, 'last'],
|
||||||
'@stylistic/js/computed-property-spacing': [2, 'never'],
|
'@stylistic/computed-property-spacing': [2, 'never'],
|
||||||
'@stylistic/js/dot-location': [2, 'property'],
|
'@stylistic/dot-location': [2, 'property'],
|
||||||
'@stylistic/js/eol-last': [2],
|
'@stylistic/eol-last': [2],
|
||||||
'@stylistic/js/function-call-spacing': [2, 'never'],
|
'@stylistic/function-call-spacing': [2, 'never'],
|
||||||
'@stylistic/js/function-call-argument-newline': [0],
|
'@stylistic/function-call-argument-newline': [0],
|
||||||
'@stylistic/js/function-paren-newline': [0],
|
'@stylistic/function-paren-newline': [0],
|
||||||
'@stylistic/js/generator-star-spacing': [0],
|
'@stylistic/generator-star-spacing': [0],
|
||||||
'@stylistic/js/implicit-arrow-linebreak': [0],
|
'@stylistic/implicit-arrow-linebreak': [0],
|
||||||
|
|
||||||
'@stylistic/js/indent': [2, 2, {
|
'@stylistic/indent': [2, 2, {
|
||||||
ignoreComments: true,
|
ignoreComments: true,
|
||||||
SwitchCase: 1,
|
SwitchCase: 1,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/key-spacing': [2],
|
'@stylistic/key-spacing': [2],
|
||||||
'@stylistic/js/keyword-spacing': [2],
|
'@stylistic/keyword-spacing': [2],
|
||||||
'@stylistic/js/linebreak-style': [2, 'unix'],
|
'@stylistic/linebreak-style': [2, 'unix'],
|
||||||
'@stylistic/js/lines-around-comment': [0],
|
'@stylistic/lines-around-comment': [0],
|
||||||
'@stylistic/js/lines-between-class-members': [0],
|
'@stylistic/lines-between-class-members': [0],
|
||||||
'@stylistic/js/max-len': [0],
|
'@stylistic/max-len': [0],
|
||||||
'@stylistic/js/max-statements-per-line': [0],
|
'@stylistic/max-statements-per-line': [0],
|
||||||
'@stylistic/js/multiline-ternary': [0],
|
'@stylistic/multiline-ternary': [0],
|
||||||
'@stylistic/js/new-parens': [2],
|
'@stylistic/new-parens': [2],
|
||||||
'@stylistic/js/newline-per-chained-call': [0],
|
'@stylistic/newline-per-chained-call': [0],
|
||||||
'@stylistic/js/no-confusing-arrow': [0],
|
'@stylistic/no-confusing-arrow': [0],
|
||||||
'@stylistic/js/no-extra-parens': [0],
|
'@stylistic/no-extra-parens': [0],
|
||||||
'@stylistic/js/no-extra-semi': [2],
|
'@stylistic/no-extra-semi': [2],
|
||||||
'@stylistic/js/no-floating-decimal': [0],
|
'@stylistic/no-floating-decimal': [0],
|
||||||
'@stylistic/js/no-mixed-operators': [0],
|
'@stylistic/no-mixed-operators': [0],
|
||||||
'@stylistic/js/no-mixed-spaces-and-tabs': [2],
|
'@stylistic/no-mixed-spaces-and-tabs': [2],
|
||||||
|
|
||||||
'@stylistic/js/no-multi-spaces': [2, {
|
'@stylistic/no-multi-spaces': [2, {
|
||||||
ignoreEOLComments: true,
|
ignoreEOLComments: true,
|
||||||
|
|
||||||
exceptions: {
|
exceptions: {
|
||||||
|
@ -132,60 +132,60 @@ export default tseslint.config(
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/no-multiple-empty-lines': [2, {
|
'@stylistic/no-multiple-empty-lines': [2, {
|
||||||
max: 1,
|
max: 1,
|
||||||
maxEOF: 0,
|
maxEOF: 0,
|
||||||
maxBOF: 0,
|
maxBOF: 0,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/no-tabs': [2],
|
'@stylistic/no-tabs': [2],
|
||||||
'@stylistic/js/no-trailing-spaces': [2],
|
'@stylistic/no-trailing-spaces': [2],
|
||||||
'@stylistic/js/no-whitespace-before-property': [2],
|
'@stylistic/no-whitespace-before-property': [2],
|
||||||
'@stylistic/js/nonblock-statement-body-position': [2],
|
'@stylistic/nonblock-statement-body-position': [2],
|
||||||
'@stylistic/js/object-curly-newline': [0],
|
'@stylistic/object-curly-newline': [0],
|
||||||
'@stylistic/js/object-curly-spacing': [2, 'never'],
|
'@stylistic/object-curly-spacing': [2, 'never'],
|
||||||
'@stylistic/js/object-property-newline': [0],
|
'@stylistic/object-property-newline': [0],
|
||||||
'@stylistic/js/one-var-declaration-per-line': [0],
|
'@stylistic/one-var-declaration-per-line': [0],
|
||||||
'@stylistic/js/operator-linebreak': [2, 'after'],
|
'@stylistic/operator-linebreak': [2, 'after'],
|
||||||
'@stylistic/js/padded-blocks': [2, 'never'],
|
'@stylistic/padded-blocks': [2, 'never'],
|
||||||
'@stylistic/js/padding-line-between-statements': [0],
|
'@stylistic/padding-line-between-statements': [0],
|
||||||
'@stylistic/js/quote-props': [0],
|
'@stylistic/quote-props': [0],
|
||||||
|
|
||||||
'@stylistic/js/quotes': [2, 'single', {
|
'@stylistic/quotes': [2, 'single', {
|
||||||
avoidEscape: true,
|
avoidEscape: true,
|
||||||
allowTemplateLiterals: true,
|
allowTemplateLiterals: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/rest-spread-spacing': [2, 'never'],
|
'@stylistic/rest-spread-spacing': [2, 'never'],
|
||||||
|
|
||||||
'@stylistic/js/semi': [2, 'always', {
|
'@stylistic/semi': [2, 'always', {
|
||||||
omitLastInOneLineBlock: true,
|
omitLastInOneLineBlock: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/semi-spacing': [2, {
|
'@stylistic/semi-spacing': [2, {
|
||||||
before: false,
|
before: false,
|
||||||
after: true,
|
after: true,
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/semi-style': [2, 'last'],
|
'@stylistic/semi-style': [2, 'last'],
|
||||||
'@stylistic/js/space-before-blocks': [2, 'always'],
|
'@stylistic/space-before-blocks': [2, 'always'],
|
||||||
|
|
||||||
'@stylistic/js/space-before-function-paren': [2, {
|
'@stylistic/space-before-function-paren': [2, {
|
||||||
anonymous: 'ignore',
|
anonymous: 'ignore',
|
||||||
named: 'never',
|
named: 'never',
|
||||||
asyncArrow: 'always',
|
asyncArrow: 'always',
|
||||||
}],
|
}],
|
||||||
|
|
||||||
'@stylistic/js/space-in-parens': [2, 'never'],
|
'@stylistic/space-in-parens': [2, 'never'],
|
||||||
'@stylistic/js/space-infix-ops': [2],
|
'@stylistic/space-infix-ops': [2],
|
||||||
'@stylistic/js/space-unary-ops': [2],
|
'@stylistic/space-unary-ops': [2],
|
||||||
'@stylistic/js/spaced-comment': [2, 'always'],
|
'@stylistic/spaced-comment': [2, 'always'],
|
||||||
'@stylistic/js/switch-colon-spacing': [2],
|
'@stylistic/switch-colon-spacing': [2],
|
||||||
'@stylistic/js/template-curly-spacing': [2, 'never'],
|
'@stylistic/template-curly-spacing': [2, 'never'],
|
||||||
'@stylistic/js/template-tag-spacing': [2, 'never'],
|
'@stylistic/template-tag-spacing': [2, 'never'],
|
||||||
'@stylistic/js/wrap-iife': [2, 'inside'],
|
'@stylistic/wrap-iife': [2, 'inside'],
|
||||||
'@stylistic/js/wrap-regex': [0],
|
'@stylistic/wrap-regex': [0],
|
||||||
'@stylistic/js/yield-star-spacing': [2, 'after'],
|
'@stylistic/yield-star-spacing': [2, 'after'],
|
||||||
'accessor-pairs': [2],
|
'accessor-pairs': [2],
|
||||||
|
|
||||||
'array-callback-return': [2, {
|
'array-callback-return': [2, {
|
||||||
|
|
6
flake.lock
generated
6
flake.lock
generated
|
@ -20,11 +20,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1733392399,
|
"lastModified": 1749285348,
|
||||||
"narHash": "sha256-kEsTJTUQfQFIJOcLYFt/RvNxIK653ZkTBIs4DG+cBns=",
|
"narHash": "sha256-frdhQvPbmDYaScPFiCnfdh3B/Vh81Uuoo0w5TkWmmjU=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d0797a04b81caeae77bcff10a9dde78bc17f5661",
|
"rev": "3e3afe5174c561dee0df6f2c2b2236990146329f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
39
flake.nix
39
flake.nix
|
@ -3,35 +3,20 @@
|
||||||
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,
|
{
|
||||||
flake-utils,
|
nixpkgs,
|
||||||
...
|
flake-utils,
|
||||||
}:
|
...
|
||||||
|
}:
|
||||||
flake-utils.lib.eachDefaultSystem (
|
flake-utils.lib.eachDefaultSystem (
|
||||||
system: let
|
system:
|
||||||
|
let
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in {
|
in
|
||||||
devShells.default = pkgs.mkShell {
|
{
|
||||||
buildInputs = with pkgs; [
|
devShells.default = import ./shell.nix { inherit pkgs; };
|
||||||
# generic
|
formatter = pkgs.nixfmt-rfc-style;
|
||||||
git
|
|
||||||
git-lfs
|
|
||||||
gnumake
|
|
||||||
gnused
|
|
||||||
gnutar
|
|
||||||
gzip
|
|
||||||
|
|
||||||
# frontend
|
|
||||||
nodejs_20
|
|
||||||
|
|
||||||
# backend
|
|
||||||
gofumpt
|
|
||||||
sqlite
|
|
||||||
go
|
|
||||||
gopls
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
68
go.mod
68
go.mod
|
@ -2,30 +2,31 @@ module forgejo.org
|
||||||
|
|
||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
toolchain go1.24.3
|
toolchain go1.24.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.forgejo.org/f3/gof3/v3 v3.10.6
|
code.forgejo.org/f3/gof3/v3 v3.11.0
|
||||||
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.0
|
code.forgejo.org/go-chi/binding v1.0.1
|
||||||
code.forgejo.org/go-chi/cache v1.0.0
|
code.forgejo.org/go-chi/cache v1.0.1
|
||||||
code.forgejo.org/go-chi/captcha v1.0.1
|
code.forgejo.org/go-chi/captcha v1.0.2
|
||||||
code.forgejo.org/go-chi/session v1.0.1
|
code.forgejo.org/go-chi/session v1.0.2
|
||||||
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.21.0
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||||
connectrpc.com/connect v1.17.0
|
connectrpc.com/connect v1.18.1
|
||||||
github.com/42wim/httpsig v1.2.3
|
github.com/42wim/httpsig v1.2.3
|
||||||
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
|
github.com/42wim/sshsig v0.0.0-20250502153856-5100632e8920
|
||||||
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.1.6
|
github.com/ProtonMail/go-crypto v1.3.0
|
||||||
github.com/PuerkitoBio/goquery v1.10.3
|
github.com/PuerkitoBio/goquery v1.10.3
|
||||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.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.18.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.1
|
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.23.0
|
||||||
github.com/chi-middleware/proxy v1.1.1
|
github.com/chi-middleware/proxy v1.1.1
|
||||||
|
@ -40,14 +41,14 @@ require (
|
||||||
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.0
|
github.com/go-chi/chi/v5 v5.2.2
|
||||||
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.21.0
|
||||||
github.com/go-sql-driver/mysql v1.9.1
|
github.com/go-sql-driver/mysql v1.9.3
|
||||||
github.com/go-webauthn/webauthn v0.13.0
|
github.com/go-webauthn/webauthn v0.13.0
|
||||||
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
|
||||||
|
@ -75,7 +76,7 @@ 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.91
|
github.com/minio/minio-go/v7 v7.0.94
|
||||||
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.8.0
|
github.com/niklasfasching/go-org v1.8.0
|
||||||
|
@ -86,27 +87,25 @@ require (
|
||||||
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.8.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
|
||||||
github.com/sassoftware/go-rpmutils v0.4.0
|
github.com/sergi/go-diff v1.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/v2 v2.27.6
|
github.com/urfave/cli/v3 v3.3.3
|
||||||
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.12
|
||||||
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.126.0
|
gitlab.com/gitlab-org/api/client-go v0.130.1
|
||||||
go.uber.org/mock v0.5.1
|
go.uber.org/mock v0.5.2
|
||||||
golang.org/x/crypto v0.38.0
|
golang.org/x/crypto v0.39.0
|
||||||
golang.org/x/image v0.27.0
|
golang.org/x/image v0.27.0
|
||||||
golang.org/x/net v0.40.0
|
golang.org/x/net v0.41.0
|
||||||
golang.org/x/oauth2 v0.30.0
|
golang.org/x/oauth2 v0.30.0
|
||||||
golang.org/x/sync v0.14.0
|
golang.org/x/sync v0.15.0
|
||||||
golang.org/x/sys v0.33.0
|
golang.org/x/sys v0.33.0
|
||||||
golang.org/x/text v0.25.0
|
golang.org/x/text v0.26.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
|
||||||
|
@ -121,7 +120,6 @@ 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,14 +144,13 @@ require (
|
||||||
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
|
||||||
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
|
||||||
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.3 // 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-20230905024940-24af94b03874 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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.3.8 // 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
|
||||||
|
@ -210,6 +207,7 @@ require (
|
||||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
|
github.com/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,15 +219,13 @@ 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
|
||||||
|
@ -237,18 +233,16 @@ 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.24.0 // indirect
|
golang.org/x/mod v0.25.0 // indirect
|
||||||
golang.org/x/time v0.10.0 // indirect
|
golang.org/x/time v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
golang.org/x/tools v0.34.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/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
|
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.28.0
|
||||||
|
|
||||||
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.26.0
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
128
go.sum
128
go.sum
|
@ -1,13 +1,15 @@
|
||||||
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.10.6 h1:Ru/Iz+pqM8IPi7atUHE7+q7v3O3DRbYgMFqrFTsO1m8=
|
code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFsAE=
|
||||||
code.forgejo.org/f3/gof3/v3 v3.10.6/go.mod h1:K6lQCWQIyN/5rjP/OJL9fMA6fd++satndE20w/I6Kss=
|
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
|
||||||
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.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs=
|
code.forgejo.org/forgejo/act v1.28.0 h1:96njNC7C1YNyjWq5OWvLZMF/nw0PMthzIA8Nwbnn7jo=
|
||||||
code.forgejo.org/forgejo/act v1.26.0/go.mod h1:HFDFrXPrqfM9aH2RCnMiBdo/3ThxDmZjp58InPjGOfo=
|
code.forgejo.org/forgejo/act v1.28.0/go.mod h1:dFuiwAmD5vyrzecysHB2kL/GM3wRpoVPl+WdbCTC8Bs=
|
||||||
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=
|
||||||
|
@ -16,22 +18,22 @@ 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.0 h1:EIDJtk9brK7WsT7rvS/D4cxX8XlnhY3LMy8ex1jeHu0=
|
code.forgejo.org/go-chi/binding v1.0.1 h1:coKNI+X1NzRN7X85LlrpvBRqk0TXpJ+ja28vusQWEuY=
|
||||||
code.forgejo.org/go-chi/binding v1.0.0/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E=
|
code.forgejo.org/go-chi/binding v1.0.1/go.mod h1:oTFFDg/dkwFbmVuusiULB1OlrIJM95cOGK7Nc3GYcoo=
|
||||||
code.forgejo.org/go-chi/cache v1.0.0 h1:akLfGxNlHcacmtutovNtYFSTMsbdcp5MGjAEsP4pxnE=
|
code.forgejo.org/go-chi/cache v1.0.1 h1:w6IsDcPbeEnEYZn7M2HJe3/3/Ehtcw/72VjcVK7+lBw=
|
||||||
code.forgejo.org/go-chi/cache v1.0.0/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk=
|
code.forgejo.org/go-chi/cache v1.0.1/go.mod h1:K3aQSyRIN4xiuqV1kanfQ6O4ToDpzDpY3bNOyGjFe3U=
|
||||||
code.forgejo.org/go-chi/captcha v1.0.1 h1:/oe1fvGOpdyyeGijg3oMYNOYLvEovNvp79Y3gLe3qbk=
|
code.forgejo.org/go-chi/captcha v1.0.2 h1:vyHDPXkpjDv8bLO9NqtWzZayzstD/WpJ5xwEkAaqZGQ=
|
||||||
code.forgejo.org/go-chi/captcha v1.0.1/go.mod h1:6EbjSVVa7WoZFENgwK/hLAJZq+HBXtgRsjnIngILC8Y=
|
code.forgejo.org/go-chi/captcha v1.0.2/go.mod h1:lxiPLcJ76UCZHoH31/Wbum4GUi2NgjfFZLrJkKv1lLE=
|
||||||
code.forgejo.org/go-chi/session v1.0.1 h1:RNkcJQZJBqlvJoIFXSth87b3kMFZLDBA18VcitD+Z0Y=
|
code.forgejo.org/go-chi/session v1.0.2 h1:pG+AXre9L9VXJmTaADXkmeEPuRalhmBXyv6tG2Rvjcc=
|
||||||
code.forgejo.org/go-chi/session v1.0.1/go.mod h1:y69sjS984wc7k4xyu77yNE5HKeSlBoQW8VSGdsK7RAs=
|
code.forgejo.org/go-chi/session v1.0.2/go.mod h1:HnEGyBny7WPzCiVLP2vzL5ssma+3gCSl/vLpuVNYrqc=
|
||||||
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.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
|
||||||
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
|
code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
|
||||||
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.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk=
|
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
|
||||||
connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
|
connectrpc.com/connect v1.18.1/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=
|
||||||
|
@ -46,13 +48,11 @@ 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.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||||
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
|
||||||
|
@ -87,8 +87,8 @@ github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCk
|
||||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
github.com/blevesearch/bleve/v2 v2.5.1 h1:cc/O++W2Hcjp1SU5ETHeE+QYWv2oV88ldYEPowdmg8M=
|
github.com/blevesearch/bleve/v2 v2.5.2 h1:Ab0r0MODV2C5A6BEL87GqLBySqp/s9xFgceCju6BQk8=
|
||||||
github.com/blevesearch/bleve/v2 v2.5.1/go.mod h1:9g/wnbWKm9AgXrU8Ecqi+IDdqjUHWymwkQRDg+5tafU=
|
github.com/blevesearch/bleve/v2 v2.5.2/go.mod h1:5Dj6dUQxZM6aqYT3eutTD/GpWKGFSsV8f7LDidFbwXo=
|
||||||
github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y=
|
github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y=
|
||||||
github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
|
||||||
github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg=
|
github.com/blevesearch/geo v0.2.3 h1:K9/vbGI9ehlXdxjxDRJtoAMt7zGAsMIzc6n8zWcwnhg=
|
||||||
|
@ -121,13 +121,13 @@ github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT
|
||||||
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
|
||||||
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
|
||||||
github.com/blevesearch/zapx/v16 v16.2.3 h1:7Y0r+a3diEvlazsncexq1qoFOcBd64xwMS7aDm4lo1s=
|
github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww=
|
||||||
github.com/blevesearch/zapx/v16 v16.2.3/go.mod h1:wVJ+GtURAaRG9KQAMNYyklq0egV+XJlGcXNCE0OFjjA=
|
github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs=
|
||||||
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-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous=
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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=
|
||||||
|
@ -150,10 +150,8 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
||||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||||
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
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=
|
||||||
|
@ -215,8 +213,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.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
|
||||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||||
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=
|
||||||
|
@ -247,8 +245,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z
|
||||||
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
|
||||||
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||||
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||||
github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
|
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||||
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
github.com/go-sql-driver/mysql v1.9.3/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=
|
||||||
|
@ -384,8 +382,6 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ=
|
github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ=
|
||||||
github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||||
github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 h1:F/3FfGmKdiKFa8kL3YrpZ7pe9H4l4AzA1pbaOUnRvPI=
|
|
||||||
github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0/go.mod h1:JEfTc3+2DF9Z4PXhLLvXL42zexJyh8rIq3OzUj/0rAk=
|
|
||||||
github.com/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=
|
||||||
|
@ -415,8 +411,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.91 h1:tWLZnEfo3OZl5PoXQwcwTAPNNrjyWwOh6cbZitW5JQc=
|
github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM=
|
||||||
github.com/minio/minio-go/v7 v7.0.91/go.mod h1:uvMUcGrpgeSAAI6+sD3818508nUyMULw94j2Nxku/Go=
|
github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
|
||||||
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=
|
||||||
|
@ -459,6 +455,8 @@ 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=
|
||||||
|
@ -497,17 +495,11 @@ 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/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
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.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
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/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
github.com/sergi/go-diff v1.4.0/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=
|
||||||
|
@ -531,12 +523,14 @@ 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/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
|
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
|
||||||
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
|
||||||
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
|
||||||
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
@ -545,8 +539,6 @@ 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=
|
||||||
|
@ -564,8 +556,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.126.0 h1:VV5TdkF6pMbEdFGvbR2CwEgJwg6qdg1u3bj5eD2tiWk=
|
gitlab.com/gitlab-org/api/client-go v0.130.1 h1:1xF5C5Zq3sFeNg3PzS2z63oqrxifne3n/OnbI7nptRc=
|
||||||
gitlab.com/gitlab-org/api/client-go v0.126.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
|
gitlab.com/gitlab-org/api/client-go v0.130.1/go.mod h1:ZhSxLAWadqP6J9lMh40IAZOlOxBLPRh7yFOXR/bMJWM=
|
||||||
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=
|
||||||
|
@ -573,8 +565,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.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
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=
|
||||||
|
@ -591,8 +583,8 @@ 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.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
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.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
@ -603,8 +595,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.25.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=
|
||||||
|
@ -620,8 +612,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||||
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=
|
||||||
|
@ -633,8 +625,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.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/sync v0.15.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=
|
||||||
|
@ -684,10 +676,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.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
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=
|
||||||
|
@ -695,8 +687,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.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||||
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/v2"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// these flags will be set by the build flags
|
// these flags will be set by the build flags
|
||||||
|
|
38
manifest.scm
Normal file
38
manifest.scm
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
;;; 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"))
|
|
@ -5,6 +5,7 @@ package actions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -54,6 +55,7 @@ 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() {
|
||||||
|
@ -222,29 +224,38 @@ 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()
|
||||||
needs := job.Needs()
|
status := StatusFailure
|
||||||
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
payload := []byte{}
|
||||||
return err
|
needs := []string{}
|
||||||
|
name := run.Title
|
||||||
|
runsOn := []string{}
|
||||||
|
if job != nil {
|
||||||
|
needs = job.Needs()
|
||||||
|
if err := v.SetJob(id, job.EraseNeeds()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
payload, _ = v.Marshal()
|
||||||
|
|
||||||
|
if len(needs) > 0 || run.NeedApproval {
|
||||||
|
status = StatusBlocked
|
||||||
|
} else {
|
||||||
|
status = StatusWaiting
|
||||||
|
hasWaiting = true
|
||||||
|
}
|
||||||
|
name, _ = util.SplitStringAtByteN(job.Name, 255)
|
||||||
|
runsOn = job.RunsOn()
|
||||||
}
|
}
|
||||||
payload, _ := v.Marshal()
|
|
||||||
status := StatusWaiting
|
|
||||||
if len(needs) > 0 || run.NeedApproval {
|
|
||||||
status = StatusBlocked
|
|
||||||
} else {
|
|
||||||
hasWaiting = true
|
|
||||||
}
|
|
||||||
job.Name, _ = util.SplitStringAtByteN(job.Name, 255)
|
|
||||||
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: job.Name,
|
Name: name,
|
||||||
WorkflowPayload: payload,
|
WorkflowPayload: payload,
|
||||||
JobID: id,
|
JobID: id,
|
||||||
Needs: needs,
|
Needs: needs,
|
||||||
RunsOn: job.RunsOn(),
|
RunsOn: runsOn,
|
||||||
Status: status,
|
Status: status,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -346,7 +357,7 @@ func UpdateRunWithoutNotification(ctx context.Context, run *ActionRun, cols ...s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if affected == 0 {
|
if affected == 0 {
|
||||||
return fmt.Errorf("run has changed")
|
return errors.New("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.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ 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 {
|
||||||
|
@ -76,5 +78,11 @@ 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
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
repo_model "forgejo.org/models/repo"
|
repo_model "forgejo.org/models/repo"
|
||||||
"forgejo.org/models/shared/types"
|
"forgejo.org/models/shared/types"
|
||||||
user_model "forgejo.org/models/user"
|
user_model "forgejo.org/models/user"
|
||||||
|
"forgejo.org/modules/log"
|
||||||
"forgejo.org/modules/optional"
|
"forgejo.org/modules/optional"
|
||||||
"forgejo.org/modules/timeutil"
|
"forgejo.org/modules/timeutil"
|
||||||
"forgejo.org/modules/translation"
|
"forgejo.org/modules/translation"
|
||||||
|
@ -353,3 +354,53 @@ func FixRunnersWithoutBelongingRepo(ctx context.Context) (int64, error) {
|
||||||
}
|
}
|
||||||
return res.RowsAffected()
|
return res.RowsAffected()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteOfflineRunners(ctx context.Context, olderThan timeutil.TimeStamp, globalOnly bool) error {
|
||||||
|
log.Info("Doing: DeleteOfflineRunners")
|
||||||
|
|
||||||
|
if olderThan.AsTime().After(timeutil.TimeStampNow().AddDuration(-RunnerOfflineTime).AsTime()) {
|
||||||
|
return fmt.Errorf("invalid `cron.cleanup_offline_runners.older_than`value: must be at least %q", RunnerOfflineTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
cond := builder.Or(
|
||||||
|
// never online
|
||||||
|
builder.And(builder.Eq{"last_online": 0}, builder.Lt{"created": olderThan}),
|
||||||
|
// was online but offline
|
||||||
|
builder.And(builder.Gt{"last_online": 0}, builder.Lt{"last_online": olderThan}),
|
||||||
|
)
|
||||||
|
|
||||||
|
if globalOnly {
|
||||||
|
cond = builder.And(cond, builder.Eq{"owner_id": 0}, builder.Eq{"repo_id": 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Iterate(
|
||||||
|
ctx,
|
||||||
|
cond,
|
||||||
|
func(ctx context.Context, r *ActionRunner) error {
|
||||||
|
if err := DeleteRunner(ctx, r); err != nil {
|
||||||
|
return fmt.Errorf("DeleteOfflineRunners: %w", err)
|
||||||
|
}
|
||||||
|
lastOnline := r.LastOnline.AsTime()
|
||||||
|
olderThanTime := olderThan.AsTime()
|
||||||
|
if !lastOnline.IsZero() && lastOnline.Before(olderThanTime) {
|
||||||
|
log.Info(
|
||||||
|
"Deleted runner [ID: %d, Name: %s], last online %s ago",
|
||||||
|
r.ID, r.Name, olderThanTime.Sub(lastOnline).String(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
log.Info(
|
||||||
|
"Deleted runner [ID: %d, Name: %s], unused since %s ago",
|
||||||
|
r.ID, r.Name, olderThanTime.Sub(r.Created.AsTime()).String(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Finished: DeleteOfflineRunners")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -6,10 +6,12 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
auth_model "forgejo.org/models/auth"
|
auth_model "forgejo.org/models/auth"
|
||||||
"forgejo.org/models/db"
|
"forgejo.org/models/db"
|
||||||
"forgejo.org/models/unittest"
|
"forgejo.org/models/unittest"
|
||||||
|
"forgejo.org/modules/timeutil"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -73,3 +75,68 @@ func TestDeleteRunner(t *testing.T) {
|
||||||
idAsBinary[6], idAsBinary[7])
|
idAsBinary[6], idAsBinary[7])
|
||||||
assert.Equal(t, idAsHexadecimal, after.UUID[19:])
|
assert.Equal(t, idAsHexadecimal, after.UUID[19:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteOfflineRunnersRunnerGlobalOnly(t *testing.T) {
|
||||||
|
baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC)
|
||||||
|
timeutil.MockSet(baseTime)
|
||||||
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
|
require.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
olderThan := timeutil.TimeStampNow().Add(-timeutil.Hour)
|
||||||
|
|
||||||
|
require.NoError(t, DeleteOfflineRunners(db.DefaultContext, olderThan, true))
|
||||||
|
|
||||||
|
// create at test base time
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 12345678})
|
||||||
|
// last_online test base time
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000001})
|
||||||
|
// created one month ago but a repo
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000002})
|
||||||
|
// last online one hour ago
|
||||||
|
unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000003})
|
||||||
|
// last online 10 seconds ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000004})
|
||||||
|
// created 1 month ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000005})
|
||||||
|
// created 1 hour ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000006})
|
||||||
|
// last online 1 hour ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000007})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteOfflineRunnersAll(t *testing.T) {
|
||||||
|
baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC)
|
||||||
|
timeutil.MockSet(baseTime)
|
||||||
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
|
require.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
olderThan := timeutil.TimeStampNow().Add(-timeutil.Hour)
|
||||||
|
|
||||||
|
require.NoError(t, DeleteOfflineRunners(db.DefaultContext, olderThan, false))
|
||||||
|
|
||||||
|
// create at test base time
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 12345678})
|
||||||
|
// last_online test base time
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000001})
|
||||||
|
// created one month ago
|
||||||
|
unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000002})
|
||||||
|
// last online one hour ago
|
||||||
|
unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000003})
|
||||||
|
// last online 10 seconds ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000004})
|
||||||
|
// created 1 month ago
|
||||||
|
unittest.AssertNotExistsBean(t, &ActionRunner{ID: 10000005})
|
||||||
|
// created 1 hour ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000006})
|
||||||
|
// last online 1 hour ago
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &ActionRunner{ID: 10000007})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteOfflineRunnersErrorOnInvalidOlderThanValue(t *testing.T) {
|
||||||
|
baseTime := time.Date(2024, 5, 19, 7, 40, 32, 0, time.UTC)
|
||||||
|
timeutil.MockSet(baseTime)
|
||||||
|
defer timeutil.MockUnset()
|
||||||
|
require.Error(t, DeleteOfflineRunners(db.DefaultContext, timeutil.TimeStampNow(), false))
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,15 @@ var statusNames = map[Status]string{
|
||||||
StatusBlocked: "blocked",
|
StatusBlocked: "blocked",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nameToStatus = make(map[string]Status, len(statusNames))
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Populate name to status lookup map
|
||||||
|
for status, name := range statusNames {
|
||||||
|
nameToStatus[name] = status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string name of the Status
|
// String returns the string name of the Status
|
||||||
func (s Status) String() string {
|
func (s Status) String() string {
|
||||||
return statusNames[s]
|
return statusNames[s]
|
||||||
|
@ -102,3 +111,8 @@ func (s Status) AsResult() runnerv1.Result {
|
||||||
}
|
}
|
||||||
return runnerv1.Result_RESULT_UNSPECIFIED
|
return runnerv1.Result_RESULT_UNSPECIFIED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StatusFromString(name string) (Status, bool) {
|
||||||
|
status, exists := nameToStatus[name]
|
||||||
|
return status, exists
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package activities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -441,6 +442,12 @@ func (a *Action) GetIssueContent(ctx context.Context) string {
|
||||||
return a.Issue.Content
|
return a.Issue.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetActivityByID(ctx context.Context, id int64) (*Action, error) {
|
||||||
|
var act Action
|
||||||
|
_, err := db.GetEngine(ctx).ID(id).Get(&act)
|
||||||
|
return &act, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetFeedsOptions options for retrieving feeds
|
// GetFeedsOptions options for retrieving feeds
|
||||||
type GetFeedsOptions struct {
|
type GetFeedsOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
|
@ -458,7 +465,7 @@ type GetFeedsOptions struct {
|
||||||
// GetFeeds returns actions according to the provided options
|
// GetFeeds returns actions according to the provided options
|
||||||
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
|
func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, error) {
|
||||||
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
|
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
|
||||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
return nil, 0, errors.New("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||||
}
|
}
|
||||||
|
|
||||||
cond, err := activityQueryCondition(ctx, opts)
|
cond, err := activityQueryCondition(ctx, opts)
|
||||||
|
@ -466,11 +473,8 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := db.GetEngine(ctx).Where(cond).
|
|
||||||
Select("`action`.*"). // this line will avoid select other joined table's columns
|
|
||||||
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
|
|
||||||
|
|
||||||
opts.SetDefaultValues()
|
opts.SetDefaultValues()
|
||||||
|
sess := db.GetEngine(ctx).Where(cond)
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
|
||||||
actions := make([]*Action, 0, opts.PageSize)
|
actions := make([]*Action, 0, opts.PageSize)
|
||||||
|
@ -597,13 +601,14 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyWatchers creates batch of actions for every watcher.
|
// NotifyWatchers creates batch of actions for every watcher.
|
||||||
func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) {
|
||||||
var watchers []*repo_model.Watch
|
var watchers []*repo_model.Watch
|
||||||
var repo *repo_model.Repository
|
var repo *repo_model.Repository
|
||||||
var err error
|
var err error
|
||||||
var permCode []bool
|
var permCode []bool
|
||||||
var permIssue []bool
|
var permIssue []bool
|
||||||
var permPR []bool
|
var permPR []bool
|
||||||
|
var out []Action
|
||||||
|
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
@ -614,14 +619,14 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
// Add feeds for user self and all watchers.
|
// Add feeds for user self and all watchers.
|
||||||
watchers, err = repo_model.GetWatchers(ctx, act.RepoID)
|
watchers, err = repo_model.GetWatchers(ctx, act.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("get watchers: %w", err)
|
return nil, fmt.Errorf("get watchers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Be aware that optimizing this correctly into the `GetWatchers` SQL
|
// Be aware that optimizing this correctly into the `GetWatchers` SQL
|
||||||
// query is for most cases less performant than doing this.
|
// query is for most cases less performant than doing this.
|
||||||
blockedDoerUserIDs, err := user_model.ListBlockedByUsersID(ctx, act.ActUserID)
|
blockedDoerUserIDs, err := user_model.ListBlockedByUsersID(ctx, act.ActUserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("user_model.ListBlockedByUsersID: %w", err)
|
return nil, fmt.Errorf("user_model.ListBlockedByUsersID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(blockedDoerUserIDs) > 0 {
|
if len(blockedDoerUserIDs) > 0 {
|
||||||
|
@ -636,8 +641,9 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
// Add feed for actioner.
|
// Add feed for actioner.
|
||||||
act.UserID = act.ActUserID
|
act.UserID = act.ActUserID
|
||||||
if _, err = e.Insert(act); err != nil {
|
if _, err = e.Insert(act); err != nil {
|
||||||
return fmt.Errorf("insert new actioner: %w", err)
|
return nil, fmt.Errorf("insert new actioner: %w", err)
|
||||||
}
|
}
|
||||||
|
out = append(out, *act)
|
||||||
|
|
||||||
if repoChanged {
|
if repoChanged {
|
||||||
act.loadRepo(ctx)
|
act.loadRepo(ctx)
|
||||||
|
@ -645,7 +651,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
|
|
||||||
// check repo owner exist.
|
// check repo owner exist.
|
||||||
if err := act.Repo.LoadOwner(ctx); err != nil {
|
if err := act.Repo.LoadOwner(ctx); err != nil {
|
||||||
return fmt.Errorf("can't get repo owner: %w", err)
|
return nil, fmt.Errorf("can't get repo owner: %w", err)
|
||||||
}
|
}
|
||||||
} else if act.Repo == nil {
|
} else if act.Repo == nil {
|
||||||
act.Repo = repo
|
act.Repo = repo
|
||||||
|
@ -656,7 +662,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
act.ID = 0
|
act.ID = 0
|
||||||
act.UserID = act.Repo.Owner.ID
|
act.UserID = act.Repo.Owner.ID
|
||||||
if err = db.Insert(ctx, act); err != nil {
|
if err = db.Insert(ctx, act); err != nil {
|
||||||
return fmt.Errorf("insert new actioner: %w", err)
|
return nil, fmt.Errorf("insert new actioner: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,26 +715,29 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = db.Insert(ctx, act); err != nil {
|
if err = db.Insert(ctx, act); err != nil {
|
||||||
return fmt.Errorf("insert new action: %w", err)
|
return nil, fmt.Errorf("insert new action: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||||
func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
|
func NotifyWatchersActions(ctx context.Context, acts []*Action) ([]Action, error) {
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
var out []Action
|
||||||
for _, act := range acts {
|
for _, act := range acts {
|
||||||
if err := NotifyWatchers(ctx, act); err != nil {
|
as, err := NotifyWatchers(ctx, act)
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
out = append(out, as...)
|
||||||
}
|
}
|
||||||
return committer.Commit()
|
return out, committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueActions delete all actions related with issueID
|
// DeleteIssueActions delete all actions related with issueID
|
||||||
|
|
|
@ -197,7 +197,8 @@ func TestNotifyWatchers(t *testing.T) {
|
||||||
RepoID: 1,
|
RepoID: 1,
|
||||||
OpType: activities_model.ActionStarRepo,
|
OpType: activities_model.ActionStarRepo,
|
||||||
}
|
}
|
||||||
require.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action))
|
_, err := activities_model.NotifyWatchers(db.DefaultContext, action)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
|
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
|
||||||
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
||||||
|
@ -226,24 +227,6 @@ func TestNotifyWatchers(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFeedsCorrupted(t *testing.T) {
|
|
||||||
require.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
|
|
||||||
ID: 8,
|
|
||||||
RepoID: 1700,
|
|
||||||
})
|
|
||||||
|
|
||||||
actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
|
|
||||||
RequestedUser: user,
|
|
||||||
Actor: user,
|
|
||||||
IncludePrivate: true,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Empty(t, actions)
|
|
||||||
assert.Equal(t, int64(0), count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConsistencyUpdateAction(t *testing.T) {
|
func TestConsistencyUpdateAction(t *testing.T) {
|
||||||
if !setting.Database.Type.IsSQLite3() {
|
if !setting.Database.Type.IsSQLite3() {
|
||||||
t.Skip("Test is only for SQLite database.")
|
t.Skip("Test is only for SQLite database.")
|
||||||
|
|
106
models/activities/federated_user_activity.go
Normal file
106
models/activities/federated_user_activity.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package activities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"forgejo.org/models/db"
|
||||||
|
user_model "forgejo.org/models/user"
|
||||||
|
"forgejo.org/modules/json"
|
||||||
|
"forgejo.org/modules/log"
|
||||||
|
"forgejo.org/modules/timeutil"
|
||||||
|
"forgejo.org/modules/validation"
|
||||||
|
|
||||||
|
ap "github.com/go-ap/activitypub"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FederatedUserActivity struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
UserID int64 `xorm:"NOT NULL"`
|
||||||
|
ActorID int64
|
||||||
|
ActorURI string
|
||||||
|
Actor *user_model.User `xorm:"-"` // transient
|
||||||
|
NoteContent string `xorm:"TEXT"`
|
||||||
|
NoteURL string `xorm:"VARCHAR(255)"`
|
||||||
|
OriginalNote string `xorm:"TEXT"`
|
||||||
|
Created timeutil.TimeStamp `xorm:"created"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(FederatedUserActivity))
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFederatedUserActivity(userID, actorID int64, actorURI, noteContent, noteURL string, originalNote ap.Activity) (FederatedUserActivity, error) {
|
||||||
|
jsonString, err := json.Marshal(originalNote)
|
||||||
|
if err != nil {
|
||||||
|
return FederatedUserActivity{}, err
|
||||||
|
}
|
||||||
|
result := FederatedUserActivity{
|
||||||
|
UserID: userID,
|
||||||
|
ActorID: actorID,
|
||||||
|
ActorURI: actorURI,
|
||||||
|
NoteContent: noteContent,
|
||||||
|
NoteURL: noteURL,
|
||||||
|
OriginalNote: string(jsonString),
|
||||||
|
}
|
||||||
|
if valid, err := validation.IsValid(result); !valid {
|
||||||
|
return FederatedUserActivity{}, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (federatedUserActivity FederatedUserActivity) Validate() []string {
|
||||||
|
var result []string
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.UserID, "UserID")...)
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorID, "ActorID")...)
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorURI, "ActorURI")...)
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteContent, "NoteContent")...)
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteURL, "NoteURL")...)
|
||||||
|
result = append(result, validation.ValidateNotEmpty(federatedUserActivity.OriginalNote, "OriginalNote")...)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateUserActivity(ctx context.Context, federatedUserActivity *FederatedUserActivity) error {
|
||||||
|
if valid, err := validation.IsValid(federatedUserActivity); !valid {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := db.GetEngine(ctx).Insert(federatedUserActivity)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetFollowingFeedsOptions struct {
|
||||||
|
db.ListOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFollowingFeeds(ctx context.Context, actorID int64, opts GetFollowingFeedsOptions) ([]*FederatedUserActivity, int64, error) {
|
||||||
|
log.Debug("user_id = %s", actorID)
|
||||||
|
sess := db.GetEngine(ctx).Where("user_id = ?", actorID)
|
||||||
|
opts.SetDefaultValues()
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
|
||||||
|
actions := make([]*FederatedUserActivity, 0, opts.PageSize)
|
||||||
|
count, err := sess.FindAndCount(&actions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, fmt.Errorf("FindAndCount: %w", err)
|
||||||
|
}
|
||||||
|
for _, act := range actions {
|
||||||
|
if err := act.loadActor(ctx); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actions, count, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (federatedUserActivity *FederatedUserActivity) loadActor(ctx context.Context) error {
|
||||||
|
log.Debug("for activity %s", federatedUserActivity)
|
||||||
|
actorUser, _, err := user_model.GetFederatedUserByUserID(ctx, federatedUserActivity.ActorID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
federatedUserActivity.Actor = actorUser
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
24
models/activities/federated_user_activity_test.go
Normal file
24
models/activities/federated_user_activity_test.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2024 The Forgejo Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package activities
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"forgejo.org/modules/validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_FederatedUserActivityValidation(t *testing.T) {
|
||||||
|
sut := FederatedUserActivity{}
|
||||||
|
sut.UserID = 13
|
||||||
|
sut.ActorID = 33
|
||||||
|
sut.ActorURI = "33"
|
||||||
|
sut.NoteContent = "Any content!"
|
||||||
|
sut.NoteURL = "https://example.org/note/17"
|
||||||
|
sut.OriginalNote = "federatedUserActivityNote-17"
|
||||||
|
|
||||||
|
if res, _ := validation.IsValid(sut); !res {
|
||||||
|
t.Errorf("sut expected to be valid: %v\n", sut.Validate())
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ package asymkey
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -209,7 +210,7 @@ func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified
|
||||||
// deleteGPGKey does the actual key deletion
|
// deleteGPGKey does the actual key deletion
|
||||||
func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
||||||
if keyID == "" {
|
if keyID == "" {
|
||||||
return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure
|
return 0, errors.New("empty KeyId forbidden") // Should never happen but just to be sure
|
||||||
}
|
}
|
||||||
// Delete imported key
|
// Delete imported key
|
||||||
n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport))
|
n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport))
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
@ -75,7 +76,7 @@ func base64DecPubKey(content string) (*packet.PublicKey, error) {
|
||||||
// Check type
|
// Check type
|
||||||
pkey, ok := p.(*packet.PublicKey)
|
pkey, ok := p.(*packet.PublicKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("key is not a public key")
|
return nil, errors.New("key is not a public key")
|
||||||
}
|
}
|
||||||
return pkey, nil
|
return pkey, nil
|
||||||
}
|
}
|
||||||
|
@ -122,15 +123,15 @@ func readArmoredSign(r io.Reader) (body io.Reader, err error) {
|
||||||
func extractSignature(s string) (*packet.Signature, error) {
|
func extractSignature(s string) (*packet.Signature, error) {
|
||||||
r, err := readArmoredSign(strings.NewReader(s))
|
r, err := readArmoredSign(strings.NewReader(s))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to read signature armor")
|
return nil, errors.New("Failed to read signature armor")
|
||||||
}
|
}
|
||||||
p, err := packet.Read(r)
|
p, err := packet.Read(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to read signature packet")
|
return nil, errors.New("Failed to read signature packet")
|
||||||
}
|
}
|
||||||
sig, ok := p.(*packet.Signature)
|
sig, ok := p.(*packet.Signature)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Packet is not a signature")
|
return nil, errors.New("Packet is not a signature")
|
||||||
}
|
}
|
||||||
return sig, nil
|
return sig, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package asymkey
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -316,7 +317,7 @@ func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, si
|
||||||
func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
|
func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
|
||||||
// Check if key can sign
|
// Check if key can sign
|
||||||
if !k.CanSign {
|
if !k.CanSign {
|
||||||
return fmt.Errorf("key can not sign")
|
return errors.New("key can not sign")
|
||||||
}
|
}
|
||||||
// Decode key
|
// Decode key
|
||||||
pkey, err := base64DecPubKey(k.Content)
|
pkey, err := base64DecPubKey(k.Content)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
@ -93,7 +94,7 @@ func parseKeyString(content string) (string, error) {
|
||||||
|
|
||||||
block, _ := pem.Decode([]byte(content))
|
block, _ := pem.Decode([]byte(content))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return "", fmt.Errorf("failed to parse PEM block containing the public key")
|
return "", errors.New("failed to parse PEM block containing the public key")
|
||||||
}
|
}
|
||||||
if strings.Contains(block.Type, "PRIVATE") {
|
if strings.Contains(block.Type, "PRIVATE") {
|
||||||
return "", ErrKeyIsPrivate
|
return "", ErrKeyIsPrivate
|
||||||
|
@ -226,7 +227,7 @@ func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
|
||||||
|
|
||||||
// The ssh library can parse the key, so next we find out what key exactly we have.
|
// The ssh library can parse the key, so next we find out what key exactly we have.
|
||||||
switch pkeyType {
|
switch pkeyType {
|
||||||
case ssh.KeyAlgoDSA:
|
case ssh.KeyAlgoDSA: //nolint:staticcheck
|
||||||
rawPub := struct {
|
rawPub := struct {
|
||||||
Name string
|
Name string
|
||||||
P, Q, G, Y *big.Int
|
P, Q, G, Y *big.Int
|
||||||
|
|
|
@ -69,6 +69,9 @@ func (l *XORMLogBridge) Warn(v ...any) {
|
||||||
|
|
||||||
// Warnf show warning log
|
// Warnf show warning log
|
||||||
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
func (l *XORMLogBridge) Warnf(format string, v ...any) {
|
||||||
|
if format == "Table %s Column %s db default is %s, struct default is %s" || format == "Table %s Column %s db nullable is %v, struct nullable is %v" {
|
||||||
|
return
|
||||||
|
}
|
||||||
l.Log(stackLevel, log.WARN, format, v...)
|
l.Log(stackLevel, log.WARN, format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,7 +414,7 @@ func IsErrSHAOrCommitIDNotProvided(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrSHAOrCommitIDNotProvided) Error() string {
|
func (err ErrSHAOrCommitIDNotProvided) Error() string {
|
||||||
return "a SHA or commit ID must be proved when updating a file"
|
return "a SHA or commit ID must be provided when updating a file"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
|
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
|
||||||
|
|
17
models/fixtures/TestGetUsedForUser/action_artifact.yaml
Normal file
17
models/fixtures/TestGetUsedForUser/action_artifact.yaml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
-
|
||||||
|
id: 1001
|
||||||
|
run_id: 792
|
||||||
|
runner_id: 1
|
||||||
|
repo_id: 4
|
||||||
|
owner_id: 1
|
||||||
|
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
|
||||||
|
storage_path: "27/5/1730330775594233150.chunk"
|
||||||
|
file_size: 693147180559
|
||||||
|
file_compressed_size: 693147180559
|
||||||
|
content_encoding: "application/zip"
|
||||||
|
artifact_path: "big-file.zip"
|
||||||
|
artifact_name: "big-file"
|
||||||
|
status: 4
|
||||||
|
created_unix: 1730330775
|
||||||
|
updated_unix: 1730330775
|
||||||
|
expired_unix: 1738106775
|
|
@ -59,14 +59,6 @@
|
||||||
created_unix: 1603011540 # grouped with id:7
|
created_unix: 1603011540 # grouped with id:7
|
||||||
|
|
||||||
- id: 8
|
- id: 8
|
||||||
user_id: 1
|
|
||||||
op_type: 12 # close issue
|
|
||||||
act_user_id: 1
|
|
||||||
repo_id: 1700 # dangling intentional
|
|
||||||
is_private: false
|
|
||||||
created_unix: 1603011541
|
|
||||||
|
|
||||||
- id: 9
|
|
||||||
user_id: 34
|
user_id: 34
|
||||||
op_type: 12 # close issue
|
op_type: 12 # close issue
|
||||||
act_user_id: 34
|
act_user_id: 34
|
||||||
|
|
|
@ -471,3 +471,64 @@
|
||||||
need_approval: 0
|
need_approval: 0
|
||||||
approved_by: 0
|
approved_by: 0
|
||||||
event_payload: '{"head_commit":{"id":"5f22f7d0d95d614d25a5b68592adb345a4b5c7fd"}}'
|
event_payload: '{"head_commit":{"id":"5f22f7d0d95d614d25a5b68592adb345a4b5c7fd"}}'
|
||||||
|
|
||||||
|
|
||||||
|
# GET action run(s) test
|
||||||
|
-
|
||||||
|
id: 892
|
||||||
|
title: "successful push run"
|
||||||
|
repo_id: 63
|
||||||
|
owner_id: 2
|
||||||
|
workflow_id: "success.yaml"
|
||||||
|
index: 1
|
||||||
|
trigger_user_id: 2
|
||||||
|
ref: "refs/heads/main"
|
||||||
|
commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee"
|
||||||
|
event: "push"
|
||||||
|
is_fork_pull_request: 0
|
||||||
|
status: 1 # success
|
||||||
|
started: 1683636528
|
||||||
|
stopped: 1683636626
|
||||||
|
created: 1683636108
|
||||||
|
updated: 1683636626
|
||||||
|
need_approval: 0
|
||||||
|
approved_by: 0
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 893
|
||||||
|
title: "failed pull_request run"
|
||||||
|
repo_id: 63
|
||||||
|
owner_id: 2
|
||||||
|
workflow_id: "failed.yaml"
|
||||||
|
index: 2
|
||||||
|
trigger_user_id: 2
|
||||||
|
ref: "refs/heads/bugfix-1"
|
||||||
|
commit_sha: "35c5cddfc19397501ec8f4f7bb808a7c8f04445f"
|
||||||
|
event: "pull_request"
|
||||||
|
is_fork_pull_request: 0
|
||||||
|
status: 2 # failure
|
||||||
|
started: 1683636528
|
||||||
|
stopped: 1683636626
|
||||||
|
created: 1683636108
|
||||||
|
updated: 1683636626
|
||||||
|
need_approval: 0
|
||||||
|
approved_by: 0
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 894
|
||||||
|
title: "running workflow_dispatch run"
|
||||||
|
repo_id: 63
|
||||||
|
owner_id: 2
|
||||||
|
workflow_id: "running.yaml"
|
||||||
|
index: 3
|
||||||
|
trigger_user_id: 2
|
||||||
|
ref: "refs/heads/main"
|
||||||
|
commit_sha: "97f29ee599c373c729132a5c46a046978311e0ee"
|
||||||
|
event: "workflow_dispatch"
|
||||||
|
is_fork_pull_request: 0
|
||||||
|
status: 6 # running
|
||||||
|
started: 1683636528
|
||||||
|
created: 1683636108
|
||||||
|
updated: 1683636626
|
||||||
|
need_approval: 0
|
||||||
|
approved_by: 0
|
||||||
|
|
|
@ -18,3 +18,122 @@
|
||||||
created: 1716104432
|
created: 1716104432
|
||||||
updated: 1716104432
|
updated: 1716104432
|
||||||
deleted: ~
|
deleted: ~
|
||||||
|
- id: 10000001
|
||||||
|
uuid: 10d3b248-6460-4bf5-b819-1f5b3109e10f
|
||||||
|
name: global-online
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 0
|
||||||
|
repo_id: 0
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: 7e9ed71f64e98ce1f70e94c63f3cb6c41a8cb0b90de3e1daf7ec5c35361d60ed44da67c5ac393b7aaf443dcfc766007dc828
|
||||||
|
token_salt: WUcgZWl7mW
|
||||||
|
last_online: 1716104422
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1716104431
|
||||||
|
updated: 1716104422
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000002
|
||||||
|
uuid: 1d188484-dd97-4a70-b707-5e87b578ab6b
|
||||||
|
name: repo-never-used
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 0
|
||||||
|
repo_id: 1
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: 51e88c17ac8b54dd101dc2e4f530a71643c703adba7170f4b1a28f1cb483b4cfb107798c521e0532ef3c6480b64518a5c6a5
|
||||||
|
token_salt: 4rh8ncXYIO
|
||||||
|
last_online: 0
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1713512432
|
||||||
|
updated: 1713512432
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000003
|
||||||
|
uuid: 7a039c6b-b0b2-4cf5-a93d-715d617f99e2
|
||||||
|
name: global-offline
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 0
|
||||||
|
repo_id: 0
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: c76960c56bc6069f0d1648991ec626500abe8c15286f5c355d565c3b5ba945d7d6f1272a6c77849e592528179511b94f5d69
|
||||||
|
token_salt: TFMe2jhOkB
|
||||||
|
last_online: 1715499632
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1715499632
|
||||||
|
updated: 1715499632
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000004
|
||||||
|
uuid: 93ca7fdd-faca-4df6-a474-8345263ef10b
|
||||||
|
name: user-online
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 1
|
||||||
|
repo_id: 0
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: 6ddf7f0f2301d2b3f66418145dc497a6d09fa6586e659afcb5ae2a0c5b639561d795aff8062537db9df73b396842ea826134
|
||||||
|
token_salt: QcdGuReAp4
|
||||||
|
last_online: 1716104422
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1716104431
|
||||||
|
updated: 1716104422
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000005
|
||||||
|
uuid: a8534df6-c4be-40f4-9714-903b69d973d9
|
||||||
|
name: user-never-used
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 1
|
||||||
|
repo_id: 0
|
||||||
|
description: desc
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: 4441de7defcfc3d21baa608dec66a562cf23307abddaabdbb836907ac5f48c8780c354891916c525b79ec7af8e95be7a09b4
|
||||||
|
token_salt: ONNqIOnj3t
|
||||||
|
last_online: 0
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1713512433
|
||||||
|
updated: 1713512433
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000006
|
||||||
|
uuid: e1c5bb6c-de68-4335-8955-5192f76708ac
|
||||||
|
name: orga-fresh-created
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 35
|
||||||
|
repo_id: 0
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: a61f9ee48c6847d243ace0a8936efe80af9277c7bc46d6da6e03d1d406608b8023ee66600ad24f0effaa8e3338f92ac97ac9
|
||||||
|
token_salt: fZJKjrFGWA
|
||||||
|
last_online: 0
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1716100832
|
||||||
|
updated: 1716100832
|
||||||
|
deleted: ~
|
||||||
|
- id: 10000007
|
||||||
|
uuid: ff755f06-948e-479b-8031-5b3e9f123e32
|
||||||
|
name: orga-offline
|
||||||
|
version: v6.3.1+7-gc4c0ca0
|
||||||
|
owner_id: 35
|
||||||
|
repo_id: 0
|
||||||
|
description: ""
|
||||||
|
base: 0
|
||||||
|
repo_range: ""
|
||||||
|
token_hash: 9372efb38f9b64efe65065380abe2f24ef34a59d9619f4cdc08f1151e9849f0b6e722aa10538e8730288de6e2f09acdac695
|
||||||
|
token_salt: TnU7iiIdCb
|
||||||
|
last_online: 1716100832
|
||||||
|
last_active: 0
|
||||||
|
agent_labels: '["docker"]'
|
||||||
|
created: 1736085520
|
||||||
|
updated: 1716100832
|
||||||
|
deleted: ~
|
||||||
|
|
|
@ -113,3 +113,344 @@
|
||||||
review_id: 22
|
review_id: 22
|
||||||
assignee_id: 5
|
assignee_id: 5
|
||||||
created_unix: 946684817
|
created_unix: 946684817
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 13
|
||||||
|
type: 29 # push
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 19 # in repo_id 58
|
||||||
|
content: '{"is_force_push":false,"commit_ids":["4ca8bcaf27e28504df7bf996819665986b01c847","96cef4a7b72b3c208340ae6f0cf55a93e9077c93","c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2"]}'
|
||||||
|
created_unix: 1688672373
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 14
|
||||||
|
type: 29 # push
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 19 # in repo_id 58
|
||||||
|
content: '{"is_force_push":false,"commit_ids":["23576dd018294e476c06e569b6b0f170d0558705"]}'
|
||||||
|
created_unix: 1688672374
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 15
|
||||||
|
type: 29 # push
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 19 # in repo_id 58
|
||||||
|
content: '{"is_force_push":false,"commit_ids":["3e64625bd6eb5bcba69ac97de6c8f507402df861", "c704db5794097441aa2d9dd834d5b7e2f8f08108"]}'
|
||||||
|
created_unix: 1688672375
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 16
|
||||||
|
type: 29 # push
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 19 # in repo_id 58
|
||||||
|
content: '{"is_force_push":false,"commit_ids":["811d46c7e518f4f180afb862c0db5cb8c80529ce", "747ddb3506a4fa04a7747808eb56ae16f9e933dc", "837d5c8125633d7d258f93b998e867eab0145520", "1978192d98bb1b65e11c2cf37da854fbf94bffd6"]}'
|
||||||
|
created_unix: 1688672376
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 17
|
||||||
|
type: 29 # push
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 19 # in repo_id 58
|
||||||
|
content: '{"is_force_push":true,"commit_ids":["1978192d98bb1b65e11c2cf37da854fbf94bffd6", "9b93963cf6de4dc33f915bb67f192d099c301f43"]}'
|
||||||
|
created_unix: 1749734240
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2000
|
||||||
|
type: 8 # milestone
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
milestone_id: 1
|
||||||
|
old_milestone_id: 0
|
||||||
|
created_unix: 946684820
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2001
|
||||||
|
type: 8 # milestone
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
milestone_id: 2
|
||||||
|
old_milestone_id: 1
|
||||||
|
created_unix: 946684920
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2002
|
||||||
|
type: 8 # milestone
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
milestone_id: 0
|
||||||
|
old_milestone_id: 2
|
||||||
|
created_unix: 946685020
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2003
|
||||||
|
type: 8 # milestone
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
milestone_id: 10 # not exsting milestone
|
||||||
|
old_milestone_id: 0
|
||||||
|
created_unix: 946685080
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2010
|
||||||
|
type: 30 # project
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
project_id: 1
|
||||||
|
old_project_id: 0
|
||||||
|
created_unix: 946685120
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2011
|
||||||
|
type: 30 # project
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
project_id: 2
|
||||||
|
old_project_id: 1
|
||||||
|
created_unix: 946685220
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2012
|
||||||
|
type: 30 # project
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
project_id: 0
|
||||||
|
old_project_id: 2
|
||||||
|
created_unix: 946685320
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2013
|
||||||
|
type: 30 # project
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
project_id: 10 # not existing project
|
||||||
|
old_project_id: 0
|
||||||
|
created_unix: 946685420
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2020
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 1
|
||||||
|
content: 1 # add label
|
||||||
|
created_unix: 946685520
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2021
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1
|
||||||
|
label_id: 2
|
||||||
|
content: 1 # add label
|
||||||
|
created_unix: 946685620
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2022
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 1
|
||||||
|
content: 0 # remove label
|
||||||
|
created_unix: 946685720
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2023
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 1
|
||||||
|
content: 1 # add label
|
||||||
|
created_unix: 946685720
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2024
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 2
|
||||||
|
content: 0 # remove label
|
||||||
|
created_unix: 946685720
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2025
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 2
|
||||||
|
content: 1 # add label
|
||||||
|
created_unix: 946685820
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2026
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 1
|
||||||
|
content: 0 # remove label
|
||||||
|
created_unix: 946685920
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 2027
|
||||||
|
type: 7 # label
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
label_id: 2
|
||||||
|
content: 0 # remove label
|
||||||
|
created_unix: 946685920
|
||||||
|
|
||||||
|
- id: 2040
|
||||||
|
type: 9 # assignee
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
assignee_id: 1 # self
|
||||||
|
removed_assignee: false # add assignee
|
||||||
|
created_unix: 946688020
|
||||||
|
|
||||||
|
- id: 2041
|
||||||
|
type: 9 # assignee
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
assignee_id: 1
|
||||||
|
removed_assignee: true # remove assignee
|
||||||
|
created_unix: 946688120
|
||||||
|
|
||||||
|
- id: 2042
|
||||||
|
type: 9 # assignee
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
assignee_id: 2
|
||||||
|
removed_assignee: false # add assignee
|
||||||
|
created_unix: 946688220
|
||||||
|
|
||||||
|
- id: 2043
|
||||||
|
type: 9 # assignee
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
assignee_id: 2 # self
|
||||||
|
removed_assignee: true # remove assignee
|
||||||
|
created_unix: 946688320
|
||||||
|
|
||||||
|
- id: 2050
|
||||||
|
type: 23 # lock
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946688420
|
||||||
|
|
||||||
|
- id: 2051
|
||||||
|
type: 24 # unlock
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946688520
|
||||||
|
|
||||||
|
- id: 2052
|
||||||
|
type: 23 # lock
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
content: "Too heated"
|
||||||
|
created_unix: 946688620
|
||||||
|
|
||||||
|
- id: 2053
|
||||||
|
type: 24 # unlock
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946688720
|
||||||
|
|
||||||
|
- id: 2060
|
||||||
|
type: 36 # pin
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946688820
|
||||||
|
|
||||||
|
- id: 2061
|
||||||
|
type: 37 # unpin
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946688920
|
||||||
|
|
||||||
|
- id: 2070
|
||||||
|
type: 2 # close
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946689020
|
||||||
|
|
||||||
|
- id: 2071
|
||||||
|
type: 1 # reopen
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 1 # in repo_id 1
|
||||||
|
created_unix: 946689220
|
||||||
|
|
||||||
|
- id: 2072
|
||||||
|
type: 2 # close
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
created_unix: 946689320
|
||||||
|
|
||||||
|
- id: 2073
|
||||||
|
type: 1 # reopen
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
created_unix: 946689420
|
||||||
|
|
||||||
|
- id: 2080
|
||||||
|
type: 3 # issue reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # issue in repo_id 1
|
||||||
|
ref_repo_id: 1
|
||||||
|
ref_issue_id: 5 # issue in repo_id 1
|
||||||
|
created_unix: 946689500
|
||||||
|
|
||||||
|
- id: 2081
|
||||||
|
type: 3 # issue reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # issue in repo_id 1
|
||||||
|
ref_repo_id: 1
|
||||||
|
ref_issue_id: 2 # pull in repo_id 1
|
||||||
|
created_unix: 946689600
|
||||||
|
|
||||||
|
- id: 2082
|
||||||
|
type: 3 # issue reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # issue in repo_id 1
|
||||||
|
ref_repo_id: 32
|
||||||
|
ref_issue_id: 16 # issue in repo_id 32
|
||||||
|
created_unix: 946689700
|
||||||
|
|
||||||
|
- id: 2083
|
||||||
|
type: 3 # issue reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 1 # issue in repo_id 1
|
||||||
|
ref_repo_id: 10
|
||||||
|
ref_issue_id: 8 # pull in repo_id 10
|
||||||
|
created_unix: 946689800
|
||||||
|
|
||||||
|
- id: 2090
|
||||||
|
type: 6 # pull reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
ref_repo_id: 1
|
||||||
|
ref_issue_id: 1 # issue in repo_id 1
|
||||||
|
created_unix: 946689900
|
||||||
|
|
||||||
|
- id: 2091
|
||||||
|
type: 6 # pull reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
ref_repo_id: 1
|
||||||
|
ref_issue_id: 2 # pull in repo_id 1
|
||||||
|
created_unix: 946690000
|
||||||
|
|
||||||
|
- id: 2092
|
||||||
|
type: 6 # pull reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
ref_repo_id: 32
|
||||||
|
ref_issue_id: 16 # issue in repo_id 32
|
||||||
|
created_unix: 946690050
|
||||||
|
|
||||||
|
- id: 2093
|
||||||
|
type: 6 # pull reference
|
||||||
|
poster_id: 1
|
||||||
|
issue_id: 2 # pull in repo_id 1
|
||||||
|
ref_repo_id: 10
|
||||||
|
ref_issue_id: 8 # pull in repo_id 10
|
||||||
|
created_unix: 946690100
|
||||||
|
|
|
@ -17,3 +17,13 @@
|
||||||
id: 4
|
id: 4
|
||||||
user_id: 31
|
user_id: 31
|
||||||
follow_id: 33
|
follow_id: 33
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 5
|
||||||
|
user_id: 4
|
||||||
|
follow_id: 8
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 6
|
||||||
|
user_id: 5
|
||||||
|
follow_id: 8
|
||||||
|
|
1
models/fixtures/pull_auto_merge.yml
Normal file
1
models/fixtures/pull_auto_merge.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
[] # empty
|
|
@ -795,3 +795,10 @@
|
||||||
type: 10
|
type: 10
|
||||||
config: "{}"
|
config: "{}"
|
||||||
created_unix: 946684810
|
created_unix: 946684810
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 115
|
||||||
|
repo_id: 63
|
||||||
|
type: 10
|
||||||
|
config: "{}"
|
||||||
|
created_unix: 946684810
|
||||||
|
|
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