mirror of
https://gitea.com/gitea/docs.git
synced 2026-09-17 19:55:34 +00:00
Fix the swagger update cron job (#481)
The scheduled `update swagger files` job has failed on **every** run since it was added (I checked the run list on gitea.com, ~250 consecutive failures). Two reasons:
1. Upstream moved the file: `go-gitea/gitea` main no longer has `templates/swagger/v1_json.tmpl`, it is now `templates/swagger/v1-swagger.generated.json`, and the placeholders changed from `{{.SwaggerAppVer}}` / `{{.SwaggerAppSubUrl}}` to `0.0.0+GITEA-API-APP-VERSION` / `/GITEA-API-APP-SUBURL/api/v1`. Because the script used `curl --silent` without `--fail`, the 404 body was written into `static/swagger-latest.json`.
2. `main` is protected (`required_approvals=1`), so the job's `git push` to main could never succeed.
Changes:
- `update_api_docs.sh`: `set -euo pipefail`, download with `--fail` (a broken download now aborts instead of committing garbage), try the new generated json first and fall back to the old template for released tags, handle the 1.28+/1.24+/<1.24 placeholder variants, and add a `--latest-only` flag.
- `Makefile`: new `update-api-docs-latest` target for the cron job; `clean` no longer deletes the committed `static/swagger-*.json` files (deleting them breaks `make build`).
- `.gitea/workflows/update_swagger.yaml`: every 12h (plus `workflow_dispatch`) it regenerates only `static/swagger-latest.json`, verifies no placeholder is left and the file is valid JSON, force pushes to `bot/update-swagger-latest` and opens a pull request via the API (HTTP 409 = a PR is already open, it just now points at the new commit). It skips entirely when the bot branch already carries the same file, so no PR churn.
- `README.md`: document the two make targets and the automation.
`secrets.DEPLOY_TOKEN` must belong to a real user with `write:repository` so the PR checks are triggered; the job fails with a clear message if it is empty.
Tested locally in a scratch clone: `make update-api-docs-latest` produces a valid `dev` spec with no placeholders left, `make update-api-docs` still regenerates all released versions, and the workflow shell logic was simulated against a local bare repo for all three paths (open PR / bot branch already up to date / main already up to date), including a shallow clone to confirm `fetch-depth: 1` force pushes work.
Fixes #454
Reviewed-on: https://gitea.com/gitea/docs/pulls/481
Reviewed-by: techknowlogick <[email protected]>
This commit is contained in:
@@ -5,24 +5,95 @@ on:
|
||||
- cron: '0 */12 * * *' # every 12 hours on the hour
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
# main is protected, so the update is proposed as a pull request from this branch
|
||||
BOT_BRANCH: bot/update-swagger-latest
|
||||
BASE_BRANCH: main
|
||||
|
||||
jobs:
|
||||
update-swagger:
|
||||
if: github.repository == 'gitea/docs'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
||||
- run: |
|
||||
with:
|
||||
ref: main
|
||||
# pushing uses DEPLOY_TOKEN, keep the ephemeral job token out of .git/config
|
||||
persist-credentials: false
|
||||
- name: regenerate swagger-latest.json
|
||||
run: make update-api-docs-latest
|
||||
- name: verify the generated file
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# placeholders must have been replaced, otherwise upstream changed them again
|
||||
if grep -q -e 'GITEA-API-APP' -e '{{' static/swagger-latest.json; then
|
||||
echo "static/swagger-latest.json still contains template placeholders"
|
||||
exit 1
|
||||
fi
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
python3 -c "import json; json.load(open('static/swagger-latest.json'))"
|
||||
fi
|
||||
- name: push bot branch
|
||||
id: bot_branch
|
||||
env:
|
||||
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
make update-api-docs
|
||||
|
||||
git config --global user.name "Gitea Bot"
|
||||
git config --global user.email "[email protected]"
|
||||
git remote set-url origin https://x-access-token:${{ secrets.DEPLOY_TOKEN }}@gitea.com/gitea/docs.git
|
||||
|
||||
if git status --porcelain | grep -q .; then
|
||||
git add --all
|
||||
git commit -m "[skip ci] Updated swagger files"
|
||||
git push
|
||||
else
|
||||
echo "No API doc changes detected; skipping commit"
|
||||
if git diff --quiet -- static/swagger-latest.json; then
|
||||
echo "swagger-latest.json is already up to date"
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$DEPLOY_TOKEN" ]; then
|
||||
echo "secrets.DEPLOY_TOKEN is missing, cannot push the update"
|
||||
exit 1
|
||||
fi
|
||||
remote="https://x-access-token:$DEPLOY_TOKEN@${GITHUB_SERVER_URL#*://}/$GITHUB_REPOSITORY.git"
|
||||
|
||||
# skip if an open bot branch already carries exactly this file
|
||||
if git fetch --quiet --depth=1 "$remote" "refs/heads/$BOT_BRANCH" 2>/dev/null; then
|
||||
old_blob="$(git rev-parse --quiet --verify "FETCH_HEAD:static/swagger-latest.json" || true)"
|
||||
if [ "$old_blob" = "$(git hash-object static/swagger-latest.json)" ]; then
|
||||
echo "$BOT_BRANCH already proposes this swagger-latest.json"
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
git config user.name "Gitea Bot"
|
||||
git config user.email "[email protected]"
|
||||
git switch --create "$BOT_BRANCH"
|
||||
git add static/swagger-latest.json
|
||||
git commit -m "Update swagger-latest.json"
|
||||
# force push: the branch is always rebuilt on top of the current main
|
||||
git push --force "$remote" "HEAD:refs/heads/$BOT_BRANCH"
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
- name: create pull request
|
||||
if: steps.bot_branch.outputs.changed == 'true'
|
||||
env:
|
||||
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
cat > pull.json <<EOF
|
||||
{
|
||||
"base": "$BASE_BRANCH",
|
||||
"head": "$BOT_BRANCH",
|
||||
"title": "Update swagger-latest.json",
|
||||
"body": "Automated update of static/swagger-latest.json from the gitea main branch, opened by the \"update swagger files\" scheduled workflow."
|
||||
}
|
||||
EOF
|
||||
|
||||
code="$(curl --silent --show-error --output pull-response.json --write-out '%{http_code}' \
|
||||
-X POST "${GITHUB_API_URL:-$GITHUB_SERVER_URL/api/v1}/repos/$GITHUB_REPOSITORY/pulls" \
|
||||
-H "Authorization: token $DEPLOY_TOKEN" \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data @pull.json)"
|
||||
|
||||
case "$code" in
|
||||
201) echo "pull request created" ;;
|
||||
409) echo "an open pull request for $BOT_BRANCH already exists, it now points at the new commit" ;;
|
||||
*) echo "unexpected response $code:"; cat pull-response.json; exit 1 ;;
|
||||
esac
|
||||
|
||||
@@ -41,18 +41,17 @@ serve: prepare-docs
|
||||
serve-zh: prepare-docs
|
||||
pnpm run start -- --locale zh-cn
|
||||
|
||||
# static/swagger-*.json are committed files, use update-api-docs to refresh them
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf .tmp
|
||||
rm -rf static/_*
|
||||
rm -rf static/swagger-latest.json
|
||||
rm -rf static/swagger-19.json
|
||||
rm -rf static/swagger-20.json
|
||||
rm -rf static/swagger-21.json
|
||||
rm -rf static/swagger-22.json
|
||||
rm -rf static/swagger-23.json
|
||||
rm -rf static/swagger-24.json
|
||||
|
||||
.PHONY: update-api-docs
|
||||
update-api-docs:
|
||||
./update_api_docs.sh
|
||||
|
||||
# only refresh static/swagger-latest.json (used by the update swagger cron job)
|
||||
.PHONY: update-api-docs-latest
|
||||
update-api-docs-latest:
|
||||
./update_api_docs.sh --latest-only
|
||||
|
||||
@@ -21,3 +21,17 @@ make serve
|
||||
```shell
|
||||
pnpm run start
|
||||
```
|
||||
|
||||
## API docs
|
||||
|
||||
The swagger definitions rendered under `/api-docs` live in `static/swagger-latest.json`
|
||||
(gitea main) and `static/swagger-<minor>.json` (released versions).
|
||||
|
||||
```shell
|
||||
make update-api-docs # refresh latest + every released version
|
||||
make update-api-docs-latest # refresh only static/swagger-latest.json
|
||||
```
|
||||
|
||||
`static/swagger-latest.json` is refreshed automatically: the `update swagger files`
|
||||
workflow runs every 12 hours and opens a pull request whenever gitea main changed.
|
||||
Released versions are updated by hand when a new gitea version is documented.
|
||||
|
||||
+59
-11
@@ -1,4 +1,19 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Regenerates the swagger definitions served by this site.
|
||||
#
|
||||
# Usage: ./update_api_docs.sh [--latest-only] [sed -i suffix] [extra sed args...]
|
||||
#
|
||||
# --latest-only only refresh static/swagger-latest.json from gitea main,
|
||||
# leaving the released static/swagger-<minor>.json untouched.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
LATEST_ONLY=0
|
||||
if [ "${1:-}" = "--latest-only" ]; then
|
||||
LATEST_ONLY=1
|
||||
shift
|
||||
fi
|
||||
|
||||
SED_INPLACE=(-i)
|
||||
EXTRA_SED_ARGS=()
|
||||
@@ -17,21 +32,54 @@ fi
|
||||
EXTRA_SED_ARGS=("$@")
|
||||
|
||||
inplace_sed() {
|
||||
sed "${SED_INPLACE[@]}" "${EXTRA_SED_ARGS[@]}" "$@"
|
||||
# ${arr[@]+...} keeps `set -u` happy with empty arrays on bash 3.2 (macOS)
|
||||
sed "${SED_INPLACE[@]}" ${EXTRA_SED_ARGS[@]+"${EXTRA_SED_ARGS[@]}"} "$@"
|
||||
}
|
||||
|
||||
curl --silent --output v1_json.tmpl https://raw.githubusercontent.com/go-gitea/gitea/refs/heads/main/templates/swagger/v1_json.tmpl
|
||||
inplace_sed 's|"version": "{{.SwaggerAppVer}}"|"version": "dev"|' v1_json.tmpl
|
||||
inplace_sed 's|"basePath": "{{.SwaggerAppSubUrl}}/api/v1"|"basePath": "https://gitea.com/api/v1"|' v1_json.tmpl
|
||||
# gitea >= 1.28 ships a pre-generated json, older versions ship a go template
|
||||
SWAGGER_PATHS=(
|
||||
'templates/swagger/v1-swagger.generated.json'
|
||||
'templates/swagger/v1_json.tmpl'
|
||||
)
|
||||
|
||||
# download_swagger <git ref> <output file>
|
||||
download_swagger() {
|
||||
local ref="$1" output="$2" path
|
||||
for path in "${SWAGGER_PATHS[@]}"; do
|
||||
if curl --silent --fail --location --output "$output" \
|
||||
"https://raw.githubusercontent.com/go-gitea/gitea/${ref}/${path}"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo "unable to download the swagger definition of ${ref}" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# rewrite_swagger <file> <version to display>
|
||||
rewrite_swagger() {
|
||||
local file="$1" version="$2"
|
||||
# gitea >= 1.28
|
||||
inplace_sed "s|\"version\": \"0.0.0+GITEA-API-APP-VERSION\"|\"version\": \"${version}\"|" "$file"
|
||||
inplace_sed 's|"basePath": "/GITEA-API-APP-SUBURL/api/v1"|"basePath": "https://gitea.com/api/v1"|' "$file"
|
||||
# gitea >= 1.24
|
||||
inplace_sed "s|\"version\": \"{{.SwaggerAppVer}}\"|\"version\": \"${version}\"|" "$file"
|
||||
inplace_sed 's|"basePath": "{{.SwaggerAppSubUrl}}/api/v1"|"basePath": "https://gitea.com/api/v1"|' "$file"
|
||||
# gitea < 1.24
|
||||
inplace_sed "s|\"version\": \"{{AppVer \| JSEscape}}\"|\"version\": \"${version}\"|" "$file"
|
||||
inplace_sed "s#\"basePath\": \"{{AppSubUrl | JSEscape}}/api/v1\"#\"basePath\": \"https://gitea.com/api/v1\"#" "$file"
|
||||
}
|
||||
|
||||
download_swagger 'refs/heads/main' v1_json.tmpl
|
||||
rewrite_swagger v1_json.tmpl 'dev'
|
||||
mv v1_json.tmpl static/swagger-latest.json
|
||||
|
||||
if [ "$LATEST_ONLY" -eq 1 ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for ver in '1.27.1' '1.26.4' '1.25.5' '1.24.7' '1.23.8' '1.22.6'; do
|
||||
curl --silent --output v1_json.tmpl https://raw.githubusercontent.com/go-gitea/gitea/refs/tags/v${ver}/templates/swagger/v1_json.tmpl
|
||||
inplace_sed "s|\"version\": \"{{.SwaggerAppVer}}\"|\"version\": \"${ver}\"|" v1_json.tmpl
|
||||
inplace_sed 's|"basePath": "{{.SwaggerAppSubUrl}}/api/v1"|"basePath": "https://gitea.com/api/v1"|' v1_json.tmpl
|
||||
# for versions < 1.24
|
||||
inplace_sed "s|\"version\": \"{{AppVer \| JSEscape}}\"|\"version\": \"${ver}\"|" v1_json.tmpl
|
||||
inplace_sed "s#\"basePath\": \"{{AppSubUrl | JSEscape}}/api/v1\"#\"basePath\": \"https://gitea.com/api/v1\"#" v1_json.tmpl
|
||||
download_swagger "refs/tags/v${ver}" v1_json.tmpl
|
||||
rewrite_swagger v1_json.tmpl "${ver}"
|
||||
minor=$(echo "$ver" | cut -d '.' -f 2)
|
||||
mv v1_json.tmpl static/swagger-$minor.json
|
||||
mv v1_json.tmpl "static/swagger-$minor.json"
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user