Skip to content

Commit

Permalink
fix: gate branch protection settings on options exclusions (#1310)
Browse files Browse the repository at this point in the history
## PR Checklist

- [x] Addresses an existing open issue: fixes #1171
- [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

This way, when creating/initializing/migrating a repository, branch
protection settings won't be created for excluded options' CI flows.
  • Loading branch information
JoshuaKGoldberg committed Feb 15, 2024
1 parent 050cacf commit 3a8c7c0
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 14 deletions.
127 changes: 123 additions & 4 deletions src/steps/initializeBranchProtectionSettings.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import { Octokit } from "octokit";
import { MockInstance, describe, expect, it, vi } from "vitest";

import { Options } from "../shared/types.js";
import { initializeBranchProtectionSettings } from "./initializeGitHubRepository/initializeBranchProtectionSettings.js";

const createMockOctokit = (request: MockInstance) =>
({
request,
}) as unknown as Octokit;

const stubValues = { owner: "", repository: "" };
const stubOptions = {
access: "public",
description: "",
directory: "",
email: {
github: "",
npm: "",
},
mode: "create",
owner: "",
repository: "",
title: "",
} satisfies Options;

describe("migrateBranchProtectionSettings", () => {
it("does not throw when the request receives a non-error response", async () => {
Expand All @@ -17,17 +30,72 @@ describe("migrateBranchProtectionSettings", () => {
await expect(
initializeBranchProtectionSettings(
createMockOctokit(mockRequest),
stubValues,
stubOptions,
),
).resolves.not.toThrow();

expect(mockRequest.mock.calls).toMatchInlineSnapshot(`
[
[
"PUT /repos///branches/main/protection",
{
"allow_deletions": false,
"allow_force_pushes": true,
"allow_fork_pushes": false,
"allow_fork_syncing": true,
"block_creations": false,
"branch": "main",
"enforce_admins": false,
"owner": "",
"repo": "",
"required_conversation_resolution": true,
"required_linear_history": false,
"required_pull_request_reviews": null,
"required_status_checks": {
"checks": [
{
"context": "build",
},
{
"context": "lint",
},
{
"context": "prettier",
},
{
"context": "compliance",
},
{
"context": "lint_knip",
},
{
"context": "lint_markdown",
},
{
"context": "lint_packages",
},
{
"context": "lint_spelling",
},
{
"context": "test",
},
],
"strict": false,
},
"restrictions": null,
},
],
]
`);
});

it("returns false when the request receives a 403 response", async () => {
const mockRequest = vi.fn().mockRejectedValue({ status: 403 });

const actual = await initializeBranchProtectionSettings(
createMockOctokit(mockRequest),
stubValues,
stubOptions,
);

expect(actual).toBe(false);
Expand All @@ -40,8 +108,59 @@ describe("migrateBranchProtectionSettings", () => {
await expect(() =>
initializeBranchProtectionSettings(
createMockOctokit(mockRequest),
stubValues,
stubOptions,
),
).rejects.toBe(error);
});

it("doesn't create workflows for excluded options when specified", async () => {
const mockRequest = vi.fn().mockResolvedValue({ status: 200 });

await initializeBranchProtectionSettings(createMockOctokit(mockRequest), {
...stubOptions,
excludeCompliance: true,
excludeLintKnip: true,
excludeLintMd: true,
excludeLintPackages: true,
excludeLintSpelling: true,
excludeTests: true,
});

expect(mockRequest.mock.calls).toMatchInlineSnapshot(`
[
[
"PUT /repos///branches/main/protection",
{
"allow_deletions": false,
"allow_force_pushes": true,
"allow_fork_pushes": false,
"allow_fork_syncing": true,
"block_creations": false,
"branch": "main",
"enforce_admins": false,
"owner": "",
"repo": "",
"required_conversation_resolution": true,
"required_linear_history": false,
"required_pull_request_reviews": null,
"required_status_checks": {
"checks": [
{
"context": "build",
},
{
"context": "lint",
},
{
"context": "prettier",
},
],
"strict": false,
},
"restrictions": null,
},
],
]
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { Options } from "../../shared/types.js";

export async function initializeBranchProtectionSettings(
octokit: Octokit,
{ owner, repository }: Pick<Options, "owner" | "repository">,
options: Options,
) {
try {
await octokit.request(
`PUT /repos/${owner}/${repository}/branches/main/protection`,
`PUT /repos/${options.owner}/${options.repository}/branches/main/protection`,
{
allow_deletions: false,
allow_force_pushes: true,
Expand All @@ -18,22 +18,26 @@ export async function initializeBranchProtectionSettings(
block_creations: false,
branch: "main",
enforce_admins: false,
owner,
repo: repository,
owner: options.owner,
repo: options.repository,
required_conversation_resolution: true,
required_linear_history: false,
required_pull_request_reviews: null,
required_status_checks: {
checks: [
{ context: "build" },
{ context: "compliance" },
{ context: "lint" },
{ context: "lint_knip" },
{ context: "lint_markdown" },
{ context: "lint_packages" },
{ context: "lint_spelling" },
{ context: "prettier" },
{ context: "test" },
...(options.excludeCompliance ? [] : [{ context: "compliance" }]),
...(options.excludeLintKnip ? [] : [{ context: "lint_knip" }]),
...(options.excludeLintMd ? [] : [{ context: "lint_markdown" }]),
...(options.excludeLintPackages
? []
: [{ context: "lint_packages" }]),
...(options.excludeLintSpelling
? []
: [{ context: "lint_spelling" }]),
...(options.excludeTests ? [] : [{ context: "test" }]),
],
strict: false,
},
Expand Down

0 comments on commit 3a8c7c0

Please sign in to comment.