shopify-cli 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/workflows/shopify.yml +106 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +23 -0
- data/Dockerfile +19 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +50 -13
- data/Rakefile +66 -0
- data/dev.yml +11 -1
- data/ext/shopify-extensions/extconf.rb +21 -0
- data/ext/shopify-extensions/shopify_extensions.rb +152 -0
- data/ext/shopify-extensions/version +1 -0
- data/lib/project_types/extension/cli.rb +14 -0
- data/lib/project_types/extension/commands/build.rb +30 -2
- data/lib/project_types/extension/commands/create.rb +25 -0
- data/lib/project_types/extension/forms/create.rb +4 -1
- data/lib/project_types/extension/forms/questions/ask_template.rb +44 -0
- data/lib/project_types/extension/messages/messages.rb +3 -0
- data/lib/project_types/extension/models/development_server.rb +35 -0
- data/lib/project_types/extension/models/development_server_requirements.rb +17 -0
- data/lib/project_types/extension/models/server_config/base.rb +31 -0
- data/lib/project_types/extension/models/server_config/development.rb +23 -0
- data/lib/project_types/extension/models/server_config/development_entries.rb +38 -0
- data/lib/project_types/extension/models/server_config/development_renderer.rb +30 -0
- data/lib/project_types/extension/models/server_config/extension.rb +35 -0
- data/lib/project_types/extension/models/server_config/root.rb +18 -0
- data/lib/project_types/extension/models/server_config/user.rb +10 -0
- data/lib/project_types/extension/tasks/choose_next_available_port.rb +1 -1
- data/lib/project_types/extension/tasks/run_extension_command.rb +58 -0
- data/lib/project_types/node/commands/create.rb +1 -5
- data/lib/project_types/rails/commands/create.rb +1 -5
- data/lib/project_types/script/cli.rb +2 -0
- data/lib/project_types/script/layers/application/push_script.rb +10 -1
- data/lib/project_types/script/layers/domain/push_package.rb +0 -12
- data/lib/project_types/script/layers/infrastructure/api_clients.rb +89 -0
- data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/script_service.rb +26 -141
- data/lib/project_types/script/layers/infrastructure/script_uploader.rb +27 -0
- data/lib/project_types/script/tasks/ensure_env.rb +2 -2
- data/lib/project_types/script/ui/error_handler.rb +1 -1
- data/lib/shopify-cli/constants.rb +26 -0
- data/lib/shopify-cli/environment.rb +60 -0
- data/lib/shopify-cli/git.rb +2 -2
- data/lib/shopify-cli/identity_auth.rb +16 -23
- data/lib/shopify-cli/partners_api.rb +3 -27
- data/lib/shopify-cli/theme/dev_server/hot_reload.rb +4 -5
- data/lib/shopify-cli/theme/development_theme.rb +16 -2
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +4 -2
- data/shopify-cli.gemspec +3 -3
- metadata +29 -9
- data/.github/workflows/build.yml +0 -28
@@ -9,18 +9,21 @@ module Script
|
|
9
9
|
class ScriptService
|
10
10
|
include SmartProperties
|
11
11
|
property! :ctx, accepts: ShopifyCli::Context
|
12
|
+
property! :api_key, accepts: String
|
12
13
|
|
13
|
-
def
|
14
|
+
def initialize(*args, ctx:, api_key:, **kwargs)
|
15
|
+
super(*args, ctx: ctx, api_key: api_key, **kwargs)
|
16
|
+
@client = ApiClients.default_client(ctx, api_key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_app_script(
|
14
20
|
uuid:,
|
15
21
|
extension_point_type:,
|
16
|
-
script_content:,
|
17
|
-
api_key: nil,
|
18
22
|
force: false,
|
19
23
|
metadata:,
|
20
|
-
script_json
|
24
|
+
script_json:,
|
25
|
+
module_upload_url:
|
21
26
|
)
|
22
|
-
url = UploadScript.new(ctx).call(api_key, script_content)
|
23
|
-
|
24
27
|
query_name = "app_script_set"
|
25
28
|
variables = {
|
26
29
|
uuid: uuid,
|
@@ -33,9 +36,9 @@ module Script
|
|
33
36
|
scriptJsonVersion: script_json.version,
|
34
37
|
configurationUi: script_json.configuration_ui,
|
35
38
|
configurationDefinition: script_json.configuration&.to_json,
|
36
|
-
moduleUploadUrl:
|
39
|
+
moduleUploadUrl: module_upload_url,
|
37
40
|
}
|
38
|
-
resp_hash =
|
41
|
+
resp_hash = make_request(query_name: query_name, variables: variables)
|
39
42
|
user_errors = resp_hash["data"]["appScriptSet"]["userErrors"]
|
40
43
|
|
41
44
|
return resp_hash["data"]["appScriptSet"]["appScript"]["uuid"] if user_errors.empty?
|
@@ -63,149 +66,31 @@ module Script
|
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
66
|
-
def get_app_scripts(
|
69
|
+
def get_app_scripts(extension_point_type:)
|
67
70
|
query_name = "get_app_scripts"
|
68
71
|
variables = { appKey: api_key, extensionPointName: extension_point_type.upcase }
|
69
|
-
response =
|
70
|
-
query_name: query_name,
|
71
|
-
api_key: api_key,
|
72
|
-
variables: variables
|
73
|
-
)
|
72
|
+
response = make_request(query_name: query_name, variables: variables)
|
74
73
|
response["data"]["appScripts"]
|
75
74
|
end
|
76
75
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
def self.query(ctx, query_name, api_key: nil, variables: {})
|
83
|
-
api_client(ctx, api_key).query(query_name, variables: variables)
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.api_client(ctx, api_key)
|
87
|
-
instance_url = spin_instance_url || LOCAL_INSTANCE_URL
|
88
|
-
new(
|
89
|
-
ctx: ctx,
|
90
|
-
url: "#{instance_url}/graphql",
|
91
|
-
token: "",
|
92
|
-
api_key: api_key
|
93
|
-
)
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.spin_instance_url
|
97
|
-
workspace = ENV["SPIN_WORKSPACE"]
|
98
|
-
namespace = ENV["SPIN_NAMESPACE"]
|
99
|
-
return if workspace.nil? || namespace.nil?
|
100
|
-
|
101
|
-
"https://script-service.#{workspace}.#{namespace}.us.spin.dev"
|
102
|
-
end
|
76
|
+
def generate_module_upload_url
|
77
|
+
query_name = "module_upload_url_generate"
|
78
|
+
variables = {}
|
79
|
+
response = make_request(query_name: query_name, variables: variables)
|
80
|
+
user_errors = response["data"]["moduleUploadUrlGenerate"]["userErrors"]
|
103
81
|
|
104
|
-
|
105
|
-
|
106
|
-
{ "X-Shopify-Authenticated-Tokens" => tokens }
|
107
|
-
end
|
82
|
+
raise Errors::GraphqlError, user_errors if user_errors.any?
|
83
|
+
response["data"]["moduleUploadUrlGenerate"]["url"]
|
108
84
|
end
|
109
|
-
private_constant(:ScriptServiceAPI)
|
110
|
-
|
111
|
-
class PartnersProxyAPI < ShopifyCli::PartnersAPI
|
112
|
-
def query(query_name, variables: {})
|
113
|
-
variables[:query] = load_query(query_name)
|
114
|
-
super("script_service_proxy", variables: variables)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
private_constant(:PartnersProxyAPI)
|
118
|
-
|
119
|
-
class MakeRequest
|
120
|
-
attr_reader :ctx
|
121
85
|
|
122
|
-
|
123
|
-
@ctx = ctx
|
124
|
-
end
|
86
|
+
private
|
125
87
|
|
126
|
-
|
127
|
-
|
128
|
-
|
88
|
+
def make_request(query_name:, variables: {})
|
89
|
+
response = @client.query(query_name, variables: variables)
|
90
|
+
raise Errors::EmptyResponseError if response.nil?
|
91
|
+
raise Errors::GraphqlError, response["errors"] if response.key?("errors")
|
129
92
|
|
130
|
-
|
131
|
-
resp = if MakeRequest.bypass_partners_proxy
|
132
|
-
ScriptServiceAPI.query(ctx, query_name, variables: variables, **options)
|
133
|
-
else
|
134
|
-
proxy_through_partners(query_name: query_name, variables: variables, **options)
|
135
|
-
end
|
136
|
-
raise_if_graphql_failed(resp)
|
137
|
-
resp
|
138
|
-
end
|
139
|
-
|
140
|
-
def proxy_through_partners(query_name:, variables: nil, **options)
|
141
|
-
options[:variables] = variables.to_json if variables
|
142
|
-
resp = PartnersProxyAPI.query(ctx, query_name, **options)
|
143
|
-
raise_if_graphql_failed(resp)
|
144
|
-
JSON.parse(resp["data"]["scriptServiceProxy"])
|
145
|
-
end
|
146
|
-
|
147
|
-
def raise_if_graphql_failed(response)
|
148
|
-
raise Errors::EmptyResponseError if response.nil?
|
149
|
-
|
150
|
-
return unless response.key?("errors")
|
151
|
-
case error_code(response["errors"])
|
152
|
-
when "forbidden"
|
153
|
-
raise Errors::ForbiddenError
|
154
|
-
when "forbidden_on_shop"
|
155
|
-
raise Errors::ShopAuthenticationError
|
156
|
-
when "app_not_installed_on_shop"
|
157
|
-
raise Errors::AppNotInstalledError
|
158
|
-
else
|
159
|
-
raise Errors::GraphqlError, response["errors"]
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
def error_code(errors)
|
164
|
-
errors.map do |e|
|
165
|
-
code = e.dig("extensions", "code")
|
166
|
-
return code if code
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
class UploadScript
|
172
|
-
attr_reader :ctx
|
173
|
-
|
174
|
-
def initialize(ctx)
|
175
|
-
@ctx = ctx
|
176
|
-
end
|
177
|
-
|
178
|
-
def call(api_key, script_content)
|
179
|
-
apply_module_upload_url(api_key).tap do |url|
|
180
|
-
upload(url, script_content)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
private
|
185
|
-
|
186
|
-
def apply_module_upload_url(api_key)
|
187
|
-
query_name = "module_upload_url_generate"
|
188
|
-
variables = {}
|
189
|
-
resp_hash = MakeRequest.new(ctx).call(query_name: query_name, api_key: api_key, variables: variables)
|
190
|
-
user_errors = resp_hash["data"]["moduleUploadUrlGenerate"]["userErrors"]
|
191
|
-
|
192
|
-
raise Errors::GraphqlError, user_errors if user_errors.any?
|
193
|
-
resp_hash["data"]["moduleUploadUrlGenerate"]["url"]
|
194
|
-
end
|
195
|
-
|
196
|
-
def upload(url, script_content)
|
197
|
-
url = URI(url)
|
198
|
-
|
199
|
-
https = Net::HTTP.new(url.host, url.port)
|
200
|
-
https.use_ssl = true
|
201
|
-
|
202
|
-
request = Net::HTTP::Put.new(url)
|
203
|
-
request["Content-Type"] = "application/wasm"
|
204
|
-
request.body = script_content
|
205
|
-
|
206
|
-
response = https.request(request)
|
207
|
-
raise Errors::ScriptUploadError unless response.code == "200"
|
208
|
-
end
|
93
|
+
response
|
209
94
|
end
|
210
95
|
end
|
211
96
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Script
|
2
|
+
module Layers
|
3
|
+
module Infrastructure
|
4
|
+
class ScriptUploader
|
5
|
+
def initialize(script_service)
|
6
|
+
@script_service = script_service
|
7
|
+
end
|
8
|
+
|
9
|
+
def upload(script_content)
|
10
|
+
@script_service.generate_module_upload_url.tap do |url|
|
11
|
+
url = URI(url)
|
12
|
+
|
13
|
+
https = Net::HTTP.new(url.host, url.port)
|
14
|
+
https.use_ssl = true
|
15
|
+
|
16
|
+
request = Net::HTTP::Put.new(url)
|
17
|
+
request["Content-Type"] = "application/wasm"
|
18
|
+
request.body = script_content
|
19
|
+
|
20
|
+
response = https.request(request)
|
21
|
+
raise Errors::ScriptUploadError unless response.code == "200"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -89,8 +89,8 @@ module Script
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def ask_script_uuid(app, extension_point_type)
|
92
|
-
script_service = Layers::Infrastructure::ScriptService.new(ctx: ctx)
|
93
|
-
scripts = script_service.get_app_scripts(
|
92
|
+
script_service = Layers::Infrastructure::ScriptService.new(ctx: ctx, api_key: app["apiKey"])
|
93
|
+
scripts = script_service.get_app_scripts(extension_point_type: extension_point_type)
|
94
94
|
|
95
95
|
return nil unless scripts.count > 0 &&
|
96
96
|
CLI::UI::Prompt.confirm(ctx.message("script.application.ensure_env.ask_connect_to_existing_script"))
|
@@ -99,7 +99,7 @@ module Script
|
|
99
99
|
cause_of_error: ShopifyCli::Context.message("script.error.invalid_extension_cause", e.type),
|
100
100
|
help_suggestion: ShopifyCli::Context.message(
|
101
101
|
"script.error.invalid_extension_help",
|
102
|
-
Script::Layers::Application::ExtensionPoints.
|
102
|
+
Script::Layers::Application::ExtensionPoints.available_types.join(", ")
|
103
103
|
),
|
104
104
|
}
|
105
105
|
when Layers::Domain::Errors::ScriptNotFoundError
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ShopifyCli
|
2
|
+
module Constants
|
3
|
+
module EnvironmentVariables
|
4
|
+
# When true the CLI points to a local instance of
|
5
|
+
# the partners dashboard and identity.
|
6
|
+
LOCAL_PARTNERS = "SHOPIFY_APP_CLI_LOCAL_PARTNERS"
|
7
|
+
|
8
|
+
# When true the CLI points to a spin instance of spin
|
9
|
+
SPIN_PARTNERS = "SHOPIFY_APP_CLI_SPIN_PARTNERS"
|
10
|
+
|
11
|
+
SPIN_WORKSPACE = "SPIN_WORKSPACE"
|
12
|
+
|
13
|
+
SPIN_NAMESPACE = "SPIN_NAMESPACE"
|
14
|
+
|
15
|
+
SPIN_HOST = "SPIN_HOST"
|
16
|
+
|
17
|
+
# Set to true when running tests.
|
18
|
+
RUNNING_TESTS = "RUNNING_SHOPIFY_CLI_TESTS"
|
19
|
+
end
|
20
|
+
|
21
|
+
module Identity
|
22
|
+
CLIENT_ID_DEV = "e5380e02-312a-7408-5718-e07017e9cf52"
|
23
|
+
CLIENT_ID = "fbdb2649-e327-4907-8f67-908d24cfd7e3"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module ShopifyCli
|
2
|
+
# The environment module provides an interface to get information from
|
3
|
+
# the environment in which the CLI runs
|
4
|
+
module Environment
|
5
|
+
TRUTHY_ENV_VARIABLE_VALUES = ["1", "true", "TRUE", "yes", "YES"]
|
6
|
+
def self.use_local_partners_instance?(env_variables: ENV)
|
7
|
+
env_variable_truthy?(
|
8
|
+
Constants::EnvironmentVariables::LOCAL_PARTNERS,
|
9
|
+
env_variables: env_variables
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.use_spin_partners_instance?(env_variables: ENV)
|
14
|
+
env_variable_truthy?(
|
15
|
+
Constants::EnvironmentVariables::SPIN_PARTNERS,
|
16
|
+
env_variables: env_variables
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.running_tests?(env_variables: ENV)
|
21
|
+
env_variable_truthy?(
|
22
|
+
Constants::EnvironmentVariables::RUNNING_TESTS,
|
23
|
+
env_variables: env_variables
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.partners_domain(env_variables: ENV)
|
28
|
+
if use_local_partners_instance?(env_variables: env_variables)
|
29
|
+
"partners.myshopify.io"
|
30
|
+
elsif use_spin_partners_instance?(env_variables: env_variables)
|
31
|
+
"partners.#{spin_url(env_variables: env_variables)}"
|
32
|
+
else
|
33
|
+
"partners.shopify.com"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.spin_url(env_variables: ENV)
|
38
|
+
spin_workspace = spin_workspace(env_variables: env_variables)
|
39
|
+
spin_namespace = spin_namespace(env_variables: env_variables)
|
40
|
+
spin_host = spin_host(env_variables: env_variables)
|
41
|
+
"#{spin_workspace}.#{spin_namespace}.#{spin_host}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.env_variable_truthy?(variable_name, env_variables: ENV)
|
45
|
+
TRUTHY_ENV_VARIABLE_VALUES.include?(env_variables[variable_name.to_s])
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.spin_workspace(env_variables: ENV)
|
49
|
+
env_variables[Constants::EnvironmentVariables::SPIN_WORKSPACE]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.spin_namespace(env_variables: ENV)
|
53
|
+
env_variables[Constants::EnvironmentVariables::SPIN_NAMESPACE]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.spin_host(env_variables: ENV)
|
57
|
+
env_variables[Constants::EnvironmentVariables::SPIN_HOST] || "us.spin.dev"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/shopify-cli/git.rb
CHANGED
@@ -108,8 +108,8 @@ module ShopifyCli
|
|
108
108
|
private
|
109
109
|
|
110
110
|
def exec(*args, dir: Dir.pwd, default: nil, ctx: Context.new)
|
111
|
-
args = %w(git) + args
|
112
|
-
out, _, stat = ctx.capture3(*args
|
111
|
+
args = %w(git) + ["--git-dir", File.join(dir, ".git")] + args
|
112
|
+
out, _, stat = ctx.capture3(*args)
|
113
113
|
return default unless stat.success?
|
114
114
|
out.chomp
|
115
115
|
end
|
@@ -17,7 +17,6 @@ module ShopifyCli
|
|
17
17
|
class Error < StandardError; end
|
18
18
|
class Timeout < StandardError; end
|
19
19
|
LocalRequest = Struct.new(:method, :path, :query, :protocol)
|
20
|
-
LOCAL_DEBUG = "SHOPIFY_APP_CLI_LOCAL_PARTNERS"
|
21
20
|
|
22
21
|
DEFAULT_PORT = 3456
|
23
22
|
REDIRECT_HOST = "http://127.0.0.1:#{DEFAULT_PORT}"
|
@@ -236,12 +235,17 @@ module ShopifyCli
|
|
236
235
|
end
|
237
236
|
|
238
237
|
def auth_url
|
239
|
-
|
240
|
-
|
238
|
+
if Environment.use_local_partners_instance?
|
239
|
+
"https://identity.myshopify.io/oauth"
|
240
|
+
elsif Environment.use_spin_partners_instance?
|
241
|
+
"https://identity.#{Environment.spin_url}/oauth"
|
242
|
+
else
|
243
|
+
"https://accounts.shopify.com/oauth"
|
244
|
+
end
|
241
245
|
end
|
242
246
|
|
243
247
|
def client_id_for_application(application_name)
|
244
|
-
client_ids = if
|
248
|
+
client_ids = if Environment.use_local_partners_instance? || Environment.use_spin_partners_instance?
|
245
249
|
DEV_APPLICATION_CLIENT_IDS
|
246
250
|
else
|
247
251
|
APPLICATION_CLIENT_IDS
|
@@ -257,26 +261,15 @@ module ShopifyCli
|
|
257
261
|
end
|
258
262
|
|
259
263
|
def client_id
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
})
|
269
|
-
|
270
|
-
response["client_id"]
|
271
|
-
end
|
272
|
-
|
273
|
-
def local_identity_running?
|
274
|
-
Net::HTTP.start("identity.myshopify.io", 443, use_ssl: true, open_timeout: 1, read_timeout: 10) do |http|
|
275
|
-
req = Net::HTTP::Get.new(URI.join("https://identity.myshopify.io", "/services/ping"))
|
276
|
-
http.request(req).is_a?(Net::HTTPSuccess)
|
264
|
+
if Environment.use_local_partners_instance? || Environment.use_spin_partners_instance?
|
265
|
+
Constants::Identity::CLIENT_ID_DEV
|
266
|
+
else
|
267
|
+
# In the future we might want to use Identity's dynamic
|
268
|
+
# registration. To migrate to a dynamic client ID we
|
269
|
+
# need to refactor some code that relies on a static
|
270
|
+
# value for the client
|
271
|
+
Constants::Identity::CLIENT_ID
|
277
272
|
end
|
278
|
-
rescue Timeout::Error, Errno::EHOSTUNREACH, Errno::EHOSTDOWN, Errno::EADDRNOTAVAIL, Errno::ECONNREFUSED
|
279
|
-
false
|
280
273
|
end
|
281
274
|
end
|
282
275
|
end
|
@@ -8,16 +8,6 @@ module ShopifyCli
|
|
8
8
|
class PartnersAPI < API
|
9
9
|
autoload :Organizations, "shopify-cli/partners_api/organizations"
|
10
10
|
|
11
|
-
# Defines the environment variable that this API looks for to operate on local
|
12
|
-
# services. If you set this environment variable in your shell then the partners
|
13
|
-
# API will operate on your local instance
|
14
|
-
#
|
15
|
-
# #### Example
|
16
|
-
#
|
17
|
-
# SHOPIFY_APP_CLI_LOCAL_PARTNERS=1 shopify create
|
18
|
-
#
|
19
|
-
LOCAL_DEBUG = "SHOPIFY_APP_CLI_LOCAL_PARTNERS"
|
20
|
-
|
21
11
|
class << self
|
22
12
|
##
|
23
13
|
# issues a graphql query or mutation to the Shopify Partners Dashboard CLI Schema.
|
@@ -59,11 +49,11 @@ module ShopifyCli
|
|
59
49
|
ctx.puts(ctx.message("core.partners_api.error.account_not_found", ShopifyCli::TOOL_NAME))
|
60
50
|
end
|
61
51
|
|
62
|
-
def partners_url_for(organization_id, api_client_id
|
52
|
+
def partners_url_for(organization_id, api_client_id)
|
63
53
|
if ShopifyCli::Shopifolk.acting_as_shopify_organization?
|
64
54
|
organization_id = "internal"
|
65
55
|
end
|
66
|
-
"
|
56
|
+
"https://#{Environment.partners_domain}/#{organization_id}/apps/#{api_client_id}"
|
67
57
|
end
|
68
58
|
|
69
59
|
private
|
@@ -72,7 +62,7 @@ module ShopifyCli
|
|
72
62
|
new(
|
73
63
|
ctx: ctx,
|
74
64
|
token: access_token(ctx),
|
75
|
-
url: "
|
65
|
+
url: "https://#{Environment.partners_domain}/api/cli/graphql",
|
76
66
|
)
|
77
67
|
end
|
78
68
|
|
@@ -83,20 +73,6 @@ module ShopifyCli
|
|
83
73
|
end
|
84
74
|
end
|
85
75
|
|
86
|
-
def endpoint
|
87
|
-
return "https://partners.shopify.com" if ENV[LOCAL_DEBUG].nil?
|
88
|
-
"https://partners.myshopify.io/"
|
89
|
-
end
|
90
|
-
|
91
|
-
def partners_endpoint(local_debug)
|
92
|
-
domain = if local_debug
|
93
|
-
"partners.myshopify.io"
|
94
|
-
else
|
95
|
-
"partners.shopify.com"
|
96
|
-
end
|
97
|
-
"https://#{domain}"
|
98
|
-
end
|
99
|
-
|
100
76
|
def auth_failure_info(ctx, error)
|
101
77
|
if error.response
|
102
78
|
headers = %w(www-authenticate x-request-id)
|
@@ -34,11 +34,10 @@ module ShopifyCli
|
|
34
34
|
files = (modified + added).reject { |file| @ignore_filter&.ignore?(file) }
|
35
35
|
.map { |file| @theme[file].relative_path }
|
36
36
|
|
37
|
-
|
38
|
-
modified: files
|
39
|
-
|
40
|
-
|
41
|
-
@ctx.debug("[HotReload] Modified #{files.join(", ")}")
|
37
|
+
unless files.empty?
|
38
|
+
@streams.broadcast(JSON.generate(modified: files))
|
39
|
+
@ctx.debug("[HotReload] Modified #{files.join(", ")}")
|
40
|
+
end
|
42
41
|
end
|
43
42
|
|
44
43
|
private
|
@@ -6,13 +6,24 @@ require "securerandom"
|
|
6
6
|
|
7
7
|
module ShopifyCli
|
8
8
|
module Theme
|
9
|
+
API_NAME_LIMIT = 50
|
10
|
+
|
9
11
|
class DevelopmentTheme < Theme
|
10
12
|
def id
|
11
13
|
ShopifyCli::DB.get(:development_theme_id)
|
12
14
|
end
|
13
15
|
|
14
16
|
def name
|
15
|
-
ShopifyCli::DB.get(:development_theme_name)
|
17
|
+
existing_name = ShopifyCli::DB.get(:development_theme_name)
|
18
|
+
# Up to version 2.3.0 (included) generated names stored locally
|
19
|
+
# could have more than 50 characters and the API rejected them.
|
20
|
+
# This code ensures we update the name for those users to ensure
|
21
|
+
# the name stays under the limit.
|
22
|
+
if existing_name.nil? || existing_name.length > API_NAME_LIMIT
|
23
|
+
generate_theme_name
|
24
|
+
else
|
25
|
+
existing_name
|
26
|
+
end
|
16
27
|
end
|
17
28
|
|
18
29
|
def role
|
@@ -58,7 +69,10 @@ module ShopifyCli
|
|
58
69
|
hostname = Socket.gethostname.split(".").shift
|
59
70
|
hash = SecureRandom.hex(3)
|
60
71
|
|
61
|
-
theme_name = "Development (
|
72
|
+
theme_name = "Development ()"
|
73
|
+
hostname_character_limit = API_NAME_LIMIT - theme_name.length - hash.length - 1
|
74
|
+
identifier = "#{hash}-#{hostname[0, hostname_character_limit]}"
|
75
|
+
theme_name = "Development (#{identifier})"
|
62
76
|
|
63
77
|
ShopifyCli::DB.set(development_theme_name: theme_name)
|
64
78
|
|
data/lib/shopify-cli/version.rb
CHANGED
data/lib/shopify_cli.rb
CHANGED
@@ -94,6 +94,8 @@ module ShopifyCli
|
|
94
94
|
)
|
95
95
|
end
|
96
96
|
|
97
|
+
autoload :Constants, "shopify-cli/constants"
|
98
|
+
autoload :Environment, "shopify-cli/environment"
|
97
99
|
autoload :AdminAPI, "shopify-cli/admin_api"
|
98
100
|
autoload :API, "shopify-cli/api"
|
99
101
|
autoload :Command, "shopify-cli/command"
|
@@ -132,7 +134,7 @@ module ShopifyCli
|
|
132
134
|
Context.load_messages(ShopifyCli::Messages::MESSAGES)
|
133
135
|
|
134
136
|
def self.cache_dir
|
135
|
-
cache_dir = if
|
137
|
+
cache_dir = if Environment.running_tests?
|
136
138
|
TEMP_DIR
|
137
139
|
elsif ENV["LOCALAPPDATA"].nil?
|
138
140
|
File.join(File.expand_path(ENV.fetch("XDG_CACHE_HOME", "~/.cache")), TOOL_NAME)
|
@@ -147,7 +149,7 @@ module ShopifyCli
|
|
147
149
|
end
|
148
150
|
|
149
151
|
def self.tool_config_path
|
150
|
-
if
|
152
|
+
if Environment.running_tests?
|
151
153
|
TEMP_DIR
|
152
154
|
elsif ENV["APPDATA"].nil?
|
153
155
|
File.join(File.expand_path(ENV.fetch("XDG_CONFIG_HOME", "~/.config")), TOOL_NAME)
|
data/shopify-cli.gemspec
CHANGED
@@ -39,10 +39,10 @@ Gem::Specification.new do |spec|
|
|
39
39
|
# `/usr/local/bin/shopify` to that script, in order to "lock" the Ruby used to
|
40
40
|
# a single Ruby (useful for debugging in multi-Ruby environments)
|
41
41
|
|
42
|
-
spec.add_development_dependency("bundler", "~> 2.
|
42
|
+
spec.add_development_dependency("bundler", "~> 2.2.2")
|
43
43
|
spec.add_development_dependency("rake", "~> 12.3", ">= 12.3.3")
|
44
44
|
spec.add_development_dependency("minitest", "~> 5.0")
|
45
45
|
|
46
|
-
spec.add_dependency("listen", "~> 3.
|
47
|
-
spec.add_dependency("theme-check", "~> 1.
|
46
|
+
spec.add_dependency("listen", "~> 3.7.0")
|
47
|
+
spec.add_dependency("theme-check", "~> 1.4.0")
|
48
48
|
end
|