From 50ca41d53f3be1d36fd80deaa3ad2b73f5472567 Mon Sep 17 00:00:00 2001 From: JeremyDev87 Date: Fri, 1 May 2026 01:00:42 +0900 Subject: [PATCH] =?UTF-8?q?fix(release):=20action=20smoke=20native=20runti?= =?UTF-8?q?me=20=EC=84=A4=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actions/marketplace-wrapper/action.yml | 5 +-- .github/workflows/dev.yml | 2 +- .github/workflows/release-docs.yml | 3 +- action.yml | 5 +-- scripts/update-release-docs.mjs | 34 ++++++++++--------- scripts/validate-rust-release-wiring.mjs | 18 ++++++++-- test/release-docs.test.js | 25 ++++++++++++++ 7 files changed, 67 insertions(+), 25 deletions(-) create mode 100644 test/release-docs.test.js diff --git a/.github/actions/marketplace-wrapper/action.yml b/.github/actions/marketplace-wrapper/action.yml index a8c0de7..72af3a0 100644 --- a/.github/actions/marketplace-wrapper/action.yml +++ b/.github/actions/marketplace-wrapper/action.yml @@ -34,7 +34,7 @@ runs: repo_root="$(cd "$GITHUB_ACTION_PATH/../../.." && pwd)" echo "repo_root=$repo_root" >> "$GITHUB_OUTPUT" - - name: Install Maximus wrapper from repository root + - name: Install published Maximus wrapper for this action ref shell: bash env: MAXIMUS_REGISTRY_URL: ${{ inputs.registry-url }} @@ -53,7 +53,8 @@ runs: export npm_config_registry="$MAXIMUS_REGISTRY_URL" fi - npm install --no-package-lock --prefix "$install_root" "$REPO_ROOT" + package_version="$(node -p "require(process.env.REPO_ROOT + '/package.json').version")" + npm install --no-package-lock --prefix "$install_root" "@jeremyfellaz/maximus@$package_version" - name: Assert native runtime is installed shell: bash diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 0023509..b919126 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -225,4 +225,4 @@ jobs: run: node ./scripts/validate-rust-release-wiring.mjs - name: Run focused release wiring test - run: node --test test/release-workflow-context.test.js test/github-action-wiring.test.js test/release-plan.test.js test/release-candidate-metadata.test.js test/release-helpers.test.js test/npm-error-classifiers.test.js test/bump-release-version.test.js + run: node --test test/release-workflow-context.test.js test/github-action-wiring.test.js test/release-docs.test.js test/release-plan.test.js test/release-candidate-metadata.test.js test/release-helpers.test.js test/npm-error-classifiers.test.js test/bump-release-version.test.js diff --git a/.github/workflows/release-docs.yml b/.github/workflows/release-docs.yml index 8924529..6ce0173 100644 --- a/.github/workflows/release-docs.yml +++ b/.github/workflows/release-docs.yml @@ -2,11 +2,12 @@ name: release-docs on: push: + branches: + - master paths: - "README.md" - "README.en.md" - "action.yml" - - "package.json" - "scripts/update-release-docs.mjs" - ".github/workflows/release-docs.yml" pull_request: diff --git a/action.yml b/action.yml index 1c0d6ac..977425b 100644 --- a/action.yml +++ b/action.yml @@ -23,7 +23,7 @@ runs: with: node-version: "24" - - name: Install Maximus wrapper from this action ref + - name: Install published Maximus wrapper for this action ref shell: bash env: MAXIMUS_REGISTRY_URL: ${{ inputs.registry-url }} @@ -41,7 +41,8 @@ runs: export npm_config_registry="$MAXIMUS_REGISTRY_URL" fi - npm install --no-package-lock --prefix "$install_root" "$GITHUB_ACTION_PATH" + package_version="$(node -p "require(process.env.GITHUB_ACTION_PATH + '/package.json').version")" + npm install --no-package-lock --prefix "$install_root" "@jeremyfellaz/maximus@$package_version" - name: Assert native runtime is installed shell: bash diff --git a/scripts/update-release-docs.mjs b/scripts/update-release-docs.mjs index 133ab17..ea00a2b 100644 --- a/scripts/update-release-docs.mjs +++ b/scripts/update-release-docs.mjs @@ -3,20 +3,17 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -const packageJsonPath = path.join(repoRoot, "package.json"); const readmePaths = [ path.join(repoRoot, "README.md"), path.join(repoRoot, "README.en.md"), ]; const markerStart = ""; const markerEnd = ""; +const exampleReleaseTag = "v0.1.0"; const isCheckMode = process.argv.includes("--check"); async function main() { - const packageManifest = JSON.parse(await readFile(packageJsonPath, "utf8")); - const releaseTag = `v${packageManifest.version}`; - const readmes = new Map( await Promise.all( readmePaths.map(async (readmePath) => [readmePath, await readFile(readmePath, "utf8")]), @@ -25,7 +22,7 @@ async function main() { const nextReadmes = new Map(); for (const [readmePath, currentText] of readmes) { - nextReadmes.set(readmePath, updateReleaseDocs(readmePath, currentText, releaseTag)); + nextReadmes.set(readmePath, updateReleaseDocs(readmePath, currentText)); } let changed = false; @@ -46,18 +43,18 @@ async function main() { return; } - console.log(`Release docs are up to date for ${releaseTag}.`); + console.log("Release docs are up to date."); return; } if (changed) { - console.log(`Updated release docs for ${releaseTag}.`); + console.log("Updated release docs."); } else { - console.log(`Release docs are already up to date for ${releaseTag}.`); + console.log("Release docs are already up to date."); } } -function updateReleaseDocs(readmePath, text, releaseTag) { +export function updateReleaseDocs(readmePath, text) { const sections = { "README.md": [ `${markerStart}`, @@ -75,7 +72,7 @@ function updateReleaseDocs(readmePath, text, releaseTag) { "- `command`: `audit`, `doctor`, `fix`", "- `path`: 검사할 프로젝트 경로, 기본값 `.`", "- `registry-url`: pre-release smoke나 사설 registry 검증이 필요할 때만 쓰는 optional npm registry override", - `- \`release-tag\`: publish된 릴리즈 태그를 넣으세요. 예: \`${releaseTag}\``, + `- \`release-tag\`: publish된 릴리즈 태그를 넣으세요. 예: \`${exampleReleaseTag}\``, "", "유지보수자가 실제 alpha/stable 릴리즈를 준비하거나 같은 태그를 안전하게 재실행할 때는 [release operator runbook](https://github.com/JeremyDev87/maximus/blob/master/docs/release-operator-runbook.md)을 기준으로 진행합니다. Release Drafter는 `master`에서 draft notes만 갱신하며, 실제 publish는 tag-driven release workflow만 담당합니다.", `${markerEnd}`, @@ -96,7 +93,7 @@ function updateReleaseDocs(readmePath, text, releaseTag) { "- `command`: `audit`, `doctor`, `fix`", "- `path`: project path to inspect, default `.`", "- `registry-url`: optional npm registry override for pre-release smoke or private registry validation", - `- \`release-tag\`: replace this with a published release tag, for example \`${releaseTag}\``, + `- \`release-tag\`: replace this with a published release tag, for example \`${exampleReleaseTag}\``, "", "Maintainers should use the [release operator runbook](https://github.com/JeremyDev87/maximus/blob/master/docs/release-operator-runbook.md) for alpha or stable releases and same-tag reruns. Release Drafter only refreshes draft notes on `master`; actual publication stays in the tag-driven release workflow.", `${markerEnd}`, @@ -121,8 +118,13 @@ function updateReleaseDocs(readmePath, text, releaseTag) { return `${before}\n\n${nextSection}${after ? `\n\n${after}` : ""}`.replace(/\n{3,}/g, "\n\n"); } -await main().catch((error) => { - const message = error instanceof Error ? error.message : String(error); - console.error(`Release docs update failed: ${message}`); - process.exitCode = 1; -}); +const isDirectExecution = + process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]); + +if (isDirectExecution) { + await main().catch((error) => { + const message = error instanceof Error ? error.message : String(error); + console.error(`Release docs update failed: ${message}`); + process.exitCode = 1; + }); +} diff --git a/scripts/validate-rust-release-wiring.mjs b/scripts/validate-rust-release-wiring.mjs index 8dc1636..a20761d 100644 --- a/scripts/validate-rust-release-wiring.mjs +++ b/scripts/validate-rust-release-wiring.mjs @@ -85,7 +85,9 @@ function validateAction(actionText) { assertContains(actionText, 'uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238', "action node setup"); assertContains(actionText, "MAXIMUS_REGISTRY_URL: ${{ inputs.registry-url }}", "action registry env wiring"); assertContains(actionText, 'if [[ -n "$MAXIMUS_REGISTRY_URL" ]]; then', "action registry env usage"); - assertContains(actionText, 'npm install --no-package-lock --prefix "$install_root" "$GITHUB_ACTION_PATH"', "action local package install"); + assertContains(actionText, "Install published Maximus wrapper for this action ref", "action published package install step"); + assertContains(actionText, "process.env.GITHUB_ACTION_PATH + '/package.json'", "action package version lookup"); + assertContains(actionText, 'npm install --no-package-lock --prefix "$install_root" "@jeremyfellaz/maximus@$package_version"', "action published package install"); assertContains(actionText, 'node "$GITHUB_ACTION_PATH/scripts/assert-installed-native-runtime.mjs" "$install_root"', "action native runtime assertion"); assertContains(actionText, "MAXIMUS_COMMAND: ${{ inputs.command }}", "action command env wiring"); assertContains(actionText, "MAXIMUS_TARGET_PATH: ${{ inputs.path }}", "action path env wiring"); @@ -100,6 +102,10 @@ function validateAction(actionText) { !actionText.includes('"${{ inputs.command }}" "${{ inputs.path }}"'), "action should not interpolate command or path inputs directly inside bash", ); + assert.ok( + !actionText.includes('npm install --no-package-lock --prefix "$install_root" "$GITHUB_ACTION_PATH"'), + "action should install the published package version instead of the local action path", + ); } function validateDevWorkflow(devText) { @@ -123,7 +129,7 @@ function validateDevWorkflow(devText) { assertContains(devText, "release-wiring:", "release wiring job"); assertContains(devText, "node ./scripts/validate-rust-release-wiring.mjs", "release wiring validation command"); - assertContains(devText, "node --test test/release-workflow-context.test.js test/github-action-wiring.test.js test/release-plan.test.js test/release-candidate-metadata.test.js test/release-helpers.test.js test/npm-error-classifiers.test.js test/bump-release-version.test.js", "release wiring node test command"); + assertContains(devText, "node --test test/release-workflow-context.test.js test/github-action-wiring.test.js test/release-docs.test.js test/release-plan.test.js test/release-candidate-metadata.test.js test/release-helpers.test.js test/npm-error-classifiers.test.js test/bump-release-version.test.js", "release wiring node test command"); } function validateMarketplaceWrapperAction(actionText) { @@ -131,9 +137,15 @@ function validateMarketplaceWrapperAction(actionText) { assertContains(actionText, "registry-url", "marketplace wrapper registry input"); assertContains(actionText, "Resolve repository root", "marketplace wrapper repo root step"); assertContains(actionText, 'repo_root="$(cd "$GITHUB_ACTION_PATH/../../.." && pwd)"', "marketplace wrapper repo root resolution"); - assertContains(actionText, 'npm install --no-package-lock --prefix "$install_root" "$REPO_ROOT"', "marketplace wrapper root install"); + assertContains(actionText, "Install published Maximus wrapper for this action ref", "marketplace wrapper published package install step"); + assertContains(actionText, "process.env.REPO_ROOT + '/package.json'", "marketplace wrapper package version lookup"); + assertContains(actionText, 'npm install --no-package-lock --prefix "$install_root" "@jeremyfellaz/maximus@$package_version"', "marketplace wrapper published package install"); assertContains(actionText, 'node "$REPO_ROOT/scripts/assert-installed-native-runtime.mjs" "$install_root"', "marketplace wrapper runtime assertion"); assertContains(actionText, 'node "$install_root/node_modules/@jeremyfellaz/maximus/bin/maximus.js"', "marketplace wrapper runtime invocation"); + assert.ok( + !actionText.includes('npm install --no-package-lock --prefix "$install_root" "$REPO_ROOT"'), + "marketplace wrapper should install the published package version instead of the local repository path", + ); } function validateActionSmokeWorkflow(actionSmokeText) { diff --git a/test/release-docs.test.js b/test/release-docs.test.js new file mode 100644 index 0000000..2f46d4e --- /dev/null +++ b/test/release-docs.test.js @@ -0,0 +1,25 @@ +import assert from "node:assert/strict"; +import path from "node:path"; +import test from "node:test"; +import { readFile } from "node:fs/promises"; +import { updateReleaseDocs } from "../scripts/update-release-docs.mjs"; + +test("release docs generator preserves the static release-tag example", async () => { + const readmePath = path.join(process.cwd(), "README.md"); + const readmeText = await readFile(readmePath, "utf8"); + const nextText = updateReleaseDocs(readmePath, readmeText); + + assert.equal(nextText, readmeText); + assert.match(nextText, /예: `v0\.1\.0`/); + assert.doesNotMatch(nextText, /예: `v0\.1\.3`/); +}); + +test("English release docs generator preserves the static release-tag example", async () => { + const readmePath = path.join(process.cwd(), "README.en.md"); + const readmeText = await readFile(readmePath, "utf8"); + const nextText = updateReleaseDocs(readmePath, readmeText); + + assert.equal(nextText, readmeText); + assert.match(nextText, /for example `v0\.1\.0`/); + assert.doesNotMatch(nextText, /for example `v0\.1\.3`/); +});