runtime error after #103 #19
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: "Issue → PR: Add Example" | |
| on: | |
| issues: | |
| types: [opened] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| make-pr: | |
| if: startsWith(github.event.issue.title, '[example]') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Extract metadata and code from issue body | |
| id: extract | |
| run: | | |
| set -euo pipefail | |
| node -e ' | |
| const fs = require("fs"); | |
| const body = process.env.ISSUE_BODY; | |
| // Extract JSON metadata | |
| const jsonMatch = body.match(/```json\s*([\s\S]*?)```/); | |
| if (!jsonMatch) { console.error("JSON block not found"); process.exit(1); } | |
| const metadata = JSON.parse(jsonMatch[1]); | |
| // Extract assembly code | |
| const codeMatch = body.match(/```assembly\s*([\s\S]*?)```/); | |
| if (!codeMatch) { console.error("Assembly code block not found"); process.exit(2); } | |
| const code = codeMatch[1]; | |
| // Validate slug | |
| const ok = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(metadata.slug || ""); | |
| if (!ok) { console.error("Invalid slug"); process.exit(3); } | |
| // Combine metadata and code into payload (temporary file, not committed) | |
| const payload = { ...metadata, code }; | |
| fs.writeFileSync("payload.json", JSON.stringify(payload, null, 2)); | |
| ' | |
| env: | |
| ISSUE_BODY: ${{ github.event.issue.body }} | |
| - name: Render files from payload | |
| id: render | |
| run: | | |
| set -euo pipefail | |
| jq -r . payload.json > /dev/null | |
| SLUG="$(jq -r .slug payload.json)" | |
| TITLE="$(jq -r .title payload.json)" | |
| DESC="$(jq -r .description payload.json)" | |
| AUTHOR="$(jq -r .author payload.json)" | |
| LICENSE="$(jq -r '.license // "CC-BY-4.0"' payload.json)" | |
| SRC_URL="$(jq -r '.sourceUrl // empty' payload.json)" | |
| GH_USER="$(jq -r '.githubUsername // empty' payload.json)" | |
| CODE="$(jq -r .code payload.json)" | |
| DISP="$(jq -r .displayMemory payload.json)" | |
| BASE_DIR="packages/examples/${SLUG}" | |
| CODE_PATH="${BASE_DIR}/${SLUG}.asm" | |
| META_PATH="${BASE_DIR}/${SLUG}.meta.ts" | |
| mkdir -p "$BASE_DIR" | |
| # Write code directly to file | |
| printf "%s" "$CODE" > "$CODE_PATH" | |
| # Helper function for JSON escaping | |
| esc() { printf "%s" "$1" | python3 -c 'import sys,json;print(json.dumps(sys.stdin.read())[1:-1])'; } | |
| # Build the TypeScript file content | |
| { | |
| echo 'import { _ } from "@learn6502/6502";' | |
| echo 'import type { ExampleMetaJson } from "../example-meta.ts";' | |
| echo 'export default {' | |
| echo " slug: \"$(esc "$SLUG")\"," | |
| echo " title: _(\"$(esc "$TITLE")\")," | |
| echo " description: _(\"$(esc "$DESC")\")," | |
| echo " author: \"$(esc "$AUTHOR")\"," | |
| echo " license: \"$(esc "$LICENSE")\"," | |
| echo " displayMemory: \"$(esc "$DISP")\"," | |
| if [ -n "$SRC_URL" ]; then | |
| echo " sourceUrl: \"$(esc "$SRC_URL")\"," | |
| fi | |
| if [ -n "$GH_USER" ]; then | |
| echo " githubUsername: \"$(esc "$GH_USER")\"," | |
| fi | |
| echo '} as ExampleMetaJson;' | |
| } > "$META_PATH" | |
| echo "CODE_PATH=$CODE_PATH" >> $GITHUB_OUTPUT | |
| echo "META_PATH=$META_PATH" >> $GITHUB_OUTPUT | |
| echo "BASE_DIR=$BASE_DIR" >> $GITHUB_OUTPUT | |
| echo "SLUG=$SLUG" >> $GITHUB_OUTPUT | |
| # Remove temporary file to prevent accidental commit | |
| rm -f payload.json | |
| - name: Create branch | |
| run: | | |
| BR="examples/issue-${{ github.event.issue.number }}" | |
| echo "BRANCH=$BR" >> $GITHUB_ENV | |
| git switch -c "$BR" | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "24" | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Install dependencies | |
| run: yarn install --immutable | |
| - name: Build examples | |
| run: yarn workspace @learn6502/examples run build | |
| - name: Format code | |
| run: yarn format | |
| - name: Commit with author = issue opener | |
| env: | |
| AUTHOR_NAME: ${{ github.event.issue.user.login }} | |
| AUTHOR_EMAIL: ${{ github.event.issue.user.id }}+${{ github.event.issue.user.login }}@users.noreply.github.com | |
| run: | | |
| git add -A | |
| git -c user.name="github-actions[bot]" \ | |
| -c user.email="41898282+github-actions[bot]@users.noreply.github.com" \ | |
| commit --author="${AUTHOR_NAME} <${AUTHOR_EMAIL}>" \ | |
| -m "feat(example): add ${{ steps.render.outputs.SLUG }} (from issue #${{ github.event.issue.number }}) | |
| Co-authored-by: ${{ github.event.issue.user.login }} <${{ github.event.issue.user.id }}+${{ github.event.issue.user.login }}@users.noreply.github.com> | |
| Signed-off-by: ${{ github.event.issue.user.login }} <${{ github.event.issue.user.id }}+${{ github.event.issue.user.login }}@users.noreply.github.com> | |
| " | |
| - name: Push | |
| run: git push -u origin "$BRANCH" | |
| - name: Open PR | |
| id: open_pr | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const { data: pr } = await github.rest.pulls.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: 'Add example: ${{ steps.render.outputs.SLUG }} (from issue #${{ github.event.issue.number }})', | |
| head: '${{ env.BRANCH }}', | |
| base: 'main', | |
| body: `Generated from issue #${{ github.event.issue.number }} by workflow. | |
| Files: | |
| - \`${{ steps.render.outputs.META_PATH }}\` | |
| - \`${{ steps.render.outputs.CODE_PATH }}\` | |
| Closes #${{ github.event.issue.number }}` | |
| }); | |
| console.log(`Pull request created: ${pr.html_url}`); | |
| core.setOutput('pr_number', pr.number); | |
| core.setOutput('pr_url', pr.html_url); | |
| - name: Comment on issue | |
| id: comment | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| await github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: '✅ Pull request created: #${{ steps.open_pr.outputs.pr_number }}\n\nYour example will be reviewed and merged soon. Thank you for contributing! 🎉' | |
| }) |