@mnci/cli 1.7.0 → 1.9.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 +157 -90
- package/dist/cli.js +780 -265
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -15,14 +15,14 @@ config package, a custom CI engine, a dependency-injection step for published
|
|
|
15
15
|
packages, a doctor/drift-sync system to keep it all consistent — already has a
|
|
16
16
|
first-party (or established community) Nx equivalent:
|
|
17
17
|
|
|
18
|
-
| Hand-rolled elsewhere
|
|
19
|
-
|
|
|
20
|
-
| Template engine + per-project config files
|
|
21
|
-
| A shared toolchain package for configs
|
|
22
|
-
| A custom multi-step CI engine
|
|
23
|
-
| A dist-package dependency injector
|
|
24
|
-
| Hand-written Azure Function templates
|
|
25
|
-
| doctor/drift sync of tool-owned files
|
|
18
|
+
| Hand-rolled elsewhere | This CLI uses instead |
|
|
19
|
+
| ------------------------------------------ | --------------------------------------------------------------------------- |
|
|
20
|
+
| Template engine + per-project config files | `create-nx-workspace --preset=ts` + `nx g` plugin generators |
|
|
21
|
+
| A shared toolchain package for configs | The configs the Nx generators emit (one root ESLint/tsconfig) |
|
|
22
|
+
| A custom multi-step CI engine | `nx affected -t lint,test,build` + `nx release` (~60-line pipeline) |
|
|
23
|
+
| A dist-package dependency injector | `nx release` updates dependent versions natively |
|
|
24
|
+
| Hand-written Azure Function templates | `@nx/node:application` (plain Node app) + a thin Azure Functions v4 overlay |
|
|
25
|
+
| doctor/drift sync of tool-owned files | Nothing to drift: this CLI owns 5 small files, Nx owns the rest |
|
|
26
26
|
|
|
27
27
|
## Commands (deliberately just three)
|
|
28
28
|
|
|
@@ -46,6 +46,12 @@ mnci add python-lib shared # publishable -> python-packages/ (twine uplo
|
|
|
46
46
|
mnci add python-internal-lib core # private shared lib -> libs/
|
|
47
47
|
mnci add python-vendor shared --lib core # wire core's module into shared's built wheel
|
|
48
48
|
|
|
49
|
+
# Go (@nx-go/nx-go — one root go.mod, golangci-lint + go test)
|
|
50
|
+
mnci add go-app api # executable -> apps/ (binary, zipped into the drop)
|
|
51
|
+
mnci add go-function-app fn # serverless handler -> apps/
|
|
52
|
+
mnci add go-lib core # publishable (by git tag) -> packages/
|
|
53
|
+
mnci add go-internal-lib util # private shared package -> libs/
|
|
54
|
+
|
|
49
55
|
mnci upgrade # re-apply the latest overlay (see below)
|
|
50
56
|
mnci upgrade --agent windows-latest # ...with an explicit override
|
|
51
57
|
```
|
|
@@ -53,16 +59,16 @@ mnci upgrade --agent windows-latest # ...with an explicit override
|
|
|
53
59
|
Everything else is plain Nx, surfaced as a small curated set of root scripts —
|
|
54
60
|
each a single cross-platform command:
|
|
55
61
|
|
|
56
|
-
| Script
|
|
57
|
-
|
|
|
58
|
-
| `npm run build`
|
|
59
|
-
| `npm run lint`
|
|
60
|
-
| `npm run test`
|
|
61
|
-
| `npm run affected`
|
|
62
|
-
| `npm run graph`
|
|
63
|
-
| `npm run release:preview` | `nx release --dry-run`
|
|
64
|
-
| `npm run python:install`
|
|
65
|
-
| `prepare`
|
|
62
|
+
| Script | Runs |
|
|
63
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
64
|
+
| `npm run build` | `nx run-many -t build` |
|
|
65
|
+
| `npm run lint` | `nx run-many -t lint` |
|
|
66
|
+
| `npm run test` | `nx run-many -t test` |
|
|
67
|
+
| `npm run affected` | `nx affected -t lint,test,build` (vs `main`) |
|
|
68
|
+
| `npm run graph` | `nx graph` |
|
|
69
|
+
| `npm run release:preview` | `nx release --dry-run` |
|
|
70
|
+
| `npm run python:install` | fixed Python toolchain (ruff/pytest/build/twine) + editable-install every Python project — the same two guards CI runs, for local dev |
|
|
71
|
+
| `prepare` | `husky` (commit-msg lint hook) |
|
|
66
72
|
|
|
67
73
|
## What `new` actually does
|
|
68
74
|
|
|
@@ -78,14 +84,17 @@ each a single cross-platform command:
|
|
|
78
84
|
`commit-msg` hook, the chosen CI provider's pipeline file(s)
|
|
79
85
|
(`azure-pipelines.yml` and/or `.github/workflows/ci.yml`, `--ci`, default
|
|
80
86
|
`azure`; `github`/`both` also gets `.github/dependabot.yml` — weekly
|
|
81
|
-
dependency-update PRs),
|
|
87
|
+
dependency-update PRs), a `<workspace-name>.code-workspace` file (VS Code
|
|
88
|
+
workspace configuration with folder structure, ESLint/Prettier settings, and
|
|
89
|
+
recommended extensions — open it in VS Code via `File > Open Workspace from
|
|
90
|
+
File`), and the curated root scripts.
|
|
82
91
|
4. Installs the chosen **stack** (see below), `husky` + `@commitlint/*` for
|
|
83
92
|
real, so versions resolve at generation time.
|
|
84
93
|
|
|
85
94
|
## `mnci upgrade`: re-applying the overlay to an existing workspace
|
|
86
95
|
|
|
87
96
|
Every fix to `overlay.ts` — a release-config correction, a CI guard rewritten,
|
|
88
|
-
a new Windows code path — only ever reached
|
|
97
|
+
a new Windows code path — only ever reached _future_ `mnci new` calls until
|
|
89
98
|
this existed; nothing let an already-generated workspace pick one up.
|
|
90
99
|
`mnci upgrade`, run from the workspace root, closes that gap: it resolves the
|
|
91
100
|
same options `new` would have and calls the exact same `applyOverlay` `new`
|
|
@@ -120,16 +129,23 @@ will overwrite hand customizations to any of the files it owns (e.g. an extra
|
|
|
120
129
|
CI job appended by hand to the pipeline file) — `git diff` is exactly how
|
|
121
130
|
you'd notice and re-apply those on top.
|
|
122
131
|
|
|
123
|
-
## Stack:
|
|
132
|
+
## Stack: one choice asked up front
|
|
133
|
+
|
|
134
|
+
`mnci new` (run bare, or with flags) asks one question — the test runner. It is
|
|
135
|
+
stored where every later `mnci add` honours it, so the whole workspace stays one
|
|
136
|
+
stack:
|
|
124
137
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
| Question | Options | Default | Stored as / honoured via |
|
|
139
|
+
| --------------- | ------------------ | ------- | ---------------------------------------------------------------------------------------- |
|
|
140
|
+
| `--test-runner` | `jest` \| `vitest` | `jest` | `nx.json` generator `unitTestRunner` default; the hand-built function app follows it too |
|
|
128
141
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
**Linting and formatting are unified across the workspace**: every project uses
|
|
143
|
+
**ESLint + Prettier** with the JavaScript Standard Style configuration (no
|
|
144
|
+
semicolons, single quotes, 2-space indents). ESLint is a per-project Nx target
|
|
145
|
+
handling code quality (correctness only), while Prettier handles all formatting.
|
|
146
|
+
Both are automatically configured; `npm run lint` checks code quality, `npm run
|
|
147
|
+
format` (write) and `npm run format:check` (CI-safe) handle formatting. The CI
|
|
148
|
+
runs lint/test/build only — formatting is left as a local/pre-commit step.
|
|
133
149
|
|
|
134
150
|
TypeScript is not a question — every workspace runs the **dual compiler** from
|
|
135
151
|
[Nx's TS 7 guide](https://nx.dev/docs/technologies/typescript/guides/typescript-7):
|
|
@@ -141,35 +157,17 @@ analysing config through the TS 6 API — no target rewiring, frozen per repo by
|
|
|
141
157
|
the lockfile. (A plain `typescript@7` install would break Nx, since TS 7 ships
|
|
142
158
|
no programmatic API yet; the two aliases are what make it work.)
|
|
143
159
|
|
|
144
|
-
- **Linter**: ESLint is a per-project Nx target; oxlint is a single
|
|
145
|
-
workspace-wide binary. Either way `npm run lint` (and the CI) is
|
|
146
|
-
linter-agnostic, so nothing downstream branches. Under oxlint a publishable
|
|
147
|
-
package's private-lib import needs no dependency-check override (that rule is
|
|
148
|
-
ESLint-only), so none is written.
|
|
149
|
-
- The oxlint stack installs **[oxc-standard](https://github.com/JohnDeved/ox-standard)**
|
|
150
|
-
(which brings `oxlint` + `oxfmt`) and generates two `.mts` configs that use
|
|
151
|
-
its **JavaScript Standard Style** preset: `oxlint.config.mts` *extends*
|
|
152
|
-
`oxc-standard`'s rule set (unicorn + React + react-perf + TypeScript + oxc),
|
|
153
|
-
and `oxfmt.config.mts` mirrors its formatting (no semicolons, single quotes,
|
|
154
|
-
2-space, `es5` trailing commas, avoid arrow parens). That gives the full
|
|
155
|
-
Standard experience — **linting *and* formatting** — since oxlint (a linter)
|
|
156
|
-
does not enforce layout.
|
|
157
|
-
- Formatting is `npm run format` (write) and `npm run format:check` (CI-safe,
|
|
158
|
-
no writes). Nx generators emit semicolon/double-quote code, so run
|
|
159
|
-
`npm run format` once after scaffolding to normalise a new workspace to
|
|
160
|
-
Standard Style. (CI stays lint/test/build only — formatting is left as a
|
|
161
|
-
local/pre-commit step so the pipeline needs no linter-specific branch.)
|
|
162
160
|
- **Test runner**: passed straight to the `@nx/*` generators; the function app
|
|
163
161
|
gets a matching `jest.config.mjs` (+ ts-jest) or `vitest.config.ts`.
|
|
164
162
|
|
|
165
163
|
## Layout convention = release scoping
|
|
166
164
|
|
|
167
|
-
| Directory | Contents
|
|
168
|
-
| ------------------ |
|
|
169
|
-
| `apps/` | React / Node / Python apps (plain or Azure Functions) | Never (packed into the drop)
|
|
170
|
-
| `packages/` | Publishable npm libraries (rollup-bundled)
|
|
171
|
-
| `python-packages/` | Publishable Python packages (hatchling wheels)
|
|
172
|
-
| `libs/` | Internal libraries (TS or Python), never published
|
|
165
|
+
| Directory | Contents | Released? |
|
|
166
|
+
| ------------------ | ----------------------------------------------------- | -------------------------------------- |
|
|
167
|
+
| `apps/` | React / Node / Python apps (plain or Azure Functions) | Never (packed into the drop) |
|
|
168
|
+
| `packages/` | Publishable npm libraries (rollup-bundled) | Yes — `nx release`, per-package tags |
|
|
169
|
+
| `python-packages/` | Publishable Python packages (hatchling wheels) | Yes — `twine upload` (Azure Artifacts) |
|
|
170
|
+
| `libs/` | Internal libraries (TS or Python), never published | Never |
|
|
173
171
|
|
|
174
172
|
No custom tags, no stamp file — the directory (and, for npm, the `private` flag)
|
|
175
173
|
are the whole model. Publishable Python packages get their own
|
|
@@ -223,13 +221,13 @@ file to add a new cross-project import** later (nothing about that is an
|
|
|
223
221
|
`mnci add`, so that step can't catch it). For that case every generated
|
|
224
222
|
workspace sets `sync.applyChanges: true` in `nx.json`: `--preset=ts` already
|
|
225
223
|
registers the `@nx/js:typescript-sync` generator on the `build`/`typecheck`
|
|
226
|
-
targets, so instead of just
|
|
224
|
+
targets, so instead of just _prompting_ ("Would you like to sync the
|
|
227
225
|
identified changes?") on your next `nx build`/`typecheck`/`affected`, Nx fixes
|
|
228
226
|
the references **automatically** — no prompt, no manual `npx nx sync`. A
|
|
229
227
|
brand-new package may still need one VSCode window reload to be picked up by
|
|
230
228
|
the TypeScript server.
|
|
231
229
|
|
|
232
|
-
`applyChanges` only affects
|
|
230
|
+
`applyChanges` only affects _interactive_ runs, by design: CI always runs sync
|
|
233
231
|
generators in dry-run mode and fails instead of silently patching an ephemeral
|
|
234
232
|
checkout that never gets committed. That's what the pipeline's `nx sync:check`
|
|
235
233
|
step (below) surfaces early — if it fails, run `npx nx sync` locally and
|
|
@@ -261,7 +259,7 @@ Every run (PR and main) installs dependencies, then runs `npm audit`
|
|
|
261
259
|
(also non-blocking) — visibility, not enforcement: verified empirically that
|
|
262
260
|
a real `npm audit` on this monorepo's own tree flagged nothing but
|
|
263
261
|
already-latest upstream packages (`nx`, `verdaccio`) bundling their own not-
|
|
264
|
-
yet-patched transitive dependencies, nothing an edit to
|
|
262
|
+
yet-patched transitive dependencies, nothing an edit to _this_ workspace's
|
|
265
263
|
manifest could fix. A hard-failing audit step would turn CI red for a
|
|
266
264
|
problem with no user-actionable fix, for as long as upstream took to patch
|
|
267
265
|
it — so both steps always exit 0 regardless of findings, surfacing results
|
|
@@ -279,7 +277,7 @@ lint,test,build`. Pushes to `main` then:
|
|
|
279
277
|
`dist/drop/<type>-<name>.zip` (e.g. `node-function-app-api.zip`,
|
|
280
278
|
`react-app-web.zip`); the whole `dist/drop` is published as the **`drop`**
|
|
281
279
|
artifact.
|
|
282
|
-
- **Tag the run per app**
|
|
280
|
+
- **Tag the run per app** _(Azure only)_ — one build tag per zip, **exactly**
|
|
283
281
|
`<type>-<name>` (derived from the zip filenames, so the tag can never drift
|
|
284
282
|
from the artifact). A classic Azure release/CD pipeline keys its trigger off
|
|
285
283
|
these; GitHub Actions has no equivalent mechanism, so the `drop` artifact
|
|
@@ -293,7 +291,16 @@ lint,test,build`. Pushes to `main` then:
|
|
|
293
291
|
the raw token twine needs for the Python publish. Skipped cleanly when there
|
|
294
292
|
is nothing to release. A guarded step installs the fixed Python toolchain
|
|
295
293
|
(`ruff`/`pytest`/`build`/`twine`/`pip-audit`) before any Python target runs,
|
|
296
|
-
skipped cleanly on a workspace with no Python projects.
|
|
294
|
+
skipped cleanly on a workspace with no Python projects. On a `--ci=github`
|
|
295
|
+
workspace this same step also creates a **GitHub Release per project**, with
|
|
296
|
+
a changelog Nx generates from conventional commits — `nx release` pushes the
|
|
297
|
+
tag itself here (needs `GITHUB_TOKEN`, which GitHub Actions provides for
|
|
298
|
+
free under the workflow's own `contents: write` permission), so there's no
|
|
299
|
+
separate explicit `git push origin --tags` step on this provider. `--ci=azure`
|
|
300
|
+
and `--ci=both` keep today's behaviour (no GitHub Release, explicit tag
|
|
301
|
+
push) — GitHub Release creation only turns on when GitHub Actions is the
|
|
302
|
+
*only* configured provider, since that's the one case a `GITHUB_TOKEN` is
|
|
303
|
+
guaranteed to exist.
|
|
297
304
|
|
|
298
305
|
**npm auth** is the base64 `PAT`, read the same way on both providers but from
|
|
299
306
|
a different place: on Azure Pipelines, a **variable group**
|
|
@@ -306,7 +313,7 @@ the root `.npmrc`'s `_password` block — the PAT value never lands in a file.
|
|
|
306
313
|
No `npmAuthenticate@0` task (it would overwrite the hand-set password).
|
|
307
314
|
|
|
308
315
|
On Azure, two one-time grants are required (project admin): **Contribute** on
|
|
309
|
-
the repo for the
|
|
316
|
+
the repo for the _Project Collection Build Service_ account (tag push), and
|
|
310
317
|
**publish** rights on the feed for the PAT's owner. On GitHub, the workflow's
|
|
311
318
|
`permissions: contents: write` is what lets its own checkout token push the
|
|
312
319
|
release tag — no separate grant, but the job still needs that permission
|
|
@@ -321,7 +328,7 @@ to feed" instructions give you. npm's `.npmrc` `_password` field expects
|
|
|
321
328
|
exactly that pre-encoded form, so it's used as-is. `twine`/pypi basic auth, by
|
|
322
329
|
contrast, wants the **raw** token — so the shared `releaseGuard` fragment
|
|
323
330
|
(`overlay.ts`, used by both `azurePipelinesYaml` and `githubActionsYaml`)
|
|
324
|
-
explicitly
|
|
331
|
+
explicitly _decodes_ the same `PAT`
|
|
325
332
|
(`Buffer.from(process.env.PAT, 'base64').toString()`) before handing it to
|
|
326
333
|
`TWINE_PASSWORD`. Both are correct for their protocol today, but it's an easy
|
|
327
334
|
trap to get backwards: if you ever wire a third registry protocol, check
|
|
@@ -356,7 +363,7 @@ hosting provider?" even with `--no-interactive` set, and exits without
|
|
|
356
363
|
creating the workspace at all when stdin isn't a TTY — a real
|
|
357
364
|
`create-nx-workspace` inconsistency, not something `mnci` can configure
|
|
358
365
|
around. The named-provider value sidesteps it and completes non-interactively
|
|
359
|
-
every time. The only visible effect of
|
|
366
|
+
every time. The only visible effect of _which_ named value is chosen is a
|
|
360
367
|
throwaway CI workflow file `create-nx-workspace` writes as a side effect of
|
|
361
368
|
Cloud setup — this CLI's own overlay unconditionally overwrites whatever
|
|
362
369
|
lands at that path immediately after, so the pipeline you actually get is
|
|
@@ -372,22 +379,17 @@ fix-ci`) — `mnci` does not automate that step.
|
|
|
372
379
|
Being upfront about what mnci leans on, so it's a conscious trade-off rather
|
|
373
380
|
than a surprise:
|
|
374
381
|
|
|
375
|
-
- **One
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
for a different, real one: **this project now owns a second package's
|
|
387
|
-
maintenance surface** (generators, executors, its own release cycle) —
|
|
388
|
-
worth being explicit about, since it did not exist before this migration.
|
|
389
|
-
If `oxc-standard` stalls or breaks compatibility with a future Nx major,
|
|
390
|
-
that surface needs a real maintenance response, not just a version bump.
|
|
382
|
+
- **One Nx plugin this project builds and maintains** carries the most weight:
|
|
383
|
+
**`@mnci/nx-python-pip`** — a real Nx plugin built into this monorepo itself
|
|
384
|
+
(`packages/nx-python-pip`), created because no maintained, Nx-23-compatible
|
|
385
|
+
Python plugin supports pip (the previous Python plugin, `@nxlv/python`,
|
|
386
|
+
requires `uv`, which the company standardizing on this tool does not use, and
|
|
387
|
+
no maintained alternative supports pip). This trades third-party risk for a
|
|
388
|
+
different, real one: **this project now owns a second package's maintenance
|
|
389
|
+
surface** (generators, executors, its own release cycle) — worth being
|
|
390
|
+
explicit about, since it did not exist before. Unlike official `@nx/*`
|
|
391
|
+
plugins, if this one needs fixes or updates, this project owns those directly.
|
|
392
|
+
That's the cost of having no maintained pip-native Nx plugin in the ecosystem.
|
|
391
393
|
- **The TS7 dual-compiler aliases pin a very new, fast-moving dependency.**
|
|
392
394
|
TypeScript 7's native compiler is recent; `TS_COMPILER_DEPENDENCIES` pins
|
|
393
395
|
`npm:typescript@^7.0.2` / `npm:@typescript/typescript6@^6.0.2` specifically
|
|
@@ -402,13 +404,18 @@ than a surprise:
|
|
|
402
404
|
- Azure Functions Core Tools is only needed for **local** `func start` — never
|
|
403
405
|
for `mnci add node-function-app`/`python-function-app` generation, since
|
|
404
406
|
neither shells out to the `func` CLI.
|
|
405
|
-
- Function-app
|
|
407
|
+
- Function-app _deployment_ (e.g. `AzureFunctionApp@2`) is not wired into the
|
|
406
408
|
pipeline; the `node-function-app-<name>.zip`/`python-function-app-<name>.zip`
|
|
407
409
|
inside the published `drop` artifact is the deploy input. Deploying it means
|
|
408
410
|
Azure's Oryx build installing real dependencies (`npm install`/`pip install`)
|
|
409
411
|
from the zipped manifest — no `node_modules`/venv is bundled.
|
|
410
|
-
- Changelog files are off (unpushable under the tag-only
|
|
411
|
-
|
|
412
|
+
- Changelog **files** are off everywhere (unpushable under the tag-only
|
|
413
|
+
model — `git.commit` stays `false`, so a written `CHANGELOG.md` would just
|
|
414
|
+
be discarded at the end of every CI run). On a `--ci=github` workspace (and
|
|
415
|
+
only that one — see below) each release still gets a real changelog: Nx
|
|
416
|
+
generates it from conventional commits and posts it straight to a GitHub
|
|
417
|
+
Release, with no file ever touched. `--ci=azure` and `--ci=both` fall back
|
|
418
|
+
to the git tag history as the changelog, same as before.
|
|
412
419
|
- **No lock file for Python** — plain pip has none, matching the company
|
|
413
420
|
standard this migration was for. A published wheel's `Requires-Dist` mirrors
|
|
414
421
|
whatever specifier the `pyproject.toml` declares (e.g. `tomli>=2.0.0`)
|
|
@@ -548,25 +555,25 @@ Windows (the standard python.org Windows installer registers no
|
|
|
548
555
|
hard-coded name, so a `windows-latest` (or self-hosted Windows) agent works
|
|
549
556
|
identically to a Linux/macOS one.
|
|
550
557
|
|
|
551
|
-
| Kind
|
|
552
|
-
|
|
|
553
|
-
| `python-app`
|
|
554
|
-
| `python-function-app` | `apps/<name>`
|
|
555
|
-
| `python-lib`
|
|
556
|
-
| `python-internal-lib` | `libs/<name>`
|
|
558
|
+
| Kind | Location | Build / deploy |
|
|
559
|
+
| --------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
560
|
+
| `python-app` | `apps/<name>` | `python -m build` wheel (the plugin's `build` executor), zipped by mnci into `dist/drop/python-app-<name>.zip` |
|
|
561
|
+
| `python-function-app` | `apps/<name>` | Azure Functions **v2** (`function_app.py` + `host.json` + `requirements.txt`); no `pyproject.toml`/wheel — the **source** is zipped by mnci into `dist/drop/python-function-app-<name>.zip` (no `func` CLI needed to generate) |
|
|
562
|
+
| `python-lib` | `python-packages/<name>` | publishable wheel; the plugin's `publish` executor (`twine upload --skip-existing`) |
|
|
563
|
+
| `python-internal-lib` | `libs/<name>` | private shared code, lint + test only — no build/package target of its own |
|
|
557
564
|
|
|
558
565
|
- **Apps** get a `package` target — mnci's own CI packaging convention, not
|
|
559
566
|
a generic plugin concern — merged into the plugin-written `project.json`
|
|
560
567
|
after generation, fitting the existing CI unchanged: the pipeline's
|
|
561
568
|
`apps/*` pack step tags them `python-app-<name>` / `python-function-app-
|
|
562
|
-
|
|
569
|
+
<name>` just like the TS apps.
|
|
563
570
|
- **Internal-lib vendoring** replaces `@nxlv/python`'s `bundleLocalDependencies`:
|
|
564
571
|
plain pip has no bundled-local-dependency feature, so a project that imports
|
|
565
572
|
a workspace-internal Python library needs a `vendor` entry (under
|
|
566
573
|
`[tool.mnci-python-pip]`) in its own `pyproject.toml` (the pip-world
|
|
567
574
|
counterpart of a `dependencies = [...]` entry — neither mnci nor the plugin
|
|
568
575
|
wires cross-project Python dependencies automatically). `mnci add
|
|
569
|
-
|
|
576
|
+
python-vendor <consumer> --lib <name>` automates writing that entry —
|
|
570
577
|
idempotent (safe to run twice), and works on any consumer with a
|
|
571
578
|
`pyproject.toml` (app, publishable lib, or another internal lib), not just
|
|
572
579
|
apps. The plugin's `build` executor reads the entry, resolves the named
|
|
@@ -600,7 +607,7 @@ identically to a Linux/macOS one.
|
|
|
600
607
|
`release.version.versionActions` override pointing at
|
|
601
608
|
`@mnci/nx-python-pip/release/version-actions` (a `VersionActions`
|
|
602
609
|
implementation — six methods, verified empirically against a real `nx
|
|
603
|
-
|
|
610
|
+
release version --dry-run`), which wins over the workspace's default
|
|
604
611
|
(npm's) `versionActions` for that one project. **Publishing** reuses the
|
|
605
612
|
registry: an Azure Artifacts feed is **multi-protocol**, so the same
|
|
606
613
|
org/project/feed serves Python — the release step exports `TWINE_*` (URL +
|
|
@@ -609,8 +616,68 @@ identically to a Linux/macOS one.
|
|
|
609
616
|
Python package is still versioned + tagged, but publishing it needs
|
|
610
617
|
user-provided `TWINE_*` — e.g. a PyPI token.)
|
|
611
618
|
- **CI** also runs `nx run-many -t lint,test,build`, so Python's ruff `lint`
|
|
612
|
-
target runs alongside the JS build
|
|
613
|
-
`npm run lint` only covers JS). One guarded pipeline step installs
|
|
619
|
+
target runs alongside the JS ESLint build. One guarded pipeline step installs
|
|
614
620
|
`requirements-dev.txt` first (the fixed toolchain), then a second installs
|
|
615
621
|
every Python project workspace-wide (the workspace-wide install above) —
|
|
616
622
|
both skipped cleanly when the workspace has no Python projects.
|
|
623
|
+
|
|
624
|
+
## Go (`@nx-go/nx-go` — one root `go.mod`, golangci-lint + `go test`)
|
|
625
|
+
|
|
626
|
+
Requires **Go 1.21+** on the machine and on the build agent; `mnci add go-*`
|
|
627
|
+
fails fast with an install link when `go` is not on the `PATH`. The generated
|
|
628
|
+
pipeline installs `golangci-lint` itself (see below).
|
|
629
|
+
|
|
630
|
+
| Kind | Location | Build / deploy |
|
|
631
|
+
| ----------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
632
|
+
| `go-app` | `apps/<name>` | `go build` binary into `dist/apps/<name>/`, zipped by mnci into `dist/drop/go-app-<name>.zip` |
|
|
633
|
+
| `go-function-app` | `apps/<name>` | same build; zipped into `dist/drop/go-function-app-<name>.zip`. The handler body is yours to write — AWS Lambda, Google Cloud Functions and Azure each want a different signature, and mnci does not pick one |
|
|
634
|
+
| `go-lib` | `packages/<name>` | publishable **by git tag** — see below; lint + test targets only |
|
|
635
|
+
| `go-internal-lib` | `libs/<name>` | private shared code, lint + test only — a non-`main` package produces no binary |
|
|
636
|
+
|
|
637
|
+
- **One root `go.mod`**, matching how TS uses one root `package.json` and
|
|
638
|
+
Python one root `requirements-dev.txt`. `add/go.ts` bootstraps it on the
|
|
639
|
+
first Go `add` by running the plugin's `init` then `convert-to-one-mod`
|
|
640
|
+
generators, in that order — `convert-to-one-mod` refuses once `go.work`
|
|
641
|
+
lists any module, so it has to happen before the first Go project exists.
|
|
642
|
+
Every Go project then shares that module and imports its siblings as
|
|
643
|
+
`<module>/libs/<name>`, with no per-project manifests and no `replace`
|
|
644
|
+
directives.
|
|
645
|
+
- **The `go.work` multi-module layout was rejected deliberately.** Besides
|
|
646
|
+
splitting dependencies across per-project manifests, it is brittle: a
|
|
647
|
+
single stale `use` entry — a project directory removed by hand — makes
|
|
648
|
+
`go list -m -json` fail, and that breaks the **entire** Nx project graph,
|
|
649
|
+
not just the Go projects. Verified empirically.
|
|
650
|
+
- **Targets are written explicitly** rather than inferred. `@nx-go/nx-go`
|
|
651
|
+
supplies `build`/`test`/`lint` by inference, but keys that inference on a
|
|
652
|
+
per-project `go.mod` — which single-module mode does not have, so nothing
|
|
653
|
+
is inferred. mnci writes them into `project.json` instead, as it already
|
|
654
|
+
does for most kinds.
|
|
655
|
+
- **Lint is `golangci-lint`, pinned deliberately.** The plugin's `lint`
|
|
656
|
+
executor defaults to `go fmt`, which only reformats — a green lint step
|
|
657
|
+
with that default would mean nothing. The generated target passes
|
|
658
|
+
`linter: golangci-lint`, and `mnci add` warns (without failing) when the
|
|
659
|
+
binary is missing locally, since CI installs its own.
|
|
660
|
+
- **Publishing a `go-lib` is a git tag, not a registry upload.** The whole
|
|
661
|
+
repository is one module, so consumers depend on a library by import path
|
|
662
|
+
at a repo-level version tag — `go get <module>/packages/<name>@v1.2.3`.
|
|
663
|
+
That tag is the one `nx release` already creates, so no
|
|
664
|
+
`nx-release-publish` target is written: there is nothing to push. The only
|
|
665
|
+
real difference between `go-lib` and `go-internal-lib` is intent, recorded
|
|
666
|
+
in the `type:go-lib` tag and the `packages/` location.
|
|
667
|
+
- **No publish-time dependency injection**, unlike Python's vendoring: `go
|
|
668
|
+
build` links statically, so the binary in the drop already contains
|
|
669
|
+
everything it needs.
|
|
670
|
+
- **Build output is a directory**, `dist/apps/<name>/`, with the binary
|
|
671
|
+
inside it. The executor's own default writes a bare file at
|
|
672
|
+
`dist/apps/<name>`, which cannot be declared as an Nx `outputs` entry —
|
|
673
|
+
Nx scans each declared output to cache it, and scanning a file fails with
|
|
674
|
+
`ENOTDIR`. Building one level deeper keeps the root-`dist` convention and
|
|
675
|
+
makes the target cacheable.
|
|
676
|
+
- **CI** runs Go through the same `nx run-many -t lint,test,build` as
|
|
677
|
+
everything else. Two guarded steps precede it: `go mod download` (so a
|
|
678
|
+
network failure reads as a dependency failure rather than a confusing
|
|
679
|
+
build error), and a `golangci-lint` install via `go install` — no package
|
|
680
|
+
manager, no sudo, same command on every agent OS — whose `GOPATH/bin` is
|
|
681
|
+
then added to `PATH` for later steps. All three skip cleanly when the
|
|
682
|
+
workspace has no root `go.mod`, and the linter install also skips when the
|
|
683
|
+
agent already provides it.
|