Skip to content

Commit 30b5495

Browse files
authored
fix: compute server release versions from tags (#1938)
Compute server-v3 and server-v4 release versions from the latest server tag plus changeset bumps, instead of recomputing from package.json. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Compute next server release versions for v3 and v4 from the latest git tag plus changeset bumps, instead of package.json. This keeps release tags consistent and avoids version drift. - **Bug Fixes** - Parse changed `.changeset/*.md` since the last `stagehand-server-v3/v*` or `stagehand-server-v4/v*` tag to find the highest bump for `@browserbasehq/stagehand-server-v3` and `@browserbasehq/stagehand-server-v4`. - Increment the tagged version (major/minor/patch), default to `0.0.0` if no tag, remove `changeset status`/`changeset-status.json`, and output `release`, `version`, and tag. <sup>Written for commit aebfc6c. Summary will update on new commits. <a href="https://cubic.dev/pr/browserbase/stagehand/pull/1938">Review in cubic</a></sup> <!-- End of auto-generated description by cubic. -->
1 parent 249f5ed commit 30b5495

2 files changed

Lines changed: 146 additions & 36 deletions

File tree

.github/workflows/stagehand-server-v3-release.yml

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,88 @@ jobs:
4444
set -euo pipefail
4545
4646
latest_tag="$(git tag -l 'stagehand-server-v3/v*' --sort=-v:refname | head -n 1 || true)"
47-
rm -f changeset-status.json
47+
changed_files="$(mktemp)"
4848
if [ -n "${latest_tag}" ]; then
49-
pnpm changeset status --since "${latest_tag}" --output changeset-status.json
49+
git diff --name-only "${latest_tag}"..HEAD -- '.changeset/*.md' > "${changed_files}"
5050
else
51-
pnpm changeset status --output changeset-status.json
51+
find .changeset -maxdepth 1 -name '*.md' -print | sort > "${changed_files}"
5252
fi
5353
54-
node <<'NODE'
54+
LATEST_TAG="${latest_tag}" CHANGED_CHANGESET_FILES="${changed_files}" node <<'NODE'
5555
const fs = require('fs');
56+
const path = require('path');
57+
58+
const packageName = '@browserbasehq/stagehand-server-v3';
59+
const latestTag = process.env.LATEST_TAG || '';
60+
const changesetFiles = fs
61+
.readFileSync(process.env.CHANGED_CHANGESET_FILES, 'utf8')
62+
.split('\n')
63+
.map((line) => line.trim())
64+
.filter(Boolean)
65+
.filter((file) => path.basename(file) !== 'config.json');
66+
67+
const releasePriority = { patch: 0, minor: 1, major: 2 };
68+
let highestReleaseType = null;
69+
70+
for (const file of changesetFiles) {
71+
const content = fs.readFileSync(file, 'utf8');
72+
const match = /^---\n([\s\S]*?)\n---/m.exec(content);
73+
if (!match) {
74+
continue;
75+
}
76+
77+
for (const rawLine of match[1].split('\n')) {
78+
const line = rawLine.trim();
79+
if (!line || line.startsWith('#')) {
80+
continue;
81+
}
82+
83+
const releaseMatch = /^"([^"]+)"\s*:\s*(patch|minor|major)\s*$/.exec(line);
84+
if (!releaseMatch) {
85+
continue;
86+
}
87+
88+
const [, releasePackage, releaseType] = releaseMatch;
89+
if (releasePackage !== packageName) {
90+
continue;
91+
}
92+
93+
if (
94+
highestReleaseType === null ||
95+
releasePriority[releaseType] > releasePriority[highestReleaseType]
96+
) {
97+
highestReleaseType = releaseType;
98+
}
99+
}
100+
}
56101
57-
const status = JSON.parse(fs.readFileSync('changeset-status.json', 'utf8'));
58-
const changesets = Array.isArray(status.changesets) ? status.changesets : [];
59-
const releases = Array.isArray(status.releases) ? status.releases : [];
60-
61-
const shouldRelease = changesets.some((cs) =>
62-
(cs.releases || []).some((r) => r?.name === '@browserbasehq/stagehand-server-v3')
63-
);
64-
65-
const serverRelease = releases.find((r) => r?.name === '@browserbasehq/stagehand-server-v3');
66-
if (shouldRelease && !serverRelease?.newVersion) {
67-
throw new Error(
68-
'Expected @browserbasehq/stagehand-server-v3 to have a computed newVersion in changeset-status.json.'
69-
);
102+
const shouldRelease = highestReleaseType !== null;
103+
let version = '';
104+
105+
if (shouldRelease) {
106+
const baseVersion = latestTag
107+
? latestTag.replace(/^stagehand-server-v3\/v/, '')
108+
: '0.0.0';
109+
const parts = baseVersion.split('.').map((part) => Number(part));
110+
if (parts.length !== 3 || parts.some((part) => Number.isNaN(part))) {
111+
throw new Error(`Invalid latest stagehand-server-v3 tag: ${latestTag || '<none>'}`);
112+
}
113+
114+
if (highestReleaseType === 'major') {
115+
parts[0] += 1;
116+
parts[1] = 0;
117+
parts[2] = 0;
118+
} else if (highestReleaseType === 'minor') {
119+
parts[1] += 1;
120+
parts[2] = 0;
121+
} else {
122+
parts[2] += 1;
123+
}
124+
125+
version = parts.join('.');
70126
}
71127
72128
const release = shouldRelease ? 'true' : 'false';
73-
const version = shouldRelease ? serverRelease.newVersion : '';
74129
const tag = `stagehand-server-v3/v${version}`;
75130
76131
const out = process.env.GITHUB_OUTPUT;

.github/workflows/stagehand-server-v4-release.yml

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,88 @@ jobs:
4444
set -euo pipefail
4545
4646
latest_tag="$(git tag -l 'stagehand-server-v4/v*' --sort=-v:refname | head -n 1 || true)"
47-
rm -f changeset-status.json
47+
changed_files="$(mktemp)"
4848
if [ -n "${latest_tag}" ]; then
49-
pnpm changeset status --since "${latest_tag}" --output changeset-status.json
49+
git diff --name-only "${latest_tag}"..HEAD -- '.changeset/*.md' > "${changed_files}"
5050
else
51-
pnpm changeset status --output changeset-status.json
51+
find .changeset -maxdepth 1 -name '*.md' -print | sort > "${changed_files}"
5252
fi
5353
54-
node <<'NODE'
54+
LATEST_TAG="${latest_tag}" CHANGED_CHANGESET_FILES="${changed_files}" node <<'NODE'
5555
const fs = require('fs');
56+
const path = require('path');
57+
58+
const packageName = '@browserbasehq/stagehand-server-v4';
59+
const latestTag = process.env.LATEST_TAG || '';
60+
const changesetFiles = fs
61+
.readFileSync(process.env.CHANGED_CHANGESET_FILES, 'utf8')
62+
.split('\n')
63+
.map((line) => line.trim())
64+
.filter(Boolean)
65+
.filter((file) => path.basename(file) !== 'config.json');
66+
67+
const releasePriority = { patch: 0, minor: 1, major: 2 };
68+
let highestReleaseType = null;
69+
70+
for (const file of changesetFiles) {
71+
const content = fs.readFileSync(file, 'utf8');
72+
const match = /^---\n([\s\S]*?)\n---/m.exec(content);
73+
if (!match) {
74+
continue;
75+
}
76+
77+
for (const rawLine of match[1].split('\n')) {
78+
const line = rawLine.trim();
79+
if (!line || line.startsWith('#')) {
80+
continue;
81+
}
82+
83+
const releaseMatch = /^"([^"]+)"\s*:\s*(patch|minor|major)\s*$/.exec(line);
84+
if (!releaseMatch) {
85+
continue;
86+
}
87+
88+
const [, releasePackage, releaseType] = releaseMatch;
89+
if (releasePackage !== packageName) {
90+
continue;
91+
}
92+
93+
if (
94+
highestReleaseType === null ||
95+
releasePriority[releaseType] > releasePriority[highestReleaseType]
96+
) {
97+
highestReleaseType = releaseType;
98+
}
99+
}
100+
}
56101
57-
const status = JSON.parse(fs.readFileSync('changeset-status.json', 'utf8'));
58-
const changesets = Array.isArray(status.changesets) ? status.changesets : [];
59-
const releases = Array.isArray(status.releases) ? status.releases : [];
60-
61-
const shouldRelease = changesets.some((cs) =>
62-
(cs.releases || []).some((r) => r?.name === '@browserbasehq/stagehand-server-v4')
63-
);
64-
65-
const serverRelease = releases.find((r) => r?.name === '@browserbasehq/stagehand-server-v4');
66-
if (shouldRelease && !serverRelease?.newVersion) {
67-
throw new Error(
68-
'Expected @browserbasehq/stagehand-server-v4 to have a computed newVersion in changeset-status.json.'
69-
);
102+
const shouldRelease = highestReleaseType !== null;
103+
let version = '';
104+
105+
if (shouldRelease) {
106+
const baseVersion = latestTag
107+
? latestTag.replace(/^stagehand-server-v4\/v/, '')
108+
: '0.0.0';
109+
const parts = baseVersion.split('.').map((part) => Number(part));
110+
if (parts.length !== 3 || parts.some((part) => Number.isNaN(part))) {
111+
throw new Error(`Invalid latest stagehand-server-v4 tag: ${latestTag || '<none>'}`);
112+
}
113+
114+
if (highestReleaseType === 'major') {
115+
parts[0] += 1;
116+
parts[1] = 0;
117+
parts[2] = 0;
118+
} else if (highestReleaseType === 'minor') {
119+
parts[1] += 1;
120+
parts[2] = 0;
121+
} else {
122+
parts[2] += 1;
123+
}
124+
125+
version = parts.join('.');
70126
}
71127
72128
const release = shouldRelease ? 'true' : 'false';
73-
const version = shouldRelease ? serverRelease.newVersion : '';
74129
const tag = `stagehand-server-v4/v${version}`;
75130
76131
const out = process.env.GITHUB_OUTPUT;

0 commit comments

Comments
 (0)