Skip to content

Post content validation comment #49

Post content validation comment

Post content validation comment #49

name: Post content validation comment
# Runs after "Validate content" completes and posts the result as a PR comment.
#
# The pull_request trigger gives a read-only GITHUB_TOKEN for fork PRs — no
# permissions block can override that. workflow_run always runs in the base
# repo's context with a writable token, so it can post comments even when the
# originating PR came from a fork. The validation result is passed via artifact.
on:
workflow_run:
workflows: ["Validate content"]
types: [completed]
jobs:
comment:
runs-on: ubuntu-latest
# Only post comments for PR-triggered runs, not manual workflow_dispatch runs
if: github.event.workflow_run.event == 'pull_request'
permissions:
pull-requests: write
issues: write
actions: read # required to download artifacts from another workflow run
steps:
- name: Download PR info artifact
id: download
uses: actions/download-artifact@v4
continue-on-error: true # gracefully skip if artifact is missing (e.g. cancelled run)
with:
name: pr-info
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
- name: Post or update PR comment
if: steps.download.outcome == 'success'
uses: actions/github-script@v7
with:
script: |
const marker = '<!-- validate-content-bot -->';
const fs = require('fs');
const prNumber = parseInt(fs.readFileSync('pr-number.txt', 'utf8').trim(), 10);
const branch = fs.readFileSync('branch.txt', 'utf8').trim();
const outcome = fs.readFileSync('outcome.txt', 'utf8').trim();
// No content files changed in this PR — nothing to comment on
if (outcome === 'skip') return;
let output = '';
try { output = fs.readFileSync('output.txt', 'utf8').trim(); } catch {}
// Detect if this PR was auto-generated from an issue
const issueMatch = branch.match(/^publish\/issue-(\d+)$/);
const linkedIssue = issueMatch ? issueMatch[1] : null;
const fixNote = linkedIssue
? `\n\nThis PR was auto-generated from issue #${linkedIssue}. [Edit the issue](https://github.com/${context.repo.owner}/${context.repo.repo}/issues/${linkedIssue}) to fix the errors above — removing and re-adding the \`approved\` label will regenerate the PR automatically.`
: `\n\nFix the errors above and push again — validation will re-run automatically.`;
const successBody = `${marker}\n✅ **Content validation passed!**`;
const failureBody = `${marker}\n## ❌ Content Validation Failed\n\n\`\`\`\n${output}\n\`\`\`${fixNote}`;
const body = outcome === 'failure' ? failureBody : successBody;
const { data: issueComments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
const existing = issueComments.find(c => c.body?.includes(marker));
if (existing) {
await github.rest.issues.deleteComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
});
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});