@mondaydotcomorg/z2h-cli 0.15.0 → 0.15.1
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/dist/commands/build.d.ts +0 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +0 -3
- package/dist/commands/clean.d.ts +1 -4
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +1 -4
- package/dist/commands/create-workspace.d.ts +1 -4
- package/dist/commands/create-workspace.d.ts.map +1 -1
- package/dist/commands/create-workspace.js +1 -4
- package/dist/commands/create.d.ts +0 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +0 -3
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/delete.d.ts.map +1 -1
- package/dist/commands/delete.js +1 -4
- package/dist/commands/deploy.d.ts +0 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +4 -7
- package/dist/commands/dev.d.ts +0 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +0 -3
- package/dist/commands/doctor.d.ts +1 -4
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -5
- package/dist/commands/edit.d.ts +1 -4
- package/dist/commands/edit.d.ts.map +1 -1
- package/dist/commands/edit.js +1 -4
- package/dist/commands/generate-z2h-token.d.ts +0 -1
- package/dist/commands/generate-z2h-token.d.ts.map +1 -1
- package/dist/commands/generate-z2h-token.js +0 -3
- package/dist/commands/grant.d.ts +1 -5
- package/dist/commands/grant.d.ts.map +1 -1
- package/dist/commands/grant.js +1 -10
- package/dist/commands/migrate.d.ts +0 -1
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +106 -4
- package/dist/commands/tag.d.ts +0 -1
- package/dist/commands/tag.d.ts.map +1 -1
- package/dist/commands/tag.js +1 -4
- package/dist/esm/commands/build.d.ts +0 -1
- package/dist/esm/commands/build.d.ts.map +1 -1
- package/dist/esm/commands/build.mjs +1 -4
- package/dist/esm/commands/clean.d.ts +1 -4
- package/dist/esm/commands/clean.d.ts.map +1 -1
- package/dist/esm/commands/clean.mjs +2 -5
- package/dist/esm/commands/create-workspace.d.ts +1 -4
- package/dist/esm/commands/create-workspace.d.ts.map +1 -1
- package/dist/esm/commands/create-workspace.mjs +2 -5
- package/dist/esm/commands/create.d.ts +0 -1
- package/dist/esm/commands/create.d.ts.map +1 -1
- package/dist/esm/commands/create.mjs +1 -4
- package/dist/esm/commands/delete.d.ts +0 -1
- package/dist/esm/commands/delete.d.ts.map +1 -1
- package/dist/esm/commands/delete.mjs +2 -5
- package/dist/esm/commands/deploy.d.ts +0 -1
- package/dist/esm/commands/deploy.d.ts.map +1 -1
- package/dist/esm/commands/deploy.mjs +5 -8
- package/dist/esm/commands/dev.d.ts +0 -1
- package/dist/esm/commands/dev.d.ts.map +1 -1
- package/dist/esm/commands/dev.mjs +1 -4
- package/dist/esm/commands/doctor.d.ts +1 -4
- package/dist/esm/commands/doctor.d.ts.map +1 -1
- package/dist/esm/commands/doctor.mjs +3 -6
- package/dist/esm/commands/edit.d.ts +1 -4
- package/dist/esm/commands/edit.d.ts.map +1 -1
- package/dist/esm/commands/edit.mjs +2 -5
- package/dist/esm/commands/generate-z2h-token.d.ts +0 -1
- package/dist/esm/commands/generate-z2h-token.d.ts.map +1 -1
- package/dist/esm/commands/generate-z2h-token.mjs +1 -4
- package/dist/esm/commands/grant.d.ts +1 -5
- package/dist/esm/commands/grant.d.ts.map +1 -1
- package/dist/esm/commands/grant.mjs +2 -11
- package/dist/esm/commands/migrate.d.ts +0 -1
- package/dist/esm/commands/migrate.d.ts.map +1 -1
- package/dist/esm/commands/migrate.mjs +101 -5
- package/dist/esm/commands/tag.d.ts +0 -1
- package/dist/esm/commands/tag.d.ts.map +1 -1
- package/dist/esm/commands/tag.mjs +2 -5
- package/dist/esm/index.mjs +20 -29
- package/dist/esm/util/workspace.d.ts +3 -0
- package/dist/esm/util/workspace.d.ts.map +1 -1
- package/dist/esm/util/workspace.mjs +64 -2
- package/dist/index.js +19 -28
- package/dist/util/workspace.d.ts +3 -0
- package/dist/util/workspace.d.ts.map +1 -1
- package/dist/util/workspace.js +65 -0
- package/package.json +1 -1
- package/src/commands/__tests__/doctor.test.ts +12 -5
- package/src/commands/build.ts +1 -6
- package/src/commands/clean.ts +2 -9
- package/src/commands/create-workspace.ts +2 -10
- package/src/commands/create.ts +1 -6
- package/src/commands/delete.ts +2 -7
- package/src/commands/deploy.ts +5 -10
- package/src/commands/dev.ts +1 -6
- package/src/commands/doctor.ts +3 -11
- package/src/commands/edit.ts +2 -10
- package/src/commands/generate-z2h-token.ts +1 -6
- package/src/commands/grant.ts +2 -16
- package/src/commands/migrate.ts +139 -6
- package/src/commands/tag.ts +2 -7
- package/src/index.ts +29 -41
- package/src/util/workspace.ts +75 -1
- package/dist/esm/migrations/auto-migrate.d.ts +0 -2
- package/dist/esm/migrations/auto-migrate.d.ts.map +0 -1
- package/dist/esm/migrations/auto-migrate.mjs +0 -169
- package/dist/migrations/auto-migrate.d.ts +0 -2
- package/dist/migrations/auto-migrate.d.ts.map +0 -1
- package/dist/migrations/auto-migrate.js +0 -177
- package/src/migrations/auto-migrate.ts +0 -217
package/src/util/workspace.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import os from 'node:os';
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { pathExists, readJson, writeFile, writeJson } from 'fs-extra';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
import { info, warn } from './logger';
|
|
4
7
|
|
|
5
8
|
export const WORKSPACE_DIR_NAME = 'zth-projects';
|
|
6
9
|
export const WORKSPACE_MARKER_FIELD = 'z2hWorkspace';
|
|
@@ -50,3 +53,74 @@ export async function assertWorkspace(): Promise<string> {
|
|
|
50
53
|
`(or set Z2H_WORKSPACE_HOME if you keep the workspace elsewhere).`
|
|
51
54
|
);
|
|
52
55
|
}
|
|
56
|
+
|
|
57
|
+
export async function runYarnInstall(workspaceHome: string, context: string): Promise<boolean> {
|
|
58
|
+
info(`${context} — running yarn install...`);
|
|
59
|
+
try {
|
|
60
|
+
await execa('yarn', ['install'], { cwd: workspaceHome, stdio: 'pipe' });
|
|
61
|
+
return true;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
const stderr = (err as { stderr?: string }).stderr || (err as Error).message;
|
|
64
|
+
warn(`yarn install failed: ${stderr}`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function getLatestTrientMonorepoVersion(): Promise<string> {
|
|
70
|
+
try {
|
|
71
|
+
const { stdout } = await execa('npm', ['view', '@mondaydotcomorg/trident-monorepo', 'version']);
|
|
72
|
+
return `^${stdout.trim()}`;
|
|
73
|
+
} catch {
|
|
74
|
+
return '*';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function isNxAvailable(workspaceHome: string): boolean {
|
|
79
|
+
try {
|
|
80
|
+
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
81
|
+
wsRequire.resolve('nx/src/generators/tree');
|
|
82
|
+
return true;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const NX_JSON_CONTENT = '{\n "extends": "@mondaydotcomorg/trident-monorepo/presets/nx.json"\n}\n';
|
|
89
|
+
|
|
90
|
+
export async function ensureWorkspaceNx(workspaceHome: string): Promise<boolean> {
|
|
91
|
+
const nxJsonPath = path.join(workspaceHome, 'nx.json');
|
|
92
|
+
const pkgPath = path.join(workspaceHome, 'package.json');
|
|
93
|
+
|
|
94
|
+
if (!(await pathExists(nxJsonPath))) {
|
|
95
|
+
await writeFile(nxJsonPath, NX_JSON_CONTENT);
|
|
96
|
+
info('added nx.json to workspace');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const pkg = (await readJson(pkgPath)) as {
|
|
100
|
+
devDependencies?: Record<string, string>;
|
|
101
|
+
scripts?: Record<string, string>;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
if (!pkg.devDependencies?.['@mondaydotcomorg/trident-monorepo']) {
|
|
105
|
+
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
106
|
+
pkg.devDependencies['@mondaydotcomorg/trident-monorepo'] = await getLatestTrientMonorepoVersion();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (!pkg.scripts?.nx) {
|
|
110
|
+
pkg.scripts = pkg.scripts ?? {};
|
|
111
|
+
pkg.scripts.nx = 'nx';
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
await writeJson(pkgPath, pkg, { spaces: 2 });
|
|
115
|
+
|
|
116
|
+
// Only install if NX isn't already importable from the workspace
|
|
117
|
+
if (!isNxAvailable(workspaceHome)) {
|
|
118
|
+
const ok = await runYarnInstall(workspaceHome, 'NX not found, installing');
|
|
119
|
+
if (!ok) {
|
|
120
|
+
warn('workspace migrations require NX. Fix the install error and run "z2h-cli migrate" to retry.');
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-migrate.d.ts","sourceRoot":"","sources":["../../../src/migrations/auto-migrate.ts"],"names":[],"mappings":"AAsHA,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkGnF"}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { pathExists, readJson, writeJson, writeFile } from 'fs-extra';
|
|
5
|
-
import { execa } from 'execa';
|
|
6
|
-
import semver from 'semver';
|
|
7
|
-
import { warn, info, errorLog } from '../util/logger.mjs';
|
|
8
|
-
import { getWorkspaceHome, isZ2hWorkspace } from '../util/workspace.mjs';
|
|
9
|
-
|
|
10
|
-
const STATE_FILE = '.z2h-migrations-state.json';
|
|
11
|
-
const NX_JSON_CONTENT = '{\n "extends": "@mondaydotcomorg/trident-monorepo/presets/nx.json"\n}\n';
|
|
12
|
-
// ─── Helpers ───
|
|
13
|
-
async function readState(workspaceHome) {
|
|
14
|
-
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
15
|
-
if (!(await pathExists(statePath))) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
try {
|
|
19
|
-
return (await readJson(statePath));
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
async function writeState(workspaceHome, state) {
|
|
26
|
-
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
27
|
-
await writeJson(statePath, state, { spaces: 2 });
|
|
28
|
-
}
|
|
29
|
-
async function yarnInstall(workspaceHome, context) {
|
|
30
|
-
info(`${context} — running yarn install...`);
|
|
31
|
-
try {
|
|
32
|
-
await execa('yarn', ['install'], { cwd: workspaceHome, stdio: 'pipe' });
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
const stderr = err.stderr || err.message;
|
|
37
|
-
warn(`yarn install failed: ${stderr}`);
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
async function getLatestTrientMonorepoVersion() {
|
|
42
|
-
try {
|
|
43
|
-
const { stdout } = await execa('npm', ['view', '@mondaydotcomorg/trident-monorepo', 'version']);
|
|
44
|
-
return `^${stdout.trim()}`;
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
return '*';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
// ─── Workspace bootstrap ───
|
|
51
|
-
function isNxAvailable(workspaceHome) {
|
|
52
|
-
try {
|
|
53
|
-
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
54
|
-
wsRequire.resolve('nx/src/generators/tree');
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
async function ensureWorkspaceNx(workspaceHome) {
|
|
62
|
-
const nxJsonPath = path.join(workspaceHome, 'nx.json');
|
|
63
|
-
const pkgPath = path.join(workspaceHome, 'package.json');
|
|
64
|
-
if (!(await pathExists(nxJsonPath))) {
|
|
65
|
-
await writeFile(nxJsonPath, NX_JSON_CONTENT);
|
|
66
|
-
info('added nx.json to workspace');
|
|
67
|
-
}
|
|
68
|
-
const pkg = (await readJson(pkgPath));
|
|
69
|
-
if (!pkg.devDependencies?.['@mondaydotcomorg/trident-monorepo']) {
|
|
70
|
-
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
71
|
-
pkg.devDependencies['@mondaydotcomorg/trident-monorepo'] = await getLatestTrientMonorepoVersion();
|
|
72
|
-
}
|
|
73
|
-
if (!pkg.scripts?.nx) {
|
|
74
|
-
pkg.scripts = pkg.scripts ?? {};
|
|
75
|
-
pkg.scripts.nx = 'nx';
|
|
76
|
-
}
|
|
77
|
-
await writeJson(pkgPath, pkg, { spaces: 2 });
|
|
78
|
-
// Only install if NX isn't already importable from the workspace
|
|
79
|
-
if (!isNxAvailable(workspaceHome)) {
|
|
80
|
-
const ok = await yarnInstall(workspaceHome, 'NX not found, installing');
|
|
81
|
-
if (!ok) {
|
|
82
|
-
warn('workspace migrations require NX. Fix the install error and run "z2h-cli migrate" to retry.');
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return true;
|
|
87
|
-
}
|
|
88
|
-
// ─── Main ───
|
|
89
|
-
async function autoMigrate(cliVersion, dryRun = false) {
|
|
90
|
-
const workspaceHome = getWorkspaceHome();
|
|
91
|
-
if (!(await isZ2hWorkspace(workspaceHome))) {
|
|
92
|
-
warn('no Z2H workspace found');
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const state = await readState(workspaceHome);
|
|
96
|
-
const lastVersion = state?.lastMigratedVersion ?? '0.0.0';
|
|
97
|
-
if (!semver.gt(cliVersion, lastVersion)) {
|
|
98
|
-
info('workspace is up to date — no migrations pending');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
info(`migrating workspace from v${lastVersion} → v${cliVersion}...`);
|
|
102
|
-
// migrations.json is at the package root — two dirs up from dist/migrations/
|
|
103
|
-
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
104
|
-
const migrationsJsonPath = path.resolve(thisDir, '..', '..', 'migrations.json');
|
|
105
|
-
if (!(await pathExists(migrationsJsonPath))) {
|
|
106
|
-
warn('migrations.json not found — skipping migrations');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const migrationsJson = (await readJson(migrationsJsonPath));
|
|
110
|
-
// Filter to pending migrations (version > lastVersion AND <= cliVersion).
|
|
111
|
-
// CONVENTION: a migration's `version` field must equal the CLI release it
|
|
112
|
-
// ships with (not the feature branch version). This ensures the `gt` check
|
|
113
|
-
// always catches a migration on the exact upgrade that introduces it.
|
|
114
|
-
const pending = Object.entries(migrationsJson.migrations)
|
|
115
|
-
.filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
|
|
116
|
-
.sort(([, a], [, b]) => semver.compare(a.version, b.version));
|
|
117
|
-
if (dryRun) {
|
|
118
|
-
info(`${pending.length} pending migration(s) (dry-run — no changes will be applied):`);
|
|
119
|
-
for (const [, entry] of pending) {
|
|
120
|
-
info(` - ${entry.description} (v${entry.version})`);
|
|
121
|
-
}
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (pending.length === 0) {
|
|
125
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const nxReady = await ensureWorkspaceNx(workspaceHome);
|
|
129
|
-
if (!nxReady) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
info(`applying ${pending.length} workspace migration(s)...`);
|
|
133
|
-
// Resolve NX from the workspace's node_modules (not from CLI's own deps)
|
|
134
|
-
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
135
|
-
const { FsTree, flushChanges } = wsRequire('nx/src/generators/tree');
|
|
136
|
-
let needsInstall = false;
|
|
137
|
-
for (const [name, entry] of pending) {
|
|
138
|
-
const tree = new FsTree(workspaceHome, false);
|
|
139
|
-
try {
|
|
140
|
-
const factoryPath = path.resolve(path.dirname(migrationsJsonPath), entry.migrate);
|
|
141
|
-
const mod = require(factoryPath);
|
|
142
|
-
const fn = mod.default || mod;
|
|
143
|
-
fn(tree);
|
|
144
|
-
const changes = tree.listChanges();
|
|
145
|
-
if (changes.length > 0) {
|
|
146
|
-
if (changes.some(c => c.path.endsWith('package.json'))) {
|
|
147
|
-
needsInstall = true;
|
|
148
|
-
}
|
|
149
|
-
flushChanges(workspaceHome, changes);
|
|
150
|
-
info(` ✓ ${entry.description}`);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
info(` ○ ${entry.description} (no changes needed)`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
const errorMessage = `migration "${name}" failed: ${err.message}`;
|
|
158
|
-
errorLog(`${errorMessage}\nSkipping remaining migrations — run "z2h-cli migrate" to retry.`);
|
|
159
|
-
throw new Error(errorMessage);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
if (needsInstall) {
|
|
163
|
-
await yarnInstall(workspaceHome, 'package.json changed');
|
|
164
|
-
}
|
|
165
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
166
|
-
info('workspace migrations complete.');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export { autoMigrate };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-migrate.d.ts","sourceRoot":"","sources":["../../src/migrations/auto-migrate.ts"],"names":[],"mappings":"AAsHA,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkGnF"}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
const node_module = require('node:module');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
const node_url = require('node:url');
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
const execa = require('execa');
|
|
8
|
-
const semver = require('semver');
|
|
9
|
-
const util_logger = require('../util/logger.js');
|
|
10
|
-
const util_workspace = require('../util/workspace.js');
|
|
11
|
-
|
|
12
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
13
|
-
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
14
|
-
|
|
15
|
-
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
16
|
-
const semver__default = /*#__PURE__*/_interopDefault(semver);
|
|
17
|
-
|
|
18
|
-
const STATE_FILE = '.z2h-migrations-state.json';
|
|
19
|
-
const NX_JSON_CONTENT = '{\n "extends": "@mondaydotcomorg/trident-monorepo/presets/nx.json"\n}\n';
|
|
20
|
-
// ─── Helpers ───
|
|
21
|
-
async function readState(workspaceHome) {
|
|
22
|
-
const statePath = path__default.default.join(workspaceHome, STATE_FILE);
|
|
23
|
-
if (!(await fs.pathExists(statePath))) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
return (await fs.readJson(statePath));
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async function writeState(workspaceHome, state) {
|
|
34
|
-
const statePath = path__default.default.join(workspaceHome, STATE_FILE);
|
|
35
|
-
await fs.writeJson(statePath, state, { spaces: 2 });
|
|
36
|
-
}
|
|
37
|
-
async function yarnInstall(workspaceHome, context) {
|
|
38
|
-
util_logger.info(`${context} — running yarn install...`);
|
|
39
|
-
try {
|
|
40
|
-
await execa.execa('yarn', ['install'], { cwd: workspaceHome, stdio: 'pipe' });
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
const stderr = err.stderr || err.message;
|
|
45
|
-
util_logger.warn(`yarn install failed: ${stderr}`);
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async function getLatestTrientMonorepoVersion() {
|
|
50
|
-
try {
|
|
51
|
-
const { stdout } = await execa.execa('npm', ['view', '@mondaydotcomorg/trident-monorepo', 'version']);
|
|
52
|
-
return `^${stdout.trim()}`;
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
return '*';
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// ─── Workspace bootstrap ───
|
|
59
|
-
function isNxAvailable(workspaceHome) {
|
|
60
|
-
try {
|
|
61
|
-
const wsRequire = node_module.createRequire(path__default.default.join(workspaceHome, 'package.json'));
|
|
62
|
-
wsRequire.resolve('nx/src/generators/tree');
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function ensureWorkspaceNx(workspaceHome) {
|
|
70
|
-
const nxJsonPath = path__default.default.join(workspaceHome, 'nx.json');
|
|
71
|
-
const pkgPath = path__default.default.join(workspaceHome, 'package.json');
|
|
72
|
-
if (!(await fs.pathExists(nxJsonPath))) {
|
|
73
|
-
await fs.writeFile(nxJsonPath, NX_JSON_CONTENT);
|
|
74
|
-
util_logger.info('added nx.json to workspace');
|
|
75
|
-
}
|
|
76
|
-
const pkg = (await fs.readJson(pkgPath));
|
|
77
|
-
if (!pkg.devDependencies?.['@mondaydotcomorg/trident-monorepo']) {
|
|
78
|
-
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
79
|
-
pkg.devDependencies['@mondaydotcomorg/trident-monorepo'] = await getLatestTrientMonorepoVersion();
|
|
80
|
-
}
|
|
81
|
-
if (!pkg.scripts?.nx) {
|
|
82
|
-
pkg.scripts = pkg.scripts ?? {};
|
|
83
|
-
pkg.scripts.nx = 'nx';
|
|
84
|
-
}
|
|
85
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
86
|
-
// Only install if NX isn't already importable from the workspace
|
|
87
|
-
if (!isNxAvailable(workspaceHome)) {
|
|
88
|
-
const ok = await yarnInstall(workspaceHome, 'NX not found, installing');
|
|
89
|
-
if (!ok) {
|
|
90
|
-
util_logger.warn('workspace migrations require NX. Fix the install error and run "z2h-cli migrate" to retry.');
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
// ─── Main ───
|
|
97
|
-
async function autoMigrate(cliVersion, dryRun = false) {
|
|
98
|
-
const workspaceHome = util_workspace.getWorkspaceHome();
|
|
99
|
-
if (!(await util_workspace.isZ2hWorkspace(workspaceHome))) {
|
|
100
|
-
util_logger.warn('no Z2H workspace found');
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const state = await readState(workspaceHome);
|
|
104
|
-
const lastVersion = state?.lastMigratedVersion ?? '0.0.0';
|
|
105
|
-
if (!semver__default.default.gt(cliVersion, lastVersion)) {
|
|
106
|
-
util_logger.info('workspace is up to date — no migrations pending');
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
util_logger.info(`migrating workspace from v${lastVersion} → v${cliVersion}...`);
|
|
110
|
-
// migrations.json is at the package root — two dirs up from dist/migrations/
|
|
111
|
-
const thisDir = path__default.default.dirname(node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('migrations/auto-migrate.js', document.baseURI).href))));
|
|
112
|
-
const migrationsJsonPath = path__default.default.resolve(thisDir, '..', '..', 'migrations.json');
|
|
113
|
-
if (!(await fs.pathExists(migrationsJsonPath))) {
|
|
114
|
-
util_logger.warn('migrations.json not found — skipping migrations');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const migrationsJson = (await fs.readJson(migrationsJsonPath));
|
|
118
|
-
// Filter to pending migrations (version > lastVersion AND <= cliVersion).
|
|
119
|
-
// CONVENTION: a migration's `version` field must equal the CLI release it
|
|
120
|
-
// ships with (not the feature branch version). This ensures the `gt` check
|
|
121
|
-
// always catches a migration on the exact upgrade that introduces it.
|
|
122
|
-
const pending = Object.entries(migrationsJson.migrations)
|
|
123
|
-
.filter(([, entry]) => semver__default.default.gt(entry.version, lastVersion) && semver__default.default.lte(entry.version, cliVersion))
|
|
124
|
-
.sort(([, a], [, b]) => semver__default.default.compare(a.version, b.version));
|
|
125
|
-
if (dryRun) {
|
|
126
|
-
util_logger.info(`${pending.length} pending migration(s) (dry-run — no changes will be applied):`);
|
|
127
|
-
for (const [, entry] of pending) {
|
|
128
|
-
util_logger.info(` - ${entry.description} (v${entry.version})`);
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (pending.length === 0) {
|
|
133
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const nxReady = await ensureWorkspaceNx(workspaceHome);
|
|
137
|
-
if (!nxReady) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
util_logger.info(`applying ${pending.length} workspace migration(s)...`);
|
|
141
|
-
// Resolve NX from the workspace's node_modules (not from CLI's own deps)
|
|
142
|
-
const wsRequire = node_module.createRequire(path__default.default.join(workspaceHome, 'package.json'));
|
|
143
|
-
const { FsTree, flushChanges } = wsRequire('nx/src/generators/tree');
|
|
144
|
-
let needsInstall = false;
|
|
145
|
-
for (const [name, entry] of pending) {
|
|
146
|
-
const tree = new FsTree(workspaceHome, false);
|
|
147
|
-
try {
|
|
148
|
-
const factoryPath = path__default.default.resolve(path__default.default.dirname(migrationsJsonPath), entry.migrate);
|
|
149
|
-
const mod = require(factoryPath);
|
|
150
|
-
const fn = mod.default || mod;
|
|
151
|
-
fn(tree);
|
|
152
|
-
const changes = tree.listChanges();
|
|
153
|
-
if (changes.length > 0) {
|
|
154
|
-
if (changes.some(c => c.path.endsWith('package.json'))) {
|
|
155
|
-
needsInstall = true;
|
|
156
|
-
}
|
|
157
|
-
flushChanges(workspaceHome, changes);
|
|
158
|
-
util_logger.info(` ✓ ${entry.description}`);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
util_logger.info(` ○ ${entry.description} (no changes needed)`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
catch (err) {
|
|
165
|
-
const errorMessage = `migration "${name}" failed: ${err.message}`;
|
|
166
|
-
util_logger.errorLog(`${errorMessage}\nSkipping remaining migrations — run "z2h-cli migrate" to retry.`);
|
|
167
|
-
throw new Error(errorMessage);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (needsInstall) {
|
|
171
|
-
await yarnInstall(workspaceHome, 'package.json changed');
|
|
172
|
-
}
|
|
173
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
174
|
-
util_logger.info('workspace migrations complete.');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
exports.autoMigrate = autoMigrate;
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { pathExists, readJson, writeFile, writeJson } from 'fs-extra';
|
|
5
|
-
import { execa } from 'execa';
|
|
6
|
-
import semver from 'semver';
|
|
7
|
-
import { errorLog, info, warn } from '../util/logger';
|
|
8
|
-
import { getWorkspaceHome, isZ2hWorkspace } from '../util/workspace';
|
|
9
|
-
|
|
10
|
-
const STATE_FILE = '.z2h-migrations-state.json';
|
|
11
|
-
const NX_JSON_CONTENT = '{\n "extends": "@mondaydotcomorg/trident-monorepo/presets/nx.json"\n}\n';
|
|
12
|
-
|
|
13
|
-
interface MigrationState {
|
|
14
|
-
lastMigratedVersion: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface MigrationEntry {
|
|
18
|
-
version: string;
|
|
19
|
-
description: string;
|
|
20
|
-
migrate: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface MigrationsJson {
|
|
24
|
-
migrations: Record<string, MigrationEntry>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ─── Helpers ───
|
|
28
|
-
|
|
29
|
-
async function readState(workspaceHome: string): Promise<MigrationState | null> {
|
|
30
|
-
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
31
|
-
if (!(await pathExists(statePath))) {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
return (await readJson(statePath)) as MigrationState;
|
|
36
|
-
} catch {
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function writeState(workspaceHome: string, state: MigrationState): Promise<void> {
|
|
42
|
-
const statePath = path.join(workspaceHome, STATE_FILE);
|
|
43
|
-
await writeJson(statePath, state, { spaces: 2 });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function yarnInstall(workspaceHome: string, context: string): Promise<boolean> {
|
|
47
|
-
info(`${context} — running yarn install...`);
|
|
48
|
-
try {
|
|
49
|
-
await execa('yarn', ['install'], { cwd: workspaceHome, stdio: 'pipe' });
|
|
50
|
-
return true;
|
|
51
|
-
} catch (err) {
|
|
52
|
-
const stderr = (err as { stderr?: string }).stderr || (err as Error).message;
|
|
53
|
-
warn(`yarn install failed: ${stderr}`);
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function getLatestTrientMonorepoVersion(): Promise<string> {
|
|
59
|
-
try {
|
|
60
|
-
const { stdout } = await execa('npm', ['view', '@mondaydotcomorg/trident-monorepo', 'version']);
|
|
61
|
-
return `^${stdout.trim()}`;
|
|
62
|
-
} catch {
|
|
63
|
-
return '*';
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ─── Workspace bootstrap ───
|
|
68
|
-
|
|
69
|
-
function isNxAvailable(workspaceHome: string): boolean {
|
|
70
|
-
try {
|
|
71
|
-
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
72
|
-
wsRequire.resolve('nx/src/generators/tree');
|
|
73
|
-
return true;
|
|
74
|
-
} catch {
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function ensureWorkspaceNx(workspaceHome: string): Promise<boolean> {
|
|
80
|
-
const nxJsonPath = path.join(workspaceHome, 'nx.json');
|
|
81
|
-
const pkgPath = path.join(workspaceHome, 'package.json');
|
|
82
|
-
|
|
83
|
-
if (!(await pathExists(nxJsonPath))) {
|
|
84
|
-
await writeFile(nxJsonPath, NX_JSON_CONTENT);
|
|
85
|
-
info('added nx.json to workspace');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const pkg = (await readJson(pkgPath)) as {
|
|
89
|
-
devDependencies?: Record<string, string>;
|
|
90
|
-
scripts?: Record<string, string>;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
if (!pkg.devDependencies?.['@mondaydotcomorg/trident-monorepo']) {
|
|
94
|
-
pkg.devDependencies = pkg.devDependencies ?? {};
|
|
95
|
-
pkg.devDependencies['@mondaydotcomorg/trident-monorepo'] = await getLatestTrientMonorepoVersion();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!pkg.scripts?.nx) {
|
|
99
|
-
pkg.scripts = pkg.scripts ?? {};
|
|
100
|
-
pkg.scripts.nx = 'nx';
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
await writeJson(pkgPath, pkg, { spaces: 2 });
|
|
104
|
-
|
|
105
|
-
// Only install if NX isn't already importable from the workspace
|
|
106
|
-
if (!isNxAvailable(workspaceHome)) {
|
|
107
|
-
const ok = await yarnInstall(workspaceHome, 'NX not found, installing');
|
|
108
|
-
if (!ok) {
|
|
109
|
-
warn('workspace migrations require NX. Fix the install error and run "z2h-cli migrate" to retry.');
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// ─── Main ───
|
|
118
|
-
|
|
119
|
-
export async function autoMigrate(cliVersion: string, dryRun = false): Promise<void> {
|
|
120
|
-
const workspaceHome = getWorkspaceHome();
|
|
121
|
-
if (!(await isZ2hWorkspace(workspaceHome))) {
|
|
122
|
-
warn('no Z2H workspace found');
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const state = await readState(workspaceHome);
|
|
127
|
-
const lastVersion = state?.lastMigratedVersion ?? '0.0.0';
|
|
128
|
-
|
|
129
|
-
if (!semver.gt(cliVersion, lastVersion)) {
|
|
130
|
-
info('workspace is up to date — no migrations pending');
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
info(`migrating workspace from v${lastVersion} → v${cliVersion}...`);
|
|
135
|
-
|
|
136
|
-
// migrations.json is at the package root — two dirs up from dist/migrations/
|
|
137
|
-
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
138
|
-
const migrationsJsonPath = path.resolve(thisDir, '..', '..', 'migrations.json');
|
|
139
|
-
|
|
140
|
-
if (!(await pathExists(migrationsJsonPath))) {
|
|
141
|
-
warn('migrations.json not found — skipping migrations');
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const migrationsJson = (await readJson(migrationsJsonPath)) as MigrationsJson;
|
|
146
|
-
|
|
147
|
-
// Filter to pending migrations (version > lastVersion AND <= cliVersion).
|
|
148
|
-
// CONVENTION: a migration's `version` field must equal the CLI release it
|
|
149
|
-
// ships with (not the feature branch version). This ensures the `gt` check
|
|
150
|
-
// always catches a migration on the exact upgrade that introduces it.
|
|
151
|
-
const pending = Object.entries(migrationsJson.migrations)
|
|
152
|
-
.filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
|
|
153
|
-
.sort(([, a], [, b]) => semver.compare(a.version, b.version));
|
|
154
|
-
|
|
155
|
-
if (dryRun) {
|
|
156
|
-
info(`${pending.length} pending migration(s) (dry-run — no changes will be applied):`);
|
|
157
|
-
for (const [, entry] of pending) {
|
|
158
|
-
info(` - ${entry.description} (v${entry.version})`);
|
|
159
|
-
}
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (pending.length === 0) {
|
|
164
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const nxReady = await ensureWorkspaceNx(workspaceHome);
|
|
169
|
-
if (!nxReady) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
info(`applying ${pending.length} workspace migration(s)...`);
|
|
174
|
-
|
|
175
|
-
// Resolve NX from the workspace's node_modules (not from CLI's own deps)
|
|
176
|
-
const wsRequire = createRequire(path.join(workspaceHome, 'package.json'));
|
|
177
|
-
const { FsTree, flushChanges } = wsRequire('nx/src/generators/tree') as {
|
|
178
|
-
FsTree: new (root: string, isVerbose: boolean) => import('@nx/devkit').Tree & {
|
|
179
|
-
listChanges(): { type: string; path: string }[];
|
|
180
|
-
};
|
|
181
|
-
flushChanges: (root: string, changes: { type: string; path: string; content?: Buffer | null }[]) => void;
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
let needsInstall = false;
|
|
185
|
-
|
|
186
|
-
for (const [name, entry] of pending) {
|
|
187
|
-
const tree = new FsTree(workspaceHome, false);
|
|
188
|
-
try {
|
|
189
|
-
const factoryPath = path.resolve(path.dirname(migrationsJsonPath), entry.migrate);
|
|
190
|
-
const mod = require(factoryPath);
|
|
191
|
-
const fn = mod.default || mod;
|
|
192
|
-
fn(tree);
|
|
193
|
-
|
|
194
|
-
const changes = tree.listChanges();
|
|
195
|
-
if (changes.length > 0) {
|
|
196
|
-
if (changes.some(c => c.path.endsWith('package.json'))) {
|
|
197
|
-
needsInstall = true;
|
|
198
|
-
}
|
|
199
|
-
flushChanges(workspaceHome, changes);
|
|
200
|
-
info(` ✓ ${entry.description}`);
|
|
201
|
-
} else {
|
|
202
|
-
info(` ○ ${entry.description} (no changes needed)`);
|
|
203
|
-
}
|
|
204
|
-
} catch (err) {
|
|
205
|
-
const errorMessage = `migration "${name}" failed: ${(err as Error).message}`;
|
|
206
|
-
errorLog(`${errorMessage}\nSkipping remaining migrations — run "z2h-cli migrate" to retry.`);
|
|
207
|
-
throw new Error(errorMessage);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (needsInstall) {
|
|
212
|
-
await yarnInstall(workspaceHome, 'package.json changed');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
await writeState(workspaceHome, { lastMigratedVersion: cliVersion });
|
|
216
|
-
info('workspace migrations complete.');
|
|
217
|
-
}
|