shopify-cli 2.6.6 → 2.7.3
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/.devcontainer.json +5 -0
- data/.github/CODEOWNERS +2 -2
- data/.github/DESIGN.md +1 -1
- data/.github/ISSUE_TEMPLATE.md +7 -0
- data/.github/workflows/shopify.yml +1 -1
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.vscode/extensions.json +5 -0
- data/.vscode/settings.json +9 -0
- data/CHANGELOG.md +44 -4
- data/CONTRIBUTING.md +1 -29
- data/{Dockerfile → Codespace.dockerfile} +2 -2
- data/Gemfile.lock +5 -5
- data/README.md +20 -99
- data/Rakefile +27 -0
- data/Tests.dockerfile +35 -0
- data/assets/logo.png +0 -0
- data/dev.yml +1 -4
- data/docs/README.md +13 -0
- data/docs/contributors/testing.md +27 -0
- data/docs/users/installation.md +46 -0
- data/{THEMEKIT_MIGRATION.md → docs/users/migrate-from-themekit.md} +1 -1
- data/ext/javy/hashes/javy-arm-macos-v0.1.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-linux-v0.1.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-macos-v0.1.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-windows-v0.1.0.gz.sha256 +1 -0
- data/ext/javy/javy.rb +205 -0
- data/ext/javy/version +1 -0
- data/lib/project_types/extension/cli.rb +6 -3
- data/lib/project_types/extension/commands/build.rb +4 -8
- data/lib/project_types/extension/commands/create.rb +2 -5
- data/lib/project_types/extension/commands/extension_command.rb +1 -1
- data/lib/project_types/extension/features/argo_serve.rb +9 -23
- data/lib/project_types/extension/forms/questions/ask_template.rb +1 -5
- data/lib/project_types/extension/messages/messages.rb +0 -2
- data/lib/project_types/extension/models/development_server.rb +2 -2
- data/lib/project_types/extension/models/development_server_requirements.rb +2 -3
- data/lib/project_types/extension/models/server_config/app.rb +13 -0
- data/lib/project_types/extension/models/server_config/development.rb +5 -4
- data/lib/project_types/extension/models/server_config/development_renderer.rb +1 -1
- data/lib/project_types/extension/models/server_config/development_resource.rb +13 -0
- data/lib/project_types/extension/models/server_config/extension.rb +3 -1
- data/lib/project_types/extension/models/server_config/root.rb +4 -1
- data/lib/project_types/extension/tasks/convert_server_config.rb +65 -0
- data/lib/project_types/extension/tasks/ensure_resource_url.rb +39 -0
- data/lib/project_types/extension/tasks/merge_server_config.rb +32 -0
- data/lib/project_types/extension/tasks/run_extension_command.rb +11 -10
- data/lib/project_types/node/cli.rb +0 -16
- data/lib/project_types/node/forms/create.rb +5 -5
- data/lib/project_types/node/messages/messages.rb +2 -144
- data/lib/project_types/php/cli.rb +0 -11
- data/lib/project_types/php/forms/create.rb +5 -6
- data/lib/project_types/php/messages/messages.rb +2 -161
- data/lib/project_types/rails/cli.rb +0 -16
- data/lib/project_types/rails/commands/create.rb +3 -5
- data/lib/project_types/rails/forms/create.rb +5 -6
- data/lib/project_types/rails/messages/messages.rb +6 -151
- data/lib/project_types/script/cli.rb +8 -2
- data/lib/project_types/script/commands/create.rb +2 -4
- data/lib/project_types/script/commands/javy.rb +29 -0
- data/lib/project_types/script/commands/push.rb +3 -2
- data/lib/project_types/script/config/extension_points.yml +12 -30
- data/lib/project_types/script/forms/ask_app.rb +32 -0
- data/lib/project_types/script/forms/ask_org.rb +30 -0
- data/lib/project_types/script/forms/ask_script_uuid.rb +22 -0
- data/lib/project_types/script/forms/run_against_shopify_org.rb +14 -0
- data/lib/project_types/script/graphql/app_script_set.graphql +2 -2
- data/lib/project_types/script/layers/application/build_script.rb +0 -1
- data/lib/project_types/script/layers/application/connect_app.rb +73 -0
- data/lib/project_types/script/layers/application/create_script.rb +1 -1
- data/lib/project_types/script/layers/application/push_script.rb +1 -1
- data/lib/project_types/script/layers/domain/errors.rb +1 -4
- data/lib/project_types/script/layers/domain/push_package.rb +3 -3
- data/lib/project_types/script/layers/domain/{script_json.rb → script_config.rb} +2 -2
- data/lib/project_types/script/layers/domain/script_project.rb +5 -1
- data/lib/project_types/script/layers/infrastructure/errors.rb +36 -7
- data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +0 -4
- data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +0 -4
- data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +2 -2
- data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +104 -27
- data/lib/project_types/script/layers/infrastructure/script_service.rb +11 -11
- data/lib/project_types/script/messages/messages.rb +21 -4
- data/lib/project_types/script/ui/error_handler.rb +31 -21
- data/lib/project_types/theme/cli.rb +1 -1
- data/lib/project_types/theme/commands/check.rb +1 -1
- data/lib/project_types/theme/commands/delete.rb +1 -1
- data/lib/project_types/theme/commands/init.rb +1 -1
- data/lib/project_types/theme/commands/language_server.rb +1 -1
- data/lib/project_types/theme/commands/package.rb +1 -1
- data/lib/project_types/theme/commands/publish.rb +1 -1
- data/lib/project_types/theme/commands/pull.rb +4 -1
- data/lib/project_types/theme/commands/push.rb +5 -1
- data/lib/project_types/theme/commands/serve.rb +9 -3
- data/lib/project_types/theme/messages/messages.rb +39 -2
- data/lib/project_types/theme/ui/sync_progress_bar.rb +2 -2
- data/lib/shopify_cli/admin_api/populate_resource_command.rb +1 -1
- data/lib/shopify_cli/api.rb +7 -2
- data/lib/shopify_cli/app_type_detector.rb +24 -20
- data/lib/shopify_cli/command/app_sub_command.rb +10 -0
- data/lib/shopify_cli/command/project_command.rb +31 -0
- data/lib/shopify_cli/command/sub_command.rb +19 -0
- data/lib/shopify_cli/command.rb +7 -2
- data/lib/shopify_cli/commands/app/connect.rb +22 -0
- data/lib/shopify_cli/commands/app/create/node.rb +36 -0
- data/lib/shopify_cli/commands/app/create/php.rb +36 -0
- data/lib/shopify_cli/commands/app/create/rails.rb +38 -0
- data/lib/shopify_cli/commands/app/create.rb +28 -0
- data/lib/shopify_cli/commands/app/deploy.rb +49 -0
- data/lib/shopify_cli/commands/app/open.rb +19 -0
- data/lib/shopify_cli/commands/app/serve.rb +49 -0
- data/lib/shopify_cli/commands/app/tunnel.rb +43 -0
- data/lib/shopify_cli/commands/app.rb +29 -0
- data/lib/shopify_cli/commands/config.rb +2 -2
- data/lib/shopify_cli/commands.rb +1 -0
- data/lib/shopify_cli/constants.rb +7 -0
- data/lib/shopify_cli/context.rb +10 -0
- data/lib/shopify_cli/environment.rb +4 -0
- data/lib/shopify_cli/exception_reporter.rb +3 -4
- data/lib/shopify_cli/git.rb +14 -1
- data/lib/shopify_cli/github/issue_url_generator.rb +19 -0
- data/lib/shopify_cli/github.rb +5 -0
- data/lib/shopify_cli/identity_auth.rb +18 -0
- data/lib/shopify_cli/messages/messages.rb +254 -9
- data/lib/shopify_cli/partners_api.rb +1 -8
- data/lib/shopify_cli/project.rb +5 -1
- data/lib/shopify_cli/project_commands.rb +1 -1
- data/lib/shopify_cli/services/app/connect_service.rb +25 -0
- data/lib/shopify_cli/services/app/create/node_service.rb +155 -0
- data/lib/shopify_cli/services/app/create/php_service.rb +152 -0
- data/lib/shopify_cli/services/app/create/rails_service.rb +215 -0
- data/lib/shopify_cli/services/app/deploy/heroku/node_service.rb +101 -0
- data/lib/shopify_cli/services/app/deploy/heroku/php_service.rb +135 -0
- data/lib/shopify_cli/services/app/deploy/heroku/rails_service.rb +120 -0
- data/lib/shopify_cli/services/app/open_service.rb +19 -0
- data/lib/shopify_cli/services/app/serve/node_service.rb +42 -0
- data/lib/shopify_cli/services/app/serve/php_service.rb +46 -0
- data/lib/shopify_cli/services/app/serve/rails_service.rb +48 -0
- data/lib/shopify_cli/services/app/tunnel/auth_service.rb +21 -0
- data/lib/shopify_cli/services/app/tunnel/start_service.rb +20 -0
- data/lib/shopify_cli/services/app/tunnel/stop_service.rb +20 -0
- data/lib/shopify_cli/services.rb +31 -0
- data/lib/shopify_cli/tasks/ensure_authenticated.rb +9 -3
- data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +73 -0
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +25 -9
- data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
- data/lib/shopify_cli/theme/dev_server.rb +37 -18
- data/lib/shopify_cli/theme/syncer/error_reporter.rb +45 -0
- data/lib/shopify_cli/theme/syncer/operation.rb +56 -0
- data/lib/shopify_cli/theme/syncer/standard_reporter.rb +32 -0
- data/lib/shopify_cli/theme/syncer.rb +40 -39
- data/lib/shopify_cli/theme/theme.rb +31 -19
- data/lib/shopify_cli/tunnel.rb +26 -22
- data/lib/shopify_cli/version.rb +1 -1
- data/lib/shopify_cli.rb +1 -2
- data/shopify-cli.gemspec +1 -1
- data/shopify-dev +18 -0
- data/utilities/constants.rb +7 -0
- data/utilities/docker/container.rb +10 -3
- data/utilities/docker.rb +2 -2
- data/utilities/utilities.rb +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +1 -1
- metadata +66 -50
- data/docs/_config.yml +0 -2
- data/docs/app/node/commands/index.md +0 -4
- data/docs/app/node/index.md +0 -4
- data/docs/app/rails/commands/index.md +0 -4
- data/docs/app/rails/index.md +0 -4
- data/docs/core/index.md +0 -4
- data/docs/getting-started/index.md +0 -4
- data/docs/getting-started/install/index.md +0 -4
- data/docs/getting-started/migrate/index.md +0 -4
- data/docs/getting-started/uninstall/index.md +0 -4
- data/docs/getting-started/upgrade/index.md +0 -4
- data/docs/help/start-app/index.md +0 -4
- data/docs/index.md +0 -4
- data/install.sh +0 -7
- data/lib/project_types/extension/tasks/converters/server_config_converter.rb +0 -30
- data/lib/project_types/extension/tasks/load_server_config.rb +0 -28
- data/lib/project_types/node/commands/connect.rb +0 -21
- data/lib/project_types/node/commands/create.rb +0 -125
- data/lib/project_types/node/commands/deploy/heroku.rb +0 -96
- data/lib/project_types/node/commands/deploy.rb +0 -32
- data/lib/project_types/node/commands/generate.rb +0 -22
- data/lib/project_types/node/commands/open.rb +0 -18
- data/lib/project_types/node/commands/serve.rb +0 -45
- data/lib/project_types/node/commands/tunnel.rb +0 -41
- data/lib/project_types/php/commands/connect.rb +0 -19
- data/lib/project_types/php/commands/create.rb +0 -143
- data/lib/project_types/php/commands/deploy/heroku.rb +0 -129
- data/lib/project_types/php/commands/deploy.rb +0 -32
- data/lib/project_types/php/commands/open.rb +0 -16
- data/lib/project_types/php/commands/serve.rb +0 -48
- data/lib/project_types/php/commands/tunnel.rb +0 -37
- data/lib/project_types/rails/commands/connect.rb +0 -21
- data/lib/project_types/rails/commands/deploy/heroku.rb +0 -115
- data/lib/project_types/rails/commands/deploy.rb +0 -32
- data/lib/project_types/rails/commands/generate/webhook.rb +0 -42
- data/lib/project_types/rails/commands/generate.rb +0 -60
- data/lib/project_types/rails/commands/open.rb +0 -18
- data/lib/project_types/rails/commands/serve.rb +0 -51
- data/lib/project_types/rails/commands/tunnel.rb +0 -41
- data/lib/project_types/script/tasks/ensure_env.rb +0 -106
- data/lib/shopify_cli/sub_command.rb +0 -17
- data/shopify.fish +0 -12
- data/shopify.sh +0 -11
|
@@ -3,6 +3,7 @@ require_relative "development_theme"
|
|
|
3
3
|
require_relative "ignore_filter"
|
|
4
4
|
require_relative "syncer"
|
|
5
5
|
|
|
6
|
+
require_relative "dev_server/cdn_fonts"
|
|
6
7
|
require_relative "dev_server/hot_reload"
|
|
7
8
|
require_relative "dev_server/header_hash"
|
|
8
9
|
require_relative "dev_server/local_assets"
|
|
@@ -17,10 +18,14 @@ require "pathname"
|
|
|
17
18
|
module ShopifyCLI
|
|
18
19
|
module Theme
|
|
19
20
|
module DevServer
|
|
21
|
+
# Errors
|
|
22
|
+
Error = Class.new(StandardError)
|
|
23
|
+
AddressBindingError = Class.new(Error)
|
|
24
|
+
|
|
20
25
|
class << self
|
|
21
26
|
attr_accessor :ctx
|
|
22
27
|
|
|
23
|
-
def start(ctx, root,
|
|
28
|
+
def start(ctx, root, host: "127.0.0.1", port: 9292, poll: false)
|
|
24
29
|
@ctx = ctx
|
|
25
30
|
theme = DevelopmentTheme.new(ctx, root: root)
|
|
26
31
|
ignore_filter = IgnoreFilter.from_path(root)
|
|
@@ -29,9 +34,11 @@ module ShopifyCLI
|
|
|
29
34
|
|
|
30
35
|
# Setup the middleware stack. Mimics Rack::Builder / config.ru, but in reverse order
|
|
31
36
|
@app = Proxy.new(ctx, theme: theme, syncer: @syncer)
|
|
37
|
+
@app = CdnFonts.new(@app, theme: theme)
|
|
32
38
|
@app = LocalAssets.new(ctx, @app, theme: theme)
|
|
33
39
|
@app = HotReload.new(ctx, @app, theme: theme, watcher: watcher, ignore_filter: ignore_filter)
|
|
34
40
|
stopped = false
|
|
41
|
+
address = "http://#{host}:#{port}"
|
|
35
42
|
|
|
36
43
|
theme.ensure_exists!
|
|
37
44
|
|
|
@@ -40,8 +47,8 @@ module ShopifyCLI
|
|
|
40
47
|
stop
|
|
41
48
|
end
|
|
42
49
|
|
|
43
|
-
CLI::UI::Frame.open(@ctx.message("theme.serve.
|
|
44
|
-
ctx.print_task("
|
|
50
|
+
CLI::UI::Frame.open(@ctx.message("theme.serve.viewing_theme")) do
|
|
51
|
+
ctx.print_task(ctx.message("theme.serve.syncing_theme", theme.id, theme.shop))
|
|
45
52
|
@syncer.start_threads
|
|
46
53
|
if block_given?
|
|
47
54
|
yield @syncer
|
|
@@ -51,18 +58,9 @@ module ShopifyCLI
|
|
|
51
58
|
|
|
52
59
|
return if stopped
|
|
53
60
|
|
|
54
|
-
ctx.puts("")
|
|
55
|
-
ctx.
|
|
56
|
-
ctx.puts("")
|
|
57
|
-
ctx.open_url!("http://127.0.0.1:#{port}")
|
|
58
|
-
ctx.puts("")
|
|
59
|
-
ctx.puts("Customize this theme in the Online Store Editor:")
|
|
60
|
-
ctx.puts("{{green:#{theme.editor_url}}}")
|
|
61
|
-
ctx.puts("")
|
|
62
|
-
ctx.puts("Share this theme preview:")
|
|
63
|
-
ctx.puts("{{green:#{theme.preview_url}}}")
|
|
64
|
-
ctx.puts("")
|
|
65
|
-
ctx.puts("(Use Ctrl-C to stop)")
|
|
61
|
+
ctx.puts(ctx.message("theme.serve.serving", theme.root))
|
|
62
|
+
ctx.open_url!(address)
|
|
63
|
+
ctx.puts(ctx.message("theme.serve.customize_or_preview", theme.editor_url, theme.preview_url))
|
|
66
64
|
end
|
|
67
65
|
|
|
68
66
|
logger = if ctx.debug?
|
|
@@ -74,7 +72,7 @@ module ShopifyCLI
|
|
|
74
72
|
watcher.start
|
|
75
73
|
WebServer.run(
|
|
76
74
|
@app,
|
|
77
|
-
BindAddress:
|
|
75
|
+
BindAddress: host,
|
|
78
76
|
Port: port,
|
|
79
77
|
Logger: logger,
|
|
80
78
|
AccessLog: [],
|
|
@@ -83,8 +81,11 @@ module ShopifyCLI
|
|
|
83
81
|
|
|
84
82
|
rescue ShopifyCLI::API::APIRequestForbiddenError,
|
|
85
83
|
ShopifyCLI::API::APIRequestUnauthorizedError
|
|
86
|
-
@ctx.
|
|
87
|
-
|
|
84
|
+
raise ShopifyCLI::Abort, @ctx.message("theme.serve.ensure_user", theme.shop)
|
|
85
|
+
rescue Errno::EADDRINUSE
|
|
86
|
+
abort_address_already_in_use(address)
|
|
87
|
+
rescue Errno::EADDRNOTAVAIL
|
|
88
|
+
raise AddressBindingError, "Error binding to the address #{host}."
|
|
88
89
|
end
|
|
89
90
|
|
|
90
91
|
def stop
|
|
@@ -93,6 +94,24 @@ module ShopifyCLI
|
|
|
93
94
|
@syncer.shutdown
|
|
94
95
|
WebServer.shutdown
|
|
95
96
|
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def abort_address_already_in_use(address)
|
|
101
|
+
open_frame(@ctx.message("theme.serve.already_in_use_error"), color: :red) do
|
|
102
|
+
@ctx.puts(@ctx.message("theme.serve.address_already_in_use", address))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
open_frame(@ctx.message("theme.serve.try_this"), color: :green) do
|
|
106
|
+
@ctx.puts(@ctx.message("theme.serve.try_port_option"))
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
raise ShopifyCLI::AbortSilent
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def open_frame(title, color:, &block)
|
|
113
|
+
CLI::UI::Frame.open(title, color: CLI::UI.resolve_color(color), timing: false, &block)
|
|
114
|
+
end
|
|
96
115
|
end
|
|
97
116
|
end
|
|
98
117
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ShopifyCLI
|
|
4
|
+
module Theme
|
|
5
|
+
class Syncer
|
|
6
|
+
##
|
|
7
|
+
# ShopifyCLI::Theme::Syncer::ErrorReporter allows delaying log of errors,
|
|
8
|
+
# mainly to not break the progress bar.
|
|
9
|
+
#
|
|
10
|
+
class ErrorReporter
|
|
11
|
+
attr_reader :ctx, :delayed_errors
|
|
12
|
+
|
|
13
|
+
def initialize(ctx)
|
|
14
|
+
@ctx = ctx
|
|
15
|
+
@has_any_error = false
|
|
16
|
+
@delay_errors = false
|
|
17
|
+
@delayed_errors = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def disable!
|
|
21
|
+
@delay_errors = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def enable!
|
|
25
|
+
@delay_errors = false
|
|
26
|
+
@delayed_errors.each { |error| report(error) }
|
|
27
|
+
@delayed_errors.clear
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def report(error_message)
|
|
31
|
+
if @delay_errors
|
|
32
|
+
@delayed_errors << error_message
|
|
33
|
+
else
|
|
34
|
+
@has_any_error = true
|
|
35
|
+
@ctx.error(error_message)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def has_any_error?
|
|
40
|
+
@has_any_error
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ShopifyCLI
|
|
4
|
+
module Theme
|
|
5
|
+
class Syncer
|
|
6
|
+
class Operation
|
|
7
|
+
attr_accessor :method, :file
|
|
8
|
+
|
|
9
|
+
COLOR_BY_STATUS = {
|
|
10
|
+
error: :red,
|
|
11
|
+
synced: :green,
|
|
12
|
+
fixed: :cyan,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def initialize(ctx, method, file)
|
|
16
|
+
@ctx = ctx
|
|
17
|
+
@method = method
|
|
18
|
+
@file = file
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"#{method} #{file_path}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def as_error_message
|
|
26
|
+
as_message_with(status: :error)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def as_synced_message
|
|
30
|
+
as_message_with(status: :synced)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def as_fix_message
|
|
34
|
+
as_message_with(status: :fixed)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def file_path
|
|
38
|
+
file&.relative_path.to_s
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def as_message_with(status:)
|
|
44
|
+
status_color = COLOR_BY_STATUS[status]
|
|
45
|
+
status_text = @ctx.message("theme.serve.operation.status.#{status}").ljust(6)
|
|
46
|
+
|
|
47
|
+
"#{timestamp} {{#{status_color}:#{status_text}}} {{>}} {{blue:#{self}}}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def timestamp
|
|
51
|
+
Time.now.strftime("%T")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ShopifyCLI
|
|
4
|
+
module Theme
|
|
5
|
+
class Syncer
|
|
6
|
+
##
|
|
7
|
+
# ShopifyCLI::Theme::Syncer::StdReporter allows disabling/enabling
|
|
8
|
+
# messages reported in the standard output (ShopifyCLI::Context#puts).
|
|
9
|
+
#
|
|
10
|
+
class StandardReporter
|
|
11
|
+
attr_reader :ctx
|
|
12
|
+
|
|
13
|
+
def initialize(ctx)
|
|
14
|
+
@enabled = true
|
|
15
|
+
@ctx = ctx
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def disable!
|
|
19
|
+
@enabled = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def enable!
|
|
23
|
+
@enabled = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def report(message)
|
|
27
|
+
ctx.puts(message) if @enabled
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -2,24 +2,31 @@
|
|
|
2
2
|
require "thread"
|
|
3
3
|
require "json"
|
|
4
4
|
require "base64"
|
|
5
|
+
require "forwardable"
|
|
6
|
+
|
|
7
|
+
require_relative "syncer/error_reporter"
|
|
8
|
+
require_relative "syncer/standard_reporter"
|
|
9
|
+
require_relative "syncer/operation"
|
|
5
10
|
|
|
6
11
|
module ShopifyCLI
|
|
7
12
|
module Theme
|
|
8
13
|
class Syncer
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"#{method} #{file&.relative_path}"
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
+
extend Forwardable
|
|
15
|
+
|
|
14
16
|
API_VERSION = "unstable"
|
|
15
17
|
|
|
16
18
|
attr_reader :checksums
|
|
17
19
|
attr_accessor :ignore_filter
|
|
18
20
|
|
|
21
|
+
def_delegators :@error_reporter, :has_any_error?
|
|
22
|
+
|
|
19
23
|
def initialize(ctx, theme:, ignore_filter: nil)
|
|
20
24
|
@ctx = ctx
|
|
21
25
|
@theme = theme
|
|
22
26
|
@ignore_filter = ignore_filter
|
|
27
|
+
@error_reporter = ErrorReporter.new(ctx)
|
|
28
|
+
@standard_reporter = StandardReporter.new(ctx)
|
|
29
|
+
@reporters = [@error_reporter, @standard_reporter]
|
|
23
30
|
|
|
24
31
|
# Queue of `Operation`s waiting to be picked up from a thread for processing.
|
|
25
32
|
@queue = Queue.new
|
|
@@ -30,12 +37,19 @@ module ShopifyCLI
|
|
|
30
37
|
# Mutex used to pause all threads when backing-off when hitting API rate limits
|
|
31
38
|
@backoff_mutex = Mutex.new
|
|
32
39
|
|
|
33
|
-
# Allows delaying log of errors, mainly to not break the progress bar.
|
|
34
|
-
@delay_errors = false
|
|
35
|
-
@delayed_errors = []
|
|
36
|
-
|
|
37
40
|
# Latest theme assets checksums. Updated on each upload.
|
|
38
41
|
@checksums = {}
|
|
42
|
+
|
|
43
|
+
# Checksums of assets with errors.
|
|
44
|
+
@error_checksums = []
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def lock_io!
|
|
48
|
+
@reporters.each { |reporter| reporter.disable! }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def unlock_io!
|
|
52
|
+
@reporters.each { |reporter| reporter.enable! }
|
|
39
53
|
end
|
|
40
54
|
|
|
41
55
|
def enqueue_updates(files)
|
|
@@ -103,25 +117,14 @@ module ShopifyCLI
|
|
|
103
117
|
break if operation.nil? # shutdown was called
|
|
104
118
|
perform(operation)
|
|
105
119
|
rescue Exception => e
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
)
|
|
120
|
+
error_suffix = ": #{e}"
|
|
121
|
+
error_suffix += + "\n\t#{e.backtrace.join("\n\t")}" if @ctx.debug?
|
|
122
|
+
report_error(operation, error_suffix)
|
|
110
123
|
end
|
|
111
124
|
end
|
|
112
125
|
end
|
|
113
126
|
end
|
|
114
127
|
|
|
115
|
-
def delay_errors!
|
|
116
|
-
@delay_errors = true
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def report_errors!
|
|
120
|
-
@delay_errors = false
|
|
121
|
-
@delayed_errors.each { |error| report_error(error) }
|
|
122
|
-
@delayed_errors.clear
|
|
123
|
-
end
|
|
124
|
-
|
|
125
128
|
def upload_theme!(delay_low_priority_files: false, delete: true, &block)
|
|
126
129
|
fetch_checksums!
|
|
127
130
|
|
|
@@ -177,21 +180,27 @@ module ShopifyCLI
|
|
|
177
180
|
|
|
178
181
|
private
|
|
179
182
|
|
|
183
|
+
def report_error(operation, error_suffix = "")
|
|
184
|
+
@error_checksums << @checksums[operation.file_path]
|
|
185
|
+
@error_reporter.report("#{operation.as_error_message}#{error_suffix}")
|
|
186
|
+
end
|
|
187
|
+
|
|
180
188
|
def enqueue(method, file)
|
|
181
189
|
raise ArgumentError, "file required" unless file
|
|
182
190
|
|
|
183
|
-
operation = Operation.new(method, @theme[file])
|
|
191
|
+
operation = Operation.new(@ctx, method, @theme[file])
|
|
184
192
|
|
|
185
193
|
# Already enqueued
|
|
186
194
|
return if @pending.include?(operation)
|
|
187
195
|
|
|
188
|
-
if @ignore_filter&.ignore?(operation.
|
|
189
|
-
@ctx.debug("ignore #{operation.
|
|
196
|
+
if @ignore_filter&.ignore?(operation.file_path)
|
|
197
|
+
@ctx.debug("ignore #{operation.file_path}")
|
|
190
198
|
return
|
|
191
199
|
end
|
|
192
200
|
|
|
193
201
|
if [:update, :get].include?(method) && operation.file.exist? && !file_has_changed?(operation.file)
|
|
194
|
-
|
|
202
|
+
is_fixed = !!@error_checksums.delete(operation.file.checksum)
|
|
203
|
+
@standard_reporter.report(operation.as_fix_message) if is_fixed
|
|
195
204
|
return
|
|
196
205
|
end
|
|
197
206
|
|
|
@@ -206,16 +215,16 @@ module ShopifyCLI
|
|
|
206
215
|
|
|
207
216
|
response = send(operation.method, operation.file)
|
|
208
217
|
|
|
218
|
+
@standard_reporter.report(operation.as_synced_message)
|
|
219
|
+
|
|
209
220
|
# Check if the API told us we're near the rate limit
|
|
210
221
|
if !backingoff? && (limit = response["x-shopify-shop-api-call-limit"])
|
|
211
222
|
used, total = limit.split("/").map(&:to_i)
|
|
212
223
|
backoff_if_near_limit!(used, total)
|
|
213
224
|
end
|
|
214
225
|
rescue ShopifyCLI::API::APIRequestError => e
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
parse_api_errors(e).join("\n ")
|
|
218
|
-
)
|
|
226
|
+
error_suffix = ":\n " + parse_api_errors(e).join("\n ")
|
|
227
|
+
report_error(operation, error_suffix)
|
|
219
228
|
ensure
|
|
220
229
|
@pending.delete(operation)
|
|
221
230
|
end
|
|
@@ -295,14 +304,6 @@ module ShopifyCLI
|
|
|
295
304
|
file.checksum != @checksums[file.relative_path.to_s]
|
|
296
305
|
end
|
|
297
306
|
|
|
298
|
-
def report_error(error)
|
|
299
|
-
if @delay_errors
|
|
300
|
-
@delayed_errors << error
|
|
301
|
-
else
|
|
302
|
-
@ctx.puts(error)
|
|
303
|
-
end
|
|
304
|
-
end
|
|
305
|
-
|
|
306
307
|
def parse_api_errors(exception)
|
|
307
308
|
parsed_body = JSON.parse(exception&.response&.body)
|
|
308
309
|
message = parsed_body.dig("errors", "asset") || parsed_body["message"] || exception.message
|
|
@@ -162,26 +162,38 @@ module ShopifyCLI
|
|
|
162
162
|
}
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
ctx
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
class << self
|
|
166
|
+
def all(ctx, root: nil)
|
|
167
|
+
_status, body = fetch_themes(ctx)
|
|
168
|
+
|
|
169
|
+
body["themes"]
|
|
170
|
+
.sort_by { |theme_attrs| Time.parse(theme_attrs["updated_at"]) }
|
|
171
|
+
.reverse
|
|
172
|
+
.map { |theme_attrs| new(ctx, root: root, **allowed_attrs(theme_attrs)) }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def live(ctx, root: nil)
|
|
176
|
+
_status, body = fetch_themes(ctx)
|
|
172
177
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
178
|
+
body["themes"]
|
|
179
|
+
.find { |theme_attrs| theme_attrs["role"] == "main" }
|
|
180
|
+
.tap { |theme_attrs| break new(ctx, root: root, **allowed_attrs(theme_attrs)) }
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
private
|
|
184
|
+
|
|
185
|
+
def allowed_attrs(attrs)
|
|
186
|
+
attrs.slice("id", "name", "role").transform_keys(&:to_sym)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def fetch_themes(ctx)
|
|
190
|
+
AdminAPI.rest_request(
|
|
191
|
+
ctx,
|
|
192
|
+
shop: AdminAPI.get_shop_or_abort(ctx),
|
|
193
|
+
path: "themes.json",
|
|
194
|
+
api_version: "unstable",
|
|
195
|
+
)
|
|
196
|
+
end
|
|
185
197
|
end
|
|
186
198
|
|
|
187
199
|
private
|
data/lib/shopify_cli/tunnel.rb
CHANGED
|
@@ -12,7 +12,7 @@ module ShopifyCLI
|
|
|
12
12
|
class Tunnel
|
|
13
13
|
extend SingleForwardable
|
|
14
14
|
|
|
15
|
-
def_delegators :new, :start, :stop, :auth, :stats, :urls, :running_on?
|
|
15
|
+
def_delegators :new, :start, :stop, :auth, :authenticated?, :stats, :urls, :running_on?
|
|
16
16
|
|
|
17
17
|
class FetchUrlError < RuntimeError; end
|
|
18
18
|
class NgrokError < RuntimeError; end
|
|
@@ -21,6 +21,7 @@ module ShopifyCLI
|
|
|
21
21
|
# mapping for supported operating systems for where to download ngrok from.
|
|
22
22
|
DOWNLOAD_URLS = {
|
|
23
23
|
mac: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip",
|
|
24
|
+
mac_m1: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-arm64.zip",
|
|
24
25
|
linux: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip",
|
|
25
26
|
windows: "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip",
|
|
26
27
|
}
|
|
@@ -65,16 +66,12 @@ module ShopifyCLI
|
|
|
65
66
|
#
|
|
66
67
|
def start(ctx, port: PORT)
|
|
67
68
|
install(ctx)
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
if authenticated?
|
|
70
|
+
url, account = start_ngrok(ctx, port)
|
|
70
71
|
ctx.puts(ctx.message("core.tunnel.start_with_account", url, account))
|
|
71
72
|
else
|
|
72
|
-
|
|
73
|
-
ctx.puts(ctx.message("core.tunnel.timed_out"))
|
|
74
|
-
url, _account, seconds_remaining = restart_ngrok(ctx, port)
|
|
75
|
-
end
|
|
73
|
+
url, _ = restart_ngrok(ctx, port)
|
|
76
74
|
ctx.puts(ctx.message("core.tunnel.start", url))
|
|
77
|
-
ctx.puts(ctx.message("core.tunnel.will_timeout", seconds_to_hm(seconds_remaining)))
|
|
78
75
|
ctx.puts(ctx.message("core.tunnel.signup_suggestion", ShopifyCLI::TOOL_NAME))
|
|
79
76
|
end
|
|
80
77
|
url
|
|
@@ -91,7 +88,16 @@ module ShopifyCLI
|
|
|
91
88
|
#
|
|
92
89
|
def auth(ctx, token)
|
|
93
90
|
install(ctx)
|
|
94
|
-
ctx.system(
|
|
91
|
+
ctx.system(ngrok_path(ctx), "authtoken", token)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# returns a boolean: if the user has a ngrok token to authenticate
|
|
96
|
+
#
|
|
97
|
+
def authenticated?
|
|
98
|
+
ngrok_config_path = File.join(Dir.home, ".ngrok2/ngrok.yml")
|
|
99
|
+
return false unless File.exist?(ngrok_config_path)
|
|
100
|
+
File.read(ngrok_config_path).include?("authtoken")
|
|
95
101
|
end
|
|
96
102
|
|
|
97
103
|
##
|
|
@@ -145,7 +151,7 @@ module ShopifyCLI
|
|
|
145
151
|
|
|
146
152
|
def install(ctx)
|
|
147
153
|
ngrok = "ngrok#{ctx.executable_file_extension}"
|
|
148
|
-
return if File.exist?(
|
|
154
|
+
return if File.exist?(ngrok_path(ctx))
|
|
149
155
|
check_prereq_command(ctx, "curl")
|
|
150
156
|
check_prereq_command(ctx, ctx.linux? ? "unzip" : "tar")
|
|
151
157
|
spinner = CLI::UI::SpinGroup.new
|
|
@@ -165,7 +171,7 @@ module ShopifyCLI
|
|
|
165
171
|
spinner.wait
|
|
166
172
|
|
|
167
173
|
# final check to see if ngrok is accessible
|
|
168
|
-
unless File.exist?(
|
|
174
|
+
unless File.exist?(ngrok_path(ctx))
|
|
169
175
|
ctx.abort(ctx.message("core.tunnel.error.ngrok", ngrok, ShopifyCLI.cache_dir))
|
|
170
176
|
end
|
|
171
177
|
end
|
|
@@ -177,8 +183,9 @@ module ShopifyCLI
|
|
|
177
183
|
raise e.class, e.message
|
|
178
184
|
end
|
|
179
185
|
|
|
180
|
-
def
|
|
181
|
-
|
|
186
|
+
def ngrok_path(ctx)
|
|
187
|
+
ngrok = "ngrok#{ctx.executable_file_extension}"
|
|
188
|
+
File.join(ShopifyCLI.cache_dir, ngrok)
|
|
182
189
|
end
|
|
183
190
|
|
|
184
191
|
def seconds_to_hm(seconds)
|
|
@@ -186,16 +193,14 @@ module ShopifyCLI
|
|
|
186
193
|
end
|
|
187
194
|
|
|
188
195
|
def start_ngrok(ctx, port)
|
|
189
|
-
|
|
196
|
+
ngrok_command = "\"#{ngrok_path(ctx)}\" http -inspect=false -log=stdout -log-level=debug #{port}"
|
|
197
|
+
process = ShopifyCLI::ProcessSupervision.start(:ngrok, ngrok_command)
|
|
190
198
|
log = fetch_url(ctx, process.log_path)
|
|
191
|
-
|
|
192
|
-
[log.url, log.account, seconds_remaining]
|
|
199
|
+
[log.url, log.account]
|
|
193
200
|
end
|
|
194
201
|
|
|
195
202
|
def restart_ngrok(ctx, port)
|
|
196
|
-
|
|
197
|
-
ctx.abort(ctx.message("core.tunnel.error.stop"))
|
|
198
|
-
end
|
|
203
|
+
ShopifyCLI::ProcessSupervision.stop(:ngrok)
|
|
199
204
|
start_ngrok(ctx, port)
|
|
200
205
|
end
|
|
201
206
|
|
|
@@ -208,7 +213,7 @@ module ShopifyCLI
|
|
|
208
213
|
class LogParser # :nodoc:
|
|
209
214
|
TIMEOUT = 10
|
|
210
215
|
|
|
211
|
-
attr_reader :url, :account
|
|
216
|
+
attr_reader :url, :account
|
|
212
217
|
|
|
213
218
|
def initialize(log_path)
|
|
214
219
|
@log_path = log_path
|
|
@@ -237,9 +242,8 @@ module ShopifyCLI
|
|
|
237
242
|
end
|
|
238
243
|
|
|
239
244
|
def parse_account
|
|
240
|
-
account,
|
|
245
|
+
account, _ = @log.match(/AccountName:(.*)\s+SessionDuration/)&.captures
|
|
241
246
|
@account = account&.empty? ? nil : account
|
|
242
|
-
@timeout = timeout&.empty? ? 0 : timeout.to_i
|
|
243
247
|
end
|
|
244
248
|
|
|
245
249
|
def error
|
data/lib/shopify_cli/version.rb
CHANGED
data/lib/shopify_cli.rb
CHANGED
|
@@ -111,6 +111,7 @@ module ShopifyCLI
|
|
|
111
111
|
autoload :Feature, "shopify_cli/feature"
|
|
112
112
|
autoload :Form, "shopify_cli/form"
|
|
113
113
|
autoload :Git, "shopify_cli/git"
|
|
114
|
+
autoload :GitHub, "shopify_cli/github"
|
|
114
115
|
autoload :Helpers, "shopify_cli/helpers"
|
|
115
116
|
autoload :Heroku, "shopify_cli/heroku"
|
|
116
117
|
autoload :IdentityAuth, "shopify_cli/identity_auth"
|
|
@@ -123,7 +124,6 @@ module ShopifyCLI
|
|
|
123
124
|
autoload :PartnersAPI, "shopify_cli/partners_api"
|
|
124
125
|
autoload :ProcessSupervision, "shopify_cli/process_supervision"
|
|
125
126
|
autoload :Project, "shopify_cli/project"
|
|
126
|
-
autoload :ProjectCommands, "shopify_cli/project_commands"
|
|
127
127
|
autoload :ProjectType, "shopify_cli/project_type"
|
|
128
128
|
autoload :ReportingConfigurationController, "shopify_cli/reporting_configuration_controller"
|
|
129
129
|
autoload :ResolveConstant, "shopify_cli/resolve_constant"
|
|
@@ -131,7 +131,6 @@ module ShopifyCLI
|
|
|
131
131
|
autoload :Result, "shopify_cli/result"
|
|
132
132
|
autoload :Services, "shopify_cli/services"
|
|
133
133
|
autoload :Shopifolk, "shopify_cli/shopifolk"
|
|
134
|
-
autoload :SubCommand, "shopify_cli/sub_command"
|
|
135
134
|
autoload :Task, "shopify_cli/task"
|
|
136
135
|
autoload :Tasks, "shopify_cli/tasks"
|
|
137
136
|
autoload :TransformDataStructure, "shopify_cli/transform_data_structure"
|
data/shopify-cli.gemspec
CHANGED
data/shopify-dev
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require_relative "./bin/load_shopify"
|
|
4
|
+
|
|
5
|
+
exit(proc do
|
|
6
|
+
begin
|
|
7
|
+
ShopifyCLI::ErrorHandler.call do
|
|
8
|
+
ShopifyCLI::Core::EntryPoint.call(ARGV.dup)
|
|
9
|
+
end
|
|
10
|
+
rescue StandardError => error
|
|
11
|
+
ShopifyCLI::ErrorHandler.exception = error
|
|
12
|
+
if ShopifyCLI::Environment.print_stacktrace?
|
|
13
|
+
raise error
|
|
14
|
+
else
|
|
15
|
+
1
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end.call)
|
|
@@ -79,12 +79,19 @@ module Utilities
|
|
|
79
79
|
if ARGV.include?("--verbose")
|
|
80
80
|
stat = Open3.popen3(*command) do |stdin, stdout, stderr, wait_thread|
|
|
81
81
|
Thread.new do
|
|
82
|
-
stdout.each { |l| STDOUT.puts("#{docker_prefix.colorize(:cyan).bold} #{l}") }
|
|
83
|
-
|
|
82
|
+
stdout.each { |l| STDOUT.puts("#{docker_prefix.colorize(:cyan).bold} #{l}") } unless stdout&.nil?
|
|
83
|
+
end
|
|
84
|
+
Thread.new do
|
|
85
|
+
stderr.each { |l| STDERR.puts("#{docker_prefix.colorize(:red).bold} #{l}") } unless stderr&.nil?
|
|
84
86
|
end
|
|
85
87
|
stdin.close
|
|
86
88
|
|
|
87
|
-
wait_thread.value
|
|
89
|
+
status = wait_thread.value
|
|
90
|
+
|
|
91
|
+
stdout.close
|
|
92
|
+
stderr.close
|
|
93
|
+
|
|
94
|
+
status
|
|
88
95
|
end
|
|
89
96
|
raise StandardError, "The command #{args.first} failed" unless stat.success?
|
|
90
97
|
else
|