Repository: JoshuaKGoldberg/create-typescript-app (ts)

Issue:
🐛 Bug: Transitioned repos remove some existing contributions
### Bug Report Checklist

- [x] I have tried restarting my IDE and the issue persists.
- [x] I have pulled the latest `main` branch of the repository.
- [x] I have [searched for related issues](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aissue) and found none that matched my issue.

### Expected

Running `npx create-typescript-app` on an existing repo fully set up with `--preset everything` should only add to contributions in `.all-contributorsrc`. It should not remove any.

### Actual

https://github.com/JoshuaKGoldberg/eslint-fix-utils/pull/79/files#r2018782689, it's dropping `"test"` and `"bug"` from my contributions. Rude.

### Additional Info

🎁 

Pull request:
fix: preserve existing owner contributions during transition
## PR Checklist

- [x] Addresses an existing open issue: fixes #2063
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/create-typescript-app/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

To work around https://github.com/all-contributors/cli/issues/371, any existing owner contributions are merged with the default starters.

🎁 

Patch:
diff --git a/src/blocks/blockAllContributors.ts b/src/blocks/blockAllContributors.ts
index 91f1108..0f5cf53 100644
--- a/src/blocks/blockAllContributors.ts
+++ b/src/blocks/blockAllContributors.ts
@@ -1,7 +1,7 @@
 import _ from "lodash";
 
 import { base } from "../base.js";
-import { ownerContributions } from "../data/contributions.js";
+import { startingOwnerContributions } from "../data/contributions.js";
 import { Contributor } from "../schemas.js";
 import { resolveUses } from "./actions/resolveUses.js";
 import { blockPrettier } from "./blockPrettier.js";
