Files
awesome-copilot/.github/workflows/skill-check-comment.yml
2026-04-14 10:39:08 +10:00

168 lines
6.0 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Skill Validator — PR Comment
# Posts results from the "Skill Validator — PR Gate" workflow.
# Runs with write permissions but never checks out PR code,
# so it is safe for fork PRs.
on:
workflow_run:
workflows: ["Skill Validator — PR Gate"]
types: [completed]
permissions:
pull-requests: write
actions: read # needed to download artifacts
jobs:
comment:
runs-on: ubuntu-latest
if: github.event.workflow_run.event == 'pull_request'
steps:
- name: Download results artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: skill-validator-results
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
- name: Post PR comment with results
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
with:
script: |
const fs = require('fs');
const total = parseInt(fs.readFileSync('total.txt', 'utf8').trim(), 10);
if (total === 0) {
console.log('No skills/agents were checked — skipping comment.');
return;
}
const prNumber = parseInt(fs.readFileSync('pr-number.txt', 'utf8').trim(), 10);
const exitCode = fs.readFileSync('exit-code.txt', 'utf8').trim();
const skillCount = parseInt(fs.readFileSync('skill-count.txt', 'utf8').trim(), 10);
const agentCount = parseInt(fs.readFileSync('agent-count.txt', 'utf8').trim(), 10);
const totalChecked = skillCount + agentCount;
const marker = '<!-- skill-validator-results -->';
const rawOutput = fs.existsSync('sv-output.txt')
? fs.readFileSync('sv-output.txt', 'utf8')
: '';
const output = rawOutput.replace(/\x1b\[[0-9;]*m/g, '').trim();
const errorCount = (output.match(/❌/g) || []).length;
const warningCount = (output.match(/⚠/g) || []).length;
const advisoryCount = (output.match(//g) || []).length;
let verdict = '✅ All checks passed';
if (exitCode !== '0' || errorCount > 0) {
verdict = '⛔ Findings need attention';
} else if (warningCount > 0 || advisoryCount > 0) {
verdict = '⚠️ Warnings or advisories found';
}
const highlightedLines = output
.split('\n')
.map(line => line.trim())
.filter(Boolean)
.filter(line => !line.startsWith('###'))
.filter(line => /^[❌⚠ℹ]/.test(line));
const summaryLines = highlightedLines.length > 0
? highlightedLines.slice(0, 10)
: output
.split('\n')
.map(line => line.trim())
.filter(Boolean)
.filter(line => !line.startsWith('###'))
.slice(0, 10);
const scopeTable = [
'| Scope | Checked |',
'|---|---:|',
`| Skills | ${skillCount} |`,
`| Agents | ${agentCount} |`,
`| Total | ${totalChecked} |`,
];
const severityTable = [
'| Severity | Count |',
'|---|---:|',
`| ❌ Errors | ${errorCount} |`,
`| ⚠️ Warnings | ${warningCount} |`,
`| Advisories | ${advisoryCount} |`,
];
const findingsTable = summaryLines.length === 0
? ['_No findings were emitted by the validator._']
: [
'| Level | Finding |',
'|---|---|',
...summaryLines.map(line => {
const level = line.startsWith('❌')
? '❌'
: line.startsWith('⚠')
? '⚠️'
: line.startsWith('')
? ''
: (exitCode !== '0' ? '⛔' : '');
const text = line.replace(/^[❌⚠ℹ️\s]+/, '').replace(/\|/g, '\\|');
return `| ${level} | ${text} |`;
}),
];
const body = [
marker,
'## 🔍 Skill Validator Results',
'',
`**${verdict}**`,
'',
...scopeTable,
'',
...severityTable,
'',
'### Summary',
'',
...findingsTable,
'',
'<details>',
'<summary>Full validator output</summary>',
'',
'```text',
output || 'No validator output captured.',
'```',
'',
'</details>',
'',
exitCode !== '0'
? '> **Note:** The validator returned a non-zero exit code. Please review the findings above before merge.'
: '',
].filter(Boolean).join('\n');
// Find existing comment with our marker
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100,
});
const existing = comments.find(c => c.body.includes(marker));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
console.log(`Updated existing comment ${existing.id}`);
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});
console.log('Created new PR comment');
}