Skip to content

Commit 39a7fce

Browse files
feat: added nodeVersion Addon to blockGitHubActionsCI (#2189)
## PR Checklist - [x] Addresses an existing open issue: fixes #2183 - [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 Includes an `intake` method so it can be inferred from disk. 🎁
1 parent c5e6c46 commit 39a7fce

File tree

2 files changed

+199
-5
lines changed

2 files changed

+199
-5
lines changed

Diff for: src/blocks/blockGitHubActionsCI.test.ts

+156-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { testBlock } from "bingo-stratum-testers";
2-
import { describe, expect, test } from "vitest";
1+
import { testBlock, testIntake } from "bingo-stratum-testers";
2+
import jsYaml from "js-yaml";
3+
import { describe, expect, it, test } from "vitest";
34

45
import { blockGitHubActionsCI } from "./blockGitHubActionsCI.js";
56
import { optionsBase } from "./options.fakes.js";
@@ -565,4 +566,157 @@ describe("blockGitHubActionsCI", () => {
565566
}
566567
`);
567568
});
569+
570+
describe("intake", () => {
571+
it("returns undefined when action.yml does not exist", () => {
572+
const actual = testIntake(blockGitHubActionsCI, {
573+
files: {},
574+
});
575+
576+
expect(actual).toBeUndefined();
577+
});
578+
579+
it("returns undefined when action.yml contains invalid yml", () => {
580+
const actual = testIntake(blockGitHubActionsCI, {
581+
files: {
582+
".github": {
583+
actions: {
584+
prepare: {
585+
"action.yml": ["invalid yml!"],
586+
},
587+
},
588+
},
589+
},
590+
});
591+
592+
expect(actual).toBeUndefined();
593+
});
594+
595+
it("returns undefined when action.yml does not contain a runs entry", () => {
596+
const actual = testIntake(blockGitHubActionsCI, {
597+
files: {
598+
".github": {
599+
actions: {
600+
prepare: {
601+
"action.yml": [
602+
jsYaml.dump({
603+
other: {
604+
steps: [],
605+
},
606+
}),
607+
],
608+
},
609+
},
610+
},
611+
},
612+
});
613+
614+
expect(actual).toBeUndefined();
615+
});
616+
617+
it("returns undefined when action.yml runs steps is not an array", () => {
618+
const actual = testIntake(blockGitHubActionsCI, {
619+
files: {
620+
".github": {
621+
actions: {
622+
prepare: {
623+
"action.yml": [
624+
jsYaml.dump({
625+
runs: {
626+
steps: true,
627+
},
628+
}),
629+
],
630+
},
631+
},
632+
},
633+
},
634+
});
635+
636+
expect(actual).toBeUndefined();
637+
});
638+
639+
it("returns undefined env when action.yml contains a test action with actions/setup-node step", () => {
640+
const actual = testIntake(blockGitHubActionsCI, {
641+
files: {
642+
".github": {
643+
actions: {
644+
prepare: {
645+
"action.yml": [
646+
jsYaml.dump({
647+
runs: {
648+
steps: [
649+
{
650+
uses: "actions/other@v1",
651+
},
652+
],
653+
},
654+
}),
655+
],
656+
},
657+
},
658+
},
659+
},
660+
});
661+
662+
expect(actual).toBeUndefined();
663+
});
664+
665+
it("returns undefined env when action.yml contains a test action with no env in its actions/setup-node step", () => {
666+
const actual = testIntake(blockGitHubActionsCI, {
667+
files: {
668+
".github": {
669+
actions: {
670+
prepare: {
671+
"action.yml": [
672+
jsYaml.dump({
673+
runs: {
674+
steps: [
675+
{
676+
uses: "actions/setup-node@v4",
677+
},
678+
],
679+
},
680+
}),
681+
],
682+
},
683+
},
684+
},
685+
},
686+
});
687+
688+
expect(actual).toBeUndefined();
689+
});
690+
691+
it("returns nodeVersion when action.yml contains a test action with node-version in its actions/setup/node step", () => {
692+
const nodeVersion = "20.10.0";
693+
694+
const actual = testIntake(blockGitHubActionsCI, {
695+
files: {
696+
".github": {
697+
actions: {
698+
prepare: {
699+
"action.yml": [
700+
jsYaml.dump({
701+
runs: {
702+
steps: [
703+
{
704+
uses: "actions/setup-node@v4",
705+
with: {
706+
"node-version": nodeVersion,
707+
},
708+
},
709+
],
710+
},
711+
}),
712+
],
713+
},
714+
},
715+
},
716+
},
717+
});
718+
719+
expect(actual).toEqual({ nodeVersion });
720+
});
721+
});
568722
});

Diff for: src/blocks/blockGitHubActionsCI.ts

+43-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import _ from "lodash";
12
import { z } from "zod";
23

34
import { base } from "../base.js";
@@ -7,6 +8,7 @@ import { blockRepositoryBranchRuleset } from "./blockRepositoryBranchRuleset.js"
78
import { createMultiWorkflowFile } from "./files/createMultiWorkflowFile.js";
89
import { createSoloWorkflowFile } from "./files/createSoloWorkflowFile.js";
910
import { formatYaml } from "./files/formatYaml.js";
11+
import { intakeFileAsYaml } from "./intake/intakeFileAsYaml.js";
1012

1113
export const zActionStep = z.intersection(
1214
z.object({
@@ -17,6 +19,11 @@ export const zActionStep = z.intersection(
1719
z.union([z.object({ run: z.string() }), z.object({ uses: z.string() })]),
1820
);
1921

22+
interface RunStep {
23+
uses?: unknown;
24+
with?: Record<string, string>;
25+
}
26+
2027
export const blockGitHubActionsCI = base.createBlock({
2128
about: {
2229
name: "GitHub Actions CI",
@@ -32,9 +39,43 @@ export const blockGitHubActionsCI = base.createBlock({
3239
}),
3340
)
3441
.optional(),
42+
nodeVersion: z.union([z.number(), z.string()]).optional(),
43+
},
44+
intake({ files }) {
45+
const actionYml = intakeFileAsYaml(files, [
46+
".github",
47+
"actions",
48+
"prepare",
49+
"action.yml",
50+
]);
51+
if (!actionYml) {
52+
return;
53+
}
54+
55+
const steps = _.get(actionYml, ["runs", "steps"]) as RunStep[] | undefined;
56+
if (!steps || !Array.isArray(steps)) {
57+
return undefined;
58+
}
59+
60+
const setupNodeStep = steps.find(
61+
(step) =>
62+
typeof step.uses === "string" &&
63+
step.uses.startsWith("actions/setup-node"),
64+
);
65+
if (!setupNodeStep) {
66+
return undefined;
67+
}
68+
69+
const nodeVersion = setupNodeStep.with?.["node-version"];
70+
if (!nodeVersion) {
71+
return undefined;
72+
}
73+
74+
return { nodeVersion };
3575
},
3676
produce({ addons, options }) {
37-
const { jobs } = addons;
77+
const { jobs, nodeVersion = options.node.pinned ?? options.node.minimum } =
78+
addons;
3879

3980
return {
4081
addons: [
@@ -66,8 +107,7 @@ export const blockGitHubActionsCI = base.createBlock({
66107
),
67108
with: {
68109
cache: "pnpm",
69-
"node-version":
70-
options.node.pinned ?? options.node.minimum,
110+
"node-version": nodeVersion,
71111
},
72112
},
73113
{

0 commit comments

Comments
 (0)