diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c3bda957409b..f9ebb39777f5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,6 +224,44 @@ jobs: message: | ⚠️ This PR is opened against **master**. You probably want to open it against **develop**. + job_external_contributor: + name: External Contributors + needs: job_install_deps + runs-on: ubuntu-20.04 + if: | + github.event_name == 'pull_request' + && (github.action == 'opened' || github.action == 'reopened') + && github.event.pull_request.author_association != 'COLLABORATOR' + && github.event.pull_request.author_association != 'MEMBER' + && github.event.pull_request.author_association != 'OWNER' + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + - name: Check dependency cache + uses: actions/cache/restore@v4 + with: + path: ${{ env.CACHED_DEPENDENCY_PATHS }} + key: ${{ needs.job_install_deps.outputs.dependency_cache_key }} + fail-on-cache-miss: true + + - name: Add external contributor to CHANGELOG.md + uses: ./dev-packages/external-contributor-gh-action + with: + name: ${{ github.event.pull_request.user.login }} + - name: Create PR with changes + uses: peter-evans/create-pull-request@v6 + with: + commit-message: "ref: Add external contributor to CHANGELOG.md" + title: "ref: Add external contributor to CHANGELOG.md" + branch: 'external-contributor/patch-${{ github.event.pull_request.user.login }}' + delete-branch: true + body: This PR adds the external contributor to the CHANGELOG.md file, so that they are credited for their contribution. + job_build: name: Build needs: [job_get_metadata, job_install_deps] diff --git a/dev-packages/external-contributor-gh-action/.eslintrc.cjs b/dev-packages/external-contributor-gh-action/.eslintrc.cjs new file mode 100644 index 000000000000..8c67e0037908 --- /dev/null +++ b/dev-packages/external-contributor-gh-action/.eslintrc.cjs @@ -0,0 +1,14 @@ +module.exports = { + extends: ['../../.eslintrc.js'], + parserOptions: { + sourceType: 'module', + ecmaVersion: 'latest', + }, + + overrides: [ + { + files: ['*.mjs'], + extends: ['@sentry-internal/sdk/src/base'], + }, + ], +}; diff --git a/dev-packages/external-contributor-gh-action/action.yml b/dev-packages/external-contributor-gh-action/action.yml new file mode 100644 index 000000000000..8c6fb9c04944 --- /dev/null +++ b/dev-packages/external-contributor-gh-action/action.yml @@ -0,0 +1,9 @@ +name: 'external-contributor-gh-action' +description: 'Add external contributors to CHANGELOG.md' +inputs: + name: + required: true + description: 'The name of the external contributor' +runs: + using: 'node20' + main: 'index.mjs' diff --git a/dev-packages/external-contributor-gh-action/index.mjs b/dev-packages/external-contributor-gh-action/index.mjs new file mode 100644 index 000000000000..7eff418e9205 --- /dev/null +++ b/dev-packages/external-contributor-gh-action/index.mjs @@ -0,0 +1,72 @@ +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import * as core from '@actions/core'; + +const UNRELEASED_HEADING = `## Unreleased + +- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +`; + +const contributorMessageRegex = /Work in this release was contributed by (.+)\. Thank you for your contribution!/; + +async function run() { + const { getInput } = core; + + const name = getInput('name'); + + if (!name) { + return; + } + + const ghUserName = name.startsWith('@') ? name : `@${name}`; + + const cwd = process.cwd(); + const changelogFilePath = path.resolve(cwd, 'CHANGELOG.md'); + + const changelogStr = await fs.readFile(changelogFilePath, 'utf8'); + + // Find the unreleased section + const start = changelogStr.indexOf(UNRELEASED_HEADING) + UNRELEASED_HEADING.length; + const end = changelogStr.slice(start).indexOf('## '); + + const inBetween = changelogStr.slice(start, start + end); + + const existing = contributorMessageRegex.exec(inBetween); + + // If the contributor message already exists, add the new contributor to the list + if (existing) { + const users = existing[1].split(/(?:,? and )|(?:, )/); + if (!users.includes(ghUserName)) { + users.push(ghUserName); + } + + const formatter = new Intl.ListFormat('en', { + style: 'long', + type: 'conjunction', + }); + + const newContributors = formatter.format(users); + const newChangelog = changelogStr.replace( + contributorMessageRegex, + `Work in this release was contributed by ${newContributors}. Thank you for your contribution!`, + ); + + fs.writeFile(changelogFilePath, newChangelog); + + // eslint-disable-next-line no-console + console.log('Added contributor to list of existing contributors.'); + return; + } + + // If the contributor message does not exist, add it + const newChangelog = changelogStr.replace( + UNRELEASED_HEADING, + `${UNRELEASED_HEADING}\nWork in this release was contributed by ${ghUserName}. Thank you for your contribution!\n`, + ); + fs.writeFile(changelogFilePath, newChangelog); + + // eslint-disable-next-line no-console + console.log('Added contributor message.'); +} + +run(); diff --git a/dev-packages/external-contributor-gh-action/package.json b/dev-packages/external-contributor-gh-action/package.json new file mode 100644 index 000000000000..6b69533b7ba2 --- /dev/null +++ b/dev-packages/external-contributor-gh-action/package.json @@ -0,0 +1,22 @@ +{ + "name": "@sentry-internal/external-contributor-gh-action", + "description": "An internal Github Action to add external contributors to the CHANGELOG.md file.", + "version": "8.8.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "private": true, + "main": "index.mjs", + "type": "module", + "scripts": { + "lint": "eslint . --format stylish", + "fix": "eslint . --format stylish --fix" + }, + "dependencies": { + "@actions/core": "1.10.1" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/package.json b/package.json index 42a1b6cd0b89..b4676d07be73 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "dev-packages/overhead-metrics", "dev-packages/test-utils", "dev-packages/size-limit-gh-action", + "dev-packages/external-contributor-gh-action", "dev-packages/rollup-utils" ], "devDependencies": {