From d9dd88c7401d9485dfbb3062269cf10bcdcfc1b7 Mon Sep 17 00:00:00 2001 From: Ian Wahbe Date: Mon, 22 Nov 2021 11:42:39 -0800 Subject: [PATCH] Add tsconfig option to specify tsconfig path (#8452) * Add tsconfig option to specify tsconfig path * Add CHANGELOG entry and fix lint * Add a test * Fix test --- CHANGELOG_PENDING.md | 5 +++- sdk/nodejs/cmd/pulumi-language-nodejs/main.go | 12 ++++++-- sdk/nodejs/cmd/run/run.ts | 28 +++++++++++++------ tests/integration/integration_nodejs_test.go | 20 +++++++++++++ tests/integration/tsconfig/Pulumi.yaml | 5 ++++ tests/integration/tsconfig/index.ts | 7 +++++ tests/integration/tsconfig/other.json | 16 +++++++++++ tests/integration/tsconfig/package.json | 9 ++++++ tests/integration/tsconfig/tsconfig.json | 16 +++++++++++ 9 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 tests/integration/tsconfig/Pulumi.yaml create mode 100644 tests/integration/tsconfig/index.ts create mode 100644 tests/integration/tsconfig/other.json create mode 100644 tests/integration/tsconfig/package.json create mode 100644 tests/integration/tsconfig/tsconfig.json diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 19fc4a4bb..a216d25dc 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -18,7 +18,10 @@ ### Bug Fixes -- [codegen/typescript] - Respect default values in Pulumi object types. +- [cli/nodejs] - Allow specifying the tsconfig file used in Pulumi.yaml. + [#8452](https://github.com/pulumi/pulumi/pull/8452) + +- [codegen/nodejs] - Respect default values in Pulumi object types. [#8400](https://github.com/pulumi/pulumi/pull/8400) - [sdk/python] - Correctly handle version checking python virtual environments. diff --git a/sdk/nodejs/cmd/pulumi-language-nodejs/main.go b/sdk/nodejs/cmd/pulumi-language-nodejs/main.go index 248ac62fa..8267d39b2 100644 --- a/sdk/nodejs/cmd/pulumi-language-nodejs/main.go +++ b/sdk/nodejs/cmd/pulumi-language-nodejs/main.go @@ -82,11 +82,14 @@ func main() { var tracing string var typescript bool var root string + var tsconfigpath string flag.StringVar(&tracing, "tracing", "", "Emit tracing to a Zipkin-compatible tracing endpoint") flag.BoolVar(&typescript, "typescript", true, "Use ts-node at runtime to support typescript source natively") flag.StringVar(&root, "root", "", "Project root path to use") + flag.StringVar(&tsconfigpath, "tsconfig", "", + "Path to tsconfig.json to use") flag.Parse() args := flag.Args() @@ -118,7 +121,7 @@ func main() { // Fire up a gRPC server, letting the kernel choose a free port. port, done, err := rpcutil.Serve(0, nil, []func(*grpc.Server) error{ func(srv *grpc.Server) error { - host := newLanguageHost(nodePath, runPath, engineAddress, tracing, typescript) + host := newLanguageHost(nodePath, runPath, engineAddress, tracing, typescript, tsconfigpath) pulumirpc.RegisterLanguageRuntimeServer(srv, host) return nil }, @@ -155,16 +158,18 @@ type nodeLanguageHost struct { engineAddress string tracing string typescript bool + tsconfigpath string } func newLanguageHost(nodePath, runPath, engineAddress, - tracing string, typescript bool) pulumirpc.LanguageRuntimeServer { + tracing string, typescript bool, tsconfigpath string) pulumirpc.LanguageRuntimeServer { return &nodeLanguageHost{ nodeBin: nodePath, runPath: runPath, engineAddress: engineAddress, tracing: tracing, typescript: typescript, + tsconfigpath: tsconfigpath, } } @@ -504,6 +509,9 @@ func (host *nodeLanguageHost) execNodejs( if host.typescript { env = append(env, "PULUMI_NODEJS_TYPESCRIPT=true") } + if host.tsconfigpath != "" { + env = append(env, "PULUMI_NODEJS_TSCONFIG_PATH="+host.tsconfigpath) + } if logging.V(5) { commandStr := strings.Join(args, " ") diff --git a/sdk/nodejs/cmd/run/run.ts b/sdk/nodejs/cmd/run/run.ts index 05e7f2809..50bef98f2 100644 --- a/sdk/nodejs/cmd/run/run.ts +++ b/sdk/nodejs/cmd/run/run.ts @@ -20,6 +20,7 @@ import { parseConfigFileTextToJson } from "typescript"; import { ResourceError, RunError } from "../../errors"; import * as log from "../../log"; import * as runtime from "../../runtime"; +import { Inputs } from "../../output"; import * as mod from "."; @@ -96,7 +97,7 @@ function throwOrPrintModuleLoadError(program: string, error: Error): void { const deps = packageObject["dependencies"] || {}; const devDeps = packageObject["devDependencies"] || {}; const scripts = packageObject["scripts"] || {}; - const mainProperty = packageObject["main"] || "index.js"; + const mainProperty = packageObject["main"] || "index.js"; // Is there a build script associated with this program? It's a little confusing that the // Pulumi CLI doesn't run build scripts before running the program so call that out @@ -106,7 +107,7 @@ function throwOrPrintModuleLoadError(program: string, error: Error): void { const command = scripts["build"]; console.error(` * Your program looks like it has a build script associated with it ('${command}').\n`); console.error("Pulumi does not run build scripts before running your program. " + - `Please run '${command}', 'yarn build', or 'npm run build' and try again.`); + `Please run '${command}', 'yarn build', or 'npm run build' and try again.`); return; } @@ -132,10 +133,11 @@ function throwOrPrintModuleLoadError(program: string, error: Error): void { } /** @internal */ -export function run(argv: minimist.ParsedArgs, - programStarted: () => void, - reportLoggedError: (err: Error) => void, - isErrorReported: (err: Error) => boolean) { +export function run( + argv: minimist.ParsedArgs, + programStarted: () => void, + reportLoggedError: (err: Error) => void, + isErrorReported: (err: Error) => boolean): Promise { // If there is a --pwd directive, switch directories. const pwd: string | undefined = argv["pwd"]; if (pwd) { @@ -150,7 +152,8 @@ export function run(argv: minimist.ParsedArgs, // find a tsconfig.json. For us, it's reasonable to say that the "root" of the project is the cwd, // if there's a tsconfig.json file here. Otherwise, just tell ts-node to not load project options at all. // This helps with cases like pulumi/pulumi#1772. - const tsConfigPath = "tsconfig.json"; + const defaultTsConfigPath = "tsconfig.json"; + const tsConfigPath: string = process.env["PULUMI_NODEJS_TSCONFIG_PATH"] ?? defaultTsConfigPath; const skipProject = !fs.existsSync(tsConfigPath); let compilerOptions: object; @@ -184,7 +187,7 @@ export function run(argv: minimist.ParsedArgs, // Now fake out the process-wide argv, to make the program think it was run normally. const programArgs: string[] = argv._.slice(1); - process.argv = [ process.argv[0], process.argv[1], ...programArgs ]; + process.argv = [process.argv[0], process.argv[1], ...programArgs]; // Set up the process uncaught exception, unhandled rejection, and program exit handlers. const uncaughtHandler = (err: Error) => { @@ -230,6 +233,15 @@ ${defaultMessage}`); programStarted(); + // This needs to occur after `programStarted` to ensure execution of the parent process stops. + if (skipProject && tsConfigPath !== defaultTsConfigPath) { + return new Promise(() => { + const e = new Error(`tsconfig path was set to ${tsConfigPath} but the file was not found`); + e.stack = undefined; + throw e; + }); + } + const runProgram = async () => { // We run the program inside this context so that it adopts all resources. // diff --git a/tests/integration/integration_nodejs_test.go b/tests/integration/integration_nodejs_test.go index bbc95369d..acd04ffc9 100644 --- a/tests/integration/integration_nodejs_test.go +++ b/tests/integration/integration_nodejs_test.go @@ -1178,3 +1178,23 @@ func TestAboutNodeJS(t *testing.T) { func TestConstructOutputValuesNode(t *testing.T) { testConstructOutputValues(t, "nodejs", "@pulumi/pulumi") } + +func TestTSConfigOption(t *testing.T) { + if runtime.GOOS == WindowsOS { + t.Skip("Skip on windows because we lack yarn") + } + + e := ptesting.NewEnvironment(t) + defer func() { + if !t.Failed() { + e.DeleteEnvironment() + } + }() + e.ImportDirectory("tsconfig") + + e.RunCommand("yarn", "link", "@pulumi/pulumi") + e.RunCommand("yarn", "install") + e.RunCommand("pulumi", "login", "--cloud-url", e.LocalURL()) + e.RunCommand("pulumi", "stack", "select", "tsconfg", "--create") + e.RunCommand("pulumi", "preview") +} diff --git a/tests/integration/tsconfig/Pulumi.yaml b/tests/integration/tsconfig/Pulumi.yaml new file mode 100644 index 000000000..63e5ce72b --- /dev/null +++ b/tests/integration/tsconfig/Pulumi.yaml @@ -0,0 +1,5 @@ +name: test-yaml-option +runtime: + name: nodejs + options: + tsconfig: other.json diff --git a/tests/integration/tsconfig/index.ts b/tests/integration/tsconfig/index.ts new file mode 100644 index 000000000..eb336282c --- /dev/null +++ b/tests/integration/tsconfig/index.ts @@ -0,0 +1,7 @@ +import * as pulumi from "@pulumi/pulumi"; + +// If this is run onder "module": "esnext", it will fail. Neither the import nor the export are +// valid for "esnext". + +// Export the name of the bucket +export const bucketName = "name"; diff --git a/tests/integration/tsconfig/other.json b/tests/integration/tsconfig/other.json new file mode 100644 index 000000000..9469ac567 --- /dev/null +++ b/tests/integration/tsconfig/other.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": ["index.ts"] +} diff --git a/tests/integration/tsconfig/package.json b/tests/integration/tsconfig/package.json new file mode 100644 index 000000000..7bdb45998 --- /dev/null +++ b/tests/integration/tsconfig/package.json @@ -0,0 +1,9 @@ +{ + "name": "tsconfig", + "devDependencies": { + "@types/node": "^14" + }, + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + } +} diff --git a/tests/integration/tsconfig/tsconfig.json b/tests/integration/tsconfig/tsconfig.json new file mode 100644 index 000000000..49c017413 --- /dev/null +++ b/tests/integration/tsconfig/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2016", + "module": "esnext", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": ["index.ts"] +}