Skip to content
This repository was archived by the owner on Jul 4, 2026. It is now read-only.

Post Test Results

Post Test Results #89

name: Post Test Results
on:
workflow_run:
workflows: ["CI/CD Pipeline"]
types: [completed]
permissions:
contents: read
issues: write
pull-requests: write
actions: read
jobs:
comment-on-pr:
# Run regardless of success or failure
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Download artifacts from triggering workflow
uses: actions/download-artifact@v4
with:
path: ./artifacts
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
continue-on-error: true
- name: Get job results from workflow run
id: get-jobs
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
// Get all jobs from the triggering workflow run
const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }}
});
// Extract job results for each node version
const results = jobs.jobs
.filter(job => job.name.includes('build-and-test'))
.map(job => {
const match = job.name.match(/\((\d+\.x)\)/);
const nodeVersion = match ? match[1] : 'unknown';
let status;
if (job.conclusion === 'success') {
status = '✅ Passed';
} else if (job.conclusion === 'failure') {
status = '❌ Failed';
} else if (job.conclusion === 'cancelled') {
status = '⚠️ Cancelled';
} else if (job.conclusion === 'skipped') {
status = '⏭️ Skipped';
} else {
status = '❓ Unknown';
}
return {
nodeVersion,
status,
conclusion: job.conclusion,
htmlUrl: job.html_url
};
});
// Save results to file
fs.mkdirSync('./job-results', { recursive: true });
fs.writeFileSync(
'./job-results/results.json',
JSON.stringify(results, null, 2)
);
console.log('Job results:', JSON.stringify(results, null, 2));
return results;
- name: Parse test logs (supplementary)
id: parse-logs
run: node .github/scripts/parse-logs.js
continue-on-error: true
- name: Post comment on Pull Request
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const owner = context.repo.owner;
const repo = context.repo.repo;
// 1) Try payload PR (works when GH provides it)
let prNumber = context.payload.workflow_run?.pull_requests?.[0]?.number;
// 2) Resolve from workflow run's head repo + head branch (works for forks)
if (!prNumber) {
const runId = context.payload.workflow_run.id;
const { data: run } = await github.rest.actions.getWorkflowRun({
owner, repo, run_id: runId
});
const headBranch = run.head_branch;
const headRepoFull = run.head_repository?.full_name;
if (headRepoFull && headBranch) {
const headSpecifier = `${headRepoFull.split('/')[0]}:${headBranch}`;
// List PRs where this fork branch is the head
const { data: prs } = await github.rest.pulls.list({
owner, repo, state: 'open', head: headSpecifier
});
if (prs.length) {
prNumber = prs[0].number;
core.info(`Resolved PR #${prNumber} via head=${headSpecifier}`);
} else {
core.info(`No open PR found with head=${headSpecifier}`);
}
} else {
core.info('head_repository or head_branch missing on workflow run.');
}
}
if (!prNumber) {
core.info('No pull request associated with this run.');
return;
}
// Read job results (if generated by the earlier step)
const resultsPath = './job-results/results.json';
let results = [];
if (fs.existsSync(resultsPath)) {
results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
} else {
core.info('No job results file found; proceeding with overall status only.');
}
// Build comment body
const overallStatus = context.payload.workflow_run.conclusion;
const statusEmoji = overallStatus === 'success' ? '✅'
: overallStatus === 'failure' ? '❌'
: 'ℹ️';
let body = `### ${statusEmoji} CI/CD Test Results\n\n`;
body += `**Overall Status**: ${overallStatus}\n\n`;
if (results.length) {
body += `#### Node.js Version Results:\n\n`;
for (const r of results) {
body += `- **Node ${r.nodeVersion}**: ${r.status}${r.htmlUrl ? ` ([View logs](${r.htmlUrl}))` : ''}\n`;
}
body += `\n`;
}
body += `---\n[View full workflow run](${context.payload.workflow_run.html_url})`;
// Upsert comment
const { data: comments } = await github.rest.issues.listComments({
owner, repo, issue_number: prNumber
});
const botComment = comments.find(c =>
c.user?.type === 'Bot' && c.body?.includes('CI/CD Test Results')
);
if (botComment) {
await github.rest.issues.updateComment({
owner, repo, comment_id: botComment.id, body
});
core.info(`Updated existing comment on PR #${prNumber}`);
} else {
await github.rest.issues.createComment({
owner, repo, issue_number: prNumber, body
});
core.info(`Created new comment on PR #${prNumber}`);
}