Compare commits

..

4 commits

Author SHA1 Message Date
3b47057ffa
Add woodpecker ci (temp)
All checks were successful
ci/woodpecker/pr/build Pipeline was successful
testing / backend-checks (pull_request) Successful in 5m29s
testing / frontend-checks (pull_request) Successful in 1m26s
/ release-notes (pull_request_target) Has been skipped
ci/woodpecker/push/build Pipeline was successful
testing / test-unit (pull_request) Successful in 7m26s
testing / test-e2e (pull_request) Successful in 2m47s
testing / test-mysql (pull_request) Successful in 31m57s
testing / test-pgsql (pull_request) Successful in 38m25s
testing / test-sqlite (pull_request) Successful in 32m14s
testing / test-remote-cacher (map[image:docker.io/bitnami/redis:7.2 port:6379]) (pull_request) Successful in 2m26s
testing / test-remote-cacher (map[image:docker.io/bitnami/valkey:7.2 port:6379]) (pull_request) Successful in 2m23s
testing / test-remote-cacher (map[image:ghcr.io/microsoft/garnet-alpine:1.0.14 port:6379]) (pull_request) Successful in 2m32s
testing / test-remote-cacher (map[image:registry.redict.io/redict:7.3.0-scratch port:6379]) (pull_request) Successful in 2m36s
testing / security-check (pull_request) Successful in 1m5s
2024-10-28 07:08:32 +01:00
7635150699
tests/integration: add integration tests for automerge pull requests
Some checks failed
testing / backend-checks (pull_request) Successful in 5m54s
testing / frontend-checks (pull_request) Failing after 47s
/ release-notes (pull_request_target) Has been skipped
testing / test-unit (pull_request) Has been skipped
testing / test-e2e (pull_request) Has been skipped
testing / test-mysql (pull_request) Has been skipped
testing / test-pgsql (pull_request) Has been skipped
testing / test-sqlite (pull_request) Has been skipped
testing / test-remote-cacher (map[image:docker.io/bitnami/redis:7.2 port:6379]) (pull_request) Has been skipped
testing / test-remote-cacher (map[image:docker.io/bitnami/valkey:7.2 port:6379]) (pull_request) Has been skipped
testing / test-remote-cacher (map[image:ghcr.io/microsoft/garnet-alpine:1.0.14 port:6379]) (pull_request) Has been skipped
testing / test-remote-cacher (map[image:registry.redict.io/redict:7.3.0-scratch port:6379]) (pull_request) Has been skipped
testing / security-check (pull_request) Has been skipped
2024-10-28 06:53:24 +01:00
19ed5ae3be
Add branch auto deletion for scheduled PRs 2024-10-28 06:53:15 +01:00
07a030af63
create "shared" package to workaround import loop issues 2024-10-28 06:32:15 +01:00
559 changed files with 6614 additions and 11631 deletions

View file

@ -137,6 +137,9 @@ code.gitea.io/gitea/modules/git
AddChangesWithArgs AddChangesWithArgs
CommitChanges CommitChanges
CommitChangesWithArgs CommitChangesWithArgs
IsErrExecTimeout
ErrExecTimeout.Error
ErrUnsupportedVersion.Error
SetUpdateHook SetUpdateHook
openRepositoryWithDefaultContext openRepositoryWithDefaultContext
IsTagExist IsTagExist
@ -247,9 +250,6 @@ code.gitea.io/gitea/modules/translation
MockLocale.TrSize MockLocale.TrSize
MockLocale.PrettyNumber MockLocale.PrettyNumber
code.gitea.io/gitea/modules/util
OptionalArg
code.gitea.io/gitea/modules/util/filebuffer code.gitea.io/gitea/modules/util/filebuffer
CreateFromReader CreateFromReader

View file

@ -1,3 +1,3 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.23.3 go 1.23.2

View file

@ -31,7 +31,7 @@ on:
jobs: jobs:
backporting: backporting:
if: > if: >
( vars.ROLE == 'forgejo-coding' ) && ( !startsWith(vars.ROLE, 'forgejo-') && (
github.event.pull_request.merged github.event.pull_request.merged
&& &&
contains(toJSON(github.event.pull_request.labels), 'backport/v') contains(toJSON(github.event.pull_request.labels), 'backport/v')
@ -45,7 +45,7 @@ jobs:
cat <<'EOF' cat <<'EOF'
${{ toJSON(github) }} ${{ toJSON(github) }}
EOF EOF
- uses: https://code.forgejo.org/actions/git-backporting@v4.8.4 - uses: https://code.forgejo.org/actions/git-backporting@v4.8.2
with: with:
target-branch-pattern: "^backport/(?<target>(v.*))$" target-branch-pattern: "^backport/(?<target>(v.*))$"
strategy: ort strategy: ort

View file

@ -22,7 +22,7 @@ on:
jobs: jobs:
release-simulation: release-simulation:
if: vars.ROLE == 'forgejo-coding' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: self-hosted runs-on: self-hosted
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View file

@ -12,10 +12,8 @@
# whatever is in the default branch instead # whatever is in the default branch instead
# #
# - after it is merged, double check it works by setting the # - after it is merged, double check it works by setting the
# run-end-to-end-test on a pull request (any pull request will do) # run-end-to-end-test on a pull request (any pull request will doe
# #
name: end-to-end
on: on:
push: push:
branches: branches:
@ -26,7 +24,7 @@ on:
jobs: jobs:
info: info:
if: vars.ROLE == 'forgejo-coding' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
container: container:
image: code.forgejo.org/oci/node:20-bookworm image: code.forgejo.org/oci/node:20-bookworm
@ -35,9 +33,10 @@ jobs:
run: | run: |
echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }} echo github.event.pull_request.head.repo.fork = ${{ github.event.pull_request.head.repo.fork }}
echo github.event.action = ${{ github.event.action }} echo github.event.action = ${{ github.event.action }}
echo github.event.label echo github.event.pull_request.merged = ${{ github.event.pull_request.merged }}
echo github.event.pull_request.labels.*.name
cat <<'EOF' cat <<'EOF'
${{ toJSON(github.event.label) }} ${{ toJSON(github.event.pull_request.labels.*.name) }}
EOF EOF
cat <<'EOF' cat <<'EOF'
${{ toJSON(github.event) }} ${{ toJSON(github.event) }}
@ -45,10 +44,10 @@ jobs:
cascade: cascade:
if: > if: >
vars.ROLE == 'forgejo-coding' && ( !startsWith(vars.ROLE, 'forgejo-') && (
github.event_name == 'push' || github.event_name == 'push' ||
( (
github.event.action == 'label_updated' && github.event.label.name == 'run-end-to-end-tests' github.event.action == 'label_updated' && contains(github.event.pull_request.labels.*.name, 'run-end-to-end-tests')
) )
) )
runs-on: docker runs-on: docker

View file

@ -1,45 +0,0 @@
# Copyright 2024 The Forgejo Authors
# SPDX-License-Identifier: MIT
name: requirements
on:
pull_request:
types:
- labeled
- edited
- opened
- synchronize
jobs:
merge-conditions:
if: vars.ROLE == 'forgejo-coding'
runs-on: docker
container:
image: 'code.forgejo.org/oci/node:20-bookworm'
steps:
- name: Debug output
run: |
cat <<'EOF'
${{ toJSON(github.event) }}
EOF
- name: Missing test label
if: >
!(
contains(toJSON(github.event.pull_request.labels), 'test/present')
|| contains(toJSON(github.event.pull_request.labels), 'test/not-needed')
|| contains(toJSON(github.event.pull_request.labels), 'test/manual')
)
run: |
echo "Test label must be set to either 'present', 'not-needed' or 'manual'."
exit 1
- name: Missing manual test instructions
if: >
(
contains(toJSON(github.event.pull_request.labels), 'test/manual')
&& !contains(toJSON(github.event.pull_request.body), '# Test')
)
run: |
echo "Manual test label is set. The PR description needs to contain test steps introduced by a heading like:"
echo "# Testing"
exit 1

View file

