diff --git a/assets/scss/td/_nav.scss b/assets/scss/td/_nav.scss index a7d0991c9..6a990ac68 100644 --- a/assets/scss/td/_nav.scss +++ b/assets/scss/td/_nav.scss @@ -162,6 +162,12 @@ $td-link-underline-offsets: ( content: ' (latest)'; } } + + &-next { + &::after { + content: ' (next)'; + } + } } } diff --git a/docsy.dev/config/_default/params.yaml b/docsy.dev/config/_default/params.yaml index 1740df017..9aa830b33 100644 --- a/docsy.dev/config/_default/params.yaml +++ b/docsy.dev/config/_default/params.yaml @@ -6,31 +6,26 @@ # version: # status: archived # Then fetch include -version: &docsyVersion 0.14.4-dev -tdBuildId: 022-over-main-6884d94e -versionLatest: &versionLatest v0.14.3 -version_menu: *docsyVersion +tdVersion: + latest: &tdLatestVers v0.14.3 + dev: &tdDevVers v0.14.4-dev + buildId: &tdBuildId 023-over-main-3bcb7385 + +version: *tdDevVers +version_menu: *tdDevVers version_menu_pagelinks: true versions: - # - name: '**About**' - # url: /project - # pagelinks: false - # - name: --- - name: '**Versions**' - - name: Next - version: *docsyVersion - # TODO: use https://next.docsy.dev once it's available - url: https://main--docsydocs.netlify.app - - version: *versionLatest - url: https://www.docsy.dev + - version: *tdDevVers + # kind: next + pagelinks: true + url: https://main--docsydocs.netlify.app # TODO: use next.docsy.dev once available + - version: *tdLatestVers kind: latest + url: https://www.docsy.dev - name: --- - name: '**Variant**' - - name: Doc-rooted - url: https://doc-rooted--docsydocs.netlify.app - # TODO: implement /docs/* redirects for doc-rooted site, then drop pagelinks:false - pagelinks: false + - name: Doc-rooted (experimental) kind: home - # - name: Goldydocs - # url: https://example.docsy.dev - # pagelinks: false + pagelinks: false # TODO: drop this once /docs/* redirects are implemented + url: https://doc-rooted--docsydocs.netlify.app diff --git a/docsy.dev/config/doc-rooted/params.yaml b/docsy.dev/config/doc-rooted/params.yaml index 67e79a171..a3b37be96 100644 --- a/docsy.dev/config/doc-rooted/params.yaml +++ b/docsy.dev/config/doc-rooted/params.yaml @@ -1,13 +1,26 @@ # cSpell:ignore pagelinks -version: &docsyVersion 0.14.3 -version_menu: *docsyVersion +tdVersion: + latest: &tdLatestVers v0.14.3 + dev: &tdDevVers v0.14.4-dev + buildId: &tdBuildId 023-over-main-3bcb7385 + +version: &tdDocRootedVers Doc-rooted of Next +version_menu: *tdLatestVers +version_menu_pagelinks: false versions: + - name: '**Versions**' - name: Next - kind: next - url: https://main--docsydocs.netlify.app/ - pagelinks: false - - version: *docsyVersion + version: *tdDevVers + # kind: next + url: https://main--docsydocs.netlify.app + - version: *tdLatestVers kind: latest url: https://www.docsy.dev - pagelinks: false + - name: --- + - name: '**Variant**' + - name: Doc-rooted (experimental) + version: *tdDocRootedVers + kind: home + pagelinks: false # TODO: drop this once /docs/* redirects are implemented + url: https://doc-rooted--docsydocs.netlify.app diff --git a/docsy.dev/config/production/params.yaml b/docsy.dev/config/production/params.yaml index d3742d70a..dd5d15c6b 100644 --- a/docsy.dev/config/production/params.yaml +++ b/docsy.dev/config/production/params.yaml @@ -1,13 +1,18 @@ # cSpell:ignore pagelinks -version: &docsyVersion 0.14.3 -version_menu: *docsyVersion +tdVersion: + latest: &tdLatestVers v0.14.3 + dev: &tdDevVers v0.14.4-dev + buildId: &tdBuildId 023-over-main-3bcb7385 + +version: *tdLatestVers +version_menu: *tdLatestVers versions: + - name: '**Versions**' - name: Next - kind: next - url: https://main--docsydocs.netlify.app/ - pagelinks: true - - version: *docsyVersion + version: *tdDevVers + # kind: next + url: https://main--docsydocs.netlify.app + - version: *tdLatestVers kind: latest url: https://www.docsy.dev - pagelinks: true diff --git a/docsy.dev/content/en/docs/get-started/other-options.md b/docsy.dev/content/en/docs/get-started/other-options.md index 489147a04..4975d8d9d 100644 --- a/docsy.dev/content/en/docs/get-started/other-options.md +++ b/docsy.dev/content/en/docs/get-started/other-options.md @@ -165,7 +165,7 @@ your project's root directory: ```sh git submodule add https://github.com/google/docsy.git themes/docsy cd themes/docsy - git checkout v{{% param version %}} + git checkout {{% param version %}} ``` To work from the development version of Docsy (_not recommended_), run the @@ -229,12 +229,12 @@ maintain your own copy of the theme directly, or your deployment choice requires you to include a copy of the theme in your repository), you can clone the theme into your project's `themes` subdirectory. -To clone Docsy at v{{% param version %}} into your project's `themes` folder, -run the following commands from your project's root directory: +To clone Docsy at {{% param version %}} into your project's `themes` folder, run +the following commands from your project's root directory: ```sh cd themes -git clone -b v{{% param version %}} https://github.com/google/docsy +git clone -b {{% param version %}} https://github.com/google/docsy cd docsy npm install ``` @@ -243,7 +243,7 @@ npm install To work from the development version of Docsy (not recommended unless, for example, you plan to upstream changes to Docsy), omit the -`-b v{{% param version %}}` argument from the clone command above. +`-b {{% param version %}}` argument from the clone command above. Then consider setting up an NPM [prepare][] script, as documented in Option 1. diff --git a/docsy.dev/content/en/project/about/maintainer-notes.md b/docsy.dev/content/en/project/about/maintainer-notes.md index f2d3d545c..f617de8ba 100644 --- a/docsy.dev/content/en/project/about/maintainer-notes.md +++ b/docsy.dev/content/en/project/about/maintainer-notes.md @@ -28,12 +28,6 @@ accordingly. 4. Run `npm run fix`. - > [!NOTE] - > - > This command might update the version in `package.json` via `fix:version`, - > but you can ignore this change since you'll be setting the version - > explicitly in the next step. - 5. **Update Docsy version** to {{% param version %}} using the following from a (bash or zsh) terminal. - First set the `VERSION` variable; we use it throughout the steps below. @@ -184,10 +178,10 @@ accordingly. ```console $ git push-all-remotes $REL - + git push origin v{{% param version %}} - * [new tag] v{{% param version %}} -> v{{% param version %}} - + git push upstream v{{% param version %}} - * [new tag] v{{% param version %}} -> v{{% param version %}} + + git push origin {{% param version %}} + * [new tag] {{% param version %}} -> {{% param version %}} + + git push upstream {{% param version %}} + * [new tag] {{% param version %}} -> {{% param version %}} ... ``` @@ -241,15 +235,15 @@ accordingly. been updated to the new release. 17. **[Draft a new release][]** using GitHub web; fill in the fields as follows: - - Visit [tags][] to find the new release tag v{{% param version %}}. + - Visit [tags][] to find the new release tag {{% param version %}}. - - Select Create a new release from the v{{% param version %}} tag dropdown + - Select Create a new release from the {{% param version %}} tag dropdown menu - **Release title**: use the release version. ```text - v{{% param version %}} + {{% param version %}} ``` - Click **Generate release notes** to get the release details inserted into @@ -299,7 +293,7 @@ with the following modifications: ## Post Docsy-release followup -Assuming that both the Docsy and Docsy-example releases v{{% param version %}} +Assuming that both the Docsy and Docsy-example releases {{% param version %}} have been successfully deployed, and that at least one other project has been successfully tested with the new release, then perform the following actions before any further changes are merged into the `main` branch: @@ -307,12 +301,12 @@ before any further changes are merged into the `main` branch: 1. Update the package version to a dev ID for Docsy and Docsy-example: ```console - $ npm run -s fix:version + $ npm run -s set:version:git-info ✓ Updated package.json version: 0.14.3 → 0.14.3-dev+003-over-main-cf4f514b ✓ Updated docsy.dev/config/_default/params.yaml version: 0.14.3 → 0.14.3-dev ✓ Updated docsy.dev/config/_default/params.yaml tdBuildId: (none) → 003-over-main-cf4f514b ... - $ npm run -s fix:version:example + $ npm run -s set:version:example:git-info ... ``` @@ -333,7 +327,7 @@ before any further changes are merged into the `main` branch: ## Release helper scripts -- NPM scripts: `fix:version`, `fix:version:example`, and `set:version`. +- NPM scripts: `set:version` and `set:version:*` - `scripts/get-build-id.sh`: Generates build ID from git describe (empty on tags). - `scripts/set-package-version/index.mjs`: Low-level version manager. See script diff --git a/docsy.dev/content/en/tests/blocks-cover/color-gradient/index.md b/docsy.dev/content/en/tests/blocks-cover/color-gradient/index.md index 208306f58..f71cbeae0 100644 --- a/docsy.dev/content/en/tests/blocks-cover/color-gradient/index.md +++ b/docsy.dev/content/en/tests/blocks-cover/color-gradient/index.md @@ -17,7 +17,8 @@ description: A Hugo theme for creating great technical documentation sites
- + Get started
- + Get started
- + Get started
- + Get started +{{ if and (not $blogPage) (not $isDevVersion) -}} + +{{ end }} +[blog]: <{{ $productionURL }}{{ $blogPage.RelPermalink | default "/blog/" }}> [changelog]: <{{ $productionURL }}{{ $changelogURL }}> diff --git a/layouts/_shortcodes/siteGetPage.html b/layouts/_shortcodes/siteGetPage.html new file mode 100644 index 000000000..3774d8b62 --- /dev/null +++ b/layouts/_shortcodes/siteGetPage.html @@ -0,0 +1,14 @@ +{{ $path := .Get 0 -}} +{{ $propertyName := .Get 1 -}} +{{ if or (not $path) (not $propertyName) -}} + {{ errorf "shortcode 'siteGetPage': path and property name are required" .Position -}} +{{ end -}} +{{ with site.GetPage $path -}} + {{ if eq $propertyName "RelPermalink" -}} + {{ .RelPermalink }} + {{ else if eq $propertyName "Permalink" -}} + {{ .Permalink }} + {{ else -}} + {{ errorf "shortcode 'siteGetPage': unsupported or unknown property name %q" $propertyName .Position -}} + {{ end -}} +{{ end -}} diff --git a/package.json b/package.json index 7dddca1e8..a3fb47d90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docsy", - "version": "0.14.4-dev+022-over-main-6884d94e", + "version": "0.14.4-dev+023-over-main-3bcb7385", "repository": "github:google/docsy", "homepage": "https://www.docsy.dev", "license": "Apache-2.0", @@ -8,6 +8,7 @@ "docsy.dev" ], "scripts": { + "__spv": "node scripts/set-package-version/index.mjs", "_cd:docsy.dev": "cd docsy.dev &&", "_check:format": "npx prettier --check assets *.md i18n scripts tasks", "_check:links": "npm run _cd:docsy.dev -- npm run _check:links", @@ -22,7 +23,8 @@ "_prepare": "npm run _cp:bs-rfs && npm run _prepare:scrollspy-patch && npm run _refresh-forward-sass-var && npm run _gen-chroma-styles && npm run get:hugo-modules", "_refresh-forward-sass-var": "bash -c scripts/refresh-sass-variables.pl", "_serve": "npm run _cd:docsy.dev -- npm run _serve --", - "_spv": "node scripts/set-package-version/index.mjs", + "_spv:example": "echo TBC - npm run -s __spv docsy.dev/config/example/params.yaml --", + "_spv": "npm run -s __spv docsy.dev/config/*/params.yaml --", "build": "npm run _cd:docsy.dev -- npm run build --", "cd:docsy.dev": "echo 'Running in docsy.dev...'; npm run _cd:docsy.dev -- npm run", "check:format": "npm list prettier && npm run _check:format || (echo '[help] Run: npm run fix:format'; exit 1)", @@ -38,10 +40,8 @@ "fix:format:diff": "npm run fix:format", "fix:format": "npm run -s _check:format -- --write && echo && npm run -s cd:docsy.dev fix:format", "fix:markdown": "npm run check:markdown -- --fix", - "fix:version:example": "npm run set:version:example -- -c ../hugo.yaml --version \"$(scripts/get-build-id.sh)\"", - "fix:version": "npm run -s _spv -- --version \"$(scripts/get-build-id.sh)\"", - "fix-for-test": "npm run fix:format && npm run fix:markdown && echo 'Skipping fix:version' && npm run cd:docsy.dev fix", - "fix": "npm run fix:format && npm run fix:markdown && npm run fix:version && npm run cd:docsy.dev fix", + "fix-for-test": "npm run fix:format && npm run fix:markdown && npm run cd:docsy.dev fix", + "fix": "npm run fix:format && npm run fix:markdown && npm run cd:docsy.dev fix", "get:hugo-modules": "node scripts/getHugoModules/index.mjs", "post-update": "echo; echo 'IMPORTANT! Run the following in case the ScrollSpy patch needs to be updated:\n npm run _prepare'; echo", "postinstall": "npm run _mkdir:hugo-mod", @@ -50,8 +50,10 @@ "prune:refcache": "npm run _cd:docsy.dev -- npm run prune:refcache --", "seq": "bash -c 'for cmd in \"$@\"; do npm run $cmd || exit 1; done' - ", "serve": "npm run _cd:docsy.dev -- npm run serve --", - "set:version:example": "cd ../docsy-example && node ../docsy/scripts/set-package-version/index.mjs", - "set:version": "npm run -s _spv -- -c config/production/params.yaml && npm run -s _spv && npm run -s fix:version", + "set:version:example:git-info": "echo FIXME - npm run set:version:example -- -c ../hugo.yaml --version \"$(scripts/get-build-id.sh)\"", + "set:version:example": "echo FIXME - 'cd ../docsy-example && node ../docsy/scripts/set-package-version/index.mjs'", + "set:version:git-info": "npm run -s _spv -- --version \"$(scripts/get-build-id.sh)\"", + "set:version": "npm run -s _spv --", "test:tooling": "node --test 'scripts/**/*.test.mjs'", "test:website": "npm run cd:docsy.dev test", "test": "npm run fix-and-test", diff --git a/scripts/get-build-id.sh b/scripts/get-build-id.sh index e7abc881b..c0a1ec17a 100755 --- a/scripts/get-build-id.sh +++ b/scripts/get-build-id.sh @@ -1,18 +1,20 @@ #!/bin/bash # -# Creates a build ID from `main` using the latest semver tag on `main` as a base, +# Creates a build ID from `release` using the latest semver tag on `release` as a base, # and the parts returned by `git describe --tags` over the current branch. # # Example, from: -# - main at v0.14.0 (617b5960) +# - release at v0.14.0 (617b5960) # - `git describe --tags` v0.14.0-1-g8047f659 -# We get: 0.14.1-dev+001-over-main-617b5960 +# We get: 0.14.1-dev+001-over-release-617b5960 set -euo pipefail -# Get the latest semver-like tag from main. -if ! base_tag=$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' main 2>/dev/null); then - echo "Error: couldn't find a semver tag on main" >&2 +base_branch="main" + +# Get the latest semver-like tag from release. +if ! base_tag=$(git describe --tags --abbrev=0 --match 'v[0-9]*.[0-9]*.[0-9]*' $base_branch 2>/dev/null); then + echo "Error: couldn't find a semver tag on $base_branch" >&2 exit 1 fi @@ -21,12 +23,12 @@ version="${base_tag#v}" IFS=. read -r major minor patch <<<"${version}" next_patch=$((patch + 1)) -# Count commits atop the base tag on main, then shift to 1-based and zero-pad. -commit_count=$(git rev-list --count --first-parent "${base_tag}..main") +# Count commits atop the base tag on release, then shift to 1-based and zero-pad. +commit_count=$(git rev-list --count --first-parent "${base_tag}..$base_branch") build_num=$((commit_count + 1)) build_num_padded=$(printf "%03d" "${build_num}") -# Pin the base to the current main tip hash. -main_sha=$(git rev-parse --short=8 main) +# Pin the base to the current release tip hash. +release_sha=$(git rev-parse --short=8 $base_branch) -echo "${major}.${minor}.${next_patch}-dev+${build_num_padded}-over-main-${main_sha}" +echo "${major}.${minor}.${next_patch}-dev+${build_num_padded}-over-$base_branch-${release_sha}" diff --git a/scripts/git/check-version.sh b/scripts/git/check-version.sh index 1d9af7c21..d9c2d7e8a 100755 --- a/scripts/git/check-version.sh +++ b/scripts/git/check-version.sh @@ -16,7 +16,7 @@ if [ -n "${SKIP_VERSION_CHECK:-}" ]; then fi new_version="$(scripts/get-build-id.sh)" -output="$(npm run -s fix:version -- --silent 2>&1)" +output="$(npm run -s set:version:git-info -- --silent 2>&1)" status=$? if [ $status -ne 0 ]; then diff --git a/scripts/set-package-version/hugo-yaml.mjs b/scripts/set-package-version/hugo-yaml.mjs index 31742e9b9..a8712af62 100644 --- a/scripts/set-package-version/hugo-yaml.mjs +++ b/scripts/set-package-version/hugo-yaml.mjs @@ -6,28 +6,53 @@ * Utilities for reading and writing version fields in docsy.dev/hugo.yaml. */ +import assert from 'node:assert'; import fs from 'fs'; +const KEY_AND_ANCHOR = { + latest: 'tdLatestVers', + dev: 'tdDevVers', + buildId: 'tdBuildId', +}; + +const VERSION_KEYS = Object.keys(KEY_AND_ANCHOR); +const VERSION_IDS = Object.values(KEY_AND_ANCHOR); +const versionKeysLineRegex = new RegExp( + `^(\\s{0,4})(${VERSION_KEYS.join('|')}):\\s*(.+)$`, +); +const versionIdsLineRegex = new RegExp(`(${VERSION_IDS.join('|')})`); + +/** + * @typedef {Object} VersionInfo + * @property {string} [latest] + * @property {string} [dev] + * @property {string} [buildId] + */ + /** - * Parses version and tdBuildId from YAML content. Finds first occurrence of - * version. + * Parses version info from YAML content. * * @param {string} yamlConfig - YAML config - * @returns {{ version?: string, tdBuildId?: string }} + * @returns {VersionInfo} */ export function parseParamsVersion(yamlConfig) { const result = {}; - const lineRegex = /^(\s{0,2})(version|tdBuildId):\s*(.+)$/; for (const line of yamlConfig.split('\n')) { - const match = line.match(lineRegex); + // Match version IDs either as YAML aliases or in a comment + // (actually, anywhere in the line): + // latest: &tdLatestVers v0.14.3 + // dev: 0.14.4-dev # tdDevVers + if (!line.match(versionIdsLineRegex)) continue; + + const match = line.match(versionKeysLineRegex); if (!match) continue; - const [, _prefix, key, value] = match; - if (key !== 'version' && key !== 'tdBuildId') continue; + const [, _indentation, key, rawValueToken] = match; + if (!VERSION_KEYS.includes(key)) continue; - const rawValueToken = value; // Matching, e.g.: - // `0.14.3-dev` - // `&docsyVersion 0.14.3-dev # comment` + // `v0.14.3` + // `&tdLatestVers v0.14.3` + // `&tdDevVers 0.14.4-dev # comment` const valueMatch = rawValueToken.match( /^(?:&\w+\s+)?["']?(.*?)["']?\s*(?:#.*)?$/, ); @@ -44,47 +69,69 @@ export function readHugoYaml(filePath) { } /** - * Writes version and tdBuildId to YAML file. + * Writes version info to YAML file. * - * @param {{ version?: string, tdBuildId?: string }} data + * @param {VersionInfo} versionInfo * @param {string} filePath */ export function writeHugoYaml(versionInfo, filePath) { - console.log('writeHugoYaml', filePath, versionInfo); const content = fs.readFileSync(filePath, 'utf8'); const newContent = updateYamlWithVersions(content, versionInfo); fs.writeFileSync(filePath, newContent); } /** - * Updates version and tdBuildId in YAML content. Uses the same regex as - * parseParamsVersion to handle both params file (0 indent) and params section (2 indent). + * Updates version info in YAML content. * * @param {string} yamlConfig - YAML file content - * @param {{ version?: string, tdBuildId?: string }} data + * @param {VersionInfo} data * @returns {string} Updated YAML content */ -export function updateYamlWithVersions(yamlConfig, { version, tdBuildId }) { - const lineRegex = /^(\s{0,2})(version|tdBuildId):\s*(.+)$/; +export function updateYamlWithVersions(yamlConfig, { latest, dev, buildId }) { + const data = { + latest, + dev: dev ?? (latest ? nextDevVersion(latest) : undefined), + buildId: buildId ?? '', + }; return yamlConfig .split('\n') .map((line) => { - const match = line.match(lineRegex); + if (!line.match(versionIdsLineRegex)) return line; + const match = line.match(versionKeysLineRegex); if (!match) return line; - const [_, prefix, key, rawValueToken] = match; - const newValue = key === 'version' ? version : tdBuildId; + const [_, indentation, key, rawValueToken] = match; + if (!VERSION_KEYS.includes(key)) return line; + const newValue = data[key]; if (newValue === undefined) return line; const anchorMatch = rawValueToken.match(/^(&\w+\s+)/); const anchor = anchorMatch ? anchorMatch[1] : ''; const commentMatch = rawValueToken.match(/(\s+#.*)$/); const comment = commentMatch ? commentMatch[1] : ''; - const value = key === 'version' ? newValue : yamlScalar(newValue); - return `${prefix}${key}: ${anchor}${value}${comment}`; + const value = + (key === 'latest' || key === 'dev') && !newValue.startsWith('v') + ? `v${newValue}` + : yamlScalar(newValue); + if (anchor) assert.strictEqual(anchor, `&${KEY_AND_ANCHOR[key]} `); + return `${indentation}${key}: ${anchor}${value}${comment}`; }) .join('\n'); } +/** + * Derives dev version from latest: patch + 1, then "-dev", with v prefix (e.g. v0.14.4 → v0.14.5-dev). + * + * @param {string} latest - e.g. "0.14.4" or "v0.14.4" + * @returns {string} e.g. "v0.14.5-dev" + */ +export function nextDevVersion(latest) { + const s = String(latest).replace(/^v/i, ''); + const m = s.match(/^(\d+)\.(\d+)\.(\d+)/); + if (!m) return `v${s}-dev`; + const [, major, minor, patch] = m; + return `v${major}.${minor}.${Number(patch) + 1}-dev`; +} + function yamlScalar(value) { if (value === '') { return "''"; diff --git a/scripts/set-package-version/hugo-yaml.test.mjs b/scripts/set-package-version/hugo-yaml.test.mjs index 3427bf633..cc1005c47 100644 --- a/scripts/set-package-version/hugo-yaml.test.mjs +++ b/scripts/set-package-version/hugo-yaml.test.mjs @@ -3,129 +3,140 @@ import assert from 'node:assert/strict'; import { parseParamsVersion, updateYamlWithVersions } from './hugo-yaml.mjs'; -const fixture_basic = ` -version: 0.14.3-dev -tdBuildId: 001-over-main-24e96f1c +// cSpell:ignore pagelinks + +const fixtureBasic = ` + latest: &tdLatestVers v0.14.3 + dev: v0.14.4-dev # tdDevVers + buildId: 018-over-main-adb0e595 # tdBuildId `; -test('parseParamsVersion extracts version and tdBuildId', () => { - const result = parseParamsVersion(fixture_basic); - assert.equal(result.version, '0.14.3-dev'); - assert.equal(result.tdBuildId, '001-over-main-24e96f1c'); +test('parseParamsVersion extracts version info', () => { + const result = parseParamsVersion(fixtureBasic); + assert.equal(result.latest, 'v0.14.3'); + assert.equal(result.dev, 'v0.14.4-dev'); + assert.equal(result.buildId, '018-over-main-adb0e595'); }); const expectedVers_basic = ` -version: 0.14.4 -tdBuildId: release-abc + latest: &tdLatestVers v0.14.4 + dev: v0.14.5-dev-abc # tdDevVers + buildId: some-build-id # tdBuildId `; -test('updateYamlWithVersions updates version and tdBuildId in content', () => { - const updated = updateYamlWithVersions(fixture_basic, { - version: '0.14.4', - tdBuildId: 'release-abc', +test('updateYamlWithVersions updates version info in content', () => { + const updated = updateYamlWithVersions(fixtureBasic, { + latest: 'v0.14.4', + dev: 'v0.14.5-dev-abc', + buildId: 'some-build-id', }); assert.equal(updated, expectedVers_basic); }); -const fixtureFieldAliases = `params: - version: &docsyVersion 0.14.3-dev - tdBuildId: 001-over-main-24e96f1c +const fixtureParams = `params: + tdVersion: + latest: &tdLatestVers v0.14.3 # TODO: ... + dev: &tdDevVers v0.14.4-dev + buildId: &tdBuildId 018-over-main-adb0e595 `; -test('parseParamsVersion extracts version and tdBuildId from field aliases', () => { - const result = parseParamsVersion(fixtureFieldAliases); - assert.equal(result.version, '0.14.3-dev'); - assert.equal(result.tdBuildId, '001-over-main-24e96f1c'); +test('parseParamsVersion extracts version info from params section', () => { + const result = parseParamsVersion(fixtureParams); + assert.equal(result.latest, 'v0.14.3'); + assert.equal(result.dev, 'v0.14.4-dev'); + assert.equal(result.buildId, '018-over-main-adb0e595'); }); -const expectedVersWithAlias = `params: - version: &docsyVersion 0.14.4 - tdBuildId: '' +const expectedVersParams = `params: + tdVersion: + latest: &tdLatestVers v0.14.4 # TODO: ... + dev: &tdDevVers v0.14.5-dev + buildId: &tdBuildId '' `; -test('updateYamlWithVersions updates version and tdBuildId in content with field aliases', () => { - const updated = updateYamlWithVersions(fixtureFieldAliases, { - version: '0.14.4', - tdBuildId: '', +test('updateYamlWithVersions updates version info in content with params section', () => { + const updated = updateYamlWithVersions(fixtureParams, { + latest: 'v0.14.4', + dev: 'v0.14.5-dev', + buildId: '', }); - assert.equal(updated, expectedVersWithAlias); -}); - -const fixture_versionWithComments = `params: - version: 0.14.3-dev # version comment - tdBuildId: 001-over-main-24e96f1c # build id comment -`; - -test('parseParamsVersion extracts version and tdBuildId from content with comments', () => { - const result = parseParamsVersion(fixture_versionWithComments); - assert.equal(result.version, '0.14.3-dev'); - assert.equal(result.tdBuildId, '001-over-main-24e96f1c'); + assert.equal(updated, expectedVersParams); }); -const expectedVersWithComments = `params: - version: 0.14.4 # version comment - tdBuildId: 1 # build id comment +const expectedVersWhenNoDevOrBuildId = ` + latest: &tdLatestVers v0.14.4 + dev: v0.14.5-dev # tdDevVers + buildId: '' # tdBuildId `; -test('updateYamlWithVersions updates version and tdBuildId in content with comments', () => { - const updated = updateYamlWithVersions(fixture_versionWithComments, { - version: '0.14.4', - tdBuildId: '1', +test('parseParamsVersion extracts version info w/o dev or buildId', () => { + const updated = updateYamlWithVersions(fixtureBasic, { + latest: 'v0.14.4', }); - assert.equal(updated, expectedVersWithComments); + assert.equal(updated, expectedVersWhenNoDevOrBuildId); }); const fixture_versionWithMenuConfig = ` -version: &docsyVersion 0.14.3-dev -tdBuildId: 001-over-main-24e96f1c # TODO: ... -version_menu: *docsyVersion +tdVersion: + latest: &tdLatestVers v0.14.3 + dev: &tdDevVers v0.14.4-dev + buildId: &tdBuildId 018-over-main-adb0e595 + +version: *tdDevVers +version_menu: *tdDevVers versions: - - version: v0.14.2 + - name: '**Versions**' + - version: *tdDevVers + # kind: next + pagelinks: true + url: https://main--docsydocs.netlify.app # TODO: use next.docsy.dev once available + - version: *tdLatestVers + kind: latest + pagelinks: true url: https://www.docsy.dev - - version: *docsyVersion - # url: https://next.docsy.dev - url: https://main--docsydocs.netlify.app/ `; -test('parseParamsVersion extracts version and tdBuildId from content with anchor', () => { +test('parseParamsVersion extracts version info even with other fields', () => { const result = parseParamsVersion(fixture_versionWithMenuConfig); - assert.equal(result.version, '0.14.3-dev'); - assert.equal(result.tdBuildId, '001-over-main-24e96f1c'); + assert.equal(result.latest, 'v0.14.3'); + assert.equal(result.dev, 'v0.14.4-dev'); + assert.equal(result.buildId, '018-over-main-adb0e595'); }); const expectedVersWithMenuConfig = ` -version: &docsyVersion 0.15.0-dev -tdBuildId: 001-over-main-24e96f1c # TODO: ... -version_menu: *docsyVersion +tdVersion: + latest: &tdLatestVers v0.14.4 + dev: &tdDevVers v0.14.5-dev + buildId: &tdBuildId '' + +version: *tdDevVers +version_menu: *tdDevVers versions: - - version: v0.14.2 + - name: '**Versions**' + - version: *tdDevVers + # kind: next + pagelinks: true + url: https://main--docsydocs.netlify.app # TODO: use next.docsy.dev once available + - version: *tdLatestVers + kind: latest + pagelinks: true url: https://www.docsy.dev - - version: *docsyVersion - # url: https://next.docsy.dev - url: https://main--docsydocs.netlify.app/ `; -test('updateYamlWithVersions updates version and tdBuildId in content with menu config', () => { +test('updateYamlWithVersions updates version info in content with menu config', () => { const updated = updateYamlWithVersions(fixture_versionWithMenuConfig, { - version: '0.15.0-dev', - tdBuildId: '001-over-main-24e96f1c', + latest: 'v0.14.4', }); assert.equal(updated, expectedVersWithMenuConfig); }); const fixture_versionQuoted = ` -version: '0.14.3-dev' -tdBuildId: "001-over-main-24e96f1c" + latest: 'v0.14.4' # tdLatestVers + buildId: '1' # tdBuildId `; -test('parseParamsVersion extracts version and tdBuildId from content with quoted values', () => { +test('parseParamsVersion extracts version info with quoted latest', () => { const result = parseParamsVersion(fixture_versionQuoted); - assert.equal(result.version, '0.14.3-dev'); - assert.equal(result.tdBuildId, '001-over-main-24e96f1c'); -}); - -test('parseParamsVersion extracts empty string for tdBuildId: ""', () => { - const result = parseParamsVersion("version: 0.14.0\ntdBuildId: ''"); - assert.equal(result.version, '0.14.0'); - assert.equal(result.tdBuildId, ''); + assert.equal(result.latest, 'v0.14.4'); + assert.equal(result.buildId, '1'); }); diff --git a/scripts/set-package-version/index.mjs b/scripts/set-package-version/index.mjs index 2b3be220c..0b91afbe1 100644 --- a/scripts/set-package-version/index.mjs +++ b/scripts/set-package-version/index.mjs @@ -12,15 +12,14 @@ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; -import { readHugoYaml, writeHugoYaml } from './hugo-yaml.mjs'; +import { nextDevVersion, readHugoYaml, writeHugoYaml } from './hugo-yaml.mjs'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const cwd = process.cwd(); -const configDir = 'docsy.dev'; -const defaultParamsYamlPath = 'config/_default/params.yaml'; -const defaultConfigPath = path.join(cwd, configDir, defaultParamsYamlPath); +const defaultParamsYamlPath = 'docsy.dev/config/_default/params.yaml'; +const defaultConfigPath = path.resolve(defaultParamsYamlPath); const packageJsonPath = 'package.json'; export function getPackagePath() { @@ -28,29 +27,27 @@ export function getPackagePath() { } const usageText = ` -Usage: node scripts/set-package-version/index.mjs [-h] [-s] [-v VERS | --id [BUILD-ID]] +Usage: node scripts/set-package-version/index.mjs [-h] [-s] [-v VERS | --id [BUILD-ID]] [FILE...] Options: - --config|-c PATH Path to config file to read/write versions from/to; - relative to ${configDir} - Default: ${defaultParamsYamlPath} --help|-h Show this help message --id [BUILD-ID] Set build ID metadata to BUILD-ID, if provided; otherwise, set it to a timestamp-based value. Version is unchanged. --silent|-s Don't log any messages --version|-v VERS Set version in target files according to VERS + FILE Config file(s) to read/write version info; paths are + relative to the current working directory or absolute. + If none given, default is ${defaultParamsYamlPath}. + The VERS specifier is a semver string of the form X.Y.Z-pre-rel+BUILD-ID. - Updates the version in the target files: + Updates the version in: - ${packageJsonPath} - - ${defaultParamsYamlPath} - - The target files are updated as follows: + - Each listed config file (or ${defaultParamsYamlPath} if no FILEs given) - In package.json, the version is set to the full version. - - In ${defaultParamsYamlPath}: the version and tdBuildId fields are set, - where version omits the build ID metadata. + - In each config file: latest, dev, and buildId fields are set. The default behavior is to strip the pre-release suffix and build ID, if any, from the target files. Useful for preparing a non-dev release. @@ -66,14 +63,10 @@ export function main( writeHugoYaml: writeHugoYamlFn = writeHugoYaml, } = {}, ) { - const { version, buildId, configPath, silent } = parseArgsAndResolveBuildId( - args, - { logger }, - ); + const { version, buildId, configPaths, silent, versionSetExplicitly } = + parseArgsAndResolveBuildId(args, { logger }); const pkg = readPackageJson(); - const hugoYaml = readHugoYamlFn(configPath); - const currentVersion = pkg.version; let newVersion; @@ -89,7 +82,6 @@ export function main( } let updated = false; - let hugoYamlUpdated = false; if (newVersion !== currentVersion) { pkg.version = newVersion; @@ -97,41 +89,70 @@ export function main( updated = true; } - const nextVersionNoBuild = removeBuildId(newVersion); const nextBuildId = getBuildId(newVersion); + const releaseVersion = getReleaseVersion(newVersion); + const versionWithoutBuild = removeBuildId(newVersion); + const hasPreRelease = versionWithoutBuild !== releaseVersion; + const leaveLatestUntouched = versionSetExplicitly && hasPreRelease; + + const newLatest = releaseVersion.startsWith('v') + ? releaseVersion + : `v${releaseVersion}`; + const newDev = leaveLatestUntouched + ? versionWithoutBuild.startsWith('v') + ? versionWithoutBuild + : `v${versionWithoutBuild}` + : nextDevVersion(releaseVersion); + const newBuildId = nextBuildId ?? ''; - // Keep config's version/tdBuildId aligned with package.json. - const currentHugoVersion = hugoYaml.version || ''; - const currentHugoBuildId = hugoYaml.tdBuildId || ''; - if ( - nextVersionNoBuild !== currentHugoVersion || - nextBuildId !== currentHugoBuildId - ) { - const data = { - ...hugoYaml, - version: nextVersionNoBuild, - tdBuildId: nextBuildId, - }; - writeHugoYamlFn(data, configPath); - hugoYamlUpdated = true; - } - - const configPathRelative = path.relative(cwd, configPath); - if (updated || hugoYamlUpdated) { - logger.log?.( - `✓ Updated package.json version: ${currentVersion} → ${newVersion}`, - ); - if (hugoYamlUpdated) { + let hugoYamlUpdated = false; + for (const configPath of configPaths) { + const hugoYaml = readHugoYamlFn(configPath); + const currentLatest = hugoYaml.latest ?? ''; + const currentDev = hugoYaml.dev ?? ''; + const currentBuildId = hugoYaml.buildId ?? ''; + + const latestDiffers = newLatest !== currentLatest; + const devOrBuildIdDiffers = + newDev !== currentDev || newBuildId !== currentBuildId; + const shouldUpdate = leaveLatestUntouched + ? devOrBuildIdDiffers + : latestDiffers || devOrBuildIdDiffers; + + if (shouldUpdate) { + const data = leaveLatestUntouched + ? { ...hugoYaml, dev: newDev, buildId: newBuildId } + : { + ...hugoYaml, + latest: newLatest, + dev: newDev, + buildId: newBuildId, + }; + writeHugoYamlFn(data, configPath); + hugoYamlUpdated = true; + const configPathRelative = path.relative(cwd, configPath); + if (!leaveLatestUntouched && latestDiffers) { + logger.log?.( + `✓ Updated ${configPathRelative} latest: ${currentLatest || '(none)'} → ${newLatest}`, + ); + } logger.log?.( - `✓ Updated ${configPathRelative} version: ${currentHugoVersion || '(none)'} → ${nextVersionNoBuild}`, + `✓ Updated ${configPathRelative} dev: ${currentDev || '(none)'} → ${newDev}`, ); logger.log?.( - `✓ Updated ${configPathRelative} tdBuildId: ${currentHugoBuildId || '(none)'} → ${nextBuildId || '(none)'}`, + `✓ Updated ${configPathRelative} buildId: ${currentBuildId || '(none)'} → ${newBuildId || '(none)'}`, + ); + } else if (!silent) { + const configPathRelative = path.relative(cwd, configPath); + logger.log?.( + `Package version in ${configPathRelative} is already set to ${currentVersion}.`, ); } - } else if (!silent) { + } + + if (updated) { logger.log?.( - `Package version in ${configPathRelative} is already set to ${currentVersion}.`, + `✓ Updated package.json version: ${currentVersion} → ${newVersion}`, ); } @@ -143,7 +164,7 @@ export function main( * * @param {string[]} args - Command line arguments * @param {{ logger?: Console }} [options] - Logger to use - * @returns {{ version: string, buildId: string, configPath: string, silent: boolean }} + * @returns {{ version: string, buildId: string, configPaths: string[], silent: boolean, versionSetExplicitly: boolean }} */ export function parseArgsAndResolveBuildId(args, { logger = console } = {}) { function usage(exitCode = 0) { @@ -154,6 +175,7 @@ export function parseArgsAndResolveBuildId(args, { logger = console } = {}) { let version; let buildId; let configPath = defaultConfigPath; + const configPaths = []; let silent = false; const warn = logger?.warn || console.warn; @@ -161,13 +183,6 @@ export function parseArgsAndResolveBuildId(args, { logger = console } = {}) { for (; i < args.length; i++) { const arg = args[i]; switch (arg) { - case '--config': - case '-c': - if (++i >= args.length) { - usage(1); - } - configPath = path.join(cwd, configDir, args[i]); - break; case '--help': case '-h': usage(); @@ -192,6 +207,10 @@ export function parseArgsAndResolveBuildId(args, { logger = console } = {}) { version = args[i]; break; default: + if (!arg.startsWith('-')) { + configPaths.push(path.resolve(arg)); + break; + } warn?.(`Unexpected argument: ${arg}`); usage(1); } @@ -201,7 +220,16 @@ export function parseArgsAndResolveBuildId(args, { logger = console } = {}) { buildId = generateTimestamp(); } - return { version, buildId, configPath, silent }; + const resolvedConfigPaths = + configPaths.length > 0 ? configPaths : [configPath]; + const versionSetExplicitly = version !== undefined; + return { + version, + buildId, + configPaths: resolvedConfigPaths, + silent, + versionSetExplicitly, + }; } export function generateTimestamp() { diff --git a/scripts/set-package-version/index.test.mjs b/scripts/set-package-version/index.test.mjs index 1ae47e865..729ed6095 100644 --- a/scripts/set-package-version/index.test.mjs +++ b/scripts/set-package-version/index.test.mjs @@ -55,24 +55,56 @@ test('parseArgsAndResolveBuildId treats --id followed by flag as omitted BUILD-I test('parseArgsAndResolveBuildId supports short -v and --version precedence', () => { const result = parseArgsAndResolveBuildId( - ['-v', '2.0.0-dev+build-123', '--id', 'ignored-id'], + ['-v', 'v2.0.0-dev+build-123', '--id', 'ignored-id'], { logger: nullLogger, }, ); - assert.equal(result.version, '2.0.0-dev+build-123'); + assert.equal(result.version, 'v2.0.0-dev+build-123'); assert.equal(result.buildId, 'ignored-id'); }); -test('parseArgsAndResolveBuildId accepts -c/--config for config file path', () => { +test('parseArgsAndResolveBuildId resolves file paths relative to cwd', () => { const result = parseArgsAndResolveBuildId( - ['--config', 'custom/params.yaml', '--id', 'build-1'], + ['rel/path/to/params.yaml', '--id', 'build-1'], { logger: nullLogger }, ); - assert.ok(result.configPath.endsWith(path.join('custom', 'params.yaml'))); + assert.equal(result.configPaths.length, 1); + assert.equal(result.configPaths[0], path.resolve('rel/path/to/params.yaml')); assert.equal(result.buildId, 'build-1'); }); +test('parseArgsAndResolveBuildId reports unknown flag for --config', () => { + const warnCalls = []; + const logger = { + log() {}, + warn(...args) { + warnCalls.push(args); + }, + }; + const exitStub = (code) => { + throw { exitCode: code }; + }; + const origExit = process.exit; + process.exit = exitStub; + try { + parseArgsAndResolveBuildId(['--config', 'custom/params.yaml'], { + logger, + }); + assert.fail('expected process.exit(1) to be called'); + } catch (err) { + if (err.exitCode !== undefined) { + assert.equal(err.exitCode, 1); + assert.equal(warnCalls.length, 1); + assert.equal(warnCalls[0][0], 'Unexpected argument: --config'); + } else { + throw err; + } + } finally { + process.exit = origExit; + } +}); + test('release/build helpers split semver strings', () => { assert.equal(getReleaseVersion('1.2.3-dev+build-9'), '1.2.3'); assert.equal(removeBuildId('1.2.3-dev+build-9'), '1.2.3-dev'); @@ -81,8 +113,12 @@ test('release/build helpers split semver strings', () => { }); test('main default strips pre-release and build metadata in both targets', () => { - const pkg = { version: '1.2.3-dev+old-build' }; - const hugoYaml = { version: '1.2.3-dev', tdBuildId: 'old-build' }; + const pkg = { version: '1.2.3-dev+some-build' }; + const hugoYaml = { + latest: 'v1.2.3', + dev: 'v1.2.4-dev', + buildId: 'some-build', + }; let writtenPkg; let writtenHugoYaml; @@ -100,14 +136,19 @@ test('main default strips pre-release and build metadata in both targets', () => assert.equal(pkg.version, '1.2.3'); assert.deepEqual(writtenPkg, { version: '1.2.3' }); - assert.equal(writtenHugoYaml.version, '1.2.3'); - assert.equal(writtenHugoYaml.tdBuildId, ''); + assert.equal(writtenHugoYaml.latest, 'v1.2.3'); + assert.equal(writtenHugoYaml.dev, 'v1.2.4-dev'); + assert.equal(writtenHugoYaml.buildId, ''); assert.equal(newVersion, '1.2.3'); }); test('main --id sets build metadata and preserves pre-release', () => { - const pkg = { version: '1.2.3-dev+old-build' }; - const hugoYaml = { version: '1.2.3-dev', tdBuildId: 'old-build' }; + const pkg = { version: '1.2.3-dev+some-build' }; + const hugoYaml = { + latest: 'v1.2.3', + dev: 'v1.2.4-dev', + buildId: 'some-build', + }; let writtenPkg; let writtenHugoYaml; @@ -125,14 +166,19 @@ test('main --id sets build metadata and preserves pre-release', () => { assert.equal(pkg.version, '1.2.3-dev+custom-build'); assert.deepEqual(writtenPkg, { version: '1.2.3-dev+custom-build' }); - assert.equal(writtenHugoYaml.version, '1.2.3-dev'); - assert.equal(writtenHugoYaml.tdBuildId, 'custom-build'); + assert.equal(writtenHugoYaml.latest, 'v1.2.3'); + assert.equal(writtenHugoYaml.dev, 'v1.2.4-dev'); + assert.equal(writtenHugoYaml.buildId, 'custom-build'); assert.equal(newVersion, '1.2.3-dev+custom-build'); }); test('main --id "" generates timestamp build metadata', () => { - const pkg = { version: '1.2.3-dev+old-build' }; - const hugoYaml = { version: '1.2.3-dev', tdBuildId: 'old-build' }; + const pkg = { version: '1.2.3-dev+some-build' }; + const hugoYaml = { + latest: 'v1.2.3', + dev: 'v1.2.4-dev', + buildId: 'some-build', + }; let writtenPkg; let writtenHugoYaml; @@ -150,17 +196,52 @@ test('main --id "" generates timestamp build metadata', () => { assert.match(newVersion, /^1\.2\.3-dev\+\d{8}-\d{4}Z$/); assert.match(writtenPkg.version, /^1\.2\.3-dev\+\d{8}-\d{4}Z$/); - assert.equal(writtenHugoYaml.version, '1.2.3-dev'); - assert.match(writtenHugoYaml.tdBuildId, /^\d{8}-\d{4}Z$/); + assert.equal(writtenHugoYaml.latest, 'v1.2.3'); + assert.equal(writtenHugoYaml.dev, 'v1.2.4-dev'); + assert.match(writtenHugoYaml.buildId, /^\d{8}-\d{4}Z$/); }); -test('main sets entire version with --version and updates hugo split fields', () => { - const pkg = { version: '1.0.0+old-build' }; - const hugoYaml = { version: '1.0.0', tdBuildId: 'old-build' }; +test('main sets version info from full version string with --version', () => { + const pkg = { version: '1.0.0+some-build' }; + const hugoYaml = { + latest: 'v1.0.0', + dev: 'v1.0.1-dev', + buildId: 'some-build', + }; + let writtenPkg; + let writtenHugoYaml; + + const newVersion = main(['--version', '1.0.1-dev+build-123'], { + logger: nullLogger, + readPackageJson: () => pkg, + writePackageJson: (updatedPkg) => { + writtenPkg = { ...updatedPkg }; + }, + readHugoYaml: () => ({ ...hugoYaml }), + writeHugoYaml: (updatedYaml) => { + writtenHugoYaml = { ...updatedYaml }; + }, + }); + + assert.equal(pkg.version, '1.0.1-dev+build-123'); + assert.deepEqual(writtenPkg, { version: '1.0.1-dev+build-123' }); + assert.equal(writtenHugoYaml.latest, 'v1.0.0'); + assert.equal(writtenHugoYaml.dev, 'v1.0.1-dev'); + assert.equal(writtenHugoYaml.buildId, 'build-123'); + assert.equal(newVersion, '1.0.1-dev+build-123'); +}); + +test('main sets version info from --version w/o pre-release or build ID', () => { + const pkg = { version: '1.0.0+some-build' }; + const hugoYaml = { + latest: 'v1.0.0', + dev: 'v1.0.1-dev', + buildId: 'some-build', + }; let writtenPkg; let writtenHugoYaml; - const newVersion = main(['--version', '2.0.0-dev+build-123'], { + const newVersion = main(['--version', '3.2.1'], { logger: nullLogger, readPackageJson: () => pkg, writePackageJson: (updatedPkg) => { @@ -172,16 +253,73 @@ test('main sets entire version with --version and updates hugo split fields', () }, }); - assert.equal(pkg.version, '2.0.0-dev+build-123'); - assert.deepEqual(writtenPkg, { version: '2.0.0-dev+build-123' }); - assert.equal(writtenHugoYaml.version, '2.0.0-dev'); - assert.equal(writtenHugoYaml.tdBuildId, 'build-123'); - assert.equal(newVersion, '2.0.0-dev+build-123'); + assert.equal(pkg.version, '3.2.1'); + assert.deepEqual(writtenPkg, { version: '3.2.1' }); + assert.equal(writtenHugoYaml.latest, 'v3.2.1'); + assert.equal(writtenHugoYaml.dev, 'v3.2.2-dev'); + assert.equal(writtenHugoYaml.buildId, ''); + assert.equal(newVersion, '3.2.1'); +}); + +// TODO: is this functionality we want? +test('set version and build ID from command line', { skip: true }, () => { + const pkg = { version: '1.2.3' }; + const hugoYaml = { + latest: 'v1.2.3', + dev: 'v1.2.4-dev', + buildId: 'some-build', + }; + let writtenPkg; + let writtenHugoYaml; + + const newVersion = main(['--version', '1.3.0', '--id', 'build-123'], { + logger: nullLogger, + readPackageJson: () => pkg, + writePackageJson: (updatedPkg) => { + writtenPkg = { ...updatedPkg }; + }, + readHugoYaml: () => ({ ...hugoYaml }), + writeHugoYaml: (updatedYaml) => { + writtenHugoYaml = { ...updatedYaml }; + }, + }); + + assert.equal(pkg.version, '1.3.1-dev+build-123'); + assert.deepEqual(writtenPkg, { version: '1.3.1-dev+build-123' }); + assert.equal(writtenHugoYaml.latest, 'v1.3.0'); + assert.equal(writtenHugoYaml.dev, 'v1.3.1-dev'); + assert.equal(writtenHugoYaml.buildId, 'build-123'); + assert.equal(newVersion, '1.3.1-dev+build-123'); +}); + +test('main with single file argument processes that file', () => { + const pkg = { version: '1.2.3' }; + const hugoYaml = { latest: 'v1.2.2', dev: 'v1.2.3-dev', buildId: '1' }; + const writtenPaths = []; + let writtenData; + const fileArg = 'config/production/params.yaml'; + + main([fileArg], { + logger: nullLogger, + readPackageJson: () => pkg, + writePackageJson: () => {}, + readHugoYaml: () => ({ ...hugoYaml }), + writeHugoYaml: (data, filePath) => { + writtenPaths.push(filePath); + writtenData = data; + }, + }); + + assert.equal(writtenPaths.length, 1); + assert.equal(writtenPaths[0], path.resolve(fileArg)); + assert.equal(writtenData.latest, 'v1.2.3'); + assert.equal(writtenData.dev, 'v1.2.4-dev'); + assert.equal(writtenData.buildId, ''); }); test('main logs when package/hugo versions already match', () => { const pkg = { version: '1.0.0+existing' }; - const hugoYaml = { version: '1.0.0', tdBuildId: 'existing' }; + const hugoYaml = { latest: 'v1.0.0', dev: 'v1.0.1-dev', buildId: 'existing' }; let writeCallCount = 0; const messages = []; const logger = {