@gatling.io/cli 3.12.0 → 3.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gatling.io/cli",
3
- "version": "3.12.0",
3
+ "version": "3.13.1",
4
4
  "license": "Apache-2.0",
5
5
  "bin": {
6
6
  "gatling": "target/index.js"
@@ -8,22 +8,24 @@
8
8
  "main": "target/index.js",
9
9
  "types": "target/index.d.ts",
10
10
  "dependencies": {
11
+ "@jspm/core": "2.1.0",
11
12
  "archiver": "7.0.1",
12
13
  "axios": "1.7.7",
13
14
  "commander": "12.1.0",
14
15
  "decompress": "4.2.1",
15
- "esbuild": "0.23.1",
16
+ "esbuild": "0.24.0",
16
17
  "esbuild-plugin-tsc": "0.4.0",
18
+ "import-meta-resolve": "4.1.0",
17
19
  "readline-sync": "1.4.10"
18
20
  },
19
21
  "devDependencies": {
20
- "@types/archiver": "6.0.2",
22
+ "@types/archiver": "6.0.3",
21
23
  "@types/decompress": "4.2.7",
22
- "@types/node": "18.19.50",
24
+ "@types/node": "18.19.64",
23
25
  "@types/readline-sync": "1.4.8",
24
26
  "prettier": "3.3.3",
25
27
  "rimraf": "6.0.1",
26
- "typescript": "5.5.4"
28
+ "typescript": "5.6.3"
27
29
  },
28
30
  "scripts": {
29
31
  "clean": "rimraf target",
@@ -0,0 +1,87 @@
1
+ import { Buffer } from "buffer"
2
+
3
+ // limit of Crypto.getRandomValues()
4
+ // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
5
+ const MAX_BYTES = 65536;
6
+
7
+ // Node supports requesting up to this number of bytes
8
+ // https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48
9
+ const MAX_UINT32 = 4294967295;
10
+
11
+ const JavaCrypto = Java.type("io.gatling.js.polyfills.Crypto");
12
+
13
+ export const randomBytes = (size, cb) => {
14
+ // Node supports requesting up to this number of bytes
15
+ // https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48
16
+ if (size > MAX_UINT32) {
17
+ throw new RangeError('requested too many random bytes');
18
+ }
19
+ const bytes = Buffer.from(JavaCrypto.randomBytes(size));
20
+ if (typeof cb === 'function') {
21
+ return process.nextTick(function () {
22
+ cb(null, bytes);
23
+ })
24
+ }
25
+ return bytes;
26
+ };
27
+ export const rng = randomBytes;
28
+ export const pseudoRandomBytes = randomBytes;
29
+ export const prng = randomBytes;
30
+ export const getRandomValues = (values) => {
31
+ const byteView = new Uint8Array(values.buffer, values.byteOffset, values.byteLength);
32
+ const bytes = randomBytes(byteView.length);
33
+ for (let i = 0; i < byteView.length; i++) {
34
+ // The range of Math.random() is [0, 1) and the ToUint8 abstract operation rounds down
35
+ byteView[i] = bytes[i];
36
+ }
37
+ return values;
38
+ };
39
+ export const randomUUID = () => JavaCrypto.randomUUID();
40
+
41
+ // export const Cipher = crypto.Cipher;
42
+ // export const Cipheriv = crypto.Cipheriv;
43
+ // export const Decipher = crypto.Decipher;
44
+ // export const Decipheriv = crypto.Decipheriv;
45
+ // export const DiffieHellman = crypto.DiffieHellman;
46
+ // export const DiffieHellmanGroup = crypto.DiffieHellmanGroup;
47
+ // export const Hash = crypto.Hash;
48
+ // export const Hmac = crypto.Hmac;
49
+ // export const Sign = crypto.Sign;
50
+ // export const Verify = crypto.Verify;
51
+ // export const constants = crypto.constants;
52
+ // export const createCipher = crypto.createCipher;
53
+ // export const createCipheriv = crypto.createCipheriv;
54
+ // export const createCredentials = crypto.createCredentials;
55
+ // export const createDecipher = crypto.createDecipher;
56
+ // export const createDecipheriv = crypto.createDecipheriv;
57
+ // export const createDiffieHellman = crypto.createDiffieHellman;
58
+ // export const createDiffieHellmanGroup = crypto.createDiffieHellmanGroup;
59
+ // export const createECDH = crypto.createECDH;
60
+ // export const createHash = crypto.createHash;
61
+ // export const createHmac = crypto.createHmac;
62
+ // export const createSign = crypto.createSign;
63
+ // export const createVerify = crypto.createVerify;
64
+ // export const getCiphers = crypto.getCiphers;
65
+ // export const getDiffieHellman = crypto.getDiffieHellman;
66
+ // export const getHashes = crypto.getHashes;
67
+ // export const listCiphers = crypto.listCiphers;
68
+ // export const pbkdf2 = crypto.pbkdf2;
69
+ // export const pbkdf2Sync = crypto.pbkdf2Sync;
70
+ // export const privateDecrypt = crypto.privateDecrypt;
71
+ // export const privateEncrypt = crypto.privateEncrypt;
72
+ // export const publicDecrypt = crypto.publicDecrypt;
73
+ // export const publicEncrypt = crypto.publicEncrypt;
74
+ // export const randomFill = crypto.randomFill;
75
+ // export const randomFillSync = crypto.randomFillSync;
76
+
77
+ const crypto = {
78
+ randomBytes,
79
+ rng,
80
+ pseudoRandomBytes,
81
+ prng,
82
+ getRandomValues,
83
+ randomUUID,
84
+ };
85
+ crypto.webcrypto = crypto;
86
+ globalThis.crypto = crypto;
87
+ export default crypto;
@@ -0,0 +1,13 @@
1
+ const global = globalThis;
2
+ export { global };
3
+
4
+ export { Buffer } from "buffer";
5
+
6
+ // These values are used by some of the JSPM polyfills
7
+ export const navigator = {
8
+ deviceMemory: 8, // Highest allowed value
9
+ hardwareConcurrency: 8, // Fairly common default
10
+ language: "en-US", // Most common default
11
+ };
12
+
13
+ export * as crypto from "crypto"
@@ -1,12 +1,14 @@
1
1
  import * as esbuild from "esbuild";
2
2
  import esbuildPluginTsc from "esbuild-plugin-tsc";
3
3
 
4
- import { SimulationFile } from "./simulations";
5
- import { logger } from "./log";
4
+ import { polyfill } from "./polyfill";
5
+ import { SimulationFile } from "../simulations";
6
+ import { logger } from "../log";
6
7
 
7
8
  export interface BundleOptions {
8
9
  sourcesFolder: string;
9
10
  bundleFile: string;
11
+ postman?: string;
10
12
  typescript: boolean;
11
13
  simulations: SimulationFile[];
12
14
  }
@@ -20,12 +22,17 @@ export const bundle = async (options: BundleOptions): Promise<void> => {
20
22
  const contents = options.simulations.map((s) => `export { default as "${s.name}" } from "./${s.path}";`).join("\n");
21
23
 
22
24
  const plugins = options.typescript ? [esbuildPluginTsc({ force: true })] : [];
25
+ if (options.postman !== undefined) {
26
+ plugins.push(polyfill());
27
+ }
23
28
  await esbuild.build({
24
29
  stdin: {
25
30
  contents,
26
31
  resolveDir: options.sourcesFolder
27
32
  },
28
33
  outfile: options.bundleFile,
34
+ platform: "neutral",
35
+ mainFields: ["main", "module"],
29
36
  bundle: true,
30
37
  minify: false,
31
38
  sourcemap: true,
@@ -0,0 +1,91 @@
1
+ import type { Plugin } from "esbuild";
2
+ import { fileURLToPath, pathToFileURL } from "url";
3
+ import { resolve, dirname } from "path";
4
+
5
+ // This is largely inspired by https://github.com/cyco130/esbuild-plugin-polyfill-node
6
+
7
+ export const polyfill = (): Plugin => ({
8
+ name: "gatling-js-polyfill",
9
+ setup: async (build) => {
10
+ // modules
11
+ const jspmResolved = await resolveImport(`@jspm/core/nodelibs/fs`);
12
+ build.onResolve({ filter: polyfillsFilter }, async ({ path }) => {
13
+ const [, , moduleName] = path.match(polyfillsFilter)!;
14
+ const resolved = customPolyfills.find((name) => name === moduleName)
15
+ ? resolve(dirname(__filename), `../../polyfills/${moduleName}.js`)
16
+ : resolve(jspmResolved, `../../browser/${moduleName}.js`);
17
+ return { path: resolved };
18
+ });
19
+
20
+ // Globals
21
+ build.initialOptions.inject = build.initialOptions.inject || [];
22
+ const injectGlobal = (name: string) =>
23
+ (build.initialOptions.inject as string[]).push(resolve(dirname(__filename), `../../polyfills/${name}.js`));
24
+ injectGlobal("global");
25
+ }
26
+ });
27
+
28
+ const customPolyfills = ["crypto"];
29
+
30
+ const jspmPolyfills = ["buffer", "path", "string_decoder"];
31
+
32
+ // Other available jspm-core modules:
33
+ // "_stream_duplex"
34
+ // "_stream_passthrough"
35
+ // "_stream_readable"
36
+ // "_stream_transform"
37
+ // "_stream_writable"
38
+ // "assert"
39
+ // "assert/strict"
40
+ // "async_hooks"
41
+ // "child_process"
42
+ // "cluster"
43
+ // "console"
44
+ // "constants"
45
+ // "crypto"
46
+ // "dgram"
47
+ // "diagnostics_channel"
48
+ // "dns"
49
+ // "domain"
50
+ // "events"
51
+ // "fs"
52
+ // "fs/promises"
53
+ // "http"
54
+ // "http2"
55
+ // "https"
56
+ // "module"
57
+ // "net"
58
+ // "os"
59
+ // "perf_hooks"
60
+ // "process"
61
+ // "punycode"
62
+ // "querystring"
63
+ // "readline"
64
+ // "repl"
65
+ // "stream"
66
+ // "sys"
67
+ // "timers"
68
+ // "timers/promises"
69
+ // "tls"
70
+ // "tty"
71
+ // "url"
72
+ // "util"
73
+ // "v8"
74
+ // "vm"
75
+ // "wasi"
76
+ // "worker_threads"
77
+ // "zlib"
78
+
79
+ const polyfillsFilter = new RegExp(`^(node:)?(${jspmPolyfills.concat(customPolyfills).join("|")})$`);
80
+
81
+ let importMetaResolve: (specifier: string, parent: string) => string;
82
+
83
+ const importMetaUrl = pathToFileURL(__filename).href;
84
+
85
+ const resolveImport = async (specifier: string) => {
86
+ if (!importMetaResolve) {
87
+ importMetaResolve = (await import("import-meta-resolve")).resolve;
88
+ }
89
+ const resolved = importMetaResolve(specifier, importMetaUrl);
90
+ return fileURLToPath(resolved);
91
+ };
@@ -3,6 +3,8 @@ import { Command } from "commander";
3
3
  import {
4
4
  bundleFileOption,
5
5
  bundleFileOptionValue,
6
+ postmanOption,
7
+ postmanOptionValueWithDefaults,
6
8
  sourcesFolderOption,
7
9
  sourcesFolderOptionValue,
8
10
  typescriptOption,
@@ -17,14 +19,16 @@ export default (program: Command): void => {
17
19
  .description("Build Gatling simulations")
18
20
  .addOption(sourcesFolderOption)
19
21
  .addOption(bundleFileOption)
22
+ .addOption(postmanOption)
20
23
  .addOption(typescriptOption)
21
24
  .action(async (options) => {
22
25
  const sourcesFolder: string = sourcesFolderOptionValue(options);
23
26
  const bundleFile = bundleFileOptionValue(options);
24
27
 
25
28
  const simulations = await findSimulations(sourcesFolder);
29
+ const postman = postmanOptionValueWithDefaults(options);
26
30
  const typescript = typescriptOptionValueWithDefaults(options, simulations);
27
31
 
28
- await bundle({ sourcesFolder, bundleFile, typescript, simulations });
32
+ await bundle({ sourcesFolder, bundleFile, postman, typescript, simulations });
29
33
  });
30
34
  };
@@ -15,6 +15,8 @@ import {
15
15
  packageDescriptorFilenameOptionValue,
16
16
  packageFileOption,
17
17
  packageFileOptionValue,
18
+ postmanOption,
19
+ postmanOptionValueWithDefaults,
18
20
  resourcesFolderOption,
19
21
  resourcesFolderOptionValue,
20
22
  resultsFolderOption,
@@ -23,8 +25,10 @@ import {
23
25
  sourcesFolderOptionValue,
24
26
  typescriptOption,
25
27
  typescriptOptionValueWithDefaults,
26
- urlOption,
27
- urlOptionValue
28
+ apiUrlOption,
29
+ apiUrlOptionValue,
30
+ webAppUrlOption,
31
+ webAppUrlOptionValue
28
32
  } from "./options";
29
33
  import { findSimulations } from "../simulations";
30
34
  import { installGatlingJs } from "../dependencies";
@@ -39,10 +43,12 @@ export default (program: Command): void => {
39
43
  .addOption(resourcesFolderOption)
40
44
  .addOption(bundleFileOption)
41
45
  .addOption(resultsFolderOption)
46
+ .addOption(postmanOption)
42
47
  .addOption(typescriptOption)
43
48
  .addOption(gatlingHomeOption)
44
49
  // Base
45
- .addOption(urlOption)
50
+ .addOption(apiUrlOption)
51
+ .addOption(webAppUrlOption)
46
52
  .addOption(apiTokenOption)
47
53
  // Plugin configuration
48
54
  .addOption(controlPlaneUrlOption)
@@ -55,13 +61,15 @@ export default (program: Command): void => {
55
61
  const sourcesFolder: string = sourcesFolderOptionValue(options);
56
62
 
57
63
  const simulations = await findSimulations(sourcesFolder);
64
+ const postman = postmanOptionValueWithDefaults(options);
58
65
  const typescript = typescriptOptionValueWithDefaults(options, simulations);
59
66
 
60
67
  const resourcesFolder: string = resourcesFolderOptionValue(options);
61
68
  const bundleFile = bundleFileOptionValue(options);
62
69
  const resultsFolder: string = resultsFolderOptionValue(options);
63
70
  const gatlingHome = gatlingHomeOptionValueWithDefaults(options);
64
- const url = urlOptionValue(options);
71
+ const apiUrl = apiUrlOptionValue(options);
72
+ const webAppUrl = webAppUrlOptionValue(options);
65
73
  const apiToken = apiTokenOptionValue(options);
66
74
  const controlPlaneUrl = controlPlaneUrlOptionValue(options);
67
75
  const nonInteractive = nonInteractiveOptionValue(options);
@@ -69,7 +77,7 @@ export default (program: Command): void => {
69
77
  const packageFile = packageFileOptionValue(options);
70
78
 
71
79
  const { graalvmHome, jvmClasspath } = await installGatlingJs({ gatlingHome });
72
- await bundle({ sourcesFolder, bundleFile, typescript, simulations });
80
+ await bundle({ sourcesFolder, bundleFile, postman, typescript, simulations });
73
81
  await enterprisePackage({ bundleFile, resourcesFolder, packageFile, simulations });
74
82
  await enterpriseDeploy({
75
83
  graalvmHome,
@@ -77,7 +85,8 @@ export default (program: Command): void => {
77
85
  bundleFile,
78
86
  resourcesFolder,
79
87
  resultsFolder,
80
- url,
88
+ apiUrl,
89
+ webAppUrl,
81
90
  apiToken,
82
91
  controlPlaneUrl,
83
92
  nonInteractive,
@@ -5,6 +5,8 @@ import {
5
5
  bundleFileOptionValue,
6
6
  packageFileOption,
7
7
  packageFileOptionValue,
8
+ postmanOption,
9
+ postmanOptionValueWithDefaults,
8
10
  resourcesFolderOption,
9
11
  resourcesFolderOptionValue,
10
12
  sourcesFolderOption,
@@ -24,6 +26,7 @@ export default (program: Command): void => {
24
26
  .addOption(resourcesFolderOption)
25
27
  .addOption(bundleFileOption)
26
28
  .addOption(packageFileOption)
29
+ .addOption(postmanOption)
27
30
  .addOption(typescriptOption)
28
31
  .action(async (options) => {
29
32
  const sourcesFolder: string = sourcesFolderOptionValue(options);
@@ -32,9 +35,10 @@ export default (program: Command): void => {
32
35
  const packageFile = packageFileOptionValue(options);
33
36
 
34
37
  const simulations = await findSimulations(sourcesFolder);
38
+ const postman = postmanOptionValueWithDefaults(options);
35
39
  const typescript = typescriptOptionValueWithDefaults(options, simulations);
36
40
 
37
- await bundle({ sourcesFolder, bundleFile, typescript, simulations });
41
+ await bundle({ sourcesFolder, bundleFile, postman, typescript, simulations });
38
42
 
39
43
  await enterprisePackage({ bundleFile, resourcesFolder, packageFile, simulations });
40
44
  });
@@ -17,6 +17,8 @@ import {
17
17
  packageDescriptorFilenameOptionValue,
18
18
  packageFileOption,
19
19
  packageFileOptionValue,
20
+ postmanOption,
21
+ postmanOptionValueWithDefaults,
20
22
  resourcesFolderOption,
21
23
  resourcesFolderOptionValue,
22
24
  resultsFolderOption,
@@ -29,8 +31,10 @@ import {
29
31
  sourcesFolderOptionValue,
30
32
  typescriptOption,
31
33
  typescriptOptionValueWithDefaults,
32
- urlOption,
33
- urlOptionValue,
34
+ apiUrlOption,
35
+ apiUrlOptionValue,
36
+ webAppUrlOption,
37
+ webAppUrlOptionValue,
34
38
  waitForRunEndOption,
35
39
  waitForRunEndOptionValue
36
40
  } from "./options";
@@ -47,10 +51,12 @@ export default (program: Command): void => {
47
51
  .addOption(resourcesFolderOption)
48
52
  .addOption(bundleFileOption)
49
53
  .addOption(resultsFolderOption)
54
+ .addOption(postmanOption)
50
55
  .addOption(typescriptOption)
51
56
  .addOption(gatlingHomeOption)
52
57
  // Base
53
- .addOption(urlOption)
58
+ .addOption(apiUrlOption)
59
+ .addOption(webAppUrlOption)
54
60
  .addOption(apiTokenOption)
55
61
  // Plugin configuration
56
62
  .addOption(controlPlaneUrlOption)
@@ -68,13 +74,15 @@ export default (program: Command): void => {
68
74
  const sourcesFolder: string = sourcesFolderOptionValue(options);
69
75
 
70
76
  const simulations = await findSimulations(sourcesFolder);
77
+ const postman = postmanOptionValueWithDefaults(options);
71
78
  const typescript = typescriptOptionValueWithDefaults(options, simulations);
72
79
 
73
80
  const resourcesFolder: string = resourcesFolderOptionValue(options);
74
81
  const bundleFile = bundleFileOptionValue(options);
75
82
  const resultsFolder: string = resultsFolderOptionValue(options);
76
83
  const gatlingHome = gatlingHomeOptionValueWithDefaults(options);
77
- const url = urlOptionValue(options);
84
+ const apiUrl = apiUrlOptionValue(options);
85
+ const webAppUrl = webAppUrlOptionValue(options);
78
86
  const apiToken = apiTokenOptionValue(options);
79
87
  const controlPlaneUrl = controlPlaneUrlOptionValue(options);
80
88
  const nonInteractive = nonInteractiveOptionValue(options);
@@ -90,7 +98,7 @@ export default (program: Command): void => {
90
98
  }
91
99
 
92
100
  const { graalvmHome, jvmClasspath } = await installGatlingJs({ gatlingHome });
93
- await bundle({ sourcesFolder, bundleFile, typescript, simulations });
101
+ await bundle({ sourcesFolder, bundleFile, postman, typescript, simulations });
94
102
  await enterprisePackage({ bundleFile, resourcesFolder, packageFile, simulations });
95
103
  await enterpriseStart({
96
104
  graalvmHome,
@@ -98,7 +106,8 @@ export default (program: Command): void => {
98
106
  bundleFile,
99
107
  resourcesFolder,
100
108
  resultsFolder,
101
- url,
109
+ apiUrl,
110
+ webAppUrl,
102
111
  apiToken,
103
112
  controlPlaneUrl,
104
113
  nonInteractive,
@@ -1,5 +1,7 @@
1
1
  import { Option, Argument } from "commander";
2
+ import fs from "fs";
2
3
  import os from "os";
4
+ import path from "path";
3
5
 
4
6
  import { SimulationFile } from "../simulations";
5
7
  import { keyInSelectPaginated } from "../readline";
@@ -95,12 +97,13 @@ export const simulationOptionValueWithDefaults = (
95
97
  "No simulation found, simulations must be defined in a <simulation name>.gatling.js or <simulation name>.gatling.ts file)"
96
98
  );
97
99
  } else if (interactive) {
100
+ const sortedSimulations = simulationsFound.sort((a, b) => a.name.localeCompare(b.name));
98
101
  const idx = keyInSelectPaginated(
99
- simulationsFound.map((s) => s.name).sort((a, b) => a.localeCompare(b)),
102
+ sortedSimulations.map((s) => s.name),
100
103
  "Choose a simulation to run"
101
104
  );
102
105
  if (idx >= 0) {
103
- const simulation = simulationsFound[idx].name;
106
+ const simulation = sortedSimulations[idx].name;
104
107
  logger.info(`Simulation '${simulation}' was chosen.`);
105
108
  return simulation;
106
109
  } else {
@@ -194,6 +197,43 @@ export const nonInteractiveOption = new Option(
194
197
  ).default(false);
195
198
  export const nonInteractiveOptionValue = getBooleanValueMandatory(nonInteractiveOption);
196
199
 
200
+ export const postmanOption = new Option(
201
+ "--postman <version>",
202
+ "Postman compatibility option: adds polyfills, etc."
203
+ ).hideHelp();
204
+ export const postmanOptionValueWithDefaults = (options: any): string | undefined => {
205
+ const postmanOptionValue = getStringValueOptional(postmanOption)(options);
206
+ if (postmanOptionValue !== undefined) {
207
+ return postmanOptionValue;
208
+ } else {
209
+ try {
210
+ const conf = JSON.parse(fs.readFileSync("package.json", { encoding: "utf-8", flag: "r" }));
211
+ const withPostman =
212
+ conf.dependencies?.["@gatling.io/postman"] !== undefined ||
213
+ conf.devDependencies?.["@gatling.io/postman"] !== undefined;
214
+ if (withPostman) {
215
+ let directory = path.normalize(path.dirname("package.json"));
216
+ const root = path.parse(directory).root;
217
+ while (true) {
218
+ const file = path.join(directory, "node_modules", "@gatling.io", "postman", "package.json");
219
+ if (fs.existsSync(file)) {
220
+ const installedPackage = JSON.parse(fs.readFileSync(file, { encoding: "utf-8", flag: "r" }));
221
+ return installedPackage.version;
222
+ } else if (directory === root) {
223
+ return undefined;
224
+ } else {
225
+ directory = path.normalize(path.join(directory, ".."));
226
+ }
227
+ }
228
+ } else {
229
+ return undefined;
230
+ }
231
+ } catch {
232
+ return undefined;
233
+ }
234
+ }
235
+ };
236
+
197
237
  export const runParametersArgument = new Argument(
198
238
  "[optionKey=optionValue...]",
199
239
  "Specify one or more parameter which can be read in the simulation script with the getParameter() function; format must be key=value"
@@ -212,10 +252,15 @@ export const parseRunParametersArgument = (args: string[]): Record<string, strin
212
252
  return parsedParameters;
213
253
  };
214
254
 
215
- export const urlOption = new Option("--url <value>", "URL of Gatling Enterprise")
255
+ export const apiUrlOption = new Option("--apiUrl <value>", "URL of the Gatling Enterprise API")
256
+ .default("https://api.gatling.io")
257
+ .hideHelp();
258
+ export const apiUrlOptionValue = getStringValueMandatory(apiUrlOption);
259
+
260
+ export const webAppUrlOption = new Option("--webAppUrl <value>", "URL of the Gatling Enterprise web app")
216
261
  .default("https://cloud.gatling.io")
217
262
  .hideHelp();
218
- export const urlOptionValue = getStringValueMandatory(urlOption);
263
+ export const webAppUrlOptionValue = getStringValueMandatory(webAppUrlOption);
219
264
 
220
265
  export const apiTokenOption = new Option(
221
266
  "--api-token <value>",
@@ -9,6 +9,8 @@ import {
9
9
  nonInteractiveOption,
10
10
  nonInteractiveOptionValue,
11
11
  parseRunParametersArgument,
12
+ postmanOption,
13
+ postmanOptionValueWithDefaults,
12
14
  resourcesFolderOption,
13
15
  resourcesFolderOptionValue,
14
16
  resultsFolderOption,
@@ -41,6 +43,7 @@ export default (program: Command): void => {
41
43
  .addOption(resultsFolderOption)
42
44
  .addOption(gatlingHomeOption)
43
45
  .addOption(memoryOption)
46
+ .addOption(postmanOption)
44
47
  .addOption(nonInteractiveOption)
45
48
  .addArgument(runParametersArgument)
46
49
  .action(async (args: string[], options) => {
@@ -51,18 +54,19 @@ export default (program: Command): void => {
51
54
  const resultsFolder: string = resultsFolderOptionValue(options);
52
55
  const memory: number | undefined = memoryOptionValue(options);
53
56
  const nonInteractive: boolean = nonInteractiveOptionValue(options);
57
+ const postman = postmanOptionValueWithDefaults(options);
54
58
  const runParameters = parseRunParametersArgument(args);
55
59
 
56
60
  const simulations = await findSimulations(sourcesFolder);
57
61
  const typescript = typescriptOptionValueWithDefaults(options, simulations);
58
62
  const simulation = simulationOptionValueWithDefaults(options, simulations, !nonInteractive);
59
63
 
60
- const { graalvmHome, coursierBinary, jvmClasspath } = await installGatlingJs({ gatlingHome });
64
+ const { graalvmHome, coursierBinary, jvmClasspath } = await installGatlingJs({ gatlingHome, postman });
61
65
  logger.debug(`graalvmHome=${graalvmHome}`);
62
66
  logger.debug(`coursierBinary=${coursierBinary}`);
63
67
  logger.debug(`jvmClasspath=${jvmClasspath}`);
64
68
 
65
- await bundle({ sourcesFolder, bundleFile, typescript, simulations });
69
+ await bundle({ sourcesFolder, bundleFile, postman, typescript, simulations });
66
70
 
67
71
  await runSimulation({
68
72
  graalvmHome,
@@ -45,20 +45,22 @@ export const installCoursier = async (gatlingHomeDir: string, downloadDir: strin
45
45
  return coursierPath;
46
46
  };
47
47
 
48
- export const resolveGatlingJsDependencies = async (coursierPath: string, javaHome: string): Promise<string> => {
49
- const gatlingDep = `"io.gatling.highcharts:gatling-charts-highcharts:${versions.gatling.core}"`;
50
- const gatlingAdapterDep = `"io.gatling:gatling-jvm-to-js-adapter:${versions.gatling.jsAdapter}"`;
51
- const gatlingEnterprisePluginCommonsDep = `"io.gatling:gatling-enterprise-plugin-commons:${versions.gatling.enterprisePluginCommons}"`;
52
- const graalvmJsDep = `"org.graalvm.polyglot:js-community:${versions.graalvm.js}"`;
48
+ export const resolveGatlingJsDependencies = async (
49
+ coursierPath: string,
50
+ javaHome: string,
51
+ postmanVersion?: string
52
+ ): Promise<string> => {
53
+ const dependencies = [
54
+ `"io.gatling.highcharts:gatling-charts-highcharts:${versions.gatling.core}"`,
55
+ `"io.gatling:gatling-jvm-to-js-adapter:${versions.gatling.jsAdapter}"`,
56
+ `"io.gatling:gatling-enterprise-plugin-commons:${versions.gatling.enterprisePluginCommons}"`,
57
+ `"org.graalvm.polyglot:js-community:${versions.graalvm.js}"`
58
+ ];
59
+ if (postmanVersion !== undefined) {
60
+ dependencies.push(`"io.gatling:gatling-postman-jvm-to-js-adapter:${postmanVersion}"`);
61
+ }
53
62
 
54
- return await resolveDependencies(
55
- coursierPath,
56
- javaHome,
57
- gatlingDep,
58
- gatlingAdapterDep,
59
- gatlingEnterprisePluginCommonsDep,
60
- graalvmJsDep
61
- );
63
+ return await resolveDependencies(coursierPath, javaHome, ...dependencies);
62
64
  };
63
65
 
64
66
  export const resolveRecorderDependencies = async (coursierPath: string, javaHome: string): Promise<string> => {
@@ -7,6 +7,7 @@ export { versions } from "./versions";
7
7
 
8
8
  export interface DependenciesOptions {
9
9
  gatlingHome: string;
10
+ postman?: string;
10
11
  }
11
12
 
12
13
  export interface ResolvedDependencies {
@@ -21,7 +22,7 @@ export const installGatlingJs = async (options: DependenciesOptions): Promise<Re
21
22
 
22
23
  const graalvmHomePath = await installGraalVm(options.gatlingHome, downloadDir);
23
24
  const coursierPath = await installCoursier(options.gatlingHome, downloadDir);
24
- const classpath = await resolveGatlingJsDependencies(coursierPath, graalvmHomePath);
25
+ const classpath = await resolveGatlingJsDependencies(coursierPath, graalvmHomePath, options.postman);
25
26
  return {
26
27
  graalvmHome: graalvmHomePath,
27
28
  coursierBinary: coursierPath,
@@ -1,12 +1,15 @@
1
1
  export const versions = {
2
2
  graalvm: {
3
- jdk: "22.0.2",
4
- js: "24.0.2"
3
+ jdk: "23.0.0",
4
+ js: "24.1.1"
5
5
  },
6
- coursier: "2.1.10",
6
+ java: {
7
+ compilerRelease: "21"
8
+ },
9
+ coursier: "2.1.12",
7
10
  gatling: {
8
- core: "3.12.0",
9
- enterprisePluginCommons: "1.9.6",
10
- jsAdapter: "3.12.0"
11
+ core: "3.13.1",
12
+ enterprisePluginCommons: "1.9.8",
13
+ jsAdapter: "3.13.1"
11
14
  }
12
15
  };
package/src/enterprise.ts CHANGED
@@ -54,7 +54,7 @@ const generateManifest = (simulationNames: string[]) => {
54
54
  "Gatling-Packager: js-cli",
55
55
  `Gatling-Packager-Version: ${versions.gatling.jsAdapter}`,
56
56
  `Gatling-Simulations: ${simulationNames.join(",")}`,
57
- `Java-Version: ${versions.graalvm.jdk.split(".")[0]}`
57
+ `Java-Version: ${versions.java.compilerRelease}`
58
58
  ];
59
59
  const pkg = getPackageNameAndVersion();
60
60
  lines.push(`Implementation-Title: ${pkg.name}`);
@@ -124,7 +124,8 @@ export interface EnterprisePluginOptions extends RunJavaProcessOptions {
124
124
  resourcesFolder: string;
125
125
  resultsFolder: string;
126
126
  // Base
127
- url: string;
127
+ apiUrl: string;
128
+ webAppUrl: string;
128
129
  apiToken?: string;
129
130
  // Plugin configuration
130
131
  controlPlaneUrl?: string;
@@ -135,7 +136,8 @@ const javaArgsFromPluginOptions = (options: EnterprisePluginOptions) => {
135
136
  const javaArgs: string[] = [];
136
137
 
137
138
  // Base
138
- javaArgs.push(`-Dgatling.enterprise.url=${options.url}`);
139
+ javaArgs.push(`-Dgatling.enterprise.apiUrl=${options.apiUrl}`);
140
+ javaArgs.push(`-Dgatling.enterprise.webAppUrl=${options.webAppUrl}`);
139
141
  if (options.apiToken !== undefined) {
140
142
  javaArgs.push(`-Dgatling.enterprise.apiToken=${options.apiToken}`);
141
143
  }
@@ -1,7 +1,8 @@
1
- import { SimulationFile } from "./simulations";
1
+ import { SimulationFile } from "../simulations";
2
2
  export interface BundleOptions {
3
3
  sourcesFolder: string;
4
4
  bundleFile: string;
5
+ postman?: string;
5
6
  typescript: boolean;
6
7
  simulations: SimulationFile[];
7
8
  }
@@ -29,7 +29,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.bundle = void 0;
30
30
  const esbuild = __importStar(require("esbuild"));
31
31
  const esbuild_plugin_tsc_1 = __importDefault(require("esbuild-plugin-tsc"));
32
- const log_1 = require("./log");
32
+ const polyfill_1 = require("./polyfill");
33
+ const log_1 = require("../log");
33
34
  const bundle = async (options) => {
34
35
  log_1.logger.info(`Bundling a Gatling simulation with options:
35
36
  - sourcesFolder: ${options.sourcesFolder}
@@ -37,12 +38,17 @@ const bundle = async (options) => {
37
38
  - typescript: ${options.typescript}`);
38
39
  const contents = options.simulations.map((s) => `export { default as "${s.name}" } from "./${s.path}";`).join("\n");
39
40
  const plugins = options.typescript ? [(0, esbuild_plugin_tsc_1.default)({ force: true })] : [];
41
+ if (options.postman !== undefined) {
42
+ plugins.push((0, polyfill_1.polyfill)());
43
+ }
40
44
  await esbuild.build({
41
45
  stdin: {
42
46
  contents,
43
47
  resolveDir: options.sourcesFolder
44
48
  },
45
49
  outfile: options.bundleFile,
50
+ platform: "neutral",
51
+ mainFields: ["main", "module"],
46
52
  bundle: true,
47
53
  minify: false,
48
54
  sourcemap: true,
@@ -0,0 +1,2 @@
1
+ import type { Plugin } from "esbuild";
2
+ export declare const polyfill: () => Plugin;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.polyfill = void 0;
4
+ const url_1 = require("url");
5
+ const path_1 = require("path");
6
+ // This is largely inspired by https://github.com/cyco130/esbuild-plugin-polyfill-node
7
+ const polyfill = () => ({
8
+ name: "gatling-js-polyfill",
9
+ setup: async (build) => {
10
+ // modules
11
+ const jspmResolved = await resolveImport(`@jspm/core/nodelibs/fs`);
12
+ build.onResolve({ filter: polyfillsFilter }, async ({ path }) => {
13
+ const [, , moduleName] = path.match(polyfillsFilter);
14
+ const resolved = customPolyfills.find((name) => name === moduleName)
15
+ ? (0, path_1.resolve)((0, path_1.dirname)(__filename), `../../polyfills/${moduleName}.js`)
16
+ : (0, path_1.resolve)(jspmResolved, `../../browser/${moduleName}.js`);
17
+ return { path: resolved };
18
+ });
19
+ // Globals
20
+ build.initialOptions.inject = build.initialOptions.inject || [];
21
+ const injectGlobal = (name) => build.initialOptions.inject.push((0, path_1.resolve)((0, path_1.dirname)(__filename), `../../polyfills/${name}.js`));
22
+ injectGlobal("global");
23
+ }
24
+ });
25
+ exports.polyfill = polyfill;
26
+ const customPolyfills = ["crypto"];
27
+ const jspmPolyfills = ["buffer", "path", "string_decoder"];
28
+ // Other available jspm-core modules:
29
+ // "_stream_duplex"
30
+ // "_stream_passthrough"
31
+ // "_stream_readable"
32
+ // "_stream_transform"
33
+ // "_stream_writable"
34
+ // "assert"
35
+ // "assert/strict"
36
+ // "async_hooks"
37
+ // "child_process"
38
+ // "cluster"
39
+ // "console"
40
+ // "constants"
41
+ // "crypto"
42
+ // "dgram"
43
+ // "diagnostics_channel"
44
+ // "dns"
45
+ // "domain"
46
+ // "events"
47
+ // "fs"
48
+ // "fs/promises"
49
+ // "http"
50
+ // "http2"
51
+ // "https"
52
+ // "module"
53
+ // "net"
54
+ // "os"
55
+ // "perf_hooks"
56
+ // "process"
57
+ // "punycode"
58
+ // "querystring"
59
+ // "readline"
60
+ // "repl"
61
+ // "stream"
62
+ // "sys"
63
+ // "timers"
64
+ // "timers/promises"
65
+ // "tls"
66
+ // "tty"
67
+ // "url"
68
+ // "util"
69
+ // "v8"
70
+ // "vm"
71
+ // "wasi"
72
+ // "worker_threads"
73
+ // "zlib"
74
+ const polyfillsFilter = new RegExp(`^(node:)?(${jspmPolyfills.concat(customPolyfills).join("|")})$`);
75
+ let importMetaResolve;
76
+ const importMetaUrl = (0, url_1.pathToFileURL)(__filename).href;
77
+ const resolveImport = async (specifier) => {
78
+ if (!importMetaResolve) {
79
+ importMetaResolve = (await import("import-meta-resolve")).resolve;
80
+ }
81
+ const resolved = importMetaResolve(specifier, importMetaUrl);
82
+ return (0, url_1.fileURLToPath)(resolved);
83
+ };
@@ -9,12 +9,14 @@ exports.default = (program) => {
9
9
  .description("Build Gatling simulations")
10
10
  .addOption(options_1.sourcesFolderOption)
11
11
  .addOption(options_1.bundleFileOption)
12
+ .addOption(options_1.postmanOption)
12
13
  .addOption(options_1.typescriptOption)
13
14
  .action(async (options) => {
14
15
  const sourcesFolder = (0, options_1.sourcesFolderOptionValue)(options);
15
16
  const bundleFile = (0, options_1.bundleFileOptionValue)(options);
16
17
  const simulations = await (0, simulations_1.findSimulations)(sourcesFolder);
18
+ const postman = (0, options_1.postmanOptionValueWithDefaults)(options);
17
19
  const typescript = (0, options_1.typescriptOptionValueWithDefaults)(options, simulations);
18
- await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, typescript, simulations });
20
+ await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, postman, typescript, simulations });
19
21
  });
20
22
  };
@@ -13,10 +13,12 @@ exports.default = (program) => {
13
13
  .addOption(options_1.resourcesFolderOption)
14
14
  .addOption(options_1.bundleFileOption)
15
15
  .addOption(options_1.resultsFolderOption)
16
+ .addOption(options_1.postmanOption)
16
17
  .addOption(options_1.typescriptOption)
17
18
  .addOption(options_1.gatlingHomeOption)
18
19
  // Base
19
- .addOption(options_1.urlOption)
20
+ .addOption(options_1.apiUrlOption)
21
+ .addOption(options_1.webAppUrlOption)
20
22
  .addOption(options_1.apiTokenOption)
21
23
  // Plugin configuration
22
24
  .addOption(options_1.controlPlaneUrlOption)
@@ -28,19 +30,21 @@ exports.default = (program) => {
28
30
  .action(async (options) => {
29
31
  const sourcesFolder = (0, options_1.sourcesFolderOptionValue)(options);
30
32
  const simulations = await (0, simulations_1.findSimulations)(sourcesFolder);
33
+ const postman = (0, options_1.postmanOptionValueWithDefaults)(options);
31
34
  const typescript = (0, options_1.typescriptOptionValueWithDefaults)(options, simulations);
32
35
  const resourcesFolder = (0, options_1.resourcesFolderOptionValue)(options);
33
36
  const bundleFile = (0, options_1.bundleFileOptionValue)(options);
34
37
  const resultsFolder = (0, options_1.resultsFolderOptionValue)(options);
35
38
  const gatlingHome = (0, options_1.gatlingHomeOptionValueWithDefaults)(options);
36
- const url = (0, options_1.urlOptionValue)(options);
39
+ const apiUrl = (0, options_1.apiUrlOptionValue)(options);
40
+ const webAppUrl = (0, options_1.webAppUrlOptionValue)(options);
37
41
  const apiToken = (0, options_1.apiTokenOptionValue)(options);
38
42
  const controlPlaneUrl = (0, options_1.controlPlaneUrlOptionValue)(options);
39
43
  const nonInteractive = (0, options_1.nonInteractiveOptionValue)(options);
40
44
  const packageDescriptorFilename = (0, options_1.packageDescriptorFilenameOptionValue)(options);
41
45
  const packageFile = (0, options_1.packageFileOptionValue)(options);
42
46
  const { graalvmHome, jvmClasspath } = await (0, dependencies_1.installGatlingJs)({ gatlingHome });
43
- await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, typescript, simulations });
47
+ await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, postman, typescript, simulations });
44
48
  await (0, enterprise_1.enterprisePackage)({ bundleFile, resourcesFolder, packageFile, simulations });
45
49
  await (0, enterprise_1.enterpriseDeploy)({
46
50
  graalvmHome,
@@ -48,7 +52,8 @@ exports.default = (program) => {
48
52
  bundleFile,
49
53
  resourcesFolder,
50
54
  resultsFolder,
51
- url,
55
+ apiUrl,
56
+ webAppUrl,
52
57
  apiToken,
53
58
  controlPlaneUrl,
54
59
  nonInteractive,
@@ -12,6 +12,7 @@ exports.default = (program) => {
12
12
  .addOption(options_1.resourcesFolderOption)
13
13
  .addOption(options_1.bundleFileOption)
14
14
  .addOption(options_1.packageFileOption)
15
+ .addOption(options_1.postmanOption)
15
16
  .addOption(options_1.typescriptOption)
16
17
  .action(async (options) => {
17
18
  const sourcesFolder = (0, options_1.sourcesFolderOptionValue)(options);
@@ -19,8 +20,9 @@ exports.default = (program) => {
19
20
  const bundleFile = (0, options_1.bundleFileOptionValue)(options);
20
21
  const packageFile = (0, options_1.packageFileOptionValue)(options);
21
22
  const simulations = await (0, simulations_1.findSimulations)(sourcesFolder);
23
+ const postman = (0, options_1.postmanOptionValueWithDefaults)(options);
22
24
  const typescript = (0, options_1.typescriptOptionValueWithDefaults)(options, simulations);
23
- await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, typescript, simulations });
25
+ await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, postman, typescript, simulations });
24
26
  await (0, enterprise_1.enterprisePackage)({ bundleFile, resourcesFolder, packageFile, simulations });
25
27
  });
26
28
  };
@@ -13,10 +13,12 @@ exports.default = (program) => {
13
13
  .addOption(options_1.resourcesFolderOption)
14
14
  .addOption(options_1.bundleFileOption)
15
15
  .addOption(options_1.resultsFolderOption)
16
+ .addOption(options_1.postmanOption)
16
17
  .addOption(options_1.typescriptOption)
17
18
  .addOption(options_1.gatlingHomeOption)
18
19
  // Base
19
- .addOption(options_1.urlOption)
20
+ .addOption(options_1.apiUrlOption)
21
+ .addOption(options_1.webAppUrlOption)
20
22
  .addOption(options_1.apiTokenOption)
21
23
  // Plugin configuration
22
24
  .addOption(options_1.controlPlaneUrlOption)
@@ -33,12 +35,14 @@ exports.default = (program) => {
33
35
  .action(async (options) => {
34
36
  const sourcesFolder = (0, options_1.sourcesFolderOptionValue)(options);
35
37
  const simulations = await (0, simulations_1.findSimulations)(sourcesFolder);
38
+ const postman = (0, options_1.postmanOptionValueWithDefaults)(options);
36
39
  const typescript = (0, options_1.typescriptOptionValueWithDefaults)(options, simulations);
37
40
  const resourcesFolder = (0, options_1.resourcesFolderOptionValue)(options);
38
41
  const bundleFile = (0, options_1.bundleFileOptionValue)(options);
39
42
  const resultsFolder = (0, options_1.resultsFolderOptionValue)(options);
40
43
  const gatlingHome = (0, options_1.gatlingHomeOptionValueWithDefaults)(options);
41
- const url = (0, options_1.urlOptionValue)(options);
44
+ const apiUrl = (0, options_1.apiUrlOptionValue)(options);
45
+ const webAppUrl = (0, options_1.webAppUrlOptionValue)(options);
42
46
  const apiToken = (0, options_1.apiTokenOptionValue)(options);
43
47
  const controlPlaneUrl = (0, options_1.controlPlaneUrlOptionValue)(options);
44
48
  const nonInteractive = (0, options_1.nonInteractiveOptionValue)(options);
@@ -52,7 +56,7 @@ exports.default = (program) => {
52
56
  throw new Error(`No simulation specified when using non-interactive mode`);
53
57
  }
54
58
  const { graalvmHome, jvmClasspath } = await (0, dependencies_1.installGatlingJs)({ gatlingHome });
55
- await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, typescript, simulations });
59
+ await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, postman, typescript, simulations });
56
60
  await (0, enterprise_1.enterprisePackage)({ bundleFile, resourcesFolder, packageFile, simulations });
57
61
  await (0, enterprise_1.enterpriseStart)({
58
62
  graalvmHome,
@@ -60,7 +64,8 @@ exports.default = (program) => {
60
64
  bundleFile,
61
65
  resourcesFolder,
62
66
  resultsFolder,
63
- url,
67
+ apiUrl,
68
+ webAppUrl,
64
69
  apiToken,
65
70
  controlPlaneUrl,
66
71
  nonInteractive,
@@ -26,10 +26,14 @@ export declare const memoryOption: Option;
26
26
  export declare const memoryOptionValue: (options: any) => number | undefined;
27
27
  export declare const nonInteractiveOption: Option;
28
28
  export declare const nonInteractiveOptionValue: (options: any) => boolean;
29
+ export declare const postmanOption: Option;
30
+ export declare const postmanOptionValueWithDefaults: (options: any) => string | undefined;
29
31
  export declare const runParametersArgument: Argument;
30
32
  export declare const parseRunParametersArgument: (args: string[]) => Record<string, string>;
31
- export declare const urlOption: Option;
32
- export declare const urlOptionValue: (options: any) => string;
33
+ export declare const apiUrlOption: Option;
34
+ export declare const apiUrlOptionValue: (options: any) => string;
35
+ export declare const webAppUrlOption: Option;
36
+ export declare const webAppUrlOptionValue: (options: any) => string;
33
37
  export declare const apiTokenOption: Option;
34
38
  export declare const apiTokenOptionValue: (options: any) => string | undefined;
35
39
  export declare const controlPlaneUrlOption: Option;
@@ -3,9 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.waitForRunEndOptionValue = exports.waitForRunEndOption = exports.runDescriptionOptionValue = exports.runDescriptionOption = exports.runTitleOptionValue = exports.runTitleOption = exports.enterpriseSimulationOptionValue = exports.enterpriseSimulationOption = exports.packageDescriptorFilenameOptionValue = exports.packageDescriptorFilenameOption = exports.controlPlaneUrlOptionValue = exports.controlPlaneUrlOption = exports.apiTokenOptionValue = exports.apiTokenOption = exports.urlOptionValue = exports.urlOption = exports.parseRunParametersArgument = exports.runParametersArgument = exports.nonInteractiveOptionValue = exports.nonInteractiveOption = exports.memoryOptionValue = exports.memoryOption = exports.jvmClasspathMandatoryOptionValue = exports.jvmClasspathMandatoryOption = exports.graalvmHomeMandatoryOptionValue = exports.graalvmHomeMandatoryOption = exports.typescriptOptionValueWithDefaults = exports.typescriptOption = exports.resultsFolderOptionValue = exports.resultsFolderOption = exports.resourcesFolderOptionValue = exports.resourcesFolderOption = exports.packageFileOptionValue = exports.packageFileOption = exports.bundleFileOptionValue = exports.bundleFileOption = exports.simulationMandatoryOptionValue = exports.simulationMandatoryOption = exports.simulationOptionValueWithDefaults = exports.simulationOption = exports.sourcesFolderOptionValue = exports.sourcesFolderOption = exports.gatlingHomeOptionValueWithDefaults = exports.gatlingHomeOption = void 0;
6
+ exports.waitForRunEndOptionValue = exports.waitForRunEndOption = exports.runDescriptionOptionValue = exports.runDescriptionOption = exports.runTitleOptionValue = exports.runTitleOption = exports.enterpriseSimulationOptionValue = exports.enterpriseSimulationOption = exports.packageDescriptorFilenameOptionValue = exports.packageDescriptorFilenameOption = exports.controlPlaneUrlOptionValue = exports.controlPlaneUrlOption = exports.apiTokenOptionValue = exports.apiTokenOption = exports.webAppUrlOptionValue = exports.webAppUrlOption = exports.apiUrlOptionValue = exports.apiUrlOption = exports.parseRunParametersArgument = exports.runParametersArgument = exports.postmanOptionValueWithDefaults = exports.postmanOption = exports.nonInteractiveOptionValue = exports.nonInteractiveOption = exports.memoryOptionValue = exports.memoryOption = exports.jvmClasspathMandatoryOptionValue = exports.jvmClasspathMandatoryOption = exports.graalvmHomeMandatoryOptionValue = exports.graalvmHomeMandatoryOption = exports.typescriptOptionValueWithDefaults = exports.typescriptOption = exports.resultsFolderOptionValue = exports.resultsFolderOption = exports.resourcesFolderOptionValue = exports.resourcesFolderOption = exports.packageFileOptionValue = exports.packageFileOption = exports.bundleFileOptionValue = exports.bundleFileOption = exports.simulationMandatoryOptionValue = exports.simulationMandatoryOption = exports.simulationOptionValueWithDefaults = exports.simulationOption = exports.sourcesFolderOptionValue = exports.sourcesFolderOption = exports.gatlingHomeOptionValueWithDefaults = exports.gatlingHomeOption = void 0;
7
7
  const commander_1 = require("commander");
8
+ const fs_1 = __importDefault(require("fs"));
8
9
  const os_1 = __importDefault(require("os"));
10
+ const path_1 = __importDefault(require("path"));
9
11
  const readline_1 = require("../readline");
10
12
  const log_1 = require("../log");
11
13
  const getStringValueOptional = (option) => (options) => {
@@ -71,9 +73,10 @@ const simulationOptionValueWithDefaults = (options, simulationsFound, interactiv
71
73
  throw new Error("No simulation found, simulations must be defined in a <simulation name>.gatling.js or <simulation name>.gatling.ts file)");
72
74
  }
73
75
  else if (interactive) {
74
- const idx = (0, readline_1.keyInSelectPaginated)(simulationsFound.map((s) => s.name).sort((a, b) => a.localeCompare(b)), "Choose a simulation to run");
76
+ const sortedSimulations = simulationsFound.sort((a, b) => a.name.localeCompare(b.name));
77
+ const idx = (0, readline_1.keyInSelectPaginated)(sortedSimulations.map((s) => s.name), "Choose a simulation to run");
75
78
  if (idx >= 0) {
76
- const simulation = simulationsFound[idx].name;
79
+ const simulation = sortedSimulations[idx].name;
77
80
  log_1.logger.info(`Simulation '${simulation}' was chosen.`);
78
81
  return simulation;
79
82
  }
@@ -130,6 +133,44 @@ exports.memoryOption = new commander_1.Option("--memory <value>", "Heap space me
130
133
  exports.memoryOptionValue = getNumberValueOptional(exports.memoryOption);
131
134
  exports.nonInteractiveOption = new commander_1.Option("--non-interactive", "Switch to non-interactive mode and fail if no simulation is explicitly specified").default(false);
132
135
  exports.nonInteractiveOptionValue = getBooleanValueMandatory(exports.nonInteractiveOption);
136
+ exports.postmanOption = new commander_1.Option("--postman <version>", "Postman compatibility option: adds polyfills, etc.").hideHelp();
137
+ const postmanOptionValueWithDefaults = (options) => {
138
+ const postmanOptionValue = getStringValueOptional(exports.postmanOption)(options);
139
+ if (postmanOptionValue !== undefined) {
140
+ return postmanOptionValue;
141
+ }
142
+ else {
143
+ try {
144
+ const conf = JSON.parse(fs_1.default.readFileSync("package.json", { encoding: "utf-8", flag: "r" }));
145
+ const withPostman = conf.dependencies?.["@gatling.io/postman"] !== undefined ||
146
+ conf.devDependencies?.["@gatling.io/postman"] !== undefined;
147
+ if (withPostman) {
148
+ let directory = path_1.default.normalize(path_1.default.dirname("package.json"));
149
+ const root = path_1.default.parse(directory).root;
150
+ while (true) {
151
+ const file = path_1.default.join(directory, "node_modules", "@gatling.io", "postman", "package.json");
152
+ if (fs_1.default.existsSync(file)) {
153
+ const installedPackage = JSON.parse(fs_1.default.readFileSync(file, { encoding: "utf-8", flag: "r" }));
154
+ return installedPackage.version;
155
+ }
156
+ else if (directory === root) {
157
+ return undefined;
158
+ }
159
+ else {
160
+ directory = path_1.default.normalize(path_1.default.join(directory, ".."));
161
+ }
162
+ }
163
+ }
164
+ else {
165
+ return undefined;
166
+ }
167
+ }
168
+ catch {
169
+ return undefined;
170
+ }
171
+ }
172
+ };
173
+ exports.postmanOptionValueWithDefaults = postmanOptionValueWithDefaults;
133
174
  exports.runParametersArgument = new commander_1.Argument("[optionKey=optionValue...]", "Specify one or more parameter which can be read in the simulation script with the getParameter() function; format must be key=value");
134
175
  const parseRunParametersArgument = (args) => {
135
176
  const parsedParameters = {};
@@ -146,10 +187,14 @@ const parseRunParametersArgument = (args) => {
146
187
  return parsedParameters;
147
188
  };
148
189
  exports.parseRunParametersArgument = parseRunParametersArgument;
149
- exports.urlOption = new commander_1.Option("--url <value>", "URL of Gatling Enterprise")
190
+ exports.apiUrlOption = new commander_1.Option("--apiUrl <value>", "URL of the Gatling Enterprise API")
191
+ .default("https://api.gatling.io")
192
+ .hideHelp();
193
+ exports.apiUrlOptionValue = getStringValueMandatory(exports.apiUrlOption);
194
+ exports.webAppUrlOption = new commander_1.Option("--webAppUrl <value>", "URL of the Gatling Enterprise web app")
150
195
  .default("https://cloud.gatling.io")
151
196
  .hideHelp();
152
- exports.urlOptionValue = getStringValueMandatory(exports.urlOption);
197
+ exports.webAppUrlOptionValue = getStringValueMandatory(exports.webAppUrlOption);
153
198
  exports.apiTokenOption = new commander_1.Option("--api-token <value>", "API Token on Gatling Enterprise. Prefer configuration using `GATLING_ENTERPRISE_API_TOKEN` environment variable.");
154
199
  exports.apiTokenOptionValue = getStringValueOptional(exports.apiTokenOption);
155
200
  // Plugin configuration
@@ -18,6 +18,7 @@ exports.default = (program) => {
18
18
  .addOption(options_1.resultsFolderOption)
19
19
  .addOption(options_1.gatlingHomeOption)
20
20
  .addOption(options_1.memoryOption)
21
+ .addOption(options_1.postmanOption)
21
22
  .addOption(options_1.nonInteractiveOption)
22
23
  .addArgument(options_1.runParametersArgument)
23
24
  .action(async (args, options) => {
@@ -28,15 +29,16 @@ exports.default = (program) => {
28
29
  const resultsFolder = (0, options_1.resultsFolderOptionValue)(options);
29
30
  const memory = (0, options_1.memoryOptionValue)(options);
30
31
  const nonInteractive = (0, options_1.nonInteractiveOptionValue)(options);
32
+ const postman = (0, options_1.postmanOptionValueWithDefaults)(options);
31
33
  const runParameters = (0, options_1.parseRunParametersArgument)(args);
32
34
  const simulations = await (0, simulations_1.findSimulations)(sourcesFolder);
33
35
  const typescript = (0, options_1.typescriptOptionValueWithDefaults)(options, simulations);
34
36
  const simulation = (0, options_1.simulationOptionValueWithDefaults)(options, simulations, !nonInteractive);
35
- const { graalvmHome, coursierBinary, jvmClasspath } = await (0, dependencies_1.installGatlingJs)({ gatlingHome });
37
+ const { graalvmHome, coursierBinary, jvmClasspath } = await (0, dependencies_1.installGatlingJs)({ gatlingHome, postman });
36
38
  log_1.logger.debug(`graalvmHome=${graalvmHome}`);
37
39
  log_1.logger.debug(`coursierBinary=${coursierBinary}`);
38
40
  log_1.logger.debug(`jvmClasspath=${jvmClasspath}`);
39
- await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, typescript, simulations });
41
+ await (0, bundle_1.bundle)({ sourcesFolder, bundleFile, postman, typescript, simulations });
40
42
  await (0, run_1.runSimulation)({
41
43
  graalvmHome,
42
44
  jvmClasspath,
@@ -1,3 +1,3 @@
1
1
  export declare const installCoursier: (gatlingHomeDir: string, downloadDir: string) => Promise<string>;
2
- export declare const resolveGatlingJsDependencies: (coursierPath: string, javaHome: string) => Promise<string>;
2
+ export declare const resolveGatlingJsDependencies: (coursierPath: string, javaHome: string, postmanVersion?: string) => Promise<string>;
3
3
  export declare const resolveRecorderDependencies: (coursierPath: string, javaHome: string) => Promise<string>;
@@ -46,12 +46,17 @@ const installCoursier = async (gatlingHomeDir, downloadDir) => {
46
46
  return coursierPath;
47
47
  };
48
48
  exports.installCoursier = installCoursier;
49
- const resolveGatlingJsDependencies = async (coursierPath, javaHome) => {
50
- const gatlingDep = `"io.gatling.highcharts:gatling-charts-highcharts:${versions_1.versions.gatling.core}"`;
51
- const gatlingAdapterDep = `"io.gatling:gatling-jvm-to-js-adapter:${versions_1.versions.gatling.jsAdapter}"`;
52
- const gatlingEnterprisePluginCommonsDep = `"io.gatling:gatling-enterprise-plugin-commons:${versions_1.versions.gatling.enterprisePluginCommons}"`;
53
- const graalvmJsDep = `"org.graalvm.polyglot:js-community:${versions_1.versions.graalvm.js}"`;
54
- return await resolveDependencies(coursierPath, javaHome, gatlingDep, gatlingAdapterDep, gatlingEnterprisePluginCommonsDep, graalvmJsDep);
49
+ const resolveGatlingJsDependencies = async (coursierPath, javaHome, postmanVersion) => {
50
+ const dependencies = [
51
+ `"io.gatling.highcharts:gatling-charts-highcharts:${versions_1.versions.gatling.core}"`,
52
+ `"io.gatling:gatling-jvm-to-js-adapter:${versions_1.versions.gatling.jsAdapter}"`,
53
+ `"io.gatling:gatling-enterprise-plugin-commons:${versions_1.versions.gatling.enterprisePluginCommons}"`,
54
+ `"org.graalvm.polyglot:js-community:${versions_1.versions.graalvm.js}"`
55
+ ];
56
+ if (postmanVersion !== undefined) {
57
+ dependencies.push(`"io.gatling:gatling-postman-jvm-to-js-adapter:${postmanVersion}"`);
58
+ }
59
+ return await resolveDependencies(coursierPath, javaHome, ...dependencies);
55
60
  };
56
61
  exports.resolveGatlingJsDependencies = resolveGatlingJsDependencies;
57
62
  const resolveRecorderDependencies = async (coursierPath, javaHome) => {
@@ -1,6 +1,7 @@
1
1
  export { versions } from "./versions";
2
2
  export interface DependenciesOptions {
3
3
  gatlingHome: string;
4
+ postman?: string;
4
5
  }
5
6
  export interface ResolvedDependencies {
6
7
  graalvmHome: string;
@@ -14,7 +14,7 @@ const installGatlingJs = async (options) => {
14
14
  await promises_1.default.mkdir(downloadDir, { recursive: true });
15
15
  const graalvmHomePath = await (0, graalVm_1.installGraalVm)(options.gatlingHome, downloadDir);
16
16
  const coursierPath = await (0, coursier_1.installCoursier)(options.gatlingHome, downloadDir);
17
- const classpath = await (0, coursier_1.resolveGatlingJsDependencies)(coursierPath, graalvmHomePath);
17
+ const classpath = await (0, coursier_1.resolveGatlingJsDependencies)(coursierPath, graalvmHomePath, options.postman);
18
18
  return {
19
19
  graalvmHome: graalvmHomePath,
20
20
  coursierBinary: coursierPath,
@@ -3,6 +3,9 @@ export declare const versions: {
3
3
  jdk: string;
4
4
  js: string;
5
5
  };
6
+ java: {
7
+ compilerRelease: string;
8
+ };
6
9
  coursier: string;
7
10
  gatling: {
8
11
  core: string;
@@ -3,13 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.versions = void 0;
4
4
  exports.versions = {
5
5
  graalvm: {
6
- jdk: "22.0.2",
7
- js: "24.0.2"
6
+ jdk: "23.0.0",
7
+ js: "24.1.1"
8
8
  },
9
- coursier: "2.1.10",
9
+ java: {
10
+ compilerRelease: "21"
11
+ },
12
+ coursier: "2.1.12",
10
13
  gatling: {
11
- core: "3.12.0",
12
- enterprisePluginCommons: "1.9.6",
13
- jsAdapter: "3.12.0"
14
+ core: "3.13.1",
15
+ enterprisePluginCommons: "1.9.8",
16
+ jsAdapter: "3.13.1"
14
17
  }
15
18
  };
@@ -11,7 +11,8 @@ export interface EnterprisePluginOptions extends RunJavaProcessOptions {
11
11
  bundleFile: string;
12
12
  resourcesFolder: string;
13
13
  resultsFolder: string;
14
- url: string;
14
+ apiUrl: string;
15
+ webAppUrl: string;
15
16
  apiToken?: string;
16
17
  controlPlaneUrl?: string;
17
18
  nonInteractive: boolean;
@@ -45,7 +45,7 @@ const generateManifest = (simulationNames) => {
45
45
  "Gatling-Packager: js-cli",
46
46
  `Gatling-Packager-Version: ${dependencies_1.versions.gatling.jsAdapter}`,
47
47
  `Gatling-Simulations: ${simulationNames.join(",")}`,
48
- `Java-Version: ${dependencies_1.versions.graalvm.jdk.split(".")[0]}`
48
+ `Java-Version: ${dependencies_1.versions.java.compilerRelease}`
49
49
  ];
50
50
  const pkg = getPackageNameAndVersion();
51
51
  lines.push(`Implementation-Title: ${pkg.name}`);
@@ -110,7 +110,8 @@ const getPackageNameAndVersion = () => {
110
110
  const javaArgsFromPluginOptions = (options) => {
111
111
  const javaArgs = [];
112
112
  // Base
113
- javaArgs.push(`-Dgatling.enterprise.url=${options.url}`);
113
+ javaArgs.push(`-Dgatling.enterprise.apiUrl=${options.apiUrl}`);
114
+ javaArgs.push(`-Dgatling.enterprise.webAppUrl=${options.webAppUrl}`);
114
115
  if (options.apiToken !== undefined) {
115
116
  javaArgs.push(`-Dgatling.enterprise.apiToken=${options.apiToken}`);
116
117
  }