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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/functionsShellCommandAction.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from "chai";

import { initializeFunctionsShellContext } from "./functionsShellCommandAction";
import { EmulatedTriggerDefinition } from "./emulator/functionsEmulatorShared";
import { FunctionsEmulatorShell } from "./emulator/functionsEmulatorShell";

describe("initializeFunctionsShellContext", () => {
it("uses trigger.entryPoint for shell bindings", () => {
const hyphenatedTrigger: EmulatedTriggerDefinition = {
id: "us-central1-dummystore-bot",
region: "us-central1",
platform: "gcfv1",
name: "dummystore-bot",
entryPoint: "dummystore-bot",
httpsTrigger: {},
};
const groupedTrigger: EmulatedTriggerDefinition = {
id: "us-central1-grouped-fn",
region: "us-central1",
platform: "gcfv1",
name: "grouped-fn",
entryPoint: "grouped.fn",
httpsTrigger: {},
};

const emulator = {
triggers: [hyphenatedTrigger, groupedTrigger],
emulatedFunctions: [hyphenatedTrigger.id, groupedTrigger.id],
urls: {
[hyphenatedTrigger.id]: "http://127.0.0.1/hyphenated",
[groupedTrigger.id]: "http://127.0.0.1/grouped",
},
} as FunctionsEmulatorShell;

const context: Record<string, unknown> = {};
initializeFunctionsShellContext(context, emulator);

expect(context).to.have.property("dummystore-bot").that.is.a("function");
expect(context).to.not.have.nested.property("dummystore.bot");
expect(context).to.have.nested.property("grouped.fn").that.is.a("function");
expect(context).to.have.property("help").that.is.a("string");
});
});
32 changes: 17 additions & 15 deletions src/functionsShellCommandAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,22 @@

const serveFunctions = new FunctionsServer();

export const initializeFunctionsShellContext = (

Check warning on line 23 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
context: Record<string, any>,

Check warning on line 24 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the repository style guide (GEMINI.md, line 38), any should not be used as an escape hatch. Since context is a REPL context object that can hold arbitrary values, we should type it as Record<string, unknown> instead of Record<string, any>.

Suggested change
context: Record<string, any>,
context: Record<string, unknown>,
References
  1. Never use any or unknown as an escape hatch. Define proper interfaces/types or use type guards. (link)

emulator: shell.FunctionsEmulatorShell,
) => {
for (const trigger of emulator.triggers) {
if (emulator.emulatedFunctions.includes(trigger.id)) {
const localFunction = new LocalFunction(trigger, emulator.urls, emulator);
_.set(context, trigger.entryPoint, localFunction.makeFn());
}
}
context.help =
"Instructions for the Functions Shell can be found at: " +
"https://firebase.google.com/docs/functions/local-emulator";
};

export const actionFunction = async (options: Options) => {

Check warning on line 38 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
if (typeof options.port === "string") {
options.port = parseInt(options.port, 10);
}
Expand Down Expand Up @@ -95,19 +110,6 @@
process.exit();
}

const initializeContext = (context: any) => {
for (const trigger of emulator.triggers) {
if (emulator.emulatedFunctions.includes(trigger.id)) {
const localFunction = new LocalFunction(trigger, emulator.urls, emulator);
const triggerNameDotNotation = trigger.name.replace(/-/g, ".");
_.set(context, triggerNameDotNotation, localFunction.makeFn());
}
}
context.help =
"Instructions for the Functions Shell can be found at: " +
"https://firebase.google.com/docs/functions/local-emulator";
};

