name: docs site build and push on: push: branches: - main # Build-only (no push) on PRs that touch the build/deploy pipeline, so # Dockerfile / workflow changes are validated before they reach main. pull_request: paths: - 'docker/**' - '.dockerignore' - '.github/workflows/build_n_push.yml' - 'next.config.mjs' - 'package.json' - 'package-lock.json' workflow_dispatch: permissions: contents: read # Serialise non-PR runs while allowing superseded PR validation to be canceled. # Builds publish only an immutable SHA tag; the mutable ref tag is promoted # separately after the build and a final ref check. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: docs_build_n_push: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # Full history so gen:last-updated / gen:sitemap can read real # per-file commit dates (a shallow clone would yield wrong dates). fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Restore Next.js build cache uses: actions/cache@v4 with: path: .next/cache key: ${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}-${{ hashFiles('src/**', 'mdx/**', 'next.config.mjs') }} restore-keys: | ${{ runner.os }}-nextjs-${{ hashFiles('package-lock.json') }}- - name: Build run: npm run build - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: netbirdio/docs.netbird.io - name: Login to DockerHub if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} # Non-PR runs publish an immutable image first. A canceled or stale run # can leave this tag behind, but it cannot change :main (or another # mutable ref tag). - name: Docker build and publish immutable image uses: docker/build-push-action@v6 with: context: . file: docker/Dockerfile push: ${{ github.event_name != 'pull_request' }} # Keep a single-arch manifest (no attestation index) so the server's # `docker compose pull` stays happy. provenance: false tags: netbirdio/docs.netbird.io:${{ github.sha }} labels: ${{ steps.meta.outputs.labels }} # Promotion is a single remote manifest-tag update after the expensive # build. Combined with serialisation and the final ref comparison, an # older run cannot replace the mutable tag after a newer run publishes. - name: Promote current image to ref tag if: github.event_name != 'pull_request' env: SOURCE_IMAGE: netbirdio/docs.netbird.io:${{ github.sha }} TARGET_TAGS: ${{ steps.meta.outputs.tags }} run: | remote_sha="$(git ls-remote origin "${GITHUB_REF}" | awk 'NR == 1 { print $1 }')" if [ -z "$remote_sha" ]; then echo "Could not resolve ${GITHUB_REF} on origin" >&2 exit 1 fi if [ "$GITHUB_SHA" != "$remote_sha" ]; then echo "Skipping tag promotion: ${GITHUB_SHA} is stale; ${GITHUB_REF} is now ${remote_sha}" exit 0 fi if [ -z "$TARGET_TAGS" ]; then echo "Docker metadata produced no target tags" >&2 exit 1 fi while IFS= read -r target_tag; do if [ -n "$target_tag" ]; then docker buildx imagetools create \ --prefer-index=false \ --tag "$target_tag" \ "$SOURCE_IMAGE" fi done <<< "$TARGET_TAGS"