shopify-cli 1.0.0 → 1.0.1
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/CHANGELOG.md +4 -0
- data/lib/project_types/node/forms/create.rb +3 -54
- data/lib/project_types/node/messages/messages.rb +1 -12
- data/lib/project_types/rails/forms/create.rb +3 -52
- data/lib/project_types/rails/messages/messages.rb +0 -11
- data/lib/shopify-cli/admin_api.rb +1 -2
- data/lib/shopify-cli/admin_api/populate_resource_command.rb +10 -1
- data/lib/shopify-cli/core/entry_point.rb +6 -0
- data/lib/shopify-cli/core/finalize.rb +13 -0
- data/lib/shopify-cli/messages/messages.rb +14 -0
- data/lib/shopify-cli/tasks.rb +1 -0
- data/lib/shopify-cli/tasks/select_org_and_shop.rb +77 -0
- data/lib/shopify-cli/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa8d08ea4c9f452ea672ebe158f4e900eda442cc17aa46905d25aa53a7f3a673
|
4
|
+
data.tar.gz: 516ee988dee9309aa0e3319d576fe5fcd13065fa08b0b9a4d648fced6642d26e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc4c9b95106709203f6153310bdee08183b3bad45f1ff7f3512b408fabfa478391ca4e5adbfe6cc6b2aaaea655363067de9bacb39a8ff02016e5df03aa7366de
|
7
|
+
data.tar.gz: 503b6c26f1c57e65f5a22b5171faa8d9e5117c404ca02bec6a92af571cadf17f74918fd8bcf2b993100b0e09b3f20576dbeca401cbbb93c7f2355ac389bdf6ed
|
data/CHANGELOG.md
CHANGED
@@ -10,8 +10,9 @@ module Node
|
|
10
10
|
self.title ||= CLI::UI::Prompt.ask(ctx.message('node.forms.create.app_name'))
|
11
11
|
self.type = ask_type
|
12
12
|
self.name = self.title.downcase.split(" ").join("_")
|
13
|
-
|
14
|
-
self.
|
13
|
+
res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx, organization_id: organization_id, shop_domain: shop_domain)
|
14
|
+
self.organization_id = res[:organization_id]
|
15
|
+
self.shop_domain = res[:shop_domain]
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
@@ -30,58 +31,6 @@ module Node
|
|
30
31
|
ctx.puts(ctx.message('node.forms.create.app_type.selected', type))
|
31
32
|
type
|
32
33
|
end
|
33
|
-
|
34
|
-
def organizations
|
35
|
-
@organizations ||= ShopifyCli::PartnersAPI::Organizations.fetch_all(ctx)
|
36
|
-
end
|
37
|
-
|
38
|
-
def organization
|
39
|
-
@organization ||= if !organization_id.nil?
|
40
|
-
org = ShopifyCli::PartnersAPI::Organizations.fetch(ctx, id: organization_id)
|
41
|
-
if org.nil?
|
42
|
-
ctx.puts(ctx.message('node.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
43
|
-
ctx.abort(ctx.message('node.forms.create.error.organization_not_found'))
|
44
|
-
end
|
45
|
-
org
|
46
|
-
elsif organizations.count == 0
|
47
|
-
ctx.puts(ctx.message('node.forms.create.partners_notice'))
|
48
|
-
ctx.puts(ctx.message('node.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
49
|
-
ctx.abort(ctx.message('node.forms.create.error.no_organizations'))
|
50
|
-
elsif organizations.count == 1
|
51
|
-
org = organizations.first
|
52
|
-
ctx.puts(ctx.message('node.forms.create.organization',
|
53
|
-
ctx.message('core.partners_api.org_name_and_id', org['businessName'], org['id'])))
|
54
|
-
org
|
55
|
-
else
|
56
|
-
org_id = CLI::UI::Prompt.ask(ctx.message('node.forms.create.organization_select')) do |handler|
|
57
|
-
organizations.each do |o|
|
58
|
-
handler.option(ctx.message('core.partners_api.org_name_and_id', o['businessName'], o['id'])) { o['id'] }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
organizations.find { |o| o['id'] == org_id }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def ask_shop_domain
|
66
|
-
valid_stores = organization['stores'].select do |store|
|
67
|
-
store['transferDisabled'] == true || store['convertableToPartnerTest'] == true
|
68
|
-
end
|
69
|
-
|
70
|
-
if valid_stores.count == 0
|
71
|
-
ctx.puts(ctx.message('node.forms.create.no_development_stores'))
|
72
|
-
ctx.puts(ctx.message('node.forms.create.create_store', organization['id']))
|
73
|
-
ctx.puts(ctx.message('node.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
74
|
-
elsif valid_stores.count == 1
|
75
|
-
domain = valid_stores.first['shopDomain']
|
76
|
-
ctx.puts(ctx.message('node.forms.create.development_store', domain))
|
77
|
-
domain
|
78
|
-
else
|
79
|
-
CLI::UI::Prompt.ask(
|
80
|
-
ctx.message('node.forms.create.development_store_select'),
|
81
|
-
options: valid_stores.map { |s| s['shopDomain'] }
|
82
|
-
)
|
83
|
-
end
|
84
|
-
end
|
85
34
|
end
|
86
35
|
end
|
87
36
|
end
|
@@ -233,25 +233,14 @@ module Node
|
|
233
233
|
create: {
|
234
234
|
error: {
|
235
235
|
invalid_app_type: "Invalid app type %s",
|
236
|
-
organization_not_found: "Cannot find a partner organization with that ID",
|
237
|
-
no_organizations: "No partner organizations available.",
|
238
236
|
},
|
239
|
-
|
240
|
-
authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
241
|
-
partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
|
242
|
-
no_development_stores: "{{x}} No Development Stores available.",
|
243
|
-
create_store: "Visit {{underline:https://partners.shopify.com/%s/stores}} to create one",
|
244
|
-
app_name: "App Name",
|
237
|
+
app_name: "App name",
|
245
238
|
app_type: {
|
246
239
|
select: "What type of app are you building?",
|
247
240
|
select_public: "Public: An app built for a wide merchant audience.",
|
248
241
|
select_custom: "Custom: An app custom built for a single client.",
|
249
242
|
selected: "App type {{green:%s}}",
|
250
243
|
},
|
251
|
-
organization_select: "Select partner organization",
|
252
|
-
organization: "Partner organization {{green:%s}}",
|
253
|
-
development_store_select: "Select a development store",
|
254
|
-
development_store: "Using development store {{green:%s}}",
|
255
244
|
},
|
256
245
|
},
|
257
246
|
},
|
@@ -22,8 +22,9 @@ module Rails
|
|
22
22
|
self.title ||= CLI::UI::Prompt.ask(ctx.message('rails.forms.create.app_name'))
|
23
23
|
self.type = ask_type
|
24
24
|
self.name = self.title.downcase.split(" ").join("_")
|
25
|
-
|
26
|
-
self.
|
25
|
+
res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx, organization_id: organization_id, shop_domain: shop_domain)
|
26
|
+
self.organization_id = res[:organization_id]
|
27
|
+
self.shop_domain = res[:shop_domain]
|
27
28
|
self.db = ask_db
|
28
29
|
end
|
29
30
|
|
@@ -44,56 +45,6 @@ module Rails
|
|
44
45
|
type
|
45
46
|
end
|
46
47
|
|
47
|
-
def organizations
|
48
|
-
@organizations ||= ShopifyCli::PartnersAPI::Organizations.fetch_all(ctx)
|
49
|
-
end
|
50
|
-
|
51
|
-
def organization
|
52
|
-
@organization ||= if !organization_id.nil?
|
53
|
-
org = ShopifyCli::PartnersAPI::Organizations.fetch(ctx, id: organization_id)
|
54
|
-
if org.nil?
|
55
|
-
ctx.puts(ctx.message('rails.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
56
|
-
ctx.abort(ctx.message('rails.forms.create.error.organization_not_found'))
|
57
|
-
end
|
58
|
-
org
|
59
|
-
elsif organizations.count == 0
|
60
|
-
ctx.puts(ctx.message('rails.forms.create.partners_notice'))
|
61
|
-
ctx.puts(ctx.message('rails.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
62
|
-
ctx.abort(ctx.message('rails.forms.create.error.no_organizations'))
|
63
|
-
elsif organizations.count == 1
|
64
|
-
org = organizations.first
|
65
|
-
ctx.puts(ctx.message('rails.forms.create.organization',
|
66
|
-
ctx.message('core.partners_api.org_name_and_id', org['businessName'], org['id'])))
|
67
|
-
org
|
68
|
-
else
|
69
|
-
org_id = CLI::UI::Prompt.ask(ctx.message('rails.forms.create.organization_select')) do |handler|
|
70
|
-
organizations.each { |o| handler.option(o['businessName']) { o['id'] } }
|
71
|
-
end
|
72
|
-
organizations.find { |o| o['id'] == org_id }
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def ask_shop_domain
|
77
|
-
valid_stores = organization['stores'].select do |store|
|
78
|
-
store['transferDisabled'] == true || store['convertableToPartnerTest'] == true
|
79
|
-
end
|
80
|
-
|
81
|
-
if valid_stores.count == 0
|
82
|
-
ctx.puts(ctx.message('rails.forms.create.no_development_stores'))
|
83
|
-
ctx.puts(ctx.message('rails.forms.create.create_store', organization['id']))
|
84
|
-
ctx.puts(ctx.message('rails.forms.create.authentication_issue', ShopifyCli::TOOL_NAME))
|
85
|
-
elsif valid_stores.count == 1
|
86
|
-
domain = valid_stores.first['shopDomain']
|
87
|
-
ctx.puts(ctx.message('rails.forms.create.development_store', domain))
|
88
|
-
domain
|
89
|
-
else
|
90
|
-
CLI::UI::Prompt.ask(
|
91
|
-
ctx.message('rails.forms.create.development_store_select'),
|
92
|
-
options: valid_stores.map { |s| s['shopDomain'] }
|
93
|
-
)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
48
|
def ask_db
|
98
49
|
if db.nil?
|
99
50
|
return 'sqlite3' unless CLI::UI::Prompt.confirm(ctx.message('rails.forms.create.db.want_select'),
|
@@ -236,14 +236,7 @@ module Rails
|
|
236
236
|
error: {
|
237
237
|
invalid_app_type: "Invalid app type %s",
|
238
238
|
invalid_db_type: "Invalid database type %s",
|
239
|
-
organization_not_found: "Cannot find a partner organization with that ID",
|
240
|
-
no_organizations: "No partner organizations available.",
|
241
239
|
},
|
242
|
-
|
243
|
-
authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
244
|
-
partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
|
245
|
-
no_development_stores: "{{x}} No development stores available.",
|
246
|
-
create_store: "Visit {{underline:https://partners.shopify.com/%s/stores}} to create one",
|
247
240
|
app_name: "App name",
|
248
241
|
app_type: {
|
249
242
|
select: "What type of app are you building?",
|
@@ -271,10 +264,6 @@ module Rails
|
|
271
264
|
select_jdbc: "JDBC",
|
272
265
|
selected: "Database Type {{green:%s}}",
|
273
266
|
},
|
274
|
-
organization_select: "Select partner organization",
|
275
|
-
organization: "Partner organization {{green:%s}}",
|
276
|
-
development_store_select: "Select a development store",
|
277
|
-
development_store: "Using development store {{green:%s}}",
|
278
267
|
},
|
279
268
|
},
|
280
269
|
},
|
@@ -37,8 +37,7 @@ module ShopifyCli
|
|
37
37
|
#
|
38
38
|
# ShopifyCli::AdminAPI.query(@ctx, 'all_organizations')
|
39
39
|
#
|
40
|
-
def query(ctx, query_name, api_version: nil,
|
41
|
-
shop ||= Project.current.env.shop
|
40
|
+
def query(ctx, query_name, shop:, api_version: nil, **variables)
|
42
41
|
authenticated_req(ctx, shop) do
|
43
42
|
api_client(ctx, api_version, shop).query(query_name, variables: variables)
|
44
43
|
end
|
@@ -41,6 +41,8 @@ module ShopifyCli
|
|
41
41
|
return @ctx.puts(output)
|
42
42
|
end
|
43
43
|
|
44
|
+
@shop ||= Project.current.env.shop || get_shop(@ctx)
|
45
|
+
|
44
46
|
if @silent
|
45
47
|
spin_group = CLI::UI::SpinGroup.new
|
46
48
|
spin_group.add(@ctx.message('core.populate.populating', @count, camel_case_resource_type)) do |spinner|
|
@@ -114,7 +116,7 @@ module ShopifyCli
|
|
114
116
|
|
115
117
|
def run_mutation(data)
|
116
118
|
kwargs = { input: data }
|
117
|
-
kwargs[:shop] = @shop
|
119
|
+
kwargs[:shop] = @shop
|
118
120
|
resp = AdminAPI.query(
|
119
121
|
@ctx, "create_#{snake_case_resource_type}", kwargs
|
120
122
|
)
|
@@ -145,6 +147,13 @@ module ShopifyCli
|
|
145
147
|
|
146
148
|
private
|
147
149
|
|
150
|
+
def get_shop(ctx)
|
151
|
+
res = ShopifyCli::Tasks::SelectOrgAndShop.call(ctx)
|
152
|
+
domain = res[:shop_domain]
|
153
|
+
Project.current.env.update(ctx, :shop, domain)
|
154
|
+
domain
|
155
|
+
end
|
156
|
+
|
148
157
|
def camel_case_resource_type
|
149
158
|
@camel_case_resource_type ||= self.class.to_s.split('::').last
|
150
159
|
end
|
@@ -11,6 +11,12 @@ module ShopifyCli
|
|
11
11
|
IO.open(9) { is_shell_shim = true }
|
12
12
|
rescue Errno::EBADF
|
13
13
|
# This is expected if the descriptor doesn't exist
|
14
|
+
rescue ArgumentError => e
|
15
|
+
# This can happen on RVM, because it can use fd 9 itself and block access to it. That only happens if the fd
|
16
|
+
# did not exist beforehand, so that means there was no fd 9 before Ruby started.
|
17
|
+
unless e.message == 'The given fd is not accessible because RubyVM reserves it'
|
18
|
+
raise e
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
if !ctx.testing? && is_shell_shim
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ShopifyCli
|
2
|
+
module Core
|
3
|
+
# This class is just a dummy to make sure that we don't trigger warnings on the first time the updated code runs.
|
4
|
+
# The old code would try to call the Finalizer after it is done updating, which would then trigger an autoload of
|
5
|
+
# this class and fail.
|
6
|
+
module Finalize
|
7
|
+
class << self
|
8
|
+
def deliver!
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -251,6 +251,20 @@ module ShopifyCli
|
|
251
251
|
"{{x}} error: For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
252
252
|
update_prompt: "Do you want to update your application url?",
|
253
253
|
},
|
254
|
+
select_org_and_shop: {
|
255
|
+
authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
256
|
+
create_store: "Visit {{underline:https://partners.shopify.com/%s/stores}} to create one",
|
257
|
+
development_store: "Using development store {{green:%s}}",
|
258
|
+
development_store_select: "Select a development store",
|
259
|
+
error: {
|
260
|
+
no_development_stores: "{{x}} No Development Stores available.",
|
261
|
+
no_organizations: "No partner organizations available.",
|
262
|
+
organization_not_found: "Cannot find a partner organization with that ID",
|
263
|
+
partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
|
264
|
+
},
|
265
|
+
organization: "Partner organization {{green:%s (%s)}}",
|
266
|
+
organization_select: "Select partner organization",
|
267
|
+
},
|
254
268
|
},
|
255
269
|
|
256
270
|
tunnel: {
|
data/lib/shopify-cli/tasks.rb
CHANGED
@@ -27,6 +27,7 @@ module ShopifyCli
|
|
27
27
|
register :EnsureEnv, :ensure_env, 'shopify-cli/tasks/ensure_env'
|
28
28
|
register :EnsureLoopbackURL, :ensure_loopback_url, 'shopify-cli/tasks/ensure_loopback_url'
|
29
29
|
register :EnsureDevStore, :ensure_dev_store, 'shopify-cli/tasks/ensure_dev_store'
|
30
|
+
register :SelectOrgAndShop, :select_org_and_shop, 'shopify-cli/tasks/select_org_and_shop'
|
30
31
|
register :UpdateDashboardURLS, :update_dashboard_urls, 'shopify-cli/tasks/update_dashboard_urls'
|
31
32
|
end
|
32
33
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'shopify_cli'
|
2
|
+
|
3
|
+
module ShopifyCli
|
4
|
+
module Tasks
|
5
|
+
class SelectOrgAndShop < ShopifyCli::Task
|
6
|
+
attr_reader :ctx
|
7
|
+
|
8
|
+
def call(ctx, organization_id: nil, shop_domain: nil)
|
9
|
+
@ctx = ctx
|
10
|
+
return response(organization_id.to_i, shop_domain) unless organization_id.nil? || shop_domain.nil?
|
11
|
+
org = get_organization(organization_id)
|
12
|
+
shop_domain ||= get_shop_domain(org)
|
13
|
+
response(org["id"].to_i, shop_domain)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def response(organization_id, shop_domain)
|
19
|
+
{
|
20
|
+
organization_id: organization_id,
|
21
|
+
shop_domain: shop_domain,
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def organizations
|
26
|
+
@organizations ||= ShopifyCli::PartnersAPI::Organizations.fetch_all(ctx)
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_organization(organization_id)
|
30
|
+
@organization ||= if !organization_id.nil?
|
31
|
+
org = ShopifyCli::PartnersAPI::Organizations.fetch(ctx, id: organization_id)
|
32
|
+
if org.nil?
|
33
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.authentication_issue', ShopifyCli::TOOL_NAME))
|
34
|
+
ctx.abort(ctx.message('core.tasks.select_org_and_shop.error.organization_not_found'))
|
35
|
+
end
|
36
|
+
org
|
37
|
+
elsif organizations.count == 0
|
38
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.partners_notice'))
|
39
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.authentication_issue', ShopifyCli::TOOL_NAME))
|
40
|
+
ctx.abort(ctx.message('core.tasks.select_org_and_shop.error.no_organizations'))
|
41
|
+
elsif organizations.count == 1
|
42
|
+
org = organizations.first
|
43
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.organization', org['businessName'], org['id']))
|
44
|
+
org
|
45
|
+
else
|
46
|
+
org_id = CLI::UI::Prompt.ask(ctx.message('core.tasks.select_org_and_shop.organization_select')) do |handler|
|
47
|
+
organizations.each do |o|
|
48
|
+
handler.option(ctx.message('core.partners_api.org_name_and_id', o['businessName'], o['id'])) { o['id'] }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
organizations.find { |o| o['id'] == org_id }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_shop_domain(organization)
|
56
|
+
valid_stores = organization['stores'].select do |store|
|
57
|
+
store['transferDisabled'] == true || store['convertableToPartnerTest'] == true
|
58
|
+
end
|
59
|
+
|
60
|
+
if valid_stores.count == 0
|
61
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.error.no_development_stores'))
|
62
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.create_store', organization['id']))
|
63
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.authentication_issue', ShopifyCli::TOOL_NAME))
|
64
|
+
elsif valid_stores.count == 1
|
65
|
+
domain = valid_stores.first['shopDomain']
|
66
|
+
ctx.puts(ctx.message('core.tasks.select_org_and_shop.development_store', domain))
|
67
|
+
domain
|
68
|
+
else
|
69
|
+
CLI::UI::Prompt.ask(
|
70
|
+
ctx.message('core.tasks.select_org_and_shop.development_store_select'),
|
71
|
+
options: valid_stores.map { |s| s['shopDomain'] }
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/shopify-cli/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -267,6 +267,7 @@ files:
|
|
267
267
|
- lib/shopify-cli/core.rb
|
268
268
|
- lib/shopify-cli/core/entry_point.rb
|
269
269
|
- lib/shopify-cli/core/executor.rb
|
270
|
+
- lib/shopify-cli/core/finalize.rb
|
270
271
|
- lib/shopify-cli/core/help_resolver.rb
|
271
272
|
- lib/shopify-cli/core/monorail.rb
|
272
273
|
- lib/shopify-cli/db.rb
|
@@ -296,6 +297,7 @@ files:
|
|
296
297
|
- lib/shopify-cli/tasks/ensure_dev_store.rb
|
297
298
|
- lib/shopify-cli/tasks/ensure_env.rb
|
298
299
|
- lib/shopify-cli/tasks/ensure_loopback_url.rb
|
300
|
+
- lib/shopify-cli/tasks/select_org_and_shop.rb
|
299
301
|
- lib/shopify-cli/tasks/update_dashboard_urls.rb
|
300
302
|
- lib/shopify-cli/tunnel.rb
|
301
303
|
- lib/shopify-cli/version.rb
|