Skip to content

Commit

Permalink
Merge e6a6c6b into 34c86a9
Browse files Browse the repository at this point in the history
  • Loading branch information
thechenky committed Jun 8, 2019
2 parents 34c86a9 + e6a6c6b commit 47a47b5
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 175 deletions.
35 changes: 0 additions & 35 deletions src/firebaseApi.js

This file was deleted.

49 changes: 49 additions & 0 deletions src/firebaseApi.ts
@@ -0,0 +1,49 @@
import * as api from "./api";

const API_VERSION = "v1beta1";

/**
* Represents the FirebaseProject resource returned from calling
* `projects.get` in Firebase Management API:
* https://firebase.google.com/docs/projects/api/reference/rest/v1beta1/projects#FirebaseProject
*/
export interface FirebaseProject {
projectId: string;
projectNumber: number;
displayName: string;
name: string;
resources: {
hostingSite?: string;
realtimeDatabaseInstance?: string;
storageBucket?: string;
locationId?: string;
};
}

export async function listProjects(
nextPageToken?: string,
projectsList: FirebaseProject[] = []
): Promise<FirebaseProject[]> {
let path = `/${API_VERSION}/projects?page_size=100`;
if (nextPageToken) {
path += `&page_token=${nextPageToken}`;
}

const response = await api.request("GET", path, {
auth: true,
origin: api.firebaseApiOrigin,
});
projectsList = projectsList.concat(response.body.results);
if (response.body.nextPageToken) {
return listProjects(response.body.nextPageToken, projectsList);
}
return projectsList;
}

export async function getProject(projectId: string): Promise<FirebaseProject> {
const response = await api.request("GET", `/${API_VERSION}/projects/${projectId}`, {
auth: true,
origin: api.firebaseApiOrigin,
});
return response.body;
}
4 changes: 2 additions & 2 deletions src/init/features/index.js
Expand Up @@ -5,7 +5,7 @@ module.exports = {
firestore: require("./firestore").doSetup,
functions: require("./functions"),
hosting: require("./hosting"),
storage: require("./storage"),
storage: require("./storage").doSetup,
// always runs, sets up .firebaserc
project: require("./project"),
project: require("./project").doSetup,
};
125 changes: 0 additions & 125 deletions src/init/features/project.js

This file was deleted.

148 changes: 148 additions & 0 deletions src/init/features/project.ts
@@ -0,0 +1,148 @@
import * as clc from "cli-color";
import * as _ from "lodash";

import * as Config from "../../config";
import { FirebaseProject, getProject, listProjects } from "../../firebaseApi";
import * as logger from "../../logger";
import { promptOnce, Question } from "../../prompt";
import * as utils from "../../utils";

const NO_PROJECT = "[don't setup a default project]";
const NEW_PROJECT = "[create a new project]";

/**
* Used in init flows to keep information about the project - basically
* a shorter version of {@link FirebaseProject} with some additional fields.
*/
export interface ProjectInfo {
id: string; // maps to FirebaseProject.projectId
label?: string;
instance?: string; // maps to FirebaseProject.resources.realtimeDatabaseInstance
location?: string; // maps to FirebaseProject.resources.locationId
}

/**
* Get the user's desired project, prompting if necessary.
* @returns A {@link ProjectInfo} object.
*/
async function getProjectInfo(options: any): Promise<ProjectInfo> {
if (options.project) {
return selectProjectFromOptions(options);
}
return selectProjectFromList(options);
}

/**
* Selects project when --project is passed in.
* @param options Command line options.
* @returns A {@link FirebaseProject} object.
*/
async function selectProjectFromOptions(options: any): Promise<ProjectInfo> {
let project: FirebaseProject;
try {
project = await getProject(options.project);
} catch (e) {
throw new Error(`Error getting project ${options.project}: ${e}`);
}
const projectId = project.projectId;
const name = project.displayName;
return {
id: projectId,
label: `${projectId} (${name})`,
instance: _.get(project, "resources.realtimeDatabaseInstance"),
};
}

/**
* Presents user with list of projects to choose from and gets project
* information for chosen project.
* @param options Command line options.
* @returns A {@link FirebaseProject} object.
*/
async function selectProjectFromList(options: any): Promise<ProjectInfo> {
let project: FirebaseProject | undefined;
const projects: FirebaseProject[] = await listProjects();
let choices = projects.filter((p: FirebaseProject) => !!p).map((p) => {
return {
name: `${p.projectId} (${p.displayName})`,
value: p.projectId,
};
});
choices = _.orderBy(choices, ["name"], ["asc"]);
choices.unshift({ name: NO_PROJECT, value: NO_PROJECT });
choices.push({ name: NEW_PROJECT, value: NEW_PROJECT });

if (choices.length >= 25) {
utils.logBullet(
`Don't want to scroll through all your projects? If you know your project ID, ` +
`you can initialize it directly using ${clc.bold(
"firebase init --project <project_id>"
)}.\n`
);
}
const projectId: string = await promptOnce({
type: "list",
name: "id",
message: "Select a default Firebase project for this directory:",
validate: (answer: any) => {
if (!_.includes(choices, answer)) {
return `Must specify a Firebase project to which you have access.`;
}
return true;
},
choices,
} as Question);
if (projectId === NEW_PROJECT || projectId === NO_PROJECT) {
return { id: projectId };
}

project = projects.find((p) => p.projectId === projectId);
const pId = choices.find((p) => p.value === projectId);
const label = pId ? pId.name : "";

return {
id: projectId,
label,
instance: _.get(project, "resources.realtimeDatabaseInstance"),
};
}

/**
* Sets up the default project if provided and writes .firebaserc file.
* @param setup A helper object to use for the rest of the init features.
* @param config Configuration for the project.
* @param options Command line options.
*/
export async function doSetup(setup: any, config: Config, options: any): Promise<void> {
setup.project = {};

logger.info();
logger.info(`First, let's associate this project directory with a Firebase project.`);
logger.info(
`You can create multiple project aliases by running ${clc.bold("firebase use --add")}, `
);
logger.info(`but for now we'll just set up a default project.`);
logger.info();

if (_.has(setup.rcfile, "projects.default")) {
utils.logBullet(`.firebaserc already has a default project, skipping`);
setup.projectId = _.get(setup.rcfile, "projects.default");
return;
}

const projectInfo: ProjectInfo = await getProjectInfo(options);
if (projectInfo.id === NEW_PROJECT) {
setup.createProject = true;
return;
} else if (projectInfo.id === NO_PROJECT) {
return;
}

utils.logBullet(`Using project ${projectInfo.label}`);

// write "default" alias and activate it immediately
_.set(setup.rcfile, "projects.default", projectInfo.id);
setup.projectId = projectInfo.id;
setup.instance = projectInfo.instance;
utils.makeActiveProject(config.projectDir, projectInfo.id);
}

0 comments on commit 47a47b5

Please sign in to comment.