shopify-cli 2.2.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/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
|