Skip to content

Commit

Permalink
Adding extensions to firebase init (#5701)
Browse files Browse the repository at this point in the history
* Adding extensions to firebase init

* changelog

* Formats
  • Loading branch information
joehan committed Apr 17, 2023
1 parent f5786fd commit d1244ee
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 33 deletions.
13 changes: 7 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
- Adds new commands for provisioning and managing Firestore databases: (#5616)
- firestore:databases:list
- firestore:databases:create
- firestore:databases:get
- firestore:databases:update
- firestore:databases:delete
- firestore:locations
- firestore:databases:list
- firestore:databases:create
- firestore:databases:get
- firestore:databases:update
- firestore:databases:delete
- firestore:locations
- Adds `extensions` as an option in `firebase init`.
- Relaxed repo URI validation in ext:dev:publish (#5698).
2 changes: 1 addition & 1 deletion src/commands/ext-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import * as refs from "../extensions/refs";
import { displayWarningPrompts } from "../extensions/warnings";
import * as paramHelper from "../extensions/paramHelper";
import {
confirm,
createSourceFromLocation,
ensureExtensionsApiEnabled,
logPrefix,
Expand All @@ -25,6 +24,7 @@ import {
isLocalPath,
canonicalizeRefInput,
} from "../extensions/extensionsHelper";
import { confirm } from "../prompt";
import { getRandomString } from "../extensions/utils";
import { requirePermissions } from "../requirePermissions";
import * as utils from "../utils";
Expand Down
2 changes: 1 addition & 1 deletion src/commands/ext-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
logPrefix,
getSourceOrigin,
SourceOrigin,
confirm,
diagnoseAndFixProject,
isLocalPath,
} from "../extensions/extensionsHelper";
import * as paramHelper from "../extensions/paramHelper";
import { inferUpdateSource } from "../extensions/updateHelper";
import * as refs from "../extensions/refs";
import { getProjectId } from "../projectUtils";
import { confirm } from "../prompt";
import { requirePermissions } from "../requirePermissions";
import * as utils from "../utils";
import * as experiments from "../experiments";
Expand Down
5 changes: 5 additions & 0 deletions src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ const choices = [
name: "Remote Config: Configure a template file for Remote Config",
checked: false,
},
{
value: "extensions",
name: "Extensions: Set up an empty Extensions manifest",
checked: false,
},
];
const featureNames = choices.map((choice) => choice.value);

Expand Down
24 changes: 1 addition & 23 deletions src/extensions/extensionsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import {
import { Extension, ExtensionSource, ExtensionSpec, ExtensionVersion, Param } from "./types";
import * as refs from "./refs";
import { EXTENSIONS_SPEC_FILE, readFile, getLocalExtensionSpec } from "./localHelper";
import { promptOnce } from "../prompt";
import { confirm, promptOnce } from "../prompt";
import { logger } from "../logger";
import { envOverride } from "../utils";
import { getLocalChangelog } from "./change-log";
Expand Down Expand Up @@ -1037,28 +1037,6 @@ export function getSourceOrigin(sourceOrVersion: string): SourceOrigin {
);
}

/**
* Confirm if the user wants to continue
*/
export async function confirm(args: {
nonInteractive?: boolean;
force?: boolean;
default?: boolean;
}): Promise<boolean> {
if (!args.nonInteractive && !args.force) {
const message = `Do you wish to continue?`;
return await promptOnce({
type: "confirm",
message,
default: args.default,
});
} else if (args.nonInteractive && !args.force) {
throw new FirebaseError("Pass the --force flag to use this command in non-interactive mode");
} else {
return true;
}
}

export async function diagnoseAndFixProject(options: any): Promise<void> {
const projectId = getProjectId(options);
if (!projectId) {
Expand Down
31 changes: 29 additions & 2 deletions src/extensions/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import * as clc from "colorette";
import * as path from "path";
import * as fs from "fs-extra";

import * as refs from "./refs";
import { Config } from "../config";
import { getExtensionSpec, ManifestInstanceSpec } from "../deploy/extensions/planner";
import { logger } from "../logger";
import { promptOnce } from "../prompt";
import { confirm, promptOnce } from "../prompt";
import { readEnvFile } from "./paramHelper";
import { FirebaseError } from "../error";
import * as utils from "../utils";
Expand Down Expand Up @@ -60,6 +62,31 @@ export async function writeToManifest(
await writeLocalSecrets(specs, config, options.force);
}

export async function writeEmptyManifest(
config: Config,
options: { nonInteractive: boolean; force: boolean }
): Promise<void> {
if (!fs.existsSync(config.path("extensions"))) {
fs.mkdirSync(config.path("extensions"));
}
if (config.has("extensions") && Object.keys(config.get("extensions")).length) {
const currentExtensions = Object.entries(config.get("extensions"))
.map((i) => `${i[0]}: ${i[1]}`)
.join("\n\t");
if (
!(await confirm({
message: `firebase.json already contains extensions:\n${currentExtensions}\nWould you like to overwrite them?`,
nonInteractive: options.nonInteractive,
force: options.force,
default: false,
}))
) {
return;
}
}
config.set("extensions", {});
}

/**
* Write the secrets in a list of ManifestInstanceSpec into extensions/{instance-id}.secret.local.
*
Expand Down Expand Up @@ -173,7 +200,7 @@ export function getInstanceRef(instanceId: string, config: Config): refs.Ref {
return refs.parse(source);
}

function writeExtensionsToFirebaseJson(specs: ManifestInstanceSpec[], config: Config): void {
export function writeExtensionsToFirebaseJson(specs: ManifestInstanceSpec[], config: Config): void {
const extensions = config.get("extensions", {});
for (const s of specs) {
let target;
Expand Down
17 changes: 17 additions & 0 deletions src/init/features/extensions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { requirePermissions } from "../../../requirePermissions";
import { Options } from "../../../options";
import { ensure } from "../../../ensureApiEnabled";
import { Config } from "../../../config";
import * as manifest from "../../../extensions/manifest";

/**
* Set up a new firebase project for extensions.
*/
export async function doSetup(setup: any, config: Config, options: Options): Promise<any> {
const projectId = setup?.rcfile?.projects?.default;
if (projectId) {
await requirePermissions({ ...options, project: projectId });
await Promise.all([ensure(projectId, "firebaseextensions.googleapis.com", "unused", true)]);
}
return manifest.writeEmptyManifest(config, options);
}
1 change: 1 addition & 0 deletions src/init/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { doSetup as functions } from "./functions";
export { doSetup as hosting } from "./hosting";
export { doSetup as storage } from "./storage";
export { doSetup as emulators } from "./emulators";
export { doSetup as extensions } from "./extensions";
// always runs, sets up .firebaserc
export { doSetup as project } from "./project";
export { doSetup as remoteconfig } from "./remoteconfig";
Expand Down
1 change: 1 addition & 0 deletions src/init/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const featureFns = new Map<string, (setup: any, config: any, options?: any) => P
["hosting", features.hosting],
["storage", features.storage],
["emulators", features.emulators],
["extensions", features.extensions],
["project", features.project], // always runs, sets up .firebaserc
["remoteconfig", features.remoteconfig],
["hosting:github", features.hostingGithub],
Expand Down
23 changes: 23 additions & 0 deletions src/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,26 @@ export async function promptOnce<A>(question: Question, options: Options = {}):
await prompt(options, [question]);
return options[question.name];
}

/**
* Confirm if the user wants to continue
*/
export async function confirm(args: {
nonInteractive?: boolean;
force?: boolean;
default?: boolean;
message?: string;
}): Promise<boolean> {
if (!args.nonInteractive && !args.force) {
const message = args.message ?? `Do you wish to continue?`;
return await promptOnce({
type: "confirm",
message,
default: args.default,
});
} else if (args.nonInteractive && !args.force) {
throw new FirebaseError("Pass the --force flag to use this command in non-interactive mode");
} else {
return true;
}
}

0 comments on commit d1244ee

Please sign in to comment.