Skip to content

Support explicit Deployment and pod annotations for HyperDX #15

Support explicit Deployment and pod annotations for HyperDX

Support explicit Deployment and pod annotations for HyperDX #15

name: Alert on external contributions
on:
issues:
types: [opened, reopened]
pull_request_target:
types: [opened, reopened, ready_for_review]
permissions:
issues: write
pull-requests: write
concurrency:
group: external-contrib-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false
jobs:
alert:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v9
env:
SLACK_WEBHOOK_OSS_PRS: ${{ secrets.SLACK_WEBHOOK_OSS_PRS }}
with:
script: |
const LABEL = 'external';
const item = context.payload.issue ?? context.payload.pull_request;
if (!item) return;
if (item.draft) { core.info(`Skipping draft PR #${item.number}`); return; }
if (item.user?.type === 'Bot') { core.info(`Skipping bot ${item.user?.login}`); return; }
const { owner, repo } = context.repo;
// fast path (free): public members & direct collaborators
let internal = ['OWNER', 'MEMBER', 'COLLABORATOR'].includes(item.author_association);
// slow path: catches PRIVATE org members via their granted repo access.
// author_association only reports MEMBER for *public* members, so private
// members would otherwise be misflagged as external. Public repos grant
// everyone implicit 'read', so require triage+ (not permission != 'none').
if (!internal) {
try {
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
owner, repo, username: item.user.login,
});
const p = data.user?.permissions ?? {};
internal = !!(p.admin || p.maintain || p.push || p.triage);
} catch (e) {
if (e.status !== 404) throw e; // 404 = not a collaborator => external
}
}
if (internal) {
core.info(`#${item.number} by ${item.user?.login} is internal; skipping.`);
return;
}
if (item.labels?.some(l => l.name === LABEL)) { core.info(`#${item.number} already handled.`); return; }
const webhook = process.env.SLACK_WEBHOOK_OSS_PRS;
if (!webhook) {
core.warning('SLACK_WEBHOOK_OSS_PRS not set — no alert sent and not labeled (will retry on next event).');
return;
}
const kind = context.payload.pull_request ? 'PR' : 'issue';
const text = `:sparkles: *New external ${kind}* in \`${owner}/${repo}\`\n`
+ `<${item.html_url}|#${item.number}: ${item.title}>\n`
+ `by \`${item.user.login}\` (${item.author_association})`;
let delivered = false;
try {
const res = await fetch(webhook, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ blocks: [{ type: 'section', text: { type: 'mrkdwn', text } }] }),
});
delivered = res.ok;
if (!delivered) core.setFailed(`Slack post failed (${res.status}); leaving #${item.number} unlabeled to retry.`);
} catch (e) {
core.setFailed(`Slack post errored (${e.message}); leaving #${item.number} unlabeled to retry.`);
}
if (!delivered) return;
try {
await github.rest.issues.createLabel({
owner, repo, name: LABEL, color: 'D4C5F9',
description: 'Opened by an external contributor',
});
core.info(`Created '${LABEL}' label.`);
} catch (e) {
if (e.status !== 422) throw e;
}
await github.rest.issues.addLabels({ owner, repo, issue_number: item.number, labels: [LABEL] });
core.info(`Alerted Slack and labeled #${item.number} (${item.author_association}).`);