@mnci/cli 1.19.8 → 3.0.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/README.md +50 -114
- package/dist/cli.js +110 -332
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -80,12 +80,11 @@ function runNpx(arguments_, cwd) {
|
|
|
80
80
|
throw new Error(`npx ${arguments_.join(" ")} failed with exit code ${status}`);
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
function runFormatter(cwd,
|
|
84
|
-
const
|
|
85
|
-
const status = runShell("npx", [command, ...arguments_], cwd);
|
|
83
|
+
function runFormatter(cwd, target = ".") {
|
|
84
|
+
const status = runShell("npx", ["eslint", target, "--fix"], cwd);
|
|
86
85
|
if (status !== 0) {
|
|
87
86
|
logger.warn(
|
|
88
|
-
|
|
87
|
+
`eslint could not format '${target}' (exit code ${status}). The project was generated; run 'npm run format' to normalise it.`
|
|
89
88
|
);
|
|
90
89
|
}
|
|
91
90
|
}
|
|
@@ -142,20 +141,7 @@ async function promptStack() {
|
|
|
142
141
|
{ name: "Vitest", value: "vitest" }
|
|
143
142
|
]
|
|
144
143
|
});
|
|
145
|
-
|
|
146
|
-
message: "Linter and formatter",
|
|
147
|
-
choices: [
|
|
148
|
-
{
|
|
149
|
-
name: "ESLint + Prettier \u2014 every file type, the widest rule coverage",
|
|
150
|
-
value: "eslint"
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: "oxlint + oxfmt for JS/TS, ESLint for the rest \u2014 much faster, same style",
|
|
154
|
-
value: "oxlint"
|
|
155
|
-
}
|
|
156
|
-
]
|
|
157
|
-
});
|
|
158
|
-
return { testRunner, linter };
|
|
144
|
+
return { testRunner };
|
|
159
145
|
}
|
|
160
146
|
|
|
161
147
|
// src/util/fsx.ts
|
|
@@ -1220,7 +1206,7 @@ async function runAdd(kind, name, options) {
|
|
|
1220
1206
|
case "python-vendor": {
|
|
1221
1207
|
await addPythonVendor(workspaceRoot, resolvedName, options, kindProvided);
|
|
1222
1208
|
syncProjectReferences(workspaceRoot);
|
|
1223
|
-
runFormatter(workspaceRoot
|
|
1209
|
+
runFormatter(workspaceRoot);
|
|
1224
1210
|
return;
|
|
1225
1211
|
}
|
|
1226
1212
|
default: {
|
|
@@ -1231,7 +1217,7 @@ async function runAdd(kind, name, options) {
|
|
|
1231
1217
|
}
|
|
1232
1218
|
}
|
|
1233
1219
|
syncProjectReferences(workspaceRoot);
|
|
1234
|
-
runFormatter(workspaceRoot
|
|
1220
|
+
runFormatter(workspaceRoot);
|
|
1235
1221
|
logger.success(`Added ${resolvedKind} '${resolvedName}'.`);
|
|
1236
1222
|
}
|
|
1237
1223
|
function syncProjectReferences(workspaceRoot) {
|
|
@@ -1248,14 +1234,7 @@ function readWorkspaceStack(workspaceRoot) {
|
|
|
1248
1234
|
);
|
|
1249
1235
|
const stack = nxJson.mnci?.stack;
|
|
1250
1236
|
return {
|
|
1251
|
-
testRunner: stack?.testRunner === "vitest" ? "vitest" : "jest"
|
|
1252
|
-
// Defaults to `eslint` when absent, the same call `mnci upgrade` makes and
|
|
1253
|
-
// for the same reason: every workspace generated before the choice existed
|
|
1254
|
-
// has no persisted value and is an ESLint workspace. Reading it at all is
|
|
1255
|
-
// the fix — this function returned `testRunner` alone, so `add` finished by
|
|
1256
|
-
// formatting an oxlint workspace with Prettier, against Prettier's defaults,
|
|
1257
|
-
// since the overlay had deleted the config that would have corrected it.
|
|
1258
|
-
linter: stack?.linter === "oxlint" ? "oxlint" : "eslint"
|
|
1237
|
+
testRunner: stack?.testRunner === "vitest" ? "vitest" : "jest"
|
|
1259
1238
|
};
|
|
1260
1239
|
}
|
|
1261
1240
|
|
|
@@ -1266,8 +1245,7 @@ var import_node_path12 = require("path");
|
|
|
1266
1245
|
// src/overlay.ts
|
|
1267
1246
|
var import_node_fs6 = require("fs");
|
|
1268
1247
|
var import_node_path11 = require("path");
|
|
1269
|
-
var DEFAULT_STACK = { testRunner: "jest"
|
|
1270
|
-
var PRETTIER_VERSION = "^3.8.1";
|
|
1248
|
+
var DEFAULT_STACK = { testRunner: "jest" };
|
|
1271
1249
|
var TS_COMPILER_DEPENDENCIES = {
|
|
1272
1250
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
1273
1251
|
typescript: "npm:@typescript/typescript6@^6.0.2"
|
|
@@ -1375,32 +1353,12 @@ var COMMITLINT_CONFIG = `export default { extends: ['@commitlint/config-conventi
|
|
|
1375
1353
|
`;
|
|
1376
1354
|
var COMMIT_MSG_HOOK = `npx --no -- commitlint --edit "$1"
|
|
1377
1355
|
`;
|
|
1378
|
-
var PRETTIER_CONFIG = `// The formatting half of @mnci/eslint-config.
|
|
1379
|
-
//
|
|
1380
|
-
// Prettier's options live in the same package as the ESLint rules on purpose:
|
|
1381
|
-
// linting and formatting are one decision. \`eslint-config-prettier\` is composed
|
|
1382
|
-
// last inside that package so every formatting rule defers to these settings, and
|
|
1383
|
-
// splitting the two across packages means a version pair that can drift until
|
|
1384
|
-
// \`npm run lint\` and \`npm run format:check\` disagree with each other.
|
|
1385
|
-
//
|
|
1386
|
-
// Consuming it as a shareable config also means a formatting fix reaches this
|
|
1387
|
-
// workspace through \`npm update\`, the same way a rule change does, instead of
|
|
1388
|
-
// waiting for \`mnci upgrade\` to rewrite a file.
|
|
1389
|
-
//
|
|
1390
|
-
// TO OVERRIDE an option, spread it rather than re-exporting:
|
|
1391
|
-
//
|
|
1392
|
-
// import mnci from '@mnci/eslint-config/prettier'
|
|
1393
|
-
// export default { ...mnci, printWidth: 120 }
|
|
1394
|
-
//
|
|
1395
|
-
// TO SEE the resolved options for a file: npx prettier --find-config-path <file>
|
|
1396
|
-
export { default } from '@mnci/eslint-config/prettier'
|
|
1397
|
-
`;
|
|
1398
1356
|
var ESLINT_CONFIG_VERSION = "^0.1.0";
|
|
1399
1357
|
function eslintConfigSpec() {
|
|
1400
1358
|
return process.env.MNCI_ESLINT_CONFIG_SPEC ?? ESLINT_CONFIG_VERSION;
|
|
1401
1359
|
}
|
|
1402
1360
|
var ESLINT_VERSION = "^10.8.0";
|
|
1403
|
-
function devcontainerJson(workspaceName
|
|
1361
|
+
function devcontainerJson(workspaceName) {
|
|
1404
1362
|
return `${toJson({
|
|
1405
1363
|
name: workspaceName,
|
|
1406
1364
|
image: `mcr.microsoft.com/devcontainers/typescript-node:${NODE_VERSION}-bookworm`,
|
|
@@ -1423,7 +1381,7 @@ function devcontainerJson(workspaceName, linter) {
|
|
|
1423
1381
|
// The same recommendations the `.code-workspace` file carries, so opening
|
|
1424
1382
|
// the folder in a container suggests the identical toolset.
|
|
1425
1383
|
customizations: {
|
|
1426
|
-
vscode: { extensions:
|
|
1384
|
+
vscode: { extensions: VSCODE_RECOMMENDED_EXTENSIONS }
|
|
1427
1385
|
}
|
|
1428
1386
|
})}
|
|
1429
1387
|
`;
|
|
@@ -1433,7 +1391,13 @@ var ROOT_LINT_TARGET = {
|
|
|
1433
1391
|
cache: true,
|
|
1434
1392
|
options: {
|
|
1435
1393
|
command: [
|
|
1436
|
-
|
|
1394
|
+
// `--cache` is the one ESLint speed option that actually pays here:
|
|
1395
|
+
// measured best-of-3 on this repo, an unchanged re-run drops from 9,546ms
|
|
1396
|
+
// to 2,835ms (3.4x). `--concurrency=auto` was measured too and REJECTED —
|
|
1397
|
+
// it came out 8% SLOWER, because per-worker TypeScript type-service
|
|
1398
|
+
// startup costs more than the parallelism saves. The cache file is
|
|
1399
|
+
// per-machine and gitignored.
|
|
1400
|
+
"eslint . --cache",
|
|
1437
1401
|
'--ignore-pattern "apps/**"',
|
|
1438
1402
|
'--ignore-pattern "libs/**"',
|
|
1439
1403
|
'--ignore-pattern "packages/**"',
|
|
@@ -1477,38 +1441,23 @@ function eslintToolchainDependencies(nxVersion) {
|
|
|
1477
1441
|
"@mnci/eslint-config": eslintConfigSpec()
|
|
1478
1442
|
};
|
|
1479
1443
|
}
|
|
1480
|
-
var
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
function
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
}
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
var OXLINT_VERSION = "^1.76.0";
|
|
1501
|
-
var OXFMT_VERSION = "^0.61.0";
|
|
1502
|
-
function oxlintToolchainDependencies() {
|
|
1503
|
-
return {
|
|
1504
|
-
"@mnci/oxlint-config": oxlintConfigSpec(),
|
|
1505
|
-
oxlint: OXLINT_VERSION,
|
|
1506
|
-
oxfmt: OXFMT_VERSION
|
|
1507
|
-
};
|
|
1508
|
-
}
|
|
1509
|
-
var OXLINT_CONFIG_VERSION = "^0.1.0";
|
|
1510
|
-
function oxlintConfigSpec() {
|
|
1511
|
-
return process.env.MNCI_OXLINT_CONFIG_SPEC ?? OXLINT_CONFIG_VERSION;
|
|
1444
|
+
var RETIRED_FORMATTER_FILES = [
|
|
1445
|
+
".prettierrc",
|
|
1446
|
+
".prettierrc.json",
|
|
1447
|
+
".prettierrc.mjs",
|
|
1448
|
+
".prettierignore",
|
|
1449
|
+
"oxlint.config.ts",
|
|
1450
|
+
".oxfmtrc.json"
|
|
1451
|
+
];
|
|
1452
|
+
function withoutRetiredFormatterDependencies(devDeps) {
|
|
1453
|
+
const retired = /* @__PURE__ */ new Set([
|
|
1454
|
+
"prettier",
|
|
1455
|
+
"eslint-config-prettier",
|
|
1456
|
+
"oxlint",
|
|
1457
|
+
"oxfmt",
|
|
1458
|
+
"@mnci/oxlint-config"
|
|
1459
|
+
]);
|
|
1460
|
+
return Object.fromEntries(Object.entries(devDeps).filter(([name]) => !retired.has(name)));
|
|
1512
1461
|
}
|
|
1513
1462
|
var ESLINT_BLOCK_INVENTORY = `// WHAT IS IN HERE. Each line is one config block, by the \`name\` it carries.
|
|
1514
1463
|
//
|
|
@@ -1535,9 +1484,9 @@ var ESLINT_BLOCK_INVENTORY = `// WHAT IS IN HERE. Each line is one config block,
|
|
|
1535
1484
|
// mnci/tests *.spec/*.test relaxations \u2014 eslint-plugin-jest
|
|
1536
1485
|
// (Vitest's globals too; the two stacks share them)
|
|
1537
1486
|
// mnci/nx-dependency-checks @nx/eslint-plugin, on publishable packages' manifests
|
|
1538
|
-
// mnci/
|
|
1539
|
-
//
|
|
1540
|
-
//
|
|
1487
|
+
// mnci/standard JavaScript Standard Style as ESLint rules \u2014 the
|
|
1488
|
+
// whole formatting opinion. Composed LAST, on
|
|
1489
|
+
// purpose: nothing may follow that disables it.
|
|
1541
1490
|
//
|
|
1542
1491
|
// To list them as ESLint actually resolves them: npx eslint --inspect-config
|
|
1543
1492
|
`;
|
|
@@ -1561,83 +1510,21 @@ ${ESLINT_BLOCK_INVENTORY}//
|
|
|
1561
1510
|
// a dependency, so \`npm update\` brings rule fixes in the way it brings any
|
|
1562
1511
|
// other. An override here survives that; an edit to the package does not.
|
|
1563
1512
|
//
|
|
1564
|
-
//
|
|
1565
|
-
// \`
|
|
1566
|
-
//
|
|
1567
|
-
//
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
var ESLINT_CONFIG_NON_JS = `import { nonJs } from '@mnci/eslint-config'
|
|
1571
|
-
|
|
1572
|
-
// This workspace lints JS/TS with oxlint (see oxlint.config.ts). ESLint keeps
|
|
1573
|
-
// the file types oxlint cannot parse at all \u2014 YAML, TOML, Markdown, CSS, HTML,
|
|
1574
|
-
// JSON \u2014 plus @nx/dependency-checks on publishable manifests.
|
|
1575
|
-
//
|
|
1576
|
-
// The JS/TS rule blocks are deliberately NOT composed here. Running both linters
|
|
1577
|
-
// over the same file would report one defect twice under two different names.
|
|
1578
|
-
//
|
|
1579
|
-
// TO OVERRIDE, append a named block after the spread, exactly as the full config
|
|
1580
|
-
// documents. To change a JS/TS rule, edit oxlint.config.ts instead \u2014 this file
|
|
1581
|
-
// does not lint JS/TS.
|
|
1582
|
-
export default [...nonJs({ workspaceRoot: import.meta.dirname })]
|
|
1583
|
-
`;
|
|
1584
|
-
var OXLINT_CONFIG = `import { defineConfig } from 'oxlint'
|
|
1585
|
-
import mnci from '@mnci/oxlint-config'
|
|
1586
|
-
|
|
1587
|
-
// oxlint owns JS/TS/JSX here; eslint.config.mjs keeps everything oxlint cannot
|
|
1588
|
-
// parse. The contract @mnci/oxlint-config holds itself to: anything
|
|
1589
|
-
// @mnci/eslint-config accepts must pass oxlint, so switching linters never turns
|
|
1590
|
-
// a green codebase red.
|
|
1591
|
-
//
|
|
1592
|
-
// oxlint.config.ts, not .oxlintrc.json, and that is not a preference: .oxlintrc's
|
|
1593
|
-
// \`extends\` takes PATHS relative to the config file, so
|
|
1594
|
-
// \`extends: ["@mnci/oxlint-config"]\` fails with "No such file or directory".
|
|
1595
|
-
// defineConfig is the only shareable-config route oxlint offers.
|
|
1513
|
+
// FORMATTING IS LINTING HERE. There is no Prettier, no oxfmt and no
|
|
1514
|
+
// \`format:check\` \u2014 \`npm run lint\` reports indentation, quotes and spacing as
|
|
1515
|
+
// ordinary errors, and \`npm run format\` is \`eslint . --fix\`. So do not add a
|
|
1516
|
+
// formatter: whichever one you pick will disagree with the \`mnci/standard\`
|
|
1517
|
+
// block above, and because a formatter runs on save it wins silently, leaving
|
|
1518
|
+
// \`lint\` to fail on files you never edited by hand.
|
|
1596
1519
|
//
|
|
1597
|
-
//
|
|
1598
|
-
//
|
|
1599
|
-
//
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
var OXFMT_CONFIG = `${JSON.stringify(
|
|
1603
|
-
{
|
|
1604
|
-
$schema: "./node_modules/oxfmt/configuration_schema.json",
|
|
1605
|
-
semi: false,
|
|
1606
|
-
singleQuote: true,
|
|
1607
|
-
trailingComma: "none",
|
|
1608
|
-
arrowParens: "avoid",
|
|
1609
|
-
printWidth: 100,
|
|
1610
|
-
tabWidth: 2,
|
|
1611
|
-
useTabs: false
|
|
1612
|
-
},
|
|
1613
|
-
null,
|
|
1614
|
-
2
|
|
1615
|
-
)}
|
|
1616
|
-
`;
|
|
1617
|
-
var PRETTIER_IGNORE = `node_modules
|
|
1618
|
-
dist
|
|
1619
|
-
dist-dev
|
|
1620
|
-
dist-uat
|
|
1621
|
-
dist-prod
|
|
1622
|
-
coverage
|
|
1623
|
-
.next
|
|
1624
|
-
out
|
|
1625
|
-
.nx
|
|
1626
|
-
tmp
|
|
1627
|
-
package-lock.json
|
|
1628
|
-
*.lock
|
|
1629
|
-
.venv
|
|
1630
|
-
venv
|
|
1631
|
-
__pycache__
|
|
1632
|
-
.pytest_cache
|
|
1633
|
-
.ruff_cache
|
|
1634
|
-
.dart_tool
|
|
1520
|
+
// That also applies to the editor. Installing a Prettier or oxfmt extension is
|
|
1521
|
+
// enough on its own \u2014 neither needs a config file, and with none present they
|
|
1522
|
+
// format against their own defaults (semicolons, double quotes), which is the
|
|
1523
|
+
// inverse of Standard.
|
|
1524
|
+
export default mnci({ workspaceRoot: import.meta.dirname })
|
|
1635
1525
|
`;
|
|
1636
|
-
var
|
|
1637
|
-
|
|
1638
|
-
oxlint: ["oxc.oxc-vscode", "dbaeumer.vscode-eslint"]
|
|
1639
|
-
};
|
|
1640
|
-
var SHARED_VSCODE_EXTENSIONS = [
|
|
1526
|
+
var VSCODE_RECOMMENDED_EXTENSIONS = [
|
|
1527
|
+
"dbaeumer.vscode-eslint",
|
|
1641
1528
|
"nrwl.angular-console",
|
|
1642
1529
|
"firsttris.vscode-jest-runner"
|
|
1643
1530
|
];
|
|
@@ -1653,25 +1540,9 @@ var FORMATTED_LANGUAGES = [
|
|
|
1653
1540
|
"css",
|
|
1654
1541
|
"html"
|
|
1655
1542
|
];
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
}
|
|
1660
|
-
function vscodeExtensions(linter) {
|
|
1661
|
-
return [...LINTER_EXTENSIONS[linter], ...SHARED_VSCODE_EXTENSIONS];
|
|
1662
|
-
}
|
|
1663
|
-
function vscodeSettings(linter) {
|
|
1664
|
-
const formatter = linter === "oxlint" ? "oxc.oxc-vscode" : "esbenp.prettier-vscode";
|
|
1665
|
-
const eslintLanguages = linter === "oxlint" ? ["json", "jsonc", "markdown", "yaml", "html", "css"] : [
|
|
1666
|
-
"javascript",
|
|
1667
|
-
"javascriptreact",
|
|
1668
|
-
"typescript",
|
|
1669
|
-
"typescriptreact",
|
|
1670
|
-
"json",
|
|
1671
|
-
"jsonc",
|
|
1672
|
-
"markdown",
|
|
1673
|
-
"yaml"
|
|
1674
|
-
];
|
|
1543
|
+
function vscodeSettings() {
|
|
1544
|
+
const formatter = "dbaeumer.vscode-eslint";
|
|
1545
|
+
const eslintLanguages = [...FORMATTED_LANGUAGES];
|
|
1675
1546
|
return {
|
|
1676
1547
|
"eslint.validate": eslintLanguages,
|
|
1677
1548
|
"editor.codeActionsOnSave": {
|
|
@@ -1686,27 +1557,27 @@ function vscodeSettings(linter) {
|
|
|
1686
1557
|
// does that comparison BEFORE scope. So a `[typescript]` block in someone's
|
|
1687
1558
|
// USER settings — left over from any other project — outranks this file's
|
|
1688
1559
|
// workspace-level `editor.defaultFormatter`, and format-on-save quietly uses
|
|
1689
|
-
// that other formatter instead
|
|
1690
|
-
// the
|
|
1691
|
-
//
|
|
1560
|
+
// that other formatter instead — and nothing reports it, because the gate
|
|
1561
|
+
// and the editor are looking at different tools. That is how it was found:
|
|
1562
|
+
// reported from a real workspace, not deduced from the docs.
|
|
1692
1563
|
//
|
|
1693
1564
|
// Reported from a real workspace where `.ts` files were not being formatted
|
|
1694
1565
|
// while `.json`/`.jsonc`/`.yaml` were — exactly the three that had explicit
|
|
1695
1566
|
// entries here and nothing else did.
|
|
1696
1567
|
...Object.fromEntries(
|
|
1697
|
-
|
|
1568
|
+
FORMATTED_LANGUAGES.map((language) => [
|
|
1698
1569
|
`[${language}]`,
|
|
1699
1570
|
{ "editor.defaultFormatter": formatter }
|
|
1700
1571
|
])
|
|
1701
1572
|
)
|
|
1702
1573
|
};
|
|
1703
1574
|
}
|
|
1704
|
-
function vscodeWorkspace(workspaceName,
|
|
1575
|
+
function vscodeWorkspace(workspaceName, existingTasks) {
|
|
1705
1576
|
return JSON.stringify(
|
|
1706
1577
|
{
|
|
1707
1578
|
folders: [{ path: ".", name: workspaceName }],
|
|
1708
|
-
settings: vscodeSettings(
|
|
1709
|
-
extensions: { recommendations:
|
|
1579
|
+
settings: vscodeSettings(),
|
|
1580
|
+
extensions: { recommendations: VSCODE_RECOMMENDED_EXTENSIONS },
|
|
1710
1581
|
tasks: {
|
|
1711
1582
|
version: existingTasks?.version ?? "2.0.0",
|
|
1712
1583
|
tasks: existingTasks?.tasks ?? []
|
|
@@ -1726,12 +1597,14 @@ var ROOT_SCRIPTS = {
|
|
|
1726
1597
|
"release:preview": "nx release --dry-run",
|
|
1727
1598
|
prepare: "husky"
|
|
1728
1599
|
};
|
|
1729
|
-
function rootScripts(
|
|
1730
|
-
const formatter = linter === "oxlint" ? "oxfmt" : "prettier";
|
|
1600
|
+
function rootScripts() {
|
|
1731
1601
|
return {
|
|
1732
1602
|
...ROOT_SCRIPTS,
|
|
1733
|
-
|
|
1734
|
-
|
|
1603
|
+
// ESLint is the formatter, so `format` is `--fix` and there is no separate
|
|
1604
|
+
// `format:check`: `lint` already reports formatting as ordinary errors.
|
|
1605
|
+
// Carrying a second script that ran the same tool twice would just make a
|
|
1606
|
+
// CI run slower for no extra coverage.
|
|
1607
|
+
format: "eslint . --fix --cache",
|
|
1735
1608
|
"python:install": `${PYTHON_INSTALL_GUARD} && ${PYTHON_WORKSPACE_INSTALL_GUARD}`
|
|
1736
1609
|
};
|
|
1737
1610
|
}
|
|
@@ -1765,7 +1638,7 @@ function mnciConfig(options) {
|
|
|
1765
1638
|
agent: options.agent,
|
|
1766
1639
|
variableGroup: options.variableGroup,
|
|
1767
1640
|
ci: options.ci,
|
|
1768
|
-
stack: { testRunner: options.stack.testRunner
|
|
1641
|
+
stack: { testRunner: options.stack.testRunner }
|
|
1769
1642
|
};
|
|
1770
1643
|
}
|
|
1771
1644
|
function readMnciConfig(workspaceRoot) {
|
|
@@ -1783,7 +1656,7 @@ var PYTHON_WORKSPACE_INSTALL_GUARD = `node -e "const fs=require('node:fs'),path=
|
|
|
1783
1656
|
var PIP_AUDIT_GUARD = `node -e "if(!require('node:fs').existsSync('requirements-dev.txt')){console.log('No Python projects - skipping.');process.exit(0)}const py=process.platform==='win32'?'python':'python3';require('node:child_process').spawnSync(py,['-m','pip_audit'],{stdio:'inherit'});process.exit(0)"`;
|
|
1784
1657
|
var GO_MODULE_DOWNLOAD_GUARD = `node -e "if(!require('node:fs').existsSync('go.mod')){console.log('No Go projects - skipping.');process.exit(0)}process.exit(require('node:child_process').spawnSync('go',['mod','download'],{stdio:'inherit'}).status ?? 1)"`;
|
|
1785
1658
|
var GOLANGCI_LINT_INSTALL_GUARD = `node -e "const fs=require('node:fs'),cp=require('node:child_process');if(!fs.existsSync('go.mod')){console.log('No Go projects - skipping.');process.exit(0)}if(cp.spawnSync('golangci-lint',['--version'],{stdio:'ignore'}).status===0){console.log('golangci-lint already installed - skipping.');process.exit(0)}process.exit(cp.spawnSync('go',['install','github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest'],{stdio:'inherit'}).status ?? 1)"`;
|
|
1786
|
-
var GO_TOOL_PATH_PRELUDE =
|
|
1659
|
+
var GO_TOOL_PATH_PRELUDE = "const fs=require('node:fs'),cp=require('node:child_process');if(!fs.existsSync('go.mod')){console.log('No Go projects - skipping.');process.exit(0)}const r=cp.spawnSync('go',['env','GOPATH'],{encoding:'utf8'});if(r.status!==0){console.log('Could not resolve GOPATH - skipping.');process.exit(0)}const bin=require('node:path').join(r.stdout.trim(),'bin');";
|
|
1787
1660
|
var GO_TOOL_PATH_AZURE = `node -e "${GO_TOOL_PATH_PRELUDE}console.log('##vso[task.prependpath]'+bin)"`;
|
|
1788
1661
|
var GO_TOOL_PATH_GITHUB = `node -e "${GO_TOOL_PATH_PRELUDE}if(!process.env.GITHUB_PATH){console.log('Not running in GitHub Actions - skipping.');process.exit(0)}fs.appendFileSync(process.env.GITHUB_PATH,bin+${String.raw`'\n'`})"`;
|
|
1789
1662
|
var FLUTTER_SDK_VERSION = "3.44.8";
|
|
@@ -1812,7 +1685,7 @@ function poolBlock(agent) {
|
|
|
1812
1685
|
return /^(?:ubuntu|windows|macos)-/i.test(agent) ? ` vmImage: ${agent}` : ` name: ${agent}`;
|
|
1813
1686
|
}
|
|
1814
1687
|
function azurePipelinesYaml(agent, variableGroup, pythonPublishUrl2, registryKind = "azure-artifacts") {
|
|
1815
|
-
const onMain =
|
|
1688
|
+
const onMain = "and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranchName'], 'main'))";
|
|
1816
1689
|
const [npmAuthName, npmAuthValue] = npmAuthEnvVariable(registryKind, (name) => `$(${name})`);
|
|
1817
1690
|
return `name: monorepo-ci-$(Date:yyyyMMdd)$(Rev:.r)
|
|
1818
1691
|
|
|
@@ -1966,17 +1839,6 @@ steps:
|
|
|
1966
1839
|
- script: npx nx sync:check
|
|
1967
1840
|
displayName: Verify the workspace is synced (run 'npx nx sync' locally and commit if this fails)
|
|
1968
1841
|
|
|
1969
|
-
# Prettier owns ALL formatting in this workspace, so it needs a gate of its
|
|
1970
|
-
# own: ESLint is configured for correctness only and deliberately reports
|
|
1971
|
-
# nothing about formatting. Without this step the entire formatting opinion is
|
|
1972
|
-
# advisory, and a workspace drifts out of compliance with no signal anywhere.
|
|
1973
|
-
#
|
|
1974
|
-
# Stays workspace-wide even on a PR, unlike the verify step below: it is one
|
|
1975
|
-
# Prettier invocation over the whole tree, not a per-project Nx target, so
|
|
1976
|
-
# there is nothing to scope down and formatting is never partially checked.
|
|
1977
|
-
- script: npm run format:check
|
|
1978
|
-
displayName: Check formatting (run 'npm run format' locally to fix)
|
|
1979
|
-
|
|
1980
1842
|
# The one verify step, and deliberately the only one: affected projects on a
|
|
1981
1843
|
# pull request, EVERY project on anything else (a push to main included, so a
|
|
1982
1844
|
# release is always verified in full). Every fallback \u2014 no target branch, an
|
|
@@ -2031,7 +1893,7 @@ steps:
|
|
|
2031
1893
|
`;
|
|
2032
1894
|
}
|
|
2033
1895
|
function githubActionsYaml(agent, pythonPublishUrl2, registryKind = "azure-artifacts", ci = "github") {
|
|
2034
|
-
const onMain =
|
|
1896
|
+
const onMain = "github.event_name == 'push' && github.ref_name == 'main'";
|
|
2035
1897
|
const [npmAuthName, npmAuthValue] = npmAuthEnvVariable(
|
|
2036
1898
|
registryKind,
|
|
2037
1899
|
(name) => `\${{ secrets.${name} }}`
|
|
@@ -2173,19 +2035,6 @@ jobs:
|
|
|
2173
2035
|
- run: npx nx sync:check
|
|
2174
2036
|
name: Verify the workspace is synced (run 'npx nx sync' locally and commit if this fails)
|
|
2175
2037
|
|
|
2176
|
-
# Prettier owns ALL formatting in this workspace, so it needs a gate of
|
|
2177
|
-
# its own: ESLint is configured for correctness only and deliberately
|
|
2178
|
-
# reports nothing about formatting. Without this step the entire
|
|
2179
|
-
# formatting opinion is advisory, and a workspace drifts out of
|
|
2180
|
-
# compliance with no signal anywhere.
|
|
2181
|
-
#
|
|
2182
|
-
# Stays workspace-wide even on a PR, unlike the verify step below: it is
|
|
2183
|
-
# one Prettier invocation over the whole tree, not a per-project Nx
|
|
2184
|
-
# target, so there is nothing to scope down and formatting is never
|
|
2185
|
-
# partially checked.
|
|
2186
|
-
- run: npm run format:check
|
|
2187
|
-
name: Check formatting (run 'npm run format' locally to fix)
|
|
2188
|
-
|
|
2189
2038
|
# The one verify step, and deliberately the only one: affected projects on
|
|
2190
2039
|
# a pull request, EVERY project on anything else (a push to main included,
|
|
2191
2040
|
# so a release is always verified in full). Every fallback \u2014 no target
|
|
@@ -2310,23 +2159,15 @@ function applyOverlay(workspaceRoot, options) {
|
|
|
2310
2159
|
const manifest = readJson(manifestPath);
|
|
2311
2160
|
const scripts = {
|
|
2312
2161
|
...manifest.scripts,
|
|
2313
|
-
...rootScripts(
|
|
2162
|
+
...rootScripts()
|
|
2314
2163
|
};
|
|
2315
2164
|
const existingDevDeps = manifest.devDependencies;
|
|
2316
|
-
const devDeps =
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
// Additive for the linter, exclusive for the formatter: the hybrid keeps
|
|
2323
|
-
// the whole ESLint toolchain for the file types oxlint cannot parse, but
|
|
2324
|
-
// exactly one of prettier/oxfmt formats the workspace. Declaring both is
|
|
2325
|
-
// how an editor ends up applying the one CI does not check.
|
|
2326
|
-
...options.stack.linter === "oxlint" ? oxlintToolchainDependencies() : { prettier: PRETTIER_VERSION }
|
|
2327
|
-
},
|
|
2328
|
-
options.stack.linter
|
|
2329
|
-
);
|
|
2165
|
+
const devDeps = withoutRetiredFormatterDependencies({
|
|
2166
|
+
...existingDevDeps,
|
|
2167
|
+
...TS_COMPILER_DEPENDENCIES,
|
|
2168
|
+
// The preset pins `nx` itself; the ESLint plugins must match it exactly.
|
|
2169
|
+
...eslintToolchainDependencies(existingDevDeps?.nx ?? "latest")
|
|
2170
|
+
});
|
|
2330
2171
|
const overrides = {
|
|
2331
2172
|
...manifest.overrides,
|
|
2332
2173
|
...ESLINT_PEER_OVERRIDES
|
|
@@ -2337,7 +2178,7 @@ function applyOverlay(workspaceRoot, options) {
|
|
|
2337
2178
|
includedScripts: existingNx?.includedScripts ?? [],
|
|
2338
2179
|
targets: {
|
|
2339
2180
|
...existingNx?.targets,
|
|
2340
|
-
lint:
|
|
2181
|
+
lint: ROOT_LINT_TARGET
|
|
2341
2182
|
}
|
|
2342
2183
|
};
|
|
2343
2184
|
writeFileEnsured(
|
|
@@ -2356,28 +2197,20 @@ function applyOverlay(workspaceRoot, options) {
|
|
|
2356
2197
|
const hookPath = (0, import_node_path11.join)(workspaceRoot, ".husky/commit-msg");
|
|
2357
2198
|
writeFileEnsured(hookPath, COMMIT_MSG_HOOK);
|
|
2358
2199
|
markExecutable(hookPath);
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
writeFileEnsured((0, import_node_path11.join)(workspaceRoot, "eslint.config.mjs"), ESLINT_CONFIG_NON_JS);
|
|
2363
|
-
removeIfPresent((0, import_node_path11.join)(workspaceRoot, ".prettierrc.mjs"));
|
|
2364
|
-
} else {
|
|
2365
|
-
writeFileEnsured((0, import_node_path11.join)(workspaceRoot, "eslint.config.mjs"), ESLINT_CONFIG);
|
|
2366
|
-
writeFileEnsured((0, import_node_path11.join)(workspaceRoot, ".prettierrc.mjs"), PRETTIER_CONFIG);
|
|
2367
|
-
removeIfPresent((0, import_node_path11.join)(workspaceRoot, "oxlint.config.ts"));
|
|
2368
|
-
removeIfPresent((0, import_node_path11.join)(workspaceRoot, ".oxfmtrc.json"));
|
|
2200
|
+
writeFileEnsured((0, import_node_path11.join)(workspaceRoot, "eslint.config.mjs"), ESLINT_CONFIG);
|
|
2201
|
+
for (const retired of RETIRED_FORMATTER_FILES) {
|
|
2202
|
+
removeIfPresent((0, import_node_path11.join)(workspaceRoot, retired));
|
|
2369
2203
|
}
|
|
2370
2204
|
writeFileEnsured(
|
|
2371
2205
|
(0, import_node_path11.join)(workspaceRoot, ".devcontainer/devcontainer.json"),
|
|
2372
|
-
devcontainerJson(options.workspaceName
|
|
2206
|
+
devcontainerJson(options.workspaceName)
|
|
2373
2207
|
);
|
|
2374
|
-
writeFileEnsured((0, import_node_path11.join)(workspaceRoot, ".prettierignore"), PRETTIER_IGNORE);
|
|
2375
2208
|
removeNxScaffolding(workspaceRoot);
|
|
2376
2209
|
const codeWorkspacePath = (0, import_node_path11.join)(workspaceRoot, `${options.workspaceName}.code-workspace`);
|
|
2377
2210
|
const existing = readCodeWorkspace(codeWorkspacePath);
|
|
2378
2211
|
writeFileEnsured(
|
|
2379
2212
|
codeWorkspacePath,
|
|
2380
|
-
vscodeWorkspace(options.workspaceName,
|
|
2213
|
+
vscodeWorkspace(options.workspaceName, existing?.tasks)
|
|
2381
2214
|
);
|
|
2382
2215
|
if (options.workspaceName !== "undefined") {
|
|
2383
2216
|
(0, import_node_fs6.rmSync)((0, import_node_path11.join)(workspaceRoot, "undefined.code-workspace"), { force: true });
|
|
@@ -2420,65 +2253,28 @@ function checkEslintConfigs(workspaceRoot) {
|
|
|
2420
2253
|
}
|
|
2421
2254
|
];
|
|
2422
2255
|
}
|
|
2423
|
-
function checkPrettierConfig(workspaceRoot) {
|
|
2424
|
-
const strayExists = fileExists((0, import_node_path12.join)(workspaceRoot, ".prettierrc"));
|
|
2425
|
-
return {
|
|
2426
|
-
check: "Prettier config is mnci\u2019s",
|
|
2427
|
-
ok: !strayExists,
|
|
2428
|
-
detail: ".prettierrc exists and outranks .prettierrc.json, so mnci\u2019s config is ignored",
|
|
2429
|
-
remedy: "delete .prettierrc (or run `mnci upgrade`, which deletes it)"
|
|
2430
|
-
};
|
|
2431
|
-
}
|
|
2432
|
-
function checkLinterModeIsConsistent(workspaceRoot) {
|
|
2433
|
-
const linter = readMnciConfig(workspaceRoot).stack?.linter ?? "eslint";
|
|
2434
|
-
const oxlintFiles = ["oxlint.config.ts", ".oxfmtrc.json"].filter(
|
|
2435
|
-
(file) => fileExists((0, import_node_path12.join)(workspaceRoot, file))
|
|
2436
|
-
);
|
|
2437
|
-
const hasPrettier = fileExists((0, import_node_path12.join)(workspaceRoot, ".prettierrc.mjs"));
|
|
2438
|
-
const stray = linter === "oxlint" ? hasPrettier ? [".prettierrc.mjs"] : [] : oxlintFiles;
|
|
2439
|
-
return {
|
|
2440
|
-
check: `linter is ${linter} and only ${linter}'s config files are present`,
|
|
2441
|
-
ok: stray.length === 0,
|
|
2442
|
-
detail: `${stray.join(", ")} belongs to the other linter mode, so two configs are in play at once`,
|
|
2443
|
-
remedy: "run `mnci upgrade`, which removes the mode the workspace did not choose"
|
|
2444
|
-
};
|
|
2445
|
-
}
|
|
2446
2256
|
function declaredDevDependencies(workspaceRoot) {
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
}
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
const declared = declaredDevDependencies(workspaceRoot)[stale] !== void 0;
|
|
2456
|
-
return {
|
|
2457
|
-
check: `only ${linter === "oxlint" ? "oxfmt" : "prettier"} is declared as the formatter`,
|
|
2458
|
-
ok: !declared,
|
|
2459
|
-
detail: `${stale} is declared but nothing runs it \u2014 the editor may still resolve and apply it, disagreeing with \`npm run format:check\``,
|
|
2460
|
-
remedy: "run `mnci upgrade`, which drops the formatter of the mode you left"
|
|
2461
|
-
};
|
|
2257
|
+
try {
|
|
2258
|
+
const manifest = readJson(
|
|
2259
|
+
(0, import_node_path12.join)(workspaceRoot, "package.json")
|
|
2260
|
+
);
|
|
2261
|
+
return manifest.devDependencies ?? {};
|
|
2262
|
+
} catch {
|
|
2263
|
+
return {};
|
|
2264
|
+
}
|
|
2462
2265
|
}
|
|
2463
|
-
function
|
|
2464
|
-
const
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
detail: "not an oxlint workspace",
|
|
2470
|
-
remedy: ""
|
|
2471
|
-
};
|
|
2266
|
+
function checkNoRetiredFormatter(workspaceRoot) {
|
|
2267
|
+
const files = RETIRED_FORMATTER_FILES.filter((file) => fileExists((0, import_node_path12.join)(workspaceRoot, file)));
|
|
2268
|
+
const declared = ["prettier", "eslint-config-prettier", "oxlint", "oxfmt", "@mnci/oxlint-config"].filter((name) => declaredDevDependencies(workspaceRoot)[name] !== void 0);
|
|
2269
|
+
const stale = [...files, ...declared];
|
|
2270
|
+
if (stale.length === 0) {
|
|
2271
|
+
return { check: "ESLint is the only linter and formatter", ok: true };
|
|
2472
2272
|
}
|
|
2473
|
-
const devDeps = declaredDevDependencies(workspaceRoot);
|
|
2474
|
-
const missing = ["oxlint", "oxfmt", "@mnci/oxlint-config"].filter(
|
|
2475
|
-
(dependency) => devDeps[dependency] === void 0
|
|
2476
|
-
);
|
|
2477
2273
|
return {
|
|
2478
|
-
check: "
|
|
2479
|
-
ok:
|
|
2480
|
-
detail: `
|
|
2481
|
-
remedy: "
|
|
2274
|
+
check: "no retired formatter is still configured",
|
|
2275
|
+
ok: false,
|
|
2276
|
+
detail: `Found: ${stale.join(", ")}. These no longer run, but an editor extension still resolves them and will reformat on save against an opinion no gate checks.`,
|
|
2277
|
+
remedy: "Run 'mnci upgrade' to remove them."
|
|
2482
2278
|
};
|
|
2483
2279
|
}
|
|
2484
2280
|
function checkEslintPlugin(nxJson) {
|
|
@@ -2574,10 +2370,7 @@ function collectFindings(workspaceRoot) {
|
|
|
2574
2370
|
const nxJson = readJson(nxJsonPath);
|
|
2575
2371
|
return [
|
|
2576
2372
|
...checkEslintConfigs(workspaceRoot),
|
|
2577
|
-
|
|
2578
|
-
checkLinterModeIsConsistent(workspaceRoot),
|
|
2579
|
-
checkOneFormatterDeclared(workspaceRoot),
|
|
2580
|
-
checkOxlintToolchainDeclared(workspaceRoot),
|
|
2373
|
+
checkNoRetiredFormatter(workspaceRoot),
|
|
2581
2374
|
checkEslintPlugin(nxJson),
|
|
2582
2375
|
checkResolvedEslint(workspaceRoot),
|
|
2583
2376
|
checkNpmrc(workspaceRoot, nxJson.mnci?.registry, nxJson.mnci?.scope),
|
|
@@ -2617,17 +2410,11 @@ function nxCloudProviderValue(ci) {
|
|
|
2617
2410
|
return ci === "azure" ? "azure" : "github";
|
|
2618
2411
|
}
|
|
2619
2412
|
async function resolveStack(options) {
|
|
2620
|
-
if (options.testRunner || options.
|
|
2621
|
-
return {
|
|
2622
|
-
testRunner: options.testRunner ?? DEFAULT_STACK.testRunner,
|
|
2623
|
-
linter: options.linter ?? DEFAULT_STACK.linter
|
|
2624
|
-
};
|
|
2413
|
+
if (options.testRunner || options.yes) {
|
|
2414
|
+
return { testRunner: options.testRunner ?? DEFAULT_STACK.testRunner };
|
|
2625
2415
|
}
|
|
2626
2416
|
const prompted = await promptStack();
|
|
2627
|
-
return {
|
|
2628
|
-
testRunner: prompted.testRunner,
|
|
2629
|
-
linter: prompted.linter
|
|
2630
|
-
};
|
|
2417
|
+
return { testRunner: prompted.testRunner };
|
|
2631
2418
|
}
|
|
2632
2419
|
var CI_PROVIDERS = /* @__PURE__ */ new Set(["azure", "github", "both"]);
|
|
2633
2420
|
async function resolveCi(options) {
|
|
@@ -2696,10 +2483,8 @@ async function runNew(name, options) {
|
|
|
2696
2483
|
throw new Error(`npm install of the toolchain failed with exit code ${installStatus}`);
|
|
2697
2484
|
}
|
|
2698
2485
|
runShell("npx", ["husky"], workspaceRoot);
|
|
2699
|
-
logger.step(
|
|
2700
|
-
|
|
2701
|
-
);
|
|
2702
|
-
runFormatter(workspaceRoot, stack.linter);
|
|
2486
|
+
logger.step("Formatting the workspace (eslint --fix, JavaScript Standard Style)");
|
|
2487
|
+
runFormatter(workspaceRoot);
|
|
2703
2488
|
logger.success("Done. Next steps:");
|
|
2704
2489
|
logger.info(` cd ${workspaceName}`);
|
|
2705
2490
|
logger.info(" mnci add react-app web # or: react-lib, react-internal-lib, node-app,");
|
|
@@ -2776,7 +2561,6 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
|
2776
2561
|
);
|
|
2777
2562
|
}
|
|
2778
2563
|
const variableGroup = options.variableGroup ?? persisted.variableGroup ?? "Build";
|
|
2779
|
-
const linter = options.linter ?? persisted.stack?.linter ?? "eslint";
|
|
2780
2564
|
const testRunner = options.testRunner ?? persisted.stack?.testRunner;
|
|
2781
2565
|
if (!testRunner) {
|
|
2782
2566
|
throw new Error(
|
|
@@ -2790,7 +2574,7 @@ function resolveOverlayOptions(workspaceRoot, options, persisted) {
|
|
|
2790
2574
|
agent,
|
|
2791
2575
|
variableGroup,
|
|
2792
2576
|
ci,
|
|
2793
|
-
stack: { testRunner
|
|
2577
|
+
stack: { testRunner }
|
|
2794
2578
|
};
|
|
2795
2579
|
}
|
|
2796
2580
|
function runUpgrade(workspaceRoot, options) {
|
|
@@ -2805,7 +2589,7 @@ function runUpgrade(workspaceRoot, options) {
|
|
|
2805
2589
|
"Re-applying the MoNecromanCI overlay (release config, .npmrc, commitlint, pipeline, stack)"
|
|
2806
2590
|
);
|
|
2807
2591
|
applyOverlay(workspaceRoot, resolved);
|
|
2808
|
-
runFormatter(workspaceRoot
|
|
2592
|
+
runFormatter(workspaceRoot);
|
|
2809
2593
|
logger.success("Done. Review the changes with `git diff` before committing.");
|
|
2810
2594
|
}
|
|
2811
2595
|
|
|
@@ -2904,10 +2688,7 @@ function buildProgram(cliVersion) {
|
|
|
2904
2688
|
program.command("new").argument("[name]", "workspace name").description("Create a new monorepo (Nx TS preset + release/pipeline overlay)").option("-y, --yes", "accept defaults for anything not passed as a flag").option("--scope <scope>", "npm scope for publishable packages (e.g. @demo)").option("--registry <kind>", "azure-artifacts | npm").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option(
|
|
2905
2689
|
"--agent <pool>",
|
|
2906
2690
|
"CI build agent: a vmImage (e.g. ubuntu-latest) or self-hosted pool name"
|
|
2907
|
-
).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option(
|
|
2908
|
-
"--linter <linter>",
|
|
2909
|
-
"linter + formatter: eslint (ESLint + Prettier) | oxlint (oxlint + oxfmt for JS/TS, ESLint for the rest)"
|
|
2910
|
-
).option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").action(async (name, options) => {
|
|
2691
|
+
).option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both").option("--test-runner <runner>", "unit-test runner: jest | vitest").option("--nx-cloud", "connect the workspace to Nx Cloud (remote caching + CI insights)").action(async (name, options) => {
|
|
2911
2692
|
await runNew(name, options);
|
|
2912
2693
|
});
|
|
2913
2694
|
program.command("upgrade").description(
|
|
@@ -2915,9 +2696,6 @@ function buildProgram(cliVersion) {
|
|
|
2915
2696
|
).option("--scope <scope>", "npm scope for publishable packages (overrides the persisted value)").option("--registry <kind>", "azure-artifacts | npm (overrides the persisted value)").option("--organization <name>", "Azure DevOps organization").option("--project <name>", "Azure DevOps project").option("--artifacts-feed <name>", "Azure Artifacts feed").option("--agent <pool>", "CI build agent (overrides the persisted value)").option("--variable-group <name>", "Azure DevOps variable group holding the npm PAT").option("--ci <provider>", "CI provider: azure | github | both (overrides the persisted value)").option(
|
|
2916
2697
|
"--test-runner <runner>",
|
|
2917
2698
|
"unit-test runner: jest | vitest (overrides the persisted value)"
|
|
2918
|
-
).option(
|
|
2919
|
-
"--linter <linter>",
|
|
2920
|
-
"linter + formatter: eslint | oxlint (overrides the persisted value)"
|
|
2921
2699
|
).action((options) => {
|
|
2922
2700
|
runUpgrade(process.cwd(), options);
|
|
2923
2701
|
});
|