@shopify/oxygen-cli 1.3.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. package/README.md +3 -3
  2. package/dist/commands/oxygen/deploy.d.ts +3 -3
  3. package/dist/commands/oxygen/deploy.js +6 -6
  4. package/dist/deploy/build-cancel.d.ts +9 -2
  5. package/dist/deploy/build-cancel.js +4 -3
  6. package/dist/deploy/build-cancel.test.js +21 -4
  7. package/dist/deploy/build-initiate.d.ts +9 -2
  8. package/dist/deploy/build-initiate.js +4 -3
  9. package/dist/deploy/build-initiate.test.js +19 -8
  10. package/dist/deploy/build-project.d.ts +7 -2
  11. package/dist/deploy/build-project.js +34 -19
  12. package/dist/deploy/build-project.test.js +14 -8
  13. package/dist/deploy/deployment-cancel.d.ts +9 -2
  14. package/dist/deploy/deployment-cancel.js +4 -3
  15. package/dist/deploy/deployment-cancel.test.js +19 -16
  16. package/dist/deploy/deployment-complete.d.ts +2 -2
  17. package/dist/deploy/deployment-initiate.d.ts +10 -4
  18. package/dist/deploy/deployment-initiate.js +4 -3
  19. package/dist/deploy/deployment-initiate.test.js +26 -10
  20. package/dist/deploy/get-upload-files.d.ts +2 -2
  21. package/dist/deploy/index.d.ts +10 -3
  22. package/dist/deploy/index.js +40 -23
  23. package/dist/deploy/metadata.d.ts +4 -3
  24. package/dist/deploy/metadata.js +3 -3
  25. package/dist/deploy/metadata.test.js +4 -4
  26. package/dist/deploy/types.d.ts +10 -2
  27. package/dist/deploy/upload-files.d.ts +9 -2
  28. package/dist/deploy/upload-files.js +7 -4
  29. package/dist/deploy/upload-files.test.js +37 -18
  30. package/dist/utils/test-helper.d.ts +2 -2
  31. package/dist/utils/test-helper.js +1 -0
  32. package/dist/utils/utils.d.ts +3 -3
  33. package/oclif.manifest.json +4 -5
  34. package/package.json +7 -7
package/README.md CHANGED
@@ -35,14 +35,14 @@ oxygen:deploy [options]
35
35
  ### Options
36
36
 
37
37
  - -t, --token <token>: (required) Oxygen deployment token. Can also be set using the `OXYGEN_DEPLOYMENT_TOKEN` environment variable (see below).
38
- - -r, --rootPath <rootPath>: Root path (defaults to the current working directory).
38
+ - -p, --path <rootPath>: Root path (defaults to the current working directory).
39
39
  - -e, --environmentTag <environmentTag>: Tag of the environment to deploy to. Defaults to branch name in supported CI environments (see below).
40
40
  - -w, --workerFolder <workerFolder>: Worker folder (default: `dist/worker/`).
41
41
  - -a, --assetsFolder <assetsFolder>: Assets folder (default: `dist/client/`).
42
42
  - -o, --workerOnly: Worker only deployment.
43
43
  - -s, --skipBuild: Skip running build command.
44
- - -p, --publicDeployment: set the deployment to be publicly accessible.
45
44
  - -b, --buildCommand <buildCommand>: Build command (default: `yarn build`).
45
+ - --publicDeployment: set the deployment to be publicly accessible.
46
46
  - --metadataUrl <metadataUrl>: URL that links to the deployment.
47
47
  - --metadataUser <metadataUser>: User that initiated the deployment.
48
48
  - --metadataVersion <metadataVersion>: A version identifier for the deployment.
@@ -52,7 +52,7 @@ oxygen:deploy [options]
52
52
  ### Example:
53
53
 
54
54
  ```
55
- oxygen:deploy -t my-deployment-token -e staging --rootPath="/my-project" --workerOnly
55
+ oxygen:deploy -t my-deployment-token -e staging --path="/my-project" --workerOnly
56
56
  ```
57
57
 
58
58
  This command will deploy your Oxygen project to the staging environment with the provided deployment token and root path. No static assets will be uploaded.
@@ -1,13 +1,13 @@
1
1
  import * as _oclif_core_lib_interfaces_parser_js from '@oclif/core/lib/interfaces/parser.js';
2
2
  import { Command } from '@oclif/core';
3
- import { DeployConfig } from '../../deploy/types.js';
3
+ import { DeploymentConfig } from '../../deploy/types.js';
4
4
 
