Edit data for **PCD @ Montreal** #32
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: Zine Intake | |
| on: | |
| issues: | |
| types: [opened, edited, reopened, labeled] | |
| concurrency: | |
| group: new-zine-intake-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| env: | |
| STATUS_COMMENT_MARKER: <!-- new-zine-intake-status --> | |
| jobs: | |
| publish-zine-review: | |
| if: contains(github.event.issue.labels.*.name, 'new zine') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.repository.default_branch }} | |
| fetch-depth: 0 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '24' | |
| cache: npm | |
| cache-dependency-path: pcd-website/package-lock.json | |
| - name: Inspect open zine review pull requests | |
| id: open-prs | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const branch = `automation/new-zine-${context.issue.number}`; | |
| const pulls = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', per_page: 100 }); | |
| const reserved = new Set(); const orders = []; let current; let currentSlug = ''; | |
| for (const pull of pulls) { | |
| const isCurrent = pull.head.ref === branch && pull.head.repo?.full_name === `${owner}/${repo}`; | |
| const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number: pull.number, per_page: 100 }); | |
| for (const file of files) { | |
| const match = file.filename.match(/^pcd-website\/src\/content\/zines\/([^/]+)\//); | |
| if (match && file.status !== 'removed' && !isCurrent) reserved.add(match[1]); | |
| if (match && file.status !== 'removed' && isCurrent) currentSlug = match[1]; | |
| const indexMatch = file.filename.match(/^pcd-website\/src\/content\/zines\/([^/]+)\/index\.md$/); | |
| if (!indexMatch || file.status === 'removed') continue; | |
| try { | |
| const index = await github.rest.repos.getContent({ owner, repo, path: file.filename, ref: pull.head.sha }); | |
| const text = Buffer.from(index.data.content, index.data.encoding).toString('utf8'); | |
| const orderMatch = text.match(/^order:\s*(\d+)\s*$/m); | |
| if (!orderMatch) continue; | |
| if (isCurrent) core.setOutput('current_order', orderMatch[1]); | |
| else orders.push(orderMatch[1]); | |
| } catch {} | |
| } | |
| if (isCurrent) current = pull; | |
| } | |
| core.setOutput('reserved_slugs', [...reserved].join(',')); | |
| core.setOutput('orders', orders.join(',')); | |
| core.setOutput('current_slug', currentSlug); | |
| core.setOutput('current_pr_number', current?.number ?? ''); | |
| - name: Install website dependencies | |
| run: npm ci | |
| working-directory: pcd-website | |
| - name: Generate and validate publication-ready zine | |
| id: generate | |
| run: node .github/scripts/process-new-zine-issue.mjs | |
| env: | |
| ZINE_RESERVED_SLUGS: ${{ steps.open-prs.outputs.reserved_slugs }} | |
| ZINE_OPEN_PR_ORDERS: ${{ steps.open-prs.outputs.orders }} | |
| ZINE_CURRENT_SLUG: ${{ steps.open-prs.outputs.current_slug }} | |
| ZINE_CURRENT_ORDER: ${{ steps.open-prs.outputs.current_order }} | |
| - name: Build the production site | |
| if: steps.generate.outputs.valid == 'true' | |
| run: npm run build | |
| working-directory: pcd-website | |
| - name: Publish review branch | |
| if: steps.generate.outputs.valid == 'true' | |
| env: | |
| BRANCH: ${{ steps.generate.outputs.branch }} | |
| MESSAGE: ${{ steps.generate.outputs.commit_message }} | |
| run: | | |
| git config user.name github-actions[bot] | |
| git config user.email 41898282+github-actions[bot]@users.noreply.github.com | |
| git switch -C "$BRANCH" | |
| git add pcd-website/src/content/zines | |
| git commit -m "$MESSAGE" | |
| git push --force-with-lease origin "$BRANCH" | |
| - name: Create or update review pull request | |
| if: steps.generate.outputs.valid == 'true' | |
| id: review-pr | |
| uses: actions/github-script@v8 | |
| env: | |
| BRANCH: ${{ steps.generate.outputs.branch }} | |
| TITLE: ${{ steps.generate.outputs.pr_title }} | |
| BODY_PATH: ${{ steps.generate.outputs.pr_body_path }} | |
| with: | |
| script: | | |
| const fs = require('fs'); const body = fs.readFileSync(process.env.BODY_PATH, 'utf8'); | |
| const pulls = await github.rest.pulls.list({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', head: `${context.repo.owner}:${process.env.BRANCH}` }); | |
| const input = { owner: context.repo.owner, repo: context.repo.repo, title: process.env.TITLE, body }; | |
| const pull = pulls.data[0] ? await github.rest.pulls.update({ ...input, pull_number: pulls.data[0].number }) : await github.rest.pulls.create({ ...input, head: process.env.BRANCH, base: context.payload.repository.default_branch }); | |
| await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pull.data.number, labels: ['new zine', 'needs review'] }); | |
| try { | |
| await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pull.data.number, name: 'needs changes' }); | |
| } catch (error) { if (error.status !== 404) throw error; } | |
| core.setOutput('number', pull.data.number); core.setOutput('url', pull.data.html_url); | |
| - name: Upsert successful intake status | |
| if: steps.generate.outputs.valid == 'true' | |
| uses: actions/github-script@v8 | |
| env: | |
| PR_NUMBER: ${{ steps.review-pr.outputs.number }} | |
| PR_URL: ${{ steps.review-pr.outputs.url }} | |
| TITLE: ${{ steps.generate.outputs.zine_title }} | |
| with: | |
| script: | | |
| const marker = process.env.STATUS_COMMENT_MARKER; | |
| const body = `${marker}\n**"${process.env.TITLE}"** is ready for review in [#${process.env.PR_NUMBER}](${process.env.PR_URL}).`; | |
| const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); | |
| const existing = comments.find((comment) => comment.user?.type === 'Bot' && comment.body?.includes(marker)); | |
| const input = { owner: context.repo.owner, repo: context.repo.repo, body }; | |
| if (existing) await github.rest.issues.updateComment({ ...input, comment_id: existing.id }); else await github.rest.issues.createComment({ ...input, issue_number: context.issue.number }); | |
| - name: Upsert validation status | |
| if: steps.generate.outputs.valid == 'false' | |
| uses: actions/github-script@v8 | |
| env: | |
| COMMENT_PATH: ${{ steps.generate.outputs.validation_comment_path }} | |
| CURRENT_PR_NUMBER: ${{ steps.open-prs.outputs.current_pr_number }} | |
| with: | |
| script: | | |
| const fs = require('fs'); const marker = process.env.STATUS_COMMENT_MARKER; | |
| const pullNumber = Number(process.env.CURRENT_PR_NUMBER); | |
| if (Number.isInteger(pullNumber) && pullNumber > 0) { | |
| const label = { name: 'needs changes', color: 'd93f0b', description: 'Submission changes are required before review can continue' }; | |
| try { await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label.name }); } | |
| catch (error) { if (error.status === 404) await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, ...label }); else throw error; } | |
| await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pullNumber, labels: [label.name] }); | |
| try { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pullNumber, name: 'needs review' }); } | |
| catch (error) { if (error.status !== 404) throw error; } | |
| } | |
| const body = `${marker}\n> [!WARNING]\n> The existing review PR, if any, was left unchanged.\n\n${fs.readFileSync(process.env.COMMENT_PATH, 'utf8')}`; | |
| const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); | |
| const existing = comments.find((comment) => comment.user?.type === 'Bot' && comment.body?.includes(marker)); | |
| const input = { owner: context.repo.owner, repo: context.repo.repo, body }; | |
| if (existing) await github.rest.issues.updateComment({ ...input, comment_id: existing.id }); else await github.rest.issues.createComment({ ...input, issue_number: context.issue.number }); |