@shopify/oxygen-cli 4.0.4-unstable.202402091547.0 → 4.1.0

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/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # @shopify/oxygen-cli
2
2
 
3
- ## 4.0.3
3
+ ## 4.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 85a58a1: Add new metrics and fix messaging
4
8
 
5
9
  ### Patch Changes
6
10
 
@@ -9,6 +13,9 @@
9
13
  - 2695e1d: Update vite from 5.0.12 to 5.1.0
10
14
  - 9e0a84b: Update @types/node from 20.11.16 to 20.11.17
11
15
  - b75cbb6: Update vite from 5.1.0 to 5.1.1
16
+ - 7c4e966: Add `--environmentFile` flag
17
+
18
+ Optionally provide the path to a local .env file to override the environment variables set on Admin.
12
19
 
13
20
  ## 4.0.2
14
21
 
package/README.md CHANGED
@@ -55,6 +55,7 @@ oxygen:deploy [options]
55
55
  - `--metadataVersion`: A version identifier for the deployment.
56
56
  - `--disableBugsnag`: Disable Bugsnag error reporting.
57
57
  - `--generateAuthBypassToken`: Generate an auth bypass token used to perform end-to-end testing against the deployment.
58
+ - `--environmentFile`: Path to an environment file to override existing environment variables for the deployment.
58
59
 
59
60
  **Note**: All metadata options (`--metadataDescription`, `--metadataUrl`, `--metadataUser`, and `--metadataVersion`) have a maximum character limit of 375.
60
61
 
@@ -22,6 +22,7 @@ declare class Deploy extends Command {
22
22
  metadataUser: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
23
23
  metadataVersion: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
24
24
  generateAuthBypassToken: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
25
+ environmentFile: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
25
26
  };
26
27
  static hasCustomBuildCommand: boolean;
27
28
  run(): Promise<void>;
@@ -4,6 +4,7 @@ import { normalizePath } from '@shopify/cli-kit/node/path';
4
4
  import { initializeBugsnag, getBugsnag } from '../../utils/bugsnag.js';
5
5
  import { createDeploy } from '../../deploy/index.js';
6
6
  import { deployDefaults, parseToken, verifyConfig, getBuildCommandFromLockFile } from '../../utils/utils.js';
7
+ import { loadEnvironmentVariableFile } from '../../utils/dotenv.js';
7
8
  import { VerificationError } from '../../deploy/types.js';
8
9
 
9
10
  class Deploy extends Command {
@@ -110,6 +111,10 @@ class Deploy extends Command {
110
111
  description: "Generate an auth bypass token used to perform end-to-end testing against the deployment.",
111
112
  required: false,
112
113
  default: false
114
+ }),
115
+ environmentFile: Flags.string({
116
+ description: "Path to an environment file to override existing environment variables for the deployment.",
117
+ required: false
113
118
  })
114
119
  };
115
120
  static hasCustomBuildCommand = false;
