diff --git a/.github/release-please/config.json b/.github/release-please/config.json index 514c86d0dc..13da55934e 100644 --- a/.github/release-please/config.json +++ b/.github/release-please/config.json @@ -13,8 +13,7 @@ { "type": "refactor", "section": "๐Ÿงน Chores", "hidden": false }, { "type": "test", "section": "๐Ÿงน Chores", "hidden": false }, { "type": "build", "section": "๐Ÿค– Automation", "hidden": false }, - { "type": "ci", "section": "๐Ÿค– Automation", "hidden": true }, - { "type": "thanks", "section": "๐Ÿ™ Thank you", "hidden": false } + { "type": "ci", "section": "๐Ÿค– Automation", "hidden": true } ], "packages": { ".": {} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 72abb07121..1005ca2e70 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -24,11 +24,43 @@ jobs: config-file: .github/release-please/config.json manifest-file: .github/release-please/manifest.json + acknowledge_contributors: + name: Acknowledge Contributors + runs-on: ubuntu-latest + needs: release_please + if: needs.release_please.outputs.releaseCreated + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + show-progress: false + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install dependencies + run: npm install octokit + + - name: Add contributors to release notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: node scripts/mention-contributors.mjs + + - name: Commit updated changelog + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add CHANGELOG.md + git commit -m "docs: update release notes with contributors" || exit 0 + git push + npm_publish: name: Publish to npm runs-on: ubuntu-latest environment: npm - needs: release_please + needs: [release_please, acknowledge_contributors] if: needs.release_please.outputs.releaseCreated permissions: id-token: write @@ -36,6 +68,7 @@ jobs: - uses: actions/checkout@v4 with: show-progress: false + - uses: actions/setup-node@v4 with: node-version: lts/* @@ -46,4 +79,4 @@ jobs: - run: npm publish --provenance --access public --tag=next env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/package.json b/package.json index fad58e1555..5a8885c288 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "version": "run-p version:* && git add -A ./AUTHORS ./CHANGELOG.md" }, "dependencies": { + "@octokit/rest": "^21.0.2", "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", "chokidar": "^3.5.3", @@ -107,6 +108,7 @@ "log-symbols": "^4.1.0", "minimatch": "^5.1.6", "ms": "^2.1.3", + "octokit": "^4.0.2", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", diff --git a/scripts/mention-contributors.mjs b/scripts/mention-contributors.mjs new file mode 100644 index 0000000000..f61b1d5176 --- /dev/null +++ b/scripts/mention-contributors.mjs @@ -0,0 +1,128 @@ +'use strict'; + +import { Octokit } from "octokit"; +import fs from "node:fs"; +import { date } from "zod"; +import { console } from "node:inspector"; + +const token = process.env.GITHUB_TOKEN || ""; +const owner = "mochajs"; +const repo = "mocha"; + +const octokit = new Octokit({ auth: token}); + +async function getLastReleaseDate() { + try { + const { data: releases } = await octokit.request('GET /repos/{owner}/{repo}/releases', { + owner, + repo, + per_page: 2 + }); + + if (releases.length > 1) { + return new Date(releases[1].published_at); + } + + return new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)); + } catch (error) { + console.error("Error fetching releases:", error); + return new Date(Date.now() - (30 * 24 * 60 * 60 * 1000)); + } +} + +async function getContributorFullName(username) { + try { + const { data } = await octokit.request('GET /users/{username}', { + username: username + }); + return data.name || username; + } catch (error) { + console.error(`Error fetching user info for ${username}:`, error); + return username; + } +} + +async function getContributors() { + try { + const lastReleaseDate = await getLastReleaseDate(); + const contributors = new Map(); + let page = 1; + const per_page = 100; + + while (true) { + const { data } = await octokit.request('GET /repos/{owner}/{repo}/pulls', { + owner, + repo, + state: "closed", + sort: "updated", + direction: "desc", + per_page, + page + }); + + if (data.length === 0) break; + + for (const pr of data) { + if (new Date(pr.merged_at) <= lastReleaseDate) { + break; + } + + if (pr.merged_at && !pr.user.login.includes('[bot]')) { + if (!contributors.has(pr.user.login)) { + const fullName = await getContributorFullName(pr.user.login); + contributors.set(pr.user.login, fullName); + } + } + } + + if (data[data.length - 1].merged_at && new Date(data[data.length - 1].merged_at) <= lastReleaseDate){ + break; + } + page++; + } + return contributors; + } catch (error) { + console.error("Error fetching contributors:", error); + return new Map(); + } +} + +async function appendThankYouSection() { + try { + const changelogPath = "CHANGELOG.md"; + const contributors = await getContributors(); + + if (contributors.size === 0) { + return; + } + let thankYouSection = "\n## โค๏ธ Thank You\n\n"; + for (const [username, fullName] of contributors) { + thankYouSection += `* ${fullName} @${username}\n`; + } + thankYouSection += "\n"; + + const existingContent = fs.readFileSync(changelogPath, "utf-8"); + + const lines = existingContent.split("\n"); + + const firstVersionIndex = lines.findIndex(line => line.startsWith("#")); + if (firstVersionIndex === -1){ + return; + } + + const nextVersionIndex = lines.slice(firstVersionIndex + 1) + .findIndex(line => line.startsWith("#")); + + const insertPosition = nextVersionIndex !== -1 + ? firstVersionIndex + nextVersionIndex + 1: lines.length; + + lines.splice(insertPosition, 0, thankYouSection); + + fs.writeFileSync(changelogPath, lines.join("\n"), "utf-8"); + console.log("Thank you section added to changelog!") + + } catch (error) { + console.error("Error updating CHANGELOG.md:", error); + } +} +appendThankYouSection(); \ No newline at end of file