Skip to content

Commit 784dfbb

Browse files
fix: only PUT a ruleset when an ID already exists (#1968)
## PR Checklist - [x] Addresses an existing open issue: fixes #1967 - [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 If `options.rulesetId` doesn't exist, then transition mode should still `POST` a new ruleset, not `PUT` to update an existing one. 🎁
1 parent 5dd93c0 commit 784dfbb

File tree

2 files changed

+106
-69
lines changed

2 files changed

+106
-69
lines changed

src/blocks/blockRepositoryBranchRuleset.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,28 @@ describe("blockRepositoryBranchRuleset", () => {
104104
}
105105
`);
106106
});
107+
108+
test("with addons and a ruleset_id option when mode is transition", () => {
109+
const creation = testBlock(blockRepositoryBranchRuleset, {
110+
addons: {
111+
requiredStatusChecks: ["build", "test"],
112+
},
113+
mode: "setup",
114+
options: {
115+
...optionsBase,
116+
rulesetId: "1234",
117+
},
118+
});
119+
120+
expect(creation).toMatchInlineSnapshot(`
121+
{
122+
"requests": [
123+
{
124+
"id": "branch-ruleset-create",
125+
"send": [Function],
126+
},
127+
],
128+
}
129+
`);
130+
});
107131
});
Lines changed: 82 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { BlockCreation } from "bingo-stratum";
21
import { z } from "zod";
32

43
import { base, BaseOptions } from "../base.js";
@@ -11,22 +10,45 @@ export const blockRepositoryBranchRuleset = base.createBlock({
1110
requiredStatusChecks: z.array(z.string()).default([]),
1211
},
1312
setup({ addons, options }) {
14-
return createRequestSend(
15-
addons.requiredStatusChecks,
16-
"POST /repos/{owner}/{repo}/rulesets",
17-
options,
18-
"branch-ruleset-create",
19-
undefined,
20-
);
13+
return {
14+
requests: [
15+
{
16+
id: "branch-ruleset-create",
17+
async send({ octokit }) {
18+
await octokit.request(
19+
"POST /repos/{owner}/{repo}/rulesets",
20+
createInnerSend(addons.requiredStatusChecks, options),
21+
);
22+
},
23+
},
24+
],
25+
};
2126
},
2227
transition({ addons, options }) {
23-
return createRequestSend(
24-
addons.requiredStatusChecks,
25-
`PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}`,
26-
options,
27-
"branch-ruleset-update",
28-
options.rulesetId,
29-
);
28+
return {
29+
requests: [
30+
{
31+
id: "branch-ruleset-update",
32+
async send({ octokit }) {
33+
if (options.rulesetId) {
34+
await octokit.request(
35+
`PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}`,
36+
createInnerSend(
37+
addons.requiredStatusChecks,
38+
options,
39+
options.rulesetId,
40+
),
41+
);
42+
} else {
43+
await octokit.request(
44+
`POST /repos/{owner}/{repo}/rulesets/{ruleset_id}`,
45+
createInnerSend(addons.requiredStatusChecks, options),
46+
);
47+
}
48+
},
49+
},
50+
],
51+
};
3052
},
3153
// TODO: Make produce() optional
3254
// This needs createBlock to be generic to know if block.produce({}) is ok
@@ -35,66 +57,57 @@ export const blockRepositoryBranchRuleset = base.createBlock({
3557
},
3658
});
3759

38-
function createRequestSend(
60+
function createInnerSend(
3961
contexts: string[],
40-
endpoint: string,
4162
options: BaseOptions,
42-
requestId: string,
43-
rulesetId: string | undefined,
44-
): Partial<BlockCreation<BaseOptions>> {
63+
rulesetId?: string,
64+
) {
4565
return {
46-
requests: [
66+
bypass_actors: [
67+
{
68+
// This *seems* to be the Repository Admin role always?
69+
// https://github.com/github/rest-api-description/issues/4406
70+
actor_id: 5,
71+
actor_type: "RepositoryRole" as const,
72+
bypass_mode: "always" as const,
73+
},
74+
],
75+
conditions: {
76+
ref_name: {
77+
exclude: [],
78+
include: ["refs/heads/main"],
79+
},
80+
},
81+
enforcement: "active" as const,
82+
name: "Branch protection for main",
83+
owner: options.owner,
84+
repo: options.repository,
85+
rules: [
86+
{ type: "deletion" as const },
87+
{
88+
parameters: {
89+
allowed_merge_methods: ["squash"],
90+
dismiss_stale_reviews_on_push: false,
91+
require_code_owner_review: false,
92+
require_last_push_approval: false,
93+
required_approving_review_count: 0,
94+
required_review_thread_resolution: false,
95+
},
96+
type: "pull_request" as const,
97+
},
4798
{
48-
id: requestId,
49-
async send({ octokit }) {
50-
await octokit.request(endpoint, {
51-
bypass_actors: [
52-
{
53-
// This *seems* to be the Repository Admin role always?
54-
// https://github.com/github/rest-api-description/issues/4406
55-
actor_id: 5,
56-
actor_type: "RepositoryRole",
57-
bypass_mode: "always",
58-
},
59-
],
60-
conditions: {
61-
ref_name: {
62-
exclude: [],
63-
include: ["refs/heads/main"],
64-
},
65-
},
66-
enforcement: "active",
67-
name: "Branch protection for main",
68-
owner: options.owner,
69-
repo: options.repository,
70-
rules: [
71-
{ type: "deletion" },
72-
{
73-
parameters: {
74-
allowed_merge_methods: ["squash"],
75-
dismiss_stale_reviews_on_push: false,
76-
require_code_owner_review: false,
77-
require_last_push_approval: false,
78-
required_approving_review_count: 0,
79-
required_review_thread_resolution: false,
80-
},
81-
type: "pull_request",
82-
},
83-
{
84-
parameters: {
85-
required_status_checks: contexts.map((context) => ({
86-
context,
87-
})),
88-
strict_required_status_checks_policy: false,
89-
},
90-
type: "required_status_checks",
91-
},
92-
],
93-
ruleset_id: rulesetId,
94-
target: "branch",
95-
});
99+
parameters: {
100+
required_status_checks: contexts.map((context) => ({
101+
context,
102+
})),
103+
strict_required_status_checks_policy: false,
96104
},
105+
type: "required_status_checks" as const,
97106
},
98107
],
108+
// Type fun because the GitHub Octokit APIs don't provide named types...
109+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
110+
ruleset_id: (rulesetId === undefined ? rulesetId : Number(rulesetId))!,
111+
target: "branch" as const,
99112
};
100113
}

0 commit comments

Comments
 (0)