@shopify/cli-hydrogen 4.2.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/hydrogen/build.js +6 -5
- package/dist/commands/hydrogen/check.js +1 -1
- package/dist/commands/hydrogen/codegen-unstable.d.ts +1 -0
- package/dist/commands/hydrogen/codegen-unstable.js +6 -0
- package/dist/commands/hydrogen/env/list.d.ts +2 -3
- package/dist/commands/hydrogen/env/list.js +42 -44
- package/dist/commands/hydrogen/env/list.test.js +18 -24
- package/dist/commands/hydrogen/env/pull.d.ts +2 -3
- package/dist/commands/hydrogen/env/pull.js +42 -23
- package/dist/commands/hydrogen/env/pull.test.js +16 -4
- package/dist/commands/hydrogen/init.js +3 -13
- package/dist/commands/hydrogen/link.d.ts +0 -1
- package/dist/commands/hydrogen/link.js +34 -36
- package/dist/commands/hydrogen/link.test.js +43 -27
- package/dist/commands/hydrogen/list.d.ts +2 -2
- package/dist/commands/hydrogen/list.js +43 -39
- package/dist/commands/hydrogen/list.test.js +24 -32
- package/dist/commands/hydrogen/shortcut.js +6 -7
- package/dist/commands/hydrogen/shortcut.test.js +8 -9
- package/dist/commands/hydrogen/unlink.d.ts +0 -1
- package/dist/commands/hydrogen/unlink.js +5 -3
- package/dist/lib/admin-session.d.ts +1 -0
- package/dist/lib/codegen.d.ts +3 -2
- package/dist/lib/codegen.js +20 -7
- package/dist/lib/combined-environment-variables.js +19 -36
- package/dist/lib/combined-environment-variables.test.js +7 -7
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.js +67 -63
- package/dist/lib/flags.js +2 -3
- package/dist/lib/graphql/admin/link-storefront.d.ts +12 -9
- package/dist/lib/graphql/admin/link-storefront.js +18 -1
- package/dist/lib/graphql/admin/list-environments.d.ts +6 -5
- package/dist/lib/graphql/admin/list-environments.js +11 -1
- package/dist/lib/graphql/admin/list-storefronts.d.ts +13 -5
- package/dist/lib/graphql/admin/list-storefronts.js +18 -1
- package/dist/lib/graphql/admin/pull-variables.d.ts +6 -1
- package/dist/lib/graphql/admin/pull-variables.js +14 -1
- package/dist/lib/mini-oxygen.js +1 -1
- package/dist/lib/process.d.ts +6 -0
- package/dist/lib/process.js +17 -0
- package/dist/lib/pull-environment-variables.d.ts +1 -0
- package/dist/lib/pull-environment-variables.js +4 -14
- package/dist/lib/remix-version-interop.js +1 -1
- package/dist/lib/shell.d.ts +5 -6
- package/dist/lib/shell.js +65 -17
- package/dist/lib/shell.test.d.ts +1 -0
- package/dist/lib/shell.test.js +85 -0
- package/dist/lib/shopify-config.d.ts +1 -1
- package/dist/lib/shopify-config.js +2 -2
- package/dist/lib/transpile-ts.js +6 -0
- package/oclif.manifest.json +1 -1
- package/package.json +7 -6
- package/dist/lib/colors.d.ts +0 -11
- package/dist/lib/colors.js +0 -11
|
@@ -2,11 +2,15 @@ import { vi, describe, beforeEach, afterEach, it, expect } from 'vitest';
|
|
|
2
2
|
import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
|
|
3
3
|
import { renderSelectPrompt, renderConfirmationPrompt } from '@shopify/cli-kit/node/ui';
|
|
4
4
|
import { adminRequest } from '../../lib/graphql.js';
|
|
5
|
-
import {
|
|
6
|
-
import { getAdminSession } from '../../lib/admin-session.js';
|
|
5
|
+
import { getStorefronts } from '../../lib/graphql/admin/link-storefront.js';
|
|
7
6
|
import { getConfig, setStorefront } from '../../lib/shopify-config.js';
|
|
8
7
|
import { linkStorefront } from './link.js';
|
|
9
8
|
|
|
9
|
+
const SHOP = "my-shop";
|
|
10
|
+
const ADMIN_SESSION = {
|
|
11
|
+
token: "abc123",
|
|
12
|
+
storeFqdn: SHOP
|
|
13
|
+
};
|
|
10
14
|
vi.mock("@shopify/cli-kit/node/ui", async () => {
|
|
11
15
|
const original = await vi.importActual("@shopify/cli-kit/node/ui");
|
|
12
16
|
return {
|
|
@@ -17,22 +21,22 @@ vi.mock("@shopify/cli-kit/node/ui", async () => {
|
|
|
17
21
|
});
|
|
18
22
|
vi.mock("../../lib/graphql.js");
|
|
19
23
|
vi.mock("../../lib/shopify-config.js");
|
|
20
|
-
vi.mock("../../lib/admin-
|
|
24
|
+
vi.mock("../../lib/graphql/admin/link-storefront.js");
|
|
21
25
|
vi.mock("../../lib/shop.js", () => ({
|
|
22
|
-
getHydrogenShop: () =>
|
|
26
|
+
getHydrogenShop: () => SHOP
|
|
27
|
+
}));
|
|
28
|
+
vi.mock("../../lib/shell.js", () => ({
|
|
29
|
+
getCliCommand: () => "h2"
|
|
23
30
|
}));
|
|
24
|
-
const ADMIN_SESSION = {
|
|
25
|
-
token: "abc123",
|
|
26
|
-
storeFqdn: "my-shop"
|
|
27
|
-
};
|
|
28
31
|
describe("link", () => {
|
|
29
32
|
const outputMock = mockAndCaptureOutput();
|
|
30
33
|
beforeEach(async () => {
|
|
31
|
-
vi.mocked(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
vi.mocked(getStorefronts).mockResolvedValue({
|
|
35
|
+
adminSession: ADMIN_SESSION,
|
|
36
|
+
storefronts: [
|
|
34
37
|
{
|
|
35
38
|
id: "gid://shopify/HydrogenStorefront/1",
|
|
39
|
+
parsedId: "1",
|
|
36
40
|
title: "Hydrogen",
|
|
37
41
|
productionUrl: "https://example.com"
|
|
38
42
|
}
|
|
@@ -46,26 +50,36 @@ describe("link", () => {
|
|
|
46
50
|
});
|
|
47
51
|
it("makes a GraphQL call to fetch the storefronts", async () => {
|
|
48
52
|
await linkStorefront({});
|
|
49
|
-
expect(
|
|
50
|
-
LinkStorefrontQuery,
|
|
51
|
-
ADMIN_SESSION
|
|
52
|
-
);
|
|
53
|
+
expect(getStorefronts).toHaveBeenCalledWith(SHOP);
|
|
53
54
|
});
|
|
54
55
|
it("renders a list of choices and forwards the selection to setStorefront", async () => {
|
|
55
56
|
vi.mocked(renderSelectPrompt).mockResolvedValue(
|
|
56
57
|
"gid://shopify/HydrogenStorefront/1"
|
|
57
58
|
);
|
|
58
59
|
await linkStorefront({ path: "my-path" });
|
|
59
|
-
expect(setStorefront).toHaveBeenCalledWith(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
expect(setStorefront).toHaveBeenCalledWith(
|
|
61
|
+
"my-path",
|
|
62
|
+
expect.objectContaining({
|
|
63
|
+
id: "gid://shopify/HydrogenStorefront/1",
|
|
64
|
+
title: "Hydrogen"
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
it("renders a success message", async () => {
|
|
69
|
+
vi.mocked(renderSelectPrompt).mockResolvedValue(
|
|
70
|
+
"gid://shopify/HydrogenStorefront/1"
|
|
71
|
+
);
|
|
72
|
+
await linkStorefront({ path: "my-path" });
|
|
73
|
+
expect(outputMock.info()).toMatch(/Hydrogen is now linked/g);
|
|
74
|
+
expect(outputMock.info()).toMatch(
|
|
75
|
+
/Run `h2 dev` to start your local development server and start building/g
|
|
76
|
+
);
|
|
64
77
|
});
|
|
65
78
|
describe("when there are no Hydrogen storefronts", () => {
|
|
66
79
|
it("renders a message and returns early", async () => {
|
|
67
|
-
vi.mocked(
|
|
68
|
-
|
|
80
|
+
vi.mocked(getStorefronts).mockResolvedValue({
|
|
81
|
+
adminSession: ADMIN_SESSION,
|
|
82
|
+
storefronts: []
|
|
69
83
|
});
|
|
70
84
|
await linkStorefront({});
|
|
71
85
|
expect(outputMock.info()).toMatch(
|
|
@@ -119,11 +133,13 @@ describe("link", () => {
|
|
|
119
133
|
it("does not prompt the user to make a selection", async () => {
|
|
120
134
|
await linkStorefront({ path: "my-path", storefront: "Hydrogen" });
|
|
121
135
|
expect(renderSelectPrompt).not.toHaveBeenCalled();
|
|
122
|
-
expect(setStorefront).toHaveBeenCalledWith(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
expect(setStorefront).toHaveBeenCalledWith(
|
|
137
|
+
"my-path",
|
|
138
|
+
expect.objectContaining({
|
|
139
|
+
id: "gid://shopify/HydrogenStorefront/1",
|
|
140
|
+
title: "Hydrogen"
|
|
141
|
+
})
|
|
142
|
+
);
|
|
127
143
|
});
|
|
128
144
|
describe("and there is no matching storefront", () => {
|
|
129
145
|
it("renders a warning message and returns early", async () => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as _oclif_core_lib_interfaces_parser_js from '@oclif/core/lib/interfaces/parser.js';
|
|
2
2
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
3
3
|
import { Deployment } from '../../lib/graphql/admin/list-storefronts.js';
|
|
4
|
+
import '@shopify/cli-kit/node/session';
|
|
4
5
|
|
|
5
6
|
declare class List extends Command {
|
|
6
7
|
static description: string;
|
|
7
|
-
static hidden: boolean;
|
|
8
8
|
static flags: {
|
|
9
9
|
path: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
10
10
|
shop: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
@@ -16,6 +16,6 @@ interface Flags {
|
|
|
16
16
|
shop?: string;
|
|
17
17
|
}
|
|
18
18
|
declare function listStorefronts({ path, shop: flagShop }: Flags): Promise<void>;
|
|
19
|
-
declare function formatDeployment(deployment: Deployment
|
|
19
|
+
declare function formatDeployment(deployment: Deployment): string;
|
|
20
20
|
|
|
21
21
|
export { List as default, formatDeployment, listStorefronts };
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
2
|
+
import { pluralize } from '@shopify/cli-kit/common/string';
|
|
3
|
+
import colors from '@shopify/cli-kit/node/colors';
|
|
4
|
+
import { outputNewline, outputInfo, outputContent } from '@shopify/cli-kit/node/output';
|
|
5
5
|
import { commonFlags } from '../../lib/flags.js';
|
|
6
6
|
import { getHydrogenShop } from '../../lib/shop.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { parseGid } from '../../lib/graphql.js';
|
|
8
|
+
import { getStorefrontsWithDeployment } from '../../lib/graphql/admin/list-storefronts.js';
|
|
9
9
|
import { logMissingStorefronts } from '../../lib/missing-storefronts.js';
|
|
10
10
|
|
|
11
11
|
class List extends Command {
|
|
12
12
|
static description = "Returns a list of Hydrogen storefronts available on a given shop.";
|
|
13
|
-
static hidden = true;
|
|
14
13
|
static flags = {
|
|
15
14
|
path: commonFlags.path,
|
|
16
15
|
shop: commonFlags.shop
|
|
@@ -22,49 +21,44 @@ class List extends Command {
|
|
|
22
21
|
}
|
|
23
22
|
async function listStorefronts({ path, shop: flagShop }) {
|
|
24
23
|
const shop = await getHydrogenShop({ path, shop: flagShop });
|
|
25
|
-
const adminSession = await
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
adminSession
|
|
29
|
-
);
|
|
30
|
-
const storefrontsCount = result.hydrogenStorefronts.length;
|
|
31
|
-
if (storefrontsCount > 0) {
|
|
24
|
+
const { storefronts, adminSession } = await getStorefrontsWithDeployment(shop);
|
|
25
|
+
if (storefronts.length > 0) {
|
|
26
|
+
outputNewline();
|
|
32
27
|
outputInfo(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
id: parseGid(id),
|
|
38
|
-
title,
|
|
39
|
-
productionUrl,
|
|
40
|
-
currentDeployment: formatDeployment(currentProductionDeployment)
|
|
41
|
-
})
|
|
28
|
+
pluralizedStorefronts({
|
|
29
|
+
storefronts,
|
|
30
|
+
shop
|
|
31
|
+
}).toString()
|
|
42
32
|
);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
33
|
+
storefronts.forEach(
|
|
34
|
+
({ currentProductionDeployment, id, productionUrl, title }) => {
|
|
35
|
+
outputNewline();
|
|
36
|
+
outputInfo(
|
|
37
|
+
outputContent`${colors.whiteBright(title)} ${colors.dim(
|
|
38
|
+
`(id: ${parseGid(id)})`
|
|
39
|
+
)}`.value
|
|
40
|
+
);
|
|
41
|
+
if (productionUrl) {
|
|
42
|
+
outputInfo(
|
|
43
|
+
outputContent` ${colors.whiteBright(productionUrl)}`.value
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
if (currentProductionDeployment) {
|
|
47
|
+
outputInfo(
|
|
48
|
+
outputContent` ${colors.dim(
|
|
49
|
+
formatDeployment(currentProductionDeployment)
|
|
50
|
+
)}`.value
|
|
51
|
+
);
|
|
58
52
|
}
|
|
59
53
|
}
|
|
60
|
-
|
|
54
|
+
);
|
|
61
55
|
} else {
|
|
62
56
|
logMissingStorefronts(adminSession);
|
|
63
57
|
}
|
|
64
58
|
}
|
|
65
59
|
const dateFormat = new Intl.DateTimeFormat("default", {
|
|
66
60
|
year: "numeric",
|
|
67
|
-
month: "
|
|
61
|
+
month: "numeric",
|
|
68
62
|
day: "numeric"
|
|
69
63
|
});
|
|
70
64
|
function formatDeployment(deployment) {
|
|
@@ -79,5 +73,15 @@ function formatDeployment(deployment) {
|
|
|
79
73
|
}
|
|
80
74
|
return message;
|
|
81
75
|
}
|
|
76
|
+
const pluralizedStorefronts = ({
|
|
77
|
+
storefronts,
|
|
78
|
+
shop
|
|
79
|
+
}) => {
|
|
80
|
+
return pluralize(
|
|
81
|
+
storefronts,
|
|
82
|
+
(storefronts2) => `Showing ${storefronts2.length} Hydrogen storefronts for the store ${shop}`,
|
|
83
|
+
(_storefront) => `Showing 1 Hydrogen storefront for the store ${shop}`
|
|
84
|
+
);
|
|
85
|
+
};
|
|
82
86
|
|
|
83
87
|
export { List as default, formatDeployment, listStorefronts };
|
|
@@ -1,32 +1,24 @@
|
|
|
1
1
|
import { vi, describe, beforeEach, afterEach, it, expect } from 'vitest';
|
|
2
2
|
import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
|
|
3
|
-
import {
|
|
4
|
-
import { getAdminSession } from '../../lib/admin-session.js';
|
|
5
|
-
import { adminRequest } from '../../lib/graphql.js';
|
|
3
|
+
import { getStorefrontsWithDeployment } from '../../lib/graphql/admin/list-storefronts.js';
|
|
6
4
|
import { listStorefronts, formatDeployment } from './list.js';
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
vi.mock("../../lib/graphql.js", async () => {
|
|
10
|
-
|
|
11
|
-
"../../lib/graphql.js"
|
|
12
|
-
);
|
|
13
|
-
return {
|
|
14
|
-
...original,
|
|
15
|
-
adminRequest: vi.fn()
|
|
16
|
-
};
|
|
6
|
+
const SHOP_NAME = "my-shop";
|
|
7
|
+
vi.mock("../../lib/graphql/admin/list-storefronts.js", async () => {
|
|
8
|
+
return { getStorefrontsWithDeployment: vi.fn() };
|
|
17
9
|
});
|
|
18
10
|
vi.mock("../../lib/shop.js", () => ({
|
|
19
|
-
getHydrogenShop: () =>
|
|
11
|
+
getHydrogenShop: () => SHOP_NAME
|
|
20
12
|
}));
|
|
21
13
|
describe("list", () => {
|
|
22
14
|
const ADMIN_SESSION = {
|
|
23
15
|
token: "abc123",
|
|
24
|
-
storeFqdn:
|
|
16
|
+
storeFqdn: SHOP_NAME
|
|
25
17
|
};
|
|
26
18
|
beforeEach(async () => {
|
|
27
|
-
vi.mocked(
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
vi.mocked(getStorefrontsWithDeployment).mockResolvedValue({
|
|
20
|
+
adminSession: ADMIN_SESSION,
|
|
21
|
+
storefronts: []
|
|
30
22
|
});
|
|
31
23
|
});
|
|
32
24
|
afterEach(() => {
|
|
@@ -35,23 +27,23 @@ describe("list", () => {
|
|
|
35
27
|
});
|
|
36
28
|
it("makes a GraphQL call to fetch the storefronts", async () => {
|
|
37
29
|
await listStorefronts({});
|
|
38
|
-
expect(
|
|
39
|
-
ListStorefrontsQuery,
|
|
40
|
-
ADMIN_SESSION
|
|
41
|
-
);
|
|
30
|
+
expect(getStorefrontsWithDeployment).toHaveBeenCalledWith(SHOP_NAME);
|
|
42
31
|
});
|
|
43
32
|
describe("and there are storefronts", () => {
|
|
44
33
|
beforeEach(() => {
|
|
45
|
-
vi.mocked(
|
|
46
|
-
|
|
34
|
+
vi.mocked(getStorefrontsWithDeployment).mockResolvedValue({
|
|
35
|
+
adminSession: ADMIN_SESSION,
|
|
36
|
+
storefronts: [
|
|
47
37
|
{
|
|
48
38
|
id: "gid://shopify/HydrogenStorefront/1",
|
|
39
|
+
parsedId: "1",
|
|
49
40
|
title: "Hydrogen",
|
|
50
41
|
productionUrl: "https://example.com",
|
|
51
42
|
currentProductionDeployment: null
|
|
52
43
|
},
|
|
53
44
|
{
|
|
54
45
|
id: "gid://shopify/HydrogenStorefront/2",
|
|
46
|
+
parsedId: "2",
|
|
55
47
|
title: "Demo Store",
|
|
56
48
|
productionUrl: "https://demo.example.com",
|
|
57
49
|
currentProductionDeployment: {
|
|
@@ -67,14 +59,13 @@ describe("list", () => {
|
|
|
67
59
|
const outputMock = mockAndCaptureOutput();
|
|
68
60
|
await listStorefronts({});
|
|
69
61
|
expect(outputMock.info()).toMatch(
|
|
70
|
-
/
|
|
71
|
-
);
|
|
72
|
-
expect(outputMock.info()).toMatch(
|
|
73
|
-
/1 Hydrogen https:\/\/example.com/g
|
|
74
|
-
);
|
|
75
|
-
expect(outputMock.info()).toMatch(
|
|
76
|
-
/2 Demo Store https:\/\/demo.example.com March 22, 2023, Update README.md/g
|
|
62
|
+
/Showing 2 Hydrogen storefronts for the store my-shop/g
|
|
77
63
|
);
|
|
64
|
+
expect(outputMock.info()).toMatch(/Hydrogen \(id: 1\)/g);
|
|
65
|
+
expect(outputMock.info()).toMatch(/https:\/\/example.com/g);
|
|
66
|
+
expect(outputMock.info()).toMatch(/Demo Store \(id: 2\)/g);
|
|
67
|
+
expect(outputMock.info()).toMatch(/https:\/\/demo.example.com/g);
|
|
68
|
+
expect(outputMock.info()).toMatch(/3\/22\/2023, Update README.md/g);
|
|
78
69
|
});
|
|
79
70
|
});
|
|
80
71
|
describe("and there are no storefronts", () => {
|
|
@@ -100,17 +91,18 @@ describe("formatDeployment", () => {
|
|
|
100
91
|
commitMessage: "Update README.md\n\nThis is a description of why the change was made."
|
|
101
92
|
};
|
|
102
93
|
expect(formatDeployment(deployment)).toStrictEqual(
|
|
103
|
-
"
|
|
94
|
+
"3/22/2023, Update README.md"
|
|
104
95
|
);
|
|
105
96
|
});
|
|
106
97
|
describe("when there is no commit message", () => {
|
|
107
98
|
it("only returns the date", () => {
|
|
108
99
|
const deployment = {
|
|
109
100
|
id: "gid://shopify/HydrogenStorefrontDeployment/1",
|
|
101
|
+
parsedId: "1",
|
|
110
102
|
createdAt,
|
|
111
103
|
commitMessage: null
|
|
112
104
|
};
|
|
113
|
-
expect(formatDeployment(deployment)).toStrictEqual("
|
|
105
|
+
expect(formatDeployment(deployment)).toStrictEqual("3/22/2023");
|
|
114
106
|
});
|
|
115
107
|
});
|
|
116
108
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
2
|
import { renderSuccess, renderFatalError } from '@shopify/cli-kit/node/ui';
|
|
3
|
-
import { isWindows, isGitBash,
|
|
3
|
+
import { ALIAS_NAME, isWindows, isGitBash, shellWriteAlias, shellRunScript } from '../../lib/shell.js';
|
|
4
4
|
|
|
5
|
-
const ALIAS_NAME = "h2";
|
|
6
5
|
class Shortcut extends Command {
|
|
7
6
|
static description = `Creates a global \`${ALIAS_NAME}\` shortcut for the Hydrogen CLI`;
|
|
8
7
|
async run() {
|
|
@@ -38,13 +37,13 @@ end
|
|
|
38
37
|
`;
|
|
39
38
|
async function createShortcutsForUnix() {
|
|
40
39
|
const shells = [];
|
|
41
|
-
if (
|
|
40
|
+
if (await shellWriteAlias("zsh", ALIAS_NAME, BASH_ZSH_COMMAND)) {
|
|
42
41
|
shells.push("zsh");
|
|
43
42
|
}
|
|
44
|
-
if (
|
|
43
|
+
if (await shellWriteAlias("bash", ALIAS_NAME, BASH_ZSH_COMMAND)) {
|
|
45
44
|
shells.push("bash");
|
|
46
45
|
}
|
|
47
|
-
if (
|
|
46
|
+
if (await shellWriteAlias("fish", ALIAS_NAME, FISH_FUNCTION)) {
|
|
48
47
|
shells.push("fish");
|
|
49
48
|
}
|
|
50
49
|
return shells;
|
|
@@ -62,10 +61,10 @@ if (!$profileContent -or $profileContent -NotLike '*Invoke-Local-H2*') {
|
|
|
62
61
|
`;
|
|
63
62
|
async function createShortcutsForWindows() {
|
|
64
63
|
const shells = [];
|
|
65
|
-
if (shellRunScript(PS_APPEND_PROFILE_COMMAND, "powershell.exe")) {
|
|
64
|
+
if (await shellRunScript(PS_APPEND_PROFILE_COMMAND, "powershell.exe")) {
|
|
66
65
|
shells.push("PowerShell");
|
|
67
66
|
}
|
|
68
|
-
if (shellRunScript(PS_APPEND_PROFILE_COMMAND, "pwsh.exe")) {
|
|
67
|
+
if (await shellRunScript(PS_APPEND_PROFILE_COMMAND, "pwsh.exe")) {
|
|
69
68
|
shells.push("PowerShell 7+");
|
|
70
69
|
}
|
|
71
70
|
return shells;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, beforeEach, vi, afterEach, expect, it } from 'vitest';
|
|
2
2
|
import { runCreateShortcut } from './shortcut.js';
|
|
3
3
|
import { mockAndCaptureOutput } from '@shopify/cli-kit/node/testing/output';
|
|
4
|
-
import {
|
|
4
|
+
import { shellWriteAlias, isWindows, isGitBash } from '../../lib/shell.js';
|
|
5
5
|
import { execSync, exec } from 'child_process';
|
|
6
6
|
|
|
7
7
|
describe("shortcut", () => {
|
|
@@ -10,18 +10,17 @@ describe("shortcut", () => {
|
|
|
10
10
|
vi.resetAllMocks();
|
|
11
11
|
vi.mock("child_process");
|
|
12
12
|
vi.mock("../../lib/shell.js", async () => {
|
|
13
|
+
const original = await vi.importActual("../../lib/shell.js");
|
|
13
14
|
return {
|
|
15
|
+
...original,
|
|
14
16
|
isWindows: vi.fn(),
|
|
15
17
|
isGitBash: vi.fn(),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
shellRunScript: () => true,
|
|
19
|
-
hasAlias: () => false,
|
|
20
|
-
homeFileExists: () => Promise.resolve(true)
|
|
18
|
+
shellWriteAlias: vi.fn(),
|
|
19
|
+
shellRunScript: async () => true
|
|
21
20
|
};
|
|
22
21
|
});
|
|
23
|
-
vi.mocked(
|
|
24
|
-
(shell) => !isWindows() || shell === "bash"
|
|
22
|
+
vi.mocked(shellWriteAlias).mockImplementation(
|
|
23
|
+
async (shell) => !isWindows() || shell === "bash"
|
|
25
24
|
);
|
|
26
25
|
});
|
|
27
26
|
afterEach(() => {
|
|
@@ -50,7 +49,7 @@ describe("shortcut", () => {
|
|
|
50
49
|
});
|
|
51
50
|
it("warns when not finding shells", async () => {
|
|
52
51
|
vi.mocked(isWindows).mockReturnValue(false);
|
|
53
|
-
vi.mocked(
|
|
52
|
+
vi.mocked(shellWriteAlias).mockResolvedValue(false);
|
|
54
53
|
await runCreateShortcut();
|
|
55
54
|
expect(outputMock.info()).toBeFalsy();
|
|
56
55
|
expect(outputMock.error()).toBeTruthy();
|
|
@@ -3,7 +3,6 @@ import Command from '@shopify/cli-kit/node/base-command';
|
|
|
3
3
|
|
|
4
4
|
declare class Unlink extends Command {
|
|
5
5
|
static description: string;
|
|
6
|
-
static hidden: boolean;
|
|
7
6
|
static flags: {
|
|
8
7
|
path: _oclif_core_lib_interfaces_parser_js.OptionFlag<string | undefined, _oclif_core_lib_interfaces_parser_js.CustomOptions>;
|
|
9
8
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import Command from '@shopify/cli-kit/node/base-command';
|
|
2
|
-
import {
|
|
2
|
+
import { renderSuccess } from '@shopify/cli-kit/node/ui';
|
|
3
|
+
import { outputWarn } from '@shopify/cli-kit/node/output';
|
|
3
4
|
import { commonFlags } from '../../lib/flags.js';
|
|
4
5
|
import { getConfig, unsetStorefront } from '../../lib/shopify-config.js';
|
|
5
6
|
|
|
6
7
|
class Unlink extends Command {
|
|
7
8
|
static description = "Unlink a local project from a Hydrogen storefront.";
|
|
8
|
-
static hidden = true;
|
|
9
9
|
static flags = {
|
|
10
10
|
path: commonFlags.path
|
|
11
11
|
};
|
|
@@ -23,7 +23,9 @@ async function unlinkStorefront({ path }) {
|
|
|
23
23
|
}
|
|
24
24
|
const storefrontTitle = configStorefront.title;
|
|
25
25
|
await unsetStorefront(actualPath);
|
|
26
|
-
|
|
26
|
+
renderSuccess({
|
|
27
|
+
body: ["You are no longer linked to", { bold: storefrontTitle }]
|
|
28
|
+
});
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export { Unlink as default, unlinkStorefront };
|
package/dist/lib/codegen.d.ts
CHANGED
|
@@ -17,9 +17,10 @@ type ProjectDirs = {
|
|
|
17
17
|
appDirectory: string;
|
|
18
18
|
};
|
|
19
19
|
type CodegenOptions = ProjectDirs & {
|
|
20
|
-
configFilePath?: string;
|
|
21
20
|
watch?: boolean;
|
|
21
|
+
configFilePath?: string;
|
|
22
|
+
forceSfapiVersion?: string;
|
|
22
23
|
};
|
|
23
|
-
declare function generateTypes({ configFilePath,
|
|
24
|
+
declare function generateTypes({ watch, configFilePath, forceSfapiVersion, ...dirs }: CodegenOptions): Promise<string[]>;
|
|
24
25
|
|
|
25
26
|
export { generateTypes, normalizeCodegenError, spawnCodegenProcess };
|
package/dist/lib/codegen.js
CHANGED
|
@@ -67,14 +67,15 @@ function spawnCodegenProcess({
|
|
|
67
67
|
return child;
|
|
68
68
|
}
|
|
69
69
|
async function generateTypes({
|
|
70
|
-
configFilePath,
|
|
71
70
|
watch,
|
|
71
|
+
configFilePath,
|
|
72
|
+
forceSfapiVersion,
|
|
72
73
|
...dirs
|
|
73
74
|
}) {
|
|
74
75
|
const { config: codegenConfig } = await loadCodegenConfig({
|
|
75
76
|
configFilePath,
|
|
76
77
|
searchPlaces: [dirs.rootDirectory]
|
|
77
|
-
}) || generateDefaultConfig(dirs);
|
|
78
|
+
}) || generateDefaultConfig(dirs, forceSfapiVersion);
|
|
78
79
|
await addHooksToHydrogenOptions(codegenConfig, dirs);
|
|
79
80
|
await generate(
|
|
80
81
|
{
|
|
@@ -87,10 +88,7 @@ async function generateTypes({
|
|
|
87
88
|
);
|
|
88
89
|
return Object.keys(codegenConfig.generates);
|
|
89
90
|
}
|
|
90
|
-
function generateDefaultConfig({
|
|
91
|
-
rootDirectory,
|
|
92
|
-
appDirectory
|
|
93
|
-
}) {
|
|
91
|
+
function generateDefaultConfig({ rootDirectory, appDirectory }, forceSfapiVersion) {
|
|
94
92
|
const tsDefaultGlob = "*!(*.d).{ts,tsx}";
|
|
95
93
|
const appDirRelative = relativePath(rootDirectory, appDirectory);
|
|
96
94
|
return {
|
|
@@ -105,7 +103,22 @@ function generateDefaultConfig({
|
|
|
105
103
|
documents: [
|
|
106
104
|
tsDefaultGlob,
|
|
107
105
|
joinPath(appDirRelative, "**", tsDefaultGlob)
|
|
108
|
-
]
|
|
106
|
+
],
|
|
107
|
+
...!!forceSfapiVersion && {
|
|
108
|
+
presetConfig: { importTypes: false },
|
|
109
|
+
schema: {
|
|
110
|
+
[`https://hydrogen-preview.myshopify.com/api/${forceSfapiVersion.split(":")[0]}/graphql.json`]: {
|
|
111
|
+
headers: {
|
|
112
|
+
"content-type": "application/json",
|
|
113
|
+
"X-Shopify-Storefront-Access-Token": forceSfapiVersion.split(":")[1] ?? "3b580e70970c4528da70c98e097c2fa0"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
config: {
|
|
118
|
+
defaultScalarType: "string",
|
|
119
|
+
scalars: { JSON: "unknown" }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
109
122
|
}
|
|
110
123
|
}
|
|
111
124
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { fileExists } from '@shopify/cli-kit/node/fs';
|
|
2
2
|
import { resolvePath } from '@shopify/cli-kit/node/path';
|
|
3
|
-
import {
|
|
3
|
+
import { linesToColumns } from '@shopify/cli-kit/common/string';
|
|
4
|
+
import { outputInfo } from '@shopify/cli-kit/node/output';
|
|
4
5
|
import { readAndParseDotEnv } from '@shopify/cli-kit/node/dot-env';
|
|
5
|
-
import
|
|
6
|
+
import colors from '@shopify/cli-kit/node/colors';
|
|
6
7
|
import { pullRemoteEnvironmentVariables } from './pull-environment-variables.js';
|
|
7
|
-
import { getConfig } from './shopify-config.js';
|
|
8
8
|
|
|
9
9
|
async function combinedEnvironmentVariables({
|
|
10
10
|
envBranch,
|
|
@@ -28,47 +28,30 @@ async function combinedEnvironmentVariables({
|
|
|
28
28
|
);
|
|
29
29
|
const localKeys = new Set(Object.keys(localEnvironmentVariables));
|
|
30
30
|
if ([...remoteKeys, ...localKeys].length) {
|
|
31
|
-
outputInfo(
|
|
32
|
-
`${colors.bold("Injecting environment variables into MiniOxygen...")}`
|
|
33
|
-
);
|
|
31
|
+
outputInfo("\nEnvironment variables injected into MiniOxygen:\n");
|
|
34
32
|
}
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
storefrontTitle = storefront.title;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
remoteEnvironmentVariables.forEach(({ key, isSecret }) => {
|
|
43
|
-
if (localKeys.has(key)) {
|
|
44
|
-
outputIgnoringKey(key, `overwritten via ${colors.yellow(".env")}`);
|
|
45
|
-
} else if (isSecret) {
|
|
46
|
-
outputIgnoringKey(key, "value is marked as secret");
|
|
47
|
-
} else {
|
|
48
|
-
outputUsingKey(key, storefrontTitle);
|
|
33
|
+
let rows = [];
|
|
34
|
+
remoteEnvironmentVariables.filter(({ isSecret }) => !isSecret).forEach(({ key }) => {
|
|
35
|
+
if (!localKeys.has(key)) {
|
|
36
|
+
rows.push([key, "from Oxygen"]);
|
|
49
37
|
}
|
|
50
38
|
});
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
localKeys.forEach((key) => {
|
|
40
|
+
rows.push([key, "from local .env"]);
|
|
41
|
+
});
|
|
42
|
+
remoteEnvironmentVariables.filter(({ isSecret }) => isSecret).forEach(({ key }) => {
|
|
43
|
+
if (!localKeys.has(key)) {
|
|
44
|
+
rows.push([
|
|
45
|
+
colors.dim(key),
|
|
46
|
+
colors.dim(`from Oxygen (Marked as secret)`)
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
53
49
|
});
|
|
50
|
+
outputInfo(linesToColumns(rows));
|
|
54
51
|
return {
|
|
55
52
|
...formattedRemoteVariables,
|
|
56
53
|
...localEnvironmentVariables
|
|
57
54
|
};
|
|
58
55
|
}
|
|
59
|
-
function outputUsingKey(keyName, source) {
|
|
60
|
-
outputInfo(
|
|
61
|
-
outputContent` Using ${outputToken.green(
|
|
62
|
-
keyName
|
|
63
|
-
)} from ${outputToken.yellow(source)}`.value
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
function outputIgnoringKey(keyName, reason) {
|
|
67
|
-
outputInfo(
|
|
68
|
-
outputContent`${colors.dim(
|
|
69
|
-
` Ignoring ${colors.green(keyName)} (${reason})`
|
|
70
|
-
)}`.value
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
56
|
|
|
74
57
|
export { combinedEnvironmentVariables };
|