-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(eng): add repo-specific contributor types #507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add eng/README.md documenting maintainer utilities - Add eng/contributor-report.mjs for generating contributor reports - Add eng/add-missing-contributors.mjs for automating contributor additions - Add eng/utils/graceful-shutdown.mjs for script lifecycle management - Update eng/update-readme.mjs with minor fixes - Update package.json with new contributor scripts Generated-by: GitHub Copilot <[email protected]> Signed-off-by: Ashley Childress <[email protected]>
- Modify generateMarkdownReport to include per-user sections with PR details - Remove total PR count and simplify PR link format Commit-generated-by: GitHub Copilot <[email protected]> Signed-off-by: Ashley Childress <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR enhances the contributor recognition system by adding custom contribution types specific to this repository (instructions, prompts, agents, collections) and implements automated contributor detection and reporting tooling.
Key changes:
- Custom contributor types configured in
.all-contributorsrcto better reflect repo-specific contributions - New contributor reporting scripts that analyze merged PRs and detect missing contributors
- Updated CI workflow to automatically check and report missing contributors weekly
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
.all-contributorsrc |
Adds custom contribution types (instructions, prompts, agents, collections), ignore list, and migrates existing contributors to new types |
package.json |
Adds contributors:report script and updates keywords |
eng/contributor-report.mjs |
New script to generate markdown reports of missing contributors by analyzing merged PRs |
eng/add-missing-contributors.mjs |
New script to automatically add missing contributors with inferred contribution types |
eng/utils/graceful-shutdown.mjs |
Utility for graceful shutdown handling in Node scripts |
eng/README.md |
Documentation for the new contributor tooling |
.github/workflows/contributors.yml |
Updates workflow to check/report missing contributors and adds timeout |
CONTRIBUTING.md |
Documents the new contributor recognition process and custom types |
README.md |
Auto-generated changes reflecting new contributor types and badge updates |
.gitignore |
Excludes reports directory from version control |
| const replacements = [ | ||
| { pattern: /\\/g, replacement: '/' }, | ||
| { pattern: /\./g, replacement: String.raw`\.` }, | ||
| { pattern: /\*\*/g, replacement: DOUBLE_WILDCARD_PLACEHOLDER }, | ||
| { pattern: /\*/g, replacement: '[^/]*' }, | ||
| { pattern: new RegExp(DOUBLE_WILDCARD_PLACEHOLDER, 'g'), replacement: '.*' }, | ||
| { pattern: /\?/g, replacement: '.' }, | ||
| { pattern: /\//g, replacement: String.raw`\/` } | ||
| ]; | ||
|
|
||
| const normalized = replacements.reduce((acc, { pattern, replacement }) => acc.replace(pattern, replacement), String(pattern)); | ||
|
|
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The glob conversion logic doesn't escape special regex characters like '+', '(', ')', '[', ']', '{', '}', '^', '$', and '|'. If any file patterns contain these characters, the regex matching will fail or behave unexpectedly.
| const replacements = [ | |
| { pattern: /\\/g, replacement: '/' }, | |
| { pattern: /\./g, replacement: String.raw`\.` }, | |
| { pattern: /\*\*/g, replacement: DOUBLE_WILDCARD_PLACEHOLDER }, | |
| { pattern: /\*/g, replacement: '[^/]*' }, | |
| { pattern: new RegExp(DOUBLE_WILDCARD_PLACEHOLDER, 'g'), replacement: '.*' }, | |
| { pattern: /\?/g, replacement: '.' }, | |
| { pattern: /\//g, replacement: String.raw`\/` } | |
| ]; | |
| const normalized = replacements.reduce((acc, { pattern, replacement }) => acc.replace(pattern, replacement), String(pattern)); | |
| // Escape all regex-special characters except glob wildcards (*, ?, /), | |
| // then translate glob syntax to regex. | |
| const regexSpecials = /[.+^${}()|[\]\\]/g; | |
| let normalized = String(pattern); | |
| // Normalize Windows-style separators to POSIX-style for matching. | |
| normalized = normalized.replace(/\\/g, '/'); | |
| // Escape regex metacharacters so they are treated literally. | |
| normalized = normalized.replace(regexSpecials, (match) => `\\${match}`); | |
| // Handle glob wildcards. | |
| normalized = normalized.replace(/\*\*/g, DOUBLE_WILDCARD_PLACEHOLDER); | |
| normalized = normalized.replace(/\*/g, '[^/]*'); | |
| normalized = normalized.replace(new RegExp(DOUBLE_WILDCARD_PLACEHOLDER, 'g'), '.*'); | |
| normalized = normalized.replace(/\?/g, '.'); | |
| // Escape path separators for the final regex. | |
| normalized = normalized.replace(/\//g, String.raw`\/`); |
| const match = upstreamUrl.match(/github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/); | ||
| if (match) return `${match[1]}/${match[2]}`; | ||
| } | ||
| } catch (e) { | ||
| console.debug('upstream not found, trying origin'); | ||
| } | ||
|
|
||
| try { | ||
| const originUrl = execSync('git config --get remote.origin.url', { | ||
| encoding: 'utf8', | ||
| stdio: ['pipe', 'pipe', 'pipe'] | ||
| }).trim(); | ||
| const match = originUrl.match(/github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/); | ||
| if (match) return `${match[1]}/${match[2]}`; |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex pattern for matching GitHub URLs only supports SSH format (github.com:owner/repo) but not HTTPS format (github.com/owner/repo). This will fail for users who have configured their Git remotes using HTTPS URLs.
| execSync(`gh pr comment ${prNumber} --repo ${repo} --body "${body.replace(/"/g, '\\"')}"`, { | ||
| encoding: 'utf8', | ||
| stdio: ['pipe', 'inherit', 'inherit'], | ||
| timeout: DEFAULT_CMD_TIMEOUT | ||
| }); |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Escaped double quotes in the command body may not work correctly on all platforms. On Windows, this escaping pattern can fail. Consider using stdio 'inherit' or writing the body to a temporary file instead of escaping quotes in the shell command.
| if (process.argv[1] === (new URL(import.meta.url)).pathname) { | ||
| main(); |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The URL constructor pathname behavior is platform-dependent. On Windows, this comparison will fail because the pathname includes the drive letter. Use fileURLToPath from 'node:url' module instead for cross-platform compatibility.
| console.log('\n' + '='.repeat(50)); | ||
| }; | ||
|
|
||
| if (process.argv[1] === (new URL(import.meta.url)).pathname) { |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same pathname comparison issue exists here. On Windows, this check will fail, preventing the script from running when executed directly.
| @@ -1,9 +1,6 @@ | |||
| # 🤖 Awesome GitHub Copilot Customizations | |||
| [](https://aka.ms/awesome-github-copilot?style=flat-square) [](#contributors-) | |||
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ACTION link in the badge URL contains a query parameter style=flat-square that should be part of the actual URL, not the link destination. The badge parameters should be in the image URL, not the link URL.
| [](https://aka.ms/awesome-github-copilot?style=flat-square) [](#contributors-) | |
| [](https://aka.ms/awesome-github-copilot) [](#contributors-) |
| // process.exit may not be desirable in some test harnesses; swallow errors | ||
| console.warn(`${name}: process.exit failed:`, e?.message); |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The graceful-shutdown utility catches process.exit errors and logs a warning, which may hide real issues. The purpose of process.exit is to immediately terminate, so catching and swallowing errors here could mask problems in test environments or other scenarios where exit behavior is intentionally modified.
| // process.exit may not be desirable in some test harnesses; swallow errors | |
| console.warn(`${name}: process.exit failed:`, e?.message); | |
| // If process.exit is stubbed or overridden (e.g. in tests), surface the failure | |
| console.error(`${name}: process.exit failed:`, e?.message || e); | |
| throw e; |
| const CONTRIBUTION_TYPE_MAP = { | ||
| 'instructions': { symbol: '🧭', description: 'The big AI prompt recipes (Copilot instruction sets)' }, | ||
| 'prompts': { symbol: '⌨️', description: 'One-shot or reusable user-level prompts' }, | ||
| 'agents': { symbol: '🎭', description: 'Defined Copilot personalities / roles' }, | ||
| 'collections': { symbol: '🎁', description: 'Bundled thematic sets (e.g., "Copilot for Docs")' } | ||
| }; | ||
|
|
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused variable CONTRIBUTION_TYPE_MAP.
| const CONTRIBUTION_TYPE_MAP = { | |
| 'instructions': { symbol: '🧭', description: 'The big AI prompt recipes (Copilot instruction sets)' }, | |
| 'prompts': { symbol: '⌨️', description: 'One-shot or reusable user-level prompts' }, | |
| 'agents': { symbol: '🎭', description: 'Defined Copilot personalities / roles' }, | |
| 'collections': { symbol: '🎁', description: 'Bundled thematic sets (e.g., "Copilot for Docs")' } | |
| }; |
Pull Request Checklist
npm startand verified thatREADME.mdis up to date.Description
@aaronpowell
I realize I probably should have started a discussion first, but I started out just playing with the contributors library and got a little carried away 😆 Tbh, I'm not incredibly attached—I just hate wasting code when it could be useful. Let me know if you want changes or something taken back out!
Type of Contribution
Additional Notes
I had to stop myself from adding a bot that does all this for you automatically! I figure less is safer, so I kept everything to the report-friendly version and an auto-add script strictly for local use. That last one I wasn't going to include at all, but then decided it could be used for automation later if one were so inclined.
This is what that report looks like with markdown formatted in workflow output summary:
By submitting this pull request, I confirm that my contribution abides by the Code of Conduct and will be licensed under the MIT License.