shopify-cli 2.15.1 → 2.15.4
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/.vscode/settings.json +1 -2
- data/CHANGELOG.md +68 -20
- data/Gemfile.lock +1 -1
- data/Rakefile +21 -0
- data/ext/javy/hashes/javy-arm-macos-v0.3.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-linux-v0.3.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-macos-v0.3.0.gz.sha256 +1 -0
- data/ext/javy/hashes/javy-x86_64-windows-v0.3.0.gz.sha256 +1 -0
- data/ext/javy/version +1 -1
- data/ext/shopify-extensions/version +1 -1
- data/lib/project_types/extension/cli.rb +4 -0
- data/lib/project_types/extension/commands/check.rb +6 -1
- data/lib/project_types/extension/forms/questions/ask_template.rb +1 -2
- data/lib/project_types/extension/messages/messages.rb +1 -3
- data/lib/project_types/extension/models/development_server_requirements.rb +1 -0
- data/lib/project_types/extension/models/specification_handlers/beacon_extension.rb +57 -0
- data/lib/project_types/extension/models/specification_handlers/beacon_extension_utils/script_config.rb +33 -0
- data/lib/project_types/extension/models/specification_handlers/beacon_extension_utils/script_config_repository.rb +75 -0
- data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +16 -1
- data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +4 -1
- data/lib/project_types/extension/tasks/configure_options.rb +2 -1
- data/lib/project_types/extension/tasks/convert_server_config.rb +13 -2
- data/lib/project_types/extension/tasks/merge_server_config.rb +5 -2
- data/lib/project_types/script/cli.rb +1 -0
- data/lib/project_types/script/layers/application/create_script.rb +14 -6
- data/lib/project_types/script/layers/infrastructure/errors.rb +17 -0
- data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +6 -21
- data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
- data/lib/project_types/script/layers/infrastructure/sparse_checkout_details.rb +35 -0
- data/lib/project_types/script/messages/messages.rb +3 -0
- data/lib/project_types/script/ui/error_handler.rb +11 -0
- data/lib/project_types/theme/cli.rb +1 -0
- data/lib/project_types/theme/commands/check.rb +4 -1
- data/lib/project_types/theme/commands/open.rb +2 -2
- data/lib/project_types/theme/commands/push.rb +1 -3
- data/lib/project_types/theme/commands/serve.rb +1 -0
- data/lib/project_types/theme/commands/share.rb +56 -0
- data/lib/project_types/theme/messages/messages.rb +64 -11
- data/lib/shopify_cli/changelog.rb +97 -25
- data/lib/shopify_cli/command_options/command_serve_options.rb +10 -0
- data/lib/shopify_cli/commands/app/serve.rb +7 -7
- data/lib/shopify_cli/commands/login.rb +5 -2
- data/lib/shopify_cli/context.rb +13 -0
- data/lib/shopify_cli/git.rb +36 -0
- data/lib/shopify_cli/identity_auth.rb +24 -4
- data/lib/shopify_cli/messages/messages.rb +22 -11
- data/lib/shopify_cli/release.rb +120 -20
- data/lib/shopify_cli/services/app/create/rails_service.rb +9 -1
- data/lib/shopify_cli/services/app/serve/node_service.rb +2 -25
- data/lib/shopify_cli/services/app/serve/php_service.rb +2 -25
- data/lib/shopify_cli/services/app/serve/rails_service.rb +8 -28
- data/lib/shopify_cli/services/app/serve/serve_service.rb +57 -0
- data/lib/shopify_cli/services.rb +1 -0
- data/lib/shopify_cli/tasks/update_dashboard_urls.rb +7 -9
- data/lib/shopify_cli/theme/dev_server/hot-reload.js +40 -13
- data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +1 -1
- data/lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb +51 -0
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +6 -1
- data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
- data/lib/shopify_cli/theme/dev_server/remote_watcher/json_files_update_job.rb +35 -0
- data/lib/shopify_cli/theme/dev_server/remote_watcher.rb +44 -0
- data/lib/shopify_cli/theme/dev_server/watcher.rb +2 -8
- data/lib/shopify_cli/theme/dev_server.rb +18 -5
- data/lib/shopify_cli/theme/file.rb +15 -4
- data/lib/shopify_cli/theme/syncer/checksums.rb +60 -0
- data/lib/shopify_cli/theme/syncer/forms/apply_to_all.rb +39 -0
- data/lib/shopify_cli/theme/syncer/forms/apply_to_all_form.rb +35 -0
- data/lib/shopify_cli/theme/syncer/forms/base_strategy_form.rb +62 -0
- data/lib/shopify_cli/theme/syncer/forms/select_delete_strategy.rb +27 -0
- data/lib/shopify_cli/theme/syncer/forms/select_update_strategy.rb +28 -0
- data/lib/shopify_cli/theme/syncer/ignore_helper.rb +33 -0
- data/lib/shopify_cli/theme/syncer/json_delete_handler.rb +51 -0
- data/lib/shopify_cli/theme/syncer/json_update_handler.rb +82 -0
- data/lib/shopify_cli/theme/syncer/merger.rb +53 -0
- data/lib/shopify_cli/theme/syncer/operation.rb +1 -1
- data/lib/shopify_cli/theme/syncer.rb +79 -63
- data/lib/shopify_cli/theme/theme.rb +21 -7
- data/lib/shopify_cli/theme/theme_admin_api.rb +23 -8
- data/lib/shopify_cli/thread_pool/job.rb +10 -2
- data/lib/shopify_cli/thread_pool.rb +15 -3
- data/lib/shopify_cli/tunnel.rb +3 -13
- data/lib/shopify_cli/version.rb +1 -1
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +8 -0
- metadata +25 -2
|
@@ -23,19 +23,23 @@ module Script
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
# remove the need to pass the whole extension-point object to the infra layer
|
|
26
|
-
sparse_checkout_repo = extension_point.libraries.for(language).repo
|
|
27
26
|
type = extension_point.dasherize_type
|
|
28
27
|
domain = extension_point.domain
|
|
29
28
|
|
|
29
|
+
sparse_checkout_details = Infrastructure::SparseCheckoutDetails.new(
|
|
30
|
+
repo: extension_point.libraries.for(language).repo,
|
|
31
|
+
branch: sparse_checkout_branch,
|
|
32
|
+
path: "#{domain}/#{language}/#{type}/default",
|
|
33
|
+
input_queries_enabled: input_queries_enabled?,
|
|
34
|
+
)
|
|
35
|
+
|
|
30
36
|
project_creator = Infrastructure::Languages::ProjectCreator.for(
|
|
31
37
|
ctx: ctx,
|
|
32
38
|
language: language,
|
|
33
39
|
type: type,
|
|
34
40
|
project_name: title,
|
|
35
41
|
path_to_project: project.id,
|
|
36
|
-
|
|
37
|
-
sparse_checkout_branch: sparse_checkout_branch,
|
|
38
|
-
sparse_checkout_set_path: "#{domain}/#{language}/#{type}/default"
|
|
42
|
+
sparse_checkout_details: sparse_checkout_details,
|
|
39
43
|
)
|
|
40
44
|
|
|
41
45
|
install_dependencies(ctx, language, title, project_creator)
|
|
@@ -49,12 +53,12 @@ module Script
|
|
|
49
53
|
task_runner = Infrastructure::Languages::TaskRunner.for(ctx, language)
|
|
50
54
|
CLI::UI::Frame.open(ctx.message(
|
|
51
55
|
"core.git.pulling_from_to",
|
|
52
|
-
project_creator.
|
|
56
|
+
project_creator.sparse_checkout_details.repo,
|
|
53
57
|
title,
|
|
54
58
|
)) do
|
|
55
59
|
UI::StrictSpinner.spin(ctx.message(
|
|
56
60
|
"core.git.pulling",
|
|
57
|
-
project_creator.
|
|
61
|
+
project_creator.sparse_checkout_details.repo,
|
|
58
62
|
title,
|
|
59
63
|
)) do |spinner|
|
|
60
64
|
project_creator.setup_dependencies
|
|
@@ -75,6 +79,10 @@ module Script
|
|
|
75
79
|
ensure
|
|
76
80
|
script_project_repo.change_to_initial_directory
|
|
77
81
|
end
|
|
82
|
+
|
|
83
|
+
def input_queries_enabled?
|
|
84
|
+
ShopifyCLI::Feature.enabled?(:scripts_beta_input_queries)
|
|
85
|
+
end
|
|
78
86
|
end
|
|
79
87
|
end
|
|
80
88
|
end
|
|
@@ -180,6 +180,23 @@ module Script
|
|
|
180
180
|
@max_size = max_size
|
|
181
181
|
end
|
|
182
182
|
end
|
|
183
|
+
|
|
184
|
+
class InvalidInputQueryErrors < ScriptProjectError
|
|
185
|
+
attr_reader :messages
|
|
186
|
+
|
|
187
|
+
def initialize(messages)
|
|
188
|
+
@messages = messages
|
|
189
|
+
super()
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def input_query_path
|
|
193
|
+
ScriptProjectRepository::INPUT_QUERY_PATH
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def message
|
|
197
|
+
messages.join("\n")
|
|
198
|
+
end
|
|
199
|
+
end
|
|
183
200
|
end
|
|
184
201
|
end
|
|
185
202
|
end
|
|
@@ -10,9 +10,7 @@ module Script
|
|
|
10
10
|
property! :type, accepts: String
|
|
11
11
|
property! :project_name, accepts: String
|
|
12
12
|
property! :path_to_project, accepts: String
|
|
13
|
-
property! :
|
|
14
|
-
property! :sparse_checkout_branch, accepts: String
|
|
15
|
-
property! :sparse_checkout_set_path, accepts: String
|
|
13
|
+
property! :sparse_checkout_details, accepts: SparseCheckoutDetails
|
|
16
14
|
|
|
17
15
|
def self.for(
|
|
18
16
|
ctx:,
|
|
@@ -20,9 +18,7 @@ module Script
|
|
|
20
18
|
type:,
|
|
21
19
|
project_name:,
|
|
22
20
|
path_to_project:,
|
|
23
|
-
|
|
24
|
-
sparse_checkout_branch:,
|
|
25
|
-
sparse_checkout_set_path:
|
|
21
|
+
sparse_checkout_details:
|
|
26
22
|
)
|
|
27
23
|
|
|
28
24
|
project_creators = {
|
|
@@ -36,33 +32,22 @@ module Script
|
|
|
36
32
|
type: type,
|
|
37
33
|
project_name: project_name,
|
|
38
34
|
path_to_project: path_to_project,
|
|
39
|
-
|
|
40
|
-
sparse_checkout_branch: sparse_checkout_branch,
|
|
41
|
-
sparse_checkout_set_path: sparse_checkout_set_path
|
|
35
|
+
sparse_checkout_details: sparse_checkout_details,
|
|
42
36
|
)
|
|
43
37
|
end
|
|
44
38
|
|
|
45
39
|
# the sparse checkout process is common to all script types
|
|
46
40
|
def setup_dependencies
|
|
47
|
-
|
|
41
|
+
sparse_checkout_details.setup(ctx)
|
|
48
42
|
clean
|
|
49
43
|
end
|
|
50
44
|
|
|
51
45
|
private
|
|
52
46
|
|
|
53
|
-
def setup_sparse_checkout
|
|
54
|
-
ShopifyCLI::Git.sparse_checkout(
|
|
55
|
-
sparse_checkout_repo,
|
|
56
|
-
sparse_checkout_set_path,
|
|
57
|
-
sparse_checkout_branch,
|
|
58
|
-
ctx
|
|
59
|
-
)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
47
|
def clean
|
|
63
|
-
source = File.join(path_to_project,
|
|
48
|
+
source = File.join(path_to_project, sparse_checkout_details.path, ".")
|
|
64
49
|
FileUtils.cp_r(source, path_to_project)
|
|
65
|
-
ctx.rm_rf(
|
|
50
|
+
ctx.rm_rf(sparse_checkout_details.path.split("/")[0])
|
|
66
51
|
ctx.rm_rf(".git")
|
|
67
52
|
end
|
|
68
53
|
|
|
@@ -83,6 +83,8 @@ module Script
|
|
|
83
83
|
valid_types: e["message"],
|
|
84
84
|
filename: script_config.filename,
|
|
85
85
|
)
|
|
86
|
+
elsif (errors = user_errors.filter { |err| err["tag"] == "input_query_validation_error" }).any?
|
|
87
|
+
raise Errors::InvalidInputQueryErrors, errors.map { |err| err["message"] }
|
|
86
88
|
elsif user_errors.find { |err| %w(not_use_msgpack_error schema_version_argument_error).include?(err["tag"]) }
|
|
87
89
|
raise Domain::Errors::MetadataValidationError
|
|
88
90
|
else
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Script
|
|
4
|
+
module Layers
|
|
5
|
+
module Infrastructure
|
|
6
|
+
class SparseCheckoutDetails
|
|
7
|
+
include SmartProperties
|
|
8
|
+
property! :repo, accepts: String
|
|
9
|
+
property! :branch, accepts: String
|
|
10
|
+
property! :path, accepts: String
|
|
11
|
+
property! :input_queries_enabled, accepts: [true, false]
|
|
12
|
+
|
|
13
|
+
def ==(other)
|
|
14
|
+
self.class == other.class &&
|
|
15
|
+
self.class.properties.all? { |name, _| self[name] == other[name] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def setup(ctx)
|
|
19
|
+
ShopifyCLI::Git.sparse_checkout(repo, patterns_to_checkout, branch, ctx)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def patterns_to_checkout
|
|
25
|
+
paths = [path]
|
|
26
|
+
unless input_queries_enabled
|
|
27
|
+
paths << "!#{path}/#{ScriptProjectRepository::INPUT_QUERY_PATH}"
|
|
28
|
+
paths << "!#{path}/schema.graphql"
|
|
29
|
+
end
|
|
30
|
+
paths.join(" ")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -86,6 +86,9 @@ module Script
|
|
|
86
86
|
"type(s): %{valid_types}.",
|
|
87
87
|
configuration_schema_field_invalid_value_error_help: "Change the value of the type.",
|
|
88
88
|
|
|
89
|
+
input_query_error_cause: "Input query is invalid:\n%{messages}\n\n",
|
|
90
|
+
input_query_error_help: "Fix the query in the `%{input_query_path}` file.",
|
|
91
|
+
|
|
89
92
|
script_not_found_cause: "Can't find script %s for Script API %s",
|
|
90
93
|
|
|
91
94
|
system_call_failure_cause: "Something went wrong while running: {{command:%{cmd}}}.",
|
|
@@ -216,6 +216,17 @@ module Script
|
|
|
216
216
|
"script.error.configuration_schema_field_invalid_value_error_help"
|
|
217
217
|
),
|
|
218
218
|
}
|
|
219
|
+
when Layers::Infrastructure::Errors::InvalidInputQueryErrors
|
|
220
|
+
{
|
|
221
|
+
cause_of_error: ShopifyCLI::Context.message(
|
|
222
|
+
"script.error.input_query_error_cause",
|
|
223
|
+
messages: e.messages.map { |message| " {{x}} #{message}." }.join("\n"),
|
|
224
|
+
),
|
|
225
|
+
help_suggestion: ShopifyCLI::Context.message(
|
|
226
|
+
"script.error.input_query_error_help",
|
|
227
|
+
input_query_path: e.input_query_path,
|
|
228
|
+
),
|
|
229
|
+
}
|
|
219
230
|
when Layers::Infrastructure::Errors::DependencyInstallError
|
|
220
231
|
{
|
|
221
232
|
cause_of_error: ShopifyCLI::Context.message("script.error.dependency_install_cause"),
|
|
@@ -16,6 +16,7 @@ module Theme
|
|
|
16
16
|
subcommand :Package, "package", Project.project_filepath("commands/package")
|
|
17
17
|
subcommand :Open, "open", Project.project_filepath("commands/open")
|
|
18
18
|
subcommand :List, "list", Project.project_filepath("commands/list")
|
|
19
|
+
subcommand :Share, "share", Project.project_filepath("commands/share")
|
|
19
20
|
subcommand :LanguageServer, "language-server", Project.project_filepath("commands/language_server")
|
|
20
21
|
end
|
|
21
22
|
ShopifyCLI::Commands.register("Theme::Command", "theme")
|
|
@@ -24,7 +24,10 @@ module Theme
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def call(*)
|
|
27
|
-
@theme_check.run
|
|
27
|
+
@theme_check.run!
|
|
28
|
+
rescue ThemeCheck::Cli::Abort, ThemeCheck::ThemeCheckError => e
|
|
29
|
+
raise ShopifyCLI::Abort,
|
|
30
|
+
ShopifyCLI::Context.message("theme.check.error", e.full_message)
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
def self.help
|
|
@@ -17,8 +17,8 @@ module Theme
|
|
|
17
17
|
def call(_args, _name)
|
|
18
18
|
theme = find_theme(**options.flags)
|
|
19
19
|
|
|
20
|
-
@ctx.puts(@ctx.message("theme.open.details", theme.name, theme.editor_url))
|
|
21
|
-
@ctx.
|
|
20
|
+
@ctx.puts(@ctx.message("theme.open.details", theme.name, theme.preview_url, theme.editor_url))
|
|
21
|
+
@ctx.open_browser_url!(theme.preview_url)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def self.help
|
|
@@ -104,9 +104,7 @@ module Theme
|
|
|
104
104
|
|
|
105
105
|
if unpublished
|
|
106
106
|
name = theme || ask_theme_name
|
|
107
|
-
|
|
108
|
-
new_theme.create
|
|
109
|
-
return new_theme
|
|
107
|
+
return ShopifyCLI::Theme::Theme.create_unpublished(@ctx, root: root, name: name)
|
|
110
108
|
end
|
|
111
109
|
|
|
112
110
|
if theme
|
|
@@ -16,6 +16,7 @@ module Theme
|
|
|
16
16
|
parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
|
|
17
17
|
parser.on("--poll") { flags[:poll] = true }
|
|
18
18
|
parser.on("--live-reload=MODE") { |mode| flags[:mode] = as_reload_mode(mode) }
|
|
19
|
+
parser.on("--theme-editor-sync") { flags[:editor_sync] = true }
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def call(_args, name)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "shopify_cli/theme/theme"
|
|
4
|
+
require "shopify_cli/theme/syncer"
|
|
5
|
+
require "project_types/theme/commands/common/root_helper"
|
|
6
|
+
|
|
7
|
+
module Theme
|
|
8
|
+
class Command
|
|
9
|
+
class Share < ShopifyCLI::Command::SubCommand
|
|
10
|
+
include Common::RootHelper
|
|
11
|
+
|
|
12
|
+
recommend_default_ruby_range
|
|
13
|
+
|
|
14
|
+
def call(_args, name)
|
|
15
|
+
root = root_value(options, name)
|
|
16
|
+
theme = create_theme(root)
|
|
17
|
+
|
|
18
|
+
upload(theme)
|
|
19
|
+
|
|
20
|
+
@ctx.done(done_message(theme))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.help
|
|
24
|
+
tool = ShopifyCLI::TOOL_NAME
|
|
25
|
+
@ctx.message("theme.share.help", tool, tool)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def create_theme(root)
|
|
31
|
+
ShopifyCLI::Theme::Theme.create_unpublished(@ctx, root: root)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def upload(theme)
|
|
35
|
+
syncer = ShopifyCLI::Theme::Syncer.new(@ctx, theme: theme)
|
|
36
|
+
syncer.start_threads
|
|
37
|
+
|
|
38
|
+
CLI::UI::Frame.open(upload_message(theme)) do
|
|
39
|
+
UI::SyncProgressBar.new(syncer).progress(:upload_theme!)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
raise ShopifyCLI::AbortSilent if syncer.has_any_error?
|
|
43
|
+
ensure
|
|
44
|
+
syncer.shutdown
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def upload_message(theme)
|
|
48
|
+
@ctx.message("theme.share.upload", theme.name, theme.id, theme.shop)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def done_message(theme)
|
|
52
|
+
@ctx.message("theme.share.done", theme.name, theme.preview_url, theme.editor_url)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -8,8 +8,9 @@ module Theme
|
|
|
8
8
|
Usage: {{command:%1$s theme [ %2$s ]}}
|
|
9
9
|
HELP
|
|
10
10
|
ensure_user_error: "You are not authorized to edit themes on %s.",
|
|
11
|
-
ensure_user_try_this:
|
|
12
|
-
|
|
11
|
+
ensure_user_try_this: <<~ENSURE_USER,
|
|
12
|
+
Check if your user is activated, has permission to edit themes at the store, and try to re-login.
|
|
13
|
+
ENSURE_USER
|
|
13
14
|
init: {
|
|
14
15
|
help: <<~HELP,
|
|
15
16
|
{{command:%s theme init}}: Clones a Git repository to use as a starting point for building a new theme.
|
|
@@ -101,13 +102,14 @@ module Theme
|
|
|
101
102
|
Usage: {{command:%s theme serve [ ROOT ]}}
|
|
102
103
|
|
|
103
104
|
Options:
|
|
104
|
-
{{command:--port=PORT}}
|
|
105
|
-
{{command:--poll}}
|
|
106
|
-
{{command:--host=HOST}}
|
|
107
|
-
{{command:--
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
{{command:--port=PORT}} Local port to serve theme preview from.
|
|
106
|
+
{{command:--poll}} Force polling to detect file changes.
|
|
107
|
+
{{command:--host=HOST}} Set which network interface the web server listens on. The default value is 127.0.0.1.
|
|
108
|
+
{{command:--theme-editor-sync}} Synchronize Theme Editor updates in the local theme files.
|
|
109
|
+
{{command:--live-reload=MODE}} The live reload mode switches the server behavior when a file is modified:
|
|
110
|
+
- {{command:hot-reload}} Hot reloads local changes to CSS and sections (default)
|
|
111
|
+
- {{command:full-page}} Always refreshes the entire page
|
|
112
|
+
- {{command:off}} Deactivate live reload
|
|
111
113
|
HELP
|
|
112
114
|
reload_mode_is_not_valid: "The live reload mode `%s` is not valid.",
|
|
113
115
|
try_a_valid_reload_mode: "Try a valid live reload mode: %s.",
|
|
@@ -121,6 +123,36 @@ module Theme
|
|
|
121
123
|
fixed: "Fixed",
|
|
122
124
|
},
|
|
123
125
|
},
|
|
126
|
+
syncer: {
|
|
127
|
+
forms: {
|
|
128
|
+
apply_to_all: {
|
|
129
|
+
title: "Would like apply this to all the other %s files?",
|
|
130
|
+
yes: "Yes",
|
|
131
|
+
no: "No",
|
|
132
|
+
},
|
|
133
|
+
update_strategy: {
|
|
134
|
+
title_context: <<~TITLE,
|
|
135
|
+
|
|
136
|
+
The local file {{command:%s}} is different from the remote version in the development theme."
|
|
137
|
+
TITLE
|
|
138
|
+
title_question: "What would you like to do?",
|
|
139
|
+
keep_remote: "Keep the remote version",
|
|
140
|
+
keep_local: "Keep the local version",
|
|
141
|
+
union_merge: "Merge files (it may break the local file)",
|
|
142
|
+
exit: "Exit",
|
|
143
|
+
},
|
|
144
|
+
delete_strategy: {
|
|
145
|
+
title_context: <<~TITLE,
|
|
146
|
+
|
|
147
|
+
The local file {{command:%s}} has been recently removed, but it's present on your remote development theme.",
|
|
148
|
+
TITLE
|
|
149
|
+
title_question: "What would you like to do?",
|
|
150
|
+
delete: "Delete permanently",
|
|
151
|
+
restore: "Restore with the remote version",
|
|
152
|
+
exit: "Exit",
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
124
156
|
error: {
|
|
125
157
|
address_binding_error: "Couldn't bind to localhost."\
|
|
126
158
|
" To serve your theme, set a different address with {{command:%s theme serve --host=<address>}}",
|
|
@@ -137,9 +169,10 @@ module Theme
|
|
|
137
169
|
Serving %s
|
|
138
170
|
|
|
139
171
|
SERVING
|
|
172
|
+
download_changes: ", and use 'theme pull' to get the changes",
|
|
140
173
|
customize_or_preview: <<~CUSTOMIZE_OR_PREVIEW,
|
|
141
174
|
|
|
142
|
-
Customize this theme in the Theme Editor:
|
|
175
|
+
Customize this theme in the Theme Editor%s:
|
|
143
176
|
{{green:%s}}
|
|
144
177
|
|
|
145
178
|
Share this theme preview:
|
|
@@ -149,7 +182,7 @@ module Theme
|
|
|
149
182
|
CUSTOMIZE_OR_PREVIEW
|
|
150
183
|
ensure_user: <<~ENSURE_USER,
|
|
151
184
|
You are not authorized to edit themes on %s.
|
|
152
|
-
|
|
185
|
+
Check if your user is activated, has permission to edit themes at the store, and try to re-login.
|
|
153
186
|
ENSURE_USER
|
|
154
187
|
address_already_in_use: "The address \"%s\" is already in use.",
|
|
155
188
|
try_port_option: "Use the --port=PORT option to serve the theme in a different port.",
|
|
@@ -159,6 +192,7 @@ module Theme
|
|
|
159
192
|
Check your theme for errors, suggestions, and best practices.
|
|
160
193
|
Usage: {{command:%s check}}
|
|
161
194
|
HELP
|
|
195
|
+
error: "Theme check failed with error:\n%s",
|
|
162
196
|
},
|
|
163
197
|
delete: {
|
|
164
198
|
help: <<~HELP,
|
|
@@ -230,6 +264,9 @@ module Theme
|
|
|
230
264
|
details: <<~DETAILS,
|
|
231
265
|
{{*}} {{bold:%s}}
|
|
232
266
|
|
|
267
|
+
Preview your theme:
|
|
268
|
+
{{green:%s}}
|
|
269
|
+
|
|
233
270
|
Customize your theme in the Theme Editor:
|
|
234
271
|
{{green:%s}}
|
|
235
272
|
|
|
@@ -253,6 +290,22 @@ module Theme
|
|
|
253
290
|
Usage: {{command:%s theme list}}
|
|
254
291
|
HELP
|
|
255
292
|
},
|
|
293
|
+
share: {
|
|
294
|
+
help: <<~HELP,
|
|
295
|
+
{{command:%s theme share}}: Creates a shareable, unpublished, and new theme on your theme library with a randomized name.
|
|
296
|
+
Works like an alias to {{command:theme push -u -t=RANDOMIZED_NAME}}.
|
|
297
|
+
|
|
298
|
+
Usage: {{command:%s theme share [ ROOT ]}}
|
|
299
|
+
HELP
|
|
300
|
+
done: <<~DONE,
|
|
301
|
+
{{green:The {{bold:%s}} theme was pushed successfully}}
|
|
302
|
+
|
|
303
|
+
{{info:Share your theme preview:}}
|
|
304
|
+
{{underline:%s}}
|
|
305
|
+
|
|
306
|
+
DONE
|
|
307
|
+
upload: "Pushing theme files to %s (#%s) on %s",
|
|
308
|
+
},
|
|
256
309
|
},
|
|
257
310
|
}.freeze
|
|
258
311
|
end
|
|
@@ -1,23 +1,32 @@
|
|
|
1
|
+
require "date"
|
|
1
2
|
require "shopify_cli/sed"
|
|
3
|
+
require "octokit"
|
|
2
4
|
|
|
3
5
|
module ShopifyCLI
|
|
4
6
|
class Changelog
|
|
5
7
|
CHANGELOG_FILE = File.join(ShopifyCLI::ROOT, "CHANGELOG.md")
|
|
8
|
+
CHANGE_CATEGORIES = %w(Added Changed Deprecated Removed Fixed Security)
|
|
6
9
|
|
|
7
10
|
def initialize
|
|
8
11
|
load(File.read(CHANGELOG_FILE))
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
def update_version!(new_version)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
changes[new_version] = changes["Unreleased"]
|
|
16
|
+
changes[new_version][:date] = Date.today.iso8601
|
|
17
|
+
changes["Unreleased"] = { changes: [], date: nil }
|
|
18
|
+
save!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update!
|
|
22
|
+
pr = pr_for_current_branch
|
|
23
|
+
category = CLI::UI::Prompt.ask("What type of change?", options: CHANGE_CATEGORIES)
|
|
24
|
+
add_change(category, { pr_id: pr.number, desc: pr.title })
|
|
25
|
+
save!
|
|
17
26
|
end
|
|
18
27
|
|
|
19
28
|
def release_notes(version)
|
|
20
|
-
changes[version].map do |change_category, changes|
|
|
29
|
+
changes[version][:changes].map do |change_category, changes|
|
|
21
30
|
<<~CHANGES
|
|
22
31
|
### #{change_category}
|
|
23
32
|
#{changes.map { |change| entry(**change) }.join("\n")}
|
|
@@ -25,17 +34,61 @@ module ShopifyCLI
|
|
|
25
34
|
end.join("\n")
|
|
26
35
|
end
|
|
27
36
|
|
|
37
|
+
def add_change(category, change)
|
|
38
|
+
changes["Unreleased"][:changes][category] << change
|
|
39
|
+
end
|
|
40
|
+
|
|
28
41
|
def entry(pr_id:, desc:)
|
|
29
42
|
"* [##{pr_id}](https://github.com/Shopify/shopify-cli/pull/#{pr_id}): #{desc}"
|
|
30
43
|
end
|
|
31
44
|
|
|
45
|
+
def full_contents
|
|
46
|
+
sorted_changes = changes.each_key.sort_by do |change|
|
|
47
|
+
if change == "Unreleased"
|
|
48
|
+
[Float::INFINITY] * 3 # end of the list
|
|
49
|
+
else
|
|
50
|
+
major, minor, patch = change.split(".").map(&:to_i)
|
|
51
|
+
[major, minor, patch]
|
|
52
|
+
end
|
|
53
|
+
end.reverse
|
|
54
|
+
[
|
|
55
|
+
heading,
|
|
56
|
+
*sorted_changes.each.map { |version| release_notes_with_header(version) }.join,
|
|
57
|
+
remainder,
|
|
58
|
+
].map { |section| section.chomp << "\n" }.join
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def save!
|
|
62
|
+
File.write(CHANGELOG_FILE, full_contents)
|
|
63
|
+
end
|
|
64
|
+
|
|
32
65
|
private
|
|
33
66
|
|
|
67
|
+
attr_reader :heading, :remainder
|
|
68
|
+
|
|
69
|
+
def release_notes_with_header(version)
|
|
70
|
+
header_line =
|
|
71
|
+
if version == "Unreleased"
|
|
72
|
+
"[Unreleased]"
|
|
73
|
+
else
|
|
74
|
+
date = changes[version][:date]
|
|
75
|
+
"Version #{version}#{" - #{date}" if date}"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
[
|
|
79
|
+
"## #{header_line}",
|
|
80
|
+
release_notes(version),
|
|
81
|
+
].reject(&:empty?).map { |section| section.chomp << "\n\n" }.join
|
|
82
|
+
end
|
|
83
|
+
|
|
34
84
|
def changes
|
|
35
85
|
@changes ||= Hash.new do |h, k|
|
|
36
|
-
h[k] =
|
|
37
|
-
|
|
38
|
-
|
|
86
|
+
h[k] = {
|
|
87
|
+
date: nil,
|
|
88
|
+
changes: Hash.new do |h2, k2|
|
|
89
|
+
h2[k2] = []
|
|
90
|
+
end,
|
|
91
|
+
}
|
|
39
92
|
end
|
|
40
93
|
end
|
|
41
94
|
|
|
@@ -43,34 +96,53 @@ module ShopifyCLI
|
|
|
43
96
|
state = :initial
|
|
44
97
|
change_category = nil
|
|
45
98
|
current_version = nil
|
|
99
|
+
@heading = ""
|
|
46
100
|
@remainder = ""
|
|
47
101
|
log.each_line do |line|
|
|
48
102
|
case state
|
|
49
103
|
when :initial
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
104
|
+
if line.chomp == "\#\# [Unreleased]"
|
|
105
|
+
state = :unreleased
|
|
106
|
+
current_version = "Unreleased"
|
|
107
|
+
# Ensure Unreleased changeset exists even if no changes have happened yet
|
|
108
|
+
changes["Unreleased"]
|
|
109
|
+
else
|
|
110
|
+
@heading << line
|
|
111
|
+
end
|
|
112
|
+
when :unreleased, :prior_versions
|
|
54
113
|
if /\A\#\#\# (?<category>\w+)/ =~ line
|
|
55
114
|
change_category = category
|
|
56
|
-
elsif %r{\A\* \[\#(?<
|
|
57
|
-
changes[current_version][change_category] << { pr_id:
|
|
58
|
-
elsif /\A\#\# Version (?<version>\d+\.\d+\.\d+)
|
|
115
|
+
elsif %r{\A\* \[\#(?<id>\d+)\]\(https://github.com/Shopify/shopify-cli/pull/\k<id>\): (?<desc>.+)\n} =~ line
|
|
116
|
+
changes[current_version][:changes][change_category] << { pr_id: id, desc: desc }
|
|
117
|
+
elsif /\A\#\# Version (?<version>\d+\.\d+\.\d+)( - (?<date>\d{4}-\d{2}-\d{2}))?/ =~ line
|
|
59
118
|
current_version = version
|
|
60
|
-
state =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
119
|
+
state = :prior_versions
|
|
120
|
+
major, minor, _patch = current_version.split(".")
|
|
121
|
+
if major.to_i <= 2 && minor.to_i < 7
|
|
122
|
+
# Changelog starts to become irregular in 2.6.x
|
|
123
|
+
state = :finished
|
|
124
|
+
end
|
|
125
|
+
changes[current_version][:date] = date unless state == :finished
|
|
67
126
|
elsif !line.match?(/\s*\n/)
|
|
68
127
|
raise "Unrecognized line: #{line.inspect}"
|
|
69
128
|
end
|
|
70
|
-
when :finished
|
|
71
|
-
@remainder << line
|
|
72
129
|
end
|
|
130
|
+
@remainder << line if state == :finished
|
|
73
131
|
end
|
|
74
132
|
end
|
|
133
|
+
|
|
134
|
+
def pr_for_current_branch
|
|
135
|
+
current_branch = %x(git branch --show-current).chomp
|
|
136
|
+
search_term = "repo:Shopify/shopify-cli is:pr is:open head:#{current_branch}"
|
|
137
|
+
results = Octokit::Client.new.search_issues(search_term)
|
|
138
|
+
case results.total_count
|
|
139
|
+
when 0
|
|
140
|
+
raise "PR not opened yet!"
|
|
141
|
+
when (2..)
|
|
142
|
+
raise "Multiple open PRs, not sure which one to use for changelog!"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
results.items.first
|
|
146
|
+
end
|
|
75
147
|
end
|
|
76
148
|
end
|
|
@@ -20,6 +20,10 @@ module ShopifyCLI
|
|
|
20
20
|
end
|
|
21
21
|
host
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
def no_update
|
|
25
|
+
options.flags[:no_update] || false
|
|
26
|
+
end
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
|
|
@@ -37,6 +41,12 @@ module ShopifyCLI
|
|
|
37
41
|
parser.on("--port=PORT") { |port| flags[:port] = port }
|
|
38
42
|
end
|
|
39
43
|
end
|
|
44
|
+
|
|
45
|
+
def parse_no_update_option
|
|
46
|
+
options do |parser, flags|
|
|
47
|
+
parser.on("--no-update") { flags[:no_update] = true }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
40
50
|
end
|
|
41
51
|
end
|
|
42
52
|
end
|