From 17562130995ee5ca4f995300a17218dfdafdc394 Mon Sep 17 00:00:00 2001 From: joehan Date: Fri, 13 Jan 2023 14:16:12 -0800 Subject: [PATCH] Add support for system params when deploying extensions (#5414) * Add support for configuring system params when deploying extensions * Allow . and / in env keys * Make partitionRecord more flexible --- src/commands/ext-configure.ts | 2 +- src/commands/ext-install.ts | 2 +- src/deploy/extensions/planner.ts | 26 +++++++----- src/deploy/extensions/tasks.ts | 6 +++ src/extensions/extensionsApi.ts | 25 +++++++++-- src/extensions/paramHelper.ts | 5 +++ src/extensions/types.ts | 6 +-- src/functional.ts | 24 +++++++++-- src/functions/env.ts | 2 +- src/test/deploy/extensions/planner.spec.ts | 4 ++ .../emulators/extensions/validation.spec.ts | 2 + src/test/emulators/extensionsEmulator.spec.ts | 2 + .../emulators/functionsEmulatorShared.spec.ts | 2 + .../extensions/billingMigrationHelper.spec.ts | 3 ++ src/test/extensions/change-log.spec.ts | 1 + .../extensions/displayExtensionInfo.spec.ts | 1 + .../extensions/emulator/optionsHelper.spec.ts | 1 + src/test/extensions/export.spec.ts | 4 ++ src/test/extensions/extensionsApi.spec.ts | 41 +++++++++++++++++-- src/test/extensions/extensionsHelper.spec.ts | 6 +++ src/test/extensions/manifest.spec.ts | 14 +++++++ src/test/extensions/paramHelper.spec.ts | 3 ++ src/test/extensions/secretUtils.spec.ts | 2 + src/test/extensions/updateHelper.spec.ts | 1 + src/test/extensions/warnings.spec.ts | 2 + src/test/functional.spec.ts | 17 ++++++++ 26 files changed, 178 insertions(+), 26 deletions(-) diff --git a/src/commands/ext-configure.ts b/src/commands/ext-configure.ts index b94e6e59dd7..59acf297db8 100644 --- a/src/commands/ext-configure.ts +++ b/src/commands/ext-configure.ts @@ -78,7 +78,7 @@ export const command = new Command("ext:configure ") }); const [immutableParams, tbdParams] = partition( - spec.params, + spec.params.concat(spec.systemParams ?? []), (param) => param.immutable ?? false ); infoImmutableParams(immutableParams, oldParamValues); diff --git a/src/commands/ext-install.ts b/src/commands/ext-install.ts index 653ab1cd61b..c0cbc298d2b 100644 --- a/src/commands/ext-install.ts +++ b/src/commands/ext-install.ts @@ -212,7 +212,7 @@ async function installToManifest(options: InstallExtensionOptions): Promise; + systemParams: Record; allowedEventTypes?: string[]; eventarcChannel?: string; etag?: string; @@ -107,6 +109,7 @@ export async function have(projectId: string): Promise const dep: DeploymentInstanceSpec = { instanceId: i.name.split("/").pop()!, params: i.config.params, + systemParams: i.config.systemParams ?? {}, allowedEventTypes: i.config.allowedEventTypes, eventarcChannel: i.config.eventarcChannel, etag: i.etag, @@ -145,7 +148,7 @@ export async function want(args: { try { const instanceId = e[0]; - const params = readInstanceParam({ + const rawParams = readInstanceParam({ projectDir: args.projectDir, instanceId, projectId: args.projectId, @@ -154,26 +157,28 @@ export async function want(args: { checkLocal: args.emulatorMode, }); const autoPopulatedParams = await getFirebaseProjectParams(args.projectId, args.emulatorMode); - const subbedParams = substituteParams(params, autoPopulatedParams); + const subbedParams = substituteParams(rawParams, autoPopulatedParams); + const [systemParams, params] = partitionRecord(subbedParams, isSystemParam); // ALLOWED_EVENT_TYPES can be undefined (user input not provided) or empty string (no events selected). // If empty string, we want to pass an empty array. If it's undefined we want to pass through undefined. const allowedEventTypes = - subbedParams.ALLOWED_EVENT_TYPES !== undefined - ? subbedParams.ALLOWED_EVENT_TYPES.split(",").filter((e) => e !== "") + params.ALLOWED_EVENT_TYPES !== undefined + ? params.ALLOWED_EVENT_TYPES.split(",").filter((e) => e !== "") : undefined; - const eventarcChannel = subbedParams.EVENTARC_CHANNEL; + const eventarcChannel = params.EVENTARC_CHANNEL; // Remove special params that are stored in the .env file but aren't actually params specified by the publisher. // Currently, only environment variables needed for Events features are considered special params stored in .env files. - delete subbedParams["EVENTARC_CHANNEL"]; - delete subbedParams["ALLOWED_EVENT_TYPES"]; + delete params["EVENTARC_CHANNEL"]; + delete params["ALLOWED_EVENT_TYPES"]; if (isLocalPath(e[1])) { instanceSpecs.push({ instanceId, localPath: e[1], - params: subbedParams, + params, + systemParams, allowedEventTypes: allowedEventTypes, eventarcChannel: eventarcChannel, }); @@ -183,7 +188,8 @@ export async function want(args: { instanceSpecs.push({ instanceId, ref, - params: subbedParams, + params, + systemParams, allowedEventTypes: allowedEventTypes, eventarcChannel: eventarcChannel, }); diff --git a/src/deploy/extensions/tasks.ts b/src/deploy/extensions/tasks.ts index 844190f1619..a34bd492dc1 100644 --- a/src/deploy/extensions/tasks.ts +++ b/src/deploy/extensions/tasks.ts @@ -49,6 +49,7 @@ export function createExtensionInstanceTask( projectId, instanceId: instanceSpec.instanceId, params: instanceSpec.params, + systemParams: instanceSpec.systemParams, extensionVersionRef: refs.toExtensionVersionRef(instanceSpec.ref), allowedEventTypes: instanceSpec.allowedEventTypes, eventarcChannel: instanceSpec.eventarcChannel, @@ -60,6 +61,7 @@ export function createExtensionInstanceTask( projectId, instanceId: instanceSpec.instanceId, params: instanceSpec.params, + systemParams: instanceSpec.systemParams, extensionSource, allowedEventTypes: instanceSpec.allowedEventTypes, eventarcChannel: instanceSpec.eventarcChannel, @@ -92,6 +94,7 @@ export function updateExtensionInstanceTask( instanceId: instanceSpec.instanceId, extRef: refs.toExtensionVersionRef(instanceSpec.ref!), params: instanceSpec.params, + systemParams: instanceSpec.systemParams, canEmitEvents: !!instanceSpec.allowedEventTypes, allowedEventTypes: instanceSpec.allowedEventTypes, eventarcChannel: instanceSpec.eventarcChannel, @@ -104,6 +107,8 @@ export function updateExtensionInstanceTask( instanceId: instanceSpec.instanceId, extensionSource, validateOnly, + params: instanceSpec.params, + systemParams: instanceSpec.systemParams, canEmitEvents: !!instanceSpec.allowedEventTypes, allowedEventTypes: instanceSpec.allowedEventTypes, eventarcChannel: instanceSpec.eventarcChannel, @@ -134,6 +139,7 @@ export function configureExtensionInstanceTask( projectId, instanceId: instanceSpec.instanceId, params: instanceSpec.params, + systemParams: instanceSpec.systemParams, canEmitEvents: !!instanceSpec.allowedEventTypes, allowedEventTypes: instanceSpec.allowedEventTypes, eventarcChannel: instanceSpec.eventarcChannel, diff --git a/src/extensions/extensionsApi.ts b/src/extensions/extensionsApi.ts index 2a99867c7f2..9c8f224e8dd 100644 --- a/src/extensions/extensionsApi.ts +++ b/src/extensions/extensionsApi.ts @@ -73,13 +73,15 @@ export async function createInstance(args: { instanceId: string; extensionSource?: ExtensionSource; extensionVersionRef?: string; - params: { [key: string]: string }; + params: Record; + systemParams?: Record; allowedEventTypes?: string[]; eventarcChannel?: string; validateOnly?: boolean; }): Promise { const config: any = { params: args.params, + systemParams: args.systemParams ?? {}, allowedEventTypes: args.allowedEventTypes, eventarcChannel: args.eventarcChannel, }; @@ -188,7 +190,8 @@ export async function listInstances(projectId: string): Promise; + systemParams?: Record; canEmitEvents: boolean; allowedEventTypes?: string[]; eventarcChannel?: string; @@ -215,6 +218,10 @@ export async function configureInstance(args: { reqBody.data.config.eventarcChannel = args.eventarcChannel; } reqBody.updateMask += ",config.allowed_event_types,config.eventarc_channel"; + if (args.systemParams) { + reqBody.data.config.systemParams = args.systemParams; + reqBody.updateMask += ",config.system_params"; + } return patchInstance(reqBody); } @@ -233,7 +240,8 @@ export async function updateInstance(args: { projectId: string; instanceId: string; extensionSource: ExtensionSource; - params?: { [option: string]: string }; + params?: Record; + systemParams?: Record; canEmitEvents: boolean; allowedEventTypes?: string[]; eventarcChannel?: string; @@ -249,6 +257,10 @@ export async function updateInstance(args: { body.config.params = args.params; updateMask += ",config.params"; } + if (args.systemParams) { + body.config.systemParams = args.systemParams; + updateMask += ",config.system_params"; + } if (args.canEmitEvents) { if (args.allowedEventTypes === undefined || args.eventarcChannel === undefined) { throw new FirebaseError( @@ -283,7 +295,8 @@ export async function updateInstanceFromRegistry(args: { projectId: string; instanceId: string; extRef: string; - params?: { [option: string]: string }; + params?: Record; + systemParams?: Record; canEmitEvents: boolean; allowedEventTypes?: string[]; eventarcChannel?: string; @@ -301,6 +314,10 @@ export async function updateInstanceFromRegistry(args: { body.config.params = args.params; updateMask += ",config.params"; } + if (args.systemParams) { + body.config.systemParams = args.systemParams; + updateMask += ",config.system_params"; + } if (args.canEmitEvents) { if (args.allowedEventTypes === undefined || args.eventarcChannel === undefined) { throw new FirebaseError( diff --git a/src/extensions/paramHelper.ts b/src/extensions/paramHelper.ts index 0e4a92aea3d..4ab26447699 100644 --- a/src/extensions/paramHelper.ts +++ b/src/extensions/paramHelper.ts @@ -265,3 +265,8 @@ export function readEnvFile(envPath: string): Record { } return result.envs; } + +export function isSystemParam(paramName: string): boolean { + const regex = /^firebaseextensions\.[a-zA-Z0-9\.]*\//; + return regex.test(paramName); +} diff --git a/src/extensions/types.ts b/src/extensions/types.ts index 2138e1643eb..a0de32e54c3 100644 --- a/src/extensions/types.ts +++ b/src/extensions/types.ts @@ -63,9 +63,8 @@ export interface ExtensionConfig { name: string; createTime: string; source: ExtensionSource; - params: { - [key: string]: any; - }; + params: Record; + systemParams: Record; populatedPostinstallContent?: string; extensionRef?: string; extensionVersion?: string; @@ -100,6 +99,7 @@ export interface ExtensionSpec { releaseNotesUrl?: string; sourceUrl?: string; params: Param[]; + systemParams: Param[]; preinstallContent?: string; postinstallContent?: string; readmeContent?: string; diff --git a/src/functional.ts b/src/functional.ts index 4746e130ab4..b6c638816cd 100644 --- a/src/functional.ts +++ b/src/functional.ts @@ -97,20 +97,38 @@ export function assertExhaustive(val: never): never { } /** - * Utility to partition an array into two based on callbackFn's truthiness for each element. + * Utility to partition an array into two based on predicate's truthiness for each element. * Returns a Array containing two Array. The first array contains all elements that returned true, * the second contains all elements that returned false. */ -export function partition(arr: T[], callbackFn: (elem: T) => boolean): [T[], T[]] { +export function partition(arr: T[], predicate: (elem: T) => boolean): [T[], T[]] { return arr.reduce<[T[], T[]]>( (acc, elem) => { - acc[callbackFn(elem) ? 0 : 1].push(elem); + acc[predicate(elem) ? 0 : 1].push(elem); return acc; }, [[], []] ); } +/** + * Utility to partition a Record into two based on predicate's truthiness for each element. + * Returns a Array containing two Record. The first array contains all elements that returned true, + * the second contains all elements that returned false. + */ +export function partitionRecord( + rec: Record, + predicate: (key: string, val: T) => boolean +): [Record, Record] { + return Object.entries(rec).reduce<[Record, Record]>( + (acc, [key, val]) => { + acc[predicate(key, val) ? 0 : 1][key] = val; + return acc; + }, + [{}, {}] + ); +} + /** * Create a map of transformed values for all keys. */ diff --git a/src/functions/env.ts b/src/functions/env.ts index 2bd72806e2c..b640aff443e 100644 --- a/src/functions/env.ts +++ b/src/functions/env.ts @@ -45,7 +45,7 @@ const RESERVED_KEYS = [ const LINE_RE = new RegExp( "^" + // begin line "\\s*" + // leading whitespaces - "(\\w+)" + // key + "([\\w./]+)" + // key "\\s*=[\\f\\t\\v]*" + // separator (=) "(" + // begin optional value "\\s*'(?:\\\\'|[^'])*'|" + // single quoted or diff --git a/src/test/deploy/extensions/planner.spec.ts b/src/test/deploy/extensions/planner.spec.ts index 1d4aef34917..c5ddffc6ca5 100644 --- a/src/test/deploy/extensions/planner.spec.ts +++ b/src/test/deploy/extensions/planner.spec.ts @@ -18,6 +18,7 @@ function extensionVersion(version?: string): any { resources: [], sourceUrl: "https://google.com", params: [], + systemParam: [], }, }; } @@ -105,6 +106,7 @@ describe("Extensions Deployment Planner", () => { name: "", sourceUrl: "", params: [], + systemParams: [], }; const INSTANCE_WITH_EVENTS: ExtensionInstance = { @@ -116,6 +118,7 @@ describe("Extensions Deployment Planner", () => { etag: "123456", config: { params: {}, + systemParams: {}, extensionRef: "firebase/image-resizer", extensionVersion: "0.1.0", name: "projects/my-test-proj/instances/image-resizer/configurations/95355951-397f-4821-a5c2-9c9788b2cc63", @@ -135,6 +138,7 @@ describe("Extensions Deployment Planner", () => { const INSTANCE_SPEC_WITH_EVENTS: planner.DeploymentInstanceSpec = { instanceId: "image-resizer", params: {}, + systemParams: {}, allowedEventTypes: ["google.firebase.custom-event-occurred"], eventarcChannel: "projects/my-test-proj/locations/us-central1/channels/firebase", etag: "123456", diff --git a/src/test/emulators/extensions/validation.spec.ts b/src/test/emulators/extensions/validation.spec.ts index 8be9e7eebd4..83ec72a1aad 100644 --- a/src/test/emulators/extensions/validation.spec.ts +++ b/src/test/emulators/extensions/validation.spec.ts @@ -30,6 +30,7 @@ function fakeInstanceSpecWithAPI(instanceId: string, apiName: string): Deploymen return { instanceId, params: {}, + systemParams: {}, ref: { publisherId: "test", extensionId: "test", @@ -47,6 +48,7 @@ function fakeInstanceSpecWithAPI(instanceId: string, apiName: string): Deploymen sourceUrl: "test.com", resources: [], params: [], + systemParams: [], apis: [{ apiName, reason: "because" }], }, }, diff --git a/src/test/emulators/extensionsEmulator.spec.ts b/src/test/emulators/extensionsEmulator.spec.ts index baa0c6c5a05..93093146ea8 100644 --- a/src/test/emulators/extensionsEmulator.spec.ts +++ b/src/test/emulators/extensionsEmulator.spec.ts @@ -45,6 +45,7 @@ const TEST_EXTENSION_VERSION: ExtensionVersion = { }, ], params: [], + systemParams: [], version: "0.1.18", sourceUrl: "https://fake.test", }, @@ -80,6 +81,7 @@ describe("Extensions Emulator", () => { "google.firebase.image-resize-started,google.firebase.image-resize-completed", EVENTARC_CHANNEL: "projects/test-project/locations/us-central1/channels/firebase", }, + systemParams: {}, allowedEventTypes: [ "google.firebase.image-resize-started", "google.firebase.image-resize-completed", diff --git a/src/test/emulators/functionsEmulatorShared.spec.ts b/src/test/emulators/functionsEmulatorShared.spec.ts index 67321d1f18d..de84d4dfc3d 100644 --- a/src/test/emulators/functionsEmulatorShared.spec.ts +++ b/src/test/emulators/functionsEmulatorShared.spec.ts @@ -158,6 +158,7 @@ describe("FunctionsEmulatorShared", () => { resources: [], sourceUrl: "test.com", params: [], + systemParams: [], postinstallContent: "Should subsitute ${param:KEY}", }; const testSubbedSpec: ExtensionSpec = { @@ -166,6 +167,7 @@ describe("FunctionsEmulatorShared", () => { resources: [], sourceUrl: "test.com", params: [], + systemParams: [], postinstallContent: "Should subsitute value", }; const testExtension: Extension = { diff --git a/src/test/extensions/billingMigrationHelper.spec.ts b/src/test/extensions/billingMigrationHelper.spec.ts index 8cf215843bf..fb487fa1378 100644 --- a/src/test/extensions/billingMigrationHelper.spec.ts +++ b/src/test/extensions/billingMigrationHelper.spec.ts @@ -27,6 +27,7 @@ const NO_RUNTIME_SPEC: ExtensionSpec = { billingRequired: true, sourceUrl: "test.com", params: [], + systemParams: [], }; const NODE8_SPEC: ExtensionSpec = { @@ -49,6 +50,7 @@ const NODE8_SPEC: ExtensionSpec = { billingRequired: true, sourceUrl: "test.com", params: [], + systemParams: [], }; const NODE10_SPEC: ExtensionSpec = { @@ -71,6 +73,7 @@ const NODE10_SPEC: ExtensionSpec = { billingRequired: true, sourceUrl: "test.com", params: [], + systemParams: [], }; describe("billingMigrationHelper", () => { diff --git a/src/test/extensions/change-log.spec.ts b/src/test/extensions/change-log.spec.ts index 366ac3e2a51..bbce32ebfa1 100644 --- a/src/test/extensions/change-log.spec.ts +++ b/src/test/extensions/change-log.spec.ts @@ -20,6 +20,7 @@ function testExtensionVersion(version: string, releaseNotes?: string): Extension version, resources: [], params: [], + systemParams: [], sourceUrl: "https://google.com", }, }; diff --git a/src/test/extensions/displayExtensionInfo.spec.ts b/src/test/extensions/displayExtensionInfo.spec.ts index 9de305461bc..8057b149dba 100644 --- a/src/test/extensions/displayExtensionInfo.spec.ts +++ b/src/test/extensions/displayExtensionInfo.spec.ts @@ -29,6 +29,7 @@ const SPEC: ExtensionSpec = { billingRequired: true, sourceUrl: "test.com", params: [], + systemParams: [], }; const TASK_FUNCTION_RESOURCE: Resource = { diff --git a/src/test/extensions/emulator/optionsHelper.spec.ts b/src/test/extensions/emulator/optionsHelper.spec.ts index 8eaed9b6e1c..9565ba36222 100644 --- a/src/test/extensions/emulator/optionsHelper.spec.ts +++ b/src/test/extensions/emulator/optionsHelper.spec.ts @@ -28,6 +28,7 @@ describe("optionsHelper", () => { resources: [], sourceUrl: "https://my.stuff.com", params: [], + systemParams: [], }; readEnvFileStub = sinon.stub(paramHelper, "readEnvFile"); }); diff --git a/src/test/extensions/export.spec.ts b/src/test/extensions/export.spec.ts index 8e234ad7415..1bbb43f531e 100644 --- a/src/test/extensions/export.spec.ts +++ b/src/test/extensions/export.spec.ts @@ -52,11 +52,13 @@ describe("ext:export helpers", () => { const testSpec = { instanceId: "my-instance", params: t.in, + systemParams: {}, }; expect(parameterizeProject(TEST_PROJECT_ID, TEST_PROJECT_NUMBER, testSpec)).to.deep.equal({ instanceId: testSpec.instanceId, params: t.expected, + systemParams: {}, }); }); } @@ -80,6 +82,7 @@ describe("ext:export helpers", () => { const testSpec: DeploymentInstanceSpec = { instanceId: "my-instance", params: t.params, + systemParams: {}, extensionVersion: { name: "test", ref: "test/test@0.1.0", @@ -102,6 +105,7 @@ describe("ext:export helpers", () => { label: "blah", }, ], + systemParams: [], }, }, }; diff --git a/src/test/extensions/extensionsApi.spec.ts b/src/test/extensions/extensionsApi.spec.ts index db56437d31d..c2a623b1479 100644 --- a/src/test/extensions/extensionsApi.spec.ts +++ b/src/test/extensions/extensionsApi.spec.ts @@ -233,9 +233,18 @@ describe("extensions", () => { name: "sources/blah", packageUri: "https://test.fake/pacakge.zip", hash: "abc123", - spec: { name: "", version: "0.1.0", sourceUrl: "", roles: [], resources: [], params: [] }, + spec: { + name: "", + version: "0.1.0", + sourceUrl: "", + roles: [], + resources: [], + params: [], + systemParams: [], + }, }, params: {}, + systemParams: {}, }); expect(nock.isDone()).to.be.true; }); @@ -294,6 +303,7 @@ describe("extensions", () => { roles: [], resources: [], params: [], + systemParams: [], }, }, params: {}, @@ -409,6 +419,7 @@ describe("extensions", () => { version: "0.1.0", resources: [], params: [], + systemParams: [], sourceUrl: "www.google.com/pack.zip", }, }; @@ -416,7 +427,7 @@ describe("extensions", () => { nock.cleanAll(); }); - it("should include config.param in updateMask is params are changed", async () => { + it("should include config.params in updateMask is params are changed", async () => { nock(api.extensionsOrigin) .patch(`/${VERSION}/projects/${PROJECT_ID}/instances/${INSTANCE_ID}`) .query({ @@ -440,7 +451,7 @@ describe("extensions", () => { expect(nock.isDone()).to.be.true; }); - it("should not include config.param in updateMask is params aren't changed", async () => { + it("should not include config.params or config.system_params in updateMask is params aren't changed", async () => { nock(api.extensionsOrigin) .patch(`/${VERSION}/projects/${PROJECT_ID}/instances/${INSTANCE_ID}`) .query({ @@ -459,6 +470,30 @@ describe("extensions", () => { expect(nock.isDone()).to.be.true; }); + it("should include config.system_params in updateMask if system_params are changed", async () => { + nock(api.extensionsOrigin) + .patch(`/${VERSION}/projects/${PROJECT_ID}/instances/${INSTANCE_ID}`) + .query({ + updateMask: + "config.source.name,config.system_params,config.allowed_event_types,config.eventarc_channel", + validateOnly: "false", + }) + .reply(200, { name: "operations/abc123" }); + nock(api.extensionsOrigin).get(`/${VERSION}/operations/abc123`).reply(200, { done: true }); + + await extensionsApi.updateInstance({ + projectId: PROJECT_ID, + instanceId: INSTANCE_ID, + extensionSource: testSource, + systemParams: { + MY_PARAM: "value", + }, + canEmitEvents: false, + }); + + expect(nock.isDone()).to.be.true; + }); + it("should include config.allowed_event_types and config.eventarc_Channel in updateMask if events config is provided", async () => { nock(api.extensionsOrigin) .patch(`/${VERSION}/projects/${PROJECT_ID}/instances/${INSTANCE_ID}`) diff --git a/src/test/extensions/extensionsHelper.spec.ts b/src/test/extensions/extensionsHelper.spec.ts index 43ac8049703..b63a2ef15e8 100644 --- a/src/test/extensions/extensionsHelper.spec.ts +++ b/src/test/extensions/extensionsHelper.spec.ts @@ -32,6 +32,7 @@ const EXT_SPEC_1: ExtensionSpec = { ], sourceUrl: "www.google.com/cool-things-here", params: [], + systemParams: [], }; const EXT_SPEC_2: ExtensionSpec = { name: "cool-things", @@ -44,6 +45,7 @@ const EXT_SPEC_2: ExtensionSpec = { ], sourceUrl: "www.google.com/cool-things-here", params: [], + systemParams: [], }; const TEST_EXT_VERSION_1: ExtensionVersion = { name: "publishers/test-pub/extensions/ext-one/versions/0.0.1-rc.0", @@ -512,6 +514,7 @@ describe("extensionsHelper", () => { specVersion: "v1beta", resources: [], params: [], + systemParams: [], sourceUrl: "https://test-source.fake", license: "apache-2.0", }; @@ -527,6 +530,7 @@ describe("extensionsHelper", () => { specVersion: "v1beta", resources: [], params: [], + systemParams: [], sourceUrl: "https://test-source.fake", }; @@ -541,6 +545,7 @@ describe("extensionsHelper", () => { specVersion: "v1beta", resources: [], params: [], + systemParams: [], sourceUrl: "https://test-source.fake", license: "invalid-license", }; @@ -807,6 +812,7 @@ describe("extensionsHelper", () => { sourceUrl: testUrl, resources: [], params: [], + systemParams: [], }, }; const testArchivedFiles: ArchiveResult = { diff --git a/src/test/extensions/manifest.spec.ts b/src/test/extensions/manifest.spec.ts index 8857fc5e286..2bdbfd65732 100644 --- a/src/test/extensions/manifest.spec.ts +++ b/src/test/extensions/manifest.spec.ts @@ -175,6 +175,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, { @@ -202,6 +203,7 @@ describe("manifest", () => { type: ParamType.SECRET, }, ], + systemParams: [], }, }, ], @@ -258,6 +260,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, { @@ -285,6 +288,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], @@ -354,6 +358,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, { @@ -394,6 +399,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], @@ -459,6 +465,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, { @@ -486,6 +493,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], @@ -545,6 +553,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], @@ -610,6 +619,7 @@ describe("manifest", () => { type: ParamType.SECRET, }, ], + systemParams: [], }, }, { @@ -640,6 +650,7 @@ describe("manifest", () => { type: ParamType.SECRET, }, ], + systemParams: [], }, }, ], @@ -691,6 +702,7 @@ describe("manifest", () => { type: ParamType.SECRET, }, ], + systemParams: [], }, }, ], @@ -737,6 +749,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], @@ -784,6 +797,7 @@ describe("manifest", () => { type: ParamType.STRING, }, ], + systemParams: [], }, }, ], diff --git a/src/test/extensions/paramHelper.spec.ts b/src/test/extensions/paramHelper.spec.ts index 0539647c410..749567abbc3 100644 --- a/src/test/extensions/paramHelper.spec.ts +++ b/src/test/extensions/paramHelper.spec.ts @@ -72,6 +72,7 @@ const SPEC = { resources: [], sourceUrl: "test.com", params: TEST_PARAMS, + systemParams: [], }; describe("paramHelper", () => { @@ -305,12 +306,14 @@ describe("paramHelper", () => { roles: [], resources: [], params: [...TEST_PARAMS], + systemParams: [], sourceUrl: "", }, }, name: "test", createTime: "now", params, + systemParams: {}, }, name: "test", createTime: "now", diff --git a/src/test/extensions/secretUtils.spec.ts b/src/test/extensions/secretUtils.spec.ts index 739824353c2..b9d408716e1 100644 --- a/src/test/extensions/secretUtils.spec.ts +++ b/src/test/extensions/secretUtils.spec.ts @@ -43,12 +43,14 @@ const TEST_INSTANCE: ExtensionInstance = { type: ParamType.SECRET, }, ], + systemParams: [], }, }, params: { SECRET1: "projects/test-project/secrets/secret1/versions/1", SECRET2: "projects/test-project/secrets/secret2/versions/1", }, + systemParams: {}, }, }; diff --git a/src/test/extensions/updateHelper.spec.ts b/src/test/extensions/updateHelper.spec.ts index badcf7ebccc..cbc852bc612 100644 --- a/src/test/extensions/updateHelper.spec.ts +++ b/src/test/extensions/updateHelper.spec.ts @@ -33,6 +33,7 @@ const SPEC: ExtensionSpec = { billingRequired: true, sourceUrl: "test.com", params: [], + systemParams: [], }; const SOURCE = { diff --git a/src/test/extensions/warnings.spec.ts b/src/test/extensions/warnings.spec.ts index 58cc02694dd..d114d073736 100644 --- a/src/test/extensions/warnings.spec.ts +++ b/src/test/extensions/warnings.spec.ts @@ -23,6 +23,7 @@ const testExtensionVersion: ExtensionVersion = { version: "0.1.0", resources: [], params: [], + systemParams: [], sourceUrl: "github.com/test/meout", }, }; @@ -50,6 +51,7 @@ const testInstanceSpec = ( version: "0.1.0", }, params: {}, + systemParams: {}, extensionVersion: testExtensionVersion, extension: testExtension(publisherId, launchStage), }; diff --git a/src/test/functional.spec.ts b/src/test/functional.spec.ts index 63d12f02327..f9280614bbc 100644 --- a/src/test/functional.spec.ts +++ b/src/test/functional.spec.ts @@ -143,4 +143,21 @@ describe("functional", () => { expect(f.partition([], (s: string) => s.startsWith("T"))).to.deep.equal([[], []]); }); }); + + describe("partitionRecord", () => { + it("should split a record into true and false", () => { + const rec = { T1: 1, F1: 2, T2: 3, F2: 4 }; + expect(f.partitionRecord(rec, (s: string) => s.startsWith("T"))).to.deep.equal([ + { T1: 1, T2: 3 }, + { F1: 2, F2: 4 }, + ]); + }); + + it("can handle an empty record", () => { + expect(f.partitionRecord({}, (s: string) => s.startsWith("T"))).to.deep.equal([ + {}, + {}, + ]); + }); + }); });