[ci] Migrate from nwtgck/actions-netlify@v3 to netlify-cli for better PR preview control #1541
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Project [using jupyter-book] | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| workflow_dispatch: | |
| inputs: | |
| preview_page: | |
| description: 'Specific page to preview (e.g., aiyagari.html)' | |
| required: false | |
| type: string | |
| jobs: | |
| preview: | |
| runs-on: "runs-on=${{ github.run_id }}/family=g4dn.2xlarge/image=quantecon_ubuntu2404/disk=large" | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| fetch-depth: 0 | |
| - name: Setup Anaconda | |
| uses: conda-incubator/setup-miniconda@v3 | |
| with: | |
| auto-update-conda: true | |
| auto-activate-base: true | |
| miniconda-version: 'latest' | |
| python-version: "3.13" | |
| environment-file: environment.yml | |
| activate-environment: quantecon | |
| - name: Install JAX, Numpyro, PyTorch | |
| shell: bash -l {0} | |
| run: | | |
| pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu128 | |
| pip install pyro-ppl | |
| pip install --upgrade "jax[cuda12-local]==0.6.2" | |
| pip install numpyro pyro-ppl | |
| python scripts/test-jax-install.py | |
| - name: Check nvidia Drivers | |
| shell: bash -l {0} | |
| run: nvidia-smi | |
| - name: Display Conda Environment Versions | |
| shell: bash -l {0} | |
| run: conda list | |
| - name: Display Pip Versions | |
| shell: bash -l {0} | |
| run: pip list | |
| - name: Download "build" folder (cache) | |
| uses: dawidd6/action-download-artifact@v11 | |
| with: | |
| workflow: cache.yml | |
| branch: main | |
| name: build-cache | |
| path: _build | |
| # Build Assets (Download Notebooks and PDF via LaTeX) | |
| - name: Build Download Notebooks (sphinx-tojupyter) | |
| shell: bash -l {0} | |
| run: | | |
| jb build lectures -n -W --keep-going --path-output ./ --builder=custom --custom-builder=jupyter | |
| mkdir -p _build/html/_notebooks | |
| cp -u _build/jupyter/*.ipynb _build/html/_notebooks | |
| - name: Upload Execution Reports (Download Notebooks) | |
| uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: execution-reports-notebooks | |
| path: _build/jupyter/reports | |
| - name: Build PDF from LaTeX | |
| shell: bash -l {0} | |
| run: | | |
| jb build lectures --builder pdflatex --path-output ./ -W --keep-going | |
| mkdir -p _build/html/_pdf | |
| cp -u _build/latex/*.pdf _build/html/_pdf | |
| - name: Upload Execution Reports (LaTeX) | |
| uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: execution-reports | |
| path: _build/latex/reports | |
| # Final Build of HTML | |
| - name: Build HTML | |
| shell: bash -l {0} | |
| run: | | |
| jb build lectures --path-output ./ -n -W --keep-going | |
| - name: Upload Execution Reports (HTML) | |
| uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: execution-reports | |
| path: _build/html/reports | |
| - name: Install Node.js and Netlify CLI | |
| shell: bash -l {0} | |
| run: | | |
| # Install Node.js via system package manager since conda-forge doesn't have npm | |
| sudo apt-get update | |
| sudo apt-get install -y nodejs npm | |
| sudo npm install -g netlify-cli | |
| - name: Detect Changed Lecture Files | |
| id: detect-changes | |
| shell: bash -l {0} | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "Detecting changed lecture files..." | |
| # Get changed files in the lectures directory | |
| changed_files=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} | grep '^lectures/.*\.md$' | grep -v '^lectures/_' || true) | |
| if [ ! -z "$changed_files" ]; then | |
| echo "Changed lecture files:" | |
| echo "$changed_files" | |
| echo "changed_files<<EOF" >> $GITHUB_OUTPUT | |
| echo "$changed_files" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| else | |
| echo "No lecture files changed" | |
| echo "changed_files=" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "Not a PR, skipping change detection" | |
| echo "changed_files=" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Preview Deploy to Netlify | |
| id: netlify-deploy | |
| shell: bash -l {0} | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| # Deploy to Netlify and capture the response | |
| deploy_message="Preview Deploy from GitHub Actions PR #${{ github.event.pull_request.number }} (commit: ${{ github.sha }})" | |
| netlify_output=$(netlify deploy \ | |
| --dir _build/html/ \ | |
| --site ${{ secrets.NETLIFY_SITE_ID }} \ | |
| --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} \ | |
| --context deploy-preview \ | |
| --alias deploy-preview-${{ github.event.pull_request.number }} \ | |
| --message "${deploy_message}" \ | |
| --json) | |
| echo "Netlify deployment output:" | |
| echo "$netlify_output" | |
| # Extract the actual deploy URL from the JSON response | |
| deploy_url=$(echo "$netlify_output" | jq -r '.deploy_url') | |
| echo "deploy_url=$deploy_url" >> $GITHUB_OUTPUT | |
| echo "✅ Deployment completed!" | |
| echo "🌐 Actual Deploy URL: $deploy_url" | |
| # Generate preview URLs for changed files using the actual deploy URL | |
| if [ ! -z "${{ steps.detect-changes.outputs.changed_files }}" ]; then | |
| echo "" | |
| echo "📚 Direct links to changed lecture pages:" | |
| while read -r file; do | |
| if [ ! -z "$file" ]; then | |
| basename=$(basename "$file" .md) | |
| html_file="${basename}.html" | |
| echo "- ${basename}: ${deploy_url}/${html_file}" | |
| fi | |
| done <<< "${{ steps.detect-changes.outputs.changed_files }}" | |
| fi | |
| # Display manual preview page if specified | |
| if [ ! -z "${{ github.event.inputs.preview_page }}" ]; then | |
| echo "" | |
| echo "🎯 Manual preview page: ${deploy_url}/${{ github.event.inputs.preview_page }}" | |
| fi | |
| else | |
| # Handle manual deployment | |
| deploy_message="Manual Deploy from GitHub Actions (commit: ${{ github.sha }})" | |
| netlify_output=$(netlify deploy \ | |
| --dir _build/html/ \ | |
| --site ${{ secrets.NETLIFY_SITE_ID }} \ | |
| --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} \ | |
| --alias manual-${{ github.run_id }} \ | |
| --context dev \ | |
| --message "${deploy_message}" \ | |
| --json) | |
| echo "Netlify deployment output:" | |
| echo "$netlify_output" | |
| # Extract the actual deploy URL from the JSON response | |
| deploy_url=$(echo "$netlify_output" | jq -r '.deploy_url') | |
| echo "deploy_url=$deploy_url" >> $GITHUB_OUTPUT | |
| echo "✅ Manual deployment completed!" | |
| echo "🌐 Actual Deploy URL: $deploy_url" | |
| if [ ! -z "${{ github.event.inputs.preview_page }}" ]; then | |
| echo "🎯 Preview page: ${deploy_url}/${{ github.event.inputs.preview_page }}" | |
| fi | |
| fi | |
| env: | |
| NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} | |
| NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} | |
| - name: Post PR Comment with Preview Links | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const changedFiles = `${{ steps.detect-changes.outputs.changed_files }}`; | |
| const manualPage = `${{ github.event.inputs.preview_page }}`; | |
| const deployUrl = `${{ steps.netlify-deploy.outputs.deploy_url }}`; | |
| const prNumber = ${{ github.event.pull_request.number }}; | |
| const commitSha = `${{ github.sha }}`; | |
| // Check if we already posted a comment for this commit | |
| const comments = await github.rest.issues.listComments({ | |
| issue_number: prNumber, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }); | |
| const existingCommentForCommit = comments.data.find(c => | |
| c.body.includes('## 📖 Netlify Preview Ready!') && | |
| c.body.includes(`**Commit:** \`${commitSha}\``) | |
| ); | |
| if (existingCommentForCommit) { | |
| console.log(`Comment already exists for commit ${commitSha}, skipping...`); | |
| return; | |
| } | |
| let comment = `## 📖 Netlify Preview Ready!\n\n`; | |
| comment += `**Preview URL:** ${deployUrl}\n\n`; | |
| comment += `**Commit:** \`${{ github.sha }}\`\n\n`; | |
| // Add manual preview page if specified | |
| if (manualPage) { | |
| comment += `🎯 **Manual Preview:** [${manualPage}](${deployUrl}/${manualPage})\n\n`; | |
| } | |
| // Add direct links to changed lecture pages | |
| if (changedFiles) { | |
| const files = changedFiles.split('\n').filter(f => f.trim()); | |
| if (files.length > 0) { | |
| comment += `📚 **Changed Lecture Pages:**\n`; | |
| for (const file of files) { | |
| if (file.trim()) { | |
| const fileName = file.replace('lectures/', '').replace('.md', ''); | |
| const pageUrl = `${deployUrl}/${fileName}.html`; | |
| comment += `- [${fileName}](${pageUrl})\n`; | |
| } | |
| } | |
| } | |
| } | |
| // Post the comment | |
| await github.rest.issues.createComment({ | |
| issue_number: prNumber, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: comment | |
| }); |