firebase-tools 13.7.2 → 13.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/apphosting/app.js +92 -0
- package/lib/apphosting/config.js +76 -10
- package/lib/apphosting/githubConnections.js +1 -1
- package/lib/apphosting/index.js +23 -11
- package/lib/apphosting/repo.js +1 -1
- package/lib/apphosting/secrets/dialogs.js +15 -14
- package/lib/commands/apphosting-backends-create.js +4 -2
- package/lib/commands/apphosting-backends-delete.js +4 -3
- package/lib/commands/apphosting-backends-get.js +8 -8
- package/lib/commands/apphosting-backends-list.js +2 -2
- package/lib/commands/apphosting-builds-create.js +32 -0
- package/lib/commands/apphosting-builds-get.js +18 -0
- package/lib/commands/apphosting-rollouts-create.js +26 -0
- package/lib/commands/apphosting-rollouts-list.js +21 -0
- package/lib/commands/apphosting-secrets-grantaccess.js +2 -2
- package/lib/commands/apphosting-secrets-set.js +9 -58
- package/lib/commands/functions-secrets-set.js +1 -17
- package/lib/commands/index.js +8 -0
- package/lib/deploy/functions/runtimes/discovery/index.js +3 -3
- package/lib/deploy/functions/runtimes/{supported.js → supported/index.js} +26 -81
- package/lib/deploy/functions/runtimes/supported/types.js +74 -0
- package/lib/extensions/emulator/specHelper.js +3 -3
- package/lib/extensions/extensionsApi.js +2 -2
- package/lib/extensions/localHelper.js +3 -3
- package/lib/frameworks/flutter/index.js +2 -2
- package/lib/init/features/hosting/github.js +4 -5
- package/lib/utils.js +17 -0
- package/package.json +3 -3
- package/templates/init/functions/typescript/_eslintrc +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fuzzy = require("fuzzy");
|
|
3
|
+
const inquirer = require("inquirer");
|
|
4
|
+
const apps_1 = require("../management/apps");
|
|
5
|
+
const prompt_1 = require("../prompt");
|
|
6
|
+
const error_1 = require("../error");
|
|
7
|
+
const CREATE_NEW_FIREBASE_WEB_APP = "CREATE_NEW_WEB_APP";
|
|
8
|
+
const CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP = "CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP";
|
|
9
|
+
const webApps = {
|
|
10
|
+
CREATE_NEW_FIREBASE_WEB_APP,
|
|
11
|
+
CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP,
|
|
12
|
+
getOrCreateWebApp,
|
|
13
|
+
promptFirebaseWebApp,
|
|
14
|
+
};
|
|
15
|
+
async function getOrCreateWebApp(projectId, firebaseWebAppName, backendId) {
|
|
16
|
+
const webAppsInProject = await (0, apps_1.listFirebaseApps)(projectId, apps_1.AppPlatform.WEB);
|
|
17
|
+
if (webAppsInProject.length === 0) {
|
|
18
|
+
const { displayName, appId } = await createFirebaseWebApp(projectId, {
|
|
19
|
+
displayName: backendId,
|
|
20
|
+
});
|
|
21
|
+
return { name: displayName, id: appId };
|
|
22
|
+
}
|
|
23
|
+
const existingUserProjectWebApps = new Map(webAppsInProject.map((obj) => {
|
|
24
|
+
var _a;
|
|
25
|
+
return [
|
|
26
|
+
(_a = obj.displayName) !== null && _a !== void 0 ? _a : obj.appId,
|
|
27
|
+
obj.appId,
|
|
28
|
+
];
|
|
29
|
+
}));
|
|
30
|
+
if (firebaseWebAppName) {
|
|
31
|
+
if (existingUserProjectWebApps.get(firebaseWebAppName) === undefined) {
|
|
32
|
+
throw new error_1.FirebaseError(`The web app '${firebaseWebAppName}' does not exist in project ${projectId}`);
|
|
33
|
+
}
|
|
34
|
+
return { name: firebaseWebAppName, id: existingUserProjectWebApps.get(firebaseWebAppName) };
|
|
35
|
+
}
|
|
36
|
+
return await webApps.promptFirebaseWebApp(projectId, backendId, existingUserProjectWebApps);
|
|
37
|
+
}
|
|
38
|
+
async function promptFirebaseWebApp(projectId, backendId, existingUserProjectWebApps) {
|
|
39
|
+
const existingWebAppKeys = Array.from(existingUserProjectWebApps.keys());
|
|
40
|
+
const firebaseWebAppName = await (0, prompt_1.promptOnce)({
|
|
41
|
+
type: "autocomplete",
|
|
42
|
+
name: "app",
|
|
43
|
+
message: "Which of the following Firebase web apps would you like to associate your backend with?",
|
|
44
|
+
source: (_, input = "") => {
|
|
45
|
+
return new Promise((resolve) => resolve([
|
|
46
|
+
new inquirer.Separator(),
|
|
47
|
+
{
|
|
48
|
+
name: "Create a new Firebase web app.",
|
|
49
|
+
value: CREATE_NEW_FIREBASE_WEB_APP,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "Continue without a Firebase web app.",
|
|
53
|
+
value: CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP,
|
|
54
|
+
},
|
|
55
|
+
new inquirer.Separator(),
|
|
56
|
+
...fuzzy.filter(input, existingWebAppKeys).map((result) => {
|
|
57
|
+
return result.original;
|
|
58
|
+
}),
|
|
59
|
+
]));
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
if (firebaseWebAppName === CREATE_NEW_FIREBASE_WEB_APP) {
|
|
63
|
+
const newFirebaseWebApp = await createFirebaseWebApp(projectId, { displayName: backendId });
|
|
64
|
+
return { name: newFirebaseWebApp.displayName, id: newFirebaseWebApp.appId };
|
|
65
|
+
}
|
|
66
|
+
else if (firebaseWebAppName === CONTINUE_WITHOUT_SELECTING_FIREBASE_WEB_APP) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
return { name: firebaseWebAppName, id: existingUserProjectWebApps.get(firebaseWebAppName) };
|
|
70
|
+
}
|
|
71
|
+
async function createFirebaseWebApp(projectId, options) {
|
|
72
|
+
try {
|
|
73
|
+
return await (0, apps_1.createWebApp)(projectId, options);
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
if (isQuotaError(e)) {
|
|
77
|
+
throw new error_1.FirebaseError("Unable to create a new web app, the project has reached the quota for Firebase apps. Navigate to your Firebase console to manage or delete a Firebase app to continue. ", { original: e instanceof Error ? e : undefined });
|
|
78
|
+
}
|
|
79
|
+
throw new error_1.FirebaseError("Unable to create a Firebase web app", {
|
|
80
|
+
original: e instanceof Error ? e : undefined,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function isQuotaError(error) {
|
|
85
|
+
var _a, _b, _c, _d, _e;
|
|
86
|
+
const original = error.original;
|
|
87
|
+
const code = (original === null || original === void 0 ? void 0 : original.status) ||
|
|
88
|
+
((_b = (_a = original === null || original === void 0 ? void 0 : original.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode) ||
|
|
89
|
+
((_e = (_d = (_c = original === null || original === void 0 ? void 0 : original.context) === null || _c === void 0 ? void 0 : _c.body) === null || _d === void 0 ? void 0 : _d.error) === null || _e === void 0 ? void 0 : _e.code);
|
|
90
|
+
return code === 429;
|
|
91
|
+
}
|
|
92
|
+
module.exports = webApps;
|
package/lib/apphosting/config.js
CHANGED
|
@@ -1,31 +1,97 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.store = exports.load = exports.yamlPath = void 0;
|
|
4
|
-
const
|
|
3
|
+
exports.maybeAddSecretToYaml = exports.upsertEnv = exports.findEnv = exports.store = exports.load = exports.yamlPath = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
|
-
const yaml = require("
|
|
6
|
+
const yaml = require("yaml");
|
|
7
7
|
const fs = require("../fsutils");
|
|
8
|
+
const prompt = require("../prompt");
|
|
9
|
+
const dialogs = require("./secrets/dialogs");
|
|
8
10
|
function yamlPath(cwd) {
|
|
9
11
|
let dir = cwd;
|
|
10
|
-
while (!fs.fileExistsSync(
|
|
11
|
-
if (fs.fileExistsSync(
|
|
12
|
+
while (!fs.fileExistsSync((0, path_1.resolve)(dir, "apphosting.yaml"))) {
|
|
13
|
+
if (fs.fileExistsSync((0, path_1.resolve)(dir, "firebase.json"))) {
|
|
12
14
|
return null;
|
|
13
15
|
}
|
|
14
|
-
const parent =
|
|
16
|
+
const parent = (0, path_1.dirname)(dir);
|
|
15
17
|
if (parent === dir) {
|
|
16
18
|
return null;
|
|
17
19
|
}
|
|
18
20
|
dir = parent;
|
|
19
21
|
}
|
|
20
|
-
return
|
|
22
|
+
return (0, path_1.resolve)(dir, "apphosting.yaml");
|
|
21
23
|
}
|
|
22
24
|
exports.yamlPath = yamlPath;
|
|
23
25
|
function load(yamlPath) {
|
|
24
26
|
const raw = fs.readFile(yamlPath);
|
|
25
|
-
return yaml.
|
|
27
|
+
return yaml.parseDocument(raw);
|
|
26
28
|
}
|
|
27
29
|
exports.load = load;
|
|
28
|
-
function store(yamlPath,
|
|
29
|
-
(0, fs_1.writeFileSync)(yamlPath,
|
|
30
|
+
function store(yamlPath, document) {
|
|
31
|
+
(0, fs_1.writeFileSync)(yamlPath, document.toString());
|
|
30
32
|
}
|
|
31
33
|
exports.store = store;
|
|
34
|
+
function findEnv(document, variable) {
|
|
35
|
+
if (!document.has("env")) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const envs = document.get("env");
|
|
39
|
+
for (const env of envs.items) {
|
|
40
|
+
if (env.get("variable") === variable) {
|
|
41
|
+
return env.toJSON();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
exports.findEnv = findEnv;
|
|
47
|
+
function upsertEnv(document, env) {
|
|
48
|
+
if (!document.has("env")) {
|
|
49
|
+
document.set("env", document.createNode([env]));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const envs = document.get("env");
|
|
53
|
+
const envYaml = document.createNode(env);
|
|
54
|
+
for (let i = 0; i < envs.items.length; i++) {
|
|
55
|
+
if (envs.items[i].get("variable") === env.variable) {
|
|
56
|
+
envs.set(i, envYaml);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
envs.add(envYaml);
|
|
61
|
+
}
|
|
62
|
+
exports.upsertEnv = upsertEnv;
|
|
63
|
+
async function maybeAddSecretToYaml(secretName) {
|
|
64
|
+
const dynamicDispatch = exports;
|
|
65
|
+
let path = dynamicDispatch.yamlPath(process.cwd());
|
|
66
|
+
let projectYaml;
|
|
67
|
+
if (path) {
|
|
68
|
+
projectYaml = dynamicDispatch.load(path);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
projectYaml = new yaml.Document();
|
|
72
|
+
}
|
|
73
|
+
if (dynamicDispatch.findEnv(projectYaml, secretName)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const addToYaml = await prompt.confirm({
|
|
77
|
+
message: "Would you like to add this secret to apphosting.yaml?",
|
|
78
|
+
default: true,
|
|
79
|
+
});
|
|
80
|
+
if (!addToYaml) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (!path) {
|
|
84
|
+
path = await prompt.promptOnce({
|
|
85
|
+
message: "It looks like you don't have an apphosting.yaml yet. Where would you like to store it?",
|
|
86
|
+
default: process.cwd(),
|
|
87
|
+
});
|
|
88
|
+
path = (0, path_1.join)(path, "apphosting.yaml");
|
|
89
|
+
}
|
|
90
|
+
const envName = await dialogs.envVarForSecret(secretName);
|
|
91
|
+
dynamicDispatch.upsertEnv(projectYaml, {
|
|
92
|
+
variable: envName,
|
|
93
|
+
secret: secretName,
|
|
94
|
+
});
|
|
95
|
+
dynamicDispatch.store(path, projectYaml);
|
|
96
|
+
}
|
|
97
|
+
exports.maybeAddSecretToYaml = maybeAddSecretToYaml;
|
|
@@ -135,7 +135,7 @@ async function promptCloneUri(projectId, connections) {
|
|
|
135
135
|
const cloneUri = await (0, prompt_1.promptOnce)({
|
|
136
136
|
type: "autocomplete",
|
|
137
137
|
name: "cloneUri",
|
|
138
|
-
message: "Which
|
|
138
|
+
message: "Which repository would you like to deploy?",
|
|
139
139
|
source: (_, input = "") => {
|
|
140
140
|
return new Promise((resolve) => resolve([
|
|
141
141
|
new inquirer.Separator(),
|
package/lib/apphosting/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.doSetup = void 0;
|
|
4
|
-
const clc = require("colorette");
|
|
3
|
+
exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.doSetup = void 0;
|
|
5
4
|
const repo = require("./repo");
|
|
6
5
|
const poller = require("../operation-poller");
|
|
7
6
|
const apphosting = require("../gcp/apphosting");
|
|
@@ -16,6 +15,7 @@ const prompt_1 = require("../prompt");
|
|
|
16
15
|
const constants_1 = require("./constants");
|
|
17
16
|
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
18
17
|
const deploymentTool = require("../deploymentTool");
|
|
18
|
+
const apps = require("./app");
|
|
19
19
|
const DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME = "firebase-app-hosting-compute";
|
|
20
20
|
const apphostingPollerOptions = {
|
|
21
21
|
apiOrigin: (0, api_1.apphostingOrigin)(),
|
|
@@ -23,7 +23,7 @@ const apphostingPollerOptions = {
|
|
|
23
23
|
masterTimeout: 25 * 60 * 1000,
|
|
24
24
|
maxBackoff: 10000,
|
|
25
25
|
};
|
|
26
|
-
async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
26
|
+
async function doSetup(projectId, webAppName, location, serviceAccount, withDevConnect) {
|
|
27
27
|
await Promise.all([
|
|
28
28
|
...(withDevConnect ? [(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.developerConnectOrigin)(), "apphosting", true)] : []),
|
|
29
29
|
(0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.cloudbuildOrigin)(), "apphosting", true),
|
|
@@ -37,15 +37,14 @@ async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
|
37
37
|
throw new error_1.FirebaseError(`Invalid location ${location}. Valid choices are ${allowedLocations.join(", ")}`);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
(0, utils_1.logBullet)("First we need a few details to create your backend
|
|
40
|
+
(0, utils_1.logBullet)("First we need a few details to create your backend.\n");
|
|
41
41
|
location =
|
|
42
42
|
location ||
|
|
43
43
|
(await (0, prompt_1.promptOnce)({
|
|
44
44
|
name: "region",
|
|
45
45
|
type: "list",
|
|
46
46
|
default: constants_1.DEFAULT_REGION,
|
|
47
|
-
message: "
|
|
48
|
-
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
|
|
47
|
+
message: "Select a region to host your backend:\n",
|
|
49
48
|
choices: allowedLocations.map((loc) => ({ value: loc })),
|
|
50
49
|
}));
|
|
51
50
|
(0, utils_1.logSuccess)(`Region set to ${location}.\n`);
|
|
@@ -55,6 +54,13 @@ async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
|
55
54
|
default: "my-web-app",
|
|
56
55
|
message: "Create a name for your backend [1-30 characters]",
|
|
57
56
|
});
|
|
57
|
+
const webApp = await apps.getOrCreateWebApp(projectId, webAppName, backendId);
|
|
58
|
+
if (webApp) {
|
|
59
|
+
(0, utils_1.logSuccess)(`Firebase web app set to ${webApp.name}.\n`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
(0, utils_1.logWarning)(`Firebase web app not set`);
|
|
63
|
+
}
|
|
58
64
|
const gitRepositoryConnection = withDevConnect
|
|
59
65
|
? await githubConnections.linkGitHubRepository(projectId, location)
|
|
60
66
|
: await repo.linkGitHubRepository(projectId, location);
|
|
@@ -62,9 +68,9 @@ async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
|
62
68
|
name: "rootDir",
|
|
63
69
|
type: "input",
|
|
64
70
|
default: "/",
|
|
65
|
-
message: "Specify
|
|
71
|
+
message: "Specify your app's root directory relative to your repository",
|
|
66
72
|
});
|
|
67
|
-
const backend = await createBackend(projectId, location, backendId, gitRepositoryConnection, serviceAccount, rootDir);
|
|
73
|
+
const backend = await createBackend(projectId, location, backendId, gitRepositoryConnection, serviceAccount, webApp === null || webApp === void 0 ? void 0 : webApp.id, rootDir);
|
|
68
74
|
const branch = await (0, prompt_1.promptOnce)({
|
|
69
75
|
name: "branch",
|
|
70
76
|
type: "input",
|
|
@@ -80,7 +86,7 @@ async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
|
80
86
|
});
|
|
81
87
|
if (!confirmRollout) {
|
|
82
88
|
(0, utils_1.logSuccess)(`Successfully created backend:\n\t${backend.name}`);
|
|
83
|
-
(0, utils_1.logSuccess)(`Your
|
|
89
|
+
(0, utils_1.logSuccess)(`Your backend will be deployed at:\n\thttps://${backend.uri}`);
|
|
84
90
|
return;
|
|
85
91
|
}
|
|
86
92
|
await orchestrateRollout(projectId, location, backendId, {
|
|
@@ -91,7 +97,7 @@ async function doSetup(projectId, location, serviceAccount, withDevConnect) {
|
|
|
91
97
|
},
|
|
92
98
|
});
|
|
93
99
|
(0, utils_1.logSuccess)(`Successfully created backend:\n\t${backend.name}`);
|
|
94
|
-
(0, utils_1.logSuccess)(`Your
|
|
100
|
+
(0, utils_1.logSuccess)(`Your backend is now deployed at:\n\thttps://${backend.uri}`);
|
|
95
101
|
}
|
|
96
102
|
exports.doSetup = doSetup;
|
|
97
103
|
async function promptNewBackendId(projectId, location, prompt) {
|
|
@@ -112,7 +118,7 @@ async function promptNewBackendId(projectId, location, prompt) {
|
|
|
112
118
|
function defaultComputeServiceAccountEmail(projectId) {
|
|
113
119
|
return `${DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME}@${projectId}.iam.gserviceaccount.com`;
|
|
114
120
|
}
|
|
115
|
-
async function createBackend(projectId, location, backendId, repository, serviceAccount, rootDir = "/") {
|
|
121
|
+
async function createBackend(projectId, location, backendId, repository, serviceAccount, webAppId, rootDir = "/") {
|
|
116
122
|
const defaultServiceAccount = defaultComputeServiceAccountEmail(projectId);
|
|
117
123
|
const backendReqBody = {
|
|
118
124
|
servingLocality: "GLOBAL_ACCESS",
|
|
@@ -122,6 +128,7 @@ async function createBackend(projectId, location, backendId, repository, service
|
|
|
122
128
|
},
|
|
123
129
|
labels: deploymentTool.labels(),
|
|
124
130
|
serviceAccount: serviceAccount || defaultServiceAccount,
|
|
131
|
+
appId: webAppId,
|
|
125
132
|
};
|
|
126
133
|
delete backendReqBody.serviceAccount;
|
|
127
134
|
async function createBackendAndPoll() {
|
|
@@ -221,3 +228,8 @@ async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
|
221
228
|
return { rollout, build };
|
|
222
229
|
}
|
|
223
230
|
exports.orchestrateRollout = orchestrateRollout;
|
|
231
|
+
async function deleteBackendAndPoll(projectId, location, backendId) {
|
|
232
|
+
const op = await apphosting.deleteBackend(projectId, location, backendId);
|
|
233
|
+
await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `delete-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
234
|
+
}
|
|
235
|
+
exports.deleteBackendAndPoll = deleteBackendAndPoll;
|
package/lib/apphosting/repo.js
CHANGED
|
@@ -132,7 +132,7 @@ async function promptRepositoryUri(projectId, connections) {
|
|
|
132
132
|
const remoteUri = await (0, prompt_1.promptOnce)({
|
|
133
133
|
type: "autocomplete",
|
|
134
134
|
name: "remoteUri",
|
|
135
|
-
message: "Which
|
|
135
|
+
message: "Which repository would you like to deploy?",
|
|
136
136
|
source: (_, input = "") => {
|
|
137
137
|
return new Promise((resolve) => resolve([
|
|
138
138
|
new inquirer.Separator(),
|
|
@@ -65,42 +65,43 @@ function selectFromMetadata(input, selected) {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
exports.selectFromMetadata = selectFromMetadata;
|
|
68
|
-
exports.WARN_NO_BACKENDS = "To use this secret, your backend's service account must
|
|
68
|
+
exports.WARN_NO_BACKENDS = "To use this secret, your backend's service account must be granted access." +
|
|
69
69
|
"It does not look like you have a backend yet. After creating a backend, grant access with " +
|
|
70
|
-
clc.bold("firebase apphosting:secrets:
|
|
70
|
+
clc.bold("firebase apphosting:secrets:grantaccess");
|
|
71
71
|
exports.GRANT_ACCESS_IN_FUTURE = `To grant access in the future, run ${clc.bold("firebase apphosting:secrets:grantaccess")}`;
|
|
72
72
|
async function selectBackendServiceAccounts(projectNumber, projectId, options) {
|
|
73
73
|
const listBackends = await apphosting.listBackends(projectId, "-");
|
|
74
74
|
if (listBackends.unreachable.length) {
|
|
75
|
-
utils.
|
|
76
|
-
`${clc.bold("firebase apphosting:secrets:
|
|
75
|
+
utils.logWarning(`Could not reach location(s) ${listBackends.unreachable.join(", ")}. You may need to run ` +
|
|
76
|
+
`${clc.bold("firebase apphosting:secrets:grantaccess")} at a later time if you have backends in these locations`);
|
|
77
77
|
}
|
|
78
78
|
if (!listBackends.backends.length) {
|
|
79
|
-
utils.
|
|
79
|
+
utils.logWarning(exports.WARN_NO_BACKENDS);
|
|
80
80
|
return { buildServiceAccounts: [], runServiceAccounts: [] };
|
|
81
81
|
}
|
|
82
82
|
if (listBackends.backends.length === 1) {
|
|
83
83
|
const grant = await prompt.confirm({
|
|
84
84
|
nonInteractive: options.nonInteractive,
|
|
85
85
|
default: true,
|
|
86
|
-
message: "To use this secret, your backend's service account must
|
|
86
|
+
message: "To use this secret, your backend's service account must be granted access. Would you like to grant access now?",
|
|
87
87
|
});
|
|
88
88
|
if (grant) {
|
|
89
89
|
return (0, _1.toMulti)((0, _1.serviceAccountsForBackend)(projectNumber, listBackends.backends[0]));
|
|
90
90
|
}
|
|
91
|
-
utils.
|
|
91
|
+
utils.logBullet(exports.GRANT_ACCESS_IN_FUTURE);
|
|
92
92
|
return { buildServiceAccounts: [], runServiceAccounts: [] };
|
|
93
93
|
}
|
|
94
94
|
const metadata = toMetadata(projectNumber, listBackends.backends);
|
|
95
95
|
if (metadata.every(matchesServiceAccounts(metadata[0]))) {
|
|
96
|
-
utils.
|
|
97
|
-
|
|
96
|
+
utils.logBullet("To use this secret, your backend's service account must be granted access.");
|
|
97
|
+
utils.logBullet("All of your backends share the following " +
|
|
98
|
+
(sameServiceAccount(metadata[0]) ? "service account: " : "service accounts: ") +
|
|
98
99
|
serviceAccountDisplay(metadata[0]) +
|
|
99
|
-
"
|
|
100
|
+
".\nGranting access to one backend will grant access to all backends.");
|
|
100
101
|
const grant = await prompt.confirm({
|
|
101
102
|
nonInteractive: options.nonInteractive,
|
|
102
103
|
default: true,
|
|
103
|
-
message: "Would you like to grant
|
|
104
|
+
message: "Would you like to grant access to all backends now?",
|
|
104
105
|
});
|
|
105
106
|
if (grant) {
|
|
106
107
|
return selectFromMetadata(metadata, [
|
|
@@ -108,10 +109,10 @@ async function selectBackendServiceAccounts(projectNumber, projectId, options) {
|
|
|
108
109
|
metadata[0].runServiceAccount,
|
|
109
110
|
]);
|
|
110
111
|
}
|
|
111
|
-
utils.
|
|
112
|
+
utils.logBullet(exports.GRANT_ACCESS_IN_FUTURE);
|
|
112
113
|
return { buildServiceAccounts: [], runServiceAccounts: [] };
|
|
113
114
|
}
|
|
114
|
-
utils.
|
|
115
|
+
utils.logBullet("To use this secret, your backend's service account must be granted access. Your backends use the following service accounts:");
|
|
115
116
|
const tableData = tableForBackends(metadata);
|
|
116
117
|
const table = new Table({
|
|
117
118
|
head: tableData[0],
|
|
@@ -131,7 +132,7 @@ async function selectBackendServiceAccounts(projectNumber, projectId, options) {
|
|
|
131
132
|
choices: [...allAccounts.values()].sort(),
|
|
132
133
|
});
|
|
133
134
|
if (!chosen.length) {
|
|
134
|
-
utils.
|
|
135
|
+
utils.logBullet(exports.GRANT_ACCESS_IN_FUTURE);
|
|
135
136
|
}
|
|
136
137
|
return selectFromMetadata(metadata, chosen);
|
|
137
138
|
}
|
|
@@ -7,7 +7,8 @@ const requireInteractive_1 = require("../requireInteractive");
|
|
|
7
7
|
const apphosting_1 = require("../apphosting");
|
|
8
8
|
const apphosting_2 = require("../gcp/apphosting");
|
|
9
9
|
exports.command = new command_1.Command("apphosting:backends:create")
|
|
10
|
-
.description("create a
|
|
10
|
+
.description("create a Firebase App Hosting backend")
|
|
11
|
+
.option("-a, --app <webApp>", "specify an existing Firebase web app to associate your App Hosting backend with")
|
|
11
12
|
.option("-l, --location <location>", "specify the region of the backend", "")
|
|
12
13
|
.option("-s, --service-account <serviceAccount>", "specify the service account used to run the server", "")
|
|
13
14
|
.option("-w, --with-dev-connect", "use the Developer Connect flow insetad of Cloud Build Repositories (testing)", false)
|
|
@@ -15,8 +16,9 @@ exports.command = new command_1.Command("apphosting:backends:create")
|
|
|
15
16
|
.before(requireInteractive_1.default)
|
|
16
17
|
.action(async (options) => {
|
|
17
18
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
19
|
+
const webApp = options.app;
|
|
18
20
|
const location = options.location;
|
|
19
21
|
const serviceAccount = options.serviceAccount;
|
|
20
22
|
const withDevConnect = options.withDevConnect;
|
|
21
|
-
await (0, apphosting_1.doSetup)(projectId, location, serviceAccount, withDevConnect);
|
|
23
|
+
await (0, apphosting_1.doSetup)(projectId, webApp, location, serviceAccount, withDevConnect);
|
|
22
24
|
});
|
|
@@ -9,9 +9,10 @@ const constants_1 = require("../apphosting/constants");
|
|
|
9
9
|
const utils = require("../utils");
|
|
10
10
|
const apphosting = require("../gcp/apphosting");
|
|
11
11
|
const apphosting_backends_list_1 = require("./apphosting-backends-list");
|
|
12
|
+
const apphosting_1 = require("../apphosting");
|
|
12
13
|
exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
13
|
-
.description("delete a
|
|
14
|
-
.option("-l, --location <location>", "
|
|
14
|
+
.description("delete a Firebase App Hosting backend")
|
|
15
|
+
.option("-l, --location <location>", "specify the region of the backend", "")
|
|
15
16
|
.withForce()
|
|
16
17
|
.before(apphosting.ensureApiEnabled)
|
|
17
18
|
.action(async (backendId, options) => {
|
|
@@ -52,7 +53,7 @@ exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
|
52
53
|
throw new error_1.FirebaseError("Deletion Aborted");
|
|
53
54
|
}
|
|
54
55
|
try {
|
|
55
|
-
await
|
|
56
|
+
await (0, apphosting_1.deleteBackendAndPoll)(projectId, location, backendId);
|
|
56
57
|
utils.logSuccess(`Successfully deleted the backend: ${backendId}`);
|
|
57
58
|
}
|
|
58
59
|
catch (err) {
|
|
@@ -7,30 +7,30 @@ const error_1 = require("../error");
|
|
|
7
7
|
const utils_1 = require("../utils");
|
|
8
8
|
const apphosting = require("../gcp/apphosting");
|
|
9
9
|
const apphosting_backends_list_1 = require("./apphosting-backends-list");
|
|
10
|
-
exports.command = new command_1.Command("apphosting:backends:get <
|
|
11
|
-
.description("
|
|
12
|
-
.option("-l, --location <location>", "
|
|
10
|
+
exports.command = new command_1.Command("apphosting:backends:get <backend>")
|
|
11
|
+
.description("print info about a Firebase App Hosting backend")
|
|
12
|
+
.option("-l, --location <location>", "backend location", "-")
|
|
13
13
|
.before(apphosting.ensureApiEnabled)
|
|
14
|
-
.action(async (
|
|
14
|
+
.action(async (backend, options) => {
|
|
15
15
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
16
16
|
const location = options.location;
|
|
17
17
|
let backendsList = [];
|
|
18
18
|
try {
|
|
19
19
|
if (location !== "-") {
|
|
20
|
-
const backendInRegion = await apphosting.getBackend(projectId, location,
|
|
20
|
+
const backendInRegion = await apphosting.getBackend(projectId, location, backend);
|
|
21
21
|
backendsList.push(backendInRegion);
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
24
|
const resp = await apphosting.listBackends(projectId, "-");
|
|
25
25
|
const allBackends = resp.backends || [];
|
|
26
|
-
backendsList = allBackends.filter((bkd) => bkd.name.split("/").pop() ===
|
|
26
|
+
backendsList = allBackends.filter((bkd) => bkd.name.split("/").pop() === backend);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
catch (err) {
|
|
30
|
-
throw new error_1.FirebaseError(`Failed to get backend: ${
|
|
30
|
+
throw new error_1.FirebaseError(`Failed to get backend: ${backend}. Please check the parameters you have provided.`, { original: err });
|
|
31
31
|
}
|
|
32
32
|
if (backendsList.length === 0) {
|
|
33
|
-
(0, utils_1.logWarning)(`
|
|
33
|
+
(0, utils_1.logWarning)(`Backend "${backend}" not found`);
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
(0, apphosting_backends_list_1.printBackendsTable)(backendsList);
|
|
@@ -10,8 +10,8 @@ const apphosting = require("../gcp/apphosting");
|
|
|
10
10
|
const Table = require("cli-table");
|
|
11
11
|
const TABLE_HEAD = ["Backend ID", "Repository", "Location", "URL", "Created Date", "Updated Date"];
|
|
12
12
|
exports.command = new command_1.Command("apphosting:backends:list")
|
|
13
|
-
.description("list
|
|
14
|
-
.option("-l, --location <location>", "
|
|
13
|
+
.description("list Firebase App Hosting backends")
|
|
14
|
+
.option("-l, --location <location>", "list backends in the specified location", "-")
|
|
15
15
|
.before(apphosting.ensureApiEnabled)
|
|
16
16
|
.action(async (options) => {
|
|
17
17
|
var _a;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const apphosting = require("../gcp/apphosting");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const command_1 = require("../command");
|
|
7
|
+
const projectUtils_1 = require("../projectUtils");
|
|
8
|
+
exports.command = new command_1.Command("apphosting:builds:create <backendId>")
|
|
9
|
+
.description("create a build for an App Hosting backend")
|
|
10
|
+
.option("-l, --location <location>", "specify the region of the backend", "us-central1")
|
|
11
|
+
.option("-i, --id <buildId>", "id of the build (defaults to autogenerating a random id)", "")
|
|
12
|
+
.option("-b, --branch <branch>", "repository branch to deploy (defaults to 'main')", "main")
|
|
13
|
+
.before(apphosting.ensureApiEnabled)
|
|
14
|
+
.action(async (backendId, options) => {
|
|
15
|
+
var _a;
|
|
16
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
17
|
+
const location = options.location;
|
|
18
|
+
const buildId = options.buildId ||
|
|
19
|
+
(await apphosting.getNextRolloutId(projectId, location, backendId));
|
|
20
|
+
const branch = (_a = options.branch) !== null && _a !== void 0 ? _a : "main";
|
|
21
|
+
const op = await apphosting.createBuild(projectId, location, backendId, buildId, {
|
|
22
|
+
source: {
|
|
23
|
+
codebase: {
|
|
24
|
+
branch,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
logger_1.logger.info(`Started a build for backend ${backendId} on branch ${branch}.`);
|
|
29
|
+
logger_1.logger.info("Check status by running:");
|
|
30
|
+
logger_1.logger.info(`\tfirebase apphosting:builds:get ${backendId} ${buildId} --location ${location}`);
|
|
31
|
+
return op;
|
|
32
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const apphosting = require("../gcp/apphosting");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const command_1 = require("../command");
|
|
7
|
+
const projectUtils_1 = require("../projectUtils");
|
|
8
|
+
exports.command = new command_1.Command("apphosting:builds:get <backendId> <buildId>")
|
|
9
|
+
.description("get a build for an App Hosting backend")
|
|
10
|
+
.option("-l, --location <location>", "specify the region of the backend", "us-central1")
|
|
11
|
+
.before(apphosting.ensureApiEnabled)
|
|
12
|
+
.action(async (backendId, buildId, options) => {
|
|
13
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
14
|
+
const location = options.location;
|
|
15
|
+
const build = await apphosting.getBuild(projectId, location, backendId, buildId);
|
|
16
|
+
logger_1.logger.info(JSON.stringify(build, null, 2));
|
|
17
|
+
return build;
|
|
18
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const apphosting = require("../gcp/apphosting");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const command_1 = require("../command");
|
|
7
|
+
const projectUtils_1 = require("../projectUtils");
|
|
8
|
+
exports.command = new command_1.Command("apphosting:rollouts:create <backendId> <buildId>")
|
|
9
|
+
.description("create a rollout using a build for an App Hosting backend")
|
|
10
|
+
.option("-l, --location <location>", "specify the region of the backend", "us-central1")
|
|
11
|
+
.option("-i, --id <rolloutId>", "id of the rollout (defaults to autogenerating a random id)", "")
|
|
12
|
+
.before(apphosting.ensureApiEnabled)
|
|
13
|
+
.action(async (backendId, buildId, options) => {
|
|
14
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
15
|
+
const location = options.location;
|
|
16
|
+
const rolloutId = options.buildId ||
|
|
17
|
+
(await apphosting.getNextRolloutId(projectId, location, backendId));
|
|
18
|
+
const build = `projects/${projectId}/backends/${backendId}/builds/${buildId}`;
|
|
19
|
+
const op = await apphosting.createRollout(projectId, location, backendId, rolloutId, {
|
|
20
|
+
build,
|
|
21
|
+
});
|
|
22
|
+
logger_1.logger.info(`Started a rollout for backend ${backendId} with build ${buildId}.`);
|
|
23
|
+
logger_1.logger.info("Check status by running:");
|
|
24
|
+
logger_1.logger.info(`\tfirebase apphosting:rollouts:list --location ${location}`);
|
|
25
|
+
return op;
|
|
26
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const apphosting = require("../gcp/apphosting");
|
|
5
|
+
const logger_1 = require("../logger");
|
|
6
|
+
const command_1 = require("../command");
|
|
7
|
+
const projectUtils_1 = require("../projectUtils");
|
|
8
|
+
exports.command = new command_1.Command("apphosting:rollouts:list <backendId>")
|
|
9
|
+
.description("list rollouts of an App Hosting backend")
|
|
10
|
+
.option("-l, --location <location>", "region of the rollouts (defaults to listing rollouts from all regions)", "-")
|
|
11
|
+
.before(apphosting.ensureApiEnabled)
|
|
12
|
+
.action(async (backendId, options) => {
|
|
13
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
14
|
+
const location = options.location;
|
|
15
|
+
const rollouts = await apphosting.listRollouts(projectId, location, backendId);
|
|
16
|
+
if (rollouts.unreachable) {
|
|
17
|
+
logger_1.logger.error(`WARNING: the following locations were unreachable: ${rollouts.unreachable.join(", ")}`);
|
|
18
|
+
}
|
|
19
|
+
logger_1.logger.info(JSON.stringify(rollouts.rollouts, null, 2));
|
|
20
|
+
return rollouts;
|
|
21
|
+
});
|
|
@@ -11,8 +11,8 @@ const apphosting = require("../gcp/apphosting");
|
|
|
11
11
|
const secrets = require("../apphosting/secrets");
|
|
12
12
|
exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretName>")
|
|
13
13
|
.description("grant service accounts permissions to the provided secret")
|
|
14
|
-
.option("-l, --location <location>", "
|
|
15
|
-
.option("-b, --backend <backend>", "
|
|
14
|
+
.option("-l, --location <location>", "backend location")
|
|
15
|
+
.option("-b, --backend <backend>", "backend name")
|
|
16
16
|
.before(requireAuth_1.requireAuth)
|
|
17
17
|
.before(secretManager.ensureApi)
|
|
18
18
|
.before(apphosting.ensureApiEnabled)
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.command = void 0;
|
|
4
|
-
const tty = require("tty");
|
|
5
4
|
const clc = require("colorette");
|
|
6
|
-
const path_1 = require("path");
|
|
7
5
|
const command_1 = require("../command");
|
|
8
6
|
const projectUtils_1 = require("../projectUtils");
|
|
9
7
|
const requireAuth_1 = require("../requireAuth");
|
|
10
|
-
const fs = require("fs");
|
|
11
8
|
const gcsm = require("../gcp/secretManager");
|
|
12
9
|
const apphosting = require("../gcp/apphosting");
|
|
13
10
|
const requirePermissions_1 = require("../requirePermissions");
|
|
14
|
-
const prompt_1 = require("../prompt");
|
|
15
11
|
const secrets = require("../apphosting/secrets");
|
|
16
12
|
const dialogs = require("../apphosting/secrets/dialogs");
|
|
17
13
|
const config = require("../apphosting/config");
|
|
18
|
-
const
|
|
14
|
+
const utils = require("../utils");
|
|
19
15
|
exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
|
|
20
|
-
.description("
|
|
16
|
+
.description("create or update a secret for use in Firebase App Hosting")
|
|
21
17
|
.option("-l, --location <location>", "optional location to retrict secret replication")
|
|
22
18
|
.withForce("Automatically create a secret, grant permissions, and add to YAML.")
|
|
23
19
|
.before(requireAuth_1.requireAuth)
|
|
@@ -33,73 +29,28 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
|
|
|
33
29
|
])
|
|
34
30
|
.option("--data-file <dataFile>", 'File path from which to read secret data. Set to "-" to read the secret data from stdin.')
|
|
35
31
|
.action(async (secretName, options) => {
|
|
36
|
-
var _a;
|
|
37
|
-
const howToAccess = `You can access the contents of the secret's latest value with ${clc.bold(`firebase apphosting:secrets:access ${secretName}`)}`;
|
|
38
|
-
const grantAccess = `To use this secret in your backend, you must grant access. You can do so in the future with ${clc.bold("firebase apphosting:secrets:grantAccess")}`;
|
|
39
32
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
40
33
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
41
34
|
const created = await secrets.upsertSecret(projectId, secretName, options.location);
|
|
42
35
|
if (created === null) {
|
|
43
36
|
return;
|
|
44
37
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
secretValue = await (0, prompt_1.promptOnce)({
|
|
48
|
-
type: "password",
|
|
49
|
-
message: `Enter a value for ${secretName}`,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
let dataFile = 0;
|
|
54
|
-
if (options.dataFile && options.dataFile !== "-") {
|
|
55
|
-
dataFile = options.dataFile;
|
|
56
|
-
}
|
|
57
|
-
secretValue = fs.readFileSync(dataFile, "utf-8");
|
|
58
|
-
}
|
|
59
|
-
if (created) {
|
|
60
|
-
(0, utils_1.logSuccess)(`Created new secret projects/${projectId}/secrets/${secretName}`);
|
|
38
|
+
else if (created) {
|
|
39
|
+
utils.logSuccess(`Created new secret projects/${projectId}/secrets/${secretName}`);
|
|
61
40
|
}
|
|
41
|
+
const secretValue = await utils.readSecretValue(`Enter a value for ${secretName}`, options.dataFile);
|
|
62
42
|
const version = await gcsm.addVersion(projectId, secretName, secretValue);
|
|
63
|
-
|
|
64
|
-
(
|
|
43
|
+
utils.logSuccess(`Created new secret version ${gcsm.toSecretVersionResourceName(version)}`);
|
|
44
|
+
utils.logBullet(`You can access the contents of the secret's latest value with ${clc.bold(`firebase apphosting:secrets:access ${secretName}\n`)}`);
|
|
65
45
|
if (!created) {
|
|
66
|
-
(0, utils_1.logWarning)(grantAccess);
|
|
67
46
|
return;
|
|
68
47
|
}
|
|
69
48
|
const accounts = await dialogs.selectBackendServiceAccounts(projectNumber, projectId, options);
|
|
70
49
|
if (!accounts.buildServiceAccounts.length && !accounts.runServiceAccounts.length) {
|
|
71
|
-
(
|
|
50
|
+
utils.logWarning(`To use this secret in your backend, you must grant access. You can do so in the future with ${clc.bold("firebase apphosting:secrets:grantaccess")}`);
|
|
72
51
|
}
|
|
73
52
|
else {
|
|
74
53
|
await secrets.grantSecretAccess(projectId, secretName, accounts);
|
|
75
54
|
}
|
|
76
|
-
|
|
77
|
-
let yaml = {};
|
|
78
|
-
if (path) {
|
|
79
|
-
yaml = config.load(path);
|
|
80
|
-
if ((_a = yaml.env) === null || _a === void 0 ? void 0 : _a.find((env) => env.variable === secretName)) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
const addToYaml = await (0, prompt_1.confirm)({
|
|
85
|
-
message: "Would you like to add this secret to apphosting.yaml?",
|
|
86
|
-
default: true,
|
|
87
|
-
});
|
|
88
|
-
if (!addToYaml) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (!path) {
|
|
92
|
-
path = await (0, prompt_1.promptOnce)({
|
|
93
|
-
message: "It looks like you don't have an apphosting.yaml yet. Where would you like to store it?",
|
|
94
|
-
default: process.cwd(),
|
|
95
|
-
});
|
|
96
|
-
path = (0, path_1.join)(path, "apphosting.yaml");
|
|
97
|
-
}
|
|
98
|
-
const envName = await dialogs.envVarForSecret(secretName);
|
|
99
|
-
yaml.env = yaml.env || [];
|
|
100
|
-
yaml.env.push({
|
|
101
|
-
variable: envName,
|
|
102
|
-
secret: secretName,
|
|
103
|
-
});
|
|
104
|
-
config.store(path, yaml);
|
|
55
|
+
await config.maybeAddSecretToYaml(secretName);
|
|
105
56
|
});
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.command = void 0;
|
|
4
|
-
const tty = require("tty");
|
|
5
|
-
const fs = require("fs");
|
|
6
4
|
const clc = require("colorette");
|
|
7
5
|
const logger_1 = require("../logger");
|
|
8
6
|
const secrets_1 = require("../functions/secrets");
|
|
@@ -33,21 +31,7 @@ exports.command = new command_1.Command("functions:secrets:set <KEY>")
|
|
|
33
31
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
34
32
|
const key = await (0, secrets_1.ensureValidKey)(unvalidatedKey, options);
|
|
35
33
|
const secret = await (0, secrets_1.ensureSecret)(projectId, key, options);
|
|
36
|
-
|
|
37
|
-
if ((!options.dataFile || options.dataFile === "-") && tty.isatty(0)) {
|
|
38
|
-
secretValue = await (0, prompt_1.promptOnce)({
|
|
39
|
-
name: key,
|
|
40
|
-
type: "password",
|
|
41
|
-
message: `Enter a value for ${key}`,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
let dataFile = 0;
|
|
46
|
-
if (options.dataFile && options.dataFile !== "-") {
|
|
47
|
-
dataFile = options.dataFile;
|
|
48
|
-
}
|
|
49
|
-
secretValue = fs.readFileSync(dataFile, "utf-8");
|
|
50
|
-
}
|
|
34
|
+
const secretValue = await (0, utils_1.readSecretValue)(`Enter a value for ${key}`, options.dataFile);
|
|
51
35
|
const secretVersion = await (0, secretManager_1.addVersion)(projectId, key, secretValue);
|
|
52
36
|
(0, utils_1.logSuccess)(`Created a new secret version ${(0, secretManager_1.toSecretVersionResourceName)(secretVersion)}`);
|
|
53
37
|
if (!(0, secretManager_1.isFunctionsManaged)(secret)) {
|
package/lib/commands/index.js
CHANGED
|
@@ -167,6 +167,14 @@ function load(client) {
|
|
|
167
167
|
client.apphosting.secrets.grantaccess = loadCommand("apphosting-secrets-grantaccess");
|
|
168
168
|
client.apphosting.secrets.describe = loadCommand("apphosting-secrets-describe");
|
|
169
169
|
client.apphosting.secrets.access = loadCommand("apphosting-secrets-access");
|
|
170
|
+
if (experiments.isEnabled("internaltesting")) {
|
|
171
|
+
client.apphosting.builds = {};
|
|
172
|
+
client.apphosting.builds.get = loadCommand("apphosting-builds-get");
|
|
173
|
+
client.apphosting.builds.create = loadCommand("apphosting-builds-create");
|
|
174
|
+
client.apphosting.rollouts = {};
|
|
175
|
+
client.apphosting.rollouts.create = loadCommand("apphosting-rollouts-create");
|
|
176
|
+
client.apphosting.rollouts.list = loadCommand("apphosting-rollouts-list");
|
|
177
|
+
}
|
|
170
178
|
}
|
|
171
179
|
client.login = loadCommand("login");
|
|
172
180
|
client.login.add = loadCommand("login-add");
|
|
@@ -4,7 +4,7 @@ exports.detectFromPort = exports.detectFromYaml = exports.yamlToBuild = exports.
|
|
|
4
4
|
const node_fetch_1 = require("node-fetch");
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const yaml = require("
|
|
7
|
+
const yaml = require("yaml");
|
|
8
8
|
const util_1 = require("util");
|
|
9
9
|
const logger_1 = require("../../../../logger");
|
|
10
10
|
const api = require("../../.../../../../api");
|
|
@@ -41,7 +41,7 @@ async function detectFromYaml(directory, project, runtime) {
|
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
logger_1.logger.debug("Found functions.yaml. Got spec:", text);
|
|
44
|
-
const parsed = yaml.
|
|
44
|
+
const parsed = yaml.parse(text);
|
|
45
45
|
return yamlToBuild(parsed, project, api.functionsDefaultRegion(), runtime);
|
|
46
46
|
}
|
|
47
47
|
exports.detectFromYaml = detectFromYaml;
|
|
@@ -74,7 +74,7 @@ async function detectFromPort(port, project, runtime, timeout = 10000) {
|
|
|
74
74
|
logger_1.logger.debug("Got response from /__/functions.yaml", text);
|
|
75
75
|
let parsed;
|
|
76
76
|
try {
|
|
77
|
-
parsed = yaml.
|
|
77
|
+
parsed = yaml.parse(text);
|
|
78
78
|
}
|
|
79
79
|
catch (err) {
|
|
80
80
|
logger_1.logger.debug("Failed to parse functions.yaml", err);
|
|
@@ -1,88 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.guardVersionSupport = exports.isDecommissioned = exports.latest = exports.runtimeIsLanguage = exports.isRuntime =
|
|
4
|
-
const error_1 = require("
|
|
5
|
-
const utils = require("
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
exports.RUNTIMES = runtimes({
|
|
10
|
-
nodejs6: {
|
|
11
|
-
friendly: "Node.js 6",
|
|
12
|
-
status: "decommissioned",
|
|
13
|
-
deprecationDate: "2019-04-17",
|
|
14
|
-
decommissionDate: "2020-08-01",
|
|
15
|
-
},
|
|
16
|
-
nodejs8: {
|
|
17
|
-
friendly: "Node.js 8",
|
|
18
|
-
status: "decommissioned",
|
|
19
|
-
deprecationDate: "2020-06-05",
|
|
20
|
-
decommissionDate: "2021-02-01",
|
|
21
|
-
},
|
|
22
|
-
nodejs10: {
|
|
23
|
-
friendly: "Node.js 10",
|
|
24
|
-
status: "GA",
|
|
25
|
-
deprecationDate: "2024-01-30",
|
|
26
|
-
decommissionDate: "2025-01-30",
|
|
27
|
-
},
|
|
28
|
-
nodejs12: {
|
|
29
|
-
friendly: "Node.js 12",
|
|
30
|
-
status: "GA",
|
|
31
|
-
deprecationDate: "2024-01-30",
|
|
32
|
-
decommissionDate: "2025-01-30",
|
|
33
|
-
},
|
|
34
|
-
nodejs14: {
|
|
35
|
-
friendly: "Node.js 14",
|
|
36
|
-
status: "GA",
|
|
37
|
-
deprecationDate: "2024-01-30",
|
|
38
|
-
decommissionDate: "2025-01-30",
|
|
39
|
-
},
|
|
40
|
-
nodejs16: {
|
|
41
|
-
friendly: "Node.js 16",
|
|
42
|
-
status: "GA",
|
|
43
|
-
deprecationDate: "2024-01-30",
|
|
44
|
-
decommissionDate: "2025-01-30",
|
|
45
|
-
},
|
|
46
|
-
nodejs18: {
|
|
47
|
-
friendly: "Node.js 18",
|
|
48
|
-
status: "GA",
|
|
49
|
-
deprecationDate: "2025-04-30",
|
|
50
|
-
decommissionDate: "2025-10-31",
|
|
51
|
-
},
|
|
52
|
-
nodejs20: {
|
|
53
|
-
friendly: "Node.js 20",
|
|
54
|
-
status: "GA",
|
|
55
|
-
deprecationDate: "2026-04-30",
|
|
56
|
-
decommissionDate: "2026-10-31",
|
|
57
|
-
},
|
|
58
|
-
python310: {
|
|
59
|
-
friendly: "Python 3.10",
|
|
60
|
-
status: "GA",
|
|
61
|
-
deprecationDate: "2026-10-04",
|
|
62
|
-
decommissionDate: "2027-04-30",
|
|
63
|
-
},
|
|
64
|
-
python311: {
|
|
65
|
-
friendly: "Python 3.11",
|
|
66
|
-
status: "GA",
|
|
67
|
-
deprecationDate: "2027-10-24",
|
|
68
|
-
decommissionDate: "2028-04-30",
|
|
69
|
-
},
|
|
70
|
-
python312: {
|
|
71
|
-
friendly: "Python 3.12",
|
|
72
|
-
status: "GA",
|
|
73
|
-
deprecationDate: "2028-10-02",
|
|
74
|
-
decommissionDate: "2029-04-30",
|
|
75
|
-
},
|
|
76
|
-
});
|
|
17
|
+
exports.guardVersionSupport = exports.isDecommissioned = exports.latest = exports.runtimeIsLanguage = exports.isRuntime = void 0;
|
|
18
|
+
const error_1 = require("../../../../error");
|
|
19
|
+
const utils = require("../../../../utils");
|
|
20
|
+
const types_1 = require("./types");
|
|
21
|
+
__exportStar(require("./types"), exports);
|
|
77
22
|
function isRuntime(maybe) {
|
|
78
|
-
return maybe in
|
|
23
|
+
return maybe in types_1.RUNTIMES;
|
|
79
24
|
}
|
|
80
25
|
exports.isRuntime = isRuntime;
|
|
81
26
|
function runtimeIsLanguage(runtime, language) {
|
|
82
27
|
return runtime.startsWith(language);
|
|
83
28
|
}
|
|
84
29
|
exports.runtimeIsLanguage = runtimeIsLanguage;
|
|
85
|
-
function latest(language, runtimes = Object.keys(
|
|
30
|
+
function latest(language, runtimes = Object.keys(types_1.RUNTIMES)) {
|
|
86
31
|
const sorted = runtimes
|
|
87
32
|
.filter((s) => runtimeIsLanguage(s, language))
|
|
88
33
|
.sort((left, right) => {
|
|
@@ -103,20 +48,20 @@ function latest(language, runtimes = Object.keys(exports.RUNTIMES)) {
|
|
|
103
48
|
}
|
|
104
49
|
exports.latest = latest;
|
|
105
50
|
function isDecommissioned(runtime, now = new Date()) {
|
|
106
|
-
const cutoff = new Date(
|
|
51
|
+
const cutoff = new Date(types_1.RUNTIMES[runtime].decommissionDate);
|
|
107
52
|
return cutoff < now;
|
|
108
53
|
}
|
|
109
54
|
exports.isDecommissioned = isDecommissioned;
|
|
110
55
|
function guardVersionSupport(runtime, now = new Date()) {
|
|
111
|
-
const { deprecationDate, decommissionDate } =
|
|
56
|
+
const { deprecationDate, decommissionDate } = types_1.RUNTIMES[runtime];
|
|
112
57
|
const decommission = new Date(decommissionDate);
|
|
113
58
|
if (now >= decommission) {
|
|
114
|
-
throw new error_1.FirebaseError(`Runtime ${
|
|
59
|
+
throw new error_1.FirebaseError(`Runtime ${types_1.RUNTIMES[runtime].friendly} was decommissioned on ${decommissionDate}. To deploy ` +
|
|
115
60
|
"you must first upgrade your runtime version.", { exit: 1 });
|
|
116
61
|
}
|
|
117
62
|
const deprecation = new Date(deprecationDate);
|
|
118
63
|
if (now >= deprecation) {
|
|
119
|
-
utils.logLabeledWarning("functions", `Runtime ${
|
|
64
|
+
utils.logLabeledWarning("functions", `Runtime ${types_1.RUNTIMES[runtime].friendly} was deprecated on ${deprecationDate} and will be ` +
|
|
120
65
|
`decommissioned on ${decommissionDate}, after which you will not be able ` +
|
|
121
66
|
"to deploy without upgrading. Consider upgrading now to avoid disruption. See " +
|
|
122
67
|
"https://cloud.google.com/functions/docs/runtime-support for full " +
|
|
@@ -125,7 +70,7 @@ function guardVersionSupport(runtime, now = new Date()) {
|
|
|
125
70
|
}
|
|
126
71
|
const warning = new Date(deprecation.getTime() - 90 * 24 * 60 * 60 * 1000);
|
|
127
72
|
if (now >= warning) {
|
|
128
|
-
utils.logLabeledWarning("functions", `Runtime ${
|
|
73
|
+
utils.logLabeledWarning("functions", `Runtime ${types_1.RUNTIMES[runtime].friendly} will be deprecated on ${deprecationDate} and will be ` +
|
|
129
74
|
`decommissioned on ${decommissionDate}, after which you will not be able ` +
|
|
130
75
|
"to deploy without upgrading. Consider upgrading now to avoid disruption. See " +
|
|
131
76
|
"https://cloud.google.com/functions/docs/runtime-support for full " +
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RUNTIMES = void 0;
|
|
4
|
+
function runtimes(r) {
|
|
5
|
+
return r;
|
|
6
|
+
}
|
|
7
|
+
exports.RUNTIMES = runtimes({
|
|
8
|
+
nodejs6: {
|
|
9
|
+
friendly: "Node.js 6",
|
|
10
|
+
status: "decommissioned",
|
|
11
|
+
deprecationDate: "2019-04-17",
|
|
12
|
+
decommissionDate: "2020-08-01",
|
|
13
|
+
},
|
|
14
|
+
nodejs8: {
|
|
15
|
+
friendly: "Node.js 8",
|
|
16
|
+
status: "decommissioned",
|
|
17
|
+
deprecationDate: "2020-06-05",
|
|
18
|
+
decommissionDate: "2021-02-01",
|
|
19
|
+
},
|
|
20
|
+
nodejs10: {
|
|
21
|
+
friendly: "Node.js 10",
|
|
22
|
+
status: "GA",
|
|
23
|
+
deprecationDate: "2024-01-30",
|
|
24
|
+
decommissionDate: "2025-01-30",
|
|
25
|
+
},
|
|
26
|
+
nodejs12: {
|
|
27
|
+
friendly: "Node.js 12",
|
|
28
|
+
status: "GA",
|
|
29
|
+
deprecationDate: "2024-01-30",
|
|
30
|
+
decommissionDate: "2025-01-30",
|
|
31
|
+
},
|
|
32
|
+
nodejs14: {
|
|
33
|
+
friendly: "Node.js 14",
|
|
34
|
+
status: "GA",
|
|
35
|
+
deprecationDate: "2024-01-30",
|
|
36
|
+
decommissionDate: "2025-01-30",
|
|
37
|
+
},
|
|
38
|
+
nodejs16: {
|
|
39
|
+
friendly: "Node.js 16",
|
|
40
|
+
status: "GA",
|
|
41
|
+
deprecationDate: "2024-01-30",
|
|
42
|
+
decommissionDate: "2025-01-30",
|
|
43
|
+
},
|
|
44
|
+
nodejs18: {
|
|
45
|
+
friendly: "Node.js 18",
|
|
46
|
+
status: "GA",
|
|
47
|
+
deprecationDate: "2025-04-30",
|
|
48
|
+
decommissionDate: "2025-10-31",
|
|
49
|
+
},
|
|
50
|
+
nodejs20: {
|
|
51
|
+
friendly: "Node.js 20",
|
|
52
|
+
status: "GA",
|
|
53
|
+
deprecationDate: "2026-04-30",
|
|
54
|
+
decommissionDate: "2026-10-31",
|
|
55
|
+
},
|
|
56
|
+
python310: {
|
|
57
|
+
friendly: "Python 3.10",
|
|
58
|
+
status: "GA",
|
|
59
|
+
deprecationDate: "2026-10-04",
|
|
60
|
+
decommissionDate: "2027-04-30",
|
|
61
|
+
},
|
|
62
|
+
python311: {
|
|
63
|
+
friendly: "Python 3.11",
|
|
64
|
+
status: "GA",
|
|
65
|
+
deprecationDate: "2027-10-24",
|
|
66
|
+
decommissionDate: "2028-04-30",
|
|
67
|
+
},
|
|
68
|
+
python312: {
|
|
69
|
+
friendly: "Python 3.12",
|
|
70
|
+
status: "GA",
|
|
71
|
+
deprecationDate: "2028-10-02",
|
|
72
|
+
decommissionDate: "2029-04-30",
|
|
73
|
+
},
|
|
74
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getRuntime = exports.DEFAULT_RUNTIME = exports.getFunctionProperties = exports.getFunctionResourcesWithParamSubstitution = exports.readFileFromDirectory = exports.readPostinstall = exports.readExtensionYaml = void 0;
|
|
4
|
-
const yaml = require("
|
|
4
|
+
const yaml = require("yaml");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs-extra");
|
|
7
7
|
const supported = require("../../deploy/functions/runtimes/supported");
|
|
@@ -17,10 +17,10 @@ const validFunctionTypes = [
|
|
|
17
17
|
];
|
|
18
18
|
function wrappedSafeLoad(source) {
|
|
19
19
|
try {
|
|
20
|
-
return yaml.
|
|
20
|
+
return yaml.parse(source);
|
|
21
21
|
}
|
|
22
22
|
catch (err) {
|
|
23
|
-
if (err instanceof yaml.
|
|
23
|
+
if (err instanceof yaml.YAMLParseError) {
|
|
24
24
|
throw new error_1.FirebaseError(`YAML Error: ${err.message}`, { original: err });
|
|
25
25
|
}
|
|
26
26
|
throw err;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.refNotFoundError = exports.getExtension = exports.listExtensionVersions = exports.listExtensions = exports.getExtensionVersion = exports.getSource = exports.createSource = exports.populateSpec = exports.updateInstanceFromRegistry = exports.updateInstance = exports.configureInstance = exports.listInstances = exports.getInstance = exports.deleteInstance = exports.createInstance = void 0;
|
|
4
|
-
const yaml = require("
|
|
4
|
+
const yaml = require("yaml");
|
|
5
5
|
const clc = require("colorette");
|
|
6
6
|
const apiv2_1 = require("../apiv2");
|
|
7
7
|
const api_1 = require("../api");
|
|
@@ -230,7 +230,7 @@ function populateSpec(spec) {
|
|
|
230
230
|
for (const r of spec.resources) {
|
|
231
231
|
try {
|
|
232
232
|
if (r.propertiesYaml) {
|
|
233
|
-
r.properties = yaml.
|
|
233
|
+
r.properties = yaml.parse(r.propertiesYaml);
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
catch (err) {
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isLocalExtension = exports.readFile = exports.findExtensionYaml = exports.getLocalExtensionSpec = exports.EXTENSIONS_SPEC_FILE = void 0;
|
|
4
4
|
const fs = require("fs-extra");
|
|
5
5
|
const path = require("path");
|
|
6
|
-
const yaml = require("
|
|
6
|
+
const yaml = require("yaml");
|
|
7
7
|
const fsutils_1 = require("../fsutils");
|
|
8
8
|
const error_1 = require("../error");
|
|
9
9
|
const logger_1 = require("../logger");
|
|
@@ -56,10 +56,10 @@ function isLocalExtension(extensionName) {
|
|
|
56
56
|
exports.isLocalExtension = isLocalExtension;
|
|
57
57
|
function parseYAML(source) {
|
|
58
58
|
try {
|
|
59
|
-
return yaml.
|
|
59
|
+
return yaml.parse(source);
|
|
60
60
|
}
|
|
61
61
|
catch (err) {
|
|
62
|
-
if (err instanceof yaml.
|
|
62
|
+
if (err instanceof yaml.YAMLParseError) {
|
|
63
63
|
throw new error_1.FirebaseError(`YAML Error: ${err.message}`, { original: err });
|
|
64
64
|
}
|
|
65
65
|
throw new error_1.FirebaseError(err.message);
|
|
@@ -4,7 +4,7 @@ exports.ɵcodegenPublicDirectory = exports.build = exports.init = exports.discov
|
|
|
4
4
|
const cross_spawn_1 = require("cross-spawn");
|
|
5
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
6
|
const path_1 = require("path");
|
|
7
|
-
const
|
|
7
|
+
const yaml = require("yaml");
|
|
8
8
|
const promises_1 = require("fs/promises");
|
|
9
9
|
const error_1 = require("../../error");
|
|
10
10
|
const utils_1 = require("./utils");
|
|
@@ -19,7 +19,7 @@ async function discover(dir) {
|
|
|
19
19
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "web"))))
|
|
20
20
|
return;
|
|
21
21
|
const pubSpecBuffer = await (0, promises_1.readFile)((0, path_1.join)(dir, "pubspec.yaml"));
|
|
22
|
-
const pubSpec =
|
|
22
|
+
const pubSpec = yaml.parse(pubSpecBuffer.toString());
|
|
23
23
|
const usingFlutter = (_a = pubSpec.dependencies) === null || _a === void 0 ? void 0 : _a.flutter;
|
|
24
24
|
if (!usingFlutter)
|
|
25
25
|
return;
|
|
@@ -3,8 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isRunningInGithubAction = exports.initGitHub = void 0;
|
|
4
4
|
const colorette_1 = require("colorette");
|
|
5
5
|
const fs = require("fs");
|
|
6
|
-
const yaml = require("
|
|
7
|
-
const js_yaml_1 = require("js-yaml");
|
|
6
|
+
const yaml = require("yaml");
|
|
8
7
|
const ora = require("ora");
|
|
9
8
|
const path = require("path");
|
|
10
9
|
const libsodium = require("libsodium-wrappers");
|
|
@@ -149,7 +148,7 @@ function loadYMLDeploy() {
|
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
function loadYML(ymlPath) {
|
|
152
|
-
return
|
|
151
|
+
return yaml.parse(fs.readFileSync(ymlPath, "utf8"));
|
|
153
152
|
}
|
|
154
153
|
function mkdirNotExists(dir) {
|
|
155
154
|
if (!(0, fsutils_1.dirExistsSync)(dir)) {
|
|
@@ -189,7 +188,7 @@ function writeChannelActionYMLFile(ymlPath, secretName, projectId, script) {
|
|
|
189
188
|
const ymlContents = `# This file was auto-generated by the Firebase CLI
|
|
190
189
|
# https://github.com/firebase/firebase-tools
|
|
191
190
|
|
|
192
|
-
${yaml.
|
|
191
|
+
${yaml.stringify(workflowConfig)}`;
|
|
193
192
|
mkdirNotExists(GITHUB_DIR);
|
|
194
193
|
mkdirNotExists(WORKFLOW_DIR);
|
|
195
194
|
fs.writeFileSync(ymlPath, ymlContents, "utf8");
|
|
@@ -222,7 +221,7 @@ function writeDeployToProdActionYMLFile(ymlPath, branch, secretName, projectId,
|
|
|
222
221
|
const ymlContents = `# This file was auto-generated by the Firebase CLI
|
|
223
222
|
# https://github.com/firebase/firebase-tools
|
|
224
223
|
|
|
225
|
-
${yaml.
|
|
224
|
+
${yaml.stringify(workflowConfig)}`;
|
|
226
225
|
mkdirNotExists(GITHUB_DIR);
|
|
227
226
|
mkdirNotExists(WORKFLOW_DIR);
|
|
228
227
|
fs.writeFileSync(ymlPath, ymlContents, "utf8");
|
package/lib/utils.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getHostnameFromUrl = exports.openInBrowserPopup = exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = exports.IS_WINDOWS = void 0;
|
|
4
|
+
exports.readSecretValue = void 0;
|
|
4
5
|
const fs = require("node:fs");
|
|
6
|
+
const tty = require("tty");
|
|
5
7
|
const path = require("node:path");
|
|
6
8
|
const _ = require("lodash");
|
|
7
9
|
const url = require("url");
|
|
@@ -19,6 +21,7 @@ const portfinder_1 = require("portfinder");
|
|
|
19
21
|
const configstore_1 = require("./configstore");
|
|
20
22
|
const error_1 = require("./error");
|
|
21
23
|
const logger_1 = require("./logger");
|
|
24
|
+
const prompt_1 = require("./prompt");
|
|
22
25
|
exports.IS_WINDOWS = process.platform === "win32";
|
|
23
26
|
const SUCCESS_CHAR = exports.IS_WINDOWS ? "+" : "✔";
|
|
24
27
|
const WARNING_CHAR = exports.IS_WINDOWS ? "!" : "⚠";
|
|
@@ -524,3 +527,17 @@ function getHostnameFromUrl(url) {
|
|
|
524
527
|
}
|
|
525
528
|
}
|
|
526
529
|
exports.getHostnameFromUrl = getHostnameFromUrl;
|
|
530
|
+
function readSecretValue(prompt, dataFile) {
|
|
531
|
+
if ((!dataFile || dataFile === "-") && tty.isatty(0)) {
|
|
532
|
+
return (0, prompt_1.promptOnce)({
|
|
533
|
+
type: "password",
|
|
534
|
+
message: prompt,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
let input = 0;
|
|
538
|
+
if (dataFile && dataFile !== "-") {
|
|
539
|
+
input = dataFile;
|
|
540
|
+
}
|
|
541
|
+
return Promise.resolve(fs.readFileSync(input, "utf-8"));
|
|
542
|
+
}
|
|
543
|
+
exports.readSecretValue = readSecretValue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "13.7.
|
|
3
|
+
"version": "13.7.3",
|
|
4
4
|
"description": "Command-Line Interface for Firebase",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"google-auth-library": "^7.11.0",
|
|
87
87
|
"inquirer": "^8.2.6",
|
|
88
88
|
"inquirer-autocomplete-prompt": "^2.0.1",
|
|
89
|
-
"js-yaml": "^3.13.1",
|
|
90
89
|
"jsonwebtoken": "^9.0.0",
|
|
91
90
|
"leven": "^3.1.0",
|
|
92
91
|
"libsodium-wrappers": "^0.7.10",
|
|
@@ -119,6 +118,7 @@
|
|
|
119
118
|
"uuid": "^8.3.2",
|
|
120
119
|
"winston": "^3.0.0",
|
|
121
120
|
"winston-transport": "^4.4.0",
|
|
122
|
-
"ws": "^7.2.3"
|
|
121
|
+
"ws": "^7.2.3",
|
|
122
|
+
"yaml": "^2.4.1"
|
|
123
123
|
}
|
|
124
124
|
}
|