@ -59,31 +59,16 @@ jobs:
gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }} gpg-passphrase: ${{ secrets.GPG_PASSPHRASE }}
verbose: ${{ vars.VERBOSE }} verbose: ${{ vars.VERBOSE }}
- name: get trigger mirror issue
id: mirror
uses: https://code.forgejo.org/infrastructure/issue-action/get@v1.1.0
with:
forgejo: https://code.forgejo.org
repository: forgejo/forgejo
labels: mirror-trigger
- name: trigger the mirror
uses: https://code.forgejo.org/infrastructure/issue-action/set@v1.1.0
with:
forgejo: https://code.forgejo.org
repository: forgejo/forgejo
token: ${{ secrets.LABEL_ISSUE_FORGEJO_MIRROR_TOKEN }}
numbers: ${{ steps.mirror.outputs.numbers }}
label-wait-if-exists: 3600
label: trigger
- name: upgrade v*.next.forgejo.org - name: upgrade v*.next.forgejo.org
uses: https://code.forgejo.org/infrastructure/next-digest@v1.1.0 run: |
with: export DEBIAN_FRONTEND=noninteractive
url: https://placeholder:${{ secrets.TOKEN_NEXT_DIGEST }}@code.forgejo.org/infrastructure/next-digest apt-get update -qq
ref_name: '${{ github.ref_name }}' apt-get -q install -y -qq curl
image: 'codeberg.org/forgejo-experimental/forgejo' version="${{ github.ref_name }}"
tag_suffix: '-rootless' version=${version##*v}
major=$(echo $version | sed -E -e 's/^([0-9]+).*/\1/')
# https://forgejo.org/docs/next/developer/infrastructure
curl -o /dev/null -sS https://v$major.next.forgejo.org/.well-known/wakeup-on-logs/forgejo-v$major
- name: set up go for the DNS update below - name: set up go for the DNS update below
if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != '' if: vars.ROLE == 'forgejo-experimental' && secrets.OVH_APP_KEY != ''

View file

@ -6,7 +6,7 @@ on:
jobs: jobs:
release-notes: release-notes:
if: vars.ROLE == 'forgejo-coding' if: ${{ !startsWith(vars.ROLE, 'forgejo-')
runs-on: docker runs-on: docker
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'

View file

@ -7,7 +7,7 @@ on:
jobs: jobs:
release-notes: release-notes:
if: ( vars.ROLE == 'forgejo-coding' ) && contains(github.event.pull_request.labels.*.name, 'worth a release-note') if: ${{ !startsWith(vars.ROLE, 'forgejo-') && contains(github.event.pull_request.labels.*.name, 'worth a release-note') }}
runs-on: docker runs-on: docker
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'

View file

@ -8,9 +8,7 @@ name: renovate
on: on:
push: push:
branches: branches:
- renovate/** # self-test updates - 'renovate/**' # self-test updates
paths:
- .forgejo/workflows/renovate.yml
schedule: schedule:
- cron: '0 0/2 * * *' - cron: '0 0/2 * * *'
workflow_dispatch: workflow_dispatch:
@ -21,11 +19,11 @@ env:
jobs: jobs:
renovate: renovate:
if: vars.ROLE == 'forgejo-coding' && secrets.RENOVATE_TOKEN != '' if: ${{ secrets.RENOVATE_TOKEN != '' }}
runs-on: docker-runner-one runs-on: docker
container: container:
image: code.forgejo.org/forgejo-contrib/renovate:39.9.1 image: code.forgejo.org/forgejo-contrib/renovate:38.128.6
steps: steps:
- name: Load renovate repo cache - name: Load renovate repo cache

View file

@ -10,7 +10,7 @@ on:
jobs: jobs:
backend-checks: backend-checks:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
@ -26,7 +26,7 @@ jobs:
- run: su forgejo -c 'make --always-make -j$(nproc) lint-backend tidy-check swagger-check fmt-check swagger-validate' # ensure the "go-licenses" make target runs - run: su forgejo -c 'make --always-make -j$(nproc) lint-backend tidy-check swagger-check fmt-check swagger-validate' # ensure the "go-licenses" make target runs
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
frontend-checks: frontend-checks:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
@ -49,22 +49,21 @@ jobs:
path: ${{github.workspace}}/public/assets path: ${{github.workspace}}/public/assets
key: frontend-build-${{ github.sha }} key: frontend-build-${{ github.sha }}
test-unit: test-unit:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks] needs: [backend-checks, frontend-checks]
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
services: services:
elasticsearch: elasticsearch:
image: code.forgejo.org/oci/bitnami/elasticsearch:7 image: docker.io/bitnami/elasticsearch:7
options: --tmpfs /bitnami/elasticsearch/data
env: env:
discovery.type: single-node discovery.type: single-node
ES_JAVA_OPTS: "-Xms512m -Xmx512m" ES_JAVA_OPTS: "-Xms512m -Xmx512m"
minio: minio:
image: code.forgejo.org/oci/bitnami/minio:2024.8.17 image: docker.io/bitnami/minio:2024.8.17
options: >- options: >-
--hostname gitea.minio --tmpfs /bitnami/minio/data --hostname gitea.minio
env: env:
MINIO_DOMAIN: minio MINIO_DOMAIN: minio
MINIO_ROOT_USER: 123456 MINIO_ROOT_USER: 123456
@ -83,13 +82,13 @@ jobs:
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
- run: | - run: |
su forgejo -c 'make test-backend test-check' su forgejo -c 'make test-backend test-check'
timeout-minutes: 120 timeout-minutes: 50
env: env:
RACE_ENABLED: 'true' RACE_ENABLED: 'true'
TAGS: bindata TAGS: bindata
TEST_ELASTICSEARCH_URL: http://elasticsearch:9200 TEST_ELASTICSEARCH_URL: http://elasticsearch:9200
test-e2e: test-e2e:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks] needs: [backend-checks, frontend-checks]
container: container:
@ -117,40 +116,32 @@ jobs:
separator: '\n' separator: '\n'
- run: | - run: |
su forgejo -c 'make generate test-e2e-sqlite' su forgejo -c 'make generate test-e2e-sqlite'
timeout-minutes: 120 timeout-minutes: 40
env: env:
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}}
- name: Upload test artifacts on failure
if: failure()
uses: https://code.forgejo.org/forgejo/upload-artifact@v4
with:
name: test-artifacts.zip
path: tests/e2e/test-artifacts/
retention-days: 3
test-remote-cacher: test-remote-cacher:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks, test-unit] needs: [backend-checks, frontend-checks, test-unit]
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
name: ${{ format('test-remote-cacher ({0})', matrix.cacher.name) }}
strategy: strategy:
matrix: matrix:
cacher: cacher:
- name: redis # redis
image: code.forgejo.org/oci/bitnami/redis:7.2 - image: docker.io/bitnami/redis:7.2
options: --tmpfs /bitnami/redis/data port: 6379
- name: redict # redict
image: registry.redict.io/redict:7.3.0-scratch - image: registry.redict.io/redict:7.3.0-scratch
options: --tmpfs /data port: 6379
- name: valkey # valkey
image: code.forgejo.org/oci/bitnami/valkey:7.2 - image: docker.io/bitnami/valkey:7.2
options: --tmpfs /bitnami/redis/data port: 6379
- name: garnet # garnet
image: ghcr.io/microsoft/garnet-alpine:1.0.14 - image: ghcr.io/microsoft/garnet-alpine:1.0.14
options: --tmpfs /data port: 6379
services: services:
cacher: cacher:
image: ${{ matrix.cacher.image }} image: ${{ matrix.cacher.image }}
@ -165,28 +156,27 @@ jobs:
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
- run: | - run: |
su forgejo -c 'make test-remote-cacher test-check' su forgejo -c 'make test-remote-cacher test-check'
timeout-minutes: 120 timeout-minutes: 50
env: env:
RACE_ENABLED: 'true' RACE_ENABLED: 'true'
TAGS: bindata TAGS: bindata
TEST_REDIS_SERVER: cacher:${{ matrix.cacher.port }} TEST_REDIS_SERVER: cacher:${{ matrix.cacher.port }}
test-mysql: test-mysql:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks] needs: [backend-checks, frontend-checks]
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
services: services:
mysql: mysql:
image: 'code.forgejo.org/oci/bitnami/mysql:8.4' image: 'docker.io/bitnami/mysql:8.4'
env: env:
ALLOW_EMPTY_PASSWORD: yes ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea MYSQL_DATABASE: testgitea
# #
# See also https://codeberg.org/forgejo/forgejo/issues/976 # See also https://codeberg.org/forgejo/forgejo/issues/976
# #
MYSQL_EXTRA_FLAGS: --innodb-adaptive-flushing=OFF --innodb-buffer-pool-size=4G --innodb-log-buffer-size=128M --innodb-flush-log-at-trx-commit=0 --innodb-flush-log-at-timeout=30 --innodb-flush-method=nosync --innodb-fsync-threshold=1000000000 --disable-log-bin MYSQL_EXTRA_FLAGS: --innodb-adaptive-flushing=OFF --innodb-buffer-pool-size=4G --innodb-log-buffer-size=128M --innodb-flush-log-at-trx-commit=0 --innodb-flush-log-at-timeout=30 --innodb-flush-method=nosync --innodb-fsync-threshold=1000000000
options: --tmpfs /bitnami/mysql/data
steps: steps:
- uses: https://code.forgejo.org/actions/checkout@v4 - uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env - uses: ./.forgejo/workflows-composite/setup-env
@ -197,30 +187,28 @@ jobs:
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
- run: | - run: |
su forgejo -c 'make test-mysql-migration test-mysql' su forgejo -c 'make test-mysql-migration test-mysql'
timeout-minutes: 120 timeout-minutes: 50
env: env:
USE_REPO_TEST_DIR: 1 USE_REPO_TEST_DIR: 1
test-pgsql: test-pgsql:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks] needs: [backend-checks, frontend-checks]
container: container:
image: 'code.forgejo.org/oci/node:20-bookworm' image: 'code.forgejo.org/oci/node:20-bookworm'
services: services:
minio: minio:
image: code.forgejo.org/oci/bitnami/minio:2024.8.17 image: docker.io/bitnami/minio:2024.8.17
env: env:
MINIO_ROOT_USER: 123456 MINIO_ROOT_USER: 123456
MINIO_ROOT_PASSWORD: 12345678 MINIO_ROOT_PASSWORD: 12345678
options: --tmpfs /bitnami/minio/data
ldap: ldap:
image: code.forgejo.org/oci/test-openldap:latest image: docker.io/gitea/test-openldap:latest
pgsql: pgsql:
image: 'code.forgejo.org/oci/postgres:15' image: 'code.forgejo.org/oci/postgres:15'
env: env:
POSTGRES_DB: test POSTGRES_DB: test
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
options: --tmpfs /var/lib/postgresql/data
steps: steps:
- uses: https://code.forgejo.org/actions/checkout@v4 - uses: https://code.forgejo.org/actions/checkout@v4
- uses: ./.forgejo/workflows-composite/setup-env - uses: ./.forgejo/workflows-composite/setup-env
@ -231,13 +219,13 @@ jobs:
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
- run: | - run: |
su forgejo -c 'make test-pgsql-migration test-pgsql' su forgejo -c 'make test-pgsql-migration test-pgsql'
timeout-minutes: 120 timeout-minutes: 50
env: env:
RACE_ENABLED: true RACE_ENABLED: true
USE_REPO_TEST_DIR: 1 USE_REPO_TEST_DIR: 1
TEST_LDAP: 1 TEST_LDAP: 1
test-sqlite: test-sqlite:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: [backend-checks, frontend-checks] needs: [backend-checks, frontend-checks]
container: container:
@ -252,14 +240,14 @@ jobs:
- uses: ./.forgejo/workflows-composite/build-backend - uses: ./.forgejo/workflows-composite/build-backend
- run: | - run: |
su forgejo -c 'make test-sqlite-migration test-sqlite' su forgejo -c 'make test-sqlite-migration test-sqlite'
timeout-minutes: 120 timeout-minutes: 50
env: env:
TAGS: sqlite sqlite_unlock_notify TAGS: sqlite sqlite_unlock_notify
RACE_ENABLED: true RACE_ENABLED: true
TEST_TAGS: sqlite sqlite_unlock_notify TEST_TAGS: sqlite sqlite_unlock_notify
USE_REPO_TEST_DIR: 1 USE_REPO_TEST_DIR: 1
security-check: security-check:
if: vars.ROLE == 'forgejo-coding' || vars.ROLE == 'forgejo-testing' if: ${{ !startsWith(vars.ROLE, 'forgejo-') }}
runs-on: docker runs-on: docker
needs: needs:
- test-sqlite - test-sqlite

3
.gitignore vendored
View file

@ -115,9 +115,6 @@ prime/
*_source.tar.bz2 *_source.tar.bz2
.DS_Store .DS_Store
# Direnv configuration
/.envrc
# nix-direnv generated files # nix-direnv generated files
.direnv/ .direnv/

View file

@ -77,8 +77,6 @@ linters-settings:
- name: unreachable-code - name: unreachable-code
- name: var-declaration - name: var-declaration
- name: var-naming - name: var-naming
- name: redefines-builtin-id
disabled: true
gofumpt: gofumpt:
extra-rules: true extra-rules: true
depguard: depguard:

38
.woodpecker/.build.yaml Normal file
View file

@ -0,0 +1,38 @@
---
steps:
- name: build (prod)
image: woodpeckerci/plugin-docker-buildx
settings:
registry: git.ar21.de
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
repo: git.ar21.de/tom/forkjo
platforms:
- linux/amd64
tags:
- latest
- ${CI_PIPELINE_NUMBER}
when:
- branch: forgejo
event: push
- name: build (experimental)
image: woodpeckerci/plugin-docker-buildx
settings:
registry: git.ar21.de
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
repo: git.ar21.de/tom/forkjo
platforms:
- linux/amd64
tags:
- experimental
- experimental-${CI_PIPELINE_NUMBER}
when:
- branch:
exclude: forgejo
event: push

View file

@ -39,7 +39,7 @@ 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.0.3 # renovate: datasource=go EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.0.3 # renovate: datasource=go
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.7.0 # renovate: datasource=go
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 # renovate: datasource=go GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.61.0 # 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 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
@ -49,7 +49,7 @@ GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1 # renovate: datasour
DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.26.0 # renovate: datasource=go DEADCODE_PACKAGE ?= golang.org/x/tools/cmd/deadcode@v0.26.0 # renovate: datasource=go
GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go GOMOCK_PACKAGE ?= go.uber.org/mock/mockgen@v0.4.0 # renovate: datasource=go
GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.2 # renovate: datasource=go GOPLS_PACKAGE ?= golang.org/x/tools/gopls@v0.16.2 # renovate: datasource=go
RENOVATE_NPM_PACKAGE ?= renovate@39.9.1 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate RENOVATE_NPM_PACKAGE ?= renovate@38.128.6 # renovate: datasource=docker packageName=code.forgejo.org/forgejo-contrib/renovate
ifeq ($(HAS_GO), yes) ifeq ($(HAS_GO), yes)
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766 CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
@ -164,8 +164,9 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(FOMAN
GO_DIRS := build cmd models modules routers services tests GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css WEB_DIRS := web_src/js web_src/css
ESLINT_FILES := web_src/js tools *.js *.mjs tests/e2e/*.js tests/e2e/shared/*.js
STYLELINT_FILES := web_src/css web_src/js/components/*.vue STYLELINT_FILES := web_src/css web_src/js/components/*.vue
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(wildcard *.go *.js *.ts *.vue *.md *.yml *.yaml *.toml) SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) docs/content templates options/locale/locale_en-US.ini .github $(wildcard *.go *.js *.md *.yml *.yaml *.toml)
GO_SOURCES := $(wildcard *.go) GO_SOURCES := $(wildcard *.go)
GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go) GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go)
@ -417,7 +418,7 @@ lint-frontend: lint-js lint-css
lint-frontend-fix: lint-js-fix lint-css-fix lint-frontend-fix: lint-js-fix lint-css-fix
.PHONY: lint-backend .PHONY: lint-backend
lint-backend: lint-go lint-go-vet lint-editorconfig lint-renovate lint-locale lint-backend: lint-go lint-go-vet lint-editorconfig lint-renovate
.PHONY: lint-backend-fix .PHONY: lint-backend-fix
lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig lint-backend-fix: lint-go-fix lint-go-vet lint-editorconfig
@ -436,11 +437,11 @@ lint-codespell-fix-i:
.PHONY: lint-js .PHONY: lint-js
lint-js: node_modules lint-js: node_modules
npx eslint --color --max-warnings=0 npx eslint --color --max-warnings=0 $(ESLINT_FILES)
.PHONY: lint-js-fix .PHONY: lint-js-fix
lint-js-fix: node_modules lint-js-fix: node_modules
npx eslint --color --max-warnings=0 --fix npx eslint --color --max-warnings=0 $(ESLINT_FILES) --fix
.PHONY: lint-css .PHONY: lint-css
lint-css: node_modules lint-css: node_modules
@ -460,10 +461,6 @@ lint-renovate: node_modules
@if grep --quiet --extended-regexp -e '^( WARN:|ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi @if grep --quiet --extended-regexp -e '^( WARN:|ERROR:)' .lint-renovate ; then cat .lint-renovate ; rm .lint-renovate ; exit 1 ; fi
@rm .lint-renovate @rm .lint-renovate
.PHONY: lint-locale
lint-locale:
$(GO) run build/lint-locale.go
.PHONY: lint-md .PHONY: lint-md
lint-md: node_modules lint-md: node_modules
npx markdownlint docs *.md npx markdownlint docs *.md
@ -660,7 +657,6 @@ generate-ini-pgsql:
-e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
-e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \
-e 's|{{TEST_STORAGE_TYPE}}|$(or $(TEST_STORAGE_TYPE),minio)|g' \
tests/pgsql.ini.tmpl > tests/pgsql.ini tests/pgsql.ini.tmpl > tests/pgsql.ini
.PHONY: test-pgsql .PHONY: test-pgsql
@ -716,6 +712,7 @@ test-e2e-pgsql\#%: playwright e2e.pgsql.test generate-ini-pgsql
.PHONY: test-e2e-debugserver .PHONY: test-e2e-debugserver
test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite test-e2e-debugserver: e2e.sqlite.test generate-ini-sqlite
sed -i s/3003/3000/g tests/sqlite.ini
GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestDebugserver -test.timeout 24h GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini ./e2e.sqlite.test -test.run TestDebugserver -test.timeout 24h
.PHONY: bench-sqlite .PHONY: bench-sqlite

View file

@ -6,14 +6,6 @@ A [patch or minor release](https://semver.org/spec/v2.0.0.html) (e.g. upgrading
The release notes of each release [are available in the corresponding milestone](https://codeberg.org/forgejo/forgejo/milestones), starting with [Forgejo 7.0.7](https://codeberg.org/forgejo/forgejo/milestone/7683) and [Forgejo 8.0.1](https://codeberg.org/forgejo/forgejo/milestone/7682). The release notes of each release [are available in the corresponding milestone](https://codeberg.org/forgejo/forgejo/milestones), starting with [Forgejo 7.0.7](https://codeberg.org/forgejo/forgejo/milestone/7683) and [Forgejo 8.0.1](https://codeberg.org/forgejo/forgejo/milestone/7682).
## 9.0.2
The Forgejo v9.0.2 release notes are [available in the v9.0.2 milestone](https://codeberg.org/forgejo/forgejo/milestone/8610).
## 9.0.1
The Forgejo v9.0.1 release notes are [available in the v9.0.1 milestone](https://codeberg.org/forgejo/forgejo/milestone/8544).
## 9.0.0 ## 9.0.0
The Forgejo v9.0.0 release notes are [available in the v9.0.0 milestone](https://codeberg.org/forgejo/forgejo/milestone/7235). The Forgejo v9.0.0 release notes are [available in the v9.0.0 milestone](https://codeberg.org/forgejo/forgejo/milestone/7235).
@ -167,14 +159,6 @@ A [companion blog post](https://forgejo.org/2024-07-release-v8-0/) provides addi
- [PR](https://codeberg.org/forgejo/forgejo/pulls/2937): <!--number 2937 --><!--number--><!--description -->31 March updates<!--description--> - [PR](https://codeberg.org/forgejo/forgejo/pulls/2937): <!--number 2937 --><!--number--><!--description -->31 March updates<!--description-->
<!--end release-notes-assistant--> <!--end release-notes-assistant-->
## 7.0.11
The Forgejo v7.0.11 release notes are [available in the v7.0.11 milestone](https://codeberg.org/forgejo/forgejo/milestone/8609).
## 7.0.10
The Forgejo v7.0.10 release notes are [available in the v7.0.10 milestone](https://codeberg.org/forgejo/forgejo/milestone/8286).
## 7.0.9 ## 7.0.9
The Forgejo v7.0.9 release notes are [available in the v7.0.9 milestone](https://codeberg.org/forgejo/forgejo/milestone/8232). The Forgejo v7.0.9 release notes are [available in the v7.0.9 milestone](https://codeberg.org/forgejo/forgejo/milestone/8232).

File diff suppressed because one or more lines are too long

View file

@ -53,6 +53,8 @@ func (e Emoji) MarshalJSON() ([]byte, error) {
} }
func main() { func main() {
var err error
flag.Parse() flag.Parse()
// generate data // generate data
@ -81,6 +83,8 @@ var replacer = strings.NewReplacer(
var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`) var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
func generate() ([]byte, error) { func generate() ([]byte, error) {
var err error
// load gemoji data // load gemoji data
res, err := http.Get(gemojiURL) res, err := http.Get(gemojiURL)
if err != nil { if err != nil {

View file

@ -1,156 +0,0 @@
// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package main
import (
"fmt"
"html"
"io/fs"
"os"
"path/filepath"
"regexp"
"slices"
"strings"
"github.com/microcosm-cc/bluemonday"
"github.com/sergi/go-diff/diffmatchpatch"
"gopkg.in/ini.v1" //nolint:depguard
)
var (
policy *bluemonday.Policy
tagRemover *strings.Replacer
safeURL = "https://TO-BE-REPLACED.COM"
// Matches href="", href="#", href="%s", href="#%s", href="%[1]s" and href="#%[1]s".
placeHolderRegex = regexp.MustCompile(`href="#?(%s|%\[\d\]s)?"`)
)
func initBlueMondayPolicy() {
policy = bluemonday.NewPolicy()
policy.RequireParseableURLs(true)
policy.AllowURLSchemes("https")
// Only allow safe URL on href.
// Only allow target="_blank".
// Only allow rel="nopener noreferrer", rel="noopener" and rel="noreferrer".
// Only allow placeholder on id and class.
policy.AllowAttrs("href").Matching(regexp.MustCompile("^" + regexp.QuoteMeta(safeURL) + "$")).OnElements("a")
policy.AllowAttrs("target").Matching(regexp.MustCompile("^_blank$")).OnElements("a")
policy.AllowAttrs("rel").Matching(regexp.MustCompile("^(noopener|noreferrer|noopener noreferrer)$")).OnElements("a")
policy.AllowAttrs("id", "class").Matching(regexp.MustCompile(`^%s|%\[\d\]s$`)).OnElements("a")
// Only allow positional placeholder as class.
positionalPlaceholderRe := regexp.MustCompile(`^%\[\d\]s$`)
policy.AllowAttrs("class").Matching(positionalPlaceholderRe).OnElements("strong")
policy.AllowAttrs("id").Matching(positionalPlaceholderRe).OnElements("code")
// Allowed elements with no attributes. Must be a recognized tagname.
policy.AllowElements("strong", "br", "b", "strike", "code", "i")
// TODO: Remove <c> in `actions.workflow.dispatch.trigger_found`.
policy.AllowNoAttrs().OnElements("c")
}
func initRemoveTags() {
oldnew := []string{}
for _, el := range []string{
"email@example.com", "correu@example.com", "epasts@domens.lv", "email@exemplo.com", "eposta@ornek.com", "email@példa.hu", "email@esempio.it",
"user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker",
"server", "servidor", "kiszolgáló", "serveris",
"label", "etichetta", "etiķete", "rótulo", "Label", "utilizador",
"filename", "bestandsnaam", "dosyaadi", "fails", "nome do arquivo", "datnes nosaukums",
} {
oldnew = append(oldnew, "<"+el+">", "REPLACED-TAG")
}
tagRemover = strings.NewReplacer(oldnew...)
}
func preprocessTranslationValue(value string) string {
// href should be a parsable URL, replace placeholder strings with a safe url.
value = placeHolderRegex.ReplaceAllString(value, `href="`+safeURL+`"`)
// Remove tags that aren't tags but will be parsed as tags. We already know they are safe and sound.
value = tagRemover.Replace(value)
return value
}
func checkLocaleContent(localeContent []byte) []string {
// Same configuration as Forgejo uses.
cfg := ini.Empty(ini.LoadOptions{
IgnoreContinuation: true,
})
cfg.NameMapper = ini.SnackCase
if err := cfg.Append(localeContent); err != nil {
panic(err)
}
dmp := diffmatchpatch.New()
errors := []string{}
for _, section := range cfg.Sections() {
for _, key := range section.Keys() {
var trKey string
if section.Name() == "" || section.Name() == "DEFAULT" || section.Name() == "common" {
trKey = key.Name()
} else {
trKey = section.Name() + "." + key.Name()
}
keyValue := preprocessTranslationValue(key.Value())
if html.UnescapeString(policy.Sanitize(keyValue)) != keyValue {
// Create a nice diff of the difference.
diffs := dmp.DiffMain(keyValue, html.UnescapeString(policy.Sanitize(keyValue)), false)
diffs = dmp.DiffCleanupSemantic(diffs)
diffs = dmp.DiffCleanupEfficiency(diffs)
errors = append(errors, trKey+": "+dmp.DiffPrettyText(diffs))
}
}
}
return errors
}
func main() {
initBlueMondayPolicy()
initRemoveTags()
localeDir := filepath.Join("options", "locale")
localeFiles, err := os.ReadDir(localeDir)
if err != nil {
panic(err)
}
if !slices.ContainsFunc(localeFiles, func(e fs.DirEntry) bool { return strings.HasSuffix(e.Name(), ".ini") }) {
fmt.Println("No locale files found")
os.Exit(1)
}
exitCode := 0
for _, localeFile := range localeFiles {
if !strings.HasSuffix(localeFile.Name(), ".ini") {
continue
}
localeContent, err := os.ReadFile(filepath.Join(localeDir, localeFile.Name()))
if err != nil {
panic(err)
}
if err := checkLocaleContent(localeContent); len(err) > 0 {
fmt.Println(localeFile.Name())
fmt.Println(strings.Join(err, "\n"))
fmt.Println()
exitCode = 1
}
}
os.Exit(exitCode)
}

View file

@ -1,65 +0,0 @@
// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestLocalizationPolicy(t *testing.T) {
initBlueMondayPolicy()
initRemoveTags()
t.Run("Remove tags", func(t *testing.T) {
assert.Empty(t, checkLocaleContent([]byte(`hidden_comment_types_description = Comment types checked here will not be shown inside issue pages. Checking "Label" for example removes all "<user> added/removed <label>" comments.`)))
assert.EqualValues(t, []string{"key: \x1b[31m<not-an-allowed-key>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<not-an-allowed-key> <label>"`)))
assert.EqualValues(t, []string{"key: \x1b[31m<user@example.com>\x1b[0m REPLACED-TAG"}, checkLocaleContent([]byte(`key = "<user@example.com> <email@example.com>"`)))
assert.EqualValues(t, []string{"key: \x1b[31m<tag>\x1b[0m REPLACED-TAG \x1b[31m</tag>\x1b[0m"}, checkLocaleContent([]byte(`key = "<tag> <email@example.com> </tag>"`)))
})
t.Run("Specific exception", func(t *testing.T) {
assert.Empty(t, checkLocaleContent([]byte(`workflow.dispatch.trigger_found = This workflow has a <c>workflow_dispatch</c> event trigger.`)))
assert.Empty(t, checkLocaleContent([]byte(`pulls.title_desc_one = wants to merge %[1]d commit from <code>%[2]s</code> into <code id="%[4]s">%[3]s</code>`)))
assert.Empty(t, checkLocaleContent([]byte(`editor.commit_directly_to_this_branch = Commit directly to the <strong class="%[2]s">%[1]s</strong> branch.`)))
assert.EqualValues(t, []string{"workflow.dispatch.trigger_found: This workflow has a \x1b[31m<d>\x1b[0mworkflow_dispatch\x1b[31m</d>\x1b[0m event trigger."}, checkLocaleContent([]byte(`workflow.dispatch.trigger_found = This workflow has a <d>workflow_dispatch</d> event trigger.`)))
assert.EqualValues(t, []string{"key: <code\x1b[31m id=\"branch_targe\"\x1b[0m>%[3]s</code>"}, checkLocaleContent([]byte(`key = <code id="branch_targe">%[3]s</code>`)))
assert.EqualValues(t, []string{"key: <a\x1b[31m class=\"ui sh\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="ui sh" href="%[3]s">`)))
assert.EqualValues(t, []string{"key: <a\x1b[31m class=\"js-click-me\"\x1b[0m href=\"https://TO-BE-REPLACED.COM\">"}, checkLocaleContent([]byte(`key = <a class="js-click-me" href="%[3]s">`)))
assert.EqualValues(t, []string{"key: <strong\x1b[31m class=\"branch-target\"\x1b[0m>%[1]s</strong>"}, checkLocaleContent([]byte(`key = <strong class="branch-target">%[1]s</strong>`)))
})
t.Run("General safe tags", func(t *testing.T) {
assert.Empty(t, checkLocaleContent([]byte("error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it.")))
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("hi_user_x = Hi <b>%s</b>,")))
assert.EqualValues(t, []string{"error404: The page you are trying to reach either <strong\x1b[31m title='aaa'\x1b[0m>does not exist</strong> or <strong>you are not authorized</strong> to view it."}, checkLocaleContent([]byte("error404 = The page you are trying to reach either <strong title='aaa'>does not exist</strong> or <strong>you are not authorized</strong> to view it.")))
})
t.Run("<a>", func(t *testing.T) {
assert.Empty(t, checkLocaleContent([]byte(`admin.new_user.text = Please <a href="%s">click here</a> to manage this user from the admin panel.`)))
assert.Empty(t, checkLocaleContent([]byte(`access_token_desc = Selected token permissions limit authorization only to the corresponding <a href="%[1]s" target="_blank">API</a> routes. Read the <a href="%[2]s" target="_blank">documentation</a> for more information.`)))
assert.Empty(t, checkLocaleContent([]byte(`webauthn_desc = Security keys are hardware devices containing cryptographic keys. They can be used for two-factor authentication. Security keys must support the <a rel="noreferrer" target="_blank" href="%s">WebAuthn Authenticator</a> standard.`)))
assert.Empty(t, checkLocaleContent([]byte("issues.closed_at = `closed this issue <a id=\"%[1]s\" href=\"#%[1]s\">%[2]s</a>`")))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com">`)))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"javascript:alert('1')\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="javascript:alert('1')">`)))
assert.EqualValues(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m download\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" download>`)))
assert.EqualValues(t, []string{"key: <a href=\"https://TO-BE-REPLACED.COM\"\x1b[31m target=\"_self\"\x1b[0m>"}, checkLocaleContent([]byte(`key = <a href="%s" target="_self">`)))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com/%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/%s">`)))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"https://example.com/?q=%s\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="https://example.com/?q=%s">`)))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"%s/open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s/open-redirect">`)))
assert.EqualValues(t, []string{"key: \x1b[31m<a href=\"%s?q=open-redirect\">\x1b[0m"}, checkLocaleContent([]byte(`key = <a href="%s?q=open-redirect">`)))
})
t.Run("Escaped HTML characters", func(t *testing.T) {
assert.Empty(t, checkLocaleContent([]byte("activity.git_stats_push_to_branch = `إلى %s و\"`")))
assert.EqualValues(t, []string{"key: و\x1b[31m&nbsp\x1b[0m\x1b[32m\u00a0\x1b[0m"}, checkLocaleContent([]byte(`key = و&nbsp;`)))
})
}

View file

@ -386,7 +386,7 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error {
return a.createAuthSource(ctx, authSource) return a.createAuthSource(ctx, authSource)
} }
// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source. // updateLdapBindDn updates a new LDAP (simple auth) authentication source.
func (a *authService) updateLdapSimpleAuth(c *cli.Context) error { func (a *authService) updateLdapSimpleAuth(c *cli.Context) error {
ctx, cancel := installSignals() ctx, cancel := installSignals()
defer cancel() defer cancel()

View file

@ -91,7 +91,7 @@ func TestMigrateActionsArtifacts(t *testing.T) {
srcStorage, _ := createLocalStorage(t) srcStorage, _ := createLocalStorage(t)
defer test.MockVariableValue(&storage.ActionsArtifacts, srcStorage)() defer test.MockVariableValue(&storage.ActionsArtifacts, srcStorage)()
id := int64(42) id := int64(0)
addArtifact := func(storagePath string, status actions.ArtifactStatus) { addArtifact := func(storagePath string, status actions.ArtifactStatus) {
id++ id++

View file

@ -1,6 +1,4 @@
{ {
"go.buildTags": "sqlite,sqlite_unlock_notify", "go.buildTags": "sqlite,sqlite_unlock_notify",
"go.testFlags": ["-v"], "go.testFlags": ["-v"]
"go.lintTool": "golangci-lint",
"go.lintFlags": ["--fast"]
} }

View file

@ -328,10 +328,6 @@ RUN_USER = ; git
;; Maximum number of locks returned per page ;; Maximum number of locks returned per page
;LFS_LOCKS_PAGING_NUM = 50 ;LFS_LOCKS_PAGING_NUM = 50
;; ;;
;; When clients make lfs batch requests, reject them if there are more pointers than this number
;; zero means 'unlimited'
;LFS_MAX_BATCH_SIZE = 0
;;
;; Allow graceful restarts using SIGHUP to fork ;; Allow graceful restarts using SIGHUP to fork
;ALLOW_GRACEFUL_RESTARTS = true ;ALLOW_GRACEFUL_RESTARTS = true
;; ;;
@ -353,25 +349,16 @@ RUN_USER = ; git
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Database to use. Either "sqlite3", "mySQL" or "postgres". ;; Database to use. Either "mysql", "postgres", "mssql" or "sqlite3".
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; SQLite Configuration
;;
DB_TYPE = sqlite3
;PATH= ; defaults to data/forgejo.db
;SQLITE_TIMEOUT = ; Query timeout defaults to: 500
;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; MySQL Configuration ;; MySQL Configuration
;; ;;
;DB_TYPE = mysql DB_TYPE = mysql
;HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock HOST = 127.0.0.1:3306 ; can use socket e.g. /var/run/mysqld/mysqld.sock
;NAME = gitea NAME = gitea
;USER = root USER = root
;PASSWD = ;Use PASSWD = `your password` for quoting if you use special characters in the password. ;PASSWD = ;Use PASSWD = `your password` for quoting if you use special characters in the password.
;SSL_MODE = false ; either "false" (default), "true", or "skip-verify" ;SSL_MODE = false ; either "false" (default), "true", or "skip-verify"
;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need. ;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need.
@ -390,6 +377,26 @@ DB_TYPE = sqlite3
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SQLite Configuration
;;
;DB_TYPE = sqlite3
;PATH= ; defaults to data/forgejo.db
;SQLITE_TIMEOUT = ; Query timeout defaults to: 500
;SQLITE_JOURNAL_MODE = ; defaults to sqlite database default (often DELETE), can be used to enable WAL mode. https://www.sqlite.org/pragma.html#pragma_journal_mode
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; MSSQL Configuration
;;
;DB_TYPE = mssql
;HOST = 172.17.0.2:1433
;NAME = gitea
;USER = SA
;PASSWD = MwantsaSecurePassword1
;CHARSET_COLLATION = ; Empty as default, Gitea will try to find a case-sensitive collation. Don't change it unless you clearly know what you need.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Other settings ;; Other settings
;; ;;
;; For iterate buffer, default is 50 ;; For iterate buffer, default is 50
@ -918,24 +925,6 @@ LEVEL = Info
;; Valid site url schemes for user profiles ;; Valid site url schemes for user profiles
;VALID_SITE_URL_SCHEMES=http,https ;VALID_SITE_URL_SCHEMES=http,https
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;[service.explore]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Only allow signed in users to view the explore pages.
;REQUIRE_SIGNIN_VIEW = false
;;
;; Disable the users explore page.
;DISABLE_USERS_PAGE = false
;;
;; Disable the organizations explore page.
;DISABLE_ORGANIZATIONS_PAGE = false
;;
;; Disable the code explore page.
;DISABLE_CODE_PAGE = false
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -1938,7 +1927,7 @@ LEVEL = Info
;ENABLED = true ;ENABLED = true
;; ;;
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types. ;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
;ALLOWED_TYPES = .avif,.cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip ;ALLOWED_TYPES = .cpuprofile,.csv,.dmp,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.json,.jsonc,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.patch,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
;; ;;
;; Max size of each file. Defaults to 2048MB ;; Max size of each file. Defaults to 2048MB
;MAX_SIZE = 2048 ;MAX_SIZE = 2048
@ -2665,10 +2654,6 @@ LEVEL = Info
;; override the minio base path if storage type is minio ;; override the minio base path if storage type is minio
;MINIO_BASE_PATH = lfs/ ;MINIO_BASE_PATH = lfs/
;[lfs_client]
;; When mirroring an upstream lfs endpoint, limit the number of pointers in each batch request to this number
;BATCH_SIZE = 20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; settings for packages, will override storage setting ;; settings for packages, will override storage setting

View file

@ -14,15 +14,10 @@ import wc from 'eslint-plugin-wc';
import globals from 'globals'; import globals from 'globals';
import vue from 'eslint-plugin-vue'; import vue from 'eslint-plugin-vue';
import vueScopedCss from 'eslint-plugin-vue-scoped-css'; import vueScopedCss from 'eslint-plugin-vue-scoped-css';
import tseslint from 'typescript-eslint';
export default tseslint.config( export default [{
...tseslint.configs.recommended, ignores: ['web_src/js/vendor', 'web_src/fomantic', 'public/assets/js'],
eslintPluginImportX.flatConfigs.typescript, }, {
{
ignores: ['web_src/js/vendor', 'web_src/fomantic', 'public/assets/js', 'tests/e2e/reports/'],
},
{
plugins: { plugins: {
'@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments, '@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments,
'@stylistic/js': stylisticEslintPluginJs, '@stylistic/js': stylisticEslintPluginJs,
@ -57,8 +52,6 @@ export default tseslint.config(
sourceType: 'module', sourceType: 'module',
}, },
rules: { rules: {
'@typescript-eslint/no-unused-vars': 'off', // TODO: enable this rule again
'@eslint-community/eslint-comments/disable-enable-pair': [2], '@eslint-community/eslint-comments/disable-enable-pair': [2],
'@eslint-community/eslint-comments/no-aggregating-enable': [2], '@eslint-community/eslint-comments/no-aggregating-enable': [2],
'@eslint-community/eslint-comments/no-duplicate-disable': [2], '@eslint-community/eslint-comments/no-duplicate-disable': [2],
@ -1038,7 +1031,6 @@ export default tseslint.config(
rules: { rules: {
'import-x/no-unused-modules': [0], 'import-x/no-unused-modules': [0],
'import-x/no-unresolved': [0], 'import-x/no-unresolved': [0],
'import-x/no-named-as-default': [0],
}, },
}, { }, {
files: ['**/*.test.*', 'web_src/js/test/setup.js'], files: ['**/*.test.*', 'web_src/js/test/setup.js'],
@ -1112,7 +1104,7 @@ export default tseslint.config(
], ],
}, },
}, { }, {
files: ['tests/e2e/**/*.ts'], files: ['tests/e2e/**/*.js'],
languageOptions: { languageOptions: {
globals: { globals: {
...globals.browser, ...globals.browser,
@ -1125,8 +1117,7 @@ export default tseslint.config(
...playwright.configs['flat/recommended'].rules, ...playwright.configs['flat/recommended'].rules,
'playwright/no-conditional-in-test': [0], 'playwright/no-conditional-in-test': [0],
'playwright/no-conditional-expect': [0], 'playwright/no-conditional-expect': [0],
// allow grouping helper functions with tests 'playwright/no-networkidle': [0],
'unicorn/consistent-function-scoping': [0],
'playwright/no-skipped-test': [ 'playwright/no-skipped-test': [
2, 2,
@ -1167,4 +1158,4 @@ export default tseslint.config(
}, },
}, },
); ];

50
go.mod
View file

@ -1,20 +1,20 @@
module code.gitea.io/gitea module code.gitea.io/gitea
go 1.23.3 go 1.23.2
require ( require (
code.forgejo.org/f3/gof3/v3 v3.7.0 code.forgejo.org/f3/gof3/v3 v3.7.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/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/cache v0.0.0-20240912103640-dcb08fba860d
code.forgejo.org/go-chi/cache v1.0.0 code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5
code.forgejo.org/go-chi/captcha v1.0.0 code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26
code.forgejo.org/go-chi/session v1.0.0
code.gitea.io/actions-proto-go v0.4.0 code.gitea.io/actions-proto-go v0.4.0
code.gitea.io/gitea-vet v0.2.3 code.gitea.io/gitea-vet v0.2.3
code.gitea.io/sdk/gitea v0.17.1 code.gitea.io/sdk/gitea v0.17.1
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.17.0
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
@ -23,8 +23,8 @@ require (
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.14.0 github.com/alecthomas/chroma/v2 v2.14.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.4.3 github.com/blevesearch/bleve/v2 v2.4.2
github.com/buildkite/terminal-to-html/v3 v3.16.4 github.com/buildkite/terminal-to-html/v3 v3.16.3
github.com/caddyserver/certmagic v0.21.4 github.com/caddyserver/certmagic v0.21.4
github.com/chi-middleware/proxy v1.1.1 github.com/chi-middleware/proxy v1.1.1
github.com/djherbis/buffer v1.2.0 github.com/djherbis/buffer v1.2.0
@ -34,7 +34,7 @@ require (
github.com/editorconfig/editorconfig-core-go/v2 v2.6.2 github.com/editorconfig/editorconfig-core-go/v2 v2.6.2
github.com/emersion/go-imap v1.2.1 github.com/emersion/go-imap v1.2.1
github.com/felixge/fgprof v0.9.5 github.com/felixge/fgprof v0.9.5
github.com/fsnotify/fsnotify v1.8.0 github.com/fsnotify/fsnotify v1.7.0
github.com/gliderlabs/ssh v0.3.7 github.com/gliderlabs/ssh v0.3.7
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
@ -57,7 +57,7 @@ require (
github.com/google/pprof v0.0.0-20241017200806-017d972448fc github.com/google/pprof v0.0.0-20241017200806-017d972448fc
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0 github.com/gorilla/feeds v1.2.0
github.com/gorilla/sessions v1.4.0 github.com/gorilla/sessions v1.2.2
github.com/h2non/gock v1.2.0 github.com/h2non/gock v1.2.0
github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/golang-lru/v2 v2.0.7
@ -72,7 +72,7 @@ require (
github.com/markbates/goth v1.80.0 github.com/markbates/goth v1.80.0
github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-sqlite3 v1.14.24 github.com/mattn/go-sqlite3 v1.14.24
github.com/meilisearch/meilisearch-go v0.29.0 github.com/meilisearch/meilisearch-go v0.28.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.78 github.com/minio/minio-go/v7 v7.0.78
@ -97,17 +97,17 @@ require (
github.com/valyala/fastjson v1.6.4 github.com/valyala/fastjson v1.6.4
github.com/xanzy/go-gitlab v0.109.0 github.com/xanzy/go-gitlab v0.109.0
github.com/yohcop/openid-go v1.0.1 github.com/yohcop/openid-go v1.0.1
github.com/yuin/goldmark v1.7.8 github.com/yuin/goldmark v1.7.4
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
go.uber.org/mock v0.4.0 go.uber.org/mock v0.4.0
golang.org/x/crypto v0.29.0 golang.org/x/crypto v0.28.0
golang.org/x/image v0.21.0 golang.org/x/image v0.21.0
golang.org/x/net v0.31.0 golang.org/x/net v0.30.0
golang.org/x/oauth2 v0.23.0 golang.org/x/oauth2 v0.23.0
golang.org/x/sys v0.27.0 golang.org/x/sys v0.26.0
golang.org/x/text v0.20.0 golang.org/x/text v0.19.0
golang.org/x/tools v0.26.0 golang.org/x/tools v0.26.0
google.golang.org/grpc v1.68.0 google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1 google.golang.org/protobuf v1.35.1
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
@ -137,13 +137,13 @@ require (
github.com/aymerick/douceur v0.2.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/blevesearch/bleve_index_api v1.1.12 // indirect github.com/blevesearch/bleve_index_api v1.1.10 // indirect
github.com/blevesearch/geo v0.1.20 // indirect github.com/blevesearch/geo v0.1.20 // indirect
github.com/blevesearch/go-faiss v1.0.23 // indirect github.com/blevesearch/go-faiss v1.0.20 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.2.16 // indirect github.com/blevesearch/scorch_segment_api/v2 v2.2.15 // indirect
github.com/blevesearch/segment v0.9.1 // indirect github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
@ -152,8 +152,8 @@ require (
github.com/blevesearch/zapx/v12 v12.3.10 // indirect github.com/blevesearch/zapx/v12 v12.3.10 // indirect
github.com/blevesearch/zapx/v13 v13.3.10 // indirect github.com/blevesearch/zapx/v13 v13.3.10 // indirect
github.com/blevesearch/zapx/v14 v14.3.10 // indirect github.com/blevesearch/zapx/v14 v14.3.10 // indirect
github.com/blevesearch/zapx/v15 v15.3.16 // indirect github.com/blevesearch/zapx/v15 v15.3.13 // indirect
github.com/blevesearch/zapx/v16 v16.1.8 // indirect github.com/blevesearch/zapx/v16 v16.1.5 // 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-20230905024940-24af94b03874 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect
@ -281,9 +281,9 @@ require (
go.uber.org/zap v1.27.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
golang.org/x/mod v0.21.0 // indirect golang.org/x/mod v0.21.0 // indirect
golang.org/x/sync v0.9.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // 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
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
@ -293,8 +293,6 @@ 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/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.22.0 replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.21.3
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
replace github.com/goccy/go-json => github.com/grafana/go-json v0.0.0-20241115232854-f14426c40ff2

100
go.sum
View file

@ -4,20 +4,18 @@ code.forgejo.org/f3/gof3/v3 v3.7.0 h1:ZfuCP8CGm8ZJbWmL+V0pUu3E0X4FCAA7GfRDy/y5/K
code.forgejo.org/f3/gof3/v3 v3.7.0/go.mod h1:oNhOeqD4DZYjVcNjQXIOdDX9b/1tqxi9ITLS8H9/Csw= code.forgejo.org/f3/gof3/v3 v3.7.0/go.mod h1:oNhOeqD4DZYjVcNjQXIOdDX9b/1tqxi9ITLS8H9/Csw=
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.22.0 h1:NbUf0+vQ48+ddwe4zVkINqnxKYl/to+NUvW7iisPA60= code.forgejo.org/forgejo/act v1.21.3 h1:EeJbrz0aar2QhIcBlOW5gjK1rjrQxcAvQSPpG/R1h5w=
code.forgejo.org/forgejo/act v1.22.0/go.mod h1:+PcvJ9iv+NTFeJSh79ra9Jbk9l0vvyA9D9me5/dbxYM= code.forgejo.org/forgejo/act v1.21.3/go.mod h1:+PcvJ9iv+NTFeJSh79ra9Jbk9l0vvyA9D9me5/dbxYM=
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/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ= code.forgejo.org/forgejo/reply v1.0.2 h1:dMhQCHV6/O3L5CLWNTol+dNzDAuyCK88z4J/lCdgFuQ=
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/go-chi/binding v1.0.0 h1:EIDJtk9brK7WsT7rvS/D4cxX8XlnhY3LMy8ex1jeHu0= code.forgejo.org/go-chi/cache v0.0.0-20240912103640-dcb08fba860d h1:nOu/2GX571t4intmtfvpctS148OqsBYrGUySVm93ifc=
code.forgejo.org/go-chi/binding v1.0.0/go.mod h1:fWwqaHj0H1/KeCpBqdvKunflq8pYfciEHI5v3UUeE2E= code.forgejo.org/go-chi/cache v0.0.0-20240912103640-dcb08fba860d/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk=
code.forgejo.org/go-chi/cache v1.0.0 h1:akLfGxNlHcacmtutovNtYFSTMsbdcp5MGjAEsP4pxnE= code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5 h1:A7P1liXCpJBHEJ5KIDsF0ujnQ8FQ/aX1UixTW0vGrDQ=
code.forgejo.org/go-chi/cache v1.0.0/go.mod h1:OVlZ/TqDYJ+RUJ+R+J+OLxtlyjo3pbjBeK7LAWAB+Vk= code.forgejo.org/go-chi/captcha v0.0.0-20240905153133-df43b9250ed5/go.mod h1:YLOsiln/arX3egGtxG4QNp49G2CIqP9pqD2VL56obLc=
code.forgejo.org/go-chi/captcha v1.0.0 h1:ZKVznXrPfruc1RMavCFBEINGxB3RAYr4I+WQAK8+eP0= code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26 h1:6XCLWu8A0nPM862Uh68kQmxsBsaQNfPPFwYjzG8M8QE=
code.forgejo.org/go-chi/captcha v1.0.0/go.mod h1:YLOsiln/arX3egGtxG4QNp49G2CIqP9pqD2VL56obLc= code.forgejo.org/go-chi/session v0.0.0-20241017103059-2a992261fc26/go.mod h1:lS76JFHZqGXYJTBHqwZ910UG046hIXAaYIN6J0Lf8sI=
code.forgejo.org/go-chi/session v1.0.0 h1:1hjLWHpXkb4vs/g9rk/unhRL4AoKEqVUPJ+opI8UO3Y=
code.forgejo.org/go-chi/session v1.0.0/go.mod h1:lS76JFHZqGXYJTBHqwZ910UG046hIXAaYIN6J0Lf8sI=
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/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI= code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
@ -34,6 +32,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o= gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4 h1:IFT+hup2xejHqdhS7keYWioqfmxdnfblFDTGoOwcZ+o=
gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/lunny/levelqueue v0.4.2-0.20230414023320-3c0159fe0fe4/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
@ -98,22 +98,22 @@ github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJR
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bits-and-blooms/bitset v1.13.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.4.3 h1:XDYj+1prgX84L2Cf+V3ojrOPqXxy0qxyd2uLMmeuD+4= github.com/blevesearch/bleve/v2 v2.4.2 h1:NooYP1mb3c0StkiY9/xviiq2LGSaE8BQBCc/pirMx0U=
github.com/blevesearch/bleve/v2 v2.4.3/go.mod h1:hEPDPrbYw3vyrm5VOa36GyS4bHWuIf4Fflp7460QQXY= github.com/blevesearch/bleve/v2 v2.4.2/go.mod h1:ATNKj7Yl2oJv/lGuF4kx39bST2dveX6w0th2FFYLkc8=
github.com/blevesearch/bleve_index_api v1.1.12 h1:P4bw9/G/5rulOF7SJ9l4FsDoo7UFJ+5kexNy1RXfegY= github.com/blevesearch/bleve_index_api v1.1.10 h1:PDLFhVjrjQWr6jCuU7TwlmByQVCSEURADHdCqVS9+g0=
github.com/blevesearch/bleve_index_api v1.1.12/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8= github.com/blevesearch/bleve_index_api v1.1.10/go.mod h1:PbcwjIcRmjhGbkS/lJCpfgVSMROV6TRubGGAODaK1W8=
github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM= github.com/blevesearch/geo v0.1.20 h1:paaSpu2Ewh/tn5DKn/FB5SzvH0EWupxHEIwbCk/QPqM=
github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w= github.com/blevesearch/geo v0.1.20/go.mod h1:DVG2QjwHNMFmjo+ZgzrIq2sfCh6rIHzy9d9d0B59I6w=
github.com/blevesearch/go-faiss v1.0.23 h1:Wmc5AFwDLKGl2L6mjLX1Da3vCL0EKa2uHHSorcIS1Uc= github.com/blevesearch/go-faiss v1.0.20 h1:AIkdTQFWuZ5LQmKQSebgMR4RynGNw8ZseJXaan5kvtI=
github.com/blevesearch/go-faiss v1.0.23/go.mod h1:OMGQwOaRRYxrmeNdMrXJPvVx8gBnvE5RYrr0BahNnkk= github.com/blevesearch/go-faiss v1.0.20/go.mod h1:jrxHrbl42X/RnDPI+wBoZU8joxxuRwedrxqswQ3xfU8=
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.2.16 h1:uGvKVvG7zvSxCwcm4/ehBa9cCEuZVE+/zvrSl57QUVY= github.com/blevesearch/scorch_segment_api/v2 v2.2.15 h1:prV17iU/o+A8FiZi9MXmqbagd8I0bCqM7OKUYPbnb5Y=
github.com/blevesearch/scorch_segment_api/v2 v2.2.16/go.mod h1:VF5oHVbIFTu+znY1v30GjSpT5+9YFs9dV2hjvuh34F0= github.com/blevesearch/scorch_segment_api/v2 v2.2.15/go.mod h1:db0cmP03bPNadXrCDuVkKLV6ywFSiRgPFT1YVrestBc=
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
@ -130,10 +130,10 @@ github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIq
github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk= github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk=
github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU= github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU=
github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns= github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns=
github.com/blevesearch/zapx/v15 v15.3.16 h1:Ct3rv7FUJPfPk99TI/OofdC+Kpb4IdyfdMH48sb+FmE= github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ=
github.com/blevesearch/zapx/v15 v15.3.16/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg= github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg=
github.com/blevesearch/zapx/v16 v16.1.8 h1:Bxzpw6YQpFs7UjoCV1+RvDw6fmAT2GZxldwX8b3wVBM= github.com/blevesearch/zapx/v16 v16.1.5 h1:b0sMcarqNFxuXvjoXsF8WtwVahnxyhEvBSRJi/AUHjU=
github.com/blevesearch/zapx/v16 v16.1.8/go.mod h1:JqQlOqlRVaYDkpLIl3JnKql8u4zKTNlVEa3nLsi0Gn8= github.com/blevesearch/zapx/v16 v16.1.5/go.mod h1:J4mSF39w1QELc11EWRSBFkPeZuO7r/NPKkHzDCoiaI8=
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=
@ -143,8 +143,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/buildkite/terminal-to-html/v3 v3.16.4 h1:QFYO8IGvRnp7tGgiQb8g9uFU8kY9wOzxsFFx17+yy6Q= github.com/buildkite/terminal-to-html/v3 v3.16.3 h1:IGuJjboHjuMLWOGsKZKNxbbn41emOLiHzXPmQZk31fk=
github.com/buildkite/terminal-to-html/v3 v3.16.4/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0= github.com/buildkite/terminal-to-html/v3 v3.16.3/go.mod h1:r/J7cC9c3EzBzP3/wDz0RJLPwv5PUAMp+KF2w+ntMc0=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0= github.com/caddyserver/certmagic v0.21.4 h1:e7VobB8rffHv8ZZpSiZtEwnLDHUwLVYLWzWSa1FfKI0=
github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE= github.com/caddyserver/certmagic v0.21.4/go.mod h1:swUXjQ1T9ZtMv95qj7/InJvWLXURU85r+CfG0T+ZbDE=
@ -221,8 +221,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
@ -307,6 +307,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
@ -379,10 +381,8 @@ github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/grafana/go-json v0.0.0-20241115232854-f14426c40ff2 h1:8xGrYqQ1GM4aaMk7pNDfecBdL/VGhEbpvvGBoqO6BIY=
github.com/grafana/go-json v0.0.0-20241115232854-f14426c40ff2/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE= github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk= github.com/h2non/gock v1.2.0/go.mod h1:tNhoxHYW2W42cYkYb1WqzdbYIieALC99kpYr7rH/BQk=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
@ -491,8 +491,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/meilisearch/meilisearch-go v0.29.0 h1:HZ9NEKN59USINQ/DXJge/aaXq8IrsKbXGTdAoBaaDz4= github.com/meilisearch/meilisearch-go v0.28.0 h1:f3XJ66ZM+R8bANAOLqsjvoq/HhQNpVJPYoNt6QgNzME=
github.com/meilisearch/meilisearch-go v0.29.0/go.mod h1:2cRCAn4ddySUsFfNDLVPod/plRibQsJkXF/4gLhxbOk= github.com/meilisearch/meilisearch-go v0.28.0/go.mod h1:Szcc9CaDiKIfjdgdt49jlmDKpEzjD+x+b6Y6heMdlQ0=
github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw= github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw=
github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw= github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw=
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
@ -692,8 +692,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY=
@ -733,8 +733,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s= golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
@ -760,8 +760,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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=
@ -771,8 +771,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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=
@ -801,8 +801,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@ -812,8 +812,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -825,8 +825,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -843,10 +843,10 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View file

@ -146,11 +146,7 @@ func (run *ActionRun) GetPushEventPayload() (*api.PushPayload, error) {
} }
func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) { func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, error) {
if run.Event == webhook_module.HookEventPullRequest || if run.Event == webhook_module.HookEventPullRequest || run.Event == webhook_module.HookEventPullRequestSync {
run.Event == webhook_module.HookEventPullRequestSync ||
run.Event == webhook_module.HookEventPullRequestAssign ||
run.Event == webhook_module.HookEventPullRequestMilestone ||
run.Event == webhook_module.HookEventPullRequestLabel {
var payload api.PullRequestPayload var payload api.PullRequestPayload
if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil {
return nil, err return nil, err

View file

@ -10,7 +10,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View file

@ -96,6 +96,6 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
// Test JSON rendering // Test JSON rendering
jsonData, err := json.Marshal(heatmap) jsonData, err := json.Marshal(heatmap)
require.NoError(t, err) require.NoError(t, err)
assert.JSONEq(t, tc.JSONResult, string(jsonData)) assert.Equal(t, tc.JSONResult, string(jsonData))
} }
} }

View file

@ -15,31 +15,12 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
) )
type AuthorizationPurpose string
var (
// Used to store long term authorization tokens.
LongTermAuthorization AuthorizationPurpose = "long_term_authorization"
// Used to activate a user account.
UserActivation AuthorizationPurpose = "user_activation"
// Used to reset the password.
PasswordReset AuthorizationPurpose = "password_reset"
)
// Used to activate the specified email address for a user.
func EmailActivation(email string) AuthorizationPurpose {
return AuthorizationPurpose("email_activation:" + email)
}
// AuthorizationToken represents a authorization token to a user. // AuthorizationToken represents a authorization token to a user.
type AuthorizationToken struct { type AuthorizationToken struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
UID int64 `xorm:"INDEX"` UID int64 `xorm:"INDEX"`
LookupKey string `xorm:"INDEX UNIQUE"` LookupKey string `xorm:"INDEX UNIQUE"`
HashedValidator string HashedValidator string
Purpose AuthorizationPurpose `xorm:"NOT NULL DEFAULT 'long_term_authorization'"`
Expiry timeutil.TimeStamp Expiry timeutil.TimeStamp
} }
@ -60,7 +41,7 @@ func (authToken *AuthorizationToken) IsExpired() bool {
// GenerateAuthToken generates a new authentication token for the given user. // GenerateAuthToken generates a new authentication token for the given user.
// It returns the lookup key and validator values that should be passed to the // It returns the lookup key and validator values that should be passed to the
// user via a long-term cookie. // user via a long-term cookie.
func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeStamp, purpose AuthorizationPurpose) (lookupKey, validator string, err error) { func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeStamp) (lookupKey, validator string, err error) {
// Request 64 random bytes. The first 32 bytes will be used for the lookupKey // Request 64 random bytes. The first 32 bytes will be used for the lookupKey
// and the other 32 bytes will be used for the validator. // and the other 32 bytes will be used for the validator.
rBytes, err := util.CryptoRandomBytes(64) rBytes, err := util.CryptoRandomBytes(64)
@ -75,15 +56,14 @@ func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeSt
Expiry: expiry, Expiry: expiry,
LookupKey: lookupKey, LookupKey: lookupKey,
HashedValidator: HashValidator(rBytes[32:]), HashedValidator: HashValidator(rBytes[32:]),
Purpose: purpose,
}) })
return lookupKey, validator, err return lookupKey, validator, err
} }
// FindAuthToken will find a authorization token via the lookup key. // FindAuthToken will find a authorization token via the lookup key.
func FindAuthToken(ctx context.Context, lookupKey string, purpose AuthorizationPurpose) (*AuthorizationToken, error) { func FindAuthToken(ctx context.Context, lookupKey string) (*AuthorizationToken, error) {
var authToken AuthorizationToken var authToken AuthorizationToken
has, err := db.GetEngine(ctx).Where("lookup_key = ? AND purpose = ?", lookupKey, purpose).Get(&authToken) has, err := db.GetEngine(ctx).Where("lookup_key = ?", lookupKey).Get(&authToken)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {

View file

@ -12,7 +12,6 @@ import (
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/auth" _ "code.gitea.io/gitea/models/auth"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/perm/access" _ "code.gitea.io/gitea/models/perm/access"
) )

View file

@ -1,71 +0,0 @@
-
id: 1
run_id: 791
runner_id: 1
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
storage_path: "26/1/1712166500347189545.chunk"
file_size: 1024
file_compressed_size: 1024
content_encoding: ""
artifact_path: "abc.txt"
artifact_name: "artifact-download"
status: 1
created_unix: 1712338649
updated_unix: 1712338649
expired_unix: 1720114649
-
id: 19
run_id: 791
runner_id: 1
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
storage_path: "26/19/1712348022422036662.chunk"
file_size: 1024
file_compressed_size: 1024
content_encoding: ""
artifact_path: "abc.txt"
artifact_name: "multi-file-download"
status: 2
created_unix: 1712348022
updated_unix: 1712348022
expired_unix: 1720124022
-
id: 20
run_id: 791
runner_id: 1
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
storage_path: "26/20/1712348022423431524.chunk"
file_size: 1024
file_compressed_size: 1024
content_encoding: ""
artifact_path: "xyz/def.txt"
artifact_name: "multi-file-download"
status: 2
created_unix: 1712348022
updated_unix: 1712348022
expired_unix: 1720124022
-
id: 22
run_id: 792
runner_id: 1
repo_id: 4
owner_id: 1
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
storage_path: "27/5/1730330775594233150.chunk"
file_size: 1024
file_compressed_size: 1024
content_encoding: "application/zip"
artifact_path: "artifact-v4-download.zip"
artifact_name: "artifact-v4-download"
status: 2
created_unix: 1730330775
updated_unix: 1730330775
expired_unix: 1738106775

View file

@ -7,7 +7,6 @@
target_url: https://example.com/builds/ target_url: https://example.com/builds/
description: My awesome CI-service description: My awesome CI-service
context: ci/awesomeness context: ci/awesomeness
context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7
creator_id: 2 creator_id: 2
- -
@ -19,7 +18,6 @@
target_url: https://example.com/coverage/ target_url: https://example.com/coverage/
description: My awesome Coverage service description: My awesome Coverage service
context: cov/awesomeness context: cov/awesomeness
context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe
creator_id: 2 creator_id: 2
- -
@ -31,7 +29,6 @@
target_url: https://example.com/coverage/ target_url: https://example.com/coverage/
description: My awesome Coverage service description: My awesome Coverage service
context: cov/awesomeness context: cov/awesomeness
context_hash: 3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe
creator_id: 2 creator_id: 2
- -
@ -43,7 +40,6 @@
target_url: https://example.com/builds/ target_url: https://example.com/builds/
description: My awesome CI-service description: My awesome CI-service
context: ci/awesomeness context: ci/awesomeness
context_hash: c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7
creator_id: 2 creator_id: 2
- -
@ -55,41 +51,15 @@
target_url: https://example.com/builds/ target_url: https://example.com/builds/
description: My awesome deploy service description: My awesome deploy service
context: deploy/awesomeness context: deploy/awesomeness
context_hash: ae9547713a6665fc4261d0756904932085a41cf2
creator_id: 2 creator_id: 2
- -
id: 6 id: 6
index: 1 index: 6
repo_id: 62 repo_id: 62
state: "failure" state: "failure"
sha: "774f93df12d14931ea93259ae93418da4482fcc1" sha: "774f93df12d14931ea93259ae93418da4482fcc1"
target_url: "/user2/test_workflows/actions" target_url: "/user2/test_workflows/actions"
description: My awesome deploy service description: My awesome deploy service
context: deploy/awesomeness context: deploy/awesomeness
context_hash: ae9547713a6665fc4261d0756904932085a41cf2
creator_id: 2
-
id: 7
index: 6
repo_id: 1
state: "pending"
sha: "1234123412341234123412341234123412341234"
target_url: https://example.com/builds/
description: My awesome deploy service
context: deploy/awesomeness
context_hash: ae9547713a6665fc4261d0756904932085a41cf2
creator_id: 2
-
id: 8
index: 2
repo_id: 62
state: "error"
sha: "774f93df12d14931ea93259ae93418da4482fcc1"
target_url: "/user2/test_workflows/actions"
description: "My awesome deploy service - v2"
context: deploy/awesomeness
context_hash: ae9547713a6665fc4261d0756904932085a41cf2
creator_id: 2 creator_id: 2

View file

@ -1 +0,0 @@
[] # empty

View file

@ -1 +0,0 @@
[] # empty

View file

@ -29,8 +29,7 @@
size: 7597 size: 7597
is_fsck_enabled: true is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false close_issues_via_commit_in_any_branch: false
created_unix: 1731254961
updated_unix: 1731254961
- -
id: 2 id: 2
owner_id: 2 owner_id: 2

View file

@ -10,7 +10,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View file

@ -84,8 +84,6 @@ var migrations = []*Migration{
NewMigration("Add `legacy` to `web_authn_credential` table", AddLegacyToWebAuthnCredential), NewMigration("Add `legacy` to `web_authn_credential` table", AddLegacyToWebAuthnCredential),
// v23 -> v24 // v23 -> v24
NewMigration("Add `delete_branch_after_merge` to `auto_merge` table", AddDeleteBranchAfterMergeToAutoMerge), NewMigration("Add `delete_branch_after_merge` to `auto_merge` table", AddDeleteBranchAfterMergeToAutoMerge),
// v24 -> v25
NewMigration("Add `purpose` column to `forgejo_auth_token` table", AddPurposeToForgejoAuthToken),
} }
// GetCurrentDBVersion returns the current Forgejo database version. // GetCurrentDBVersion returns the current Forgejo database version.

View file

@ -1,19 +0,0 @@
// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package forgejo_migrations //nolint:revive
import "xorm.io/xorm"
func AddPurposeToForgejoAuthToken(x *xorm.Engine) error {
type ForgejoAuthToken struct {
ID int64 `xorm:"pk autoincr"`
Purpose string `xorm:"NOT NULL DEFAULT 'long_term_authorization'"`
}
if err := x.Sync(new(ForgejoAuthToken)); err != nil {
return err
}
_, err := x.Exec("UPDATE `forgejo_auth_token` SET purpose = 'long_term_authorization' WHERE purpose = ''")
return err
}

View file

@ -288,18 +288,27 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs // GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
func GetLatestCommitStatusForPairs(ctx context.Context, repoSHAs []RepoSHA) (map[int64][]*CommitStatus, error) { func GetLatestCommitStatusForPairs(ctx context.Context, repoSHAs []RepoSHA) (map[int64][]*CommitStatus, error) {
results := []*CommitStatus{} type result struct {
Index int64
RepoID int64
SHA string
}
results := make([]result, 0, len(repoSHAs))
getBase := func() *xorm.Session {
return db.GetEngine(ctx).Table(&CommitStatus{})
}
// Create a disjunction of conditions for each repoID and SHA pair // Create a disjunction of conditions for each repoID and SHA pair
conds := make([]builder.Cond, 0, len(repoSHAs)) conds := make([]builder.Cond, 0, len(repoSHAs))
for _, repoSHA := range repoSHAs { for _, repoSHA := range repoSHAs {
conds = append(conds, builder.Eq{"repo_id": repoSHA.RepoID, "sha": repoSHA.SHA}) conds = append(conds, builder.Eq{"repo_id": repoSHA.RepoID, "sha": repoSHA.SHA})
} }
sess := getBase().Where(builder.Or(conds...)).
Select("max( `index` ) as `index`, repo_id, sha").
GroupBy("context_hash, repo_id, sha").OrderBy("max( `index` ) desc")
sess := db.GetEngine(ctx).Table(&CommitStatus{}).
Select("MAX(`index`) AS `index`, *").
Where(builder.Or(conds...)).
GroupBy("context_hash, repo_id, sha").OrderBy("MAX(`index`) DESC")
err := sess.Find(&results) err := sess.Find(&results)
if err != nil { if err != nil {
return nil, err return nil, err
@ -307,10 +316,28 @@ func GetLatestCommitStatusForPairs(ctx context.Context, repoSHAs []RepoSHA) (map
repoStatuses := make(map[int64][]*CommitStatus) repoStatuses := make(map[int64][]*CommitStatus)
if len(results) > 0 {
statuses := make([]*CommitStatus, 0, len(results))
conds = make([]builder.Cond, 0, len(results))
for _, result := range results {
cond := builder.Eq{
"`index`": result.Index,
"repo_id": result.RepoID,
"sha": result.SHA,
}
conds = append(conds, cond)
}
err = getBase().Where(builder.Or(conds...)).Find(&statuses)
if err != nil {
return nil, err
}
// Group the statuses by repo ID // Group the statuses by repo ID
for _, status := range results { for _, status := range statuses {
repoStatuses[status.RepoID] = append(repoStatuses[status.RepoID], status) repoStatuses[status.RepoID] = append(repoStatuses[status.RepoID], status)
} }
}
return repoStatuses, nil return repoStatuses, nil
} }

View file

@ -35,8 +35,8 @@ func TestGetCommitStatuses(t *testing.T) {
SHA: sha1, SHA: sha1,
}) })
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(t, 6, maxResults) assert.Equal(t, 5, int(maxResults))
assert.Len(t, statuses, 6) assert.Len(t, statuses, 5)
assert.Equal(t, "ci/awesomeness", statuses[0].Context) assert.Equal(t, "ci/awesomeness", statuses[0].Context)
assert.Equal(t, structs.CommitStatusPending, statuses[0].State) assert.Equal(t, structs.CommitStatusPending, statuses[0].State)
@ -58,17 +58,13 @@ func TestGetCommitStatuses(t *testing.T) {
assert.Equal(t, structs.CommitStatusError, statuses[4].State) assert.Equal(t, structs.CommitStatusError, statuses[4].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext)) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL(db.DefaultContext))
assert.Equal(t, "deploy/awesomeness", statuses[5].Context)
assert.Equal(t, structs.CommitStatusPending, statuses[5].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[5].APIURL(db.DefaultContext))
statuses, maxResults, err = db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{ statuses, maxResults, err = db.FindAndCount[git_model.CommitStatus](db.DefaultContext, &git_model.CommitStatusOptions{
ListOptions: db.ListOptions{Page: 2, PageSize: 50}, ListOptions: db.ListOptions{Page: 2, PageSize: 50},
RepoID: repo1.ID, RepoID: repo1.ID,
SHA: sha1, SHA: sha1,
}) })
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(t, 6, maxResults) assert.Equal(t, 5, int(maxResults))
assert.Empty(t, statuses) assert.Empty(t, statuses)
} }
@ -269,148 +265,3 @@ func TestCommitStatusesHideActionsURL(t *testing.T) {
assert.Empty(t, statuses[0].TargetURL) assert.Empty(t, statuses[0].TargetURL)
assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL) assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL)
} }
func TestGetLatestCommitStatusForPairs(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
t.Run("All", func(t *testing.T) {
pairs, err := git_model.GetLatestCommitStatusForPairs(db.DefaultContext, nil)
require.NoError(t, err)
assert.EqualValues(t, map[int64][]*git_model.CommitStatus{
1: {
{
ID: 7,
Index: 6,
RepoID: 1,
State: structs.CommitStatusPending,
SHA: "1234123412341234123412341234123412341234",
TargetURL: "https://example.com/builds/",
Description: "My awesome deploy service",
ContextHash: "ae9547713a6665fc4261d0756904932085a41cf2",
Context: "deploy/awesomeness",
CreatorID: 2,
},
{
ID: 4,
Index: 4,
State: structs.CommitStatusFailure,
TargetURL: "https://example.com/builds/",
Description: "My awesome CI-service",
Context: "ci/awesomeness",
CreatorID: 2,
RepoID: 1,
SHA: "1234123412341234123412341234123412341234",
ContextHash: "c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7",
},
{
ID: 3,
Index: 3,
State: structs.CommitStatusSuccess,
TargetURL: "https://example.com/coverage/",
Description: "My awesome Coverage service",
Context: "cov/awesomeness",
CreatorID: 2,
RepoID: 1,
SHA: "1234123412341234123412341234123412341234",
ContextHash: "3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe",
},
},
62: {
{
ID: 8,
Index: 2,
RepoID: 62,
State: structs.CommitStatusError,
TargetURL: "/user2/test_workflows/actions",
Description: "My awesome deploy service - v2",
Context: "deploy/awesomeness",
SHA: "774f93df12d14931ea93259ae93418da4482fcc1",
ContextHash: "ae9547713a6665fc4261d0756904932085a41cf2",
CreatorID: 2,
},
},
}, pairs)
})
t.Run("Repo 1", func(t *testing.T) {
pairs, err := git_model.GetLatestCommitStatusForPairs(db.DefaultContext, []git_model.RepoSHA{{1, "1234123412341234123412341234123412341234"}})
require.NoError(t, err)
assert.EqualValues(t, map[int64][]*git_model.CommitStatus{
1: {
{
ID: 7,
Index: 6,
RepoID: 1,
State: structs.CommitStatusPending,
SHA: "1234123412341234123412341234123412341234",
TargetURL: "https://example.com/builds/",
Description: "My awesome deploy service",
ContextHash: "ae9547713a6665fc4261d0756904932085a41cf2",
Context: "deploy/awesomeness",
CreatorID: 2,
},
{
ID: 4,
Index: 4,
State: structs.CommitStatusFailure,
TargetURL: "https://example.com/builds/",
Description: "My awesome CI-service",
Context: "ci/awesomeness",
CreatorID: 2,
RepoID: 1,
SHA: "1234123412341234123412341234123412341234",
ContextHash: "c65f4d64a3b14a3eced0c9b36799e66e1bd5ced7",
},
{
ID: 3,
Index: 3,
State: structs.CommitStatusSuccess,
TargetURL: "https://example.com/coverage/",
Description: "My awesome Coverage service",
Context: "cov/awesomeness",
CreatorID: 2,
RepoID: 1,
SHA: "1234123412341234123412341234123412341234",
ContextHash: "3929ac7bccd3fa1bf9b38ddedb77973b1b9a8cfe",
},
},
}, pairs)
})
t.Run("Repo 62", func(t *testing.T) {
pairs, err := git_model.GetLatestCommitStatusForPairs(db.DefaultContext, []git_model.RepoSHA{{62, "774f93df12d14931ea93259ae93418da4482fcc1"}})
require.NoError(t, err)
assert.EqualValues(t, map[int64][]*git_model.CommitStatus{
62: {
{
ID: 8,
Index: 2,
RepoID: 62,
State: structs.CommitStatusError,
TargetURL: "/user2/test_workflows/actions",
Description: "My awesome deploy service - v2",
Context: "deploy/awesomeness",
SHA: "774f93df12d14931ea93259ae93418da4482fcc1",
ContextHash: "ae9547713a6665fc4261d0756904932085a41cf2",
CreatorID: 2,
},
},
}, pairs)
})
t.Run("Repo 62 nonexistant sha", func(t *testing.T) {
pairs, err := git_model.GetLatestCommitStatusForPairs(db.DefaultContext, []git_model.RepoSHA{{62, "774f93df12d14931ea93259ae93418da4482fcc"}})
require.NoError(t, err)
assert.EqualValues(t, map[int64][]*git_model.CommitStatus{}, pairs)
})
t.Run("SHA with non existant repo id", func(t *testing.T) {
pairs, err := git_model.GetLatestCommitStatusForPairs(db.DefaultContext, []git_model.RepoSHA{{1, "774f93df12d14931ea93259ae93418da4482fcc1"}})
require.NoError(t, err)
assert.EqualValues(t, map[int64][]*git_model.CommitStatus{}, pairs)
})
}

