@shopify/cli-hydrogen 5.5.1 → 5.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,8 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import Command from '@shopify/cli-kit/node/base-command';
3
- import colors from '@shopify/cli-kit/node/colors';
4
- import { outputWarn, outputInfo, outputContent } from '@shopify/cli-kit/node/output';
5
- import { AbortError } from '@shopify/cli-kit/node/error';
6
- import { getLatestGitCommit } from '@shopify/cli-kit/node/git';
7
- import { resolvePath } from '@shopify/cli-kit/node/path';
8
- import { renderFatalError, renderSelectPrompt, renderSuccess, renderTasks } from '@shopify/cli-kit/node/ui';
9
- import { ciPlatform } from '@shopify/cli-kit/node/context/local';
10
- import { parseToken, createDeploy } from '@shopify/oxygen-cli/deploy';
11
- import { commonFlags, flagsToCamelObject } from '../../lib/flags.js';
12
- import { getOxygenDeploymentData } from '../../lib/get-oxygen-deployment-data.js';
13
- import { runBuild } from './build.js';
3
+ import { outputWarn } from '@shopify/cli-kit/node/output';
4
+ import { renderWarning } from '@shopify/cli-kit/node/ui';
5
+ import { commonFlags } from '../../lib/flags.js';
14
6
 
