@highstate/cli 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/template/packages/library/package.tpl.json +2 -2
- package/assets/template/packages/units/package.tpl.json +7 -5
- package/dist/chunk-VNBLDKUT.js +1744 -0
- package/dist/chunk-VNBLDKUT.js.map +1 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/highstate.manifest.json +2 -1
- package/dist/main.js +10 -1372
- package/dist/main.js.map +1 -1
- package/package.json +13 -4
- package/src/commands/designer.ts +25 -2
- package/src/commands/index.ts +12 -0
- package/src/commands/init.ts +52 -23
- package/src/commands/package/create.ts +1 -1
- package/src/commands/package/list.ts +1 -1
- package/src/commands/package/remove.ts +1 -1
- package/src/commands/package/update-references.ts +1 -1
- package/src/commands/update.ts +156 -0
- package/src/main.ts +18 -15
- package/src/shared/entry-points.ts +11 -4
- package/src/shared/index.ts +8 -0
- package/src/shared/npm-registry.ts +67 -0
- package/src/shared/overrides.ts +73 -0
- package/src/shared/package-json.ts +6 -0
- package/src/shared/pnpm-workspace.ts +32 -0
- package/src/shared/project-versions.ts +54 -0
- package/src/shared/pulumi-cli.ts +21 -0
- package/src/shared/version-bundle.ts +51 -0
- package/src/shared/version-sets.ts +36 -0
- package/src/commands/package/index.ts +0 -4
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises"
|
|
2
|
+
import { Command, Option } from "clipanion"
|
|
3
|
+
import { detectPackageManager } from "nypm"
|
|
4
|
+
import semver from "semver"
|
|
5
|
+
import {
|
|
6
|
+
applyOverrides,
|
|
7
|
+
buildOverrides,
|
|
8
|
+
fetchManifest,
|
|
9
|
+
getDependencyRange,
|
|
10
|
+
getProjectPlatformVersion,
|
|
11
|
+
logger,
|
|
12
|
+
resolveVersionBundle,
|
|
13
|
+
} from "../shared"
|
|
14
|
+
|
|
15
|
+
export class UpdateCommand extends Command {
|
|
16
|
+
static paths = [["update"]]
|
|
17
|
+
|
|
18
|
+
static usage = Command.Usage({
|
|
19
|
+
description: "Updates version overrides in an existing Highstate project.",
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
platformVersion = Option.String("--platform-version", {
|
|
23
|
+
description: "The Highstate platform version to set.",
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
stdlibVersion = Option.String("--stdlib-version", {
|
|
27
|
+
description: "The Highstate standard library version to set.",
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
platformOnly = Option.Boolean("--platform", false, {
|
|
31
|
+
description: "Update only platform versions.",
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
stdlibOnly = Option.Boolean("--stdlib", false, {
|
|
35
|
+
description: "Update only standard library versions.",
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
install = Option.Boolean("--install", true, {
|
|
39
|
+
description: "Install dependencies after updating overrides.",
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
async execute(): Promise<void> {
|
|
43
|
+
const projectRoot = process.cwd()
|
|
44
|
+
|
|
45
|
+
const packageManager = await resolveProjectPackageManager(projectRoot)
|
|
46
|
+
|
|
47
|
+
if (this.platformOnly && this.stdlibOnly) {
|
|
48
|
+
throw new Error('Flags "--platform" and "--stdlib" cannot be used together')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const updatePlatform = this.platformOnly || !this.stdlibOnly
|
|
52
|
+
const updateStdlib = this.stdlibOnly || !this.platformOnly
|
|
53
|
+
|
|
54
|
+
if (this.stdlibOnly) {
|
|
55
|
+
const currentPlatformVersion = await getProjectPlatformVersion(projectRoot, {
|
|
56
|
+
packageManager,
|
|
57
|
+
})
|
|
58
|
+
if (!currentPlatformVersion) {
|
|
59
|
+
throw new Error('Current platform version is not set in overrides for "@highstate/pulumi"')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const targetStdlibVersion = (this.stdlibVersion ?? "").trim()
|
|
63
|
+
if (targetStdlibVersion.length === 0) {
|
|
64
|
+
throw new Error('Flag "--stdlib-version" must be provided when using "--stdlib"')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const stdlibManifest = await fetchManifest("@highstate/library", targetStdlibVersion)
|
|
68
|
+
const supportedPlatformRange = getDependencyRange(stdlibManifest, "@highstate/pulumi")
|
|
69
|
+
if (!supportedPlatformRange) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Unable to infer "@highstate/pulumi" version from "@highstate/library@${targetStdlibVersion}"`,
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const validPlatform = semver.valid(currentPlatformVersion)
|
|
76
|
+
if (!validPlatform) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Current platform version is not a valid semver "${currentPlatformVersion}"`,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const ok = semver.satisfies(validPlatform, supportedPlatformRange, {
|
|
83
|
+
includePrerelease: true,
|
|
84
|
+
})
|
|
85
|
+
if (!ok) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Current platform version "${currentPlatformVersion}" does not satisfy requirement "${supportedPlatformRange}"`,
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const bundle = await resolveVersionBundle({
|
|
93
|
+
platformVersion: updatePlatform ? this.platformVersion : undefined,
|
|
94
|
+
stdlibVersion: updateStdlib ? this.stdlibVersion : undefined,
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const overrides = buildOverrides(bundle)
|
|
98
|
+
await applyOverrides({
|
|
99
|
+
projectRoot,
|
|
100
|
+
packageManager,
|
|
101
|
+
overrides,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
logger.info(
|
|
105
|
+
"updated overrides: platform=%s stdlib=%s pulumi=%s",
|
|
106
|
+
bundle.platformVersion,
|
|
107
|
+
bundle.stdlibVersion,
|
|
108
|
+
bundle.pulumiVersion,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if (this.install) {
|
|
112
|
+
const { installDependencies } = await import("nypm")
|
|
113
|
+
|
|
114
|
+
logger.info("installing dependencies using %s...", packageManager)
|
|
115
|
+
|
|
116
|
+
await installDependencies({
|
|
117
|
+
cwd: projectRoot,
|
|
118
|
+
packageManager,
|
|
119
|
+
silent: false,
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
logger.info("update completed successfully")
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function resolveProjectPackageManager(projectRoot: string) {
|
|
128
|
+
const detected = await detectPackageManager(projectRoot)
|
|
129
|
+
if (!detected?.name) {
|
|
130
|
+
throw new Error("Unable to detect package manager for this project")
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (detected.name === "bun") {
|
|
134
|
+
throw new Error('Package manager "bun" is not supported')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (detected.name === "deno") {
|
|
138
|
+
throw new Error('Package manager "deno" is not supported')
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (detected.name !== "npm" && detected.name !== "pnpm" && detected.name !== "yarn") {
|
|
142
|
+
throw new Error(`Unsupported package manager: "${detected.name}"`)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await assertPackageJsonExists(projectRoot)
|
|
146
|
+
|
|
147
|
+
return detected.name
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function assertPackageJsonExists(projectRoot: string): Promise<void> {
|
|
151
|
+
try {
|
|
152
|
+
await readFile(`${projectRoot}/package.json`, "utf8")
|
|
153
|
+
} catch {
|
|
154
|
+
throw new Error(`File "package.json" not found in "${projectRoot}"`)
|
|
155
|
+
}
|
|
156
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import { Builtins, Cli } from "clipanion"
|
|
2
|
-
import { version } from "../package.json"
|
|
3
|
-
import { BackendIdentityCommand } from "./commands/backend/identity"
|
|
4
|
-
import { BackendUnlockMethodAddCommand } from "./commands/backend/unlock-method/add"
|
|
5
|
-
import { BackendUnlockMethodDeleteCommand } from "./commands/backend/unlock-method/delete"
|
|
6
|
-
import { BackendUnlockMethodListCommand } from "./commands/backend/unlock-method/list"
|
|
7
|
-
import { BuildCommand } from "./commands/build"
|
|
8
|
-
import { DesignerCommand } from "./commands/designer"
|
|
9
|
-
import { InitCommand } from "./commands/init"
|
|
10
2
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
BackendIdentityCommand,
|
|
4
|
+
BackendUnlockMethodAddCommand,
|
|
5
|
+
BackendUnlockMethodDeleteCommand,
|
|
6
|
+
BackendUnlockMethodListCommand,
|
|
7
|
+
BuildCommand,
|
|
8
|
+
DesignerCommand,
|
|
9
|
+
InitCommand,
|
|
10
|
+
PackageCreateCommand,
|
|
11
|
+
PackageListCommand,
|
|
12
|
+
PackageRemoveCommand,
|
|
13
|
+
PackageUpdateReferencesCommand,
|
|
14
|
+
UpdateCommand,
|
|
15
|
+
} from "./commands"
|
|
16
|
+
|
|
17
|
+
// const { version } = await import("@highstate/cli/package.json")
|
|
16
18
|
|
|
17
19
|
const cli = new Cli({
|
|
18
20
|
binaryName: "highstate",
|
|
19
21
|
binaryLabel: "Highstate",
|
|
20
|
-
binaryVersion: version,
|
|
22
|
+
// binaryVersion: version,
|
|
21
23
|
})
|
|
22
24
|
|
|
23
25
|
cli.register(BuildCommand)
|
|
24
26
|
cli.register(DesignerCommand)
|
|
25
27
|
cli.register(InitCommand)
|
|
28
|
+
cli.register(UpdateCommand)
|
|
26
29
|
cli.register(BackendIdentityCommand)
|
|
27
30
|
cli.register(BackendUnlockMethodListCommand)
|
|
28
31
|
cli.register(BackendUnlockMethodAddCommand)
|
|
29
32
|
cli.register(BackendUnlockMethodDeleteCommand)
|
|
30
|
-
cli.register(
|
|
33
|
+
cli.register(PackageUpdateReferencesCommand)
|
|
31
34
|
cli.register(PackageListCommand)
|
|
32
35
|
cli.register(PackageCreateCommand)
|
|
33
36
|
cli.register(PackageRemoveCommand)
|
|
@@ -55,18 +55,25 @@ export function extractEntryPoints(packageJson: PackageJson): Record<string, Ent
|
|
|
55
55
|
throw new Error(`Export "${key}" must be a string or an object in package.json`)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
const isJsonExport = distPath.endsWith(".json")
|
|
59
|
+
const isJsExport = distPath.endsWith(".js")
|
|
60
|
+
|
|
61
|
+
if (!isJsonExport && !isJsExport) {
|
|
59
62
|
throw new Error(
|
|
60
|
-
`The default value of export "${key}" must
|
|
63
|
+
`The default value of export "${key}" must end with ".js" or ".json" in package.json, got "${distPath}"`,
|
|
61
64
|
)
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
if (!distPath.
|
|
67
|
+
if (isJsExport && !distPath.startsWith("./dist/")) {
|
|
65
68
|
throw new Error(
|
|
66
|
-
`The default value of export "${key}" must
|
|
69
|
+
`The default value of export "${key}" must start with "./dist/" when exporting ".js" in package.json, got "${distPath}"`,
|
|
67
70
|
)
|
|
68
71
|
}
|
|
69
72
|
|
|
73
|
+
if (isJsonExport) {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
const targetName = distPath.slice(7).slice(0, -3)
|
|
71
78
|
|
|
72
79
|
result[targetName] = {
|
package/src/shared/index.ts
CHANGED
|
@@ -2,8 +2,16 @@ export * from "./bin-transformer"
|
|
|
2
2
|
export * from "./entry-points"
|
|
3
3
|
export * from "./generator"
|
|
4
4
|
export * from "./logger"
|
|
5
|
+
export * from "./npm-registry"
|
|
6
|
+
export * from "./overrides"
|
|
7
|
+
export * from "./package-json"
|
|
8
|
+
export * from "./pnpm-workspace"
|
|
9
|
+
export * from "./project-versions"
|
|
10
|
+
export * from "./pulumi-cli"
|
|
5
11
|
export * from "./schema-transformer"
|
|
6
12
|
export * from "./schemas"
|
|
7
13
|
export * from "./services"
|
|
8
14
|
export * from "./source-hash-calculator"
|
|
15
|
+
export * from "./version-bundle"
|
|
16
|
+
export * from "./version-sets"
|
|
9
17
|
export * from "./workspace"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type NpmRegistryManifest = {
|
|
2
|
+
name?: string
|
|
3
|
+
version?: string
|
|
4
|
+
peerDependencies?: Record<string, string>
|
|
5
|
+
dependencies?: Record<string, string>
|
|
6
|
+
optionalDependencies?: Record<string, string>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type NpmRegistryPackument = {
|
|
10
|
+
"dist-tags"?: {
|
|
11
|
+
latest?: string
|
|
12
|
+
}
|
|
13
|
+
versions?: Record<string, NpmRegistryManifest>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function fetchNpmPackument(packageName: string): Promise<NpmRegistryPackument> {
|
|
17
|
+
const encoded = encodeURIComponent(packageName)
|
|
18
|
+
const url = `https://registry.npmjs.org/${encoded}`
|
|
19
|
+
|
|
20
|
+
const response = await fetch(url)
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Failed to fetch package "${packageName}" from NPM registry (HTTP ${response.status})`,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (await response.json()) as NpmRegistryPackument
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function fetchLatestVersion(packageName: string): Promise<string> {
|
|
31
|
+
const packument = await fetchNpmPackument(packageName)
|
|
32
|
+
const latest = packument["dist-tags"]?.latest
|
|
33
|
+
if (!latest) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`NPM registry response for package "${packageName}" does not include "dist-tags.latest"`,
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return latest
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function fetchManifest(
|
|
43
|
+
packageName: string,
|
|
44
|
+
version: string,
|
|
45
|
+
): Promise<NpmRegistryManifest> {
|
|
46
|
+
const packument = await fetchNpmPackument(packageName)
|
|
47
|
+
const manifest = packument.versions?.[version]
|
|
48
|
+
if (!manifest) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`NPM registry response for package "${packageName}" does not include version "${version}"`,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return manifest
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getDependencyRange(
|
|
58
|
+
manifest: NpmRegistryManifest,
|
|
59
|
+
dependencyName: string,
|
|
60
|
+
): string | null {
|
|
61
|
+
return (
|
|
62
|
+
manifest.peerDependencies?.[dependencyName] ??
|
|
63
|
+
manifest.dependencies?.[dependencyName] ??
|
|
64
|
+
manifest.optionalDependencies?.[dependencyName] ??
|
|
65
|
+
null
|
|
66
|
+
)
|
|
67
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { PackageManagerName } from "nypm"
|
|
2
|
+
import type { VersionBundle } from "./version-bundle"
|
|
3
|
+
import { access } from "node:fs/promises"
|
|
4
|
+
import { readPackageJSON, resolvePackageJSON } from "pkg-types"
|
|
5
|
+
import { writeJsonFile } from "./package-json"
|
|
6
|
+
import { readPnpmWorkspace, resolvePnpmWorkspacePath, writePnpmWorkspace } from "./pnpm-workspace"
|
|
7
|
+
import { PLATFORM_PACKAGES, PULUMI_PACKAGES, STDLIB_PACKAGES } from "./version-sets"
|
|
8
|
+
|
|
9
|
+
export type Overrides = Record<string, string>
|
|
10
|
+
|
|
11
|
+
export function buildOverrides(bundle: VersionBundle): Overrides {
|
|
12
|
+
const platform = Object.fromEntries(PLATFORM_PACKAGES.map(name => [name, bundle.platformVersion]))
|
|
13
|
+
const stdlib = Object.fromEntries(STDLIB_PACKAGES.map(name => [name, bundle.stdlibVersion]))
|
|
14
|
+
const pulumi = Object.fromEntries(PULUMI_PACKAGES.map(name => [name, bundle.pulumiVersion]))
|
|
15
|
+
|
|
16
|
+
const merged: Overrides = {
|
|
17
|
+
...platform,
|
|
18
|
+
...stdlib,
|
|
19
|
+
...pulumi,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return merged
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ApplyOverridesArgs = {
|
|
26
|
+
packageManager: PackageManagerName
|
|
27
|
+
overrides: Overrides
|
|
28
|
+
projectRoot: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function applyOverrides(args: ApplyOverridesArgs): Promise<void> {
|
|
32
|
+
const { packageManager, overrides, projectRoot } = args
|
|
33
|
+
|
|
34
|
+
if (packageManager === "pnpm") {
|
|
35
|
+
const pnpmWorkspacePath = resolvePnpmWorkspacePath(projectRoot)
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await access(pnpmWorkspacePath)
|
|
39
|
+
} catch {
|
|
40
|
+
throw new Error(`PNPM workspace file is missing: "${pnpmWorkspacePath}"`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const workspace = await readPnpmWorkspace(pnpmWorkspacePath)
|
|
44
|
+
const nextWorkspace = {
|
|
45
|
+
...workspace,
|
|
46
|
+
overrides,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await writePnpmWorkspace(pnpmWorkspacePath, nextWorkspace)
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const packageJsonPath = await resolvePackageJSON(projectRoot)
|
|
54
|
+
const packageJson = await readPackageJSON(projectRoot)
|
|
55
|
+
|
|
56
|
+
if (packageManager === "npm") {
|
|
57
|
+
await writeJsonFile(packageJsonPath, {
|
|
58
|
+
...packageJson,
|
|
59
|
+
overrides,
|
|
60
|
+
})
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (packageManager === "yarn") {
|
|
65
|
+
await writeJsonFile(packageJsonPath, {
|
|
66
|
+
...packageJson,
|
|
67
|
+
resolutions: overrides,
|
|
68
|
+
})
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await writeJsonFile(packageJsonPath, packageJson)
|
|
73
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises"
|
|
2
|
+
import { resolve } from "node:path"
|
|
3
|
+
import { parse, stringify } from "yaml"
|
|
4
|
+
|
|
5
|
+
export type PnpmWorkspace = {
|
|
6
|
+
packages?: string[]
|
|
7
|
+
overrides?: Record<string, string>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function resolvePnpmWorkspacePath(projectRoot: string): string {
|
|
11
|
+
return resolve(projectRoot, "pnpm-workspace.yaml")
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function readPnpmWorkspace(filePath: string): Promise<PnpmWorkspace> {
|
|
15
|
+
const raw = await readFile(filePath, "utf8")
|
|
16
|
+
const parsed = parse(raw)
|
|
17
|
+
|
|
18
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
19
|
+
return {}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return parsed as PnpmWorkspace
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function writePnpmWorkspace(
|
|
26
|
+
filePath: string,
|
|
27
|
+
workspace: PnpmWorkspace,
|
|
28
|
+
): Promise<void> {
|
|
29
|
+
const raw = stringify(workspace)
|
|
30
|
+
|
|
31
|
+
await writeFile(filePath, raw, "utf8")
|
|
32
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { PackageManagerName } from "nypm"
|
|
2
|
+
import type { PackageJson } from "pkg-types"
|
|
3
|
+
import { readFile } from "node:fs/promises"
|
|
4
|
+
import { resolvePackageJSON } from "pkg-types"
|
|
5
|
+
import { readPnpmWorkspace, resolvePnpmWorkspacePath } from "./pnpm-workspace"
|
|
6
|
+
|
|
7
|
+
export async function getProjectOverrideVersion(
|
|
8
|
+
projectRoot: string,
|
|
9
|
+
args: { packageManager: PackageManagerName; packageName: string },
|
|
10
|
+
): Promise<string | null> {
|
|
11
|
+
const { packageManager, packageName } = args
|
|
12
|
+
|
|
13
|
+
if (packageManager === "pnpm") {
|
|
14
|
+
const path = resolvePnpmWorkspacePath(projectRoot)
|
|
15
|
+
const workspace = await readPnpmWorkspace(path)
|
|
16
|
+
return workspace.overrides?.[packageName] ?? null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const packageJsonPath = await resolvePackageJSON(projectRoot)
|
|
20
|
+
const rawPackageJson = await readFile(packageJsonPath, "utf8")
|
|
21
|
+
const packageJson = JSON.parse(rawPackageJson) as PackageJson
|
|
22
|
+
|
|
23
|
+
if (packageManager === "npm") {
|
|
24
|
+
const overrides = packageJson.overrides as Record<string, string> | undefined
|
|
25
|
+
return overrides?.[packageName] ?? null
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (packageManager === "yarn") {
|
|
29
|
+
const resolutions = packageJson.resolutions as Record<string, string> | undefined
|
|
30
|
+
return resolutions?.[packageName] ?? null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function getProjectPlatformVersion(
|
|
37
|
+
projectRoot: string,
|
|
38
|
+
args: { packageManager: PackageManagerName },
|
|
39
|
+
): Promise<string | null> {
|
|
40
|
+
return await getProjectOverrideVersion(projectRoot, {
|
|
41
|
+
packageManager: args.packageManager,
|
|
42
|
+
packageName: "@highstate/pulumi",
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function getProjectPulumiSdkVersion(
|
|
47
|
+
projectRoot: string,
|
|
48
|
+
args: { packageManager: PackageManagerName },
|
|
49
|
+
): Promise<string | null> {
|
|
50
|
+
return await getProjectOverrideVersion(projectRoot, {
|
|
51
|
+
packageManager: args.packageManager,
|
|
52
|
+
packageName: "@pulumi/pulumi",
|
|
53
|
+
})
|
|
54
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { execFile } from "node:child_process"
|
|
2
|
+
import { promisify } from "node:util"
|
|
3
|
+
|
|
4
|
+
const execFileAsync = promisify(execFile)
|
|
5
|
+
|
|
6
|
+
export async function getPulumiCliVersion(cwd: string): Promise<string | null> {
|
|
7
|
+
try {
|
|
8
|
+
const { stdout } = await execFileAsync("pulumi", ["version"], {
|
|
9
|
+
cwd,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const raw = stdout.trim()
|
|
13
|
+
if (raw.length === 0) {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return raw.startsWith("v") ? raw.slice(1) : raw
|
|
18
|
+
} catch {
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { fetchLatestVersion, fetchManifest, getDependencyRange } from "./npm-registry"
|
|
2
|
+
|
|
3
|
+
export type VersionBundle = {
|
|
4
|
+
platformVersion: string
|
|
5
|
+
stdlibVersion: string
|
|
6
|
+
pulumiVersion: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ResolveVersionBundleArgs = {
|
|
10
|
+
platformVersion?: string
|
|
11
|
+
stdlibVersion?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const platformSourcePackage = "@highstate/pulumi"
|
|
15
|
+
const stdlibSourcePackage = "@highstate/library"
|
|
16
|
+
|
|
17
|
+
export async function resolveVersionBundle(args: ResolveVersionBundleArgs): Promise<VersionBundle> {
|
|
18
|
+
const platformVersion = normalizeProvidedVersion(args.platformVersion, "platform")
|
|
19
|
+
const stdlibVersion = normalizeProvidedVersion(args.stdlibVersion, "stdlib")
|
|
20
|
+
|
|
21
|
+
const resolvedPlatformVersion =
|
|
22
|
+
platformVersion ?? (await fetchLatestVersion(platformSourcePackage))
|
|
23
|
+
const resolvedStdlibVersion = stdlibVersion ?? (await fetchLatestVersion(stdlibSourcePackage))
|
|
24
|
+
|
|
25
|
+
const platformManifest = await fetchManifest(platformSourcePackage, resolvedPlatformVersion)
|
|
26
|
+
const inferredPulumi = getDependencyRange(platformManifest, "@pulumi/pulumi")
|
|
27
|
+
if (!inferredPulumi) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Unable to infer "@pulumi/pulumi" version from "${platformSourcePackage}@${resolvedPlatformVersion}"`,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
platformVersion: resolvedPlatformVersion,
|
|
35
|
+
stdlibVersion: resolvedStdlibVersion,
|
|
36
|
+
pulumiVersion: inferredPulumi,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeProvidedVersion(value: string | undefined, label: string): string | undefined {
|
|
41
|
+
if (value === undefined) {
|
|
42
|
+
return undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const trimmed = value.trim()
|
|
46
|
+
if (trimmed.length === 0) {
|
|
47
|
+
throw new Error(`Version flag "${label}" must not be empty`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return trimmed
|
|
51
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const PLATFORM_PACKAGES = [
|
|
2
|
+
"@highstate/api",
|
|
3
|
+
"@highstate/backend",
|
|
4
|
+
"@highstate/backend-api",
|
|
5
|
+
"@highstate/cli",
|
|
6
|
+
"@highstate/contract",
|
|
7
|
+
"@highstate/designer",
|
|
8
|
+
"@highstate/pulumi",
|
|
9
|
+
"@highstate/worker-sdk",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
export const STDLIB_PACKAGES = [
|
|
13
|
+
"@highstate/cilium",
|
|
14
|
+
"@highstate/cloudflare",
|
|
15
|
+
"@highstate/common",
|
|
16
|
+
"@highstate/distributions",
|
|
17
|
+
"@highstate/git",
|
|
18
|
+
"@highstate/k3s",
|
|
19
|
+
"@highstate/k8s",
|
|
20
|
+
"@highstate/k8s.apps",
|
|
21
|
+
"@highstate/k8s.game-servers",
|
|
22
|
+
"@highstate/k8s.monitor-worker",
|
|
23
|
+
"@highstate/k8s.obfuscators",
|
|
24
|
+
"@highstate/library",
|
|
25
|
+
"@highstate/mullvad",
|
|
26
|
+
"@highstate/nixos",
|
|
27
|
+
"@highstate/proxmox",
|
|
28
|
+
"@highstate/restic",
|
|
29
|
+
"@highstate/sops",
|
|
30
|
+
"@highstate/talos",
|
|
31
|
+
"@highstate/timeweb",
|
|
32
|
+
"@highstate/wireguard",
|
|
33
|
+
"@highstate/yandex",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
export const PULUMI_PACKAGES = ["@pulumi/pulumi"]
|