shopify-cli 2.7.3 → 2.10.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +44 -0
- data/Gemfile.lock +1 -1
- data/RELEASING.md +4 -3
- data/dev.yml +2 -2
- data/ext/javy/javy.rb +8 -9
- data/lib/graphql/get_extension_registrations.graphql +27 -0
- data/lib/project_types/extension/cli.rb +27 -2
- data/lib/project_types/extension/commands/build.rb +10 -10
- data/lib/project_types/extension/commands/create.rb +2 -3
- data/lib/project_types/extension/commands/push.rb +36 -8
- data/lib/project_types/extension/extension_project.rb +1 -1
- data/lib/project_types/extension/features/argo_serve.rb +6 -5
- data/lib/project_types/extension/forms/questions/ask_registration.rb +6 -2
- data/lib/project_types/extension/loaders/project.rb +29 -0
- data/lib/project_types/extension/loaders/specification_handler.rb +22 -0
- data/lib/project_types/extension/messages/messages.rb +4 -0
- data/lib/project_types/extension/models/app.rb +1 -1
- data/lib/project_types/extension/models/development_server.rb +2 -4
- data/lib/project_types/extension/models/specification_handlers/default.rb +4 -0
- data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
- data/lib/project_types/extension/tasks/execute_commands/base.rb +13 -0
- data/lib/project_types/extension/tasks/execute_commands/build.rb +29 -0
- data/lib/project_types/extension/tasks/execute_commands/create.rb +33 -0
- data/lib/project_types/extension/tasks/execute_commands/serve.rb +35 -0
- data/lib/project_types/extension/tasks/merge_server_config.rb +33 -22
- data/lib/project_types/rails/gem.rb +1 -2
- data/lib/project_types/script/cli.rb +7 -0
- data/lib/project_types/script/commands/connect.rb +19 -0
- data/lib/project_types/script/commands/create.rb +8 -2
- data/lib/project_types/script/commands/push.rb +35 -12
- data/lib/project_types/script/layers/application/connect_app.rb +15 -3
- data/lib/project_types/script/layers/application/create_script.rb +16 -16
- data/lib/project_types/script/layers/application/extension_points.rb +50 -26
- data/lib/project_types/script/layers/application/push_script.rb +5 -2
- data/lib/project_types/script/layers/domain/errors.rb +3 -2
- data/lib/project_types/script/layers/domain/extension_point.rb +14 -0
- data/lib/project_types/script/layers/domain/script_config.rb +6 -4
- data/lib/project_types/script/layers/infrastructure/errors.rb +38 -23
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +49 -28
- data/lib/project_types/script/layers/infrastructure/script_service.rb +22 -5
- data/lib/project_types/script/loaders/project.rb +44 -0
- data/lib/project_types/script/loaders/specification_handler.rb +22 -0
- data/lib/project_types/script/messages/messages.rb +39 -16
- data/lib/project_types/script/ui/error_handler.rb +46 -29
- data/lib/project_types/theme/commands/pull.rb +45 -17
- data/lib/project_types/theme/commands/push.rb +65 -28
- data/lib/project_types/theme/commands/serve.rb +5 -0
- data/lib/project_types/theme/messages/messages.rb +34 -18
- data/lib/shopify_cli/command.rb +6 -0
- data/lib/shopify_cli/commands/login.rb +1 -1
- data/lib/shopify_cli/commands/switch.rb +1 -1
- data/lib/shopify_cli/constants.rb +11 -2
- data/lib/shopify_cli/context.rb +66 -12
- data/lib/shopify_cli/core/executor.rb +4 -4
- data/lib/shopify_cli/environment.rb +50 -20
- data/lib/shopify_cli/form.rb +2 -0
- data/lib/shopify_cli/identity_auth.rb +4 -3
- data/lib/shopify_cli/messages/messages.rb +9 -1
- data/lib/shopify_cli/method_object.rb +21 -9
- data/lib/shopify_cli/partners_api/app_extensions/job.rb +36 -0
- data/lib/shopify_cli/partners_api/app_extensions.rb +46 -0
- data/lib/shopify_cli/partners_api/organizations.rb +2 -5
- data/lib/shopify_cli/partners_api.rb +1 -0
- data/lib/shopify_cli/project.rb +8 -7
- data/lib/shopify_cli/resources/env_file.rb +18 -6
- data/lib/shopify_cli/result.rb +61 -59
- data/lib/shopify_cli/task.rb +5 -3
- data/lib/shopify_cli/theme/dev_server/cdn/cdn_helper.rb +49 -0
- data/lib/shopify_cli/theme/dev_server/cdn_assets.rb +69 -0
- data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +8 -28
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +34 -3
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +18 -2
- data/lib/shopify_cli/theme/dev_server/local_assets.rb +4 -0
- data/lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb +84 -0
- data/lib/shopify_cli/theme/dev_server/proxy.rb +10 -15
- data/lib/shopify_cli/theme/dev_server/reload_mode.rb +34 -0
- data/lib/shopify_cli/theme/dev_server.rb +8 -21
- data/lib/shopify_cli/theme/file.rb +2 -2
- data/lib/shopify_cli/theme/filter/path_matcher.rb +38 -0
- data/lib/shopify_cli/theme/ignore_filter.rb +14 -18
- data/lib/shopify_cli/theme/include_filter.rb +43 -0
- data/lib/shopify_cli/theme/syncer.rb +17 -2
- data/lib/shopify_cli/theme/theme.rb +26 -4
- data/lib/shopify_cli/thread_pool/job.rb +27 -0
- data/lib/shopify_cli/thread_pool.rb +37 -0
- data/lib/shopify_cli/version.rb +1 -1
- data/lib/shopify_cli.rb +6 -1
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +3 -1
- data/vendor/deps/ruby2_keywords/LICENSE +22 -0
- data/vendor/deps/ruby2_keywords/README.md +67 -0
- data/vendor/deps/ruby2_keywords/Rakefile +54 -0
- data/vendor/deps/ruby2_keywords/lib/ruby2_keywords.rb +57 -0
- data/vendor/deps/ruby2_keywords/ruby2_keywords.gemspec +18 -0
- data/vendor/deps/ruby2_keywords/test/test_keyword.rb +41 -0
- metadata +28 -4
- data/lib/graphql/all_orgs_with_extensions.graphql +0 -37
- data/lib/project_types/extension/tasks/run_extension_command.rb +0 -82
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require "shopify_cli/theme/theme"
|
|
3
3
|
require "shopify_cli/theme/development_theme"
|
|
4
4
|
require "shopify_cli/theme/ignore_filter"
|
|
5
|
+
require "shopify_cli/theme/include_filter"
|
|
5
6
|
require "shopify_cli/theme/syncer"
|
|
6
7
|
|
|
7
8
|
module Theme
|
|
@@ -10,12 +11,14 @@ module Theme
|
|
|
10
11
|
options do |parser, flags|
|
|
11
12
|
parser.on("-n", "--nodelete") { flags[:nodelete] = true }
|
|
12
13
|
parser.on("-i", "--themeid=ID") { |theme_id| flags[:theme_id] = theme_id }
|
|
14
|
+
parser.on("-t", "--theme=NAME_OR_ID") { |theme| flags[:theme] = theme }
|
|
13
15
|
parser.on("-l", "--live") { flags[:live] = true }
|
|
14
16
|
parser.on("-d", "--development") { flags[:development] = true }
|
|
15
17
|
parser.on("-u", "--unpublished") { flags[:unpublished] = true }
|
|
16
18
|
parser.on("-j", "--json") { flags[:json] = true }
|
|
17
19
|
parser.on("-a", "--allow-live") { flags[:allow_live] = true }
|
|
18
20
|
parser.on("-p", "--publish") { flags[:publish] = true }
|
|
21
|
+
parser.on("-o", "--only=PATTERN") { |pattern| flags[:includes] = pattern }
|
|
19
22
|
parser.on("-x", "--ignore=PATTERN") do |pattern|
|
|
20
23
|
flags[:ignores] ||= []
|
|
21
24
|
flags[:ignores] << pattern
|
|
@@ -25,39 +28,22 @@ module Theme
|
|
|
25
28
|
def call(args, _name)
|
|
26
29
|
root = args.first || "."
|
|
27
30
|
delete = !options.flags[:nodelete]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ShopifyCLI::Theme::Theme.new(@ctx, root: root, id: theme_id)
|
|
31
|
-
elsif options.flags[:live]
|
|
32
|
-
ShopifyCLI::Theme::Theme.live(@ctx, root: root)
|
|
33
|
-
elsif options.flags[:development]
|
|
34
|
-
theme = ShopifyCLI::Theme::DevelopmentTheme.new(@ctx, root: root)
|
|
35
|
-
theme.ensure_exists!
|
|
36
|
-
theme
|
|
37
|
-
elsif options.flags[:unpublished]
|
|
38
|
-
name = CLI::UI::Prompt.ask(@ctx.message("theme.push.name"), allow_empty: false)
|
|
39
|
-
theme = ShopifyCLI::Theme::Theme.new(@ctx, root: root, name: name, role: "unpublished")
|
|
40
|
-
theme.create
|
|
41
|
-
theme
|
|
42
|
-
else
|
|
43
|
-
form = Forms::Select.ask(
|
|
44
|
-
@ctx,
|
|
45
|
-
[],
|
|
46
|
-
title: @ctx.message("theme.push.select"),
|
|
47
|
-
root: root,
|
|
48
|
-
)
|
|
49
|
-
return unless form
|
|
50
|
-
form.theme
|
|
51
|
-
end
|
|
31
|
+
theme = find_theme(root, **options.flags)
|
|
32
|
+
return if theme.nil?
|
|
52
33
|
|
|
53
34
|
if theme.live? && !options.flags[:allow_live]
|
|
54
|
-
|
|
35
|
+
question = @ctx.message("theme.push.live")
|
|
36
|
+
question += @ctx.message("theme.push.theme", theme.name, theme.id) if options.flags[:live]
|
|
37
|
+
return unless CLI::UI::Prompt.confirm(question)
|
|
55
38
|
end
|
|
56
39
|
|
|
40
|
+
include_filter = ShopifyCLI::Theme::IncludeFilter.new(options.flags[:includes])
|
|
57
41
|
ignore_filter = ShopifyCLI::Theme::IgnoreFilter.from_path(root)
|
|
58
42
|
ignore_filter.add_patterns(options.flags[:ignores]) if options.flags[:ignores]
|
|
59
43
|
|
|
60
|
-
syncer = ShopifyCLI::Theme::Syncer.new(@ctx, theme: theme,
|
|
44
|
+
syncer = ShopifyCLI::Theme::Syncer.new(@ctx, theme: theme,
|
|
45
|
+
include_filter: include_filter,
|
|
46
|
+
ignore_filter: ignore_filter)
|
|
61
47
|
begin
|
|
62
48
|
syncer.start_threads
|
|
63
49
|
if options.flags[:json]
|
|
@@ -76,16 +62,67 @@ module Theme
|
|
|
76
62
|
end
|
|
77
63
|
end
|
|
78
64
|
raise ShopifyCLI::AbortSilent if syncer.has_any_error?
|
|
79
|
-
rescue ShopifyCLI::API::APIRequestNotFoundError
|
|
80
|
-
@ctx.abort(@ctx.message("theme.push.theme_not_found", theme.id))
|
|
81
65
|
ensure
|
|
82
66
|
syncer.shutdown
|
|
83
67
|
end
|
|
68
|
+
rescue ShopifyCLI::API::APIRequestNotFoundError
|
|
69
|
+
@ctx.abort(@ctx.message("theme.push.theme_not_found", "##{theme.id}"))
|
|
84
70
|
end
|
|
85
71
|
|
|
86
72
|
def self.help
|
|
87
73
|
ShopifyCLI::Context.message("theme.push.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
|
|
88
74
|
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def find_theme(root, theme_id: nil, theme: nil, live: nil, development: nil, unpublished: nil, **_args)
|
|
79
|
+
if theme_id
|
|
80
|
+
@ctx.warn(@ctx.message("theme.push.deprecated_themeid"))
|
|
81
|
+
return ShopifyCLI::Theme::Theme.new(@ctx, root: root, id: theme_id)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if live
|
|
85
|
+
return ShopifyCLI::Theme::Theme.live(@ctx, root: root)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if development
|
|
89
|
+
new_theme = ShopifyCLI::Theme::DevelopmentTheme.new(@ctx, root: root)
|
|
90
|
+
new_theme.ensure_exists!
|
|
91
|
+
return new_theme
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if unpublished
|
|
95
|
+
name = theme || ask_theme_name
|
|
96
|
+
new_theme = ShopifyCLI::Theme::Theme.new(@ctx, root: root, name: name, role: "unpublished")
|
|
97
|
+
new_theme.create
|
|
98
|
+
return new_theme
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if theme
|
|
102
|
+
selected_theme = ShopifyCLI::Theme::Theme.find_by_identifier(@ctx, root: root, identifier: theme)
|
|
103
|
+
return selected_theme || @ctx.abort(@ctx.message("theme.push.theme_not_found", theme))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
select_theme(root)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def ask_theme_name
|
|
110
|
+
CLI::UI::Prompt.ask(@ctx.message("theme.push.name"), allow_empty: false)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def select_theme(root)
|
|
114
|
+
form = Forms::Select.ask(
|
|
115
|
+
@ctx,
|
|
116
|
+
[],
|
|
117
|
+
title: @ctx.message("theme.push.select"),
|
|
118
|
+
root: root,
|
|
119
|
+
)
|
|
120
|
+
form&.theme
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def themes(root)
|
|
124
|
+
ShopifyCLI::Theme::Theme.all(@ctx, root: root)
|
|
125
|
+
end
|
|
89
126
|
end
|
|
90
127
|
end
|
|
91
128
|
end
|
|
@@ -10,6 +10,7 @@ module Theme
|
|
|
10
10
|
parser.on("--host=HOST") { |host| flags[:host] = host.to_s }
|
|
11
11
|
parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
|
|
12
12
|
parser.on("--poll") { flags[:poll] = true }
|
|
13
|
+
parser.on("--live-reload=MODE") { |mode| flags[:mode] = as_reload_mode(mode) }
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def call(*)
|
|
@@ -23,6 +24,10 @@ module Theme
|
|
|
23
24
|
ShopifyCLI::Context.message("theme.serve.error.address_binding_error", ShopifyCLI::TOOL_NAME)
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
def self.as_reload_mode(mode)
|
|
28
|
+
ShopifyCLI::Theme::DevServer::ReloadMode.get!(mode)
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def self.help
|
|
27
32
|
ShopifyCLI::Context.message("theme.serve.help", ShopifyCLI::TOOL_NAME)
|
|
28
33
|
end
|
|
@@ -57,14 +57,16 @@ module Theme
|
|
|
57
57
|
Usage: {{command:%s theme push [ ROOT ]}}
|
|
58
58
|
|
|
59
59
|
Options:
|
|
60
|
-
{{command:-
|
|
61
|
-
{{command:-l, --live}}
|
|
62
|
-
{{command:-d, --development}}
|
|
63
|
-
{{command:-u, --unpublished}}
|
|
64
|
-
{{command:-n, --nodelete}}
|
|
65
|
-
{{command:-j, --json}}
|
|
66
|
-
{{command:-a, --allow-live}}
|
|
67
|
-
{{command:-p, --publish}}
|
|
60
|
+
{{command:-t, --theme=NAME_OR_ID}} Theme ID or name of the remote theme.
|
|
61
|
+
{{command:-l, --live}} Push to your remote live theme, and update your live store.
|
|
62
|
+
{{command:-d, --development}} Push to your remote development theme, and create it if needed.
|
|
63
|
+
{{command:-u, --unpublished}} Create a new unpublished theme and push to it.
|
|
64
|
+
{{command:-n, --nodelete}} Runs the push command without deleting remote files from Shopify.
|
|
65
|
+
{{command:-j, --json}} Output JSON instead of a UI.
|
|
66
|
+
{{command:-a, --allow-live}} Allow push to a live theme.
|
|
67
|
+
{{command:-p, --publish}} Publish as the live theme after uploading.
|
|
68
|
+
{{command:-o, --only}} Upload only the specified files.
|
|
69
|
+
{{command:-x, --ignore}} Skip uploading the specified files.
|
|
68
70
|
|
|
69
71
|
Run without options to select theme from a list.
|
|
70
72
|
HELP
|
|
@@ -74,7 +76,11 @@ module Theme
|
|
|
74
76
|
push: "Pushing theme files to Shopify",
|
|
75
77
|
select: "Select theme to push to",
|
|
76
78
|
live: "Are you sure you want to push to your live theme?",
|
|
77
|
-
|
|
79
|
+
theme: "\n Theme: {{blue:%s #%s}} {{green:[live]}}",
|
|
80
|
+
deprecated_themeid: <<~WARN,
|
|
81
|
+
{{warning:The {{command:-i, --themeid}} flag is deprecated. Use {{command:-t, --theme}} instead.}}
|
|
82
|
+
WARN
|
|
83
|
+
theme_not_found: "Theme \"%s\" doesn't exist",
|
|
78
84
|
done: <<~DONE,
|
|
79
85
|
{{green:Your theme was pushed successfully}}
|
|
80
86
|
|
|
@@ -93,10 +99,16 @@ module Theme
|
|
|
93
99
|
Usage: {{command:%s theme serve}}
|
|
94
100
|
|
|
95
101
|
Options:
|
|
96
|
-
{{command:--port=PORT}}
|
|
97
|
-
{{command:--poll}}
|
|
98
|
-
{{command:--host=HOST}}
|
|
102
|
+
{{command:--port=PORT}} Local port to serve theme preview from.
|
|
103
|
+
{{command:--poll}} Force polling to detect file changes.
|
|
104
|
+
{{command:--host=HOST}} Set which network interface the web server listens on. The default value is 127.0.0.1.
|
|
105
|
+
{{command:--live-reload=MODE}} The live reload mode switches the server behavior when a file is modified:
|
|
106
|
+
- {{command:hot-reload}} Hot reloads local changes to CSS and sections (default)
|
|
107
|
+
- {{command:full-page}} Always refreshes the entire page
|
|
108
|
+
- {{command:off}} Deactivate live reload
|
|
99
109
|
HELP
|
|
110
|
+
reload_mode_is_not_valid: "The live reload mode `%s` is not valid.",
|
|
111
|
+
try_a_valid_reload_mode: "Try a valid live reload mode: %s.",
|
|
100
112
|
viewing_theme: "Viewing theme…",
|
|
101
113
|
syncing_theme: "Syncing theme #%s on %s",
|
|
102
114
|
open_fail: "Couldn't open the theme",
|
|
@@ -130,9 +142,7 @@ module Theme
|
|
|
130
142
|
You are not authorized to edit themes on %s.
|
|
131
143
|
Make sure you are a user of that store, and allowed to edit themes.
|
|
132
144
|
ENSURE_USER
|
|
133
|
-
already_in_use_error: "Error",
|
|
134
145
|
address_already_in_use: "The address \"%s\" is already in use.",
|
|
135
|
-
try_this: "Try this",
|
|
136
146
|
try_port_option: "Use the --port=PORT option to serve the theme in a different port.",
|
|
137
147
|
},
|
|
138
148
|
check: {
|
|
@@ -188,16 +198,22 @@ module Theme
|
|
|
188
198
|
Usage: {{command:%s theme pull [ ROOT ]}}
|
|
189
199
|
|
|
190
200
|
Options:
|
|
191
|
-
{{command:-
|
|
192
|
-
{{command:-l, --live}}
|
|
193
|
-
{{command:-
|
|
201
|
+
{{command:-t, --theme=NAME_OR_ID}} Theme ID or name of the remote theme.
|
|
202
|
+
{{command:-l, --live}} Pull theme files from your remote live theme.
|
|
203
|
+
{{command:-d, --development}} Pull theme files from your remote development theme.
|
|
204
|
+
{{command:-n, --nodelete}} Runs the pull command without deleting local files.
|
|
205
|
+
{{command:-o, --only}} Download only the specified files.
|
|
206
|
+
{{command:-x, --ignore}} Skip downloading the specified files.
|
|
194
207
|
|
|
195
208
|
Run without options to select theme from a list.
|
|
196
209
|
HELP
|
|
197
210
|
select: "Select a theme to pull from",
|
|
198
211
|
pulling: "Pulling theme files from %s (#%s) on %s",
|
|
199
212
|
done: "Theme pulled successfully",
|
|
200
|
-
|
|
213
|
+
deprecated_themeid: <<~WARN,
|
|
214
|
+
{{warning:The {{command:-i, --themeid}} flag is deprecated. Use {{command:-t, --theme}} instead.}}
|
|
215
|
+
WARN
|
|
216
|
+
theme_not_found: "Theme \"%s\" doesn't exist",
|
|
201
217
|
},
|
|
202
218
|
},
|
|
203
219
|
}.freeze
|
data/lib/shopify_cli/command.rb
CHANGED
|
@@ -29,6 +29,12 @@ module ShopifyCLI
|
|
|
29
29
|
run_prerequisites
|
|
30
30
|
cmd.call(args, command_name)
|
|
31
31
|
end
|
|
32
|
+
rescue OptionParser::InvalidOption => error
|
|
33
|
+
arg = error.args.first
|
|
34
|
+
raise ShopifyCLI::Abort, @ctx.message("core.errors.option_parser.invalid_option", arg)
|
|
35
|
+
rescue OptionParser::MissingArgument => error
|
|
36
|
+
arg = error.args.first
|
|
37
|
+
raise ShopifyCLI::Abort, @ctx.message("core.errors.option_parser.missing_argument", arg)
|
|
32
38
|
end
|
|
33
39
|
|
|
34
40
|
def options(&block)
|
|
@@ -7,7 +7,7 @@ module ShopifyCLI
|
|
|
7
7
|
PERMANENT_DOMAIN_SUFFIX = /\.myshopify\.(com|io)$/
|
|
8
8
|
|
|
9
9
|
options do |parser, flags|
|
|
10
|
-
parser.on("--store=STORE") { |url| flags[:shop] = url }
|
|
10
|
+
parser.on("-s", "--store=STORE") { |url| flags[:shop] = url }
|
|
11
11
|
# backwards compatibility allow 'shop' for now
|
|
12
12
|
parser.on("--shop=SHOP") { |url| flags[:shop] = url }
|
|
13
13
|
parser.on("--password=PASSWORD") { |password| flags[:password] = password }
|
|
@@ -4,7 +4,7 @@ module ShopifyCLI
|
|
|
4
4
|
module Commands
|
|
5
5
|
class Switch < ShopifyCLI::Command
|
|
6
6
|
options do |parser, flags|
|
|
7
|
-
parser.on("--store=STORE") { |url| flags[:shop] = url }
|
|
7
|
+
parser.on("-s", "--store=STORE") { |url| flags[:shop] = url }
|
|
8
8
|
# backwards compatibility allow 'shop' for now
|
|
9
9
|
parser.on("--shop=SHOP") { |url| flags[:shop] = url }
|
|
10
10
|
end
|
|
@@ -30,17 +30,22 @@ module ShopifyCLI
|
|
|
30
30
|
|
|
31
31
|
module EnvironmentVariables
|
|
32
32
|
STACKTRACE = "SHOPIFY_CLI_STACKTRACE"
|
|
33
|
+
TTY = "SHOPIFY_CLI_TTY"
|
|
33
34
|
|
|
34
35
|
# When true the CLI points to a local instance of
|
|
35
36
|
# the partners dashboard and identity.
|
|
36
37
|
LOCAL_PARTNERS = "SHOPIFY_APP_CLI_LOCAL_PARTNERS"
|
|
37
38
|
|
|
38
|
-
# When true the CLI points to
|
|
39
|
-
|
|
39
|
+
# When true the CLI points to spin instances of services
|
|
40
|
+
SPIN = "SPIN"
|
|
41
|
+
INFER_SPIN = "INFER_SPIN"
|
|
40
42
|
SPIN_WORKSPACE = "SPIN_WORKSPACE"
|
|
41
43
|
SPIN_NAMESPACE = "SPIN_NAMESPACE"
|
|
42
44
|
SPIN_HOST = "SPIN_HOST"
|
|
43
45
|
|
|
46
|
+
# Deprecated, equivalent to using SPIN=1
|
|
47
|
+
SPIN_PARTNERS = "SHOPIFY_APP_CLI_SPIN_PARTNERS"
|
|
48
|
+
|
|
44
49
|
# Environments
|
|
45
50
|
TEST = "SHOPIFY_CLI_TEST"
|
|
46
51
|
ACCEPTANCE_TEST = "SHOPIFY_CLI_ACCEPTANCE_TEST"
|
|
@@ -61,5 +66,9 @@ module ShopifyCLI
|
|
|
61
66
|
module Links
|
|
62
67
|
NEW_ISSUE = "https://github.com/Shopify/shopify-cli/issues/new"
|
|
63
68
|
end
|
|
69
|
+
|
|
70
|
+
module Extension
|
|
71
|
+
DEFAULT_PORT = 39351
|
|
72
|
+
end
|
|
64
73
|
end
|
|
65
74
|
end
|
data/lib/shopify_cli/context.rb
CHANGED
|
@@ -44,6 +44,56 @@ module ShopifyCLI
|
|
|
44
44
|
str = Context.messages.dig(*key_parts)
|
|
45
45
|
str ? str % params : key
|
|
46
46
|
end
|
|
47
|
+
|
|
48
|
+
# a wrapper around Kernel.puts to allow for easy formatting
|
|
49
|
+
#
|
|
50
|
+
# #### Parameters
|
|
51
|
+
# * `text` - a string message to output
|
|
52
|
+
def puts(*args)
|
|
53
|
+
Kernel.puts(CLI::UI.fmt(*args))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# aborts the current running command and outputs an error message:
|
|
57
|
+
# - when the `help_message` is not provided, the error message appears in
|
|
58
|
+
# a red frame, prefixed by an ✗ icon
|
|
59
|
+
# - when the `help_message` is provided, the error message appears in a
|
|
60
|
+
# red frame, and the help message appears in a green frame
|
|
61
|
+
#
|
|
62
|
+
# #### Parameters
|
|
63
|
+
# * `error_message` - an error message to output
|
|
64
|
+
# * `help_message` - an optional help message
|
|
65
|
+
#
|
|
66
|
+
# #### Example
|
|
67
|
+
#
|
|
68
|
+
# ShopifyCLI::Context.abort("Execution error")
|
|
69
|
+
# # Output:
|
|
70
|
+
# # ┏━━ Error ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
71
|
+
# # ┃ ✗ Execution error
|
|
72
|
+
# # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
73
|
+
#
|
|
74
|
+
# ShopifyCLI::Context.abort("Execution error", "export EXECUTION=1")
|
|
75
|
+
# # Output:
|
|
76
|
+
# # ┏━━ Error ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
77
|
+
# # ┃ Execution error
|
|
78
|
+
# # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
79
|
+
# # ┏━━ Try this ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
80
|
+
# # ┃ export EXECUTION=1
|
|
81
|
+
# # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
82
|
+
#
|
|
83
|
+
def abort(error_message, help_message = nil)
|
|
84
|
+
raise ShopifyCLI::Abort, "{{x}} #{error_message}" if help_message.nil?
|
|
85
|
+
|
|
86
|
+
frame(message("core.error"), color: :red) { self.puts(error_message) }
|
|
87
|
+
frame(message("core.try_this"), color: :green) { self.puts(help_message) }
|
|
88
|
+
|
|
89
|
+
raise ShopifyCLI::AbortSilent
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def frame(title, color:, &block)
|
|
95
|
+
CLI::UI::Frame.open(title, color: CLI::UI.resolve_color(color), timing: false, &block)
|
|
96
|
+
end
|
|
47
97
|
end
|
|
48
98
|
|
|
49
99
|
# is the directory root that the current command is running in. If you want to
|
|
@@ -61,14 +111,19 @@ module ShopifyCLI
|
|
|
61
111
|
# will return which operating system that the cli is running on [:mac, :linux]
|
|
62
112
|
def os
|
|
63
113
|
host = uname
|
|
64
|
-
return :mac_m1 if /arm64
|
|
114
|
+
return :mac_m1 if /arm64.*darwin/i.match(host)
|
|
65
115
|
return :mac if /darwin/i.match(host)
|
|
66
116
|
return :windows if /mswin|mingw|cygwin/i.match(host)
|
|
67
117
|
return :linux if /linux|bsd/i.match(host)
|
|
68
118
|
:unknown
|
|
69
119
|
end
|
|
70
120
|
|
|
71
|
-
# will return true if the cli is running on an
|
|
121
|
+
# will return true if the cli is running on an ARM Apple computer.
|
|
122
|
+
def mac_m1?
|
|
123
|
+
os == :mac_m1
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# will return true if the cli is running on a Intel x86 Apple computer.
|
|
72
127
|
def mac?
|
|
73
128
|
os == :mac
|
|
74
129
|
end
|
|
@@ -90,7 +145,7 @@ module ShopifyCLI
|
|
|
90
145
|
|
|
91
146
|
# will return true if being launched from a tty
|
|
92
147
|
def tty?
|
|
93
|
-
$stdin.tty?
|
|
148
|
+
$stdin.tty?
|
|
94
149
|
end
|
|
95
150
|
|
|
96
151
|
# will return true if the cli is being run from an installation, and not a
|
|
@@ -329,7 +384,7 @@ module ShopifyCLI
|
|
|
329
384
|
system("xdg-open", uri.to_s)
|
|
330
385
|
elsif windows?
|
|
331
386
|
system("start \"\" \"#{uri}\"")
|
|
332
|
-
elsif mac?
|
|
387
|
+
elsif mac? || mac_m1?
|
|
333
388
|
system("open", uri.to_s)
|
|
334
389
|
else
|
|
335
390
|
open_url!(uri)
|
|
@@ -349,13 +404,13 @@ module ShopifyCLI
|
|
|
349
404
|
puts "{{yellow:*}} #{text}"
|
|
350
405
|
end
|
|
351
406
|
|
|
352
|
-
#
|
|
407
|
+
# proxy call to Context.puts.
|
|
353
408
|
#
|
|
354
409
|
# #### Parameters
|
|
355
410
|
# * `text` - a string message to output
|
|
356
411
|
#
|
|
357
412
|
def puts(*args)
|
|
358
|
-
|
|
413
|
+
Context.puts(*args)
|
|
359
414
|
end
|
|
360
415
|
|
|
361
416
|
# a wrapper around $stderr.puts to allow for easy formatting
|
|
@@ -385,14 +440,13 @@ module ShopifyCLI
|
|
|
385
440
|
puts("{{v}} #{text}")
|
|
386
441
|
end
|
|
387
442
|
|
|
388
|
-
#
|
|
389
|
-
# by a red x
|
|
443
|
+
# proxy call to Context.abort.
|
|
390
444
|
#
|
|
391
445
|
# #### Parameters
|
|
392
|
-
# * `
|
|
393
|
-
#
|
|
394
|
-
def abort(
|
|
395
|
-
|
|
446
|
+
# * `error_message` - an error message to output
|
|
447
|
+
# * `help_message` - an optional help message
|
|
448
|
+
def abort(error_message, help_message = nil)
|
|
449
|
+
Context.abort(error_message, help_message)
|
|
396
450
|
end
|
|
397
451
|
|
|
398
452
|
# outputs a message, prefixed by a red `DEBUG` tag. This will only output to
|
|
@@ -3,10 +3,10 @@ require "shopify_cli"
|
|
|
3
3
|
module ShopifyCLI
|
|
4
4
|
module Core
|
|
5
5
|
class Executor < CLI::Kit::Executor
|
|
6
|
-
def initialize(ctx, task_registry, *args
|
|
7
|
-
@ctx = ctx ||
|
|
8
|
-
@task_registry = task_registry ||
|
|
9
|
-
super(*args
|
|
6
|
+
ruby2_keywords def initialize(ctx, task_registry, *args)
|
|
7
|
+
@ctx = ctx || ShopifyCli::Context.new
|
|
8
|
+
@task_registry = task_registry || ShopifyCli::Tasks::TaskRegistry.new
|
|
9
|
+
super(*args)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def call(command, command_name, args)
|
|
@@ -4,6 +4,21 @@ module ShopifyCLI
|
|
|
4
4
|
module Environment
|
|
5
5
|
TRUTHY_ENV_VARIABLE_VALUES = ["1", "true", "TRUE", "yes", "YES"]
|
|
6
6
|
|
|
7
|
+
def self.interactive=(interactive)
|
|
8
|
+
@interactive = interactive
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.interactive?(env_variables: ENV)
|
|
12
|
+
if env_variables.key?(Constants::EnvironmentVariables::TTY)
|
|
13
|
+
env_variable_truthy?(
|
|
14
|
+
Constants::EnvironmentVariables::TTY,
|
|
15
|
+
env_variables: env_variables
|
|
16
|
+
)
|
|
17
|
+
else
|
|
18
|
+
@interactive ||= STDIN.tty?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
7
22
|
def self.development?(env_variables: ENV)
|
|
8
23
|
env_variable_truthy?(
|
|
9
24
|
Constants::EnvironmentVariables::DEVELOPMENT,
|
|
@@ -11,10 +26,6 @@ module ShopifyCLI
|
|
|
11
26
|
)
|
|
12
27
|
end
|
|
13
28
|
|
|
14
|
-
def self.interactive?
|
|
15
|
-
ShopifyCLI::Context.new.tty?
|
|
16
|
-
end
|
|
17
|
-
|
|
18
29
|
def self.use_local_partners_instance?(env_variables: ENV)
|
|
19
30
|
env_variable_truthy?(
|
|
20
31
|
Constants::EnvironmentVariables::LOCAL_PARTNERS,
|
|
@@ -50,17 +61,10 @@ module ShopifyCLI
|
|
|
50
61
|
)
|
|
51
62
|
end
|
|
52
63
|
|
|
53
|
-
def self.use_spin_partners_instance?(env_variables: ENV)
|
|
54
|
-
env_variable_truthy?(
|
|
55
|
-
Constants::EnvironmentVariables::SPIN_PARTNERS,
|
|
56
|
-
env_variables: env_variables
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
64
|
def self.partners_domain(env_variables: ENV)
|
|
61
65
|
if use_local_partners_instance?(env_variables: env_variables)
|
|
62
66
|
"partners.myshopify.io"
|
|
63
|
-
elsif
|
|
67
|
+
elsif use_spin?(env_variables: env_variables)
|
|
64
68
|
"partners.#{spin_url(env_variables: env_variables)}"
|
|
65
69
|
else
|
|
66
70
|
"partners.shopify.com"
|
|
@@ -68,15 +72,31 @@ module ShopifyCLI
|
|
|
68
72
|
end
|
|
69
73
|
|
|
70
74
|
def self.use_spin?(env_variables: ENV)
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
env_variable_truthy?(
|
|
76
|
+
Constants::EnvironmentVariables::SPIN,
|
|
77
|
+
env_variables: env_variables
|
|
78
|
+
) || env_variable_truthy?(
|
|
79
|
+
Constants::EnvironmentVariables::SPIN_PARTNERS,
|
|
80
|
+
env_variables: env_variables
|
|
81
|
+
)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.infer_spin?(env_variables: ENV)
|
|
85
|
+
env_variable_truthy?(
|
|
86
|
+
Constants::EnvironmentVariables::INFER_SPIN,
|
|
87
|
+
env_variables: env_variables
|
|
88
|
+
)
|
|
73
89
|
end
|
|
74
90
|
|
|
75
91
|
def self.spin_url(env_variables: ENV)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
if infer_spin?(env_variables: env_variables)
|
|
93
|
+
%x(spin info fqdn 2> /dev/null).strip
|
|
94
|
+
else
|
|
95
|
+
spin_workspace = spin_workspace(env_variables: env_variables)
|
|
96
|
+
spin_namespace = spin_namespace(env_variables: env_variables)
|
|
97
|
+
spin_host = spin_host(env_variables: env_variables)
|
|
98
|
+
"#{spin_workspace}.#{spin_namespace}.#{spin_host}"
|
|
99
|
+
end
|
|
80
100
|
end
|
|
81
101
|
|
|
82
102
|
def self.send_monorail_events?(env_variables: ENV)
|
|
@@ -95,11 +115,21 @@ module ShopifyCLI
|
|
|
95
115
|
end
|
|
96
116
|
|
|
97
117
|
def self.spin_workspace(env_variables: ENV)
|
|
98
|
-
env_variables[Constants::EnvironmentVariables::SPIN_WORKSPACE]
|
|
118
|
+
env_value = env_variables[Constants::EnvironmentVariables::SPIN_WORKSPACE]
|
|
119
|
+
return env_value unless env_value.nil?
|
|
120
|
+
|
|
121
|
+
if env_value.nil?
|
|
122
|
+
raise "No value set for #{Constants::EnvironmentVariables::SPIN_WORKSPACE}"
|
|
123
|
+
end
|
|
99
124
|
end
|
|
100
125
|
|
|
101
126
|
def self.spin_namespace(env_variables: ENV)
|
|
102
|
-
env_variables[Constants::EnvironmentVariables::SPIN_NAMESPACE]
|
|
127
|
+
env_value = env_variables[Constants::EnvironmentVariables::SPIN_NAMESPACE]
|
|
128
|
+
return env_value unless env_value.nil?
|
|
129
|
+
|
|
130
|
+
if env_value.nil?
|
|
131
|
+
raise "No value set for #{Constants::EnvironmentVariables::SPIN_NAMESPACE}"
|
|
132
|
+
end
|
|
103
133
|
end
|
|
104
134
|
|
|
105
135
|
def self.spin_host(env_variables: ENV)
|
data/lib/shopify_cli/form.rb
CHANGED
|
@@ -229,6 +229,7 @@ module ShopifyCLI
|
|
|
229
229
|
uri = URI.parse("#{auth_url}#{endpoint}")
|
|
230
230
|
https = Net::HTTP.new(uri.host, uri.port)
|
|
231
231
|
https.use_ssl = true
|
|
232
|
+
https.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV["SSL_VERIFY_NONE"]
|
|
232
233
|
request = Net::HTTP::Post.new(uri.path)
|
|
233
234
|
request["User-Agent"] = "Shopify CLI #{::ShopifyCLI::VERSION}"
|
|
234
235
|
request.body = URI.encode_www_form(params)
|
|
@@ -255,7 +256,7 @@ module ShopifyCLI
|
|
|
255
256
|
def auth_url
|
|
256
257
|
if Environment.use_local_partners_instance?
|
|
257
258
|
"https://identity.myshopify.io/oauth"
|
|
258
|
-
elsif Environment.
|
|
259
|
+
elsif Environment.use_spin?
|
|
259
260
|
"https://identity.#{Environment.spin_url}/oauth"
|
|
260
261
|
else
|
|
261
262
|
"https://accounts.shopify.com/oauth"
|
|
@@ -263,7 +264,7 @@ module ShopifyCLI
|
|
|
263
264
|
end
|
|
264
265
|
|
|
265
266
|
def client_id_for_application(application_name)
|
|
266
|
-
client_ids = if Environment.use_local_partners_instance? || Environment.
|
|
267
|
+
client_ids = if Environment.use_local_partners_instance? || Environment.use_spin?
|
|
267
268
|
DEV_APPLICATION_CLIENT_IDS
|
|
268
269
|
else
|
|
269
270
|
APPLICATION_CLIENT_IDS
|
|
@@ -279,7 +280,7 @@ module ShopifyCLI
|
|
|
279
280
|
end
|
|
280
281
|
|
|
281
282
|
def client_id
|
|
282
|
-
if Environment.use_local_partners_instance? || Environment.
|
|
283
|
+
if Environment.use_local_partners_instance? || Environment.use_spin?
|
|
283
284
|
Constants::Identity::CLIENT_ID_DEV
|
|
284
285
|
else
|
|
285
286
|
# In the future we might want to use Identity's dynamic
|
|
@@ -14,6 +14,12 @@ module ShopifyCLI
|
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
16
|
core: {
|
|
17
|
+
errors: {
|
|
18
|
+
option_parser: {
|
|
19
|
+
invalid_option: "The option {{command:%s}} is not supported.",
|
|
20
|
+
missing_argument: "The required argument {{command:%s}} is missing.",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
17
23
|
app: {
|
|
18
24
|
help: <<~HELP,
|
|
19
25
|
Suite of commands for developing apps. See {{command:%1$s app <command> --help}} for usage of each command.
|
|
@@ -719,7 +725,7 @@ module ShopifyCLI
|
|
|
719
725
|
signup_suggestion: <<~MESSAGE,
|
|
720
726
|
{{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
|
|
721
727
|
account at {{underline:https://ngrok.com/signup}}. After you signup, install your
|
|
722
|
-
personalized authorization token using {{command:%s
|
|
728
|
+
personalized authorization token using {{command:%s app tunnel auth <token>}}.
|
|
723
729
|
MESSAGE
|
|
724
730
|
start: "{{v}} ngrok tunnel running at {{underline:%s}}",
|
|
725
731
|
start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
|
|
@@ -784,6 +790,8 @@ module ShopifyCLI
|
|
|
784
790
|
logged_in_partner_only: "Logged into partner organization {{green:%s}}",
|
|
785
791
|
logged_in_partner_and_shop: "Logged into store {{green:%s}} in partner organization {{green:%s}}",
|
|
786
792
|
},
|
|
793
|
+
error: "Error",
|
|
794
|
+
try_this: "Try this",
|
|
787
795
|
},
|
|
788
796
|
}.freeze
|
|
789
797
|
end
|