diff --git a/.gitea/workflows/update_swagger.yaml b/.gitea/workflows/update_swagger.yaml index a2a09098..bf2b1dfc 100644 --- a/.gitea/workflows/update_swagger.yaml +++ b/.gitea/workflows/update_swagger.yaml @@ -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 "teabot@gitea.io" - 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 "teabot@gitea.io" + 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 <.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. diff --git a/update_api_docs.sh b/update_api_docs.sh index 1f11651d..3a2ad1dd 100755 --- a/update_api_docs.sh +++ b/update_api_docs.sh @@ -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-.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 +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 +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