mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-27 15:25:25 +00:00
Compare commits
104 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c749ce548 | ||
|
|
f540f57354 | ||
|
|
1c2d5e9b03 | ||
|
|
a859221a62 | ||
|
|
d37f7b44a9 | ||
|
|
a34eac5ef4 | ||
|
|
6d2b02dac1 | ||
|
|
1b70a4451a | ||
|
|
bc29cd0d3d | ||
|
|
edfba678ec | ||
|
|
9c0ad8291b | ||
|
|
58597cc30a | ||
|
|
86cc3e8783 | ||
|
|
5038561235 | ||
|
|
1d7b84922f | ||
|
|
2965b0c08a | ||
|
|
ab0d52b4c7 | ||
|
|
519b8d6d88 | ||
|
|
7b82ded82a | ||
|
|
1d5163133b | ||
|
|
0e53c41694 | ||
|
|
c7af094b0a | ||
|
|
28729ef7e3 | ||
|
|
57dd9f5bab | ||
|
|
5829522019 | ||
|
|
5eaa0bc603 | ||
|
|
fb159eae8f | ||
|
|
631a9b5d16 | ||
|
|
5636219dbc | ||
|
|
439984474c | ||
|
|
a55be951e3 | ||
|
|
65f3feaa84 | ||
|
|
b28c4f2b08 | ||
|
|
677ab982bf | ||
|
|
e10da87ebe | ||
|
|
3004c45607 | ||
|
|
7d77631881 | ||
|
|
2bafa41554 | ||
|
|
b586d80f97 | ||
|
|
58a66cae3c | ||
|
|
356a119f30 | ||
|
|
b79529015e | ||
|
|
eeb4d8ffa2 | ||
|
|
dd78d87dcd | ||
|
|
e2b211f291 | ||
|
|
8a49e9d346 | ||
|
|
b88bad2a01 | ||
|
|
5632abff9e | ||
|
|
74e515623b | ||
|
|
4ee74d7699 | ||
|
|
c4a1ff7d16 | ||
|
|
78899832eb | ||
|
|
fb3c1b031d | ||
|
|
cff6eb5661 | ||
|
|
2a61284ba5 | ||
|
|
11f77efea5 | ||
|
|
afdbd9b7c5 | ||
|
|
64d12024d6 | ||
|
|
6cc1ee9424 | ||
|
|
5d7768f34c | ||
|
|
55a6cfe79b | ||
|
|
1f643072c1 | ||
|
|
0280455356 | ||
|
|
a8e465e893 | ||
|
|
fc9dfe0e56 | ||
|
|
0916039c2a | ||
|
|
291f6cbd3a | ||
|
|
f536bcd508 | ||
|
|
fc4296a21a | ||
|
|
657ea10cf1 | ||
|
|
ef096b0f90 | ||
|
|
7bd55deab3 | ||
|
|
e4b7120bc2 | ||
|
|
f0fd185f14 | ||
|
|
adfa535dc2 | ||
|
|
e6691b0e8d | ||
|
|
82613a40a0 | ||
|
|
ba5117e4e4 | ||
|
|
9b9d1e31aa | ||
|
|
eb43da41f5 | ||
|
|
1412009d0a | ||
|
|
26a618ac1a | ||
|
|
145898b358 | ||
|
|
b191cf7e77 | ||
|
|
4adee80f58 | ||
|
|
4de12baf9b | ||
|
|
5d852d2d0a | ||
|
|
2aca966c5f | ||
|
|
3b253e06a3 | ||
|
|
df0ad4e8c1 | ||
|
|
68f5e40e46 | ||
|
|
d1be5c3612 | ||
|
|
8687faaf3a | ||
|
|
789a3d3a4d | ||
|
|
b37e098ff0 | ||
|
|
f9b808a8d2 | ||
|
|
0112ec9b34 | ||
|
|
7a7376dfc8 | ||
|
|
fc5e0ec877 | ||
|
|
d0a39bc3a4 | ||
|
|
4eca71d6d4 | ||
|
|
a2283a0c03 | ||
|
|
3e6b9e5312 | ||
|
|
1ad9e996be |
@@ -37,7 +37,10 @@ groups:
|
|||||||
name: BUGFIXES
|
name: BUGFIXES
|
||||||
labels:
|
labels:
|
||||||
- type/bug
|
- type/bug
|
||||||
|
-
|
||||||
|
name: API
|
||||||
|
labels:
|
||||||
|
- modifies/api
|
||||||
-
|
-
|
||||||
name: TESTING
|
name: TESTING
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "Gitea DevContainer",
|
"name": "Gitea DevContainer",
|
||||||
"image": "mcr.microsoft.com/devcontainers/go:1.26-trixie",
|
"image": "mcr.microsoft.com/devcontainers/go:1.25-trixie",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
// override "local" from packaged version
|
// override "local" from packaged version
|
||||||
"GOTOOLCHAIN": "auto"
|
"GOTOOLCHAIN": "auto"
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ cpu.out
|
|||||||
*.log
|
*.log
|
||||||
|
|
||||||
/gitea
|
/gitea
|
||||||
|
/gitea-vet
|
||||||
/debug
|
/debug
|
||||||
|
/integrations.test
|
||||||
|
|
||||||
/bin
|
/bin
|
||||||
/dist
|
/dist
|
||||||
@@ -52,6 +54,12 @@ cpu.out
|
|||||||
/indexers
|
/indexers
|
||||||
/log
|
/log
|
||||||
/tests/integration/gitea-integration-*
|
/tests/integration/gitea-integration-*
|
||||||
|
/tests/integration/indexers-*
|
||||||
|
/tests/e2e/gitea-e2e-*
|
||||||
|
/tests/e2e/indexers-*
|
||||||
|
/tests/e2e/reports
|
||||||
|
/tests/e2e/test-artifacts
|
||||||
|
/tests/e2e/test-snapshots
|
||||||
/tests/*.ini
|
/tests/*.ini
|
||||||
/node_modules
|
/node_modules
|
||||||
/yarn.lock
|
/yarn.lock
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ indent_style = tab
|
|||||||
[templates/custom/*.tmpl]
|
[templates/custom/*.tmpl]
|
||||||
insert_final_newline = false
|
insert_final_newline = false
|
||||||
|
|
||||||
[templates/swagger/*_json.tmpl]
|
[templates/swagger/v1_json.tmpl]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
insert_final_newline = false
|
insert_final_newline = false
|
||||||
|
|
||||||
|
|||||||
42
.gitea/issue_template.md
Normal file
42
.gitea/issue_template.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<!-- NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
1. Please speak English, this is the language all maintainers can speak and write.
|
||||||
|
2. Please ask questions or configuration/deploy problems on our Discord
|
||||||
|
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
|
||||||
|
3. Please take a moment to check that your issue doesn't already exist.
|
||||||
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||||
|
5. Please give all relevant information below for bug reports, because
|
||||||
|
incomplete details will be handled as an invalid report.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Gitea version (or commit ref):
|
||||||
|
- Git version:
|
||||||
|
- Operating system:
|
||||||
|
<!-- Please include information on whether you built gitea yourself, used one of our downloads or are using some other package -->
|
||||||
|
<!-- Please also tell us how you are running gitea, e.g. if it is being run from docker, a command-line, systemd etc. --->
|
||||||
|
<!-- If you are using a package or systemd tell us what distribution you are using -->
|
||||||
|
- Database (use `[x]`):
|
||||||
|
- [ ] PostgreSQL
|
||||||
|
- [ ] MySQL
|
||||||
|
- [ ] MSSQL
|
||||||
|
- [ ] SQLite
|
||||||
|
- Can you reproduce the bug at https://demo.gitea.com:
|
||||||
|
- [ ] Yes (provide example URL)
|
||||||
|
- [ ] No
|
||||||
|
- Log gist:
|
||||||
|
<!-- It really is important to provide pertinent logs -->
|
||||||
|
<!-- Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help -->
|
||||||
|
<!-- In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini -->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
<!-- If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please
|
||||||
|
disable the proxy/CDN fully and connect to gitea directly to confirm
|
||||||
|
the issue still persists without those services. -->
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<!-- **If this issue involves the Web Interface, please include a screenshot** -->
|
||||||
83
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
83
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
@@ -1,28 +1,91 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Something isn't working as expected.
|
description: Found something you weren't expecting? Report it here!
|
||||||
labels: ["type/bug"]
|
labels: ["type/bug"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
- **Security issue?** Email security@gitea.io instead of opening a public issue.
|
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
|
||||||
- **Need help** with setup or configuration? Ask on [Discord](https://discord.gg/Gitea) or the [forum](https://forum.gitea.com).
|
- type: markdown
|
||||||
- Search [existing issues](https://github.com/go-gitea/gitea/issues?q=is%3Aissue) first.
|
attributes:
|
||||||
|
value: |
|
||||||
|
1. Please speak English, this is the language all maintainers can speak and write.
|
||||||
|
2. Please ask questions or configuration/deploy problems on our Discord
|
||||||
|
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
|
||||||
|
3. Make sure you are using the latest release and
|
||||||
|
take a moment to check that your issue hasn't been reported before.
|
||||||
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||||
|
5. It's really important to provide pertinent details and logs (https://docs.gitea.com/help/support),
|
||||||
|
incomplete details will be handled as an invalid report.
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
||||||
|
If you are using a proxy or a CDN (e.g. Cloudflare) in front of Gitea, please disable the proxy/CDN fully and access Gitea directly to confirm the issue still persists without those services.
|
||||||
- type: input
|
- type: input
|
||||||
id: gitea-ver
|
id: gitea-ver
|
||||||
attributes:
|
attributes:
|
||||||
label: Gitea Version
|
label: Gitea Version
|
||||||
|
description: Gitea version (or commit reference) of your instance
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: dropdown
|
||||||
id: description
|
id: can-reproduce
|
||||||
attributes:
|
attributes:
|
||||||
label: What happened?
|
label: Can you reproduce the bug on the Gitea demo site?
|
||||||
description: What you did, what you expected to happen, and what happened instead. Include logs if relevant.
|
description: |
|
||||||
|
If so, please provide a URL in the Description field
|
||||||
|
URL of Gitea demo: https://demo.gitea.com
|
||||||
|
options:
|
||||||
|
- "Yes"
|
||||||
|
- "No"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
It's really important to provide pertinent logs
|
||||||
|
Please read https://docs.gitea.com/administration/logging-config#collecting-logs-for-help
|
||||||
|
In addition, if your problem relates to git commands set `RUN_MODE=dev` at the top of app.ini
|
||||||
|
- type: input
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Log Gist
|
||||||
|
description: Please provide a gist URL of your logs, with any sensitive information (e.g. API keys) removed/hidden
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: environment
|
id: screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: If this issue involves the Web Interface, please provide one or more screenshots
|
||||||
|
- type: input
|
||||||
|
id: git-ver
|
||||||
|
attributes:
|
||||||
|
label: Git Version
|
||||||
|
description: The version of git running on the server
|
||||||
|
- type: input
|
||||||
|
id: os-ver
|
||||||
|
attributes:
|
||||||
|
label: Operating System
|
||||||
|
description: The operating system you are using to run Gitea
|
||||||
|
- type: textarea
|
||||||
|
id: run-info
|
||||||
attributes:
|
attributes:
|
||||||
label: How are you running Gitea?
|
label: How are you running Gitea?
|
||||||
description: Install method (binary, Docker, package), operating system, and database.
|
description: |
|
||||||
|
Please include information on whether you built Gitea yourself, used one of our downloads, are using https://demo.gitea.com or are using some other package
|
||||||
|
Please also tell us how you are running Gitea, e.g. if it is being run from docker, a command-line, systemd etc.
|
||||||
|
If you are using a package or systemd tell us what distribution you are using
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: database
|
||||||
|
attributes:
|
||||||
|
label: Database
|
||||||
|
description: What database system are you running?
|
||||||
|
options:
|
||||||
|
- PostgreSQL
|
||||||
|
- MySQL/MariaDB
|
||||||
|
- MSSQL
|
||||||
|
- SQLite
|
||||||
|
|||||||
20
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
20
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
@@ -1,20 +1,24 @@
|
|||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: Suggest an idea for Gitea.
|
description: Got an idea for a feature that Gitea doesn't have currently? Submit your idea here!
|
||||||
labels: ["type/proposal"]
|
labels: ["type/proposal"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Search [existing issues](https://github.com/go-gitea/gitea/issues?q=is%3Aissue) first.
|
1. Please speak English, this is the language all maintainers can speak and write.
|
||||||
|
2. Please ask questions or configuration/deploy problems on our Discord
|
||||||
|
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
|
||||||
|
3. Please take a moment to check that your feature hasn't already been suggested.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: problem
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
label: What problem would this solve?
|
label: Feature Description
|
||||||
|
placeholder: |
|
||||||
|
I think it would be great if Gitea had...
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: proposal
|
id: screenshots
|
||||||
attributes:
|
attributes:
|
||||||
label: What do you propose?
|
label: Screenshots
|
||||||
validations:
|
description: If you can, provide screenshots of an implementation on another site e.g. GitHub
|
||||||
required: true
|
|
||||||
|
|||||||
66
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
Normal file
66
.github/ISSUE_TEMPLATE/ui.bug-report.yaml
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
name: Web Interface Bug Report
|
||||||
|
description: Something doesn't look quite as it should? Report it here!
|
||||||
|
labels: ["type/bug", "topic/ui"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
NOTE: If your issue is a security concern, please send an email to security@gitea.io instead of opening a public issue.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
1. Please speak English, this is the language all maintainers can speak and write.
|
||||||
|
2. Please ask questions or configuration/deploy problems on our Discord
|
||||||
|
server (https://discord.gg/gitea) or forum (https://forum.gitea.com).
|
||||||
|
3. Please take a moment to check that your issue doesn't already exist.
|
||||||
|
4. Make sure it's not mentioned in the FAQ (https://docs.gitea.com/help/faq)
|
||||||
|
5. Please give all relevant information below for bug reports, because
|
||||||
|
incomplete details will be handled as an invalid report.
|
||||||
|
6. In particular it's really important to provide pertinent logs. If you are certain that this is a javascript
|
||||||
|
error, show us the javascript console. If the error appears to relate to Gitea the server you must also give us
|
||||||
|
DEBUG level logs. (See https://docs.gitea.com/administration/logging-config#collecting-logs-for-help)
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: |
|
||||||
|
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below)
|
||||||
|
If using a proxy or a CDN (e.g. CloudFlare) in front of gitea, please disable the proxy/CDN fully and connect to gitea directly to confirm the issue still persists without those services.
|
||||||
|
- type: textarea
|
||||||
|
id: screenshots
|
||||||
|
attributes:
|
||||||
|
label: Screenshots
|
||||||
|
description: Please provide at least 1 screenshot showing the issue.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: gitea-ver
|
||||||
|
attributes:
|
||||||
|
label: Gitea Version
|
||||||
|
description: Gitea version (or commit reference) your instance is running
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: can-reproduce
|
||||||
|
attributes:
|
||||||
|
label: Can you reproduce the bug on the Gitea demo site?
|
||||||
|
description: |
|
||||||
|
If so, please provide a URL in the Description field
|
||||||
|
URL of Gitea demo: https://demo.gitea.com
|
||||||
|
options:
|
||||||
|
- "Yes"
|
||||||
|
- "No"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: os-ver
|
||||||
|
attributes:
|
||||||
|
label: Operating System
|
||||||
|
description: The operating system you are using to access Gitea
|
||||||
|
- type: input
|
||||||
|
id: browser-ver
|
||||||
|
attributes:
|
||||||
|
label: Browser Version
|
||||||
|
description: The browser and version that you are using to access Gitea
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
29
.github/actions/docker-dryrun/action.yml
vendored
29
.github/actions/docker-dryrun/action.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
name: docker-dryrun
|
|
||||||
description: Composite action that performs the container build steps for a single platform.
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
platform:
|
|
||||||
description: "The target platform: linux/amd64, linux/arm64, linux/riscv64."
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
|
||||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
||||||
- name: Build regular image
|
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: ${{ inputs.platform }}
|
|
||||||
push: false
|
|
||||||
file: Dockerfile
|
|
||||||
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
|
|
||||||
- name: Build rootless image
|
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: ${{ inputs.platform }}
|
|
||||||
push: false
|
|
||||||
file: Dockerfile.rootless
|
|
||||||
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
|
|
||||||
9
.github/actions/free-disk-space/action.yml
vendored
9
.github/actions/free-disk-space/action.yml
vendored
@@ -1,9 +0,0 @@
|
|||||||
name: free-disk-space
|
|
||||||
description: Free space on / before large cache restores
|
|
||||||
|
|
||||||
# Delete preinstalled toolchains which gitea doesn't use
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- shell: bash
|
|
||||||
run: sudo rm -rf /usr/local/lib/android /usr/local/.ghcup /opt/ghc /usr/share/dotnet
|
|
||||||
51
.github/actions/go-cache/action.yml
vendored
51
.github/actions/go-cache/action.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
name: go-caches
|
|
||||||
description: Restore the go module, build, and golangci-lint caches. Save only on the cache-seeder workflow.
|
|
||||||
|
|
||||||
# Only the cache-seeder workflow saves; rename requires updating cache-seeder.yml.
|
|
||||||
# The lint job restores but does not save the gobuild cache, so only one writer
|
|
||||||
# (the gobuild job) populates it and there is no contention on the cache key.
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
lint-cache:
|
|
||||||
description: Restore (and save in cache-seeder) ~/.cache/golangci-lint
|
|
||||||
default: "false"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- if: ${{ github.workflow == 'cache-seeder' }}
|
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
|
|
||||||
restore-keys: gomod-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- if: ${{ github.workflow != 'cache-seeder' }}
|
|
||||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/go/pkg/mod
|
|
||||||
key: gomod-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
|
|
||||||
restore-keys: gomod-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- if: ${{ github.workflow == 'cache-seeder' && inputs.lint-cache != 'true' }}
|
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/.cache/go-build
|
|
||||||
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
|
|
||||||
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- if: ${{ github.workflow != 'cache-seeder' || inputs.lint-cache == 'true' }}
|
|
||||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/.cache/go-build
|
|
||||||
key: gobuild-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum') }}
|
|
||||||
restore-keys: gobuild-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- if: ${{ inputs.lint-cache == 'true' && github.workflow == 'cache-seeder' }}
|
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/.cache/golangci-lint
|
|
||||||
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
|
|
||||||
restore-keys: golint-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- if: ${{ inputs.lint-cache == 'true' && github.workflow != 'cache-seeder' }}
|
|
||||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/.cache/golangci-lint
|
|
||||||
key: golint-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('go.sum', '.golangci.yml') }}
|
|
||||||
restore-keys: golint-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
24
.github/actions/go-setup/action.yml
vendored
24
.github/actions/go-setup/action.yml
vendored
@@ -1,24 +0,0 @@
|
|||||||
name: go-setup
|
|
||||||
description: Set up go and restore caches
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
cache:
|
|
||||||
description: Restore go caches
|
|
||||||
default: "true"
|
|
||||||
lint-cache:
|
|
||||||
description: Also restore the golangci-lint cache
|
|
||||||
default: "false"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- uses: ./.github/actions/free-disk-space
|
|
||||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
cache: false
|
|
||||||
- if: ${{ inputs.cache == 'true' }}
|
|
||||||
uses: ./.github/actions/go-cache
|
|
||||||
with:
|
|
||||||
lint-cache: ${{ inputs.lint-cache }}
|
|
||||||
22
.github/actions/node-setup/action.yml
vendored
22
.github/actions/node-setup/action.yml
vendored
@@ -1,22 +0,0 @@
|
|||||||
name: node-setup
|
|
||||||
description: Set up pnpm and node and restore caches
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
cache:
|
|
||||||
description: Cache pnpm downloads
|
|
||||||
default: "true"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
|
|
||||||
- if: ${{ inputs.cache == 'true' }}
|
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
cache: pnpm
|
|
||||||
cache-dependency-path: pnpm-lock.yaml
|
|
||||||
- if: ${{ inputs.cache != 'true' }}
|
|
||||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
40
.github/actions/pgsql-shard/action.yml
vendored
40
.github/actions/pgsql-shard/action.yml
vendored
@@ -1,40 +0,0 @@
|
|||||||
name: pgsql-shard
|
|
||||||
description: Run one pgsql integration test shard
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
shard:
|
|
||||||
description: Shard index
|
|
||||||
required: true
|
|
||||||
total-shards:
|
|
||||||
description: Total shard count
|
|
||||||
required: true
|
|
||||||
run-migration:
|
|
||||||
description: Also run migration tests
|
|
||||||
default: "false"
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: composite
|
|
||||||
steps:
|
|
||||||
- name: Add hosts to /etc/hosts
|
|
||||||
shell: bash
|
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
|
|
||||||
- shell: bash
|
|
||||||
run: make deps-backend
|
|
||||||
- shell: bash
|
|
||||||
run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- name: run migration tests
|
|
||||||
if: ${{ inputs.run-migration == 'true' }}
|
|
||||||
shell: bash
|
|
||||||
run: GITEA_TEST_DATABASE=pgsql make test-migration
|
|
||||||
- name: run tests
|
|
||||||
shell: bash
|
|
||||||
run: GITEA_TEST_DATABASE=pgsql make test-integration
|
|
||||||
env:
|
|
||||||
# pgsql is chosen to be the unlucky one to run with the slow "race detector", it is about 60% slower.
|
|
||||||
GOTEST_FLAGS: -race -timeout=40m
|
|
||||||
TAGS: bindata gogit
|
|
||||||
TEST_LDAP: 1
|
|
||||||
TEST_SHARD: ${{ inputs.shard }}
|
|
||||||
TEST_TOTAL_SHARDS: ${{ inputs.total-shards }}
|
|
||||||
10
.github/dependabot.yml
vendored
Normal file
10
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
labels: [modifies/dependencies]
|
||||||
|
directory: /
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
cooldown:
|
||||||
|
default-days: 5
|
||||||
77
.github/labeler.yml
vendored
77
.github/labeler.yml
vendored
@@ -1,3 +1,80 @@
|
|||||||
|
modifies/docs:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "**/*.md"
|
||||||
|
- "docs/**"
|
||||||
|
|
||||||
|
modifies/templates:
|
||||||
|
- changed-files:
|
||||||
|
- all-globs-to-any-file:
|
||||||
|
- "templates/**"
|
||||||
|
- "!templates/swagger/v1_json.tmpl"
|
||||||
|
|
||||||
|
modifies/api:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "routers/api/**"
|
||||||
|
- "templates/swagger/v1_json.tmpl"
|
||||||
|
|
||||||
|
modifies/cli:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "cmd/**"
|
||||||
|
|
||||||
|
modifies/translation:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "options/locale/*.ini"
|
||||||
|
|
||||||
|
modifies/migrations:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "models/migrations/**"
|
||||||
|
|
||||||
|
modifies/internal:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- ".air.toml"
|
||||||
|
- "Makefile"
|
||||||
|
- "Dockerfile"
|
||||||
|
- "Dockerfile.rootless"
|
||||||
|
- ".dockerignore"
|
||||||
|
- "docker/**"
|
||||||
|
- ".editorconfig"
|
||||||
|
- ".eslintrc.cjs"
|
||||||
|
- ".golangci.yml"
|
||||||
|
- ".markdownlint.yaml"
|
||||||
|
- ".spectral.yaml"
|
||||||
|
- "stylelint.config.*"
|
||||||
|
- ".yamllint.yaml"
|
||||||
|
- ".github/**"
|
||||||
|
- ".gitea/**"
|
||||||
|
- ".devcontainer/**"
|
||||||
|
- "build/**"
|
||||||
|
- "contrib/**"
|
||||||
|
|
||||||
|
modifies/dependencies:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "package.json"
|
||||||
|
- "pnpm-lock.yaml"
|
||||||
|
- "pyproject.toml"
|
||||||
|
- "uv.lock"
|
||||||
|
- "go.mod"
|
||||||
|
- "go.sum"
|
||||||
|
|
||||||
|
modifies/go:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "**/*.go"
|
||||||
|
|
||||||
|
modifies/frontend:
|
||||||
|
- changed-files:
|
||||||
|
- any-glob-to-any-file:
|
||||||
|
- "*.js"
|
||||||
|
- "*.ts"
|
||||||
|
- "web_src/**"
|
||||||
|
|
||||||
docs-update-needed:
|
docs-update-needed:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
|
|||||||
19
.github/pull_request_template.md
vendored
19
.github/pull_request_template.md
vendored
@@ -1,9 +1,10 @@
|
|||||||
<!--
|
<!-- start tips -->
|
||||||
Before submitting:
|
Please check the following:
|
||||||
- Target the `main` branch; release branches are for backports only.
|
1. Make sure you are targeting the `main` branch, pull requests on release branches are only allowed for backports.
|
||||||
- Use a Conventional Commits title, e.g. `fix(repo): handle empty branch names`.
|
2. Make sure you have read contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md .
|
||||||
- Read the contributing guidelines: https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md
|
3. For documentations contribution, please go to https://gitea.com/gitea/docs
|
||||||
- Documentation changes go to https://gitea.com/gitea/docs
|
4. Describe what your pull request does and which issue you're targeting (if any).
|
||||||
|
5. It is recommended to enable "Allow edits by maintainers", so maintainers can help more easily.
|
||||||
Describe your change below and link any issue it fixes.
|
6. Your input here will be included in the commit message when this PR has been merged. If you don't want some content to be included, please separate them with a line like `---`.
|
||||||
-->
|
7. Delete all these tips before posting.
|
||||||
|
<!-- end tips -->
|
||||||
|
|||||||
72
.github/workflows/cache-seeder.yml
vendored
72
.github/workflows/cache-seeder.yml
vendored
@@ -1,72 +0,0 @@
|
|||||||
# Populates main's cache scope so PR runs warm-start from it. Saves the go
|
|
||||||
# module, go build (incl. test compile), and golangci-lint caches.
|
|
||||||
#
|
|
||||||
# Caches are ref-scoped: PR runs read their own scope then fall back to the
|
|
||||||
# base branch. Per .github/actions/go-cache/action.yml, PRs are restore-only,
|
|
||||||
# so push-to-main is the only opportunity to populate the fallback scope.
|
|
||||||
|
|
||||||
name: cache-seeder
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- "go.sum"
|
|
||||||
- ".golangci.yml"
|
|
||||||
- ".github/actions/go-cache/action.yml"
|
|
||||||
- ".github/actions/go-setup/action.yml"
|
|
||||||
- ".github/workflows/cache-seeder.yml"
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: cache-seeder
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
gobuild:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: ./.github/actions/go-setup
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: TAGS="bindata" make backend
|
|
||||||
- run: TAGS="bindata gogit" GOEXPERIMENT="" make backend
|
|
||||||
- name: warm test compile cache (bindata)
|
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
GOTEST_FLAGS: -race -list=^$$ -count=1
|
|
||||||
run: make test-backend
|
|
||||||
- name: warm test compile cache (bindata gogit)
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
GOEXPERIMENT:
|
|
||||||
GOTEST_FLAGS: -race -list=^$$ -count=1
|
|
||||||
run: make test-backend
|
|
||||||
- name: warm integration compile cache
|
|
||||||
run: |
|
|
||||||
TAGS="bindata" make test-integration-compile
|
|
||||||
TAGS="bindata gogit" GOEXPERIMENT="" make test-integration-compile
|
|
||||||
TAGS="bindata gogit" GOTEST_FLAGS="-race" make test-integration-compile
|
|
||||||
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- { tags: "bindata", target: "lint-backend" }
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: ./.github/actions/go-setup
|
|
||||||
with:
|
|
||||||
lint-cache: "true"
|
|
||||||
- run: make deps-backend deps-tools
|
|
||||||
- run: make generate-go
|
|
||||||
env:
|
|
||||||
TAGS: ${{ matrix.tags }}
|
|
||||||
- run: make ${{ matrix.target }}
|
|
||||||
env:
|
|
||||||
TAGS: ${{ matrix.tags }}
|
|
||||||
22
.github/workflows/cron-flake-updater.yml
vendored
Normal file
22
.github/workflows/cron-flake-updater.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: cron-flake-updater
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 0 * * 0' # runs weekly on Sunday at 00:00
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nix-flake-update:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: DeterminateSystems/determinate-nix-action@v3
|
||||||
|
- uses: DeterminateSystems/update-flake-lock@main
|
||||||
|
with:
|
||||||
|
pr-title: "Update Nix flake"
|
||||||
|
pr-labels: |
|
||||||
|
dependencies
|
||||||
6
.github/workflows/cron-licenses.yml
vendored
6
.github/workflows/cron-licenses.yml
vendored
@@ -12,15 +12,15 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- run: make generate-gitignore
|
- run: make generate-gitignore
|
||||||
timeout-minutes: 40
|
timeout-minutes: 40
|
||||||
- name: push translations to repo
|
- name: push translations to repo
|
||||||
uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
|
uses: appleboy/git-push-action@v1.2.0
|
||||||
with:
|
with:
|
||||||
author_email: "teabot@gitea.io"
|
author_email: "teabot@gitea.io"
|
||||||
author_name: GiteaBot
|
author_name: GiteaBot
|
||||||
|
|||||||
32
.github/workflows/cron-renovate.yml
vendored
32
.github/workflows/cron-renovate.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: cron-renovate
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "23 * * * *" # hourly at :23
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: cron-renovate
|
|
||||||
|
|
||||||
env:
|
|
||||||
RENOVATE_VERSION: 43.141.5 # renovate: datasource=docker depName=ghcr.io/renovatebot/renovate
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cron-renovate:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository == 'go-gitea/gitea' # prevent running on forks
|
|
||||||
timeout-minutes: 30
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: renovatebot/github-action@693b9ef15eec82123529a37c782242f091365961 # v46.1.14
|
|
||||||
with:
|
|
||||||
renovate-version: ${{ env.RENOVATE_VERSION }}
|
|
||||||
configurationFile: renovate.json5
|
|
||||||
token: ${{ secrets.RENOVATE_TOKEN }}
|
|
||||||
env:
|
|
||||||
RENOVATE_BINARY_SOURCE: install # auto-install go/node toolchains needed by post-upgrade tasks.
|
|
||||||
RENOVATE_ALLOWED_POST_UPGRADE_COMMANDS: '["^make (tidy|svg nolyfill)$"]'
|
|
||||||
RENOVATE_REPOSITORIES: '["go-gitea/gitea"]'
|
|
||||||
6
.github/workflows/cron-translations.yml
vendored
6
.github/workflows/cron-translations.yml
vendored
@@ -12,8 +12,8 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2.16.2
|
- uses: crowdin/github-action@v2
|
||||||
with:
|
with:
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- name: update locales
|
- name: update locales
|
||||||
run: ./build/update-locales.sh
|
run: ./build/update-locales.sh
|
||||||
- name: push translations to repo
|
- name: push translations to repo
|
||||||
uses: appleboy/git-push-action@3b2c8661652360dbf1afe1b319a49dbb739c39f1 # v1.2.0
|
uses: appleboy/git-push-action@v1.2.0
|
||||||
with:
|
with:
|
||||||
author_email: "teabot@gitea.io"
|
author_email: "teabot@gitea.io"
|
||||||
author_name: GiteaBot
|
author_name: GiteaBot
|
||||||
|
|||||||
48
.github/workflows/files-changed.yml
vendored
48
.github/workflows/files-changed.yml
vendored
@@ -15,26 +15,19 @@ on:
|
|||||||
value: ${{ jobs.detect.outputs.templates }}
|
value: ${{ jobs.detect.outputs.templates }}
|
||||||
docker:
|
docker:
|
||||||
value: ${{ jobs.detect.outputs.docker }}
|
value: ${{ jobs.detect.outputs.docker }}
|
||||||
dockerfile:
|
|
||||||
value: ${{ jobs.detect.outputs.dockerfile }}
|
|
||||||
swagger:
|
swagger:
|
||||||
value: ${{ jobs.detect.outputs.swagger }}
|
value: ${{ jobs.detect.outputs.swagger }}
|
||||||
yaml:
|
yaml:
|
||||||
value: ${{ jobs.detect.outputs.yaml }}
|
value: ${{ jobs.detect.outputs.yaml }}
|
||||||
json:
|
json:
|
||||||
value: ${{ jobs.detect.outputs.json }}
|
value: ${{ jobs.detect.outputs.json }}
|
||||||
e2e:
|
|
||||||
value: ${{ jobs.detect.outputs.e2e }}
|
|
||||||
shell:
|
|
||||||
value: ${{ jobs.detect.outputs.shell }}
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
detect:
|
detect:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 3
|
timeout-minutes: 3
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
outputs:
|
outputs:
|
||||||
backend: ${{ steps.changes.outputs.backend }}
|
backend: ${{ steps.changes.outputs.backend }}
|
||||||
frontend: ${{ steps.changes.outputs.frontend }}
|
frontend: ${{ steps.changes.outputs.frontend }}
|
||||||
@@ -42,15 +35,12 @@ jobs:
|
|||||||
actions: ${{ steps.changes.outputs.actions }}
|
actions: ${{ steps.changes.outputs.actions }}
|
||||||
templates: ${{ steps.changes.outputs.templates }}
|
templates: ${{ steps.changes.outputs.templates }}
|
||||||
docker: ${{ steps.changes.outputs.docker }}
|
docker: ${{ steps.changes.outputs.docker }}
|
||||||
dockerfile: ${{ steps.changes.outputs.dockerfile }}
|
|
||||||
swagger: ${{ steps.changes.outputs.swagger }}
|
swagger: ${{ steps.changes.outputs.swagger }}
|
||||||
yaml: ${{ steps.changes.outputs.yaml }}
|
yaml: ${{ steps.changes.outputs.yaml }}
|
||||||
json: ${{ steps.changes.outputs.json }}
|
json: ${{ steps.changes.outputs.json }}
|
||||||
e2e: ${{ steps.changes.outputs.e2e }}
|
|
||||||
shell: ${{ steps.changes.outputs.shell }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1
|
- uses: dorny/paths-filter@v4
|
||||||
id: changes
|
id: changes
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
@@ -66,54 +56,47 @@ jobs:
|
|||||||
- "options/locale/locale_en-US.json"
|
- "options/locale/locale_en-US.json"
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
|
- "*.js"
|
||||||
- "*.ts"
|
- "*.ts"
|
||||||
- "web_src/**"
|
- "web_src/**"
|
||||||
- "tools/generate-svg.ts"
|
- "tools/*.js"
|
||||||
- "tools/generate-svg-vscode-extensions.json"
|
- "tools/*.ts"
|
||||||
- "tsconfig.json"
|
|
||||||
- "assets/emoji.json"
|
- "assets/emoji.json"
|
||||||
- "package.json"
|
- "package.json"
|
||||||
- "pnpm-lock.yaml"
|
- "pnpm-lock.yaml"
|
||||||
- "pnpm-workspace.yaml"
|
|
||||||
- "Makefile"
|
- "Makefile"
|
||||||
|
- ".eslintrc.cjs"
|
||||||
|
- ".npmrc"
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
- "**/*.md"
|
- "**/*.md"
|
||||||
- ".markdownlint.yaml"
|
- ".markdownlint.yaml"
|
||||||
- "package.json"
|
- "package.json"
|
||||||
- "pnpm-lock.yaml"
|
- "pnpm-lock.yaml"
|
||||||
- "pnpm-workspace.yaml"
|
|
||||||
|
|
||||||
actions:
|
actions:
|
||||||
- ".github/workflows/*"
|
- ".github/workflows/*"
|
||||||
- ".github/actions/**"
|
|
||||||
- "Makefile"
|
- "Makefile"
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
- "tools/lint-templates-*.ts"
|
- "tools/lint-templates-*.js"
|
||||||
- "templates/**/*.tmpl"
|
- "templates/**/*.tmpl"
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
- "uv.lock"
|
- "uv.lock"
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
- ".github/workflows/pull-docker-dryrun.yml"
|
- ".github/workflows/pull-docker-dryrun.yml"
|
||||||
- ".github/actions/docker-dryrun/**"
|
|
||||||
- "Dockerfile"
|
- "Dockerfile"
|
||||||
- "Dockerfile.rootless"
|
- "Dockerfile.rootless"
|
||||||
- "docker/**"
|
- "docker/**"
|
||||||
- "Makefile"
|
- "Makefile"
|
||||||
|
|
||||||
dockerfile:
|
|
||||||
- "Dockerfile"
|
|
||||||
- "Dockerfile.rootless"
|
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
- "templates/swagger/v1_json.tmpl"
|
- "templates/swagger/v1_json.tmpl"
|
||||||
- "templates/swagger/v1_input.json"
|
- "templates/swagger/v1_input.json"
|
||||||
- "Makefile"
|
- "Makefile"
|
||||||
- "package.json"
|
- "package.json"
|
||||||
- "pnpm-lock.yaml"
|
- "pnpm-lock.yaml"
|
||||||
- "pnpm-workspace.yaml"
|
|
||||||
- ".spectral.yaml"
|
- ".spectral.yaml"
|
||||||
|
|
||||||
yaml:
|
yaml:
|
||||||
@@ -124,14 +107,3 @@ jobs:
|
|||||||
|
|
||||||
json:
|
json:
|
||||||
- "**/*.json"
|
- "**/*.json"
|
||||||
- "**/*.json5"
|
|
||||||
- "eslint.json.config.ts"
|
|
||||||
|
|
||||||
e2e:
|
|
||||||
- "tests/e2e/**"
|
|
||||||
- "tools/test-e2e.sh"
|
|
||||||
- "playwright.config.ts"
|
|
||||||
|
|
||||||
shell:
|
|
||||||
- "**/*.sh"
|
|
||||||
- ".shellcheckrc"
|
|
||||||
|
|||||||
26
.github/workflows/giteabot-backport.yml
vendored
26
.github/workflows/giteabot-backport.yml
vendored
@@ -1,26 +0,0 @@
|
|||||||
name: giteabot backport
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
giteabot:
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 30
|
|
||||||
steps:
|
|
||||||
- uses: go-gitea/giteabot@d4f19d5b4a88059d8c3ca78d660631506fc0c286 # add retry logic to giteabot
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITEABOT_TOKEN }}
|
|
||||||
gitea_fork: giteabot/gitea
|
|
||||||
checks: backport
|
|
||||||
51
.github/workflows/giteabot.yml
vendored
51
.github/workflows/giteabot.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
name: giteabot
|
|
||||||
|
|
||||||
on:
|
|
||||||
# pull_request_target gives this workflow access to GITEABOT_TOKEN on PRs from
|
|
||||||
# forks, which the bot needs to write labels, statuses and comments. Safe here
|
|
||||||
# because the job only runs a pinned action and never checks out PR HEAD.
|
|
||||||
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
|
||||||
types:
|
|
||||||
- opened
|
|
||||||
- synchronize
|
|
||||||
- labeled
|
|
||||||
- unlabeled
|
|
||||||
- closed
|
|
||||||
- review_requested
|
|
||||||
- review_request_removed
|
|
||||||
pull_request_review:
|
|
||||||
types:
|
|
||||||
- submitted
|
|
||||||
- edited
|
|
||||||
- dismissed
|
|
||||||
schedule:
|
|
||||||
- cron: "15 3 * * *"
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
checks:
|
|
||||||
description: Comma-separated list of non-backport checks to run
|
|
||||||
required: false
|
|
||||||
default: labels,merge_queue,lock,feedback,last_call,milestones,lgtm,translation_comment,pr_actions
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
issues: write
|
|
||||||
pull-requests: write
|
|
||||||
statuses: write
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ format('{0}-{1}', github.workflow, (github.event_name == 'pull_request_target' || github.event_name == 'pull_request_review') && format('pr-{0}', github.event.pull_request.number) || 'maintenance') }}
|
|
||||||
cancel-in-progress: false
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
giteabot:
|
|
||||||
if: github.repository == 'go-gitea/gitea'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 30
|
|
||||||
steps:
|
|
||||||
# pull_request_review runs without repository secrets on fork PRs, so fall
|
|
||||||
# back to the workflow token for the non-backport checks handled here.
|
|
||||||
- uses: go-gitea/giteabot@d4f19d5b4a88059d8c3ca78d660631506fc0c286 # add retry logic to giteabot
|
|
||||||
with:
|
|
||||||
github_token: ${{ secrets.GITEABOT_TOKEN || github.token }}
|
|
||||||
checks: ${{ github.event.inputs.checks || 'labels,merge_queue,lock,feedback,last_call,milestones,lgtm,translation_comment,pr_actions' }}
|
|
||||||
213
.github/workflows/pull-compliance.yml
vendored
213
.github/workflows/pull-compliance.yml
vendored
@@ -7,63 +7,156 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
files-changed:
|
files-changed:
|
||||||
uses: ./.github/workflows/files-changed.yml
|
uses: ./.github/workflows/files-changed.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
lint-backend:
|
lint-backend:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
lint-cache: "true"
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- run: make deps-backend deps-tools
|
- run: make deps-backend deps-tools
|
||||||
- run: TAGS="bindata" make generate-go # lint-go also lints with "bindata" tags which requires "_bindata.go"
|
|
||||||
- run: make lint-backend
|
- run: make lint-backend
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
|
||||||
lint-on-demand:
|
lint-templates:
|
||||||
|
if: needs.files-changed.outputs.templates == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: astral-sh/setup-uv@v8.0.0
|
||||||
|
- run: uv python install 3.14
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
cache: "false"
|
node-version: 24
|
||||||
- uses: ./.github/actions/node-setup
|
cache: pnpm
|
||||||
with:
|
cache-dependency-path: pnpm-lock.yaml
|
||||||
cache: "false"
|
- run: make deps-py
|
||||||
|
- run: make deps-frontend
|
||||||
|
- run: make lint-templates
|
||||||
|
|
||||||
|
lint-yaml:
|
||||||
|
if: needs.files-changed.outputs.yaml == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: astral-sh/setup-uv@v8.0.0
|
||||||
|
- run: uv python install 3.14
|
||||||
|
- run: make deps-py
|
||||||
|
- run: make lint-yaml
|
||||||
|
|
||||||
|
lint-json:
|
||||||
|
if: needs.files-changed.outputs.json == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v5
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
- run: make deps-frontend
|
||||||
|
- run: make lint-json
|
||||||
|
|
||||||
|
lint-swagger:
|
||||||
|
if: needs.files-changed.outputs.swagger == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: pnpm-lock.yaml
|
||||||
|
- run: make deps-frontend
|
||||||
|
- run: make lint-swagger
|
||||||
|
|
||||||
|
lint-spell:
|
||||||
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.templates == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- run: make lint-spell
|
- run: make lint-spell
|
||||||
|
|
||||||
- if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true' || needs.files-changed.outputs.actions == 'true'
|
lint-go-windows:
|
||||||
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
python-version: 3.14
|
go-version-file: go.mod
|
||||||
- if: needs.files-changed.outputs.templates == 'true' || needs.files-changed.outputs.yaml == 'true'
|
check-latest: true
|
||||||
run: make deps-py lint-templates lint-yaml
|
- run: make deps-backend deps-tools
|
||||||
|
- run: make lint-go-windows lint-go-gitea-vet
|
||||||
|
env:
|
||||||
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
|
GOOS: windows
|
||||||
|
GOARCH: amd64
|
||||||
|
|
||||||
- if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.swagger == 'true' || needs.files-changed.outputs.json == 'true'
|
lint-go-gogit:
|
||||||
run: make deps-frontend lint-md lint-swagger lint-json
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
|
needs: files-changed
|
||||||
- if: needs.files-changed.outputs.actions == 'true'
|
runs-on: ubuntu-latest
|
||||||
run: make lint-actions
|
permissions:
|
||||||
|
contents: read
|
||||||
- if: needs.files-changed.outputs.shell == 'true'
|
steps:
|
||||||
run: make lint-shell
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
- run: make deps-backend deps-tools
|
||||||
|
- run: make lint-go
|
||||||
|
env:
|
||||||
|
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||||
|
|
||||||
checks-backend:
|
checks-backend:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- run: make deps-backend deps-tools
|
- run: make deps-backend deps-tools
|
||||||
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
- run: make --always-make checks-backend # ensure the "go-licenses" make target runs
|
||||||
|
|
||||||
@@ -71,9 +164,16 @@ jobs:
|
|||||||
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/node-setup
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: pnpm-lock.yaml
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
- run: make lint-frontend
|
- run: make lint-frontend
|
||||||
- run: make checks-frontend
|
- run: make checks-frontend
|
||||||
@@ -84,14 +184,20 @@ jobs:
|
|||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
- run: make deps-backend generate-go
|
with:
|
||||||
# no frontend build here as backend should be able to build, even without any frontend files
|
go-version-file: go.mod
|
||||||
# CGO is not used when cross-compile, so these steps also test if the code is compatible with CGO disabled
|
check-latest: true
|
||||||
|
# no frontend build here as backend should be able to build
|
||||||
|
# even without any frontend files
|
||||||
|
- run: make deps-backend
|
||||||
|
- run: go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||||
- name: build-backend-arm64
|
- name: build-backend-arm64
|
||||||
run: go build -o gitea_linux_arm64
|
run: make backend # test cross compile
|
||||||
env:
|
env:
|
||||||
GOOS: linux
|
GOOS: linux
|
||||||
GOARCH: arm64
|
GOARCH: arm64
|
||||||
@@ -103,7 +209,38 @@ jobs:
|
|||||||
GOARCH: amd64
|
GOARCH: amd64
|
||||||
TAGS: bindata gogit
|
TAGS: bindata gogit
|
||||||
- name: build-backend-386
|
- name: build-backend-386
|
||||||
run: go build -o gitea_linux_386
|
run: go build -o gitea_linux_386 # test if compatible with 32 bit
|
||||||
env:
|
env:
|
||||||
GOOS: linux
|
GOOS: linux
|
||||||
GOARCH: 386
|
GOARCH: 386
|
||||||
|
|
||||||
|
docs:
|
||||||
|
if: needs.files-changed.outputs.docs == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: pnpm-lock.yaml
|
||||||
|
- run: make deps-frontend
|
||||||
|
- run: make lint-md
|
||||||
|
|
||||||
|
actions:
|
||||||
|
if: needs.files-changed.outputs.actions == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
|
needs: files-changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
- run: make lint-actions
|
||||||
|
|||||||
182
.github/workflows/pull-db-tests.yml
vendored
182
.github/workflows/pull-db-tests.yml
vendored
@@ -7,18 +7,18 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
files-changed:
|
files-changed:
|
||||||
uses: ./.github/workflows/files-changed.yml
|
uses: ./.github/workflows/files-changed.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
test-pgsql-shard-1:
|
test-pgsql:
|
||||||
if: needs.files-changed.outputs.backend == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 50
|
permissions:
|
||||||
|
contents: read
|
||||||
services:
|
services:
|
||||||
pgsql:
|
pgsql:
|
||||||
image: postgres:14
|
image: postgres:14
|
||||||
@@ -28,98 +28,79 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
ldap:
|
ldap:
|
||||||
image: gitea/test-openldap:latest@sha256:4ac633b01d684e6b2a458cc0c8530c92f9b3702f6e040ce5f365607df34fbda0
|
image: gitea/test-openldap:latest
|
||||||
ports:
|
ports:
|
||||||
- "389:389"
|
- "389:389"
|
||||||
- "636:636"
|
- "636:636"
|
||||||
minio:
|
minio:
|
||||||
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
||||||
# that has a custom entrypoint set to "minio server /data"
|
# that has a custom entrypoint set to "minio server /data"
|
||||||
image: bitnamilegacy/minio:2025.7.23
|
image: bitnamilegacy/minio:2023.8.31
|
||||||
env:
|
env:
|
||||||
MINIO_ROOT_USER: 123456
|
MINIO_ROOT_USER: 123456
|
||||||
MINIO_ROOT_PASSWORD: 12345678
|
MINIO_ROOT_PASSWORD: 12345678
|
||||||
ports:
|
ports:
|
||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
- uses: ./.github/actions/pgsql-shard
|
|
||||||
with:
|
with:
|
||||||
shard: 1
|
go-version-file: go.mod
|
||||||
total-shards: 2
|
check-latest: true
|
||||||
run-migration: "true"
|
- name: Add hosts to /etc/hosts
|
||||||
|
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 pgsql ldap minio" | sudo tee -a /etc/hosts'
|
||||||
test-pgsql-shard-2:
|
- run: make deps-backend
|
||||||
if: needs.files-changed.outputs.backend == 'true'
|
- run: make backend
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 50
|
|
||||||
services:
|
|
||||||
pgsql:
|
|
||||||
image: postgres:14
|
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: test
|
TAGS: bindata
|
||||||
POSTGRES_PASSWORD: postgres
|
- name: run migration tests
|
||||||
ports:
|
run: make test-pgsql-migration
|
||||||
- "5432:5432"
|
- name: run tests
|
||||||
ldap:
|
run: make test-pgsql
|
||||||
image: gitea/test-openldap:latest@sha256:4ac633b01d684e6b2a458cc0c8530c92f9b3702f6e040ce5f365607df34fbda0
|
timeout-minutes: 50
|
||||||
ports:
|
|
||||||
- "389:389"
|
|
||||||
- "636:636"
|
|
||||||
minio:
|
|
||||||
# as github actions doesn't support "entrypoint", we need to use a non-official image
|
|
||||||
# that has a custom entrypoint set to "minio server /data"
|
|
||||||
image: bitnamilegacy/minio:2025.7.23
|
|
||||||
env:
|
env:
|
||||||
MINIO_ROOT_USER: 123456
|
TAGS: bindata gogit
|
||||||
MINIO_ROOT_PASSWORD: 12345678
|
RACE_ENABLED: true
|
||||||
ports:
|
TEST_TAGS: gogit
|
||||||
- "9000:9000"
|
TEST_LDAP: 1
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: ./.github/actions/go-setup
|
|
||||||
- uses: ./.github/actions/pgsql-shard
|
|
||||||
with:
|
|
||||||
shard: 2
|
|
||||||
total-shards: 2
|
|
||||||
|
|
||||||
test-sqlite:
|
test-sqlite:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make backend
|
- run: GOEXPERIMENT='' make backend
|
||||||
env:
|
env:
|
||||||
TAGS: bindata gogit
|
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||||
GOEXPERIMENT:
|
- name: run migration tests
|
||||||
- run: GITEA_TEST_DATABASE=sqlite make test-migration
|
run: make test-sqlite-migration
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
run: GITEA_TEST_DATABASE=sqlite make test-integration
|
run: GOEXPERIMENT='' make test-sqlite
|
||||||
timeout-minutes: 50
|
timeout-minutes: 50
|
||||||
env:
|
env:
|
||||||
# sqlite driver can contain large amount of Golang code, so don't use race detector for it, otherwise, extremely slow
|
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||||
GOTEST_FLAGS: -timeout=40m
|
RACE_ENABLED: true
|
||||||
TAGS: bindata gogit
|
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
||||||
GOEXPERIMENT:
|
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
if: needs.files-changed.outputs.backend == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
services:
|
services:
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
|
image: elasticsearch:7.5.0
|
||||||
env:
|
env:
|
||||||
discovery.type: single-node
|
discovery.type: single-node
|
||||||
xpack.security.enabled: false
|
|
||||||
ES_JAVA_OPTS: "-Xms512m -Xmx512m" # reduce from ES default of 50%
|
|
||||||
ports:
|
ports:
|
||||||
- "9200:9200"
|
- "9200:9200"
|
||||||
meilisearch:
|
meilisearch:
|
||||||
@@ -129,7 +110,7 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- "7700:7700"
|
- "7700:7700"
|
||||||
redis:
|
redis:
|
||||||
image: redis:latest@sha256:48e78eb9d1e1adcfb10184b2cc3c7fc5ed21e5a3be08875f239257d194bab8c9
|
image: redis
|
||||||
options: >- # wait until redis has started
|
options: >- # wait until redis has started
|
||||||
--health-cmd "redis-cli ping"
|
--health-cmd "redis-cli ping"
|
||||||
--health-interval 5s
|
--health-interval 5s
|
||||||
@@ -138,49 +119,51 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- 6379:6379
|
- 6379:6379
|
||||||
minio:
|
minio:
|
||||||
image: bitnamilegacy/minio:2025.7.23
|
image: bitnamilegacy/minio:2021.3.17
|
||||||
env:
|
env:
|
||||||
MINIO_ROOT_USER: 123456
|
MINIO_ACCESS_KEY: 123456
|
||||||
MINIO_ROOT_PASSWORD: 12345678
|
MINIO_SECRET_KEY: 12345678
|
||||||
ports:
|
ports:
|
||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
|
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
|
||||||
image: mcr.microsoft.com/azure-storage/azurite:latest@sha256:dae2a5f96553962901304b94e72ef87e299d0825e4b679673bcc527a25076fe4
|
image: mcr.microsoft.com/azure-storage/azurite:latest
|
||||||
ports:
|
ports:
|
||||||
- 10000:10000
|
- 10000:10000
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- name: Add hosts to /etc/hosts
|
- name: Add hosts to /etc/hosts
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
|
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make generate-go
|
- run: make backend
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
- name: unit-tests
|
- name: unit-tests
|
||||||
run: make test-backend
|
run: make unit-test-coverage test-check
|
||||||
env:
|
env:
|
||||||
GOTEST_FLAGS: -race -timeout=20m
|
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
|
RACE_ENABLED: true
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||||
- name: unit-tests-gogit
|
- name: unit-tests-gogit
|
||||||
run: make test-backend
|
run: GOEXPERIMENT='' make unit-test-coverage test-check
|
||||||
env:
|
env:
|
||||||
GOTEST_FLAGS: -race -timeout=20m
|
|
||||||
TAGS: bindata gogit
|
TAGS: bindata gogit
|
||||||
GOEXPERIMENT:
|
RACE_ENABLED: true
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||||
GITEA_TEST_CI_SKIP_EXTERNAL: true
|
|
||||||
- run: make test-check
|
|
||||||
|
|
||||||
test-mysql:
|
test-mysql:
|
||||||
if: needs.files-changed.outputs.backend == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
# the bitnami mysql image has more options than the official one, it's easier to customize
|
# the bitnami mysql image has more options than the official one, it's easier to customize
|
||||||
image: bitnamilegacy/mysql:8.4
|
image: bitnamilegacy/mysql:8.0
|
||||||
env:
|
env:
|
||||||
ALLOW_EMPTY_PASSWORD: true
|
ALLOW_EMPTY_PASSWORD: true
|
||||||
MYSQL_DATABASE: testgitea
|
MYSQL_DATABASE: testgitea
|
||||||
@@ -189,40 +172,46 @@ jobs:
|
|||||||
options: >-
|
options: >-
|
||||||
--mount type=tmpfs,destination=/bitnami/mysql/data
|
--mount type=tmpfs,destination=/bitnami/mysql/data
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
|
image: elasticsearch:7.5.0
|
||||||
env:
|
env:
|
||||||
discovery.type: single-node
|
discovery.type: single-node
|
||||||
xpack.security.enabled: false
|
|
||||||
ES_JAVA_OPTS: "-Xms512m -Xmx512m" # reduce from ES default of 50%
|
|
||||||
ports:
|
ports:
|
||||||
- "9200:9200"
|
- "9200:9200"
|
||||||
smtpimap:
|
smtpimap:
|
||||||
image: tabascoterrier/docker-imap-devel:latest@sha256:3fb7cf50b47693e7b80f6f74abea2def4d7386016931d61359864de8a0aba551
|
image: tabascoterrier/docker-imap-devel:latest
|
||||||
ports:
|
ports:
|
||||||
- "25:25"
|
- "25:25"
|
||||||
- "143:143"
|
- "143:143"
|
||||||
- "587:587"
|
- "587:587"
|
||||||
- "993:993"
|
- "993:993"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- name: Add hosts to /etc/hosts
|
- name: Add hosts to /etc/hosts
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
|
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql elasticsearch smtpimap" | sudo tee -a /etc/hosts'
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make backend
|
- run: make backend
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
- run: GITEA_TEST_DATABASE=mysql make test-migration
|
- name: run migration tests
|
||||||
|
run: make test-mysql-migration
|
||||||
- name: run tests
|
- name: run tests
|
||||||
run: GITEA_TEST_DATABASE=mysql make test-integration
|
# run: make integration-test-coverage (at the moment, no coverage is really handled)
|
||||||
|
run: make test-mysql
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
|
RACE_ENABLED: true
|
||||||
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
|
||||||
|
|
||||||
test-mssql:
|
test-mssql:
|
||||||
if: needs.files-changed.outputs.backend == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
services:
|
services:
|
||||||
mssql:
|
mssql:
|
||||||
image: mcr.microsoft.com/mssql/server:2019-latest
|
image: mcr.microsoft.com/mssql/server:2019-latest
|
||||||
@@ -233,21 +222,24 @@ jobs:
|
|||||||
ports:
|
ports:
|
||||||
- "1433:1433"
|
- "1433:1433"
|
||||||
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
|
devstoreaccount1.azurite.local: # https://github.com/Azure/Azurite/issues/1583
|
||||||
image: mcr.microsoft.com/azure-storage/azurite:latest@sha256:dae2a5f96553962901304b94e72ef87e299d0825e4b679673bcc527a25076fe4
|
image: mcr.microsoft.com/azure-storage/azurite:latest
|
||||||
ports:
|
ports:
|
||||||
- 10000:10000
|
- 10000:10000
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
- name: Add hosts to /etc/hosts
|
- name: Add hosts to /etc/hosts
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts'
|
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mssql devstoreaccount1.azurite.local" | sudo tee -a /etc/hosts'
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make backend
|
- run: make backend
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
- run: GITEA_TEST_DATABASE=mssql make test-migration
|
- run: make test-mssql-migration
|
||||||
- name: run tests
|
- name: run tests
|
||||||
run: GITEA_TEST_DATABASE=mssql make test-integration
|
run: make test-mssql
|
||||||
timeout-minutes: 50
|
timeout-minutes: 50
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
|
|||||||
51
.github/workflows/pull-docker-dryrun.yml
vendored
51
.github/workflows/pull-docker-dryrun.yml
vendored
@@ -7,41 +7,34 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
files-changed:
|
files-changed:
|
||||||
uses: ./.github/workflows/files-changed.yml
|
uses: ./.github/workflows/files-changed.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
# QEMU-based build is slow (40-50 minutes), so run arm64 and riscv64 when dockerfile changes.
|
container:
|
||||||
# Run amd64 when any docker-related files change, which is fast (4 minutes).
|
|
||||||
container-amd64:
|
|
||||||
if: needs.files-changed.outputs.docker == 'true'
|
if: needs.files-changed.outputs.docker == 'true'
|
||||||
needs: [files-changed]
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/docker-dryrun
|
- uses: docker/setup-qemu-action@v4
|
||||||
|
- uses: docker/setup-buildx-action@v4
|
||||||
|
- name: Build regular container image
|
||||||
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
platform: linux/amd64
|
context: .
|
||||||
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
container-arm64:
|
push: false
|
||||||
if: needs.files-changed.outputs.dockerfile == 'true'
|
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
|
||||||
needs: [files-changed]
|
- name: Build rootless container image
|
||||||
runs-on: ubuntu-latest
|
uses: docker/build-push-action@v7
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: ./.github/actions/docker-dryrun
|
|
||||||
with:
|
with:
|
||||||
platform: linux/arm64
|
context: .
|
||||||
|
push: false
|
||||||
container-riscv64:
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
if: needs.files-changed.outputs.dockerfile == 'true'
|
file: Dockerfile.rootless
|
||||||
needs: [files-changed]
|
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: ./.github/actions/docker-dryrun
|
|
||||||
with:
|
|
||||||
platform: linux/riscv64
|
|
||||||
|
|||||||
28
.github/workflows/pull-e2e-tests.yml
vendored
28
.github/workflows/pull-e2e-tests.yml
vendored
@@ -7,31 +7,37 @@ concurrency:
|
|||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
files-changed:
|
files-changed:
|
||||||
uses: ./.github/workflows/files-changed.yml
|
uses: ./.github/workflows/files-changed.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
test-e2e:
|
test-e2e:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true' || needs.files-changed.outputs.e2e == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.frontend == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
- uses: ./.github/actions/go-setup
|
- uses: actions/setup-go@v6
|
||||||
- uses: ./.github/actions/node-setup
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
- uses: pnpm/action-setup@v5
|
||||||
|
- uses: actions/setup-node@v6
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: pnpm-lock.yaml
|
||||||
- run: make deps-frontend
|
- run: make deps-frontend
|
||||||
- run: make frontend
|
- run: make frontend
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make backend
|
- run: make gitea-e2e
|
||||||
env:
|
|
||||||
TAGS: bindata
|
|
||||||
- run: make playwright
|
- run: make playwright
|
||||||
- run: make test-e2e
|
- run: make test-e2e
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
|
||||||
FORCE_COLOR: 1
|
FORCE_COLOR: 1
|
||||||
GITEA_TEST_E2E_DEBUG: 1
|
GITEA_TEST_E2E_DEBUG: 1
|
||||||
|
|||||||
33
.github/workflows/pull-labeler.yml
vendored
33
.github/workflows/pull-labeler.yml
vendored
@@ -1,10 +1,8 @@
|
|||||||
name: labeler
|
name: labeler
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# pull_request_target is required to label PRs from forks; jobs only use pinned
|
pull_request_target:
|
||||||
# actions or base-branch checkout, never PR-head code.
|
types: [opened, synchronize, reopened]
|
||||||
pull_request_target: # zizmor: ignore[dangerous-triggers]
|
|
||||||
types: [opened, synchronize, reopened, edited, ready_for_review]
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
@@ -17,31 +15,6 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
|
- uses: actions/labeler@v6
|
||||||
with:
|
with:
|
||||||
sync-labels: true
|
sync-labels: true
|
||||||
|
|
||||||
pr-title:
|
|
||||||
if: github.event.pull_request.draft == false
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
timeout-minutes: 5
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
# Base-branch checkout only: pull_request_target runs with elevated token; never run PR-head code here.
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
with:
|
|
||||||
ref: ${{ github.event.pull_request.base.sha }}
|
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
||||||
with:
|
|
||||||
node-version: 24
|
|
||||||
# Labels are only synced after the title lints, so an invalid title never reaches the label diff.
|
|
||||||
- run: node ./tools/ci-tools.ts lint-pr-title
|
|
||||||
env:
|
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
||||||
- run: node ./tools/ci-tools.ts set-pr-labels
|
|
||||||
env:
|
|
||||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
|
||||||
|
|||||||
41
.github/workflows/release-nightly-snapcraft.yml
vendored
41
.github/workflows/release-nightly-snapcraft.yml
vendored
@@ -1,41 +0,0 @@
|
|||||||
name: release-nightly-snapcraft
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
env:
|
|
||||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
|
|
||||||
- name: Install snapcraft
|
|
||||||
run: sudo snap install snapcraft --classic
|
|
||||||
|
|
||||||
- name: Remote build
|
|
||||||
run: |
|
|
||||||
snapcraft remote-build \
|
|
||||||
--launchpad-accept-public-upload \
|
|
||||||
--build-for=amd64,arm64,armhf
|
|
||||||
|
|
||||||
- name: List built snaps
|
|
||||||
run: find . -maxdepth 1 -type f -name '*.snap' -print
|
|
||||||
|
|
||||||
- name: Upload and release snapcraft nightly build
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
for snap in ./*.snap; do
|
|
||||||
echo "Uploading $snap to edge"
|
|
||||||
snapcraft upload --release="latest/edge" "$snap"
|
|
||||||
done
|
|
||||||
50
.github/workflows/release-nightly.yml
vendored
50
.github/workflows/release-nightly.yml
vendored
@@ -14,16 +14,16 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
|
- uses: pnpm/action-setup@v5
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -32,42 +32,34 @@ jobs:
|
|||||||
# xgo build
|
# xgo build
|
||||||
- run: make release
|
- run: make release
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
- name: import gpg key
|
- name: import gpg key
|
||||||
id: import_gpg
|
id: import_gpg
|
||||||
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
|
uses: crazy-max/ghaction-import-gpg@v7
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||||
- name: sign binaries
|
- name: sign binaries
|
||||||
env:
|
|
||||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
|
||||||
GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
run: |
|
run: |
|
||||||
for f in dist/release/*; do
|
for f in dist/release/*; do
|
||||||
echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f"
|
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
||||||
done
|
done
|
||||||
# clean branch name to get the folder name in S3
|
# clean branch name to get the folder name in S3
|
||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
env:
|
|
||||||
REF: ${{ github.ref }}
|
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "$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\///' -e 's/release\/v//')
|
||||||
echo "Cleaned name is ${REF_NAME}"
|
echo "Cleaned name is ${REF_NAME}"
|
||||||
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
||||||
- name: configure aws
|
- name: configure aws
|
||||||
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
|
uses: aws-actions/configure-aws-credentials@v6
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: upload binaries to s3
|
- name: upload binaries to s3
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
||||||
BRANCH: ${{ steps.clean_name.outputs.branch }}
|
|
||||||
run: |
|
run: |
|
||||||
aws s3 sync dist/release "s3://$AWS_S3_BUCKET/gitea/$BRANCH" --no-progress
|
aws s3 sync dist/release s3://${{ secrets.AWS_S3_BUCKET }}/gitea/${{ steps.clean_name.outputs.branch }} --no-progress
|
||||||
|
|
||||||
nightly-container:
|
nightly-container:
|
||||||
runs-on: namespace-profile-gitea-release-docker
|
runs-on: namespace-profile-gitea-release-docker
|
||||||
@@ -75,20 +67,18 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write # to publish to ghcr.io
|
packages: write # to publish to ghcr.io
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
- uses: docker/setup-qemu-action@v4
|
||||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
- uses: docker/setup-buildx-action@v4
|
||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
env:
|
|
||||||
REF: ${{ github.ref }}
|
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "$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\///' -e 's/release\/v//')
|
||||||
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
echo "branch=${REF_NAME}-nightly" >> "$GITHUB_OUTPUT"
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta
|
id: meta
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -98,7 +88,7 @@ jobs:
|
|||||||
type=raw,value=${{ steps.clean_name.outputs.branch }}
|
type=raw,value=${{ steps.clean_name.outputs.branch }}
|
||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta_rootless
|
id: meta_rootless
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -112,18 +102,18 @@ jobs:
|
|||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Login to GHCR using PAT
|
- name: Login to GHCR using PAT
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: build regular docker image
|
- name: build regular docker image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
@@ -133,7 +123,7 @@ jobs:
|
|||||||
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
|
cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
|
||||||
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
|
cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
|
||||||
- name: build rootless docker image
|
- name: build rootless docker image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
|
|||||||
53
.github/workflows/release-tag-rc.yml
vendored
53
.github/workflows/release-tag-rc.yml
vendored
@@ -15,16 +15,16 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
|
- uses: pnpm/action-setup@v5
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -33,52 +33,43 @@ jobs:
|
|||||||
# xgo build
|
# xgo build
|
||||||
- run: make release
|
- run: make release
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
- name: import gpg key
|
- name: import gpg key
|
||||||
id: import_gpg
|
id: import_gpg
|
||||||
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
|
uses: crazy-max/ghaction-import-gpg@v7
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||||
- name: sign binaries
|
- name: sign binaries
|
||||||
env:
|
|
||||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
|
||||||
GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
run: |
|
run: |
|
||||||
for f in dist/release/*; do
|
for f in dist/release/*; do
|
||||||
echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f"
|
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
||||||
done
|
done
|
||||||
# clean branch name to get the folder name in S3
|
# clean branch name to get the folder name in S3
|
||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
env:
|
|
||||||
REF: ${{ github.ref }}
|
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -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
|
||||||
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
|
uses: aws-actions/configure-aws-credentials@v6
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: upload binaries to s3
|
- name: upload binaries to s3
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
||||||
BRANCH: ${{ steps.clean_name.outputs.branch }}
|
|
||||||
run: |
|
run: |
|
||||||
aws s3 sync dist/release "s3://$AWS_S3_BUCKET/gitea/$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
|
- name: Install GH CLI
|
||||||
uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
|
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1
|
||||||
with:
|
with:
|
||||||
gh-cli-version: 2.39.1
|
gh-cli-version: 2.39.1
|
||||||
- name: create github release
|
- name: create github release
|
||||||
|
run: |
|
||||||
|
gh release create ${{ github.ref_name }} --title ${{ github.ref_name }} --draft --notes-from-tag dist/release/*
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
TAG: ${{ github.ref_name }}
|
|
||||||
run: |
|
|
||||||
gh release create "$TAG" --title "$TAG" --draft --notes-from-tag dist/release/*
|
|
||||||
|
|
||||||
container:
|
container:
|
||||||
runs-on: namespace-profile-gitea-release-docker
|
runs-on: namespace-profile-gitea-release-docker
|
||||||
@@ -86,13 +77,13 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write # to publish to ghcr.io
|
packages: write # to publish to ghcr.io
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
- uses: docker/setup-qemu-action@v4
|
||||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
- uses: docker/setup-buildx-action@v4
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta
|
id: meta
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -105,7 +96,7 @@ jobs:
|
|||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta_rootless
|
id: meta_rootless
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -121,18 +112,18 @@ jobs:
|
|||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Login to GHCR using PAT
|
- name: Login to GHCR using PAT
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: build regular container image
|
- name: build regular container image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
@@ -140,7 +131,7 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
annotations: ${{ steps.meta.outputs.annotations }}
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
- name: build rootless container image
|
- name: build rootless container image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
|
|||||||
53
.github/workflows/release-tag-version.yml
vendored
53
.github/workflows/release-tag-version.yml
vendored
@@ -18,16 +18,16 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write # to publish to ghcr.io
|
packages: write # to publish to ghcr.io
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
- uses: actions/setup-go@v6
|
||||||
with:
|
with:
|
||||||
go-version-file: go.mod
|
go-version-file: go.mod
|
||||||
check-latest: true
|
check-latest: true
|
||||||
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
|
- uses: pnpm/action-setup@v5
|
||||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 24
|
node-version: 24
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
@@ -36,52 +36,43 @@ jobs:
|
|||||||
# xgo build
|
# xgo build
|
||||||
- run: make release
|
- run: make release
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata sqlite sqlite_unlock_notify
|
||||||
- name: import gpg key
|
- name: import gpg key
|
||||||
id: import_gpg
|
id: import_gpg
|
||||||
uses: crazy-max/ghaction-import-gpg@2dc316deee8e90f13e1a351ab510b4d5bc0c82cd # v7.0.0
|
uses: crazy-max/ghaction-import-gpg@v7
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
gpg_private_key: ${{ secrets.GPGSIGN_KEY }}
|
||||||
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
||||||
- name: sign binaries
|
- name: sign binaries
|
||||||
env:
|
|
||||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
|
||||||
GPG_PASSPHRASE: ${{ secrets.GPGSIGN_PASSPHRASE }}
|
|
||||||
run: |
|
run: |
|
||||||
for f in dist/release/*; do
|
for f in dist/release/*; do
|
||||||
echo "$GPG_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u "$GPG_FINGERPRINT" --output "$f.asc" "$f"
|
echo '${{ secrets.GPGSIGN_PASSPHRASE }}' | gpg --pinentry-mode loopback --passphrase-fd 0 --batch --yes --detach-sign -u ${{ steps.import_gpg.outputs.fingerprint }} --output "$f.asc" "$f"
|
||||||
done
|
done
|
||||||
# clean branch name to get the folder name in S3
|
# clean branch name to get the folder name in S3
|
||||||
- name: Get cleaned branch name
|
- name: Get cleaned branch name
|
||||||
id: clean_name
|
id: clean_name
|
||||||
env:
|
|
||||||
REF: ${{ github.ref }}
|
|
||||||
run: |
|
run: |
|
||||||
REF_NAME=$(echo "$REF" | sed -e 's/refs\/heads\///' -e 's/refs\/tags\/v//' -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
|
||||||
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
|
uses: aws-actions/configure-aws-credentials@v6
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||||
- name: upload binaries to s3
|
- name: upload binaries to s3
|
||||||
env:
|
|
||||||
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
|
|
||||||
BRANCH: ${{ steps.clean_name.outputs.branch }}
|
|
||||||
run: |
|
run: |
|
||||||
aws s3 sync dist/release "s3://$AWS_S3_BUCKET/gitea/$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
|
- name: Install GH CLI
|
||||||
uses: dev-hanz-ops/install-gh-cli-action@af38ce09b1ec248aeb08eea2b16bbecea9e059f8 # v0.2.1
|
uses: dev-hanz-ops/install-gh-cli-action@v0.2.1
|
||||||
with:
|
with:
|
||||||
gh-cli-version: 2.39.1
|
gh-cli-version: 2.39.1
|
||||||
- name: create github release
|
- name: create github release
|
||||||
|
run: |
|
||||||
|
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 }}
|
||||||
TAG: ${{ github.ref_name }}
|
|
||||||
run: |
|
|
||||||
gh release create "$TAG" --title "$TAG" --notes-from-tag dist/release/*
|
|
||||||
|
|
||||||
container:
|
container:
|
||||||
runs-on: namespace-profile-gitea-release-docker
|
runs-on: namespace-profile-gitea-release-docker
|
||||||
@@ -89,13 +80,13 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
packages: write # to publish to ghcr.io
|
packages: write # to publish to ghcr.io
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@v6
|
||||||
# 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: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
- uses: docker/setup-qemu-action@v4
|
||||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
- uses: docker/setup-buildx-action@v4
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta
|
id: meta
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -112,7 +103,7 @@ jobs:
|
|||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
- uses: docker/metadata-action@v6
|
||||||
id: meta_rootless
|
id: meta_rootless
|
||||||
with:
|
with:
|
||||||
images: |-
|
images: |-
|
||||||
@@ -133,18 +124,18 @@ jobs:
|
|||||||
annotations: |
|
annotations: |
|
||||||
org.opencontainers.image.authors="maintainers@gitea.io"
|
org.opencontainers.image.authors="maintainers@gitea.io"
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Login to GHCR using PAT
|
- name: Login to GHCR using PAT
|
||||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ github.repository_owner }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: build regular container image
|
- name: build regular container image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
@@ -152,7 +143,7 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
annotations: ${{ steps.meta.outputs.annotations }}
|
annotations: ${{ steps.meta.outputs.annotations }}
|
||||||
- name: build rootless container image
|
- name: build rootless container image
|
||||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
platforms: linux/amd64,linux/arm64,linux/riscv64
|
platforms: linux/amd64,linux/arm64,linux/riscv64
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -55,7 +55,10 @@ cpu.out
|
|||||||
*.log.*.gz
|
*.log.*.gz
|
||||||
|
|
||||||
/gitea
|
/gitea
|
||||||
|
/gitea-e2e
|
||||||
|
/gitea-vet
|
||||||
/debug
|
/debug
|
||||||
|
/integrations.test
|
||||||
|
|
||||||
/bin
|
/bin
|
||||||
/dist
|
/dist
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ linters:
|
|||||||
desc: use os or io instead
|
desc: use os or io instead
|
||||||
- pkg: golang.org/x/exp
|
- pkg: golang.org/x/exp
|
||||||
desc: it's experimental and unreliable
|
desc: it's experimental and unreliable
|
||||||
- pkg: gitea.dev/modules/git/internal
|
- pkg: code.gitea.io/gitea/modules/git/internal
|
||||||
desc: do not use the internal package, use AddXxx function instead
|
desc: do not use the internal package, use AddXxx function instead
|
||||||
- pkg: gopkg.in/ini.v1
|
- pkg: gopkg.in/ini.v1
|
||||||
desc: do not use the ini package, use gitea's config system instead
|
desc: do not use the ini package, use gitea's config system instead
|
||||||
@@ -51,14 +51,6 @@ linters:
|
|||||||
desc: do not use the go-chi cache package, use gitea's cache system
|
desc: do not use the go-chi cache package, use gitea's cache system
|
||||||
- pkg: github.com/pkg/errors
|
- pkg: github.com/pkg/errors
|
||||||
desc: use builtin errors package instead
|
desc: use builtin errors package instead
|
||||||
migrations:
|
|
||||||
files:
|
|
||||||
- '**/models/migrations/**/*.go'
|
|
||||||
deny:
|
|
||||||
- pkg: gitea.dev/models$
|
|
||||||
desc: migrations must not depend on the models package
|
|
||||||
- pkg: gitea.dev/modules/structs
|
|
||||||
desc: migrations must not depend on modules/structs (API structures change over time)
|
|
||||||
nolintlint:
|
nolintlint:
|
||||||
allow-unused: false
|
allow-unused: false
|
||||||
require-explanation: true
|
require-explanation: true
|
||||||
@@ -166,16 +158,9 @@ issues:
|
|||||||
max-same-issues: 0
|
max-same-issues: 0
|
||||||
formatters:
|
formatters:
|
||||||
enable:
|
enable:
|
||||||
- gci
|
- gofmt
|
||||||
- gofumpt
|
- gofumpt
|
||||||
settings:
|
settings:
|
||||||
gci:
|
|
||||||
custom-order: true
|
|
||||||
sections:
|
|
||||||
- standard
|
|
||||||
- prefix(gitea.dev)
|
|
||||||
- blank
|
|
||||||
- default
|
|
||||||
gofumpt:
|
gofumpt:
|
||||||
extra-rules: true
|
extra-rules: true
|
||||||
exclusions:
|
exclusions:
|
||||||
@@ -185,6 +170,9 @@ formatters:
|
|||||||
- .venv
|
- .venv
|
||||||
- public
|
- public
|
||||||
- web_src
|
- web_src
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
|
||||||
run:
|
run:
|
||||||
timeout: 10m
|
timeout: 10m
|
||||||
|
|||||||
7
.npmrc
Normal file
7
.npmrc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
audit=false
|
||||||
|
fund=false
|
||||||
|
update-notifier=false
|
||||||
|
save-exact=true
|
||||||
|
auto-install-peers=true
|
||||||
|
dedupe-peer-dependents=false
|
||||||
|
enable-pre-post-scripts=true
|
||||||
@@ -1 +0,0 @@
|
|||||||
disable=SC1091,SC2001,SC2002,SC2016,SC2028,SC2046,SC2124,SC2128,SC2129,SC2154,SC2155,SC2164,SC2181,SC2207
|
|
||||||
@@ -2,18 +2,10 @@
|
|||||||
- Run `make fmt` to format `.go` files, and run `make lint-go` to lint them
|
- Run `make fmt` to format `.go` files, and run `make lint-go` to lint them
|
||||||
- Run `make lint-js` to lint `.ts` files
|
- Run `make lint-js` to lint `.ts` files
|
||||||
- Run `make tidy` after any `go.mod` changes
|
- Run `make tidy` after any `go.mod` changes
|
||||||
- Run single go tests with `go test -run '^TestName$' ./modulepath/`
|
|
||||||
- Run single js test files with `pnpm exec vitest <path-filter>`
|
|
||||||
- Run single playwright e2e test files with `GITEA_TEST_E2E_FLAGS='<filepath>' make test-e2e`
|
|
||||||
- Add the current year into the copyright header of new `.go` files
|
- Add the current year into the copyright header of new `.go` files
|
||||||
- Ensure no trailing whitespace in edited files
|
- Ensure no trailing whitespace in edited files
|
||||||
- Use Conventional Commits for commit messages and PR titles, e.g. `type(scope): subject`; `!` before the colon if breaking. Use `test` type for test-only changes.
|
|
||||||
- Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates
|
- Never force-push, amend, or squash unless asked. Use new commits and normal push for pull request updates
|
||||||
- Preserve existing code comments, do not remove or rewrite comments that are still relevant
|
- Preserve existing code comments, do not remove or rewrite comments that are still relevant
|
||||||
- Keep comments short, prefer same-line, explain why, never narrate code
|
|
||||||
- Prefer unit tests over integration tests when logic is testable in isolation
|
|
||||||
- Aim for sub-2s local runtime for integration and e2e tests
|
|
||||||
- In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist
|
- In TypeScript, use `!` (non-null assertion) instead of `?.`/`??` when a value is known to always exist
|
||||||
- For CSS layout, prefer `flex-*` helpers over per-child `tw-ml-*` / `tw-mr-*` margins; fall back to `tw-*` utilities when specificity requires `!important`
|
|
||||||
- Include authorship attribution in issue and pull request comments
|
- Include authorship attribution in issue and pull request comments
|
||||||
- Add `Co-Authored-By` lines to all commits, indicating name and model used
|
- Add `Co-Authored-By` lines to all commits, indicating name and model used
|
||||||
|
|||||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -86,7 +86,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
|||||||
* Fix button layout shift when collapsing file tree in editor (#37363) #37375
|
* Fix button layout shift when collapsing file tree in editor (#37363) #37375
|
||||||
* Fix org team assignee/reviewer lookups for team member permissions (#37365) #37391
|
* Fix org team assignee/reviewer lookups for team member permissions (#37365) #37391
|
||||||
* Fix repo init README EOL (#37388) #37399
|
* Fix repo init README EOL (#37388) #37399
|
||||||
* Fix: dump with default zip type produces uncompressed zip (#37401) #37402
|
* Fix: dump with default zip type produces uncompressed zip (#37401)#37402
|
||||||
|
|
||||||
## [1.26.0](https://github.com/go-gitea/gitea/releases/tag/v1.26.0) - 2026-04-17
|
## [1.26.0](https://github.com/go-gitea/gitea/releases/tag/v1.26.0) - 2026-04-17
|
||||||
|
|
||||||
@@ -1445,7 +1445,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
|||||||
* Fix mCaptcha bug (#33659) (#33661)
|
* Fix mCaptcha bug (#33659) (#33661)
|
||||||
* Git graph: don't show detached commits (#33645) (#33650)
|
* Git graph: don't show detached commits (#33645) (#33650)
|
||||||
* Use MatchPhraseQuery for bleve code search (#33628)
|
* Use MatchPhraseQuery for bleve code search (#33628)
|
||||||
* Adjust appearance of commit status webhook (#33778) #33789
|
* Adjust appearence of commit status webhook (#33778) #33789
|
||||||
* Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) #33796
|
* Upgrade golang net from 0.35.0 -> 0.36.0 (#33795) #33796
|
||||||
|
|
||||||
## [1.23.4](https://github.com/go-gitea/gitea/releases/tag/v1.23.4) - 2025-02-16
|
## [1.23.4](https://github.com/go-gitea/gitea/releases/tag/v1.23.4) - 2025-02-16
|
||||||
@@ -2176,7 +2176,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.com).
|
|||||||
* Optimize repo-list layout to enhance visual experience (#31272) (#31276)
|
* Optimize repo-list layout to enhance visual experience (#31272) (#31276)
|
||||||
* fixed the dropdown menu for the top New button to expand to the left (#31273) (#31275)
|
* fixed the dropdown menu for the top New button to expand to the left (#31273) (#31275)
|
||||||
* Fix Activity Page Contributors dropdown (#31264) (#31269)
|
* Fix Activity Page Contributors dropdown (#31264) (#31269)
|
||||||
* fix: allow actions artifacts storage migration to complete successfully (#31251) (#31257)
|
* fix: allow actions artifacts storage migration to complete succesfully (#31251) (#31257)
|
||||||
* Make blockquote attention recognize more syntaxes (#31240) (#31250)
|
* Make blockquote attention recognize more syntaxes (#31240) (#31250)
|
||||||
* Remove .segment from .project-column (#31204) (#31239)
|
* Remove .segment from .project-column (#31204) (#31239)
|
||||||
* Ignore FindRecentlyPushedNewBranches err (#31164) (#31171)
|
* Ignore FindRecentlyPushedNewBranches err (#31164) (#31171)
|
||||||
@@ -2360,7 +2360,7 @@ Key highlights of this release encompass significant changes categorized under `
|
|||||||
* Performance optimization for git push and check permissions for push options (#30104) (#30354)
|
* Performance optimization for git push and check permissions for push options (#30104) (#30354)
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
* Fix close file in the Upload func (#30262) (#30269)
|
* Fix close file in the Upload func (#30262) (#30269)
|
||||||
* Fix inline math blocks can't be preceded/followed by alphanumerical characters (#30175) (#30250)
|
* Fix inline math blocks can't be preceeded/followed by alphanumerical characters (#30175) (#30250)
|
||||||
* Fix missing 0 prefix of GPG key id (#30245) (#30247)
|
* Fix missing 0 prefix of GPG key id (#30245) (#30247)
|
||||||
* Include encoding in signature payload (#30174) (#30181)
|
* Include encoding in signature payload (#30174) (#30181)
|
||||||
* Move from `max( id )` to `max( index )` for latest commit statuses (#30076) (#30155)
|
* Move from `max( id )` to `max( index )` for latest commit statuses (#30076) (#30155)
|
||||||
@@ -5652,7 +5652,7 @@ Key highlights of this release encompass significant changes categorized under `
|
|||||||
* Fix navbar on project view (#17749)
|
* Fix navbar on project view (#17749)
|
||||||
* More pleasantly handle broken or missing git repositories (#17747)
|
* More pleasantly handle broken or missing git repositories (#17747)
|
||||||
* Use `*PushUpdateOptions` as receiver (#17724)
|
* Use `*PushUpdateOptions` as receiver (#17724)
|
||||||
* Remove unused `user` parameter (#17723)
|
* Remove unused `user` paramater (#17723)
|
||||||
* Better builtin avatar generator (#17707)
|
* Better builtin avatar generator (#17707)
|
||||||
* Cleanup and use global style on popups (#17674)
|
* Cleanup and use global style on popups (#17674)
|
||||||
* Move user/org deletion to services (#17673)
|
* Move user/org deletion to services (#17673)
|
||||||
|
|||||||
447
CONTRIBUTING.md
447
CONTRIBUTING.md
@@ -1,14 +1,5 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
|
|
||||||
This document explains how to contribute changes to the Gitea project. Topic-specific guides live in separate files so the essentials are easier to find.
|
|
||||||
|
|
||||||
| Topic | Document |
|
|
||||||
| :---- | :------- |
|
|
||||||
| Backend (Go modules, API v1) | [docs/guideline-backend.md](docs/guideline-backend.md) |
|
|
||||||
| Frontend (npm, UI guidelines) | [docs/guideline-frontend.md](docs/guideline-frontend.md) |
|
|
||||||
| Maintainers, TOC, labels, merge queue, commit format for mergers | [docs/community-governance.md](docs/community-governance.md) |
|
|
||||||
| Release cycle, backports, tagging releases | [docs/release-management.md](docs/release-management.md) |
|
|
||||||
|
|
||||||
<details><summary>Table of Contents</summary>
|
<details><summary>Table of Contents</summary>
|
||||||
|
|
||||||
- [Contribution Guidelines](#contribution-guidelines)
|
- [Contribution Guidelines](#contribution-guidelines)
|
||||||
@@ -20,6 +11,10 @@ This document explains how to contribute changes to the Gitea project. Topic-spe
|
|||||||
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
|
- [Discuss your design before the implementation](#discuss-your-design-before-the-implementation)
|
||||||
- [Issue locking](#issue-locking)
|
- [Issue locking](#issue-locking)
|
||||||
- [Building Gitea](#building-gitea)
|
- [Building Gitea](#building-gitea)
|
||||||
|
- [Dependencies](#dependencies)
|
||||||
|
- [Backend](#backend)
|
||||||
|
- [Frontend](#frontend)
|
||||||
|
- [Design guideline](#design-guideline)
|
||||||
- [Styleguide](#styleguide)
|
- [Styleguide](#styleguide)
|
||||||
- [Copyright](#copyright)
|
- [Copyright](#copyright)
|
||||||
- [Testing](#testing)
|
- [Testing](#testing)
|
||||||
@@ -27,19 +22,47 @@ This document explains how to contribute changes to the Gitea project. Topic-spe
|
|||||||
- [Code review](#code-review)
|
- [Code review](#code-review)
|
||||||
- [Pull request format](#pull-request-format)
|
- [Pull request format](#pull-request-format)
|
||||||
- [PR title and summary](#pr-title-and-summary)
|
- [PR title and summary](#pr-title-and-summary)
|
||||||
|
- [Milestone](#milestone)
|
||||||
|
- [Labels](#labels)
|
||||||
- [Breaking PRs](#breaking-prs)
|
- [Breaking PRs](#breaking-prs)
|
||||||
- [What is a breaking PR?](#what-is-a-breaking-pr)
|
- [What is a breaking PR?](#what-is-a-breaking-pr)
|
||||||
- [How to handle breaking PRs?](#how-to-handle-breaking-prs)
|
- [How to handle breaking PRs?](#how-to-handle-breaking-prs)
|
||||||
- [Maintaining open PRs](#maintaining-open-prs)
|
- [Maintaining open PRs](#maintaining-open-prs)
|
||||||
- [Reviewing PRs](#reviewing-prs)
|
- [Getting PRs merged](#getting-prs-merged)
|
||||||
- [For PR authors](#for-pr-authors)
|
- [Final call](#final-call)
|
||||||
|
- [Commit messages](#commit-messages)
|
||||||
|
- [PR Co-authors](#pr-co-authors)
|
||||||
|
- [PRs targeting `main`](#prs-targeting-main)
|
||||||
|
- [Backport PRs](#backport-prs)
|
||||||
- [Documentation](#documentation)
|
- [Documentation](#documentation)
|
||||||
|
- [API v1](#api-v1)
|
||||||
|
- [GitHub API compatibility](#github-api-compatibility)
|
||||||
|
- [Adding/Maintaining API routes](#addingmaintaining-api-routes)
|
||||||
|
- [When to use what HTTP method](#when-to-use-what-http-method)
|
||||||
|
- [Requirements for API routes](#requirements-for-api-routes)
|
||||||
|
- [Backports and Frontports](#backports-and-frontports)
|
||||||
|
- [What is backported?](#what-is-backported)
|
||||||
|
- [How to backport?](#how-to-backport)
|
||||||
|
- [Format of backport PRs](#format-of-backport-prs)
|
||||||
|
- [Frontports](#frontports)
|
||||||
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
|
- [Developer Certificate of Origin (DCO)](#developer-certificate-of-origin-dco)
|
||||||
|
- [Release Cycle](#release-cycle)
|
||||||
|
- [Maintainers](#maintainers)
|
||||||
|
- [Technical Oversight Committee (TOC)](#technical-oversight-committee-toc)
|
||||||
|
- [TOC election process](#toc-election-process)
|
||||||
|
- [Current TOC members](#current-toc-members)
|
||||||
|
- [Previous TOC/owners members](#previous-tocowners-members)
|
||||||
|
- [Governance Compensation](#governance-compensation)
|
||||||
|
- [TOC \& Working groups](#toc--working-groups)
|
||||||
|
- [Roadmap](#roadmap)
|
||||||
|
- [Versions](#versions)
|
||||||
|
- [Releasing Gitea](#releasing-gitea)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
This document explains how to contribute changes to the Gitea project. \
|
||||||
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
|
It assumes you have followed the [installation instructions](https://docs.gitea.com/category/installation). \
|
||||||
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
|
Sensitive security-related issues should be reported to [security@gitea.io](mailto:security@gitea.io).
|
||||||
|
|
||||||
@@ -108,6 +131,34 @@ If further discussion is needed, we encourage you to open a new issue instead an
|
|||||||
|
|
||||||
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
|
See the [development setup instructions](https://docs.gitea.com/development/hacking-on-gitea).
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
|
||||||
|
Go dependencies are managed using [Go Modules](https://go.dev/cmd/go/#hdr-Module_maintenance). \
|
||||||
|
You can find more details in the [go mod documentation](https://go.dev/ref/mod) and the [Go Modules Wiki](https://github.com/golang/go/wiki/Modules).
|
||||||
|
|
||||||
|
Pull requests should only modify `go.mod` and `go.sum` where it is related to your change, be it a bugfix or a new feature. \
|
||||||
|
Apart from that, these files should only be modified by Pull Requests whose only purpose is to update dependencies.
|
||||||
|
|
||||||
|
The `go.mod`, `go.sum` update needs to be justified as part of the PR description,
|
||||||
|
and must be verified by the reviewers and/or merger to always reference
|
||||||
|
an existing upstream commit.
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
|
||||||
|
For the frontend, we use [npm](https://www.npmjs.com/).
|
||||||
|
|
||||||
|
The same restrictions apply for frontend dependencies as for backend dependencies, with the exceptions that the files for it are `package.json` and `package-lock.json`, and that new versions must always reference an existing version.
|
||||||
|
|
||||||
|
## Design guideline
|
||||||
|
|
||||||
|
Depending on your change, please read the
|
||||||
|
|
||||||
|
- [backend development guideline](https://docs.gitea.com/contributing/guidelines-backend)
|
||||||
|
- [frontend development guideline](https://docs.gitea.com/contributing/guidelines-frontend)
|
||||||
|
- [refactoring guideline](https://docs.gitea.com/contributing/guidelines-refactoring)
|
||||||
|
|
||||||
## Styleguide
|
## Styleguide
|
||||||
|
|
||||||
You should always run `make fmt` before committing to conform to Gitea's styleguide.
|
You should always run `make fmt` before committing to conform to Gitea's styleguide.
|
||||||
@@ -139,11 +190,11 @@ Here's how to run the test suite:
|
|||||||
|
|
||||||
- run tests (we suggest running them on Linux)
|
- run tests (we suggest running them on Linux)
|
||||||
|
|
||||||
| Command | Action | |
|
| Command | Action | |
|
||||||
|:----------------------------------------------|:-----------------------------------------------------| ------------------------------------------- |
|
| :------------------------------------------ | :------------------------------------------------------- | ------------------------------------------- |
|
||||||
| ``make test-backend[\#SpecificTestName]`` | run unit test(s) | |
|
|``make test[\#SpecificTestName]`` | run unit test(s) | |
|
||||||
| ``make test-integration[\#SpecificTestName]`` | run [integration](tests/integration) test(s) | [More details](tests/integration/README.md) |
|
|``make test-sqlite[\#SpecificTestName]`` | run [integration](tests/integration) test(s) for SQLite | [More details](tests/integration/README.md) |
|
||||||
| ``make test-e2e`` | run [end-to-end](tests/e2e) test(s) using Playwright | |
|
|``make test-e2e`` | run [end-to-end](tests/e2e) test(s) using Playwright | |
|
||||||
|
|
||||||
- E2E test environment variables
|
- E2E test environment variables
|
||||||
|
|
||||||
@@ -151,7 +202,7 @@ Here's how to run the test suite:
|
|||||||
| :-------------------------------- | :---------------------------------------------------------- |
|
| :-------------------------------- | :---------------------------------------------------------- |
|
||||||
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
|
| ``GITEA_TEST_E2E_DEBUG`` | When set, show Gitea server output |
|
||||||
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
|
| ``GITEA_TEST_E2E_FLAGS`` | Additional flags passed to Playwright, for example ``--ui`` |
|
||||||
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 4 on CI, 1 locally) |
|
| ``GITEA_TEST_E2E_TIMEOUT_FACTOR`` | Timeout multiplier (default: 3 on CI, 1 locally) |
|
||||||
|
|
||||||
## Translation
|
## Translation
|
||||||
|
|
||||||
@@ -165,8 +216,6 @@ The tool `go run build/backport-locale.go` can be used to backport locales from
|
|||||||
|
|
||||||
## Code review
|
## Code review
|
||||||
|
|
||||||
How labels, milestones, and the merge queue work is documented in [docs/community-governance.md](docs/community-governance.md).
|
|
||||||
|
|
||||||
### Pull request format
|
### Pull request format
|
||||||
|
|
||||||
Please try to make your pull request easy to review for us. \
|
Please try to make your pull request easy to review for us. \
|
||||||
@@ -189,38 +238,6 @@ In the PR title, describe the problem you are fixing, not how you are fixing it.
|
|||||||
Use the first comment as a summary of your PR. \
|
Use the first comment as a summary of your PR. \
|
||||||
In the PR summary, you can describe exactly how you are fixing this problem.
|
In the PR summary, you can describe exactly how you are fixing this problem.
|
||||||
|
|
||||||
PR titles must follow the [Conventional Commits](https://www.conventionalcommits.org/) format, because PRs are squash-merged and the PR title becomes the resulting commit message:
|
|
||||||
|
|
||||||
```text
|
|
||||||
type(scope)!: subject
|
|
||||||
```
|
|
||||||
|
|
||||||
The scope in parentheses is optional. A `!` immediately before the colon marks a [breaking change](https://www.conventionalcommits.org/en/v1.0.0/#summary): either `type!:` or `type(scope)!:` (not `type!(scope):`).
|
|
||||||
|
|
||||||
Use one of these types:
|
|
||||||
|
|
||||||
- `build`: Changes affecting the build system, packaging, or external dependencies
|
|
||||||
- `ci`: Changes to CI/CD configuration files and scripts
|
|
||||||
- `chore`: Maintenance changes that do not affect production code or should not appear in the changelog
|
|
||||||
- `docs`: Documentation-only changes
|
|
||||||
- `feat`: A larger user-facing feature, improvement, or new functionality
|
|
||||||
- `enhance`: Small or trivial user-facing improvements or UX polish (for example wording changes, color adjustments, spacing or padding tweaks, placeholders, small UI behavior improvements)
|
|
||||||
- `fix`: A bug fix, UX correction, or security-related dependency update
|
|
||||||
- `perf`: Performance improvements (speed, memory, scalability)
|
|
||||||
- `refactor`: A code change that neither fixes a bug nor adds a feature
|
|
||||||
- `revert`: Reverts a previous change
|
|
||||||
- `style`: Formatting or style-only changes that do not affect code behavior (for example lint-driven edits)
|
|
||||||
- `test`: Adding or correcting tests
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
```text
|
|
||||||
fix(web): prevent avatar upload crash on empty file
|
|
||||||
feat(api): add pagination to repo hooks list
|
|
||||||
enhance(repo): improve diff toolbar spacing
|
|
||||||
ci(workflows): lint PR titles in CI
|
|
||||||
```
|
|
||||||
|
|
||||||
Keep this summary up-to-date as the PR evolves. \
|
Keep this summary up-to-date as the PR evolves. \
|
||||||
If your PR changes the UI, you must add **after** screenshots in the PR summary. \
|
If your PR changes the UI, you must add **after** screenshots in the PR summary. \
|
||||||
If you are not implementing a new feature, you should also post **before** screenshots for comparison.
|
If you are not implementing a new feature, you should also post **before** screenshots for comparison.
|
||||||
@@ -233,10 +250,6 @@ Another requirement for merging PRs is that the PR is labeled correctly.\
|
|||||||
However, this is not your job as a contributor, but the job of the person merging your PR.\
|
However, this is not your job as a contributor, but the job of the person merging your PR.\
|
||||||
If you think that your PR was labeled incorrectly, or notice that it was merged without labels, please let us know.
|
If you think that your PR was labeled incorrectly, or notice that it was merged without labels, please let us know.
|
||||||
|
|
||||||
For pull requests that use a valid Conventional Commits title, CI automatically applies a matching `type/…` label when the title prefix is `feat`, `enhance`, `fix`, `docs`, or `test` (for example `enhance(web): …` receives `type/enhancement`).\
|
|
||||||
That label is kept in sync with the PR title when the title is edited.\
|
|
||||||
Other title prefixes do not get an automatic `type/…` label; the merger still assigns the correct labels (including `type/…` when needed) for changelog and backport decisions.
|
|
||||||
|
|
||||||
If your PR closes some issues, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like
|
If your PR closes some issues, you must note that in a way that both GitHub and Gitea understand, i.e. by appending a paragraph like
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -247,6 +260,29 @@ Fixes/Closes/Resolves #<ISSUE_NR_Y>.
|
|||||||
to your summary. \
|
to your summary. \
|
||||||
Each issue that will be closed must stand on a separate line.
|
Each issue that will be closed must stand on a separate line.
|
||||||
|
|
||||||
|
### Milestone
|
||||||
|
|
||||||
|
A PR should only be assigned to a milestone if it will likely be merged into the given version. \
|
||||||
|
As a rule of thumb, assume that a PR will stay open for an additional month for every 100 added lines. \
|
||||||
|
PRs without a milestone may not be merged.
|
||||||
|
|
||||||
|
### Labels
|
||||||
|
|
||||||
|
Almost all labels used inside Gitea can be classified as one of the following:
|
||||||
|
|
||||||
|
- `modifies/…`: Determines which parts of the codebase are affected. These labels will be set through the CI.
|
||||||
|
- `topic/…`: Determines the conceptual component of Gitea that is affected, i.e. issues, projects, or authentication. At best, PRs should only target one component but there might be overlap. Must be set manually.
|
||||||
|
- `type/…`: Determines the type of an issue or PR (feature, refactoring, docs, bug, …). If GitHub supported scoped labels, these labels would be exclusive, so you should set **exactly** one, not more or less (every PR should fall into one of the provided categories, and only one).
|
||||||
|
- `issue/…` / `pr/…`: Labels that are specific to issues or PRs respectively and that are only necessary in a given context, i.e. `issue/not-a-bug` or `pr/need-2-approvals`
|
||||||
|
|
||||||
|
Every PR should be labeled correctly with every label that applies.
|
||||||
|
|
||||||
|
There are also some labels that will be managed automatically.\
|
||||||
|
In particular, these are
|
||||||
|
|
||||||
|
- the amount of pending required approvals
|
||||||
|
- has all `backport`s or needs a manual backport
|
||||||
|
|
||||||
### Breaking PRs
|
### Breaking PRs
|
||||||
|
|
||||||
#### What is a breaking PR?
|
#### What is a breaking PR?
|
||||||
@@ -275,29 +311,165 @@ Breaking PRs will not be merged as long as not both of these requirements are me
|
|||||||
|
|
||||||
### Maintaining open PRs
|
### Maintaining open PRs
|
||||||
|
|
||||||
Code review starts when you open a non-draft PR or move a draft out of draft state. After that, do not rebase or squash your branch; it makes new changes harder to review.
|
The moment you create a non-draft PR or the moment you convert a draft PR to a non-draft PR is the moment code review starts for it. \
|
||||||
|
Once that happens, do not rebase or squash your branch anymore as it makes it difficult to review the new changes. \
|
||||||
|
Merge the base branch into your branch only when you really need to, i.e. because of conflicting changes in the mean time. \
|
||||||
|
This reduces unnecessary CI runs. \
|
||||||
|
Don't worry about merge commits messing up your commit history as every PR will be squash merged. \
|
||||||
|
This means that all changes are joined into a single new commit whose message is as described below.
|
||||||
|
|
||||||
Merge the base branch into yours only when you need to, for example because of conflicting changes elsewhere. That limits unnecessary CI runs.
|
### Getting PRs merged
|
||||||
|
|
||||||
Every PR is squash-merged, so merge commits on your branch do not matter for final history. The squash produces a single commit; mergers follow the [commit message format](docs/community-governance.md#commit-messages) in the governance guide.
|
Changes to Gitea must be reviewed before they are accepted — no matter who
|
||||||
|
makes the change, even if they are an owner or a maintainer. \
|
||||||
|
The only exception are critical bugs that prevent Gitea from being compiled or started. \
|
||||||
|
Specifically, we require two approvals from maintainers for every PR. \
|
||||||
|
Once this criteria has been met, your PR receives the `lgtm/done` label. \
|
||||||
|
From this point on, your only responsibility is to fix merge conflicts or respond to/implement requests by maintainers. \
|
||||||
|
It is the responsibility of the maintainers from this point to get your PR merged.
|
||||||
|
|
||||||
### Reviewing PRs
|
If a PR has the `lgtm/done` label and there are no open discussions or merge conflicts anymore, any maintainer can add the `reviewed/wait-merge` label. \
|
||||||
|
This label means that the PR is part of the merge queue and will be merged as soon as possible. \
|
||||||
|
The merge queue will be cleared in the order of the list below:
|
||||||
|
|
||||||
Maintainers are encouraged to review pull requests in areas where they have expertise or particular interest.
|
<https://github.com/go-gitea/gitea/pulls?q=is%3Apr+label%3Areviewed%2Fwait-merge+sort%3Acreated-asc+is%3Aopen>
|
||||||
|
|
||||||
#### For PR authors
|
Gitea uses it's own tool, the <https://github.com/GiteaBot/gitea-backporter> to automate parts of the review process. \
|
||||||
|
This tool does the things listed below automatically:
|
||||||
|
|
||||||
- **Response**: When answering reviewer questions, use real-world cases or examples and avoid speculation.
|
- create a backport PR if needed once the initial PR was merged
|
||||||
- **Discussion**: A discussion is always welcome and should be used to clarify the changes and the intent of the PR.
|
- remove the PR from the merge queue after the PR merged
|
||||||
- **Help**: If you need help with the PR or comments are unclear, ask for clarification.
|
- keep the oldest branch in the merge queue up to date with merges
|
||||||
|
|
||||||
Guidance for reviewers, the merge queue, and the squash commit message format is in [docs/community-governance.md](docs/community-governance.md).
|
### Final call
|
||||||
|
|
||||||
|
If a PR has been ignored for more than 7 days with no comments or reviews, and the author or any maintainer believes it will not survive a long wait (such as a refactoring PR), they can send "final call" to the TOC by mentioning them in a comment.
|
||||||
|
|
||||||
|
After another 7 days, if there is still zero approval, this is considered a polite refusal, and the PR will be closed to avoid wasting further time. Therefore, the "final call" has a cost, and should be used cautiously.
|
||||||
|
|
||||||
|
However, if there are no objections from maintainers, the PR can be merged with only one approval from the TOC (not the author).
|
||||||
|
|
||||||
|
### Commit messages
|
||||||
|
|
||||||
|
Mergers are able and required to rewrite the PR title and summary (the first comment of a PR) so that it can produce an easily understandable commit message if necessary. \
|
||||||
|
The final commit message should no longer contain any uncertainty such as `hopefully, <x> won't happen anymore`. Replace uncertainty with certainty.
|
||||||
|
|
||||||
|
#### PR Co-authors
|
||||||
|
|
||||||
|
A person counts as a PR co-author the moment they (co-)authored a commit that is not simply a `Merge base branch into branch` commit. \
|
||||||
|
Mergers are required to remove such "false-positive" co-authors when writing the commit message. \
|
||||||
|
The true co-authors must remain in the commit message.
|
||||||
|
|
||||||
|
#### PRs targeting `main`
|
||||||
|
|
||||||
|
The commit message of PRs targeting `main` is always
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$PR_TITLE ($PR_INDEX)
|
||||||
|
|
||||||
|
$REWRITTEN_PR_SUMMARY
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Backport PRs
|
||||||
|
|
||||||
|
The commit message of backport PRs is always
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$PR_TITLE ($INITIAL_PR_INDEX) ($BACKPORT_PR_INDEX)
|
||||||
|
|
||||||
|
$REWRITTEN_PR_SUMMARY
|
||||||
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
|
If you add a new feature or change an existing aspect of Gitea, the documentation for that feature must be created or updated in another PR at [https://gitea.com/gitea/docs](https://gitea.com/gitea/docs).
|
||||||
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
|
**The docs directory on main repository will be removed at some time. We will have a yaml file to store configuration file's meta data. After that completed, configuration documentation should be in the main repository.**
|
||||||
|
|
||||||
|
## API v1
|
||||||
|
|
||||||
|
The API is documented by [swagger](https://gitea.com/api/swagger) and is based on [the GitHub API](https://docs.github.com/en/rest).
|
||||||
|
|
||||||
|
### GitHub API compatibility
|
||||||
|
|
||||||
|
Gitea's API should use the same endpoints and fields as the GitHub API as far as possible, unless there are good reasons to deviate. \
|
||||||
|
If Gitea provides functionality that GitHub does not, a new endpoint can be created. \
|
||||||
|
If information is provided by Gitea that is not provided by the GitHub API, a new field can be used that doesn't collide with any GitHub fields. \
|
||||||
|
Updating an existing API should not remove existing fields unless there is a really good reason to do so. \
|
||||||
|
The same applies to status responses. If you notice a problem, feel free to leave a comment in the code for future refactoring to API v2 (which is currently not planned).
|
||||||
|
|
||||||
|
### Adding/Maintaining API routes
|
||||||
|
|
||||||
|
All expected results (errors, success, fail messages) must be documented ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L319-L327)). \
|
||||||
|
All JSON input types must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L76-L91)) \
|
||||||
|
and referenced in [routers/api/v1/swagger/options.go](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/options.go). \
|
||||||
|
They can then be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L318). \
|
||||||
|
All JSON responses must be defined as a struct in [modules/structs/](modules/structs/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/modules/structs/issue.go#L36-L68)) \
|
||||||
|
and referenced in its category in [routers/api/v1/swagger/](routers/api/v1/swagger/) ([example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/swagger/issue.go#L11-L16)) \
|
||||||
|
They can be used like [this example](https://github.com/go-gitea/gitea/blob/c620eb5b2d0d874da68ebd734d3864c5224f71f7/routers/api/v1/repo/issue.go#L277-L279).
|
||||||
|
|
||||||
|
### When to use what HTTP method
|
||||||
|
|
||||||
|
In general, HTTP methods are chosen as follows:
|
||||||
|
|
||||||
|
- **GET** endpoints return the requested object(s) and status **OK (200)**
|
||||||
|
- **DELETE** endpoints return the status **No Content (204)** and no content either
|
||||||
|
- **POST** endpoints are used to **create** new objects (e.g. a User) and return the status **Created (201)** and the created object
|
||||||
|
- **PUT** endpoints are used to **add/assign** existing Objects (e.g. a user to a team) and return the status **No Content (204)** and no content either
|
||||||
|
- **PATCH** endpoints are used to **edit/change** an existing object and return the changed object and the status **OK (200)**
|
||||||
|
|
||||||
|
### Requirements for API routes
|
||||||
|
|
||||||
|
All parameters of endpoints changing/editing an object must be optional (except the ones to identify the object, which are required).
|
||||||
|
|
||||||
|
Endpoints returning lists must
|
||||||
|
|
||||||
|
- support pagination (`page` & `limit` options in query)
|
||||||
|
- set `X-Total-Count` header via **SetTotalCountHeader** ([example](https://github.com/go-gitea/gitea/blob/7aae98cc5d4113f1e9918b7ee7dd09f67c189e3e/routers/api/v1/repo/issue.go#L444))
|
||||||
|
|
||||||
|
## Backports and Frontports
|
||||||
|
|
||||||
|
### What is backported?
|
||||||
|
|
||||||
|
We backport PRs given the following circumstances:
|
||||||
|
|
||||||
|
1. Feature freeze is active, but `<version>-rc0` has not been released yet. Here, we backport as much as possible. <!-- TODO: Is that our definition with the new backport bot? -->
|
||||||
|
2. `rc0` has been released. Here, we only backport bug- and security-fixes, and small enhancements. Large PRs such as refactors are not backported anymore. <!-- TODO: Is that our definition with the new backport bot? -->
|
||||||
|
3. We never backport new features.
|
||||||
|
4. We never backport breaking changes except when
|
||||||
|
1. The breaking change has no effect on the vast majority of users
|
||||||
|
2. The component triggering the breaking change is marked as experimental
|
||||||
|
|
||||||
|
### How to backport?
|
||||||
|
|
||||||
|
In the past, it was necessary to manually backport your PRs. \
|
||||||
|
Now, that's not a requirement anymore as our [backport bot](https://github.com/GiteaBot) tries to create backports automatically once the PR is merged when the PR
|
||||||
|
|
||||||
|
- does not have the label `backport/manual`
|
||||||
|
- has the label `backport/<version>`
|
||||||
|
|
||||||
|
The `backport/manual` label signifies either that you want to backport the change yourself, or that there were conflicts when backporting, thus you **must** do it yourself.
|
||||||
|
|
||||||
|
### Format of backport PRs
|
||||||
|
|
||||||
|
The title of backport PRs should be
|
||||||
|
|
||||||
|
```
|
||||||
|
<original PR title> (#<original pr number>)
|
||||||
|
```
|
||||||
|
|
||||||
|
The first two lines of the summary of the backporting PR should be
|
||||||
|
|
||||||
|
```
|
||||||
|
Backport #<original pr number>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
with the rest of the summary and labels matching the original PR.
|
||||||
|
|
||||||
|
### Frontports
|
||||||
|
|
||||||
|
Frontports behave exactly as described above for backports.
|
||||||
|
|
||||||
## Developer Certificate of Origin (DCO)
|
## Developer Certificate of Origin (DCO)
|
||||||
|
|
||||||
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
|
We consider the act of contributing to the code by submitting a Pull Request as the "Sign off" or agreement to the certifications and terms of the [DCO](DCO) and [MIT license](LICENSE). \
|
||||||
@@ -311,3 +483,148 @@ Signed-off-by: Joe Smith <joe.smith@email.com>
|
|||||||
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
|
If you set the `user.name` and `user.email` Git config options, you can add the line to the end of your commits automatically with `git commit -s`.
|
||||||
|
|
||||||
We assume in good faith that the information you provide is legally binding.
|
We assume in good faith that the information you provide is legally binding.
|
||||||
|
|
||||||
|
## Release Cycle
|
||||||
|
|
||||||
|
We adopted a release schedule to streamline the process of working on, finishing, and issuing releases. \
|
||||||
|
The overall goal is to make a major release every three or four months, which breaks down into two or three months of general development followed by one month of testing and polishing known as the release freeze. \
|
||||||
|
All the feature pull requests should be
|
||||||
|
merged before feature freeze. All feature pull requests haven't been merged before this feature freeze will be moved to next milestone, please notice our feature freeze announcement on discord. And, during the frozen period, a corresponding
|
||||||
|
release branch is open for fixes backported from main branch. Release candidates
|
||||||
|
are made during this period for user testing to
|
||||||
|
obtain a final version that is maintained in this branch.
|
||||||
|
|
||||||
|
During a development cycle, we may also publish any necessary minor releases
|
||||||
|
for the previous version. For example, if the latest, published release is
|
||||||
|
v1.2, then minor changes for the previous release—e.g., v1.1.0 -> v1.1.1—are
|
||||||
|
still possible.
|
||||||
|
|
||||||
|
## Maintainers
|
||||||
|
|
||||||
|
To make sure every PR is checked, we have [maintainers](MAINTAINERS). \
|
||||||
|
Every PR **must** be reviewed by at least two maintainers (or owners) before it can get merged. \
|
||||||
|
For refactoring PRs after a week and documentation only PRs, the approval of only one maintainer is enough. \
|
||||||
|
A maintainer should be a contributor of Gitea and contributed at least
|
||||||
|
4 accepted PRs. A contributor should apply as a maintainer in the
|
||||||
|
[Discord](https://discord.gg/Gitea) `#develop` channel. The team maintainers may invite the contributor. A maintainer
|
||||||
|
should spend some time on code reviews. If a maintainer has no
|
||||||
|
time to do that, they should apply to leave the maintainers team
|
||||||
|
and we will give them the honor of being a member of the [advisors
|
||||||
|
team](https://github.com/orgs/go-gitea/teams/advisors). Of course, if
|
||||||
|
an advisor has time to code review, we will gladly welcome them back
|
||||||
|
to the maintainers team. If a maintainer is inactive for more than 3
|
||||||
|
months and forgets to leave the maintainers team, the owners may move
|
||||||
|
him or her from the maintainers team to the advisors team.
|
||||||
|
For security reasons, Maintainers should use 2FA for their accounts and
|
||||||
|
if possible provide GPG signed commits.
|
||||||
|
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
||||||
|
https://help.github.com/articles/signing-commits-with-gpg/
|
||||||
|
|
||||||
|
Furthermore, any account with write access (like bots and TOC members) **must** use 2FA.
|
||||||
|
https://help.github.com/articles/securing-your-account-with-two-factor-authentication-2fa/
|
||||||
|
|
||||||
|
## Technical Oversight Committee (TOC)
|
||||||
|
|
||||||
|
At the start of 2023, the `Owners` team was dissolved. Instead, the governance charter proposed a technical oversight committee (TOC) which expands the ownership team of the Gitea project from three elected positions to six positions. Three positions are elected as it has been over the past years, and the other three consist of appointed members from the Gitea company.
|
||||||
|
https://blog.gitea.com/quarterly-23q1/
|
||||||
|
|
||||||
|
### TOC election process
|
||||||
|
|
||||||
|
Any maintainer is eligible to be part of the community TOC if they are not associated with the Gitea company.
|
||||||
|
A maintainer can either nominate themselves, or can be nominated by other maintainers to be a candidate for the TOC election.
|
||||||
|
If you are nominated by someone else, you must first accept your nomination before the vote starts to be a candidate.
|
||||||
|
|
||||||
|
The TOC is elected for one year, the TOC election happens yearly.
|
||||||
|
After the announcement of the results of the TOC election, elected members have two weeks time to confirm or refuse the seat.
|
||||||
|
If an elected member does not answer within this timeframe, they are automatically assumed to refuse the seat.
|
||||||
|
Refusals result in the person with the next highest vote getting the same choice.
|
||||||
|
As long as seats are empty in the TOC, members of the previous TOC can fill them until an elected member accepts the seat.
|
||||||
|
|
||||||
|
If an elected member that accepts the seat does not have 2FA configured yet, they will be temporarily counted as `answer pending` until they manage to configure 2FA, thus leaving their seat empty for this duration.
|
||||||
|
|
||||||
|
### Current TOC members
|
||||||
|
|
||||||
|
- 2024-01-01 ~ 2024-12-31
|
||||||
|
- Company
|
||||||
|
- [Jason Song](https://gitea.com/wolfogre) <i@wolfogre.com>
|
||||||
|
- [Lunny Xiao](https://gitea.com/lunny) <xiaolunwen@gmail.com>
|
||||||
|
- [Matti Ranta](https://gitea.com/techknowlogick) <techknowlogick@gitea.com>
|
||||||
|
- Community
|
||||||
|
- [6543](https://gitea.com/6543) <6543@obermui.de>
|
||||||
|
- [delvh](https://gitea.com/delvh) <dev.lh@web.de>
|
||||||
|
- [John Olheiser](https://gitea.com/jolheiser) <john.olheiser@gmail.com>
|
||||||
|
|
||||||
|
### Previous TOC/owners members
|
||||||
|
|
||||||
|
Here's the history of the owners and the time they served:
|
||||||
|
|
||||||
|
- [Lunny Xiao](https://gitea.com/lunny) - 2016, 2017, [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
|
||||||
|
- [Kim Carlbäcker](https://github.com/bkcsoft) - 2016, 2017
|
||||||
|
- [Thomas Boerger](https://gitea.com/tboerger) - 2016, 2017
|
||||||
|
- [Lauris Bukšis-Haberkorns](https://gitea.com/lafriks) - [2018](https://github.com/go-gitea/gitea/issues/3255), [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801)
|
||||||
|
- [Matti Ranta](https://gitea.com/techknowlogick) - [2019](https://github.com/go-gitea/gitea/issues/5572), [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
|
||||||
|
- [Andrew Thornton](https://gitea.com/zeripath) - [2020](https://github.com/go-gitea/gitea/issues/9230), [2021](https://github.com/go-gitea/gitea/issues/13801), [2022](https://github.com/go-gitea/gitea/issues/17872), 2023
|
||||||
|
- [6543](https://gitea.com/6543) - 2023
|
||||||
|
- [John Olheiser](https://gitea.com/jolheiser) - 2023
|
||||||
|
- [Jason Song](https://gitea.com/wolfogre) - 2023
|
||||||
|
|
||||||
|
## Governance Compensation
|
||||||
|
|
||||||
|
Each member of the community elected TOC will be granted $500 each month as compensation for their work.
|
||||||
|
|
||||||
|
Furthermore, any community release manager for a specific release or LTS will be compensated $500 for the delivery of said release.
|
||||||
|
|
||||||
|
These funds will come from community sources like the OpenCollective rather than directly from the company.
|
||||||
|
Only non-company members are eligible for this compensation, and if a member of the community TOC takes the responsibility of release manager, they would only be compensated for their TOC duties.
|
||||||
|
Gitea Ltd employees are not eligible to receive any funds from the OpenCollective unless it is reimbursement for a purchase made for the Gitea project itself.
|
||||||
|
|
||||||
|
## TOC & Working groups
|
||||||
|
|
||||||
|
With Gitea covering many projects outside of the main repository, several groups will be created to help focus on specific areas instead of requiring maintainers to be a jack-of-all-trades. Maintainers are of course more than welcome to be part of multiple groups should they wish to contribute in multiple places.
|
||||||
|
|
||||||
|
The currently proposed groups are:
|
||||||
|
|
||||||
|
- **Core Group**: maintain the primary Gitea repository
|
||||||
|
- **Integration Group**: maintain the Gitea ecosystem's related tools, including go-sdk/tea/changelog/bots etc.
|
||||||
|
- **Documentation Group**: maintain related documents and repositories
|
||||||
|
- **Translation Group**: coordinate with translators and maintain translations
|
||||||
|
- **Security Group**: managed by TOC directly, members are decided by TOC, maintains security patches/responsible for security items
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
Each year a roadmap will be discussed with the entire Gitea maintainers team, and feedback will be solicited from various stakeholders.
|
||||||
|
TOC members need to review the roadmap every year and work together on the direction of the project.
|
||||||
|
|
||||||
|
When a vote is required for a proposal or other change, the vote of community elected TOC members count slightly more than the vote of company elected TOC members. With this approach, we both avoid ties and ensure that changes align with the mission statement and community opinion.
|
||||||
|
|
||||||
|
You can visit our roadmap on the wiki.
|
||||||
|
|
||||||
|
## Versions
|
||||||
|
|
||||||
|
Gitea has the `main` branch as a tip branch and has version branches
|
||||||
|
such as `release/v1.19`. `release/v1.19` is a release branch and we will
|
||||||
|
tag `v1.19.0` for binary download. If `v1.19.0` has bugs, we will accept
|
||||||
|
pull requests on the `release/v1.19` branch and publish a `v1.19.1` tag,
|
||||||
|
after bringing the bug fix also to the main branch.
|
||||||
|
|
||||||
|
Since the `main` branch is a tip version, if you wish to use Gitea
|
||||||
|
in production, please download the latest release tag version. All the
|
||||||
|
branches will be protected via GitHub, all the PRs to every branch must
|
||||||
|
be reviewed by two maintainers and must pass the automatic tests.
|
||||||
|
|
||||||
|
## Releasing Gitea
|
||||||
|
|
||||||
|
- Let $vmaj, $vmin and $vpat be Major, Minor and Patch version numbers, $vpat should be rc1, rc2, 0, 1, ...... $vmaj.$vmin will be kept the same as milestones on github or gitea in future.
|
||||||
|
- Before releasing, confirm all the version's milestone issues or PRs has been resolved. Then discuss the release on Discord channel #maintainers and get agreed with almost all the owners and mergers. Or you can declare the version and if nobody is against it in about several hours.
|
||||||
|
- If this is a big version first you have to create PR for changelog on branch `main` with PRs with label `changelog` and after it has been merged do following steps:
|
||||||
|
- Create `-dev` tag as `git tag -s -F release.notes v$vmaj.$vmin.0-dev` and push the tag as `git push origin v$vmaj.$vmin.0-dev`.
|
||||||
|
- When CI has finished building tag then you have to create a new branch named `release/v$vmaj.$vmin`
|
||||||
|
- If it is bugfix version create PR for changelog on branch `release/v$vmaj.$vmin` and wait till it is reviewed and merged.
|
||||||
|
- Add a tag as `git tag -s -F release.notes v$vmaj.$vmin.$`, release.notes file could be a temporary file to only include the changelog this version which you added to `CHANGELOG.md`.
|
||||||
|
- And then push the tag as `git push origin v$vmaj.$vmin.$`. Drone CI will automatically create a release and upload all the compiled binary. (But currently it doesn't add the release notes automatically. Maybe we should fix that.)
|
||||||
|
- If needed send a frontport PR for the changelog to branch `main` and update the version in `docs/config.yaml` to refer to the new version.
|
||||||
|
- Send PR to [blog repository](https://gitea.com/gitea/blog) announcing the release.
|
||||||
|
- Verify all release assets were correctly published through CI on dl.gitea.com and GitHub releases. Once ACKed:
|
||||||
|
- bump the version of https://dl.gitea.com/gitea/version.json
|
||||||
|
- merge the blog post PR
|
||||||
|
- announce the release in discord `#announcements`
|
||||||
|
|||||||
10
Dockerfile
10
Dockerfile
@@ -3,7 +3,7 @@
|
|||||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
|
||||||
RUN apk --no-cache add build-base git nodejs pnpm
|
RUN apk --no-cache add build-base git nodejs pnpm
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
COPY package.json pnpm-lock.yaml .npmrc ./
|
||||||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
|
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
|
||||||
COPY --exclude=.git/ . .
|
COPY --exclude=.git/ . .
|
||||||
RUN make frontend
|
RUN make frontend
|
||||||
@@ -12,7 +12,7 @@ RUN make frontend
|
|||||||
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
|
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
|
||||||
|
|
||||||
ARG GITEA_VERSION
|
ARG GITEA_VERSION
|
||||||
ARG TAGS=""
|
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
ENV TAGS="bindata timetzdata $TAGS"
|
ENV TAGS="bindata timetzdata $TAGS"
|
||||||
ARG CGO_EXTRA_CFLAGS
|
ARG CGO_EXTRA_CFLAGS
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ RUN apk --no-cache add \
|
|||||||
build-base \
|
build-base \
|
||||||
git
|
git
|
||||||
|
|
||||||
WORKDIR ${GOPATH}/src/gitea.dev
|
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
# Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded.
|
# Use COPY instead of bind mount as read-only one breaks makefile state tracking and read-write one needs binary to be moved as it's discarded.
|
||||||
@@ -42,7 +42,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
|
|||||||
/tmp/local/etc/s6/gitea/* \
|
/tmp/local/etc/s6/gitea/* \
|
||||||
/tmp/local/etc/s6/openssh/* \
|
/tmp/local/etc/s6/openssh/* \
|
||||||
/tmp/local/etc/s6/.s6-svscan/* \
|
/tmp/local/etc/s6/.s6-svscan/* \
|
||||||
/go/src/gitea.dev/gitea
|
/go/src/code.gitea.io/gitea/gitea
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.23 AS gitea
|
FROM docker.io/library/alpine:3.23 AS gitea
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ RUN addgroup \
|
|||||||
echo "git:*" | chpasswd -e
|
echo "git:*" | chpasswd -e
|
||||||
|
|
||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
COPY --from=build-env /go/src/gitea.dev/gitea /app/gitea/gitea
|
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
|
|
||||||
ENV USER=git
|
ENV USER=git
|
||||||
ENV GITEA_CUSTOM=/data/gitea
|
ENV GITEA_CUSTOM=/data/gitea
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
|
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.26-alpine3.23 AS frontend-build
|
||||||
RUN apk --no-cache add build-base git nodejs pnpm
|
RUN apk --no-cache add build-base git nodejs pnpm
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
COPY package.json pnpm-lock.yaml .npmrc ./
|
||||||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
|
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
|
||||||
COPY --exclude=.git/ . .
|
COPY --exclude=.git/ . .
|
||||||
RUN make frontend
|
RUN make frontend
|
||||||
@@ -12,7 +12,7 @@ RUN make frontend
|
|||||||
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
|
FROM docker.io/library/golang:1.26-alpine3.23 AS build-env
|
||||||
|
|
||||||
ARG GITEA_VERSION
|
ARG GITEA_VERSION
|
||||||
ARG TAGS=""
|
ARG TAGS="sqlite sqlite_unlock_notify"
|
||||||
ENV TAGS="bindata timetzdata $TAGS"
|
ENV TAGS="bindata timetzdata $TAGS"
|
||||||
ARG CGO_EXTRA_CFLAGS
|
ARG CGO_EXTRA_CFLAGS
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ RUN apk --no-cache add \
|
|||||||
build-base \
|
build-base \
|
||||||
git
|
git
|
||||||
|
|
||||||
WORKDIR ${GOPATH}/src/gitea.dev
|
WORKDIR ${GOPATH}/src/code.gitea.io/gitea
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
# See the comments in Dockerfile
|
# See the comments in Dockerfile
|
||||||
@@ -37,7 +37,7 @@ COPY docker/rootless /tmp/local
|
|||||||
|
|
||||||
# Set permissions for builds that made under windows which strips the executable bit from file
|
# Set permissions for builds that made under windows which strips the executable bit from file
|
||||||
RUN chmod 755 /tmp/local/usr/local/bin/* \
|
RUN chmod 755 /tmp/local/usr/local/bin/* \
|
||||||
/go/src/gitea.dev/gitea
|
/go/src/code.gitea.io/gitea/gitea
|
||||||
|
|
||||||
FROM docker.io/library/alpine:3.23 AS gitea-rootless
|
FROM docker.io/library/alpine:3.23 AS gitea-rootless
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ RUN mkdir -p /var/lib/gitea /etc/gitea
|
|||||||
RUN chown git:git /var/lib/gitea /etc/gitea
|
RUN chown git:git /var/lib/gitea /etc/gitea
|
||||||
|
|
||||||
COPY --from=build-env /tmp/local /
|
COPY --from=build-env /tmp/local /
|
||||||
COPY --from=build-env --chown=root:root /go/src/gitea.dev/gitea /app/gitea/gitea
|
COPY --from=build-env --chown=root:root /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||||
|
|
||||||
# git:git
|
# git:git
|
||||||
USER 1000:1000
|
USER 1000:1000
|
||||||
|
|||||||
395
Makefile
395
Makefile
@@ -7,44 +7,33 @@ export GOEXPERIMENT ?= jsonv2
|
|||||||
|
|
||||||
GO ?= go
|
GO ?= go
|
||||||
SHASUM ?= shasum -a 256
|
SHASUM ?= shasum -a 256
|
||||||
|
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
|
||||||
COMMA := ,
|
COMMA := ,
|
||||||
|
|
||||||
XGO_VERSION := go-1.26.x
|
XGO_VERSION := go-1.25.x
|
||||||
|
|
||||||
AIR_PACKAGE ?= github.com/air-verse/air@v1.65.2 # renovate: datasource=go
|
AIR_PACKAGE ?= github.com/air-verse/air@v1
|
||||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3.6.1 # renovate: datasource=go
|
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 # renovate: datasource=go
|
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2
|
||||||
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15 # renovate: datasource=go
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.11.4
|
||||||
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0 # renovate: datasource=go
|
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.2 # renovate: datasource=go
|
MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@v1.9.0 # renovate: datasource=go
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1
|
||||||
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1.3.0 # renovate: datasource=go
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.12 # renovate: datasource=go
|
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
|
||||||
SHELLCHECK_IMAGE ?= docker.io/koalaman/shellcheck:v0.11.0@sha256:61862eba1fcf09a484ebcc6feea46f1782532571a34ed51fedf90dd25f925a8d # renovate: datasource=docker
|
ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11
|
||||||
|
|
||||||
CONTAINER_RUNTIME ?= $(shell hash docker >/dev/null 2>&1 && echo docker || echo podman)
|
DOCKER_IMAGE ?= gitea/gitea
|
||||||
|
DOCKER_TAG ?= latest
|
||||||
|
DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
|
||||||
|
|
||||||
HAS_GO := $(shell hash $(GO) > /dev/null 2>&1 && echo yes)
|
|
||||||
ifeq ($(HAS_GO), yes)
|
ifeq ($(HAS_GO), yes)
|
||||||
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
CGO_EXTRA_CFLAGS := -DSQLITE_MAX_VARIABLE_NUMBER=32766
|
||||||
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
CGO_CFLAGS ?= $(shell $(GO) env CGO_CFLAGS) $(CGO_EXTRA_CFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
MAKE_EVIDENCE_DIR := .make_evidence
|
|
||||||
|
|
||||||
# Use sqlite as default database if running tests, only do so for local tests, not in CI.
|
|
||||||
# CI should explicitly set the database to avoid unexpected results.
|
|
||||||
ifneq ($(findstring test-,$(MAKECMDGOALS)),)
|
|
||||||
ifeq ($(CI),)
|
|
||||||
GITEA_TEST_DATABASE ?= sqlite
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
TAGS ?=
|
|
||||||
TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
|
|
||||||
|
|
||||||
CGO_ENABLED ?= 0
|
CGO_ENABLED ?= 0
|
||||||
ifneq (,$(findstring sqlite_mattn,$(TAGS))$(findstring pam,$(TAGS)))
|
ifneq (,$(findstring sqlite,$(TAGS))$(findstring pam,$(TAGS)))
|
||||||
CGO_ENABLED = 1
|
CGO_ENABLED = 1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -61,16 +50,15 @@ else ifeq ($(patsubst Windows%,Windows,$(OS)),Windows)
|
|||||||
IS_WINDOWS := yes
|
IS_WINDOWS := yes
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# GOFLAGS and EXTRA_GOFLAGS are for the 'go build' command only
|
|
||||||
ifeq ($(IS_WINDOWS),yes)
|
ifeq ($(IS_WINDOWS),yes)
|
||||||
GOFLAGS := -v -buildmode=exe
|
GOFLAGS := -v -buildmode=exe
|
||||||
EXECUTABLE ?= gitea.exe
|
EXECUTABLE ?= gitea.exe
|
||||||
|
EXECUTABLE_E2E ?= gitea-e2e.exe
|
||||||
else
|
else
|
||||||
GOFLAGS := -v
|
GOFLAGS := -v
|
||||||
EXECUTABLE ?= gitea
|
EXECUTABLE ?= gitea
|
||||||
|
EXECUTABLE_E2E ?= gitea-e2e
|
||||||
endif
|
endif
|
||||||
EXTRA_GOFLAGS ?=
|
|
||||||
|
|
||||||
ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu)
|
ifeq ($(shell sed --version 2>/dev/null | grep -q GNU && echo gnu),gnu)
|
||||||
SED_INPLACE := sed -i
|
SED_INPLACE := sed -i
|
||||||
@@ -78,8 +66,15 @@ else
|
|||||||
SED_INPLACE := sed -i ''
|
SED_INPLACE := sed -i ''
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# GOTEST_FLAGS is for unit test and integration test
|
EXTRA_GOFLAGS ?=
|
||||||
GOTEST_FLAGS ?= -timeout 40m
|
|
||||||
|
MAKE_EVIDENCE_DIR := .make_evidence
|
||||||
|
|
||||||
|
GOTESTFLAGS ?=
|
||||||
|
ifeq ($(RACE_ENABLED),true)
|
||||||
|
GOFLAGS += -race
|
||||||
|
GOTESTFLAGS += -race
|
||||||
|
endif
|
||||||
|
|
||||||
STORED_VERSION_FILE := VERSION
|
STORED_VERSION_FILE := VERSION
|
||||||
|
|
||||||
@@ -113,8 +108,8 @@ LDFLAGS := $(LDFLAGS) -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
|||||||
|
|
||||||
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/riscv64
|
LINUX_ARCHS ?= linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/riscv64
|
||||||
|
|
||||||
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list gitea.dev/models/migrations/...) gitea.dev/tests/integration/migration-test gitea.dev/tests gitea.dev/tests/integration,$(shell $(GO) list ./... | grep -v /vendor/))
|
GO_TEST_PACKAGES ?= $(filter-out $(shell $(GO) list code.gitea.io/gitea/models/migrations/...) code.gitea.io/gitea/tests/integration/migration-test code.gitea.io/gitea/tests code.gitea.io/gitea/tests/integration,$(shell $(GO) list ./... | grep -v /vendor/))
|
||||||
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list gitea.dev/models/migrations/...)
|
MIGRATE_TEST_PACKAGES ?= $(shell $(GO) list code.gitea.io/gitea/models/migrations/...)
|
||||||
|
|
||||||
FRONTEND_SOURCES := $(shell find web_src/js web_src/css -type f)
|
FRONTEND_SOURCES := $(shell find web_src/js web_src/css -type f)
|
||||||
FRONTEND_CONFIGS := vite.config.ts tailwind.config.ts
|
FRONTEND_CONFIGS := vite.config.ts tailwind.config.ts
|
||||||
@@ -132,6 +127,12 @@ AIR_TMP_DIR := .air
|
|||||||
|
|
||||||
GO_LICENSE_FILE := assets/go-licenses.json
|
GO_LICENSE_FILE := assets/go-licenses.json
|
||||||
|
|
||||||
|
TAGS ?=
|
||||||
|
TAGS_SPLIT := $(subst $(COMMA), ,$(TAGS))
|
||||||
|
TAGS_EVIDENCE := $(MAKE_EVIDENCE_DIR)/tags
|
||||||
|
|
||||||
|
TEST_TAGS ?= $(TAGS_SPLIT) sqlite sqlite_unlock_notify
|
||||||
|
|
||||||
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR)
|
TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST) $(MAKE_EVIDENCE_DIR) $(AIR_TMP_DIR)
|
||||||
|
|
||||||
GO_DIRS := build cmd models modules routers services tests tools
|
GO_DIRS := build cmd models modules routers services tests tools
|
||||||
@@ -151,7 +152,6 @@ ESLINT_CONCURRENCY ?= 2
|
|||||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||||
SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
|
SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
|
||||||
SWAGGER_EXCLUDE := code.gitea.io/sdk
|
SWAGGER_EXCLUDE := code.gitea.io/sdk
|
||||||
OPENAPI3_SPEC := templates/swagger/v1_openapi3_json.tmpl
|
|
||||||
|
|
||||||
TEST_MYSQL_HOST ?= mysql:3306
|
TEST_MYSQL_HOST ?= mysql:3306
|
||||||
TEST_MYSQL_DBNAME ?= testgitea
|
TEST_MYSQL_DBNAME ?= testgitea
|
||||||
@@ -164,19 +164,13 @@ TEST_PGSQL_PASSWORD ?= postgres
|
|||||||
TEST_PGSQL_SCHEMA ?= gtestschema
|
TEST_PGSQL_SCHEMA ?= gtestschema
|
||||||
TEST_MINIO_ENDPOINT ?= minio:9000
|
TEST_MINIO_ENDPOINT ?= minio:9000
|
||||||
TEST_MSSQL_HOST ?= mssql:1433
|
TEST_MSSQL_HOST ?= mssql:1433
|
||||||
TEST_MSSQL_DBNAME ?= testgitea
|
TEST_MSSQL_DBNAME ?= gitea
|
||||||
TEST_MSSQL_USERNAME ?= sa
|
TEST_MSSQL_USERNAME ?= sa
|
||||||
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
|
||||||
|
|
||||||
# Include local Makefile
|
# Include local Makefile
|
||||||
# Makefile.local is listed in .gitignore
|
# Makefile.local is listed in .gitignore
|
||||||
ifneq ("$(wildcard Makefile.local)","")
|
sinclude Makefile.local
|
||||||
include Makefile.local
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(foreach v, $(filter TEST_%, $(.VARIABLES)), $(eval MAKEFILE_VARS+=$v=$($v)))
|
|
||||||
$(foreach v, $(filter GITEA_TEST_%, $(.VARIABLES)), $(eval MAKEFILE_VARS+=$v=$($v)))
|
|
||||||
export MAKEFILE_VARS
|
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: build
|
all: build
|
||||||
@@ -185,8 +179,15 @@ all: build
|
|||||||
help: Makefile ## print Makefile help information.
|
help: Makefile ## print Makefile help information.
|
||||||
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m[TARGETS] default target: build\033[0m\n\n\033[35mTargets:\033[0m\n"} /^[0-9A-Za-z._-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 }' Makefile #$(MAKEFILE_LIST)
|
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m[TARGETS] default target: build\033[0m\n\n\033[35mTargets:\033[0m\n"} /^[0-9A-Za-z._-]+:.*?##/ { printf " \033[36m%-45s\033[0m %s\n", $$1, $$2 }' Makefile #$(MAKEFILE_LIST)
|
||||||
@printf " \033[36m%-46s\033[0m %s\n" "test-e2e" "test end to end using playwright"
|
@printf " \033[36m%-46s\033[0m %s\n" "test-e2e" "test end to end using playwright"
|
||||||
@printf " \033[36m%-46s\033[0m %s\n" "test-backend[#TestSpecificName]" "run unit test (sqlite only)"
|
@printf " \033[36m%-46s\033[0m %s\n" "test[#TestSpecificName]" "run unit test"
|
||||||
@printf " \033[36m%-46s\033[0m %s\n" "test-integration[#TestSpecificName]" "run integration test for GITEA_TEST_DATABASE (sqlite, mysql, pgsql, mssql)"
|
@printf " \033[36m%-46s\033[0m %s\n" "test-sqlite[#TestSpecificName]" "run integration test for sqlite"
|
||||||
|
|
||||||
|
.PHONY: git-check
|
||||||
|
git-check:
|
||||||
|
@if git lfs >/dev/null 2>&1 ; then : ; else \
|
||||||
|
echo "Gitea requires git with lfs support to run tests." ; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
.PHONY: clean-all
|
.PHONY: clean-all
|
||||||
clean-all: clean ## delete backend, frontend and integration files
|
clean-all: clean ## delete backend, frontend and integration files
|
||||||
@@ -194,12 +195,18 @@ clean-all: clean ## delete backend, frontend and integration files
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: ## delete backend and integration files
|
clean: ## delete backend and integration files
|
||||||
rm -f $(EXECUTABLE) test-*.test tests/*.ini
|
rm -rf $(EXECUTABLE) $(EXECUTABLE_E2E) $(DIST) $(BINDATA_DEST_WILDCARD) \
|
||||||
rm -rf $(DIST) $(BINDATA_DEST_WILDCARD) man tests/integration/gitea-integration-*
|
integrations*.test \
|
||||||
|
tests/integration/gitea-integration-* \
|
||||||
|
tests/integration/indexers-* \
|
||||||
|
tests/sqlite.ini tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \
|
||||||
|
tests/e2e/gitea-e2e-*/ \
|
||||||
|
tests/e2e/indexers-*/ \
|
||||||
|
tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/
|
||||||
|
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt: ## format the Go and template code
|
fmt: ## format the Go and template code
|
||||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) fmt
|
@GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run tools/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||||
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
$(eval TEMPLATES := $(shell find templates -type f -name '*.tmpl'))
|
||||||
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
@# strip whitespace after '{{' or '(' and before '}}' or ')' unless there is only
|
||||||
@# whitespace before it
|
@# whitespace before it
|
||||||
@@ -227,7 +234,7 @@ TAGS_PREREQ := $(TAGS_EVIDENCE)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: generate-swagger
|
.PHONY: generate-swagger
|
||||||
generate-swagger: $(SWAGGER_SPEC) $(OPENAPI3_SPEC) ## generate the swagger spec from code comments
|
generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
|
||||||
|
|
||||||
$(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT)
|
$(SWAGGER_SPEC): $(GO_SOURCES) $(SWAGGER_SPEC_INPUT)
|
||||||
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
|
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
|
||||||
@@ -249,21 +256,6 @@ swagger-validate: ## check if the swagger spec is valid
|
|||||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||||
@$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath
|
@$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath
|
||||||
|
|
||||||
.PHONY: generate-openapi3
|
|
||||||
generate-openapi3: $(OPENAPI3_SPEC) ## generate the OpenAPI 3.0 spec from the Swagger 2.0 spec
|
|
||||||
|
|
||||||
$(OPENAPI3_SPEC): $(SWAGGER_SPEC) build/generate-openapi.go $(wildcard build/openapi3gen/*.go)
|
|
||||||
$(GO) run build/generate-openapi.go
|
|
||||||
|
|
||||||
.PHONY: openapi3-check
|
|
||||||
openapi3-check: generate-openapi3
|
|
||||||
@diff=$$(git diff --color=always '$(OPENAPI3_SPEC)'); \
|
|
||||||
if [ -n "$$diff" ]; then \
|
|
||||||
echo "Please run 'make generate-openapi3' and commit the result:"; \
|
|
||||||
printf "%s" "$${diff}"; \
|
|
||||||
exit 1; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
.PHONY: checks
|
.PHONY: checks
|
||||||
checks: checks-frontend checks-backend ## run various consistency checks
|
checks: checks-frontend checks-backend ## run various consistency checks
|
||||||
|
|
||||||
@@ -271,10 +263,10 @@ checks: checks-frontend checks-backend ## run various consistency checks
|
|||||||
checks-frontend: lockfile-check svg-check ## check frontend files
|
checks-frontend: lockfile-check svg-check ## check frontend files
|
||||||
|
|
||||||
.PHONY: checks-backend
|
.PHONY: checks-backend
|
||||||
checks-backend: tidy-check swagger-check openapi3-check fmt-check swagger-validate security-check ## check backend files
|
checks-backend: tidy-check swagger-check fmt-check swagger-validate security-check ## check backend files
|
||||||
|
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint: lint-frontend lint-backend lint-templates lint-swagger lint-spell lint-md lint-actions lint-json lint-yaml lint-shell ## lint everything
|
lint: lint-frontend lint-backend lint-spell ## lint everything
|
||||||
|
|
||||||
.PHONY: lint-fix
|
.PHONY: lint-fix
|
||||||
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues
|
lint-fix: lint-frontend-fix lint-backend-fix lint-spell-fix ## lint everything and fix issues
|
||||||
@@ -286,10 +278,10 @@ lint-frontend: lint-js lint-css ## lint frontend files
|
|||||||
lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues
|
lint-frontend-fix: lint-js-fix lint-css-fix ## lint frontend files and fix issues
|
||||||
|
|
||||||
.PHONY: lint-backend
|
.PHONY: lint-backend
|
||||||
lint-backend: lint-go lint-editorconfig ## lint backend files
|
lint-backend: lint-go lint-go-gitea-vet lint-editorconfig ## lint backend files
|
||||||
|
|
||||||
.PHONY: lint-backend-fix
|
.PHONY: lint-backend-fix
|
||||||
lint-backend-fix: lint-go-fix lint-editorconfig ## lint backend files and fix issues
|
lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backend files and fix issues
|
||||||
|
|
||||||
.PHONY: lint-js
|
.PHONY: lint-js
|
||||||
lint-js: node_modules ## lint js and ts files
|
lint-js: node_modules ## lint js and ts files
|
||||||
@@ -331,11 +323,23 @@ lint-spell-fix: ## lint spelling and fix issues
|
|||||||
|
|
||||||
.PHONY: lint-go
|
.PHONY: lint-go
|
||||||
lint-go: ## lint go files
|
lint-go: ## lint go files
|
||||||
GO=$(GO) GOLANGCI_LINT_PACKAGE=$(GOLANGCI_LINT_PACKAGE) $(GO) run ./tools/lint-go-all.go
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||||
|
|
||||||
.PHONY: lint-go-fix
|
.PHONY: lint-go-fix
|
||||||
lint-go-fix: ## lint go files and fix issues
|
lint-go-fix: ## lint go files and fix issues
|
||||||
GO=$(GO) GOLANGCI_LINT_PACKAGE=$(GOLANGCI_LINT_PACKAGE) $(GO) run ./tools/lint-go-all.go --fix
|
$(GO) run $(GOLANGCI_LINT_PACKAGE) run --fix
|
||||||
|
|
||||||
|
# workaround step for the lint-go-windows CI task because 'go run' can not
|
||||||
|
# have distinct GOOS/GOARCH for its build and run steps
|
||||||
|
.PHONY: lint-go-windows
|
||||||
|
lint-go-windows:
|
||||||
|
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
.PHONY: lint-go-gitea-vet
|
||||||
|
lint-go-gitea-vet: ## lint go files with gitea-vet
|
||||||
|
@echo "Running gitea-vet..."
|
||||||
|
@$(GO) vet -vettool="$(shell GOOS= GOARCH= go tool -n gitea-vet)" ./...
|
||||||
|
|
||||||
.PHONY: lint-editorconfig
|
.PHONY: lint-editorconfig
|
||||||
lint-editorconfig:
|
lint-editorconfig:
|
||||||
@@ -343,13 +347,8 @@ lint-editorconfig:
|
|||||||
@$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES)
|
@$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES)
|
||||||
|
|
||||||
.PHONY: lint-actions
|
.PHONY: lint-actions
|
||||||
lint-actions: .venv ## lint action workflow files
|
lint-actions: ## lint action workflow files
|
||||||
@$(GO) run $(ACTIONLINT_PACKAGE)
|
$(GO) run $(ACTIONLINT_PACKAGE)
|
||||||
@uv run --frozen zizmor --quiet --min-confidence=medium .github
|
|
||||||
|
|
||||||
.PHONY: lint-shell
|
|
||||||
lint-shell: ## lint shell scripts
|
|
||||||
@SHELLCHECK_IMAGE=$(SHELLCHECK_IMAGE) CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/lint-shell.sh $$(git ls-files '*.sh')
|
|
||||||
|
|
||||||
.PHONY: lint-templates
|
.PHONY: lint-templates
|
||||||
lint-templates: .venv node_modules ## lint template files
|
lint-templates: .venv node_modules ## lint template files
|
||||||
@@ -380,10 +379,13 @@ watch-frontend: node_modules ## start vite dev server for frontend
|
|||||||
watch-backend: ## watch backend files and continuously rebuild
|
watch-backend: ## watch backend files and continuously rebuild
|
||||||
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
|
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: test-frontend test-backend ## test everything
|
||||||
|
|
||||||
.PHONY: test-backend
|
.PHONY: test-backend
|
||||||
test-backend: ## test backend files
|
test-backend: ## test backend files
|
||||||
@echo "Running go test with $(GOTEST_FLAGS) -tags '$(TAGS)'..."
|
@echo "Running go test with $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
|
||||||
@$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $(GO_TEST_PACKAGES)
|
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' $(GO_TEST_PACKAGES)
|
||||||
|
|
||||||
.PHONY: test-frontend
|
.PHONY: test-frontend
|
||||||
test-frontend: node_modules ## test frontend files
|
test-frontend: node_modules ## test frontend files
|
||||||
@@ -401,10 +403,10 @@ test-check:
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
.PHONY: test-backend\#%
|
.PHONY: test\#%
|
||||||
test-backend\#%:
|
test\#%:
|
||||||
@echo "Running go test with -tags '$(TAGS)'..."
|
@echo "Running go test with -tags '$(TEST_TAGS)'..."
|
||||||
@$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
@$(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -run $(subst .,/,$*) $(GO_TEST_PACKAGES)
|
||||||
|
|
||||||
.PHONY: coverage
|
.PHONY: coverage
|
||||||
coverage:
|
coverage:
|
||||||
@@ -414,8 +416,8 @@ coverage:
|
|||||||
|
|
||||||
.PHONY: unit-test-coverage
|
.PHONY: unit-test-coverage
|
||||||
unit-test-coverage:
|
unit-test-coverage:
|
||||||
@echo "Running unit-test-coverage $(GOTEST_FLAGS) -tags '$(TAGS)'..."
|
@echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..."
|
||||||
@$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
@$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_TEST_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
||||||
|
|
||||||
.PHONY: tidy
|
.PHONY: tidy
|
||||||
tidy: ## run go mod tidy
|
tidy: ## run go mod tidy
|
||||||
@@ -442,45 +444,193 @@ go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses
|
|||||||
$(GO_LICENSE_FILE): go.mod go.sum
|
$(GO_LICENSE_FILE): go.mod go.sum
|
||||||
GO=$(GO) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_FILE)
|
GO=$(GO) $(GO) run build/generate-go-licenses.go $(GO_LICENSE_FILE)
|
||||||
|
|
||||||
.PHONY: test-integration
|
generate-ini-sqlite:
|
||||||
test-integration:
|
sed -e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-sqlite|g' \
|
||||||
@# Use a compiled binary: testlogger forwards gitea logs to t.Log, so `go test -v`
|
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||||
@# would flood output per passing test. testcache can't help these tests anyway —
|
tests/sqlite.ini.tmpl > tests/sqlite.ini
|
||||||
@# they mutate the work directory, so cache inputs change between runs.
|
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -c gitea.dev/tests/integration -o ./test-integration-$(GITEA_TEST_DATABASE).test
|
|
||||||
./tools/test-integration.sh ./test-integration-$(GITEA_TEST_DATABASE).test
|
|
||||||
|
|
||||||
.PHONY: test-integration-compile
|
.PHONY: test-sqlite
|
||||||
test-integration-compile:
|
test-sqlite: integrations.sqlite.test generate-ini-sqlite
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -c -o /dev/null gitea.dev/tests/integration
|
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test
|
||||||
|
|
||||||
.PHONY: test-integration\#%
|
.PHONY: test-sqlite\#%
|
||||||
test-integration\#%:
|
test-sqlite\#%: integrations.sqlite.test generate-ini-sqlite
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -run $(subst .,/,$*) gitea.dev/tests/integration
|
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.run $(subst .,/,$*)
|
||||||
|
|
||||||
.PHONY: test-migration
|
.PHONY: test-sqlite-migration
|
||||||
test-migration: migrations.integration.test migrations.individual.test
|
test-sqlite-migration: migrations.sqlite.test migrations.individual.sqlite.test
|
||||||
|
|
||||||
.PHONY: migrations.integration.test
|
generate-ini-mysql:
|
||||||
migrations.integration.test:
|
sed -e 's|{{TEST_MYSQL_HOST}}|${TEST_MYSQL_HOST}|g' \
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' gitea.dev/tests/integration/migration-test
|
-e 's|{{TEST_MYSQL_DBNAME}}|${TEST_MYSQL_DBNAME}|g' \
|
||||||
|
-e 's|{{TEST_MYSQL_USERNAME}}|${TEST_MYSQL_USERNAME}|g' \
|
||||||
|
-e 's|{{TEST_MYSQL_PASSWORD}}|${TEST_MYSQL_PASSWORD}|g' \
|
||||||
|
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mysql|g' \
|
||||||
|
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||||
|
tests/mysql.ini.tmpl > tests/mysql.ini
|
||||||
|
|
||||||
.PHONY: migrations.individual.test
|
.PHONY: test-mysql
|
||||||
migrations.individual.test:
|
test-mysql: integrations.mysql.test generate-ini-mysql
|
||||||
@# tests of multiple packages use the same database, don't run in parallel
|
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
|
||||||
|
|
||||||
.PHONY: migrations.individual.test\#%
|
.PHONY: test-mysql\#%
|
||||||
migrations.individual.test\#%:
|
test-mysql\#%: integrations.mysql.test generate-ini-mysql
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags '$(TAGS)' gitea.dev/models/migrations/$*
|
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.run $(subst .,/,$*)
|
||||||
|
|
||||||
|
.PHONY: test-mysql-migration
|
||||||
|
test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test
|
||||||
|
|
||||||
|
generate-ini-pgsql:
|
||||||
|
sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \
|
||||||
|
-e 's|{{TEST_PGSQL_DBNAME}}|${TEST_PGSQL_DBNAME}|g' \
|
||||||
|
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
|
||||||
|
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
|
||||||
|
-e 's|{{TEST_PGSQL_SCHEMA}}|${TEST_PGSQL_SCHEMA}|g' \
|
||||||
|
-e 's|{{TEST_MINIO_ENDPOINT}}|${TEST_MINIO_ENDPOINT}|g' \
|
||||||
|
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-pgsql|g' \
|
||||||
|
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||||
|
tests/pgsql.ini.tmpl > tests/pgsql.ini
|
||||||
|
|
||||||
|
.PHONY: test-pgsql
|
||||||
|
test-pgsql: integrations.pgsql.test generate-ini-pgsql
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test
|
||||||
|
|
||||||
|
.PHONY: test-pgsql\#%
|
||||||
|
test-pgsql\#%: integrations.pgsql.test generate-ini-pgsql
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.run $(subst .,/,$*)
|
||||||
|
|
||||||
|
.PHONY: test-pgsql-migration
|
||||||
|
test-pgsql-migration: migrations.pgsql.test migrations.individual.pgsql.test
|
||||||
|
|
||||||
|
generate-ini-mssql:
|
||||||
|
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
|
||||||
|
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
|
||||||
|
-e 's|{{WORK_PATH}}|$(CURDIR)/tests/$(or $(TEST_TYPE),integration)/gitea-$(or $(TEST_TYPE),integration)-mssql|g' \
|
||||||
|
-e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \
|
||||||
|
tests/mssql.ini.tmpl > tests/mssql.ini
|
||||||
|
|
||||||
|
.PHONY: test-mssql
|
||||||
|
test-mssql: integrations.mssql.test generate-ini-mssql
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test
|
||||||
|
|
||||||
|
.PHONY: test-mssql\#%
|
||||||
|
test-mssql\#%: integrations.mssql.test generate-ini-mssql
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.run $(subst .,/,$*)
|
||||||
|
|
||||||
|
.PHONY: test-mssql-migration
|
||||||
|
test-mssql-migration: migrations.mssql.test migrations.individual.mssql.test
|
||||||
|
|
||||||
.PHONY: playwright
|
.PHONY: playwright
|
||||||
playwright: deps-frontend
|
playwright: deps-frontend
|
||||||
@CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) ./tools/test-e2e.sh install
|
@# on GitHub Actions VMs, playwright's system deps are pre-installed
|
||||||
|
@pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium firefox $(PLAYWRIGHT_FLAGS)
|
||||||
|
|
||||||
.PHONY: test-e2e
|
.PHONY: test-e2e
|
||||||
test-e2e: playwright frontend backend
|
test-e2e: playwright $(EXECUTABLE_E2E)
|
||||||
@CONTAINER_RUNTIME=$(CONTAINER_RUNTIME) EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh run $(GITEA_TEST_E2E_FLAGS)
|
@EXECUTABLE=$(EXECUTABLE_E2E) ./tools/test-e2e.sh $(GITEA_TEST_E2E_FLAGS)
|
||||||
|
|
||||||
|
.PHONY: bench-sqlite
|
||||||
|
bench-sqlite: integrations.sqlite.test generate-ini-sqlite
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
||||||
|
.PHONY: bench-mysql
|
||||||
|
bench-mysql: integrations.mysql.test generate-ini-mysql
|
||||||
|
GITEA_TEST_CONF=tests/mysql.ini ./integrations.mysql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
||||||
|
.PHONY: bench-mssql
|
||||||
|
bench-mssql: integrations.mssql.test generate-ini-mssql
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini ./integrations.mssql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
||||||
|
.PHONY: bench-pgsql
|
||||||
|
bench-pgsql: integrations.pgsql.test generate-ini-pgsql
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini ./integrations.pgsql.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
|
||||||
|
|
||||||
|
.PHONY: integration-test-coverage
|
||||||
|
integration-test-coverage: integrations.cover.test generate-ini-mysql
|
||||||
|
GITEA_TEST_CONF=tests/mysql.ini ./integrations.cover.test -test.coverprofile=integration.coverage.out
|
||||||
|
|
||||||
|
.PHONY: integration-test-coverage-sqlite
|
||||||
|
integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sqlite
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini ./integrations.cover.sqlite.test -test.coverprofile=integration.coverage.out
|
||||||
|
|
||||||
|
integrations.mysql.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test
|
||||||
|
|
||||||
|
integrations.pgsql.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test
|
||||||
|
|
||||||
|
integrations.mssql.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mssql.test
|
||||||
|
|
||||||
|
integrations.sqlite.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
|
||||||
|
integrations.cover.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.test
|
||||||
|
|
||||||
|
integrations.cover.sqlite.test: git-check $(GO_SOURCES)
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -coverpkg $(shell echo $(GO_TEST_PACKAGES) | tr ' ' ',') -o integrations.cover.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
|
||||||
|
.PHONY: migrations.mysql.test
|
||||||
|
migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test
|
||||||
|
GITEA_TEST_CONF=tests/mysql.ini ./migrations.mysql.test
|
||||||
|
|
||||||
|
.PHONY: migrations.pgsql.test
|
||||||
|
migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini ./migrations.pgsql.test
|
||||||
|
|
||||||
|
.PHONY: migrations.mssql.test
|
||||||
|
migrations.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mssql.test
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini ./migrations.mssql.test
|
||||||
|
|
||||||
|
.PHONY: migrations.sqlite.test
|
||||||
|
migrations.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||||
|
$(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.sqlite.test -tags '$(TEST_TAGS)'
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini ./migrations.sqlite.test
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.mysql.test
|
||||||
|
migrations.individual.mysql.test: $(GO_SOURCES) generate-ini-mysql
|
||||||
|
GITEA_TEST_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.sqlite.test\#%
|
||||||
|
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.pgsql.test
|
||||||
|
migrations.individual.pgsql.test: $(GO_SOURCES) generate-ini-pgsql
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.pgsql.test\#%
|
||||||
|
migrations.individual.pgsql.test\#%: $(GO_SOURCES) generate-ini-pgsql
|
||||||
|
GITEA_TEST_CONF=tests/pgsql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.mssql.test
|
||||||
|
migrations.individual.mssql.test: $(GO_SOURCES) generate-ini-mssql
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.mssql.test\#%
|
||||||
|
migrations.individual.mssql.test\#%: $(GO_SOURCES) generate-ini-mssql
|
||||||
|
GITEA_TEST_CONF=tests/mssql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.sqlite.test
|
||||||
|
migrations.individual.sqlite.test: $(GO_SOURCES) generate-ini-sqlite
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags='$(TEST_TAGS)' -p 1 $(MIGRATE_TEST_PACKAGES)
|
||||||
|
|
||||||
|
.PHONY: migrations.individual.sqlite.test\#%
|
||||||
|
migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite
|
||||||
|
GITEA_TEST_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$*
|
||||||
|
|
||||||
|
.PHONY: check
|
||||||
|
check: test
|
||||||
|
|
||||||
|
.PHONY: install $(TAGS_PREREQ)
|
||||||
|
install: $(wildcard *.go)
|
||||||
|
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) install -v -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)'
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: frontend backend ## build everything
|
build: frontend backend ## build everything
|
||||||
@@ -513,6 +663,9 @@ ifneq ($(and $(STATIC),$(findstring pam,$(TAGS))),)
|
|||||||
endif
|
endif
|
||||||
CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
|
CGO_ENABLED="$(CGO_ENABLED)" CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
|
||||||
|
|
||||||
|
$(EXECUTABLE_E2E): $(GO_SOURCES) $(FRONTEND_DEST)
|
||||||
|
CGO_ENABLED=1 $(GO) build $(GOFLAGS) $(EXTRA_GOFLAGS) -tags '$(TEST_TAGS)' -ldflags '-s -w $(EXTLDFLAGS) $(LDFLAGS)' -o $@
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
|
release: frontend generate release-windows release-linux release-darwin release-freebsd release-copy release-compress vendor release-sources release-check
|
||||||
|
|
||||||
@@ -577,6 +730,7 @@ deps-backend: ## install backend dependencies
|
|||||||
deps-tools: ## install tool dependencies
|
deps-tools: ## install tool dependencies
|
||||||
$(GO) install $(AIR_PACKAGE) & \
|
$(GO) install $(AIR_PACKAGE) & \
|
||||||
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \
|
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE) & \
|
||||||
|
$(GO) install $(GOFUMPT_PACKAGE) & \
|
||||||
$(GO) install $(GOLANGCI_LINT_PACKAGE) & \
|
$(GO) install $(GOLANGCI_LINT_PACKAGE) & \
|
||||||
$(GO) install $(GXZ_PACKAGE) & \
|
$(GO) install $(GXZ_PACKAGE) & \
|
||||||
$(GO) install $(MISSPELL_PACKAGE) & \
|
$(GO) install $(MISSPELL_PACKAGE) & \
|
||||||
@@ -607,13 +761,7 @@ update-js: node_modules ## update js dependencies
|
|||||||
pnpm exec updates -u -f package.json
|
pnpm exec updates -u -f package.json
|
||||||
rm -rf node_modules pnpm-lock.yaml
|
rm -rf node_modules pnpm-lock.yaml
|
||||||
pnpm install
|
pnpm install
|
||||||
@touch node_modules
|
|
||||||
$(MAKE) --no-print-directory nolyfill
|
|
||||||
|
|
||||||
.PHONY: nolyfill
|
|
||||||
nolyfill: node_modules ## apply nolyfill overrides to package.json and relock
|
|
||||||
pnpm exec nolyfill install
|
pnpm exec nolyfill install
|
||||||
node tools/migrate-nolyfills.ts
|
|
||||||
pnpm install
|
pnpm install
|
||||||
@touch node_modules
|
@touch node_modules
|
||||||
|
|
||||||
@@ -668,10 +816,6 @@ generate-gitignore: ## update gitignore files
|
|||||||
generate-images: | node_modules ## generate images
|
generate-images: | node_modules ## generate images
|
||||||
cd tools && node generate-images.ts $(TAGS)
|
cd tools && node generate-images.ts $(TAGS)
|
||||||
|
|
||||||
.PHONY: generate-codemirror-languages
|
|
||||||
generate-codemirror-languages: | node_modules ## generate codemirror languages
|
|
||||||
node tools/generate-codemirror-languages.ts
|
|
||||||
|
|
||||||
.PHONY: generate-manpage
|
.PHONY: generate-manpage
|
||||||
generate-manpage: ## generate manpage
|
generate-manpage: ## generate manpage
|
||||||
@[ -f gitea ] || make backend
|
@[ -f gitea ] || make backend
|
||||||
@@ -680,6 +824,11 @@ generate-manpage: ## generate manpage
|
|||||||
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
|
@gzip -9 man/man1/gitea.1 && echo man/man1/gitea.1.gz created
|
||||||
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
|
@#TODO A small script that formats config-cheat-sheet.en-us.md nicely for use as a config man page
|
||||||
|
|
||||||
|
.PHONY: docker
|
||||||
|
docker:
|
||||||
|
docker build --disable-content-trust=false -t $(DOCKER_REF) .
|
||||||
|
# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" .
|
||||||
|
|
||||||
# Disable parallel execution because it would break some targets that don't
|
# Disable parallel execution because it would break some targets that don't
|
||||||
# specify exact dependencies like 'backend' which does currently not depend
|
# specify exact dependencies like 'backend' which does currently not depend
|
||||||
# on 'frontend' to enable Node.js-less builds from source tarballs.
|
# on 'frontend' to enable Node.js-less builds from source tarballs.
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
||||||
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
||||||
[](https://goreportcard.com/report/gitea.dev "Go Report Card")
|
[](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
|
||||||
[](https://pkg.go.dev/gitea.dev "GoDoc")
|
[](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
|
||||||
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
||||||
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
||||||
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
||||||
@@ -44,6 +44,10 @@ From the root of the source tree, run:
|
|||||||
|
|
||||||
TAGS="bindata" make build
|
TAGS="bindata" make build
|
||||||
|
|
||||||
|
or if SQLite support is required:
|
||||||
|
|
||||||
|
TAGS="bindata sqlite sqlite_unlock_notify" make build
|
||||||
|
|
||||||
The `build` target is split into two sub-targets:
|
The `build` target is split into two sub-targets:
|
||||||
|
|
||||||
- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
|
- `make backend` which requires [Go Stable](https://go.dev/dl/), the required version is defined in [go.mod](/go.mod).
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
||||||
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
||||||
[](https://goreportcard.com/report/gitea.dev "Go Report Card")
|
[](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
|
||||||
[](https://pkg.go.dev/gitea.dev "GoDoc")
|
[](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
|
||||||
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
||||||
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
||||||
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
||||||
@@ -38,6 +38,10 @@
|
|||||||
|
|
||||||
TAGS="bindata" make build
|
TAGS="bindata" make build
|
||||||
|
|
||||||
|
如果需要 SQLite 支持:
|
||||||
|
|
||||||
|
TAGS="bindata sqlite sqlite_unlock_notify" make build
|
||||||
|
|
||||||
`build` 目标分为两个子目标:
|
`build` 目标分为两个子目标:
|
||||||
|
|
||||||
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。
|
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定义。
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
[](https://github.com/go-gitea/gitea/actions/workflows/release-nightly.yml?query=branch%3Amain "Release Nightly")
|
||||||
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
[](https://discord.gg/Gitea "Join the Discord chat at https://discord.gg/Gitea")
|
||||||
[](https://goreportcard.com/report/gitea.dev "Go Report Card")
|
[](https://goreportcard.com/report/code.gitea.io/gitea "Go Report Card")
|
||||||
[](https://pkg.go.dev/gitea.dev "GoDoc")
|
[](https://pkg.go.dev/code.gitea.io/gitea "GoDoc")
|
||||||
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
[](https://github.com/go-gitea/gitea/releases/latest "GitHub release")
|
||||||
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
[](https://www.codetriage.com/go-gitea/gitea "Help Contribute to Open Source")
|
||||||
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
[](https://opencollective.com/gitea "Become a backer/sponsor of gitea")
|
||||||
@@ -38,6 +38,10 @@
|
|||||||
|
|
||||||
TAGS="bindata" make build
|
TAGS="bindata" make build
|
||||||
|
|
||||||
|
如果需要 SQLite 支援:
|
||||||
|
|
||||||
|
TAGS="bindata sqlite sqlite_unlock_notify" make build
|
||||||
|
|
||||||
`build` 目標分為兩個子目標:
|
`build` 目標分為兩個子目標:
|
||||||
|
|
||||||
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。
|
- `make backend` 需要 [Go Stable](https://go.dev/dl/),所需版本在 [go.mod](/go.mod) 中定義。
|
||||||
|
|||||||
1277
assets/codemirror-languages.json
generated
1277
assets/codemirror-languages.json
generated
File diff suppressed because it is too large
Load Diff
135
assets/go-licenses.json
generated
135
assets/go-licenses.json
generated
File diff suppressed because one or more lines are too long
@@ -9,7 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitea.dev/modules/assetfs"
|
"code.gitea.io/gitea/modules/assetfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"gitea.dev/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
//go:build ignore
|
//go:build ignore
|
||||||
|
|
||||||
package main
|
package main
|
||||||
@@ -18,7 +15,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ var primaryLicenseRe = regexp.MustCompile(`^(?i)(LICEN[SC]E|COPYING)$`)
|
|||||||
|
|
||||||
// ignoredNames are LicenseEntry.Name values to exclude from the output.
|
// ignoredNames are LicenseEntry.Name values to exclude from the output.
|
||||||
var ignoredNames = map[string]bool{
|
var ignoredNames = map[string]bool{
|
||||||
"gitea.dev": true,
|
"code.gitea.io/gitea": true,
|
||||||
"gitea.dev/options/license": true,
|
"code.gitea.io/gitea/options/license": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
var excludedExt = map[string]bool{
|
var excludedExt = map[string]bool{
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
// generate-openapi converts Gitea's Swagger 2.0 spec into an OpenAPI 3.0 spec.
|
|
||||||
//
|
|
||||||
// Gitea generates a Swagger 2.0 spec from code annotations (make generate-swagger).
|
|
||||||
// This tool converts it to OAS3 so that SDK generators and tools that require
|
|
||||||
// OAS3 (e.g. progenitor for Rust) can consume it directly. The conversion also
|
|
||||||
// deduplicates inline enum definitions into named schema components, producing
|
|
||||||
// cleaner SDK output with proper enum types instead of anonymous strings.
|
|
||||||
//
|
|
||||||
// Run: go run build/generate-openapi.go
|
|
||||||
// Output: templates/swagger/v1_openapi3_json.tmpl
|
|
||||||
|
|
||||||
//go:build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gitea.dev/build/openapi3gen"
|
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
swaggerSpecPath = "templates/swagger/v1_json.tmpl"
|
|
||||||
openapi3OutPath = "templates/swagger/v1_openapi3_json.tmpl"
|
|
||||||
|
|
||||||
appSubUrlVar = "{{.SwaggerAppSubUrl}}"
|
|
||||||
appVerVar = "{{.SwaggerAppVer}}"
|
|
||||||
|
|
||||||
appSubUrlPlaceholder = "GITEA_APP_SUB_URL_PLACEHOLDER"
|
|
||||||
appVerPlaceholder = "0.0.0-gitea-placeholder"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
appSubUrlRe = regexp.MustCompile(regexp.QuoteMeta(appSubUrlVar))
|
|
||||||
appVerRe = regexp.MustCompile(regexp.QuoteMeta(appVerVar))
|
|
||||||
|
|
||||||
enumScanDirs = []string{
|
|
||||||
"modules/structs",
|
|
||||||
"modules/commitstatus",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
astEnumMap, err := openapi3gen.ScanSwaggerEnumTypes(enumScanDirs)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("scanning swagger:enum annotations: %v", err)
|
|
||||||
}
|
|
||||||
names := make([]string, 0, len(astEnumMap))
|
|
||||||
for _, n := range astEnumMap {
|
|
||||||
names = append(names, n)
|
|
||||||
}
|
|
||||||
sort.Strings(names)
|
|
||||||
fmt.Fprintf(os.Stderr, "discovered %d swagger:enum types: %s\n", len(names), strings.Join(names, ", "))
|
|
||||||
|
|
||||||
data, err := os.ReadFile(swaggerSpecPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("reading swagger spec: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cleaned := appSubUrlRe.ReplaceAll(data, []byte(appSubUrlPlaceholder))
|
|
||||||
cleaned = appVerRe.ReplaceAll(cleaned, []byte(appVerPlaceholder))
|
|
||||||
|
|
||||||
oas3, err := openapi3gen.Convert(cleaned, astEnumMap)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("converting to openapi 3.0: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oas3.Servers = openapi3.Servers{
|
|
||||||
{URL: appSubUrlPlaceholder + "/api/v1"},
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err := json.MarshalIndent(oas3, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("marshaling openapi 3.0: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := strings.ReplaceAll(string(out), appSubUrlPlaceholder, appSubUrlVar)
|
|
||||||
result = strings.ReplaceAll(result, appVerPlaceholder, appVerVar)
|
|
||||||
result = strings.TrimSpace(result)
|
|
||||||
|
|
||||||
if err := os.WriteFile(openapi3OutPath, []byte(result), 0o644); err != nil {
|
|
||||||
log.Fatalf("writing openapi 3.0 spec: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Generated %s\n", openapi3OutPath)
|
|
||||||
}
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package openapi3gen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gitea.dev/modules/json"
|
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi2"
|
|
||||||
"github.com/getkin/kin-openapi/openapi2conv"
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rxDeprecated matches "deprecated" as a word at the start of a description
|
|
||||||
// or preceded by whitespace/punctuation that indicates a leading marker (e.g.
|
|
||||||
// "Deprecated: true", "deprecated (use X instead)"). Rejects negated phrases
|
|
||||||
// like "not deprecated" or "previously deprecated, now supported".
|
|
||||||
var rxDeprecated = regexp.MustCompile(`(?i)(?:^|[\n.;])\s*deprecated\b`)
|
|
||||||
|
|
||||||
// Convert parses a Swagger 2.0 spec and returns an OAS3 spec, applying
|
|
||||||
// Gitea-specific post-processing: file-schema fixups, URI formats,
|
|
||||||
// deprecated flags, and shared-enum extraction.
|
|
||||||
//
|
|
||||||
// astEnumMap is a value-set-key → Go-type-name map (built by
|
|
||||||
// ScanSwaggerEnumTypes). If a shared enum in the spec has no entry in the
|
|
||||||
// map, Convert returns an error — no fallback naming.
|
|
||||||
func Convert(swaggerJSON []byte, astEnumMap map[string]string) (*openapi3.T, error) {
|
|
||||||
var swagger2 openapi2.T
|
|
||||||
if err := json.Unmarshal(swaggerJSON, &swagger2); err != nil {
|
|
||||||
return nil, fmt.Errorf("parsing swagger 2.0: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oas3, err := openapi2conv.ToV3(&swagger2)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("converting to openapi 3.0: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fixFileSchemas(oas3)
|
|
||||||
addURIFormats(oas3)
|
|
||||||
addDeprecatedFlags(oas3)
|
|
||||||
if err := extractSharedEnums(oas3, astEnumMap); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return oas3, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixFileSchemas(doc *openapi3.T) {
|
|
||||||
for _, pathItem := range doc.Paths.Map() {
|
|
||||||
for _, op := range []*openapi3.Operation{
|
|
||||||
pathItem.Get, pathItem.Post, pathItem.Put, pathItem.Patch,
|
|
||||||
pathItem.Delete, pathItem.Head, pathItem.Options, pathItem.Trace,
|
|
||||||
} {
|
|
||||||
if op == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, resp := range op.Responses.Map() {
|
|
||||||
if resp.Value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, mediaType := range resp.Value.Content {
|
|
||||||
fixSchema(mediaType.Schema)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if op.RequestBody != nil && op.RequestBody.Value != nil {
|
|
||||||
for _, mediaType := range op.RequestBody.Value.Content {
|
|
||||||
fixSchema(mediaType.Schema)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixSchema rewrites any "type: file" schemas to the OAS3 equivalent
|
|
||||||
// (type: string, format: binary), recursing into Properties, Items, and
|
|
||||||
// AllOf/OneOf/AnyOf/Not branches. $ref nodes are skipped so shared schemas
|
|
||||||
// are rewritten exactly once when visited through their declaration.
|
|
||||||
func fixSchema(ref *openapi3.SchemaRef) {
|
|
||||||
if ref == nil || ref.Value == nil || ref.Ref != "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s := ref.Value
|
|
||||||
if s.Type.Is("file") {
|
|
||||||
s.Type = &openapi3.Types{"string"}
|
|
||||||
s.Format = "binary"
|
|
||||||
}
|
|
||||||
for _, p := range s.Properties {
|
|
||||||
fixSchema(p)
|
|
||||||
}
|
|
||||||
fixSchema(s.Items)
|
|
||||||
for _, sub := range s.AllOf {
|
|
||||||
fixSchema(sub)
|
|
||||||
}
|
|
||||||
for _, sub := range s.OneOf {
|
|
||||||
fixSchema(sub)
|
|
||||||
}
|
|
||||||
for _, sub := range s.AnyOf {
|
|
||||||
fixSchema(sub)
|
|
||||||
}
|
|
||||||
fixSchema(s.Not)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addURIFormats sets format: uri on string properties whose names indicate
|
|
||||||
// they hold URLs. This information is lost in Swagger 2.0 but is valuable
|
|
||||||
// for code generators.
|
|
||||||
func addURIFormats(doc *openapi3.T) {
|
|
||||||
if doc.Components == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, schemaRef := range doc.Components.Schemas {
|
|
||||||
if schemaRef.Value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for propName, propRef := range schemaRef.Value.Properties {
|
|
||||||
if propRef == nil || propRef.Value == nil || propRef.Ref != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
prop := propRef.Value
|
|
||||||
if !prop.Type.Is("string") || prop.Format != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isURLProperty(propName) {
|
|
||||||
prop.Format = "uri"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isURLProperty(name string) bool {
|
|
||||||
if strings.HasSuffix(name, "_url") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
switch name {
|
|
||||||
case "url", "html_url", "clone_url":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// addDeprecatedFlags sets deprecated: true on schema properties whose
|
|
||||||
// description starts with a "deprecated" marker (e.g. "Deprecated: true"
|
|
||||||
// or "deprecated (use X instead)"). Does not match negated phrases.
|
|
||||||
func addDeprecatedFlags(doc *openapi3.T) {
|
|
||||||
if doc.Components == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, schemaRef := range doc.Components.Schemas {
|
|
||||||
if schemaRef.Value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, propRef := range schemaRef.Value.Properties {
|
|
||||||
if propRef == nil || propRef.Value == nil || propRef.Ref != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if rxDeprecated.MatchString(propRef.Value.Description) {
|
|
||||||
propRef.Value.Deprecated = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type enumUsage struct {
|
|
||||||
schemaName string
|
|
||||||
propName string
|
|
||||||
propRef *openapi3.SchemaRef
|
|
||||||
inItems bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractSharedEnums finds identical enum arrays used by multiple schema
|
|
||||||
// properties, creates a standalone named schema for each, and replaces
|
|
||||||
// the inline enums with $ref pointers.
|
|
||||||
//
|
|
||||||
// If the derived enum name collides with an existing component schema, or
|
|
||||||
// no // swagger:enum annotation matches the value set, generation aborts
|
|
||||||
// with an actionable error — there are no silent fallbacks.
|
|
||||||
func extractSharedEnums(doc *openapi3.T, astEnumMap map[string]string) error {
|
|
||||||
if doc.Components == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
enumGroups := map[string][]enumUsage{}
|
|
||||||
|
|
||||||
for schemaName, schemaRef := range doc.Components.Schemas {
|
|
||||||
if schemaRef.Value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for propName, propRef := range schemaRef.Value.Properties {
|
|
||||||
if propRef == nil || propRef.Value == nil || propRef.Ref != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if len(propRef.Value.Enum) > 1 && propRef.Value.Type.Is("string") {
|
|
||||||
key := EnumKey(propRef.Value.Enum)
|
|
||||||
enumGroups[key] = append(enumGroups[key], enumUsage{schemaName, propName, propRef, false})
|
|
||||||
}
|
|
||||||
if propRef.Value.Type.Is("array") && propRef.Value.Items != nil &&
|
|
||||||
propRef.Value.Items.Value != nil && propRef.Value.Items.Ref == "" &&
|
|
||||||
len(propRef.Value.Items.Value.Enum) > 1 && propRef.Value.Items.Value.Type.Is("string") {
|
|
||||||
key := EnumKey(propRef.Value.Items.Value.Enum)
|
|
||||||
enumGroups[key] = append(enumGroups[key], enumUsage{schemaName, propName, propRef, true})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, usages := range enumGroups {
|
|
||||||
if len(usages) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
enumName, err := deriveEnumName(key, usages, astEnumMap)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, exists := doc.Components.Schemas[enumName]; exists {
|
|
||||||
return fmt.Errorf("enum name collision: %s already exists as a component schema", enumName)
|
|
||||||
}
|
|
||||||
|
|
||||||
var enumValues []any
|
|
||||||
if usages[0].inItems {
|
|
||||||
enumValues = usages[0].propRef.Value.Items.Value.Enum
|
|
||||||
} else {
|
|
||||||
enumValues = usages[0].propRef.Value.Enum
|
|
||||||
}
|
|
||||||
|
|
||||||
doc.Components.Schemas[enumName] = &openapi3.SchemaRef{
|
|
||||||
Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"string"},
|
|
||||||
Enum: enumValues,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ref := "#/components/schemas/" + enumName
|
|
||||||
|
|
||||||
for _, usage := range usages {
|
|
||||||
if usage.inItems {
|
|
||||||
usage.propRef.Value.Items = &openapi3.SchemaRef{Ref: ref}
|
|
||||||
} else {
|
|
||||||
old := usage.propRef.Value
|
|
||||||
if old.Description == "" && !old.Deprecated && old.Format == "" {
|
|
||||||
usage.propRef.Ref = ref
|
|
||||||
usage.propRef.Value = nil
|
|
||||||
} else {
|
|
||||||
usage.propRef.Value = &openapi3.Schema{
|
|
||||||
AllOf: openapi3.SchemaRefs{
|
|
||||||
{Ref: ref},
|
|
||||||
},
|
|
||||||
Description: old.Description,
|
|
||||||
Deprecated: old.Deprecated,
|
|
||||||
Format: old.Format,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// deriveEnumName looks up a shared enum's Go type name from astEnumMap by
|
|
||||||
// value-set key. If no annotation matches, returns an error identifying the
|
|
||||||
// offending properties and the fix.
|
|
||||||
func deriveEnumName(key string, usages []enumUsage, astEnumMap map[string]string) (string, error) {
|
|
||||||
if name, ok := astEnumMap[key]; ok {
|
|
||||||
return name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
props := map[string]bool{}
|
|
||||||
for _, u := range usages {
|
|
||||||
props[fmt.Sprintf("%s.%s", u.schemaName, u.propName)] = true
|
|
||||||
}
|
|
||||||
propList := make([]string, 0, len(props))
|
|
||||||
for p := range props {
|
|
||||||
propList = append(propList, p)
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf(
|
|
||||||
"no swagger:enum annotation matches value-set %q used by %d properties: %v; "+
|
|
||||||
"fix by adding a named string type with // swagger:enum to modules/structs or modules/commitstatus",
|
|
||||||
key, len(usages), propList,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package openapi3gen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDeriveEnumName_hit(t *testing.T) {
|
|
||||||
key := EnumKey([]any{"red", "green", "blue"})
|
|
||||||
astMap := map[string]string{key: "Color"}
|
|
||||||
usages := []enumUsage{{schemaName: "Paint", propName: "color"}}
|
|
||||||
got, err := deriveEnumName(key, usages, astMap)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if got != "Color" {
|
|
||||||
t.Fatalf("got %q, want %q", got, "Color")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeriveEnumName_miss(t *testing.T) {
|
|
||||||
key := EnumKey([]any{"x", "y"})
|
|
||||||
usages := []enumUsage{{schemaName: "Thing", propName: "kind"}}
|
|
||||||
_, err := deriveEnumName(key, usages, map[string]string{})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected miss error, got nil")
|
|
||||||
}
|
|
||||||
msg := err.Error()
|
|
||||||
if !strings.Contains(msg, "Thing.kind") {
|
|
||||||
t.Fatalf("error %q should list the missing usage", msg)
|
|
||||||
}
|
|
||||||
if !strings.Contains(msg, "swagger:enum") {
|
|
||||||
t.Fatalf("error %q should hint at the fix", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractSharedEnums_usesASTMap(t *testing.T) {
|
|
||||||
doc := &openapi3.T{
|
|
||||||
Components: &openapi3.Components{
|
|
||||||
Schemas: openapi3.Schemas{
|
|
||||||
"A": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"object"},
|
|
||||||
Properties: openapi3.Schemas{
|
|
||||||
"color": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"string"},
|
|
||||||
Enum: []any{"red", "green", "blue"},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
"B": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"object"},
|
|
||||||
Properties: openapi3.Schemas{
|
|
||||||
"color": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"string"},
|
|
||||||
Enum: []any{"red", "green", "blue"},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
astMap := map[string]string{EnumKey([]any{"red", "green", "blue"}): "Color"}
|
|
||||||
if err := extractSharedEnums(doc, astMap); err != nil {
|
|
||||||
t.Fatalf("extractSharedEnums: %v", err)
|
|
||||||
}
|
|
||||||
if _, ok := doc.Components.Schemas["Color"]; !ok {
|
|
||||||
t.Fatalf("expected Color schema to be extracted")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFixFileSchemas_recursesIntoNested(t *testing.T) {
|
|
||||||
fileType := func() *openapi3.SchemaRef {
|
|
||||||
return &openapi3.SchemaRef{Value: &openapi3.Schema{Type: &openapi3.Types{"file"}}}
|
|
||||||
}
|
|
||||||
doc := &openapi3.T{
|
|
||||||
Paths: openapi3.NewPaths(),
|
|
||||||
}
|
|
||||||
doc.Paths.Set("/upload", &openapi3.PathItem{
|
|
||||||
Post: &openapi3.Operation{
|
|
||||||
RequestBody: &openapi3.RequestBodyRef{
|
|
||||||
Value: &openapi3.RequestBody{
|
|
||||||
Content: openapi3.Content{
|
|
||||||
"multipart/form-data": {
|
|
||||||
Schema: &openapi3.SchemaRef{Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"object"},
|
|
||||||
Properties: openapi3.Schemas{
|
|
||||||
"attachment": fileType(),
|
|
||||||
"items": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"array"},
|
|
||||||
Items: fileType(),
|
|
||||||
}},
|
|
||||||
"alt": {Value: &openapi3.Schema{
|
|
||||||
AllOf: openapi3.SchemaRefs{fileType()},
|
|
||||||
}},
|
|
||||||
"one": {Value: &openapi3.Schema{
|
|
||||||
OneOf: openapi3.SchemaRefs{fileType()},
|
|
||||||
}},
|
|
||||||
"any": {Value: &openapi3.Schema{
|
|
||||||
AnyOf: openapi3.SchemaRefs{fileType()},
|
|
||||||
}},
|
|
||||||
"not": {Value: &openapi3.Schema{
|
|
||||||
Not: fileType(),
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Responses: openapi3.NewResponses(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
fixFileSchemas(doc)
|
|
||||||
|
|
||||||
props := doc.Paths.Value("/upload").Post.RequestBody.Value.Content["multipart/form-data"].Schema.Value.Properties
|
|
||||||
if !props["attachment"].Value.Type.Is("string") || props["attachment"].Value.Format != "binary" {
|
|
||||||
t.Errorf("nested property not fixed: %+v", props["attachment"].Value)
|
|
||||||
}
|
|
||||||
if !props["items"].Value.Items.Value.Type.Is("string") || props["items"].Value.Items.Value.Format != "binary" {
|
|
||||||
t.Errorf("array items not fixed: %+v", props["items"].Value.Items.Value)
|
|
||||||
}
|
|
||||||
if !props["alt"].Value.AllOf[0].Value.Type.Is("string") || props["alt"].Value.AllOf[0].Value.Format != "binary" {
|
|
||||||
t.Errorf("allOf branch not fixed: %+v", props["alt"].Value.AllOf[0].Value)
|
|
||||||
}
|
|
||||||
if !props["one"].Value.OneOf[0].Value.Type.Is("string") || props["one"].Value.OneOf[0].Value.Format != "binary" {
|
|
||||||
t.Errorf("oneOf branch not fixed: %+v", props["one"].Value.OneOf[0].Value)
|
|
||||||
}
|
|
||||||
if !props["any"].Value.AnyOf[0].Value.Type.Is("string") || props["any"].Value.AnyOf[0].Value.Format != "binary" {
|
|
||||||
t.Errorf("anyOf branch not fixed: %+v", props["any"].Value.AnyOf[0].Value)
|
|
||||||
}
|
|
||||||
if !props["not"].Value.Not.Value.Type.Is("string") || props["not"].Value.Not.Value.Format != "binary" {
|
|
||||||
t.Errorf("not branch not fixed: %+v", props["not"].Value.Not.Value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExtractSharedEnums_missReturnsError(t *testing.T) {
|
|
||||||
doc := &openapi3.T{
|
|
||||||
Components: &openapi3.Components{
|
|
||||||
Schemas: openapi3.Schemas{
|
|
||||||
"A": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"object"},
|
|
||||||
Properties: openapi3.Schemas{
|
|
||||||
"color": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"string"},
|
|
||||||
Enum: []any{"red", "green"},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
"B": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"object"},
|
|
||||||
Properties: openapi3.Schemas{
|
|
||||||
"color": {Value: &openapi3.Schema{
|
|
||||||
Type: &openapi3.Types{"string"},
|
|
||||||
Enum: []any{"red", "green"},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := extractSharedEnums(doc, map[string]string{}); err == nil {
|
|
||||||
t.Fatal("expected miss error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
// Package openapi3gen converts Gitea's Swagger 2.0 spec to an OpenAPI 3.0
|
|
||||||
// spec. It discovers Go enum type names by scanning swagger:enum annotations
|
|
||||||
// in the source tree, then names extracted shared-enum schemas accordingly.
|
|
||||||
package openapi3gen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EnumKey returns a canonical key for a set of enum values: values are
|
|
||||||
// stringified, sorted, and joined with "|". Used to match enum value sets
|
|
||||||
// across spec properties and scanned Go type declarations.
|
|
||||||
func EnumKey(values []any) string {
|
|
||||||
strs := make([]string, len(values))
|
|
||||||
for i, v := range values {
|
|
||||||
strs[i] = fmt.Sprintf("%v", v)
|
|
||||||
}
|
|
||||||
sort.Strings(strs)
|
|
||||||
return strings.Join(strs, "|")
|
|
||||||
}
|
|
||||||
|
|
||||||
var rxSwaggerEnum = regexp.MustCompile(`swagger:enum\s+(\w+)`)
|
|
||||||
|
|
||||||
// ScanSwaggerEnumTypes walks .go files under each dir and returns a map from
|
|
||||||
// a canonical value-set key (see EnumKey) to the Go type name declared with
|
|
||||||
// // swagger:enum TypeName.
|
|
||||||
//
|
|
||||||
// Returns an error on parse failure, on an annotation for a type whose
|
|
||||||
// constants can't be extracted, or on value-set collisions between two
|
|
||||||
// different enum types.
|
|
||||||
func ScanSwaggerEnumTypes(dirs []string) (map[string]string, error) {
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
parsed := []*ast.File{}
|
|
||||||
|
|
||||||
for _, dir := range dirs {
|
|
||||||
entries, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("reading %s: %w", dir, err)
|
|
||||||
}
|
|
||||||
for _, entry := range entries {
|
|
||||||
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(entry.Name(), "_test.go") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
path := filepath.Join(dir, entry.Name())
|
|
||||||
file, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s: %w", path, err)
|
|
||||||
}
|
|
||||||
parsed = append(parsed, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enumTypes := map[string]string{} // typeName → "" (presence marker)
|
|
||||||
enumValues := map[string][]any{} // typeName → values
|
|
||||||
|
|
||||||
// Pass 1: collect every // swagger:enum TypeName declaration.
|
|
||||||
for _, file := range parsed {
|
|
||||||
for _, decl := range file.Decls {
|
|
||||||
gd, ok := decl.(*ast.GenDecl)
|
|
||||||
if !ok || gd.Tok != token.TYPE {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := collectEnumType(gd, enumTypes); err != nil {
|
|
||||||
return nil, fmt.Errorf("%s: %w", fset.Position(gd.Pos()).Filename, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pass 2: collect const values; now every annotated type is visible.
|
|
||||||
for _, file := range parsed {
|
|
||||||
for _, decl := range file.Decls {
|
|
||||||
gd, ok := decl.(*ast.GenDecl)
|
|
||||||
if !ok || gd.Tok != token.CONST {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
collectEnumValues(gd, enumTypes, enumValues)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result := map[string]string{}
|
|
||||||
for typeName := range enumTypes {
|
|
||||||
values, ok := enumValues[typeName]
|
|
||||||
if !ok || len(values) == 0 {
|
|
||||||
return nil, fmt.Errorf("swagger:enum %s has no const block with typed string values", typeName)
|
|
||||||
}
|
|
||||||
key := EnumKey(values)
|
|
||||||
if existing, ok := result[key]; ok && existing != typeName {
|
|
||||||
return nil, fmt.Errorf("swagger:enum value-set collision: %s and %s both use %q", existing, typeName, key)
|
|
||||||
}
|
|
||||||
result[key] = typeName
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// collectEnumType scans a `type` GenDecl for // swagger:enum annotations,
|
|
||||||
// handling both the lone form (`// swagger:enum Foo\n type Foo string`)
|
|
||||||
// where the comment group is attached to the GenDecl, and the grouped form:
|
|
||||||
//
|
|
||||||
// type (
|
|
||||||
// // swagger:enum Foo
|
|
||||||
// Foo string
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// where the comment group is attached to each TypeSpec. Caveat: Go's parser
|
|
||||||
// only attaches a CommentGroup when it is immediately adjacent to the decl.
|
|
||||||
// A blank line (not a `//` continuation line) between the comment and the
|
|
||||||
// declaration drops the Doc, so annotations MUST sit directly above their
|
|
||||||
// type. All current annotated files obey this — the rule is noted here so
|
|
||||||
// a future edit that inserts a blank line fails fast rather than silently.
|
|
||||||
func collectEnumType(gd *ast.GenDecl, enumTypes map[string]string) error {
|
|
||||||
if err := registerEnumAnnotation(gd.Doc, gd.Specs, enumTypes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, spec := range gd.Specs {
|
|
||||||
ts, ok := spec.(*ast.TypeSpec)
|
|
||||||
if !ok || ts.Doc == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := registerEnumAnnotation(ts.Doc, []ast.Spec{ts}, enumTypes); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerEnumAnnotation(doc *ast.CommentGroup, specs []ast.Spec, enumTypes map[string]string) error {
|
|
||||||
if doc == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
matches := rxSwaggerEnum.FindStringSubmatch(doc.Text())
|
|
||||||
if len(matches) < 2 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
annotated := matches[1]
|
|
||||||
for _, spec := range specs {
|
|
||||||
ts, ok := spec.(*ast.TypeSpec)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ts.Name.Name == annotated {
|
|
||||||
enumTypes[annotated] = ""
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("swagger:enum %s: no type declaration with that name in the same decl group; check for a typo", annotated)
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectEnumValues(gd *ast.GenDecl, enumTypes map[string]string, enumValues map[string][]any) {
|
|
||||||
for _, spec := range gd.Specs {
|
|
||||||
vs, ok := spec.(*ast.ValueSpec)
|
|
||||||
if !ok || vs.Type == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ident, ok := vs.Type.(*ast.Ident)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, isEnum := enumTypes[ident.Name]; !isEnum {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, val := range vs.Values {
|
|
||||||
lit, ok := val.(*ast.BasicLit)
|
|
||||||
if !ok || lit.Kind != token.STRING {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
unquoted, err := strconv.Unquote(lit.Value)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
enumValues[ident.Name] = append(enumValues[ident.Name], unquoted)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
package openapi3gen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEnumKey_sortsAndJoins(t *testing.T) {
|
|
||||||
key := EnumKey([]any{"b", "a", "c"})
|
|
||||||
if key != "a|b|c" {
|
|
||||||
t.Fatalf("EnumKey = %q, want %q", key, "a|b|c")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnumKey_handlesNonStringValues(t *testing.T) {
|
|
||||||
key := EnumKey([]any{2, 1, 3})
|
|
||||||
if key != "1|2|3" {
|
|
||||||
t.Fatalf("EnumKey = %q, want %q", key, "1|2|3")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_basic(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
// Color is a primary color.
|
|
||||||
// swagger:enum Color
|
|
||||||
type Color string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ColorRed Color = "red"
|
|
||||||
ColorGreen Color = "green"
|
|
||||||
ColorBlue Color = "blue"
|
|
||||||
)
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "color.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
||||||
}
|
|
||||||
wantKey := EnumKey([]any{"red", "green", "blue"})
|
|
||||||
if got[wantKey] != "Color" {
|
|
||||||
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Color")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_orphanAnnotation(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
// swagger:enum Sttype
|
|
||||||
type StateType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
StateOpen StateType = "open"
|
|
||||||
)
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "typo.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error for annotation referencing a non-matching type name")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "Sttype") {
|
|
||||||
t.Fatalf("error %q should mention the typo'd name Sttype", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_collision(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
// swagger:enum Alpha
|
|
||||||
type Alpha string
|
|
||||||
const (
|
|
||||||
AlphaX Alpha = "x"
|
|
||||||
AlphaY Alpha = "y"
|
|
||||||
)
|
|
||||||
|
|
||||||
// swagger:enum Beta
|
|
||||||
type Beta string
|
|
||||||
const (
|
|
||||||
BetaX Beta = "x"
|
|
||||||
BetaY Beta = "y"
|
|
||||||
)
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "dup.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected collision error, got nil")
|
|
||||||
}
|
|
||||||
msg := err.Error()
|
|
||||||
if !strings.Contains(msg, "Alpha") || !strings.Contains(msg, "Beta") {
|
|
||||||
t.Fatalf("error %q should mention both Alpha and Beta", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_parseFailure(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "bad.go"), []byte("package fixture\nfunc Foo() {"), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected parse error, got nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_annotationWithoutConsts(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
// swagger:enum Lonely
|
|
||||||
type Lonely string
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "lonely.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("expected error for annotation without consts")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), "Lonely") {
|
|
||||||
t.Fatalf("error %q should mention Lonely", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_constsAndTypeInDifferentFiles(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
// Name ordering: `a_consts.go` < `b_type.go`, so readdir returns consts first.
|
|
||||||
// Old single-pass scanner would miss the values; two-pass must not.
|
|
||||||
constsSrc := `package fixture
|
|
||||||
|
|
||||||
const (
|
|
||||||
HueA Hue = "a"
|
|
||||||
HueB Hue = "b"
|
|
||||||
)
|
|
||||||
`
|
|
||||||
typeSrc := `package fixture
|
|
||||||
|
|
||||||
// swagger:enum Hue
|
|
||||||
type Hue string
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "a_consts.go"), []byte(constsSrc), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "b_type.go"), []byte(typeSrc), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
||||||
}
|
|
||||||
wantKey := EnumKey([]any{"a", "b"})
|
|
||||||
if got[wantKey] != "Hue" {
|
|
||||||
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Hue")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_constsBeforeType(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
const (
|
|
||||||
ShadeDark Shade = "dark"
|
|
||||||
ShadeLight Shade = "light"
|
|
||||||
)
|
|
||||||
|
|
||||||
// swagger:enum Shade
|
|
||||||
type Shade string
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "shade.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
||||||
}
|
|
||||||
wantKey := EnumKey([]any{"dark", "light"})
|
|
||||||
if got[wantKey] != "Shade" {
|
|
||||||
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Shade")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScanSwaggerEnumTypes_groupedTypeDecl(t *testing.T) {
|
|
||||||
dir := t.TempDir()
|
|
||||||
src := `package fixture
|
|
||||||
|
|
||||||
type (
|
|
||||||
// swagger:enum Color
|
|
||||||
Color string
|
|
||||||
// swagger:enum Shade
|
|
||||||
Shade string
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ColorRed Color = "red"
|
|
||||||
ColorBlue Color = "blue"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ShadeDark Shade = "dark"
|
|
||||||
ShadeLight Shade = "light"
|
|
||||||
)
|
|
||||||
`
|
|
||||||
if err := os.WriteFile(filepath.Join(dir, "grouped.go"), []byte(src), 0o644); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
||||||
}
|
|
||||||
colorKey := EnumKey([]any{"red", "blue"})
|
|
||||||
shadeKey := EnumKey([]any{"dark", "light"})
|
|
||||||
if got[colorKey] != "Color" {
|
|
||||||
t.Fatalf("Color: map[%q] = %q, want %q", colorKey, got[colorKey], "Color")
|
|
||||||
}
|
|
||||||
if got[shadeKey] != "Shade" {
|
|
||||||
t.Fatalf("Shade: map[%q] = %q, want %q", shadeKey, got[shadeKey], "Shade")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
build/test-env-check.sh
Executable file
24
build/test-env-check.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -f ./build/test-env-check.sh ]; then
|
||||||
|
echo "${0} can only be executed in gitea source root directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "check uid ..."
|
||||||
|
|
||||||
|
# the uid of gitea defined in "https://gitea.com/gitea/test-env" is 1000
|
||||||
|
gitea_uid=$(id -u gitea)
|
||||||
|
if [ "$gitea_uid" != "1000" ]; then
|
||||||
|
echo "The uid of linux user 'gitea' is expected to be 1000, but it is $gitea_uid"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cur_uid=$(id -u)
|
||||||
|
if [ "$cur_uid" != "0" -a "$cur_uid" != "$gitea_uid" ]; then
|
||||||
|
echo "The uid of current linux user is expected to be 0 or $gitea_uid, but it is $cur_uid"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
11
build/test-env-prepare.sh
Executable file
11
build/test-env-prepare.sh
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ ! -f ./build/test-env-prepare.sh ]; then
|
||||||
|
echo "${0} can only be executed in gitea source root directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "change the owner of files to gitea ..."
|
||||||
|
chown -R gitea:gitea .
|
||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
12
cmd/admin.go
12
cmd/admin.go
@@ -8,12 +8,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "gitea.dev/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"gitea.dev/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"gitea.dev/modules/gitrepo"
|
"code.gitea.io/gitea/modules/gitrepo"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "gitea.dev/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
auth_service "gitea.dev/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/models/auth"
|
"code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"gitea.dev/services/auth/source/ldap"
|
"code.gitea.io/gitea/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/models/auth"
|
"code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/modules/test"
|
"code.gitea.io/gitea/modules/test"
|
||||||
"gitea.dev/services/auth/source/ldap"
|
"code.gitea.io/gitea/services/auth/source/ldap"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"gitea.dev/services/auth/source/oauth2"
|
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/services/auth/source/oauth2"
|
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"gitea.dev/services/auth/source/smtp"
|
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/services/auth/source/smtp"
|
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.dev/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
asymkey_service "gitea.dev/services/asymkey"
|
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||||
repo_service "gitea.dev/services/repository"
|
repo_service "code.gitea.io/gitea/services/repository"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"gitea.dev/modules/auth/password"
|
"code.gitea.io/gitea/modules/auth/password"
|
||||||
"gitea.dev/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
user_service "gitea.dev/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,12 +4,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -83,9 +82,7 @@ func TestChangePasswordCommand(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
cmd := microcmdUserChangePassword()
|
err := microcmdUserChangePassword().Run(ctx, tc.args)
|
||||||
cmd.Writer, cmd.ErrWriter = io.Discard, io.Discard
|
|
||||||
err := cmd.Run(ctx, tc.args)
|
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), tc.expectedErr)
|
require.Contains(t, err.Error(), tc.expectedErr)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
pwd "gitea.dev/modules/auth/password"
|
pwd "code.gitea.io/gitea/modules/auth/password"
|
||||||
"gitea.dev/modules/optional"
|
"code.gitea.io/gitea/modules/optional"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
user_service "gitea.dev/services/user"
|
user_service "code.gitea.io/gitea/services/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
auth_model "gitea.dev/models/auth"
|
auth_model "code.gitea.io/gitea/models/auth"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -108,7 +107,6 @@ func TestCertCommandFailures(t *testing.T) {
|
|||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.name, func(t *testing.T) {
|
t.Run(c.name, func(t *testing.T) {
|
||||||
app := cmdCert()
|
app := cmdCert()
|
||||||
app.Writer, app.ErrWriter = io.Discard, io.Discard
|
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
certFile := filepath.Join(tempDir, "cert.pem")
|
certFile := filepath.Join(tempDir, "cert.pem")
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
@@ -124,7 +124,7 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl
|
|||||||
if setting.InstallLock {
|
if setting.InstallLock {
|
||||||
// During config loading, there might also be logs (for example: deprecation warnings).
|
// During config loading, there might also be logs (for example: deprecation warnings).
|
||||||
// It must make sure that console logger is set up before config is loaded.
|
// It must make sure that console logger is set up before config is loaded.
|
||||||
log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it. CustomConf=%s", setting.CustomConf)
|
log.Error("Config is loaded before console logger is setup, it will cause bugs. Please fix it.")
|
||||||
return nil, errors.New("console logger must be setup before config is loaded")
|
return nil, errors.New("console logger must be setup before config is loaded")
|
||||||
}
|
}
|
||||||
level := defaultLevel
|
level := defaultLevel
|
||||||
@@ -134,7 +134,7 @@ func PrepareConsoleLoggerLevel(defaultLevel log.Level) func(context.Context, *cl
|
|||||||
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
if globalBool(c, "debug") || globalBool(c, "verbose") {
|
||||||
level = log.TRACE
|
level = log.TRACE
|
||||||
}
|
}
|
||||||
log.SetupStderrLogger(log.DEFAULT, "console-stderr", level)
|
log.SetConsoleLogger(log.DEFAULT, "console-default", level)
|
||||||
return ctx, nil
|
return ctx, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
38
cmd/cmd_test.go
Normal file
38
cmd/cmd_test.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultCommand(t *testing.T) {
|
||||||
|
test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) {
|
||||||
|
called := false
|
||||||
|
cmd := &cli.Command{
|
||||||
|
DefaultCommand: "test",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "test",
|
||||||
|
Action: func(ctx context.Context, command *cli.Command) error {
|
||||||
|
retName, retValid := isValidDefaultSubCommand(command)
|
||||||
|
assert.Equal(t, expectedRetName, retName)
|
||||||
|
assert.Equal(t, expectedRetValid, retValid)
|
||||||
|
called = true
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.NoError(t, cmd.Run(t.Context(), args))
|
||||||
|
assert.True(t, called)
|
||||||
|
}
|
||||||
|
test(t, []string{"./gitea"}, "", true)
|
||||||
|
test(t, []string{"./gitea", "test"}, "", true)
|
||||||
|
test(t, []string{"./gitea", "other"}, "other", false)
|
||||||
|
}
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
// Tests here reload the config system multiple times with uncontrollable details.
|
|
||||||
// So they must be in a separate package, to avoid affecting other tests
|
|
||||||
|
|
||||||
package cmdtest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gitea.dev/cmd"
|
|
||||||
"gitea.dev/models/unittest"
|
|
||||||
"gitea.dev/modules/setting"
|
|
||||||
"gitea.dev/modules/test"
|
|
||||||
"gitea.dev/modules/util"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/urfave/cli/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
unittest.MainTest(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makePathOutput(workPath, customPath, customConf string) string {
|
|
||||||
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTestApp(testCmd cli.Command) *cli.Command {
|
|
||||||
app := cmd.NewMainApp(cmd.AppVersion{})
|
|
||||||
testCmd.Name = util.IfZero(testCmd.Name, "test-cmd")
|
|
||||||
cmd.PrepareSubcommandWithGlobalFlags(&testCmd)
|
|
||||||
app.Commands = append(app.Commands, &testCmd)
|
|
||||||
app.DefaultCommand = testCmd.Name
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
type runResult struct {
|
|
||||||
Stdout string
|
|
||||||
Stderr string
|
|
||||||
ExitCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
|
|
||||||
outBuf := new(strings.Builder)
|
|
||||||
errBuf := new(strings.Builder)
|
|
||||||
app.Writer = outBuf
|
|
||||||
app.ErrWriter = errBuf
|
|
||||||
exitCode := -1
|
|
||||||
defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
|
|
||||||
defer test.MockVariableValue(&cli.OsExiter, func(code int) {
|
|
||||||
if exitCode == -1 {
|
|
||||||
exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
|
|
||||||
app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
err := cmd.RunMainApp(app, args...)
|
|
||||||
return runResult{outBuf.String(), errBuf.String(), exitCode}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCliCmd(t *testing.T) {
|
|
||||||
defaultWorkPath := filepath.FromSlash("/tmp/mocked-work-path")
|
|
||||||
defaultCustomPath := filepath.Join(defaultWorkPath, "custom")
|
|
||||||
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
|
||||||
defer setting.MockBuiltinPaths(defaultWorkPath, "", "")()
|
|
||||||
|
|
||||||
cli.CommandHelpTemplate = "(command help template)"
|
|
||||||
cli.RootCommandHelpTemplate = "(app help template)"
|
|
||||||
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
env map[string]string
|
|
||||||
cmd string
|
|
||||||
exp string
|
|
||||||
}{
|
|
||||||
// help commands
|
|
||||||
{
|
|
||||||
cmd: "./gitea -h",
|
|
||||||
exp: "DEFAULT CONFIGURATION:",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea help",
|
|
||||||
exp: "DEFAULT CONFIGURATION:",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea help -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null test-cmd -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -c /dev/null -h",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -h -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /dev/null test-cmd help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -c /dev/null help",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd help -c /dev/null",
|
|
||||||
exp: "ConfigFile: /dev/null",
|
|
||||||
},
|
|
||||||
|
|
||||||
// parse paths
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd",
|
|
||||||
exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea -c /tmp/app.ini test-cmd",
|
|
||||||
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
cmd: "./gitea test-cmd -c /tmp/app.ini",
|
|
||||||
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
|
||||||
cmd: "./gitea test-cmd",
|
|
||||||
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
|
||||||
cmd: "./gitea test-cmd --work-path /tmp/other",
|
|
||||||
exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
|
||||||
cmd: "./gitea test-cmd --config /tmp/app-other.ini",
|
|
||||||
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range cases {
|
|
||||||
t.Run(c.cmd, func(t *testing.T) {
|
|
||||||
app := newTestApp(cli.Command{
|
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
|
||||||
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
})
|
|
||||||
for k, v := range c.env {
|
|
||||||
t.Setenv(k, v)
|
|
||||||
}
|
|
||||||
args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
|
|
||||||
r, err := runTestApp(app, args...)
|
|
||||||
assert.NoError(t, err, c.cmd)
|
|
||||||
assert.NotEmpty(t, c.exp, c.cmd)
|
|
||||||
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) {
|
|
||||||
t.Log("Full output:\n" + r.Stdout)
|
|
||||||
t.Log("Expected:\n" + c.exp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCliCmdError(t *testing.T) {
|
|
||||||
app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }})
|
|
||||||
r, err := runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
|
||||||
assert.Empty(t, r.Stdout)
|
|
||||||
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
|
||||||
|
|
||||||
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }})
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 2, r.ExitCode)
|
|
||||||
assert.Empty(t, r.Stdout)
|
|
||||||
assert.Equal(t, "exit error\n", r.Stderr)
|
|
||||||
|
|
||||||
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
|
||||||
assert.Empty(t, r.Stdout)
|
|
||||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
|
||||||
|
|
||||||
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
|
||||||
assert.Empty(t, r.Stdout)
|
|
||||||
assert.Empty(t, r.Stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCliCmdBefore(t *testing.T) {
|
|
||||||
ctxNew := context.WithValue(context.Background(), any("key"), "value")
|
|
||||||
configValues := map[string]string{}
|
|
||||||
setting.CustomConf = "/tmp/any.ini"
|
|
||||||
var actionCtx context.Context
|
|
||||||
app := newTestApp(cli.Command{
|
|
||||||
Before: func(context.Context, *cli.Command) (context.Context, error) {
|
|
||||||
configValues["before"] = setting.CustomConf
|
|
||||||
return ctxNew, nil
|
|
||||||
},
|
|
||||||
Action: func(ctx context.Context, cmd *cli.Command) error {
|
|
||||||
configValues["action"] = setting.CustomConf
|
|
||||||
actionCtx = ctx
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
})
|
|
||||||
_, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, ctxNew, actionCtx)
|
|
||||||
assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config")
|
|
||||||
assert.Equal(t, "/dev/null", configValues["action"])
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,15 +12,16 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
migrate_base "gitea.dev/models/migrations/base"
|
migrate_base "code.gitea.io/gitea/models/migrations/base"
|
||||||
"gitea.dev/modules/container"
|
"code.gitea.io/gitea/modules/container"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/services/doctor"
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDoctorCommand() *cli.Command {
|
func newDoctorCommand() *cli.Command {
|
||||||
@@ -131,7 +132,7 @@ func runRecreateTable(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
recreateTables := migrate_base.RecreateTables(beans...)
|
recreateTables := migrate_base.RecreateTables(beans...)
|
||||||
|
|
||||||
return db.InitEngineWithMigration(context.Background(), func(ctx context.Context, x db.EngineMigration) error {
|
return db.InitEngineWithMigration(context.Background(), func(ctx context.Context, x *xorm.Engine) error {
|
||||||
if err := migrations.EnsureUpToDate(ctx, x); err != nil {
|
if err := migrations.EnsureUpToDate(ctx, x); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/services/doctor"
|
"code.gitea.io/gitea/services/doctor"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
|||||||
18
cmd/dump.go
18
cmd/dump.go
@@ -11,13 +11,13 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/modules/dump"
|
"code.gitea.io/gitea/modules/dump"
|
||||||
"gitea.dev/modules/json"
|
"code.gitea.io/gitea/modules/json"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"gitea.com/go-chi/session"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
@@ -203,8 +203,8 @@ func runDump(ctx context.Context, cmd *cli.Command) error {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
targetDBType := setting.DatabaseType(cmd.String("database"))
|
targetDBType := cmd.String("database")
|
||||||
if targetDBType != "" && targetDBType != setting.Database.Type {
|
if len(targetDBType) > 0 && targetDBType != setting.Database.Type.String() {
|
||||||
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
log.Info("Dumping database %s => %s...", setting.Database.Type, targetDBType)
|
||||||
} else {
|
} else {
|
||||||
log.Info("Dumping database...")
|
log.Info("Dumping database...")
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
base "gitea.dev/modules/migration"
|
base "code.gitea.io/gitea/modules/migration"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"gitea.dev/services/convert"
|
"code.gitea.io/gitea/services/convert"
|
||||||
"gitea.dev/services/migrations"
|
"code.gitea.io/gitea/services/migrations"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/assetfs"
|
"code.gitea.io/gitea/modules/assetfs"
|
||||||
"gitea.dev/modules/glob"
|
"code.gitea.io/gitea/modules/glob"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/options"
|
"code.gitea.io/gitea/modules/options"
|
||||||
"gitea.dev/modules/public"
|
"code.gitea.io/gitea/modules/public"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/modules/templates"
|
"code.gitea.io/gitea/modules/templates"
|
||||||
"gitea.dev/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitea.dev/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
|
|||||||
12
cmd/hook.go
12
cmd/hook.go
@@ -14,12 +14,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.dev/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"gitea.dev/modules/git/gitcmd"
|
"code.gitea.io/gitea/modules/git/gitcmd"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
repo_module "gitea.dev/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
@@ -48,7 +48,7 @@ DEFAULT CONFIGURATION:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
|
func prepareSubcommandWithGlobalFlags(originCmd *cli.Command) {
|
||||||
originBefore := originCmd.Before
|
originBefore := originCmd.Before
|
||||||
originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) {
|
originCmd.Before = func(ctxOrig context.Context, cmd *cli.Command) (ctx context.Context, err error) {
|
||||||
ctx = ctxOrig
|
ctx = ctxOrig
|
||||||
@@ -145,7 +145,7 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
|||||||
|
|
||||||
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
app.Before = PrepareConsoleLoggerLevel(log.INFO)
|
||||||
for i := range subCmdWithConfig {
|
for i := range subCmdWithConfig {
|
||||||
PrepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
|
prepareSubcommandWithGlobalFlags(subCmdWithConfig[i])
|
||||||
}
|
}
|
||||||
app.Commands = append(app.Commands, subCmdWithConfig...)
|
app.Commands = append(app.Commands, subCmdWithConfig...)
|
||||||
app.Commands = append(app.Commands, subCmdStandalone...)
|
app.Commands = append(app.Commands, subCmdStandalone...)
|
||||||
|
|||||||
239
cmd/main_test.go
239
cmd/main_test.go
@@ -5,9 +5,17 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/test"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
@@ -17,28 +25,209 @@ func TestMain(m *testing.M) {
|
|||||||
unittest.MainTest(m)
|
unittest.MainTest(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultCommand(t *testing.T) {
|
func makePathOutput(workPath, customPath, customConf string) string {
|
||||||
test := func(t *testing.T, args []string, expectedRetName string, expectedRetValid bool) {
|
return fmt.Sprintf("WorkPath=%s\nCustomPath=%s\nCustomConf=%s", workPath, customPath, customConf)
|
||||||
called := false
|
}
|
||||||
cmd := &cli.Command{
|
|
||||||
DefaultCommand: "test",
|
func newTestApp(testCmd cli.Command) *cli.Command {
|
||||||
Commands: []*cli.Command{
|
app := NewMainApp(AppVersion{})
|
||||||
{
|
testCmd.Name = util.IfZero(testCmd.Name, "test-cmd")
|
||||||
Name: "test",
|
prepareSubcommandWithGlobalFlags(&testCmd)
|
||||||
Action: func(ctx context.Context, command *cli.Command) error {
|
app.Commands = append(app.Commands, &testCmd)
|
||||||
retName, retValid := isValidDefaultSubCommand(command)
|
app.DefaultCommand = testCmd.Name
|
||||||
assert.Equal(t, expectedRetName, retName)
|
return app
|
||||||
assert.Equal(t, expectedRetValid, retValid)
|
}
|
||||||
called = true
|
|
||||||
return nil
|
type runResult struct {
|
||||||
},
|
Stdout string
|
||||||
},
|
Stderr string
|
||||||
},
|
ExitCode int
|
||||||
}
|
}
|
||||||
assert.NoError(t, cmd.Run(t.Context(), args))
|
|
||||||
assert.True(t, called)
|
func runTestApp(app *cli.Command, args ...string) (runResult, error) {
|
||||||
}
|
outBuf := new(strings.Builder)
|
||||||
test(t, []string{"./gitea"}, "", true)
|
errBuf := new(strings.Builder)
|
||||||
test(t, []string{"./gitea", "test"}, "", true)
|
app.Writer = outBuf
|
||||||
test(t, []string{"./gitea", "other"}, "other", false)
|
app.ErrWriter = errBuf
|
||||||
|
exitCode := -1
|
||||||
|
defer test.MockVariableValue(&cli.ErrWriter, app.ErrWriter)()
|
||||||
|
defer test.MockVariableValue(&cli.OsExiter, func(code int) {
|
||||||
|
if exitCode == -1 {
|
||||||
|
exitCode = code // save the exit code once and then reset the writer (to simulate the exit)
|
||||||
|
app.Writer, app.ErrWriter, cli.ErrWriter = io.Discard, io.Discard, io.Discard
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
err := RunMainApp(app, args...)
|
||||||
|
return runResult{outBuf.String(), errBuf.String(), exitCode}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCliCmd(t *testing.T) {
|
||||||
|
defaultWorkPath := filepath.Dir(setting.AppPath)
|
||||||
|
defaultCustomPath := filepath.Join(defaultWorkPath, "custom")
|
||||||
|
defaultCustomConf := filepath.Join(defaultCustomPath, "conf/app.ini")
|
||||||
|
|
||||||
|
cli.CommandHelpTemplate = "(command help template)"
|
||||||
|
cli.RootCommandHelpTemplate = "(app help template)"
|
||||||
|
cli.SubcommandHelpTemplate = "(subcommand help template)"
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
env map[string]string
|
||||||
|
cmd string
|
||||||
|
exp string
|
||||||
|
}{
|
||||||
|
// help commands
|
||||||
|
{
|
||||||
|
cmd: "./gitea -h",
|
||||||
|
exp: "DEFAULT CONFIGURATION:",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea help",
|
||||||
|
exp: "DEFAULT CONFIGURATION:",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
cmd: "./gitea -c /dev/null -h",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
cmd: "./gitea -c /dev/null help",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea help -c /dev/null",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
cmd: "./gitea -c /dev/null test-cmd -h",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd -c /dev/null -h",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd -h -c /dev/null",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
cmd: "./gitea -c /dev/null test-cmd help",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd -c /dev/null help",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd help -c /dev/null",
|
||||||
|
exp: "ConfigFile: /dev/null",
|
||||||
|
},
|
||||||
|
|
||||||
|
// parse paths
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd",
|
||||||
|
exp: makePathOutput(defaultWorkPath, defaultCustomPath, defaultCustomConf),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea -c /tmp/app.ini test-cmd",
|
||||||
|
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cmd: "./gitea test-cmd -c /tmp/app.ini",
|
||||||
|
exp: makePathOutput(defaultWorkPath, defaultCustomPath, "/tmp/app.ini"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
||||||
|
cmd: "./gitea test-cmd",
|
||||||
|
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/custom/conf/app.ini"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
||||||
|
cmd: "./gitea test-cmd --work-path /tmp/other",
|
||||||
|
exp: makePathOutput("/tmp/other", "/tmp/other/custom", "/tmp/other/custom/conf/app.ini"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: map[string]string{"GITEA_WORK_DIR": "/tmp"},
|
||||||
|
cmd: "./gitea test-cmd --config /tmp/app-other.ini",
|
||||||
|
exp: makePathOutput("/tmp", "/tmp/custom", "/tmp/app-other.ini"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.cmd, func(t *testing.T) {
|
||||||
|
defer test.MockVariableValue(&setting.InstallLock, false)()
|
||||||
|
app := newTestApp(cli.Command{
|
||||||
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||||
|
_, _ = fmt.Fprint(cmd.Root().Writer, makePathOutput(setting.AppWorkPath, setting.CustomPath, setting.CustomConf))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
for k, v := range c.env {
|
||||||
|
t.Setenv(k, v)
|
||||||
|
}
|
||||||
|
args := strings.Split(c.cmd, " ") // for test only, "split" is good enough
|
||||||
|
r, err := runTestApp(app, args...)
|
||||||
|
assert.NoError(t, err, c.cmd)
|
||||||
|
assert.NotEmpty(t, c.exp, c.cmd)
|
||||||
|
if !assert.Contains(t, r.Stdout, c.exp, c.cmd) {
|
||||||
|
t.Log("Full output:\n" + r.Stdout)
|
||||||
|
t.Log("Expected:\n" + c.exp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCliCmdError(t *testing.T) {
|
||||||
|
app := newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return errors.New("normal error") }})
|
||||||
|
r, err := runTestApp(app, "./gitea", "test-cmd")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
|
assert.Empty(t, r.Stdout)
|
||||||
|
assert.Equal(t, "Command error: normal error\n", r.Stderr)
|
||||||
|
|
||||||
|
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return cli.Exit("exit error", 2) }})
|
||||||
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, 2, r.ExitCode)
|
||||||
|
assert.Empty(t, r.Stdout)
|
||||||
|
assert.Equal(t, "exit error\n", r.Stderr)
|
||||||
|
|
||||||
|
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
||||||
|
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
|
assert.Empty(t, r.Stdout)
|
||||||
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
||||||
|
|
||||||
|
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
||||||
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, -1, r.ExitCode) // the cli.OsExiter is not called
|
||||||
|
assert.Empty(t, r.Stdout)
|
||||||
|
assert.Empty(t, r.Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCliCmdBefore(t *testing.T) {
|
||||||
|
ctxNew := context.WithValue(context.Background(), any("key"), "value")
|
||||||
|
configValues := map[string]string{}
|
||||||
|
setting.CustomConf = "/tmp/any.ini"
|
||||||
|
var actionCtx context.Context
|
||||||
|
app := newTestApp(cli.Command{
|
||||||
|
Before: func(context.Context, *cli.Command) (context.Context, error) {
|
||||||
|
configValues["before"] = setting.CustomConf
|
||||||
|
return ctxNew, nil
|
||||||
|
},
|
||||||
|
Action: func(ctx context.Context, cmd *cli.Command) error {
|
||||||
|
configValues["action"] = setting.CustomConf
|
||||||
|
actionCtx = ctx
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
_, err := runTestApp(app, "./gitea", "--config", "/dev/null", "test-cmd")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, ctxNew, actionCtx)
|
||||||
|
assert.Equal(t, "/tmp/any.ini", configValues["before"], "BeforeFunc must be called before preparing config")
|
||||||
|
assert.Equal(t, "/dev/null", configValues["action"])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/private"
|
"code.gitea.io/gitea/modules/private"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"gitea.dev/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"gitea.dev/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"gitea.dev/services/versioned_migration"
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"github.com/urfave/cli/v3"
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user