2020 * dist/webbrain-edge-<version>.zip
2121 * dist/webbrain-firefox-<version>.zip
2222 *
23- * <version> is read from package.json so a single npm-version bump
24- * cascades into the right filenames.
23+ * <version> is read from package.json at HEAD, and every archived manifest
24+ * must match it. An uncommitted version bump is rejected instead of creating
25+ * a new-looking filename around an old manifest.
2526 */
2627
2728import { readFileSync , mkdirSync } from 'node:fs' ;
2829import { execFileSync } from 'node:child_process' ;
29- import { fileURLToPath } from 'node:url' ;
30+ import { fileURLToPath , pathToFileURL } from 'node:url' ;
3031import path from 'node:path' ;
3132
3233const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
3334const root = path . resolve ( __dirname , '..' ) ;
34- const pkg = JSON . parse ( readFileSync ( path . join ( root , 'package.json' ) , 'utf8' ) ) ;
35- const version = pkg . version ;
36-
37- const distDir = path . join ( root , 'dist' ) ;
38- mkdirSync ( distDir , { recursive : true } ) ;
39-
40- console . log ( `Building extension zips for v${ version } …` ) ;
4135
4236const targets = [
4337 { packageName : 'chrome' , sourceDir : 'chrome' } ,
@@ -46,14 +40,58 @@ const targets = [
4640 { packageName : 'firefox' , sourceDir : 'firefox' } ,
4741] ;
4842
49- for ( const { packageName, sourceDir } of targets ) {
50- const out = path . join ( distDir , `webbrain-${ packageName } -${ version } .zip` ) ;
51- // -o writes directly to the file; avoids needing shell redirection,
52- // so this runs identically on bash, zsh, cmd, and PowerShell.
53- execFileSync (
54- 'git' ,
55- [ 'archive' , '--format=zip' , '-o' , out , `HEAD:src/${ sourceDir } ` ] ,
56- { stdio : 'inherit' , cwd : root }
43+ export function assertMatchingArchiveVersion ( expected , actual , label ) {
44+ if ( actual !== expected ) {
45+ throw new Error ( `${ label } is ${ actual } , but the release package version is ${ expected } .` ) ;
46+ }
47+ }
48+
49+ function readJsonAtHead ( relativePath ) {
50+ const json = execFileSync ( 'git' , [ 'show' , `HEAD:${ relativePath } ` ] , {
51+ cwd : root ,
52+ encoding : 'utf8' ,
53+ stdio : [ 'ignore' , 'pipe' , 'pipe' ] ,
54+ } ) ;
55+ return JSON . parse ( json ) ;
56+ }
57+
58+ function runCli ( ) {
59+ const workingPackage = JSON . parse ( readFileSync ( path . join ( root , 'package.json' ) , 'utf8' ) ) ;
60+ const headPackage = readJsonAtHead ( 'package.json' ) ;
61+ assertMatchingArchiveVersion (
62+ headPackage . version ,
63+ workingPackage . version ,
64+ 'Working-tree package.json version'
5765 ) ;
58- console . log ( ` ✓ dist/webbrain-${ packageName } -${ version } .zip` ) ;
66+
67+ const version = headPackage . version ;
68+ for ( const { sourceDir } of targets ) {
69+ const manifest = readJsonAtHead ( `src/${ sourceDir } /manifest.json` ) ;
70+ assertMatchingArchiveVersion ( version , manifest . version , `HEAD src/${ sourceDir } /manifest.json version` ) ;
71+ }
72+
73+ const distDir = path . join ( root , 'dist' ) ;
74+ mkdirSync ( distDir , { recursive : true } ) ;
75+ console . log ( `Building extension zips for v${ version } from HEAD …` ) ;
76+
77+ for ( const { packageName, sourceDir } of targets ) {
78+ const out = path . join ( distDir , `webbrain-${ packageName } -${ version } .zip` ) ;
79+ // -o writes directly to the file; avoids needing shell redirection,
80+ // so this runs identically on bash, zsh, cmd, and PowerShell.
81+ execFileSync (
82+ 'git' ,
83+ [ 'archive' , '--format=zip' , '-o' , out , `HEAD:src/${ sourceDir } ` ] ,
84+ { stdio : 'inherit' , cwd : root }
85+ ) ;
86+ console . log ( ` ✓ dist/webbrain-${ packageName } -${ version } .zip` ) ;
87+ }
88+ }
89+
90+ if ( process . argv [ 1 ] && import . meta. url === pathToFileURL ( process . argv [ 1 ] ) . href ) {
91+ try {
92+ runCli ( ) ;
93+ } catch ( error ) {
94+ console . error ( `build-zip: ${ error . message } ` ) ;
95+ process . exit ( 1 ) ;
96+ }
5997}
0 commit comments