5
5
  declare class Deploy extends Command {
6
6
  static description: string;
7
7
  static hidden: boolean;
8
8
  static flags: {
9
9
  token: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
10
- rootPath: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
10
+ path: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
11
11
  environmentTag: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
12
12
  workerFolder: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
13
13
  assetsFolder: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
@@ -22,6 +22,6 @@ declare class Deploy extends Command {
22
22
  static hasCustomBuildCommand: boolean;
23
23
  run(): Promise<void>;
24
24
  }
25
- declare function runInit(options: DeployConfig): void;
25
+ declare function runInit(config: DeploymentConfig): void;
26
26
 
27
27
  export { Deploy, runInit };
@@ -14,8 +14,8 @@ class Deploy extends Command {
14
14
  env: "OXYGEN_DEPLOYMENT_TOKEN",
15
15
  required: true
16
16
  }),
17
- rootPath: Flags.string({
18
- char: "r",
17
+ path: Flags.string({
18
+ char: "p",
19
19
  description: "Root path",
20
20
  default: "./",
21
21
  required: false
@@ -60,7 +60,6 @@ class Deploy extends Command {
60
60
  }
61
61
  }),
62
62
  publicDeployment: Flags.boolean({
63
- char: "p",
64
63
  env: "OXYGEN_PUBLIC_DEPLOYMENT",
65
64
  description: "Marks a preview deployment as publicly accessible.",
66
65
  required: false,
@@ -93,6 +92,7 @@ class Deploy extends Command {
93
92
  const config = {
94
93
  assetsDir: normalizePath(flags.assetsFolder),
95
94
  buildCommand: flags.buildCommand,
95
+ buildOutput: true,
96
96
  deploymentToken: parseToken(flags.token),
97
97
  environmentTag: flags.environmentTag,
98
98
  deploymentUrl,
@@ -102,7 +102,7 @@ class Deploy extends Command {
102
102
  version: flags.metadataVersion
103
103
  },
104
104
  publicDeployment: flags.publicDeployment,
105
- rootPath: normalizePath(flags.rootPath),
105
+ rootPath: normalizePath(flags.path),
106
106
  skipBuild: flags.skipBuild,
107
107
  workerDir: normalizePath(flags.workerFolder),
108
108
  workerOnly: flags.workerOnly
@@ -122,8 +122,8 @@ class Deploy extends Command {
122
122
  }
123
123
  }
124
124
  }
125
- function runInit(options) {
126
- createDeploy(options);
125
+ function runInit(config) {
126
+ createDeploy({ config });
127
127
  }
128
128
 
129
129
  export { Deploy, runInit };
@@ -1,6 +1,13 @@
1
- import { DeployConfig } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig } from './types.js';
2
3
  import { BuildCancelResponse } from './graphql/build-cancel.js';
3
4
 
4
- declare function buildCancel(config: DeployConfig, buildId: string, reason: string): Promise<BuildCancelResponse>;
5
+ interface BuildCancelOptions {
6
+ config: DeploymentConfig;
7
+ buildId: string;
8
+ reason: string;
9
+ logger: Logger;
10
+ }
11
+ declare function buildCancel(options: BuildCancelOptions): Promise<BuildCancelResponse>;
5
12
 
6
13
  export { buildCancel };
@@ -1,10 +1,11 @@
1
1
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
2
2
  import { AbortError } from '@shopify/cli-kit/node/error';
3
3
  import { outputInfo } from '@shopify/cli-kit/node/output';
4
- import { Header, stderrLogger, errorHandler } from '../utils/utils.js';
4
+ import { Header, errorHandler } from '../utils/utils.js';
5
5
  import { BuildCancelQuery } from './graphql/build-cancel.js';
6
6
 
7
- async function buildCancel(config, buildId, reason) {
7
+ async function buildCancel(options) {
8
+ const { config, buildId, reason, logger } = options;
8
9
  const variables = {
9
10
  buildId,
10
11
  reason
@@ -25,7 +26,7 @@ async function buildCancel(config, buildId, reason) {
25
26
  `Failed to cancel build: ${response.buildCancel.userErrors[0]?.message}`
26
27
  );
27
28
  }
28
- outputInfo(`Build with id ${buildId} cancelled.`, stderrLogger);
29
+ outputInfo(`Build with id ${buildId} cancelled.`, logger);
29
30
  return response.buildCancel;
30
31
  } catch (error) {
31
32
  errorHandler(error);
@@ -2,7 +2,7 @@ import { AbortError } from '@shopify/cli-kit/node/error';
2
2
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
3
3
  import { vi, describe, test, expect } from 'vitest';
4
4
  import { createTestConfig } from '../utils/test-helper.js';
5
- import { Header } from '../utils/utils.js';
5
+ import { stderrLogger, Header } from '../utils/utils.js';
6
6
  import { buildCancel } from './build-cancel.js';
7
7
 
8
8
  vi.mock("@shopify/cli-kit/node/api/graphql");
@@ -20,7 +20,12 @@ describe("BuildCancel", () => {
20
20
  }
21
21
  };
22
22
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
23
- const cancelResponse = await buildCancel(testConfig, "build-1", "because");
23
+ const cancelResponse = await buildCancel({
24
+ config: testConfig,
25
+ buildId: "build-1",
26
+ reason: "because",
27
+ logger: stderrLogger
28
+ });
24
29
  expect(cancelResponse).toEqual(response.buildCancel);
25
30
  expect(graphqlRequest).toHaveBeenCalledWith({
26
31
  query: expect.any(String),
@@ -47,7 +52,14 @@ describe("BuildCancel", () => {
47
52
  }
48
53
  };
49
54
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
50
- await expect(buildCancel(testConfig, "build-1", "because")).rejects.toThrow(
55
+ await expect(
56
+ buildCancel({
57
+ config: testConfig,
58
+ buildId: "build-1",
59
+ reason: "because",
60
+ logger: stderrLogger
61
+ })
62
+ ).rejects.toThrow(
51
63
  new AbortError(
52
64
  `Failed to cancel build: ${response.buildCancel.userErrors[0]?.message}`
53
65
  )
@@ -60,7 +72,12 @@ describe("BuildCancel", () => {
60
72
  vi.mocked(graphqlRequest).mockRejectedValueOnce(error);
61
73
  try {
62
74
  await expect(
63
- buildCancel(testConfig, "build-1", "because")
75
+ buildCancel({
76
+ config: testConfig,
77
+ buildId: "build-1",
78
+ reason: "because",
79
+ logger: stderrLogger
80
+ })
64
81
  ).rejects.toThrow(
65
82
  new AbortError(
66
83
  "You are not authorized to perform this action. Please check your deployment token."
@@ -1,6 +1,13 @@
1
- import { DeployConfig, EnvironmentInput } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig, EnvironmentInput } from './types.js';
2
3
  import { BuildInitiateResponse } from './graphql/build-initiate.js';
3
4
 
4
- declare function buildInitiate(config: DeployConfig, environment?: EnvironmentInput, labels?: string[]): Promise<BuildInitiateResponse>;
5
+ interface BuildInitiateOptions {
6
+ config: DeploymentConfig;
7
+ logger: Logger;
8
+ environment?: EnvironmentInput;
9
+ labels?: string[];
10
+ }
11
+ declare function buildInitiate(options: BuildInitiateOptions): Promise<BuildInitiateResponse>;
5
12
 
6
13
  export { buildInitiate };
@@ -1,10 +1,11 @@
1
1
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
2
2
  import { AbortError } from '@shopify/cli-kit/node/error';
3
3
  import { outputCompleted } from '@shopify/cli-kit/node/output';
4
- import { Header, stderrLogger, errorHandler } from '../utils/utils.js';
4
+ import { Header, errorHandler } from '../utils/utils.js';
5
5
  import { BuildInitiateQuery } from './graphql/build-initiate.js';
6
6
 
7
- async function buildInitiate(config, environment, labels = []) {
7
+ async function buildInitiate(options) {
8
+ const { config, logger, environment, labels = [] } = options;
8
9
  const variables = {
9
10
  environment,
10
11
  labels
@@ -27,7 +28,7 @@ async function buildInitiate(config, environment, labels = []) {
27
28
  }
28
29
  outputCompleted(
29
30
  `Build initiated successfully with id ${response.buildInitiate.build.id}.`,
30
- stderrLogger
31
+ logger
31
32
  );
32
33
  return response.buildInitiate;
33
34
  } catch (error) {
@@ -2,7 +2,7 @@ import { AbortError } from '@shopify/cli-kit/node/error';
2
2
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
3
3
  import { outputCompleted } from '@shopify/cli-kit/node/output';
4
4
  import { vi, describe, test, expect } from 'vitest';
5
- import { Header, stderrLogger } from '../utils/utils.js';
5
+ import { stderrLogger, Header } from '../utils/utils.js';
6
6
  import { createTestConfig } from '../utils/test-helper.js';
7
7
  import { buildInitiate } from './build-initiate.js';
8
8
 
@@ -20,13 +20,14 @@ describe("BuildInitiate", () => {
20
20
  }
21
21
  };
22
22
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
23
- const initiateResponse = await buildInitiate(
24
- testConfig,
25
- {
23
+ const initiateResponse = await buildInitiate({
24
+ config: testConfig,
25
+ environment: {
26
26
  tag: testConfig.environmentTag
27
27
  },
28
- []
29
- );
28
+ labels: [],
29
+ logger: stderrLogger
30
+ });
30
31
  expect(initiateResponse).toEqual(response.buildInitiate);
31
32
  expect(graphqlRequest).toHaveBeenCalledWith({
32
33
  query: expect.any(String),
@@ -55,7 +56,12 @@ describe("BuildInitiate", () => {
55
56
  };
56
57
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
57
58
  await expect(
58
- buildInitiate(testConfig, { tag: "preview" }, [])
59
+ buildInitiate({
60
+ config: testConfig,
61
+ environment: { tag: "preview" },
62
+ labels: [],
63
+ logger: stderrLogger
64
+ })
59
65
  ).rejects.toThrow(
60
66
  new AbortError(
61
67
  `Failed to create build. ${response.buildInitiate.userErrors[0]?.message}`
@@ -69,7 +75,12 @@ describe("BuildInitiate", () => {
69
75
  vi.mocked(graphqlRequest).mockRejectedValueOnce(error);
70
76
  try {
71
77
  await expect(
72
- buildInitiate(testConfig, { tag: "preview" }, [])
78
+ buildInitiate({
79
+ config: testConfig,
80
+ environment: { tag: "preview" },
81
+ labels: [],
82
+ logger: stderrLogger
83
+ })
73
84
  ).rejects.toThrow(
74
85
  new AbortError(
75
86
  "You are not authorized to perform this action. Please check your deployment token."
@@ -1,5 +1,10 @@
1
- import { DeployConfig } from './types.js';
1
+ import { DeploymentConfig, DeploymentHooks } from './types.js';
2
2
 
3
- declare function buildProject(config: DeployConfig, assetPath?: string): Promise<void>;
3
+ interface BuildProjectOptions {
4
+ config: DeploymentConfig;
5
+ assetPath?: string;
6
+ hooks?: DeploymentHooks;
7
+ }
8
+ declare function buildProject(options: BuildProjectOptions): Promise<void>;
4
9
 
5
10
  export { buildProject };
@@ -1,28 +1,43 @@
1
1
  import { spawn } from 'child_process';
2
2
 
3
- async function buildProject(config, assetPath) {
3
+ async function buildProject(options) {
4
+ const { config, assetPath, hooks } = options;
5
+ hooks?.onBuildStart?.();
4
6
  const assetPathEnvironment = assetPath ? { HYDROGEN_ASSET_BASE_URL: assetPath } : {};
5
- await new Promise((resolve, reject) => {
6
- const buildCommand = spawn(config.buildCommand, [], {
7
- stdio: ["inherit", "pipe", "inherit"],
8
- env: {
9
- // eslint-disable-next-line no-process-env
10
- ...process.env,
11
- ...assetPathEnvironment
12
- },
13
- cwd: config.rootPath,
14
- shell: true
15
- });
16
- buildCommand.stdout.pipe(process.stderr);
17
- buildCommand.on("close", (code) => {
18
- if (code !== 0) {
19
- reject(code);
7
+ try {
8
+ await new Promise((resolve, reject) => {
9
+ const buildCommand = spawn(config.buildCommand, [], {
10
+ stdio: config.buildOutput ? ["inherit", "pipe", "inherit"] : ["ignore", "ignore", "pipe"],
11
+ env: {
12
+ // eslint-disable-next-line no-process-env
13
+ ...process.env,
14
+ ...assetPathEnvironment
15
+ },
16
+ cwd: config.rootPath,
17
+ shell: true
18
+ });
19
+ let stderrOutput = "";
20
+ if (buildCommand.stderr) {
21
+ buildCommand.stderr.on("data", (data) => {
22
+ stderrOutput += data;
23
+ });
24
+ }
25
+ if (config.buildOutput && buildCommand.stdout) {
26
+ buildCommand.stdout.pipe(process.stderr);
20
27
  }
21
- resolve(code);
28
+ buildCommand.on("close", (code) => {
29
+ if (code !== 0) {
30
+ hooks?.onBuildError?.(new Error(stderrOutput));
31
+ reject(code);
32
+ return;
33
+ }
34
+ hooks?.onBuildComplete?.();
35
+ resolve(code);
36
+ });
22
37
  });
23
- }).catch((error) => {
38
+ } catch (error) {
24
39
  throw new Error(`Build failed with error code: ${error}`);
25
- });
40
+ }
26
41
  }
27
42
 
28
43
  export { buildProject };
@@ -30,7 +30,11 @@ test("BuildProject builds the project successfully", async () => {
30
30
  buildCommand: "npm run build"
31
31
  };
32
32
  const assetPath = "https://example.com/assets";
33
- await buildProject(config, assetPath);
33
+ const hooks = {
34
+ onBuildStart: vi.fn(),
35
+ onBuildComplete: vi.fn()
36
+ };
37
+ await buildProject({ config, assetPath, hooks });
34
38
  expect(spawn).toBeCalledWith("npm run build", [], {
35
39
  cwd: "rootFolder",
36
40
  shell: true,
@@ -41,15 +45,17 @@ test("BuildProject builds the project successfully", async () => {
41
45
  HYDROGEN_ASSET_BASE_URL: "https://example.com/assets"
42
46
  }
43
47
  });
48
+ expect(hooks.onBuildStart).toBeCalled();
49
+ expect(hooks.onBuildComplete).toBeCalled();
44
50
  });
45
51
  test("should throw error on build command failure", async () => {
46
52
  returnCode = 1;
47
- ({
48
- ...testConfig,
49
- buildCommand: "yarn build"
50
- });
53
+ const hooks = {
54
+ onBuildError: vi.fn()
55
+ };
51
56
  const assetPath = "https://example.com/assets";
52
- await expect(() => buildProject(testConfig, assetPath)).rejects.toThrow(
53
- "Build failed with error code: 1"
54
- );
57
+ await expect(
58
+ () => buildProject({ config: testConfig, assetPath, hooks })
59
+ ).rejects.toThrow("Build failed with error code: 1");
60
+ expect(hooks.onBuildError).toBeCalled();
55
61
  });
@@ -1,10 +1,17 @@
1
- import { DeployConfig } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig } from './types.js';
2
3
  import { DeploymentCancelResponse } from './graphql/deployment-cancel.js';
3
4
 
4
5
  declare enum DeploymentCancelReason {
5
6
  Failed = "FAILED",
6
7
  Cancelled = "CANCELLED"
7
8
  }
8
- declare function deploymentCancel(config: DeployConfig, deploymentId: string, reason: DeploymentCancelReason): Promise<DeploymentCancelResponse>;
9
+ interface DeploymentCancelOptions {
10
+ config: DeploymentConfig;
11
+ deploymentId: string;
12
+ reason: DeploymentCancelReason;
13
+ logger: Logger;
14
+ }
15
+ declare function deploymentCancel(options: DeploymentCancelOptions): Promise<DeploymentCancelResponse>;
9
16
 
10
17
  export { DeploymentCancelReason, deploymentCancel };
@@ -1,7 +1,7 @@
1
1
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
2
2
  import { AbortError } from '@shopify/cli-kit/node/error';
3
3
  import { outputInfo } from '@shopify/cli-kit/node/output';
4
- import { Header, stderrLogger, errorHandler } from '../utils/utils.js';
4
+ import { Header, errorHandler } from '../utils/utils.js';
5
5
  import { DeploymentCancelQuery } from './graphql/deployment-cancel.js';
6
6
 
7
7
  var DeploymentCancelReason = /* @__PURE__ */ ((DeploymentCancelReason2) => {
@@ -9,7 +9,8 @@ var DeploymentCancelReason = /* @__PURE__ */ ((DeploymentCancelReason2) => {
9
9
  DeploymentCancelReason2["Cancelled"] = "CANCELLED";
10
10
  return DeploymentCancelReason2;
11
11
  })(DeploymentCancelReason || {});
12
- async function deploymentCancel(config, deploymentId, reason) {
12
+ async function deploymentCancel(options) {
13
+ const { config, deploymentId, reason, logger } = options;
13
14
  const variables = {
14
15
  deploymentId,
15
16
  reason
@@ -30,7 +31,7 @@ async function deploymentCancel(config, deploymentId, reason) {
30
31
  `Failed to cancel deployment: ${response.deploymentCancel.userErrors[0]?.message}`
31
32
  );
32
33
  }
33
- outputInfo(`Deployment with id ${deploymentId} cancelled.`, stderrLogger);
34
+ outputInfo(`Deployment with id ${deploymentId} cancelled.`, logger);
34
35
  return response.deploymentCancel;
35
36
  } catch (error) {
36
37
  errorHandler(error);
@@ -2,7 +2,7 @@ import { AbortError } from '@shopify/cli-kit/node/error';
2
2
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
3
3
  import { vi, describe, test, expect } from 'vitest';
4
4
  import { createTestConfig } from '../utils/test-helper.js';
5
- import { Header } from '../utils/utils.js';
5
+ import { stderrLogger, Header } from '../utils/utils.js';
6
6
  import { deploymentCancel, DeploymentCancelReason } from './deployment-cancel.js';
7
7
 
8
8
  vi.mock("@shopify/cli-kit/node/api/graphql");
@@ -19,11 +19,12 @@ describe("DeploymentComplete", () => {
19
19
  }
20
20
  };
21
21
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
22
- const completeResponse = await deploymentCancel(
23
- testConfig,
24
- "deployment-1",
25
- DeploymentCancelReason.Failed
26
- );
22
+ const completeResponse = await deploymentCancel({
23
+ config: testConfig,
24
+ deploymentId: "deployment-1",
25
+ reason: DeploymentCancelReason.Failed,
26
+ logger: stderrLogger
27
+ });
27
28
  expect(completeResponse).toEqual(response.deploymentCancel);
28
29
  expect(graphqlRequest).toHaveBeenCalledWith({
29
30
  query: expect.any(String),
@@ -51,11 +52,12 @@ describe("DeploymentComplete", () => {
51
52
  };
52
53
  vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
53
54
  await expect(
54
- deploymentCancel(
55
- testConfig,
56
- "deployment-1",
57
- DeploymentCancelReason.Failed
58
- )
55
+ deploymentCancel({
56
+ config: testConfig,
57
+ deploymentId: "deployment-1",
58
+ reason: DeploymentCancelReason.Failed,
59
+ logger: stderrLogger
60
+ })
59
61
  ).rejects.toThrow(
60
62
  new AbortError(
61
63
  `Failed to cancel deployment: ${response.deploymentCancel.userErrors[0]?.message}`
@@ -69,11 +71,12 @@ describe("DeploymentComplete", () => {
69
71
  vi.mocked(graphqlRequest).mockRejectedValueOnce(error);
70
72
  try {
71
73
  await expect(
72
- deploymentCancel(
73
- testConfig,
74
- "deployment-1",
75
- DeploymentCancelReason.Failed
76
- )
74
+ deploymentCancel({
75
+ config: testConfig,
76
+ deploymentId: "deployment-1",
77
+ reason: DeploymentCancelReason.Failed,
78
+ logger: stderrLogger
79
+ })
77
80
  ).rejects.toThrow(
78
81
  new AbortError(
79
82
  "You are not authorized to perform this action. Please check your deployment token."
@@ -1,6 +1,6 @@
1
1
  import { DeploymentCompleteResponse } from './graphql/deployment-complete.js';
2
- import { DeployConfig } from './types.js';
2
+ import { DeploymentConfig } from './types.js';
3
3
 
4
- declare function deploymentComplete(config: DeployConfig, deploymentId: string): Promise<DeploymentCompleteResponse>;
4
+ declare function deploymentComplete(config: DeploymentConfig, deploymentId: string): Promise<DeploymentCompleteResponse>;
5
5
 
6
6
  export { deploymentComplete };
@@ -1,17 +1,23 @@
1
- import { DeployConfig, DeploymentManifestFile, EnvironmentInput } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig, DeploymentManifestFile, EnvironmentInput } from './types.js';
2
3
  import { DeploymentInitiateResponse } from './graphql/deployment-initiate.js';
3
4
 
4
5
  type DeploymentInitiateInput = {
5
6
  buildId: string;
6
7
  environment?: never;
7
- manifest: DeploymentManifestFile[];
8
8
  labels?: string[];
9
+ manifest: DeploymentManifestFile[];
9
10
  } | {
10
11
  environment?: EnvironmentInput;
11
12
  buildId?: never;
12
- manifest: DeploymentManifestFile[];
13
13
  labels?: string[];
14
+ manifest: DeploymentManifestFile[];
14
15
  };
15
- declare function deploymentInitiate(config: DeployConfig, input: DeploymentInitiateInput): Promise<DeploymentInitiateResponse>;
16
+ interface DeploymentInitiateOptions {
17
+ config: DeploymentConfig;
18
+ input: DeploymentInitiateInput;
19
+ logger: Logger;
20
+ }
21
+ declare function deploymentInitiate(options: DeploymentInitiateOptions): Promise<DeploymentInitiateResponse>;
16
22
 
17
23
  export { deploymentInitiate };
@@ -1,10 +1,11 @@
1
1
  import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
2
2
  import { AbortError } from '@shopify/cli-kit/node/error';
3
3
  import { outputCompleted } from '@shopify/cli-kit/node/output';
4
- import { Header, stderrLogger, errorHandler } from '../utils/utils.js';
4
+ import { Header, errorHandler } from '../utils/utils.js';
5
5
  import { DeploymentInitiateQuery } from './graphql/deployment-initiate.js';
6
6
 
7
- async function deploymentInitiate(config, input) {
7
+ async function deploymentInitiate(options) {
8
+ const { config, input, logger } = options;
8
9
  const variables = {
9
10
  buildId: input.buildId,
10
11
  environment: input.environment,
@@ -30,7 +31,7 @@ async function deploymentInitiate(config, input) {
30
31
  }
31
32
  outputCompleted(
32
33
  `Deployment initiated, ${response.deploymentInitiate.deploymentTargets.length} files to upload.`,
33
- stderrLogger
34
+ logger
34
35
  );
35
36
  return response.deploymentInitiate;
36
37
  } catch (error) {
@@ -3,7 +3,7 @@ import { graphqlRequest } from '@shopify/cli-kit/node/api/graphql';
3
3
  import { outputCompleted } from '@shopify/cli-kit/node/output';
4
4
  import { vi, describe, test, expect } from 'vitest';
5
5
  import { createTestConfig } from '../utils/test-helper.js';
6
- import { Header, stderrLogger } from '../utils/utils.js';
6
+ import { stderrLogger, Header } from '../utils/utils.js';
7
7
  import { deploymentInitiate } from './deployment-initiate.js';
8
8
 
9
9
  vi.mock("@shopify/cli-kit/node/api/graphql");
@@ -38,9 +38,13 @@ const testResponse = {
38
38
  describe("DeploymentInitiate", () => {
39
39
  test("should initiate a deployment with a buildId", async () => {
40
40
  vi.mocked(graphqlRequest).mockResolvedValueOnce(testResponse);
41
- const initiateResponse = await deploymentInitiate(testConfig, {
42
- buildId: "build-1",
43
- manifest: testManifest
41
+ const initiateResponse = await deploymentInitiate({
42
+ config: testConfig,
43
+ input: {
44
+ buildId: "build-1",
45
+ manifest: testManifest
46
+ },
47
+ logger: stderrLogger
44
48
  });
45
49
  expect(initiateResponse).toEqual(testResponse.deploymentInitiate);
46
50
  expect(graphqlRequest).toHaveBeenCalledWith({
@@ -65,10 +69,14 @@ describe("DeploymentInitiate", () => {
65
69
  });
66
70
  test("should initiate a deployment with an environmentName", async () => {
67
71
  vi.mocked(graphqlRequest).mockResolvedValueOnce(testResponse);
68
- const initiateResponse = await deploymentInitiate(testConfig, {
69
- buildId: void 0,
70
- environment: { tag: "preview" },
71
- manifest: testManifest
72
+ const initiateResponse = await deploymentInitiate({
73
+ config: testConfig,
74
+ input: {
75
+ buildId: void 0,
76
+ environment: { tag: "preview" },
77
+ manifest: testManifest
78
+ },
79
+ logger: stderrLogger
72
80
  });
73
81
  expect(initiateResponse).toEqual(testResponse.deploymentInitiate);
74
82
  expect(graphqlRequest).toHaveBeenCalledWith({
@@ -108,7 +116,11 @@ describe("DeploymentInitiate", () => {
108
116
  manifest: testManifest
109
117
  };
110
118
  await expect(
111
- deploymentInitiate(testConfig, deploymentInitData)
119
+ deploymentInitiate({
120
+ config: testConfig,
121
+ input: deploymentInitData,
122
+ logger: stderrLogger
123
+ })
112
124
  ).rejects.toThrow(
113
125
  new AbortError(
114
126
  `Failed to create deployment. ${response.deploymentInitiate.userErrors[0]?.message}`
@@ -127,7 +139,11 @@ describe("DeploymentInitiate", () => {
127
139
  manifest: testManifest
128
140
  };
129
141
  await expect(
130
- deploymentInitiate(testConfig, deploymentInitData)
142
+ deploymentInitiate({
143
+ config: testConfig,
144
+ input: deploymentInitData,
145
+ logger: stderrLogger
146
+ })
131
147
  ).rejects.toThrow(
132
148
  new AbortError(
133
149
  "You are not authorized to perform this action. Please check your deployment token."
@@ -1,5 +1,5 @@
1
- import { DeployConfig, DeploymentManifestFile } from './types.js';
1
+ import { DeploymentConfig, DeploymentManifestFile } from './types.js';
2
2
 
3
- declare function getUploadFiles(config: DeployConfig): Promise<DeploymentManifestFile[]>;
3
+ declare function getUploadFiles(config: DeploymentConfig): Promise<DeploymentManifestFile[]>;
4
4
 
5
5
  export { getUploadFiles };
@@ -1,5 +1,12 @@
1
- import { DeployConfig } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig, DeploymentHooks } from './types.js';
3
+ export { parseToken } from '../utils/utils.js';
2
4
 
3
- declare function createDeploy(config: DeployConfig): Promise<void>;
5
+ interface CreateDeployOptions {
6
+ config: DeploymentConfig;
7
+ hooks?: DeploymentHooks;
8
+ logger?: Logger;
9
+ }
10
+ declare function createDeploy(options: CreateDeployOptions): Promise<string | undefined>;
4
11
 
5
- export { createDeploy };
12
+ export { DeploymentConfig, DeploymentHooks, createDeploy };
@@ -1,5 +1,6 @@
1
1
  import { outputSuccess, outputInfo, outputWarn, consoleError } from '@shopify/cli-kit/node/output';
2
- import { verifyConfig, stderrLogger } from '../utils/utils.js';
2
+ import { stderrLogger, verifyConfig } from '../utils/utils.js';
3
+ export { parseToken } from '../utils/utils.js';
3
4
  import { buildInitiate } from './build-initiate.js';
4
5
  import { buildCancel } from './build-cancel.js';
5
6
  import { getUploadFiles } from './get-upload-files.js';
@@ -10,32 +11,43 @@ import { uploadFiles } from './upload-files.js';
10
11
  import { buildProject } from './build-project.js';
11
12
  import { getMetadata, createLabels, getEnvironmentInput } from './metadata.js';
12
13
 
13
- async function createDeploy(config) {
14
+ async function createDeploy(options) {
15
+ const { config, hooks } = options;
16
+ const logger = options.logger ?? stderrLogger;
14
17
  const build = {};
15
18
  let buildCompleted;
16
19
  let deployment;
17
20
  try {
18
- const metadata = await getMetadata(config);
21
+ const metadata = await getMetadata(config, logger);
19
22
  const labels = createLabels(metadata);
20
23
  const environment = getEnvironmentInput(config, metadata);
21
24
  if (!config.workerOnly && !config.skipBuild) {
22
- const buildInitiateResponse = await buildInitiate(
25
+ const buildInitiateResponse = await buildInitiate({
23
26
  config,
24
27
  environment,
25
- labels
26
- );
28
+ labels,
29
+ logger
30
+ });
27
31
  build.id = buildInitiateResponse.build.id;
28
32
  build.assetPath = buildInitiateResponse.build.assetPath;
29
33
  }
30
34
  if (!config.skipBuild) {
31
- await buildProject(config, build.assetPath);
35
+ await buildProject({
36
+ config,
37
+ assetPath: build.assetPath,
38
+ hooks
39
+ });
32
40
  verifyConfig({ config, performedBuild: true });
33
41
  }
34
42
  buildCompleted = true;
35
43
  const manifest = await getUploadFiles(config);
36
44
  const deploymentInitiateInput = build.id ? { buildId: build.id, manifest } : { environment, manifest, labels };
37
- deployment = await deploymentInitiate(config, deploymentInitiateInput);
38
- await uploadFiles(config, deployment.deploymentTargets);
45
+ deployment = await deploymentInitiate({
46
+ config,
47
+ input: deploymentInitiateInput,
48
+ logger
49
+ });
50
+ await uploadFiles({ config, targets: deployment.deploymentTargets, logger });
39
51
  const deploymentCompleteOp = await deploymentComplete(
40
52
  config,
41
53
  deployment.deployment.id
@@ -44,45 +56,50 @@ async function createDeploy(config) {
44
56
  outputSuccess(
45
57
  `Deployment complete.
46
58
  ${urlMessage} preview URL: ${deploymentCompleteOp.deployment.url}`,
47
- stderrLogger
59
+ logger
48
60
  );
49
61
  if (metadata.name !== "none") {
50
62
  outputInfo(deploymentCompleteOp.deployment.url);
51
63
  }
64
+ return deploymentCompleteOp.deployment.url;
52
65
  } catch (error) {
53
66
  if (!(error instanceof Error)) {
54
67
  console.error("Unknown error", error);
55
- return;
68
+ return Promise.reject(new Error("Unknown error"));
56
69
  }
57
70
  if (build.id && !buildCompleted) {
58
71
  outputWarn(
59
72
  `Build failed with: ${error.message}, cancelling build.`,
60
- stderrLogger
73
+ logger
61
74
  );
62
- await buildCancel(config, build.id, error.message).catch((err) => {
75
+ await buildCancel({
76
+ config,
77
+ buildId: build.id,
78
+ reason: error.message,
79
+ logger
80
+ }).catch((err) => {
63
81
  if (err instanceof Error) {
64
- outputWarn(`Failed to cancel build: ${err.message}`, stderrLogger);
82
+ outputWarn(`Failed to cancel build: ${err.message}`, logger);
65
83
  }
66
84
  });
67
85
  } else if (deployment?.deployment.id) {
68
86
  outputWarn(
69
87
  `Deployment failed with: ${error.message}, cancelling deployment.`,
70
- stderrLogger
88
+ logger
71
89
  );
72
- await deploymentCancel(
90
+ await deploymentCancel({
73
91
  config,
74
- deployment.deployment.id,
75
- DeploymentCancelReason.Failed
76
- ).catch((err) => {
92
+ deploymentId: deployment.deployment.id,
93
+ reason: DeploymentCancelReason.Failed,
94
+ logger
95
+ }).catch((err) => {
77
96
  if (err instanceof Error) {
78
- outputWarn(
79
- `Failed to cancel deployment: ${err.message}`,
80
- stderrLogger
81
- );
97
+ outputWarn(`Failed to cancel deployment: ${err.message}`, logger);
82
98
  }
83
99
  });
84
100
  }
85
101
  consoleError(error.message);
102
+ return Promise.reject(error);
86
103
  }
87
104
  }
88
105
 
@@ -1,11 +1,12 @@
1
1
  import { CIMetadata } from '@shopify/cli-kit/node/context/local';
2
- import { DeployConfig, EnvironmentInput } from './types.js';
2
+ import { Logger } from '@shopify/cli-kit/node/output';
3
+ import { DeploymentConfig, EnvironmentInput } from './types.js';
3
4
 
4
5
  type Metadata = CIMetadata & {
5
6
  name: string;
6
7
  };
7
- declare function getMetadata(config: DeployConfig): Promise<Metadata>;
8
- declare function getEnvironmentInput(config: DeployConfig, metadata: CIMetadata): EnvironmentInput | undefined;
8
+ declare function getMetadata(config: DeploymentConfig, logger: Logger): Promise<Metadata>;
9
+ declare function getEnvironmentInput(config: DeploymentConfig, metadata: CIMetadata): EnvironmentInput | undefined;
9
10
  declare function createLabels(metadata: Metadata): string[];
10
11
 
11
12
  export { createLabels, getEnvironmentInput, getMetadata };
@@ -1,9 +1,9 @@
1
1
  import { ciPlatform } from '@shopify/cli-kit/node/context/local';
2
2
  import { getLatestGitCommit } from '@shopify/cli-kit/node/git';
3
3
  import { outputWarn } from '@shopify/cli-kit/node/output';
4
- import { stderrLogger, maxLabelLength } from '../utils/utils.js';
4
+ import { maxLabelLength } from '../utils/utils.js';
5
5
 
6
- async function getMetadata(config) {
6
+ async function getMetadata(config, logger) {
7
7
  const ciInfo = ciPlatform();
8
8
  let metadata = {};
9
9
  if (ciInfo.isCI && ciInfo.name !== "unknown") {
@@ -19,7 +19,7 @@ async function getMetadata(config) {
19
19
  commitMessage: gitCommit.message
20
20
  };
21
21
  } catch (error) {
22
- outputWarn("No CI metadata loaded from environment", stderrLogger);
22
+ outputWarn("No CI metadata loaded from environment", logger);
23
23
  }
24
24
  }
25
25
  return {
@@ -1,7 +1,7 @@
1
1
  import { getLatestGitCommit } from '@shopify/cli-kit/node/git';
2
2
  import { ciPlatform } from '@shopify/cli-kit/node/context/local';
3
3
  import { vi, describe, test, expect } from 'vitest';
4
- import { maxLabelLength } from '../utils/utils.js';
4
+ import { stderrLogger, maxLabelLength } from '../utils/utils.js';
5
5
  import { createTestConfig } from '../utils/test-helper.js';
6
6
  import { getMetadata, getEnvironmentInput, createLabels } from './metadata.js';
7
7
 
@@ -19,7 +19,7 @@ describe("getMetadata", () => {
19
19
  }
20
20
  });
21
21
  const testConfig = createTestConfig("/tmp/deploymentRoot/");
22
- const metadataResult = await getMetadata(testConfig);
22
+ const metadataResult = await getMetadata(testConfig, stderrLogger);
23
23
  expect(metadataResult.actor).toBe("circle_actor");
24
24
  expect(metadataResult.commitSha).toBe("circle_sha");
25
25
  expect(metadataResult.name).toBe("circle");
@@ -41,7 +41,7 @@ describe("getMetadata", () => {
41
41
  version: "custom_version",
42
42
  url: "custom_url"
43
43
  };
44
- const metadataResult = await getMetadata(testConfig);
44
+ const metadataResult = await getMetadata(testConfig, stderrLogger);
45
45
  expect(metadataResult.actor).toBe("custom_user");
46
46
  expect(metadataResult.commitSha).toBe("custom_version");
47
47
  expect(metadataResult.name).toBe("circle");
@@ -61,7 +61,7 @@ describe("getMetadata", () => {
61
61
  body: "gh_body"
62
62
  });
63
63
  const testConfig = createTestConfig("/tmp/deploymentRoot/");
64
- const metadataResult = await getMetadata(testConfig);
64
+ const metadataResult = await getMetadata(testConfig, stderrLogger);
65
65
  expect(metadataResult.actor).toBe("gh_author");
66
66
  expect(metadataResult.commitSha).toBe("gh_hash");
67
67
  expect(metadataResult.name).toBe("none");
@@ -5,9 +5,17 @@ interface Build {
5
5
  interface ClientError extends Error {
6
6
  statusCode: number;
7
7
  }
8
- interface DeployConfig {
8
+ interface DeploymentHooks {
9
+ onBuildStart?: () => void;
10
+ onBuildComplete?: () => void;
11
+ onBuildError?: (error: Error) => void;
12
+ onUploadFilesStart?: () => void;
13
+ onUploadFilesComplete?: () => void;
14
+ }
15
+ interface DeploymentConfig {
9
16
  assetsDir?: string;
10
17
  buildCommand: string;
18
+ buildOutput: boolean;
11
19
  deploymentToken: DeploymentToken;
12
20
  deploymentUrl: string;
13
21
  environmentTag?: string;
@@ -50,4 +58,4 @@ interface OxygenError {
50
58
  message: string;
51
59
  }
52
60
 
53
- export { Build, ClientError, DeployConfig, DeploymentManifestFile, DeploymentToken, EnvironmentInput, FileType, OxygenError };
61
+ export { Build, ClientError, DeploymentConfig, DeploymentHooks, DeploymentManifestFile, DeploymentToken, EnvironmentInput, FileType, OxygenError };
@@ -1,6 +1,13 @@
1
- import { DeployConfig } from './types.js';
1
+ import { Logger } from '@shopify/cli-kit/node/output';
2
+ import { DeploymentConfig, DeploymentHooks } from './types.js';
2
3
  import { DeploymentTargetResponse } from './graphql/deployment-initiate.js';
3
4
 
4
- declare function uploadFiles(config: DeployConfig, targets: DeploymentTargetResponse[]): Promise<void>;
5
+ interface UploadFilesOptions {
6
+ config: DeploymentConfig;
7
+ hooks?: DeploymentHooks;
8
+ logger: Logger;
9
+ targets: DeploymentTargetResponse[];
10
+ }
11
+ declare function uploadFiles(options: UploadFilesOptions): Promise<void>;
5
12
 
6
13
  export { uploadFiles };
@@ -3,14 +3,17 @@ import { createFileReadStream } from '@shopify/cli-kit/node/fs';
3
3
  import { outputInfo, outputCompleted } from '@shopify/cli-kit/node/output';
4
4
  import { joinPath } from '@shopify/cli-kit/node/path';
5
5
  import { mapLimit } from 'async';
6
- import { stderrLogger, deployDefaults } from '../utils/utils.js';
6
+ import { deployDefaults } from '../utils/utils.js';
7
7
 
8
- async function uploadFiles(config, targets) {
9
- outputInfo(`Uploading ${targets.length} files...`, stderrLogger);
8
+ async function uploadFiles(options) {
9
+ const { config, logger, targets, hooks } = options;
10
+ outputInfo(`Uploading ${targets.length} files...`, logger);
11
+ hooks?.onUploadFilesStart?.();
10
12
  return mapLimit(targets, 6, async (target) => {
11
13
  await uploadFile(config, target);
12
14
  }).then(() => {
13
- outputCompleted(`Files uploaded successfully`, stderrLogger);
15
+ hooks?.onUploadFilesComplete?.();
16
+ outputCompleted(`Files uploaded successfully`, logger);
14
17
  });
15
18
  }
16
19
  async function uploadFile(config, target) {
@@ -3,7 +3,7 @@ import { fetch } from '@shopify/cli-kit/node/http';
3
3
  import { vi, describe, beforeEach, it, expect } from 'vitest';
4
4
  import { Response } from 'node-fetch';
5
5
  import { createTestConfig } from '../utils/test-helper.js';
6
- import { deployDefaults } from '../utils/utils.js';
6
+ import { stderrLogger, deployDefaults } from '../utils/utils.js';
7
7
  import { uploadFiles } from './upload-files.js';
8
8
 
9
9
  class NamedReadable extends Readable {
@@ -29,22 +29,16 @@ vi.mock("@shopify/cli-kit/node/fs", () => {
29
29
  })
30
30
  };
31
31
  });
32
- vi.mock("fs", () => {
33
- return {
34
- createReadStream: vi.fn(() => {
35
- const readable = new NamedReadable();
36
- readable.push("dummy");
37
- readable.emit("end");
38
- return readable;
39
- })
40
- };
41
- });
42
32
  const testConfig = createTestConfig("/tmp/deploymentRoot");
43
33
  describe("UploadFiles", () => {
44
34
  beforeEach(() => {
45
35
  vi.mocked(fetch).mockReset();
46
36
  });
47
37
  it("Performs a form upload", async () => {
38
+ const hooks = {
39
+ onUploadFilesStart: vi.fn(),
40
+ onUploadFilesComplete: vi.fn()
41
+ };
48
42
  const response = new Response();
49
43
  vi.mocked(fetch).mockResolvedValueOnce(response);
50
44
  const testWorkerUpload = [
@@ -56,7 +50,12 @@ describe("UploadFiles", () => {
56
50
  parameters: [{ name: "someName", value: "someValue" }]
57
51
  }
58
52
  ];
59
- await uploadFiles(testConfig, testWorkerUpload);
53
+ await uploadFiles({
54
+ config: testConfig,
55
+ targets: testWorkerUpload,
56
+ logger: stderrLogger,
57
+ hooks
58
+ });
60
59
  expect(vi.mocked(fetch)).toHaveBeenCalledTimes(1);
61
60
  expect(vi.mocked(fetch)).toHaveBeenCalledWith(
62
61
  "https://storage.googleapis.com/the-bucket/",
@@ -73,6 +72,8 @@ describe("UploadFiles", () => {
73
72
  })
74
73
  })
75
74
  );
75
+ expect(hooks.onUploadFilesStart).toBeCalled();
76
+ expect(hooks.onUploadFilesComplete).toBeCalled();
76
77
  });
77
78
  it("Retries a failed form upload until the max upload attempts then throws", async () => {
78
79
  vi.mocked(fetch).mockRejectedValue(new Error("some error"));
@@ -85,9 +86,13 @@ describe("UploadFiles", () => {
85
86
  parameters: [{ name: "someName", value: "someValue" }]
86
87
  }
87
88
  ];
88
- await expect(uploadFiles(testConfig, testWorkerUpload)).rejects.toThrow(
89
- "Failed to upload file index.js"
90
- );
89
+ await expect(
90
+ uploadFiles({
91
+ config: testConfig,
92
+ targets: testWorkerUpload,
93
+ logger: stderrLogger
94
+ })
95
+ ).rejects.toThrow("Failed to upload file index.js");
91
96
  expect(vi.mocked(fetch)).toHaveBeenCalledTimes(
92
97
  Number(deployDefaults.maxUploadAttempts) + 1
93
98
  );
@@ -108,7 +113,11 @@ describe("UploadFiles", () => {
108
113
  parameters: null
109
114
  }
110
115
  ];
111
- await uploadFiles(testConfig, testWorkerUpload);
116
+ await uploadFiles({
117
+ config: testConfig,
118
+ targets: testWorkerUpload,
119
+ logger: stderrLogger
120
+ });
112
121
  expect(vi.mocked(fetch)).toHaveBeenCalledTimes(2);
113
122
  const secondCall = vi.mocked(fetch).mock.calls[1];
114
123
  expect(secondCall[0]).toBe("https://upload-it-here.com/");
@@ -145,7 +154,11 @@ describe("UploadFiles", () => {
145
154
  parameters: null
146
155
  }
147
156
  ];
148
- await uploadFiles(testConfig, testWorkerUpload);
157
+ await uploadFiles({
158
+ config: testConfig,
159
+ targets: testWorkerUpload,
160
+ logger: stderrLogger
161
+ });
149
162
  expect(vi.mocked(fetch)).toHaveBeenCalledTimes(4);
150
163
  const statusCall = vi.mocked(fetch).mock.calls[2];
151
164
  expect(statusCall[0]).toBe("https://upload-it-here.com/");
@@ -183,7 +196,13 @@ describe("UploadFiles", () => {
183
196
  parameters: null
184
197
  }
185
198
  ];
186
- await expect(uploadFiles(testConfig, testWorkerUpload)).rejects.toThrow(
199
+ await expect(
200
+ uploadFiles({
201
+ config: testConfig,
202
+ targets: testWorkerUpload,
203
+ logger: stderrLogger
204
+ })
205
+ ).rejects.toThrow(
187
206
  `Failed to upload file index.js after ${deployDefaults.maxResumabeUploadAttempts} attempts`
188
207
  );
189
208
  expect(vi.mocked(fetch)).toHaveBeenCalledTimes(
@@ -1,4 +1,4 @@
1
- import { DeployConfig } from '../deploy/types.js';
1
+ import { DeploymentConfig } from '../deploy/types.js';
2
2
 
3
3
  declare const testToken: {
4
4
  accessToken: string;
@@ -9,6 +9,6 @@ declare const testToken: {
9
9
  namespace: string;
10
10
  namespaceId: string;
11
11
  };
12
- declare function createTestConfig(rootFolder: string): DeployConfig;
12
+ declare function createTestConfig(rootFolder: string): DeploymentConfig;
13
13
 
14
14
  export { createTestConfig, testToken };
@@ -13,6 +13,7 @@ function createTestConfig(rootFolder) {
13
13
  return {
14
14
  assetsDir: "/assets/",
15
15
  buildCommand: String(deployDefaults.buildCommandDefault),
16
+ buildOutput: true,
16
17
  deploymentToken: testToken,
17
18
  environmentTag: "environment",
18
19
  deploymentUrl: "https://localhost:3000",
@@ -1,10 +1,10 @@
1
- import { DeployConfig, ClientError, DeploymentToken } from '../deploy/types.js';
1
+ import { DeploymentConfig, ClientError, DeploymentToken } from '../deploy/types.js';
2
2
 
3
3
  declare const deployDefaults: {
4
4
  [key: string]: string | number;
5
5
  };
6
6
  declare function errorHandler(error: any): void;
7
- declare function getBuildCommandFromLockFile(config: DeployConfig): string;
7
+ declare function getBuildCommandFromLockFile(config: DeploymentConfig): string;
8
8
  declare enum Header {
9
9
  OxygenNamespaceHandle = "X-Oxygen-Namespace-Handle"
10
10
  }
@@ -13,7 +13,7 @@ declare function stderrLogger(log: string): void;
13
13
  declare const maxLabelLength = 90;
14
14
  declare function parseToken(inputToken: string): DeploymentToken;
15
15
  interface VerifyConfigParams {
16
- config: DeployConfig;
16
+ config: DeploymentConfig;
17
17
  performedBuild?: boolean;
18
18
  }
19
19
  declare function verifyConfig({ config, performedBuild, }: VerifyConfigParams): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.3.1",
2
+ "version": "1.5.0",
3
3
  "commands": {
4
4
  "oxygen:deploy": {
5
5
  "id": "oxygen:deploy",
@@ -19,10 +19,10 @@
19
19
  "required": true,
20
20
  "multiple": false
21
21
  },
22
- "rootPath": {
23
- "name": "rootPath",
22
+ "path": {
23
+ "name": "path",
24
24
  "type": "option",
25
- "char": "r",
25
+ "char": "p",
26
26
  "description": "Root path",
27
27
  "required": false,
28
28
  "multiple": false,
@@ -82,7 +82,6 @@
82
82
  "publicDeployment": {
83
83
  "name": "publicDeployment",
84
84
  "type": "boolean",
85
- "char": "p",
86
85
  "description": "Marks a preview deployment as publicly accessible.",
87
86
  "required": false,
88
87
  "allowNo": false
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "1.3.1",
8
+ "version": "1.5.0",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "build": "tsup --clean --config ./tsup.config.ts && oclif manifest",
@@ -31,8 +31,8 @@
31
31
  "/oclif.manifest.json"
32
32
  ],
33
33
  "dependencies": {
34
- "@oclif/core": "2.8.6",
35
- "@shopify/cli-kit": "^3.46.0",
34
+ "@oclif/core": "2.8.11",
35
+ "@shopify/cli-kit": "^3.46.5",
36
36
  "async": "^3.2.4"
37
37
  },
38
38
  "devDependencies": {
@@ -40,15 +40,15 @@
40
40
  "@shopify/eslint-plugin": "^42.1.0",
41
41
  "@shopify/prettier-config": "^1.1.2",
42
42
  "@types/async": "^3.2.18",
43
- "@types/node": "^18.15.11",
43
+ "@types/node": "^20.3.1",
44
44
  "@types/prettier": "^2.7.3",
45
- "eslint": "^8.42.0",
45
+ "eslint": "^8.43.0",
46
46
  "node-fetch": "^3.3.1",
47
47
  "oclif": "^3",
48
- "tsup": "^6.7.0",
48
+ "tsup": "^7.1.0",
49
49
  "typescript": "^5.1.3",
50
50
  "vite": "^4.3.9",
51
- "vitest": "^0.32.0"
51
+ "vitest": "^0.32.2"
52
52
  },
53
53
  "prettier": "@shopify/prettier-config",
54
54
  "oclif": {