Merge remote-tracking branch 'upstream/main' into feat/api-project-boards
This commit is contained in:
54
.github/stale.yml
vendored
54
.github/stale.yml
vendored
@@ -1,54 +0,0 @@
|
|||||||
# Configuration for probot-stale - https://github.com/probot/stale
|
|
||||||
|
|
||||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
|
||||||
daysUntilStale: 60
|
|
||||||
|
|
||||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
|
||||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
|
||||||
daysUntilClose: 14
|
|
||||||
|
|
||||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
|
||||||
exemptLabels:
|
|
||||||
- status/blocked
|
|
||||||
- kind/security
|
|
||||||
- lgtm/done
|
|
||||||
- reviewed/confirmed
|
|
||||||
- priority/critical
|
|
||||||
- kind/proposal
|
|
||||||
|
|
||||||
# Set to true to ignore issues in a project (defaults to false)
|
|
||||||
exemptProjects: false
|
|
||||||
|
|
||||||
# Set to true to ignore issues in a milestone (defaults to false)
|
|
||||||
exemptMilestones: false
|
|
||||||
|
|
||||||
# Label to use when marking as stale
|
|
||||||
staleLabel: stale
|
|
||||||
|
|
||||||
# Comment to post when marking as stale. Set to `false` to disable
|
|
||||||
markComment: >
|
|
||||||
This issue has been automatically marked as stale because it has not had recent activity.
|
|
||||||
I am here to help clear issues left open even if solved or waiting for more insight.
|
|
||||||
This issue will be closed if no further activity occurs during the next 2 weeks.
|
|
||||||
If the issue is still valid just add a comment to keep it alive.
|
|
||||||
Thank you for your contributions.
|
|
||||||
|
|
||||||
# Comment to post when closing a stale Issue or Pull Request.
|
|
||||||
closeComment: >
|
|
||||||
This issue has been automatically closed because of inactivity.
|
|
||||||
You can re-open it if needed.
|
|
||||||
|
|
||||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
|
||||||
limitPerRun: 1
|
|
||||||
|
|
||||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
|
||||||
pulls:
|
|
||||||
daysUntilStale: 60
|
|
||||||
daysUntilClose: 60
|
|
||||||
markComment: >
|
|
||||||
This pull request has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs during the next 2 months. Thank you
|
|
||||||
for your contributions.
|
|
||||||
closeComment: >
|
|
||||||
This pull request has been automatically closed because of inactivity.
|
|
||||||
You can re-open it if needed.
|
|
||||||
2
.github/workflows/cron-licenses.yml
vendored
2
.github/workflows/cron-licenses.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
if: github.repository == 'go-gitea/gitea'
|
if: github.repository == 'go-gitea/gitea'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
2
.github/workflows/cron-lock.yml
vendored
2
.github/workflows/cron-lock.yml
vendored
@@ -17,6 +17,6 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.repository == 'go-gitea/gitea'
|
if: github.repository == 'go-gitea/gitea'
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v4
|
- uses: dessant/lock-threads@v5
|
||||||
with:
|
with:
|
||||||
issue-inactive-days: 45
|
issue-inactive-days: 45
|
||||||
|
|||||||
12
.github/workflows/pull-compliance.yml
vendored
12
.github/workflows/pull-compliance.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -130,7 +130,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -175,7 +175,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
10
.github/workflows/pull-db-tests.yml
vendored
10
.github/workflows/pull-db-tests.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -115,7 +115,7 @@ jobs:
|
|||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -165,7 +165,7 @@ jobs:
|
|||||||
- "993:993"
|
- "993:993"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -198,7 +198,7 @@ jobs:
|
|||||||
- "1433:1433"
|
- "1433:1433"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
2
.github/workflows/pull-e2e-tests.yml
vendored
2
.github/workflows/pull-e2e-tests.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
6
.github/workflows/release-nightly.yml
vendored
6
.github/workflows/release-nightly.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
- run: git fetch --unshallow --quiet --tags --force
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
- run: git fetch --unshallow --quiet --tags --force
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -101,7 +101,7 @@ jobs:
|
|||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
- run: git fetch --unshallow --quiet --tags --force
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|||||||
11
.github/workflows/release-tag-rc.yml
vendored
11
.github/workflows/release-tag-rc.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
- run: git fetch --unshallow --quiet --tags --force
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
|
||||||
echo "Cleaned name is ${REF_NAME}"
|
echo "Cleaned name is ${REF_NAME}"
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
- name: configure aws
|
- name: configure aws
|
||||||
@@ -56,6 +56,10 @@ jobs:
|
|||||||
- name: upload binaries to s3
|
- name: upload binaries to s3
|
||||||
run: |
|
run: |
|
||||||
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
||||||
|
- name: Install GH CLI
|
||||||
|
uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
|
||||||
|
with:
|
||||||
|
gh-cli-version: 2.39.1
|
||||||
- name: create github release
|
- name: create github release
|
||||||
run: |
|
run: |
|
||||||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
||||||
@@ -74,6 +78,8 @@ jobs:
|
|||||||
id: meta
|
id: meta
|
||||||
with:
|
with:
|
||||||
images: gitea/gitea
|
images: gitea/gitea
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
# 1.2.3-rc0
|
# 1.2.3-rc0
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
@@ -105,6 +111,7 @@ jobs:
|
|||||||
images: gitea/gitea
|
images: gitea/gitea
|
||||||
# each tag below will have the suffix of -rootless
|
# each tag below will have the suffix of -rootless
|
||||||
flavor: |
|
flavor: |
|
||||||
|
latest=false
|
||||||
suffix=-rootless
|
suffix=-rootless
|
||||||
# 1.2.3-rc0
|
# 1.2.3-rc0
|
||||||
tags: |
|
tags: |
|
||||||
|
|||||||
14
.github/workflows/release-tag-version.yml
vendored
14
.github/workflows/release-tag-version.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
# fetch all commits instead of only the last as some branches are long lived and could have many between versions
|
||||||
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
# fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567
|
||||||
- run: git fetch --unshallow --quiet --tags --force
|
- run: git fetch --unshallow --quiet --tags --force
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\///' -e 's/release\/v//')
|
REF_NAME=$(echo "${{ github.ref }}" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -e 's/release\/v//')
|
||||||
echo "Cleaned name is ${REF_NAME}"
|
echo "Cleaned name is ${REF_NAME}"
|
||||||
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
echo "branch=${REF_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
- name: configure aws
|
- name: configure aws
|
||||||
@@ -58,9 +58,13 @@ jobs:
|
|||||||
- name: upload binaries to s3
|
- name: upload binaries to s3
|
||||||
run: |
|
run: |
|
||||||
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
||||||
|
- name: Install GH CLI
|
||||||
|
uses: dev-hanz-ops/install-gh-cli-action@v0.1.0
|
||||||
|
with:
|
||||||
|
gh-cli-version: 2.39.1
|
||||||
- name: create github release
|
- name: create github release
|
||||||
run: |
|
run: |
|
||||||
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --notes-from-tag dist/release/*
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
docker-rootful:
|
docker-rootful:
|
||||||
@@ -82,7 +86,6 @@ jobs:
|
|||||||
# 1.2
|
# 1.2
|
||||||
# 1.2.3
|
# 1.2.3
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest
|
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
@@ -114,14 +117,13 @@ jobs:
|
|||||||
images: gitea/gitea
|
images: gitea/gitea
|
||||||
# each tag below will have the suffix of -rootless
|
# each tag below will have the suffix of -rootless
|
||||||
flavor: |
|
flavor: |
|
||||||
suffix=-rootless
|
suffix=-rootless,onlatest=true
|
||||||
# this will generate tags in the following format (with -rootless suffix added):
|
# this will generate tags in the following format (with -rootless suffix added):
|
||||||
# latest
|
# latest
|
||||||
# 1
|
# 1
|
||||||
# 1.2
|
# 1.2
|
||||||
# 1.2.3
|
# 1.2.3
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,value=latest
|
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,6 +11,7 @@ _test
|
|||||||
.idea
|
.idea
|
||||||
# Goland's output filename can not be set manually
|
# Goland's output filename can not be set manually
|
||||||
/go_build_*
|
/go_build_*
|
||||||
|
/gitea_*
|
||||||
|
|
||||||
# MS VSCode
|
# MS VSCode
|
||||||
.vscode
|
.vscode
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
commands-show-output: false
|
commands-show-output: false
|
||||||
fenced-code-language: false
|
fenced-code-language: false
|
||||||
first-line-h1: false
|
first-line-h1: false
|
||||||
header-increment: false
|
heading-increment: false
|
||||||
line-length: {code_blocks: false, tables: false, stern: true, line_length: -1}
|
line-length: {code_blocks: false, tables: false, stern: true, line_length: -1}
|
||||||
no-alt-text: false
|
no-alt-text: false
|
||||||
no-bare-urls: false
|
no-bare-urls: false
|
||||||
no-blanks-blockquote: false
|
no-blanks-blockquote: false
|
||||||
no-emphasis-as-header: false
|
no-emphasis-as-heading: false
|
||||||
no-empty-links: false
|
no-empty-links: false
|
||||||
no-hard-tabs: {code_blocks: false}
|
no-hard-tabs: {code_blocks: false}
|
||||||
no-inline-html: false
|
no-inline-html: false
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ rules:
|
|||||||
keyframe-declaration-no-important: true
|
keyframe-declaration-no-important: true
|
||||||
keyframe-selector-notation: null
|
keyframe-selector-notation: null
|
||||||
keyframes-name-pattern: null
|
keyframes-name-pattern: null
|
||||||
length-zero-no-unit: true
|
length-zero-no-unit: [true, ignore: [custom-properties], ignoreFunctions: [var]]
|
||||||
max-nesting-depth: null
|
max-nesting-depth: null
|
||||||
media-feature-name-allowed-list: null
|
media-feature-name-allowed-list: null
|
||||||
media-feature-name-disallowed-list: null
|
media-feature-name-disallowed-list: null
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.21-alpine3.18 AS build-env
|
FROM docker.io/library/golang:1.21-alpine3.19 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
@@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
|||||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.18
|
FROM docker.io/library/alpine:3.19
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 22 3000
|
EXPOSE 22 3000
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM docker.io/library/golang:1.21-alpine3.18 AS build-env
|
FROM docker.io/library/golang:1.21-alpine3.19 AS build-env
|
||||||
|
|
||||||
ARG GOPROXY
|
ARG GOPROXY
|
||||||
ENV GOPROXY ${GOPROXY:-direct}
|
ENV GOPROXY ${GOPROXY:-direct}
|
||||||
@@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
|
|||||||
/go/src/code.gitea.io/gitea/environment-to-ini
|
/go/src/code.gitea.io/gitea/environment-to-ini
|
||||||
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.18
|
FROM docker.io/library/alpine:3.19
|
||||||
LABEL maintainer="maintainers@gitea.io"
|
LABEL maintainer="maintainers@gitea.io"
|
||||||
|
|
||||||
EXPOSE 2222 3000
|
EXPOSE 2222 3000
|
||||||
|
|||||||
@@ -62,11 +62,16 @@ painless way of setting up a self-hosted Git service.
|
|||||||
As Gitea is written in Go, it works across **all** the platforms and
|
As Gitea is written in Go, it works across **all** the platforms and
|
||||||
architectures that are supported by Go, including Linux, macOS, and
|
architectures that are supported by Go, including Linux, macOS, and
|
||||||
Windows on x86, amd64, ARM and PowerPC architectures.
|
Windows on x86, amd64, ARM and PowerPC architectures.
|
||||||
You can try it out using [the online demo](https://try.gitea.io/).
|
|
||||||
This project has been
|
This project has been
|
||||||
[forked](https://blog.gitea.com/welcome-to-gitea/) from
|
[forked](https://blog.gitea.com/welcome-to-gitea/) from
|
||||||
[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
|
[Gogs](https://gogs.io) since November of 2016, but a lot has changed.
|
||||||
|
|
||||||
|
For online demonstrations, you can visit [try.gitea.io](https://try.gitea.io).
|
||||||
|
|
||||||
|
For accessing free Gitea service (with a limited number of repositories), you can visit [gitea.com](https://gitea.com/user/login).
|
||||||
|
|
||||||
|
To quickly deploy your own dedicated Gitea instance on Gitea Cloud, you can start a free trial at [cloud.gitea.com](https://cloud.gitea.com).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
From the root of the source tree, run:
|
From the root of the source tree, run:
|
||||||
|
|||||||
@@ -58,7 +58,11 @@
|
|||||||
|
|
||||||
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。
|
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。
|
||||||
|
|
||||||
如果您想试用一下,请访问 [在线Demo](https://try.gitea.io/)!
|
如果你想试用在线演示,请访问 [try.gitea.io](https://try.gitea.io/)。
|
||||||
|
|
||||||
|
如果你想使用免费的 Gitea 服务(有仓库数量限制),请访问 [gitea.com](https://gitea.com/user/login)。
|
||||||
|
|
||||||
|
如果你想在 Gitea Cloud 上快速部署你自己独享的 Gitea 实例,请访问 [cloud.gitea.com](https://cloud.gitea.com) 开始免费试用。
|
||||||
|
|
||||||
## 提示
|
## 提示
|
||||||
|
|
||||||
|
|||||||
18
assets/go-licenses.json
generated
18
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@@ -15,9 +15,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
// CmdActions represents the available actions sub-commands.
|
// CmdActions represents the available actions sub-commands.
|
||||||
CmdActions = &cli.Command{
|
CmdActions = &cli.Command{
|
||||||
Name: "actions",
|
Name: "actions",
|
||||||
Usage: "",
|
Usage: "Manage Gitea Actions",
|
||||||
Description: "Commands for managing Gitea Actions",
|
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdActionsGenRunnerToken,
|
subcmdActionsGenRunnerToken,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ var (
|
|||||||
// CmdAdmin represents the available admin sub-command.
|
// CmdAdmin represents the available admin sub-command.
|
||||||
CmdAdmin = &cli.Command{
|
CmdAdmin = &cli.Command{
|
||||||
Name: "admin",
|
Name: "admin",
|
||||||
Usage: "Command line interface to perform common administrative operations",
|
Usage: "Perform common administrative operations",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdUser,
|
subcmdUser,
|
||||||
subcmdRepoSyncReleases,
|
subcmdRepoSyncReleases,
|
||||||
@@ -157,10 +157,10 @@ func runRepoSyncReleases(_ *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getReleaseCount(ctx context.Context, id int64) (int64, error) {
|
func getReleaseCount(ctx context.Context, id int64) (int64, error) {
|
||||||
return repo_model.GetReleaseCountByRepoID(
|
return db.Count[repo_model.Release](
|
||||||
ctx,
|
ctx,
|
||||||
id,
|
|
||||||
repo_model.FindReleasesOptions{
|
repo_model.FindReleasesOptions{
|
||||||
|
RepoID: id,
|
||||||
IncludeTags: true,
|
IncludeTags: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
migrate_base "code.gitea.io/gitea/models/migrations/base"
|
migrate_base "code.gitea.io/gitea/models/migrations/base"
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
"code.gitea.io/gitea/modules/doctor"
|
"code.gitea.io/gitea/modules/doctor"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -22,6 +23,19 @@ import (
|
|||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CmdDoctor represents the available doctor sub-command.
|
||||||
|
var CmdDoctor = &cli.Command{
|
||||||
|
Name: "doctor",
|
||||||
|
Usage: "Diagnose and optionally fix problems, convert or re-create database tables",
|
||||||
|
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
||||||
|
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
cmdDoctorCheck,
|
||||||
|
cmdRecreateTable,
|
||||||
|
cmdDoctorConvert,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var cmdDoctorCheck = &cli.Command{
|
var cmdDoctorCheck = &cli.Command{
|
||||||
Name: "check",
|
Name: "check",
|
||||||
Usage: "Diagnose and optionally fix problems",
|
Usage: "Diagnose and optionally fix problems",
|
||||||
@@ -60,19 +74,6 @@ var cmdDoctorCheck = &cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// CmdDoctor represents the available doctor sub-command.
|
|
||||||
var CmdDoctor = &cli.Command{
|
|
||||||
Name: "doctor",
|
|
||||||
Usage: "Diagnose and optionally fix problems",
|
|
||||||
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
|
|
||||||
|
|
||||||
Subcommands: []*cli.Command{
|
|
||||||
cmdDoctorCheck,
|
|
||||||
cmdRecreateTable,
|
|
||||||
cmdDoctorConvert,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var cmdRecreateTable = &cli.Command{
|
var cmdRecreateTable = &cli.Command{
|
||||||
Name: "recreate-table",
|
Name: "recreate-table",
|
||||||
Usage: "Recreate tables from XORM definitions and copy the data.",
|
Usage: "Recreate tables from XORM definitions and copy the data.",
|
||||||
@@ -177,6 +178,7 @@ func runDoctorCheck(ctx *cli.Context) error {
|
|||||||
if ctx.IsSet("list") {
|
if ctx.IsSet("list") {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
|
||||||
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
|
_, _ = w.Write([]byte("Default\tName\tTitle\n"))
|
||||||
|
doctor.SortChecks(doctor.Checks)
|
||||||
for _, check := range doctor.Checks {
|
for _, check := range doctor.Checks {
|
||||||
if check.IsDefault {
|
if check.IsDefault {
|
||||||
_, _ = w.Write([]byte{'*'})
|
_, _ = w.Write([]byte{'*'})
|
||||||
@@ -192,26 +194,20 @@ func runDoctorCheck(ctx *cli.Context) error {
|
|||||||
|
|
||||||
var checks []*doctor.Check
|
var checks []*doctor.Check
|
||||||
if ctx.Bool("all") {
|
if ctx.Bool("all") {
|
||||||
checks = doctor.Checks
|
checks = make([]*doctor.Check, len(doctor.Checks))
|
||||||
|
copy(checks, doctor.Checks)
|
||||||
} else if ctx.IsSet("run") {
|
} else if ctx.IsSet("run") {
|
||||||
addDefault := ctx.Bool("default")
|
addDefault := ctx.Bool("default")
|
||||||
names := ctx.StringSlice("run")
|
runNamesSet := container.SetOf(ctx.StringSlice("run")...)
|
||||||
for i, name := range names {
|
|
||||||
names[i] = strings.ToLower(strings.TrimSpace(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, check := range doctor.Checks {
|
for _, check := range doctor.Checks {
|
||||||
if addDefault && check.IsDefault {
|
if (addDefault && check.IsDefault) || runNamesSet.Contains(check.Name) {
|
||||||
checks = append(checks, check)
|
checks = append(checks, check)
|
||||||
continue
|
runNamesSet.Remove(check.Name)
|
||||||
}
|
|
||||||
for _, name := range names {
|
|
||||||
if name == check.Name {
|
|
||||||
checks = append(checks, check)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(runNamesSet) > 0 {
|
||||||
|
return fmt.Errorf("unknown checks: %q", strings.Join(runNamesSet.Values(), ","))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, check := range doctor.Checks {
|
for _, check := range doctor.Checks {
|
||||||
if check.IsDefault {
|
if check.IsDefault {
|
||||||
@@ -219,6 +215,5 @@ func runDoctorCheck(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return doctor.RunChecks(stdCtx, colorize, ctx.Bool("fix"), checks)
|
return doctor.RunChecks(stdCtx, colorize, ctx.Bool("fix"), checks)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ func runDoctorConvert(ctx *cli.Context) error {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case setting.Database.Type.IsMySQL():
|
case setting.Database.Type.IsMySQL():
|
||||||
if err := db.ConvertUtf8ToUtf8mb4(); err != nil {
|
if err := db.ConvertDatabaseTable(); err != nil {
|
||||||
log.Fatal("Failed to convert database from utf8 to utf8mb4: %v", err)
|
log.Fatal("Failed to convert database & table: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
fmt.Println("Converted successfully, please confirm your database's character set is now utf8mb4")
|
||||||
|
|||||||
33
cmd/doctor_test.go
Normal file
33
cmd/doctor_test.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/doctor"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDoctorRun(t *testing.T) {
|
||||||
|
doctor.Register(&doctor.Check{
|
||||||
|
Title: "Test Check",
|
||||||
|
Name: "test-check",
|
||||||
|
Run: func(ctx context.Context, logger log.Logger, autofix bool) error { return nil },
|
||||||
|
|
||||||
|
SkipDatabaseInitialization: true,
|
||||||
|
})
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Commands = []*cli.Command{cmdDoctorCheck}
|
||||||
|
err := app.Run([]string{"./gitea", "check", "--run", "test-check"})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = app.Run([]string{"./gitea", "check", "--run", "no-such"})
|
||||||
|
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
|
err = app.Run([]string{"./gitea", "check", "--run", "test-check,no-such"})
|
||||||
|
assert.ErrorContains(t, err, `unknown checks: "no-such"`)
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ var (
|
|||||||
// CmdGenerate represents the available generate sub-command.
|
// CmdGenerate represents the available generate sub-command.
|
||||||
CmdGenerate = &cli.Command{
|
CmdGenerate = &cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Usage: "Command line interface for running generators",
|
Usage: "Generate Gitea's secrets/keys/tokens",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdSecret,
|
subcmdSecret,
|
||||||
},
|
},
|
||||||
|
|||||||
11
cmd/hook.go
11
cmd/hook.go
@@ -31,8 +31,8 @@ var (
|
|||||||
// CmdHook represents the available hooks sub-command.
|
// CmdHook represents the available hooks sub-command.
|
||||||
CmdHook = &cli.Command{
|
CmdHook = &cli.Command{
|
||||||
Name: "hook",
|
Name: "hook",
|
||||||
Usage: "Delegate commands to corresponding Git hooks",
|
Usage: "(internal) Should only be called by Git",
|
||||||
Description: "This should only be called by Git",
|
Description: "Delegate commands to corresponding Git hooks",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
subcmdHookPreReceive,
|
subcmdHookPreReceive,
|
||||||
@@ -376,7 +376,9 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
oldCommitIDs[count] = string(fields[0])
|
oldCommitIDs[count] = string(fields[0])
|
||||||
newCommitIDs[count] = string(fields[1])
|
newCommitIDs[count] = string(fields[1])
|
||||||
refFullNames[count] = git.RefName(fields[2])
|
refFullNames[count] = git.RefName(fields[2])
|
||||||
if refFullNames[count] == git.BranchPrefix+"master" && newCommitIDs[count] != git.EmptySHA && count == total {
|
|
||||||
|
commitID, _ := git.NewIDFromString(newCommitIDs[count])
|
||||||
|
if refFullNames[count] == git.BranchPrefix+"master" && !commitID.IsZero() && count == total {
|
||||||
masterPushed = true
|
masterPushed = true
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
@@ -669,7 +671,8 @@ Gitea or set your environment appropriately.`, "")
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rs.OldOID != git.EmptySHA {
|
commitID, _ := git.NewIDFromString(rs.OldOID)
|
||||||
|
if !commitID.IsZero() {
|
||||||
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
|
err = writeDataPktLine(ctx, os.Stdout, []byte("option old-oid "+rs.OldOID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ import (
|
|||||||
|
|
||||||
// CmdKeys represents the available keys sub-command
|
// CmdKeys represents the available keys sub-command
|
||||||
var CmdKeys = &cli.Command{
|
var CmdKeys = &cli.Command{
|
||||||
Name: "keys",
|
Name: "keys",
|
||||||
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
Usage: "(internal) Should only be called by SSH server",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Description: "Queries the Gitea database to get the authorized command for a given ssh key fingerprint",
|
||||||
Action: runKeys,
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
|
Action: runKeys,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "expected",
|
Name: "expected",
|
||||||
|
|||||||
21
cmd/main.go
21
cmd/main.go
@@ -10,12 +10,12 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cmdHelp is our own help subcommand with more information
|
// cmdHelp is our own help subcommand with more information
|
||||||
|
// Keep in mind that the "./gitea help"(subcommand) is different from "./gitea --help"(flag), the flag doesn't parse the config or output "DEFAULT CONFIGURATION:" information
|
||||||
func cmdHelp() *cli.Command {
|
func cmdHelp() *cli.Command {
|
||||||
c := &cli.Command{
|
c := &cli.Command{
|
||||||
Name: "help",
|
Name: "help",
|
||||||
@@ -47,16 +47,10 @@ DEFAULT CONFIGURATION:
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
var helpFlag = cli.HelpFlag
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// cli.HelpFlag = nil TODO: after https://github.com/urfave/cli/issues/1794 we can use this
|
|
||||||
}
|
|
||||||
|
|
||||||
func appGlobalFlags() []cli.Flag {
|
func appGlobalFlags() []cli.Flag {
|
||||||
return []cli.Flag{
|
return []cli.Flag{
|
||||||
// make the builtin flags at the top
|
// make the builtin flags at the top
|
||||||
helpFlag,
|
cli.HelpFlag,
|
||||||
|
|
||||||
// shared configuration flags, they are for global and for each sub-command at the same time
|
// shared configuration flags, they are for global and for each sub-command at the same time
|
||||||
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
// eg: such command is valid: "./gitea --config /tmp/app.ini web --config /tmp/app.ini", while it's discouraged indeed
|
||||||
@@ -121,20 +115,22 @@ func prepareWorkPathAndCustomConf(action cli.ActionFunc) func(ctx *cli.Context)
|
|||||||
func NewMainApp(version, versionExtra string) *cli.App {
|
func NewMainApp(version, versionExtra string) *cli.App {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "Gitea"
|
app.Name = "Gitea"
|
||||||
|
app.HelpName = "gitea"
|
||||||
app.Usage = "A painless self-hosted Git service"
|
app.Usage = "A painless self-hosted Git service"
|
||||||
app.Description = `By default, Gitea will start serving using the web-server with no argument, which can alternatively be run by running the subcommand "web".`
|
app.Description = `Gitea program contains "web" and other subcommands. If no subcommand is given, it starts the web server by default. Use "web" subcommand for more web server arguments, use other subcommands for other purposes.`
|
||||||
app.Version = version + versionExtra
|
app.Version = version + versionExtra
|
||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
|
|
||||||
// these sub-commands need to use config file
|
// these sub-commands need to use config file
|
||||||
subCmdWithConfig := []*cli.Command{
|
subCmdWithConfig := []*cli.Command{
|
||||||
|
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
||||||
CmdWeb,
|
CmdWeb,
|
||||||
CmdServ,
|
CmdServ,
|
||||||
CmdHook,
|
CmdHook,
|
||||||
|
CmdKeys,
|
||||||
CmdDump,
|
CmdDump,
|
||||||
CmdAdmin,
|
CmdAdmin,
|
||||||
CmdMigrate,
|
CmdMigrate,
|
||||||
CmdKeys,
|
|
||||||
CmdDoctor,
|
CmdDoctor,
|
||||||
CmdManager,
|
CmdManager,
|
||||||
CmdEmbedded,
|
CmdEmbedded,
|
||||||
@@ -142,13 +138,8 @@ func NewMainApp(version, versionExtra string) *cli.App {
|
|||||||
CmdDumpRepository,
|
CmdDumpRepository,
|
||||||
CmdRestoreRepository,
|
CmdRestoreRepository,
|
||||||
CmdActions,
|
CmdActions,
|
||||||
cmdHelp(), // the "help" sub-command was used to show the more information for "work path" and "custom config"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdConvert := util.ToPointer(*cmdDoctorConvert)
|
|
||||||
cmdConvert.Hidden = true // still support the legacy "./gitea doctor" by the hidden sub-command, remove it in next release
|
|
||||||
subCmdWithConfig = append(subCmdWithConfig, cmdConvert)
|
|
||||||
|
|
||||||
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
// these sub-commands do not need the config file, and they do not depend on any path or environment variable.
|
||||||
subCmdStandalone := []*cli.Command{
|
subCmdStandalone := []*cli.Command{
|
||||||
CmdCert,
|
CmdCert,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ const (
|
|||||||
// CmdServ represents the available serv sub-command.
|
// CmdServ represents the available serv sub-command.
|
||||||
var CmdServ = &cli.Command{
|
var CmdServ = &cli.Command{
|
||||||
Name: "serv",
|
Name: "serv",
|
||||||
Usage: "This command should only be called by SSH shell",
|
Usage: "(internal) Should only be called by SSH shell",
|
||||||
Description: "Serv provides access auth for repositories",
|
Description: "Serv provides access auth for repositories",
|
||||||
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
Before: PrepareConsoleLoggerLevel(log.FATAL),
|
||||||
Action: runServ,
|
Action: runServ,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/google/go-github/v53/github"
|
"github.com/google/go-github/v57/github"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ After=network.target
|
|||||||
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
|
# Uncomment the next line if you have repos with lots of files and get a HTTP 500 error because of that
|
||||||
# LimitNOFILE=524288:524288
|
# LimitNOFILE=524288:524288
|
||||||
RestartSec=2s
|
RestartSec=2s
|
||||||
Type=notify
|
Type=simple
|
||||||
User=git
|
User=git
|
||||||
Group=git
|
Group=git
|
||||||
WorkingDirectory=/var/lib/gitea/
|
WorkingDirectory=/var/lib/gitea/
|
||||||
@@ -62,7 +62,6 @@ WorkingDirectory=/var/lib/gitea/
|
|||||||
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
|
||||||
Restart=always
|
Restart=always
|
||||||
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea
|
||||||
WatchdogSec=30s
|
|
||||||
# If you install Git to directory prefix other than default PATH (which happens
|
# If you install Git to directory prefix other than default PATH (which happens
|
||||||
# for example if you install other versions of Git side-to-side with
|
# for example if you install other versions of Git side-to-side with
|
||||||
# distribution version), uncomment below line and add that prefix to PATH
|
# distribution version), uncomment below line and add that prefix to PATH
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ RUN_USER = ; git
|
|||||||
;MINIMUM_KEY_SIZE_CHECK = false
|
;MINIMUM_KEY_SIZE_CHECK = false
|
||||||
;;
|
;;
|
||||||
;; Disable CDN even in "prod" mode
|
;; Disable CDN even in "prod" mode
|
||||||
;OFFLINE_MODE = false
|
;OFFLINE_MODE = true
|
||||||
;;
|
;;
|
||||||
;; TLS Settings: Either ACME or manual
|
;; TLS Settings: Either ACME or manual
|
||||||
;; (Other common TLS configuration are found before)
|
;; (Other common TLS configuration are found before)
|
||||||
@@ -351,6 +351,7 @@ 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.
|
||||||
;;
|
;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
@@ -382,6 +383,7 @@ USER = root
|
|||||||
;NAME = gitea
|
;NAME = gitea
|
||||||
;USER = SA
|
;USER = SA
|
||||||
;PASSWD = MwantsaSecurePassword1
|
;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.
|
||||||
;;
|
;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
@@ -492,6 +494,11 @@ INTERNAL_TOKEN=
|
|||||||
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
|
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
|
||||||
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||||
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
|
||||||
|
;;
|
||||||
|
;; Reject API tokens sent in URL query string (Accept Header-based API tokens only). This avoids security vulnerabilities
|
||||||
|
;; stemming from cached/logged plain-text API tokens.
|
||||||
|
;; In future releases, this will become the default behavior
|
||||||
|
;DISABLE_QUERY_AUTH_TOKEN = false
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1060,6 +1067,9 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
|
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
|
||||||
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
|
||||||
|
;;
|
||||||
|
;; Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
||||||
|
;RETARGET_CHILDREN_ON_MERGE = true
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1153,15 +1163,9 @@ LEVEL = Info
|
|||||||
;; enable cors headers (disabled by default)
|
;; enable cors headers (disabled by default)
|
||||||
;ENABLED = false
|
;ENABLED = false
|
||||||
;;
|
;;
|
||||||
;; scheme of allowed requests
|
;; list of requesting origins that are allowed, eg: "https://*.example.com"
|
||||||
;SCHEME = http
|
|
||||||
;;
|
|
||||||
;; list of requesting domains that are allowed
|
|
||||||
;ALLOW_DOMAIN = *
|
;ALLOW_DOMAIN = *
|
||||||
;;
|
;;
|
||||||
;; allow subdomains of headers listed above to request
|
|
||||||
;ALLOW_SUBDOMAIN = false
|
|
||||||
;;
|
|
||||||
;; list of methods allowed to request
|
;; list of methods allowed to request
|
||||||
;METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
|
;METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
|
||||||
;;
|
;;
|
||||||
@@ -1207,6 +1211,9 @@ LEVEL = Info
|
|||||||
;; Max size of files to be displayed (default is 8MiB)
|
;; Max size of files to be displayed (default is 8MiB)
|
||||||
;MAX_DISPLAY_FILE_SIZE = 8388608
|
;MAX_DISPLAY_FILE_SIZE = 8388608
|
||||||
;;
|
;;
|
||||||
|
;; Detect ambiguous unicode characters in file contents and show warnings on the UI
|
||||||
|
;AMBIGUOUS_UNICODE_DETECTION = true
|
||||||
|
;;
|
||||||
;; Whether the email of the user should be shown in the Explore Users page
|
;; Whether the email of the user should be shown in the Explore Users page
|
||||||
;SHOW_USER_EMAIL = true
|
;SHOW_USER_EMAIL = true
|
||||||
;;
|
;;
|
||||||
@@ -1242,6 +1249,10 @@ LEVEL = Info
|
|||||||
;; Change the sort type of the explore pages.
|
;; Change the sort type of the explore pages.
|
||||||
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
|
;; Default is "recentupdate", but you also have "alphabetically", "reverselastlogin", "newest", "oldest".
|
||||||
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
|
;EXPLORE_PAGING_DEFAULT_SORT = recentupdate
|
||||||
|
;;
|
||||||
|
;; The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`.
|
||||||
|
;; `mixed` means most timestamps are rendered in relative time (i.e. 2 days ago).
|
||||||
|
;PREFERRED_TIMESTAMP_TENSE = mixed
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
@@ -1523,6 +1534,10 @@ LEVEL = Info
|
|||||||
;; userid = use the userid / sub attribute
|
;; userid = use the userid / sub attribute
|
||||||
;; nickname = use the nickname attribute
|
;; nickname = use the nickname attribute
|
||||||
;; email = use the username part of the email attribute
|
;; email = use the username part of the email attribute
|
||||||
|
;; Note: `nickname` and `email` options will normalize input strings using the following criteria:
|
||||||
|
;; - diacritics are removed
|
||||||
|
;; - the characters in the set `['´\x60]` are removed
|
||||||
|
;; - the characters in the set `[\s~+]` are replaced with `-`
|
||||||
;USERNAME = nickname
|
;USERNAME = nickname
|
||||||
;;
|
;;
|
||||||
;; Update avatar if available from oauth2 provider.
|
;; Update avatar if available from oauth2 provider.
|
||||||
@@ -1697,9 +1712,6 @@ LEVEL = Info
|
|||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;
|
;;
|
||||||
;; if the cache enabled
|
|
||||||
;ENABLED = true
|
|
||||||
;;
|
|
||||||
;; Either "memory", "redis", "memcache", or "twoqueue". default is "memory"
|
;; Either "memory", "redis", "memcache", or "twoqueue". default is "memory"
|
||||||
;ADAPTER = memory
|
;ADAPTER = memory
|
||||||
;;
|
;;
|
||||||
@@ -1724,8 +1736,6 @@ LEVEL = Info
|
|||||||
;[cache.last_commit]
|
;[cache.last_commit]
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; if the cache enabled
|
|
||||||
;ENABLED = true
|
|
||||||
;;
|
;;
|
||||||
;; Time to keep items in cache if not used, default is 8760 hours.
|
;; Time to keep items in cache if not used, default is 8760 hours.
|
||||||
;; Setting it to -1 disables caching
|
;; Setting it to -1 disables caching
|
||||||
@@ -2575,7 +2585,7 @@ LEVEL = Info
|
|||||||
;;
|
;;
|
||||||
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||||
;DEFAULT_ACTIONS_URL = github
|
;DEFAULT_ACTIONS_URL = github
|
||||||
;; Default artifact retention time in days, default is 90 days
|
;; Default artifact retention time in days. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
|
||||||
;ARTIFACT_RETENTION_DAYS = 90
|
;ARTIFACT_RETENTION_DAYS = 90
|
||||||
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
;; Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
;ZOMBIE_TASK_TIMEOUT = 10m
|
;ZOMBIE_TASK_TIMEOUT = 10m
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ Some jurisdictions (such as EU), requires certain legal pages (e.g. Privacy Poli
|
|||||||
|
|
||||||
## Getting Pages
|
## Getting Pages
|
||||||
|
|
||||||
Gitea source code ships with sample pages, available in `contrib/legal` directory. Copy them to `custom/public/`. For example, to add Privacy Policy:
|
Gitea source code ships with sample pages, available in `contrib/legal` directory. Copy them to `custom/public/assets/`. For example, to add Privacy Policy:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget -O /path/to/custom/public/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
wget -O /path/to/custom/public/assets/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you need to edit the page to meet your requirements. In particular you must change the email addresses, web addresses and references to "Your Gitea Instance" to match your situation.
|
Now you need to edit the page to meet your requirements. In particular you must change the email addresses, web addresses and references to "Your Gitea Instance" to match your situation.
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ menu:
|
|||||||
|
|
||||||
## 获取页面
|
## 获取页面
|
||||||
|
|
||||||
Gitea 源代码附带了示例页面,位于 `contrib/legal` 目录中。将它们复制到 `custom/public/` 目录下。例如,如果要添加隐私政策:
|
Gitea 源代码附带了示例页面,位于 `contrib/legal` 目录中。将它们复制到 `custom/public/assets/` 目录下。例如,如果要添加隐私政策:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget -O /path/to/custom/public/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
wget -O /path/to/custom/public/assets/privacy.html https://raw.githubusercontent.com/go-gitea/gitea/main/contrib/legal/privacy.html.sample
|
||||||
```
|
```
|
||||||
|
|
||||||
现在,你需要编辑该页面以满足你的需求。特别是,你必须更改电子邮件地址、网址以及与 "Your Gitea Instance" 相关的引用,以匹配你的情况。
|
现在,你需要编辑该页面以满足你的需求。特别是,你必须更改电子邮件地址、网址以及与 "Your Gitea Instance" 相关的引用,以匹配你的情况。
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ In addition, there is _`StaticRootPath`_ which can be set as a built-in at build
|
|||||||
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
|
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
|
||||||
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
|
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
|
||||||
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
|
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
|
||||||
|
- `RETARGET_CHILDREN_ON_MERGE`: **true**: Retarget child pull requests to the parent pull request branch target on merge of parent pull request. It only works on merged PRs where the head and base branch target the same repo.
|
||||||
|
|
||||||
### Repository - Issue (`repository.issue`)
|
### Repository - Issue (`repository.issue`)
|
||||||
|
|
||||||
@@ -196,9 +197,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||||||
## CORS (`cors`)
|
## CORS (`cors`)
|
||||||
|
|
||||||
- `ENABLED`: **false**: enable cors headers (disabled by default)
|
- `ENABLED`: **false**: enable cors headers (disabled by default)
|
||||||
- `SCHEME`: **http**: scheme of allowed requests
|
- `ALLOW_DOMAIN`: **\***: list of requesting origins that are allowed, eg: "https://*.example.com"
|
||||||
- `ALLOW_DOMAIN`: **\***: list of requesting domains that are allowed
|
|
||||||
- `ALLOW_SUBDOMAIN`: **false**: allow subdomains of headers listed above to request
|
|
||||||
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request
|
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: list of methods allowed to request
|
||||||
- `MAX_AGE`: **10m**: max time to cache response
|
- `MAX_AGE`: **10m**: max time to cache response
|
||||||
- `ALLOW_CREDENTIALS`: **false**: allow request with credentials
|
- `ALLOW_CREDENTIALS`: **false**: allow request with credentials
|
||||||
@@ -220,6 +219,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||||||
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
|
- `THEMES`: **gitea-auto,gitea-light,gitea-dark**: All available themes. Allow users select personalized themes.
|
||||||
regardless of the value of `DEFAULT_THEME`.
|
regardless of the value of `DEFAULT_THEME`.
|
||||||
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
|
- `MAX_DISPLAY_FILE_SIZE`: **8388608**: Max size of files to be displayed (default is 8MiB)
|
||||||
|
- `AMBIGUOUS_UNICODE_DETECTION`: **true**: Detect ambiguous unicode characters in file contents and show warnings on the UI
|
||||||
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
|
- `REACTIONS`: All available reactions users can choose on issues/prs and comments
|
||||||
Values can be emoji alias (:smile:) or a unicode emoji.
|
Values can be emoji alias (:smile:) or a unicode emoji.
|
||||||
For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
|
For custom reactions, add a tightly cropped square image to public/assets/img/emoji/reaction_name.png
|
||||||
@@ -232,6 +232,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||||||
- `ONLY_SHOW_RELEVANT_REPOS`: **false**: Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
|
- `ONLY_SHOW_RELEVANT_REPOS`: **false**: Whether to only show relevant repos on the explore page when no keyword is specified and default sorting is used.
|
||||||
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
|
A repo is considered irrelevant if it's a fork or if it has no metadata (no description, no icon, no topic).
|
||||||
- `EXPLORE_PAGING_DEFAULT_SORT`: **recentupdate**: Change the sort type of the explore pages. Valid values are "recentupdate", "alphabetically", "reverselastlogin", "newest" and "oldest"
|
- `EXPLORE_PAGING_DEFAULT_SORT`: **recentupdate**: Change the sort type of the explore pages. Valid values are "recentupdate", "alphabetically", "reverselastlogin", "newest" and "oldest"
|
||||||
|
- `PREFERRED_TIMESTAMP_TENSE`: **mixed**: The tense all timestamps should be rendered in. Possible values are `absolute` time (i.e. 1970-01-01, 11:59) and `mixed`. `mixed` means most timestamps are rendered in relative time (i.e. 2 days ago).
|
||||||
|
|
||||||
### UI - Admin (`ui.admin`)
|
### UI - Admin (`ui.admin`)
|
||||||
|
|
||||||
@@ -356,7 +357,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||||||
- `SSH_PER_WRITE_PER_KB_TIMEOUT`: **10s**: Timeout per Kb written to SSH connections.
|
- `SSH_PER_WRITE_PER_KB_TIMEOUT`: **10s**: Timeout per Kb written to SSH connections.
|
||||||
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
|
- `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type.
|
||||||
|
|
||||||
- `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures.
|
- `OFFLINE_MODE`: **true**: Disables use of CDN for static files and Gravatar for profile pictures.
|
||||||
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
||||||
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`.
|
||||||
- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**: Upper level of template and static files path.
|
- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**: Upper level of template and static files path.
|
||||||
@@ -430,6 +431,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
|||||||
- `NAME`: **gitea**: Database name.
|
- `NAME`: **gitea**: Database name.
|
||||||
- `USER`: **root**: Database username.
|
- `USER`: **root**: Database username.
|
||||||
- `PASSWD`: **_empty_**: Database user password. Use \`your password\` or """your password""" for quoting if you use special characters in the password.
|
- `PASSWD`: **_empty_**: Database user password. Use \`your password\` or """your password""" for quoting if you use special characters in the password.
|
||||||
|
- `CHARSET_COLLATION`: **_empty_**: (MySQL/MSSQL only) Gitea expects to use a case-sensitive collation for database. Leave it empty to use the default collation decided by the Gitea. Don't change it unless you clearly know what you need.
|
||||||
- `SCHEMA`: **_empty_**: For PostgreSQL only, schema to use if different from "public". The schema must exist beforehand,
|
- `SCHEMA`: **_empty_**: For PostgreSQL only, schema to use if different from "public". The schema must exist beforehand,
|
||||||
the user must have creation privileges on it, and the user search path must be set to the look into the schema first
|
the user must have creation privileges on it, and the user search path must be set to the look into the schema first
|
||||||
(e.g. `ALTER USER user SET SEARCH_PATH = schema_name,"$user",public;`).
|
(e.g. `ALTER USER user SET SEARCH_PATH = schema_name,"$user",public;`).
|
||||||
@@ -572,6 +574,7 @@ And the following unique queues:
|
|||||||
- off - do not check password complexity
|
- off - do not check password complexity
|
||||||
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
|
- `PASSWORD_CHECK_PWN`: **false**: Check [HaveIBeenPwned](https://haveibeenpwned.com/Passwords) to see if a password has been exposed.
|
||||||
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
- `SUCCESSFUL_TOKENS_CACHE_SIZE`: **20**: Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations. This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
|
||||||
|
- `DISABLE_QUERY_AUTH_TOKEN`: **false**: Reject API tokens sent in URL query string (Accept Header-based API tokens only). This setting will default to `true` in Gitea 1.23 and be deprecated in Gitea 1.24.
|
||||||
|
|
||||||
## Camo (`camo`)
|
## Camo (`camo`)
|
||||||
|
|
||||||
@@ -595,9 +598,13 @@ And the following unique queues:
|
|||||||
- `OPENID_CONNECT_SCOPES`: **_empty_**: List of additional openid connect scopes. (`openid` is implicitly added)
|
- `OPENID_CONNECT_SCOPES`: **_empty_**: List of additional openid connect scopes. (`openid` is implicitly added)
|
||||||
- `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users.
|
- `ENABLE_AUTO_REGISTRATION`: **false**: Automatically create user accounts for new oauth2 users.
|
||||||
- `USERNAME`: **nickname**: The source of the username for new oauth2 accounts:
|
- `USERNAME`: **nickname**: The source of the username for new oauth2 accounts:
|
||||||
- userid - use the userid / sub attribute
|
- `userid` - use the userid / sub attribute
|
||||||
- nickname - use the nickname attribute
|
- `nickname` - use the nickname attribute
|
||||||
- email - use the username part of the email attribute
|
- `email` - use the username part of the email attribute
|
||||||
|
- Note: `nickname` and `email` options will normalize input strings using the following criteria:
|
||||||
|
- diacritics are removed
|
||||||
|
- the characters in the set `['´\x60]` are removed
|
||||||
|
- the characters in the set `[\s~+]` are replaced with `-`
|
||||||
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
|
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
|
||||||
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
|
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:
|
||||||
- disabled - show an error
|
- disabled - show an error
|
||||||
@@ -761,7 +768,6 @@ and
|
|||||||
|
|
||||||
## Cache (`cache`)
|
## Cache (`cache`)
|
||||||
|
|
||||||
- `ENABLED`: **true**: Enable the cache.
|
|
||||||
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
|
- `ADAPTER`: **memory**: Cache engine adapter, either `memory`, `redis`, `redis-cluster`, `twoqueue` or `memcache`. (`twoqueue` represents a size limited LRU cache.)
|
||||||
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
|
- `INTERVAL`: **60**: Garbage Collection interval (sec), for memory and twoqueue cache only.
|
||||||
- `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue.
|
- `HOST`: **_empty_**: Connection string for `redis`, `redis-cluster` and `memcache`. For `twoqueue` sets configuration for the queue.
|
||||||
@@ -773,7 +779,6 @@ and
|
|||||||
|
|
||||||
## Cache - LastCommitCache settings (`cache.last_commit`)
|
## Cache - LastCommitCache settings (`cache.last_commit`)
|
||||||
|
|
||||||
- `ENABLED`: **true**: Enable the cache.
|
|
||||||
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
|
- `ITEM_TTL`: **8760h**: Time to keep items in cache if not used, Setting it to -1 disables caching.
|
||||||
- `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than.
|
- `COMMITS_COUNT`: **1000**: Only enable the cache when repository's commits count great than.
|
||||||
|
|
||||||
@@ -1392,15 +1397,15 @@ PROXY_HOSTS = *.github.com
|
|||||||
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
|
||||||
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||||
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`
|
||||||
- `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set.
|
- `ARTIFACT_RETENTION_DAYS`: **90**: Default number of days to keep artifacts. Artifacts could have their own retention periods by setting the `retention-days` option in `actions/upload-artifact` step.
|
||||||
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time
|
||||||
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time
|
||||||
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time
|
||||||
- `SKIP_WORKFLOW_STRINGS`: **[skip ci],[ci skip],[no ci],[skip actions],[actions skip]**: Strings committers can place inside a commit message to skip executing the corresponding actions workflow
|
- `SKIP_WORKFLOW_STRINGS`: **[skip ci],[ci skip],[no ci],[skip actions],[actions skip]**: Strings committers can place inside a commit message to skip executing the corresponding actions workflow
|
||||||
|
|
||||||
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
|
||||||
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
For example, `uses: actions/checkout@v4` means `https://github.com/actions/checkout@v4` since the value of `DEFAULT_ACTIONS_URL` is `github`.
|
||||||
And it can be changed to `self` to make it `root_url_of_your_gitea/actions/checkout@v3`.
|
And it can be changed to `self` to make it `root_url_of_your_gitea/actions/checkout@v4`.
|
||||||
|
|
||||||
Please note that using `self` is not recommended for most cases, as it could make names globally ambiguous.
|
Please note that using `self` is not recommended for most cases, as it could make names globally ambiguous.
|
||||||
Additionally, it requires you to mirror all the actions you need to your Gitea instance, which may not be worth it.
|
Additionally, it requires you to mirror all the actions you need to your Gitea instance, which may not be worth it.
|
||||||
@@ -1409,7 +1414,7 @@ Therefore, please use `self` only if you understand what you are doing.
|
|||||||
In earlier versions (`<= 1.19`), `DEFAULT_ACTIONS_URL` could be set to any custom URLs like `https://gitea.com` or `http://your-git-server,https://gitea.com`, and the default value was `https://gitea.com`.
|
In earlier versions (`<= 1.19`), `DEFAULT_ACTIONS_URL` could be set to any custom URLs like `https://gitea.com` or `http://your-git-server,https://gitea.com`, and the default value was `https://gitea.com`.
|
||||||
However, later updates removed those options, and now the only options are `github` and `self`, with the default value being `github`.
|
However, later updates removed those options, and now the only options are `github` and `self`, with the default value being `github`.
|
||||||
However, if you want to use actions from other git server, you can use a complete URL in `uses` field, it's supported by Gitea (but not GitHub).
|
However, if you want to use actions from other git server, you can use a complete URL in `uses` field, it's supported by Gitea (but not GitHub).
|
||||||
Like `uses: https://gitea.com/actions/checkout@v3` or `uses: http://your-git-server/actions/checkout@v3`.
|
Like `uses: https://gitea.com/actions/checkout@v4` or `uses: http://your-git-server/actions/checkout@v4`.
|
||||||
|
|
||||||
## Other (`other`)
|
## Other (`other`)
|
||||||
|
|
||||||
|
|||||||
@@ -195,9 +195,7 @@ menu:
|
|||||||
## 跨域 (`cors`)
|
## 跨域 (`cors`)
|
||||||
|
|
||||||
- `ENABLED`: **false**: 启用 CORS 头部(默认禁用)
|
- `ENABLED`: **false**: 启用 CORS 头部(默认禁用)
|
||||||
- `SCHEME`: **http**: 允许请求的协议
|
|
||||||
- `ALLOW_DOMAIN`: **\***: 允许请求的域名列表
|
- `ALLOW_DOMAIN`: **\***: 允许请求的域名列表
|
||||||
- `ALLOW_SUBDOMAIN`: **false**: 允许上述列出的头部的子域名发出请求。
|
|
||||||
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: 允许发起的请求方式列表
|
- `METHODS`: **GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS**: 允许发起的请求方式列表
|
||||||
- `MAX_AGE`: **10m**: 缓存响应的最大时间
|
- `MAX_AGE`: **10m**: 缓存响应的最大时间
|
||||||
- `ALLOW_CREDENTIALS`: **false**: 允许带有凭据的请求
|
- `ALLOW_CREDENTIALS`: **false**: 允许带有凭据的请求
|
||||||
@@ -346,7 +344,7 @@ menu:
|
|||||||
- `SSH_PER_WRITE_TIMEOUT`: **30s**:对 SSH 连接的任何写入设置超时。(将其设置为 -1 可以禁用所有超时。)
|
- `SSH_PER_WRITE_TIMEOUT`: **30s**:对 SSH 连接的任何写入设置超时。(将其设置为 -1 可以禁用所有超时。)
|
||||||
- `SSH_PER_WRITE_PER_KB_TIMEOUT`: **10s**:对写入 SSH 连接的每 KB 设置超时。
|
- `SSH_PER_WRITE_PER_KB_TIMEOUT`: **10s**:对写入 SSH 连接的每 KB 设置超时。
|
||||||
- `MINIMUM_KEY_SIZE_CHECK`: **true**:指示是否检查最小密钥大小与相应类型。
|
- `MINIMUM_KEY_SIZE_CHECK`: **true**:指示是否检查最小密钥大小与相应类型。
|
||||||
- `OFFLINE_MODE`: **false**:禁用 CDN 用于静态文件和 Gravatar 用于个人资料图片。
|
- `OFFLINE_MODE`: **true**:禁用 CDN 用于静态文件和 Gravatar 用于个人资料图片。
|
||||||
- `CERT_FILE`: **https/cert.pem**:用于 HTTPS 的证书文件路径。在链接时,服务器证书必须首先出现,然后是中间 CA 证书(如果有)。如果 `ENABLE_ACME=true`,则此设置会被忽略。路径相对于 `CUSTOM_PATH`。
|
- `CERT_FILE`: **https/cert.pem**:用于 HTTPS 的证书文件路径。在链接时,服务器证书必须首先出现,然后是中间 CA 证书(如果有)。如果 `ENABLE_ACME=true`,则此设置会被忽略。路径相对于 `CUSTOM_PATH`。
|
||||||
- `KEY_FILE`: **https/key.pem**:用于 HTTPS 的密钥文件路径。如果 `ENABLE_ACME=true`,则此设置会被忽略。路径相对于 `CUSTOM_PATH`。
|
- `KEY_FILE`: **https/key.pem**:用于 HTTPS 的密钥文件路径。如果 `ENABLE_ACME=true`,则此设置会被忽略。路径相对于 `CUSTOM_PATH`。
|
||||||
- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**:模板和静态文件路径的上一级。
|
- `STATIC_ROOT_PATH`: **_`StaticRootPath`_**:模板和静态文件路径的上一级。
|
||||||
@@ -721,7 +719,6 @@ Gitea 创建以下非唯一队列:
|
|||||||
|
|
||||||
## 缓存 (`cache`)
|
## 缓存 (`cache`)
|
||||||
|
|
||||||
- `ENABLED`: **true**: 是否启用缓存。
|
|
||||||
- `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis`, `redis-cluster`, `twoqueue` 和 `memcache`. (`twoqueue` 代表缓冲区固定的LRU缓存)
|
- `ADAPTER`: **memory**: 缓存引擎,可以为 `memory`, `redis`, `redis-cluster`, `twoqueue` 和 `memcache`. (`twoqueue` 代表缓冲区固定的LRU缓存)
|
||||||
- `INTERVAL`: **60**: 垃圾回收间隔(秒),只对`memory`和`towqueue`有效。
|
- `INTERVAL`: **60**: 垃圾回收间隔(秒),只对`memory`和`towqueue`有效。
|
||||||
- `HOST`: **_empty_**: 缓存配置。`redis`, `redis-cluster`,`memcache`配置连接字符串;`twoqueue` 设置队列参数
|
- `HOST`: **_empty_**: 缓存配置。`redis`, `redis-cluster`,`memcache`配置连接字符串;`twoqueue` 设置队列参数
|
||||||
@@ -733,7 +730,6 @@ Gitea 创建以下非唯一队列:
|
|||||||
|
|
||||||
### 缓存 - 最后提交缓存设置 (`cache.last_commit`)
|
### 缓存 - 最后提交缓存设置 (`cache.last_commit`)
|
||||||
|
|
||||||
- `ENABLED`: **true**:是否启用缓存。
|
|
||||||
- `ITEM_TTL`: **8760h**:如果未使用,保持缓存中的项目的时间,将其设置为 -1 会禁用缓存。
|
- `ITEM_TTL`: **8760h**:如果未使用,保持缓存中的项目的时间,将其设置为 -1 会禁用缓存。
|
||||||
- `COMMITS_COUNT`: **1000**:仅在存储库的提交计数大于时启用缓存。
|
- `COMMITS_COUNT`: **1000**:仅在存储库的提交计数大于时启用缓存。
|
||||||
|
|
||||||
@@ -991,7 +987,7 @@ Gitea 创建以下非唯一队列:
|
|||||||
- `LAST_UPDATED_MORE_THAN_AGO`: **72h**: 只会尝试回收超过此时间(默认3天)没有尝试过回收的 LFSMetaObject。
|
- `LAST_UPDATED_MORE_THAN_AGO`: **72h**: 只会尝试回收超过此时间(默认3天)没有尝试过回收的 LFSMetaObject。
|
||||||
- `NUMBER_TO_CHECK_PER_REPO`: **100**: 每个仓库要检查的过期 LFSMetaObject 的最小数量。设置为 `0` 以始终检查所有。
|
- `NUMBER_TO_CHECK_PER_REPO`: **100**: 每个仓库要检查的过期 LFSMetaObject 的最小数量。设置为 `0` 以始终检查所有。
|
||||||
|
|
||||||
# Git (`git`)
|
## Git (`git`)
|
||||||
|
|
||||||
- `PATH`: **""**: Git可执行文件的路径。如果为空,Gitea将在PATH环境中搜索。
|
- `PATH`: **""**: Git可执行文件的路径。如果为空,Gitea将在PATH环境中搜索。
|
||||||
- `HOME_PATH`: **%(APP_DATA_PATH)s/home**: Git的HOME目录。
|
- `HOME_PATH`: **%(APP_DATA_PATH)s/home**: Git的HOME目录。
|
||||||
@@ -1039,10 +1035,11 @@ Gitea 创建以下非唯一队列:
|
|||||||
|
|
||||||
## API (`api`)
|
## API (`api`)
|
||||||
|
|
||||||
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 (`/api/swagger`, `/api/v1/swagger`, …)。
|
- `ENABLE_SWAGGER`: **true**: 启用API文档接口 (`/api/swagger`, `/api/v1/swagger`, …). True or false。
|
||||||
- `MAX_RESPONSE_ITEMS`: **50**: 单个页面的最大 Feed.
|
- `MAX_RESPONSE_ITEMS`: **50**: API分页的最大单页项目数。
|
||||||
- `ENABLE_OPENID_SIGNIN`: **false**: 允许使用OpenID登录,当设置为`true`时可以通过 `/user/login` 页面进行OpenID登录。
|
- `DEFAULT_PAGING_NUM`: **30**: API分页的默认分页数。
|
||||||
- `DISABLE_REGISTRATION`: **false**: 关闭用户注册。
|
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: Git trees API的默认单页项目数。
|
||||||
|
- `DEFAULT_MAX_BLOB_SIZE`: **10485760** (10MiB): blobs API的默认最大文件大小。
|
||||||
|
|
||||||
## OAuth2 (`oauth2`)
|
## OAuth2 (`oauth2`)
|
||||||
|
|
||||||
@@ -1336,8 +1333,8 @@ PROXY_HOSTS = *.github.com
|
|||||||
- `MINIO_BASE_PATH`: **actions_log/**:Minio存储桶上的基本路径,仅在`STORAGE_TYPE`为`minio`时可用。
|
- `MINIO_BASE_PATH`: **actions_log/**:Minio存储桶上的基本路径,仅在`STORAGE_TYPE`为`minio`时可用。
|
||||||
|
|
||||||
`DEFAULT_ACTIONS_URL` 指示 Gitea 操作运行程序应该在哪里找到带有相对路径的操作。
|
`DEFAULT_ACTIONS_URL` 指示 Gitea 操作运行程序应该在哪里找到带有相对路径的操作。
|
||||||
例如,`uses: actions/checkout@v3` 表示 `https://github.com/actions/checkout@v3`,因为 `DEFAULT_ACTIONS_URL` 的值为 `github`。
|
例如,`uses: actions/checkout@v4` 表示 `https://github.com/actions/checkout@v4`,因为 `DEFAULT_ACTIONS_URL` 的值为 `github`。
|
||||||
它可以更改为 `self`,以使其成为 `root_url_of_your_gitea/actions/checkout@v3`。
|
它可以更改为 `self`,以使其成为 `root_url_of_your_gitea/actions/checkout@v4`。
|
||||||
|
|
||||||
请注意,对于大多数情况,不建议使用 `self`,因为它可能使名称在全局范围内产生歧义。
|
请注意,对于大多数情况,不建议使用 `self`,因为它可能使名称在全局范围内产生歧义。
|
||||||
此外,它要求您将所有所需的操作镜像到您的 Gitea 实例,这可能不值得。
|
此外,它要求您将所有所需的操作镜像到您的 Gitea 实例,这可能不值得。
|
||||||
@@ -1346,7 +1343,7 @@ PROXY_HOSTS = *.github.com
|
|||||||
在早期版本(`<= 1.19`)中,`DEFAULT_ACTIONS_URL` 可以设置为任何自定义 URL,例如 `https://gitea.com` 或 `http://your-git-server,https://gitea.com`,默认值为 `https://gitea.com`。
|
在早期版本(`<= 1.19`)中,`DEFAULT_ACTIONS_URL` 可以设置为任何自定义 URL,例如 `https://gitea.com` 或 `http://your-git-server,https://gitea.com`,默认值为 `https://gitea.com`。
|
||||||
然而,后来的更新删除了这些选项,现在唯一的选项是 `github` 和 `self`,默认值为 `github`。
|
然而,后来的更新删除了这些选项,现在唯一的选项是 `github` 和 `self`,默认值为 `github`。
|
||||||
但是,如果您想要使用其他 Git 服务器中的操作,您可以在 `uses` 字段中使用完整的 URL,Gitea 支持此功能(GitHub 不支持)。
|
但是,如果您想要使用其他 Git 服务器中的操作,您可以在 `uses` 字段中使用完整的 URL,Gitea 支持此功能(GitHub 不支持)。
|
||||||
例如 `uses: https://gitea.com/actions/checkout@v3` 或 `uses: http://your-git-server/actions/checkout@v3`。
|
例如 `uses: https://gitea.com/actions/checkout@v4` 或 `uses: http://your-git-server/actions/checkout@v4`。
|
||||||
|
|
||||||
## 其他 (`other`)
|
## 其他 (`other`)
|
||||||
|
|
||||||
|
|||||||
@@ -42,11 +42,11 @@ Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板
|
|||||||
|
|
||||||
将自定义的公共文件(比如页面和图片)作为 webroot 放在 `custom/public/` 中来让 Gitea 提供这些自定义内容(符号链接将被追踪)。
|
将自定义的公共文件(比如页面和图片)作为 webroot 放在 `custom/public/` 中来让 Gitea 提供这些自定义内容(符号链接将被追踪)。
|
||||||
|
|
||||||
举例说明:`image.png` 存放在 `custom/public/`中,那么它可以通过链接 http://gitea.domain.tld/assets/image.png 访问。
|
举例说明:`image.png` 存放在 `custom/public/assets/`中,那么它可以通过链接 http://gitea.domain.tld/assets/image.png 访问。
|
||||||
|
|
||||||
## 修改默认头像
|
## 修改默认头像
|
||||||
|
|
||||||
替换以下目录中的 png 图片: `custom/public/img/avatar\_default.png`
|
替换以下目录中的 png 图片: `custom/public/assets/img/avatar\_default.png`
|
||||||
|
|
||||||
## 自定义 Gitea 页面
|
## 自定义 Gitea 页面
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ PASSWD = `password`
|
|||||||
|
|
||||||
要发送测试邮件以验证设置,请转到 Gitea > 站点管理 > 配置 > SMTP 邮件配置。
|
要发送测试邮件以验证设置,请转到 Gitea > 站点管理 > 配置 > SMTP 邮件配置。
|
||||||
|
|
||||||
有关所有选项的完整列表,请查看[配置速查表](doc/administration/config-cheat-sheet.md)。
|
有关所有选项的完整列表,请查看[配置速查表](administration/config-cheat-sheet.md)。
|
||||||
|
|
||||||
请注意:只有在使用 TLS 或 `HOST=localhost` 加密 SMTP 服务器通信时才支持身份验证。TLS 加密可以通过以下方式进行:
|
请注意:只有在使用 TLS 或 `HOST=localhost` 加密 SMTP 服务器通信时才支持身份验证。TLS 加密可以通过以下方式进行:
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ ALLOW_DATA_URI_IMAGES = true
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
将您的样式表添加到自定义目录中,例如 `custom/public/css/my-style-XXXXX.css`,并使用自定义的头文件 `custom/templates/custom/header.tmpl` 进行导入:
|
将您的样式表添加到自定义目录中,例如 `custom/public/assets/css/my-style-XXXXX.css`,并使用自定义的头文件 `custom/templates/custom/header.tmpl` 进行导入:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="{{AppSubUrl}}/assets/css/my-style-XXXXX.css" />
|
<link rel="stylesheet" href="{{AppSubUrl}}/assets/css/my-style-XXXXX.css" />
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ CERT_FILE = cert.pem
|
|||||||
KEY_FILE = key.pem
|
KEY_FILE = key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
请注意,如果您的证书由第三方证书颁发机构签名(即不是自签名的),则 cert.pem 应包含证书链。服务器证书必须是 cert.pem 中的第一个条目,后跟中介(如果有)。不必包含根证书,因为连接客户端必须已经拥有根证书才能建立信任关系。要了解有关配置值的更多信息,请查看 [配置备忘单](../config-cheat-sheet#server-server)。
|
请注意,如果您的证书由第三方证书颁发机构签名(即不是自签名的),则 cert.pem 应包含证书链。服务器证书必须是 cert.pem 中的第一个条目,后跟中介(如果有)。不必包含根证书,因为连接客户端必须已经拥有根证书才能建立信任关系。要了解有关配置值的更多信息,请查看 [配置备忘单](administration/config-cheat-sheet#server-server)。
|
||||||
|
|
||||||
对于“CERT_FILE”或“KEY_FILE”字段,当文件路径是相对路径时,文件路径相对于“GITEA_CUSTOM”环境变量。它也可以是绝对路径。
|
对于“CERT_FILE”或“KEY_FILE”字段,当文件路径是相对路径时,文件路径相对于“GITEA_CUSTOM”环境变量。它也可以是绝对路径。
|
||||||
|
|
||||||
|
|||||||
@@ -48,11 +48,12 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h
|
|||||||
10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
|
10. Avoid mixing different events in one event listener, prefer to use individual event listeners for every event.
|
||||||
11. Custom event names are recommended to use `ce-` prefix.
|
11. Custom event names are recommended to use `ce-` prefix.
|
||||||
12. Gitea's tailwind-style CSS classes use `gt-` prefix (`gt-relative`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
|
12. Gitea's tailwind-style CSS classes use `gt-` prefix (`gt-relative`), while Gitea's own private framework-level CSS classes use `g-` prefix (`g-modal-confirm`).
|
||||||
|
13. Avoid inline scripts & styles as much as possible, it's recommended to put JS code into JS files and use CSS classes. If inline scripts & styles are unavoidable, explain the reason why it can't be avoided.
|
||||||
|
|
||||||
### Accessibility / ARIA
|
### Accessibility / ARIA
|
||||||
|
|
||||||
In history, Gitea heavily uses Fomantic UI which is not an accessibility-friendly framework.
|
In history, Gitea heavily uses Fomantic UI which is not an accessibility-friendly framework.
|
||||||
Gitea uses some patches to make Fomantic UI more accessible (see the `aria.js` and `aria.md`),
|
Gitea uses some patches to make Fomantic UI more accessible (see `aria.md` and related JS files),
|
||||||
but there are still many problems which need a lot of work and time to fix.
|
but there are still many problems which need a lot of work and time to fix.
|
||||||
|
|
||||||
### Framework Usage
|
### Framework Usage
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ menu:
|
|||||||
|
|
||||||
## Enabling/configuring API access
|
## Enabling/configuring API access
|
||||||
|
|
||||||
By default, `ENABLE_SWAGGER` is true, and
|
By default, `ENABLE_SWAGGER` is true, and `MAX_RESPONSE_ITEMS` is set to 50. See [Config Cheat Sheet](administration/config-cheat-sheet.md) for more information.
|
||||||
`MAX_RESPONSE_ITEMS` is set to 50. See [Config Cheat
|
|
||||||
Sheet](administration/config-cheat-sheet.md) for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ menu:
|
|||||||
|
|
||||||
## 开启/配置 API 访问
|
## 开启/配置 API 访问
|
||||||
|
|
||||||
通常情况下, `ENABLE_SWAGGER` 默认开启并且参数 `MAX_RESPONSE_ITEMS` 默认为 50。您可以从 [Config Cheat
|
通常情况下, `ENABLE_SWAGGER` 默认开启并且参数 `MAX_RESPONSE_ITEMS` 默认为 50。您可以从 [Config Cheat Sheet](administration/config-cheat-sheet.md) 中获取更多配置相关信息。
|
||||||
Sheet](administration/config-cheat-sheet.md) 中获取更多配置相关信息。
|
|
||||||
|
|
||||||
## 通过 API 认证
|
## 通过 API 认证
|
||||||
|
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ If you are receiving errors on upgrade of Gitea using MySQL that read:
|
|||||||
|
|
||||||
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
|
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
|
||||||
|
|
||||||
Please run `gitea convert` or run `ALTER TABLE table_name ROW_FORMAT=dynamic;` for each table in the database.
|
Please run `gitea doctor convert` or run `ALTER TABLE table_name ROW_FORMAT=dynamic;` for each table in the database.
|
||||||
|
|
||||||
The underlying problem is that the space allocated for indices by the default row format
|
The underlying problem is that the space allocated for indices by the default row format
|
||||||
is too small. Gitea requires that the `ROWFORMAT` for its tables is `DYNAMIC`.
|
is too small. Gitea requires that the `ROWFORMAT` for its tables is `DYNAMIC`.
|
||||||
@@ -371,24 +371,6 @@ If you are receiving an error line containing `Error 1071: Specified key was too
|
|||||||
then you are attempting to run Gitea on tables which use the ISAM engine. While this may have worked by chance in previous versions of Gitea, it has never been officially supported and
|
then you are attempting to run Gitea on tables which use the ISAM engine. While this may have worked by chance in previous versions of Gitea, it has never been officially supported and
|
||||||
you must use InnoDB. You should run `ALTER TABLE table_name ENGINE=InnoDB;` for each table in the database.
|
you must use InnoDB. You should run `ALTER TABLE table_name ENGINE=InnoDB;` for each table in the database.
|
||||||
|
|
||||||
If you are using MySQL 5, another possible fix is
|
|
||||||
|
|
||||||
```mysql
|
|
||||||
SET GLOBAL innodb_file_format=Barracuda;
|
|
||||||
SET GLOBAL innodb_file_per_table=1;
|
|
||||||
SET GLOBAL innodb_large_prefix=1;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why Are Emoji Broken On MySQL
|
|
||||||
|
|
||||||
Unfortunately MySQL's `utf8` charset does not completely allow all possible UTF-8 characters, in particular Emoji.
|
|
||||||
They created a new charset and collation called `utf8mb4` that allows for emoji to be stored but tables which use
|
|
||||||
the `utf8` charset, and connections which use the `utf8` charset will not use this.
|
|
||||||
|
|
||||||
Please run `gitea convert`, or run `ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
|
|
||||||
for the database_name and run `ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
|
|
||||||
for each table in the database.
|
|
||||||
|
|
||||||
## Why are Emoji displaying only as placeholders or in monochrome
|
## Why are Emoji displaying only as placeholders or in monochrome
|
||||||
|
|
||||||
Gitea requires the system or browser to have one of the supported Emoji fonts installed, which are Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji and Twemoji Mozilla. Generally, the operating system should already provide one of these fonts, but especially on Linux, it may be necessary to install them manually.
|
Gitea requires the system or browser to have one of the supported Emoji fonts installed, which are Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji and Twemoji Mozilla. Generally, the operating system should already provide one of these fonts, but especially on Linux, it may be necessary to install them manually.
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ Gitea 目前支持三个官方主题,分别是 `gitea-light`、`gitea-dark`
|
|||||||
|
|
||||||
假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到)
|
假设我们的主题是 `arc-blue`(这是一个真实的主题,可以在[此问题](https://github.com/go-gitea/gitea/issues/6011)中找到)
|
||||||
|
|
||||||
将`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/css`文件夹中
|
将`.css`文件命名为`theme-arc-blue.css`并将其添加到`custom/public/assets/css`文件夹中
|
||||||
|
|
||||||
通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题
|
通过将`arc-blue`添加到`app.ini`中的`THEMES`列表中,允许用户使用该主题
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ Gitea 提供了一个子命令`gitea migrate`来初始化数据库,然后您
|
|||||||
|
|
||||||
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
|
> `ORM engine initialization failed: migrate: do migrate: Error: 1118: Row size too large...`
|
||||||
|
|
||||||
请运行`gitea convert`或对数据库中的每个表运行`ALTER TABLE table_name ROW_FORMAT=dynamic;`。
|
请运行 `gitea doctor convert` 或对数据库中的每个表运行 `ALTER TABLE table_name ROW_FORMAT=dynamic;`。
|
||||||
|
|
||||||
潜在问题是默认行格式分配给每个表的索引空间
|
潜在问题是默认行格式分配给每个表的索引空间
|
||||||
太小。Gitea 要求其表的`ROWFORMAT`为`DYNAMIC`。
|
太小。Gitea 要求其表的`ROWFORMAT`为`DYNAMIC`。
|
||||||
@@ -375,26 +375,6 @@ Gitea 提供了一个子命令`gitea migrate`来初始化数据库,然后您
|
|||||||
的错误行,则表示您正在尝试在使用 ISAM 引擎的表上运行 Gitea。尽管在先前版本的 Gitea 中可能是凑巧能够工作的,但它从未得到官方支持,
|
的错误行,则表示您正在尝试在使用 ISAM 引擎的表上运行 Gitea。尽管在先前版本的 Gitea 中可能是凑巧能够工作的,但它从未得到官方支持,
|
||||||
您必须使用 InnoDB。您应该对数据库中的每个表运行`ALTER TABLE table_name ENGINE=InnoDB;`。
|
您必须使用 InnoDB。您应该对数据库中的每个表运行`ALTER TABLE table_name ENGINE=InnoDB;`。
|
||||||
|
|
||||||
如果您使用的是 MySQL 5,另一个可能的修复方法是:
|
|
||||||
|
|
||||||
```mysql
|
|
||||||
SET GLOBAL innodb_file_format=Barracuda;
|
|
||||||
SET GLOBAL innodb_file_per_table=1;
|
|
||||||
SET GLOBAL innodb_large_prefix=1;
|
|
||||||
```
|
|
||||||
|
|
||||||
## 为什么 MySQL 上的 Emoji 显示错误
|
|
||||||
|
|
||||||
不幸的是,MySQL 的`utf8`字符集不完全允许所有可能的 UTF-8 字符,特别是 Emoji。
|
|
||||||
他们创建了一个名为 `utf8mb4`的字符集和校对规则,允许存储 Emoji,但使用
|
|
||||||
utf8 字符集的表和连接将不会使用它。
|
|
||||||
|
|
||||||
请运行 `gitea convert` 或对数据库运行`ALTER DATABASE database_name CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
|
|
||||||
并对每个表运行
|
|
||||||
`ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`。
|
|
||||||
|
|
||||||
您还需要将`app.ini`文件中的数据库字符集设置为`CHARSET=utf8mb4`。
|
|
||||||
|
|
||||||
## 为什么 Emoji 只显示占位符或单色图像
|
## 为什么 Emoji 只显示占位符或单色图像
|
||||||
|
|
||||||
Gitea 需要系统或浏览器安装其中一个受支持的 Emoji 字体,例如 Apple Color Emoji、Segoe UI Emoji、Segoe UI Symbol、Noto Color Emoji 和 Twemoji Mozilla。通常,操作系统应该已经提供了其中一个字体,但特别是在 Linux 上,可能需要手动安装它们。
|
Gitea 需要系统或浏览器安装其中一个受支持的 Emoji 字体,例如 Apple Color Emoji、Segoe UI Emoji、Segoe UI Symbol、Noto Color Emoji 和 Twemoji Mozilla。通常,操作系统应该已经提供了其中一个字体,但特别是在 Linux 上,可能需要手动安装它们。
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ _Symbols used in table:_
|
|||||||
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ |
|
||||||
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ |
|
||||||
|
| Gists / Snippets | [⚙️][opengist] | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ |
|
||||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||||
@@ -147,3 +148,4 @@ _Symbols used in table:_
|
|||||||
|
|
||||||
[gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea
|
[gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea
|
||||||
[gitea-pages-server]: https://codeberg.org/Codeberg/pages-server
|
[gitea-pages-server]: https://codeberg.org/Codeberg/pages-server
|
||||||
|
[opengist]: https://github.com/thomiceli/opengist
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ menu:
|
|||||||
|
|
||||||
# Database Preparation
|
# Database Preparation
|
||||||
|
|
||||||
You need a database to use Gitea. Gitea supports PostgreSQL (>= 12), MySQL (>= 8.0), MariaDB, SQLite, and MSSQL (>= 2012 SP4). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
You need a database to use Gitea. Gitea supports PostgreSQL (>= 12), MySQL (>= 8.0), MariaDB (>= 10.4), SQLite (builtin), and MSSQL (>= 2012 SP4). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter.
|
||||||
|
|
||||||
If you use an unsupported database version, please [get in touch](/help/support) with us for information on our Extended Support Contracts. We can provide testing and support for older databases and integrate those fixes into the Gitea codebase.
|
If you use an unsupported database version, please [get in touch](/help/support) with us for information on our Extended Support Contracts. We can provide testing and support for older databases and integrate those fixes into the Gitea codebase.
|
||||||
|
|
||||||
@@ -61,10 +61,14 @@ Note: All steps below requires that the database engine of your choice is instal
|
|||||||
|
|
||||||
Replace username and password above as appropriate.
|
Replace username and password above as appropriate.
|
||||||
|
|
||||||
4. Create database with UTF-8 charset and collation. Make sure to use `utf8mb4` charset instead of `utf8` as the former supports all Unicode characters (including emojis) beyond _Basic Multilingual Plane_. Also, collation chosen depending on your expected content. When in doubt, use either `unicode_ci` or `general_ci`.
|
4. Create database with UTF-8 charset and case-sensitive collation.
|
||||||
|
|
||||||
|
`utf8mb4_bin` is a common collation for both MySQL/MariaDB.
|
||||||
|
When Gitea starts, it will try to find a better collation (`utf8mb4_0900_as_cs` or `uca1400_as_cs`) and alter the database if it is possible.
|
||||||
|
If you would like to use other collation, you can set `[database].CHARSET_COLLATION` in the `app.ini` file.
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
|
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';
|
||||||
```
|
```
|
||||||
|
|
||||||
Replace database name as appropriate.
|
Replace database name as appropriate.
|
||||||
|
|||||||
@@ -59,10 +59,12 @@ menu:
|
|||||||
|
|
||||||
根据需要替换上述用户名和密码。
|
根据需要替换上述用户名和密码。
|
||||||
|
|
||||||
4. 使用 UTF-8 字符集和排序规则创建数据库。确保使用 `**utf8mb4**` 字符集,而不是 `utf8`,因为前者支持 _Basic Multilingual Plane_ 之外的所有 Unicode 字符(包括表情符号)。排序规则根据您预期的内容选择。如果不确定,可以使用 `unicode_ci` 或 `general_ci`。
|
4. 使用 UTF-8 字符集和大小写敏感的排序规则创建数据库。
|
||||||
|
|
||||||
|
Gitea 启动后会尝试把数据库修改为更合适的字符集,如果你想指定自己的字符集规则,可以在 app.ini 中设置 `[database].CHARSET_COLLATION`。
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
|
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';
|
||||||
```
|
```
|
||||||
|
|
||||||
根据需要替换数据库名称。
|
根据需要替换数据库名称。
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ chmod 770 /etc/gitea
|
|||||||
- 使用 `gitea generate secret` 创建 `SECRET_KEY` 和 `INTERNAL_TOKEN`
|
- 使用 `gitea generate secret` 创建 `SECRET_KEY` 和 `INTERNAL_TOKEN`
|
||||||
- 提供所有必要的密钥
|
- 提供所有必要的密钥
|
||||||
|
|
||||||
详情参考 [命令行文档](/zh-cn/command-line/) 中有关 `gitea generate secret` 的内容。
|
详情参考 [命令行文档](administration/command-line.md) 中有关 `gitea generate secret` 的内容。
|
||||||
|
|
||||||
### 配置 Gitea 工作路径
|
### 配置 Gitea 工作路径
|
||||||
|
|
||||||
@@ -209,6 +209,6 @@ remote: ./hooks/pre-receive.d/gitea: line 2: [...]: No such file or directory
|
|||||||
|
|
||||||
如果您没有使用 Gitea 内置的 SSH 服务器,您还需要通过在管理选项中运行任务 `Update the '.ssh/authorized_keys' file with Gitea SSH keys.` 来重新编写授权密钥文件。
|
如果您没有使用 Gitea 内置的 SSH 服务器,您还需要通过在管理选项中运行任务 `Update the '.ssh/authorized_keys' file with Gitea SSH keys.` 来重新编写授权密钥文件。
|
||||||
|
|
||||||
> 更多经验总结,请参考英文版 [Troubleshooting](/en-us/install-from-binary/#troubleshooting)
|
> 更多经验总结,请参考英文版 [Troubleshooting](https://docs.gitea.com/installation/install-from-binary#troubleshooting)
|
||||||
|
|
||||||
如果从本页中没有找到你需要的内容,请访问 [帮助页面](help/support.md)
|
如果从本页中没有找到你需要的内容,请访问 [帮助页面](help/support.md)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ git checkout v@version@ # or git checkout pr-xyz
|
|||||||
|
|
||||||
- `go` @minGoVersion@ 或更高版本,请参阅 [这里](https://golang.org/dl/)
|
- `go` @minGoVersion@ 或更高版本,请参阅 [这里](https://golang.org/dl/)
|
||||||
- `node` @minNodeVersion@ 或更高版本,并且安装 `npm`, 请参阅 [这里](https://nodejs.org/zh-cn/download/)
|
- `node` @minNodeVersion@ 或更高版本,并且安装 `npm`, 请参阅 [这里](https://nodejs.org/zh-cn/download/)
|
||||||
- `make`, 请参阅 [这里](/zh-cn/hacking-on-gitea/)
|
- `make`, 请参阅 [这里](development/hacking-on-gitea.md)
|
||||||
|
|
||||||
为了尽可能简化编译过程,提供了各种 [make任务](https://github.com/go-gitea/gitea/blob/main/Makefile)。
|
为了尽可能简化编译过程,提供了各种 [make任务](https://github.com/go-gitea/gitea/blob/main/Makefile)。
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ If you cannot see the settings page, please make sure that you have the right pe
|
|||||||
|
|
||||||
The format of the registration token is a random string `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`.
|
The format of the registration token is a random string `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`.
|
||||||
|
|
||||||
A registration token can also be obtained from the gitea [command-line interface](../../administration/command-line.md#actions-generate-runner-token):
|
A registration token can also be obtained from the gitea [command-line interface](administration/command-line.md#actions-generate-runner-token):
|
||||||
|
|
||||||
```
|
```
|
||||||
gitea --config /etc/gitea/app.ini actions generate-runner-token
|
gitea --config /etc/gitea/app.ini actions generate-runner-token
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ Runner级别决定了从哪里获取注册令牌。
|
|||||||
|
|
||||||
注册令牌的格式是一个随机字符串 `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`。
|
注册令牌的格式是一个随机字符串 `D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx`。
|
||||||
|
|
||||||
注册令牌也可以通过 Gitea 的 [命令行](../../administration/command-line.md#actions-generate-runner-token) 获得:
|
注册令牌也可以通过 Gitea 的 [命令行](administration/command-line.md#actions-generate-runner-token) 获得:
|
||||||
|
|
||||||
### 注册Runner
|
### 注册Runner
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,17 @@ Even though Gitea Actions is designed to be compatible with GitHub Actions, ther
|
|||||||
### Absolute action URLs
|
### Absolute action URLs
|
||||||
|
|
||||||
Gitea Actions supports defining actions via absolute URL, which means that you can use actions from any git repository.
|
Gitea Actions supports defining actions via absolute URL, which means that you can use actions from any git repository.
|
||||||
Like `uses: https://github.com/actions/checkout@v3` or `uses: http://your_gitea.com/owner/repo@branch`.
|
Like `uses: https://github.com/actions/checkout@v4` or `uses: http://your_gitea.com/owner/repo@branch`.
|
||||||
|
|
||||||
### Actions written in Go
|
### Actions written in Go
|
||||||
|
|
||||||
Gitea Actions supports writing actions in Go.
|
Gitea Actions supports writing actions in Go.
|
||||||
See [Creating Go Actions](https://blog.gitea.com/creating-go-actions/).
|
See [Creating Go Actions](https://blog.gitea.com/creating-go-actions/).
|
||||||
|
|
||||||
|
### Support the non-standard syntax @yearly, @monthly, @weekly, @daily, @hourly on schedule
|
||||||
|
|
||||||
|
Github Actions doesn't support that. https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
|
||||||
|
|
||||||
## Unsupported workflows syntax
|
## Unsupported workflows syntax
|
||||||
|
|
||||||
### `concurrency`
|
### `concurrency`
|
||||||
@@ -110,6 +114,10 @@ It's ignored by Gitea Actions now.
|
|||||||
|
|
||||||
Pre and Post steps don't have their own section in the job log user interface.
|
Pre and Post steps don't have their own section in the job log user interface.
|
||||||
|
|
||||||
|
### Services steps
|
||||||
|
|
||||||
|
Services steps don't have their own section in the job log user interface.
|
||||||
|
|
||||||
## Different behavior
|
## Different behavior
|
||||||
|
|
||||||
### Downloading actions
|
### Downloading actions
|
||||||
@@ -117,9 +125,9 @@ Pre and Post steps don't have their own section in the job log user interface.
|
|||||||
Previously (Pre 1.21.0), `[actions].DEFAULT_ACTIONS_URL` defaulted to `https://gitea.com`.
|
Previously (Pre 1.21.0), `[actions].DEFAULT_ACTIONS_URL` defaulted to `https://gitea.com`.
|
||||||
We have since restricted this option to only allow two values (`github` and `self`).
|
We have since restricted this option to only allow two values (`github` and `self`).
|
||||||
When set to `github`, the new default, Gitea will download non-fully-qualified actions from `https://github.com`.
|
When set to `github`, the new default, Gitea will download non-fully-qualified actions from `https://github.com`.
|
||||||
For example, if you use `uses: actions/checkout@v3`, it will download the checkout repository from `https://github.com/actions/checkout.git`.
|
For example, if you use `uses: actions/checkout@v4`, it will download the checkout repository from `https://github.com/actions/checkout.git`.
|
||||||
|
|
||||||
If you want to download an action from another git hoster, you can use an absolute URL, e.g. `uses: https://gitea.com/actions/checkout@v3`.
|
If you want to download an action from another git hoster, you can use an absolute URL, e.g. `uses: https://gitea.com/actions/checkout@v4`.
|
||||||
|
|
||||||
If your Gitea instance is in an intranet or a restricted area, you can set the URL to `self` to only download actions from your own instance by default.
|
If your Gitea instance is in an intranet or a restricted area, you can set the URL to `self` to only download actions from your own instance by default.
|
||||||
Of course, you can still use absolute URLs in workflows.
|
Of course, you can still use absolute URLs in workflows.
|
||||||
|
|||||||
@@ -22,13 +22,17 @@ menu:
|
|||||||
### Action URL绝对路径
|
### Action URL绝对路径
|
||||||
|
|
||||||
Gitea Actions支持通过URL绝对路径定义actions,这意味着您可以使用来自任何Git存储库的Actions。
|
Gitea Actions支持通过URL绝对路径定义actions,这意味着您可以使用来自任何Git存储库的Actions。
|
||||||
例如,`uses: https://github.com/actions/checkout@v3`或`uses: http://your_gitea.com/owner/repo@branch`。
|
例如,`uses: https://github.com/actions/checkout@v4`或`uses: http://your_gitea.com/owner/repo@branch`。
|
||||||
|
|
||||||
### 使用Go编写Actions
|
### 使用Go编写Actions
|
||||||
|
|
||||||
Gitea Actions支持使用Go编写Actions。
|
Gitea Actions支持使用Go编写Actions。
|
||||||
请参阅[创建Go Actions](https://blog.gitea.com/creating-go-actions/)。
|
请参阅[创建Go Actions](https://blog.gitea.com/creating-go-actions/)。
|
||||||
|
|
||||||
|
### 支持非标准的调度语法 @yearly, @monthly, @weekly, @daily, @hourly
|
||||||
|
|
||||||
|
Github Actions 不支持这些语法,详见: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
|
||||||
|
|
||||||
## 不支持的工作流语法
|
## 不支持的工作流语法
|
||||||
|
|
||||||
### `concurrency`
|
### `concurrency`
|
||||||
@@ -116,15 +120,19 @@ Gitea Actions目前不支持此功能。
|
|||||||
|
|
||||||
预处理和后处理步骤在Job日志用户界面中没有自己的用户界面。
|
预处理和后处理步骤在Job日志用户界面中没有自己的用户界面。
|
||||||
|
|
||||||
|
### 服务步骤
|
||||||
|
|
||||||
|
服务步骤在Job日志用户界面中没有自己的用户界面。
|
||||||
|
|
||||||
## 不一样的行为
|
## 不一样的行为
|
||||||
|
|
||||||
### 下载Actions
|
### 下载Actions
|
||||||
|
|
||||||
当 `[actions].DEFAULT_ACTIONS_URL` 保持默认值为 `github` 时,Gitea将会从 https://github.com 下载相对路径的actions。比如:
|
当 `[actions].DEFAULT_ACTIONS_URL` 保持默认值为 `github` 时,Gitea将会从 https://github.com 下载相对路径的actions。比如:
|
||||||
如果你使用 `uses: actions/checkout@v3`,Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目。
|
如果你使用 `uses: actions/checkout@v4`,Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目。
|
||||||
如果你想要从另外一个 Git服务下载actions,你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v3` 来下载。
|
如果你想要从另外一个 Git服务下载actions,你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v4` 来下载。
|
||||||
|
|
||||||
如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用,将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v3` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
|
如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用,将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v4` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。
|
||||||
|
|
||||||
设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
|
设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ The act runner must be able to connect to Gitea to receive tasks and send back t
|
|||||||
### Connection 2, job containers to Gitea instance
|
### Connection 2, job containers to Gitea instance
|
||||||
|
|
||||||
The job containers have different network namespaces than the runner, even if they are on the same machine.
|
The job containers have different network namespaces than the runner, even if they are on the same machine.
|
||||||
They need to connect to Gitea to fetch codes if there is `actions/checkout@v3` in the workflow, for example.
|
They need to connect to Gitea to fetch codes if there is `actions/checkout@v4` in the workflow, for example.
|
||||||
Fetching code is not always necessary to run some jobs, but it is required in most cases.
|
Fetching code is not always necessary to run some jobs, but it is required in most cases.
|
||||||
|
|
||||||
If you use a loopback address to register a runner, the runner can connect to Gitea when it is on the same machine.
|
If you use a loopback address to register a runner, the runner can connect to Gitea when it is on the same machine.
|
||||||
@@ -103,7 +103,7 @@ However, if a job container tries to fetch code from localhost, it will fail bec
|
|||||||
|
|
||||||
### Connection 3, act runner to internet
|
### Connection 3, act runner to internet
|
||||||
|
|
||||||
When you use some actions like `actions/checkout@v3`, the act runner downloads the scripts, not the job containers.
|
When you use some actions like `actions/checkout@v4`, the act runner downloads the scripts, not the job containers.
|
||||||
By default, it downloads from [gitea.com](http://gitea.com/), so it requires access to the internet.
|
By default, it downloads from [gitea.com](http://gitea.com/), so it requires access to the internet.
|
||||||
It also downloads some docker images from Docker Hub by default, which also requires internet access.
|
It also downloads some docker images from Docker Hub by default, which also requires internet access.
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ And [Gitea Container Registry](usage/packages/container.md) can be used as a Doc
|
|||||||
|
|
||||||
### Connection 4, job containers to internet
|
### Connection 4, job containers to internet
|
||||||
|
|
||||||
When using actions such as `actions/setup-go@v4`, it may be necessary to download resources from the internet to set up the Go language environment in job containers.
|
When using actions such as `actions/setup-go@v5`, it may be necessary to download resources from the internet to set up the Go language environment in job containers.
|
||||||
Therefore, access to the internet is required for the successful completion of these actions.
|
Therefore, access to the internet is required for the successful completion of these actions.
|
||||||
|
|
||||||
However, it is optional as well.
|
However, it is optional as well.
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来
|
|||||||
### 连接 2,Job容器到Gitea实例
|
### 连接 2,Job容器到Gitea实例
|
||||||
|
|
||||||
即使Job容器位于同一台机器上,它们的网络命名空间与Runner不同。
|
即使Job容器位于同一台机器上,它们的网络命名空间与Runner不同。
|
||||||
举个例子,如果工作流中包含 `actions/checkout@v3`,Job容器需要连接到Gitea来获取代码。
|
举个例子,如果工作流中包含 `actions/checkout@v4`,Job容器需要连接到Gitea来获取代码。
|
||||||
获取代码并不总是运行某些Job所必需的,但在大多数情况下是必需的。
|
获取代码并不总是运行某些Job所必需的,但在大多数情况下是必需的。
|
||||||
|
|
||||||
如果您使用回环地址注册Runner,当Runner与Gitea在同一台机器上时,Runner可以连接到Gitea。
|
如果您使用回环地址注册Runner,当Runner与Gitea在同一台机器上时,Runner可以连接到Gitea。
|
||||||
@@ -104,7 +104,7 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来
|
|||||||
|
|
||||||
### 连接 3,act runner到互联网
|
### 连接 3,act runner到互联网
|
||||||
|
|
||||||
当您使用诸如 `actions/checkout@v3` 的一些Actions时,act runner下载的是脚本,而不是Job容器。
|
当您使用诸如 `actions/checkout@v4` 的一些Actions时,act runner下载的是脚本,而不是Job容器。
|
||||||
默认情况下,它从[gitea.com](http://gitea.com/)下载,因此需要访问互联网。
|
默认情况下,它从[gitea.com](http://gitea.com/)下载,因此需要访问互联网。
|
||||||
它还默认从Docker Hub下载一些Docker镜像,这也需要互联网访问。
|
它还默认从Docker Hub下载一些Docker镜像,这也需要互联网访问。
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ act runner 必须能够连接到Gitea以接收任务并发送执行结果回来
|
|||||||
|
|
||||||
### 连接 4,Job容器到互联网
|
### 连接 4,Job容器到互联网
|
||||||
|
|
||||||
当使用诸如`actions/setup-go@v4`的Actions时,可能需要从互联网下载资源,以设置Job容器中的Go语言环境。
|
当使用诸如`actions/setup-go@v5`的Actions时,可能需要从互联网下载资源,以设置Job容器中的Go语言环境。
|
||||||
因此,成功完成这些Actions需要访问互联网。
|
因此,成功完成这些Actions需要访问互联网。
|
||||||
|
|
||||||
然而,这也是可选的。
|
然而,这也是可选的。
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ Still, this is completely optional since both options have the same effect at th
|
|||||||
Not yet.
|
Not yet.
|
||||||
It is technically possible to implement, but we need to discuss whether it is necessary.
|
It is technically possible to implement, but we need to discuss whether it is necessary.
|
||||||
|
|
||||||
## Where will the runner download scripts when using actions such as `actions/checkout@v3`?
|
## Where will the runner download scripts when using actions such as `actions/checkout@v4`?
|
||||||
|
|
||||||
You may be aware that there are tens of thousands of [marketplace actions](https://github.com/marketplace?type=actions) in GitHub.
|
You may be aware that there are tens of thousands of [marketplace actions](https://github.com/marketplace?type=actions) in GitHub.
|
||||||
However, when you write `uses: actions/checkout@v3`, it actually downloads the scripts from [gitea.com/actions/checkout](http://gitea.com/actions/checkout) by default (not GitHub).
|
However, when you write `uses: actions/checkout@v4`, it actually downloads the scripts from [gitea.com/actions/checkout](http://gitea.com/actions/checkout) by default (not GitHub).
|
||||||
This is a mirror of [github.com/actions/checkout](http://github.com/actions/checkout), but it's impossible to mirror all of them.
|
This is a mirror of [github.com/actions/checkout](http://github.com/actions/checkout), but it's impossible to mirror all of them.
|
||||||
That's why you may encounter failures when trying to use some actions that haven't been mirrored.
|
That's why you may encounter failures when trying to use some actions that haven't been mirrored.
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ DEFAULT_REPO_UNITS = ...,repo.actions
|
|||||||
目前还不可以。
|
目前还不可以。
|
||||||
从技术上讲是可以实现的,但我们需要讨论是否有必要。
|
从技术上讲是可以实现的,但我们需要讨论是否有必要。
|
||||||
|
|
||||||
## 使用`actions/checkout@v3`等Actions时,Job容器会从何处下载脚本?
|
## 使用`actions/checkout@v4`等Actions时,Job容器会从何处下载脚本?
|
||||||
|
|
||||||
您可能知道GitHub上有成千上万个[Actions市场](https://github.com/marketplace?type=actions)。
|
您可能知道GitHub上有成千上万个[Actions市场](https://github.com/marketplace?type=actions)。
|
||||||
然而,当您编写`uses: actions/checkout@v3`时,它实际上默认从[gitea.com/actions/checkout](http://gitea.com/actions/checkout)下载脚本(而不是从GitHub下载)。
|
然而,当您编写`uses: actions/checkout@v4`时,它实际上默认从[gitea.com/actions/checkout](http://gitea.com/actions/checkout)下载脚本(而不是从GitHub下载)。
|
||||||
这是[github.com/actions/checkout](http://github.com/actions/checkout)的镜像,但无法将它们全部镜像。
|
这是[github.com/actions/checkout](http://github.com/actions/checkout)的镜像,但无法将它们全部镜像。
|
||||||
这就是为什么在尝试使用尚未镜像的某些Actions时可能会遇到失败的原因。
|
这就是为什么在尝试使用尚未镜像的某些Actions时可能会遇到失败的原因。
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ To avoid confusion, we have clarified the spelling here:
|
|||||||
- "Gitea Actions" (with an "s", both words capitalized) is the name of the Gitea feature.
|
- "Gitea Actions" (with an "s", both words capitalized) is the name of the Gitea feature.
|
||||||
- "GitHub Actions" is the name of the GitHub feature.
|
- "GitHub Actions" is the name of the GitHub feature.
|
||||||
- "Actions" could refer to either of the above, depending on the context. So it refers to "Gitea Actions" in this document.
|
- "Actions" could refer to either of the above, depending on the context. So it refers to "Gitea Actions" in this document.
|
||||||
- "action" or "actions" refer to some scripts/plugins to be used, like "actions/checkout@v3" or "actions/cache@v3".
|
- "action" or "actions" refer to some scripts/plugins to be used, like "actions/checkout@v4" or "actions/cache@v3".
|
||||||
|
|
||||||
## Runners
|
## Runners
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Gitea Actions与[GitHub Actions](https://github.com/features/actions)相似且
|
|||||||
- "Gitea Actions"(两个单词都大写且带有"s")是Gitea功能的名称。
|
- "Gitea Actions"(两个单词都大写且带有"s")是Gitea功能的名称。
|
||||||
- "GitHub Actions"是GitHub功能的名称。
|
- "GitHub Actions"是GitHub功能的名称。
|
||||||
- "Actions"根据上下文的不同可以指代以上任意一个。在本文档中指代的是"Gitea Actions"。
|
- "Actions"根据上下文的不同可以指代以上任意一个。在本文档中指代的是"Gitea Actions"。
|
||||||
- "action"或"actions"指代一些要使用的脚本/插件,比如"actions/checkout@v3"或"actions/cache@v3"。
|
- "action"或"actions"指代一些要使用的脚本/插件,比如"actions/checkout@v4"或"actions/cache@v3"。
|
||||||
|
|
||||||
## Runner
|
## Runner
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ jobs:
|
|||||||
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||||
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ jobs:
|
|||||||
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||||
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
- name: Check out repository code
|
- name: Check out repository code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
|
|||||||
@@ -145,25 +145,25 @@ Adds the following fields:
|
|||||||
|
|
||||||
Uses the following fields:
|
Uses the following fields:
|
||||||
|
|
||||||
- Group Search Base (optional)
|
- Group Search Base DN (optional)
|
||||||
|
|
||||||
- The LDAP DN used for groups.
|
- The LDAP DN used for groups.
|
||||||
- Example: `ou=group,dc=mydomain,dc=com`
|
- Example: `ou=group,dc=mydomain,dc=com`
|
||||||
|
|
||||||
- Group Name Filter (optional)
|
- Group Attribute Containing List Of Users (optional)
|
||||||
|
- The attribute of the group object that lists/contains the group members.
|
||||||
|
- Example: `memberUid` or `member`
|
||||||
|
|
||||||
- An LDAP filter declaring how to find valid groups in the above DN.
|
- User Attribute Listed in Group (optional)
|
||||||
- Example: `(|(cn=gitea_users)(cn=admins))`
|
|
||||||
|
|
||||||
- User Attribute in Group (optional)
|
|
||||||
|
|
||||||
- The user attribute that is used to reference a user in the group object.
|
- The user attribute that is used to reference a user in the group object.
|
||||||
- Example: `uid` if the group objects contains a `member: bender` and the user object contains a `uid: bender`.
|
- Example: `uid` if the group objects contains a `member: bender` and the user object contains a `uid: bender`.
|
||||||
- Example: `dn` if the group object contains a `member: uid=bender,ou=users,dc=planetexpress,dc=com`.
|
- Example: `dn` if the group object contains a `member: uid=bender,ou=users,dc=planetexpress,dc=com`.
|
||||||
|
|
||||||
- Group Attribute for User (optional)
|
- Verify group membership in LDAP (optional)
|
||||||
- The attribute of the group object that lists/contains the group members.
|
|
||||||
- Example: `memberUid` or `member`
|
- An LDAP filter declaring how to find valid groups in the above DN.
|
||||||
|
- Example: `(|(cn=gitea_users)(cn=admins))`
|
||||||
|
|
||||||
## PAM (Pluggable Authentication Module)
|
## PAM (Pluggable Authentication Module)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ The following examples use `apt`.
|
|||||||
To register the Debian registry add the url to the list of known apt sources:
|
To register the Debian registry add the url to the list of known apt sources:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
| Placeholder | Description |
|
| Placeholder | Description |
|
||||||
@@ -39,13 +39,13 @@ echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {
|
|||||||
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
The Debian registry files are signed with a PGP key which must be known to apt:
|
The Debian registry files are signed with a PGP key which must be known to apt:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/trusted.gpg.d/gitea-{owner}.asc
|
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/keyrings/gitea-{owner}.asc
|
||||||
```
|
```
|
||||||
|
|
||||||
Afterwards update the local package index:
|
Afterwards update the local package index:
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ menu:
|
|||||||
要注册 Debian 注册表,请将 URL 添加到已知 `apt` 源列表中:
|
要注册 Debian 注册表,请将 URL 添加到已知 `apt` 源列表中:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
| 占位符 | 描述 |
|
| 占位符 | 描述 |
|
||||||
@@ -39,13 +39,13 @@ echo "deb https://gitea.example.com/api/packages/{owner}/debian {distribution} {
|
|||||||
如果注册表是私有的,请在 URL 中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
如果注册表是私有的,请在 URL 中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
echo "deb https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
echo "deb [signed-by=/etc/apt/keyrings/gitea-{owner}.asc] https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/debian {distribution} {component}" | sudo tee -a /etc/apt/sources.list.d/gitea.list
|
||||||
```
|
```
|
||||||
|
|
||||||
Debian 注册表文件使用 PGP 密钥进行签名,`apt` 必须知道该密钥:
|
Debian 注册表文件使用 PGP 密钥进行签名,`apt` 必须知道该密钥:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/trusted.gpg.d/gitea-{owner}.asc
|
sudo curl https://gitea.example.com/api/packages/{owner}/debian/repository.key -o /etc/apt/keyrings/gitea-{owner}.asc
|
||||||
```
|
```
|
||||||
|
|
||||||
然后更新本地软件包索引:
|
然后更新本地软件包索引:
|
||||||
|
|||||||
@@ -27,17 +27,18 @@ The following examples use `dnf`.
|
|||||||
To register the RPM registry add the url to the list of known apt sources:
|
To register the RPM registry add the url to the list of known apt sources:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
|
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
| Placeholder | Description |
|
| Placeholder | Description |
|
||||||
| ----------- | ----------- |
|
| ----------- |----------------------------------------------------|
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
|
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
|
||||||
|
|
||||||
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
If the registry is private, provide credentials in the url. You can use a password or a [personal access token](development/api-usage.md#authentication):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
|
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
|
You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.repos.d` too.
|
||||||
@@ -47,19 +48,20 @@ You have to add the credentials to the urls in the `rpm.repo` file in `/etc/yum.
|
|||||||
To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body.
|
To publish a RPM package (`*.rpm`), perform a HTTP PUT operation with the package content in the request body.
|
||||||
|
|
||||||
```
|
```
|
||||||
PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
|
PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
| --------- | ----------- |
|
| --------- | ----------- |
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
|
| `group` | Everything, e.g. `el7`, `rocky/el9` , `test/fc38`.|
|
||||||
|
|
||||||
Example request using HTTP Basic authentication:
|
Example request using HTTP Basic authentication:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --user your_username:your_password_or_token \
|
curl --user your_username:your_password_or_token \
|
||||||
--upload-file path/to/file.rpm \
|
--upload-file path/to/file.rpm \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/upload
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/upload
|
||||||
```
|
```
|
||||||
|
|
||||||
If you are using 2FA or OAuth use a [personal access token](development/api-usage.md#authentication) instead of the password.
|
If you are using 2FA or OAuth use a [personal access token](development/api-usage.md#authentication) instead of the password.
|
||||||
@@ -78,21 +80,22 @@ The server responds with the following HTTP Status codes.
|
|||||||
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
To delete an RPM package perform a HTTP DELETE operation. This will delete the package version too if there is no file left.
|
||||||
|
|
||||||
```
|
```
|
||||||
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
|
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
| ----------------- | ----------- |
|
|-------------------|----------------------------|
|
||||||
| `owner` | The owner of the package. |
|
| `owner` | The owner of the package. |
|
||||||
| `package_name` | The package name. |
|
| `group` | The package group . |
|
||||||
| `package_version` | The package version. |
|
| `package_name` | The package name. |
|
||||||
| `architecture` | The package architecture. |
|
| `package_version` | The package version. |
|
||||||
|
| `architecture` | The package architecture. |
|
||||||
|
|
||||||
Example request using HTTP Basic authentication:
|
Example request using HTTP Basic authentication:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --user your_username:your_token_or_password -X DELETE \
|
curl --user your_username:your_token_or_password -X DELETE \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
The server responds with the following HTTP Status codes.
|
The server responds with the following HTTP Status codes.
|
||||||
|
|||||||
@@ -27,17 +27,18 @@ menu:
|
|||||||
要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中:
|
要注册RPM注册表,请将 URL 添加到已知 `apt` 源列表中:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm.repo
|
dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
| 占位符 | 描述 |
|
| 占位符 | 描述 |
|
||||||
| ------- | -------------- |
|
| ------- |--------------------------------------|
|
||||||
| `owner` | 软件包的所有者 |
|
| `owner` | 软件包的所有者 |
|
||||||
|
| `group` | 任何名称,例如 `centos/7`、`el-7`、`fc38` |
|
||||||
|
|
||||||
如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
如果注册表是私有的,请在URL中提供凭据。您可以使用密码或[个人访问令牌](development/api-usage.md#通过-api-认证):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
|
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm/{group}.repo
|
||||||
```
|
```
|
||||||
|
|
||||||
您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。
|
您还必须将凭据添加到 `/etc/yum.repos.d` 中的 `rpm.repo` 文件中的URL中。
|
||||||
@@ -47,19 +48,20 @@ dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.
|
|||||||
要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。
|
要发布RPM软件包(`*.rpm`),请执行带有软件包内容的 HTTP `PUT` 操作。
|
||||||
|
|
||||||
```
|
```
|
||||||
PUT https://gitea.example.com/api/packages/{owner}/rpm/upload
|
PUT https://gitea.example.com/api/packages/{owner}/rpm/{group}/upload
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 描述 |
|
| 参数 | 描述 |
|
||||||
| ------- | -------------- |
|
| ------- |--------------|
|
||||||
| `owner` | 软件包的所有者 |
|
| `owner` | 软件包的所有者 |
|
||||||
|
| `group` | 软件包自定义分组名称 |
|
||||||
|
|
||||||
使用HTTP基本身份验证的示例请求:
|
使用HTTP基本身份验证的示例请求:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --user your_username:your_password_or_token \
|
curl --user your_username:your_password_or_token \
|
||||||
--upload-file path/to/file.rpm \
|
--upload-file path/to/file.rpm \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/upload
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/version/upload
|
||||||
```
|
```
|
||||||
|
|
||||||
如果您使用 2FA 或 OAuth,请使用[个人访问令牌](development/api-usage.md#通过-api-认证)替代密码。您无法将具有相同名称的文件两次发布到软件包中。您必须先删除现有的软件包版本。
|
如果您使用 2FA 或 OAuth,请使用[个人访问令牌](development/api-usage.md#通过-api-认证)替代密码。您无法将具有相同名称的文件两次发布到软件包中。您必须先删除现有的软件包版本。
|
||||||
@@ -77,12 +79,13 @@ curl --user your_username:your_password_or_token \
|
|||||||
要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。
|
要删除 RPM 软件包,请执行 HTTP `DELETE` 操作。如果没有文件剩余,这也将删除软件包版本。
|
||||||
|
|
||||||
```
|
```
|
||||||
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{package_version}/{architecture}
|
DELETE https://gitea.example.com/api/packages/{owner}/rpm/{group}/package/{package_name}/{package_version}/{architecture}
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 描述 |
|
| 参数 | 描述 |
|
||||||
| ----------------- | -------------- |
|
| ----------------- | -------------- |
|
||||||
| `owner` | 软件包的所有者 |
|
| `owner` | 软件包的所有者 |
|
||||||
|
| `group` | 软件包自定义分组 |
|
||||||
| `package_name` | 软件包名称 |
|
| `package_name` | 软件包名称 |
|
||||||
| `package_version` | 软件包版本 |
|
| `package_version` | 软件包版本 |
|
||||||
| `architecture` | 软件包架构 |
|
| `architecture` | 软件包架构 |
|
||||||
@@ -91,7 +94,7 @@ DELETE https://gitea.example.com/api/packages/{owner}/rpm/{package_name}/{packag
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --user your_username:your_token_or_password -X DELETE \
|
curl --user your_username:your_token_or_password -X DELETE \
|
||||||
https://gitea.example.com/api/packages/testuser/rpm/test-package/1.0.0/x86_64
|
https://gitea.example.com/api/packages/testuser/rpm/centos/el7/package/test-package/1.0.0/x86_64
|
||||||
```
|
```
|
||||||
|
|
||||||
服务器将以以下HTTP状态码响应:
|
服务器将以以下HTTP状态码响应:
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ The repository now gets mirrored periodically to the remote repository. You can
|
|||||||
|
|
||||||
To set up a mirror from Gitea to GitHub, you need to follow these steps:
|
To set up a mirror from Gitea to GitHub, you need to follow these steps:
|
||||||
|
|
||||||
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked.
|
1. Create a [GitHub personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with the *public_repo* box checked. Also check the **workflow** checkbox in case your repo using act for continuous integration.
|
||||||
2. Create a repository with that name on GitHub. Unlike Gitea, GitHub does not support creating repositories by pushing to the remote. You can also use an existing remote repo if it has the same commit history as your Gitea repo.
|
2. Create a repository with that name on GitHub. Unlike Gitea, GitHub does not support creating repositories by pushing to the remote. You can also use an existing remote repo if it has the same commit history as your Gitea repo.
|
||||||
3. In the settings of your Gitea repo, fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
|
3. In the settings of your Gitea repo, fill in the **Git Remote Repository URL**: `https://github.com/<your_github_group>/<your_github_project>.git`.
|
||||||
4. Fill in the **Authorization** fields with your GitHub username and the personal access token as **Password**.
|
4. Fill in the **Authorization** fields with your GitHub username and the personal access token as **Password**.
|
||||||
|
|||||||
170
go.mod
170
go.mod
@@ -5,7 +5,7 @@ go 1.21
|
|||||||
require (
|
require (
|
||||||
code.gitea.io/actions-proto-go v0.3.1
|
code.gitea.io/actions-proto-go v0.3.1
|
||||||
code.gitea.io/gitea-vet v0.2.3
|
code.gitea.io/gitea-vet v0.2.3
|
||||||
code.gitea.io/sdk/gitea v0.16.0
|
code.gitea.io/sdk/gitea v0.17.0
|
||||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||||
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669
|
gitea.com/go-chi/binding v0.0.0-20230415142243-04b515c6d669
|
||||||
gitea.com/go-chi/cache v0.2.0
|
gitea.com/go-chi/cache v0.2.0
|
||||||
@@ -17,12 +17,12 @@ require (
|
|||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.8.1
|
||||||
github.com/alecthomas/chroma/v2 v2.10.0
|
github.com/alecthomas/chroma/v2 v2.12.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.3.10
|
github.com/blevesearch/bleve/v2 v2.3.10
|
||||||
github.com/bufbuild/connect-go v1.10.0
|
github.com/bufbuild/connect-go v1.10.0
|
||||||
github.com/buildkite/terminal-to-html/v3 v3.9.1
|
github.com/buildkite/terminal-to-html/v3 v3.10.0
|
||||||
github.com/caddyserver/certmagic v0.19.2
|
github.com/caddyserver/certmagic v0.20.0
|
||||||
github.com/chi-middleware/proxy v1.1.1
|
github.com/chi-middleware/proxy v1.1.1
|
||||||
github.com/denisenkom/go-mssqldb v0.12.3
|
github.com/denisenkom/go-mssqldb v0.12.3
|
||||||
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
|
github.com/dimiro1/reply v0.0.0-20200315094148-d0136a4c9e21
|
||||||
@@ -35,13 +35,13 @@ require (
|
|||||||
github.com/emirpasic/gods v1.18.1
|
github.com/emirpasic/gods v1.18.1
|
||||||
github.com/ethantkoenig/rupture v1.0.1
|
github.com/ethantkoenig/rupture v1.0.1
|
||||||
github.com/felixge/fgprof v0.9.3
|
github.com/felixge/fgprof v0.9.3
|
||||||
github.com/fsnotify/fsnotify v1.6.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46
|
github.com/gliderlabs/ssh v0.3.6-0.20230927171611-ece6c7995e46
|
||||||
github.com/go-ap/activitypub v0.0.0-20231003111253-1fba3772399b
|
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
|
||||||
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
|
||||||
github.com/go-chi/chi/v5 v5.0.10
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
github.com/go-co-op/gocron v1.31.1
|
github.com/go-co-op/gocron v1.37.0
|
||||||
github.com/go-enry/go-enry/v2 v2.8.6
|
github.com/go-enry/go-enry/v2 v2.8.6
|
||||||
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e
|
||||||
github.com/go-git/go-billy/v5 v5.5.0
|
github.com/go-git/go-billy/v5 v5.5.0
|
||||||
@@ -50,34 +50,34 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.7.1
|
github.com/go-sql-driver/mysql v1.7.1
|
||||||
github.com/go-swagger/go-swagger v0.30.5
|
github.com/go-swagger/go-swagger v0.30.5
|
||||||
github.com/go-testfixtures/testfixtures/v3 v3.9.0
|
github.com/go-testfixtures/testfixtures/v3 v3.9.0
|
||||||
github.com/go-webauthn/webauthn v0.8.6
|
github.com/go-webauthn/webauthn v0.9.4
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
github.com/golang-jwt/jwt/v5 v5.2.0
|
||||||
github.com/google/go-github/v53 v53.2.0
|
github.com/google/go-github/v57 v57.0.0
|
||||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98
|
github.com/google/pprof v0.0.0-20231212022811-ec68065c825e
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.5.0
|
||||||
github.com/gorilla/feeds v1.1.1
|
github.com/gorilla/feeds v1.1.2
|
||||||
github.com/gorilla/sessions v1.2.1
|
github.com/gorilla/sessions v1.2.2
|
||||||
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
|
||||||
github.com/huandu/xstrings v1.4.0
|
github.com/huandu/xstrings v1.4.0
|
||||||
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
|
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
|
||||||
github.com/jhillyerd/enmime v1.0.1
|
github.com/jhillyerd/enmime v1.1.0
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
|
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
|
||||||
github.com/klauspost/compress v1.17.0
|
github.com/klauspost/compress v1.17.4
|
||||||
github.com/klauspost/cpuid/v2 v2.2.5
|
github.com/klauspost/cpuid/v2 v2.2.6
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/markbates/goth v1.78.0
|
github.com/markbates/goth v1.78.0
|
||||||
github.com/mattn/go-isatty v0.0.19
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mattn/go-sqlite3 v1.14.17
|
github.com/mattn/go-sqlite3 v1.14.19
|
||||||
github.com/meilisearch/meilisearch-go v0.25.1
|
github.com/meilisearch/meilisearch-go v0.26.0
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26
|
github.com/microcosm-cc/bluemonday v1.0.26
|
||||||
github.com/minio/minio-go/v7 v7.0.63
|
github.com/minio/minio-go/v7 v7.0.66
|
||||||
github.com/minio/sha256-simd v1.0.1
|
github.com/minio/sha256-simd v1.0.1
|
||||||
github.com/msteinert/pam v1.2.0
|
github.com/msteinert/pam v1.2.0
|
||||||
github.com/nektos/act v0.2.52
|
github.com/nektos/act v0.2.52
|
||||||
@@ -89,7 +89,7 @@ require (
|
|||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
github.com/prometheus/client_golang v1.17.0
|
github.com/prometheus/client_golang v1.17.0
|
||||||
github.com/quasoft/websspi v1.1.2
|
github.com/quasoft/websspi v1.1.2
|
||||||
github.com/redis/go-redis/v9 v9.2.1
|
github.com/redis/go-redis/v9 v9.3.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
|
||||||
github.com/sassoftware/go-rpmutils v0.2.0
|
github.com/sassoftware/go-rpmutils v0.2.0
|
||||||
@@ -99,21 +99,21 @@ require (
|
|||||||
github.com/syndtr/goleveldb v1.0.0
|
github.com/syndtr/goleveldb v1.0.0
|
||||||
github.com/tstranex/u2f v1.0.0
|
github.com/tstranex/u2f v1.0.0
|
||||||
github.com/ulikunitz/xz v0.5.11
|
github.com/ulikunitz/xz v0.5.11
|
||||||
github.com/urfave/cli/v2 v2.25.7
|
github.com/urfave/cli/v2 v2.26.0
|
||||||
github.com/xanzy/go-gitlab v0.93.1
|
github.com/xanzy/go-gitlab v0.95.2
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0
|
github.com/xeipuuv/gojsonschema v1.2.0
|
||||||
github.com/yohcop/openid-go v1.0.1
|
github.com/yohcop/openid-go v1.0.1
|
||||||
github.com/yuin/goldmark v1.5.6
|
github.com/yuin/goldmark v1.6.0
|
||||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||||
github.com/yuin/goldmark-meta v1.1.0
|
github.com/yuin/goldmark-meta v1.1.0
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/image v0.13.0
|
golang.org/x/image v0.14.0
|
||||||
golang.org/x/net v0.17.0
|
golang.org/x/net v0.19.0
|
||||||
golang.org/x/oauth2 v0.13.0
|
golang.org/x/oauth2 v0.15.0
|
||||||
golang.org/x/sys v0.13.0
|
golang.org/x/sys v0.15.0
|
||||||
golang.org/x/text v0.13.0
|
golang.org/x/text v0.14.0
|
||||||
golang.org/x/tools v0.14.0
|
golang.org/x/tools v0.16.1
|
||||||
google.golang.org/grpc v1.58.3
|
google.golang.org/grpc v1.60.0
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.31.0
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gopkg.in/ini.v1 v1.67.0
|
gopkg.in/ini.v1 v1.67.0
|
||||||
@@ -121,37 +121,37 @@ require (
|
|||||||
mvdan.cc/xurls/v2 v2.5.0
|
mvdan.cc/xurls/v2 v2.5.0
|
||||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||||
xorm.io/builder v0.3.13
|
xorm.io/builder v0.3.13
|
||||||
xorm.io/xorm v1.3.4
|
xorm.io/xorm v1.3.7-0.20240101024435-4992cba040fe
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.23.1 // indirect
|
cloud.google.com/go/compute v1.23.3 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
|
||||||
github.com/ClickHouse/ch-go v0.58.2 // indirect
|
github.com/ClickHouse/ch-go v0.61.0 // indirect
|
||||||
github.com/ClickHouse/clickhouse-go/v2 v2.14.3 // indirect
|
github.com/ClickHouse/clickhouse-go/v2 v2.16.0 // indirect
|
||||||
github.com/DataDog/zstd v1.5.5 // indirect
|
github.com/DataDog/zstd v1.5.5 // indirect
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
|
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect
|
||||||
github.com/RoaringBitmap/roaring v1.6.0 // indirect
|
github.com/RoaringBitmap/roaring v1.7.0 // indirect
|
||||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.6 // indirect
|
||||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
github.com/andybalholm/cascadia v1.3.2 // indirect
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||||
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.9.0 // indirect
|
github.com/bits-and-blooms/bitset v1.12.0 // indirect
|
||||||
github.com/blevesearch/bleve_index_api v1.0.6 // indirect
|
github.com/blevesearch/bleve_index_api v1.1.4 // indirect
|
||||||
github.com/blevesearch/geo v0.1.18 // indirect
|
github.com/blevesearch/geo v0.1.18 // 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.1.6 // indirect
|
github.com/blevesearch/scorch_segment_api/v2 v2.2.5 // 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
|
||||||
@@ -165,9 +165,9 @@ require (
|
|||||||
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/cloudflare/circl v1.3.3 // indirect
|
github.com/cloudflare/circl v1.3.7 // indirect
|
||||||
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
github.com/couchbase/go-couchbase v0.1.1 // indirect
|
||||||
github.com/couchbase/gomemcached v0.2.1 // indirect
|
github.com/couchbase/gomemcached v0.3.0 // indirect
|
||||||
github.com/couchbase/goutils v0.1.2 // indirect
|
github.com/couchbase/goutils v0.1.2 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||||
@@ -175,28 +175,28 @@ require (
|
|||||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||||
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead // indirect
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
|
||||||
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||||
github.com/go-faster/city v1.0.1 // indirect
|
github.com/go-faster/city v1.0.1 // indirect
|
||||||
github.com/go-faster/errors v0.6.1 // indirect
|
github.com/go-faster/errors v0.7.1 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-openapi/analysis v0.21.4 // indirect
|
github.com/go-openapi/analysis v0.21.5 // indirect
|
||||||
github.com/go-openapi/errors v0.20.4 // indirect
|
github.com/go-openapi/errors v0.21.0 // indirect
|
||||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
github.com/go-openapi/jsonpointer v0.20.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.3 // indirect
|
||||||
github.com/go-openapi/loads v0.21.2 // indirect
|
github.com/go-openapi/loads v0.21.3 // indirect
|
||||||
github.com/go-openapi/runtime v0.26.0 // indirect
|
github.com/go-openapi/runtime v0.26.2 // indirect
|
||||||
github.com/go-openapi/spec v0.20.9 // indirect
|
github.com/go-openapi/spec v0.20.12 // indirect
|
||||||
github.com/go-openapi/strfmt v0.21.7 // indirect
|
github.com/go-openapi/strfmt v0.21.10 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // indirect
|
github.com/go-openapi/swag v0.22.5 // indirect
|
||||||
github.com/go-openapi/validate v0.22.1 // indirect
|
github.com/go-openapi/validate v0.22.4 // indirect
|
||||||
github.com/go-webauthn/x v0.1.4 // indirect
|
github.com/go-webauthn/x v0.1.5 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
@@ -207,12 +207,12 @@ require (
|
|||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/go-tpm v0.9.0 // indirect
|
github.com/google/go-tpm v0.9.0 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/gorilla/handlers v1.5.1 // indirect
|
github.com/gorilla/handlers v1.5.2 // indirect
|
||||||
github.com/gorilla/mux v1.8.0 // indirect
|
github.com/gorilla/mux v1.8.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.16 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
@@ -228,9 +228,9 @@ require (
|
|||||||
github.com/markbates/going v1.0.3 // indirect
|
github.com/markbates/going v1.0.3 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||||
github.com/mholt/acmez v1.2.0 // indirect
|
github.com/mholt/acmez v1.2.0 // indirect
|
||||||
github.com/miekg/dns v1.1.56 // indirect
|
github.com/miekg/dns v1.1.57 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
@@ -244,19 +244,19 @@ require (
|
|||||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.5 // indirect
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/paulmach/orb v0.10.0 // indirect
|
github.com/paulmach/orb v0.10.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.18 // indirect
|
github.com/pierrec/lz4/v4 v4.1.19 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/client_model v0.5.0 // indirect
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
github.com/prometheus/common v0.44.0 // indirect
|
github.com/prometheus/common v0.45.0 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/rhysd/actionlint v1.6.26 // indirect
|
github.com/rhysd/actionlint v1.6.26 // indirect
|
||||||
github.com/rivo/uniseg v0.4.4 // indirect
|
github.com/rivo/uniseg v0.4.4 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||||
github.com/rs/xid v1.5.0 // indirect
|
github.com/rs/xid v1.5.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.0 // indirect
|
||||||
github.com/shopspring/decimal v1.3.1 // indirect
|
github.com/shopspring/decimal v1.3.1 // indirect
|
||||||
@@ -264,37 +264,37 @@ require (
|
|||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.2.1 // indirect
|
github.com/skeema/knownhosts v1.2.1 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/afero v1.10.0 // indirect
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
github.com/spf13/cast v1.5.1 // indirect
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.17.0 // indirect
|
github.com/spf13/viper v1.18.2 // indirect
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||||
github.com/unknwon/com v1.0.1 // indirect
|
github.com/unknwon/com v1.0.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.50.0 // indirect
|
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||||
github.com/valyala/fastjson v1.6.4 // indirect
|
github.com/valyala/fastjson v1.6.4 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
||||||
github.com/zeebo/blake3 v0.2.3 // indirect
|
github.com/zeebo/blake3 v0.2.3 // indirect
|
||||||
go.etcd.io/bbolt v1.3.7 // indirect
|
go.etcd.io/bbolt v1.3.8 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.12.1 // indirect
|
go.mongodb.org/mongo-driver v1.13.1 // indirect
|
||||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.26.0 // indirect
|
go.uber.org/zap v1.26.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
|
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect
|
||||||
golang.org/x/mod v0.13.0 // indirect
|
golang.org/x/mod v0.14.0 // indirect
|
||||||
golang.org/x/sync v0.4.0 // indirect
|
golang.org/x/sync v0.5.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
google.golang.org/appengine v1.6.8 // indirect
|
google.golang.org/appengine v1.6.8 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // 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
|
||||||
|
|||||||
@@ -90,19 +90,6 @@ func getArtifactByNameAndPath(ctx context.Context, runID int64, name, fpath stri
|
|||||||
return &art, nil
|
return &art, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetArtifactByID returns an artifact by id
|
|
||||||
func GetArtifactByID(ctx context.Context, id int64) (*ActionArtifact, error) {
|
|
||||||
var art ActionArtifact
|
|
||||||
has, err := db.GetEngine(ctx).ID(id).Get(&art)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if !has {
|
|
||||||
return nil, util.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return &art, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateArtifactByID updates an artifact by id
|
// UpdateArtifactByID updates an artifact by id
|
||||||
func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) error {
|
func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) error {
|
||||||
art.ID = id
|
art.ID = id
|
||||||
|
|||||||
@@ -168,13 +168,14 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CancelRunningJobs cancels all running and waiting jobs associated with a specific workflow.
|
// CancelRunningJobs cancels all running and waiting jobs associated with a specific workflow.
|
||||||
func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string) error {
|
func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string, event webhook_module.HookEventType) error {
|
||||||
// Find all runs in the specified repository, reference, and workflow with statuses 'Running' or 'Waiting'.
|
// Find all runs in the specified repository, reference, and workflow with statuses 'Running' or 'Waiting'.
|
||||||
runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
|
runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
|
||||||
RepoID: repoID,
|
RepoID: repoID,
|
||||||
Ref: ref,
|
Ref: ref,
|
||||||
WorkflowID: workflowID,
|
WorkflowID: workflowID,
|
||||||
Status: []Status{StatusRunning, StatusWaiting},
|
TriggerEvent: event,
|
||||||
|
Status: []Status{StatusRunning, StatusWaiting},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
@@ -71,6 +72,7 @@ type FindRunOptions struct {
|
|||||||
WorkflowID string
|
WorkflowID string
|
||||||
Ref string // the commit/tag/… that caused this workflow
|
Ref string // the commit/tag/… that caused this workflow
|
||||||
TriggerUserID int64
|
TriggerUserID int64
|
||||||
|
TriggerEvent webhook_module.HookEventType
|
||||||
Approved bool // not util.OptionalBool, it works only when it's true
|
Approved bool // not util.OptionalBool, it works only when it's true
|
||||||
Status []Status
|
Status []Status
|
||||||
}
|
}
|
||||||
@@ -98,6 +100,9 @@ func (opts FindRunOptions) ToConds() builder.Cond {
|
|||||||
if opts.Ref != "" {
|
if opts.Ref != "" {
|
||||||
cond = cond.And(builder.Eq{"ref": opts.Ref})
|
cond = cond.And(builder.Eq{"ref": opts.Ref})
|
||||||
}
|
}
|
||||||
|
if opts.TriggerEvent != "" {
|
||||||
|
cond = cond.And(builder.Eq{"trigger_event": opts.TriggerEvent})
|
||||||
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ type ActionRunner struct {
|
|||||||
Deleted timeutil.TimeStamp `xorm:"deleted"`
|
Deleted timeutil.TimeStamp `xorm:"deleted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
RunnerOfflineTime = time.Minute
|
||||||
|
RunnerIdleTime = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// BelongsToOwnerName before calling, should guarantee that all attributes are loaded
|
// BelongsToOwnerName before calling, should guarantee that all attributes are loaded
|
||||||
func (r *ActionRunner) BelongsToOwnerName() string {
|
func (r *ActionRunner) BelongsToOwnerName() string {
|
||||||
if r.RepoID != 0 {
|
if r.RepoID != 0 {
|
||||||
@@ -76,11 +81,12 @@ func (r *ActionRunner) BelongsToOwnerType() types.OwnerType {
|
|||||||
return types.OwnerTypeSystemGlobal
|
return types.OwnerTypeSystemGlobal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the logic here changed, you should also modify FindRunnerOptions.ToCond
|
||||||
func (r *ActionRunner) Status() runnerv1.RunnerStatus {
|
func (r *ActionRunner) Status() runnerv1.RunnerStatus {
|
||||||
if time.Since(r.LastOnline.AsTime()) > time.Minute {
|
if time.Since(r.LastOnline.AsTime()) > RunnerOfflineTime {
|
||||||
return runnerv1.RunnerStatus_RUNNER_STATUS_OFFLINE
|
return runnerv1.RunnerStatus_RUNNER_STATUS_OFFLINE
|
||||||
}
|
}
|
||||||
if time.Since(r.LastActive.AsTime()) > 10*time.Second {
|
if time.Since(r.LastActive.AsTime()) > RunnerIdleTime {
|
||||||
return runnerv1.RunnerStatus_RUNNER_STATUS_IDLE
|
return runnerv1.RunnerStatus_RUNNER_STATUS_IDLE
|
||||||
}
|
}
|
||||||
return runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE
|
return runnerv1.RunnerStatus_RUNNER_STATUS_ACTIVE
|
||||||
@@ -153,6 +159,7 @@ type FindRunnerOptions struct {
|
|||||||
OwnerID int64
|
OwnerID int64
|
||||||
Sort string
|
Sort string
|
||||||
Filter string
|
Filter string
|
||||||
|
IsOnline util.OptionalBool
|
||||||
WithAvailable bool // not only runners belong to, but also runners can be used
|
WithAvailable bool // not only runners belong to, but also runners can be used
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +185,12 @@ func (opts FindRunnerOptions) ToConds() builder.Cond {
|
|||||||
if opts.Filter != "" {
|
if opts.Filter != "" {
|
||||||
cond = cond.And(builder.Like{"name", opts.Filter})
|
cond = cond.And(builder.Like{"name", opts.Filter})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.IsOnline.IsTrue() {
|
||||||
|
cond = cond.And(builder.Gt{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
|
||||||
|
} else if opts.IsOnline.IsFalse() {
|
||||||
|
cond = cond.And(builder.Lte{"last_online": time.Now().Add(-RunnerOfflineTime).Unix()})
|
||||||
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +254,7 @@ func DeleteRunner(ctx context.Context, id int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.GetEngine(ctx).Delete(&ActionRunner{ID: id})
|
_, err := db.DeleteByID[ActionRunner](ctx, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package actions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@@ -118,3 +119,22 @@ func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
|
|||||||
|
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CleanRepoScheduleTasks(ctx context.Context, repo *repo_model.Repository) error {
|
||||||
|
// If actions disabled when there is schedule task, this will remove the outdated schedule tasks
|
||||||
|
// There is no other place we can do this because the app.ini will be changed manually
|
||||||
|
if err := DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
|
||||||
|
return fmt.Errorf("DeleteCronTaskByRepo: %v", err)
|
||||||
|
}
|
||||||
|
// cancel running cron jobs of this repository and delete old schedules
|
||||||
|
if err := CancelRunningJobs(
|
||||||
|
ctx,
|
||||||
|
repo.ID,
|
||||||
|
repo.DefaultBranch,
|
||||||
|
"",
|
||||||
|
webhook_module.HookEventSchedule,
|
||||||
|
); err != nil {
|
||||||
|
return fmt.Errorf("CancelRunningJobs: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask
|
|||||||
}
|
}
|
||||||
|
|
||||||
var jobs []*ActionRunJob
|
var jobs []*ActionRunJob
|
||||||
if err := e.Where("task_id=? AND status=?", 0, StatusWaiting).And(jobCond).Asc("id").Find(&jobs); err != nil {
|
if err := e.Where("task_id=? AND status=?", 0, StatusWaiting).And(jobCond).Asc("updated", "id").Find(&jobs); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *ActionVariable) Validate() error {
|
func (v *ActionVariable) Validate() error {
|
||||||
if v.OwnerID == 0 && v.RepoID == 0 {
|
if v.OwnerID != 0 && v.RepoID != 0 {
|
||||||
return errors.New("the variable is not bound to any scope")
|
return errors.New("a variable should not be bound to an owner and a repository at the same time")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -58,12 +58,8 @@ type FindVariablesOpts struct {
|
|||||||
|
|
||||||
func (opts FindVariablesOpts) ToConds() builder.Cond {
|
func (opts FindVariablesOpts) ToConds() builder.Cond {
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
if opts.OwnerID > 0 {
|
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||||
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
||||||
}
|
|
||||||
if opts.RepoID > 0 {
|
|
||||||
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
|
|
||||||
}
|
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -446,9 +446,12 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
|
|||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := db.GetEngine(ctx).Where(cond).
|
sess := db.GetEngine(ctx).Where(cond)
|
||||||
Select("`action`.*"). // this line will avoid select other joined table's columns
|
if setting.Database.Type.IsMySQL() {
|
||||||
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
|
sess = sess.IndexHint("USE", "JOIN", "IDX_action_c_u_d")
|
||||||
|
}
|
||||||
|
sess = sess.Select("`action`.*"). // this line will avoid select other joined table's columns
|
||||||
|
Join("INNER", "repository", "`repository`.id = `action`.repo_id")
|
||||||
|
|
||||||
opts.SetDefaultValues()
|
opts.SetDefaultValues()
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
|
|||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
// Mock time
|
// Mock time
|
||||||
timeutil.Set(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
|
timeutil.MockSet(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
|
||||||
defer timeutil.Unset()
|
defer timeutil.MockUnset()
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID})
|
||||||
|
|||||||
@@ -11,21 +11,13 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"github.com/keybase/go-crypto/openpgp"
|
"github.com/keybase/go-crypto/openpgp"
|
||||||
"github.com/keybase/go-crypto/openpgp/packet"
|
"github.com/keybase/go-crypto/openpgp/packet"
|
||||||
"xorm.io/xorm"
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// __________________ ________ ____ __.
|
|
||||||
// / _____/\______ \/ _____/ | |/ _|____ ___.__.
|
|
||||||
// / \ ___ | ___/ \ ___ | <_/ __ < | |
|
|
||||||
// \ \_\ \| | \ \_\ \ | | \ ___/\___ |
|
|
||||||
// \______ /|____| \______ / |____|__ \___ > ____|
|
|
||||||
// \/ \/ \/ \/\/
|
|
||||||
|
|
||||||
// GPGKey represents a GPG key.
|
// GPGKey represents a GPG key.
|
||||||
type GPGKey struct {
|
type GPGKey struct {
|
||||||
ID int64 `xorm:"pk autoincr"`
|
ID int64 `xorm:"pk autoincr"`
|
||||||
@@ -54,12 +46,11 @@ func (key *GPGKey) BeforeInsert() {
|
|||||||
key.AddedUnix = timeutil.TimeStampNow()
|
key.AddedUnix = timeutil.TimeStampNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
func (key *GPGKey) LoadSubKeys(ctx context.Context) error {
|
||||||
func (key *GPGKey) AfterLoad(session *xorm.Session) {
|
if err := db.GetEngine(ctx).Where("primary_key_id=?", key.KeyID).Find(&key.SubsKey); err != nil {
|
||||||
err := session.Where("primary_key_id=?", key.KeyID).Find(&key.SubsKey)
|
return fmt.Errorf("find Sub GPGkeys[%s]: %v", key.KeyID, err)
|
||||||
if err != nil {
|
|
||||||
log.Error("Find Sub GPGkeys[%s]: %v", key.KeyID, err)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaddedKeyID show KeyID padded to 16 characters
|
// PaddedKeyID show KeyID padded to 16 characters
|
||||||
@@ -76,26 +67,31 @@ func PaddedKeyID(keyID string) string {
|
|||||||
return zeros[0:16-len(keyID)] + keyID
|
return zeros[0:16-len(keyID)] + keyID
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListGPGKeys returns a list of public keys belongs to given user.
|
type FindGPGKeyOptions struct {
|
||||||
func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) {
|
db.ListOptions
|
||||||
sess := db.GetEngine(ctx).Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
|
OwnerID int64
|
||||||
if listOptions.Page != 0 {
|
KeyID string
|
||||||
sess = db.SetSessionPagination(sess, &listOptions)
|
IncludeSubKeys bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts FindGPGKeyOptions) ToConds() builder.Cond {
|
||||||
|
cond := builder.NewCond()
|
||||||
|
if !opts.IncludeSubKeys {
|
||||||
|
cond = cond.And(builder.Eq{"primary_key_id": ""})
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make([]*GPGKey, 0, 2)
|
if opts.OwnerID > 0 {
|
||||||
return keys, sess.Find(&keys)
|
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
|
||||||
|
}
|
||||||
|
if opts.KeyID != "" {
|
||||||
|
cond = cond.And(builder.Eq{"key_id": opts.KeyID})
|
||||||
|
}
|
||||||
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountUserGPGKeys return number of gpg keys a user own
|
func GetGPGKeyForUserByID(ctx context.Context, ownerID, keyID int64) (*GPGKey, error) {
|
||||||
func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) {
|
|
||||||
return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGPGKeyByID returns public key by given ID.
|
|
||||||
func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) {
|
|
||||||
key := new(GPGKey)
|
key := new(GPGKey)
|
||||||
has, err := db.GetEngine(ctx).ID(keyID).Get(key)
|
has, err := db.GetEngine(ctx).Where("id=? AND owner_id=?", keyID, ownerID).Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
@@ -104,12 +100,6 @@ func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) {
|
|||||||
return key, nil
|
return key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGPGKeysByKeyID returns public key by given ID.
|
|
||||||
func GetGPGKeysByKeyID(ctx context.Context, keyID string) ([]*GPGKey, error) {
|
|
||||||
keys := make([]*GPGKey, 0, 1)
|
|
||||||
return keys, db.GetEngine(ctx).Where("key_id=?", keyID).Find(&keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GPGKeyToEntity retrieve the imported key and the traducted entity
|
// GPGKeyToEntity retrieve the imported key and the traducted entity
|
||||||
func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) {
|
func GPGKeyToEntity(ctx context.Context, k *GPGKey) (*openpgp.Entity, error) {
|
||||||
impKey, err := GetGPGImportByKeyID(ctx, k.KeyID)
|
impKey, err := GetGPGImportByKeyID(ctx, k.KeyID)
|
||||||
@@ -225,7 +215,7 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) {
|
|||||||
|
|
||||||
// DeleteGPGKey deletes GPG key information in database.
|
// DeleteGPGKey deletes GPG key information in database.
|
||||||
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) {
|
||||||
key, err := GetGPGKeyByID(ctx, id)
|
key, err := GetGPGKeyForUserByID(ctx, doer.ID, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if IsErrGPGKeyNotExist(err) {
|
if IsErrGPGKeyNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
@@ -233,11 +223,6 @@ func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err err
|
|||||||
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
return fmt.Errorf("GetPublicKeyByID: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user has access to delete this key.
|
|
||||||
if !doer.IsAdmin && doer.ID != key.OwnerID {
|
|
||||||
return ErrGPGKeyAccessDenied{doer.ID, key.ID}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -166,7 +166,9 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
|||||||
|
|
||||||
// Now try to associate the signature with the committer, if present
|
// Now try to associate the signature with the committer, if present
|
||||||
if committer.ID != 0 {
|
if committer.ID != 0 {
|
||||||
keys, err := ListGPGKeys(ctx, committer.ID, db.ListOptions{})
|
keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{
|
||||||
|
OwnerID: committer.ID,
|
||||||
|
})
|
||||||
if err != nil { // Skipping failed to get gpg keys of user
|
if err != nil { // Skipping failed to get gpg keys of user
|
||||||
log.Error("ListGPGKeys: %v", err)
|
log.Error("ListGPGKeys: %v", err)
|
||||||
return &CommitVerification{
|
return &CommitVerification{
|
||||||
@@ -176,6 +178,15 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := GPGKeyList(keys).LoadSubKeys(ctx); err != nil {
|
||||||
|
log.Error("LoadSubKeys: %v", err)
|
||||||
|
return &CommitVerification{
|
||||||
|
CommittingUser: committer,
|
||||||
|
Verified: false,
|
||||||
|
Reason: "gpg.error.failed_retrieval_gpg_keys",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID)
|
committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID)
|
||||||
activated := false
|
activated := false
|
||||||
for _, e := range committerEmailAddresses {
|
for _, e := range committerEmailAddresses {
|
||||||
@@ -392,7 +403,10 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
|||||||
if keyID == "" {
|
if keyID == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
keys, err := GetGPGKeysByKeyID(ctx, keyID)
|
keys, err := db.Find[GPGKey](ctx, FindGPGKeyOptions{
|
||||||
|
KeyID: keyID,
|
||||||
|
IncludeSubKeys: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||||
return &CommitVerification{
|
return &CommitVerification{
|
||||||
@@ -407,7 +421,10 @@ func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload s
|
|||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
var primaryKeys []*GPGKey
|
var primaryKeys []*GPGKey
|
||||||
if key.PrimaryKeyID != "" {
|
if key.PrimaryKeyID != "" {
|
||||||
primaryKeys, err = GetGPGKeysByKeyID(ctx, key.PrimaryKeyID)
|
primaryKeys, err = db.Find[GPGKey](ctx, FindGPGKeyOptions{
|
||||||
|
KeyID: key.PrimaryKeyID,
|
||||||
|
IncludeSubKeys: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||||
return &CommitVerification{
|
return &CommitVerification{
|
||||||
|
|||||||
38
models/asymkey/gpg_key_list.go
Normal file
38
models/asymkey/gpg_key_list.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package asymkey
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GPGKeyList []*GPGKey
|
||||||
|
|
||||||
|
func (keys GPGKeyList) keyIDs() []string {
|
||||||
|
ids := make([]string, len(keys))
|
||||||
|
for i, key := range keys {
|
||||||
|
ids[i] = key.KeyID
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func (keys GPGKeyList) LoadSubKeys(ctx context.Context) error {
|
||||||
|
subKeys := make([]*GPGKey, 0, len(keys))
|
||||||
|
if err := db.GetEngine(ctx).In("primary_key_id", keys.keyIDs()).Find(&subKeys); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
subKeysMap := make(map[string][]*GPGKey, len(subKeys))
|
||||||
|
for _, key := range subKeys {
|
||||||
|
subKeysMap[key.PrimaryKeyID] = append(subKeysMap[key.PrimaryKeyID], key)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if subKeys, ok := subKeysMap[key.KeyID]; ok {
|
||||||
|
key.SubsKey = subKeys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -107,8 +107,9 @@ func VerifyGPGKey(ctx context.Context, ownerID int64, keyID, token, signature st
|
|||||||
// VerificationToken returns token for the user that will be valid in minutes (time)
|
// VerificationToken returns token for the user that will be valid in minutes (time)
|
||||||
func VerificationToken(user *user_model.User, minutes int) string {
|
func VerificationToken(user *user_model.User, minutes int) string {
|
||||||
return base.EncodeSha256(
|
return base.EncodeSha256(
|
||||||
time.Now().Truncate(1*time.Minute).Add(time.Duration(minutes)*time.Minute).Format(time.RFC1123Z) + ":" +
|
time.Now().Truncate(1*time.Minute).Add(time.Duration(minutes)*time.Minute).Format(
|
||||||
user.CreatedUnix.FormatLong() + ":" +
|
time.RFC1123Z) + ":" +
|
||||||
|
user.CreatedUnix.Format(time.RFC1123Z) + ":" +
|
||||||
user.Name + ":" +
|
user.Name + ":" +
|
||||||
user.Email + ":" +
|
user.Email + ":" +
|
||||||
strconv.FormatInt(user.ID, 10))
|
strconv.FormatInt(user.ID, 10))
|
||||||
|
|||||||
@@ -197,10 +197,10 @@ func (opts FindPublicKeyOptions) ToConds() builder.Cond {
|
|||||||
cond = cond.And(builder.Eq{"fingerprint": opts.Fingerprint})
|
cond = cond.And(builder.Eq{"fingerprint": opts.Fingerprint})
|
||||||
}
|
}
|
||||||
if len(opts.KeyTypes) > 0 {
|
if len(opts.KeyTypes) > 0 {
|
||||||
cond = cond.And(builder.In("type", opts.KeyTypes))
|
cond = cond.And(builder.In("`type`", opts.KeyTypes))
|
||||||
}
|
}
|
||||||
if opts.NotKeytype > 0 {
|
if opts.NotKeytype > 0 {
|
||||||
cond = cond.And(builder.Neq{"type": opts.NotKeytype})
|
cond = cond.And(builder.Neq{"`type`": opts.NotKeytype})
|
||||||
}
|
}
|
||||||
if opts.LoginSourceID > 0 {
|
if opts.LoginSourceID > 0 {
|
||||||
cond = cond.And(builder.Eq{"login_source_id": opts.LoginSourceID})
|
cond = cond.And(builder.Eq{"login_source_id": opts.LoginSourceID})
|
||||||
@@ -227,16 +227,6 @@ func UpdatePublicKeyUpdated(ctx context.Context, id int64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePublicKeys does the actual key deletion but does not update authorized_keys file.
|
|
||||||
func DeletePublicKeys(ctx context.Context, keyIDs ...int64) error {
|
|
||||||
if len(keyIDs) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := db.GetEngine(ctx).In("id", keyIDs).Delete(new(PublicKey))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key
|
// PublicKeysAreExternallyManaged returns whether the provided KeyID represents an externally managed Key
|
||||||
func PublicKeysAreExternallyManaged(ctx context.Context, keys []*PublicKey) ([]bool, error) {
|
func PublicKeysAreExternallyManaged(ctx context.Context, keys []*PublicKey) ([]bool, error) {
|
||||||
sources := make([]*auth.Source, 0, 5)
|
sources := make([]*auth.Source, 0, 5)
|
||||||
@@ -322,8 +312,8 @@ func deleteKeysMarkedForDeletion(ctx context.Context, keys []string) (bool, erro
|
|||||||
log.Error("SearchPublicKeyByContent: %v", err)
|
log.Error("SearchPublicKeyByContent: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err = DeletePublicKeys(ctx, key.ID); err != nil {
|
if _, err = db.DeleteByID[PublicKey](ctx, key.ID); err != nil {
|
||||||
log.Error("deletePublicKeys: %v", err)
|
log.Error("DeleteByID[PublicKey]: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sshKeysNeedUpdate = true
|
sshKeysNeedUpdate = true
|
||||||
|
|||||||
@@ -131,24 +131,22 @@ func AddDeployKey(ctx context.Context, repoID int64, name, content string, readO
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
pkey := &PublicKey{
|
pkey, exist, err := db.Get[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
|
||||||
Fingerprint: fingerprint,
|
|
||||||
}
|
|
||||||
has, err := db.GetByBean(ctx, pkey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
} else if exist {
|
||||||
|
|
||||||
if has {
|
|
||||||
if pkey.Type != KeyTypeDeploy {
|
if pkey.Type != KeyTypeDeploy {
|
||||||
return nil, ErrKeyAlreadyExist{0, fingerprint, ""}
|
return nil, ErrKeyAlreadyExist{0, fingerprint, ""}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// First time use this deploy key.
|
// First time use this deploy key.
|
||||||
pkey.Mode = accessMode
|
pkey = &PublicKey{
|
||||||
pkey.Type = KeyTypeDeploy
|
Fingerprint: fingerprint,
|
||||||
pkey.Content = content
|
Mode: accessMode,
|
||||||
pkey.Name = name
|
Type: KeyTypeDeploy,
|
||||||
|
Content: content,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
if err = addKey(ctx, pkey); err != nil {
|
if err = addKey(ctx, pkey); err != nil {
|
||||||
return nil, fmt.Errorf("addKey: %w", err)
|
return nil, fmt.Errorf("addKey: %w", err)
|
||||||
}
|
}
|
||||||
@@ -164,11 +162,10 @@ func AddDeployKey(ctx context.Context, repoID int64, name, content string, readO
|
|||||||
|
|
||||||
// GetDeployKeyByID returns deploy key by given ID.
|
// GetDeployKeyByID returns deploy key by given ID.
|
||||||
func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) {
|
func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) {
|
||||||
key := new(DeployKey)
|
key, exist, err := db.GetByID[DeployKey](ctx, id)
|
||||||
has, err := db.GetEngine(ctx).ID(id).Get(key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !exist {
|
||||||
return nil, ErrDeployKeyNotExist{id, 0, 0}
|
return nil, ErrDeployKeyNotExist{id, 0, 0}
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
@@ -176,14 +173,10 @@ func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) {
|
|||||||
|
|
||||||
// GetDeployKeyByRepo returns deploy key by given public key ID and repository ID.
|
// GetDeployKeyByRepo returns deploy key by given public key ID and repository ID.
|
||||||
func GetDeployKeyByRepo(ctx context.Context, keyID, repoID int64) (*DeployKey, error) {
|
func GetDeployKeyByRepo(ctx context.Context, keyID, repoID int64) (*DeployKey, error) {
|
||||||
key := &DeployKey{
|
key, exist, err := db.Get[DeployKey](ctx, builder.Eq{"key_id": keyID, "repo_id": repoID})
|
||||||
KeyID: keyID,
|
|
||||||
RepoID: repoID,
|
|
||||||
}
|
|
||||||
has, err := db.GetByBean(ctx, key)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !exist {
|
||||||
return nil, ErrDeployKeyNotExist{0, keyID, repoID}
|
return nil, ErrDeployKeyNotExist{0, keyID, repoID}
|
||||||
}
|
}
|
||||||
return key, nil
|
return key, nil
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ___________.__ .__ __
|
// ___________.__ .__ __
|
||||||
@@ -31,9 +32,7 @@ import (
|
|||||||
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
|
// checkKeyFingerprint only checks if key fingerprint has been used as public key,
|
||||||
// it is OK to use same key as deploy key for multiple repositories/users.
|
// it is OK to use same key as deploy key for multiple repositories/users.
|
||||||
func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
|
func checkKeyFingerprint(ctx context.Context, fingerprint string) error {
|
||||||
has, err := db.GetByBean(ctx, &PublicKey{
|
has, err := db.Exist[PublicKey](ctx, builder.Eq{"fingerprint": fingerprint})
|
||||||
Fingerprint: fingerprint,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if has {
|
} else if has {
|
||||||
|
|||||||
@@ -15,15 +15,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// __________ .__ .__ .__
|
|
||||||
// \______ _______|__| ____ ____ |_____________ | | ______
|
|
||||||
// | ___\_ __ | |/ \_/ ___\| \____ \__ \ | | / ___/
|
|
||||||
// | | | | \| | | \ \___| | |_> / __ \| |__\___ \
|
|
||||||
// |____| |__| |__|___| /\___ |__| __(____ |____/____ >
|
|
||||||
// \/ \/ |__| \/ \/
|
|
||||||
//
|
|
||||||
// This file contains functions related to principals
|
|
||||||
|
|
||||||
// AddPrincipalKey adds new principal to database and authorized_principals file.
|
// AddPrincipalKey adds new principal to database and authorized_principals file.
|
||||||
func AddPrincipalKey(ctx context.Context, ownerID int64, content string, authSourceID int64) (*PublicKey, error) {
|
func AddPrincipalKey(ctx context.Context, ownerID int64, content string, authSourceID int64) (*PublicKey, error) {
|
||||||
dbCtx, committer, err := db.TxContext(ctx)
|
dbCtx, committer, err := db.TxContext(ctx)
|
||||||
@@ -103,17 +94,3 @@ func CheckPrincipalKeyString(ctx context.Context, user *user_model.User, content
|
|||||||
|
|
||||||
return "", fmt.Errorf("didn't match allowed principals: %s", setting.SSH.AuthorizedPrincipalsAllow)
|
return "", fmt.Errorf("didn't match allowed principals: %s", setting.SSH.AuthorizedPrincipalsAllow)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListPrincipalKeys returns a list of principals belongs to given user.
|
|
||||||
func ListPrincipalKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*PublicKey, error) {
|
|
||||||
sess := db.GetEngine(ctx).Where("owner_id = ? AND type = ?", uid, KeyTypePrincipal)
|
|
||||||
if listOptions.Page != 0 {
|
|
||||||
sess = db.SetSessionPagination(sess, &listOptions)
|
|
||||||
|
|
||||||
keys := make([]*PublicKey, 0, listOptions.PageSize)
|
|
||||||
return keys, sess.Find(&keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
keys := make([]*PublicKey, 0, 5)
|
|
||||||
return keys, sess.Find(&keys)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,10 +30,15 @@ func VerifySSHKey(ctx context.Context, ownerID int64, fingerprint, token, signat
|
|||||||
return "", ErrKeyNotExist{}
|
return "", ErrKeyNotExist{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea"); err != nil {
|
err = sshsig.Verify(bytes.NewBuffer([]byte(token)), []byte(signature), []byte(key.Content), "gitea")
|
||||||
log.Error("Unable to validate token signature. Error: %v", err)
|
if err != nil {
|
||||||
return "", ErrSSHInvalidTokenSignature{
|
// edge case for Windows based shells that will add CR LF if piped to ssh-keygen command
|
||||||
Fingerprint: key.Fingerprint,
|
// see https://github.com/PowerShell/PowerShell/issues/5974
|
||||||
|
if sshsig.Verify(bytes.NewBuffer([]byte(token+"\r\n")), []byte(signature), []byte(key.Content), "gitea") != nil {
|
||||||
|
log.Error("Unable to validate token signature. Error: %v", err)
|
||||||
|
return "", ErrSSHInvalidTokenSignature{
|
||||||
|
Fingerprint: key.Fingerprint,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
|
"xorm.io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Session represents a session compatible for go-chi session
|
// Session represents a session compatible for go-chi session
|
||||||
@@ -33,34 +35,31 @@ func UpdateSession(ctx context.Context, key string, data []byte) error {
|
|||||||
|
|
||||||
// ReadSession reads the data for the provided session
|
// ReadSession reads the data for the provided session
|
||||||
func ReadSession(ctx context.Context, key string) (*Session, error) {
|
func ReadSession(ctx context.Context, key string) (*Session, error) {
|
||||||
session := Session{
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext(ctx)
|
ctx, committer, err := db.TxContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
if has, err := db.GetByBean(ctx, &session); err != nil {
|
session, exist, err := db.Get[Session](ctx, builder.Eq{"`key`": key})
|
||||||
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !exist {
|
||||||
session.Expiry = timeutil.TimeStampNow()
|
session = &Session{
|
||||||
if err := db.Insert(ctx, &session); err != nil {
|
Key: key,
|
||||||
|
Expiry: timeutil.TimeStampNow(),
|
||||||
|
}
|
||||||
|
if err := db.Insert(ctx, session); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &session, committer.Commit()
|
return session, committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExistSession checks if a session exists
|
// ExistSession checks if a session exists
|
||||||
func ExistSession(ctx context.Context, key string) (bool, error) {
|
func ExistSession(ctx context.Context, key string) (bool, error) {
|
||||||
session := Session{
|
return db.Exist[Session](ctx, builder.Eq{"`key`": key})
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
return db.GetEngine(ctx).Get(&session)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DestroySession destroys a session
|
// DestroySession destroys a session
|
||||||
@@ -79,17 +78,13 @@ func RegenerateSession(ctx context.Context, oldKey, newKey string) (*Session, er
|
|||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
if has, err := db.GetByBean(ctx, &Session{
|
if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": newKey}); err != nil {
|
||||||
Key: newKey,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if has {
|
} else if has {
|
||||||
return nil, fmt.Errorf("session Key: %s already exists", newKey)
|
return nil, fmt.Errorf("session Key: %s already exists", newKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if has, err := db.GetByBean(ctx, &Session{
|
if has, err := db.Exist[Session](ctx, builder.Eq{"`key`": oldKey}); err != nil {
|
||||||
Key: oldKey,
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
if err := db.Insert(ctx, &Session{
|
if err := db.Insert(ctx, &Session{
|
||||||
@@ -104,14 +99,13 @@ func RegenerateSession(ctx context.Context, oldKey, newKey string) (*Session, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s := Session{
|
s, _, err := db.Get[Session](ctx, builder.Eq{"`key`": newKey})
|
||||||
Key: newKey,
|
if err != nil {
|
||||||
}
|
// is not exist, it should be impossible
|
||||||
if _, err := db.GetByBean(ctx, &s); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &s, committer.Commit()
|
return s, committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountSessions returns the number of sessions
|
// CountSessions returns the number of sessions
|
||||||
|
|||||||
@@ -261,16 +261,12 @@ func (opts FindSourcesOptions) ToConds() builder.Cond {
|
|||||||
// IsSSPIEnabled returns true if there is at least one activated login
|
// IsSSPIEnabled returns true if there is at least one activated login
|
||||||
// source of type LoginSSPI
|
// source of type LoginSSPI
|
||||||
func IsSSPIEnabled(ctx context.Context) bool {
|
func IsSSPIEnabled(ctx context.Context) bool {
|
||||||
if !db.HasEngine {
|
exist, err := db.Exist[Source](ctx, FindSourcesOptions{
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
exist, err := db.Exists[Source](ctx, FindSourcesOptions{
|
|
||||||
IsActive: util.OptionalBoolTrue,
|
IsActive: util.OptionalBoolTrue,
|
||||||
LoginType: SSPI,
|
LoginType: SSPI,
|
||||||
})
|
}.ToConds())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Active SSPI Sources: %v", err)
|
log.Error("IsSSPIEnabled: failed to query active SSPI sources: %v", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return exist
|
return exist
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/go-webauthn/webauthn/webauthn"
|
"github.com/go-webauthn/webauthn/webauthn"
|
||||||
"xorm.io/xorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrWebAuthnCredentialNotExist represents a "ErrWebAuthnCRedentialNotExist" kind of error.
|
// ErrWebAuthnCredentialNotExist represents a "ErrWebAuthnCRedentialNotExist" kind of error.
|
||||||
@@ -83,7 +82,7 @@ func (cred *WebAuthnCredential) BeforeUpdate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
|
||||||
func (cred *WebAuthnCredential) AfterLoad(session *xorm.Session) {
|
func (cred *WebAuthnCredential) AfterLoad() {
|
||||||
cred.LowerName = strings.ToLower(cred.Name)
|
cred.LowerName = strings.ToLower(cred.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package avatars
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@@ -13,7 +15,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/modules/base"
|
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@@ -90,7 +91,9 @@ func DefaultAvatarLink() string {
|
|||||||
|
|
||||||
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
// HashEmail hashes email address to MD5 string. https://en.gravatar.com/site/implement/hash/
|
||||||
func HashEmail(email string) string {
|
func HashEmail(email string) string {
|
||||||
return base.EncodeMD5(strings.ToLower(strings.TrimSpace(email)))
|
m := md5.New()
|
||||||
|
_, _ = m.Write([]byte(strings.ToLower(strings.TrimSpace(email))))
|
||||||
|
return hex.EncodeToString(m.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetEmailForHash converts a provided md5sum to the email
|
// GetEmailForHash converts a provided md5sum to the email
|
||||||
|
|||||||
191
models/db/collation.go
Normal file
191
models/db/collation.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Copyright 2023 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/container"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
"xorm.io/xorm/schemas"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckCollationsResult struct {
|
||||||
|
ExpectedCollation string
|
||||||
|
AvailableCollation container.Set[string]
|
||||||
|
DatabaseCollation string
|
||||||
|
IsCollationCaseSensitive func(s string) bool
|
||||||
|
CollationEquals func(a, b string) bool
|
||||||
|
ExistingTableNumber int
|
||||||
|
|
||||||
|
InconsistentCollationColumns []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func findAvailableCollationsMySQL(x *xorm.Engine) (ret container.Set[string], err error) {
|
||||||
|
var res []struct {
|
||||||
|
Collation string
|
||||||
|
}
|
||||||
|
if err = x.SQL("SHOW COLLATION WHERE (Collation = 'utf8mb4_bin') OR (Collation LIKE '%\\_as\\_cs%')").Find(&res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = make(container.Set[string], len(res))
|
||||||
|
for _, r := range res {
|
||||||
|
ret.Add(r.Collation)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findAvailableCollationsMSSQL(x *xorm.Engine) (ret container.Set[string], err error) {
|
||||||
|
var res []struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
if err = x.SQL("SELECT * FROM sys.fn_helpcollations() WHERE name LIKE '%[_]CS[_]AS%'").Find(&res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = make(container.Set[string], len(res))
|
||||||
|
for _, r := range res {
|
||||||
|
ret.Add(r.Name)
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckCollations(x *xorm.Engine) (*CheckCollationsResult, error) {
|
||||||
|
dbTables, err := x.DBMetas()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &CheckCollationsResult{
|
||||||
|
ExistingTableNumber: len(dbTables),
|
||||||
|
CollationEquals: func(a, b string) bool { return a == b },
|
||||||
|
}
|
||||||
|
|
||||||
|
var candidateCollations []string
|
||||||
|
if x.Dialect().URI().DBType == schemas.MYSQL {
|
||||||
|
if _, err = x.SQL("SELECT @@collation_database").Get(&res.DatabaseCollation); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.IsCollationCaseSensitive = func(s string) bool {
|
||||||
|
return s == "utf8mb4_bin" || strings.HasSuffix(s, "_as_cs")
|
||||||
|
}
|
||||||
|
candidateCollations = []string{"utf8mb4_0900_as_cs", "uca1400_as_cs", "utf8mb4_bin"}
|
||||||
|
res.AvailableCollation, err = findAvailableCollationsMySQL(x)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.CollationEquals = func(a, b string) bool {
|
||||||
|
// MariaDB adds the "utf8mb4_" prefix, eg: "utf8mb4_uca1400_as_cs", but not the name "uca1400_as_cs" in "SHOW COLLATION"
|
||||||
|
// At the moment, it's safe to ignore the database difference, just trim the prefix and compare. It could be fixed easily if there is any problem in the future.
|
||||||
|
return a == b || strings.TrimPrefix(a, "utf8mb4_") == strings.TrimPrefix(b, "utf8mb4_")
|
||||||
|
}
|
||||||
|
} else if x.Dialect().URI().DBType == schemas.MSSQL {
|
||||||
|
if _, err = x.SQL("SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation')").Get(&res.DatabaseCollation); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res.IsCollationCaseSensitive = func(s string) bool {
|
||||||
|
return strings.HasSuffix(s, "_CS_AS")
|
||||||
|
}
|
||||||
|
candidateCollations = []string{"Latin1_General_CS_AS"}
|
||||||
|
res.AvailableCollation, err = findAvailableCollationsMSSQL(x)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.DatabaseCollation == "" {
|
||||||
|
return nil, errors.New("unable to get collation for current database")
|
||||||
|
}
|
||||||
|
|
||||||
|
res.ExpectedCollation = setting.Database.CharsetCollation
|
||||||
|
if res.ExpectedCollation == "" {
|
||||||
|
for _, collation := range candidateCollations {
|
||||||
|
if res.AvailableCollation.Contains(collation) {
|
||||||
|
res.ExpectedCollation = collation
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.ExpectedCollation == "" {
|
||||||
|
return nil, errors.New("unable to find a suitable collation for current database")
|
||||||
|
}
|
||||||
|
|
||||||
|
allColumnsMatchExpected := true
|
||||||
|
allColumnsMatchDatabase := true
|
||||||
|
for _, table := range dbTables {
|
||||||
|
for _, col := range table.Columns() {
|
||||||
|
if col.Collation != "" {
|
||||||
|
allColumnsMatchExpected = allColumnsMatchExpected && res.CollationEquals(col.Collation, res.ExpectedCollation)
|
||||||
|
allColumnsMatchDatabase = allColumnsMatchDatabase && res.CollationEquals(col.Collation, res.DatabaseCollation)
|
||||||
|
if !res.IsCollationCaseSensitive(col.Collation) || !res.CollationEquals(col.Collation, res.DatabaseCollation) {
|
||||||
|
res.InconsistentCollationColumns = append(res.InconsistentCollationColumns, fmt.Sprintf("%s.%s", table.Name, col.Name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if all columns match expected collation or all match database collation, then it could also be considered as "consistent"
|
||||||
|
if allColumnsMatchExpected || allColumnsMatchDatabase {
|
||||||
|
res.InconsistentCollationColumns = nil
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckCollationsDefaultEngine() (*CheckCollationsResult, error) {
|
||||||
|
return CheckCollations(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func alterDatabaseCollation(x *xorm.Engine, collation string) error {
|
||||||
|
if x.Dialect().URI().DBType == schemas.MYSQL {
|
||||||
|
_, err := x.Exec("ALTER DATABASE CHARACTER SET utf8mb4 COLLATE " + collation)
|
||||||
|
return err
|
||||||
|
} else if x.Dialect().URI().DBType == schemas.MSSQL {
|
||||||
|
// TODO: MSSQL has many limitations on changing database collation, it could fail in many cases.
|
||||||
|
_, err := x.Exec("ALTER DATABASE CURRENT COLLATE " + collation)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return errors.New("unsupported database type")
|
||||||
|
}
|
||||||
|
|
||||||
|
// preprocessDatabaseCollation checks database & table column collation, and alter the database collation if needed
|
||||||
|
func preprocessDatabaseCollation(x *xorm.Engine) {
|
||||||
|
r, err := CheckCollations(x)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to check database collation: %v", err)
|
||||||
|
}
|
||||||
|
if r == nil {
|
||||||
|
return // no check result means the database doesn't need to do such check/process (at the moment ....)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to alter database collation to expected if the database is empty, it might fail in some cases (and it isn't necessary to succeed)
|
||||||
|
// at the moment, there is no "altering" solution for MSSQL, site admin should manually change the database collation
|
||||||
|
// and there is a bug https://github.com/go-testfixtures/testfixtures/pull/182 mssql: Invalid object name 'information_schema.tables'.
|
||||||
|
if !r.CollationEquals(r.DatabaseCollation, r.ExpectedCollation) && r.ExistingTableNumber == 0 && x.Dialect().URI().DBType == schemas.MYSQL {
|
||||||
|
if err = alterDatabaseCollation(x, r.ExpectedCollation); err != nil {
|
||||||
|
log.Error("Failed to change database collation to %q: %v", r.ExpectedCollation, err)
|
||||||
|
} else {
|
||||||
|
_, _ = x.Exec("SELECT 1") // after "altering", MSSQL's session becomes invalid, so make a simple query to "refresh" the session
|
||||||
|
if r, err = CheckCollations(x); err != nil {
|
||||||
|
log.Error("Failed to check database collation again after altering: %v", err) // impossible case
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Warn("Current database has been altered to use collation %q", r.DatabaseCollation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check column collation, and show warning/error to end users -- no need to fatal, do not block the startup
|
||||||
|
if !r.IsCollationCaseSensitive(r.DatabaseCollation) {
|
||||||
|
log.Warn("Current database is using a case-insensitive collation %q, although Gitea could work with it, there might be some rare cases which don't work as expected.", r.DatabaseCollation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.InconsistentCollationColumns) > 0 {
|
||||||
|
log.Error("There are %d table columns using inconsistent collation, they should use %q. Please go to admin panel Self Check page", len(r.InconsistentCollationColumns), r.DatabaseCollation)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -173,9 +173,69 @@ func Exec(ctx context.Context, sqlAndArgs ...any) (sql.Result, error) {
|
|||||||
return GetEngine(ctx).Exec(sqlAndArgs...)
|
return GetEngine(ctx).Exec(sqlAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByBean filled empty fields of the bean according non-empty fields to query in database.
|
func Get[T any](ctx context.Context, cond builder.Cond) (object *T, exist bool, err error) {
|
||||||
func GetByBean(ctx context.Context, bean any) (bool, error) {
|
if !cond.IsValid() {
|
||||||
return GetEngine(ctx).Get(bean)
|
panic("cond is invalid in db.Get(ctx, cond). This should not be possible.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var bean T
|
||||||
|
has, err := GetEngine(ctx).Where(cond).NoAutoCondition().Get(&bean)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
return &bean, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetByID[T any](ctx context.Context, id int64) (object *T, exist bool, err error) {
|
||||||
|
var bean T
|
||||||
|
has, err := GetEngine(ctx).ID(id).NoAutoCondition().Get(&bean)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
} else if !has {
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
return &bean, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Exist[T any](ctx context.Context, cond builder.Cond) (bool, error) {
|
||||||
|
if !cond.IsValid() {
|
||||||
|
panic("cond is invalid in db.Exist(ctx, cond). This should not be possible.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var bean T
|
||||||
|
return GetEngine(ctx).Where(cond).NoAutoCondition().Exist(&bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExistByID[T any](ctx context.Context, id int64) (bool, error) {
|
||||||
|
var bean T
|
||||||
|
return GetEngine(ctx).ID(id).NoAutoCondition().Exist(&bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteByID deletes the given bean with the given ID
|
||||||
|
func DeleteByID[T any](ctx context.Context, id int64) (int64, error) {
|
||||||
|
var bean T
|
||||||
|
return GetEngine(ctx).ID(id).NoAutoCondition().NoAutoTime().Delete(&bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteByIDs[T any](ctx context.Context, ids ...int64) error {
|
||||||
|
if len(ids) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var bean T
|
||||||
|
_, err := GetEngine(ctx).In("id", ids).NoAutoCondition().NoAutoTime().Delete(&bean)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Delete[T any](ctx context.Context, opts FindOptions) (int64, error) {
|
||||||
|
if opts == nil || !opts.ToConds().IsValid() {
|
||||||
|
panic("opts are empty or invalid in db.Delete(ctx, opts). This should not be possible.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var bean T
|
||||||
|
return GetEngine(ctx).Where(opts.ToConds()).NoAutoCondition().NoAutoTime().Delete(&bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteByBean deletes all records according non-empty fields of the bean as conditions.
|
// DeleteByBean deletes all records according non-empty fields of the bean as conditions.
|
||||||
@@ -183,11 +243,6 @@ func DeleteByBean(ctx context.Context, bean any) (int64, error) {
|
|||||||
return GetEngine(ctx).Delete(bean)
|
return GetEngine(ctx).Delete(bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteByID deletes the given bean with the given ID
|
|
||||||
func DeleteByID(ctx context.Context, id int64, bean any) (int64, error) {
|
|
||||||
return GetEngine(ctx).ID(id).NoAutoCondition().NoAutoTime().Delete(bean)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindIDs finds the IDs for the given table name satisfying the given condition
|
// FindIDs finds the IDs for the given table name satisfying the given condition
|
||||||
// By passing a different value than "id" for "idCol", you can query for foreign IDs, i.e. the repo IDs which satisfy the condition
|
// By passing a different value than "id" for "idCol", you can query for foreign IDs, i.e. the repo IDs which satisfy the condition
|
||||||
func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([]int64, error) {
|
func FindIDs(ctx context.Context, tableName, idCol string, cond builder.Cond) ([]int64, error) {
|
||||||
@@ -264,8 +319,3 @@ func inTransaction(ctx context.Context) (*xorm.Session, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Exists[T any](ctx context.Context, opts FindOptions) (bool, error) {
|
|
||||||
var bean T
|
|
||||||
return GetEngine(ctx).Where(opts.ToConds()).Exist(&bean)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,13 +14,18 @@ import (
|
|||||||
"xorm.io/xorm/schemas"
|
"xorm.io/xorm/schemas"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConvertUtf8ToUtf8mb4 converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic
|
// ConvertDatabaseTable converts database and tables from utf8 to utf8mb4 if it's mysql and set ROW_FORMAT=dynamic
|
||||||
func ConvertUtf8ToUtf8mb4() error {
|
func ConvertDatabaseTable() error {
|
||||||
if x.Dialect().URI().DBType != schemas.MYSQL {
|
if x.Dialect().URI().DBType != schemas.MYSQL {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", setting.Database.Name))
|
r, err := CheckCollations(x)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = x.Exec(fmt.Sprintf("ALTER DATABASE `%s` CHARACTER SET utf8mb4 COLLATE %s", setting.Database.Name, r.ExpectedCollation))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -30,11 +35,11 @@ func ConvertUtf8ToUtf8mb4() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic;", table.Name)); err != nil {
|
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` ROW_FORMAT=dynamic", table.Name)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;", table.Name)); err != nil {
|
if _, err := x.Exec(fmt.Sprintf("ALTER TABLE `%s` CONVERT TO CHARACTER SET utf8mb4 COLLATE %s", table.Name, r.ExpectedCollation)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ var (
|
|||||||
x *xorm.Engine
|
x *xorm.Engine
|
||||||
tables []any
|
tables []any
|
||||||
initFuncs []func() error
|
initFuncs []func() error
|
||||||
|
|
||||||
// HasEngine specifies if we have a xorm.Engine
|
|
||||||
HasEngine bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Engine represents a xorm engine or session.
|
// Engine represents a xorm engine or session.
|
||||||
@@ -185,6 +182,8 @@ func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preprocessDatabaseCollation(x)
|
||||||
|
|
||||||
// We have to run migrateFunc here in case the user is re-running installation on a previously created DB.
|
// We have to run migrateFunc here in case the user is re-running installation on a previously created DB.
|
||||||
// If we do not then table schemas will be changed and there will be conflicts when the migrations run properly.
|
// If we do not then table schemas will be changed and there will be conflicts when the migrations run properly.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -31,11 +31,11 @@ func TestIterate(t *testing.T) {
|
|||||||
assert.EqualValues(t, cnt, repoUnitCnt)
|
assert.EqualValues(t, cnt, repoUnitCnt)
|
||||||
|
|
||||||
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error {
|
||||||
reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID}
|
has, err := db.ExistByID[repo_model.RepoUnit](ctx, repoUnit.ID)
|
||||||
has, err := db.GetByBean(ctx, &reopUnit2)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
}
|
||||||
|
if !has {
|
||||||
return db.ErrNotExist{Resource: "repo_unit", ID: repoUnit.ID}
|
return db.ErrNotExist{Resource: "repo_unit", ID: repoUnit.ID}
|
||||||
}
|
}
|
||||||
assert.EqualValues(t, repoUnit.RepoID, repoUnit.RepoID)
|
assert.EqualValues(t, repoUnit.RepoID, repoUnit.RepoID)
|
||||||
|
|||||||
@@ -21,17 +21,9 @@ const (
|
|||||||
// Paginator is the base for different ListOptions types
|
// Paginator is the base for different ListOptions types
|
||||||
type Paginator interface {
|
type Paginator interface {
|
||||||
GetSkipTake() (skip, take int)
|
GetSkipTake() (skip, take int)
|
||||||
GetStartEnd() (start, end int)
|
|
||||||
IsListAll() bool
|
IsListAll() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPaginatedSession creates a paginated database session
|
|
||||||
func GetPaginatedSession(p Paginator) *xorm.Session {
|
|
||||||
skip, take := p.GetSkipTake()
|
|
||||||
|
|
||||||
return x.Limit(take, skip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSessionPagination sets pagination for a database session
|
// SetSessionPagination sets pagination for a database session
|
||||||
func SetSessionPagination(sess Engine, p Paginator) *xorm.Session {
|
func SetSessionPagination(sess Engine, p Paginator) *xorm.Session {
|
||||||
skip, take := p.GetSkipTake()
|
skip, take := p.GetSkipTake()
|
||||||
@@ -39,13 +31,6 @@ func SetSessionPagination(sess Engine, p Paginator) *xorm.Session {
|
|||||||
return sess.Limit(take, skip)
|
return sess.Limit(take, skip)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetEnginePagination sets pagination for a database engine
|
|
||||||
func SetEnginePagination(e Engine, p Paginator) Engine {
|
|
||||||
skip, take := p.GetSkipTake()
|
|
||||||
|
|
||||||
return e.Limit(take, skip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListOptions options to paginate results
|
// ListOptions options to paginate results
|
||||||
type ListOptions struct {
|
type ListOptions struct {
|
||||||
PageSize int
|
PageSize int
|
||||||
@@ -66,13 +51,6 @@ func (opts *ListOptions) GetSkipTake() (skip, take int) {
|
|||||||
return (opts.Page - 1) * opts.PageSize, opts.PageSize
|
return (opts.Page - 1) * opts.PageSize, opts.PageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStartEnd returns the start and end of the ListOptions
|
|
||||||
func (opts *ListOptions) GetStartEnd() (start, end int) {
|
|
||||||
start, take := opts.GetSkipTake()
|
|
||||||
end = start + take
|
|
||||||
return start, end
|
|
||||||
}
|
|
||||||
|
|
||||||
func (opts ListOptions) GetPage() int {
|
func (opts ListOptions) GetPage() int {
|
||||||
return opts.Page
|
return opts.Page
|
||||||
}
|
}
|
||||||
@@ -135,11 +113,6 @@ func (opts *AbsoluteListOptions) GetSkipTake() (skip, take int) {
|
|||||||
return opts.skip, opts.take
|
return opts.skip, opts.take
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStartEnd returns the start and end values
|
|
||||||
func (opts *AbsoluteListOptions) GetStartEnd() (start, end int) {
|
|
||||||
return opts.skip, opts.skip + opts.take
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOptions represents a find options
|
// FindOptions represents a find options
|
||||||
type FindOptions interface {
|
type FindOptions interface {
|
||||||
GetPage() int
|
GetPage() int
|
||||||
@@ -148,15 +121,34 @@ type FindOptions interface {
|
|||||||
ToConds() builder.Cond
|
ToConds() builder.Cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type JoinFunc func(sess Engine) error
|
||||||
|
|
||||||
|
type FindOptionsJoin interface {
|
||||||
|
ToJoins() []JoinFunc
|
||||||
|
}
|
||||||
|
|
||||||
type FindOptionsOrder interface {
|
type FindOptionsOrder interface {
|
||||||
ToOrders() string
|
ToOrders() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find represents a common find function which accept an options interface
|
// Find represents a common find function which accept an options interface
|
||||||
func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
|
func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
|
||||||
sess := GetEngine(ctx).Where(opts.ToConds())
|
sess := GetEngine(ctx)
|
||||||
|
|
||||||
|
if joinOpt, ok := opts.(FindOptionsJoin); ok && len(joinOpt.ToJoins()) > 0 {
|
||||||
|
for _, joinFunc := range joinOpt.ToJoins() {
|
||||||
|
if err := joinFunc(sess); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sess = sess.Where(opts.ToConds())
|
||||||
page, pageSize := opts.GetPage(), opts.GetPageSize()
|
page, pageSize := opts.GetPage(), opts.GetPageSize()
|
||||||
if !opts.IsListAll() && pageSize > 0 && page >= 1 {
|
if !opts.IsListAll() && pageSize > 0 {
|
||||||
|
if page == 0 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
sess.Limit(pageSize, (page-1)*pageSize)
|
sess.Limit(pageSize, (page-1)*pageSize)
|
||||||
}
|
}
|
||||||
if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
|
if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
|
||||||
@@ -176,8 +168,17 @@ func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
|
|||||||
|
|
||||||
// Count represents a common count function which accept an options interface
|
// Count represents a common count function which accept an options interface
|
||||||
func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
|
func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
|
||||||
|
sess := GetEngine(ctx)
|
||||||
|
if joinOpt, ok := opts.(FindOptionsJoin); ok && len(joinOpt.ToJoins()) > 0 {
|
||||||
|
for _, joinFunc := range joinOpt.ToJoins() {
|
||||||
|
if err := joinFunc(sess); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var object T
|
var object T
|
||||||
return GetEngine(ctx).Where(opts.ToConds()).Count(&object)
|
return sess.Where(opts.ToConds()).Count(&object)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindAndCount represents a common findandcount function which accept an options interface
|
// FindAndCount represents a common findandcount function which accept an options interface
|
||||||
|
|||||||
@@ -52,11 +52,8 @@ func TestPaginator(t *testing.T) {
|
|||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
skip, take := c.Paginator.GetSkipTake()
|
skip, take := c.Paginator.GetSkipTake()
|
||||||
start, end := c.Paginator.GetStartEnd()
|
|
||||||
|
|
||||||
assert.Equal(t, c.Skip, skip)
|
assert.Equal(t, c.Skip, skip)
|
||||||
assert.Equal(t, c.Take, take)
|
assert.Equal(t, c.Take, take)
|
||||||
assert.Equal(t, c.Start, start)
|
|
||||||
assert.Equal(t, c.End, end)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,21 @@ func (err ErrUserOwnPackages) Error() string {
|
|||||||
return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID)
|
return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error.
|
||||||
|
type ErrDeleteLastAdminUser struct {
|
||||||
|
UID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser.
|
||||||
|
func IsErrDeleteLastAdminUser(err error) bool {
|
||||||
|
_, ok := err.(ErrDeleteLastAdminUser)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrDeleteLastAdminUser) Error() string {
|
||||||
|
return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID)
|
||||||
|
}
|
||||||
|
|
||||||
// ErrNoPendingRepoTransfer is an error type for repositories without a pending
|
// ErrNoPendingRepoTransfer is an error type for repositories without a pending
|
||||||
// transfer request
|
// transfer request
|
||||||
type ErrNoPendingRepoTransfer struct {
|
type ErrNoPendingRepoTransfer struct {
|
||||||
|
|||||||
@@ -66,3 +66,12 @@
|
|||||||
tree_path: "README.md"
|
tree_path: "README.md"
|
||||||
created_unix: 946684812
|
created_unix: 946684812
|
||||||
invalidated: true
|
invalidated: true
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 8
|
||||||
|
type: 0 # comment
|
||||||
|
poster_id: 2
|
||||||
|
issue_id: 4 # in repo_id 2
|
||||||
|
content: "comment in private pository"
|
||||||
|
created_unix: 946684811
|
||||||
|
updated_unix: 946684811
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
priority: 0
|
priority: 0
|
||||||
is_closed: true
|
is_closed: true
|
||||||
is_pull: false
|
is_pull: false
|
||||||
num_comments: 0
|
num_comments: 1
|
||||||
created_unix: 946684830
|
created_unix: 946684830
|
||||||
updated_unix: 978307200
|
updated_unix: 978307200
|
||||||
is_locked: false
|
is_locked: false
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user