Skip to content

Commit c8b7ed6

Browse files
connector: deploy slack
1 parent 9c36252 commit c8b7ed6

1 file changed

Lines changed: 126 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# .github/workflows/connector-slack.yml
2+
# Slack connector — posts to Slack on all important git events
3+
# Set org secret: SLACK_WEBHOOK_URL (Incoming Webhook URL)
4+
5+
name: "Connector: Slack"
6+
7+
on:
8+
push:
9+
branches: [main]
10+
pull_request:
11+
types: [opened, closed, merged]
12+
issues:
13+
types: [opened, closed]
14+
release:
15+
types: [published]
16+
workflow_run:
17+
workflows: ["Agent: Org Health Monitor", "Agent: Repo Improver"]
18+
types: [completed]
19+
schedule:
20+
- cron: '0 14 * * 1-5' # Weekdays 2pm UTC — daily digest
21+
22+
permissions:
23+
contents: read
24+
issues: read
25+
pull-requests: read
26+
27+
jobs:
28+
notify:
29+
name: "Slack Notify"
30+
runs-on: ubuntu-latest
31+
if: vars.SLACK_ENABLED == 'true' || secrets.SLACK_WEBHOOK_URL != ''
32+
33+
steps:
34+
- name: Build and send Slack message
35+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
36+
env:
37+
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
38+
with:
39+
script: |
40+
const webhook = process.env.SLACK_WEBHOOK;
41+
if (!webhook) { console.log('No SLACK_WEBHOOK_URL set — skipping'); return; }
42+
43+
const event = context.eventName;
44+
const repo = `${context.repo.owner}/${context.repo.repo}`;
45+
const repoUrl = `https://github.com/${repo}`;
46+
let blocks = [];
47+
48+
if (event === 'push') {
49+
const commits = context.payload.commits || [];
50+
const branch = context.ref.replace('refs/heads/', '');
51+
blocks = [{
52+
type: 'section',
53+
text: { type: 'mrkdwn', text: `*Push to ${repo}* (${branch})\n${commits.map(c => `• <${c.url}|${c.message.split('\n')[0].substring(0, 80)}>`).join('\n')}` }
54+
}];
55+
}
56+
57+
else if (event === 'pull_request') {
58+
const pr = context.payload.pull_request;
59+
const action = context.payload.action;
60+
const emoji = action === 'opened' ? '🔀' : action === 'closed' && pr.merged ? '✅' : '❌';
61+
blocks = [{
62+
type: 'section',
63+
text: { type: 'mrkdwn', text: `${emoji} *PR ${action}:* <${pr.html_url}|${pr.title}>\n${repo} • ${pr.additions}+ ${pr.deletions}- • ${pr.changed_files} files` }
64+
}];
65+
}
66+
67+
else if (event === 'issues') {
68+
const issue = context.payload.issue;
69+
const emoji = context.payload.action === 'opened' ? '🆕' : '✅';
70+
blocks = [{
71+
type: 'section',
72+
text: { type: 'mrkdwn', text: `${emoji} *Issue ${context.payload.action}:* <${issue.html_url}|${issue.title}>\n${repo} • Labels: ${issue.labels.map(l => l.name).join(', ') || 'none'}` }
73+
}];
74+
}
75+
76+
else if (event === 'release') {
77+
const release = context.payload.release;
78+
blocks = [{
79+
type: 'section',
80+
text: { type: 'mrkdwn', text: `🚀 *Release published:* <${release.html_url}|${release.tag_name}>\n${repo} • ${release.name || release.tag_name}` }
81+
}];
82+
}
83+
84+
else if (event === 'workflow_run') {
85+
const run = context.payload.workflow_run;
86+
const emoji = run.conclusion === 'success' ? '✅' : '❌';
87+
blocks = [{
88+
type: 'section',
89+
text: { type: 'mrkdwn', text: `${emoji} *Agent completed:* ${run.name}\n${repo} • ${run.conclusion} • <${run.html_url}|View run>` }
90+
}];
91+
}
92+
93+
else if (event === 'schedule') {
94+
// Daily digest
95+
const { data: repos } = await github.rest.repos.listForOrg({
96+
org: 'BlackRoad-OS-Inc', per_page: 5, sort: 'pushed', direction: 'desc'
97+
});
98+
const { data: issues } = await github.rest.issues.listForRepo({
99+
owner: context.repo.owner, repo: context.repo.repo, state: 'open', per_page: 5
100+
});
101+
102+
blocks = [
103+
{ type: 'header', text: { type: 'plain_text', text: '📊 BlackRoad Daily Digest' } },
104+
{ type: 'section', text: { type: 'mrkdwn', text:
105+
`*Recently active repos:*\n${repos.map(r => `• <${r.html_url}|${r.name}> — ${r.description?.substring(0, 60) || 'no description'}`).join('\n')}`
106+
}},
107+
{ type: 'section', text: { type: 'mrkdwn', text:
108+
`*Open issues (${issues.length}):*\n${issues.map(i => `• <${i.html_url}|${i.title}>`).join('\n') || 'None'}`
109+
}}
110+
];
111+
}
112+
113+
if (blocks.length === 0) return;
114+
115+
// Add footer
116+
blocks.push({
117+
type: 'context',
118+
elements: [{ type: 'mrkdwn', text: `BlackRoad OS • <${repoUrl}|${repo}> • ${new Date().toISOString().split('T')[0]}` }]
119+
});
120+
121+
const resp = await fetch(webhook, {
122+
method: 'POST',
123+
headers: { 'Content-Type': 'application/json' },
124+
body: JSON.stringify({ blocks })
125+
});
126+
console.log(`Slack: ${resp.status}`);

0 commit comments

Comments
 (0)