1
1
import * as clc from "colorette" ;
2
2
import * as _ from "lodash" ;
3
3
4
- import { FirebaseError } from "../../error" ;
5
4
import {
6
5
addFirebaseToCloudProjectAndLog ,
7
6
createFirebaseProjectAndLog ,
8
7
getFirebaseProject ,
9
- getOrPromptProject ,
10
8
promptAvailableProjectId ,
11
9
promptProjectCreation ,
10
+ selectProjectInteractively ,
12
11
} from "../../management/projects" ;
13
12
import { FirebaseProjectMetadata } from "../../types/project" ;
14
13
import { logger } from "../../logger" ;
15
14
import * as utils from "../../utils" ;
16
15
import * as prompt from "../../prompt" ;
17
- import { Options } from "../../options" ;
16
+ import { requireAuth } from "../../requireAuth" ;
17
+ import { Constants } from "../../emulator/constants" ;
18
+ import { FirebaseError } from "../../error" ;
18
19
19
20
const OPTION_NO_PROJECT = "Don't set up a default project" ;
20
21
const OPTION_USE_PROJECT = "Use an existing project" ;
21
22
const OPTION_NEW_PROJECT = "Create a new project" ;
22
23
const OPTION_ADD_FIREBASE = "Add Firebase to an existing Google Cloud Platform project" ;
23
24
24
- /**
25
- * Used in init flows to keep information about the project - basically
26
- * a shorter version of {@link FirebaseProjectMetadata} with some additional fields.
27
- */
28
- export interface InitProjectInfo {
29
- id : string ; // maps to FirebaseProjectMetadata.projectId
30
- label ?: string ;
31
- instance ?: string ; // maps to FirebaseProjectMetadata.resources.realtimeDatabaseInstance
32
- location ?: string ; // maps to FirebaseProjectMetadata.resources.locationId
33
- }
34
-
35
- function toInitProjectInfo ( projectMetaData : FirebaseProjectMetadata ) : InitProjectInfo {
36
- const { projectId, displayName, resources } = projectMetaData ;
37
- return {
38
- id : projectId ,
39
- label : `${ projectId } ` + ( displayName ? ` (${ displayName } )` : "" ) ,
40
- instance : resources ?. realtimeDatabaseInstance ,
41
- location : resources ?. locationId ,
42
- } ;
43
- }
44
-
45
- async function promptAndCreateNewProject ( options : Options ) : Promise < FirebaseProjectMetadata > {
46
- utils . logBullet (
47
- "If you want to create a project in a Google Cloud organization or folder, please use " +
48
- `"firebase projects:create" instead, and return to this command when you've created the project.` ,
49
- ) ;
50
- const { projectId, displayName } = await promptProjectCreation ( options ) ;
51
- // N.B. This shouldn't be possible because of the validator on the input field, but it
52
- // is being left around in case there's something I don't know.
53
- if ( ! projectId ) {
54
- throw new FirebaseError ( "Project ID cannot be empty" ) ;
55
- }
56
-
57
- return await createFirebaseProjectAndLog ( projectId , { displayName } ) ;
58
- }
59
-
60
- async function promptAndAddFirebaseToCloudProject ( ) : Promise < FirebaseProjectMetadata > {
61
- const projectId = await promptAvailableProjectId ( ) ;
62
- if ( ! projectId ) {
63
- // N.B. This shouldn't be possible because of the validator on the input field, but it
64
- // is being left around in case there's something I don't know.
65
- throw new FirebaseError ( "Project ID cannot be empty" ) ;
66
- }
67
- return await addFirebaseToCloudProjectAndLog ( projectId ) ;
68
- }
69
-
70
- /**
71
- * Prompt the user about how they would like to select a project.
72
- * @param options the Firebase CLI options object.
73
- * @return the project metadata, or undefined if no project was selected.
74
- */
75
- async function projectChoicePrompt ( options : any ) : Promise < FirebaseProjectMetadata | undefined > {
76
- const choices = [ OPTION_USE_PROJECT , OPTION_NEW_PROJECT , OPTION_ADD_FIREBASE , OPTION_NO_PROJECT ] ;
77
- const projectSetupOption : string = await prompt . select < ( typeof choices ) [ number ] > ( {
78
- message : "Please select an option:" ,
79
- choices,
80
- } ) ;
81
-
82
- switch ( projectSetupOption ) {
83
- case OPTION_USE_PROJECT :
84
- return getOrPromptProject ( options ) ;
85
- case OPTION_NEW_PROJECT :
86
- return promptAndCreateNewProject ( options ) ;
87
- case OPTION_ADD_FIREBASE :
88
- return promptAndAddFirebaseToCloudProject ( ) ;
89
- default :
90
- // Do nothing if user chooses NO_PROJECT
91
- return ;
92
- }
93
- }
94
-
95
25
/**
96
26
* Sets up the default project if provided and writes .firebaserc file.
97
27
* @param setup A helper object to use for the rest of the init features.
@@ -106,52 +36,94 @@ export async function doSetup(setup: any, config: any, options: any): Promise<vo
106
36
logger . info (
107
37
`You can create multiple project aliases by running ${ clc . bold ( "firebase use --add" ) } , ` ,
108
38
) ;
109
- logger . info ( `but for now we'll just set up a default project.` ) ;
110
39
logger . info ( ) ;
111
40
41
+ if ( options . project ) {
42
+ // If the user presented a project with `--project`, try to fetch that project.
43
+ if ( Constants . isDemoProject ( options . project ) ) {
44
+ logger . info ( `Skipping Firebase project setup because a demo project is provided` ) ;
45
+ return ;
46
+ }
47
+ await requireAuth ( options ) ;
48
+ await usingProject ( setup , config , options . project ) ;
49
+ return ;
50
+ }
112
51
const projectFromRcFile = setup . rcfile ?. projects ?. default ;
113
- if ( projectFromRcFile && ! options . project ) {
114
- utils . logBullet ( `.firebaserc already has a default project, using ${ projectFromRcFile } .` ) ;
115
- // we still need to get project info in case user wants to init firestore or storage, which
116
- // require a resource location:
117
- const rcProject : FirebaseProjectMetadata = await getFirebaseProject ( projectFromRcFile ) ;
118
- setup . projectId = rcProject . projectId ;
119
- setup . projectLocation = rcProject ?. resources ?. locationId ;
52
+ if ( projectFromRcFile ) {
53
+ await requireAuth ( options ) ;
54
+ await usingProject ( setup , config , projectFromRcFile as string , ".firebaserc" ) ;
120
55
return ;
121
56
}
122
-
123
- let projectMetaData ;
124
- if ( options . project ) {
125
- // If the user presented a project with `--project`, try to fetch that project.
126
- logger . debug ( `Using project from CLI flag: ${ options . project } ` ) ;
127
- projectMetaData = await getFirebaseProject ( options . project ) ;
128
- } else {
129
- const projectEnvVar = utils . envOverride ( "FIREBASE_PROJECT" , "" ) ;
57
+ const projectEnvVar = utils . envOverride ( "FIREBASE_PROJECT" , "" ) ;
58
+ if ( projectEnvVar ) {
130
59
// If env var $FIREBASE_PROJECT is set, try to fetch that project.
131
60
// This is used in some shell scripts e.g. under https://firebase.tools/.
132
- if ( projectEnvVar ) {
133
- logger . debug ( `Using project from $FIREBASE_PROJECT: ${ projectEnvVar } ` ) ;
134
- projectMetaData = await getFirebaseProject ( projectEnvVar ) ;
135
- } else {
136
- if ( options . nonInteractive ) {
137
- logger . info (
138
- "No default project found. Continuing without a project in non interactive mode." ,
139
- ) ;
140
- return ;
141
- }
142
- projectMetaData = await projectChoicePrompt ( options ) ;
143
- if ( ! projectMetaData ) {
144
- return ;
145
- }
61
+ await requireAuth ( options ) ;
62
+ await usingProject ( setup , config , projectEnvVar , "$FIREBASE_PROJECT" ) ;
63
+ return ;
64
+ }
65
+ if ( options . nonInteractive ) {
66
+ logger . info ( "No default project found. Continuing without a project in non interactive mode." ) ;
67
+ return ;
68
+ }
69
+
70
+ // Prompt users about how to setup a project.
71
+ const choices = [ OPTION_USE_PROJECT , OPTION_NEW_PROJECT , OPTION_ADD_FIREBASE , OPTION_NO_PROJECT ] ;
72
+ const projectSetupOption : string = await prompt . select < ( typeof choices ) [ number ] > ( {
73
+ message : "Please select an option:" ,
74
+ choices,
75
+ } ) ;
76
+ switch ( projectSetupOption ) {
77
+ case OPTION_USE_PROJECT : {
78
+ await requireAuth ( options ) ;
79
+ const pm = await selectProjectInteractively ( ) ;
80
+ return await usingProjectMetadata ( setup , config , pm ) ;
81
+ }
82
+ case OPTION_NEW_PROJECT : {
83
+ utils . logBullet (
84
+ "If you want to create a project in a Google Cloud organization or folder, please use " +
85
+ `"firebase projects:create" instead, and return to this command when you've created the project.` ,
86
+ ) ;
87
+ await requireAuth ( options ) ;
88
+ const { projectId, displayName } = await promptProjectCreation ( options ) ;
89
+ const pm = await createFirebaseProjectAndLog ( projectId , { displayName } ) ;
90
+ return await usingProjectMetadata ( setup , config , pm ) ;
91
+ }
92
+ case OPTION_ADD_FIREBASE : {
93
+ await requireAuth ( options ) ;
94
+ const pm = await addFirebaseToCloudProjectAndLog ( await promptAvailableProjectId ( ) ) ;
95
+ return await usingProjectMetadata ( setup , config , pm ) ;
146
96
}
97
+ default :
98
+ // Do nothing if user chooses NO_PROJECT
99
+ return ;
147
100
}
101
+ }
148
102
149
- const projectInfo = toInitProjectInfo ( projectMetaData ) ;
150
- utils . logBullet ( `Using project ${ projectInfo . label } ` ) ;
103
+ async function usingProject (
104
+ setup : any ,
105
+ config : any ,
106
+ projectId : string ,
107
+ from : string = "" ,
108
+ ) : Promise < void > {
109
+ const pm = await getFirebaseProject ( projectId ) ;
110
+ const label = `${ pm . projectId } ` + ( pm . displayName ? ` (${ pm . displayName } )` : "" ) ;
111
+ utils . logBullet ( `Using project ${ label } ${ from ? "from ${from}" : "" } .` ) ;
112
+ await usingProjectMetadata ( setup , config , pm ) ;
113
+ }
114
+
115
+ async function usingProjectMetadata (
116
+ setup : any ,
117
+ config : any ,
118
+ pm : FirebaseProjectMetadata ,
119
+ ) : Promise < void > {
120
+ if ( ! pm ) {
121
+ throw new FirebaseError ( "null FirebaseProjectMetadata" ) ;
122
+ }
151
123
// write "default" alias and activate it immediately
152
- _ . set ( setup . rcfile , "projects.default" , projectInfo . id ) ;
153
- setup . projectId = projectInfo . id ;
154
- setup . instance = projectInfo . instance ;
155
- setup . projectLocation = projectInfo . location ;
156
- utils . makeActiveProject ( config . projectDir , projectInfo . id ) ;
124
+ _ . set ( setup . rcfile , "projects.default" , pm . projectId ) ;
125
+ setup . projectId = pm . projectId ;
126
+ setup . instance = pm . resources ?. realtimeDatabaseInstance ;
127
+ setup . projectLocation = pm . resources ?. locationId ;
128
+ utils . makeActiveProject ( config . projectDir , pm . projectId ) ;
157
129
}
0 commit comments