15
7
  const deploymentLogger = (message, level = "info") => {
16
8
  if (level === "error" || level === "warn") {
@@ -56,175 +48,13 @@ class Deploy extends Command {
56
48
  };
57
49
  static hidden = true;
58
50
  async run() {
59
- const { flags } = await this.parse(Deploy);
60
- const deploymentOptions = this.flagsToOxygenDeploymentOptions(flags);
61
- await oxygenDeploy(deploymentOptions).catch((error) => {
62
- renderFatalError(error);
63
- process.exit(1);
64
- }).finally(() => {
65
- process.exit(0);
66
- });
67
- }
68
- flagsToOxygenDeploymentOptions(flags) {
69
- const camelFlags = flagsToCamelObject(flags);
70
- return {
71
- ...camelFlags,
72
- environmentTag: flags["env-branch"],
73
- path: flags.path ? resolvePath(flags.path) : process.cwd()
74
- };
75
- }
76
- }
77
- async function oxygenDeploy(options) {
78
- const {
79
- environmentTag,
80
- path,
81
- shop,
82
- publicDeployment,
83
- metadataUrl,
84
- metadataUser,
85
- metadataVersion
86
- } = options;
87
- const ci = ciPlatform();
88
- let token = options.token;
89
- let branch;
90
- let deploymentData;
91
- let deploymentEnvironmentTag = void 0;
92
- let gitCommit;
93
- try {
94
- gitCommit = await getLatestGitCommit(path);
95
- branch = (/HEAD -> ([^,]*)/.exec(gitCommit.refs) || [])[1];
96
- } catch (error) {
97
- outputWarn("Could not retrieve Git history.");
98
- branch = void 0;
99
- }
100
- if (!ci.isCI) {
101
- deploymentData = await getOxygenDeploymentData({
102
- root: path,
103
- flagShop: shop
104
- });
105
- if (!deploymentData) {
106
- return;
107
- }
108
- token = token || deploymentData.oxygenDeploymentToken;
109
- }
110
- if (!token) {
111
- const errMessage = ci.isCI ? [
112
- "No deployment token provided. Use the ",
113
- { command: "--token" },
114
- " flag to provide a token."
115
- ] : `Could not obtain an Oxygen deployment token, please try again or contact Shopify support.`;
116
- throw new AbortError(errMessage);
117
- }
118
- if (!ci.isCI && !environmentTag && deploymentData?.environments) {
119
- if (deploymentData.environments.length > 1) {
120
- const choices = [
121
- ...deploymentData.environments.map(({ name, branch: branch2 }) => ({
122
- label: name,
123
- value: branch2
124
- }))
125
- ];
126
- deploymentEnvironmentTag = await renderSelectPrompt({
127
- message: "Select an environment to deploy to",
128
- choices,
129
- defaultValue: branch
130
- });
131
- } else {
132
- outputInfo(
133
- `Using current checked out branch ${branch} as environment tag`
134
- );
135
- }
136
- }
137
- const config = {
138
- assetsDir: "dist/client",
139
- deploymentUrl: "https://oxygen.shopifyapps.com",
140
- deploymentToken: parseToken(token),
141
- environmentTag: environmentTag || deploymentEnvironmentTag || branch,
142
- verificationMaxDuration: 180,
143
- metadata: {
144
- ...metadataUrl ? { url: metadataUrl } : {},
145
- ...metadataUser ? { user: metadataUser } : {},
146
- ...metadataVersion ? { version: metadataVersion } : {}
147
- },
148
- publicDeployment,
149
- skipVerification: false,
150
- rootPath: path,
151
- skipBuild: false,
152
- workerOnly: false,
153
- workerDir: "dist/worker"
154
- };
155
- let resolveUpload;
156
- const uploadPromise = new Promise((resolve) => {
157
- resolveUpload = resolve;
158
- });
159
- let resolveHealthCheck;
160
- const healthCheckPromise = new Promise((resolve) => {
161
- resolveHealthCheck = resolve;
162
- });
163
- let deployError = null;
164
- let resolveDeploy;
165
- let rejectDeploy;
166
- const deployPromise = new Promise((resolve, reject) => {
167
- resolveDeploy = resolve;
168
- rejectDeploy = reject;
169
- });
170
- const hooks = {
171
- buildFunction: async (assetPath) => {
172
- outputInfo(
173
- outputContent`${colors.whiteBright("Building project...")}`.value
174
- );
175
- await runBuild({
176
- directory: path,
177
- assetPath,
178
- sourcemap: false,
179
- useCodegen: false
180
- });
181
- },
182
- onVerificationComplete: () => resolveHealthCheck(),
183
- onUploadFilesStart: () => uploadStart(),
184
- onUploadFilesComplete: () => resolveUpload(),
185
- onVerificationError: (error) => {
186
- deployError = new AbortError(
187
- error.message,
188
- "Please verify the deployment status in the Shopify Admin and retry deploying if necessary."
189
- );
190
- },
191
- onUploadFilesError: (error) => {
192
- deployError = new AbortError(
193
- error.message,
194
- "Check your connection and try again. If the problem persists, try again later or contact support."
195
- );
196
- }
197
- };
198
- const uploadStart = async () => {
199
- outputInfo(
200
- outputContent`${colors.whiteBright("Deploying to Oxygen..\n")}`.value
201
- );
202
- await renderTasks([
203
- {
204
- title: "Uploading files",
205
- task: async () => await uploadPromise
206
- },
207
- {
208
- title: "Verifying deployment",
209
- task: async () => await healthCheckPromise
210
- }
211
- ]);
212
- };
213
- await createDeploy({ config, hooks, logger: deploymentLogger }).then((url) => {
214
- const deploymentType = config.publicDeployment ? "public" : "private";
215
- renderSuccess({
216
- body: ["Successfully deployed to Oxygen"],
51
+ renderWarning({
52
+ body: "Deploy command unavailable.",
217
53
  nextSteps: [
218
- [
219
- `Open ${url} in your browser to view your ${deploymentType} deployment`
220
- ]
54
+ "To use the deploy command, upgrade cli-hydrogen to v7.0.0+."
221
55
  ]
222
56
  });
223
- resolveDeploy();
224
- }).catch((error) => {
225
- rejectDeploy(deployError || error);
226
- });
227
- return deployPromise;
57
+ }
228
58
  }
229
59
 
230
- export { Deploy as default, deploymentLogger, oxygenDeploy };
60
+ export { Deploy as default, deploymentLogger };
@@ -15,7 +15,7 @@
15
15
  "dependencies": {
16
16
  "@remix-run/react": "1.19.1",
17
17
  "@shopify/cli": "3.49.2",
18
- "@shopify/cli-hydrogen": "^5.5.1",
18
+ "@shopify/cli-hydrogen": "^5.5.2",
19
19
  "@shopify/hydrogen": "^2023.7.13",
20
20
  "@shopify/remix-oxygen": "^1.1.8",
21
21
  "graphql": "^16.6.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.5.1",
2
+ "version": "5.5.2",
3
3
  "commands": {
4
4
  "hydrogen:build": {
5
5
  "id": "hydrogen:build",
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
- "version": "5.5.1",
7
+ "version": "5.5.2",
8
8
  "license": "MIT",
9
9
  "type": "module",
10
10
  "scripts": {
@@ -1,237 +0,0 @@
1
- import { vi, describe, expect, beforeEach, afterEach, it } from 'vitest';
2
- import { login } from '../../lib/auth.js';
3
- import { getStorefronts } from '../../lib/graphql/admin/link-storefront.js';
4
- import { AbortError } from '@shopify/cli-kit/node/error';
5
- import { renderSelectPrompt, renderSuccess, renderFatalError } from '@shopify/cli-kit/node/ui';
6
- import { getLatestGitCommit } from '@shopify/cli-kit/node/git';
7
- import { oxygenDeploy, deploymentLogger } from './deploy.js';
8
- import { getOxygenDeploymentData } from '../../lib/get-oxygen-deployment-data.js';
9
- import { createDeploy, parseToken } from '@shopify/oxygen-cli/deploy';
10
-
11
- vi.mock("../../lib/get-oxygen-deployment-data.js");
12
- vi.mock("@shopify/oxygen-cli/deploy");
13
- vi.mock("../../lib/auth.js");
14
- vi.mock("../../lib/shopify-config.js");
15
- vi.mock("../../lib/graphql/admin/link-storefront.js");
16
- vi.mock("../../lib/graphql/admin/create-storefront.js");
17
- vi.mock("../../lib/graphql/admin/fetch-job.js");
18
- vi.mock("../../lib/shell.js", () => ({ getCliCommand: () => "h2" }));
19
- vi.mock("@shopify/cli-kit/node/output", async () => {
20
- return {
21
- outputContent: () => ({ value: "" }),
22
- outputInfo: () => {
23
- },
24
- outputWarn: () => {
25
- }
26
- };
27
- });
28
- vi.mock("@shopify/cli-kit/node/ui", async () => {
29
- return {
30
- renderFatalError: vi.fn(),
31
- renderSelectPrompt: vi.fn(),
32
- renderSuccess: vi.fn(),
33
- renderTasks: vi.fn()
34
- };
35
- });
36
- vi.mock("@shopify/cli-kit/node/git", async () => {
37
- return {
38
- getLatestGitCommit: vi.fn()
39
- };
40
- });
41
- vi.mock("@shopify/cli-kit/node/context/local", async () => {
42
- return {
43
- ciPlatform: () => ({ isCI: false })
44
- };
45
- });
46
- describe("deploy", () => {
47
- const ADMIN_SESSION = {
48
- token: "abc123",
49
- storeFqdn: "my-shop.myshopify.com"
50
- };
51
- const FULL_SHOPIFY_CONFIG = {
52
- shop: "my-shop.myshopify.com",
53
- shopName: "My Shop",
54
- email: "email",
55
- storefront: {
56
- id: "gid://shopify/HydrogenStorefront/1",
57
- title: "Hydrogen"
58
- }
59
- };
60
- const UNLINKED_SHOPIFY_CONFIG = {
61
- ...FULL_SHOPIFY_CONFIG,
62
- storefront: void 0
63
- };
64
- const originalExit = process.exit;
65
- const deployParams = {
66
- path: "./",
67
- shop: "snowdevil.myshopify.com",
68
- publicDeployment: false,
69
- metadataUrl: "https://example.com",
70
- metadataUser: "user",
71
- metadataVersion: "1.0.0"
72
- };
73
- const mockToken = {
74
- accessToken: "some-token",
75
- allowedResource: "some-resource",
76
- appId: "1",
77
- client: "1",
78
- expiresAt: "some-time",
79
- namespace: "some-namespace",
80
- namespaceId: "1"
81
- };
82
- const expectedConfig = {
83
- assetsDir: "dist/client",
84
- deploymentUrl: "https://oxygen.shopifyapps.com",
85
- deploymentToken: mockToken,
86
- verificationMaxDuration: 180,
87
- metadata: {
88
- url: deployParams.metadataUrl,
89
- user: deployParams.metadataUser,
90
- version: deployParams.metadataVersion
91
- },
92
- publicDeployment: deployParams.publicDeployment,
93
- skipVerification: false,
94
- rootPath: deployParams.path,
95
- skipBuild: false,
96
- workerOnly: false,
97
- workerDir: "dist/worker"
98
- };
99
- const expectedHooks = {
100
- buildFunction: expect.any(Function),
101
- onVerificationComplete: expect.any(Function),
102
- onUploadFilesStart: expect.any(Function),
103
- onUploadFilesComplete: expect.any(Function),
104
- onVerificationError: expect.any(Function),
105
- onUploadFilesError: expect.any(Function)
106
- };
107
- beforeEach(async () => {
108
- process.exit = vi.fn();
109
- vi.mocked(login).mockResolvedValue({
110
- session: ADMIN_SESSION,
111
- config: UNLINKED_SHOPIFY_CONFIG
112
- });
113
- vi.mocked(getStorefronts).mockResolvedValue([
114
- {
115
- ...FULL_SHOPIFY_CONFIG.storefront,
116
- parsedId: "1",
117
- productionUrl: "https://example.com"
118
- }
119
- ]);
120
- vi.mocked(renderSelectPrompt).mockResolvedValue(FULL_SHOPIFY_CONFIG.shop);
121
- vi.mocked(createDeploy).mockResolvedValue(
122
- "https://a-lovely-deployment.com"
123
- );
124
- vi.mocked(getOxygenDeploymentData).mockResolvedValue({
125
- oxygenDeploymentToken: "some-encoded-token",
126
- environments: []
127
- });
128
- vi.mocked(parseToken).mockReturnValue(mockToken);
129
- });
130
- afterEach(() => {
131
- vi.resetAllMocks();
132
- process.exit = originalExit;
133
- });
134
- it("calls getOxygenDeploymentData with the correct parameters", async () => {
135
- await oxygenDeploy(deployParams);
136
- expect(getOxygenDeploymentData).toHaveBeenCalledWith({
137
- root: "./",
138
- flagShop: "snowdevil.myshopify.com"
139
- });
140
- expect(getOxygenDeploymentData).toHaveBeenCalledTimes(1);
141
- });
142
- it("calls createDeploy with the correct parameters", async () => {
143
- await oxygenDeploy(deployParams);
144
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
145
- config: expectedConfig,
146
- hooks: expectedHooks,
147
- logger: deploymentLogger
148
- });
149
- expect(vi.mocked(renderSuccess)).toHaveBeenCalled;
150
- });
151
- it("calls createDeploy with the checked out branch name", async () => {
152
- vi.mocked(getLatestGitCommit).mockResolvedValue({
153
- hash: "123",
154
- message: "test commit",
155
- date: "2021-01-01",
156
- author_name: "test author",
157
- author_email: "test@author.com",
158
- body: "test body",
159
- refs: "HEAD -> main"
160
- });
161
- await oxygenDeploy(deployParams);
162
- expect(vi.mocked(createDeploy)).toHaveBeenCalledWith({
163
- config: { ...expectedConfig, environmentTag: "main" },
164
- hooks: expectedHooks,
165
- logger: deploymentLogger
166
- });
167
- expect(vi.mocked(renderSuccess)).toHaveBeenCalled;
168
- });
169
- it("calls renderSelectPrompt when there are multiple environments", async () => {
170
- vi.mocked(getOxygenDeploymentData).mockResolvedValue({
171
- oxygenDeploymentToken: "some-encoded-token",
172
- environments: [
173
- { name: "production", branch: "main" },
174
- { name: "preview", branch: "staging" }
175
- ]
176
- });
177
- await oxygenDeploy(deployParams);
178
- expect(vi.mocked(renderSelectPrompt)).toHaveBeenCalledWith({
179
- message: "Select an environment to deploy to",
180
- choices: [
181
- { label: "production", value: "main" },
182
- { label: "preview", value: "staging" }
183
- ]
184
- });
185
- });
186
- it("handles error during uploadFiles", async () => {
187
- const mockRenderFatalError = vi.fn();
188
- vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
189
- const error = new Error("Wonky internet!");
190
- vi.mocked(createDeploy).mockImplementation((options) => {
191
- options.hooks?.onUploadFilesStart?.();
192
- options.hooks?.onUploadFilesError?.(error);
193
- return new Promise((_resolve, reject) => {
194
- reject(error);
195
- });
196
- });
197
- try {
198
- await oxygenDeploy(deployParams);
199
- expect(true).toBe(false);
200
- } catch (err) {
201
- if (err instanceof AbortError) {
202
- expect(err.message).toBe(error.message);
203
- expect(err.tryMessage).toBe(
204
- "Check your connection and try again. If the problem persists, try again later or contact support."
205
- );
206
- } else {
207
- expect(true).toBe(false);
208
- }
209
- }
210
- });
211
- it("handles error during deployment verification", async () => {
212
- const mockRenderFatalError = vi.fn();
213
- vi.mocked(renderFatalError).mockImplementation(mockRenderFatalError);
214
- const error = new Error("Cloudflare is down!");
215
- vi.mocked(createDeploy).mockImplementation((options) => {
216
- options.hooks?.onUploadFilesStart?.();
217
- options.hooks?.onUploadFilesComplete?.();
218
- options.hooks?.onVerificationError?.(error);
219
- return new Promise((_resolve, reject) => {
220
- reject(error);
221
- });
222
- });
223
- try {
224
- await oxygenDeploy(deployParams);
225
- expect(true).toBe(false);
226
- } catch (err) {
227
- if (err instanceof AbortError) {
228
- expect(err.message).toBe(error.message);
229
- expect(err.tryMessage).toBe(
230
- "Please verify the deployment status in the Shopify Admin and retry deploying if necessary."
231
- );
232
- } else {
233
- expect(true).toBe(false);
234
- }
235
- }
236
- });
237
- });