From 1eceb86ca31416dca15cef5f9eabbb349a709928 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 8 Jul 2026 13:02:43 +1000 Subject: [PATCH 1/2] INFR: Migrate GitHub Pages deploy to artifact-based workflow Replace the peaceiris/actions-gh-pages deploy with native, artifact-based GitHub Pages deployment via quantecon/actions/publish-gh-pages@v0.6.0, matching lecture-jax and lecture-python-advanced.myst. This removes the gh-pages branch dependency so the branch can be deleted, reclaiming a large amount of space (repo is currently ~4.5 GB). The single publish-gh-pages step replaces the previous three-step archive/upload-release/peaceiris-deploy block: it uploads the release assets (create-release-assets) and deploys the Pages artifact via OIDC. The GPU runner, execution-report uploads, and notebook sync are unchanged. linkcheck.yml previously checked out the gh-pages branch, which will no longer exist. Switch it to download and extract the latest release .tar.gz (permanent, not subject to artifact expiry) into _site and point lychee's --root-dir and glob there. lychee is kept (not swapped for the QuantEcon AI checker) to preserve the tuned false-positive suppression from QuantEcon/lecture-python.myst#906 and #933; a follow-up issue tracks the eventual AI-checker upgrade. Part of the rollout tracked in QuantEcon/meta#282. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/linkcheck.yml | 37 ++++++++++++++++------- .github/workflows/publish.yml | 53 ++++++++++++++------------------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 6e447db95..f99e06758 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -9,26 +9,43 @@ jobs: name: Link Checking runs-on: "ubuntu-latest" permissions: + contents: read # read latest release assets via gh api issues: write # required for peter-evans/create-issue-from-file steps: - # Checkout the live site (html) - - name: Checkout - uses: actions/checkout@v7 - with: - ref: gh-pages + # Download the live site (html) from the latest release archive + # (permanent, not subject to artifact expiry) instead of the gh-pages + # branch, which no longer exists after the artifact-based Pages migration. + - name: Get latest release asset URL + id: release + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + ASSET_URL=$(gh api repos/${{ github.repository }}/releases/latest \ + --jq '[.assets[] | select(.name | endswith(".tar.gz")) | .browser_download_url] | first // ""') + if [ -z "$ASSET_URL" ]; then + echo "::error::No .tar.gz asset found on the latest release" + exit 1 + fi + echo "asset-url=$ASSET_URL" >> "$GITHUB_OUTPUT" + - name: Download and extract release HTML + run: | + set -euo pipefail + mkdir -p _site + curl -fsSL "${{ steps.release.outputs.asset-url }}" | tar -xz -C _site - name: Link Checker id: lychee uses: lycheeverse/lychee-action@v2 with: fail: false # --root-dir resolves root-relative links (e.g. /_notebooks/*.ipynb, - # /_pdf/quantecon-python.pdf) against the gh-pages checkout so they are + # /_pdf/quantecon-python.pdf) against the extracted site so they are # not reported as errors. See QuantEcon/lecture-python.myst#906. # # The flags below clear the residual false positives reported in # QuantEcon/lecture-python.myst#933. Configuration is kept inline (rather - # than a lychee.toml) because lychee runs against the gh-pages checkout, - # which does not contain repo-root config files. + # than a lychee.toml) because lychee runs against the extracted release + # archive in _site, which does not contain repo-root config files. # --accept 202 IEEE Xplore returns "202 Accepted" (anti-bot) for # valid links, e.g. doi.org/10.1109/TAC.1977.1101561 # --exclude-path ... genindex / search / prf-prf are auto-generated @@ -42,13 +59,13 @@ jobs: # login/paywall loop (exceeds max-redirects); the # citation itself is valid. args: >- - --root-dir ${{ github.workspace }} + --root-dir ${{ github.workspace }}/_site --accept 200,202,403,503 --exclude-path 'genindex\.html$' --exclude-path 'search\.html$' --exclude-path 'prf-prf\.html$' --exclude '10\.3905/jod\.2012\.20\.1\.038' - *.html + _site/*.html - name: Create Issue From File if: steps.lychee.outputs.exit_code != 0 uses: peter-evans/create-issue-from-file@v6 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 465aecf27..853157949 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,10 +3,26 @@ on: push: tags: - 'publish*' + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: write # write: upload release assets (html archive, checksum, manifest) + actions: read # dawidd6/action-download-artifact reads the cache.yml build artifact + pages: write + id-token: write # required for OIDC-based Pages deployment + +# Allow only one concurrent deployment; don't cancel an in-flight deploy +concurrency: + group: "pages" + cancel-in-progress: false + jobs: publish: if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') runs-on: "runs-on=${{ github.run_id }}/family=g4dn.2xlarge/image=quantecon_ubuntu2404/volume=80gb/spot=false" + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page-url }} steps: - name: Checkout uses: actions/checkout@v7 @@ -92,38 +108,15 @@ jobs: with: name: execution-reports-html path: _build/html/reports - # Create HTML archive for release assets - - name: Create HTML archive - shell: bash -l {0} - run: | - tar -czf lecture-python-html-${{ github.ref_name }}.tar.gz -C _build/html . - sha256sum lecture-python-html-${{ github.ref_name }}.tar.gz > html-checksum.txt - - # Create metadata manifest - cat > html-manifest.json << EOF - { - "tag": "${{ github.ref_name }}", - "commit": "${{ github.sha }}", - "timestamp": "$(date -Iseconds)", - "size_mb": $(du -sm _build/html | cut -f1), - "file_count": $(find _build/html -type f | wc -l) - } - EOF - - name: Upload archives to release - uses: softprops/action-gh-release@v3 - with: - files: | - lecture-python-html-${{ github.ref_name }}.tar.gz - html-checksum.txt - html-manifest.json - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Deploy website to gh-pages - uses: peaceiris/actions-gh-pages@v4 + - name: Deploy to GitHub Pages + id: deployment + uses: quantecon/actions/publish-gh-pages@v0.6.0 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: _build/html/ + build-dir: _build/html cname: python.quantecon.org + create-release-assets: 'true' + asset-name: 'lecture-python-html' + github-token: ${{ secrets.GITHUB_TOKEN }} - name: Prepare lecture-python.notebooks sync shell: bash -l {0} run: | From 53c17a876111f97efd0f5b206b7e1593b90170d7 Mon Sep 17 00:00:00 2001 From: Matt McKay Date: Wed, 8 Jul 2026 13:28:24 +1000 Subject: [PATCH 2/2] linkcheck: pass explicit `-f -` to tar when extracting from the curl pipe Make stdin extraction explicit (tar -xzf -) rather than relying on GNU tar's compiled-in default archive device. Addresses Copilot review feedback on #953. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/linkcheck.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index f99e06758..f6b07c21a 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -32,7 +32,7 @@ jobs: run: | set -euo pipefail mkdir -p _site - curl -fsSL "${{ steps.release.outputs.asset-url }}" | tar -xz -C _site + curl -fsSL "${{ steps.release.outputs.asset-url }}" | tar -xzf - -C _site - name: Link Checker id: lychee uses: lycheeverse/lychee-action@v2