View file

@ -136,6 +136,8 @@ var ErrLFSObjectNotExist = db.ErrNotExist{Resource: "LFS Meta object"}
// NewLFSMetaObject stores a given populated LFSMetaObject structure in the database // NewLFSMetaObject stores a given populated LFSMetaObject structure in the database
// if it is not already present. // if it is not already present.
func NewLFSMetaObject(ctx context.Context, repoID int64, p lfs.Pointer) (*LFSMetaObject, error) { func NewLFSMetaObject(ctx context.Context, repoID int64, p lfs.Pointer) (*LFSMetaObject, error) {
var err error
ctx, committer, err := db.TxContext(ctx) ctx, committer, err := db.TxContext(ctx)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View file

@ -75,32 +75,3 @@ func TestBranchRuleMatchPriority(t *testing.T) {
} }
} }
} }
func TestBranchRuleSort(t *testing.T) {
in := []*ProtectedBranch{{
RuleName: "b",
CreatedUnix: 1,
}, {
RuleName: "b/*",
CreatedUnix: 3,
}, {
RuleName: "a/*",
CreatedUnix: 2,
}, {
RuleName: "c",
CreatedUnix: 0,
}, {
RuleName: "a",
CreatedUnix: 4,
}}
expect := []string{"c", "b", "a", "a/*", "b/*"}
pbr := ProtectedBranchRules(in)
pbr.sort()
var got []string
for i := range pbr {
got = append(got, pbr[i].RuleName)
}
assert.Equal(t, expect, got)
}

