shopify-cli 0.9.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -3
- data/docs/_config.yml +3 -0
- data/docs/_data/nav.yml +9 -0
- data/docs/getting-started/index.md +5 -40
- data/docs/getting-started/install/index.md +75 -0
- data/docs/getting-started/migrate/index.md +96 -0
- data/docs/getting-started/uninstall/index.md +37 -0
- data/docs/getting-started/upgrade/index.md +37 -0
- data/docs/index.md +5 -6
- data/lib/project_types/extension/cli.rb +3 -2
- data/lib/project_types/extension/commands/build.rb +1 -1
- data/lib/project_types/extension/commands/tunnel.rb +1 -1
- data/lib/project_types/extension/forms/register.rb +2 -3
- data/lib/project_types/extension/graphql/get_app_by_api_key.graphql +9 -0
- data/lib/project_types/extension/tasks/converters/app_converter.rb +27 -0
- data/lib/project_types/extension/tasks/get_app.rb +22 -0
- data/lib/project_types/extension/tasks/get_apps.rb +1 -6
- data/lib/project_types/node/forms/create.rb +3 -54
- data/lib/project_types/node/messages/messages.rb +3 -14
- data/lib/project_types/rails/cli.rb +0 -1
- data/lib/project_types/rails/forms/create.rb +3 -52
- data/lib/project_types/rails/messages/messages.rb +2 -13
- data/lib/project_types/script/cli.rb +5 -5
- data/lib/project_types/script/commands/create.rb +5 -4
- data/lib/project_types/script/commands/disable.rb +4 -14
- data/lib/project_types/script/commands/enable.rb +35 -11
- data/lib/project_types/script/commands/push.rb +9 -9
- data/lib/project_types/script/config/extension_points.yml +9 -3
- data/lib/project_types/script/errors.rb +1 -0
- data/lib/project_types/script/forms/create.rb +8 -4
- data/lib/project_types/script/forms/script_form.rb +5 -2
- data/lib/project_types/script/layers/application/create_script.rb +14 -20
- data/lib/project_types/script/layers/application/disable_script.rb +9 -7
- data/lib/project_types/script/layers/application/enable_script.rb +11 -9
- data/lib/project_types/script/layers/application/project_dependencies.rb +0 -5
- data/lib/project_types/script/layers/application/push_script.rb +6 -4
- data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +106 -0
- data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +2 -2
- data/lib/project_types/script/layers/infrastructure/errors.rb +2 -1
- data/lib/project_types/script/layers/infrastructure/project_creator.rb +23 -0
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -1
- data/lib/project_types/script/layers/infrastructure/script_repository.rb +1 -34
- data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
- data/lib/project_types/script/messages/messages.rb +21 -25
- data/lib/project_types/script/script_project.rb +8 -4
- data/lib/project_types/script/templates/ts/as-pect.config.js +6 -0
- data/lib/project_types/script/templates/ts/as-pect.d.ts +1 -0
- data/lib/project_types/script/ui/error_handler.rb +9 -0
- data/lib/project_types/script/ui/printing_spinner.rb +75 -0
- 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/admin_api/schema.rb +20 -8
- data/lib/shopify-cli/command.rb +2 -5
- data/lib/shopify-cli/commands.rb +1 -0
- data/lib/shopify-cli/commands/config.rb +44 -0
- data/lib/shopify-cli/commands/connect.rb +17 -10
- data/lib/shopify-cli/commands/create.rb +1 -1
- data/lib/shopify-cli/commands/help.rb +1 -1
- data/lib/shopify-cli/commands/system.rb +1 -1
- data/lib/shopify-cli/context.rb +10 -1
- data/lib/shopify-cli/core.rb +0 -1
- data/lib/shopify-cli/core/entry_point.rb +6 -0
- data/lib/shopify-cli/core/finalize.rb +13 -0
- data/lib/shopify-cli/feature.rb +97 -0
- data/lib/shopify-cli/messages/messages.rb +45 -2
- data/lib/shopify-cli/partners_api/organizations.rb +7 -7
- data/lib/shopify-cli/project_type.rb +2 -5
- data/lib/shopify-cli/tasks.rb +1 -0
- data/lib/shopify-cli/tasks/ensure_env.rb +0 -1
- data/lib/shopify-cli/tasks/select_org_and_shop.rb +77 -0
- data/lib/shopify-cli/tasks/update_dashboard_urls.rb +4 -3
- data/lib/shopify-cli/tunnel.rb +66 -10
- data/lib/shopify-cli/version.rb +1 -1
- data/lib/shopify_cli.rb +1 -0
- data/vendor/deps/cli-ui/REVISION +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui.rb +52 -11
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +11 -7
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +34 -21
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +107 -149
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +99 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +119 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +158 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +112 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +9 -15
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +47 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +9 -7
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +39 -14
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +62 -44
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +7 -2
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +23 -3
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +34 -10
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +12 -7
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +26 -16
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +3 -3
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +75 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +27 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +61 -0
- metadata +25 -9
- data/lib/project_types/extension/features/tunnel_url.rb +0 -20
- data/lib/project_types/script/forms/enable.rb +0 -24
- data/lib/project_types/script/forms/push.rb +0 -19
- data/lib/project_types/script/layers/infrastructure/assemblyscript_dependency_manager.rb +0 -51
- data/lib/project_types/script/layers/infrastructure/dependency_manager.rb +0 -36
- data/lib/project_types/script/layers/infrastructure/test_suite_repository.rb +0 -62
- data/vendor/deps/cli-ui/lib/cli/ui/box.rb +0 -15
data/lib/shopify-cli/context.rb
CHANGED
@@ -146,10 +146,19 @@ module ShopifyCli
|
|
146
146
|
# #### Parameters
|
147
147
|
# * `path` - the file path to a directory, relative to the context root to remove from the FS
|
148
148
|
#
|
149
|
-
def
|
149
|
+
def dir_exist?(path)
|
150
150
|
Dir.exist?(ctx_path(path))
|
151
151
|
end
|
152
152
|
|
153
|
+
# checks if a file exists, the filepath is relative to the command root unless absolute
|
154
|
+
#
|
155
|
+
# #### Parameters
|
156
|
+
# * `path` - the file path to a file, relative to the context root to remove from the FS
|
157
|
+
#
|
158
|
+
def file_exist?(path)
|
159
|
+
File.exist?(ctx_path(path))
|
160
|
+
end
|
161
|
+
|
153
162
|
# will recursively copy a directory from the FS, the filepath is relative to the command
|
154
163
|
# root unless absolute
|
155
164
|
#
|
data/lib/shopify-cli/core.rb
CHANGED
@@ -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
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ShopifyCli
|
2
|
+
##
|
3
|
+
# ShopifyCli::Feature contains the logic to hide and show features across the CLI
|
4
|
+
# These features can be either commands or project types currently.
|
5
|
+
#
|
6
|
+
# Feature flags will persist between runs so if the flag is enabled or disabled,
|
7
|
+
# it will still be in that same state on the next cli invocation.
|
8
|
+
class Feature
|
9
|
+
SECTION = 'features'
|
10
|
+
|
11
|
+
##
|
12
|
+
# ShopifyCli::Feature::Set is included on commands and projects to allow you to hide
|
13
|
+
# and enable projects and commands based on feature flags.
|
14
|
+
module Set
|
15
|
+
##
|
16
|
+
# will hide a feature, either a project_type or a command
|
17
|
+
#
|
18
|
+
# #### Parameters
|
19
|
+
#
|
20
|
+
# * `feature_set` - either a single, or array of symbols that represent feature sets
|
21
|
+
#
|
22
|
+
# #### Example
|
23
|
+
#
|
24
|
+
# module ShopifyCli
|
25
|
+
# module Commands
|
26
|
+
# class Config < ShopifyCli::Command
|
27
|
+
# hidden_feature(feature_set: :basic)
|
28
|
+
# ....
|
29
|
+
#
|
30
|
+
def hidden_feature(feature_set: [])
|
31
|
+
@feature_hidden = true
|
32
|
+
@hidden_feature_set = Array(feature_set).compact
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# will return if the feature has been hidden or not
|
37
|
+
#
|
38
|
+
# #### Returns
|
39
|
+
#
|
40
|
+
# * `is_hidden` - returns true if the feature has been hidden and false otherwise
|
41
|
+
#
|
42
|
+
# #### Example
|
43
|
+
#
|
44
|
+
# ShopifyCli::Commands::Config.hidden?
|
45
|
+
#
|
46
|
+
def hidden?
|
47
|
+
enabled = (@hidden_feature_set || []).any? do |feature|
|
48
|
+
Feature.enabled?(feature)
|
49
|
+
end
|
50
|
+
@feature_hidden && !enabled
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
##
|
56
|
+
# will enable a feature in the CLI.
|
57
|
+
#
|
58
|
+
# #### Parameters
|
59
|
+
#
|
60
|
+
# * `feature` - a symbol representing the flag to be enabled
|
61
|
+
def enable(feature)
|
62
|
+
set(feature, true)
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# will disable a feature in the CLI.
|
67
|
+
#
|
68
|
+
# #### Parameters
|
69
|
+
#
|
70
|
+
# * `feature` - a symbol representing the flag to be disabled
|
71
|
+
def disable(feature)
|
72
|
+
set(feature, false)
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# will check if the feature has been enabled
|
77
|
+
#
|
78
|
+
# #### Parameters
|
79
|
+
#
|
80
|
+
# * `feature` - a symbol representing a flag that the status should be requested
|
81
|
+
#
|
82
|
+
# #### Returns
|
83
|
+
#
|
84
|
+
# * `is_enabled` - will be true if the feature has been enabled.
|
85
|
+
def enabled?(feature)
|
86
|
+
return false if feature.nil?
|
87
|
+
ShopifyCli::Config.get_bool(SECTION, feature.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def set(feature, value)
|
93
|
+
ShopifyCli::Config.set(SECTION, feature.to_s, value)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -24,6 +24,15 @@ module ShopifyCli
|
|
24
24
|
MESSAGE
|
25
25
|
development_store_select: "Which development store would you like to use?",
|
26
26
|
cli_yml_saved: ".shopify-cli.yml saved to project root",
|
27
|
+
|
28
|
+
no_apps: 'You have no apps to connect to, creating a new app.',
|
29
|
+
app_name: "App name",
|
30
|
+
app_type: {
|
31
|
+
select: "What type of app are you building?",
|
32
|
+
select_public: "Public: An app built for a wide merchant audience.",
|
33
|
+
select_custom: "Custom: An app custom built for a single client.",
|
34
|
+
selected: "App type {{green:%s}}",
|
35
|
+
},
|
27
36
|
},
|
28
37
|
|
29
38
|
context: {
|
@@ -52,6 +61,19 @@ module ShopifyCli
|
|
52
61
|
saved: "%s saved to project root",
|
53
62
|
},
|
54
63
|
|
64
|
+
config: {
|
65
|
+
help: <<~HELP,
|
66
|
+
Change configuration of how the CLI operates
|
67
|
+
Usage: {{command:%s config [ feature ] [ feature_name ] }}
|
68
|
+
HELP
|
69
|
+
feature: {
|
70
|
+
enabled: "{{v}} feature {{green:%s}} was enabled",
|
71
|
+
disabled: "{{v}} feature {{green:%s}} was disabled",
|
72
|
+
is_enabled: "{{v}} feature {{green:%s}} is enabled",
|
73
|
+
is_disabled: "{{v}} feature {{green:%s}} is disabled",
|
74
|
+
},
|
75
|
+
},
|
76
|
+
|
55
77
|
git: {
|
56
78
|
error: {
|
57
79
|
directory_exists: "Project directory already exists. Please create a project with a new name.",
|
@@ -251,6 +273,20 @@ module ShopifyCli
|
|
251
273
|
"{{x}} error: For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
252
274
|
update_prompt: "Do you want to update your application url?",
|
253
275
|
},
|
276
|
+
select_org_and_shop: {
|
277
|
+
authentication_issue: "For authentication issues, run {{command:%s logout}} to clear invalid credentials",
|
278
|
+
create_store: "Visit {{underline:https://partners.shopify.com/%s/stores}} to create one",
|
279
|
+
development_store: "Using development store {{green:%s}}",
|
280
|
+
development_store_select: "Select a development store",
|
281
|
+
error: {
|
282
|
+
no_development_stores: "{{x}} No Development Stores available.",
|
283
|
+
no_organizations: "No partner organizations available.",
|
284
|
+
organization_not_found: "Cannot find a partner organization with that ID",
|
285
|
+
partners_notice: "Please visit https://partners.shopify.com/ to create a partners account",
|
286
|
+
},
|
287
|
+
organization: "Partner organization {{green:%s (%s)}}",
|
288
|
+
organization_select: "Select partner organization",
|
289
|
+
},
|
254
290
|
},
|
255
291
|
|
256
292
|
tunnel: {
|
@@ -259,10 +295,17 @@ module ShopifyCli
|
|
259
295
|
url_fetch_failure: "Unable to fetch external url",
|
260
296
|
},
|
261
297
|
|
262
|
-
stopped: "{{green:x}} ngrok tunnel stopped",
|
263
298
|
not_running: "{{green:x}} ngrok tunnel not running",
|
264
|
-
|
299
|
+
signup_suggestion: <<~MESSAGE,
|
300
|
+
{{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
|
301
|
+
account at {{underline:https://ngrok.com/signup}}. After you signup, install your
|
302
|
+
personalized authorization token using {{command:%s tunnel auth <token>}}.
|
303
|
+
MESSAGE
|
265
304
|
start: "{{v}} ngrok tunnel running at {{underline:%s}}",
|
305
|
+
start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
|
306
|
+
stopped: "{{green:x}} ngrok tunnel stopped",
|
307
|
+
timed_out: "{{x}} ngrok tunnel has timed out, restarting ...",
|
308
|
+
will_timeout: "{{*}} This tunnel will timeout in {{red:%s}}",
|
266
309
|
},
|
267
310
|
|
268
311
|
version: {
|
@@ -4,25 +4,25 @@ module ShopifyCli
|
|
4
4
|
class << self
|
5
5
|
def fetch_all(ctx)
|
6
6
|
resp = PartnersAPI.query(ctx, 'all_organizations')
|
7
|
-
resp
|
8
|
-
org['stores'] = org
|
7
|
+
(resp.dig('data', 'organizations', 'nodes') || []).map do |org|
|
8
|
+
org['stores'] = (org.dig('stores', 'nodes') || [])
|
9
9
|
org
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
def fetch(ctx, id:)
|
14
14
|
resp = PartnersAPI.query(ctx, 'find_organization', id: id)
|
15
|
-
org = resp
|
15
|
+
org = resp.dig('data', 'organizations', 'nodes').first
|
16
16
|
return nil if org.nil?
|
17
|
-
org['stores'] = org
|
17
|
+
org['stores'] = (org.dig('stores', 'nodes') || [])
|
18
18
|
org
|
19
19
|
end
|
20
20
|
|
21
21
|
def fetch_with_app(ctx)
|
22
22
|
resp = PartnersAPI.query(ctx, 'all_orgs_with_apps')
|
23
|
-
resp
|
24
|
-
org['stores'] = org
|
25
|
-
org['apps'] = org
|
23
|
+
(resp.dig('data', 'organizations', 'nodes') || []).map do |org|
|
24
|
+
org['stores'] = (org.dig('stores', 'nodes') || [])
|
25
|
+
org['apps'] = (org.dig('apps', 'nodes') || [])
|
26
26
|
org
|
27
27
|
end
|
28
28
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module ShopifyCli
|
2
2
|
class ProjectType
|
3
|
+
extend Feature::Set
|
4
|
+
|
3
5
|
class << self
|
4
6
|
attr_accessor :project_type,
|
5
7
|
:project_name,
|
6
8
|
:project_creator_command_class,
|
7
9
|
:project_load_shallow
|
8
|
-
attr_reader :hidden
|
9
10
|
|
10
11
|
def repository
|
11
12
|
@repository ||= []
|
@@ -53,10 +54,6 @@ module ShopifyCli
|
|
53
54
|
const_get(@project_creator_command_class)
|
54
55
|
end
|
55
56
|
|
56
|
-
def hidden_project_type
|
57
|
-
@hidden = true
|
58
|
-
end
|
59
|
-
|
60
57
|
def register_command(const, cmd)
|
61
58
|
return if project_load_shallow
|
62
59
|
Context.new.abort(
|
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
|
@@ -14,7 +14,6 @@ module ShopifyCli
|
|
14
14
|
api_key = CLI::UI.ask(@ctx.message('core.tasks.ensure_env.api_key_question'))
|
15
15
|
api_secret = CLI::UI.ask(@ctx.message('core.tasks.ensure_env.api_secret_key_question'))
|
16
16
|
shop = CLI::UI.ask(@ctx.message('core.tasks.ensure_env.development_store_question'))
|
17
|
-
|
18
17
|
shop.gsub!(/https?\:\/\//, '')
|
19
18
|
|
20
19
|
env = Resources::EnvFile.new(
|
@@ -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
|
@@ -28,16 +28,17 @@ module ShopifyCli
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def construct_redirect_urls(urls, new_url, callback_url)
|
31
|
-
urls.map do |url|
|
31
|
+
new_urls = urls.map do |url|
|
32
32
|
if (match = url.match(NGROK_REGEX))
|
33
33
|
"#{new_url}#{match[2]}"
|
34
34
|
else
|
35
35
|
url
|
36
36
|
end
|
37
37
|
end
|
38
|
-
if
|
39
|
-
|
38
|
+
if new_urls.grep(/#{new_url}#{callback_url}/).empty?
|
39
|
+
new_urls.push("#{new_url}#{callback_url}")
|
40
40
|
end
|
41
|
+
new_urls.uniq
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
data/lib/shopify-cli/tunnel.rb
CHANGED
@@ -11,7 +11,7 @@ module ShopifyCli
|
|
11
11
|
class Tunnel
|
12
12
|
extend SingleForwardable
|
13
13
|
|
14
|
-
def_delegators :new, :start, :stop, :auth
|
14
|
+
def_delegators :new, :start, :stop, :auth, :stats, :urls
|
15
15
|
|
16
16
|
class FetchUrlError < RuntimeError; end
|
17
17
|
class NgrokError < RuntimeError; end
|
@@ -23,6 +23,10 @@ module ShopifyCli
|
|
23
23
|
linux: 'https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip',
|
24
24
|
}
|
25
25
|
|
26
|
+
NGROK_TUNNELS_URI = URI.parse('http://localhost:4040/api/tunnels')
|
27
|
+
TUNNELS_FIELD = 'tunnels'
|
28
|
+
PUBLIC_URL_FIELD = 'public_url'
|
29
|
+
|
26
30
|
##
|
27
31
|
# will find and stop a running tunnel process. It will also output if the
|
28
32
|
# operation was successful or not
|
@@ -58,14 +62,19 @@ module ShopifyCli
|
|
58
62
|
#
|
59
63
|
def start(ctx, port: PORT)
|
60
64
|
install(ctx)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
ctx.puts(ctx.message('core.tunnel.start_with_account', log.url, log.account))
|
65
|
+
url, account, seconds_remaining = start_ngrok(ctx, port)
|
66
|
+
if account
|
67
|
+
ctx.puts(ctx.message('core.tunnel.start_with_account', url, account))
|
65
68
|
else
|
66
|
-
|
69
|
+
if seconds_remaining <= 0
|
70
|
+
ctx.puts(ctx.message('core.tunnel.timed_out'))
|
71
|
+
url, _account, seconds_remaining = restart_ngrok(ctx, port)
|
72
|
+
end
|
73
|
+
ctx.puts(ctx.message('core.tunnel.start', url))
|
74
|
+
ctx.puts(ctx.message('core.tunnel.will_timeout', seconds_to_hm(seconds_remaining)))
|
75
|
+
ctx.puts(ctx.message('core.tunnel.signup_suggestion', ShopifyCli::TOOL_NAME))
|
67
76
|
end
|
68
|
-
|
77
|
+
url
|
69
78
|
end
|
70
79
|
|
71
80
|
##
|
@@ -82,6 +91,34 @@ module ShopifyCli
|
|
82
91
|
ctx.system(File.join(ShopifyCli::CACHE_DIR, 'ngrok'), 'authtoken', token)
|
83
92
|
end
|
84
93
|
|
94
|
+
##
|
95
|
+
# will return the statistics of the current running tunnels
|
96
|
+
#
|
97
|
+
# #### Returns
|
98
|
+
#
|
99
|
+
# * `stats` - the hash of running statistics returning from the ngrok api
|
100
|
+
#
|
101
|
+
def stats
|
102
|
+
response = Net::HTTP.get_response(NGROK_TUNNELS_URI)
|
103
|
+
JSON.parse(response.body)
|
104
|
+
rescue
|
105
|
+
{}
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# will return the urls of the current running tunnels
|
110
|
+
#
|
111
|
+
# #### Returns
|
112
|
+
#
|
113
|
+
# * `stats` - the array of urls
|
114
|
+
#
|
115
|
+
def urls
|
116
|
+
tunnels = stats.dig(TUNNELS_FIELD)
|
117
|
+
tunnels.map { |tunnel| tunnel.dig(PUBLIC_URL_FIELD) }
|
118
|
+
rescue
|
119
|
+
[]
|
120
|
+
end
|
121
|
+
|
85
122
|
private
|
86
123
|
|
87
124
|
def install(ctx)
|
@@ -106,13 +143,30 @@ module ShopifyCli
|
|
106
143
|
end
|
107
144
|
|
108
145
|
def ngrok_command(port)
|
109
|
-
"exec #{File.join(ShopifyCli::CACHE_DIR, 'ngrok')} http -log=stdout -log-level=debug #{port}"
|
146
|
+
"exec #{File.join(ShopifyCli::CACHE_DIR, 'ngrok')} http -inspect=false -log=stdout -log-level=debug #{port}"
|
147
|
+
end
|
148
|
+
|
149
|
+
def seconds_to_hm(seconds)
|
150
|
+
format("%d hours %d minutes", seconds / 3600, seconds / 60 % 60)
|
110
151
|
end
|
111
152
|
|
153
|
+
def start_ngrok(ctx, port)
|
154
|
+
process = ShopifyCli::ProcessSupervision.start(:ngrok, ngrok_command(port))
|
155
|
+
log = fetch_url(ctx, process.log_path)
|
156
|
+
seconds_remaining = (process.time.to_i + log.timeout) - Time.now.to_i
|
157
|
+
[log.url, log.account, seconds_remaining]
|
158
|
+
end
|
159
|
+
|
160
|
+
def restart_ngrok(ctx, port)
|
161
|
+
unless ShopifyCli::ProcessSupervision.stop(:ngrok)
|
162
|
+
ctx.abort(ctx.message('core.tunnel.error.stop'))
|
163
|
+
end
|
164
|
+
start_ngrok(ctx, port)
|
165
|
+
end
|
112
166
|
class LogParser # :nodoc:
|
113
167
|
TIMEOUT = 10
|
114
168
|
|
115
|
-
attr_reader :url, :account
|
169
|
+
attr_reader :url, :account, :timeout
|
116
170
|
|
117
171
|
def initialize(log_path)
|
118
172
|
@log_path = log_path
|
@@ -141,7 +195,9 @@ module ShopifyCli
|
|
141
195
|
end
|
142
196
|
|
143
197
|
def parse_account
|
144
|
-
|
198
|
+
account, timeout, _ = @log.match(/AccountName:([\w\s]*) SessionDuration:([\d]+) PlanName/)&.captures
|
199
|
+
@account = account&.empty? ? nil : account
|
200
|
+
@timeout = timeout&.empty? ? 0 : timeout.to_i
|
145
201
|
end
|
146
202
|
|
147
203
|
def error
|