@mnci/cli 1.13.0 → 1.14.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 +41 -8
- package/dist/cli.js +88 -7
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ that would just fail felt worse than being upfront that it doesn't exist yet.
|
|
|
126
126
|
is ever pushed to `main`; future runs resolve versions from tag names.
|
|
127
127
|
3. Writes `eslint.config.mjs` (three lines importing `@mnci/eslint-config` —
|
|
128
128
|
the whole linting opinion, in one root config), `.prettierrc.json` +
|
|
129
|
-
`.prettierignore`, `.npmrc` (
|
|
129
|
+
`.prettierignore`, `.npmrc` (publish auth — see **Publish auth** below),
|
|
130
130
|
`commitlint.config.mjs`, a husky `commit-msg` hook, the chosen CI provider's
|
|
131
131
|
pipeline file(s)
|
|
132
132
|
(`azure-pipelines.yml` and/or `.github/workflows/ci.yml`, `--ci`, default
|
|
@@ -404,6 +404,42 @@ lint,test,build`. Pushes to `main` then:
|
|
|
404
404
|
_only_ configured provider, since that's the one case a `GITHUB_TOKEN` is
|
|
405
405
|
guaranteed to exist.
|
|
406
406
|
|
|
407
|
+
### Publish auth
|
|
408
|
+
|
|
409
|
+
The generated `.npmrc` differs by registry kind, because the honest answer does.
|
|
410
|
+
|
|
411
|
+
**`--registry azure-artifacts`** routes the workspace's own scope to the feed and
|
|
412
|
+
supplies the feed's credentials:
|
|
413
|
+
|
|
414
|
+
```ini
|
|
415
|
+
@my:registry=https://pkgs.dev.azure.com/<org>/<proj>/_packaging/<feed>/npm/registry/
|
|
416
|
+
//pkgs.dev.azure.com/.../npm/registry/:username=AzureArtifacts
|
|
417
|
+
//pkgs.dev.azure.com/.../npm/registry/:_password=${PAT}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
Scope routing is **real protection** here, not decoration: npm prefers a scope's
|
|
421
|
+
registry over the global one when publishing a scoped package, so `@my/*` cannot
|
|
422
|
+
reach npmjs.org by accident. Verified against a real registry — with only the
|
|
423
|
+
scope line set, npm reports `Publishing to <feed>` — and again from a generated
|
|
424
|
+
workspace, whose `npm publish --dry-run` targets the feed.
|
|
425
|
+
|
|
426
|
+
Only the scope is routed, deliberately. A global `registry=` would push every
|
|
427
|
+
install through the feed as well, so `npm ci` would need feed auth just to fetch
|
|
428
|
+
public packages; as generated, public dependencies still come from npmjs.org and
|
|
429
|
+
a developer with no `PAT` set can install normally.
|
|
430
|
+
|
|
431
|
+
**`--registry npm`** gets the auth line and nothing else:
|
|
432
|
+
|
|
433
|
+
```ini
|
|
434
|
+
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
There is no `@scope:registry` line, and the generated file explains why: npmjs.org
|
|
438
|
+
is already the default, so routing the scope there changes nothing — and calling
|
|
439
|
+
it protection against an accidental public publish would be false, because the
|
|
440
|
+
public registry is the intended target. Worth stating plainly because this file
|
|
441
|
+
previously claimed exactly that protection while emitting no routing line at all.
|
|
442
|
+
|
|
407
443
|
**npm auth** is the base64 `PAT`, read the same way on both providers but from
|
|
408
444
|
a different place: on Azure Pipelines, a **variable group**
|
|
409
445
|
(`--variable-group`, default `Build`) exposes it as `$(PAT)`; on GitHub
|
|
@@ -516,13 +552,10 @@ than a surprise:
|
|
|
516
552
|
|
|
517
553
|
## Known gaps (accepted for the experiment)
|
|
518
554
|
|
|
519
|
-
- **
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
than ship half-wired auth, the CI token export (`NODE_AUTH_TOKEN`/`PAT`) is
|
|
524
|
-
left in place so wiring it later is one line, and the generated `.npmrc`
|
|
525
|
-
carries a comment saying so. Publish-path e2e assertions are relaxed to match.
|
|
555
|
+
- **A scoped package on public npm has no accidental-publish protection**, and
|
|
556
|
+
cannot: npmjs.org is the intended target there, so no `.npmrc` line could
|
|
557
|
+
prevent it. Generate with `--registry azure-artifacts` if you need a scope kept
|
|
558
|
+
off the public registry — that variant routes it (see **Publish auth** above).
|
|
526
559
|
- No `doctor`/`resurrect`/`spell` — out of scope until the model is proven.
|
|
527
560
|
- **Flutter apps build for web only.** Android would require the Android SDK and
|
|
528
561
|
NDK on every build agent; iOS is impossible on a Linux agent regardless. Add
|
package/dist/cli.js
CHANGED
|
@@ -1250,15 +1250,49 @@ var TS_COMPILER_DEPENDENCIES = {
|
|
|
1250
1250
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
1251
1251
|
typescript: "npm:@typescript/typescript6@^6.0.2"
|
|
1252
1252
|
};
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1253
|
+
function registryUrl(registry) {
|
|
1254
|
+
if (registry.kind === "azure-artifacts") {
|
|
1255
|
+
return `https://pkgs.dev.azure.com/${registry.organization}/${registry.project}/_packaging/${registry.artifactsFeed}/npm/registry/`;
|
|
1256
|
+
}
|
|
1257
|
+
return void 0;
|
|
1258
|
+
}
|
|
1259
|
+
function npmrcContent(registry, scope) {
|
|
1260
|
+
if (registry.kind === "npm") {
|
|
1261
|
+
return `; Publish authentication for the public npm registry.
|
|
1255
1262
|
;
|
|
1256
|
-
;
|
|
1257
|
-
;
|
|
1258
|
-
|
|
1259
|
-
|
|
1263
|
+
; NODE_AUTH_TOKEN is exported by the generated CI's release step; an unset value
|
|
1264
|
+
; is harmless locally, so no token is needed for day-to-day work.
|
|
1265
|
+
//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}
|
|
1266
|
+
|
|
1267
|
+
; There is deliberately NO '${scope}:registry' line here. npmjs.org is already
|
|
1268
|
+
; the default registry, so routing the scope to it would change nothing \u2014 and
|
|
1269
|
+
; presenting that as protection against an accidental public publish would be
|
|
1270
|
+
; false, because the public registry is the intended target. (An earlier version
|
|
1271
|
+
; of this file made exactly that claim while emitting no routing line at all.)
|
|
1272
|
+
; To keep a scoped package off npmjs.org, use a private feed: generate with
|
|
1273
|
+
; --registry azure-artifacts, which does route the scope.
|
|
1274
|
+
`;
|
|
1275
|
+
}
|
|
1276
|
+
const feedUrl = registryUrl(registry);
|
|
1277
|
+
const feedKey = feedUrl.replace(/^https:/, "");
|
|
1278
|
+
return `; Publish + resolution routing for this workspace's own scope.
|
|
1260
1279
|
;
|
|
1261
|
-
;
|
|
1280
|
+
; '${scope}:registry' sends BOTH resolution and 'npm publish' of ${scope}/* to the
|
|
1281
|
+
; feed: npm prefers a scope's registry over the global one when publishing a
|
|
1282
|
+
; scoped package, so a ${scope}/* package cannot reach npmjs.org by accident.
|
|
1283
|
+
;
|
|
1284
|
+
; Only the scope is routed, on purpose. A global 'registry=' would send every
|
|
1285
|
+
; install through the feed as well, so 'npm ci' would need feed auth just to fetch
|
|
1286
|
+
; public packages.
|
|
1287
|
+
${scope}:registry=${feedUrl}
|
|
1288
|
+
|
|
1289
|
+
; Feed credentials. PAT is the BASE64 value Azure Artifacts' "Connect to feed"
|
|
1290
|
+
; instructions give you, which is exactly what _password expects, so it is used
|
|
1291
|
+
; as-is. (twine wants the RAW token; the CI release step decodes it there.)
|
|
1292
|
+
; Azure ignores the username, and npm requires an email it never uses.
|
|
1293
|
+
${feedKey}:username=AzureArtifacts
|
|
1294
|
+
${feedKey}:_password=\${PAT}
|
|
1295
|
+
${feedKey}:email=npm-requires-this-and-never-uses-it
|
|
1262
1296
|
`;
|
|
1263
1297
|
}
|
|
1264
1298
|
function releaseConfig(ci) {
|
|
@@ -1502,9 +1536,18 @@ function azurePipelinesYaml(agent, variableGroup, pythonPublishUrl2, registryKin
|
|
|
1502
1536
|
# runs unchanged on Linux, macOS and Windows agents.
|
|
1503
1537
|
|
|
1504
1538
|
trigger:
|
|
1539
|
+
# While a run is in progress, queue further pushes and run them together rather
|
|
1540
|
+
# than concurrently. This is the closest thing Azure Pipelines YAML has to
|
|
1541
|
+
# GitHub's concurrency group, and it is load-bearing on main for the same
|
|
1542
|
+
# reason: two concurrent 'nx release' runs would race to create the same tag.
|
|
1543
|
+
batch: true
|
|
1505
1544
|
branches:
|
|
1506
1545
|
include: [main]
|
|
1507
1546
|
|
|
1547
|
+
# Note: cancelling a superseded PR validation run is NOT a YAML setting on Azure
|
|
1548
|
+
# \u2014 it lives in the branch policy ("Build validation -> automatically cancel").
|
|
1549
|
+
# Nothing here can express it, so it is left to whoever configures the policy
|
|
1550
|
+
# rather than faked with a batch setting that would only delay PR runs.
|
|
1508
1551
|
pr:
|
|
1509
1552
|
branches:
|
|
1510
1553
|
include: [main]
|
|
@@ -1517,6 +1560,12 @@ variables:
|
|
|
1517
1560
|
# for an Azure Artifacts feed, or a raw npm automation token as \`NPM_TOKEN\`
|
|
1518
1561
|
# for public npm. Mark it secret in Library. Add app build vars here too if needed.
|
|
1519
1562
|
- group: ${variableGroup}
|
|
1563
|
+
# Relocates npm's cache inside the pipeline workspace so Cache@2 can restore it
|
|
1564
|
+
# (the default ~/.npm is outside the cacheable area on hosted agents). npm reads
|
|
1565
|
+
# this as an ordinary env var, so it needs no config file and works on every
|
|
1566
|
+
# agent OS.
|
|
1567
|
+
- name: npm_config_cache
|
|
1568
|
+
value: $(Pipeline.Workspace)/.npm
|
|
1520
1569
|
|
|
1521
1570
|
steps:
|
|
1522
1571
|
- checkout: self
|
|
@@ -1541,6 +1590,20 @@ steps:
|
|
|
1541
1590
|
inputs:
|
|
1542
1591
|
version: 24.x
|
|
1543
1592
|
|
|
1593
|
+
# The Azure counterpart of \`cache: npm\` on actions/setup-node: restores npm's
|
|
1594
|
+
# download cache so \`npm ci\` does not re-fetch every tarball on every run.
|
|
1595
|
+
# Keyed on the lockfile, so a dependency change misses and anything else hits;
|
|
1596
|
+
# restoreKeys falls back to the newest cache for this OS on a miss, which still
|
|
1597
|
+
# avoids a fully cold install. Agent.OS is in the key because a cached native
|
|
1598
|
+
# module built for one OS is not reusable on another.
|
|
1599
|
+
- task: Cache@2
|
|
1600
|
+
displayName: Cache npm packages
|
|
1601
|
+
inputs:
|
|
1602
|
+
key: 'npm | "$(Agent.OS)" | package-lock.json'
|
|
1603
|
+
restoreKeys: |
|
|
1604
|
+
npm | "$(Agent.OS)"
|
|
1605
|
+
path: $(npm_config_cache)
|
|
1606
|
+
|
|
1544
1607
|
- script: npm ci
|
|
1545
1608
|
displayName: Install dependencies
|
|
1546
1609
|
env:
|
|
@@ -1698,6 +1761,19 @@ on:
|
|
|
1698
1761
|
pull_request:
|
|
1699
1762
|
branches: [main]
|
|
1700
1763
|
|
|
1764
|
+
concurrency:
|
|
1765
|
+
# One run at a time per ref, but \`cancel-in-progress\` is an **expression** on
|
|
1766
|
+
# purpose rather than a flat \`true\`.
|
|
1767
|
+
#
|
|
1768
|
+
# A superseded PR run is pure waste, so cancel it. A run on \`main\` must never
|
|
1769
|
+
# be cancelled: it publishes packages and pushes release tags, and killing it
|
|
1770
|
+
# part-way can leave a tag pushed with the publish only half done \u2014 a state no
|
|
1771
|
+
# rerun repairs cleanly, because the version is then already tagged. Those runs
|
|
1772
|
+
# queue instead, which also stops two \`nx release\` invocations racing to create
|
|
1773
|
+
# the same tag when two commits land close together.
|
|
1774
|
+
group: \${{ github.workflow }}-\${{ github.ref }}
|
|
1775
|
+
cancel-in-progress: \${{ github.event_name == 'pull_request' }}
|
|
1776
|
+
|
|
1701
1777
|
permissions:
|
|
1702
1778
|
# Lets the release step push the version tag nx release creates back to main,
|
|
1703
1779
|
# and (github-only provider) create the GitHub Release itself.
|
|
@@ -1721,6 +1797,11 @@ jobs:
|
|
|
1721
1797
|
- uses: actions/setup-node@v4
|
|
1722
1798
|
with:
|
|
1723
1799
|
node-version: 24
|
|
1800
|
+
# Caches ~/.npm keyed on package-lock.json, so \`npm ci\` restores from
|
|
1801
|
+
# the local cache instead of re-downloading every tarball on every run.
|
|
1802
|
+
# Nothing to invalidate by hand: the action keys on the lockfile, so a
|
|
1803
|
+
# dependency change misses the cache and a no-op change hits it.
|
|
1804
|
+
cache: npm
|
|
1724
1805
|
|
|
1725
1806
|
- run: npm ci
|
|
1726
1807
|
name: Install dependencies
|