@shopify/oxygen-cli 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +7 -7
- package/dist/commands/oxygen/deploy.d.ts +2 -2
- package/dist/commands/oxygen/deploy.js +7 -8
- package/dist/deploy/deployment-cancel.d.ts +6 -2
- package/dist/deploy/deployment-cancel.js +6 -1
- package/dist/deploy/deployment-cancel.test.js +13 -5
- package/dist/deploy/graphql/deployment-complete.d.ts +1 -2
- package/dist/deploy/graphql/deployment-complete.js +0 -1
- package/dist/deploy/graphql/deployment-initiate.d.ts +1 -2
- package/dist/deploy/graphql/deployment-initiate.js +0 -1
- package/dist/deploy/index.js +12 -10
- package/dist/utils/utils.js +6 -1
- package/oclif.manifest.json +8 -9
- package/package.json +10 -10
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
|
-
- -
|
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 --
|
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.
|
@@ -68,7 +68,7 @@ environment:
|
|
68
68
|
OXYGEN_DEPLOYMENT_TOKEN: ${YOUR_ENV_VARIABLE}
|
69
69
|
```
|
70
70
|
|
71
|
-
When run from a supported CI/CD environment, the tool will automatically retrieve metadata from relevant environment variables. Metadata describes the author making the deployment (user), the version (commit Sha) and the deployment URL (workflow URL).
|
71
|
+
When run from a supported CI/CD environment, the tool will automatically retrieve metadata from relevant environment variables. Metadata describes the author making the deployment (user), the version (commit Sha) and the deployment URL (workflow URL). This metadata will be saved and used to show details about the Oxygen deployment in the Hydrogen channel within the Shopify Admin.
|
72
72
|
|
73
73
|
The following environment variables are relevant, depending on your environment:
|
74
74
|
|
@@ -78,9 +78,9 @@ The following environment variables are relevant, depending on your environment:
|
|
78
78
|
| Version | BITBUCKET_COMMIT | CIRCLE_SHA1 | GITHUB_SHA | CI_COMMIT_SHA |
|
79
79
|
| URL | BITBUCKET_BUILD_URL | CIRCLE_BUILD_URL | `${GITHUB_SERVER_URL}${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}` | CI_PROJECT_URL |
|
80
80
|
|
81
|
-
These values can be
|
81
|
+
These values can be overridden by the command line flags `metadataUser`, `metadataUrl` and `metadataVersion` respectively.
|
82
82
|
|
83
|
-
The tag
|
83
|
+
The environment tag to deploy to will be derived from the following variables:
|
84
84
|
|
85
85
|
| Service | Branch |
|
86
86
|
| ------- | ------ |
|
@@ -89,4 +89,4 @@ The tag of the environment to deploy to, will be derived from the following vari
|
|
89
89
|
| Github | GITHUB_REF_NAME |
|
90
90
|
| Gitlab | CI_COMMIT_REF_NAME |
|
91
91
|
|
92
|
-
The `environmentTag` command line option can be used to override this,
|
92
|
+
The `environmentTag` command line option can be used to override this. If not provided, or there is no environment with the specified tag, the deployment will be deployed to the default environment for the app (if one exists).
|
@@ -6,8 +6,8 @@ declare class Deploy extends Command {
|
|
6
6
|
static description: string;
|
7
7
|
static hidden: boolean;
|
8
8
|
static flags: {
|
9
|
-
token: _oclif_core_lib_interfaces_parser_js.OptionFlag<string, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
10
|
-
|
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
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>;
|
@@ -12,10 +12,10 @@ class Deploy extends Command {
|
|
12
12
|
char: "t",
|
13
13
|
description: "Oxygen deployment token",
|
14
14
|
env: "OXYGEN_DEPLOYMENT_TOKEN",
|
15
|
-
required:
|
15
|
+
required: false
|
16
16
|
}),
|
17
|
-
|
18
|
-
char: "
|
17
|
+
path: Flags.string({
|
18
|
+
char: "p",
|
19
19
|
description: "Root path",
|
20
20
|
default: "./",
|
21
21
|
required: false
|
@@ -60,24 +60,23 @@ 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,
|
67
66
|
default: false
|
68
67
|
}),
|
69
68
|
metadataUrl: Flags.string({
|
70
|
-
description: "URL that links to the deployment",
|
69
|
+
description: "URL that links to the deployment. Will be saved and displayed in the Shopify admin",
|
71
70
|
required: false,
|
72
71
|
env: "OXYGEN_METADATA_URL"
|
73
72
|
}),
|
74
73
|
metadataUser: Flags.string({
|
75
|
-
description: "User that initiated the deployment",
|
74
|
+
description: "User that initiated the deployment. Will be saved and displayed in the Shopify admin",
|
76
75
|
required: false,
|
77
76
|
env: "OXYGEN_METADATA_USER"
|
78
77
|
}),
|
79
78
|
metadataVersion: Flags.string({
|
80
|
-
description: "A version identifier for the deployment",
|
79
|
+
description: "A version identifier for the deployment. Will be saved and displayed in the Shopify admin",
|
81
80
|
required: false,
|
82
81
|
env: "OXYGEN_METADATA_VERSION"
|
83
82
|
})
|
@@ -102,7 +101,7 @@ class Deploy extends Command {
|
|
102
101
|
version: flags.metadataVersion
|
103
102
|
},
|
104
103
|
publicDeployment: flags.publicDeployment,
|
105
|
-
rootPath: normalizePath(flags.
|
104
|
+
rootPath: normalizePath(flags.path),
|
106
105
|
skipBuild: flags.skipBuild,
|
107
106
|
workerDir: normalizePath(flags.workerFolder),
|
108
107
|
workerOnly: flags.workerOnly
|
@@ -1,6 +1,10 @@
|
|
1
1
|
import { DeployConfig } from './types.js';
|
2
2
|
import { DeploymentCancelResponse } from './graphql/deployment-cancel.js';
|
3
3
|
|
4
|
-
declare
|
4
|
+
declare enum DeploymentCancelReason {
|
5
|
+
Failed = "FAILED",
|
6
|
+
Cancelled = "CANCELLED"
|
7
|
+
}
|
8
|
+
declare function deploymentCancel(config: DeployConfig, deploymentId: string, reason: DeploymentCancelReason): Promise<DeploymentCancelResponse>;
|
5
9
|
|
6
|
-
export { deploymentCancel };
|
10
|
+
export { DeploymentCancelReason, deploymentCancel };
|
@@ -4,6 +4,11 @@ import { outputInfo } from '@shopify/cli-kit/node/output';
|
|
4
4
|
import { Header, stderrLogger, errorHandler } from '../utils/utils.js';
|
5
5
|
import { DeploymentCancelQuery } from './graphql/deployment-cancel.js';
|
6
6
|
|
7
|
+
var DeploymentCancelReason = /* @__PURE__ */ ((DeploymentCancelReason2) => {
|
8
|
+
DeploymentCancelReason2["Failed"] = "FAILED";
|
9
|
+
DeploymentCancelReason2["Cancelled"] = "CANCELLED";
|
10
|
+
return DeploymentCancelReason2;
|
11
|
+
})(DeploymentCancelReason || {});
|
7
12
|
async function deploymentCancel(config, deploymentId, reason) {
|
8
13
|
const variables = {
|
9
14
|
deploymentId,
|
@@ -33,4 +38,4 @@ async function deploymentCancel(config, deploymentId, reason) {
|
|
33
38
|
}
|
34
39
|
}
|
35
40
|
|
36
|
-
export { deploymentCancel };
|
41
|
+
export { DeploymentCancelReason, deploymentCancel };
|
@@ -3,7 +3,7 @@ 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
5
|
import { Header } from '../utils/utils.js';
|
6
|
-
import { deploymentCancel } from './deployment-cancel.js';
|
6
|
+
import { deploymentCancel, DeploymentCancelReason } from './deployment-cancel.js';
|
7
7
|
|
8
8
|
vi.mock("@shopify/cli-kit/node/api/graphql");
|
9
9
|
vi.mock("@shopify/cli-kit/node/output");
|
@@ -22,7 +22,7 @@ describe("DeploymentComplete", () => {
|
|
22
22
|
const completeResponse = await deploymentCancel(
|
23
23
|
testConfig,
|
24
24
|
"deployment-1",
|
25
|
-
|
25
|
+
DeploymentCancelReason.Failed
|
26
26
|
);
|
27
27
|
expect(completeResponse).toEqual(response.deploymentCancel);
|
28
28
|
expect(graphqlRequest).toHaveBeenCalledWith({
|
@@ -32,7 +32,7 @@ describe("DeploymentComplete", () => {
|
|
32
32
|
token: testConfig.deploymentToken.accessToken,
|
33
33
|
variables: {
|
34
34
|
deploymentId: "deployment-1",
|
35
|
-
reason:
|
35
|
+
reason: DeploymentCancelReason.Failed
|
36
36
|
},
|
37
37
|
addedHeaders: {
|
38
38
|
[Header.OxygenNamespaceHandle]: `${testConfig.deploymentToken.namespace}`
|
@@ -51,7 +51,11 @@ describe("DeploymentComplete", () => {
|
|
51
51
|
};
|
52
52
|
vi.mocked(graphqlRequest).mockResolvedValueOnce(response);
|
53
53
|
await expect(
|
54
|
-
deploymentCancel(
|
54
|
+
deploymentCancel(
|
55
|
+
testConfig,
|
56
|
+
"deployment-1",
|
57
|
+
DeploymentCancelReason.Failed
|
58
|
+
)
|
55
59
|
).rejects.toThrow(
|
56
60
|
new AbortError(
|
57
61
|
`Failed to cancel deployment: ${response.deploymentCancel.userErrors[0]?.message}`
|
@@ -65,7 +69,11 @@ describe("DeploymentComplete", () => {
|
|
65
69
|
vi.mocked(graphqlRequest).mockRejectedValueOnce(error);
|
66
70
|
try {
|
67
71
|
await expect(
|
68
|
-
deploymentCancel(
|
72
|
+
deploymentCancel(
|
73
|
+
testConfig,
|
74
|
+
"deployment-1",
|
75
|
+
DeploymentCancelReason.Failed
|
76
|
+
)
|
69
77
|
).rejects.toThrow(
|
70
78
|
new AbortError(
|
71
79
|
"You are not authorized to perform this action. Please check your deployment token."
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { OxygenError } from '../types.js';
|
2
2
|
|
3
|
-
declare const DeploymentCompleteQuery = "\n mutation DeploymentComplete($deploymentId: ID!) {\n deploymentComplete(id: $deploymentId) {\n deployment {\n id\n
|
3
|
+
declare const DeploymentCompleteQuery = "\n mutation DeploymentComplete($deploymentId: ID!) {\n deploymentComplete(id: $deploymentId) {\n deployment {\n id\n url\n }\n userErrors {\n message\n }\n }\n }\n";
|
4
4
|
interface DeploymentCompleteQueryData {
|
5
5
|
deploymentComplete: DeploymentCompleteResponse;
|
6
6
|
}
|
@@ -10,7 +10,6 @@ interface DeploymentCompleteResponse {
|
|
10
10
|
}
|
11
11
|
interface Deployment {
|
12
12
|
id: string;
|
13
|
-
status: string;
|
14
13
|
url: string;
|
15
14
|
}
|
16
15
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { OxygenError } from '../types.js';
|
2
2
|
|
3
|
-
declare const DeploymentInitiateQuery = "\n mutation DeploymentInitiate($buildId: ID, $environment: EnvironmentSelectorInput, $labels: [String!], $files: [FileInput!]!, $isPrivate: Boolean) {\n deploymentInitiate(buildId: $buildId, environment: $environment, labels: $labels, files: $files, isPrivate: $isPrivate) {\n deployment {\n id\n
|
3
|
+
declare const DeploymentInitiateQuery = "\n mutation DeploymentInitiate($buildId: ID, $environment: EnvironmentSelectorInput, $labels: [String!], $files: [FileInput!]!, $isPrivate: Boolean) {\n deploymentInitiate(buildId: $buildId, environment: $environment, labels: $labels, files: $files, isPrivate: $isPrivate) {\n deployment {\n id\n }\n deploymentTargets {\n filePath\n fileSize\n uploadUrl\n fileType\n parameters {\n name\n value\n }\n }\n userErrors {\n message\n }\n }\n }\n";
|
4
4
|
interface DeploymentInitiateQueryData {
|
5
5
|
deploymentInitiate: DeploymentInitiateResponse;
|
6
6
|
}
|
@@ -18,7 +18,6 @@ interface DeploymentTargetResponse {
|
|
18
18
|
}
|
19
19
|
interface Deployment {
|
20
20
|
id: string;
|
21
|
-
status: string;
|
22
21
|
}
|
23
22
|
interface DeploymentInitiateParameters {
|
24
23
|
name: string;
|
package/dist/deploy/index.js
CHANGED
@@ -5,7 +5,7 @@ import { buildCancel } from './build-cancel.js';
|
|
5
5
|
import { getUploadFiles } from './get-upload-files.js';
|
6
6
|
import { deploymentInitiate } from './deployment-initiate.js';
|
7
7
|
import { deploymentComplete } from './deployment-complete.js';
|
8
|
-
import { deploymentCancel } from './deployment-cancel.js';
|
8
|
+
import { deploymentCancel, DeploymentCancelReason } from './deployment-cancel.js';
|
9
9
|
import { uploadFiles } from './upload-files.js';
|
10
10
|
import { buildProject } from './build-project.js';
|
11
11
|
import { getMetadata, createLabels, getEnvironmentInput } from './metadata.js';
|
@@ -69,16 +69,18 @@ ${urlMessage} preview URL: ${deploymentCompleteOp.deployment.url}`,
|
|
69
69
|
`Deployment failed with: ${error.message}, cancelling deployment.`,
|
70
70
|
stderrLogger
|
71
71
|
);
|
72
|
-
await deploymentCancel(
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
72
|
+
await deploymentCancel(
|
73
|
+
config,
|
74
|
+
deployment.deployment.id,
|
75
|
+
DeploymentCancelReason.Failed
|
76
|
+
).catch((err) => {
|
77
|
+
if (err instanceof Error) {
|
78
|
+
outputWarn(
|
79
|
+
`Failed to cancel deployment: ${err.message}`,
|
80
|
+
stderrLogger
|
81
|
+
);
|
80
82
|
}
|
81
|
-
);
|
83
|
+
});
|
82
84
|
}
|
83
85
|
consoleError(error.message);
|
84
86
|
}
|
package/dist/utils/utils.js
CHANGED
@@ -72,6 +72,11 @@ function stderrLogger(log) {
|
|
72
72
|
}
|
73
73
|
const maxLabelLength = 90;
|
74
74
|
function parseToken(inputToken) {
|
75
|
+
if (!inputToken) {
|
76
|
+
throw new Error(
|
77
|
+
"No deployment token provided. Use the --token flag to set a deployment token."
|
78
|
+
);
|
79
|
+
}
|
75
80
|
try {
|
76
81
|
const decodedToken = Buffer.from(inputToken, "base64").toString("utf-8");
|
77
82
|
const rawToken = JSON.parse(decodedToken);
|
@@ -99,7 +104,7 @@ async function verifyConfig({
|
|
99
104
|
for (const pathType of Object.keys(checkPaths)) {
|
100
105
|
await checkPath(checkPaths[pathType], pathType);
|
101
106
|
}
|
102
|
-
const addressRegex = /^
|
107
|
+
const addressRegex = /^https:\/\/(?:[\w-]+\.)*[\w-]+|^https:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/;
|
103
108
|
if (!addressRegex.test(config.deploymentUrl)) {
|
104
109
|
throw new Error(`Invalid deployment service URL: ${config.deploymentUrl}`);
|
105
110
|
}
|
package/oclif.manifest.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"version": "1.
|
2
|
+
"version": "1.4.0",
|
3
3
|
"commands": {
|
4
4
|
"oxygen:deploy": {
|
5
5
|
"id": "oxygen:deploy",
|
@@ -16,13 +16,13 @@
|
|
16
16
|
"type": "option",
|
17
17
|
"char": "t",
|
18
18
|
"description": "Oxygen deployment token",
|
19
|
-
"required":
|
19
|
+
"required": false,
|
20
20
|
"multiple": false
|
21
21
|
},
|
22
|
-
"
|
23
|
-
"name": "
|
22
|
+
"path": {
|
23
|
+
"name": "path",
|
24
24
|
"type": "option",
|
25
|
-
"char": "
|
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
|
@@ -90,21 +89,21 @@
|
|
90
89
|
"metadataUrl": {
|
91
90
|
"name": "metadataUrl",
|
92
91
|
"type": "option",
|
93
|
-
"description": "URL that links to the deployment",
|
92
|
+
"description": "URL that links to the deployment. Will be saved and displayed in the Shopify admin",
|
94
93
|
"required": false,
|
95
94
|
"multiple": false
|
96
95
|
},
|
97
96
|
"metadataUser": {
|
98
97
|
"name": "metadataUser",
|
99
98
|
"type": "option",
|
100
|
-
"description": "User that initiated the deployment",
|
99
|
+
"description": "User that initiated the deployment. Will be saved and displayed in the Shopify admin",
|
101
100
|
"required": false,
|
102
101
|
"multiple": false
|
103
102
|
},
|
104
103
|
"metadataVersion": {
|
105
104
|
"name": "metadataVersion",
|
106
105
|
"type": "option",
|
107
|
-
"description": "A version identifier for the deployment",
|
106
|
+
"description": "A version identifier for the deployment. Will be saved and displayed in the Shopify admin",
|
108
107
|
"required": false,
|
109
108
|
"multiple": false
|
110
109
|
}
|
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.
|
8
|
+
"version": "1.4.0",
|
9
9
|
"type": "module",
|
10
10
|
"scripts": {
|
11
11
|
"build": "tsup --clean --config ./tsup.config.ts && oclif manifest",
|
@@ -13,7 +13,7 @@
|
|
13
13
|
"dev": "tsup --watch --config ./tsup.config.ts",
|
14
14
|
"typecheck": "tsc --noEmit",
|
15
15
|
"lint": "eslint --ext .js,.ts --max-warnings 0 src",
|
16
|
-
"lint:format": "npm run lint --fix",
|
16
|
+
"lint:format": "prettier --write \"**/*.*\" && npm run lint --fix",
|
17
17
|
"generate:manifest": "oclif manifest",
|
18
18
|
"prepack": "npm install && npm run build",
|
19
19
|
"release": "npm run build && npx changeset publish",
|
@@ -31,8 +31,8 @@
|
|
31
31
|
"/oclif.manifest.json"
|
32
32
|
],
|
33
33
|
"dependencies": {
|
34
|
-
"@oclif/core": "2.
|
35
|
-
"@shopify/cli-kit": "^3.46.
|
34
|
+
"@oclif/core": "2.8.7",
|
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": "^
|
44
|
-
"@types/prettier": "^2.7.
|
45
|
-
"eslint": "^8.
|
43
|
+
"@types/node": "^20.3.1",
|
44
|
+
"@types/prettier": "^2.7.3",
|
45
|
+
"eslint": "^8.43.0",
|
46
46
|
"node-fetch": "^3.3.1",
|
47
47
|
"oclif": "^3",
|
48
48
|
"tsup": "^6.7.0",
|
49
|
-
"typescript": "^5.
|
50
|
-
"vite": "^4.
|
51
|
-
"vitest": "^0.
|
49
|
+
"typescript": "^5.1.3",
|
50
|
+
"vite": "^4.3.9",
|
51
|
+
"vitest": "^0.32.2"
|
52
52
|
},
|
53
53
|
"prettier": "@shopify/prettier-config",
|
54
54
|
"oclif": {
|