@inditextech/docouture-cli 0.1.0-SNAPSHOT.88.1 → 1.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/build/bin.js CHANGED
@@ -137,8 +137,9 @@ Example:
137
137
  docouture doctor [--dir <path>] [--json]
138
138
 
139
139
  Check that the environment and site configuration are healthy: Node
140
- version, the four names that must agree (component name, start page,
141
- content path, package name), git history, that antora is installed,
140
+ version, that the declared package manager (package.json's packageManager
141
+ field) is installed, the four names that must agree (component name, start
142
+ page, content path, package name), git history, that antora is installed,
142
143
  and (advisory only) whether AGENTS.md and the scaffolded skills are
143
144
  still present, whether the docs/release label exists, and whether the
144
145
  declared branching model (docs/package.json's docouture.branching)
@@ -161,6 +161,11 @@ export async function runBranchModel(argv) {
161
161
  // there is nothing meaningful to compute either from.
162
162
  componentName: 'unused-by-branch-model',
163
163
  cliVersion,
164
+ // .tool-versions (the only template file these two placeholders appear
165
+ // in) is never re-copied by branch-model — same reasoning as
166
+ // componentName above.
167
+ nodeVersion: 'unused-by-branch-model',
168
+ pnpmToolVersionsLine: 'unused-by-branch-model',
164
169
  pmName: pm.pm,
165
170
  pmCacheName: pm.cacheName,
166
171
  pmLockfile: pm.lockfile,
@@ -11,7 +11,7 @@ import { getContext } from '../lib/cli-context.js';
11
11
  import { theme } from '../lib/theme.js';
12
12
  import { readSourceUrl, readStartPageComponent, readStartPath } from '../lib/playbook-yml.js';
13
13
  import { detectBranches, inferBranching } from '../lib/branch-detect.js';
14
- import { checkAgentFilesPresent, checkAntoraAvailable, checkBranchingAgrees, checkGitHasCommit, checkNamesAgree, checkNodeVersion, checkReleaseLabelExists, } from '../lib/doctor-checks.js';
14
+ import { checkAgentFilesPresent, checkAntoraAvailable, checkBranchingAgrees, checkGitHasCommit, checkNamesAgree, checkNodeVersion, checkPackageManagerAvailable, checkReleaseLabelExists, } from '../lib/doctor-checks.js';
15
15
  async function readJson(file) {
16
16
  try {
17
17
  return JSON.parse(await readFile(file, 'utf8'));
@@ -82,6 +82,10 @@ export async function runDoctor(argv) {
82
82
  status |= record(report, 'toolchain', nodeResult, 'fail');
83
83
  if (!json)
84
84
  printResult(nodeResult);
85
+ const pmResult = await checkPackageManagerAvailable(pkg?.packageManager ?? null);
86
+ status |= record(report, 'toolchain', pmResult, 'fail');
87
+ if (!json)
88
+ printResult(pmResult);
85
89
  log('names');
86
90
  const playbookFile = join(siteRoot, 'antora-playbook.yml');
87
91
  const antoraYmlFile = join(siteRoot, 'src', 'antora.yml');
@@ -475,11 +475,20 @@ export async function runNew(argv, io = defaultIO()) {
475
475
  // it always matches whatever CLI actually generated it, snapshot/local
476
476
  // releases included.
477
477
  const { version: cliVersion } = await readCliInfo(import.meta.url, 2);
478
+ // Whatever Node is actually running this scaffold — same reasoning as
479
+ // cliVersion above (readCliInfo's own comment), just for the runtime
480
+ // rather than the CLI package. Written as .tool-versions' `nodejs` line.
481
+ const nodeVersion = process.version.replace(/^v/, '');
478
482
  // The user's own choice (--pm, wizard answer, or the auto-guess computed
479
483
  // above if neither was given) — never re-detected against `target`, so
480
484
  // whatever was actually chosen/confirmed is what the workflows and
481
485
  // printed next-steps agree on.
482
486
  const pm = packageManagerPlan(pmChoice);
487
+ // .tool-versions' second line — present only for a pnpm-scaffolded site
488
+ // (see TemplateValues.pnpmToolVersionsLine's own comment); pm.packageManagerField
489
+ // is already the corepack-convention 'pnpm@<version>' string, so this
490
+ // just reshapes it into asdf/mise's own 'pnpm <version>' line syntax.
491
+ const pnpmToolVersionsLine = pm.pm === 'pnpm' ? `pnpm ${pm.packageManagerField.split('@')[1]}\n` : '';
483
492
  const values = {
484
493
  name,
485
494
  title,
@@ -494,6 +503,8 @@ export async function runNew(argv, io = defaultIO()) {
494
503
  // component-name check when this is the literal 'ROOT'.
495
504
  componentName: urlSegment ? name : 'ROOT',
496
505
  cliVersion,
506
+ nodeVersion,
507
+ pnpmToolVersionsLine,
497
508
  pmName: pm.pm,
498
509
  pmCacheName: pm.cacheName,
499
510
  pmLockfile: pm.lockfile,
@@ -119,6 +119,12 @@ export async function runUpgrade(argv) {
119
119
  // substituted anywhere upgrade touches.
120
120
  componentName: 'unused-by-upgrade',
121
121
  cliVersion,
122
+ // .tool-versions (the only template file these two placeholders appear
123
+ // in) is never re-copied by upgrade — same reasoning as componentName
124
+ // above: structurally required by TemplateValues, but nothing
125
+ // meaningful to compute either from here.
126
+ nodeVersion: 'unused-by-upgrade',
127
+ pnpmToolVersionsLine: 'unused-by-upgrade',
122
128
  pmName: pm.pm,
123
129
  pmCacheName: pm.cacheName,
124
130
  pmLockfile: pm.lockfile,
@@ -9,6 +9,12 @@ const PLACEHOLDERS = {
9
9
  __DOCOUTURE_TITLE__: 'title',
10
10
  __DOCOUTURE_COMPONENT_NAME__: 'componentName',
11
11
  __DOCOUTURE_CLI_VERSION__: 'cliVersion',
12
+ __DOCOUTURE_NODE_VERSION__: 'nodeVersion',
13
+ // Whole-line token, same reasoning as pmSetupStepYaml's own comment below
14
+ // — the value (or '' for npm) already carries its own trailing newline,
15
+ // so substituting the token-plus-newline is what lets the line vanish
16
+ // entirely rather than leaving a blank line in the npm case.
17
+ '__DOCOUTURE_PNPM_TOOL_VERSIONS_LINE__\n': 'pnpmToolVersionsLine',
12
18
  __DOCOUTURE_PM__: 'pmName',
13
19
  __DOCOUTURE_PM_CACHE__: 'pmCacheName',
14
20
  __DOCOUTURE_LOCKFILE__: 'pmLockfile',
@@ -37,6 +37,51 @@ export function checkNodeVersion(engineRange, actualVersion) {
37
37
  detail: `install Node ${wantMajor} or newer — this is what 'npm run build'/'docouture dev' will actually run under`,
38
38
  };
39
39
  }
40
+ /**
41
+ * Confirms the package manager a site actually declares (`package.json`'s
42
+ * own `packageManager` field, corepack convention, e.g. `pnpm@10.24.0`) is
43
+ * installed and reachable — `checkNodeVersion` above gets a shortcut
44
+ * (`docouture` *is* a Node process, so Node's presence is proof positive,
45
+ * only its version is an open question), but `docouture` doesn't run *as*
46
+ * npm or pnpm, so their presence has to be checked by actually spawning the
47
+ * binary. Presence only — no version-match against the declared field is
48
+ * required, the field just says which binary to look for.
49
+ *
50
+ * The `<name>` before `@` is read as-is rather than restricted to a
51
+ * hardcoded `npm`/`pnpm` allow-list — this is what `docouture new` ever
52
+ * writes there in practice, but nothing here depends on that being true.
53
+ */
54
+ export function checkPackageManagerAvailable(packageManagerField) {
55
+ const label = 'package manager';
56
+ if (!packageManagerField) {
57
+ return Promise.resolve({
58
+ ok: true,
59
+ label,
60
+ message: 'no packageManager field declared in package.json — skipping',
61
+ });
62
+ }
63
+ const match = /^([^@\s]+)@/.exec(packageManagerField);
64
+ const pm = match?.[1];
65
+ if (!pm) {
66
+ return Promise.resolve({
67
+ ok: true,
68
+ label,
69
+ message: `could not parse packageManager '${packageManagerField}' — skipping`,
70
+ });
71
+ }
72
+ return new Promise((resolvePromise) => {
73
+ execFile(pm, ['--version'], { timeout: 10_000 }, (err, stdout) => {
74
+ resolvePromise(err
75
+ ? {
76
+ ok: false,
77
+ label,
78
+ message: `'${pm}' is not available on PATH`,
79
+ detail: `package.json declares packageManager: '${packageManagerField}' — install ${pm} (or run via corepack)`,
80
+ }
81
+ : { ok: true, label, message: `${pm} ${stdout.trim()} is available` });
82
+ });
83
+ });
84
+ }
40
85
  /**
41
86
  * The four names the docs-site-package skill documents as having to agree,
42
87
  * or a site builds to zero pages, or dies on "start page not found" — see
@@ -0,0 +1,2 @@
1
+ nodejs __DOCOUTURE_NODE_VERSION__
2
+ __DOCOUTURE_PNPM_TOOL_VERSIONS_LINE__
@@ -1,3 +1,4 @@
1
1
  node_modules/
2
2
  build/
3
3
  .DS_Store
4
+ .npmrc
@@ -24,7 +24,11 @@ on:
24
24
  branches: ['__DOCOUTURE_RELEASE_BRANCH__*']
25
25
 
26
26
  concurrency:
27
- group: release-preview
27
+ # Scoped per-PR, not just per-workflow: a bare 'release-preview' group name
28
+ # collides with this monorepo's own code-release_preview.yml, so a label
29
+ # change firing both workflows at once could have one cancel the other
30
+ # mid-run even though they preview unrelated releases.
31
+ group: docouture-release-preview-${{ github.event.pull_request.number }}
28
32
  cancel-in-progress: true
29
33
 
30
34
  jobs:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inditextech/docouture-cli",
3
- "version": "0.1.0-SNAPSHOT.88.1",
3
+ "version": "1.0.0",
4
4
  "description": "Command-line tool for docouture documentation sites: scaffold a new site and set its Antora version outside the monorepo",
5
5
  "repository": {
6
6
  "type": "git",