-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f96b2d6
commit 65890ac
Showing
8 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import arg, { ArgError } from "arg"; | ||
import { existsSync } from "node:fs"; | ||
import { resolve } from "node:path"; | ||
import { cliCommand } from "../bin/entrypoint"; | ||
import { printAndExit } from "./utils"; | ||
import run from "../run"; | ||
|
||
const argumentSchema = { | ||
"-h": "--help", | ||
"--help": Boolean, | ||
|
||
"--env": String, | ||
|
||
"-p": "--port", | ||
"--port": Number, | ||
}; | ||
|
||
export const cmdRun: cliCommand = argv => { | ||
let args: arg.Result<typeof argumentSchema>; | ||
|
||
try { | ||
args = arg(argumentSchema, { argv }); | ||
} catch (error) { | ||
if (error instanceof ArgError && error.code === "ARG_UNKNOWN_OPTION") { | ||
return printAndExit(error.message); | ||
} | ||
|
||
throw error; | ||
} | ||
|
||
if (args["--help"]) { | ||
return printAndExit( | ||
` | ||
Usage | ||
$ cloud-seed run <path/to/function.ts> --env=<environment> | ||
Options | ||
--env=<environment> Use the configuration from the specified environment in cloud-seed.json | ||
--help, -h Displays this message | ||
--port=<number>, -p=<number> Specify the port to run the environment on (default: 3000)`, | ||
0, | ||
); | ||
} | ||
|
||
const environment = args["--env"]; | ||
if (!environment) { | ||
return printAndExit("> Environment is required. Please set the --env flag."); | ||
} | ||
|
||
const port = args["--port"] ?? 3000; | ||
|
||
const sourceFile = args._[0]; | ||
if (!existsSync(resolve(sourceFile))) { | ||
return printAndExit(`> No such file exists: ${sourceFile}`); | ||
} | ||
|
||
return run({ | ||
environment, | ||
port, | ||
sourceFile, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { ChildProcess, spawn } from "node:child_process"; | ||
import { BaseConfig } from "../../utils/rootConfig"; | ||
import { RuntimeConfig } from "../../utils/runtimeConfig"; | ||
import { DevelopmentServer } from "./types"; | ||
|
||
export default class GcpServer implements DevelopmentServer { | ||
private sourceFile: string; | ||
private signatureType: string; | ||
private port: string; | ||
private environmentVariables: { [key: string]: string | undefined } = {}; | ||
|
||
private serverProcess: ChildProcess | undefined; | ||
|
||
constructor( | ||
projectConfig: BaseConfig, | ||
functionConfig: RuntimeConfig, | ||
compiledFile: string, | ||
port: number, | ||
environment: string, | ||
) { | ||
this.sourceFile = compiledFile; | ||
this.signatureType = getFunctionSignatureType(functionConfig); | ||
this.port = port.toString(); | ||
this.environmentVariables = getFunctionEnvironmentVariables(projectConfig, environment); | ||
} | ||
|
||
public up() { | ||
if (this.serverProcess === undefined) { | ||
this.startServerProcess(); | ||
} else { | ||
this.serverProcess.on("exit", () => { | ||
setTimeout(this.startServerProcess.bind(this), 500); | ||
}); | ||
this.serverProcess.kill("SIGINT"); | ||
} | ||
} | ||
|
||
public down() { | ||
if (this.serverProcess !== undefined) { | ||
this.serverProcess.on("exit", () => { | ||
this.serverProcess = undefined; | ||
}); | ||
this.serverProcess.kill("SIGINT"); | ||
} | ||
} | ||
|
||
public isRunning() { | ||
return this.serverProcess !== undefined; | ||
} | ||
|
||
private startServerProcess() { | ||
this.serverProcess = spawn( | ||
"npx", | ||
[ | ||
"-y", | ||
"@google-cloud/functions-framework", | ||
"--source", | ||
this.sourceFile, | ||
"--target", | ||
"default", | ||
"--signature-type", | ||
this.signatureType, | ||
"--port", | ||
this.port, | ||
], | ||
{ | ||
env: this.environmentVariables, | ||
stdio: "inherit", | ||
}, | ||
); | ||
} | ||
} | ||
|
||
function getFunctionSignatureType(functionConfig: RuntimeConfig): "http" | "event" | "cloudevent" { | ||
switch (functionConfig.type) { | ||
case "event": | ||
case "schedule": | ||
case "firestore": | ||
case "storage": | ||
return "cloudevent"; | ||
default: | ||
return "http"; | ||
} | ||
} | ||
|
||
function getFunctionEnvironmentVariables(projectConfig: BaseConfig, environment: string) { | ||
return { | ||
CLOUD_SEED_ENVIRONMENT: environment, | ||
CLOUD_SEED_PROJECT: projectConfig.cloud.gcp.project, | ||
CLOUD_SEED_REGION: projectConfig.cloud.gcp.region, | ||
...projectConfig.runtimeEnvironmentVariables, | ||
...process.env, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { BaseConfig } from "../../utils/rootConfig"; | ||
import { RuntimeConfig } from "../../utils/runtimeConfig"; | ||
import GcpServer from "./GcpServer"; | ||
import { DevelopmentServer } from "./types"; | ||
|
||
export function getDevelopmentServer( | ||
projectConfig: BaseConfig, | ||
functionConfig: RuntimeConfig, | ||
compiledFile: string, | ||
port: number, | ||
environment: string, | ||
): DevelopmentServer { | ||
switch (functionConfig.cloud) { | ||
case "gcp": | ||
return new GcpServer(projectConfig, functionConfig, compiledFile, port, environment); | ||
default: | ||
throw new Error( | ||
`The development server does not support running functions using the "${functionConfig.cloud}" cloud at this time.`, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export interface DevelopmentServer { | ||
/** | ||
* Start the development server, or restart it if it's already running. | ||
*/ | ||
up(): void; | ||
|
||
/** | ||
* Stop the development server. | ||
*/ | ||
down(): void; | ||
|
||
/** | ||
* Check if the server is currently running. | ||
*/ | ||
isRunning(): boolean; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { context } from "esbuild"; | ||
import { mkdirSync } from "node:fs"; | ||
import { dirname, resolve } from "node:path"; | ||
import { printAndExit } from "../cli/utils"; | ||
import { getEsbuildOptions } from "../utils/esbuild"; | ||
import { getRootConfig } from "../utils/rootConfig"; | ||
import { getRuntimeConfig } from "../utils/runtimeConfig"; | ||
import { getDevelopmentServer } from "./DevelopmentServer"; | ||
|
||
export type RunOptions = { | ||
environment: string; | ||
port: number; | ||
sourceFile: string; | ||
}; | ||
|
||
export default ({ environment, port, sourceFile }: RunOptions): void => { | ||
const projectConfig = getRootConfig(dirname(sourceFile), { environment }); | ||
const functionConfig = getRuntimeConfig(sourceFile, environment); | ||
|
||
if (functionConfig === undefined) { | ||
printAndExit( | ||
`> Provided source file "${sourceFile}" does not include a valid function runtime configuration!`, | ||
); | ||
|
||
return; | ||
} | ||
|
||
const outputDirectory = resolve(projectConfig.buildConfig.outDir); | ||
mkdirSync(outputDirectory, { recursive: true }); | ||
|
||
const esbuildOptions = getEsbuildOptions(functionConfig, outputDirectory, { | ||
...projectConfig.buildConfig.esbuildOptions, | ||
plugins: [ | ||
...(projectConfig.buildConfig.esbuildOptions?.plugins ?? []), | ||
{ | ||
name: "Development Server", | ||
setup(build) { | ||
const compiledFile = build.initialOptions.outfile; | ||
if (compiledFile === undefined) return; | ||
|
||
const developmentServer = getDevelopmentServer( | ||
projectConfig, | ||
functionConfig, | ||
compiledFile, | ||
port, | ||
environment, | ||
); | ||
|
||
build.onEnd(result => { | ||
if (result.errors.length > 0) return; | ||
|
||
const action = developmentServer.isRunning() ? "Restarting" : "Starting"; | ||
|
||
console.log(`Build completed successfully. ${action} the development server...`); | ||
developmentServer.up(); | ||
}); | ||
}, | ||
}, | ||
], | ||
}); | ||
|
||
context(esbuildOptions).then(context => context.watch()); | ||
}; |