Updated contributing guidelines
This commit is contained in:
3
.github/allowed-pr-authors.txt
vendored
Normal file
3
.github/allowed-pr-authors.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# GitHub usernames allowed to open pull requests directly.
|
||||
mdecimus
|
||||
mdyring
|
||||
116
.github/workflows/auto-close-prs.yml
vendored
Normal file
116
.github/workflows/auto-close-prs.yml
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
name: Auto-close PRs from non-allowed authors
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
auto-close:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: .github/allowed-pr-authors.txt
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Close PRs from non-allowed authors
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
let allowedAuthors = [];
|
||||
try {
|
||||
allowedAuthors = fs.readFileSync('.github/allowed-pr-authors.txt', 'utf8')
|
||||
.split('\n')
|
||||
.map(line => line.trim())
|
||||
.filter(line => line && !line.startsWith('#'))
|
||||
.map(line => line.toLowerCase());
|
||||
} catch (err) {
|
||||
core.warning(`Could not read allowed-pr-authors.txt: ${err.message}`);
|
||||
}
|
||||
|
||||
const pr = context.payload.pull_request;
|
||||
const author = (pr.user && pr.user.login) || '';
|
||||
const login = author.toLowerCase();
|
||||
|
||||
if (author.endsWith('[bot]')) {
|
||||
core.info(`PR #${pr.number} opened by bot '${author}'. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allowedAuthors.includes(login)) {
|
||||
core.info(`PR #${pr.number} opened by allowed author '${author}'. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
username: author,
|
||||
});
|
||||
if (perm.permission === 'admin' || perm.permission === 'write') {
|
||||
core.info(`PR #${pr.number} author '${author}' is a collaborator (${perm.permission}). Skipping.`);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
core.info(`Could not resolve collaborator permission for '${author}': ${err.message}`);
|
||||
}
|
||||
|
||||
const contributingUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/blob/HEAD/CONTRIBUTING.md`;
|
||||
|
||||
const haystack = `${pr.title || ''}\n${pr.body || ''}`;
|
||||
const aiPatterns = [
|
||||
/[—―]/,
|
||||
];
|
||||
const looksAiGenerated = aiPatterns.some(re => re.test(haystack));
|
||||
|
||||
const aiMessage = [
|
||||
`Hi @${author}, thanks for your interest in contributing.`,
|
||||
``,
|
||||
`This pull request is being **automatically closed and locked**. The description contains strong indicators of AI-generated content, and this project does not accept AI-generated code or unsolicited machine-authored contributions.`,
|
||||
``,
|
||||
`Please read [CONTRIBUTING.md](${contributingUrl}) to learn what kinds of contributions are currently accepted. If this is a genuine hand-written change that fits those guidelines, please open a discussion at **[support.stalw.art](https://support.stalw.art)** before submitting.`,
|
||||
].join('\n');
|
||||
|
||||
const standardMessage = [
|
||||
`Hi @${author}, thanks for taking the time to open this pull request.`,
|
||||
``,
|
||||
`This PR is being **automatically closed** because it was submitted by an author who is not on the list of approved contributors. This policy helps us keep review capacity focused and filter out unsolicited or low-quality contributions.`,
|
||||
``,
|
||||
`Please read [CONTRIBUTING.md](${contributingUrl}) to learn what kinds of contributions are currently accepted. If your change fits those guidelines, please first discuss it at our support portal: **[support.stalw.art](https://support.stalw.art)**. You can sign in with your existing GitHub account.`,
|
||||
``,
|
||||
`Thank you for understanding.`,
|
||||
].join('\n');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
body: looksAiGenerated ? aiMessage : standardMessage,
|
||||
});
|
||||
|
||||
await github.rest.pulls.update({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: pr.number,
|
||||
state: 'closed',
|
||||
});
|
||||
|
||||
if (looksAiGenerated) {
|
||||
try {
|
||||
await github.rest.issues.lock({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pr.number,
|
||||
lock_reason: 'spam',
|
||||
});
|
||||
} catch (err) {
|
||||
core.warning(`Could not lock PR #${pr.number}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user