@mnci/cli 1.7.0 → 1.8.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 +140 -87
- package/dist/cli.js +735 -237
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
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
|
|
@@ -306,7 +304,7 @@ the root `.npmrc`'s `_password` block — the PAT value never lands in a file.
|
|
|
306
304
|
No `npmAuthenticate@0` task (it would overwrite the hand-set password).
|
|
307
305
|
|
|
308
306
|
On Azure, two one-time grants are required (project admin): **Contribute** on
|
|
309
|
-
the repo for the
|
|
307
|
+
the repo for the _Project Collection Build Service_ account (tag push), and
|
|
310
308
|
**publish** rights on the feed for the PAT's owner. On GitHub, the workflow's
|
|
311
309
|
`permissions: contents: write` is what lets its own checkout token push the
|
|
312
310
|
release tag — no separate grant, but the job still needs that permission
|
|
@@ -321,7 +319,7 @@ to feed" instructions give you. npm's `.npmrc` `_password` field expects
|
|
|
321
319
|
exactly that pre-encoded form, so it's used as-is. `twine`/pypi basic auth, by
|
|
322
320
|
contrast, wants the **raw** token — so the shared `releaseGuard` fragment
|
|
323
321
|
(`overlay.ts`, used by both `azurePipelinesYaml` and `githubActionsYaml`)
|
|
324
|
-
explicitly
|
|
322
|
+
explicitly _decodes_ the same `PAT`
|
|
325
323
|
(`Buffer.from(process.env.PAT, 'base64').toString()`) before handing it to
|
|
326
324
|
`TWINE_PASSWORD`. Both are correct for their protocol today, but it's an easy
|
|
327
325
|
trap to get backwards: if you ever wire a third registry protocol, check
|
|
@@ -356,7 +354,7 @@ hosting provider?" even with `--no-interactive` set, and exits without
|
|
|
356
354
|
creating the workspace at all when stdin isn't a TTY — a real
|
|
357
355
|
`create-nx-workspace` inconsistency, not something `mnci` can configure
|
|
358
356
|
around. The named-provider value sidesteps it and completes non-interactively
|
|
359
|
-
every time. The only visible effect of
|
|
357
|
+
every time. The only visible effect of _which_ named value is chosen is a
|
|
360
358
|
throwaway CI workflow file `create-nx-workspace` writes as a side effect of
|
|
361
359
|
Cloud setup — this CLI's own overlay unconditionally overwrites whatever
|
|
362
360
|
lands at that path immediately after, so the pipeline you actually get is
|
|
@@ -372,22 +370,17 @@ fix-ci`) — `mnci` does not automate that step.
|
|
|
372
370
|
Being upfront about what mnci leans on, so it's a conscious trade-off rather
|
|
373
371
|
than a surprise:
|
|
374
372
|
|
|
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.
|
|
373
|
+
- **One Nx plugin this project builds and maintains** carries the most weight:
|
|
374
|
+
**`@mnci/nx-python-pip`** — a real Nx plugin built into this monorepo itself
|
|
375
|
+
(`packages/nx-python-pip`), created because no maintained, Nx-23-compatible
|
|
376
|
+
Python plugin supports pip (the previous Python plugin, `@nxlv/python`,
|
|
377
|
+
requires `uv`, which the company standardizing on this tool does not use, and
|
|
378
|
+
no maintained alternative supports pip). This trades third-party risk for a
|
|
379
|
+
different, real one: **this project now owns a second package's maintenance
|
|
380
|
+
surface** (generators, executors, its own release cycle) — worth being
|
|
381
|
+
explicit about, since it did not exist before. Unlike official `@nx/*`
|
|
382
|
+
plugins, if this one needs fixes or updates, this project owns those directly.
|
|
383
|
+
That's the cost of having no maintained pip-native Nx plugin in the ecosystem.
|
|
391
384
|
- **The TS7 dual-compiler aliases pin a very new, fast-moving dependency.**
|
|
392
385
|
TypeScript 7's native compiler is recent; `TS_COMPILER_DEPENDENCIES` pins
|
|
393
386
|
`npm:typescript@^7.0.2` / `npm:@typescript/typescript6@^6.0.2` specifically
|
|
@@ -402,7 +395,7 @@ than a surprise:
|
|
|
402
395
|
- Azure Functions Core Tools is only needed for **local** `func start` — never
|
|
403
396
|
for `mnci add node-function-app`/`python-function-app` generation, since
|
|
404
397
|
neither shells out to the `func` CLI.
|
|
405
|
-
- Function-app
|
|
398
|
+
- Function-app _deployment_ (e.g. `AzureFunctionApp@2`) is not wired into the
|
|
406
399
|
pipeline; the `node-function-app-<name>.zip`/`python-function-app-<name>.zip`
|
|
407
400
|
inside the published `drop` artifact is the deploy input. Deploying it means
|
|
408
401
|
Azure's Oryx build installing real dependencies (`npm install`/`pip install`)
|
|
@@ -548,25 +541,25 @@ Windows (the standard python.org Windows installer registers no
|
|
|
548
541
|
hard-coded name, so a `windows-latest` (or self-hosted Windows) agent works
|
|
549
542
|
identically to a Linux/macOS one.
|
|
550
543
|
|
|
551
|
-
| Kind
|
|
552
|
-
|
|
|
553
|
-
| `python-app`
|
|
554
|
-
| `python-function-app` | `apps/<name>`
|
|
555
|
-
| `python-lib`
|
|
556
|
-
| `python-internal-lib` | `libs/<name>`
|
|
544
|
+
| Kind | Location | Build / deploy |
|
|
545
|
+
| --------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
546
|
+
| `python-app` | `apps/<name>` | `python -m build` wheel (the plugin's `build` executor), zipped by mnci into `dist/drop/python-app-<name>.zip` |
|
|
547
|
+
| `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) |
|
|
548
|
+
| `python-lib` | `python-packages/<name>` | publishable wheel; the plugin's `publish` executor (`twine upload --skip-existing`) |
|
|
549
|
+
| `python-internal-lib` | `libs/<name>` | private shared code, lint + test only — no build/package target of its own |
|
|
557
550
|
|
|
558
551
|
- **Apps** get a `package` target — mnci's own CI packaging convention, not
|
|
559
552
|
a generic plugin concern — merged into the plugin-written `project.json`
|
|
560
553
|
after generation, fitting the existing CI unchanged: the pipeline's
|
|
561
554
|
`apps/*` pack step tags them `python-app-<name>` / `python-function-app-
|
|
562
|
-
|
|
555
|
+
<name>` just like the TS apps.
|
|
563
556
|
- **Internal-lib vendoring** replaces `@nxlv/python`'s `bundleLocalDependencies`:
|
|
564
557
|
plain pip has no bundled-local-dependency feature, so a project that imports
|
|
565
558
|
a workspace-internal Python library needs a `vendor` entry (under
|
|
566
559
|
`[tool.mnci-python-pip]`) in its own `pyproject.toml` (the pip-world
|
|
567
560
|
counterpart of a `dependencies = [...]` entry — neither mnci nor the plugin
|
|
568
561
|
wires cross-project Python dependencies automatically). `mnci add
|
|
569
|
-
|
|
562
|
+
python-vendor <consumer> --lib <name>` automates writing that entry —
|
|
570
563
|
idempotent (safe to run twice), and works on any consumer with a
|
|
571
564
|
`pyproject.toml` (app, publishable lib, or another internal lib), not just
|
|
572
565
|
apps. The plugin's `build` executor reads the entry, resolves the named
|
|
@@ -600,7 +593,7 @@ identically to a Linux/macOS one.
|
|
|
600
593
|
`release.version.versionActions` override pointing at
|
|
601
594
|
`@mnci/nx-python-pip/release/version-actions` (a `VersionActions`
|
|
602
595
|
implementation — six methods, verified empirically against a real `nx
|
|
603
|
-
|
|
596
|
+
release version --dry-run`), which wins over the workspace's default
|
|
604
597
|
(npm's) `versionActions` for that one project. **Publishing** reuses the
|
|
605
598
|
registry: an Azure Artifacts feed is **multi-protocol**, so the same
|
|
606
599
|
org/project/feed serves Python — the release step exports `TWINE_*` (URL +
|
|
@@ -609,8 +602,68 @@ identically to a Linux/macOS one.
|
|
|
609
602
|
Python package is still versioned + tagged, but publishing it needs
|
|
610
603
|
user-provided `TWINE_*` — e.g. a PyPI token.)
|
|
611
604
|
- **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
|
|
605
|
+
target runs alongside the JS ESLint build. One guarded pipeline step installs
|
|
614
606
|
`requirements-dev.txt` first (the fixed toolchain), then a second installs
|
|
615
607
|
every Python project workspace-wide (the workspace-wide install above) —
|
|
616
608
|
both skipped cleanly when the workspace has no Python projects.
|
|
609
|
+
|
|
610
|
+
## Go (`@nx-go/nx-go` — one root `go.mod`, golangci-lint + `go test`)
|
|
611
|
+
|
|
612
|
+
Requires **Go 1.21+** on the machine and on the build agent; `mnci add go-*`
|
|
613
|
+
fails fast with an install link when `go` is not on the `PATH`. The generated
|
|
614
|
+
pipeline installs `golangci-lint` itself (see below).
|
|
615
|
+
|
|
616
|
+
| Kind | Location | Build / deploy |
|
|
617
|
+
| ----------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
618
|
+
| `go-app` | `apps/<name>` | `go build` binary into `dist/apps/<name>/`, zipped by mnci into `dist/drop/go-app-<name>.zip` |
|
|
619
|
+
| `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 |
|
|
620
|
+
| `go-lib` | `packages/<name>` | publishable **by git tag** — see below; lint + test targets only |
|
|
621
|
+
| `go-internal-lib` | `libs/<name>` | private shared code, lint + test only — a non-`main` package produces no binary |
|
|
622
|
+
|
|
623
|
+
- **One root `go.mod`**, matching how TS uses one root `package.json` and
|
|
624
|
+
Python one root `requirements-dev.txt`. `add/go.ts` bootstraps it on the
|
|
625
|
+
first Go `add` by running the plugin's `init` then `convert-to-one-mod`
|
|
626
|
+
generators, in that order — `convert-to-one-mod` refuses once `go.work`
|
|
627
|
+
lists any module, so it has to happen before the first Go project exists.
|
|
628
|
+
Every Go project then shares that module and imports its siblings as
|
|
629
|
+
`<module>/libs/<name>`, with no per-project manifests and no `replace`
|
|
630
|
+
directives.
|
|
631
|
+
- **The `go.work` multi-module layout was rejected deliberately.** Besides
|
|
632
|
+
splitting dependencies across per-project manifests, it is brittle: a
|
|
633
|
+
single stale `use` entry — a project directory removed by hand — makes
|
|
634
|
+
`go list -m -json` fail, and that breaks the **entire** Nx project graph,
|
|
635
|
+
not just the Go projects. Verified empirically.
|
|
636
|
+
- **Targets are written explicitly** rather than inferred. `@nx-go/nx-go`
|
|
637
|
+
supplies `build`/`test`/`lint` by inference, but keys that inference on a
|
|
638
|
+
per-project `go.mod` — which single-module mode does not have, so nothing
|
|
639
|
+
is inferred. mnci writes them into `project.json` instead, as it already
|
|
640
|
+
does for most kinds.
|
|
641
|
+
- **Lint is `golangci-lint`, pinned deliberately.** The plugin's `lint`
|
|
642
|
+
executor defaults to `go fmt`, which only reformats — a green lint step
|
|
643
|
+
with that default would mean nothing. The generated target passes
|
|
644
|
+
`linter: golangci-lint`, and `mnci add` warns (without failing) when the
|
|
645
|
+
binary is missing locally, since CI installs its own.
|
|
646
|
+
- **Publishing a `go-lib` is a git tag, not a registry upload.** The whole
|
|
647
|
+
repository is one module, so consumers depend on a library by import path
|
|
648
|
+
at a repo-level version tag — `go get <module>/packages/<name>@v1.2.3`.
|
|
649
|
+
That tag is the one `nx release` already creates, so no
|
|
650
|
+
`nx-release-publish` target is written: there is nothing to push. The only
|
|
651
|
+
real difference between `go-lib` and `go-internal-lib` is intent, recorded
|
|
652
|
+
in the `type:go-lib` tag and the `packages/` location.
|
|
653
|
+
- **No publish-time dependency injection**, unlike Python's vendoring: `go
|
|
654
|
+
build` links statically, so the binary in the drop already contains
|
|
655
|
+
everything it needs.
|
|
656
|
+
- **Build output is a directory**, `dist/apps/<name>/`, with the binary
|
|
657
|
+
inside it. The executor's own default writes a bare file at
|
|
658
|
+
`dist/apps/<name>`, which cannot be declared as an Nx `outputs` entry —
|
|
659
|
+
Nx scans each declared output to cache it, and scanning a file fails with
|
|
660
|
+
`ENOTDIR`. Building one level deeper keeps the root-`dist` convention and
|
|
661
|
+
makes the target cacheable.
|
|
662
|
+
- **CI** runs Go through the same `nx run-many -t lint,test,build` as
|
|
663
|
+
everything else. Two guarded steps precede it: `go mod download` (so a
|
|
664
|
+
network failure reads as a dependency failure rather than a confusing
|
|
665
|
+
build error), and a `golangci-lint` install via `go install` — no package
|
|
666
|
+
manager, no sudo, same command on every agent OS — whose `GOPATH/bin` is
|
|
667
|
+
then added to `PATH` for later steps. All three skip cleanly when the
|
|
668
|
+
workspace has no root `go.mod`, and the linter install also skips when the
|
|
669
|
+
agent already provides it.
|