Repository: JoshuaKGoldberg/template-typescript-node-package (ts)

Issue:
🐛 Bug: Initialization in newly created repo: no git remotes found from gh label list --json name
### 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/template-typescript-node-package/issues?q=is%3Aissue) and found none that matched my issue.

### Expected

After running `npx template-typescript-node-package --skip-github-api`, you're suggested to run the `npx template-typescript-node-package --mode initialize` command in the new repo. That should pass.

### Actual

First I get this error about `no git remotes found`:

```plaintext
Error: Failed initializing GitHub repository
    at withSpinner (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/shared/cli/spinners.js:16:11)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async initializeWithOptions (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/initializeWithOptions.js:39:5)
    at async run (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/index.js:11:7)
    at async runOrRestore (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/shared/runOrRestore.js:7:5)
    at async Object.initialize (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/index.js:9:10)
    at async bin (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/bin/index.js:47:10)
    at async file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/bin/index.js:4:20 {
  [cause]: Error: Command failed with exit code 1: gh label list --json name
  no git remotes found
      at makeError (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/execa/lib/error.js:60:11)
      at handlePromise (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/execa/index.js:124:26)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async initializeRepositoryLabels (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/steps/initializeGitHubRepository/labels/initializeRepositoryLabels.js:7:6)
      at async initializeGitHubRepository (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/steps/initializeGitHubRepository/index.js:6:3)
      at async file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/initializeWithOptions.js:40:7
      at async withSpinner (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/shared/cli/spinners.js:11:20)
      at async initializeWithOptions (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/initializeWithOptions.js:39:5)
      at async run (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/initialize/index.js:11:7)
      at async runOrRestore (file:///Users/josh/.npm/_npx/b39740db704b12a5/node_modules/template-typescript-node-package/lib/shared/runOrRestore.js:7:5) {
    shortMessage: 'Command failed with exit code 1: gh label list --json name',
    command: 'gh label list --json name',
    escapedCommand: 'gh label list --json name',
    exitCode: 1,
    signal: undefined,
    signalDescription: undefined,
    stdout: '',
    stderr: 'no git remotes found',
    cwd: '/Users/josh/repos/temp/testing-cta-6',
    failed: true,
    timedOut: false,
    isCanceled: false,
    killed: false
  }
}
```

### Additional Info

_No response_

Pull request description:
fix: initialize git remote if needed
## PR Checklist

- [x] Addresses an existing open issue: fixes #722
- [x] That issue was marked as [`status: accepting prs`](https://github.com/JoshuaKGoldberg/template-typescript-node-package/issues?q=is%3Aopen+is%3Aissue+label%3A%22status%3A+accepting+prs%22)
- [x] Steps in [CONTRIBUTING.md](https://github.com/JoshuaKGoldberg/template-typescript-node-package/blob/main/.github/CONTRIBUTING.md) were taken

## Overview

In `initializeGitHubRepository`, if there isn't yet an `origin` remote per `git remote`, adds one.

Patch:
diff --git a/src/steps/initializeGitHubRepository/index.ts b/src/steps/initializeGitHubRepository/index.ts
index 472dc14..5298e71 100644
--- a/src/steps/initializeGitHubRepository/index.ts
+++ b/src/steps/initializeGitHubRepository/index.ts
@@ -1,6 +1,7 @@
 import { Octokit } from "octokit";
 
 import { Options } from "../../shared/types.js";
+import { initializeGitRemote } from "../initializeGitRemote.js";
 import { initializeRepositorySettings } from "../initializeRepositorySettings.js";
 import { initializeBranchProtectionSettings } from "./initializeBranchProtectionSettings.js";
 import { initializeRepositoryLabels } from "./labels/initializeRepositoryLabels.js";
@@ -9,7 +10,8 @@ export async function initializeGitHubRepository(
 	octokit: Octokit,
 	options: Options,
 ) {
+	await initializeGitRemote(options);
+	await initializeRepositorySettings(octokit, options);
 	await initializeBranchProtectionSettings(octokit, options);
 	await initializeRepositoryLabels();
-	await initializeRepositorySettings(octokit, options);
 }
diff --git a/src/steps/initializeGitRemote.ts b/src/steps/initializeGitRemote.ts
new file mode 100644
index 0000000..46c7a70
--- /dev/null
+++ b/src/steps/initializeGitRemote.ts
@@ -0,0 +1,17 @@
+import { $ } from "execa";
+
+import { Options } from "../shared/types.js";
+
+type InitializeRepositorySettings = Pick<Options, "owner" | "repository">;
+
+export async function initializeGitRemote({
+	owner,
+	repository,
+}: InitializeRepositorySettings) {
+	const remotes = (await $`git remote`).stdout.trim().split("\n");
+
+	if (!remotes.includes("origin")) {
+		await $`git remote add origin https://github.com/${owner}/${repository}`;
+		await $`git fetch`;
+	}
+}


Test patch:
diff --git a/src/steps/initializeGitRemote.test.ts b/src/steps/initializeGitRemote.test.ts
new file mode 100644
index 0000000..65b67d9
--- /dev/null
+++ b/src/steps/initializeGitRemote.test.ts
@@ -0,0 +1,68 @@
+import { describe, expect, it, vi } from "vitest";
+
+import { initializeGitRemote } from "./initializeGitRemote.js";
+
+const mock$ = vi.fn();
+
+vi.mock("execa", () => ({
+	get $() {
+		return mock$;
+	},
+}));
+
+const options = {
+	owner: "TestOwner",
+	repository: "test-repository",
+};
+
+describe("initializeGitRemote", () => {
+	it("does not add an origin or fetch when remotes already includes origin", async () => {
+		mock$.mockResolvedValue({
+			stdout: "origin",
+		});
+
+		await initializeGitRemote(options);
+
+		expect(mock$.mock.calls).toMatchInlineSnapshot(`
+			[
+			  [
+			    [
+			      "git remote",
+			    ],
+			  ],
+			]
+		`);
+	});
+
+	it("add an origin and fetch when remotes does not include origin", async () => {
+		mock$.mockResolvedValue({
+			stdout: "",
+		});
+
+		await initializeGitRemote(options);
+
+		expect(mock$.mock.calls).toMatchInlineSnapshot(`
+			[
+			  [
+			    [
+			      "git remote",
+			    ],
+			  ],
+			  [
+			    [
+			      "git remote add origin https://github.com/",
+			      "/",
+			      "",
+			    ],
+			    "TestOwner",
+			    "test-repository",
+			  ],
+			  [
+			    [
+			      "git fetch",
+			    ],
+			  ],
+			]
+		`);
+	});
+});