@@ -11,7 +11,7 @@ import { CloudRequest } from '../api/cloud_request'
1111import { isRetryableError } from '../network/is_retryable_error'
1212import { asyncRetry } from '../../util/async_retry'
1313import { postStudioSession } from '../api/studio/post_studio_session'
14- import type { StudioStatus } from '@packages/types'
14+ import type { StudioServerOptions , StudioStatus } from '@packages/types'
1515import path from 'path'
1616import os from 'os'
1717import { ensureStudioBundle } from './ensure_studio_bundle'
@@ -39,7 +39,6 @@ export class StudioLifecycleManager {
3939 private currentStudioHash ?: string
4040
4141 private initializationParams ?: {
42- projectId ?: string
4342 cloudDataSource : CloudDataSource
4443 cfg : Cfg
4544 debugData : any
@@ -55,20 +54,17 @@ export class StudioLifecycleManager {
5554 /**
5655 * Initialize the studio manager and possibly set up protocol.
5756 * Also registers this instance in the data context.
58- * @param projectId The project ID
5957 * @param cloudDataSource The cloud data source
6058 * @param cfg The project configuration
6159 * @param debugData Debug data for the configuration
6260 * @param ctx Data context to register this instance with
6361 */
6462 initializeStudioManager ( {
65- projectId,
6663 cloudDataSource,
6764 cfg,
6865 debugData,
6966 ctx,
7067 } : {
71- projectId ?: string
7268 cloudDataSource : CloudDataSource
7369 cfg : Cfg
7470 debugData : any
@@ -77,7 +73,7 @@ export class StudioLifecycleManager {
7773 debug ( 'Initializing studio manager' )
7874
7975 // Store initialization parameters for retry
80- this . initializationParams = { projectId , cloudDataSource, cfg, debugData, ctx }
76+ this . initializationParams = { cloudDataSource, cfg, debugData, ctx }
8177
8278 // Register this instance in the data context
8379 ctx . update ( ( data ) => {
@@ -88,48 +84,64 @@ export class StudioLifecycleManager {
8884
8985 this . updateStatus ( 'INITIALIZING' )
9086
87+ const getProjectOptions = async ( ) => {
88+ const [ user , config ] = await Promise . all ( [
89+ ctx . actions . auth . authApi . getUser ( ) ,
90+ ctx . project . getConfig ( ) ,
91+ ] )
92+
93+ return {
94+ user,
95+ projectSlug : config . projectId || undefined ,
96+ }
97+ }
98+
9199 const studioManagerPromise = this . createStudioManager ( {
92- projectId,
93100 cloudDataSource,
94101 cfg,
95102 debugData,
103+ getProjectOptions,
96104 } ) . catch ( async ( error ) => {
97105 debug ( 'Error during studio manager setup: %o' , error )
98106
99- const { cloudUrl, cloudHeaders } = await getCloudMetadata ( cloudDataSource )
100-
101- reportStudioError ( {
102- cloudApi : {
103- cloudUrl,
104- cloudHeaders,
105- CloudRequest,
106- isRetryableError,
107- asyncRetry,
108- } ,
109- studioHash : projectId ,
110- projectSlug : cfg . projectId ,
111- error,
112- studioMethod : 'initializeStudioManager' ,
113- studioMethodArgs : [ ] ,
114- } )
107+ try {
108+ const { cloudUrl, cloudHeaders } = await getCloudMetadata ( cloudDataSource )
109+
110+ reportStudioError ( {
111+ cloudApi : {
112+ cloudUrl,
113+ cloudHeaders,
114+ CloudRequest,
115+ isRetryableError,
116+ asyncRetry,
117+ } ,
118+ studioHash : this . currentStudioHash ,
119+ projectSlug : ( await getProjectOptions ( ) ) . projectSlug ,
120+ error,
121+ studioMethod : 'initializeStudioManager' ,
122+ studioMethodArgs : [ ] ,
123+ } )
115124
116- this . updateStatus ( 'IN_ERROR' )
125+ this . updateStatus ( 'IN_ERROR' )
117126
118- telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . BUNDLE_LIFECYCLE_END )
119- reportTelemetry ( BUNDLE_LIFECYCLE_TELEMETRY_GROUP_NAMES . COMPLETE_BUNDLE_LIFECYCLE , {
120- success : false ,
121- } )
127+ telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . BUNDLE_LIFECYCLE_END )
128+ reportTelemetry ( BUNDLE_LIFECYCLE_TELEMETRY_GROUP_NAMES . COMPLETE_BUNDLE_LIFECYCLE , {
129+ success : false ,
130+ } )
131+ } catch ( error ) {
132+ debug ( 'Error reporting studio error: %o' , error )
133+ }
122134
123135 return null
124136 } )
125137
126138 this . studioManagerPromise = studioManagerPromise
127139
128140 this . setupWatcher ( {
129- projectId,
130141 cloudDataSource,
131142 cfg,
132143 debugData,
144+ getProjectOptions,
133145 } )
134146 }
135147
@@ -158,30 +170,32 @@ export class StudioLifecycleManager {
158170 }
159171
160172 private async createStudioManager ( {
161- projectId,
162173 cloudDataSource,
163174 cfg,
164175 debugData,
176+ getProjectOptions,
165177 } : {
166- projectId ?: string
167178 cloudDataSource : CloudDataSource
168179 cfg : Cfg
169180 debugData : any
181+ getProjectOptions : StudioServerOptions [ 'getProjectOptions' ]
170182 } ) : Promise < StudioManager > {
171183 let studioPath : string
172184 let studioHash : string
173185 let manifest : Record < string , string >
174186
187+ const currentProjectOptions = await getProjectOptions ( )
188+
175189 initializeTelemetryReporter ( {
176- projectSlug : projectId ,
190+ projectSlug : currentProjectOptions . projectSlug ,
177191 cloudDataSource,
178192 } )
179193
180194 telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . BUNDLE_LIFECYCLE_START )
181195
182196 telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . POST_STUDIO_SESSION_START )
183197 const studioSession = await postStudioSession ( {
184- projectId,
198+ projectId : currentProjectOptions . projectSlug ,
185199 } )
186200
187201 telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . POST_STUDIO_SESSION_END )
@@ -192,22 +206,27 @@ export class StudioLifecycleManager {
192206 studioHash = studioSession . studioUrl . split ( '/' ) . pop ( ) ?. split ( '.' ) [ 0 ] ?? ''
193207 studioPath = path . join ( os . tmpdir ( ) , 'cypress' , 'studio' , studioHash )
194208
209+ debug ( 'Setting current studio hash: %s' , studioHash )
195210 // Store the current studio hash so that we can clear the cache entry when retrying
196211 this . currentStudioHash = studioHash
197212
198213 let hashLoadingPromise = StudioLifecycleManager . hashLoadingMap . get ( studioHash )
199214
200215 if ( ! hashLoadingPromise ) {
216+ debug ( 'Ensuring studio bundle for hash: %s' , studioHash )
217+
201218 hashLoadingPromise = ensureStudioBundle ( {
202219 studioUrl : studioSession . studioUrl ,
203220 studioPath,
204- projectId,
221+ projectId : currentProjectOptions . projectSlug ,
205222 } )
206223
207224 StudioLifecycleManager . hashLoadingMap . set ( studioHash , hashLoadingPromise )
208225 }
209226
210227 manifest = await hashLoadingPromise
228+
229+ debug ( 'Manifest: %o' , manifest )
211230 } else {
212231 studioPath = process . env . CYPRESS_LOCAL_STUDIO_PATH
213232 studioHash = 'local'
@@ -226,10 +245,14 @@ export class StudioLifecycleManager {
226245 const actualHash = crypto . createHash ( 'sha256' ) . update ( script ) . digest ( 'hex' )
227246
228247 if ( ! expectedHash ) {
248+ debug ( 'Expected hash %s for studio server script not found in manifest: %o' , expectedHash , manifest )
249+
229250 throw new Error ( 'Expected hash for studio server script not found in manifest' )
230251 }
231252
232253 if ( actualHash !== expectedHash ) {
254+ debug ( 'Invalid hash for studio server script: %s !== %s' , actualHash , expectedHash )
255+
233256 throw new Error ( 'Invalid hash for studio server script' )
234257 }
235258 }
@@ -244,16 +267,15 @@ export class StudioLifecycleManager {
244267 script,
245268 studioPath,
246269 studioHash,
247- projectSlug : projectId ,
248270 cloudApi : {
249271 cloudUrl,
250272 cloudHeaders,
251273 CloudRequest,
252274 isRetryableError,
253275 asyncRetry,
254276 } ,
255- shouldEnableStudio : this . cloudStudioRequested ,
256277 manifest,
278+ getProjectOptions,
257279 } )
258280
259281 telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . STUDIO_MANAGER_SETUP_END )
@@ -270,7 +292,7 @@ export class StudioLifecycleManager {
270292 telemetryManager . mark ( BUNDLE_LIFECYCLE_MARK_NAMES . STUDIO_PROTOCOL_PREPARE_START )
271293 await protocolManager . prepareProtocol ( script , {
272294 runId : 'studio' ,
273- projectId : cfg . projectId ,
295+ projectId : currentProjectOptions . projectSlug ,
274296 testingType : cfg . testingType ,
275297 cloudApi : {
276298 url : routes . apiUrl ,
@@ -320,15 +342,15 @@ export class StudioLifecycleManager {
320342 }
321343
322344 private setupWatcher ( {
323- projectId,
324345 cloudDataSource,
325346 cfg,
326347 debugData,
348+ getProjectOptions,
327349 } : {
328- projectId ?: string
329350 cloudDataSource : CloudDataSource
330351 cfg : Cfg
331352 debugData : any
353+ getProjectOptions : StudioServerOptions [ 'getProjectOptions' ]
332354 } ) {
333355 // Don't setup a watcher if the studio bundle is NOT local
334356 if ( ! process . env . CYPRESS_LOCAL_STUDIO_PATH ) {
@@ -348,10 +370,10 @@ export class StudioLifecycleManager {
348370 await this . studioManager ?. destroy ( )
349371 this . studioManager = undefined
350372 this . studioManagerPromise = this . createStudioManager ( {
351- projectId,
352373 cloudDataSource,
353374 cfg,
354375 debugData,
376+ getProjectOptions,
355377 } ) . then ( ( studioManager ) => {
356378 // eslint-disable-next-line no-console
357379 console . log ( 'Studio manager reloaded' )
0 commit comments