Skip to content

Commit b5b75e1

Browse files
committed
refactor: replace stdio discovery with file-based manifest output
- Remove XML-style stdio discovery mode - Add FUNCTIONS_MANIFEST_OUTPUT_PATH environment variable support - Write manifest directly to specified file path when env var is set - Update tests to use file-based discovery instead of stdio parsing - Simplify error handling with direct stderr output
1 parent 478b8c2 commit b5b75e1

File tree

2 files changed

+46
-51
lines changed

2 files changed

+46
-51
lines changed

scripts/bin-test/test.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import * as subprocess from "child_process";
22
import * as path from "path";
33
import { promisify } from "util";
4+
import * as fs from "fs/promises";
5+
import * as os from "os";
46

57
import { expect } from "chai";
68
import * as yaml from "js-yaml";
@@ -185,15 +187,16 @@ async function runHttpDiscovery(modulePath: string): Promise<DiscoveryResult> {
185187
}
186188
}
187189

188-
async function runStdioDiscovery(modulePath: string): Promise<DiscoveryResult> {
190+
async function runFileDiscovery(modulePath: string): Promise<DiscoveryResult> {
191+
const outputPath = path.join(os.tmpdir(), `firebase-functions-test-${Date.now()}.json`);
192+
189193
return new Promise((resolve, reject) => {
190194
const proc = subprocess.spawn("npx", ["firebase-functions"], {
191195
cwd: path.resolve(modulePath),
192196
env: {
193197
PATH: process.env.PATH,
194198
GCLOUD_PROJECT: "test-project",
195-
FUNCTIONS_CONTROL_API: "true",
196-
FUNCTIONS_DISCOVERY_MODE: "stdio",
199+
FUNCTIONS_MANIFEST_OUTPUT_PATH: outputPath,
197200
},
198201
});
199202

@@ -205,31 +208,26 @@ async function runStdioDiscovery(modulePath: string): Promise<DiscoveryResult> {
205208

206209
const timeoutId = setTimeout(() => {
207210
proc.kill(9);
208-
reject(new Error(`Stdio discovery timed out after ${TIMEOUT_M}ms`));
211+
resolve({ success: false, error: `File discovery timed out after ${TIMEOUT_M}ms` });
209212
}, TIMEOUT_M);
210213

211-
proc.on("close", () => {
214+
proc.on("close", async (code) => {
212215
clearTimeout(timeoutId);
213-
const manifestMatch = stderr.match(
214-
/<FIREBASE_FUNCTIONS_MANIFEST>\n([\s\S]+?)\n<\/FIREBASE_FUNCTIONS_MANIFEST>/
215-
);
216-
if (manifestMatch) {
217-
const base64 = manifestMatch[1];
218-
const manifestJson = Buffer.from(base64, "base64").toString("utf8");
219-
const manifest = JSON.parse(manifestJson) as Record<string, unknown>;
220-
resolve({ success: true, manifest });
221-
return;
222-
}
223-
224-
const errorMatch = stderr.match(
225-
/<FIREBASE_FUNCTIONS_MANIFEST_ERROR>\n([\s\S]+?)\n<\/FIREBASE_FUNCTIONS_MANIFEST_ERROR>/
226-
);
227-
if (errorMatch) {
228-
resolve({ success: false, error: errorMatch[1] });
229-
return;
216+
217+
if (code === 0) {
218+
try {
219+
const manifestJson = await fs.readFile(outputPath, "utf8");
220+
const manifest = JSON.parse(manifestJson) as Record<string, unknown>;
221+
await fs.unlink(outputPath).catch(() => {});
222+
resolve({ success: true, manifest });
223+
} catch (e) {
224+
resolve({ success: false, error: `Failed to read manifest file: ${e}` });
225+
}
226+
} else {
227+
const errorLines = stderr.split('\n').filter(line => line.trim());
228+
const errorMessage = errorLines.join(' ') || "No error message found";
229+
resolve({ success: false, error: errorMessage });
230230
}
231-
232-
resolve({ success: false, error: "No manifest or error found" });
233231
});
234232

235233
proc.on("error", (err) => {
@@ -245,7 +243,7 @@ describe("functions.yaml", function () {
245243

246244
const discoveryMethods = [
247245
{ name: "http", fn: runHttpDiscovery },
248-
{ name: "stdio", fn: runStdioDiscovery },
246+
{ name: "file", fn: runFileDiscovery },
249247
];
250248

251249
function runDiscoveryTests(

src/bin/firebase-functions.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import * as http from "http";
2626
import * as express from "express";
27+
import * as fs from "fs/promises";
2728
import { loadStack } from "../runtime/loader";
2829
import { stackToWire } from "../runtime/manifest";
2930

@@ -49,37 +50,33 @@ if (args.length > 1) {
4950
functionsDir = args[0];
5051
}
5152

52-
const MANIFEST_START_TAG = "<FIREBASE_FUNCTIONS_MANIFEST>";
53-
const MANIFEST_END_TAG = "</FIREBASE_FUNCTIONS_MANIFEST>";
54-
const MANIFEST_ERROR_START_TAG = "<FIREBASE_FUNCTIONS_MANIFEST_ERROR>";
55-
const MANIFEST_ERROR_END_TAG = "</FIREBASE_FUNCTIONS_MANIFEST_ERROR>";
56-
57-
async function runStdioDiscovery() {
58-
try {
59-
const stack = await loadStack(functionsDir);
60-
const wireFormat = stackToWire(stack);
61-
const manifestJson = JSON.stringify(wireFormat);
62-
const base64 = Buffer.from(manifestJson).toString("base64");
63-
process.stderr.write(`${MANIFEST_START_TAG}\n${base64}\n${MANIFEST_END_TAG}\n`);
64-
process.exitCode = 0;
65-
} catch (e) {
66-
const message = `Failed to generate manifest from function source: ${
67-
e instanceof Error ? e.message : String(e)
68-
}`;
69-
process.stderr.write(`${MANIFEST_ERROR_START_TAG}\n${message}\n${MANIFEST_ERROR_END_TAG}\n`);
70-
}
71-
}
72-
7353
function handleQuitquitquit(req: express.Request, res: express.Response, server: http.Server) {
7454
res.send("ok");
7555
server.close();
7656
}
7757

78-
if (
79-
process.env.FUNCTIONS_CONTROL_API === "true" &&
80-
process.env.FUNCTIONS_DISCOVERY_MODE === "stdio"
81-
) {
82-
void runStdioDiscovery();
58+
if (process.env.FUNCTIONS_MANIFEST_OUTPUT_PATH) {
59+
void (async () => {
60+
try {
61+
const stack = await loadStack(functionsDir);
62+
const wireFormat = stackToWire(stack);
63+
await fs.writeFile(
64+
process.env.FUNCTIONS_MANIFEST_OUTPUT_PATH,
65+
JSON.stringify(wireFormat, null, 2)
66+
);
67+
process.exit(0);
68+
} catch (e) {
69+
console.error(
70+
`Failed to generate manifest from function source: ${
71+
e instanceof Error ? e.message : String(e)
72+
}`
73+
);
74+
if (e instanceof Error && e.stack) {
75+
console.error(e.stack);
76+
}
77+
process.exit(1);
78+
}
79+
})();
8380
} else {
8481
let server: http.Server = undefined;
8582
const app = express();

0 commit comments

Comments
 (0)