fix: add contribution gate dry run mode
This commit is contained in:
@@ -9,6 +9,10 @@ permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: contribution-gate-approval
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
approve:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -56,12 +60,14 @@ jobs:
|
||||
const targetLogin = issue.user.login;
|
||||
const normalizedLogin = targetLogin.toLowerCase();
|
||||
const entry = `${scope}:${normalizedLogin}`;
|
||||
const branchSlug = normalizedLogin.replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'contributor';
|
||||
|
||||
const defaultContent = [
|
||||
'# Scoped contribution-gate allowlist.',
|
||||
'#',
|
||||
'# Maintainers and collaborators bypass the gate automatically. Use this file',
|
||||
'# for external contributors who are allowed through the automated front door.',
|
||||
'# Seed active contributors here before switching the gate workflows to enforce mode.',
|
||||
'#',
|
||||
'# Supported entries:',
|
||||
'# pr:username',
|
||||
@@ -119,6 +125,29 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
const { data: openPrs } = await github.rest.pulls.list({
|
||||
owner,
|
||||
repo,
|
||||
state: 'open',
|
||||
per_page: 100,
|
||||
});
|
||||
const repoFullName = `${owner}/${repo}`.toLowerCase();
|
||||
const pendingPr = openPrs.find(openPr => {
|
||||
const sameRepo = (openPr.head?.repo?.full_name || '').toLowerCase() === repoFullName;
|
||||
const body = openPr.body || '';
|
||||
return sameRepo && body.includes(`Adds \`${entry}\` to \`${path}\`.`);
|
||||
});
|
||||
|
||||
if (pendingPr) {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issue.number,
|
||||
body: `@${targetLogin} already has a pending allowlist update PR for ${scope} contributions: ${pendingPr.html_url}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const nextContent = `${content.trimEnd()}\n${entry}\n`;
|
||||
const { data: blob } = await github.rest.git.createBlob({
|
||||
owner,
|
||||
@@ -140,7 +169,6 @@ jobs:
|
||||
],
|
||||
});
|
||||
|
||||
const branchSlug = normalizedLogin.replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'contributor';
|
||||
const branchName = `contribution-gate/${scope}-${branchSlug}-${Date.now()}`;
|
||||
await github.rest.git.createRef({
|
||||
owner,
|
||||
|
||||
@@ -8,11 +8,16 @@ permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
env:
|
||||
# Keep new gates observable first. Switch to "enforce" only after maintainers
|
||||
# have seeded active contributors and reviewed the dry-run signal.
|
||||
CONTRIBUTION_GATE_MODE: dry-run
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close unapproved external issues
|
||||
- name: Gate unapproved external issues
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -20,6 +25,12 @@ jobs:
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const privileged = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
|
||||
const gateMode = (process.env.CONTRIBUTION_GATE_MODE || 'dry-run').trim().toLowerCase();
|
||||
const enforceGate = gateMode === 'enforce';
|
||||
|
||||
if (!['dry-run', 'enforce'].includes(gateMode)) {
|
||||
core.warning(`Unknown CONTRIBUTION_GATE_MODE "${gateMode}"; defaulting to dry-run.`);
|
||||
}
|
||||
|
||||
if (privileged.has(issue.author_association)) return;
|
||||
if (issue.user.login === 'github-actions[bot]') return;
|
||||
@@ -60,6 +71,10 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
const gateMessage = enforceGate
|
||||
? 'This repository currently uses a maintainer-managed contribution gate, so issues from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` are closed automatically.'
|
||||
: 'This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this issue is staying open. When enforcement is enabled, issues from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` will be closed automatically.';
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
@@ -67,12 +82,14 @@ jobs:
|
||||
body: [
|
||||
`Thanks @${issue.user.login} for the report.`,
|
||||
'',
|
||||
'This repository currently uses a maintainer-managed contribution gate, so issues from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` are closed automatically.',
|
||||
gateMessage,
|
||||
'',
|
||||
'Please read `CONTRIBUTING.md` for the expected issue shape. A maintainer can grant issue access by commenting `/lgtmi` on an issue.',
|
||||
].join('\n'),
|
||||
});
|
||||
|
||||
if (!enforceGate) return;
|
||||
|
||||
await github.rest.issues.update({
|
||||
owner,
|
||||
repo,
|
||||
|
||||
@@ -9,11 +9,16 @@ permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
env:
|
||||
# Keep new gates observable first. Switch to "enforce" only after maintainers
|
||||
# have seeded active contributors and reviewed the dry-run signal.
|
||||
CONTRIBUTION_GATE_MODE: dry-run
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close unapproved external pull requests
|
||||
- name: Gate unapproved external pull requests
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -21,6 +26,12 @@ jobs:
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const privileged = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
|
||||
const gateMode = (process.env.CONTRIBUTION_GATE_MODE || 'dry-run').trim().toLowerCase();
|
||||
const enforceGate = gateMode === 'enforce';
|
||||
|
||||
if (!['dry-run', 'enforce'].includes(gateMode)) {
|
||||
core.warning(`Unknown CONTRIBUTION_GATE_MODE "${gateMode}"; defaulting to dry-run.`);
|
||||
}
|
||||
|
||||
if (privileged.has(pr.author_association)) return;
|
||||
if (pr.user.login === 'github-actions[bot]') return;
|
||||
@@ -61,6 +72,10 @@ jobs:
|
||||
return;
|
||||
}
|
||||
|
||||
const gateMessage = enforceGate
|
||||
? 'This repository currently uses a maintainer-managed contribution gate, so pull requests from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` are closed automatically.'
|
||||
: 'This repository is currently observing a maintainer-managed contribution gate in dry-run mode, so this pull request is staying open. When enforcement is enabled, pull requests from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` will be closed automatically.';
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
@@ -68,12 +83,14 @@ jobs:
|
||||
body: [
|
||||
`Thanks @${pr.user.login} for taking the time to contribute.`,
|
||||
'',
|
||||
'This repository currently uses a maintainer-managed contribution gate, so pull requests from contributors who are not listed in `.github/APPROVED_CONTRIBUTORS` are closed automatically.',
|
||||
gateMessage,
|
||||
'',
|
||||
'Please read `CONTRIBUTING.md` for the expected contribution shape. A maintainer can grant PR access by commenting `/lgtm` on a pull request.',
|
||||
].join('\n'),
|
||||
});
|
||||
|
||||
if (!enforceGate) return;
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner,
|
||||
repo,
|
||||
|
||||
Reference in New Issue
Block a user