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
66 changes: 66 additions & 0 deletions release.profileEditA11y.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"defaultBranch": "main",
"skipIfNoDiff": true,
"defaultInstall": "npm install",
"defaultTest": "npm test",
"defaultBuild": "npm run build",
"modes": {
"stable": {
"branch": "main",
"versionBump": "patch",
"npmTag": "latest",
"gitTag": true,
"gitPush": true
},
"test": {
"branch": "dev",
"versionBump": "prerelease",
"preid": "test",
"npmTag": "test",
"gitTag": false,
"gitPush": false
}
},
"repos": [
{
"name": "solid-ui",
"path": "workspaces/solid-ui",
"repo": "https://github.com/SolidOS/solid-ui.git",
"afterInstall": [
"npm install pane-registry@latest solid-logic@latest rdflib@latest solid-namespace@latest"
]
},
{
"name": "contacts-pane",
"path": "workspaces/contacts-pane",
"repo": "https://github.com/SolidOS/contacts-pane.git",
"afterInstall": [
"npm install solid-ui solid-logic@latest rdflib@latest"
]
},
{
"name": "profile-pane",
"path": "workspaces/profile-pane",
"repo": "https://github.com/SolidOS/profile-pane.git",
"afterInstall": [
"npm install chat-pane@latest contacts-pane solid-ui pane-registry@latest solid-logic@latest rdflib@latest"
]
},
{
"name": "solid-panes",
"path": "workspaces/solid-panes",
"repo": "https://github.com/SolidOS/solid-panes.git",
"afterInstall": [
"npm install activitystreams-pane@latest chat-pane@latest contacts-pane folder-pane@latest issue-pane@latest meeting-pane@latest pane-registry@latest profile-pane source-pane@latest solid-ui solid-logic@latest solid-namespace@latest rdflib@latest"
]
},
{
"name": "mashlib",
"path": "workspaces/mashlib",
"repo": "https://github.com/SolidOS/mashlib.git",
"afterInstall": [
"npm install solid-panes solid-ui solid-logic@latest rdflib@latest"
]
}
]
}
5 changes: 3 additions & 2 deletions scripts/release
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -e

unset PREFIX npm_config_prefix
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm

function gitCheckoutMainOf {
Expand Down Expand Up @@ -81,8 +81,9 @@ updateRepo folder-pane # folder-pane (solid-ui, solid-logic)
updateRepo issue-pane # issue-pane (solid-ui, pane-registry, rdflib)
updateRepo meeting-pane # meeting-pane (solid-ui, solid-logic, rdflib)
updateRepo contacts-pane # contacts-pane (solid-ui, pane-registry, solid-logic, rdflib)
updateRepo profile-pane # profile-pane (chat-pane, solid-ui, pane-registry, solid-logic, rdflib)
updateRepo profile-pane # profile-pane (contacts-pane, solid-ui, pane-registry, solid-logic, rdflib)
updateRepo source-pane # source-pane (solid-ui)
updateRepo folder-pane # folder-pane (solid-ui, solid-logic)
updateRepo solid-panes # solid-panes (chat-pane, contacts-pane, folder-pane, issue-pane, meeting-pane, pane-registry, rdflib, solid-ui, source-pane)

updateRepo mashlib # mashlib (rdflib, solid-panes, solid-ui)
Expand Down
240 changes: 214 additions & 26 deletions scripts/release-orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,34 +223,219 @@ function publishStable(repoDir, modeConfig, dryRun) {

function publishTest(repoDir, modeConfig, dryRun) {
const preid = modeConfig.preid || 'test';
const originalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, originalScripts);
}

const pkg = getPackageJson(repoDir);
const name = pkg ? pkg.name : null;
let version = getPackageVersion(repoDir);
let attempts = 0;
const maxAttempts = 5;

if (!dryRun && name) {
while (attempts < maxAttempts && packageVersionExists(name, version, repoDir)) {
console.log(`Version ${version} already published. Bumping prerelease...`);
const retryOriginalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, retryOriginalScripts);
let localVersion = pkg ? pkg.version : null;

console.log(`Local package.json version: ${localVersion}`);

// Get the latest @test version from npm FIRST to understand what's already published
let latestTestVersion = null;
if (name) {
try {
const result = runQuiet(`npm view ${name}@${preid} version`, repoDir);
if (result && result.trim()) {
latestTestVersion = result.trim();
console.log(`Latest published @${preid} version: ${latestTestVersion}`);
}
} catch (err) {
// No @test version published yet, that's fine
console.log(`No @${preid} version published yet`);
}
}

// Get the latest stable version from npm
let latestStableVersion = null;
if (name) {
try {
const result = runQuiet(`npm view ${name}@latest version`, repoDir);
if (result && result.trim()) {
latestStableVersion = result.trim();
console.log(`Latest published @latest version: ${latestStableVersion}`);
}
version = getPackageVersion(repoDir);
attempts += 1;
} catch (err) {
console.log(`No @latest version published yet`);
}
}

if (attempts === maxAttempts && packageVersionExists(name, version, repoDir)) {
throw new Error(`Unable to find an unpublished prerelease version after ${maxAttempts} attempts.`);
let version;

// Strategy: Always compute baseVersion from the latest published @test version first
// This ensures we're incrementing from what npm sees, not what our local checkout has
if (latestTestVersion) {
// Extract the base version and counter from the latest published @test version
// Match pattern 1: X.Y.Z-preid.N (standard test version with counter)
// Match pattern 2: X.Y.Z (just a version, no test suffix yet)
const regexPattern = `^(\\d+\\.\\d+\\.\\d+)(?:.*)?-${preid.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\.(\\d+)$`;
console.log(`[DEBUG] Testing regex: ${regexPattern}`);
console.log(`[DEBUG] Against version: ${latestTestVersion}`);
const counterMatch = latestTestVersion.match(new RegExp(regexPattern));
console.log(`[DEBUG] Regex match result:`, counterMatch);

if (counterMatch && counterMatch[1]) {
// Found a version with -test.N pattern
const publishedBaseVersion = counterMatch[1];
const publishedCounter = parseInt(counterMatch[2], 10);
console.log(`Base version from published @${preid}: ${publishedBaseVersion}, counter: ${publishedCounter}`);

// Check if the base version from @test matches the latest stable
// If yes, we need to bump to the next patch version for the test
if (latestStableVersion && publishedBaseVersion === latestStableVersion) {
console.log(`Base version ${publishedBaseVersion} matches latest stable. Bumping to next patch for test...`);
// Increment patch version and start at -test.0
const versionParts = publishedBaseVersion.split('.');
if (versionParts.length >= 3) {
versionParts[2] = String(parseInt(versionParts[2], 10) + 1);
const newBaseVersion = versionParts.join('.');
version = `${newBaseVersion}-${preid}.0`;
console.log(`Bumping to ${version}...`);
} else {
// Fallback to normal bump if version format is unexpected
console.log(`Unexpected version format. Doing normal prerelease bump...`);
const originalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, originalScripts);
}
version = getPackageVersion(repoDir);
}

// Update package.json manually with this version
if (version && !dryRun) {
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
} else {
// Base version doesn't match stable, increment the test counter
const nextCounter = parseInt(counterMatch[2], 10) + 1;
version = `${publishedBaseVersion}-${preid}.${nextCounter}`;
console.log(`Latest @${preid} is ${latestTestVersion}. Incrementing to ${version}...`);

// Update package.json manually with this version
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
} else {
// Couldn't find exact -test.N pattern, but we do have a @test version
// Extract just the X.Y.Z base from latestTestVersion
const baseVersionMatch = latestTestVersion.match(/^(\d+\.\d+\.\d+)/);
if (baseVersionMatch && baseVersionMatch[1]) {
const publishedBaseVersion = baseVersionMatch[1];
console.log(`Found @${preid} version but no -${preid}.N pattern. Extracted base: ${publishedBaseVersion}`);

// Check if this base version matches the latest stable
if (latestStableVersion && publishedBaseVersion === latestStableVersion) {
console.log(`Base version ${publishedBaseVersion} matches latest stable. Bumping to next patch for test...`);
const versionParts = publishedBaseVersion.split('.');
if (versionParts.length >= 3) {
versionParts[2] = String(parseInt(versionParts[2], 10) + 1);
const newBaseVersion = versionParts.join('.');
version = `${newBaseVersion}-${preid}.0`;
console.log(`Bumping to ${version}...`);
} else {
console.log(`Unexpected version format. Doing normal prerelease bump...`);
const originalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, originalScripts);
}
version = getPackageVersion(repoDir);
}

// Update package.json manually with this version
if (version && !dryRun) {
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
} else {
// Base version doesn't match stable, use this version as starting point for -test
version = `${publishedBaseVersion}-${preid}.0`;
console.log(`Base version ${publishedBaseVersion} differs from stable. Starting test version at ${version}...`);

// Update package.json manually with this version
if (!dryRun) {
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
}
} else {
// Couldn't parse base version at all, do normal prerelease bump
console.log(`Found @${preid} (${latestTestVersion}) but couldn't parse base version. Doing normal prerelease bump...`);
const originalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, originalScripts);
}
version = getPackageVersion(repoDir);
if (dryRun) {
console.log(`[dry-run simulation] Prerelease version would be: ${version}`);
} else {
console.log(`After prerelease bump: ${version}`);
}
}
}
} else {
// No existing @test version, but we can be smart about versioning
console.log(`No @${preid} version found. Determining strategy for first test release...`);

// Extract base version from local version (just X.Y.Z, strip any pre-release identifiers)
const localBaseMatch = localVersion.match(/^(\d+\.\d+\.\d+)/);
const localBaseVersion = localBaseMatch ? localBaseMatch[1] : localVersion;
console.log(`Local base version: ${localBaseVersion}`);

if (latestStableVersion && localBaseVersion === latestStableVersion) {
// Local version base matches latest stable, so bump patch and start at -test.0
console.log(`Local base ${localBaseVersion} matches latest stable. Bumping to next patch for test...`);
const versionParts = localBaseVersion.split('.');
if (versionParts.length >= 3) {
versionParts[2] = String(parseInt(versionParts[2], 10) + 1);
const newBaseVersion = versionParts.join('.');
version = `${newBaseVersion}-${preid}.0`;
console.log(`Using ${version} for test release...`);

if (!dryRun) {
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
} else {
// Fallback to normal prerelease bump if format is unexpected
console.log(`Unexpected version format. Doing normal prerelease bump...`);
const originalScripts = disableVersionScripts(repoDir);
try {
run(`npm version prerelease --preid ${preid} --no-git-tag-version`, repoDir, dryRun);
} finally {
restoreVersionScripts(repoDir, originalScripts);
}
version = getPackageVersion(repoDir);
}
} else {
// Local version is newer than stable (or no stable exists), use it with -test.0
version = `${localBaseVersion}-${preid}.0`;
console.log(`Local base ${localBaseVersion} is ahead of stable. Starting test at ${version}...`);

if (!dryRun) {
const pkgPath = path.join(repoDir, 'package.json');
const pkgData = readJson(pkgPath);
pkgData.version = version;
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + '\n');
}
}

if (dryRun) {
console.log(`[dry-run simulation] Test version would be: ${version}`);
}
}

Expand Down Expand Up @@ -325,9 +510,12 @@ function main() {
continue;
}

const { behind, ahead } = getAheadBehind(repoDir, branch);
if (behind > 0) {
throw new Error(`Local branch behind origin/${branch}. Pull first.`);
// Skip ahead/behind check in dry-run since git commands don't actually execute
if (!dryRun) {
const { behind, ahead } = getAheadBehind(repoDir, branch);
if (behind > 0) {
throw new Error(`Local branch behind origin/${branch}. Pull first.`);
}
}

const pkg = getPackageJson(repoDir);
Expand Down
Loading