@@ -16,6 +16,20 @@ export const blockAllContributors = base.createBlock({
 	},
 	produce({ options }) {
 		const contributions = options.contributors?.length;
+		const ownerContributions = Array.from(
+			new Set(
+				[
+					options.contributors?.find(
+						(contributor) =>
+							contributor.login.toLowerCase() === options.owner.toLowerCase(),
+					)?.contributions,
+					startingOwnerContributions,
+				]
+					.filter(Boolean)
+					.flat(),
+			),
+		);
+
 		return {
 			addons: [
 				blockPrettier({
diff --git a/src/data/contributions.ts b/src/data/contributions.ts
index 8d4a135..0313c90 100644
--- a/src/data/contributions.ts
+++ b/src/data/contributions.ts
@@ -1,4 +1,4 @@
-export const ownerContributions = [
+export const startingOwnerContributions = [
 	"code",
 	"content",
 	"doc",
diff --git a/src/options/readAllContributors.ts b/src/options/readAllContributors.ts
index 6a6d9eb..62c219d 100644
--- a/src/options/readAllContributors.ts
+++ b/src/options/readAllContributors.ts
@@ -1,7 +1,7 @@
 import { TakeInput } from "bingo";
 import { inputFromFileJSON } from "input-from-file-json";
 
-import { ownerContributions } from "../data/contributions.js";
+import { startingOwnerContributions } from "../data/contributions.js";
 import { inputFromOctokit } from "../inputs/inputFromOctokit.js";
 import { AllContributorsData } from "../types.js";
 
@@ -24,7 +24,7 @@ export async function readAllContributors(take: TakeInput) {
 		user && [
 			{
 				avatar_url: user.avatar_url,
-				contributions: ownerContributions,
+				contributions: startingOwnerContributions,
 				login: user.login,
 				name: user.name,
 				profile: user.blog,


Test patch:
diff --git a/src/blocks/blockAllContributors.test.ts b/src/blocks/blockAllContributors.test.ts
index 6624e50..a4227ae 100644
--- a/src/blocks/blockAllContributors.test.ts
+++ b/src/blocks/blockAllContributors.test.ts
@@ -90,132 +90,240 @@ describe("blockAllContributors", () => {
 		`);
 	});
 
-	it("includes contributors when provided", () => {
+	it("runs add including existing owner contributions when they exist", () => {
 		const creation = testBlock(blockAllContributors, {
 			options: {
 				...optionsBase,
 				contributors: [
 					{
 						avatar_url: "https://avatars.githubusercontent.com/u/3335181?v=4",
-						contributions: [
-							"bug",
-							"code",
-							"design",
-							"doc",
-							"ideas",
-							"infra",
-							"maintenance",
-							"review",
-							"test",
-							"tool",
-						],
+						contributions: ["bug", "code", "design", "doc", "test", "tool"],
 						login: "JoshuaKGoldberg",
 						name: "Josh Goldberg",
 						profile: "http://www.joshuakgoldberg.com",
 					},
 				],
+				owner: "JoshuaKGoldberg",
 			},
 		});
 
 		expect(creation).toMatchInlineSnapshot(`
-							{
-							  "addons": [
-							    {
-							      "addons": {
-							        "ignores": [
-							          "/.all-contributorsrc",
-							        ],
-							      },
-							      "block": [Function],
-							    },
-							    {
-							      "addons": {
-							        "badges": [
-							          {
-							            "alt": "👪 All Contributors: 1",
-							            "comments": {
-							              "after": "
-							<!-- ALL-CONTRIBUTORS-BADGE:END -->
-								<!-- prettier-ignore-end -->",
-							              "before": "<!-- prettier-ignore-start -->
-								<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
-								",
-							            },
-							            "href": "#contributors",
-							            "src": "https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-1-21bb42.svg",
-							          },
-							        ],
-							        "sections": [
-							          "## Contributors
-
-							<!-- spellchecker: disable -->
-							<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
-							<!-- prettier-ignore-start -->
-							<!-- markdownlint-disable -->
-							<table>
-							  <tbody>
-							    <tr>
-							      <td align="center" valign="top" width="14.28%"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt="Josh Goldberg"/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=author%3AJoshuaKGoldberg" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Code">💻</a> <a href="#design-JoshuaKGoldberg" title="Design">🎨</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Documentation">📖</a> <a href="#ideas-JoshuaKGoldberg" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-JoshuaKGoldberg" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-JoshuaKGoldberg" title="Maintenance">🚧</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/pulls?q=is%3Apr+reviewed-by%3AJoshuaKGoldberg" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Tests">⚠️</a> <a href="#tool-JoshuaKGoldberg" title="Tools">🔧</a></td>
-							    </tr>
-							  </tbody>
-							</table>
-
-							<!-- markdownlint-restore -->
-							<!-- prettier-ignore-end -->
-
-							<!-- ALL-CONTRIBUTORS-LIST:END -->
-							<!-- spellchecker: enable -->",
-							        ],
-							      },
-							      "block": [Function],
-							    },
-							    {
-							      "addons": {
-							        "secrets": [
-							          {
-							            "description": "a GitHub PAT with repo and workflow permissions",
-							            "name": "ACCESS_TOKEN",
-							          },
-							        ],
-							      },
-							      "block": [Function],
-							    },
-							  ],
-							  "files": {
-							    ".all-contributorsrc": "{"badgeTemplate":"\\t<a href=\\"#contributors\\" target=\\"_blank\\"><img alt=\\"👪 All Contributors: <%= contributors.length %>\\" src=\\"https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-<%= contributors.length %>-21bb42.svg\\" /></a>","contributors":[{"avatar_url":"https://avatars.githubusercontent.com/u/3335181?v=4","contributions":["bug","code","design","doc","ideas","infra","maintenance","review","test","tool"],"login":"JoshuaKGoldberg","name":"Josh Goldberg","profile":"http://www.joshuakgoldberg.com"}],"contributorsSortAlphabetically":true,"projectName":"test-repository","projectOwner":"test-owner"}",
-							    ".github": {
-							      "workflows": {
-							        "contributors.yml": "jobs:
-							  contributors:
-							    runs-on: ubuntu-latest
-							    steps:
-							      - uses: actions/checkout@v4
-							        with:
-							          fetch-depth: 0
-							      - uses: ./.github/actions/prepare
-							      - env:
-							          GITHUB_TOKEN: \${{ secrets.ACCESS_TOKEN }}
-							        uses: JoshuaKGoldberg/all-contributors-auto-action@v0.5.0
-
-							name: Contributors
-
-							on:
-							  push:
-							    branches:
-							      - main
-							",
-							      },
-							    },
-							  },
-							  "scripts": [
-							    {
-							      "commands": [
-							        "pnpx all-contributors-cli add test-owner code,content,doc,ideas,infra,maintenance,projectManagement,tool",
-							      ],
-							      "phase": 3,
-							    },
-							  ],
-							}
-						`);
+			{
+			  "addons": [
+			    {
+			      "addons": {
+			        "ignores": [
+			          "/.all-contributorsrc",
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			    {
+			      "addons": {
+			        "badges": [
+			          {
+			            "alt": "👪 All Contributors: 1",
+			            "comments": {
+			              "after": "
+			<!-- ALL-CONTRIBUTORS-BADGE:END -->
+				<!-- prettier-ignore-end -->",
+			              "before": "<!-- prettier-ignore-start -->
+				<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
+				",
+			            },
+			            "href": "#contributors",
+			            "src": "https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-1-21bb42.svg",
+			          },
+			        ],
+			        "sections": [
+			          "## Contributors
+
+			<!-- spellchecker: disable -->
+			<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
+			<!-- prettier-ignore-start -->
+			<!-- markdownlint-disable -->
+			<table>
+			  <tbody>
+			    <tr>
+			      <td align="center" valign="top" width="14.28%"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt="Josh Goldberg"/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=author%3AJoshuaKGoldberg" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Code">💻</a> <a href="#design-JoshuaKGoldberg" title="Design">🎨</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Documentation">📖</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=JoshuaKGoldberg" title="Tests">⚠️</a> <a href="#tool-JoshuaKGoldberg" title="Tools">🔧</a></td>
+			    </tr>
+			  </tbody>
+			</table>
+
+			<!-- markdownlint-restore -->
+			<!-- prettier-ignore-end -->
+
+			<!-- ALL-CONTRIBUTORS-LIST:END -->
+			<!-- spellchecker: enable -->",
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			    {
+			      "addons": {
+			        "secrets": [
+			          {
+			            "description": "a GitHub PAT with repo and workflow permissions",
+			            "name": "ACCESS_TOKEN",
+			          },
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			  ],
+			  "files": {
+			    ".all-contributorsrc": "{"badgeTemplate":"\\t<a href=\\"#contributors\\" target=\\"_blank\\"><img alt=\\"👪 All Contributors: <%= contributors.length %>\\" src=\\"https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-<%= contributors.length %>-21bb42.svg\\" /></a>","contributors":[{"avatar_url":"https://avatars.githubusercontent.com/u/3335181?v=4","contributions":["bug","code","design","doc","test","tool"],"login":"JoshuaKGoldberg","name":"Josh Goldberg","profile":"http://www.joshuakgoldberg.com"}],"contributorsSortAlphabetically":true,"projectName":"test-repository","projectOwner":"JoshuaKGoldberg"}",
+			    ".github": {
+			      "workflows": {
+			        "contributors.yml": "jobs:
+			  contributors:
+			    runs-on: ubuntu-latest
+			    steps:
+			      - uses: actions/checkout@v4
+			        with:
+			          fetch-depth: 0
+			      - uses: ./.github/actions/prepare
+			      - env:
+			          GITHUB_TOKEN: \${{ secrets.ACCESS_TOKEN }}
+			        uses: JoshuaKGoldberg/all-contributors-auto-action@v0.5.0
+
+			name: Contributors
+
+			on:
+			  push:
+			    branches:
+			      - main
+			",
+			      },
+			    },
+			  },
+			  "scripts": [
+			    {
+			      "commands": [
+			        "pnpx all-contributors-cli add JoshuaKGoldberg bug,code,design,doc,test,tool,content,ideas,infra,maintenance,projectManagement",
+			      ],
+			      "phase": 3,
+			    },
+			  ],
+			}
+		`);
+	});
+
+	it("adds full owner contributions when no existing contributor is the owner", () => {
+		const creation = testBlock(blockAllContributors, {
+			options: {
+				...optionsBase,
+				contributors: [
+					{
+						avatar_url: "https://avatars.githubusercontent.com/u/3335181?v=4",
+						contributions: ["bug", "code", "design", "doc", "test", "tool"],
+						login: "other",
+						name: "Other",
+						profile: "http://www.example.com",
+					},
+				],
+			},
+		});
+
+		expect(creation).toMatchInlineSnapshot(`
+			{
+			  "addons": [
+			    {
+			      "addons": {
+			        "ignores": [
+			          "/.all-contributorsrc",
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			    {
+			      "addons": {
+			        "badges": [
+			          {
+			            "alt": "👪 All Contributors: 1",
+			            "comments": {
+			              "after": "
+			<!-- ALL-CONTRIBUTORS-BADGE:END -->
+				<!-- prettier-ignore-end -->",
+			              "before": "<!-- prettier-ignore-start -->
+				<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
+				",
+			            },
+			            "href": "#contributors",
+			            "src": "https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-1-21bb42.svg",
+			          },
+			        ],
+			        "sections": [
+			          "## Contributors
+
+			<!-- spellchecker: disable -->
+			<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
+			<!-- prettier-ignore-start -->
+			<!-- markdownlint-disable -->
+			<table>
+			  <tbody>
+			    <tr>
+			      <td align="center" valign="top" width="14.28%"><a href="http://www.example.com"><img src="https://avatars.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt="Other"/><br /><sub><b>Other</b></sub></a><br /><a href="https://github.com/JoshuaKGoldberg/create-typescript-app/issues?q=author%3Aother" title="Bug reports">🐛</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=other" title="Code">💻</a> <a href="#design-other" title="Design">🎨</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=other" title="Documentation">📖</a> <a href="https://github.com/JoshuaKGoldberg/create-typescript-app/commits?author=other" title="Tests">⚠️</a> <a href="#tool-other" title="Tools">🔧</a></td>
+			    </tr>
+			  </tbody>
+			</table>
+
+			<!-- markdownlint-restore -->
+			<!-- prettier-ignore-end -->
+
+			<!-- ALL-CONTRIBUTORS-LIST:END -->
+			<!-- spellchecker: enable -->",
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			    {
+			      "addons": {
+			        "secrets": [
+			          {
+			            "description": "a GitHub PAT with repo and workflow permissions",
+			            "name": "ACCESS_TOKEN",
+			          },
+			        ],
+			      },
+			      "block": [Function],
+			    },
+			  ],
+			  "files": {
+			    ".all-contributorsrc": "{"badgeTemplate":"\\t<a href=\\"#contributors\\" target=\\"_blank\\"><img alt=\\"👪 All Contributors: <%= contributors.length %>\\" src=\\"https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-<%= contributors.length %>-21bb42.svg\\" /></a>","contributors":[{"avatar_url":"https://avatars.githubusercontent.com/u/3335181?v=4","contributions":["bug","code","design","doc","test","tool"],"login":"other","name":"Other","profile":"http://www.example.com"}],"contributorsSortAlphabetically":true,"projectName":"test-repository","projectOwner":"test-owner"}",
+			    ".github": {
+			      "workflows": {
+			        "contributors.yml": "jobs:
+			  contributors:
+			    runs-on: ubuntu-latest
+			    steps:
+			      - uses: actions/checkout@v4
+			        with:
+			          fetch-depth: 0
+			      - uses: ./.github/actions/prepare
+			      - env:
+			          GITHUB_TOKEN: \${{ secrets.ACCESS_TOKEN }}
+			        uses: JoshuaKGoldberg/all-contributors-auto-action@v0.5.0
+
+			name: Contributors
+
+			on:
+			  push:
+			    branches:
+			      - main
+			",
+			      },
+			    },
+			  },
+			  "scripts": [
+			    {
+			      "commands": [
+			        "pnpx all-contributors-cli add test-owner code,content,doc,ideas,infra,maintenance,projectManagement,tool",
+			      ],
+			      "phase": 3,
+			    },
+			  ],
+			}
+		`);
 	});
 });
diff --git a/src/options/readAllContributors.test.ts b/src/options/readAllContributors.test.ts
index aac45a8..beff9df 100644
--- a/src/options/readAllContributors.test.ts
+++ b/src/options/readAllContributors.test.ts
@@ -1,7 +1,7 @@
 import { createMockSystems } from "bingo-testers";
 import { describe, expect, it, vi } from "vitest";
 
-import { ownerContributions } from "../data/contributions.js";
+import { startingOwnerContributions } from "../data/contributions.js";
 import { readAllContributors } from "./readAllContributors.js";
 
 const mockInputFromFileJSON = vi.fn();
@@ -56,7 +56,7 @@ describe(readAllContributors, () => {
 		expect(actual).toEqual([
 			{
 				avatar_url: "avatar_url",
-				contributions: ownerContributions,
+				contributions: startingOwnerContributions,
 				login: "login",
 				name: "name",
 				profile: "blog",