shopify-cli 2.3.0 → 2.4.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/.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
|