View file

@ -79,21 +79,15 @@ func IsRuleNameSpecial(ruleName string) bool {
} }
func (protectBranch *ProtectedBranch) loadGlob() { func (protectBranch *ProtectedBranch) loadGlob() {
if protectBranch.isPlainName || protectBranch.globRule != nil { if protectBranch.globRule == nil {
return
}
// detect if it is not glob
if !IsRuleNameSpecial(protectBranch.RuleName) {
protectBranch.isPlainName = true
return
}
// now we load the glob
var err error var err error
protectBranch.globRule, err = glob.Compile(protectBranch.RuleName, '/') protectBranch.globRule, err = glob.Compile(protectBranch.RuleName, '/')
if err != nil { if err != nil {
log.Warn("Invalid glob rule for ProtectedBranch[%d]: %s %v", protectBranch.ID, protectBranch.RuleName, err) log.Warn("Invalid glob rule for ProtectedBranch[%d]: %s %v", protectBranch.ID, protectBranch.RuleName, err)
protectBranch.globRule = glob.MustCompile(glob.QuoteMeta(protectBranch.RuleName), '/') protectBranch.globRule = glob.MustCompile(glob.QuoteMeta(protectBranch.RuleName), '/')
} }
protectBranch.isPlainName = !IsRuleNameSpecial(protectBranch.RuleName)
}
} }
// Match tests if branchName matches the rule // Match tests if branchName matches the rule

View file

@ -875,7 +875,7 @@ func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList,
return issues, nil return issues, nil
} }
// IsNewPinAllowed returns if a new Issue or Pull request can be pinned // IsNewPinnedAllowed returns if a new Issue or Pull request can be pinned
func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) { func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) {
var maxPin int var maxPin int
_, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ? AND pin_order > 0", repoID, isPull).Get(&maxPin) _, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ? AND pin_order > 0", repoID, isPull).Get(&maxPin)

View file

@ -111,7 +111,9 @@ func NewIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m
return err return err
} }
if err = issue.ReloadLabels(ctx); err != nil { issue.isLabelsLoaded = false
issue.Labels = nil
if err = issue.LoadLabels(ctx); err != nil {
return err return err
} }
@ -159,7 +161,10 @@ func NewIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
return err return err
} }
if err = issue.ReloadLabels(ctx); err != nil { // reload all labels
issue.isLabelsLoaded = false
issue.Labels = nil
if err = issue.LoadLabels(ctx); err != nil {
return err return err
} }
@ -200,7 +205,8 @@ func DeleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use
return err return err
} }
return issue.ReloadLabels(ctx) issue.Labels = nil
return issue.LoadLabels(ctx)
} }
// DeleteLabelsByRepoID deletes labels of some repository // DeleteLabelsByRepoID deletes labels of some repository
@ -320,23 +326,14 @@ func FixIssueLabelWithOutsideLabels(ctx context.Context) (int64, error) {
return res.RowsAffected() return res.RowsAffected()
} }
// LoadLabels only if they are not already set // LoadLabels loads labels
func (issue *Issue) LoadLabels(ctx context.Context) (err error) { func (issue *Issue) LoadLabels(ctx context.Context) (err error) {
if !issue.isLabelsLoaded && issue.Labels == nil { if !issue.isLabelsLoaded && issue.Labels == nil && issue.ID != 0 {
if err := issue.ReloadLabels(ctx); err != nil {
return err
}
issue.isLabelsLoaded = true
}
return nil
}
func (issue *Issue) ReloadLabels(ctx context.Context) (err error) {
if issue.ID != 0 {
issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID) issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID)
if err != nil { if err != nil {
return fmt.Errorf("getLabelsByIssueID [%d]: %w", issue.ID, err) return fmt.Errorf("getLabelsByIssueID [%d]: %w", issue.ID, err)
} }
issue.isLabelsLoaded = true
} }
return nil return nil
} }
@ -499,7 +496,8 @@ func ReplaceIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer
} }
} }
if err = issue.ReloadLabels(ctx); err != nil { issue.Labels = nil
if err = issue.LoadLabels(ctx); err != nil {
return err return err
} }

View file

@ -15,114 +15,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestIssueNewIssueLabels(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 4})
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
label3 := &issues_model.Label{RepoID: 1, Name: "label3", Color: "#123"}
require.NoError(t, issues_model.NewLabel(db.DefaultContext, label3))
// label1 is already set, do nothing
// label3 is new, add it
require.NoError(t, issues_model.NewIssueLabels(db.DefaultContext, issue, []*issues_model.Label{label1, label3}, doer))
assert.Len(t, issue.Labels, 3)
// check that the pre-existing label1 is still present
assert.Equal(t, label1.ID, issue.Labels[0].ID)
// check that new label3 was added
assert.Equal(t, label3.ID, issue.Labels[1].ID)
// check that pre-existing label2 was not removed
assert.Equal(t, label2.ID, issue.Labels[2].ID)
}
func TestIssueNewIssueLabel(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3})
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
label := &issues_model.Label{RepoID: 1, Name: "label3", Color: "#123"}
require.NoError(t, issues_model.NewLabel(db.DefaultContext, label))
require.NoError(t, issues_model.NewIssueLabel(db.DefaultContext, issue, label, doer))
assert.Len(t, issue.Labels, 1)
assert.Equal(t, label.ID, issue.Labels[0].ID)
}
func TestIssueReplaceIssueLabels(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 4})
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
label3 := &issues_model.Label{RepoID: 1, Name: "label3", Color: "#123"}
require.NoError(t, issues_model.NewLabel(db.DefaultContext, label3))
issue.LoadLabels(db.DefaultContext)
assert.Len(t, issue.Labels, 2)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
assert.Equal(t, label2.ID, issue.Labels[1].ID)
// label1 is already set, do nothing
// label3 is new, add it
// label2 is not in the list but already set, remove it
require.NoError(t, issues_model.ReplaceIssueLabels(db.DefaultContext, issue, []*issues_model.Label{label1, label3}, doer))
assert.Len(t, issue.Labels, 2)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
assert.Equal(t, label3.ID, issue.Labels[1].ID)
}
func TestIssueDeleteIssueLabel(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 4})
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
issue.LoadLabels(db.DefaultContext)
assert.Len(t, issue.Labels, 2)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
assert.Equal(t, label2.ID, issue.Labels[1].ID)
require.NoError(t, issues_model.DeleteIssueLabel(db.DefaultContext, issue, label2, doer))
assert.Len(t, issue.Labels, 1)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
}
func TestIssueLoadLabels(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2})
label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1})
label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 4})
assert.Empty(t, issue.Labels)
issue.LoadLabels(db.DefaultContext)
assert.Len(t, issue.Labels, 2)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
assert.Equal(t, label2.ID, issue.Labels[1].ID)
unittest.AssertSuccessfulDelete(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label2.ID})
// the database change is not noticed because the labels are cached
issue.LoadLabels(db.DefaultContext)
assert.Len(t, issue.Labels, 2)
issue.ReloadLabels(db.DefaultContext)
assert.Len(t, issue.Labels, 1)
assert.Equal(t, label1.ID, issue.Labels[0].ID)
}
func TestNewIssueLabelsScope(t *testing.T) { func TestNewIssueLabelsScope(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase()) require.NoError(t, unittest.PrepareTestDatabase())

View file

@ -231,7 +231,8 @@ func TestGetLabelsByOrgID(t *testing.T) {
testSuccess(3, "reversealphabetically", []int64{4, 3}) testSuccess(3, "reversealphabetically", []int64{4, 3})
testSuccess(3, "default", []int64{3, 4}) testSuccess(3, "default", []int64{3, 4})
_, err := issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{}) var err error
_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{})
assert.True(t, issues_model.IsErrOrgLabelNotExist(err)) assert.True(t, issues_model.IsErrOrgLabelNotExist(err))
_, err = issues_model.GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{}) _, err = issues_model.GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{})

View file

