diff --git a/scripts/linux-binaries-manifest.test.mjs b/scripts/linux-binaries-manifest.test.mjs index bf66fc342f..be980d0e7c 100644 --- a/scripts/linux-binaries-manifest.test.mjs +++ b/scripts/linux-binaries-manifest.test.mjs @@ -451,6 +451,34 @@ test('the mirror keeps only the two newest versions and skips an unchanged lates assert.doesNotMatch(syncScript, /! -name '0\.2\.\*'/); }); +test('pruning keeps the two newest SemVer releases and drops a newer-looking beta', () => { + const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'openbitfun-prune-')); + for (const name of ['0.2.19', '1.0.0-beta', '1.0.0', '1.0.1']) { + fs.mkdirSync(path.join(temp, name)); + } + const result = spawnSync( + 'bash', + ['-c', ` + source "$SYNC_SCRIPT" + WEBSITE_RELEASE_DIR="$TEST_DIR" + KEEP_VERSIONS=2 + PYTHON=python3 + prune_old_versions + `], + { + encoding: 'utf8', + env: { + ...process.env, + SYNC_SCRIPT: path.join(repoRoot, 'scripts/openbitfun-release-sync.sh'), + TEST_DIR: temp, + }, + } + ); + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(fs.readdirSync(temp).sort(), ['1.0.0', '1.0.1']); + fs.rmSync(temp, { recursive: true, force: true }); +}); + test('openbitfun sync lock and cron use the in-repo script, not a server-only copy', () => { const syncScript = fs.readFileSync( path.join(repoRoot, 'scripts/openbitfun-release-sync.sh'), diff --git a/scripts/openbitfun-release-sync.sh b/scripts/openbitfun-release-sync.sh index 8f1866268c..4ff569e177 100755 --- a/scripts/openbitfun-release-sync.sh +++ b/scripts/openbitfun-release-sync.sh @@ -683,7 +683,22 @@ prune_old_versions() { local dirs=() total remove_count i while IFS= read -r d; do dirs+=("$d") - done < <(find "$WEBSITE_RELEASE_DIR" -mindepth 1 -maxdepth 1 -type d | sort -V) + done < <("$PYTHON" - "$WEBSITE_RELEASE_DIR" <<'PY' +import os, re, sys +root = sys.argv[1] +names = [name for name in os.listdir(root) if os.path.isdir(os.path.join(root, name))] + +def key(name): + match = re.fullmatch(r"(\d+)\.(\d+)\.(\d+)(?:-(.+))?", name) + if not match: + return (0, 0, 0, 0, name) + pre = match.group(4) + return (int(match.group(1)), int(match.group(2)), int(match.group(3)), 1 if pre is None else 0, pre or "") + +for name in sorted(names, key=key): + print(os.path.join(root, name)) +PY +) total=${#dirs[@]} if [ "$total" -le "$KEEP_VERSIONS" ]; then return 0