Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import { errNoDefaultSite } from "../getDefaultHostingSite";
import { FirebaseError } from "../error";
import { bold } from "colorette";
import { interactiveCreateHostingSite } from "../hosting/interactive";
import { pickHostingSiteName } from "../hosting/interactive";
import { logBullet } from "../utils";
import { createSite } from "../hosting/api";
import { Options } from "../options";

// in order of least time-consuming to most time-consuming
export const VALID_DEPLOY_TARGETS = [
Expand Down Expand Up @@ -98,26 +100,26 @@
"In order to provide better validation, this may still enable APIs on the target project",
)
.before(requireConfig)
.before((options) => {
.before((options: Options) => {
options.filteredTargets = filterTargets(options, VALID_DEPLOY_TARGETS);
const permissions = options.filteredTargets.reduce((perms: string[], target: string) => {
return perms.concat(TARGET_PERMISSIONS[target]);
}, []);
return requirePermissions(options, permissions);
})
.before((options) => {
.before((options: Options) => {
if (options.filteredTargets.includes("functions")) {
return checkServiceAccountIam(options.project);
return checkServiceAccountIam(options.project!);

Check warning on line 112 in src/commands/deploy.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Forbidden non-null assertion
}
})
.before(async (options) => {
.before(async (options: Options) => {
// only fetch the default instance for hosting or database deploys
if (options.filteredTargets.includes("database")) {
await requireDatabaseInstance(options);
}

if (options.filteredTargets.includes("hosting")) {
let createSite = false;
let shouldCreateSite = false;
try {
await requireHostingSite(options);
} catch (err: unknown) {
Expand All @@ -128,10 +130,10 @@
if (isPermissionError) {
throw err;
} else if (err === errNoDefaultSite) {
createSite = true;
shouldCreateSite = true;
}
}
if (!createSite) {
if (!shouldCreateSite) {
return;
}
if (options.nonInteractive) {
Expand All @@ -142,10 +144,11 @@
);
}
logBullet("No Hosting site detected.");
await interactiveCreateHostingSite("", "", options);
const siteId = await pickHostingSiteName("", options);
await createSite(options.project!, siteId);

Check warning on line 148 in src/commands/deploy.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Forbidden non-null assertion
}
})
.before(checkValidTargetFilters)
.action((options) => {
return deploy(options.filteredTargets, options);

Check warning on line 153 in src/commands/deploy.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `DeployOptions`

Check warning on line 153 in src/commands/deploy.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .filteredTargets on an `any` value

Check warning on line 153 in src/commands/deploy.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `("database" | "storage" | "firestore" | "functions" | "hosting" | "remoteconfig" | "extensions" | "dataconnect" | "apphosting")[]`
});
14 changes: 7 additions & 7 deletions src/commands/hosting-sites-create.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { bold } from "colorette";

import { Command } from "../command";
import { interactiveCreateHostingSite } from "../hosting/interactive";
import { last, logLabeledSuccess } from "../utils";
import { pickHostingSiteName } from "../hosting/interactive";
import { logLabeledSuccess } from "../utils";
import { logger } from "../logger";
import { needProjectId } from "../projectUtils";
import { Options } from "../options";
import { requirePermissions } from "../requirePermissions";
import { Site } from "../hosting/api";
import { createSite, Site } from "../hosting/api";
import { FirebaseError } from "../error";

const LOG_TAG = "hosting:sites";
Expand All @@ -16,16 +16,16 @@ export const command = new Command("hosting:sites:create [siteId]")
.description("create a Firebase Hosting site")
.option("--app <appId>", "specify an existing Firebase Web App ID")
.before(requirePermissions, ["firebasehosting.sites.update"])
.action(async (siteId: string, options: Options & { app: string }): Promise<Site> => {
.action(async (siteId: string | undefined, options: Options & { app: string }): Promise<Site> => {
const projectId = needProjectId(options);
const appId = options.app;

if (options.nonInteractive && !siteId) {
throw new FirebaseError(`${bold(siteId)} is required in a non-interactive environment`);
throw new FirebaseError(`${bold("siteId")} is required in a non-interactive environment`);
}

const site = await interactiveCreateHostingSite(siteId, appId, options);
siteId = last(site.name.split("/"));
siteId = await pickHostingSiteName(siteId ?? "", options);
const site = await createSite(projectId, siteId, appId);

logger.info();
logLabeledSuccess(
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@

export const supportedRange = "16 - 20";

export async function discover(dir: string): Promise<Discovery | undefined> {

Check warning on line 41 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment
if (!(await pathExists(join(dir, "package.json")))) return;
if (!(await pathExists(join(dir, "angular.json")))) return;
const version = getAngularVersion(dir);
return { mayWantBackend: true, version };
}

export function init(setup: any, config: any) {

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
execSync(
`npx --yes -p @angular/cli@"${supportedRange}" ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`,
`npx --yes -p @angular/cli@"${supportedRange}" ng new ${setup.projectId} --directory ${setup.featureInfo.hosting.source} --skip-git`,
{
stdio: "inherit",
cwd: config.projectDir,
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/flutter/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describe("Flutter", () => {

const stub = sandbox.stub(crossSpawn, "sync").returns(process as any);

const result = init({ projectId, hosting: { source } }, { projectDir });
const result = init({ projectId, featureInfo: { hosting: { source } } }, { projectDir });

expect(await result).to.eql(undefined);
sinon.assert.calledWith(
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/flutter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function init(setup: any, config: any) {
`--project-name=${projectName}`,
"--overwrite",
"--platforms=web",
setup.hosting.source,
setup.featureInfo.hosting.source,
],
{ stdio: "inherit", cwd: config.projectDir },
);
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ export async function init(setup: any, config: any) {
});
execSync(
`npx --yes create-next-app@"${supportedRange}" -e hello-world ` +
`${setup.hosting.source} --use-npm --${language}`,
`${setup.featureInfo.hosting.source} --use-npm --${language}`,
{ stdio: "inherit", cwd: config.projectDir },
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/frameworks/nuxt/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export async function getConfig(cwd: string): Promise<NuxtOptions> {
* Utility method used during project initialization.
*/
export function init(setup: any, config: any) {
execSync(`npx --yes nuxi@"${supportedRange}" init ${setup.hosting.source}`, {
execSync(`npx --yes nuxi@"${supportedRange}" init ${setup.featureInfo.hosting.source}`, {
stdio: "inherit",
cwd: config.projectDir,
});
Expand Down
7 changes: 5 additions & 2 deletions src/frameworks/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,16 @@ export async function init(setup: any, config: any, baseTemplate: string = "vani
],
});
execSync(
`npm create vite@"${supportedRange}" ${setup.hosting.source} --yes -- --template ${template}`,
`npm create vite@"${supportedRange}" ${setup.featureInfo.hosting.source} --yes -- --template ${template}`,
{
stdio: "inherit",
cwd: config.projectDir,
},
);
execSync(`npm install`, { stdio: "inherit", cwd: join(config.projectDir, setup.hosting.source) });
execSync(`npm install`, {
stdio: "inherit",
cwd: join(config.projectDir, setup.featureInfo.hosting.source),
});
}

export const viteDiscoverWithNpmDependency = (dep: string) => async (dir: string) =>
Expand Down
36 changes: 15 additions & 21 deletions src/hosting/interactive.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FirebaseError } from "../error";
import { logWarning } from "../utils";
import { needProjectId, needProjectNumber } from "../projectUtils";
import { Site, createSite } from "./api";
import { createSite } from "./api";
import { input } from "../prompt";

const nameSuggestion = new RegExp("try something like `(.+)`");
Expand All @@ -11,17 +11,16 @@ const prompt =
'We recommend using letters, numbers, and hyphens (e.g. "{project-id}-{random-hash}"):';

/**
* Interactively prompt to create a Hosting site.
* Interactively prompt to name a Hosting site.
*/
export async function interactiveCreateHostingSite(
export async function pickHostingSiteName(
siteId: string,
appId: string,
options: { projectId?: string; nonInteractive?: boolean },
): Promise<Site> {
): Promise<string> {
const projectId = needProjectId(options);
const projectNumber = await needProjectNumber(options);
let id = siteId;
let newSite: Site | undefined;
let nameConfirmed: boolean = false;
let suggestion: string | undefined;

// If we were given an ID, we're going to start with that, so don't check the project ID.
Expand All @@ -35,34 +34,26 @@ export async function interactiveCreateHostingSite(
}
}

while (!newSite) {
while (!nameConfirmed) {
if (!id || suggestion) {
id = await input({
message: prompt,
validate: (s: string) => s.length > 0, // Prevents an empty string from being submitted!
default: suggestion,
});
}
try {
newSite = await createSite(projectNumber, id, appId);
} catch (err: unknown) {
if (!(err instanceof FirebaseError)) {
throw err;
}
if (options.nonInteractive) {
throw err;
}

id = ""; // Clear so the prompt comes back.
suggestion = getSuggestionFromError(err);
}
const attempt = await trySiteID(projectNumber, id, options.nonInteractive);
nameConfirmed = attempt.available;
suggestion = attempt.suggestion;
if (!nameConfirmed) id = ""; // Clear so the prompt comes back.
}
return newSite;
return id;
}

async function trySiteID(
projectNumber: string,
id: string,
nonInteractive = false,
): Promise<{ available: boolean; suggestion?: string }> {
try {
await createSite(projectNumber, id, "", true);
Expand All @@ -71,6 +62,9 @@ async function trySiteID(
if (!(err instanceof FirebaseError)) {
throw err;
}
if (nonInteractive) {
throw err;
}
const suggestion = getSuggestionFromError(err);
return { available: false, suggestion };
}
Expand Down
Loading
Loading