Skip to content

Release v0.2.0-rc3: Headless Components with RC2 Features #66

Release v0.2.0-rc3: Headless Components with RC2 Features

Release v0.2.0-rc3: Headless Components with RC2 Features #66

name: Bot CI Integration
on:
pull_request:
types: [opened, synchronize]
check_suite:
types: [completed]
workflow_run:
workflows: ["CI"]
types: [completed]
permissions:
contents: write
pull-requests: write
checks: read
jobs:
monitor-ci-for-bots:
name: Monitor CI for Bot PRs
runs-on: ubuntu-latest
# Only run for bot-created PRs
if: |
(github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'bot-created')) ||
(github.event_name == 'check_suite' && github.event.check_suite.pull_requests[0] && contains(github.event.check_suite.pull_requests[0].labels.*.name, 'bot-created')) ||
(github.event_name == 'workflow_run' && github.event.workflow_run.pull_requests[0])
steps:
- name: Get PR details
id: pr-details
uses: actions/github-script@v7
with:
script: |
let prNumber;
if (context.eventName === 'pull_request') {
prNumber = context.payload.pull_request.number;
} else if (context.eventName === 'check_suite') {
prNumber = context.payload.check_suite.pull_requests[0]?.number;
} else if (context.eventName === 'workflow_run') {
prNumber = context.payload.workflow_run.pull_requests[0]?.number;
}
if (!prNumber) {
console.log('No PR number found');
return null;
}
// Get PR details
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
// Check if this is a bot PR
const labels = pr.data.labels.map(l => l.name);
const isBotPR = labels.includes('bot-created') || labels.includes('agent:wip') || labels.includes('agent:needs-review');
core.setOutput('pr_number', prNumber);
core.setOutput('is_bot_pr', isBotPR);
core.setOutput('branch', pr.data.head.ref);
return {
prNumber,
isBotPR,
branch: pr.data.head.ref,
labels
};
- name: Check CI status
if: steps.pr-details.outputs.is_bot_pr == 'true'
id: ci-status
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ steps.pr-details.outputs.pr_number }};
// Get check runs for the PR
const checkRuns = await github.rest.checks.listForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: '${{ steps.pr-details.outputs.branch }}'
});
const checks = checkRuns.data.check_runs;
const failedChecks = checks.filter(c => c.conclusion === 'failure');
const pendingChecks = checks.filter(c => c.status === 'in_progress' || c.status === 'queued');
console.log(`Total checks: ${checks.length}`);
console.log(`Failed: ${failedChecks.length}`);
console.log(`Pending: ${pendingChecks.length}`);
core.setOutput('has_failures', failedChecks.length > 0);
core.setOutput('all_complete', pendingChecks.length === 0);
core.setOutput('failed_count', failedChecks.length);
// Get failure details
const failures = failedChecks.map(c => ({
name: c.name,
conclusion: c.conclusion,
detailsUrl: c.details_url
}));
return {
totalChecks: checks.length,
failedChecks: failedChecks.length,
pendingChecks: pendingChecks.length,
failures
};
- name: Notify bot of CI failures
if: |
steps.pr-details.outputs.is_bot_pr == 'true' &&
steps.ci-status.outputs.has_failures == 'true' &&
steps.ci-status.outputs.all_complete == 'true'
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ steps.pr-details.outputs.pr_number }};
const failedCount = ${{ steps.ci-status.outputs.failed_count }};
// Check if we've already notified about these failures
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const recentBotComments = comments.data.filter(c =>
c.user.type === 'Bot' &&
c.body.includes('CI Failure Detected') &&
(new Date() - new Date(c.created_at)) < 3600000 // Within last hour
);
if (recentBotComments.length === 0) {
// Post notification comment
const comment = `🚨 **CI Failure Detected**
${failedCount} CI check(s) have failed on this PR.
**Bot Actions Available:**
1. Attempt automatic fixes: \`node scripts/bot-workflow/utils/bot-fix-ci.js ${prNumber}\`
2. Analyze failures: \`gh pr checks ${prNumber}\`
3. Request human help: \`/bot handoff "CI failures need manual intervention"\`
The bot can attempt to fix common issues like:
- Formatting errors
- Linting issues
- Whitespace problems
For test failures or type errors, human intervention may be required.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: comment
});
// Add label to indicate CI issues
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['bot:ci-failure']
});
}
- name: Auto-trigger bot CI fix
if: |
steps.pr-details.outputs.is_bot_pr == 'true' &&
steps.ci-status.outputs.has_failures == 'true' &&
steps.ci-status.outputs.all_complete == 'true' &&
github.event_name == 'workflow_run'
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ steps.pr-details.outputs.pr_number }};
// Check if this is the first CI failure
const labels = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const hasAutoFixed = labels.data.some(l => l.name === 'bot:ci-auto-fixed');
if (!hasAutoFixed) {
// Add comment to trigger bot fix
const comment = `🤖 **Auto-triggering CI fix**
/bot fix-ci
The bot will attempt to automatically fix CI failures.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: comment
});
// Add label to prevent multiple attempts
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['bot:ci-auto-fixed']
});
}
- name: Celebrate CI success
if: |
steps.pr-details.outputs.is_bot_pr == 'true' &&
steps.ci-status.outputs.has_failures == 'false' &&
steps.ci-status.outputs.all_complete == 'true'
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ steps.pr-details.outputs.pr_number }};
// Remove CI failure labels if present
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'bot:ci-failure'
});
} catch (e) {
// Label might not exist
}
// Check if we should add success comment
const labels = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const needsReview = labels.data.some(l => l.name === 'agent:needs-review');
if (needsReview) {
// Add success comment
const comment = `✅ **All CI Checks Passed!**
This PR is ready for human review.
- All tests are passing
- Code quality checks passed
- No type errors
- Build successful
@${context.repo.owner} - This bot PR is ready for your review.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: comment
});
}