PR Comment on Notebook Format Check #138
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: PR Comment on Notebook Format Check | |
| on: | |
| workflow_run: | |
| workflows: ["Test Notebook Format"] | |
| types: [completed] | |
| # Write permissions for commenting | |
| permissions: | |
| pull-requests: write | |
| jobs: | |
| comment: | |
| runs-on: ubuntu-latest | |
| if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'failure' | |
| steps: | |
| - name: Download PR comment data | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: pr-comment-data | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-id: ${{ github.event.workflow_run.id }} | |
| - name: Post comment on PR | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| // Read PR number from artifact | |
| const prNumber = parseInt(fs.readFileSync('pr_number', 'utf8').trim()); | |
| if (!prNumber || isNaN(prNumber)) { | |
| console.log('No valid PR number found, skipping comment.'); | |
| return; | |
| } | |
| const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${{ github.event.workflow_run.id }}`; | |
| const commentBody = `## ❌ Notebook Format Check Failed | |
| **One or more Jupyter notebooks are not in canonical format.** | |
| Please check the [workflow run logs](${runUrl}) for details on which notebooks have issues. | |
| ### What is checked: | |
| All notebooks must be in **canonical format** (the exact output of \`nbformat.write()\`): | |
| 1. **Canonical serialization** — 1-space indentation, sorted keys, standard separators | |
| 2. **Cell IDs** — every cell must have an \`id\` field (nbformat 4.5) | |
| 3. **Metadata conformance** — notebooks must have the standard metadata block (accelerator, colab, kernelspec, language_info) | |
| 4. **Clean outputs** — non-SOLUTION notebooks must have outputs, execution counts, and execution timing metadata cleared | |
| 5. **Well-formed outputs** — SOLUTION notebook outputs must be schema-valid (e.g. stream outputs need the \`name\` field) | |
| ### How to fix: | |
| \`\`\`bash | |
| # Auto-fix all issues | |
| python3 brev/test-notebook-format.py --fix | |
| # Auto-fix a specific tutorial | |
| python3 brev/test-notebook-format.py <tutorial-name> --fix | |
| \`\`\` | |
| `; | |
| // Check if we already commented on this PR to avoid spam | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber | |
| }); | |
| const botComment = comments.find(comment => | |
| comment.user.type === 'Bot' && | |
| comment.body.includes('Notebook Format Check Failed') | |
| ); | |
| if (botComment) { | |
| // Update existing comment | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: commentBody | |
| }); | |
| console.log(`Updated existing comment on PR #${prNumber}`); | |
| } else { | |
| // Create new comment | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: commentBody | |
| }); | |
| console.log(`Created comment on PR #${prNumber}`); | |
| } |