From e761182bba37fff97f692e57e34bdfbd6d4f51a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Sat, 10 Aug 2024 15:37:08 -0400 Subject: [PATCH] feat: retrieve issue co-authors (#445) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## PR Checklist - [x] Addresses an existing open issue: fixes #252 - [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/all-contributors-for-repository/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22) - [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/all-contributors-for-repository/blob/main/.github/CONTRIBUTING.md) were taken ## Overview Adds in the same co-author detection using `description-to-co-authors` for issue bodies as commit bodies. 💖 --- package.json | 2 +- pnpm-lock.yaml | 19 +++--- src/collect/adding/addAcceptedIssues.test.ts | 62 ++++++++++++++++--- src/collect/adding/addAcceptedIssues.ts | 25 ++++++-- src/collect/parsing/parseMergedPullAuthors.ts | 4 +- 5 files changed, 86 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 2055c0c2..c0e38e01 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,8 @@ }, "dependencies": { "co-author-to-username": "^0.1.1", - "commit-to-co-authors": "^0.1.0", "conventional-commits-parser": "^6.0.0", + "description-to-co-authors": "^0.3.0", "octokit": "^4.0.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f389350..84f4ac1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,12 @@ importers: co-author-to-username: specifier: ^0.1.1 version: 0.1.1 - commit-to-co-authors: - specifier: ^0.1.0 - version: 0.1.0 conventional-commits-parser: specifier: ^6.0.0 version: 6.0.0 + description-to-co-authors: + specifier: ^0.3.0 + version: 0.3.0 octokit: specifier: ^4.0.0 version: 4.0.2 @@ -1514,11 +1514,6 @@ packages: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} - commit-to-co-authors@0.1.0: - resolution: {integrity: sha512-5v1M+gBD0H7G2++D1L3z8ekVkTsIYNTuUFmL8KgIumuJdZ1CFjRulgUvYA7dFDmZNENu0G//yp+krWGcXb2WYA==} - engines: {node: '>=18'} - deprecated: Renamed to description-to-co-authors. This will work for GitHub issue bodies too. - compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -1757,6 +1752,10 @@ packages: deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + description-to-co-authors@0.3.0: + resolution: {integrity: sha512-GaMDuvOCmtkQ3tjjawAEl3YhxNEIsR9tmlXV4xeypGyiO75YLXRm3iHKltqrmxNgtNlppVzT2pdsPM2Yzm67CA==} + engines: {node: '>=18.3.0'} + detect-indent@7.0.1: resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==} engines: {node: '>=12.20'} @@ -5279,8 +5278,6 @@ snapshots: comment-parser@1.4.1: {} - commit-to-co-authors@0.1.0: {} - compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -5569,6 +5566,8 @@ snapshots: deprecation@2.3.1: {} + description-to-co-authors@0.3.0: {} + detect-indent@7.0.1: {} detect-newline@4.0.1: {} diff --git a/src/collect/adding/addAcceptedIssues.test.ts b/src/collect/adding/addAcceptedIssues.test.ts index 0df9f7b0..cfce7307 100644 --- a/src/collect/adding/addAcceptedIssues.test.ts +++ b/src/collect/adding/addAcceptedIssues.test.ts @@ -11,10 +11,22 @@ const options = { }; const login = "abc123"; +const loginCoAuthor = "other-login"; -const createStubIssue = (label: string) => +const mockDescriptionToCoAuthors = vi + .fn() + .mockReturnValue([{ username: loginCoAuthor }]); + +vi.mock("description-to-co-authors", () => ({ + get descriptionToCoAuthors() { + return mockDescriptionToCoAuthors; + }, +})); + +const createStubIssue = ({ body, labels }: Partial) => ({ - labels: [label], + body, + labels, number: 0, user: { login }, }) as AcceptedIssue; @@ -22,7 +34,9 @@ const createStubIssue = (label: string) => describe("addAcceptedIssues", () => { it("adds an issue when it has a bug label", () => { const add = vi.fn(); - const issue = createStubIssue(options.labelTypeBug); + const issue = createStubIssue({ + labels: [options.labelTypeBug], + }); addAcceptedIssues([issue], { add }, options); @@ -31,7 +45,9 @@ describe("addAcceptedIssues", () => { it("adds an issue when it has a docs label", () => { const add = vi.fn(); - const issue = createStubIssue(options.labelTypeDocs); + const issue = createStubIssue({ + labels: [options.labelTypeDocs], + }); addAcceptedIssues([issue], { add }, options); @@ -40,7 +56,9 @@ describe("addAcceptedIssues", () => { it("adds an issue when it has a feature label", () => { const add = vi.fn(); - const issue = createStubIssue(options.labelTypeIdeas); + const issue = createStubIssue({ + labels: [options.labelTypeIdeas], + }); addAcceptedIssues([issue], { add }, options); @@ -49,16 +67,46 @@ describe("addAcceptedIssues", () => { it("adds an issue when it has a tool label", () => { const add = vi.fn(); - const issue = createStubIssue(options.labelTypeTool); + const issue = createStubIssue({ + labels: [options.labelTypeTool], + }); + + addAcceptedIssues([issue], { add }, options); + + expect(add).toHaveBeenCalledWith(login, issue.number, "tool"); + }); + + it("adds an issue's co-author when the body includes them", () => { + const add = vi.fn(); + const issue = createStubIssue({ + body: `(mocked)`, + labels: [options.labelTypeTool], + }); + + addAcceptedIssues([issue], { add }, options); + + expect(add).toHaveBeenCalledWith(login, issue.number, "tool"); + expect(add).toHaveBeenCalledWith(loginCoAuthor, issue.number, "tool"); + expect(mockDescriptionToCoAuthors).toHaveBeenCalledWith(issue.body); + }); + + it("doesn't call for co-authors when there is no issue body", () => { + const add = vi.fn(); + const issue = createStubIssue({ + labels: [options.labelTypeTool], + }); addAcceptedIssues([issue], { add }, options); expect(add).toHaveBeenCalledWith(login, issue.number, "tool"); + expect(add).toHaveBeenCalledTimes(1); }); it("doesn't add an issue when it has an unrelated label", () => { const add = vi.fn(); - const issue = createStubIssue("other"); + const issue = createStubIssue({ + labels: ["other"], + }); addAcceptedIssues([issue], { add }, options); diff --git a/src/collect/adding/addAcceptedIssues.ts b/src/collect/adding/addAcceptedIssues.ts index d07d0d41..56add3e8 100644 --- a/src/collect/adding/addAcceptedIssues.ts +++ b/src/collect/adding/addAcceptedIssues.ts @@ -1,3 +1,4 @@ +import { descriptionToCoAuthors } from "description-to-co-authors"; import { ContributorsCollection } from "../../ContributorsCollection.js"; import { AllContributorsForRepositoryOptions } from "../../options.js"; import { AcceptedIssue } from "../collecting/collectAcceptedIssues.js"; @@ -25,12 +26,24 @@ export function addAcceptedIssues( // - 🔧 `tool`: authors of merged PRs that address issues labeled as tooling [options.labelTypeTool, "tool"], ] as const) { - if (labels.some((label) => label === labelType)) { - contributors.add( - acceptedIssue.user?.login, - acceptedIssue.number, - contribution, - ); + if (!labels.some((label) => label === labelType)) { + continue; + } + + const logins = []; + + if (acceptedIssue.user) { + logins.push(acceptedIssue.user.login); + } + + if (acceptedIssue.body) { + for (const coAuthor of descriptionToCoAuthors(acceptedIssue.body)) { + logins.push(coAuthor.username); + } + } + + for (const login of logins) { + contributors.add(login, acceptedIssue.number, contribution); } } } diff --git a/src/collect/parsing/parseMergedPullAuthors.ts b/src/collect/parsing/parseMergedPullAuthors.ts index a8c47521..8626ba50 100644 --- a/src/collect/parsing/parseMergedPullAuthors.ts +++ b/src/collect/parsing/parseMergedPullAuthors.ts @@ -1,5 +1,5 @@ import { CachingCoAuthorToUsername } from "co-author-to-username"; -import { commitToCoAuthors } from "commit-to-co-authors"; +import { descriptionToCoAuthors } from "description-to-co-authors"; interface MergedPullForAuthors { body?: string; @@ -15,7 +15,7 @@ export async function parseMergedPullAuthors( authors.push(mergedPull.user?.login); if (mergedPull.body) { - const coAuthors = commitToCoAuthors(mergedPull.body); + const coAuthors = descriptionToCoAuthors(mergedPull.body); for (const coAuthor of coAuthors) { authors.push(await cachingCoAuthorToUsername(coAuthor));