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
2 changes: 2 additions & 0 deletions .craft.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ targets:
includeNames: /^vitest-evals-\d.*\.tgz$/
- name: npm
id: "@vitest-evals/harness-ai-sdk"
access: public
includeNames: /^vitest-evals-harness-ai-sdk-\d.*\.tgz$/
- name: npm
id: "@vitest-evals/harness-pi-ai"
access: public
includeNames: /^vitest-evals-harness-pi-ai-\d.*\.tgz$/
20 changes: 19 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ on:
- minor
- patch
- major
prerelease:
description: Prepare a prerelease instead of a stable release
required: false
type: boolean
default: false
prerelease_id:
description: Prerelease identifier
required: false
type: choice
default: beta
options:
- beta
- rc
- alpha
force:
description: Force release (bypass blockers)
required: false
Expand Down Expand Up @@ -53,9 +67,13 @@ jobs:
id: version
env:
BUMP: ${{ inputs.bump }}
PRERELEASE: ${{ inputs.prerelease }}
PRERELEASE_ID: ${{ inputs.prerelease_id }}
run: |
set -euo pipefail
CURRENT=$(node -p "require('./packages/vitest-evals/package.json').version")
NEW=$(npx semver -i "$BUMP" "$CURRENT")
NEW=$(node ./scripts/calculate-release-version.mjs \
"$CURRENT" "$BUMP" "$PRERELEASE" "$PRERELEASE_ID")
echo "current=$CURRENT" >> "$GITHUB_OUTPUT"
echo "new=$NEW" >> "$GITHUB_OUTPUT"

Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ tables.
Pull request CI runs the same core safety checks: release config validation,
lint, typecheck, the CI test suite, and the workspace build.

## Releases

Use the manual Release workflow for stable releases. Select `patch`, `minor`,
or `major` for the normal version bump.

For a preview release that should not become the main stable version, set
`prerelease` to `true` and leave `prerelease_id` as `beta` unless you want an
`rc` or `alpha` line. From `0.8.0`, `bump=minor` produces `0.9.0-beta.0` and
`bump=major` produces `1.0.0-beta.0`; running prerelease again from
`1.0.0-beta.0` produces `1.0.0-beta.1`. Craft publishes npm prereleases under a
prerelease dist-tag so the stable `latest` line is not moved.

## Example

The `apps/demo-pi` app shows the intended explicit-run flow:
Expand Down
3 changes: 3 additions & 0 deletions packages/harness-ai-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"files": ["dist"],
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"source": "./src/index.ts",
Expand Down
3 changes: 3 additions & 0 deletions packages/harness-pi-ai/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"files": ["dist"],
"publishConfig": {
"access": "public"
},
"exports": {
".": {
"source": "./src/index.ts",
Expand Down
103 changes: 103 additions & 0 deletions scripts/calculate-release-version.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env node

const current = process.argv[2];
const bump = process.argv[3];
const prerelease = process.argv[4] === "true";
const prereleaseId = process.argv[5] || "beta";

const allowedBumps = new Set(["patch", "minor", "major"]);
const allowedPrereleaseIds = new Set(["beta", "rc", "alpha"]);

if (!current || !bump) {
console.error(
"Usage: node scripts/calculate-release-version.mjs <current> <patch|minor|major> <true|false> [prerelease-id]",
);
process.exit(1);
}

if (!allowedBumps.has(bump)) {
console.error(`Invalid bump: ${bump}`);
process.exit(1);
}

if (!allowedPrereleaseIds.has(prereleaseId)) {
console.error(`Invalid prerelease id: ${prereleaseId}`);
process.exit(1);
}

const version = parseVersion(current);
if (!version) {
console.error(`Invalid current version: ${current}`);
process.exit(1);
}

const next = prerelease
? nextPrereleaseVersion(version, bump, prereleaseId)
: nextStableVersion(version, bump);

console.log(next);

function parseVersion(value) {
const match = value.match(
/^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/,
);

if (!match) {
return null;
}

return {
major: Number(match[1]),
minor: Number(match[2]),
patch: Number(match[3]),
prerelease: match[4]?.split(".") ?? [],
};
}

function formatVersion({ major, minor, patch }, prereleaseParts = []) {
const base = `${major}.${minor}.${patch}`;
return prereleaseParts.length > 0
? `${base}-${prereleaseParts.join(".")}`
: base;
}

function bumpStableBase(version, bumpType) {
switch (bumpType) {
case "major":
return { major: version.major + 1, minor: 0, patch: 0 };
case "minor":
return { major: version.major, minor: version.minor + 1, patch: 0 };
case "patch":
return {
major: version.major,
minor: version.minor,
patch: version.patch + 1,
};
}
}

function nextStableVersion(version, bumpType) {
if (version.prerelease.length > 0) {
return formatVersion(version);
}

return formatVersion(bumpStableBase(version, bumpType));
}

function nextPrereleaseVersion(version, bumpType, id) {
if (version.prerelease.length === 0) {
return formatVersion(bumpStableBase(version, bumpType), [id, "0"]);
}

const [currentId] = version.prerelease;
const lastPart = version.prerelease.at(-1);

if (currentId !== id || !/^[0-9]+$/.test(lastPart)) {
return formatVersion(version, [id, "0"]);
}

return formatVersion(version, [
...version.prerelease.slice(0, -1),
String(Number(lastPart) + 1),
]);
}
Loading