@@ -117,6 +122,7 @@ class Deploy extends Command {
117
122
  try {
118
123
  const { flags } = await this.parse(Deploy);
119
124
  const rootPath = normalizePath(flags.path);
125
+ const overriddenEnvironmentVariables = flags.environmentFile ? loadEnvironmentVariableFile(flags.environmentFile) : void 0;
120
126
  initializeBugsnag(flags.disableBugsnag);
121
127
  const Bugsnag = getBugsnag();
122
128
  const deploymentUrl = (
@@ -147,7 +153,8 @@ class Deploy extends Command {
147
153
  skipVerification: flags.skipVerification,
148
154
  workerDir: normalizePath(flags.workerFolder),
149
155
  workerOnly: flags.workerOnly,
150
- generateAuthBypassToken: flags.generateAuthBypassToken
156
+ generateAuthBypassToken: flags.generateAuthBypassToken,
157
+ overriddenEnvironmentVariables
151
158
  };
152
159
  await verifyConfig({ config });
153
160
  if (!Deploy.hasCustomBuildCommand && !config.skipBuild) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/oxygen/deploy.ts"],"names":[],"mappings":"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","sourcesContent":["import {Command, Flags} from '@oclif/core';\nimport {consoleError} from '@shopify/cli-kit/node/output';\nimport {normalizePath} from '@shopify/cli-kit/node/path';\n\nimport {getBugsnag, initializeBugsnag} from '../../utils/bugsnag.js';\nimport {createDeploy} from '../../deploy/index.js';\nimport {\n deployDefaults,\n getBuildCommandFromLockFile,\n parseToken,\n verifyConfig,\n} from '../../utils/utils.js';\nimport type {DeploymentConfig} from '../../deploy/types.js';\nimport {VerificationError} from '../../deploy/types.js';\n\nexport class Deploy extends Command {\n static description = 'Creates a deployment to Oxygen';\n static hidden = false;\n static flags = {\n assetsFolder: Flags.string({\n char: 'a',\n description: 'Assets folder',\n default: String(deployDefaults.assetsDirDefault),\n required: false,\n }),\n buildCommand: Flags.string({\n char: 'b',\n description: 'Build command',\n required: false,\n default: String(deployDefaults.buildCommandDefault!),\n parse: (input): Promise<string> => {\n this.hasCustomBuildCommand = true;\n return Promise.resolve(input);\n },\n }),\n disableBugsnag: Flags.boolean({\n description: 'Disable Bugsnag error reporting',\n required: false,\n default: false,\n }),\n environmentTag: Flags.string({\n char: 'e',\n description: 'Tag of the environment to deploy to',\n required: false,\n }),\n verificationMaxDuration: Flags.integer({\n char: 'd',\n description:\n 'the maximum duration (in seconds) that the deployment verification step is allowed to run before it is considered failed.',\n min: 10,\n max: 300,\n required: false,\n default: deployDefaults.verificationMaxDurationDefault as number,\n }),\n path: Flags.string({\n char: 'p',\n description: 'Root path',\n default: './',\n required: false,\n }),\n defaultEnvironment: Flags.boolean({\n env: 'OXYGEN_DEFAULT_ENVIRONMENT',\n description: 'Deploys to the default environment of the app',\n required: false,\n default: false,\n }),\n skipBuild: Flags.boolean({\n char: 's',\n description: 'Skip running build command',\n required: false,\n default: false,\n }),\n skipVerification: Flags.boolean({\n char: 'v',\n description: 'Skip running deployment verification step',\n required: false,\n default: false,\n }),\n token: Flags.string({\n char: 't',\n description: 'Oxygen deployment token',\n env: 'OXYGEN_DEPLOYMENT_TOKEN',\n required: true,\n }),\n workerFolder: Flags.string({\n char: 'w',\n description: 'Worker folder',\n default: String(deployDefaults.workerDirDefault),\n required: false,\n }),\n workerOnly: Flags.boolean({\n char: 'o',\n description: 'Worker only deployment',\n default: false,\n required: false,\n }),\n metadataDescription: Flags.string({\n description:\n 'Description of the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_DESCRIPTION',\n }),\n metadataUrl: Flags.string({\n description:\n 'URL that links to the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_URL',\n }),\n metadataUser: Flags.string({\n description:\n 'User that initiated the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_USER',\n }),\n metadataVersion: Flags.string({\n description:\n 'A version identifier for the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_VERSION',\n }),\n generateAuthBypassToken: Flags.boolean({\n description:\n 'Generate an auth bypass token used to perform end-to-end testing against the deployment.',\n required: false,\n default: false,\n }),\n };\n\n static hasCustomBuildCommand = false;\n\n async run() {\n try {\n const {flags} = await this.parse(Deploy);\n const rootPath = normalizePath(flags.path);\n\n initializeBugsnag(flags.disableBugsnag);\n const Bugsnag = getBugsnag();\n\n const deploymentUrl =\n // eslint-disable-next-line no-process-env\n process.env.UNSAFE_OXYGEN_DEPLOYMENT_URL ||\n 'https://oxygen.shopifyapps.com';\n Bugsnag?.addMetadata('flags', {\n flags: {...flags, token: '***'},\n deploymentUrl,\n });\n\n const config: DeploymentConfig = {\n assetsDir: normalizePath(flags.assetsFolder),\n bugsnag: !flags.disableBugsnag,\n buildCommand: flags.buildCommand!,\n deploymentToken: parseToken(flags.token!),\n environmentTag: flags.environmentTag,\n deploymentUrl,\n verificationMaxDuration: flags.verificationMaxDuration,\n metadata: {\n description: flags.metadataDescription,\n url: flags.metadataUrl,\n user: flags.metadataUser,\n version: flags.metadataVersion,\n },\n defaultEnvironment: flags.defaultEnvironment,\n rootPath,\n skipBuild: flags.skipBuild,\n skipVerification: flags.skipVerification,\n workerDir: normalizePath(flags.workerFolder),\n workerOnly: flags.workerOnly,\n generateAuthBypassToken: flags.generateAuthBypassToken,\n };\n\n await verifyConfig({config});\n if (!Deploy.hasCustomBuildCommand && !config.skipBuild) {\n config.buildCommand = getBuildCommandFromLockFile(config);\n }\n await createDeploy({config});\n } catch (error) {\n const Bugsnag = getBugsnag();\n if (Bugsnag && (error instanceof Error || typeof error === 'string')) {\n Bugsnag.notify(error);\n }\n\n if (!(error instanceof Error)) {\n consoleError(error as string);\n } else if (!(error instanceof VerificationError)) {\n consoleError(error.message);\n }\n\n this.exit(1);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../src/commands/oxygen/deploy.ts"],"names":[],"mappings":"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","sourcesContent":["import {Command, Flags} from '@oclif/core';\nimport {consoleError} from '@shopify/cli-kit/node/output';\nimport {normalizePath} from '@shopify/cli-kit/node/path';\n\nimport {getBugsnag, initializeBugsnag} from '../../utils/bugsnag.js';\nimport {createDeploy} from '../../deploy/index.js';\nimport {\n deployDefaults,\n getBuildCommandFromLockFile,\n parseToken,\n verifyConfig,\n} from '../../utils/utils.js';\nimport {loadEnvironmentVariableFile} from '../../utils/dotenv.js';\nimport type {DeploymentConfig} from '../../deploy/types.js';\nimport {VerificationError} from '../../deploy/types.js';\n\nexport class Deploy extends Command {\n static description = 'Creates a deployment to Oxygen';\n static hidden = false;\n static flags = {\n assetsFolder: Flags.string({\n char: 'a',\n description: 'Assets folder',\n default: String(deployDefaults.assetsDirDefault),\n required: false,\n }),\n buildCommand: Flags.string({\n char: 'b',\n description: 'Build command',\n required: false,\n default: String(deployDefaults.buildCommandDefault!),\n parse: (input): Promise<string> => {\n this.hasCustomBuildCommand = true;\n return Promise.resolve(input);\n },\n }),\n disableBugsnag: Flags.boolean({\n description: 'Disable Bugsnag error reporting',\n required: false,\n default: false,\n }),\n environmentTag: Flags.string({\n char: 'e',\n description: 'Tag of the environment to deploy to',\n required: false,\n }),\n verificationMaxDuration: Flags.integer({\n char: 'd',\n description:\n 'the maximum duration (in seconds) that the deployment verification step is allowed to run before it is considered failed.',\n min: 10,\n max: 300,\n required: false,\n default: deployDefaults.verificationMaxDurationDefault as number,\n }),\n path: Flags.string({\n char: 'p',\n description: 'Root path',\n default: './',\n required: false,\n }),\n defaultEnvironment: Flags.boolean({\n env: 'OXYGEN_DEFAULT_ENVIRONMENT',\n description: 'Deploys to the default environment of the app',\n required: false,\n default: false,\n }),\n skipBuild: Flags.boolean({\n char: 's',\n description: 'Skip running build command',\n required: false,\n default: false,\n }),\n skipVerification: Flags.boolean({\n char: 'v',\n description: 'Skip running deployment verification step',\n required: false,\n default: false,\n }),\n token: Flags.string({\n char: 't',\n description: 'Oxygen deployment token',\n env: 'OXYGEN_DEPLOYMENT_TOKEN',\n required: true,\n }),\n workerFolder: Flags.string({\n char: 'w',\n description: 'Worker folder',\n default: String(deployDefaults.workerDirDefault),\n required: false,\n }),\n workerOnly: Flags.boolean({\n char: 'o',\n description: 'Worker only deployment',\n default: false,\n required: false,\n }),\n metadataDescription: Flags.string({\n description:\n 'Description of the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_DESCRIPTION',\n }),\n metadataUrl: Flags.string({\n description:\n 'URL that links to the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_URL',\n }),\n metadataUser: Flags.string({\n description:\n 'User that initiated the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_USER',\n }),\n metadataVersion: Flags.string({\n description:\n 'A version identifier for the deployment. Will be saved and displayed in the Shopify admin',\n required: false,\n env: 'OXYGEN_METADATA_VERSION',\n }),\n generateAuthBypassToken: Flags.boolean({\n description:\n 'Generate an auth bypass token used to perform end-to-end testing against the deployment.',\n required: false,\n default: false,\n }),\n environmentFile: Flags.string({\n description:\n 'Path to an environment file to override existing environment variables for the deployment.',\n required: false,\n }),\n };\n\n static hasCustomBuildCommand = false;\n\n async run() {\n try {\n const {flags} = await this.parse(Deploy);\n const rootPath = normalizePath(flags.path);\n const overriddenEnvironmentVariables = flags.environmentFile\n ? loadEnvironmentVariableFile(flags.environmentFile)\n : undefined;\n\n initializeBugsnag(flags.disableBugsnag);\n const Bugsnag = getBugsnag();\n\n const deploymentUrl =\n // eslint-disable-next-line no-process-env\n process.env.UNSAFE_OXYGEN_DEPLOYMENT_URL ||\n 'https://oxygen.shopifyapps.com';\n Bugsnag?.addMetadata('flags', {\n flags: {...flags, token: '***'},\n deploymentUrl,\n });\n\n const config: DeploymentConfig = {\n assetsDir: normalizePath(flags.assetsFolder),\n bugsnag: !flags.disableBugsnag,\n buildCommand: flags.buildCommand!,\n deploymentToken: parseToken(flags.token!),\n environmentTag: flags.environmentTag,\n deploymentUrl,\n verificationMaxDuration: flags.verificationMaxDuration,\n metadata: {\n description: flags.metadataDescription,\n url: flags.metadataUrl,\n user: flags.metadataUser,\n version: flags.metadataVersion,\n },\n defaultEnvironment: flags.defaultEnvironment,\n rootPath,\n skipBuild: flags.skipBuild,\n skipVerification: flags.skipVerification,\n workerDir: normalizePath(flags.workerFolder),\n workerOnly: flags.workerOnly,\n generateAuthBypassToken: flags.generateAuthBypassToken,\n overriddenEnvironmentVariables,\n };\n\n await verifyConfig({config});\n if (!Deploy.hasCustomBuildCommand && !config.skipBuild) {\n config.buildCommand = getBuildCommandFromLockFile(config);\n }\n await createDeploy({config});\n } catch (error) {\n const Bugsnag = getBugsnag();\n if (Bugsnag && (error instanceof Error || typeof error === 'string')) {\n Bugsnag.notify(error);\n }\n\n if (!(error instanceof Error)) {\n consoleError(error as string);\n } else if (!(error instanceof VerificationError)) {\n consoleError(error.message);\n }\n\n this.exit(1);\n }\n }\n}\n"]}
@@ -23,7 +23,7 @@ async function deploymentCancel(options) {
23
23
  });
24
24
  if (response.deploymentCancel.userErrors.length >= 1) {
25
25
  throw new AbortError(
26
- `Failed to cancel deployment: ${response.deploymentCancel.userErrors[0]?.message}`
26
+ response.deploymentCancel.userErrors[0]?.message || ""
27
27
  );
28
28
  }
29
29
  outputInfo(`Deployment with id ${deploymentId} cancelled.`, logger);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/deploy/deployment-cancel.ts"],"names":[],"mappings":"AAAA,SAAQ,sBAAqB;AAC7B,SAAQ,kBAAiB;AACzB,SAAgB,kBAAiB;AAEjC,SAAQ,cAAc,cAAa;AAGnC;AAAA,EACE;AAAA,OAGK;AASP,eAAsB,iBACpB,SACmC;AACnC,QAAM,EAAC,QAAQ,cAAc,QAAQ,OAAM,IAAI;AAE/C,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAsC,MAAM,eAAe;AAAA,MAC/D,OAAO;AAAA,MACP,KAAK;AAAA,MACL,KAAK,GAAG,OAAO,aAAa;AAAA,MAC5B,OAAO,OAAO,gBAAgB;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,QACZ,CAAC,OAAO,qBAAqB,GAAG,OAAO,gBAAgB;AAAA,MACzD;AAAA,IACF,CAAC;AAED,QAAI,SAAS,iBAAiB,WAAW,UAAU,GAAG;AACpD,YAAM,IAAI;AAAA,QACR,gCAAgC,SAAS,iBAAiB,WAAW,CAAC,GAAG,OAAO;AAAA,MAClF;AAAA,IACF;AACA,eAAW,sBAAsB,YAAY,eAAe,MAAM;AAElE,WAAO,SAAS;AAAA,EAClB,SAAS,OAAO;AACd,iBAAa,KAAK;AAElB,UAAM;AAAA,EACR;AACF","sourcesContent":["import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql';\nimport {AbortError} from '@shopify/cli-kit/node/error';\nimport {Logger, outputInfo} from '@shopify/cli-kit/node/output';\n\nimport {errorHandler, Header} from '../utils/utils.js';\n\nimport type {DeploymentConfig} from './types.js';\nimport {\n DeploymentCancelQuery,\n DeploymentCancelQueryData,\n DeploymentCancelResponse,\n} from './graphql/deployment-cancel.js';\n\ninterface DeploymentCancelOptions {\n config: DeploymentConfig;\n deploymentId: string;\n reason: string;\n logger: Logger;\n}\n\nexport async function deploymentCancel(\n options: DeploymentCancelOptions,\n): Promise<DeploymentCancelResponse> {\n const {config, deploymentId, reason, logger} = options;\n\n const variables = {\n deploymentId,\n reason,\n };\n\n try {\n const response: DeploymentCancelQueryData = await graphqlRequest({\n query: DeploymentCancelQuery,\n api: 'Oxygen',\n url: `${config.deploymentUrl}/api/v2/admin/graphql`,\n token: config.deploymentToken.accessToken,\n variables,\n addedHeaders: {\n [Header.OxygenNamespaceHandle]: config.deploymentToken.namespace,\n },\n });\n\n if (response.deploymentCancel.userErrors.length >= 1) {\n throw new AbortError(\n `Failed to cancel deployment: ${response.deploymentCancel.userErrors[0]?.message}`,\n );\n }\n outputInfo(`Deployment with id ${deploymentId} cancelled.`, logger);\n\n return response.deploymentCancel;\n } catch (error) {\n errorHandler(error);\n\n throw error;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/deploy/deployment-cancel.ts"],"names":[],"mappings":"AAAA,SAAQ,sBAAqB;AAC7B,SAAQ,kBAAiB;AACzB,SAAgB,kBAAiB;AAEjC,SAAQ,cAAc,cAAa;AAGnC;AAAA,EACE;AAAA,OAGK;AASP,eAAsB,iBACpB,SACmC;AACnC,QAAM,EAAC,QAAQ,cAAc,QAAQ,OAAM,IAAI;AAE/C,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAsC,MAAM,eAAe;AAAA,MAC/D,OAAO;AAAA,MACP,KAAK;AAAA,MACL,KAAK,GAAG,OAAO,aAAa;AAAA,MAC5B,OAAO,OAAO,gBAAgB;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,QACZ,CAAC,OAAO,qBAAqB,GAAG,OAAO,gBAAgB;AAAA,MACzD;AAAA,IACF,CAAC;AAED,QAAI,SAAS,iBAAiB,WAAW,UAAU,GAAG;AACpD,YAAM,IAAI;AAAA,QACR,SAAS,iBAAiB,WAAW,CAAC,GAAG,WAAW;AAAA,MACtD;AAAA,IACF;AACA,eAAW,sBAAsB,YAAY,eAAe,MAAM;AAElE,WAAO,SAAS;AAAA,EAClB,SAAS,OAAO;AACd,iBAAa,KAAK;AAElB,UAAM;AAAA,EACR;AACF","sourcesContent":["import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql';\nimport {AbortError} from '@shopify/cli-kit/node/error';\nimport {Logger, outputInfo} from '@shopify/cli-kit/node/output';\n\nimport {errorHandler, Header} from '../utils/utils.js';\n\nimport type {DeploymentConfig} from './types.js';\nimport {\n DeploymentCancelQuery,\n DeploymentCancelQueryData,\n DeploymentCancelResponse,\n} from './graphql/deployment-cancel.js';\n\ninterface DeploymentCancelOptions {\n config: DeploymentConfig;\n deploymentId: string;\n reason: string;\n logger: Logger;\n}\n\nexport async function deploymentCancel(\n options: DeploymentCancelOptions,\n): Promise<DeploymentCancelResponse> {\n const {config, deploymentId, reason, logger} = options;\n\n const variables = {\n deploymentId,\n reason,\n };\n\n try {\n const response: DeploymentCancelQueryData = await graphqlRequest({\n query: DeploymentCancelQuery,\n api: 'Oxygen',\n url: `${config.deploymentUrl}/api/v2/admin/graphql`,\n token: config.deploymentToken.accessToken,\n variables,\n addedHeaders: {\n [Header.OxygenNamespaceHandle]: config.deploymentToken.namespace,\n },\n });\n\n if (response.deploymentCancel.userErrors.length >= 1) {\n throw new AbortError(\n response.deploymentCancel.userErrors[0]?.message || '',\n );\n }\n outputInfo(`Deployment with id ${deploymentId} cancelled.`, logger);\n\n return response.deploymentCancel;\n } catch (error) {\n errorHandler(error);\n\n throw error;\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { DeploymentCompleteResponse } from './graphql/deployment-complete.js';
2
2
  import { DeploymentConfig } from './types.js';
3
+ import 'graphql-request';
3
4
  import './graphql/deployment-verification-details.js';
4
5
 
5
6
  declare function deploymentComplete(config: DeploymentConfig, deploymentId: string): Promise<DeploymentCompleteResponse>;
@@ -8,6 +8,9 @@ async function deploymentComplete(config, deploymentId) {
8
8
  deploymentId,
9
9
  generateAuthBypassToken: config.generateAuthBypassToken
10
10
  };
11
+ if (config.overriddenEnvironmentVariables) {
12
+ variables.environmentVariables = config.overriddenEnvironmentVariables;
13
+ }
11
14
  try {
12
15
  const response = await graphqlRequest({
13
16
  query: DeploymentCompleteQuery,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/deploy/deployment-complete.ts"],"names":[],"mappings":"AAAA,SAAQ,sBAAqB;AAC7B,SAAQ,kBAAiB;AAEzB,SAAQ,cAAc,cAAa;AAEnC;AAAA,EACE;AAAA,OAGK;AAGP,eAAsB,mBACpB,QACA,cACqC;AACrC,QAAM,YAAY;AAAA,IAChB;AAAA,IACA,yBAAyB,OAAO;AAAA,EAClC;AAEA,MAAI;AACF,UAAM,WAAwC,MAAM,eAAe;AAAA,MACjE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,KAAK,GAAG,OAAO,aAAa;AAAA,MAC5B,OAAO,OAAO,gBAAgB;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,QACZ,CAAC,OAAO,qBAAqB,GAAG,OAAO,gBAAgB;AAAA,MACzD;AAAA,IACF,CAAC;AAED,QAAI,SAAS,mBAAmB,WAAW,UAAU,GAAG;AACtD,YAAM,IAAI;AAAA,QACR,kCAAkC,SAAS,mBAAmB,WAAW,CAAC,GAAG,OAAO;AAAA,MACtF;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB,SAAS,OAAO;AACd,iBAAa,KAAK;AAElB,UAAM;AAAA,EACR;AACF","sourcesContent":["import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql';\nimport {AbortError} from '@shopify/cli-kit/node/error';\n\nimport {errorHandler, Header} from '../utils/utils.js';\n\nimport {\n DeploymentCompleteQuery,\n DeploymentCompleteQueryData,\n DeploymentCompleteResponse,\n} from './graphql/deployment-complete.js';\nimport type {DeploymentConfig} from './types.js';\n\nexport async function deploymentComplete(\n config: DeploymentConfig,\n deploymentId: string,\n): Promise<DeploymentCompleteResponse> {\n const variables = {\n deploymentId,\n generateAuthBypassToken: config.generateAuthBypassToken,\n };\n\n try {\n const response: DeploymentCompleteQueryData = await graphqlRequest({\n query: DeploymentCompleteQuery,\n api: 'Oxygen',\n url: `${config.deploymentUrl}/api/v2/admin/graphql`,\n token: config.deploymentToken.accessToken,\n variables,\n addedHeaders: {\n [Header.OxygenNamespaceHandle]: config.deploymentToken.namespace,\n },\n });\n\n if (response.deploymentComplete.userErrors.length >= 1) {\n throw new AbortError(\n `Failed to complete deployment: ${response.deploymentComplete.userErrors[0]?.message}`,\n );\n }\n\n return response.deploymentComplete;\n } catch (error) {\n errorHandler(error);\n\n throw error;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/deploy/deployment-complete.ts"],"names":[],"mappings":"AAAA,SAAQ,sBAAqB;AAC7B,SAAQ,kBAAiB;AAEzB,SAAQ,cAAc,cAAa;AAEnC;AAAA,EACE;AAAA,OAIK;AAGP,eAAsB,mBACpB,QACA,cACqC;AACrC,QAAM,YAA8C;AAAA,IAClD;AAAA,IACA,yBAAyB,OAAO;AAAA,EAClC;AAEA,MAAI,OAAO,gCAAgC;AACzC,cAAU,uBAAuB,OAAO;AAAA,EAC1C;AAEA,MAAI;AACF,UAAM,WAAwC,MAAM,eAAe;AAAA,MACjE,OAAO;AAAA,MACP,KAAK;AAAA,MACL,KAAK,GAAG,OAAO,aAAa;AAAA,MAC5B,OAAO,OAAO,gBAAgB;AAAA,MAC9B;AAAA,MACA,cAAc;AAAA,QACZ,CAAC,OAAO,qBAAqB,GAAG,OAAO,gBAAgB;AAAA,MACzD;AAAA,IACF,CAAC;AAED,QAAI,SAAS,mBAAmB,WAAW,UAAU,GAAG;AACtD,YAAM,IAAI;AAAA,QACR,kCAAkC,SAAS,mBAAmB,WAAW,CAAC,GAAG,OAAO;AAAA,MACtF;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB,SAAS,OAAO;AACd,iBAAa,KAAK;AAElB,UAAM;AAAA,EACR;AACF","sourcesContent":["import {graphqlRequest} from '@shopify/cli-kit/node/api/graphql';\nimport {AbortError} from '@shopify/cli-kit/node/error';\n\nimport {errorHandler, Header} from '../utils/utils.js';\n\nimport {\n DeploymentCompleteQuery,\n DeploymentCompleteQueryVariables,\n DeploymentCompleteQueryData,\n DeploymentCompleteResponse,\n} from './graphql/deployment-complete.js';\nimport type {DeploymentConfig} from './types.js';\n\nexport async function deploymentComplete(\n config: DeploymentConfig,\n deploymentId: string,\n): Promise<DeploymentCompleteResponse> {\n const variables: DeploymentCompleteQueryVariables = {\n deploymentId,\n generateAuthBypassToken: config.generateAuthBypassToken,\n };\n\n if (config.overriddenEnvironmentVariables) {\n variables.environmentVariables = config.overriddenEnvironmentVariables;\n }\n\n try {\n const response: DeploymentCompleteQueryData = await graphqlRequest({\n query: DeploymentCompleteQuery,\n api: 'Oxygen',\n url: `${config.deploymentUrl}/api/v2/admin/graphql`,\n token: config.deploymentToken.accessToken,\n variables,\n addedHeaders: {\n [Header.OxygenNamespaceHandle]: config.deploymentToken.namespace,\n },\n });\n\n if (response.deploymentComplete.userErrors.length >= 1) {\n throw new AbortError(\n `Failed to complete deployment: ${response.deploymentComplete.userErrors[0]?.message}`,\n );\n }\n\n return response.deploymentComplete;\n } catch (error) {\n errorHandler(error);\n\n throw error;\n }\n}\n"]}
@@ -1,10 +1,21 @@
1
+ import { Variables } from 'graphql-request';
1
2
  import { OxygenError } from '../types.js';
2
3
  import './deployment-verification-details.js';
3
4
 
4
- declare const DeploymentCompleteQuery = "\n mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean) {\n deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken) {\n deployment {\n id\n url\n }\n authBypassToken\n userErrors {\n message\n }\n }\n }\n";
5
+ declare const DeploymentCompleteQuery = "\n mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean, $environmentVariables: [EnvironmentVariableInput!]) {\n deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken, environmentVariables: $environmentVariables) {\n deployment {\n id\n url\n }\n authBypassToken\n userErrors {\n message\n }\n }\n }\n";
5
6
  interface DeploymentCompleteQueryData {
6
7
  deploymentComplete: DeploymentCompleteResponse;
7
8
  }
9
+ interface EnvironmentVariable {
10
+ isSecret: boolean;
11
+ key: string;
12
+ value: string;
13
+ }
14
+ interface DeploymentCompleteQueryVariables extends Variables {
15
+ deploymentId: string;
16
+ generateAuthBypassToken: boolean;
17
+ environmentVariables?: EnvironmentVariable[];
18
+ }
8
19
  interface DeploymentCompleteResponse {
9
20
  deployment: Deployment;
10
21
  authBypassToken: string | null;
@@ -15,4 +26,4 @@ interface Deployment {
15
26
  url: string;
16
27
  }
17
28
 
18
- export { DeploymentCompleteQuery, type DeploymentCompleteQueryData, type DeploymentCompleteResponse };
29
+ export { DeploymentCompleteQuery, type DeploymentCompleteQueryData, type DeploymentCompleteQueryVariables, type DeploymentCompleteResponse };
@@ -1,6 +1,6 @@
1
1
  const DeploymentCompleteQuery = `
2
- mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean) {
3
- deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken) {
2
+ mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean, $environmentVariables: [EnvironmentVariableInput!]) {
3
+ deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken, environmentVariables: $environmentVariables) {
4
4
  deployment {
5
5
  id
6
6
  url
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/deploy/graphql/deployment-complete.ts"],"names":[],"mappings":"AAEO,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA","sourcesContent":["import {OxygenError} from '../types.js';\n\nexport const DeploymentCompleteQuery = `\n mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean) {\n deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken) {\n deployment {\n id\n url\n }\n authBypassToken\n userErrors {\n message\n }\n }\n }\n`;\n\nexport interface DeploymentCompleteQueryData {\n deploymentComplete: DeploymentCompleteResponse;\n}\n\nexport interface DeploymentCompleteResponse {\n deployment: Deployment;\n authBypassToken: string | null;\n userErrors: OxygenError[];\n}\n\ninterface Deployment {\n id: string;\n url: string;\n}\n"]}
1
+ {"version":3,"sources":["../../../src/deploy/graphql/deployment-complete.ts"],"names":[],"mappings":"AAIO,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA","sourcesContent":["import {Variables} from 'graphql-request';\n\nimport {OxygenError} from '../types.js';\n\nexport const DeploymentCompleteQuery = `\n mutation DeploymentComplete($deploymentId: ID!, $generateAuthBypassToken: Boolean, $environmentVariables: [EnvironmentVariableInput!]) {\n deploymentComplete(id: $deploymentId, generateAuthBypassToken: $generateAuthBypassToken, environmentVariables: $environmentVariables) {\n deployment {\n id\n url\n }\n authBypassToken\n userErrors {\n message\n }\n }\n }\n`;\n\nexport interface DeploymentCompleteQueryData {\n deploymentComplete: DeploymentCompleteResponse;\n}\n\ninterface EnvironmentVariable {\n isSecret: boolean;\n key: string;\n value: string;\n}\n\nexport interface DeploymentCompleteQueryVariables extends Variables {\n deploymentId: string;\n generateAuthBypassToken: boolean;\n environmentVariables?: EnvironmentVariable[];\n}\n\nexport interface DeploymentCompleteResponse {\n deployment: Deployment;\n authBypassToken: string | null;\n userErrors: OxygenError[];\n}\n\ninterface Deployment {\n id: string;\n url: string;\n}\n"]}
@@ -29,6 +29,7 @@ async function createDeploy(options) {
29
29
  const build = {};
30
30
  let buildCompleted;
31
31
  let deployment;
32
+ let metricsExporter;
32
33
  try {
33
34
  const metadata = await getMetadata(config, logger);
34
35
  const labels = createLabels(metadata);
@@ -38,7 +39,7 @@ async function createDeploy(options) {
38
39
  labels,
39
40
  metadata
40
41
  });
41
- const metricsExporter = new MetricsExporter({
42
+ metricsExporter = new MetricsExporter({
42
43
  ciProvider: metadata.name || "unknown",
43
44
  rootPath: config.rootPath
44
45
  });
@@ -77,12 +78,12 @@ async function createDeploy(options) {
77
78
  logger,
78
79
  metricsExporter
79
80
  });
81
+ const deploymentCompleteRequestStartTime = performance.now();
80
82
  const deploymentCompleteOp = await deploymentComplete(
81
83
  config,
82
84
  deployment.deployment.id
83
85
  );
84
86
  metricsExporter.add(MetricName.TotalTime, performance.now() - cliStartTime);
85
- await metricsExporter.export();
86
87
  await verifyDeploymentCompleted(
87
88
  {
88
89
  config,
@@ -92,6 +93,10 @@ async function createDeploy(options) {
92
93
  },
93
94
  deployment.deployment.id
94
95
  );
96
+ metricsExporter.add(
97
+ MetricName.DeploymentCompletedTime,
98
+ performance.now() - deploymentCompleteRequestStartTime
99
+ );
95
100
  if (!config.skipVerification) {
96
101
  await verifyDeployment({
97
102
  config,
@@ -99,6 +104,10 @@ async function createDeploy(options) {
99
104
  logger,
100
105
  hooks
101
106
  });
107
+ metricsExporter.add(
108
+ MetricName.DeploymentRoutableTime,
109
+ performance.now() - deploymentCompleteRequestStartTime
110
+ );
102
111
  }
103
112
  const completedDeployment = {
104
113
  url: deploymentCompleteOp.deployment.url
@@ -156,6 +165,8 @@ The deployment can be reached at the ${completedDeployment.url} preview URL`;
156
165
  });
157
166
  }
158
167
  return Promise.reject(error);
168
+ } finally {
169
+ metricsExporter?.export();
159
170
  }
160
171
  }
161
172
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/deploy/index.ts"],"names":[],"mappings":"AAAA;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAQ,cAAc,oBAAmB;AACzC,SAAQ,YAAY,yBAAwB;AAC5C,SAAQ,iBAAiB,kBAAiB;AAE1C,SAAQ,qBAAoB;AAC5B,SAAQ,mBAAkB;AAC1B,SAAQ,sBAAqB;AAC7B,SAAQ,0BAAyB;AACjC,SAAQ,0BAAyB;AACjC,SAAQ,wBAAuB;AAC/B,SAAQ,wBAAuB;AAC/B,SAAQ,mBAAkB;AAC1B,SAAQ,iCAAgC;AACxC;AAAA,EAEE;AAAA,EAGA;AAAA,OACK;AACP,SAAQ,oBAAmB;AAC3B,SAAQ,cAAc,aAAa,2BAA0B;AAa7D,eAAsB,aACpB,SAC0C;AAC1C,QAAM,eAAe,YAAY,IAAI;AACrC,oBAAkB,CAAC,QAAQ,OAAO,OAAO;AACzC,QAAM,UAAU,WAAW;AAC3B,WAAS,YAAY,UAAU;AAAA,IAC7B,GAAG,QAAQ;AAAA,IACX,iBAAiB,EAAC,GAAG,QAAQ,OAAO,iBAAiB,aAAa,MAAK;AAAA,EACzE,CAAC;AAED,QAAM,EAAC,QAAQ,MAAK,IAAI;AACxB,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,QAAQ,CAAC;AACf,MAAI;AACJ,MAAI;AAEJ,MAAI;AACF,UAAM,WAAW,MAAM,YAAY,QAAQ,MAAM;AACjD,UAAM,SAAS,aAAa,QAAQ;AACpC,UAAM,cAAc,oBAAoB,QAAQ,QAAQ;AACxD,aAAS,YAAY,YAAY;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,kBAAkB,IAAI,gBAAgB;AAAA,MAC1C,YAAY,SAAS,QAAQ;AAAA,MAC7B,UAAU,OAAO;AAAA,IACnB,CAAC;AAED,QAAI,CAAC,OAAO,cAAc,CAAC,OAAO,WAAW;AAC3C,YAAM,wBAAwB,MAAM,cAAc;AAAA,QAChD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,YAAM,KAAK,sBAAsB,MAAM;AACvC,YAAM,YAAY,sBAAsB,MAAM;AAAA,IAChD;AAEA,QAAI,CAAC,OAAO,WAAW;AACrB,YAAM,aAAa;AAAA,QACjB;AAAA,QACA,WAAW,MAAM;AAAA,QACjB;AAAA,QACA;AAAA,MACF,CAAC;AACD,YAAM,aAAa,EAAC,QAAQ,gBAAgB,KAAI,CAAC;AAAA,IACnD;AACA,qBAAiB;AAEjB,UAAM,WAAW,MAAM,eAAe,QAAQ,eAAe;AAC7D,aAAS,YAAY,YAAY,QAAQ;AACzC,UAAM,0BAA0B,MAAM,KAClC,EAAC,SAAS,MAAM,IAAI,SAAQ,IAC5B,EAAC,aAAa,UAAU,OAAM;AAElC,iBAAa,MAAM,mBAAmB;AAAA,MACpC;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAED,UAAM,YAAY;AAAA,MAChB;AAAA,MACA,SAAS,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,UAAM,uBAAuB,MAAM;AAAA,MACjC;AAAA,MACA,WAAW,WAAW;AAAA,IACxB;AACA,oBAAgB,IAAI,WAAW,WAAW,YAAY,IAAI,IAAI,YAAY;AAC1E,UAAM,gBAAgB,OAAO;AAE7B,UAAM;AAAA,MACJ;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA,kBAAkB,WAAW,wBAAwB;AAAA,MACvD;AAAA,MACA,WAAW,WAAW;AAAA,IACxB;AAEA,QAAI,CAAC,OAAO,kBAAkB;AAC5B,YAAM,iBAAiB;AAAA,QACrB;AAAA,QACA,KAAK,qBAAqB,WAAW;AAAA,QACrC;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,sBAA2C;AAAA,MAC/C,KAAK,qBAAqB,WAAW;AAAA,IACvC;AAEA,QAAI,iBAAiB;AAAA,uCAA0C,oBAAoB,GAAG;AAEtF,QAAI,qBAAqB,iBAAiB;AACxC,0BAAoB,kBAClB,qBAAqB;AAEvB,wBAAkB,iDAAiD,oBAAoB,eAAe;AAAA,IACxG;AAEA,kBAAc,gBAAgB,MAAM;AAGpC,QAAI,SAAS,SAAS,QAAQ;AAC5B,iBAAW,KAAK,UAAU,mBAAmB,CAAC;AAAA,IAChD;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,QACE,OAAO,WACP,YACC,iBAAiB,SAAS,OAAO,UAAU,WAC5C;AACA,cAAQ,OAAO,KAAK;AAAA,IACtB;AAEA,QAAI,EAAE,iBAAiB,QAAQ;AAE7B,cAAQ,MAAM,iBAAiB,KAAK;AACpC,aAAO,QAAQ,OAAO,IAAI,MAAM,eAAe,CAAC;AAAA,IAClD;AAEA,QACE,iBAAiB,qBACjB,iBAAiB,sCACjB;AACA,iBAAW,MAAM,SAAS,MAAM;AAAA,IAClC,WAAW,MAAM,MAAM,CAAC,gBAAgB;AACtC;AAAA,QACE,sBAAsB,MAAM,OAAO;AAAA,QACnC;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA,SAAS,MAAM;AAAA,QACf,QAAQ,MAAM;AAAA,QACd;AAAA,MACF,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,YAAI,eAAe,OAAO;AACxB,qBAAW,2BAA2B,IAAI,OAAO,IAAI,MAAM;AAAA,QAC7D;AAAA,MACF,CAAC;AAAA,IACH,WAAW,YAAY,WAAW,IAAI;AACpC;AAAA,QACE,2BAA2B,MAAM,OAAO;AAAA,QACxC;AAAA,MACF;AACA,YAAM,iBAAiB;AAAA,QACrB;AAAA,QACA,cAAc,WAAW,WAAW;AAAA,QACpC,QAAQ,MAAM;AAAA,QACd;AAAA,MACF,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,YAAI,eAAe,OAAO;AACxB,qBAAW,gCAAgC,IAAI,OAAO,IAAI,MAAM;AAAA,QAClE;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO,QAAQ,OAAO,KAAK;AAAA,EAC7B;AACF;AAGA,SAAQ,kBAAiB","sourcesContent":["import {\n Logger,\n outputInfo,\n outputSuccess,\n outputWarn,\n} from '@shopify/cli-kit/node/output';\n\nimport {stderrLogger, verifyConfig} from '../utils/utils.js';\nimport {getBugsnag, initializeBugsnag} from '../utils/bugsnag.js';\nimport {MetricsExporter, MetricName} from '../utils/metrics-exporter.js';\n\nimport {buildInitiate} from './build-initiate.js';\nimport {buildCancel} from './build-cancel.js';\nimport {getUploadFiles} from './get-upload-files.js';\nimport {deploymentInitiate} from './deployment-initiate.js';\nimport {deploymentComplete} from './deployment-complete.js';\nimport {verifyDeployment} from './verify-deployment.js';\nimport {deploymentCancel} from './deployment-cancel.js';\nimport {uploadFiles} from './upload-files.js';\nimport {verifyDeploymentCompleted} from './verify-deployment-completed.js';\nimport {\n Build,\n DeploymentCompletedVerificationError,\n DeploymentConfig,\n DeploymentHooks,\n VerificationError,\n} from './types.js';\nimport {buildProject} from './build-project.js';\nimport {createLabels, getMetadata, getEnvironmentInput} from './metadata.js';\n\ninterface CreateDeployOptions {\n config: DeploymentConfig;\n hooks?: DeploymentHooks;\n logger?: Logger;\n}\n\ninterface CompletedDeployment {\n url: string;\n authBypassToken?: string;\n}\n\nexport async function createDeploy(\n options: CreateDeployOptions,\n): Promise<CompletedDeployment | undefined> {\n const cliStartTime = performance.now();\n initializeBugsnag(!options.config.bugsnag);\n const Bugsnag = getBugsnag();\n Bugsnag?.addMetadata('config', {\n ...options.config,\n deploymentToken: {...options.config.deploymentToken, accessToken: '***'},\n });\n\n const {config, hooks} = options;\n const logger = options.logger ?? stderrLogger;\n const build = {} as Build;\n let buildCompleted;\n let deployment;\n\n try {\n const metadata = await getMetadata(config, logger);\n const labels = createLabels(metadata);\n const environment = getEnvironmentInput(config, metadata);\n Bugsnag?.addMetadata('metadata', {\n environment,\n labels,\n metadata,\n });\n const metricsExporter = new MetricsExporter({\n ciProvider: metadata.name || 'unknown',\n rootPath: config.rootPath!,\n });\n\n if (!config.workerOnly && !config.skipBuild) {\n const buildInitiateResponse = await buildInitiate({\n config,\n environment,\n labels,\n logger,\n });\n build.id = buildInitiateResponse.build.id;\n build.assetPath = buildInitiateResponse.build.assetPath;\n }\n\n if (!config.skipBuild) {\n await buildProject({\n config,\n assetPath: build.assetPath,\n hooks,\n metricsExporter,\n });\n await verifyConfig({config, performedBuild: true});\n }\n buildCompleted = true;\n\n const manifest = await getUploadFiles(config, metricsExporter);\n Bugsnag?.addMetadata('manifest', manifest);\n const deploymentInitiateInput = build.id\n ? {buildId: build.id, manifest}\n : {environment, manifest, labels};\n\n deployment = await deploymentInitiate({\n config,\n input: deploymentInitiateInput,\n logger,\n });\n\n await uploadFiles({\n config,\n targets: deployment.deploymentTargets,\n hooks,\n logger,\n metricsExporter,\n });\n const deploymentCompleteOp = await deploymentComplete(\n config,\n deployment.deployment.id,\n );\n metricsExporter.add(MetricName.TotalTime, performance.now() - cliStartTime);\n await metricsExporter.export();\n\n await verifyDeploymentCompleted(\n {\n config,\n hooks,\n logger,\n timeoutInSeconds: deployment.deploymentConfiguration.timeoutInSeconds,\n },\n deployment.deployment.id,\n );\n\n if (!config.skipVerification) {\n await verifyDeployment({\n config,\n url: deploymentCompleteOp.deployment.url,\n logger,\n hooks,\n });\n }\n\n const completedDeployment: CompletedDeployment = {\n url: deploymentCompleteOp.deployment.url,\n };\n\n let successMessage = `\\nThe deployment can be reached at the ${completedDeployment.url} preview URL`;\n\n if (deploymentCompleteOp.authBypassToken) {\n completedDeployment.authBypassToken =\n deploymentCompleteOp.authBypassToken;\n\n successMessage += `. The auth bypass token for the deployment is ${completedDeployment.authBypassToken}`;\n }\n\n outputSuccess(successMessage, logger);\n\n // in CI environments, we want to output the URL + auth bypass token to stdout\n if (metadata.name !== 'none') {\n outputInfo(JSON.stringify(completedDeployment));\n }\n\n return completedDeployment;\n } catch (error) {\n if (\n config.bugsnag &&\n Bugsnag &&\n (error instanceof Error || typeof error === 'string')\n ) {\n Bugsnag.notify(error);\n }\n\n if (!(error instanceof Error)) {\n // eslint-disable-next-line no-console\n console.error('Unknown error', error);\n return Promise.reject(new Error('Unknown error'));\n }\n\n if (\n error instanceof VerificationError ||\n error instanceof DeploymentCompletedVerificationError\n ) {\n outputWarn(error.message, logger);\n } else if (build.id && !buildCompleted) {\n outputWarn(\n `Build failed with: ${error.message}, cancelling build.`,\n logger,\n );\n\n await buildCancel({\n config,\n buildId: build.id!,\n reason: error.message,\n logger,\n }).catch((err) => {\n if (err instanceof Error) {\n outputWarn(`Failed to cancel build: ${err.message}`, logger);\n }\n });\n } else if (deployment?.deployment.id) {\n outputWarn(\n `Deployment failed with: ${error.message}, cancelling deployment.`,\n logger,\n );\n await deploymentCancel({\n config,\n deploymentId: deployment.deployment.id,\n reason: error.message,\n logger,\n }).catch((err) => {\n if (err instanceof Error) {\n outputWarn(`Failed to cancel deployment: ${err.message}`, logger);\n }\n });\n }\n return Promise.reject(error);\n }\n}\n\nexport type {DeploymentConfig, DeploymentHooks, CompletedDeployment};\nexport {parseToken} from '../utils/utils.js';\nexport type {DeploymentVerificationDetailsResponse} from './graphql/deployment-verification-details.js';\n"]}
1
+ {"version":3,"sources":["../../src/deploy/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Logger,\n outputInfo,\n outputSuccess,\n outputWarn,\n} from '@shopify/cli-kit/node/output';\n\nimport {stderrLogger, verifyConfig} from '../utils/utils.js';\nimport {getBugsnag, initializeBugsnag} from '../utils/bugsnag.js';\nimport {MetricsExporter, MetricName} from '../utils/metrics-exporter.js';\n\nimport {buildInitiate} from './build-initiate.js';\nimport {buildCancel} from './build-cancel.js';\nimport {getUploadFiles} from './get-upload-files.js';\nimport {deploymentInitiate} from './deployment-initiate.js';\nimport {deploymentComplete} from './deployment-complete.js';\nimport {verifyDeployment} from './verify-deployment.js';\nimport {deploymentCancel} from './deployment-cancel.js';\nimport {uploadFiles} from './upload-files.js';\nimport {verifyDeploymentCompleted} from './verify-deployment-completed.js';\nimport {\n Build,\n DeploymentCompletedVerificationError,\n DeploymentConfig,\n DeploymentHooks,\n VerificationError,\n} from './types.js';\nimport {buildProject} from './build-project.js';\nimport {createLabels, getMetadata, getEnvironmentInput} from './metadata.js';\n\ninterface CreateDeployOptions {\n config: DeploymentConfig;\n hooks?: DeploymentHooks;\n logger?: Logger;\n}\n\ninterface CompletedDeployment {\n url: string;\n authBypassToken?: string;\n}\n\nexport async function createDeploy(\n options: CreateDeployOptions,\n): Promise<CompletedDeployment | undefined> {\n const cliStartTime = performance.now();\n initializeBugsnag(!options.config.bugsnag);\n const Bugsnag = getBugsnag();\n Bugsnag?.addMetadata('config', {\n ...options.config,\n deploymentToken: {...options.config.deploymentToken, accessToken: '***'},\n });\n\n const {config, hooks} = options;\n const logger = options.logger ?? stderrLogger;\n const build = {} as Build;\n let buildCompleted;\n let deployment;\n let metricsExporter;\n\n try {\n const metadata = await getMetadata(config, logger);\n const labels = createLabels(metadata);\n const environment = getEnvironmentInput(config, metadata);\n Bugsnag?.addMetadata('metadata', {\n environment,\n labels,\n metadata,\n });\n metricsExporter = new MetricsExporter({\n ciProvider: metadata.name || 'unknown',\n rootPath: config.rootPath!,\n });\n\n if (!config.workerOnly && !config.skipBuild) {\n const buildInitiateResponse = await buildInitiate({\n config,\n environment,\n labels,\n logger,\n });\n build.id = buildInitiateResponse.build.id;\n build.assetPath = buildInitiateResponse.build.assetPath;\n }\n\n if (!config.skipBuild) {\n await buildProject({\n config,\n assetPath: build.assetPath,\n hooks,\n metricsExporter,\n });\n await verifyConfig({config, performedBuild: true});\n }\n buildCompleted = true;\n\n const manifest = await getUploadFiles(config, metricsExporter);\n Bugsnag?.addMetadata('manifest', manifest);\n const deploymentInitiateInput = build.id\n ? {buildId: build.id, manifest}\n : {environment, manifest, labels};\n\n deployment = await deploymentInitiate({\n config,\n input: deploymentInitiateInput,\n logger,\n });\n\n await uploadFiles({\n config,\n targets: deployment.deploymentTargets,\n hooks,\n logger,\n metricsExporter,\n });\n\n const deploymentCompleteRequestStartTime = performance.now();\n\n const deploymentCompleteOp = await deploymentComplete(\n config,\n deployment.deployment.id,\n );\n metricsExporter.add(MetricName.TotalTime, performance.now() - cliStartTime);\n\n await verifyDeploymentCompleted(\n {\n config,\n hooks,\n logger,\n timeoutInSeconds: deployment.deploymentConfiguration.timeoutInSeconds,\n },\n deployment.deployment.id,\n );\n\n metricsExporter.add(\n MetricName.DeploymentCompletedTime,\n performance.now() - deploymentCompleteRequestStartTime,\n );\n\n if (!config.skipVerification) {\n await verifyDeployment({\n config,\n url: deploymentCompleteOp.deployment.url,\n logger,\n hooks,\n });\n\n metricsExporter.add(\n MetricName.DeploymentRoutableTime,\n performance.now() - deploymentCompleteRequestStartTime,\n );\n }\n\n const completedDeployment: CompletedDeployment = {\n url: deploymentCompleteOp.deployment.url,\n };\n\n let successMessage = `\\nThe deployment can be reached at the ${completedDeployment.url} preview URL`;\n\n if (deploymentCompleteOp.authBypassToken) {\n completedDeployment.authBypassToken =\n deploymentCompleteOp.authBypassToken;\n\n successMessage += `. The auth bypass token for the deployment is ${completedDeployment.authBypassToken}`;\n }\n\n outputSuccess(successMessage, logger);\n\n // in CI environments, we want to output the URL + auth bypass token to stdout\n if (metadata.name !== 'none') {\n outputInfo(JSON.stringify(completedDeployment));\n }\n\n return completedDeployment;\n } catch (error) {\n if (\n config.bugsnag &&\n Bugsnag &&\n (error instanceof Error || typeof error === 'string')\n ) {\n Bugsnag.notify(error);\n }\n\n if (!(error instanceof Error)) {\n // eslint-disable-next-line no-console\n console.error('Unknown error', error);\n return Promise.reject(new Error('Unknown error'));\n }\n\n if (\n error instanceof VerificationError ||\n error instanceof DeploymentCompletedVerificationError\n ) {\n outputWarn(error.message, logger);\n } else if (build.id && !buildCompleted) {\n outputWarn(\n `Build failed with: ${error.message}, cancelling build.`,\n logger,\n );\n\n await buildCancel({\n config,\n buildId: build.id!,\n reason: error.message,\n logger,\n }).catch((err) => {\n if (err instanceof Error) {\n outputWarn(`Failed to cancel build: ${err.message}`, logger);\n }\n });\n } else if (deployment?.deployment.id) {\n outputWarn(\n `Deployment failed with: ${error.message}, cancelling deployment.`,\n logger,\n );\n await deploymentCancel({\n config,\n deploymentId: deployment.deployment.id,\n reason: error.message,\n logger,\n }).catch((err) => {\n if (err instanceof Error) {\n outputWarn(`Failed to cancel deployment: ${err.message}`, logger);\n }\n });\n }\n return Promise.reject(error);\n } finally {\n metricsExporter?.export();\n }\n}\n\nexport type {DeploymentConfig, DeploymentHooks, CompletedDeployment};\nexport {parseToken} from '../utils/utils.js';\nexport type {DeploymentVerificationDetailsResponse} from './graphql/deployment-verification-details.js';\n"]}
@@ -41,6 +41,12 @@ interface DeploymentConfig {
41
41
  workerDir?: string;
42
42
  workerOnly: boolean;
43
43
  generateAuthBypassToken: boolean;
44
+ overriddenEnvironmentVariables?: EnvironmentVariable[];
45
+ }
46
+ interface EnvironmentVariable {
47
+ isSecret: boolean;
48
+ key: string;
49
+ value: string;
44
50
  }
45
51
  interface DeploymentToken {
46
52
  accessToken: string;
@@ -74,4 +80,4 @@ declare class VerificationError extends Error {
74
80
  declare class DeploymentCompletedVerificationError extends Error {
75
81
  }
76
82
 
77
- export { type Build, type ClientError, DeploymentCompletedVerificationError, type DeploymentConfig, type DeploymentHooks, type DeploymentManifestFile, type DeploymentToken, type EnvironmentInput, FileType, type OxygenError, VerificationError };
83
+ export { type Build, type ClientError, DeploymentCompletedVerificationError, type DeploymentConfig, type DeploymentHooks, type DeploymentManifestFile, type DeploymentToken, type EnvironmentInput, type EnvironmentVariable, FileType, type OxygenError, VerificationError };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/deploy/types.ts"],"names":["FileType"],"mappings":"AAyEO,IAAK,WAAL,kBAAKA,cAAL;AACL,EAAAA,UAAA,YAAS;AACT,EAAAA,UAAA,WAAQ;AAFE,SAAAA;AAAA,GAAA;AASL,MAAM,0BAA0B,MAAM;AAAC;AAEvC,MAAM,6CAA6C,MAAM;AAAC","sourcesContent":["import {DeploymentVerificationDetailsResponse} from './graphql/deployment-verification-details.js';\n\nexport interface Build {\n id: string;\n assetPath: string;\n}\n\nexport interface ClientError extends Error {\n statusCode: number;\n}\n\nexport interface DeploymentHooks {\n buildFunction?: (urlPath?: string) => Promise<void>;\n onDeploymentCompletedVerificationStart?: () => void;\n onDeploymentCompletedVerificationError?: () => void;\n onDeploymentFailed?: (\n responseData: DeploymentVerificationDetailsResponse,\n ) => void;\n onDeploymentCompleted?: () => void;\n onVerificationStart?: () => void;\n onVerificationComplete?: () => void;\n onVerificationError?: (error: Error) => void;\n onUploadFilesStart?: () => void;\n onUploadFilesError?: (error: Error) => void;\n onUploadFilesComplete?: () => void;\n}\n\nexport interface DeploymentConfig {\n assetsDir?: string;\n bugsnag: boolean;\n buildCommand?: string;\n deploymentToken: DeploymentToken;\n deploymentUrl: string;\n environmentTag?: string;\n metadata: {\n description?: string;\n user?: string;\n version?: string;\n url?: string;\n };\n defaultEnvironment: boolean;\n rootPath?: string;\n skipBuild: boolean;\n skipVerification: boolean;\n verificationMaxDuration: number;\n workerDir?: string;\n workerOnly: boolean;\n generateAuthBypassToken: boolean;\n}\n\nexport interface DeploymentToken {\n accessToken: string;\n allowedResource: string;\n appId: string;\n client: string;\n expiresAt: string;\n namespace: string;\n namespaceId: string;\n}\n\nexport interface DeploymentManifestFile {\n filePath: string;\n fileSize: number;\n mimeType: string;\n fileHash: string;\n fileType: string;\n}\n\nexport interface EnvironmentInput {\n handle?: string;\n tag?: string;\n}\n\nexport enum FileType {\n Worker = 'WORKER',\n Asset = 'ASSET',\n}\n\nexport interface OxygenError {\n message: string;\n}\n\nexport class VerificationError extends Error {}\n\nexport class DeploymentCompletedVerificationError extends Error {}\n"]}
1
+ {"version":3,"sources":["../../src/deploy/types.ts"],"names":["FileType"],"mappings":"AAgFO,IAAK,WAAL,kBAAKA,cAAL;AACL,EAAAA,UAAA,YAAS;AACT,EAAAA,UAAA,WAAQ;AAFE,SAAAA;AAAA,GAAA;AASL,MAAM,0BAA0B,MAAM;AAAC;AAEvC,MAAM,6CAA6C,MAAM;AAAC","sourcesContent":["import {DeploymentVerificationDetailsResponse} from './graphql/deployment-verification-details.js';\n\nexport interface Build {\n id: string;\n assetPath: string;\n}\n\nexport interface ClientError extends Error {\n statusCode: number;\n}\n\nexport interface DeploymentHooks {\n buildFunction?: (urlPath?: string) => Promise<void>;\n onDeploymentCompletedVerificationStart?: () => void;\n onDeploymentCompletedVerificationError?: () => void;\n onDeploymentFailed?: (\n responseData: DeploymentVerificationDetailsResponse,\n ) => void;\n onDeploymentCompleted?: () => void;\n onVerificationStart?: () => void;\n onVerificationComplete?: () => void;\n onVerificationError?: (error: Error) => void;\n onUploadFilesStart?: () => void;\n onUploadFilesError?: (error: Error) => void;\n onUploadFilesComplete?: () => void;\n}\n\nexport interface DeploymentConfig {\n assetsDir?: string;\n bugsnag: boolean;\n buildCommand?: string;\n deploymentToken: DeploymentToken;\n deploymentUrl: string;\n environmentTag?: string;\n metadata: {\n description?: string;\n user?: string;\n version?: string;\n url?: string;\n };\n defaultEnvironment: boolean;\n rootPath?: string;\n skipBuild: boolean;\n skipVerification: boolean;\n verificationMaxDuration: number;\n workerDir?: string;\n workerOnly: boolean;\n generateAuthBypassToken: boolean;\n overriddenEnvironmentVariables?: EnvironmentVariable[];\n}\n\nexport interface EnvironmentVariable {\n isSecret: boolean;\n key: string;\n value: string;\n}\n\nexport interface DeploymentToken {\n accessToken: string;\n allowedResource: string;\n appId: string;\n client: string;\n expiresAt: string;\n namespace: string;\n namespaceId: string;\n}\n\nexport interface DeploymentManifestFile {\n filePath: string;\n fileSize: number;\n mimeType: string;\n fileHash: string;\n fileType: string;\n}\n\nexport interface EnvironmentInput {\n handle?: string;\n tag?: string;\n}\n\nexport enum FileType {\n Worker = 'WORKER',\n Asset = 'ASSET',\n}\n\nexport interface OxygenError {\n message: string;\n}\n\nexport class VerificationError extends Error {}\n\nexport class DeploymentCompletedVerificationError extends Error {}\n"]}
@@ -0,0 +1,7 @@
1
+ import { EnvironmentVariable } from '../deploy/types.js';
2
+ import '../deploy/graphql/deployment-verification-details.js';
3
+
4
+ declare function loadEnvironmentVariableFile(path: string): EnvironmentVariable[];
5
+ declare function parseDotEnvFile(path: string): Record<string, string>;
6
+
7
+ export { loadEnvironmentVariableFile, parseDotEnvFile };
@@ -0,0 +1,21 @@
1
+ import fs from 'fs';
2
+ import * as dotenv from 'dotenv';
3
+
4
+ function loadEnvironmentVariableFile(path) {
5
+ return Object.entries(parseDotEnvFile(path)).map(([key, value]) => ({
6
+ isSecret: true,
7
+ key,
8
+ value
9
+ }));
10
+ }
11
+ function parseDotEnvFile(path) {
12
+ if (!fs.existsSync(path) || !fs.lstatSync(path).isFile()) {
13
+ throw new Error(`Environment file not found: ${path}`);
14
+ }
15
+ const file = fs.readFileSync(path, "utf8");
16
+ return dotenv.parse(file);
17
+ }
18
+
19
+ export { loadEnvironmentVariableFile, parseDotEnvFile };
20
+ //# sourceMappingURL=out.js.map
21
+ //# sourceMappingURL=dotenv.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/dotenv.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ;AAEf,YAAY,YAAY;AAIjB,SAAS,4BACd,MACuB;AAGvB,SAAO,OAAO,QAAQ,gBAAgB,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO;AAAA,IAClE,UAAU;AAAA,IACV;AAAA,IACA;AAAA,EACF,EAAE;AACJ;AAEO,SAAS,gBAAgB,MAAsC;AACpE,MAAI,CAAC,GAAG,WAAW,IAAI,KAAK,CAAC,GAAG,UAAU,IAAI,EAAE,OAAO,GAAG;AACxD,UAAM,IAAI,MAAM,+BAA+B,IAAI,EAAE;AAAA,EACvD;AAEA,QAAM,OAAO,GAAG,aAAa,MAAM,MAAM;AACzC,SAAO,OAAO,MAAM,IAAI;AAC1B","sourcesContent":["import fs from 'fs';\n\nimport * as dotenv from 'dotenv';\n\nimport {EnvironmentVariable} from '../deploy/types.js';\n\nexport function loadEnvironmentVariableFile(\n path: string,\n): EnvironmentVariable[] {\n // We are forcing every environment variable passed in by the merchant to be secret.\n // This will only affect the privacy setting of the environment variable on Cloudflare\n return Object.entries(parseDotEnvFile(path)).map(([key, value]) => ({\n isSecret: true,\n key,\n value,\n }));\n}\n\nexport function parseDotEnvFile(path: string): Record<string, string> {\n if (!fs.existsSync(path) || !fs.lstatSync(path).isFile()) {\n throw new Error(`Environment file not found: ${path}`);\n }\n\n const file = fs.readFileSync(path, 'utf8');\n return dotenv.parse(file);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export { loadEnvironmentVariableFile, parseDotEnvFile } from './dotenv.js';
2
+ import '../deploy/types.js';
3
+ import '../deploy/graphql/deployment-verification-details.js';
@@ -0,0 +1,3 @@
1
+ export { loadEnvironmentVariableFile, parseDotEnvFile } from './dotenv.js';
2
+ //# sourceMappingURL=out.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,SAAQ,6BAA6B,uBAAsB","sourcesContent":["export {loadEnvironmentVariableFile, parseDotEnvFile} from './dotenv.js';\n"]}
@@ -9,7 +9,9 @@ declare enum MetricName {
9
9
  TotalSizeUploaded = "total_size_uploaded",
10
10
  TotalSizeRequested = "total_size_requested",
11
11
  TotalTime = "total_time",
12
- UploadTime = "upload_time"
12
+ UploadTime = "upload_time",
13
+ DeploymentCompletedTime = "deployment_completed_time",
14
+ DeploymentRoutableTime = "deployment_routable_time"
13
15
  }
14
16
  declare class MetricsExporter {
15
17
  private metrics;
@@ -10,6 +10,8 @@ var MetricName = /* @__PURE__ */ ((MetricName2) => {
10
10
  MetricName2["TotalSizeRequested"] = "total_size_requested";
11
11
  MetricName2["TotalTime"] = "total_time";
12
12
  MetricName2["UploadTime"] = "upload_time";
13
+ MetricName2["DeploymentCompletedTime"] = "deployment_completed_time";
14
+ MetricName2["DeploymentRoutableTime"] = "deployment_routable_time";
13
15
  return MetricName2;
14
16
  })(MetricName || {});
15
17
  class MetricsExporter {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/metrics-exporter.ts"],"names":["MetricName"],"mappings":"AACA,SAAQ,aAAY;AAEpB,SAAQ,kBAAiB;AACzB,SAAQ,uBAAsB;AAmBvB,IAAK,aAAL,kBAAKA,gBAAL;AACL,EAAAA,YAAA,eAAY;AACZ,EAAAA,YAAA,uBAAoB;AACpB,EAAAA,YAAA,sBAAmB;AACnB,EAAAA,YAAA,uBAAoB;AACpB,EAAAA,YAAA,wBAAqB;AACrB,EAAAA,YAAA,eAAY;AACZ,EAAAA,YAAA,gBAAa;AAPH,SAAAA;AAAA,GAAA;AAUL,MAAM,gBAAgB;AAAA,EACnB,UAA4B,CAAC;AAAA,EACpB,eAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EAEjB,YAAY,SAAiC;AAC3C,UAAM,EAAC,SAAS,WAAU,IAAI,gBAAgB;AAC9C,UAAM,EAAC,SAAS,gBAAe,IAAI;AAAA,MACjC,GAAG,QAAQ,QAAQ;AAAA,IACrB;AACA,SAAK,cAAc;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,aAAa,cAAc,cAAc,SAAS;AAAA,MAClD,kBAAkB,mBAAmB;AAAA,IACvC;AACA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,IACE,MACA,OACA,OAA+B,CAAC,GAC1B;AACN,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,IAAI,GAAG;AACtB,WAAK,QAAQ,IAAI,EAAG,KAAK,MAAM;AAAA,IACjC,OAAO;AACL,WAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,WAAW,MAAwC;AACjD,WAAO,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,EACrE;AAAA,EAEA,MAAM,SAAwB;AAC5B,UAAM,kBAAgC,OAAO,QAAQ,KAAK,OAAO,EAC9D,IAAI,CAAC,CAAC,YAAY,MAAM,MAAM;AAC7B,YAAM,OAAO,GAAG,KAAK,YAAY,IAAI,UAAU;AAE/C,aAAO,OAAO,IAAI,CAAC,EAAC,OAAO,KAAI,MAAM;AACnC,eAAO;AAAA,UACL;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,MAAM,KAAK,WAAW,EAAC,GAAG,MAAM,GAAG,KAAK,YAAW,CAAC;AAAA,QACtD;AAAA,MACF,CAAC;AAAA,IACH,CAAC,EACA,KAAK;AAER,QAAI;AACF,YAAM,MAAM,KAAK,WAAW;AAAA,QAC1B,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAC,QAAQ,gBAAe,CAAC;AAAA,MAChD,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,WAAW;AAC3B,UAAI,YAAY,iBAAiB,SAAS,OAAO,UAAU,WAAW;AACpE,gBAAQ,OAAO,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport {fetch} from '@shopify/cli-kit/node/http';\n\nimport {getBugsnag} from './bugsnag.js';\nimport {loadPackageJson} from './utils.js';\n\ninterface GodogEvent {\n name: string;\n type: string;\n value: number;\n tags: string[];\n}\n\ntype MetricCollection = Record<\n string,\n [{value: number; tags: Record<string, string>}]\n>;\n\ninterface MetricsExporterOptions {\n ciProvider: string;\n rootPath: string;\n}\n\nexport enum MetricName {\n BuildTime = 'build_time',\n NumFilesRequested = 'num_files_requested',\n NumFilesUploaded = 'num_files_uploaded',\n TotalSizeUploaded = 'total_size_uploaded',\n TotalSizeRequested = 'total_size_requested',\n TotalTime = 'total_time',\n UploadTime = 'upload_time',\n}\n\nexport class MetricsExporter {\n private metrics: MetricCollection = {};\n private readonly metricPrefix: string = 'oxygen.cli';\n private readonly defaultTags: Record<string, string>;\n private readonly exportUrl: string;\n\n constructor(options: MetricsExporterOptions) {\n const {version: cliVersion} = loadPackageJson();\n const {version: hydrogenVersion} = loadPackageJson(\n `${options.rootPath}/node_modules/@shopify/hydrogen`,\n );\n this.defaultTags = {\n ci_provider: options.ciProvider,\n cli_version: `oxygen-cli@${cliVersion || 'unknown'}`,\n hydrogen_version: hydrogenVersion || 'unknown',\n };\n this.exportUrl = 'https://metrics.myshopify.dev';\n }\n\n add(\n name: MetricName,\n value: number,\n tags: Record<string, string> = {},\n ): void {\n const metric = {\n value,\n tags,\n };\n\n if (this.metrics[name]) {\n this.metrics[name]!.push(metric);\n } else {\n this.metrics[name] = [metric];\n }\n }\n\n formatTags(tags: Record<string, string>): string[] {\n return Object.entries(tags).map(([key, value]) => `${key}:${value}`);\n }\n\n async export(): Promise<void> {\n const metricsToExport: GodogEvent[] = Object.entries(this.metrics)\n .map(([metricName, values]) => {\n const name = `${this.metricPrefix}.${metricName}`;\n\n return values.map(({value, tags}) => {\n return {\n name,\n type: 'gauge',\n value,\n tags: this.formatTags({...tags, ...this.defaultTags}),\n };\n });\n })\n .flat();\n\n try {\n await fetch(this.exportUrl, {\n method: 'POST',\n body: JSON.stringify({events: metricsToExport}),\n });\n } catch (error) {\n const Bugsnag = getBugsnag();\n if (Bugsnag && (error instanceof Error || typeof error === 'string')) {\n Bugsnag.notify(error);\n }\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/metrics-exporter.ts"],"names":["MetricName"],"mappings":"AACA,SAAQ,aAAY;AAEpB,SAAQ,kBAAiB;AACzB,SAAQ,uBAAsB;AAmBvB,IAAK,aAAL,kBAAKA,gBAAL;AACL,EAAAA,YAAA,eAAY;AACZ,EAAAA,YAAA,uBAAoB;AACpB,EAAAA,YAAA,sBAAmB;AACnB,EAAAA,YAAA,uBAAoB;AACpB,EAAAA,YAAA,wBAAqB;AACrB,EAAAA,YAAA,eAAY;AACZ,EAAAA,YAAA,gBAAa;AACb,EAAAA,YAAA,6BAA0B;AAC1B,EAAAA,YAAA,4BAAyB;AATf,SAAAA;AAAA,GAAA;AAYL,MAAM,gBAAgB;AAAA,EACnB,UAA4B,CAAC;AAAA,EACpB,eAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EAEjB,YAAY,SAAiC;AAC3C,UAAM,EAAC,SAAS,WAAU,IAAI,gBAAgB;AAC9C,UAAM,EAAC,SAAS,gBAAe,IAAI;AAAA,MACjC,GAAG,QAAQ,QAAQ;AAAA,IACrB;AACA,SAAK,cAAc;AAAA,MACjB,aAAa,QAAQ;AAAA,MACrB,aAAa,cAAc,cAAc,SAAS;AAAA,MAClD,kBAAkB,mBAAmB;AAAA,IACvC;AACA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,IACE,MACA,OACA,OAA+B,CAAC,GAC1B;AACN,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,IAAI,GAAG;AACtB,WAAK,QAAQ,IAAI,EAAG,KAAK,MAAM;AAAA,IACjC,OAAO;AACL,WAAK,QAAQ,IAAI,IAAI,CAAC,MAAM;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,WAAW,MAAwC;AACjD,WAAO,OAAO,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,EACrE;AAAA,EAEA,MAAM,SAAwB;AAC5B,UAAM,kBAAgC,OAAO,QAAQ,KAAK,OAAO,EAC9D,IAAI,CAAC,CAAC,YAAY,MAAM,MAAM;AAC7B,YAAM,OAAO,GAAG,KAAK,YAAY,IAAI,UAAU;AAE/C,aAAO,OAAO,IAAI,CAAC,EAAC,OAAO,KAAI,MAAM;AACnC,eAAO;AAAA,UACL;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,MAAM,KAAK,WAAW,EAAC,GAAG,MAAM,GAAG,KAAK,YAAW,CAAC;AAAA,QACtD;AAAA,MACF,CAAC;AAAA,IACH,CAAC,EACA,KAAK;AAER,QAAI;AACF,YAAM,MAAM,KAAK,WAAW;AAAA,QAC1B,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAC,QAAQ,gBAAe,CAAC;AAAA,MAChD,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM,UAAU,WAAW;AAC3B,UAAI,YAAY,iBAAiB,SAAS,OAAO,UAAU,WAAW;AACpE,gBAAQ,OAAO,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF","sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention */\nimport {fetch} from '@shopify/cli-kit/node/http';\n\nimport {getBugsnag} from './bugsnag.js';\nimport {loadPackageJson} from './utils.js';\n\ninterface GodogEvent {\n name: string;\n type: string;\n value: number;\n tags: string[];\n}\n\ntype MetricCollection = Record<\n string,\n [{value: number; tags: Record<string, string>}]\n>;\n\ninterface MetricsExporterOptions {\n ciProvider: string;\n rootPath: string;\n}\n\nexport enum MetricName {\n BuildTime = 'build_time',\n NumFilesRequested = 'num_files_requested',\n NumFilesUploaded = 'num_files_uploaded',\n TotalSizeUploaded = 'total_size_uploaded',\n TotalSizeRequested = 'total_size_requested',\n TotalTime = 'total_time',\n UploadTime = 'upload_time',\n DeploymentCompletedTime = 'deployment_completed_time',\n DeploymentRoutableTime = 'deployment_routable_time',\n}\n\nexport class MetricsExporter {\n private metrics: MetricCollection = {};\n private readonly metricPrefix: string = 'oxygen.cli';\n private readonly defaultTags: Record<string, string>;\n private readonly exportUrl: string;\n\n constructor(options: MetricsExporterOptions) {\n const {version: cliVersion} = loadPackageJson();\n const {version: hydrogenVersion} = loadPackageJson(\n `${options.rootPath}/node_modules/@shopify/hydrogen`,\n );\n this.defaultTags = {\n ci_provider: options.ciProvider,\n cli_version: `oxygen-cli@${cliVersion || 'unknown'}`,\n hydrogen_version: hydrogenVersion || 'unknown',\n };\n this.exportUrl = 'https://metrics.myshopify.dev';\n }\n\n add(\n name: MetricName,\n value: number,\n tags: Record<string, string> = {},\n ): void {\n const metric = {\n value,\n tags,\n };\n\n if (this.metrics[name]) {\n this.metrics[name]!.push(metric);\n } else {\n this.metrics[name] = [metric];\n }\n }\n\n formatTags(tags: Record<string, string>): string[] {\n return Object.entries(tags).map(([key, value]) => `${key}:${value}`);\n }\n\n async export(): Promise<void> {\n const metricsToExport: GodogEvent[] = Object.entries(this.metrics)\n .map(([metricName, values]) => {\n const name = `${this.metricPrefix}.${metricName}`;\n\n return values.map(({value, tags}) => {\n return {\n name,\n type: 'gauge',\n value,\n tags: this.formatTags({...tags, ...this.defaultTags}),\n };\n });\n })\n .flat();\n\n try {\n await fetch(this.exportUrl, {\n method: 'POST',\n body: JSON.stringify({events: metricsToExport}),\n });\n } catch (error) {\n const Bugsnag = getBugsnag();\n if (Bugsnag && (error instanceof Error || typeof error === 'string')) {\n Bugsnag.notify(error);\n }\n }\n }\n}\n"]}
@@ -154,6 +154,14 @@
154
154
  "required": false,
155
155
  "allowNo": false,
156
156
  "type": "boolean"
157
+ },
158
+ "environmentFile": {
159
+ "description": "Path to an environment file to override existing environment variables for the deployment.",
160
+ "name": "environmentFile",
161
+ "required": false,
162
+ "hasDynamicHelp": false,
163
+ "multiple": false,
164
+ "type": "option"
157
165
  }
158
166
  },
159
167
  "hasDynamicHelp": false,
@@ -174,5 +182,5 @@
174
182
  ]
175
183
  }
176
184
  },
177
- "version": "4.0.4-unstable.202402091547.0"
185
+ "version": "4.1.0"
178
186
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "4.0.4-unstable.202402091547.0",
8
+ "version": "4.1.0",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "build": "tsup --sourcemap --clean --config ./tsup.config.ts && oclif manifest",
@@ -28,7 +28,8 @@
28
28
  "node": ">=16.14.0"
29
29
  },
30
30
  "exports": {
31
- "./deploy": "./dist/deploy/index.js"
31
+ "./deploy": "./dist/deploy/index.js",
32
+ "./utils": "./dist/utils/index.js"
32
33
  },
33
34
  "files": [
34
35
  "dist",
@@ -39,7 +40,8 @@
39
40
  "@bugsnag/core": "^7.19.0",
40
41
  "@bugsnag/js": "^7.22.4",
41
42
  "@bugsnag/node": "^7.19.0",
42
- "async": "^3.2.5"
43
+ "async": "^3.2.5",
44
+ "dotenv": "^16.4.1"
43
45
  },
44
46
  "peerDependencies": {
45
47
  "@oclif/core": "^2.11.7",