@@ -127,6 +127,7 @@ describe("Dockerfile", () => {
127127 const dockerfile = await readFile ( dockerfilePath , "utf8" ) ;
128128 const installIndex = dockerfile . indexOf ( "pnpm install --frozen-lockfile" ) ;
129129 const postinstallIndex = dockerfile . indexOf ( "COPY scripts/postinstall-bundled-plugins.mjs" ) ;
130+ const prepareIndex = dockerfile . indexOf ( "scripts/prepare-git-hooks.mjs" ) ;
130131 const distImportHelperIndex = dockerfile . indexOf (
131132 "COPY scripts/lib/package-dist-imports.mjs ./scripts/lib/package-dist-imports.mjs" ,
132133 ) ;
@@ -138,6 +139,7 @@ describe("Dockerfile", () => {
138139 ) ;
139140
140141 expect ( postinstallIndex ) . toBeGreaterThan ( - 1 ) ;
142+ expect ( prepareIndex ) . toBeGreaterThan ( - 1 ) ;
141143 expect ( distImportHelperIndex ) . toBeGreaterThan ( - 1 ) ;
142144 expect ( packageManifestIndex ) . toBeGreaterThan ( - 1 ) ;
143145 expect ( extensionManifestIndex ) . toBeGreaterThan ( - 1 ) ;
@@ -146,11 +148,42 @@ describe("Dockerfile", () => {
146148 `if [ -f "/tmp/\${OPENCLAW_BUNDLED_PLUGIN_DIR}/$ext/package.json" ]; then` ,
147149 ) ;
148150 expect ( postinstallIndex ) . toBeLessThan ( installIndex ) ;
151+ expect ( prepareIndex ) . toBeLessThan ( installIndex ) ;
149152 expect ( distImportHelperIndex ) . toBeLessThan ( installIndex ) ;
150153 expect ( packageManifestIndex ) . toBeLessThan ( installIndex ) ;
151154 expect ( extensionManifestIndex ) . toBeLessThan ( installIndex ) ;
152155 } ) ;
153156
157+ it ( "copies root package lifecycle scripts before pnpm install" , async ( ) => {
158+ const [ dockerfile , packageJsonText ] = await Promise . all ( [
159+ readFile ( dockerfilePath , "utf8" ) ,
160+ readFile ( join ( repoRoot , "package.json" ) , "utf8" ) ,
161+ ] ) ;
162+ const installIndex = dockerfile . indexOf ( "pnpm install --frozen-lockfile" ) ;
163+ const packageJson = JSON . parse ( packageJsonText ) as {
164+ scripts ?: Record < string , string > ;
165+ } ;
166+ const installLifecycleScripts = [ "preinstall" , "install" , "postinstall" , "prepare" ] as const ;
167+
168+ for ( const lifecycleScript of installLifecycleScripts ) {
169+ const command = packageJson . scripts ?. [ lifecycleScript ] ;
170+ const scriptPath = command ?. match ( / \b n o d e \s + ( s c r i p t s \/ [ ^ \s ] + ) / ) ?. [ 1 ] ;
171+ if ( ! scriptPath ) {
172+ continue ;
173+ }
174+
175+ const copyIndex = dockerfile . indexOf ( scriptPath ) ;
176+ expect (
177+ copyIndex ,
178+ `${ lifecycleScript } must copy ${ scriptPath } before pnpm install` ,
179+ ) . toBeGreaterThan ( - 1 ) ;
180+ expect (
181+ copyIndex ,
182+ `${ lifecycleScript } must copy ${ scriptPath } before pnpm install` ,
183+ ) . toBeLessThan ( installIndex ) ;
184+ }
185+ } ) ;
186+
154187 it ( "does not let pnpm resync the full source workspace during Docker build scripts" , async ( ) => {
155188 const dockerfile = await readFile ( dockerfilePath , "utf8" ) ;
156189
0 commit comments