Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/actions/marketplace-wrapper/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion .github/workflows/release-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand All @@ -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
Expand Down
34 changes: 18 additions & 16 deletions scripts/update-release-docs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<!-- release-docs:start -->";
const markerEnd = "<!-- release-docs:end -->";
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")]),
Expand All @@ -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;
Expand All @@ -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}`,
Expand All @@ -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}`,
Expand All @@ -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}`,
Expand All @@ -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;
});
}
18 changes: 15 additions & 3 deletions scripts/validate-rust-release-wiring.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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) {
Expand All @@ -123,17 +129,23 @@ 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) {
assertContains(actionText, "name: Maximus Marketplace Wrapper", "marketplace wrapper metadata name");
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) {
Expand Down
25 changes: 25 additions & 0 deletions test/release-docs.test.js
Original file line number Diff line number Diff line change
@@ -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`/);
});