@shopify/oxygen-cli 1.4.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +2 -0
- package/dist/commands/oxygen/deploy.d.ts +9 -9
- package/dist/commands/oxygen/deploy.js +58 -43
- package/dist/deploy/build-cancel.d.ts +9 -2
- package/dist/deploy/build-cancel.js +4 -3
- package/dist/deploy/build-cancel.test.js +21 -4
- package/dist/deploy/build-initiate.d.ts +9 -2
- package/dist/deploy/build-initiate.js +4 -3
- package/dist/deploy/build-initiate.test.js +19 -8
- package/dist/deploy/build-project.d.ts +7 -2
- package/dist/deploy/build-project.js +34 -19
- package/dist/deploy/build-project.test.js +14 -8
- package/dist/deploy/deployment-cancel.d.ts +9 -2
- package/dist/deploy/deployment-cancel.js +4 -3
- package/dist/deploy/deployment-cancel.test.js +19 -16
- package/dist/deploy/deployment-complete.d.ts +2 -2
- package/dist/deploy/deployment-initiate.d.ts +10 -4
- package/dist/deploy/deployment-initiate.js +4 -3
- package/dist/deploy/deployment-initiate.test.js +26 -10
- package/dist/deploy/get-upload-files.d.ts +2 -2
- package/dist/deploy/health-check.d.ts +12 -0
- package/dist/deploy/health-check.js +44 -0
- package/dist/deploy/health-check.test.d.ts +2 -0
- package/dist/deploy/health-check.test.js +92 -0
- package/dist/deploy/index.d.ts +10 -3
- package/dist/deploy/index.js +54 -26
- package/dist/deploy/metadata.d.ts +4 -3
- package/dist/deploy/metadata.js +3 -3
- package/dist/deploy/metadata.test.js +4 -4
- package/dist/deploy/types.d.ts +17 -2
- package/dist/deploy/types.js +3 -1
- package/dist/deploy/upload-files.d.ts +9 -2
- package/dist/deploy/upload-files.js +7 -4
- package/dist/deploy/upload-files.test.js +37 -18
- package/dist/utils/test-helper.d.ts +2 -2
- package/dist/utils/test-helper.js +3 -0
- package/dist/utils/utils.d.ts +3 -3
- package/dist/utils/utils.js +1 -5
- package/oclif.manifest.json +50 -33
- package/package.json +8 -8
package/README.md
CHANGED
@@ -42,6 +42,8 @@ oxygen:deploy [options]
|
|
42
42
|
- -o, --workerOnly: Worker only deployment.
|
43
43
|
- -s, --skipBuild: Skip running build command.
|
44
44
|
- -b, --buildCommand <buildCommand>: Build command (default: `yarn build`).
|
45
|
+
- -h, --skipHealthCheck: Skip running the health check on the deployment
|
46
|
+
- -d, --healthCheckMaxDuration: The maximum duration (in seconds) that the health check is allowed to run before it is considered failed. Accepts values between 10 and 300.
|
45
47
|
- --publicDeployment: set the deployment to be publicly accessible.
|
46
48
|
- --metadataUrl <metadataUrl>: URL that links to the deployment.
|
47
49
|
- --metadataUser <metadataUser>: User that initiated the deployment.
|
@@ -1,20 +1,21 @@
|
|
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';
|
4
3
|
|
5
4
|
declare class Deploy extends Command {
|
6
5
|
static description: string;
|
7
6
|
static hidden: boolean;
|
8
7
|
static flags: {
|
9
|
-
token: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _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
|
-
environmentTag: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
12
|
-
workerFolder: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
13
8
|
assetsFolder: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
14
|
-
workerOnly: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
15
|
-
skipBuild: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
16
9
|
buildCommand: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
10
|
+
environmentTag: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
11
|
+
healthCheckMaxDuration: _oclif_core_lib_interfaces_parser_js.OptionFlag<number, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
12
|
+
path: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
17
13
|
publicDeployment: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
14
|
+
skipBuild: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
15
|
+
skipHealthCheck: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
16
|
+
token: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
17
|
+
workerFolder: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
18
|
+
workerOnly: _oclif_core_lib_interfaces_parser_js.BooleanFlag<boolean>;
|
18
19
|
metadataUrl: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
19
20
|
metadataUser: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
20
21
|
metadataVersion: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
@@ -22,6 +23,5 @@ declare class Deploy extends Command {
|
|
22
23
|
static hasCustomBuildCommand: boolean;
|
23
24
|
run(): Promise<void>;
|
24
25
|
}
|
25
|
-
declare function runInit(options: DeployConfig): void;
|
26
26
|
|
27
|
-
export { Deploy
|
27
|
+
export { Deploy };
|
@@ -3,52 +3,18 @@ import { consoleError } from '@shopify/cli-kit/node/output';
|
|
3
3
|
import { normalizePath } from '@shopify/cli-kit/node/path';
|
4
4
|
import { createDeploy } from '../../deploy/index.js';
|
5
5
|
import { deployDefaults, parseToken, verifyConfig, getBuildCommandFromLockFile } from '../../utils/utils.js';
|
6
|
+
import { HealthCheckError } from '../../deploy/types.js';
|
6
7
|
|
7
8
|
class Deploy extends Command {
|
8
9
|
static description = "Creates a deployment to Oxygen";
|
9
10
|
static hidden = false;
|
10
11
|
static flags = {
|
11
|
-
token: Flags.string({
|
12
|
-
char: "t",
|
13
|
-
description: "Oxygen deployment token",
|
14
|
-
env: "OXYGEN_DEPLOYMENT_TOKEN",
|
15
|
-
required: false
|
16
|
-
}),
|
17
|
-
path: Flags.string({
|
18
|
-
char: "p",
|
19
|
-
description: "Root path",
|
20
|
-
default: "./",
|
21
|
-
required: false
|
22
|
-
}),
|
23
|
-
environmentTag: Flags.string({
|
24
|
-
char: "e",
|
25
|
-
description: "Tag of the environment to deploy to",
|
26
|
-
required: false
|
27
|
-
}),
|
28
|
-
workerFolder: Flags.string({
|
29
|
-
char: "w",
|
30
|
-
description: "Worker folder",
|
31
|
-
default: String(deployDefaults.workerDirDefault),
|
32
|
-
required: false
|
33
|
-
}),
|
34
12
|
assetsFolder: Flags.string({
|
35
13
|
char: "a",
|
36
14
|
description: "Assets folder",
|
37
15
|
default: String(deployDefaults.assetsDirDefault),
|
38
16
|
required: false
|
39
17
|
}),
|
40
|
-
workerOnly: Flags.boolean({
|
41
|
-
char: "o",
|
42
|
-
description: "Worker only deployment",
|
43
|
-
default: false,
|
44
|
-
required: false
|
45
|
-
}),
|
46
|
-
skipBuild: Flags.boolean({
|
47
|
-
char: "s",
|
48
|
-
description: "Skip running build command",
|
49
|
-
required: false,
|
50
|
-
default: false
|
51
|
-
}),
|
52
18
|
buildCommand: Flags.string({
|
53
19
|
char: "b",
|
54
20
|
description: "Build command",
|
@@ -59,12 +25,61 @@ class Deploy extends Command {
|
|
59
25
|
return Promise.resolve(input);
|
60
26
|
}
|
61
27
|
}),
|
28
|
+
environmentTag: Flags.string({
|
29
|
+
char: "e",
|
30
|
+
description: "Tag of the environment to deploy to",
|
31
|
+
required: false
|
32
|
+
}),
|
33
|
+
healthCheckMaxDuration: Flags.integer({
|
34
|
+
char: "d",
|
35
|
+
description: "the maximum duration (in seconds) that the health check is allowed to run before it is considered failed.",
|
36
|
+
min: 10,
|
37
|
+
max: 300,
|
38
|
+
required: false,
|
39
|
+
default: deployDefaults.healthCheckMaxDurationDefault
|
40
|
+
}),
|
41
|
+
path: Flags.string({
|
42
|
+
char: "p",
|
43
|
+
description: "Root path",
|
44
|
+
default: "./",
|
45
|
+
required: false
|
46
|
+
}),
|
62
47
|
publicDeployment: Flags.boolean({
|
63
48
|
env: "OXYGEN_PUBLIC_DEPLOYMENT",
|
64
49
|
description: "Marks a preview deployment as publicly accessible.",
|
65
50
|
required: false,
|
66
51
|
default: false
|
67
52
|
}),
|
53
|
+
skipBuild: Flags.boolean({
|
54
|
+
char: "s",
|
55
|
+
description: "Skip running build command",
|
56
|
+
required: false,
|
57
|
+
default: false
|
58
|
+
}),
|
59
|
+
skipHealthCheck: Flags.boolean({
|
60
|
+
char: "h",
|
61
|
+
description: "Skip running deployment health check",
|
62
|
+
required: false,
|
63
|
+
default: false
|
64
|
+
}),
|
65
|
+
token: Flags.string({
|
66
|
+
char: "t",
|
67
|
+
description: "Oxygen deployment token",
|
68
|
+
env: "OXYGEN_DEPLOYMENT_TOKEN",
|
69
|
+
required: true
|
70
|
+
}),
|
71
|
+
workerFolder: Flags.string({
|
72
|
+
char: "w",
|
73
|
+
description: "Worker folder",
|
74
|
+
default: String(deployDefaults.workerDirDefault),
|
75
|
+
required: false
|
76
|
+
}),
|
77
|
+
workerOnly: Flags.boolean({
|
78
|
+
char: "o",
|
79
|
+
description: "Worker only deployment",
|
80
|
+
default: false,
|
81
|
+
required: false
|
82
|
+
}),
|
68
83
|
metadataUrl: Flags.string({
|
69
84
|
description: "URL that links to the deployment. Will be saved and displayed in the Shopify admin",
|
70
85
|
required: false,
|
@@ -92,9 +107,11 @@ class Deploy extends Command {
|
|
92
107
|
const config = {
|
93
108
|
assetsDir: normalizePath(flags.assetsFolder),
|
94
109
|
buildCommand: flags.buildCommand,
|
110
|
+
buildOutput: true,
|
95
111
|
deploymentToken: parseToken(flags.token),
|
96
112
|
environmentTag: flags.environmentTag,
|
97
113
|
deploymentUrl,
|
114
|
+
healthCheckMaxDuration: flags.healthCheckMaxDuration,
|
98
115
|
metadata: {
|
99
116
|
url: flags.metadataUrl,
|
100
117
|
user: flags.metadataUser,
|
@@ -103,6 +120,7 @@ class Deploy extends Command {
|
|
103
120
|
publicDeployment: flags.publicDeployment,
|
104
121
|
rootPath: normalizePath(flags.path),
|
105
122
|
skipBuild: flags.skipBuild,
|
123
|
+
skipHealthCheck: flags.skipHealthCheck,
|
106
124
|
workerDir: normalizePath(flags.workerFolder),
|
107
125
|
workerOnly: flags.workerOnly
|
108
126
|
};
|
@@ -110,19 +128,16 @@ class Deploy extends Command {
|
|
110
128
|
if (!Deploy.hasCustomBuildCommand && !config.skipBuild) {
|
111
129
|
config.buildCommand = getBuildCommandFromLockFile(config);
|
112
130
|
}
|
113
|
-
|
131
|
+
await createDeploy({ config });
|
114
132
|
} catch (error) {
|
115
|
-
if (error instanceof Error) {
|
133
|
+
if (!(error instanceof Error)) {
|
134
|
+
consoleError(error);
|
135
|
+
} else if (!(error instanceof HealthCheckError)) {
|
116
136
|
consoleError(error.message);
|
117
|
-
} else {
|
118
|
-
console.error(error);
|
119
137
|
}
|
120
138
|
this.exit(1);
|
121
139
|
}
|
122
140
|
}
|
123
141
|
}
|
124
|
-
function runInit(options) {
|
125
|
-
createDeploy(options);
|
126
|
-
}
|
127
142
|
|
128
|
-
export { Deploy
|
143
|
+
export { Deploy };
|
@@ -1,6 +1,13 @@
|
|
1
|
-
import {
|
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
|
-
|
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,
|
4
|
+
import { Header, errorHandler } from '../utils/utils.js';
|
5
5
|
import { BuildCancelQuery } from './graphql/build-cancel.js';
|
6
6
|
|
7
|
-
async function buildCancel(
|
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.`,
|
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(
|
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(
|
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(
|
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 {
|
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
|
-
|
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,
|
4
|
+
import { Header, errorHandler } from '../utils/utils.js';
|
5
5
|
import { BuildInitiateQuery } from './graphql/build-initiate.js';
|
6
6
|
|
7
|
-
async function buildInitiate(
|
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
|
-
|
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 {
|
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(
|
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(
|
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 {
|
1
|
+
import { DeploymentConfig, DeploymentHooks } from './types.js';
|
2
2
|
|
3
|
-
|
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(
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
if (
|
19
|
-
|
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
|
-
|
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
|
-
}
|
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
|
-
|
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
|
-
|
49
|
-
|
50
|
-
});
|
53
|
+
const hooks = {
|
54
|
+
onBuildError: vi.fn()
|
55
|
+
};
|
51
56
|
const assetPath = "https://example.com/assets";
|
52
|
-
await expect(
|
53
|
-
|
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 {
|
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
|
-
|
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,
|
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(
|
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.`,
|
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 {
|
2
|
+
import { DeploymentConfig } from './types.js';
|
3
3
|
|
4
|
-
declare function deploymentComplete(config:
|
4
|
+
declare function deploymentComplete(config: DeploymentConfig, deploymentId: string): Promise<DeploymentCompleteResponse>;
|
5
5
|
|
6
6
|
export { deploymentComplete };
|
@@ -1,17 +1,23 @@
|
|
1
|
-
import {
|
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
|
-
|
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 };
|