for (const e of runningEmulators) {
const info = remoteEmulators[e];
utils.logLabeledBullet(
Expand All @@ -124,7 +126,7 @@
)}`,
);

const writer = (output: any) => {

Check warning on line 129 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 129 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
if (output === HTTPS_SENTINEL) {
return HTTPS_SENTINEL;
}
Expand All @@ -138,11 +140,11 @@
writer: writer,
useColors: true,
});
initializeContext(replServer.context);
replServer.on("reset", initializeContext);
initializeFunctionsShellContext(replServer.context, emulator);
replServer.on("reset", (context) => initializeFunctionsShellContext(context, emulator));

return new Promise((resolve) => {
replServer.on("exit", () => {

Check warning on line 147 in src/functionsShellCommandAction.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Promise returned in function argument where a void return was expected
return serveFunctions.stop().then(resolve).catch(resolve);
});
});
Expand Down
50 changes: 50 additions & 0 deletions src/gcp/cloudfunctionsv2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@
serviceConfig: {
...HAVE_CLOUD_FUNCTION_V2.serviceConfig,
directVpcNetworkInterface: [{ network: "my-net" }],
directVpcEgress: "ALL_TRAFFIC" as any,

Check warning on line 317 in src/gcp/cloudfunctionsv2.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 317 in src/gcp/cloudfunctionsv2.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
uri: RUN_URI,
service: "service",
},
Expand All @@ -328,7 +328,7 @@
serviceConfig: {
...HAVE_CLOUD_FUNCTION_V2.serviceConfig,
directVpcNetworkInterface: [{ network: "my-net" }],
directVpcEgress: "VPC_EGRESS_UNSPECIFIED" as any,

Check warning on line 331 in src/gcp/cloudfunctionsv2.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 331 in src/gcp/cloudfunctionsv2.spec.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
uri: RUN_URI,
service: "service",
},
Expand Down Expand Up @@ -925,6 +925,31 @@
await cloudfunctionsv2.createFunction(testFunction);
expect(scope.isDone()).to.be.true;
});

it("should preserve a hyphenated entry point in FUNCTION_TARGET", async () => {
const testFunction = {
...CLOUD_FUNCTION_V2,
buildConfig: {
...CLOUD_FUNCTION_V2.buildConfig,
entryPoint: "dummystore-bot",
environmentVariables: {},
},
};

const scope = nock(functionsV2Origin())
.post("/v2/projects/project/locations/region/functions", (body) => {
expect(body.serviceConfig.environmentVariables).to.have.property(
"FUNCTION_TARGET",
"dummystore-bot",
);
return true;
})
.query({ functionId: "id" })
.reply(200, { name: "operations/123", done: true });

await cloudfunctionsv2.createFunction(testFunction);
expect(scope.isDone()).to.be.true;
});
});

describe("updateFunction", () => {
Expand All @@ -951,5 +976,30 @@
await cloudfunctionsv2.updateFunction(CLOUD_FUNCTION_V2);
expect(scope.isDone()).to.be.true;
});

it("should preserve a hyphenated entry point in FUNCTION_TARGET", async () => {
const testFunction = {
...CLOUD_FUNCTION_V2,
buildConfig: {
...CLOUD_FUNCTION_V2.buildConfig,
entryPoint: "dummystore-bot",
environmentVariables: {},
},
};

const scope = nock(functionsV2Origin())
.patch("/v2/projects/project/locations/region/functions/id", (body) => {
expect(body.serviceConfig.environmentVariables).to.have.property(
"FUNCTION_TARGET",
"dummystore-bot",
);
return true;
})
.query(true)
.reply(200, { name: "operations/123", done: true });

await cloudfunctionsv2.updateFunction(testFunction);
expect(scope.isDone()).to.be.true;
});
});
});
4 changes: 2 additions & 2 deletions src/gcp/cloudfunctionsv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export async function createFunction(cloudFunction: InputCloudFunction): Promise

cloudFunction.serviceConfig.environmentVariables = {
...cloudFunction.serviceConfig.environmentVariables,
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint.replaceAll("-", "."),
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint,
// Enable logging execution id by default for better debugging
LOG_EXECUTION_ID: "true",
};
Expand Down Expand Up @@ -394,7 +394,7 @@ export async function updateFunction(cloudFunction: InputCloudFunction): Promise
};
cloudFunction.serviceConfig.environmentVariables = {
...cloudFunction.serviceConfig.environmentVariables,
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint.replaceAll("-", "."),
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint,
// Enable logging execution id by default for better debugging
LOG_EXECUTION_ID: "true",
};
Expand Down
Loading