@@ -25,6 +25,7 @@ import {
2525} from 'google-auth-library' ;
2626import { Service } from './service' ;
2727import { MethodOptions } from 'googleapis-common' ;
28+ import { get } from 'lodash' ;
2829
2930/**
3031 * Available options to create the client.
@@ -185,7 +186,7 @@ export class CloudRun {
185186 * @param service Service object.
186187 * @returns Service object.
187188 */
188- async deploy ( service : Service ) : Promise < run_v1 . Schema$Service > {
189+ async deploy ( service : Service ) : Promise < string > {
189190 const authClient = await this . getAuthClient ( ) ;
190191 const serviceNames = await this . listServices ( ) ;
191192 let serviceResponse : GaxiosResponse < run_v1 . Schema$Service > ;
@@ -218,8 +219,11 @@ export class CloudRun {
218219 this . methodOptions ,
219220 ) ;
220221 }
222+
223+ const url = await this . pollService ( serviceResponse . data ) ;
221224 core . info ( `Service ${ service . name } has been successfully deployed.` ) ;
222- return serviceResponse . data ;
225+ // return serviceResponse.data;
226+ return url ;
223227 }
224228
225229 /**
@@ -299,4 +303,74 @@ export class CloudRun {
299303 this . methodOptions ,
300304 ) ;
301305 }
306+
307+ /**
308+ * Poll service revision until ready
309+ * @param serviceResponse
310+ * @returns service url or revision url
311+ */
312+ async pollService ( serviceResponse : run_v1 . Schema$Service ) : Promise < string > {
313+ let url = getUrl ( serviceResponse ) ;
314+ const maxAttempts = 60 ; // Timeout after 300 seconds
315+ let attempt = 0 ;
316+ // Revision is ready and url is found before timeout
317+ while ( ! getReadyStatus ( serviceResponse ) && ! url && attempt < maxAttempts ) {
318+ attempt += 1 ;
319+ await sleep ( 5000 ) ;
320+ serviceResponse = await this . getService ( serviceResponse . metadata ! . name ! ) ;
321+ url = getUrl ( serviceResponse ) ;
322+ }
323+ if ( ! url ) throw new Error ( 'Timeout error: service revision is not ready.' ) ;
324+ return url ;
325+ }
326+ }
327+
328+ /** Retrieve status of new revision */
329+ function getReadyStatus ( serviceResponse : run_v1 . Schema$Service ) : boolean {
330+ // Retrieve the revision name
331+ const revisionName = get ( serviceResponse , 'spec.template.metadata.name' ) ;
332+ // Retrieve the revision statuses
333+ const createdRevision = get (
334+ serviceResponse ,
335+ 'status.latestCreatedRevisionName' ,
336+ ) ;
337+ const latestRevision = get ( serviceResponse , 'status.latestReadyRevisionName' ) ;
338+ // Latest created revision must equal latest ready revision
339+ if ( revisionName ) {
340+ // After first deployment, revision name is set
341+ return (
342+ revisionName &&
343+ createdRevision &&
344+ latestRevision &&
345+ revisionName == createdRevision &&
346+ revisionName == latestRevision
347+ ) ;
348+ } else {
349+ // First deployment will not have a revision name
350+ return (
351+ createdRevision && latestRevision && latestRevision == createdRevision
352+ ) ;
353+ }
354+ }
355+
356+ function sleep ( ms : number ) : Promise < void > {
357+ return new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
358+ }
359+
360+ /** Get service url or tagged revision url */
361+ function getUrl ( serviceResponse : run_v1 . Schema$Service ) : string {
362+ const revisionName = get ( serviceResponse , 'spec.template.metadata.name' ) ;
363+ // Find revision url
364+ const traffic : run_v1 . Schema$TrafficTarget [ ] = get (
365+ serviceResponse ,
366+ 'status.traffic' ,
367+ ) ;
368+ let revision ;
369+ if ( traffic ) {
370+ revision = traffic . find ( ( revision ) => {
371+ return revision . revisionName == revisionName && revision . url ;
372+ } ) ;
373+ }
374+ // Or return service url
375+ return get ( revision , 'url' ) || get ( serviceResponse , 'status.url' ) || '' ;
302376}
0 commit comments