Skip to content

Commit a5d0802

Browse files
authored
chore(release): repair published CLI verification (#820)
## Summary - replace the failing scoped-package `npm exec` publication proof with a clean temporary global-prefix installation - invoke the installed `zeroshot` executable for `--version`, `--help`, and `list` under an isolated home - always remove the temporary installation and cover success/failure cleanup with focused tests ## Evidence Release workflow run 30277903920 successfully published `v6.7.2`, npm `latest` and `gitHead` are correct, provenance and the curated GitHub Release exist, but the final assertion failed because npm could not resolve the scoped package's bin through `npm exec --package=...`. This is a `chore:` release-process correction and is intentionally a semantic-release no-op. ## Validation The complete CI, including the integration suite, must run on GitHub-hosted workers. Locally I only ran syntax and diff checks.
1 parent 088db99 commit a5d0802

2 files changed

Lines changed: 119 additions & 15 deletions

File tree

scripts/assert-release-published.js

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
const fs = require('fs');
44
const https = require('https');
5+
const os = require('os');
56
const path = require('path');
67
const { execFileSync } = require('child_process');
78
const { releaseTypeForMessages } = require('./release-preflight');
89

910
const DEFAULT_ATTEMPTS = 24;
1011
const DEFAULT_DELAY_MS = 5000;
1112

12-
function run(command, args) {
13-
return execFileSync(command, args, { encoding: 'utf8' }).trim();
13+
function run(command, args, options = {}) {
14+
return execFileSync(command, args, { encoding: 'utf8', ...options }).trim();
1415
}
1516

1617
function packageName() {
@@ -85,21 +86,50 @@ function verifyCuratedNotes(tag, release) {
8586
}
8687
}
8788

88-
function verifyInstalledCli(name, version) {
89+
function verifyInstalledCli(name, version, options = {}) {
8990
const packageSpec = `${name}@${version}`;
90-
const reported = run('npm', [
91-
'exec',
92-
'--yes',
93-
`--package=${packageSpec}`,
94-
'--',
95-
'zeroshot',
96-
'--version',
97-
]);
98-
if (!reported.split(/\s+/).includes(version)) {
99-
throw new Error(`installed CLI reported ${reported}; expected ${version}`);
91+
const execute = options.execute || run;
92+
const makeTempRoot =
93+
options.makeTempRoot ||
94+
(() => fs.mkdtempSync(path.join(os.tmpdir(), 'zeroshot-release-cli-')));
95+
const removeTempRoot =
96+
options.removeTempRoot ||
97+
((root) => {
98+
fs.rmSync(root, { recursive: true, force: true });
99+
});
100+
const platform = options.platform || process.platform;
101+
const prefix = makeTempRoot();
102+
103+
try {
104+
execute('npm', [
105+
'install',
106+
'--global',
107+
'--prefix',
108+
prefix,
109+
'--no-audit',
110+
'--no-fund',
111+
packageSpec,
112+
]);
113+
114+
const executable = path.join(
115+
prefix,
116+
platform === 'win32' ? 'zeroshot.cmd' : 'bin',
117+
...(platform === 'win32' ? [] : ['zeroshot'])
118+
);
119+
const isolatedEnv = {
120+
...process.env,
121+
HOME: prefix,
122+
USERPROFILE: prefix,
123+
};
124+
const reported = execute(executable, ['--version'], { env: isolatedEnv });
125+
if (!reported.split(/\s+/).includes(version)) {
126+
throw new Error(`installed CLI reported ${reported}; expected ${version}`);
127+
}
128+
execute(executable, ['--help'], { env: isolatedEnv });
129+
execute(executable, ['list'], { env: isolatedEnv });
130+
} finally {
131+
removeTempRoot(prefix);
100132
}
101-
run('npm', ['exec', '--yes', `--package=${packageSpec}`, '--', 'zeroshot', '--help']);
102-
run('npm', ['exec', '--yes', `--package=${packageSpec}`, '--', 'zeroshot', 'list']);
103133
}
104134

105135
function tagsPointingAtHead() {
@@ -230,6 +260,7 @@ module.exports = {
230260
npmLatest,
231261
provenanceStatement,
232262
tagsPointingAtHead,
263+
verifyInstalledCli,
233264
verifyProvenance,
234265
waitForNpmLatest,
235266
};

tests/assert-release-published.test.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const assert = require('assert');
33
const {
44
latestReleaseTag,
55
provenanceStatement,
6+
verifyInstalledCli,
67
verifyProvenance,
78
} = require('../scripts/assert-release-published');
89
const { releaseTypeForMessages } = require('../scripts/release-preflight');
@@ -59,4 +60,76 @@ describe('release publication assertion', () => {
5960

6061
assert.deepStrictEqual(provenanceStatement(attestations), statement);
6162
});
63+
64+
it('verifies the published CLI through a clean global-prefix install', () => {
65+
const calls = [];
66+
const execute = (command, args, options) => {
67+
calls.push({ command, args, options });
68+
if (args.includes('--version')) return 'zeroshot 6.7.2';
69+
return '';
70+
};
71+
let removed = null;
72+
73+
verifyInstalledCli('@the-open-engine/zeroshot', '6.7.2', {
74+
execute,
75+
makeTempRoot: () => '/tmp/zeroshot-release-proof',
76+
removeTempRoot: (root) => {
77+
removed = root;
78+
},
79+
platform: 'linux',
80+
});
81+
82+
assert.deepStrictEqual(calls[0], {
83+
command: 'npm',
84+
args: [
85+
'install',
86+
'--global',
87+
'--prefix',
88+
'/tmp/zeroshot-release-proof',
89+
'--no-audit',
90+
'--no-fund',
91+
'@the-open-engine/zeroshot@6.7.2',
92+
],
93+
options: undefined,
94+
});
95+
assert.deepStrictEqual(
96+
calls.slice(1).map(({ command, args }) => ({ command, args })),
97+
[
98+
{
99+
command: '/tmp/zeroshot-release-proof/bin/zeroshot',
100+
args: ['--version'],
101+
},
102+
{
103+
command: '/tmp/zeroshot-release-proof/bin/zeroshot',
104+
args: ['--help'],
105+
},
106+
{
107+
command: '/tmp/zeroshot-release-proof/bin/zeroshot',
108+
args: ['list'],
109+
},
110+
]
111+
);
112+
assert.strictEqual(removed, '/tmp/zeroshot-release-proof');
113+
});
114+
115+
it('cleans up the temporary install when CLI verification fails', () => {
116+
let removed = null;
117+
118+
assert.throws(
119+
() =>
120+
verifyInstalledCli('@the-open-engine/zeroshot', '6.7.2', {
121+
execute: (command, args) => {
122+
if (args.includes('--version')) return 'zeroshot 6.7.1';
123+
return '';
124+
},
125+
makeTempRoot: () => '/tmp/zeroshot-release-proof-failure',
126+
removeTempRoot: (root) => {
127+
removed = root;
128+
},
129+
platform: 'linux',
130+
}),
131+
/expected 6.7.2/
132+
);
133+
assert.strictEqual(removed, '/tmp/zeroshot-release-proof-failure');
134+
});
62135
});

0 commit comments

Comments
 (0)