Skip to content

Commit 67af8ae

Browse files
authored
Better handling when updating from LOCATION to system param (#6202)
* Better handling when updating from LOCATION to system param * test fix * Format * Use the correct spec in test
1 parent 69721e7 commit 67af8ae

File tree

4 files changed

+78
-117
lines changed

4 files changed

+78
-117
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
- Fix bug where functions:secrets:\* family of commands did not work when Firebase CLI is authenticated via GOOGLE_APPLICATION_CREDENTIALS (#6190)
1+
- Fixed bug where `functions:secrets:\*` family of commands did not work when Firebase CLI is authenticated via GOOGLE_APPLICATION_CREDENTIALS (#6190)
2+
- Fixed bug where some extension instance updates would default to the wrong location.

src/commands/ext-configure.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ export const command = new Command("ext:configure <extensionInstanceId>")
7676
instanceId,
7777
projectDir: config.projectDir,
7878
});
79+
const params = (spec.params ?? []).concat(spec.systemParams ?? []);
7980
const [immutableParams, tbdParams] = partition(
80-
(spec.params ?? []).concat(spec.systemParams ?? []),
81-
(param) => param.immutable ?? false
81+
params,
82+
(param) => (param.immutable && !!oldParamValues[param.param]) ?? false
8283
);
8384
infoImmutableParams(immutableParams, oldParamValues);
8485

src/extensions/paramHelper.ts

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import * as fs from "fs-extra";
44

55
import { FirebaseError } from "../error";
66
import { logger } from "../logger";
7-
import { ExtensionInstance, ExtensionSpec, Param } from "./types";
7+
import { ExtensionSpec, Param } from "./types";
88
import { getFirebaseProjectParams, substituteParams } from "./extensionsHelper";
99
import * as askUserForParam from "./askUserForParam";
1010
import * as env from "../functions/env";
11-
import { cloneDeep } from "../utils";
1211

1312
const NONINTERACTIVE_ERROR_MESSAGE =
1413
"As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
@@ -61,26 +60,19 @@ export function buildBindingOptionsWithBaseValue(baseParams: { [key: string]: st
6160
* @param newDefaults a map of { PARAM_NAME: default_value }
6261
*/
6362
export function setNewDefaults(params: Param[], newDefaults: { [key: string]: string }): Param[] {
64-
params.forEach((param) => {
65-
if (newDefaults[param.param.toUpperCase()]) {
66-
param.default = newDefaults[param.param.toUpperCase()];
63+
for (const param of params) {
64+
if (newDefaults[param.param]) {
65+
param.default = newDefaults[param.param];
66+
} else if (
67+
(param.param = `firebaseextensions.v1beta.function/location` && newDefaults["LOCATION"])
68+
) {
69+
// Special case handling for when we are updating from LOCATION to system param location.
70+
param.default = newDefaults["LOCATION"];
6771
}
68-
});
72+
}
6973
return params;
7074
}
7175

72-
/**
73-
* Returns a copy of the params for a extension instance with the defaults set to the instance's current param values
74-
* @param extensionInstance the extension instance to change the default params of
75-
*/
76-
export function getParamsWithCurrentValuesAsDefaults(
77-
extensionInstance: ExtensionInstance
78-
): Param[] {
79-
const specParams = cloneDeep(extensionInstance?.config?.source?.spec?.params || []);
80-
const currentParams = cloneDeep(extensionInstance?.config?.params || {});
81-
return setNewDefaults(specParams, currentParams);
82-
}
83-
8476
/**
8577
* Gets params from the user
8678
* or prompting the user for each param.
@@ -160,15 +152,37 @@ export async function promptForNewParams(args: {
160152
return left.filter((aLeft) => !right.find(sameParam(aLeft)));
161153
};
162154

155+
let combinedOldParams = args.spec.params.concat(
156+
args.spec.systemParams.filter((p) => !p.advanced) ?? []
157+
);
158+
let combinedNewParams = args.newSpec.params.concat(
159+
args.newSpec.systemParams.filter((p) => !p.advanced) ?? []
160+
);
161+
162+
// Special case for updating from LOCATION to system param location
163+
if (
164+
combinedOldParams.some((p) => p.param === "LOCATION") &&
165+
combinedNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location") &&
166+
!!args.currentParams["LOCATION"]
167+
) {
168+
newParamBindingOptions["firebaseextensions.v1beta.function/location"] = {
169+
baseValue: args.currentParams["LOCATION"],
170+
};
171+
delete newParamBindingOptions["LOCATION"];
172+
combinedOldParams = combinedOldParams.filter((p) => p.param !== "LOCATION");
173+
combinedNewParams = combinedNewParams.filter(
174+
(p) => p.param !== "firebaseextensions.v1beta.function/location"
175+
);
176+
}
177+
163178
// Some params are in the spec but not in currentParams, remove so we can prompt for them.
164-
const oldParams = args.spec.params.filter((p) =>
179+
const oldParams = combinedOldParams.filter((p) =>
165180
Object.keys(args.currentParams).includes(p.param)
166181
);
167-
168-
let paramsDiffDeletions = paramDiff(oldParams, args.newSpec.params);
182+
let paramsDiffDeletions = paramDiff(oldParams, combinedNewParams);
169183
paramsDiffDeletions = substituteParams<Param[]>(paramsDiffDeletions, firebaseProjectParams);
170184

171-
let paramsDiffAdditions = paramDiff(args.newSpec.params, oldParams);
185+
let paramsDiffAdditions = paramDiff(combinedNewParams, oldParams);
172186
paramsDiffAdditions = substituteParams<Param[]>(paramsDiffAdditions, firebaseProjectParams);
173187

174188
if (paramsDiffDeletions.length) {

src/test/extensions/paramHelper.spec.ts

Lines changed: 37 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as sinon from "sinon";
33
import * as fs from "fs-extra";
44

55
import { FirebaseError } from "../../error";
6-
import { ExtensionInstance, Param, ParamType } from "../../extensions/types";
6+
import { ExtensionSpec, Param, ParamType } from "../../extensions/types";
77
import * as extensionsHelper from "../../extensions/extensionsHelper";
88
import * as paramHelper from "../../extensions/paramHelper";
99
import * as prompt from "../../prompt";
@@ -63,7 +63,7 @@ const TEST_PARAMS_3: Param[] = [
6363
},
6464
];
6565

66-
const SPEC = {
66+
const SPEC: ExtensionSpec = {
6767
name: "test",
6868
version: "0.1.0",
6969
roles: [],
@@ -152,96 +152,6 @@ describe("paramHelper", () => {
152152
});
153153
});
154154

155-
describe("getParamsWithCurrentValuesAsDefaults", () => {
156-
let params: { [key: string]: string };
157-
let testInstance: ExtensionInstance;
158-
beforeEach(() => {
159-
params = { A_PARAMETER: "new default" };
160-
testInstance = {
161-
config: {
162-
source: {
163-
state: "ACTIVE",
164-
name: "",
165-
packageUri: "",
166-
hash: "",
167-
spec: {
168-
name: "",
169-
version: "0.1.0",
170-
roles: [],
171-
resources: [],
172-
params: [...TEST_PARAMS],
173-
systemParams: [],
174-
sourceUrl: "",
175-
},
176-
},
177-
name: "test",
178-
createTime: "now",
179-
params,
180-
systemParams: {},
181-
},
182-
name: "test",
183-
createTime: "now",
184-
updateTime: "now",
185-
state: "ACTIVE",
186-
serviceAccountEmail: "test@test.com",
187-
};
188-
189-
it("should add defaults to params without them using the current state and leave other values unchanged", () => {
190-
const newParams = paramHelper.getParamsWithCurrentValuesAsDefaults(testInstance);
191-
192-
expect(newParams).to.eql([
193-
{
194-
param: "A_PARAMETER",
195-
label: "Param",
196-
default: "new default",
197-
type: ParamType.STRING,
198-
required: true,
199-
},
200-
{
201-
param: "ANOTHER_PARAMETER",
202-
label: "Another",
203-
default: "default",
204-
type: ParamType.STRING,
205-
},
206-
]);
207-
});
208-
});
209-
210-
it("should change existing defaults to the current state and leave other values unchanged", () => {
211-
(testInstance.config?.source?.spec?.params || []).push({
212-
param: "THIRD",
213-
label: "3rd",
214-
default: "default",
215-
type: ParamType.STRING,
216-
});
217-
testInstance.config.params.THIRD = "New Default";
218-
const newParams = paramHelper.getParamsWithCurrentValuesAsDefaults(testInstance);
219-
220-
expect(newParams).to.eql([
221-
{
222-
param: "A_PARAMETER",
223-
label: "Param",
224-
default: "new default",
225-
type: ParamType.STRING,
226-
required: true,
227-
},
228-
{
229-
param: "ANOTHER_PARAMETER",
230-
label: "Another Param",
231-
default: "default",
232-
required: true,
233-
type: ParamType.STRING,
234-
},
235-
{
236-
param: "THIRD",
237-
label: "3rd",
238-
default: "New Default",
239-
type: ParamType.STRING,
240-
},
241-
]);
242-
});
243-
});
244-
245155
describe("promptForNewParams", () => {
246156
let promptStub: sinon.SinonStub;
247157

@@ -319,6 +229,41 @@ describe("paramHelper", () => {
319229
expect(newParams).to.eql(expected);
320230
});
321231

232+
it("should map LOCATION to system param location and not prompt for it", async () => {
233+
promptStub.resolves("user input");
234+
const oldSpec = cloneDeep(SPEC);
235+
const newSpec = cloneDeep(SPEC);
236+
oldSpec.params = [
237+
{
238+
param: "LOCATION",
239+
label: "",
240+
},
241+
];
242+
newSpec.params = [];
243+
newSpec.systemParams = [
244+
{
245+
param: "firebaseextensions.v1beta.function/location",
246+
label: "",
247+
},
248+
];
249+
250+
const newParams = await paramHelper.promptForNewParams({
251+
spec: oldSpec,
252+
newSpec,
253+
currentParams: {
254+
LOCATION: "us-east1",
255+
},
256+
projectId: PROJECT_ID,
257+
instanceId: INSTANCE_ID,
258+
});
259+
260+
const expected = {
261+
"firebaseextensions.v1beta.function/location": { baseValue: "us-east1" },
262+
};
263+
expect(newParams).to.eql(expected);
264+
expect(promptStub).not.to.have.been.called;
265+
});
266+
322267
it("should not prompt the user for params that did not change type or param", async () => {
323268
promptStub.resolves("Fail");
324269
const newSpec = cloneDeep(SPEC);

0 commit comments

Comments
 (0)