name: generate api pages on: workflow_dispatch: inputs: tag: description: 'Netbird release tag version' required: true default: "refs/tags/vX.Y.Z" type: string permissions: actions: read contents: read # One run at a time: overlapping dispatches (several release tags in a day # happen — see run history) regenerate the same files and would collide. A # queued run superseded by a newer dispatch is fine: every run regenerates the # whole directory from its own tag, so the latest dispatch is the end state. # NB "latest dispatched", not "newest tag" — re-dispatching an older tag after # a newer one regresses the pages to the older spec. concurrency: group: ${{ github.workflow }}-${{ github.ref }} jobs: generate_api_pages: runs-on: macos-latest steps: - name: Parse tag input id: semver_parser uses: booxmedialtd/ws-action-parse-semver@v1 with: input_string: ${{ github.event.inputs.tag }} version_extractor_regex: '\/v(.*)$' - uses: actions/checkout@v6 with: token: ${{ secrets.DEV_GITHUB_TOKEN }} # A run queued behind another (see concurrency above) checks out the # commit pinned at its dispatch time, not the branch's current tip. # Sync before generating so the diff is computed against reality — # otherwise the pre-push rebase replays a stale-base snapshot, and a # file the newer spec removed could silently survive from the prior run. - name: Sync to branch tip run: | git fetch origin "${GITHUB_REF_NAME}" git reset --hard "origin/${GITHUB_REF_NAME}" - name: Create directory run: mkdir -p generator/openapi - name: Download openapi.yml run: curl -L -o generator/openapi/openapi.yml "https://raw.githubusercontent.com/netbirdio/netbird/v${{ steps.semver_parser.outputs.fullversion }}/shared/management/http/api/openapi.yml" - name: Install Go uses: actions/setup-go@v6 with: go-version: '1.25' - name: Build Go project run: (cd ./generator && go build -o expandOpenAPIRef) - name: Expand openapi.yml run: (cd ./generator && ./expandOpenAPIRef) - name: Remove old generated files run: rm -rf src/pages/ipa/resources/* - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' # npm ci: this workflow never changes dependencies, so install exactly # the committed lockfile and never mutate it (macos-latest's npm can # differ from the one that generated package-lock.json). - name: Install dependencies run: npm ci - name: Generate api pages for netbird main openapi definition run: npx ts-node generator/index.ts gen --input generator/openapi/expanded.yml --output src/pages/ipa/resources - name: Check git diff and untracked files id: git_diff run: | if [ -n "$(git status --porcelain src/pages/ipa/resources)" ]; then echo "changed=true" >> "$GITHUB_OUTPUT" else echo "changed=false" >> "$GITHUB_OUTPUT" fi # Concurrency serialises runs but does not guarantee dispatch order. A # delayed older run must not overwrite output from a newer dispatch. - name: Check whether this is the latest dispatch id: freshness if: steps.git_diff.outputs.changed == 'true' env: GH_TOKEN: ${{ github.token }} run: | latest_run_id="$( curl --fail --silent --show-error \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28" \ --get \ --data-urlencode "event=workflow_dispatch" \ --data-urlencode "branch=${GITHUB_REF_NAME}" \ --data-urlencode "per_page=1" \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/workflows/generate_api_pages.yml/runs" \ | python3 -c 'import json, sys; print(json.load(sys.stdin)["workflow_runs"][0]["id"])' )" if [ "$GITHUB_RUN_ID" = "$latest_run_id" ]; then echo "push=true" >> "$GITHUB_OUTPUT" else echo "push=false" >> "$GITHUB_OUTPUT" echo "Skipping generated-page commit: run ${GITHUB_RUN_ID} was superseded by ${latest_run_id}" fi - name: Commit and push changes if: steps.git_diff.outputs.changed == 'true' && steps.freshness.outputs.push == 'true' run: | git config --global user.email "dev@netbird.io" git config --global user.name "netbirddev" # Stage only the regenerated API pages — never sweep up incidental # changes like a rewritten package-lock.json. git add src/pages/ipa/resources git commit -m "Update API pages with v${{ steps.semver_parser.outputs.fullversion }}" # The run takes minutes; if the branch moved meanwhile, replay our # single generated-files commit on top instead of failing the push. # A conflict is only possible against a concurrent edit of the # generated files themselves and fails the run loudly. git pull --rebase origin "${GITHUB_REF_NAME}" git push