diff --git a/Makefile b/Makefile index 23dab22991..725303bd01 100644 --- a/Makefile +++ b/Makefile @@ -49,12 +49,16 @@ install:: mkdir -p "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)" cp -r pack/nodejs/bin/. "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)" rm -rf "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)/node_modules" + rm -rf "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)/tests" cd "$(PULUMI_NODE_MODULES)/$(NODE_MODULE_NAME)" && \ yarn install --offline --production && \ (yarn unlink > /dev/null 2>&1 || true) && \ yarn link -test_all:: +test_fast:: + ./pack/nodejs/node_modules/mocha/bin/mocha ./pack/nodejs/bin/tests + +test_all:: test_fast PATH=$(PULUMI_BIN):$(PATH) $(GO) test -v -cover -timeout 1h -parallel ${TESTPARALLELISM} $(TESTABLE_PKGS) .PHONY: publish_tgz diff --git a/pack/nodejs/helm.ts b/pack/nodejs/helm.ts index bb87170896..4b0a846eee 100644 --- a/pack/nodejs/helm.ts +++ b/pack/nodejs/helm.ts @@ -5,6 +5,7 @@ import * as k8s from "./index"; import * as pulumi from "@pulumi/pulumi"; import * as shell from "shell-quote"; import * as tmp from "tmp"; +import * as path from "./path"; export namespace v2 { export interface ChartOpts { @@ -142,16 +143,16 @@ export function fetch(chart: string, opts?: FetchOpts) { if(opts.untar !== false) { flags.push(`--untar`); } if (opts.version !== undefined) { flags.push(`--version ${shell.quote([opts.version])}`); } - if (opts.caFile !== undefined) { flags.push(`--ca-file ${shell.quote([opts.caFile])}`); } - if (opts.certFile !== undefined) { flags.push(`--cert-file ${shell.quote([opts.certFile])}`); } - if (opts.keyFile !== undefined) { flags.push(`--key-file ${shell.quote([opts.keyFile])}`); } - if (opts.destination !== undefined) { flags.push(`--destination ${shell.quote([opts.destination])}`); } - if (opts.keyring !== undefined) { flags.push(`--keyring ${shell.quote([opts.keyring])}`); } + if (opts.caFile !== undefined) { flags.push(`--ca-file ${path.quotePath(opts.caFile)}`); } + if (opts.certFile !== undefined) { flags.push(`--cert-file ${path.quotePath(opts.certFile)}`); } + if (opts.keyFile !== undefined) { flags.push(`--key-file ${path.quotePath(opts.keyFile)}`); } + if (opts.destination !== undefined) { flags.push(`--destination ${path.quotePath(opts.destination)}`); } + if (opts.keyring !== undefined) { flags.push(`--keyring ${path.quotePath(opts.keyring)}`); } if (opts.password !== undefined) { flags.push(`--password ${shell.quote([opts.password])}`); } if (opts.repo !== undefined) { flags.push(`--repo ${shell.quote([opts.repo])}`); } - if (opts.untardir !== undefined) { flags.push(`--untardir ${shell.quote([opts.untardir])}`); } + if (opts.untardir !== undefined) { flags.push(`--untardir ${path.quotePath(opts.untardir)}`); } if (opts.username !== undefined) { flags.push(`--username ${shell.quote([opts.username])}`); } - if (opts.home !== undefined) { flags.push(`--home ${shell.quote([opts.home])}`); } + if (opts.home !== undefined) { flags.push(`--home ${path.quotePath(opts.home)}`); } if (opts.devel === true) { flags.push(`--devel`); } if (opts.prov === true) { flags.push(`--prov`); } if (opts.verify === true) { flags.push(`--verify`); } diff --git a/pack/nodejs/package.json b/pack/nodejs/package.json index fba672aed0..e38b4529d5 100755 --- a/pack/nodejs/package.json +++ b/pack/nodejs/package.json @@ -20,7 +20,9 @@ "tmp": "^0.0.33", "@types/tmp": "^0.0.33", "glob": "^7.1.2", - "@types/glob": "^5.0.35" + "@types/glob": "^5.0.35", + "mocha": "^5.2.0", + "@types/mocha": "^5.2.5" }, "devDependencies": { "typescript": "^2.6.2", diff --git a/pack/nodejs/path.ts b/pack/nodejs/path.ts new file mode 100644 index 0000000000..fe5ab552f6 --- /dev/null +++ b/pack/nodejs/path.ts @@ -0,0 +1,19 @@ +import * as shell from "shell-quote"; + +export function quotePath(path: string): string { + if (process.platform === "win32") { + return quoteWindowsPath(path); + } else { + return shell.quote([path]); + } +} + +export function quoteWindowsPath(path: string): string { + // Unescape paths for Windows. Taken directly from[1], an unmerged, but LGTM'd PR to the + // official library. + // + // [1]: https://github.com/substack/node-shell-quote/pull/34 + + path = String(path).replace(/([A-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g, "$1\\$2"); + return path.replace(/\\\\/g, "\\"); +} diff --git a/pack/nodejs/tests/path.ts b/pack/nodejs/tests/path.ts new file mode 100644 index 0000000000..18af4f74b4 --- /dev/null +++ b/pack/nodejs/tests/path.ts @@ -0,0 +1,17 @@ +import * as assert from "assert"; +import * as path from "../path"; + +describe("path.quoteWindowsPath", () => { + it("escapes Windows path with drive prefix correctly", () => { + const p = path.quoteWindowsPath("C:\\Users\\grace hopper\\AppData\\Local\\Temp"); + assert.equal(p, "C:\\Users\\grace hopper\\AppData\\Local\\Temp"); + }); + it("escapes Windows path with no drive prefix correctly", () => { + const p = path.quoteWindowsPath("\\Users\\grace hopper\\AppData\\Local\\Temp"); + assert.equal(p, "\\Users\\grace hopper\\AppData\\Local\\Temp"); + }); + it("escapes relative Windows path correctly", () => { + const p = path.quoteWindowsPath("Users\\grace hopper\\AppData\\Local\\Temp"); + assert.equal(p, "Users\\grace hopper\\AppData\\Local\\Temp"); + }); +}); diff --git a/pack/nodejs/yarn.lock b/pack/nodejs/yarn.lock index 8d65b16878..8bc45607fe 100644 --- a/pack/nodejs/yarn.lock +++ b/pack/nodejs/yarn.lock @@ -83,6 +83,10 @@ version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" +"@types/mocha@^5.2.5": + version "5.2.5" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.5.tgz#8a4accfc403c124a0bafe8a9fc61a05ec1032073" + "@types/node@*": version "10.5.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.8.tgz#6f14ccecad1d19332f063a6a764f8907801fece0" @@ -166,6 +170,10 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -204,6 +212,10 @@ colour@~0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" +commander@2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -216,6 +228,12 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + debug@^2.1.2: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -249,10 +267,14 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diff@^3.1.0: +diff@3.5.0, diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" +escape-string-regexp@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -280,7 +302,7 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: +glob@7.1.2, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -299,6 +321,10 @@ graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + grpc@^1.12.2: version "1.14.0" resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.14.0.tgz#5aea131ef078285eff543301b99ba994e4db2c73" @@ -308,10 +334,18 @@ grpc@^1.12.2: node-pre-gyp "^0.10.0" protobufjs "^5.0.3" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -404,7 +438,7 @@ make-error@^1.1.1: version "1.3.4" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535" -minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -431,12 +465,28 @@ minizlib@^1.1.0: dependencies: minipass "^2.2.1" -mkdirp@^0.5.0, mkdirp@^0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" +mocha@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" + dependencies: + browser-stdout "1.3.1" + commander "2.15.1" + debug "3.1.0" + diff "3.5.0" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.5" + he "1.1.1" + minimatch "3.0.4" + mkdirp "0.5.1" + supports-color "5.4.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -760,6 +810,12 @@ strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +supports-color@5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + tar@^4: version "4.4.6" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.6.tgz#63110f09c00b4e60ac8bcfe1bf3c8660235fbc9b" diff --git a/pkg/gen/node-templates/helm.ts.mustache b/pkg/gen/node-templates/helm.ts.mustache index bb87170896..4b0a846eee 100644 --- a/pkg/gen/node-templates/helm.ts.mustache +++ b/pkg/gen/node-templates/helm.ts.mustache @@ -5,6 +5,7 @@ import * as k8s from "./index"; import * as pulumi from "@pulumi/pulumi"; import * as shell from "shell-quote"; import * as tmp from "tmp"; +import * as path from "./path"; export namespace v2 { export interface ChartOpts { @@ -142,16 +143,16 @@ export function fetch(chart: string, opts?: FetchOpts) { if(opts.untar !== false) { flags.push(`--untar`); } if (opts.version !== undefined) { flags.push(`--version ${shell.quote([opts.version])}`); } - if (opts.caFile !== undefined) { flags.push(`--ca-file ${shell.quote([opts.caFile])}`); } - if (opts.certFile !== undefined) { flags.push(`--cert-file ${shell.quote([opts.certFile])}`); } - if (opts.keyFile !== undefined) { flags.push(`--key-file ${shell.quote([opts.keyFile])}`); } - if (opts.destination !== undefined) { flags.push(`--destination ${shell.quote([opts.destination])}`); } - if (opts.keyring !== undefined) { flags.push(`--keyring ${shell.quote([opts.keyring])}`); } + if (opts.caFile !== undefined) { flags.push(`--ca-file ${path.quotePath(opts.caFile)}`); } + if (opts.certFile !== undefined) { flags.push(`--cert-file ${path.quotePath(opts.certFile)}`); } + if (opts.keyFile !== undefined) { flags.push(`--key-file ${path.quotePath(opts.keyFile)}`); } + if (opts.destination !== undefined) { flags.push(`--destination ${path.quotePath(opts.destination)}`); } + if (opts.keyring !== undefined) { flags.push(`--keyring ${path.quotePath(opts.keyring)}`); } if (opts.password !== undefined) { flags.push(`--password ${shell.quote([opts.password])}`); } if (opts.repo !== undefined) { flags.push(`--repo ${shell.quote([opts.repo])}`); } - if (opts.untardir !== undefined) { flags.push(`--untardir ${shell.quote([opts.untardir])}`); } + if (opts.untardir !== undefined) { flags.push(`--untardir ${path.quotePath(opts.untardir)}`); } if (opts.username !== undefined) { flags.push(`--username ${shell.quote([opts.username])}`); } - if (opts.home !== undefined) { flags.push(`--home ${shell.quote([opts.home])}`); } + if (opts.home !== undefined) { flags.push(`--home ${path.quotePath(opts.home)}`); } if (opts.devel === true) { flags.push(`--devel`); } if (opts.prov === true) { flags.push(`--prov`); } if (opts.verify === true) { flags.push(`--verify`); } diff --git a/pkg/gen/node-templates/package.json.mustache b/pkg/gen/node-templates/package.json.mustache index fba672aed0..e38b4529d5 100644 --- a/pkg/gen/node-templates/package.json.mustache +++ b/pkg/gen/node-templates/package.json.mustache @@ -20,7 +20,9 @@ "tmp": "^0.0.33", "@types/tmp": "^0.0.33", "glob": "^7.1.2", - "@types/glob": "^5.0.35" + "@types/glob": "^5.0.35", + "mocha": "^5.2.0", + "@types/mocha": "^5.2.5" }, "devDependencies": { "typescript": "^2.6.2",