shopify-cli 2.2.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/ISSUE_TEMPLATE.md +0 -4
- data/.github/workflows/shopify.yml +106 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +23 -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/commands/push.rb +0 -1
- data/lib/project_types/extension/features/argo.rb +1 -11
- 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/models/specification_handlers/checkout_post_purchase.rb +10 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +1 -1
- 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/graphql/app_script_set.graphql +40 -0
- data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -44
- data/lib/project_types/script/graphql/module_upload_url_generate.graphql +9 -0
- data/lib/project_types/script/layers/application/push_script.rb +10 -1
- data/lib/project_types/script/layers/domain/push_package.rb +1 -14
- data/lib/project_types/script/layers/infrastructure/api_clients.rb +89 -0
- data/lib/project_types/script/layers/infrastructure/errors.rb +2 -0
- data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +0 -1
- data/lib/project_types/script/layers/infrastructure/script_service.rb +29 -94
- data/lib/project_types/script/layers/infrastructure/script_uploader.rb +27 -0
- data/lib/project_types/script/messages/messages.rb +3 -0
- data/lib/project_types/script/tasks/ensure_env.rb +2 -2
- data/lib/project_types/script/ui/error_handler.rb +6 -1
- data/lib/project_types/theme/commands/pull.rb +6 -0
- data/lib/project_types/theme/commands/push.rb +6 -0
- 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/process_supervision.rb +14 -14
- data/lib/shopify-cli/theme/dev_server/header_hash.rb +4 -0
- data/lib/shopify-cli/theme/dev_server/hot_reload.rb +4 -5
- data/lib/shopify-cli/theme/dev_server/proxy.rb +13 -1
- data/lib/shopify-cli/theme/development_theme.rb +16 -2
- data/lib/shopify-cli/theme/file.rb +11 -3
- data/lib/shopify-cli/theme/ignore_filter.rb +7 -0
- data/lib/shopify-cli/theme/syncer.rb +1 -1
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +4 -2
- data/shopify-cli.gemspec +3 -3
- metadata +31 -9
- data/.github/workflows/build.yml +0 -28
@@ -1,44 +0,0 @@
|
|
1
|
-
mutation AppScriptUpdateOrCreate(
|
2
|
-
$extensionPointName: ExtensionPointName!,
|
3
|
-
$title: String,
|
4
|
-
$description: String,
|
5
|
-
$sourceCode: String,
|
6
|
-
$language: String,
|
7
|
-
$force: Boolean,
|
8
|
-
$schemaMajorVersion: String,
|
9
|
-
$schemaMinorVersion: String,
|
10
|
-
$useMsgpack: Boolean,
|
11
|
-
$uuid: String,
|
12
|
-
$configurationUi: Boolean!,
|
13
|
-
$scriptJsonVersion: String!,
|
14
|
-
$configurationDefinition: String!,
|
15
|
-
) {
|
16
|
-
appScriptUpdateOrCreate(
|
17
|
-
extensionPointName: $extensionPointName
|
18
|
-
title: $title
|
19
|
-
description: $description
|
20
|
-
sourceCode: $sourceCode
|
21
|
-
language: $language
|
22
|
-
force: $force
|
23
|
-
schemaMajorVersion: $schemaMajorVersion
|
24
|
-
schemaMinorVersion: $schemaMinorVersion
|
25
|
-
useMsgpack: $useMsgpack,
|
26
|
-
uuid: $uuid
|
27
|
-
configurationUi: $configurationUi
|
28
|
-
scriptJsonVersion: $scriptJsonVersion
|
29
|
-
configurationDefinition: $configurationDefinition
|
30
|
-
) {
|
31
|
-
userErrors {
|
32
|
-
field
|
33
|
-
message
|
34
|
-
tag
|
35
|
-
}
|
36
|
-
appScript {
|
37
|
-
uuid
|
38
|
-
appKey
|
39
|
-
configSchema
|
40
|
-
extensionPointName
|
41
|
-
title
|
42
|
-
}
|
43
|
-
}
|
44
|
-
}
|
@@ -20,7 +20,16 @@ module Script
|
|
20
20
|
compiled_type: task_runner.compiled_type,
|
21
21
|
metadata: task_runner.metadata,
|
22
22
|
)
|
23
|
-
|
23
|
+
script_service = Infrastructure::ScriptService.new(ctx: p_ctx, api_key: script_project.api_key)
|
24
|
+
module_upload_url = Infrastructure::ScriptUploader.new(script_service).upload(package.script_content)
|
25
|
+
uuid = script_service.set_app_script(
|
26
|
+
uuid: package.uuid,
|
27
|
+
extension_point_type: package.extension_point_type,
|
28
|
+
force: force,
|
29
|
+
metadata: package.metadata,
|
30
|
+
script_json: package.script_json,
|
31
|
+
module_upload_url: module_upload_url,
|
32
|
+
)
|
24
33
|
script_project_repo.update_env(uuid: uuid)
|
25
34
|
spinner.update_title(p_ctx.message("script.application.pushed"))
|
26
35
|
end
|
@@ -17,7 +17,7 @@ module Script
|
|
17
17
|
uuid:,
|
18
18
|
extension_point_type:,
|
19
19
|
script_content:,
|
20
|
-
compiled_type
|
20
|
+
compiled_type: nil,
|
21
21
|
metadata:,
|
22
22
|
script_json:
|
23
23
|
)
|
@@ -29,19 +29,6 @@ module Script
|
|
29
29
|
@metadata = metadata
|
30
30
|
@script_json = script_json
|
31
31
|
end
|
32
|
-
|
33
|
-
def push(script_service, api_key, force)
|
34
|
-
script_service.push(
|
35
|
-
uuid: @uuid,
|
36
|
-
extension_point_type: @extension_point_type,
|
37
|
-
script_content: @script_content,
|
38
|
-
compiled_type: @compiled_type,
|
39
|
-
api_key: api_key,
|
40
|
-
force: force,
|
41
|
-
metadata: @metadata,
|
42
|
-
script_json: @script_json,
|
43
|
-
)
|
44
|
-
end
|
45
32
|
end
|
46
33
|
end
|
47
34
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Script
|
2
|
+
module Layers
|
3
|
+
module Infrastructure
|
4
|
+
class ApiClients
|
5
|
+
def self.default_client(ctx, api_key)
|
6
|
+
if ENV["BYPASS_PARTNERS_PROXY"]
|
7
|
+
ScriptServiceApiClient.new(ctx, api_key)
|
8
|
+
else
|
9
|
+
PartnersProxyApiClient.new(ctx, api_key)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ScriptServiceApiClient
|
14
|
+
LOCAL_INSTANCE_URL = "https://script-service.myshopify.io"
|
15
|
+
|
16
|
+
def initialize(ctx, api_key)
|
17
|
+
instance_url = script_service_url
|
18
|
+
@api = ShopifyCli::API.new(
|
19
|
+
ctx: ctx,
|
20
|
+
url: "#{instance_url}/graphql",
|
21
|
+
token: { "APP_KEY" => api_key }.compact.to_json,
|
22
|
+
auth_header: "X-Shopify-Authenticated-Tokens"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def query(query_name, variables: {})
|
27
|
+
@api.query(query_name, variables: variables)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def script_service_url
|
33
|
+
if ::ShopifyCli::Environment.use_spin_partners_instance?
|
34
|
+
"https://script-service.#{::ShopifyCli::Environment.spin_url}"
|
35
|
+
else
|
36
|
+
LOCAL_INSTANCE_URL
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
private_constant(:ScriptServiceApiClient)
|
41
|
+
|
42
|
+
class PartnersProxyApiClient
|
43
|
+
def initialize(ctx, api_key)
|
44
|
+
@ctx = ctx
|
45
|
+
@api_key = api_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def query(query_name, variables: {})
|
49
|
+
response = ShimAPI.query(@ctx, query_name, api_key: @api_key, variables: variables.to_json)
|
50
|
+
raise_if_graphql_failed(response)
|
51
|
+
JSON.parse(response["data"]["scriptServiceProxy"])
|
52
|
+
end
|
53
|
+
|
54
|
+
def raise_if_graphql_failed(response)
|
55
|
+
raise Errors::EmptyResponseError if response.nil?
|
56
|
+
|
57
|
+
return unless response.key?("errors")
|
58
|
+
case error_code(response["errors"])
|
59
|
+
when "forbidden"
|
60
|
+
raise Errors::ForbiddenError
|
61
|
+
when "forbidden_on_shop"
|
62
|
+
raise Errors::ShopAuthenticationError
|
63
|
+
when "app_not_installed_on_shop"
|
64
|
+
raise Errors::AppNotInstalledError
|
65
|
+
else
|
66
|
+
raise Errors::GraphqlError, response["errors"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def error_code(errors)
|
71
|
+
errors.map do |e|
|
72
|
+
code = e.dig("extensions", "code")
|
73
|
+
return code if code
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class ShimAPI < ShopifyCli::PartnersAPI
|
78
|
+
def query(query_name, variables: {})
|
79
|
+
variables[:query] = load_query(query_name)
|
80
|
+
super("script_service_proxy", variables: variables)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
private_constant(:ShimAPI)
|
84
|
+
end
|
85
|
+
private_constant(:PartnersProxyApiClient)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb
CHANGED
@@ -40,7 +40,7 @@ module Script
|
|
40
40
|
def extension_point_version
|
41
41
|
return extension_point.sdks.assemblyscript.version if extension_point.sdks.assemblyscript.versioned?
|
42
42
|
|
43
|
-
out = command_runner.call("npm show #{extension_point.sdks.assemblyscript.package} version --json")
|
43
|
+
out = command_runner.call("npm -s show #{extension_point.sdks.assemblyscript.package} version --json")
|
44
44
|
"^#{JSON.parse(out)}"
|
45
45
|
end
|
46
46
|
|
@@ -9,37 +9,39 @@ 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
|
-
compiled_type:,
|
18
|
-
api_key: nil,
|
19
22
|
force: false,
|
20
23
|
metadata:,
|
21
|
-
script_json
|
24
|
+
script_json:,
|
25
|
+
module_upload_url:
|
22
26
|
)
|
23
|
-
query_name = "
|
27
|
+
query_name = "app_script_set"
|
24
28
|
variables = {
|
25
29
|
uuid: uuid,
|
26
30
|
extensionPointName: extension_point_type.upcase,
|
27
31
|
title: script_json.title,
|
28
32
|
description: script_json.description,
|
29
|
-
sourceCode: Base64.encode64(script_content),
|
30
|
-
language: compiled_type,
|
31
33
|
force: force,
|
32
34
|
schemaMajorVersion: metadata.schema_major_version.to_s, # API expects string value
|
33
35
|
schemaMinorVersion: metadata.schema_minor_version.to_s, # API expects string value
|
34
|
-
useMsgpack: metadata.use_msgpack,
|
35
36
|
scriptJsonVersion: script_json.version,
|
36
37
|
configurationUi: script_json.configuration_ui,
|
37
38
|
configurationDefinition: script_json.configuration&.to_json,
|
39
|
+
moduleUploadUrl: module_upload_url,
|
38
40
|
}
|
39
|
-
resp_hash =
|
40
|
-
user_errors = resp_hash["data"]["
|
41
|
+
resp_hash = make_request(query_name: query_name, variables: variables)
|
42
|
+
user_errors = resp_hash["data"]["appScriptSet"]["userErrors"]
|
41
43
|
|
42
|
-
return resp_hash["data"]["
|
44
|
+
return resp_hash["data"]["appScriptSet"]["appScript"]["uuid"] if user_errors.empty?
|
43
45
|
|
44
46
|
if user_errors.any? { |e| e["tag"] == "already_exists_error" }
|
45
47
|
raise Errors::ScriptRepushError, uuid
|
@@ -64,98 +66,31 @@ module Script
|
|
64
66
|
end
|
65
67
|
end
|
66
68
|
|
67
|
-
def get_app_scripts(
|
69
|
+
def get_app_scripts(extension_point_type:)
|
68
70
|
query_name = "get_app_scripts"
|
69
71
|
variables = { appKey: api_key, extensionPointName: extension_point_type.upcase }
|
70
|
-
|
72
|
+
response = make_request(query_name: query_name, variables: variables)
|
73
|
+
response["data"]["appScripts"]
|
71
74
|
end
|
72
75
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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"]
|
77
81
|
|
78
|
-
|
79
|
-
|
80
|
-
def self.query(ctx, query_name, api_key: nil, variables: {})
|
81
|
-
api_client(ctx, api_key).query(query_name, variables: variables)
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.api_client(ctx, api_key)
|
85
|
-
instance_url = spin_instance_url || LOCAL_INSTANCE_URL
|
86
|
-
new(
|
87
|
-
ctx: ctx,
|
88
|
-
url: "#{instance_url}/graphql",
|
89
|
-
token: "",
|
90
|
-
api_key: api_key
|
91
|
-
)
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.spin_instance_url
|
95
|
-
workspace = ENV["SPIN_WORKSPACE"]
|
96
|
-
namespace = ENV["SPIN_NAMESPACE"]
|
97
|
-
return if workspace.nil? || namespace.nil?
|
98
|
-
|
99
|
-
"https://script-service.#{workspace}.#{namespace}.us.spin.dev"
|
100
|
-
end
|
101
|
-
|
102
|
-
def auth_headers(*)
|
103
|
-
tokens = { "APP_KEY" => api_key }.compact.to_json
|
104
|
-
{ "X-Shopify-Authenticated-Tokens" => tokens }
|
105
|
-
end
|
82
|
+
raise Errors::GraphqlError, user_errors if user_errors.any?
|
83
|
+
response["data"]["moduleUploadUrlGenerate"]["url"]
|
106
84
|
end
|
107
|
-
private_constant(:ScriptServiceAPI)
|
108
85
|
|
109
|
-
|
110
|
-
def query(query_name, variables: {})
|
111
|
-
variables[:query] = load_query(query_name)
|
112
|
-
super("script_service_proxy", variables: variables)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
private_constant(:PartnersProxyAPI)
|
116
|
-
|
117
|
-
def script_service_request(query_name:, variables: nil, **options)
|
118
|
-
resp = if bypass_partners_proxy
|
119
|
-
ScriptServiceAPI.query(ctx, query_name, variables: variables, **options)
|
120
|
-
else
|
121
|
-
proxy_through_partners(query_name: query_name, variables: variables, **options)
|
122
|
-
end
|
123
|
-
raise_if_graphql_failed(resp)
|
124
|
-
resp
|
125
|
-
end
|
126
|
-
|
127
|
-
def bypass_partners_proxy
|
128
|
-
!ENV["BYPASS_PARTNERS_PROXY"].nil?
|
129
|
-
end
|
130
|
-
|
131
|
-
def proxy_through_partners(query_name:, variables: nil, **options)
|
132
|
-
options[:variables] = variables.to_json if variables
|
133
|
-
resp = PartnersProxyAPI.query(ctx, query_name, **options)
|
134
|
-
raise_if_graphql_failed(resp)
|
135
|
-
JSON.parse(resp["data"]["scriptServiceProxy"])
|
136
|
-
end
|
86
|
+
private
|
137
87
|
|
138
|
-
def
|
88
|
+
def make_request(query_name:, variables: {})
|
89
|
+
response = @client.query(query_name, variables: variables)
|
139
90
|
raise Errors::EmptyResponseError if response.nil?
|
91
|
+
raise Errors::GraphqlError, response["errors"] if response.key?("errors")
|
140
92
|
|
141
|
-
|
142
|
-
case error_code(response["errors"])
|
143
|
-
when "forbidden"
|
144
|
-
raise Errors::ForbiddenError
|
145
|
-
when "forbidden_on_shop"
|
146
|
-
raise Errors::ShopAuthenticationError
|
147
|
-
when "app_not_installed_on_shop"
|
148
|
-
raise Errors::AppNotInstalledError
|
149
|
-
else
|
150
|
-
raise Errors::GraphqlError, response["errors"]
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def error_code(errors)
|
155
|
-
errors.map do |e|
|
156
|
-
code = e.dig("extensions", "code")
|
157
|
-
return code if code
|
158
|
-
end
|
93
|
+
response
|
159
94
|
end
|
160
95
|
end
|
161
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
|
@@ -141,6 +141,9 @@ module Script
|
|
141
141
|
web_assembly_binary_not_found_suggestion: "No WebAssembly binary found." \
|
142
142
|
"Check that your build npm script outputs the generated binary to the root of the directory." \
|
143
143
|
"Generated binary should match the script name: <script_name>.wasm",
|
144
|
+
|
145
|
+
script_upload_cause: "Fail to upload script.",
|
146
|
+
script_upload_help: "Try again.",
|
144
147
|
},
|
145
148
|
|
146
149
|
create: {
|
@@ -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
|
@@ -237,6 +237,11 @@ module Script
|
|
237
237
|
cause_of_error: ShopifyCli::Context.message("script.error.web_assembly_binary_not_found"),
|
238
238
|
help_suggestion: ShopifyCli::Context.message("script.error.web_assembly_binary_not_found_suggestion"),
|
239
239
|
}
|
240
|
+
when Layers::Infrastructure::Errors::ScriptUploadError
|
241
|
+
{
|
242
|
+
cause_of_error: ShopifyCli::Context.message("script.error.script_upload_cause"),
|
243
|
+
help_suggestion: ShopifyCli::Context.message("script.error.script_upload_help"),
|
244
|
+
}
|
240
245
|
end
|
241
246
|
end
|
242
247
|
end
|
@@ -9,6 +9,10 @@ module Theme
|
|
9
9
|
options do |parser, flags|
|
10
10
|
parser.on("-n", "--nodelete") { flags[:nodelete] = true }
|
11
11
|
parser.on("-i", "--themeid=ID") { |theme_id| flags[:theme_id] = theme_id }
|
12
|
+
parser.on("-x", "--ignore=PATTERN") do |pattern|
|
13
|
+
flags[:ignores] ||= []
|
14
|
+
flags[:ignores] << pattern
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
def call(args, _name)
|
@@ -29,6 +33,8 @@ module Theme
|
|
29
33
|
end
|
30
34
|
|
31
35
|
ignore_filter = ShopifyCli::Theme::IgnoreFilter.from_path(root)
|
36
|
+
ignore_filter.add_patterns(options.flags[:ignores]) if options.flags[:ignores]
|
37
|
+
|
32
38
|
syncer = ShopifyCli::Theme::Syncer.new(@ctx, theme: theme, ignore_filter: ignore_filter)
|
33
39
|
begin
|
34
40
|
syncer.start_threads
|
@@ -15,6 +15,10 @@ module Theme
|
|
15
15
|
parser.on("-j", "--json") { flags[:json] = true }
|
16
16
|
parser.on("-a", "--allow-live") { flags[:allow_live] = true }
|
17
17
|
parser.on("-p", "--publish") { flags[:publish] = true }
|
18
|
+
parser.on("-x", "--ignore=PATTERN") do |pattern|
|
19
|
+
flags[:ignores] ||= []
|
20
|
+
flags[:ignores] << pattern
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def call(args, _name)
|
@@ -48,6 +52,8 @@ module Theme
|
|
48
52
|
end
|
49
53
|
|
50
54
|
ignore_filter = ShopifyCli::Theme::IgnoreFilter.from_path(root)
|
55
|
+
ignore_filter.add_patterns(options.flags[:ignores]) if options.flags[:ignores]
|
56
|
+
|
51
57
|
syncer = ShopifyCli::Theme::Syncer.new(@ctx, theme: theme, ignore_filter: ignore_filter)
|
52
58
|
begin
|
53
59
|
syncer.start_threads
|
@@ -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
|