@ -689,7 +689,7 @@ func GetPullRequestByIssueID(ctx context.Context, issueID int64) (*PullRequest,
return pr, pr.LoadAttributes(ctx) return pr, pr.LoadAttributes(ctx)
} }
// GetPullRequestByBaseHeadInfo returns the pull request by given base and head // GetPullRequestsByBaseHeadInfo returns the pull request by given base and head
func GetPullRequestByBaseHeadInfo(ctx context.Context, baseID, headID int64, base, head string) (*PullRequest, error) { func GetPullRequestByBaseHeadInfo(ctx context.Context, baseID, headID int64, base, head string) (*PullRequest, error) {
pr := &PullRequest{} pr := &PullRequest{}
sess := db.GetEngine(ctx). sess := db.GetEngine(ctx).

View file

@ -13,7 +13,6 @@ import (
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/system" _ "code.gitea.io/gitea/models/system"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View file

@ -38,15 +38,25 @@ import (
const minDBVersion = 70 // Gitea 1.5.3 const minDBVersion = 70 // Gitea 1.5.3
// Migration describes on migration from lower version to high version
type Migration interface {
Description() string
Migrate(*xorm.Engine) error
}
type migration struct { type migration struct {
idNumber int64 // DB version is "the last migration's idNumber" + 1
description string description string
migrate func(*xorm.Engine) error migrate func(*xorm.Engine) error
} }
// newMigration creates a new migration // NewMigration creates a new migration
func newMigration(idNumber int64, desc string, fn func(*xorm.Engine) error) *migration { func NewMigration(desc string, fn func(*xorm.Engine) error) Migration {
return &migration{idNumber, desc, fn} return &migration{desc, fn}
}
// Description returns the migration's description
func (m *migration) Description() string {
return m.description
} }
// Migrate executes the migration // Migrate executes the migration
@ -57,313 +67,538 @@ func (m *migration) Migrate(x *xorm.Engine) error {
// Version describes the version table. Should have only one row with id==1 // Version describes the version table. Should have only one row with id==1
type Version struct { type Version struct {
ID int64 `xorm:"pk autoincr"` ID int64 `xorm:"pk autoincr"`
Version int64 // DB version is "the last migration's idNumber" + 1 Version int64
} }
// Use noopMigration when there is a migration that has been no-oped // Use noopMigration when there is a migration that has been no-oped
var noopMigration = func(_ *xorm.Engine) error { return nil } var noopMigration = func(_ *xorm.Engine) error { return nil }
var preparedMigrations []*migration
// This is a sequence of migrations. Add new migrations to the bottom of the list. // This is a sequence of migrations. Add new migrations to the bottom of the list.
// If you want to "retire" a migration, remove it from the top of the list and // If you want to "retire" a migration, remove it from the top of the list and
// update minDBVersion accordingly // update minDBVersion accordingly
func prepareMigrationTasks() []*migration { var migrations = []Migration{
if preparedMigrations != nil { // Gitea 1.5.0 ends at v69
return preparedMigrations
}
preparedMigrations = []*migration{
// Gitea 1.5.0 ends at database version 69
newMigration(70, "add issue_dependencies", v1_6.AddIssueDependencies), // v70 -> v71
newMigration(71, "protect each scratch token", v1_6.AddScratchHash), NewMigration("add issue_dependencies", v1_6.AddIssueDependencies),
newMigration(72, "add review", v1_6.AddReview), // v71 -> v72
NewMigration("protect each scratch token", v1_6.AddScratchHash),
// v72 -> v73
NewMigration("add review", v1_6.AddReview),
// Gitea 1.6.0 ends at database version 73 // Gitea 1.6.0 ends at v73
newMigration(73, "add must_change_password column for users table", v1_7.AddMustChangePassword), // v73 -> v74
newMigration(74, "add approval whitelists to protected branches", v1_7.AddApprovalWhitelistsToProtectedBranches), NewMigration("add must_change_password column for users table", v1_7.AddMustChangePassword),
newMigration(75, "clear nonused data which not deleted when user was deleted", v1_7.ClearNonusedData), // v74 -> v75
NewMigration("add approval whitelists to protected branches", v1_7.AddApprovalWhitelistsToProtectedBranches),
// v75 -> v76
NewMigration("clear nonused data which not deleted when user was deleted", v1_7.ClearNonusedData),
// Gitea 1.7.0 ends at database version 76 // Gitea 1.7.0 ends at v76
newMigration(76, "add pull request rebase with merge commit", v1_8.AddPullRequestRebaseWithMerge), // v76 -> v77
newMigration(77, "add theme to users", v1_8.AddUserDefaultTheme), NewMigration("add pull request rebase with merge commit", v1_8.AddPullRequestRebaseWithMerge),
newMigration(78, "rename repo is_bare to repo is_empty", v1_8.RenameRepoIsBareToIsEmpty), // v77 -> v78
newMigration(79, "add can close issues via commit in any branch", v1_8.AddCanCloseIssuesViaCommitInAnyBranch), NewMigration("add theme to users", v1_8.AddUserDefaultTheme),
newMigration(80, "add is locked to issues", v1_8.AddIsLockedToIssues), // v78 -> v79
newMigration(81, "update U2F counter type", v1_8.ChangeU2FCounterType), NewMigration("rename repo is_bare to repo is_empty", v1_8.RenameRepoIsBareToIsEmpty),
// v79 -> v80
NewMigration("add can close issues via commit in any branch", v1_8.AddCanCloseIssuesViaCommitInAnyBranch),
// v80 -> v81
NewMigration("add is locked to issues", v1_8.AddIsLockedToIssues),
// v81 -> v82
NewMigration("update U2F counter type", v1_8.ChangeU2FCounterType),
// Gitea 1.8.0 ends at database version 82 // Gitea 1.8.0 ends at v82
newMigration(82, "hot fix for wrong release sha1 on release table", v1_9.FixReleaseSha1OnReleaseTable), // v82 -> v83
newMigration(83, "add uploader id for table attachment", v1_9.AddUploaderIDForAttachment), NewMigration("hot fix for wrong release sha1 on release table", v1_9.FixReleaseSha1OnReleaseTable),
newMigration(84, "add table to store original imported gpg keys", v1_9.AddGPGKeyImport), // v83 -> v84
newMigration(85, "hash application token", v1_9.HashAppToken), NewMigration("add uploader id for table attachment", v1_9.AddUploaderIDForAttachment),
newMigration(86, "add http method to webhook", v1_9.AddHTTPMethodToWebhook), // v84 -> v85
newMigration(87, "add avatar field to repository", v1_9.AddAvatarFieldToRepository), NewMigration("add table to store original imported gpg keys", v1_9.AddGPGKeyImport),
// v85 -> v86
NewMigration("hash application token", v1_9.HashAppToken),
// v86 -> v87
NewMigration("add http method to webhook", v1_9.AddHTTPMethodToWebhook),
// v87 -> v88
NewMigration("add avatar field to repository", v1_9.AddAvatarFieldToRepository),
// Gitea 1.9.0 ends at database version 88 // Gitea 1.9.0 ends at v88
newMigration(88, "add commit status context field to commit_status", v1_10.AddCommitStatusContext), // v88 -> v89
newMigration(89, "add original author/url migration info to issues, comments, and repo ", v1_10.AddOriginalMigrationInfo), NewMigration("add commit status context field to commit_status", v1_10.AddCommitStatusContext),
newMigration(90, "change length of some repository columns", v1_10.ChangeSomeColumnsLengthOfRepo), // v89 -> v90
newMigration(91, "add index on owner_id of repository and type, review_id of comment", v1_10.AddIndexOnRepositoryAndComment), NewMigration("add original author/url migration info to issues, comments, and repo ", v1_10.AddOriginalMigrationInfo),
newMigration(92, "remove orphaned repository index statuses", v1_10.RemoveLingeringIndexStatus), // v90 -> v91
newMigration(93, "add email notification enabled preference to user", v1_10.AddEmailNotificationEnabledToUser), NewMigration("change length of some repository columns", v1_10.ChangeSomeColumnsLengthOfRepo),
newMigration(94, "add enable_status_check, status_check_contexts to protected_branch", v1_10.AddStatusCheckColumnsForProtectedBranches), // v91 -> v92
newMigration(95, "add table columns for cross referencing issues", v1_10.AddCrossReferenceColumns), NewMigration("add index on owner_id of repository and type, review_id of comment", v1_10.AddIndexOnRepositoryAndComment),
newMigration(96, "delete orphaned attachments", v1_10.DeleteOrphanedAttachments), // v92 -> v93
newMigration(97, "add repo_admin_change_team_access to user", v1_10.AddRepoAdminChangeTeamAccessColumnForUser), NewMigration("remove orphaned repository index statuses", v1_10.RemoveLingeringIndexStatus),
newMigration(98, "add original author name and id on migrated release", v1_10.AddOriginalAuthorOnMigratedReleases), // v93 -> v94
newMigration(99, "add task table and status column for repository table", v1_10.AddTaskTable), NewMigration("add email notification enabled preference to user", v1_10.AddEmailNotificationEnabledToUser),
newMigration(100, "update migration repositories' service type", v1_10.UpdateMigrationServiceTypes), // v94 -> v95
newMigration(101, "change length of some external login users columns", v1_10.ChangeSomeColumnsLengthOfExternalLoginUser), NewMigration("add enable_status_check, status_check_contexts to protected_branch", v1_10.AddStatusCheckColumnsForProtectedBranches),
// v95 -> v96
NewMigration("add table columns for cross referencing issues", v1_10.AddCrossReferenceColumns),
// v96 -> v97
NewMigration("delete orphaned attachments", v1_10.DeleteOrphanedAttachments),
// v97 -> v98
NewMigration("add repo_admin_change_team_access to user", v1_10.AddRepoAdminChangeTeamAccessColumnForUser),
// v98 -> v99
NewMigration("add original author name and id on migrated release", v1_10.AddOriginalAuthorOnMigratedReleases),
// v99 -> v100
NewMigration("add task table and status column for repository table", v1_10.AddTaskTable),
// v100 -> v101
NewMigration("update migration repositories' service type", v1_10.UpdateMigrationServiceTypes),
// v101 -> v102
NewMigration("change length of some external login users columns", v1_10.ChangeSomeColumnsLengthOfExternalLoginUser),
// Gitea 1.10.0 ends at database version 102 // Gitea 1.10.0 ends at v102
newMigration(102, "update migration repositories' service type", v1_11.DropColumnHeadUserNameOnPullRequest), // v102 -> v103
newMigration(103, "Add WhitelistDeployKeys to protected branch", v1_11.AddWhitelistDeployKeysToBranches), NewMigration("update migration repositories' service type", v1_11.DropColumnHeadUserNameOnPullRequest),
newMigration(104, "remove unnecessary columns from label", v1_11.RemoveLabelUneededCols), // v103 -> v104
newMigration(105, "add includes_all_repositories to teams", v1_11.AddTeamIncludesAllRepositories), NewMigration("Add WhitelistDeployKeys to protected branch", v1_11.AddWhitelistDeployKeysToBranches),
newMigration(106, "add column `mode` to table watch", v1_11.AddModeColumnToWatch), // v104 -> v105
newMigration(107, "Add template options to repository", v1_11.AddTemplateToRepo), NewMigration("remove unnecessary columns from label", v1_11.RemoveLabelUneededCols),
newMigration(108, "Add comment_id on table notification", v1_11.AddCommentIDOnNotification), // v105 -> v106
newMigration(109, "add can_create_org_repo to team", v1_11.AddCanCreateOrgRepoColumnForTeam), NewMigration("add includes_all_repositories to teams", v1_11.AddTeamIncludesAllRepositories),
newMigration(110, "change review content type to text", v1_11.ChangeReviewContentToText), // v106 -> v107
newMigration(111, "update branch protection for can push and whitelist enable", v1_11.AddBranchProtectionCanPushAndEnableWhitelist), NewMigration("add column `mode` to table watch", v1_11.AddModeColumnToWatch),
newMigration(112, "remove release attachments which repository deleted", v1_11.RemoveAttachmentMissedRepo), // v107 -> v108
newMigration(113, "new feature: change target branch of pull requests", v1_11.FeatureChangeTargetBranch), NewMigration("Add template options to repository", v1_11.AddTemplateToRepo),
newMigration(114, "Remove authentication credentials from stored URL", v1_11.SanitizeOriginalURL), // v108 -> v109
newMigration(115, "add user_id prefix to existing user avatar name", v1_11.RenameExistingUserAvatarName), NewMigration("Add comment_id on table notification", v1_11.AddCommentIDOnNotification),
newMigration(116, "Extend TrackedTimes", v1_11.ExtendTrackedTimes), // v109 -> v110
NewMigration("add can_create_org_repo to team", v1_11.AddCanCreateOrgRepoColumnForTeam),
// v110 -> v111
NewMigration("change review content type to text", v1_11.ChangeReviewContentToText),
// v111 -> v112
NewMigration("update branch protection for can push and whitelist enable", v1_11.AddBranchProtectionCanPushAndEnableWhitelist),
// v112 -> v113
NewMigration("remove release attachments which repository deleted", v1_11.RemoveAttachmentMissedRepo),
// v113 -> v114
NewMigration("new feature: change target branch of pull requests", v1_11.FeatureChangeTargetBranch),
// v114 -> v115
NewMigration("Remove authentication credentials from stored URL", v1_11.SanitizeOriginalURL),
// v115 -> v116
NewMigration("add user_id prefix to existing user avatar name", v1_11.RenameExistingUserAvatarName),
// v116 -> v117
NewMigration("Extend TrackedTimes", v1_11.ExtendTrackedTimes),
// Gitea 1.11.0 ends at database version 117 // Gitea 1.11.0 ends at v117
newMigration(117, "Add block on rejected reviews branch protection", v1_12.AddBlockOnRejectedReviews), // v117 -> v118
newMigration(118, "Add commit id and stale to reviews", v1_12.AddReviewCommitAndStale), NewMigration("Add block on rejected reviews branch protection", v1_12.AddBlockOnRejectedReviews),
newMigration(119, "Fix migrated repositories' git service type", v1_12.FixMigratedRepositoryServiceType), // v118 -> v119
newMigration(120, "Add owner_name on table repository", v1_12.AddOwnerNameOnRepository), NewMigration("Add commit id and stale to reviews", v1_12.AddReviewCommitAndStale),
newMigration(121, "add is_restricted column for users table", v1_12.AddIsRestricted), // v119 -> v120
newMigration(122, "Add Require Signed Commits to ProtectedBranch", v1_12.AddRequireSignedCommits), NewMigration("Fix migrated repositories' git service type", v1_12.FixMigratedRepositoryServiceType),
newMigration(123, "Add original information for reactions", v1_12.AddReactionOriginals), // v120 -> v121
newMigration(124, "Add columns to user and repository", v1_12.AddUserRepoMissingColumns), NewMigration("Add owner_name on table repository", v1_12.AddOwnerNameOnRepository),
newMigration(125, "Add some columns on review for migration", v1_12.AddReviewMigrateInfo), // v121 -> v122
newMigration(126, "Fix topic repository count", v1_12.FixTopicRepositoryCount), NewMigration("add is_restricted column for users table", v1_12.AddIsRestricted),
newMigration(127, "add repository code language statistics", v1_12.AddLanguageStats), // v122 -> v123
newMigration(128, "fix merge base for pull requests", v1_12.FixMergeBase), NewMigration("Add Require Signed Commits to ProtectedBranch", v1_12.AddRequireSignedCommits),
newMigration(129, "remove dependencies from deleted repositories", v1_12.PurgeUnusedDependencies), // v123 -> v124
newMigration(130, "Expand webhooks for more granularity", v1_12.ExpandWebhooks), NewMigration("Add original information for reactions", v1_12.AddReactionOriginals),
newMigration(131, "Add IsSystemWebhook column to webhooks table", v1_12.AddSystemWebhookColumn), // v124 -> v125
newMigration(132, "Add Branch Protection Protected Files Column", v1_12.AddBranchProtectionProtectedFilesColumn), NewMigration("Add columns to user and repository", v1_12.AddUserRepoMissingColumns),
newMigration(133, "Add EmailHash Table", v1_12.AddEmailHashTable), // v125 -> v126
newMigration(134, "Refix merge base for merged pull requests", v1_12.RefixMergeBase), NewMigration("Add some columns on review for migration", v1_12.AddReviewMigrateInfo),
newMigration(135, "Add OrgID column to Labels table", v1_12.AddOrgIDLabelColumn), // v126 -> v127
newMigration(136, "Add CommitsAhead and CommitsBehind Column to PullRequest Table", v1_12.AddCommitDivergenceToPulls), NewMigration("Fix topic repository count", v1_12.FixTopicRepositoryCount),
newMigration(137, "Add Branch Protection Block Outdated Branch", v1_12.AddBlockOnOutdatedBranch), // v127 -> v128
newMigration(138, "Add ResolveDoerID to Comment table", v1_12.AddResolveDoerIDCommentColumn), NewMigration("add repository code language statistics", v1_12.AddLanguageStats),
newMigration(139, "prepend refs/heads/ to issue refs", v1_12.PrependRefsHeadsToIssueRefs), // v128 -> v129
NewMigration("fix merge base for pull requests", v1_12.FixMergeBase),
// v129 -> v130
NewMigration("remove dependencies from deleted repositories", v1_12.PurgeUnusedDependencies),
// v130 -> v131
NewMigration("Expand webhooks for more granularity", v1_12.ExpandWebhooks),
// v131 -> v132
NewMigration("Add IsSystemWebhook column to webhooks table", v1_12.AddSystemWebhookColumn),
// v132 -> v133
NewMigration("Add Branch Protection Protected Files Column", v1_12.AddBranchProtectionProtectedFilesColumn),
// v133 -> v134
NewMigration("Add EmailHash Table", v1_12.AddEmailHashTable),
// v134 -> v135
NewMigration("Refix merge base for merged pull requests", v1_12.RefixMergeBase),
// v135 -> v136
NewMigration("Add OrgID column to Labels table", v1_12.AddOrgIDLabelColumn),
// v136 -> v137
NewMigration("Add CommitsAhead and CommitsBehind Column to PullRequest Table", v1_12.AddCommitDivergenceToPulls),
// v137 -> v138
NewMigration("Add Branch Protection Block Outdated Branch", v1_12.AddBlockOnOutdatedBranch),
// v138 -> v139
NewMigration("Add ResolveDoerID to Comment table", v1_12.AddResolveDoerIDCommentColumn),
// v139 -> v140
NewMigration("prepend refs/heads/ to issue refs", v1_12.PrependRefsHeadsToIssueRefs),
// Gitea 1.12.0 ends at database version 140 // Gitea 1.12.0 ends at v140
newMigration(140, "Save detected language file size to database instead of percent", v1_13.FixLanguageStatsToSaveSize), // v140 -> v141
newMigration(141, "Add KeepActivityPrivate to User table", v1_13.AddKeepActivityPrivateUserColumn), NewMigration("Save detected language file size to database instead of percent", v1_13.FixLanguageStatsToSaveSize),
newMigration(142, "Ensure Repository.IsArchived is not null", v1_13.SetIsArchivedToFalse), // v141 -> v142
newMigration(143, "recalculate Stars number for all user", v1_13.RecalculateStars), NewMigration("Add KeepActivityPrivate to User table", v1_13.AddKeepActivityPrivateUserColumn),
newMigration(144, "update Matrix Webhook http method to 'PUT'", v1_13.UpdateMatrixWebhookHTTPMethod), // v142 -> v143
newMigration(145, "Increase Language field to 50 in LanguageStats", v1_13.IncreaseLanguageField), NewMigration("Ensure Repository.IsArchived is not null", v1_13.SetIsArchivedToFalse),
newMigration(146, "Add projects info to repository table", v1_13.AddProjectsInfo), // v143 -> v144
newMigration(147, "create review for 0 review id code comments", v1_13.CreateReviewsForCodeComments), NewMigration("recalculate Stars number for all user", v1_13.RecalculateStars),
newMigration(148, "remove issue dependency comments who refer to non existing issues", v1_13.PurgeInvalidDependenciesComments), // v144 -> v145
newMigration(149, "Add Created and Updated to Milestone table", v1_13.AddCreatedAndUpdatedToMilestones), NewMigration("update Matrix Webhook http method to 'PUT'", v1_13.UpdateMatrixWebhookHTTPMethod),
newMigration(150, "add primary key to repo_topic", v1_13.AddPrimaryKeyToRepoTopic), // v145 -> v146
newMigration(151, "set default password algorithm to Argon2", v1_13.SetDefaultPasswordToArgon2), NewMigration("Increase Language field to 50 in LanguageStats", v1_13.IncreaseLanguageField),
newMigration(152, "add TrustModel field to Repository", v1_13.AddTrustModelToRepository), // v146 -> v147
newMigration(153, "add Team review request support", v1_13.AddTeamReviewRequestSupport), NewMigration("Add projects info to repository table", v1_13.AddProjectsInfo),
newMigration(154, "add timestamps to Star, Label, Follow, Watch and Collaboration", v1_13.AddTimeStamps), // v147 -> v148
NewMigration("create review for 0 review id code comments", v1_13.CreateReviewsForCodeComments),
// v148 -> v149
NewMigration("remove issue dependency comments who refer to non existing issues", v1_13.PurgeInvalidDependenciesComments),
// v149 -> v150
NewMigration("Add Created and Updated to Milestone table", v1_13.AddCreatedAndUpdatedToMilestones),
// v150 -> v151
NewMigration("add primary key to repo_topic", v1_13.AddPrimaryKeyToRepoTopic),
// v151 -> v152
NewMigration("set default password algorithm to Argon2", v1_13.SetDefaultPasswordToArgon2),
// v152 -> v153
NewMigration("add TrustModel field to Repository", v1_13.AddTrustModelToRepository),
// v153 > v154
NewMigration("add Team review request support", v1_13.AddTeamReviewRequestSupport),
// v154 > v155
NewMigration("add timestamps to Star, Label, Follow, Watch and Collaboration", v1_13.AddTimeStamps),
// Gitea 1.13.0 ends at database version 155 // Gitea 1.13.0 ends at v155
newMigration(155, "add changed_protected_files column for pull_request table", v1_14.AddChangedProtectedFilesPullRequestColumn), // v155 -> v156
newMigration(156, "fix publisher ID for tag releases", v1_14.FixPublisherIDforTagReleases), NewMigration("add changed_protected_files column for pull_request table", v1_14.AddChangedProtectedFilesPullRequestColumn),
newMigration(157, "ensure repo topics are up-to-date", v1_14.FixRepoTopics), // v156 -> v157
newMigration(158, "code comment replies should have the commitID of the review they are replying to", v1_14.UpdateCodeCommentReplies), NewMigration("fix publisher ID for tag releases", v1_14.FixPublisherIDforTagReleases),
newMigration(159, "update reactions constraint", v1_14.UpdateReactionConstraint), // v157 -> v158
newMigration(160, "Add block on official review requests branch protection", v1_14.AddBlockOnOfficialReviewRequests), NewMigration("ensure repo topics are up-to-date", v1_14.FixRepoTopics),
newMigration(161, "Convert task type from int to string", v1_14.ConvertTaskTypeToString), // v158 -> v159
newMigration(162, "Convert webhook task type from int to string", v1_14.ConvertWebhookTaskTypeToString), NewMigration("code comment replies should have the commitID of the review they are replying to", v1_14.UpdateCodeCommentReplies),
newMigration(163, "Convert topic name from 25 to 50", v1_14.ConvertTopicNameFrom25To50), // v159 -> v160
newMigration(164, "Add scope and nonce columns to oauth2_grant table", v1_14.AddScopeAndNonceColumnsToOAuth2Grant), NewMigration("update reactions constraint", v1_14.UpdateReactionConstraint),
newMigration(165, "Convert hook task type from char(16) to varchar(16) and trim the column", v1_14.ConvertHookTaskTypeToVarcharAndTrim), // v160 -> v161
newMigration(166, "Where Password is Valid with Empty String delete it", v1_14.RecalculateUserEmptyPWD), NewMigration("Add block on official review requests branch protection", v1_14.AddBlockOnOfficialReviewRequests),
newMigration(167, "Add user redirect", v1_14.AddUserRedirect), // v161 -> v162
newMigration(168, "Recreate user table to fix default values", v1_14.RecreateUserTableToFixDefaultValues), NewMigration("Convert task type from int to string", v1_14.ConvertTaskTypeToString),
newMigration(169, "Update DeleteBranch comments to set the old_ref to the commit_sha", v1_14.CommentTypeDeleteBranchUseOldRef), // v162 -> v163
newMigration(170, "Add Dismissed to Review table", v1_14.AddDismissedReviewColumn), NewMigration("Convert webhook task type from int to string", v1_14.ConvertWebhookTaskTypeToString),
newMigration(171, "Add Sorting to ProjectBoard table", v1_14.AddSortingColToProjectBoard), // v163 -> v164
newMigration(172, "Add sessions table for go-chi/session", v1_14.AddSessionTable), NewMigration("Convert topic name from 25 to 50", v1_14.ConvertTopicNameFrom25To50),
newMigration(173, "Add time_id column to Comment", v1_14.AddTimeIDCommentColumn), // v164 -> v165
newMigration(174, "Create repo transfer table", v1_14.AddRepoTransfer), NewMigration("Add scope and nonce columns to oauth2_grant table", v1_14.AddScopeAndNonceColumnsToOAuth2Grant),
newMigration(175, "Fix Postgres ID Sequences broken by recreate-table", v1_14.FixPostgresIDSequences), // v165 -> v166
newMigration(176, "Remove invalid labels from comments", v1_14.RemoveInvalidLabels), NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", v1_14.ConvertHookTaskTypeToVarcharAndTrim),
newMigration(177, "Delete orphaned IssueLabels", v1_14.DeleteOrphanedIssueLabels), // v166 -> v167
NewMigration("Where Password is Valid with Empty String delete it", v1_14.RecalculateUserEmptyPWD),
// v167 -> v168
NewMigration("Add user redirect", v1_14.AddUserRedirect),
// v168 -> v169
NewMigration("Recreate user table to fix default values", v1_14.RecreateUserTableToFixDefaultValues),
// v169 -> v170
NewMigration("Update DeleteBranch comments to set the old_ref to the commit_sha", v1_14.CommentTypeDeleteBranchUseOldRef),
// v170 -> v171
NewMigration("Add Dismissed to Review table", v1_14.AddDismissedReviewColumn),
// v171 -> v172
NewMigration("Add Sorting to ProjectBoard table", v1_14.AddSortingColToProjectBoard),
// v172 -> v173
NewMigration("Add sessions table for go-chi/session", v1_14.AddSessionTable),
// v173 -> v174
NewMigration("Add time_id column to Comment", v1_14.AddTimeIDCommentColumn),
// v174 -> v175
NewMigration("Create repo transfer table", v1_14.AddRepoTransfer),
// v175 -> v176
NewMigration("Fix Postgres ID Sequences broken by recreate-table", v1_14.FixPostgresIDSequences),
// v176 -> v177
NewMigration("Remove invalid labels from comments", v1_14.RemoveInvalidLabels),
// v177 -> v178
NewMigration("Delete orphaned IssueLabels", v1_14.DeleteOrphanedIssueLabels),
// Gitea 1.14.0 ends at database version 178 // Gitea 1.14.0 ends at v178
newMigration(178, "Add LFS columns to Mirror", v1_15.AddLFSMirrorColumns), // v178 -> v179
newMigration(179, "Convert avatar url to text", v1_15.ConvertAvatarURLToText), NewMigration("Add LFS columns to Mirror", v1_15.AddLFSMirrorColumns),
newMigration(180, "Delete credentials from past migrations", v1_15.DeleteMigrationCredentials), // v179 -> v180
newMigration(181, "Always save primary email on email address table", v1_15.AddPrimaryEmail2EmailAddress), NewMigration("Convert avatar url to text", v1_15.ConvertAvatarURLToText),
newMigration(182, "Add issue resource index table", v1_15.AddIssueResourceIndexTable), // v180 -> v181
newMigration(183, "Create PushMirror table", v1_15.CreatePushMirrorTable), NewMigration("Delete credentials from past migrations", v1_15.DeleteMigrationCredentials),
newMigration(184, "Rename Task errors to message", v1_15.RenameTaskErrorsToMessage), // v181 -> v182
newMigration(185, "Add new table repo_archiver", v1_15.AddRepoArchiver), NewMigration("Always save primary email on email address table", v1_15.AddPrimaryEmail2EmailAddress),
newMigration(186, "Create protected tag table", v1_15.CreateProtectedTagTable), // v182 -> v183
newMigration(187, "Drop unneeded webhook related columns", v1_15.DropWebhookColumns), NewMigration("Add issue resource index table", v1_15.AddIssueResourceIndexTable),
newMigration(188, "Add key is verified to gpg key", v1_15.AddKeyIsVerified), // v183 -> v184
NewMigration("Create PushMirror table", v1_15.CreatePushMirrorTable),
// v184 -> v185
NewMigration("Rename Task errors to message", v1_15.RenameTaskErrorsToMessage),
// v185 -> v186
NewMigration("Add new table repo_archiver", v1_15.AddRepoArchiver),
// v186 -> v187
NewMigration("Create protected tag table", v1_15.CreateProtectedTagTable),
// v187 -> v188
NewMigration("Drop unneeded webhook related columns", v1_15.DropWebhookColumns),
// v188 -> v189
NewMigration("Add key is verified to gpg key", v1_15.AddKeyIsVerified),
// Gitea 1.15.0 ends at database version 189 // Gitea 1.15.0 ends at v189
newMigration(189, "Unwrap ldap.Sources", v1_16.UnwrapLDAPSourceCfg), // v189 -> v190
newMigration(190, "Add agit flow pull request support", v1_16.AddAgitFlowPullRequest), NewMigration("Unwrap ldap.Sources", v1_16.UnwrapLDAPSourceCfg),
newMigration(191, "Alter issue/comment table TEXT fields to LONGTEXT", v1_16.AlterIssueAndCommentTextFieldsToLongText), // v190 -> v191
newMigration(192, "RecreateIssueResourceIndexTable to have a primary key instead of an unique index", v1_16.RecreateIssueResourceIndexTable), NewMigration("Add agit flow pull request support", v1_16.AddAgitFlowPullRequest),
newMigration(193, "Add repo id column for attachment table", v1_16.AddRepoIDForAttachment), // v191 -> v192
newMigration(194, "Add Branch Protection Unprotected Files Column", v1_16.AddBranchProtectionUnprotectedFilesColumn), NewMigration("Alter issue/comment table TEXT fields to LONGTEXT", v1_16.AlterIssueAndCommentTextFieldsToLongText),
newMigration(195, "Add table commit_status_index", v1_16.AddTableCommitStatusIndex), // v192 -> v193
newMigration(196, "Add Color to ProjectBoard table", v1_16.AddColorColToProjectBoard), NewMigration("RecreateIssueResourceIndexTable to have a primary key instead of an unique index", v1_16.RecreateIssueResourceIndexTable),
newMigration(197, "Add renamed_branch table", v1_16.AddRenamedBranchTable), // v193 -> v194
newMigration(198, "Add issue content history table", v1_16.AddTableIssueContentHistory), NewMigration("Add repo id column for attachment table", v1_16.AddRepoIDForAttachment),
newMigration(199, "No-op (remote version is using AppState now)", noopMigration), // v194 -> v195
newMigration(200, "Add table app_state", v1_16.AddTableAppState), NewMigration("Add Branch Protection Unprotected Files Column", v1_16.AddBranchProtectionUnprotectedFilesColumn),
newMigration(201, "Drop table remote_version (if exists)", v1_16.DropTableRemoteVersion), // v195 -> v196
newMigration(202, "Create key/value table for user settings", v1_16.CreateUserSettingsTable), NewMigration("Add table commit_status_index", v1_16.AddTableCommitStatusIndex),
newMigration(203, "Add Sorting to ProjectIssue table", v1_16.AddProjectIssueSorting), // v196 -> v197
newMigration(204, "Add key is verified to ssh key", v1_16.AddSSHKeyIsVerified), NewMigration("Add Color to ProjectBoard table", v1_16.AddColorColToProjectBoard),
newMigration(205, "Migrate to higher varchar on user struct", v1_16.MigrateUserPasswordSalt), // v197 -> v198
newMigration(206, "Add authorize column to team_unit table", v1_16.AddAuthorizeColForTeamUnit), NewMigration("Add renamed_branch table", v1_16.AddRenamedBranchTable),
newMigration(207, "Add webauthn table and migrate u2f data to webauthn - NO-OPED", v1_16.AddWebAuthnCred), // v198 -> v199
newMigration(208, "Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", v1_16.UseBase32HexForCredIDInWebAuthnCredential), NewMigration("Add issue content history table", v1_16.AddTableIssueContentHistory),
newMigration(209, "Increase WebAuthentication CredentialID size to 410 - NO-OPED", v1_16.IncreaseCredentialIDTo410), // v199 -> v200
newMigration(210, "v208 was completely broken - remigrate", v1_16.RemigrateU2FCredentials), NewMigration("No-op (remote version is using AppState now)", noopMigration),
// v200 -> v201
NewMigration("Add table app_state", v1_16.AddTableAppState),
// v201 -> v202
NewMigration("Drop table remote_version (if exists)", v1_16.DropTableRemoteVersion),
// v202 -> v203
NewMigration("Create key/value table for user settings", v1_16.CreateUserSettingsTable),
// v203 -> v204
NewMigration("Add Sorting to ProjectIssue table", v1_16.AddProjectIssueSorting),
// v204 -> v205
NewMigration("Add key is verified to ssh key", v1_16.AddSSHKeyIsVerified),
// v205 -> v206
NewMigration("Migrate to higher varchar on user struct", v1_16.MigrateUserPasswordSalt),
// v206 -> v207
NewMigration("Add authorize column to team_unit table", v1_16.AddAuthorizeColForTeamUnit),
// v207 -> v208
NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", v1_16.AddWebAuthnCred),
// v208 -> v209
NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", v1_16.UseBase32HexForCredIDInWebAuthnCredential),
// v209 -> v210
NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", v1_16.IncreaseCredentialIDTo410),
// v210 -> v211
NewMigration("v208 was completely broken - remigrate", v1_16.RemigrateU2FCredentials),
// Gitea 1.16.2 ends at database version 211 // Gitea 1.16.2 ends at v211
newMigration(211, "Create ForeignReference table", v1_17.CreateForeignReferenceTable), // v211 -> v212
newMigration(212, "Add package tables", v1_17.AddPackageTables), NewMigration("Create ForeignReference table", v1_17.CreateForeignReferenceTable),
newMigration(213, "Add allow edits from maintainers to PullRequest table", v1_17.AddAllowMaintainerEdit), // v212 -> v213
newMigration(214, "Add auto merge table", v1_17.AddAutoMergeTable), NewMigration("Add package tables", v1_17.AddPackageTables),
newMigration(215, "allow to view files in PRs", v1_17.AddReviewViewedFiles), // v213 -> v214
newMigration(216, "No-op (Improve Action table indices v1)", noopMigration), NewMigration("Add allow edits from maintainers to PullRequest table", v1_17.AddAllowMaintainerEdit),
newMigration(217, "Alter hook_task table TEXT fields to LONGTEXT", v1_17.AlterHookTaskTextFieldsToLongText), // v214 -> v215
newMigration(218, "Improve Action table indices v2", v1_17.ImproveActionTableIndices), NewMigration("Add auto merge table", v1_17.AddAutoMergeTable),
newMigration(219, "Add sync_on_commit column to push_mirror table", v1_17.AddSyncOnCommitColForPushMirror), // v215 -> v216
newMigration(220, "Add container repository property", v1_17.AddContainerRepositoryProperty), NewMigration("allow to view files in PRs", v1_17.AddReviewViewedFiles),
newMigration(221, "Store WebAuthentication CredentialID as bytes and increase size to at least 1024", v1_17.StoreWebauthnCredentialIDAsBytes), // v216 -> v217
newMigration(222, "Drop old CredentialID column", v1_17.DropOldCredentialIDColumn), NewMigration("No-op (Improve Action table indices v1)", noopMigration),
newMigration(223, "Rename CredentialIDBytes column to CredentialID", v1_17.RenameCredentialIDBytes), // v217 -> v218
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", v1_17.AlterHookTaskTextFieldsToLongText),
// v218 -> v219
NewMigration("Improve Action table indices v2", v1_17.ImproveActionTableIndices),
// v219 -> v220
NewMigration("Add sync_on_commit column to push_mirror table", v1_17.AddSyncOnCommitColForPushMirror),
// v220 -> v221
NewMigration("Add container repository property", v1_17.AddContainerRepositoryProperty),
// v221 -> v222
NewMigration("Store WebAuthentication CredentialID as bytes and increase size to at least 1024", v1_17.StoreWebauthnCredentialIDAsBytes),
// v222 -> v223
NewMigration("Drop old CredentialID column", v1_17.DropOldCredentialIDColumn),
// v223 -> v224
NewMigration("Rename CredentialIDBytes column to CredentialID", v1_17.RenameCredentialIDBytes),
// Gitea 1.17.0 ends at database version 224 // Gitea 1.17.0 ends at v224
newMigration(224, "Add badges to users", v1_18.CreateUserBadgesTable), // v224 -> v225
newMigration(225, "Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", v1_18.AlterPublicGPGKeyContentFieldsToMediumText), NewMigration("Add badges to users", v1_18.CreateUserBadgesTable),
newMigration(226, "Conan and generic packages do not need to be semantically versioned", v1_18.FixPackageSemverField), // v225 -> v226
newMigration(227, "Create key/value table for system settings", v1_18.CreateSystemSettingsTable), NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", v1_18.AlterPublicGPGKeyContentFieldsToMediumText),
newMigration(228, "Add TeamInvite table", v1_18.AddTeamInviteTable), // v226 -> v227
newMigration(229, "Update counts of all open milestones", v1_18.UpdateOpenMilestoneCounts), NewMigration("Conan and generic packages do not need to be semantically versioned", v1_18.FixPackageSemverField),
newMigration(230, "Add ConfidentialClient column (default true) to OAuth2Application table", v1_18.AddConfidentialClientColumnToOAuth2ApplicationTable), // v227 -> v228
NewMigration("Create key/value table for system settings", v1_18.CreateSystemSettingsTable),
// v228 -> v229
NewMigration("Add TeamInvite table", v1_18.AddTeamInviteTable),
// v229 -> v230
NewMigration("Update counts of all open milestones", v1_18.UpdateOpenMilestoneCounts),
// v230 -> v231
NewMigration("Add ConfidentialClient column (default true) to OAuth2Application table", v1_18.AddConfidentialClientColumnToOAuth2ApplicationTable),
// Gitea 1.18.0 ends at database version 231 // Gitea 1.18.0 ends at v231
newMigration(231, "Add index for hook_task", v1_19.AddIndexForHookTask), // v231 -> v232
newMigration(232, "Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText), NewMigration("Add index for hook_task", v1_19.AddIndexForHookTask),
newMigration(233, "Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook), // v232 -> v233
newMigration(234, "Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable), NewMigration("Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText),
newMigration(235, "Add index for access_token", v1_19.AddIndexForAccessToken), // v233 -> v234
newMigration(236, "Create secrets table", v1_19.CreateSecretsTable), NewMigration("Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook),
newMigration(237, "Drop ForeignReference table", v1_19.DropForeignReferenceTable), // v234 -> v235
newMigration(238, "Add updated unix to LFSMetaObject", v1_19.AddUpdatedUnixToLFSMetaObject), NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable),
newMigration(239, "Add scope for access_token", v1_19.AddScopeForAccessTokens), // v235 -> v236
newMigration(240, "Add actions tables", v1_19.AddActionsTables), NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
newMigration(241, "Add card_type column to project table", v1_19.AddCardTypeToProjectTable), // v236 -> v237
newMigration(242, "Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText), NewMigration("Create secrets table", v1_19.CreateSecretsTable),
newMigration(243, "Add exclusive label", v1_19.AddExclusiveLabel), // v237 -> v238
NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable),
// v238 -> v239
NewMigration("Add updated unix to LFSMetaObject", v1_19.AddUpdatedUnixToLFSMetaObject),
// v239 -> v240
NewMigration("Add scope for access_token", v1_19.AddScopeForAccessTokens),
// v240 -> v241
NewMigration("Add actions tables", v1_19.AddActionsTables),
// v241 -> v242
NewMigration("Add card_type column to project table", v1_19.AddCardTypeToProjectTable),
// v242 -> v243
NewMigration("Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText),
// v243 -> v244
NewMigration("Add exclusive label", v1_19.AddExclusiveLabel),
// Gitea 1.19.0 ends at database version 244 // Gitea 1.19.0 ends at v244
newMigration(244, "Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun), // v244 -> v245
newMigration(245, "Rename Webhook org_id to owner_id", v1_20.RenameWebhookOrgToOwner), NewMigration("Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun),
newMigration(246, "Add missed column owner_id for project table", v1_20.AddNewColumnForProject), // v245 -> v246
newMigration(247, "Fix incorrect project type", v1_20.FixIncorrectProjectType), NewMigration("Rename Webhook org_id to owner_id", v1_20.RenameWebhookOrgToOwner),
newMigration(248, "Add version column to action_runner table", v1_20.AddVersionToActionRunner), // v246 -> v247
newMigration(249, "Improve Action table indices v3", v1_20.ImproveActionTableIndices), NewMigration("Add missed column owner_id for project table", v1_20.AddNewColumnForProject),
newMigration(250, "Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch), // v247 -> v248
newMigration(251, "Fix incorrect owner team unit access mode", v1_20.FixIncorrectOwnerTeamUnitAccessMode), NewMigration("Fix incorrect project type", v1_20.FixIncorrectProjectType),
newMigration(252, "Fix incorrect admin team unit access mode", v1_20.FixIncorrectAdminTeamUnitAccessMode), // v248 -> v249
newMigration(253, "Fix ExternalTracker and ExternalWiki accessMode in owner and admin team", v1_20.FixExternalTrackerAndExternalWikiAccessModeInOwnerAndAdminTeam), NewMigration("Add version column to action_runner table", v1_20.AddVersionToActionRunner),
newMigration(254, "Add ActionTaskOutput table", v1_20.AddActionTaskOutputTable), // v249 -> v250
newMigration(255, "Add ArchivedUnix Column", v1_20.AddArchivedUnixToRepository), NewMigration("Improve Action table indices v3", v1_20.ImproveActionTableIndices),
newMigration(256, "Add is_internal column to package", v1_20.AddIsInternalColumnToPackage), // v250 -> v251
newMigration(257, "Add Actions Artifact table", v1_20.CreateActionArtifactTable), NewMigration("Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch),
newMigration(258, "Add PinOrder Column", v1_20.AddPinOrderToIssue), // v251 -> v252
newMigration(259, "Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), NewMigration("Fix incorrect owner team unit access mode", v1_20.FixIncorrectOwnerTeamUnitAccessMode),
// v252 -> v253
NewMigration("Fix incorrect admin team unit access mode", v1_20.FixIncorrectAdminTeamUnitAccessMode),
// v253 -> v254
NewMigration("Fix ExternalTracker and ExternalWiki accessMode in owner and admin team", v1_20.FixExternalTrackerAndExternalWikiAccessModeInOwnerAndAdminTeam),
// v254 -> v255
NewMigration("Add ActionTaskOutput table", v1_20.AddActionTaskOutputTable),
// v255 -> v256
NewMigration("Add ArchivedUnix Column", v1_20.AddArchivedUnixToRepository),
// v256 -> v257
NewMigration("Add is_internal column to package", v1_20.AddIsInternalColumnToPackage),
// v257 -> v258
NewMigration("Add Actions Artifact table", v1_20.CreateActionArtifactTable),
// v258 -> v259
NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue),
// v259 -> v260
NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens),
// Gitea 1.20.0 ends at database version 260 // Gitea 1.20.0 ends at 260
newMigration(260, "Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), // v260 -> v261
newMigration(261, "Add variable table", v1_21.CreateVariableTable), NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner),
newMigration(262, "Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun), // v261 -> v262
newMigration(263, "Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable), NewMigration("Add variable table", v1_21.CreateVariableTable),
newMigration(264, "Add branch table", v1_21.AddBranchTable), // v262 -> v263
newMigration(265, "Alter Actions Artifact table", v1_21.AlterActionArtifactTable), NewMigration("Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun),
newMigration(266, "Reduce commit status", v1_21.ReduceCommitStatus), // v263 -> v264
newMigration(267, "Add action_tasks_version table", v1_21.CreateActionTasksVersionTable), NewMigration("Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable),
newMigration(268, "Update Action Ref", v1_21.UpdateActionsRefIndex), // v264 -> v265
newMigration(269, "Drop deleted branch table", v1_21.DropDeletedBranchTable), NewMigration("Add branch table", v1_21.AddBranchTable),
newMigration(270, "Fix PackageProperty typo", v1_21.FixPackagePropertyTypo), // v265 -> v266
newMigration(271, "Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable), NewMigration("Alter Actions Artifact table", v1_21.AlterActionArtifactTable),
newMigration(272, "Add Version to ActionRun table", v1_21.AddVersionToActionRunTable), // v266 -> v267
newMigration(273, "Add Action Schedule Table", v1_21.AddActionScheduleTable), NewMigration("Reduce commit status", v1_21.ReduceCommitStatus),
newMigration(274, "Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable), // v267 -> v268
newMigration(275, "Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), NewMigration("Add action_tasks_version table", v1_21.CreateActionTasksVersionTable),
newMigration(276, "Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors), // v268 -> v269
newMigration(277, "Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID), NewMigration("Update Action Ref", v1_21.UpdateActionsRefIndex),
newMigration(278, "Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID), // v269 -> v270
newMigration(279, "Add Index to action.user_id", v1_21.AddIndexToActionUserID), NewMigration("Drop deleted branch table", v1_21.DropDeletedBranchTable),
// v270 -> v271
NewMigration("Fix PackageProperty typo", v1_21.FixPackagePropertyTypo),
// v271 -> v272
NewMigration("Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable),
// v272 -> v273
NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable),
// v273 -> v274
NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable),
// v274 -> v275
NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable),
// v275 -> v276
NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun),
// v276 -> v277
NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors),
// v277 -> v278
NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID),
// v278 -> v279
NewMigration("Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID),
// v279 -> v280
NewMigration("Add Index to action.user_id", v1_21.AddIndexToActionUserID),
// Gitea 1.21.0 ends at database version 280 // Gitea 1.21.0 ends at 280
newMigration(280, "Rename user themes", v1_22.RenameUserThemes), // v280 -> v281
newMigration(281, "Add auth_token table", v1_22.CreateAuthTokenTable), NewMigration("Rename user themes", v1_22.RenameUserThemes),
newMigration(282, "Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID), // v281 -> v282
newMigration(283, "Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser), NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable),
newMigration(284, "Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable), // v282 -> v283
newMigration(285, "Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun), NewMigration("Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID),
newMigration(286, "Add support for SHA256 git repositories", v1_22.AdjustDBForSha256), // v283 -> v284
newMigration(287, "Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges), NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser),
newMigration(288, "Add user_blocking table", v1_22.AddUserBlockingTable), // v284 -> v285
newMigration(289, "Add default_wiki_branch to repository table", v1_22.AddDefaultWikiBranch), NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable),
newMigration(290, "Add PayloadVersion to HookTask", v1_22.AddPayloadVersionToHookTaskTable), // v285 -> v286
newMigration(291, "Add Index to attachment.comment_id", v1_22.AddCommentIDIndexofAttachment), NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun),
newMigration(292, "Ensure every project has exactly one default column - No Op", noopMigration), // v286 -> v287
newMigration(293, "Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256),
// v287 -> v288
NewMigration("Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges),
// v288 -> v289
NewMigration("Add user_blocking table", v1_22.AddUserBlockingTable),
// v289 -> v290
NewMigration("Add default_wiki_branch to repository table", v1_22.AddDefaultWikiBranch),
// v290 -> v291
NewMigration("Add PayloadVersion to HookTask", v1_22.AddPayloadVersionToHookTaskTable),
// v291 -> v292
NewMigration("Add Index to attachment.comment_id", v1_22.AddCommentIDIndexofAttachment),
// v292 -> v293
NewMigration("Ensure every project has exactly one default column - No Op", noopMigration),
// v293 -> v294
NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency),
// Gitea 1.22.0-rc0 ends at database version 294 // Gitea 1.22.0-rc0 ends at 294
newMigration(294, "Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue), // v294 -> v295
newMigration(295, "Add commit status summary table", v1_22.AddCommitStatusSummary), NewMigration("Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue),
newMigration(296, "Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2), // v295 -> v296
newMigration(297, "Add everyone_access_mode for repo_unit", noopMigration), NewMigration("Add commit status summary table", v1_22.AddCommitStatusSummary),
newMigration(298, "Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable), // v296 -> v297
NewMigration("Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2),
// v297 -> v298
NewMigration("Add everyone_access_mode for repo_unit", noopMigration),
// v298 -> v299
NewMigration("Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable),
// Gitea 1.22.0-rc1 ends at migration ID number 298 (database version 299) // Gitea 1.22.0-rc1 ends at 299
newMigration(299, "Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment), // v299 -> v300
newMigration(300, "Add force-push branch protection support", v1_23.AddForcePushBranchProtection), NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment),
newMigration(301, "Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable), // v300 -> v301
newMigration(302, "Add index to action_task stopped log_expired", v1_23.AddIndexToActionTaskStoppedLogExpired), NewMigration("Add force-push branch protection support", v1_23.AddForcePushBranchProtection),
} // v301 -> v302
return preparedMigrations NewMigration("Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable),
// v302 -> v303
NewMigration("Add index to action_task stopped log_expired", v1_23.AddIndexToActionTaskStoppedLogExpired),
} }
// GetCurrentDBVersion returns the current db version // GetCurrentDBVersion returns the current db version
@ -383,20 +618,9 @@ func GetCurrentDBVersion(x *xorm.Engine) (int64, error) {
return currentVersion.Version, nil return currentVersion.Version, nil
} }
func calcDBVersion(migrations []*migration) int64 { // ExpectedVersion returns the expected db version
dbVer := int64(minDBVersion + len(migrations)) func ExpectedVersion() int64 {
if migrations[0].idNumber != minDBVersion { return int64(minDBVersion + len(migrations))
panic("migrations should start at minDBVersion")
}
if dbVer != migrations[len(migrations)-1].idNumber+1 {
panic("migrations are not in order")
}
return dbVer
}
// ExpectedDBVersion returns the expected db version
func ExpectedDBVersion() int64 {
return calcDBVersion(prepareMigrationTasks())
} }
// EnsureUpToDate will check if the db is at the correct version // EnsureUpToDate will check if the db is at the correct version
@ -407,35 +631,24 @@ func EnsureUpToDate(x *xorm.Engine) error {
} }
if currentDB < 0 { if currentDB < 0 {
return fmt.Errorf("database has not been initialized") return fmt.Errorf("Database has not been initialized")
} }
if minDBVersion > currentDB { if minDBVersion > currentDB {
return fmt.Errorf("DB version %d (<= %d) is too old for auto-migration. Upgrade to Gitea 1.6.4 first then upgrade to this version", currentDB, minDBVersion) return fmt.Errorf("DB version %d (<= %d) is too old for auto-migration. Upgrade to Gitea 1.6.4 first then upgrade to this version", currentDB, minDBVersion)
} }
expectedDB := ExpectedDBVersion() expected := ExpectedVersion()
if currentDB != expectedDB { if currentDB != expected {
return fmt.Errorf(`current database version %d is not equal to the expected version %d. Please run "forgejo [--config /path/to/app.ini] migrate" to update the database version`, currentDB, expectedDB) return fmt.Errorf(`Current database version %d is not equal to the expected version %d. Please run "forgejo [--config /path/to/app.ini] migrate" to update the database version`, currentDB, expected)
} }
return forgejo_migrations.EnsureUpToDate(x) return forgejo_migrations.EnsureUpToDate(x)
} }
func getPendingMigrations(curDBVer int64, migrations []*migration) []*migration {
return migrations[curDBVer-minDBVersion:]
}
func migrationIDNumberToDBVersion(idNumber int64) int64 {
return idNumber + 1
}
// Migrate database to current version // Migrate database to current version
func Migrate(x *xorm.Engine) error { func Migrate(x *xorm.Engine) error {
migrations := prepareMigrationTasks()
maxDBVer := calcDBVersion(migrations)
// Set a new clean the default mapper to GonicMapper as that is the default for Gitea. // Set a new clean the default mapper to GonicMapper as that is the default for Gitea.
x.SetMapper(names.GonicMapper{}) x.SetMapper(names.GonicMapper{})
if err := x.Sync(new(Version)); err != nil { if err := x.Sync(new(Version)); err != nil {
@ -448,10 +661,11 @@ func Migrate(x *xorm.Engine) error {
if err != nil { if err != nil {
return fmt.Errorf("get: %w", err) return fmt.Errorf("get: %w", err)
} else if !has { } else if !has {
// If the version record does not exist, it is a fresh installation, and we can skip all migrations. // If the version record does not exist we think
// XORM model framework will create all tables when initializing. // it is a fresh installation and we can skip all migrations.
currentVersion.ID = 0 currentVersion.ID = 0
currentVersion.Version = maxDBVer currentVersion.Version = int64(minDBVersion + len(migrations))
if _, err = x.InsertOne(currentVersion); err != nil { if _, err = x.InsertOne(currentVersion); err != nil {
return fmt.Errorf("insert: %w", err) return fmt.Errorf("insert: %w", err)
} }
@ -459,20 +673,19 @@ func Migrate(x *xorm.Engine) error {
previousVersion = currentVersion.Version previousVersion = currentVersion.Version
} }
curDBVer := currentVersion.Version v := currentVersion.Version
// Outdated Forgejo database version is not supported if minDBVersion > v {
if curDBVer < minDBVersion {
log.Fatal(`Forgejo no longer supports auto-migration from your previously installed version. log.Fatal(`Forgejo no longer supports auto-migration from your previously installed version.
Please try upgrading to a lower version first (suggested v1.6.4), then upgrade to this version.`) Please try upgrading to a lower version first (suggested v1.6.4), then upgrade to this version.`)
return nil return nil
} }
// Downgrading Forgejo's database version not supported // Downgrading Forgejo database version is not supported
if maxDBVer < curDBVer { if int(v-minDBVersion) > len(migrations) {
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Forgejo, you can not use the newer database for this old Forgejo release (%d).", curDBVer, maxDBVer) msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Forgejo, you can not use the newer database for this old Forgejo release (%d).", v, minDBVersion+len(migrations))
msg += "\nForgejo will exit to keep your database safe and unchanged. Please use the correct Forgejo release, do not change the migration version manually (incorrect manual operation may lose data)." msg += "\nForgejo will exit to keep your database safe and unchanged. Please use the correct Forgejo release, do not change the migration version manually (incorrect manual operation may lose data)."
if !setting.IsProd { if !setting.IsProd {
msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", maxDBVer) msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations))
} }
log.Fatal("Migration Error: %s", msg) log.Fatal("Migration Error: %s", msg)
return nil return nil
@ -490,14 +703,14 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
} }
// Migrate // Migrate
for _, m := range getPendingMigrations(curDBVer, migrations) { for i, m := range migrations[v-minDBVersion:] {
log.Info("Migration[%d]: %s", m.idNumber, m.description) log.Info("Migration[%d]: %s", v+int64(i), m.Description())
// Reset the mapper between each migration - migrations are not supposed to depend on each other // Reset the mapper between each migration - migrations are not supposed to depend on each other
x.SetMapper(names.GonicMapper{}) x.SetMapper(names.GonicMapper{})
if err = m.Migrate(x); err != nil { if err = m.Migrate(x); err != nil {
return fmt.Errorf("migration[%d]: %s failed: %w", m.idNumber, m.description, err) return fmt.Errorf("migration[%d]: %s failed: %w", v+int64(i), m.Description(), err)
} }
currentVersion.Version = migrationIDNumberToDBVersion(m.idNumber) currentVersion.Version = v + int64(i) + 1
if _, err = x.ID(1).Update(currentVersion); err != nil { if _, err = x.ID(1).Update(currentVersion); err != nil {
return err return err
} }

View file

@ -1,27 +0,0 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package migrations
import (
"testing"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
func TestMigrations(t *testing.T) {
defer test.MockVariableValue(&preparedMigrations, []*migration{
{idNumber: 70},
{idNumber: 71},
})()
assert.EqualValues(t, 72, calcDBVersion(preparedMigrations))
assert.EqualValues(t, 72, ExpectedDBVersion())
assert.EqualValues(t, 71, migrationIDNumberToDBVersion(70))
assert.EqualValues(t, []*migration{{idNumber: 70}, {idNumber: 71}}, getPendingMigrations(70, preparedMigrations))
assert.EqualValues(t, []*migration{{idNumber: 71}}, getPendingMigrations(71, preparedMigrations))
assert.EqualValues(t, []*migration{}, getPendingMigrations(72, preparedMigrations))
}

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/organization" _ "code.gitea.io/gitea/models/organization"
_ "code.gitea.io/gitea/models/repo" _ "code.gitea.io/gitea/models/repo"
_ "code.gitea.io/gitea/models/user" _ "code.gitea.io/gitea/models/user"

View file

@ -19,7 +19,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View file

@ -16,7 +16,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/repo" _ "code.gitea.io/gitea/models/repo"
_ "code.gitea.io/gitea/models/user" _ "code.gitea.io/gitea/models/user"
) )

View file

@ -5,6 +5,7 @@ package project
import ( import (
"fmt" "fmt"
"strings"
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -123,5 +124,5 @@ func Test_NewColumn(t *testing.T) {
ProjectID: project1.ID, ProjectID: project1.ID,
}) })
require.Error(t, err) require.Error(t, err)
assert.Contains(t, err.Error(), "maximum number of columns reached") assert.True(t, strings.Contains(err.Error(), "maximum number of columns reached"))
} }

View file

@ -1,30 +0,0 @@
-
id: 1001
owner_id: 33
owner_name: user33
lower_name: repo1001
name: repo1001
default_branch: main
num_watches: 0
num_stars: 0
num_forks: 0
num_issues: 0
num_closed_issues: 0
num_pulls: 0
num_closed_pulls: 0
num_milestones: 0
num_closed_milestones: 0
num_projects: 0
num_closed_projects: 0
is_private: false
is_empty: false
is_archived: false
is_mirror: false
status: 0
is_fork: false
fork_id: 0
is_template: false
template_id: 0
size: 0
is_fsck_enabled: true
close_issues_via_commit_in_any_branch: false

View file

@ -7,7 +7,6 @@ import (
"context" "context"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder" "xorm.io/builder"
@ -55,9 +54,9 @@ func GetUserFork(ctx context.Context, repoID, userID int64) (*Repository, error)
return &forkedRepo, nil return &forkedRepo, nil
} }
// GetForks returns all the forks of the repository that are visible to the user. // GetForks returns all the forks of the repository
func GetForks(ctx context.Context, repo *Repository, user *user_model.User, listOptions db.ListOptions) ([]*Repository, int64, error) { func GetForks(ctx context.Context, repo *Repository, listOptions db.ListOptions) ([]*Repository, error) {
sess := db.GetEngine(ctx).Where(AccessibleRepositoryCondition(user, unit.TypeInvalid)) sess := db.GetEngine(ctx)
var forks []*Repository var forks []*Repository
if listOptions.Page == 0 { if listOptions.Page == 0 {
@ -67,8 +66,7 @@ func GetForks(ctx context.Context, repo *Repository, user *user_model.User, list
sess = db.SetSessionPagination(sess, &listOptions) sess = db.SetSessionPagination(sess, &listOptions)
} }
count, err := sess.FindAndCount(&forks, &Repository{ForkID: repo.ID}) return forks, sess.Find(&forks, &Repository{ForkID: repo.ID})
return forks, count, err
} }
// IncrementRepoForkNum increment repository fork number // IncrementRepoForkNum increment repository fork number

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" // register table model _ "code.gitea.io/gitea/models" // register table model
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/perm/access" // register table model _ "code.gitea.io/gitea/models/perm/access" // register table model
_ "code.gitea.io/gitea/models/repo" // register table model _ "code.gitea.io/gitea/models/repo" // register table model
_ "code.gitea.io/gitea/models/user" // register table model _ "code.gitea.io/gitea/models/user" // register table model

View file

@ -249,7 +249,6 @@ type FindReleasesOptions struct {
IsDraft optional.Option[bool] IsDraft optional.Option[bool]
TagNames []string TagNames []string
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
Keyword string
} }
func (opts FindReleasesOptions) ToConds() builder.Cond { func (opts FindReleasesOptions) ToConds() builder.Cond {
@ -277,15 +276,6 @@ func (opts FindReleasesOptions) ToConds() builder.Cond {
cond = cond.And(builder.Eq{"sha1": ""}) cond = cond.And(builder.Eq{"sha1": ""})
} }
} }
if opts.Keyword != "" {
keywordCond := builder.NewCond()
keywordCond = keywordCond.Or(builder.Like{"lower_tag_name", strings.ToLower(opts.Keyword)})
keywordCond = keywordCond.Or(db.BuildCaseInsensitiveLike("title", opts.Keyword))
keywordCond = keywordCond.Or(db.BuildCaseInsensitiveLike("note", opts.Keyword))
cond = cond.And(keywordCond)
}
return cond return cond
} }

View file

@ -641,9 +641,12 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu
// 1. Be able to see all non-private repositories that either: // 1. Be able to see all non-private repositories that either:
cond = cond.Or(builder.And( cond = cond.Or(builder.And(
builder.Eq{"`repository`.is_private": false}, builder.Eq{"`repository`.is_private": false},
// 2. Aren't in an private organisation/user or limited organisation/user if the doer is not logged in. // 2. Aren't in an private organisation or limited organisation if we're not logged in
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where( builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(
builder.In("visibility", orgVisibilityLimit))))) builder.And(
builder.Eq{"type": user_model.UserTypeOrganization},
builder.In("visibility", orgVisibilityLimit)),
))))
} }
if user != nil { if user != nil {

View file

@ -4,18 +4,13 @@
package repo_test package repo_test
import ( import (
"path/filepath"
"slices"
"strings" "strings"
"testing" "testing"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -408,43 +403,3 @@ func TestSearchRepositoryByTopicName(t *testing.T) {
}) })
} }
} }
func TestSearchRepositoryIDsByCondition(t *testing.T) {
defer unittest.OverrideFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(setting.AppWorkPath, "models/fixtures/"),
Base: setting.AppWorkPath,
Dirs: []string{"models/repo/TestSearchRepositoryIDsByCondition/"},
},
)()
require.NoError(t, unittest.PrepareTestDatabase())
// Sanity check of the database
limitedUser := unittest.AssertExistsAndLoadBean(t, &user.User{ID: 33, Visibility: structs.VisibleTypeLimited})
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1001, OwnerID: limitedUser.ID})
testCases := []struct {
user *user.User
repoIDs []int64
}{
{
user: nil,
repoIDs: []int64{1, 4, 8, 9, 10, 11, 12, 14, 17, 18, 21, 23, 25, 27, 29, 32, 33, 34, 35, 36, 37, 42, 44, 45, 46, 47, 48, 49, 50, 51, 53, 57, 58, 60, 61, 62, 1059},
},
{
user: unittest.AssertExistsAndLoadBean(t, &user.User{ID: 4}),
repoIDs: []int64{1, 3, 4, 8, 9, 10, 11, 12, 14, 17, 18, 21, 23, 25, 27, 29, 32, 33, 34, 35, 36, 37, 38, 40, 42, 44, 45, 46, 47, 48, 49, 50, 51, 53, 57, 58, 60, 61, 62, 1001, 1059},
},
{
user: unittest.AssertExistsAndLoadBean(t, &user.User{ID: 5}),
repoIDs: []int64{1, 4, 8, 9, 10, 11, 12, 14, 17, 18, 21, 23, 25, 27, 29, 32, 33, 34, 35, 36, 37, 38, 40, 42, 44, 45, 46, 47, 48, 49, 50, 51, 53, 57, 58, 60, 61, 62, 1001, 1059},
},
}
for _, testCase := range testCases {
repoIDs, err := repo_model.FindUserCodeAccessibleRepoIDs(db.DefaultContext, testCase.user)
require.NoError(t, err)
slices.Sort(repoIDs)
assert.EqualValues(t, testCase.repoIDs, repoIDs)
}
}

View file

@ -75,10 +75,6 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
return nil, err return nil, err
} }
uniqueUserIDs := make(container.Set[int64])
uniqueUserIDs.AddMultiple(userIDs...)
if repo.Owner.IsOrganization() {
additionalUserIDs := make([]int64, 0, 10) additionalUserIDs := make([]int64, 0, 10)
if err = e.Table("team_user"). if err = e.Table("team_user").
Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id").
@ -90,13 +86,15 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
Find(&additionalUserIDs); err != nil { Find(&additionalUserIDs); err != nil {
return nil, err return nil, err
} }
uniqueUserIDs := make(container.Set[int64])
uniqueUserIDs.AddMultiple(userIDs...)
uniqueUserIDs.AddMultiple(additionalUserIDs...) uniqueUserIDs.AddMultiple(additionalUserIDs...)
}
// Leave a seat for owner itself to append later, but if owner is an organization // Leave a seat for owner itself to append later, but if owner is an organization
// and just waste 1 unit is cheaper than re-allocate memory once. // and just waste 1 unit is cheaper than re-allocate memory once.
users := make([]*user_model.User, 0, len(uniqueUserIDs)+1) users := make([]*user_model.User, 0, len(uniqueUserIDs)+1)
if len(uniqueUserIDs) > 0 { if len(userIDs) > 0 {
if err = e.In("id", uniqueUserIDs.Values()). if err = e.In("id", uniqueUserIDs.Values()).
Where(builder.Eq{"`user`.is_active": true}). Where(builder.Eq{"`user`.is_active": true}).
OrderBy(user_model.GetOrderByName()). OrderBy(user_model.GetOrderByName()).

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" // register models _ "code.gitea.io/gitea/models" // register models
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
_ "code.gitea.io/gitea/models/system" // register models of system _ "code.gitea.io/gitea/models/system" // register models of system
) )

View file

@ -4,12 +4,99 @@
package unittest package unittest
import ( import (
"errors"
"io"
"os" "os"
"path"
"strings"
"code.gitea.io/gitea/modules/util"
) )
// Copy copies file from source to target path.
func Copy(src, dest string) error {
// Gather file information to set back later.
si, err := os.Lstat(src)
if err != nil {
return err
}
// Handle symbolic link.
if si.Mode()&os.ModeSymlink != 0 {
target, err := os.Readlink(src)
if err != nil {
return err
}
// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
// which will lead "no such file or directory" error.
return os.Symlink(target, dest)
}
sr, err := os.Open(src)
if err != nil {
return err
}
defer sr.Close()
dw, err := os.Create(dest)
if err != nil {
return err
}
defer dw.Close()
if _, err = io.Copy(dw, sr); err != nil {
return err
}
// Set back file information.
if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
return err
}
return os.Chmod(dest, si.Mode())
}
// CopyDir copy files recursively from source to target directory. // CopyDir copy files recursively from source to target directory.
// //
// The filter accepts a function that process the path info.
// and should return true for need to filter.
//
// It returns error when error occurs in underlying functions. // It returns error when error occurs in underlying functions.
func CopyDir(srcPath, destPath string) error { func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {
return os.CopyFS(destPath, os.DirFS(srcPath)) // Check if target directory exists.
if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) {
return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath)
}
err := os.MkdirAll(destPath, os.ModePerm)
if err != nil {
return err
}
// Gather directory info.
infos, err := util.StatDir(srcPath, true)
if err != nil {
return err
}
var filter func(filePath string) bool
if len(filters) > 0 {
filter = filters[0]
}
for _, info := range infos {
if filter != nil && filter(info) {
continue
}
curPath := path.Join(destPath, info)
if strings.HasSuffix(info, "/") {
err = os.MkdirAll(curPath, os.ModePerm)
} else {
err = Copy(path.Join(srcPath, info), curPath)
}
if err != nil {
return err
}
}
return nil
} }

View file

@ -33,11 +33,6 @@ func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveM
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := NormalizedFullPath(r.URL) path := NormalizedFullPath(r.URL)
isGh := liveServerBaseURL == "https://api.github.com"
if isGh {
// Workaround for GitHub: trim `/api/v3` from the path
path = strings.TrimPrefix(path, "/api/v3")
}
log.Info("Mock HTTP Server: got request for path %s", r.URL.Path) log.Info("Mock HTTP Server: got request for path %s", r.URL.Path)
// TODO check request method (support POST?) // TODO check request method (support POST?)
fixturePath := fmt.Sprintf("%s/%s_%s", testDataDir, r.Method, url.PathEscape(path)) fixturePath := fmt.Sprintf("%s/%s_%s", testDataDir, r.Method, url.PathEscape(path))
@ -91,10 +86,6 @@ func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveM
// replace any mention of the live HTTP service by the mocked host // replace any mention of the live HTTP service by the mocked host
stringFixture := strings.ReplaceAll(string(fixture), liveServerBaseURL, mockServerBaseURL) stringFixture := strings.ReplaceAll(string(fixture), liveServerBaseURL, mockServerBaseURL)
if isGh {
// Workaround for GitHub: replace github.com by the mock server's base URL
stringFixture = strings.ReplaceAll(stringFixture, "https://github.com", mockServerBaseURL)
}
// parse back the fixture file into a series of HTTP headers followed by response body // parse back the fixture file into a series of HTTP headers followed by response body
lines := strings.Split(stringFixture, "\n") lines := strings.Split(stringFixture, "\n")
for idx, line := range lines { for idx, line := range lines {

View file

@ -8,8 +8,10 @@ import (
"context" "context"
"fmt" "fmt"
"strings" "strings"
"time"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -244,6 +246,23 @@ func updateActivation(ctx context.Context, email *EmailAddress, activate bool) e
return UpdateUserCols(ctx, user, "rands") return UpdateUserCols(ctx, user, "rands")
} }
// VerifyActiveEmailCode verifies active email code when active account
func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress {
if user := GetVerifyUser(ctx, code); user != nil {
// time limit code
prefix := code[:base.TimeLimitCodeLength]
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
emailAddress := &EmailAddress{UID: user.ID, Email: email}
if has, _ := db.GetEngine(ctx).Get(emailAddress); has {
return emailAddress
}
}
}
return nil
}
// SearchEmailOrderBy is used to sort the results from SearchEmails() // SearchEmailOrderBy is used to sort the results from SearchEmails()
type SearchEmailOrderBy string type SearchEmailOrderBy string

View file

@ -7,9 +7,7 @@ package user
import ( import (
"context" "context"
"crypto/subtle"
"encoding/hex" "encoding/hex"
"errors"
"fmt" "fmt"
"net/mail" "net/mail"
"net/url" "net/url"
@ -320,14 +318,15 @@ func (u *User) OrganisationLink() string {
return setting.AppSubURL + "/org/" + url.PathEscape(u.Name) return setting.AppSubURL + "/org/" + url.PathEscape(u.Name)
} }
// GenerateEmailAuthorizationCode generates an activation code based for the user for the specified purpose. // GenerateEmailActivateCode generates an activate code based on user information and given e-mail.
// The standard expiry is ActiveCodeLives minutes. func (u *User) GenerateEmailActivateCode(email string) string {
func (u *User) GenerateEmailAuthorizationCode(ctx context.Context, purpose auth.AuthorizationPurpose) (string, error) { code := base.CreateTimeLimitCode(
lookup, validator, err := auth.GenerateAuthToken(ctx, u.ID, timeutil.TimeStampNow().Add(int64(setting.Service.ActiveCodeLives)*60), purpose) fmt.Sprintf("%d%s%s%s%s", u.ID, email, u.LowerName, u.Passwd, u.Rands),
if err != nil { setting.Service.ActiveCodeLives, time.Now(), nil)
return "", err
} // Add tail hex username
return lookup + ":" + validator, nil code += hex.EncodeToString([]byte(u.LowerName))
return code
} }
// GetUserFollowers returns range of user's followers. // GetUserFollowers returns range of user's followers.
@ -839,50 +838,35 @@ func countUsers(ctx context.Context, opts *CountUserFilter) int64 {
return count return count
} }
// VerifyUserActiveCode verifies that the code is valid for the given purpose for this user. // GetVerifyUser get user by verify code
// If delete is specified, the token will be deleted. func GetVerifyUser(ctx context.Context, code string) (user *User) {
func VerifyUserAuthorizationToken(ctx context.Context, code string, purpose auth.AuthorizationPurpose, delete bool) (*User, error) { if len(code) <= base.TimeLimitCodeLength {
lookupKey, validator, found := strings.Cut(code, ":") return nil
if !found {
return nil, nil
} }
authToken, err := auth.FindAuthToken(ctx, lookupKey, purpose) // use tail hex username query user
if err != nil { hexStr := code[base.TimeLimitCodeLength:]
if errors.Is(err, util.ErrNotExist) { if b, err := hex.DecodeString(hexStr); err == nil {
return nil, nil if user, err = GetUserByName(ctx, string(b)); user != nil {
return user
} }
return nil, err log.Error("user.getVerifyUser: %v", err)
} }
if authToken.IsExpired() { return nil
return nil, auth.DeleteAuthToken(ctx, authToken)
} }
rawValidator, err := hex.DecodeString(validator) // VerifyUserActiveCode verifies active code when active account
if err != nil { func VerifyUserActiveCode(ctx context.Context, code string) (user *User) {
return nil, err if user = GetVerifyUser(ctx, code); user != nil {
} // time limit code
prefix := code[:base.TimeLimitCodeLength]
if subtle.ConstantTimeCompare([]byte(authToken.HashedValidator), []byte(auth.HashValidator(rawValidator))) == 0 { data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands)
return nil, errors.New("validator doesn't match") if base.VerifyTimeLimitCode(time.Now(), data, setting.Service.ActiveCodeLives, prefix) {
} return user
u, err := GetUserByID(ctx, authToken.UID)
if err != nil {
if IsErrUserNotExist(err) {
return nil, nil
}
return nil, err
}
if delete {
if err := auth.DeleteAuthToken(ctx, authToken); err != nil {
return nil, err
} }
} }
return nil
return u, nil
} }
// ValidateUser check if user is valid to insert / update into database // ValidateUser check if user is valid to insert / update into database

View file

@ -7,7 +7,6 @@ package user_test
import ( import (
"context" "context"
"crypto/rand" "crypto/rand"
"encoding/hex"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@ -22,9 +21,7 @@ import (
"code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/tests" "code.gitea.io/gitea/tests"
@ -703,66 +700,3 @@ func TestDisabledUserFeatures(t *testing.T) {
assert.True(t, user_model.IsFeatureDisabledWithLoginType(user, f)) assert.True(t, user_model.IsFeatureDisabledWithLoginType(user, f))
} }
} }
func TestGenerateEmailAuthorizationCode(t *testing.T) {
defer test.MockVariableValue(&setting.Service.ActiveCodeLives, 2)()
require.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
code, err := user.GenerateEmailAuthorizationCode(db.DefaultContext, auth.UserActivation)
require.NoError(t, err)
lookupKey, validator, ok := strings.Cut(code, ":")
assert.True(t, ok)
rawValidator, err := hex.DecodeString(validator)
require.NoError(t, err)
authToken, err := auth.FindAuthToken(db.DefaultContext, lookupKey, auth.UserActivation)
require.NoError(t, err)
assert.False(t, authToken.IsExpired())
assert.EqualValues(t, authToken.HashedValidator, auth.HashValidator(rawValidator))
authToken.Expiry = authToken.Expiry.Add(-int64(setting.Service.ActiveCodeLives) * 60)
assert.True(t, authToken.IsExpired())
}
func TestVerifyUserAuthorizationToken(t *testing.T) {
defer test.MockVariableValue(&setting.Service.ActiveCodeLives, 2)()
require.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
code, err := user.GenerateEmailAuthorizationCode(db.DefaultContext, auth.UserActivation)
require.NoError(t, err)
lookupKey, _, ok := strings.Cut(code, ":")
assert.True(t, ok)
t.Run("Wrong purpose", func(t *testing.T) {
u, err := user_model.VerifyUserAuthorizationToken(db.DefaultContext, code, auth.PasswordReset, false)
require.NoError(t, err)
assert.Nil(t, u)
})
t.Run("No delete", func(t *testing.T) {
u, err := user_model.VerifyUserAuthorizationToken(db.DefaultContext, code, auth.UserActivation, false)
require.NoError(t, err)
assert.EqualValues(t, user.ID, u.ID)
authToken, err := auth.FindAuthToken(db.DefaultContext, lookupKey, auth.UserActivation)
require.NoError(t, err)
assert.NotNil(t, authToken)
})
t.Run("Delete", func(t *testing.T) {
u, err := user_model.VerifyUserAuthorizationToken(db.DefaultContext, code, auth.UserActivation, true)
require.NoError(t, err)
assert.EqualValues(t, user.ID, u.ID)
authToken, err := auth.FindAuthToken(db.DefaultContext, lookupKey, auth.UserActivation)
require.ErrorIs(t, err, util.ErrNotExist)
assert.Nil(t, authToken)
})
}

View file

@ -9,6 +9,7 @@ import (
"io" "io"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"regexp"
"testing" "testing"
"time" "time"
@ -118,7 +119,7 @@ func TestActivityPubSignedPost(t *testing.T) {
expected := "BODY" expected := "BODY"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Regexp(t, "^"+setting.Federation.DigestAlgorithm, r.Header.Get("Digest")) assert.Regexp(t, regexp.MustCompile("^"+setting.Federation.DigestAlgorithm), r.Header.Get("Digest"))
assert.Contains(t, r.Header.Get("Signature"), pubID) assert.Contains(t, r.Header.Get("Signature"), pubID)
assert.Equal(t, ActivityStreamsContentType, r.Header.Get("Content-Type")) assert.Equal(t, ActivityStreamsContentType, r.Header.Get("Content-Type"))
body, err := io.ReadAll(r.Body) body, err := io.ReadAll(r.Body)

View file

@ -11,7 +11,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {

View file

@ -4,20 +4,26 @@
package base package base
import ( import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256" "crypto/sha256"
"crypto/subtle"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"time"
"unicode/utf8" "unicode/utf8"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
) )
@ -48,6 +54,66 @@ func BasicAuthDecode(encoded string) (string, string, error) {
return "", "", errors.New("invalid basic authentication") return "", "", errors.New("invalid basic authentication")
} }
// VerifyTimeLimitCode verify time limit code
func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) bool {
if len(code) <= 18 {
return false
}
startTimeStr := code[:12]
aliveTimeStr := code[12:18]
aliveTime, _ := strconv.Atoi(aliveTimeStr) // no need to check err, if anything wrong, the following code check will fail soon
// check code
retCode := CreateTimeLimitCode(data, aliveTime, startTimeStr, nil)
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
retCode = CreateTimeLimitCode(data, aliveTime, startTimeStr, sha1.New()) // TODO: this is only for the support of legacy codes, remove this in/after 1.23
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
return false
}
}
// check time is expired or not: startTime <= now && now < startTime + minutes
startTime, _ := time.ParseInLocation("200601021504", startTimeStr, time.Local)
return (startTime.Before(now) || startTime.Equal(now)) && now.Before(startTime.Add(time.Minute*time.Duration(minutes)))
}
// TimeLimitCodeLength default value for time limit code
const TimeLimitCodeLength = 12 + 6 + 40
// CreateTimeLimitCode create a time-limited code.
// Format: 12 length date time string + 6 minutes string (not used) + 40 hash string, some other code depends on this fixed length
// If h is nil, then use the default hmac hash.
func CreateTimeLimitCode[T time.Time | string](data string, minutes int, startTimeGeneric T, h hash.Hash) string {
const format = "200601021504"
var start time.Time
var startTimeAny any = startTimeGeneric
if t, ok := startTimeAny.(time.Time); ok {
start = t
} else {
var err error
start, err = time.ParseInLocation(format, startTimeAny.(string), time.Local)
if err != nil {
return "" // return an invalid code because the "parse" failed
}
}
startStr := start.Format(format)
end := start.Add(time.Minute * time.Duration(minutes))
if h == nil {
h = hmac.New(sha1.New, setting.GetGeneralTokenSigningSecret())
}
_, _ = fmt.Fprintf(h, "%s%s%s%s%d", data, hex.EncodeToString(setting.GetGeneralTokenSigningSecret()), startStr, end.Format(format), minutes)
encoded := hex.EncodeToString(h.Sum(nil))
code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)
if len(code) != TimeLimitCodeLength {
panic("there is a hard requirement for the length of time-limited code") // it shouldn't happen
}
return code
}
// FileSize calculates the file size and generate user-friendly string. // FileSize calculates the file size and generate user-friendly string.
func FileSize(s int64) string { func FileSize(s int64) string {
return humanize.IBytes(uint64(s)) return humanize.IBytes(uint64(s))

View file

@ -4,7 +4,13 @@
package base package base
import ( import (
"crypto/sha1"
"fmt"
"testing" "testing"
"time"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -40,6 +46,57 @@ func TestBasicAuthDecode(t *testing.T) {
require.Error(t, err) require.Error(t, err)
} }
func TestVerifyTimeLimitCode(t *testing.T) {
defer test.MockVariableValue(&setting.InstallLock, true)()
initGeneralSecret := func(secret string) {
setting.InstallLock = true
setting.CfgProvider, _ = setting.NewConfigProviderFromData(fmt.Sprintf(`
[oauth2]
JWT_SECRET = %s
`, secret))
setting.LoadCommonSettings()
}
initGeneralSecret("KZb_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
now := time.Now()
t.Run("TestGenericParameter", func(t *testing.T) {
time2000 := time.Date(2000, 1, 2, 3, 4, 5, 0, time.Local)
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, time2000, sha1.New()))
assert.Equal(t, "2000010203040000026fa5221b2731b7cf80b1b506f5e39e38c115fee5", CreateTimeLimitCode("test-sha1", 2, "200001020304", sha1.New()))
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, time2000, nil))
assert.Equal(t, "2000010203040000024842227a2f87041ff82025199c0187410a9297bf", CreateTimeLimitCode("test-hmac", 2, "200001020304", nil))
})
t.Run("TestInvalidCode", func(t *testing.T) {
assert.False(t, VerifyTimeLimitCode(now, "data", 2, ""))
assert.False(t, VerifyTimeLimitCode(now, "data", 2, "invalid code"))
})
t.Run("TestCreateAndVerify", func(t *testing.T) {
code := CreateTimeLimitCode("data", 2, now, nil)
assert.False(t, VerifyTimeLimitCode(now.Add(-time.Minute), "data", 2, code)) // not started yet
assert.True(t, VerifyTimeLimitCode(now, "data", 2, code))
assert.True(t, VerifyTimeLimitCode(now.Add(time.Minute), "data", 2, code))
assert.False(t, VerifyTimeLimitCode(now.Add(time.Minute), "DATA", 2, code)) // invalid data
assert.False(t, VerifyTimeLimitCode(now.Add(2*time.Minute), "data", 2, code)) // expired
})
t.Run("TestDifferentSecret", func(t *testing.T) {
// use another secret to ensure the code is invalid for different secret
verifyDataCode := func(c string) bool {
return VerifyTimeLimitCode(now, "data", 2, c)
}
code1 := CreateTimeLimitCode("data", 2, now, sha1.New())
code2 := CreateTimeLimitCode("data", 2, now, nil)
assert.True(t, verifyDataCode(code1))
assert.True(t, verifyDataCode(code2))
initGeneralSecret("000_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
assert.False(t, verifyDataCode(code1))
assert.False(t, verifyDataCode(code2))
})
}
func TestFileSize(t *testing.T) { func TestFileSize(t *testing.T) {
var size int64 = 512 var size int64 = 512
assert.Equal(t, "512 B", FileSize(size)) assert.Equal(t, "512 B", FileSize(size))

View file

@ -41,12 +41,14 @@ func TestMaybeRemoveBOM(t *testing.T) {
func TestToUTF8(t *testing.T) { func TestToUTF8(t *testing.T) {
resetDefaultCharsetsOrder() resetDefaultCharsetsOrder()
var res string
var err error
// Note: golang compiler seems so behave differently depending on the current // Note: golang compiler seems so behave differently depending on the current
// locale, so some conversions might behave differently. For that reason, we don't // locale, so some conversions might behave differently. For that reason, we don't
// depend on particular conversions but in expected behaviors. // depend on particular conversions but in expected behaviors.
res, err := ToUTF8([]byte{0x41, 0x42, 0x43}, ConvertOpts{}) res, err = ToUTF8([]byte{0x41, 0x42, 0x43}, ConvertOpts{})
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "ABC", res) assert.Equal(t, "ABC", res)

View file

@ -4,14 +4,28 @@
package git package git
import ( import (
"context"
"errors"
"fmt" "fmt"
"strings" "strings"
"time"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
) )
// ErrExecTimeout error when exec timed out
type ErrExecTimeout struct {
Duration time.Duration
}
// IsErrExecTimeout if some error is ErrExecTimeout
func IsErrExecTimeout(err error) bool {
_, ok := err.(ErrExecTimeout)
return ok
}
func (err ErrExecTimeout) Error() string {
return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration)
}
// ErrNotExist commit not exist error // ErrNotExist commit not exist error
type ErrNotExist struct { type ErrNotExist struct {
ID string ID string
@ -48,6 +62,21 @@ func IsErrBadLink(err error) bool {
return ok return ok
} }
// ErrUnsupportedVersion error when required git version not matched
type ErrUnsupportedVersion struct {
Required string
}
// IsErrUnsupportedVersion if some error is ErrUnsupportedVersion
func IsErrUnsupportedVersion(err error) bool {
_, ok := err.(ErrUnsupportedVersion)
return ok
}
func (err ErrUnsupportedVersion) Error() string {
return fmt.Sprintf("Operation requires higher version [required: %s]", err.Required)
}
// ErrBranchNotExist represents a "BranchNotExist" kind of error. // ErrBranchNotExist represents a "BranchNotExist" kind of error.
type ErrBranchNotExist struct { type ErrBranchNotExist struct {
Name string Name string
@ -156,10 +185,3 @@ func IsErrMoreThanOne(err error) bool {
func (err *ErrMoreThanOne) Error() string { func (err *ErrMoreThanOne) Error() string {
return fmt.Sprintf("ErrMoreThanOne Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut) return fmt.Sprintf("ErrMoreThanOne Error: %v: %s\n%s", err.Err, err.StdErr, err.StdOut)
} }
func IsErrCanceledOrKilled(err error) bool {
// When "cancel()" a git command's context, the returned error of "Run()" could be one of them:
// - context.Canceled
// - *exec.ExitError: "signal: killed"
return err != nil && (errors.Is(err, context.Canceled) || err.Error() == "signal: killed")
}

View file

@ -17,7 +17,6 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
) )
@ -39,7 +38,7 @@ const (
type GrepOptions struct { type GrepOptions struct {
RefName string RefName string
MaxResultLimit int MaxResultLimit int
MatchesPerFile int // >= git 2.38 MatchesPerFile int
ContextLineNumber int ContextLineNumber int
Mode grepMode Mode grepMode
PathSpec []setting.Glob PathSpec []setting.Glob
@ -93,16 +92,8 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
} else { } else {
cmd.AddArguments("--fixed-strings", "--column") cmd.AddArguments("--fixed-strings", "--column")
} }
cmd.AddOptionValues("--context", fmt.Sprint(opts.ContextLineNumber)) cmd.AddOptionValues("--context", fmt.Sprint(opts.ContextLineNumber))
// --max-count requires at least git 2.38
if CheckGitVersionAtLeast("2.38.0") == nil {
cmd.AddOptionValues("--max-count", fmt.Sprint(opts.MatchesPerFile)) cmd.AddOptionValues("--max-count", fmt.Sprint(opts.MatchesPerFile))
} else {
log.Warn("git-grep: --max-count requires at least git 2.38")
}
words := []string{search} words := []string{search}
if opts.Mode == FixedAnyGrepMode { if opts.Mode == FixedAnyGrepMode {
words = strings.Fields(search) words = strings.Fields(search)

View file

@ -250,7 +250,7 @@ func (repo *Repository) GitAttributeChecker(treeish string, attributes ...string
err = e err = e
} }
if err != nil && !IsErrCanceledOrKilled(err) { // decorate the returned error if err != nil { // decorate the returned error
err = fmt.Errorf("git check-attr (stderr: %q): %w", strings.TrimSpace(stdErr.String()), err) err = fmt.Errorf("git check-attr (stderr: %q): %w", strings.TrimSpace(stdErr.String()), err)
ac.err.Store(err) ac.err.Store(err)
} }

View file

@ -50,35 +50,25 @@ func (repo *Repository) readTreeToIndex(id ObjectID, indexFilename ...string) er
} }
// ReadTreeToTemporaryIndex reads a treeish to a temporary index file // ReadTreeToTemporaryIndex reads a treeish to a temporary index file
func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (tmpIndexFilename, tmpDir string, cancel context.CancelFunc, err error) { func (repo *Repository) ReadTreeToTemporaryIndex(treeish string) (filename, tmpDir string, cancel context.CancelFunc, err error) {
defer func() {
// if error happens and there is a cancel function, do clean up
if err != nil && cancel != nil {
cancel()
cancel = nil
}
}()
removeDirFn := func(dir string) func() { // it can't use the return value "tmpDir" directly because it is empty when error occurs
return func() {
if err := util.RemoveAll(dir); err != nil {
log.Error("failed to remove tmp index dir: %v", err)
}
}
}
tmpDir, err = os.MkdirTemp("", "index") tmpDir, err = os.MkdirTemp("", "index")
if err != nil { if err != nil {
return "", "", nil, err return filename, tmpDir, cancel, err
} }
tmpIndexFilename = filepath.Join(tmpDir, ".tmp-index") filename = filepath.Join(tmpDir, ".tmp-index")
cancel = removeDirFn(tmpDir) cancel = func() {
err = repo.ReadTreeToIndex(treeish, tmpIndexFilename) err := util.RemoveAll(tmpDir)
if err != nil { if err != nil {
return "", "", cancel, err log.Error("failed to remove tmp index file: %v", err)
} }
return tmpIndexFilename, tmpDir, cancel, err }
err = repo.ReadTreeToIndex(treeish, filename)
if err != nil {
defer cancel()
return "", "", func() {}, err
}
return filename, tmpDir, cancel, err
} }
// EmptyIndex empties the index // EmptyIndex empties the index

View file

@ -16,7 +16,7 @@ import (
// GetCommitGraph return a list of commit (GraphItems) from all branches // GetCommitGraph return a list of commit (GraphItems) from all branches
func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) { func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bool, branches, files []string) (*Graph, error) {
format := "DATA:%D|%H|%aD|%h|%s" format := "DATA:%D|%H|%ad|%h|%s"
if page == 0 { if page == 0 {
page = 1 page = 1

View file

@ -8,7 +8,6 @@ import (
"context" "context"
"fmt" "fmt"
"strings" "strings"
"time"
asymkey_model "code.gitea.io/gitea/models/asymkey" asymkey_model "code.gitea.io/gitea/models/asymkey"
"code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/db"
@ -199,11 +198,6 @@ func NewCommit(row, column int, line []byte) (*Commit, error) {
if len(data) < 5 { if len(data) < 5 {
return nil, fmt.Errorf("malformed data section on line %d with commit: %s", row, string(line)) return nil, fmt.Errorf("malformed data section on line %d with commit: %s", row, string(line))
} }
// Format is a slight modifcation from RFC1123Z
t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 -0700", string(data[2]))
if err != nil {
return nil, fmt.Errorf("could not parse date of commit: %w", err)
}
return &Commit{ return &Commit{
Row: row, Row: row,
Column: column, Column: column,
@ -211,8 +205,8 @@ func NewCommit(row, column int, line []byte) (*Commit, error) {
Refs: newRefsFromRefNames(data[0]), Refs: newRefsFromRefNames(data[0]),
// 1 matches git log --pretty=format:%H => commit hash // 1 matches git log --pretty=format:%H => commit hash
Rev: string(data[1]), Rev: string(data[1]),
// 2 matches git log --pretty=format:%aD => author date, RFC2822 style // 2 matches git log --pretty=format:%ad => author date (format respects --date= option)
Date: t, Date: string(data[2]),
// 3 matches git log --pretty=format:%h => abbreviated commit hash // 3 matches git log --pretty=format:%h => abbreviated commit hash
ShortRev: string(data[3]), ShortRev: string(data[3]),
// 4 matches git log --pretty=format:%s => subject // 4 matches git log --pretty=format:%s => subject
@ -251,7 +245,7 @@ type Commit struct {
Column int Column int
Refs []git.Reference Refs []git.Reference
Rev string Rev string
Date time.Time Date string
ShortRev string ShortRev string
Subject string Subject string
} }

View file

@ -241,7 +241,7 @@ func TestParseGlyphs(t *testing.T) {
} }
func TestCommitStringParsing(t *testing.T) { func TestCommitStringParsing(t *testing.T) {
dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|Tue, 20 Dec 2016 21:10:41 +0100|4e61bac|" dataFirstPart := "* DATA:|4e61bacab44e9b4730e44a6615d04098dd3a8eaf|2016-12-20 21:10:41 +0100|4e61bac|"
tests := []struct { tests := []struct {
shouldPass bool shouldPass bool
testName string testName string

View file

@ -18,7 +18,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View file

@ -19,15 +19,6 @@ func NumericEqualityQuery(value int64, field string) *query.NumericRangeQuery {
return q return q
} }
// MatchQuery generates a match query for the given phrase, field and analyzer
func MatchQuery(matchTerm, field, analyzer string, fuzziness int) *query.MatchQuery {
q := bleve.NewMatchQuery(matchTerm)
q.FieldVal = field
q.Analyzer = analyzer
q.Fuzziness = fuzziness
return q
}
// MatchPhraseQuery generates a match phrase query for the given phrase, field and analyzer // MatchPhraseQuery generates a match phrase query for the given phrase, field and analyzer
func MatchPhraseQuery(matchPhrase, field, analyzer string, fuzziness int) *query.MatchPhraseQuery { func MatchPhraseQuery(matchPhrase, field, analyzer string, fuzziness int) *query.MatchPhraseQuery {
q := bleve.NewMatchPhraseQuery(matchPhrase) q := bleve.NewMatchPhraseQuery(matchPhrase)

View file

@ -35,7 +35,13 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error {
}) })
} }
const maxBatchSize = 16 const (
maxBatchSize = 16
// fuzzyDenominator determines the levenshtein distance per each character of a keyword
fuzzyDenominator = 4
// see https://github.com/blevesearch/bleve/issues/1563#issuecomment-786822311
maxFuzziness = 2
)
// IndexerData an update to the issue indexer // IndexerData an update to the issue indexer
type IndexerData internal.IndexerData type IndexerData internal.IndexerData
@ -156,25 +162,16 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
var queries []query.Query var queries []query.Query
if options.Keyword != "" { if options.Keyword != "" {
fuzziness := 0
if options.IsFuzzyKeyword { if options.IsFuzzyKeyword {
fuzziness := 1 fuzziness = min(maxFuzziness, len(options.Keyword)/fuzzyDenominator)
if kl := len(options.Keyword); kl > 3 {
fuzziness = 2
} else if kl < 2 {
fuzziness = 0
} }
queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{ queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{
inner_bleve.MatchQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness), inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, fuzziness),
inner_bleve.MatchQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness), inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, fuzziness),
inner_bleve.MatchQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness), inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, fuzziness),
}...)) }...))
} else {
queries = append(queries, bleve.NewDisjunctionQuery([]query.Query{
inner_bleve.MatchPhraseQuery(options.Keyword, "title", issueIndexerAnalyzer, 0),
inner_bleve.MatchPhraseQuery(options.Keyword, "content", issueIndexerAnalyzer, 0),
inner_bleve.MatchPhraseQuery(options.Keyword, "comments", issueIndexerAnalyzer, 0),
}...))
}
} }
if len(options.RepoIDs) > 0 || options.AllPublic { if len(options.RepoIDs) > 0 || options.AllPublic {

View file

@ -78,9 +78,7 @@ func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOp
searchOpt.Paginator = opts.Paginator searchOpt.Paginator = opts.Paginator
switch opts.SortType { switch opts.SortType {
case "", "relevance": case "", "latest":
searchOpt.SortBy = SortByScore
case "latest":
searchOpt.SortBy = SortByCreatedDesc searchOpt.SortBy = SortByCreatedDesc
case "oldest": case "oldest":
searchOpt.SortBy = SortByCreatedAsc searchOpt.SortBy = SortByCreatedAsc

View file

@ -236,7 +236,7 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
} }
if options.SortBy == "" { if options.SortBy == "" {
options.SortBy = internal.SortByScore options.SortBy = internal.SortByCreatedAsc
} }
sortBy := []elastic.Sorter{ sortBy := []elastic.Sorter{
parseSortBy(options.SortBy), parseSortBy(options.SortBy),

View file

@ -269,7 +269,6 @@ func IsAvailable(ctx context.Context) bool {
type SearchOptions = internal.SearchOptions type SearchOptions = internal.SearchOptions
const ( const (
SortByScore = internal.SortByScore
SortByCreatedDesc = internal.SortByCreatedDesc SortByCreatedDesc = internal.SortByCreatedDesc
SortByUpdatedDesc = internal.SortByUpdatedDesc SortByUpdatedDesc = internal.SortByUpdatedDesc
SortByCommentsDesc = internal.SortByCommentsDesc SortByCommentsDesc = internal.SortByCommentsDesc

View file

@ -17,7 +17,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View file

@ -127,7 +127,6 @@ func (o *SearchOptions) Copy(edit ...func(options *SearchOptions)) *SearchOption
type SortBy string type SortBy string
const ( const (
SortByScore SortBy = "-_score"
SortByCreatedDesc SortBy = "-created_unix" SortByCreatedDesc SortBy = "-created_unix"
SortByUpdatedDesc SortBy = "-updated_unix" SortByUpdatedDesc SortBy = "-updated_unix"
SortByCommentsDesc SortBy = "-comment_count" SortByCommentsDesc SortBy = "-comment_count"

View file

@ -126,7 +126,6 @@ var cases = []*testIndexerCase{
}, },
SearchOptions: &internal.SearchOptions{ SearchOptions: &internal.SearchOptions{
Keyword: "hello", Keyword: "hello",
SortBy: internal.SortByCreatedDesc,
}, },
ExpectedIDs: []int64{1002, 1001, 1000}, ExpectedIDs: []int64{1002, 1001, 1000},
ExpectedTotal: 3, ExpectedTotal: 3,
@ -140,7 +139,6 @@ var cases = []*testIndexerCase{
}, },
SearchOptions: &internal.SearchOptions{ SearchOptions: &internal.SearchOptions{
Keyword: "hello world", Keyword: "hello world",
SortBy: internal.SortByCreatedDesc,
IsFuzzyKeyword: true, IsFuzzyKeyword: true,
}, },
ExpectedIDs: []int64{1002, 1001, 1000}, ExpectedIDs: []int64{1002, 1001, 1000},
@ -159,7 +157,6 @@ var cases = []*testIndexerCase{
}, },
SearchOptions: &internal.SearchOptions{ SearchOptions: &internal.SearchOptions{
Keyword: "hello", Keyword: "hello",
SortBy: internal.SortByCreatedDesc,
RepoIDs: []int64{1, 4}, RepoIDs: []int64{1, 4},
}, },
ExpectedIDs: []int64{1006, 1002, 1001}, ExpectedIDs: []int64{1006, 1002, 1001},
@ -178,7 +175,6 @@ var cases = []*testIndexerCase{
}, },
SearchOptions: &internal.SearchOptions{ SearchOptions: &internal.SearchOptions{
Keyword: "hello", Keyword: "hello",
SortBy: internal.SortByCreatedDesc,
RepoIDs: []int64{1, 4}, RepoIDs: []int64{1, 4},
AllPublic: true, AllPublic: true,
}, },
@ -601,22 +597,6 @@ var cases = []*testIndexerCase{
} }
}, },
}, },
{
Name: "SortByScore",
SearchOptions: &internal.SearchOptions{
Paginator: &db.ListOptionsAll,
SortBy: internal.SortByScore,
},
Expected: func(t *testing.T, data map[int64]*internal.IndexerData, result *internal.SearchResult) {
assert.Equal(t, len(data), len(result.Hits))
assert.Equal(t, len(data), int(result.Total))
for i, v := range result.Hits {
if i < len(result.Hits)-1 {
assert.GreaterOrEqual(t, v.Score, result.Hits[i+1].Score)
}
}
},
},
{ {
Name: "SortByCreatedAsc", Name: "SortByCreatedAsc",
SearchOptions: &internal.SearchOptions{ SearchOptions: &internal.SearchOptions{

View file

@ -208,19 +208,13 @@ func (b *Indexer) Search(ctx context.Context, options *internal.SearchOptions) (
query.And(inner_meilisearch.NewFilterLte("updated_unix", options.UpdatedBeforeUnix.Value())) query.And(inner_meilisearch.NewFilterLte("updated_unix", options.UpdatedBeforeUnix.Value()))
} }
var sortBy []string if options.SortBy == "" {
switch options.SortBy { options.SortBy = internal.SortByCreatedAsc
// sort by relevancy (no explicit sorting) }
case internal.SortByScore: sortBy := []string{
fallthrough
case "":
sortBy = []string{}
default:
sortBy = []string{
parseSortBy(options.SortBy), parseSortBy(options.SortBy),
"id:desc", "id:desc",
} }
}
skip, limit := indexer_internal.ParsePaginator(options.Paginator, maxTotalHits) skip, limit := indexer_internal.ParsePaginator(options.Paginator, maxTotalHits)

View file

@ -17,7 +17,6 @@ import (
_ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models"
_ "code.gitea.io/gitea/models/actions" _ "code.gitea.io/gitea/models/actions"
_ "code.gitea.io/gitea/models/activities" _ "code.gitea.io/gitea/models/activities"
_ "code.gitea.io/gitea/models/forgefed"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"

View file

@ -13,7 +13,7 @@ import (
"code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/container"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.forgejo.org/go-chi/binding" "gitea.com/go-chi/binding"
) )
// Validate checks whether an IssueTemplate is considered valid, and returns the first error // Validate checks whether an IssueTemplate is considered valid, and returns the first error

View file

@ -16,9 +16,10 @@ import (
"code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/setting"
) )
const httpBatchSize = 20
// HTTPClient is used to communicate with the LFS server // HTTPClient is used to communicate with the LFS server
// https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md // https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md
type HTTPClient struct { type HTTPClient struct {
@ -29,7 +30,7 @@ type HTTPClient struct {
// BatchSize returns the preferred size of batchs to process // BatchSize returns the preferred size of batchs to process
func (c *HTTPClient) BatchSize() int { func (c *HTTPClient) BatchSize() int {
return setting.LFSClient.BatchSize return httpBatchSize
} }
func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient { func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient {

View file

@ -267,7 +267,7 @@ func TestHTTPClientDownload(t *testing.T) {
return nil return nil
}) })
if len(c.expectederror) > 0 { if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else { } else {
require.NoError(t, err, "case %d", n) require.NoError(t, err, "case %d", n)
} }
@ -369,7 +369,7 @@ func TestHTTPClientUpload(t *testing.T) {
return io.NopCloser(new(bytes.Buffer)), objectError return io.NopCloser(new(bytes.Buffer)), objectError
}) })
if len(c.expectederror) > 0 { if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else { } else {
require.NoError(t, err, "case %d", n) require.NoError(t, err, "case %d", n)
} }

View file

@ -97,7 +97,7 @@ func TestBasicTransferAdapter(t *testing.T) {
for n, c := range cases { for n, c := range cases {
_, err := a.Download(context.Background(), c.link) _, err := a.Download(context.Background(), c.link)
if len(c.expectederror) > 0 { if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else { } else {
require.NoError(t, err, "case %d", n) require.NoError(t, err, "case %d", n)
} }
@ -130,7 +130,7 @@ func TestBasicTransferAdapter(t *testing.T) {
for n, c := range cases { for n, c := range cases {
err := a.Upload(context.Background(), c.link, p, bytes.NewBufferString("dummy")) err := a.Upload(context.Background(), c.link, p, bytes.NewBufferString("dummy"))
if len(c.expectederror) > 0 { if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else { } else {
require.NoError(t, err, "case %d", n) require.NoError(t, err, "case %d", n)
} }
@ -163,7 +163,7 @@ func TestBasicTransferAdapter(t *testing.T) {
for n, c := range cases { for n, c := range cases {
err := a.Verify(context.Background(), c.link, p) err := a.Verify(context.Background(), c.link, p)
if len(c.expectederror) > 0 { if len(c.expectederror) > 0 {
assert.Contains(t, err.Error(), c.expectederror, "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror) assert.True(t, strings.Contains(err.Error(), c.expectederror), "case %d: '%s' should contain '%s'", n, err.Error(), c.expectederror)
} else { } else {
require.NoError(t, err, "case %d", n) require.NoError(t, err, "case %d", n)
} }

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