@@ -4,7 +4,13 @@ import * as poller from "../../../operation-poller";
4
4
import * as apphosting from "../../../gcp/apphosting" ;
5
5
import { logBullet , logSuccess , logWarning } from "../../../utils" ;
6
6
import { apphostingOrigin } from "../../../api" ;
7
- import { Backend , BackendOutputOnlyFields , API_VERSION } from "../../../gcp/apphosting" ;
7
+ import {
8
+ Backend ,
9
+ BackendOutputOnlyFields ,
10
+ API_VERSION ,
11
+ Build ,
12
+ BuildInput ,
13
+ } from "../../../gcp/apphosting" ;
8
14
import { Repository } from "../../../gcp/cloudbuild" ;
9
15
import { FirebaseError } from "../../../error" ;
10
16
import { promptOnce } from "../../../prompt" ;
@@ -66,27 +72,50 @@ export async function doSetup(setup: any, projectId: string): Promise<void> {
66
72
}
67
73
logWarning ( `Backend with id ${ backendId } already exists in ${ location } ` ) ;
68
74
}
69
- const backend : Backend = await onboardBackend ( projectId , location , backendId ) ;
75
+ const backend = await onboardBackend ( projectId , location , backendId ) ;
76
+
77
+ const branch = await promptOnce ( {
78
+ name : "branch" ,
79
+ type : "input" ,
80
+ default : "main" ,
81
+ message : "Which branch do you want to deploy?" ,
82
+ } ) ;
83
+ const build = await createBuild ( projectId , location , backendId , {
84
+ source : {
85
+ codebase : {
86
+ branch,
87
+ } ,
88
+ } ,
89
+ } ) ;
90
+
91
+ if ( build . state !== "READY" ) {
92
+ throw new FirebaseError (
93
+ `Failed to build your app. Please inspect the build logs at ${ build . buildLogsUri } .` ,
94
+ { children : [ build . error ] }
95
+ ) ;
96
+ }
97
+
98
+ await setDefaultTraffic ( projectId , location , backendId , build . name . split ( "/" ) . pop ( ) ! ) ;
70
99
71
100
if ( backend ) {
72
101
logSuccess ( `Successfully created backend:\n\t${ backend . name } ` ) ;
73
- logSuccess ( `Your site is being deployed at:\n\thttps://${ backend . uri } ` ) ;
102
+ logSuccess ( `Your site is now deployed at:\n\thttps://${ backend . uri } ` ) ;
74
103
logSuccess (
75
104
`View the rollout status by running:\n\tfirebase apphosting:backends:get ${ backendId } --project ${ projectId } `
76
105
) ;
77
106
}
78
107
}
79
108
80
109
async function promptLocation ( projectId : string , locations : string [ ] ) : Promise < string > {
81
- return await promptOnce ( {
110
+ return ( await promptOnce ( {
82
111
name : "region" ,
83
112
type : "list" ,
84
113
default : DEFAULT_REGION ,
85
114
message :
86
115
"Please select a region " +
87
116
`(${ clc . yellow ( "info" ) } : Your region determines where your backend is located):\n` ,
88
117
choices : locations . map ( ( loc ) => ( { value : loc } ) ) ,
89
- } ) ;
118
+ } ) ) as string ;
90
119
}
91
120
92
121
function toBackend ( cloudBuildConnRepo : Repository ) : Omit < Backend , BackendOutputOnlyFields > {
@@ -109,20 +138,12 @@ export async function onboardBackend(
109
138
backendId : string
110
139
) : Promise < Backend > {
111
140
const cloudBuildConnRepo = await repo . linkGitHubRepository ( projectId , location ) ;
112
- const barnchName = await promptOnce ( {
113
- name : "branchName" ,
114
- type : "input" ,
115
- default : "main" ,
116
- message : "Which branch do you want to deploy?" ,
117
- } ) ;
118
- // branchName unused for now.
119
- void barnchName ;
120
141
const backendDetails = toBackend ( cloudBuildConnRepo ) ;
121
142
return await createBackend ( projectId , location , backendDetails , backendId ) ;
122
143
}
123
144
124
145
/**
125
- * Creates backend object from long running operations .
146
+ * Creates (and waits for) a new backend .
126
147
*/
127
148
export async function createBackend (
128
149
projectId : string ,
@@ -136,6 +157,69 @@ export async function createBackend(
136
157
pollerName : `create-${ projectId } -${ location } -${ backendId } ` ,
137
158
operationResourceName : op . name ,
138
159
} ) ;
139
-
140
160
return backend ;
141
161
}
162
+
163
+ /**
164
+ * Only lowercase, digits, and hyphens; must begin with letter, and cannot end with hyphen
165
+ */
166
+ function generateBuildId ( n = 6 ) {
167
+ const letters = "abcdefghijklmnopqrstuvwxyz" ;
168
+ const allChars = "01234567890-abcdefghijklmnopqrstuvwxyz" ;
169
+ let id = letters [ Math . floor ( Math . random ( ) * letters . length ) ] ;
170
+ for ( let i = 1 ; i < n ; i ++ ) {
171
+ const idx = Math . floor ( Math . random ( ) * allChars . length ) ;
172
+ id += allChars [ idx ] ;
173
+ }
174
+ return id ;
175
+ }
176
+
177
+ /**
178
+ * Create (and waits for) a new build.
179
+ */
180
+ export async function createBuild (
181
+ projectId : string ,
182
+ location : string ,
183
+ backendId : string ,
184
+ buildInput : Omit < BuildInput , "name" >
185
+ ) : Promise < Build > {
186
+ logBullet ( "Creating a new build... this may take a few minutes." ) ;
187
+ const buildId = generateBuildId ( ) ;
188
+ const op = await apphosting . createBuild ( projectId , location , backendId , buildId , buildInput ) ;
189
+ const build = await poller . pollOperation < Build > ( {
190
+ ...apphostingPollerOptions ,
191
+ pollerName : `create-${ projectId } -${ location } -backend-${ backendId } -build-${ buildId } ` ,
192
+ operationResourceName : op . name ,
193
+ } ) ;
194
+ logSuccess ( "Build finished." ) ;
195
+ return build ;
196
+ }
197
+
198
+ /**
199
+ * Set (and waits for) a default traffic that directs all traffic to the buildId.
200
+ */
201
+ export async function setDefaultTraffic (
202
+ projectId : string ,
203
+ location : string ,
204
+ backendId : string ,
205
+ buildId : string
206
+ ) : Promise < Build > {
207
+ logBullet ( "Directing traffic to the new build..." ) ;
208
+ const op = await apphosting . updateTraffic ( projectId , location , backendId , {
209
+ target : {
210
+ splits : [
211
+ {
212
+ build : buildId ,
213
+ percent : 100 ,
214
+ } ,
215
+ ] ,
216
+ } ,
217
+ } ) ;
218
+ const traffic = await poller . pollOperation < Build > ( {
219
+ ...apphostingPollerOptions ,
220
+ pollerName : `create-${ projectId } -${ location } -backend-${ backendId } -traffic` ,
221
+ operationResourceName : op . name ,
222
+ } ) ;
223
+ logSuccess ( "Traffic update finished." ) ;
224
+ return traffic ;
225
+ }
0 commit comments