Skip to content

Commit f237e04

Browse files
committed
fix: hidden --node-version flag to bypass version discovery
Signed-off-by: Michael Molisani <mmolisani@bloomberg.net>
1 parent 1a762b0 commit f237e04

11 files changed

+346
-8
lines changed

packages/create-app/src/app.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright 2024 Bloomberg Finance L.P.
22
// Distributed under the terms of the Apache 2.0 license.
3-
import { buildApplication, buildCommand } from "@stricli/core";
3+
import { buildApplication, buildCommand, numberParser } from "@stricli/core";
44
import packageJson from "../package.json";
55

66
const command = buildCommand({
@@ -67,6 +67,13 @@ const command = buildCommand({
6767
parse: String,
6868
default: "",
6969
},
70+
nodeVersion: {
71+
kind: "parsed",
72+
brief: "Node.js major version to use for engines.node minimum and @types/node, bypasses version discovery logic",
73+
parse: numberParser,
74+
optional: true,
75+
hidden: true,
76+
},
7077
},
7178
aliases: {
7279
n: "name",

packages/create-app/src/impl.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export interface CreateProjectFlags extends PackageJsonTemplateValues {
115115
readonly template: "single" | "multi";
116116
readonly autoComplete: boolean;
117117
readonly command?: string;
118+
readonly nodeVersion?: number;
118119
}
119120

120121
export default async function (this: LocalContext, flags: CreateProjectFlags, directoryPath: string): Promise<void> {
@@ -137,7 +138,12 @@ export default async function (this: LocalContext, flags: CreateProjectFlags, di
137138
const packageName = flags.name ?? path.basename(directoryPath);
138139
const commandName = flags.command ?? packageName;
139140

140-
const nodeVersions = await calculateAcceptableNodeVersions(this.process);
141+
let nodeVersions: NodeVersions;
142+
if (flags.nodeVersion) {
143+
nodeVersions = { engine: `>=${flags.nodeVersion}`, types: `${flags.nodeVersion}.x` };
144+
} else {
145+
nodeVersions = await calculateAcceptableNodeVersions(this.process);
146+
}
141147

142148
let packageJson = buildPackageJson(
143149
{

packages/create-app/src/node.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ export async function calculateAcceptableNodeVersions(process: NodeJS.Process):
3636
process.stderr.write(
3737
`No version of @types/node found with major ${majorVersion}, falling back to ${typesVersion}\n`,
3838
);
39+
process.stderr.write(
40+
`Rerun this command with the hidden flag --node-version to manually specify the Node.js major version`,
41+
);
3942
}
4043
}
4144
}
@@ -49,6 +52,9 @@ export async function calculateAcceptableNodeVersions(process: NodeJS.Process):
4952
process.stderr.write(
5053
`Unable to determine version of @types/node for ${process.versions.node}, assuming ${typesVersion}\n`,
5154
);
55+
process.stderr.write(
56+
`Rerun this command with the hidden flag --node-version to manually specify the Node.js major version`,
57+
);
5258
}
5359

5460
return {

packages/create-app/tests/app.spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,48 @@ describe("creates new application", () => {
783783
});
784784

785785
describe("node version logic", () => {
786+
it("version discovery skipped when --node-version is provided", async function () {
787+
const stdout = new FakeWritableStream();
788+
const stderr = new FakeWritableStream();
789+
const cwd = sinon.stub().returns("/home");
790+
const vol = Volume.fromJSON({});
791+
const memfs = createFsFromVolume(vol);
792+
793+
const execFileSync = sandbox.stub(child_process, "execFileSync");
794+
execFileSync.returns("REGISTRY");
795+
796+
const fetch = sandbox.stub(globalThis, "fetch");
797+
fetch.resolves(new Response(JSON.stringify({})));
798+
799+
const context: DeepPartial<LocalContext> = {
800+
process: {
801+
stdout,
802+
stderr,
803+
cwd,
804+
versions: {
805+
node: `${futureLTSNodeMajorVersion}.0.0`,
806+
},
807+
},
808+
fs: memfs as any,
809+
path: nodePath,
810+
};
811+
812+
await run(
813+
app,
814+
["node-version-test", "--node-version", `${futureLTSNodeMajorVersion + 1}`],
815+
context as LocalContext,
816+
);
817+
818+
const result = {
819+
stdout: stdout.text,
820+
stderr: stderr.text,
821+
files: vol.toJSON(),
822+
};
823+
compareToBaseline(this, ApplicationTestResultFormat, result);
824+
expect(execFileSync.callCount).to.equal(0, "execFileSync called unexpectedly");
825+
expect(fetch.callCount).to.equal(0, "fetch called unexpectedly");
826+
});
827+
786828
it("exact version exists for types", async function () {
787829
const stdout = new FakeWritableStream();
788830
const stderr = new FakeWritableStream();

packages/create-app/tests/baselines/reference/app/creates new application/checks for @types__node/node version logic/major version does not exist in registry, picks highest even major.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[STDERR]
44
No version of @types/node found with major 30, falling back to 20.x
5-
5+
Rerun this command with the hidden flag --node-version to manually specify the Node.js major version
66
[FILES]
77
::::/home/node-version-test/.gitignore
88
# Logs

0 commit comments

Comments
 (0)