shopify-cli 2.11.0 → 2.11.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 +7 -1
- data/Gemfile.lock +1 -1
- data/lib/project_types/extension/commands/push.rb +13 -0
- data/lib/project_types/extension/loaders/project.rb +28 -8
- data/lib/project_types/extension/messages/messages.rb +10 -2
- 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/infrastructure/languages/assemblyscript_task_runner.rb +1 -8
- data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +35 -9
- data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +1 -8
- data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +3 -7
- data/lib/project_types/script/messages/messages.rb +6 -6
- data/lib/project_types/theme/commands/check.rb +0 -1
- data/lib/project_types/theme/commands/delete.rb +0 -1
- data/lib/project_types/theme/commands/init.rb +0 -1
- data/lib/project_types/theme/commands/language_server.rb +0 -1
- data/lib/project_types/theme/commands/package.rb +0 -1
- data/lib/project_types/theme/commands/publish.rb +0 -1
- data/lib/project_types/theme/commands/pull.rb +0 -1
- data/lib/project_types/theme/commands/push.rb +0 -1
- data/lib/project_types/theme/commands/serve.rb +0 -1
- data/lib/shopify_cli/command.rb +9 -3
- data/lib/shopify_cli/commands/app/create/rails.rb +1 -1
- data/lib/shopify_cli/commands/app/create.rb +0 -3
- data/lib/shopify_cli/commands/app/deploy.rb +0 -1
- data/lib/shopify_cli/commands/app/serve.rb +0 -1
- data/lib/shopify_cli/constants.rb +1 -1
- data/lib/shopify_cli/environment.rb +39 -45
- data/lib/shopify_cli/messages/messages.rb +1 -0
- data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +63 -0
- data/lib/shopify_cli/theme/dev_server/hot_reload.rb +22 -6
- data/lib/shopify_cli/theme/dev_server/proxy.rb +4 -5
- data/lib/shopify_cli/theme/file.rb +4 -0
- data/lib/shopify_cli/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4c9bb44a8b7b750acbf3364201705d93dfb39ce9772976ba2af04183cfc5748
|
4
|
+
data.tar.gz: fa32248af15c17d01d80132b4caf42ea224edba35146098954f51b4453db50de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3446d1a595e343f6566b7ec087c187d31518398ad57be75ff519a394133c75e4f0a5f8670d78913271091632d8ef9fdeef4fb1bb3c1b4ac5cb99d0bc12aef765
|
7
|
+
data.tar.gz: 48ad3c64a367e80facb7aecc393295fb8fa838949a51c7a71310c50a40e6bf2c648b57dbcaf53ade5e15af90ff911593e38865cbb8e2b8dce6b70a8918d83a03
|
data/CHANGELOG.md
CHANGED
@@ -2,8 +2,14 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
-
## Version 2.11.
|
5
|
+
## Version 2.11.1
|
6
|
+
### Fixed
|
7
|
+
* [#1973](https://github.com/Shopify/shopify-cli/pull/1973): Fix `theme serve` to preview generated files (`*.css.liquid`)
|
8
|
+
* [#2034](https://github.com/Shopify/shopify-cli/pull/2034): Fix `theme serve` to accept parameters with multiple values
|
9
|
+
* [#2033](https://github.com/Shopify/shopify-cli/pull/2033): Pin Homebrew Ruby to 3.0
|
10
|
+
* [#2032](https://github.com/Shopify/shopify-cli/pull/2032): Runtime error checking the Node version if Node is not present in the environment.
|
6
11
|
|
12
|
+
## Version 2.11.0
|
7
13
|
### Fixed
|
8
14
|
* [#2005](https://github.com/Shopify/shopify-cli/pull/2005): Fix PHP app serve on Windows environments
|
9
15
|
|
data/Gemfile.lock
CHANGED
@@ -27,6 +27,10 @@ module Extension
|
|
27
27
|
api_secret: options.flags[:api_secret],
|
28
28
|
registration_id: options.flags[:registration_id]
|
29
29
|
)
|
30
|
+
# on ci, registration id must be present
|
31
|
+
registration_id = options.flags[:registration_id]
|
32
|
+
check_registration(registration_id: registration_id, context: @ctx)
|
33
|
+
|
30
34
|
specification_handler = Extension::Loaders::SpecificationHandler.load(project: project, context: @ctx)
|
31
35
|
register_if_necessary(project: project, args: args, name: name)
|
32
36
|
|
@@ -43,6 +47,15 @@ module Extension
|
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
50
|
+
def check_registration(registration_id:, context:)
|
51
|
+
if !ShopifyCLI::Environment.interactive? && (!registration_id || registration_id.empty?)
|
52
|
+
message = context.message("errors.missing_push_options_ci", "--registration-id")
|
53
|
+
message += context.message("errors.missing_push_options_ci_solution", ShopifyCLI::TOOL_NAME)
|
54
|
+
raise ShopifyCLI::Abort,
|
55
|
+
message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
def self.help
|
47
60
|
ShopifyCLI::Context.new.message("push.help", ShopifyCLI::TOOL_NAME)
|
48
61
|
end
|
@@ -9,20 +9,40 @@ module Extension
|
|
9
9
|
"SHOPIFY_API_SECRET" => api_secret,
|
10
10
|
"EXTENSION_ID" => registration_id,
|
11
11
|
}.compact
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
env_file_present = env_file_exists?(directory)
|
13
|
+
env = if env_file_present
|
14
|
+
ShopifyCLI::Resources::EnvFile.read(directory, overrides: env_overrides)
|
15
|
+
else
|
16
|
+
ShopifyCLI::Resources::EnvFile.from_hash(env_overrides)
|
17
|
+
end
|
18
18
|
# This is a somewhat uncomfortable hack we use because `Project::at` is
|
19
19
|
# a global cache and we can't rely on this class loading the project
|
20
20
|
# first. Long-term we should move away from that global cache.
|
21
21
|
project = ExtensionProject.at(directory)
|
22
22
|
project.env = env
|
23
23
|
project
|
24
|
-
rescue SmartProperties::InitializationError, SmartProperties::MissingValueError
|
25
|
-
|
24
|
+
rescue SmartProperties::InitializationError, SmartProperties::MissingValueError => error
|
25
|
+
handle_error(error, context: context)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.handle_error(error, context:)
|
29
|
+
if ShopifyCLI::Environment.interactive?
|
30
|
+
properties_hash = { api_key: "SHOPIFY_API_KEY", secret: "SHOPIFY_API_SECRET" }
|
31
|
+
missing_env_variables = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
|
32
|
+
message = context.message("errors.missing_env_file_variables", missing_env_variables)
|
33
|
+
message += context.message("errors.missing_env_file_variables_solution", ShopifyCLI::TOOL_NAME)
|
34
|
+
else
|
35
|
+
properties_hash = { api_key: "--api-key", secret: "--api-secret" }
|
36
|
+
missing_options = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
|
37
|
+
message = context.message("errors.missing_push_options_ci", missing_options)
|
38
|
+
message += context.message("errors.missing_push_options_ci_solution", ShopifyCLI::TOOL_NAME)
|
39
|
+
end
|
40
|
+
raise ShopifyCLI::Abort,
|
41
|
+
message
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.env_file_exists?(directory)
|
45
|
+
File.exist?(ShopifyCLI::Resources::EnvFile.path(directory))
|
26
46
|
end
|
27
47
|
end
|
28
48
|
end
|
@@ -174,9 +174,17 @@ module Extension
|
|
174
174
|
},
|
175
175
|
},
|
176
176
|
errors: {
|
177
|
-
unknown_type: "Unknown extension type %s"
|
177
|
+
unknown_type: "Unknown extension type %s. Valid extension types include: CHECKOUT_POST_PURCHASE, " \
|
178
|
+
"CHECKOUT_UI_EXTENSION, THEME_APP_EXTENSION, and PRODUCT_SUBSCRIPTION.",
|
178
179
|
package_not_found: "`%s` package not found.",
|
179
|
-
|
180
|
+
missing_push_options_ci: "The following are missing: %s. ",
|
181
|
+
missing_push_options_ci_solution: "To add them to a CI environment:\n\t1. Run a connect command " \
|
182
|
+
"({{command:%1$s extension connect}})\n\t2. Navigate to the .env file at the root of your project\n\t" \
|
183
|
+
"3. Copy the missing values and pass them through as arguments in {{command:%1$s extension push}}",
|
184
|
+
missing_env_file_variables: "The following are missing in the .env file: %s. ",
|
185
|
+
missing_env_file_variables_solution: "To add it, connect your extension with " \
|
186
|
+
"{{command:%1$s extension connect}} " \
|
187
|
+
"or run {{command:%1$s extension register}} to register a new extension.",
|
180
188
|
module_not_found: "Unable to find module %s. Ensure your dependencies are up-to-date and try again.",
|
181
189
|
},
|
182
190
|
warnings: {
|
@@ -47,7 +47,7 @@ module Script
|
|
47
47
|
private
|
48
48
|
|
49
49
|
def install_dependencies(ctx, language, script_name, project_creator)
|
50
|
-
task_runner = Infrastructure::Languages::TaskRunner.for(ctx, language
|
50
|
+
task_runner = Infrastructure::Languages::TaskRunner.for(ctx, language)
|
51
51
|
CLI::UI::Frame.open(ctx.message(
|
52
52
|
"core.git.pulling_from_to",
|
53
53
|
project_creator.sparse_checkout_repo,
|
@@ -10,7 +10,7 @@ module Script
|
|
10
10
|
script_project = script_project_repo.get
|
11
11
|
script_project.env = project.env
|
12
12
|
task_runner = Infrastructure::Languages::TaskRunner
|
13
|
-
.for(ctx, script_project.language
|
13
|
+
.for(ctx, script_project.language)
|
14
14
|
|
15
15
|
extension_point = ExtensionPoints.get(type: script_project.extension_point_type)
|
16
16
|
|
@@ -4,18 +4,11 @@ module Script
|
|
4
4
|
module Layers
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
|
-
class AssemblyScriptTaskRunner
|
7
|
+
class AssemblyScriptTaskRunner < TaskRunner
|
8
8
|
BYTECODE_FILE = "build/script.wasm"
|
9
9
|
METADATA_FILE = "build/metadata.json"
|
10
10
|
SCRIPT_SDK_BUILD = "npm run build"
|
11
11
|
|
12
|
-
attr_reader :ctx, :script_name
|
13
|
-
|
14
|
-
def initialize(ctx, script_name)
|
15
|
-
@ctx = ctx
|
16
|
-
@script_name = script_name
|
17
|
-
end
|
18
|
-
|
19
12
|
def build
|
20
13
|
compile
|
21
14
|
bytecode
|
@@ -5,15 +5,41 @@ module Script
|
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
7
|
class TaskRunner
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
attr_reader :ctx
|
9
|
+
|
10
|
+
def self.for(ctx, language)
|
11
|
+
task_runners = {
|
12
|
+
"assemblyscript" => AssemblyScriptTaskRunner,
|
13
|
+
"typescript" => TypeScriptTaskRunner,
|
14
|
+
"wasm" => WasmTaskRunner,
|
15
|
+
}
|
16
|
+
|
17
|
+
raise Errors::TaskRunnerNotFoundError unless task_runners[language]
|
18
|
+
task_runners[language].new(ctx)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(ctx)
|
22
|
+
@ctx = ctx
|
23
|
+
end
|
24
|
+
|
25
|
+
def build
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
def dependencies_installed?
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
def install_dependencies
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def metadata_file_location
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
40
|
+
|
41
|
+
def library_version(_library_name)
|
42
|
+
raise NotImplementedError
|
17
43
|
end
|
18
44
|
end
|
19
45
|
end
|
@@ -4,19 +4,12 @@ module Script
|
|
4
4
|
module Layers
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
|
-
class TypeScriptTaskRunner
|
7
|
+
class TypeScriptTaskRunner < TaskRunner
|
8
8
|
BYTECODE_FILE = "build/index.wasm"
|
9
9
|
METADATA_FILE = "build/metadata.json"
|
10
10
|
SCRIPT_SDK_BUILD = "npm run build"
|
11
11
|
GEN_METADATA = "npm run gen-metadata"
|
12
12
|
|
13
|
-
attr_reader :ctx, :script_name
|
14
|
-
|
15
|
-
def initialize(ctx, script_name)
|
16
|
-
@ctx = ctx
|
17
|
-
@script_name = script_name
|
18
|
-
end
|
19
|
-
|
20
13
|
def build
|
21
14
|
compile
|
22
15
|
bytecode
|
@@ -4,19 +4,15 @@ module Script
|
|
4
4
|
module Layers
|
5
5
|
module Infrastructure
|
6
6
|
module Languages
|
7
|
-
class WasmTaskRunner
|
7
|
+
class WasmTaskRunner < TaskRunner
|
8
8
|
BYTECODE_FILE = "script.wasm"
|
9
|
-
attr_reader :ctx, :script_name
|
10
|
-
|
11
|
-
def initialize(ctx, script_name)
|
12
|
-
@ctx = ctx
|
13
|
-
@script_name = script_name
|
14
|
-
end
|
15
9
|
|
16
10
|
def dependencies_installed?
|
17
11
|
true
|
18
12
|
end
|
19
13
|
|
14
|
+
def install_dependencies; end
|
15
|
+
|
20
16
|
def library_version(_library_name)
|
21
17
|
nil
|
22
18
|
end
|
@@ -149,12 +149,12 @@ module Script
|
|
149
149
|
|
150
150
|
language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
|
151
151
|
language_library_for_api_not_found_help: "Make sure extension_point.yml contains the correct API library.",
|
152
|
-
no_scripts_found_in_app: "The selected apps have no scripts.
|
153
|
-
missing_env_file_variables: "The following
|
154
|
-
"
|
155
|
-
|
156
|
-
|
157
|
-
"
|
152
|
+
no_scripts_found_in_app: "The selected apps have no scripts. Please, create them first on the partners' dashboard.",
|
153
|
+
missing_env_file_variables: "The following are missing in the .env file: %s."\
|
154
|
+
" To add it, run {{command:%s script connect}}",
|
155
|
+
missing_push_options: "The following are missing: %s. "\
|
156
|
+
"To add them to a CI environment:\n\t1. Run a connect command {{command:%s script connect}}\n\t2. Navigate to the .env file at the root of your project\n\t"\
|
157
|
+
"3. Copy the missing values, then pass them through as arguments.",
|
158
158
|
},
|
159
159
|
|
160
160
|
create: {
|
data/lib/shopify_cli/command.rb
CHANGED
@@ -100,14 +100,20 @@ module ShopifyCLI
|
|
100
100
|
end
|
101
101
|
|
102
102
|
def check_node_version
|
103
|
+
context = Context.new
|
104
|
+
if @compatible_node_range && context.which("node").nil?
|
105
|
+
raise ShopifyCLI::Abort, context.message("core.errors.missing_node")
|
106
|
+
end
|
107
|
+
|
103
108
|
check_version(
|
104
109
|
Environment.node_version,
|
105
110
|
range: @compatible_node_range,
|
106
|
-
runtime: "Node"
|
111
|
+
runtime: "Node",
|
112
|
+
context: context
|
107
113
|
)
|
108
114
|
end
|
109
115
|
|
110
|
-
def check_version(version, range:, runtime:)
|
116
|
+
def check_version(version, range:, runtime:, context: Context.new)
|
111
117
|
return if Environment.test?
|
112
118
|
return if range.nil?
|
113
119
|
|
@@ -116,7 +122,7 @@ module ShopifyCLI
|
|
116
122
|
is_lower_than_top = version_without_pre_nor_build < Utilities.version_dropping_pre_and_build(range.to)
|
117
123
|
return if is_higher_than_bottom && is_lower_than_top
|
118
124
|
|
119
|
-
|
125
|
+
context.warn("Your environment #{runtime} version, #{version},"\
|
120
126
|
" is outside of the range supported by the CLI,"\
|
121
127
|
" #{range.from}..<#{range.to},"\
|
122
128
|
" and might cause incompatibility issues.")
|
@@ -5,8 +5,8 @@ module ShopifyCLI
|
|
5
5
|
class Rails < ShopifyCLI::Command::AppSubCommand
|
6
6
|
prerequisite_task :ensure_authenticated
|
7
7
|
|
8
|
-
recommend_default_node_range
|
9
8
|
recommend_default_ruby_range
|
9
|
+
recommend_default_node_range
|
10
10
|
|
11
11
|
options do |parser, flags|
|
12
12
|
parser.on("--name=NAME") { |t| flags[:name] = t }
|
@@ -6,9 +6,6 @@ module ShopifyCLI
|
|
6
6
|
subcommand :PHP, "php", "shopify_cli/commands/app/create/php"
|
7
7
|
subcommand :Node, "node", "shopify_cli/commands/app/create/node"
|
8
8
|
|
9
|
-
recommend_default_node_range
|
10
|
-
recommend_default_ruby_range
|
11
|
-
|
12
9
|
def call(_args, _command_name)
|
13
10
|
@ctx.puts(self.class.help)
|
14
11
|
end
|
@@ -38,7 +38,7 @@ module ShopifyCLI
|
|
38
38
|
|
39
39
|
# When true the CLI points to spin instances of services
|
40
40
|
SPIN = "SPIN"
|
41
|
-
|
41
|
+
SPIN_INSTANCE = "SPIN_INSTANCE"
|
42
42
|
SPIN_WORKSPACE = "SPIN_WORKSPACE"
|
43
43
|
SPIN_NAMESPACE = "SPIN_NAMESPACE"
|
44
44
|
SPIN_HOST = "SPIN_HOST"
|
@@ -5,6 +5,11 @@ module ShopifyCLI
|
|
5
5
|
# the environment in which the CLI runs
|
6
6
|
module Environment
|
7
7
|
TRUTHY_ENV_VARIABLE_VALUES = ["1", "true", "TRUE", "yes", "YES"]
|
8
|
+
SPIN_OVERRIDE_ENV_NAMES = [
|
9
|
+
Constants::EnvironmentVariables::SPIN_WORKSPACE,
|
10
|
+
Constants::EnvironmentVariables::SPIN_NAMESPACE,
|
11
|
+
Constants::EnvironmentVariables::SPIN_HOST,
|
12
|
+
]
|
8
13
|
|
9
14
|
def self.ruby_version(context: Context.new)
|
10
15
|
out, err, stat = context.capture3('ruby -e "puts RUBY_VERSION"')
|
@@ -87,6 +92,20 @@ module ShopifyCLI
|
|
87
92
|
end
|
88
93
|
end
|
89
94
|
|
95
|
+
def self.spin_url_override(env_variables: ENV)
|
96
|
+
tokens = SPIN_OVERRIDE_ENV_NAMES.map do |name|
|
97
|
+
env_variables[name]
|
98
|
+
end
|
99
|
+
|
100
|
+
return if tokens.all?(&:nil?)
|
101
|
+
|
102
|
+
if tokens.any?(&:nil?)
|
103
|
+
raise "To manually target a spin instance, you must set #{SPIN_OVERRIDE_ENV_NAMES}"
|
104
|
+
else
|
105
|
+
tokens.join(".")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
90
109
|
def self.use_spin?(env_variables: ENV)
|
91
110
|
env_variable_truthy?(
|
92
111
|
Constants::EnvironmentVariables::SPIN,
|
@@ -97,32 +116,29 @@ module ShopifyCLI
|
|
97
116
|
)
|
98
117
|
end
|
99
118
|
|
100
|
-
def self.infer_spin?(env_variables: ENV)
|
101
|
-
env_variable_truthy?(
|
102
|
-
Constants::EnvironmentVariables::INFER_SPIN,
|
103
|
-
env_variables: env_variables
|
104
|
-
)
|
105
|
-
end
|
106
|
-
|
107
119
|
def self.spin_url(env_variables: ENV)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
%x(spin show -o fqdn 2> /dev/null).strip
|
116
|
-
else
|
117
|
-
# spin-legacy
|
118
|
-
%x(spin info fqdn 2> /dev/null).strip
|
119
|
-
end
|
120
|
+
override = spin_url_override(env_variables: env_variables)
|
121
|
+
return override unless override.nil?
|
122
|
+
|
123
|
+
spin_response = if env_variables.key?(
|
124
|
+
Constants::EnvironmentVariables::SPIN_INSTANCE
|
125
|
+
)
|
126
|
+
spin_show
|
120
127
|
else
|
121
|
-
|
122
|
-
spin_namespace = spin_namespace(env_variables: env_variables)
|
123
|
-
spin_host = spin_host(env_variables: env_variables)
|
124
|
-
"#{spin_workspace}.#{spin_namespace}.#{spin_host}"
|
128
|
+
spin_show(latest: true)
|
125
129
|
end
|
130
|
+
|
131
|
+
begin
|
132
|
+
instance = JSON.parse(spin_response)
|
133
|
+
raise "Missing key 'fqdn' from spin show. Actual response: #{instance}" unless instance.include?("fqdn")
|
134
|
+
instance["fqdn"]
|
135
|
+
rescue => e
|
136
|
+
raise "Failed to infer spin environment from spin show response #{spin_response}: #{e}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.spin_show(latest: false)
|
141
|
+
latest ? %x(spin show --latest --json) : %x(spin show --json)
|
126
142
|
end
|
127
143
|
|
128
144
|
def self.send_monorail_events?(env_variables: ENV)
|
@@ -139,27 +155,5 @@ module ShopifyCLI
|
|
139
155
|
def self.env_variable_truthy?(variable_name, env_variables: ENV)
|
140
156
|
TRUTHY_ENV_VARIABLE_VALUES.include?(env_variables[variable_name.to_s])
|
141
157
|
end
|
142
|
-
|
143
|
-
def self.spin_workspace(env_variables: ENV)
|
144
|
-
env_value = env_variables[Constants::EnvironmentVariables::SPIN_WORKSPACE]
|
145
|
-
return env_value unless env_value.nil?
|
146
|
-
|
147
|
-
if env_value.nil?
|
148
|
-
raise "No value set for #{Constants::EnvironmentVariables::SPIN_WORKSPACE}"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def self.spin_namespace(env_variables: ENV)
|
153
|
-
env_value = env_variables[Constants::EnvironmentVariables::SPIN_NAMESPACE]
|
154
|
-
return env_value unless env_value.nil?
|
155
|
-
|
156
|
-
if env_value.nil?
|
157
|
-
raise "No value set for #{Constants::EnvironmentVariables::SPIN_NAMESPACE}"
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def self.spin_host(env_variables: ENV)
|
162
|
-
env_variables[Constants::EnvironmentVariables::SPIN_HOST] || "us.spin.dev"
|
163
|
-
end
|
164
158
|
end
|
165
159
|
end
|
@@ -15,6 +15,7 @@ module ShopifyCLI
|
|
15
15
|
},
|
16
16
|
core: {
|
17
17
|
errors: {
|
18
|
+
missing_node: "Node is necessary for this command and was not found in the environment.",
|
18
19
|
option_parser: {
|
19
20
|
invalid_option: "The option {{command:%s}} is not supported.",
|
20
21
|
missing_argument: "The required argument {{command:%s}} is missing.",
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyCLI
|
4
|
+
module Theme
|
5
|
+
module DevServer
|
6
|
+
class HotReload
|
7
|
+
class RemoteFileReloader
|
8
|
+
def initialize(ctx, theme:, streams:)
|
9
|
+
@ctx = ctx
|
10
|
+
@theme = theme
|
11
|
+
@streams = streams
|
12
|
+
end
|
13
|
+
|
14
|
+
def reload(file)
|
15
|
+
retries = 6
|
16
|
+
|
17
|
+
until retries.zero?
|
18
|
+
retries -= 1
|
19
|
+
|
20
|
+
_status, body = fetch_asset(file)
|
21
|
+
retries = 0 if updated_file?(body, file)
|
22
|
+
|
23
|
+
wait
|
24
|
+
end
|
25
|
+
|
26
|
+
notify(file)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def updated_file?(body, file)
|
32
|
+
remote_checksum = body.dig("asset", "checksum")
|
33
|
+
local_checksum = file.checksum
|
34
|
+
|
35
|
+
remote_checksum == local_checksum
|
36
|
+
end
|
37
|
+
|
38
|
+
def notify(file)
|
39
|
+
@streams.broadcast(JSON.generate(modified: [file]))
|
40
|
+
@ctx.debug("[RemoteFileReloader] Modified #{file}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def wait
|
44
|
+
sleep(1)
|
45
|
+
end
|
46
|
+
|
47
|
+
def fetch_asset(file)
|
48
|
+
ShopifyCLI::AdminAPI.rest_request(
|
49
|
+
@ctx,
|
50
|
+
shop: @theme.shop,
|
51
|
+
path: "themes/#{@theme.id}/assets.json",
|
52
|
+
method: "GET",
|
53
|
+
api_version: "unstable",
|
54
|
+
query: URI.encode_www_form("asset[key]" => file.relative_path.to_s),
|
55
|
+
)
|
56
|
+
rescue ShopifyCLI::API::APIRequestNotFoundError
|
57
|
+
[404, {}]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "hot_reload/remote_file_reloader"
|
4
|
+
|
3
5
|
module ShopifyCLI
|
4
6
|
module Theme
|
5
7
|
module DevServer
|
@@ -10,6 +12,7 @@ module ShopifyCLI
|
|
10
12
|
@theme = theme
|
11
13
|
@mode = mode
|
12
14
|
@streams = SSE::Streams.new
|
15
|
+
@remote_file_reloader = RemoteFileReloader.new(ctx, theme: @theme, streams: @streams)
|
13
16
|
@watcher = watcher
|
14
17
|
@watcher.add_observer(self, :notify_streams_of_file_change)
|
15
18
|
@ignore_filter = ignore_filter
|
@@ -32,17 +35,30 @@ module ShopifyCLI
|
|
32
35
|
end
|
33
36
|
|
34
37
|
def notify_streams_of_file_change(modified, added, _removed)
|
35
|
-
files = (modified + added)
|
36
|
-
.
|
38
|
+
files = (modified + added)
|
39
|
+
.reject { |file| @ignore_filter&.ignore?(file) }
|
40
|
+
.map { |file| @theme[file] }
|
37
41
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
files -= liquid_css_files = files.select(&:liquid_css?)
|
43
|
+
|
44
|
+
hot_reload(files) unless files.empty?
|
45
|
+
remote_reload(liquid_css_files)
|
42
46
|
end
|
43
47
|
|
44
48
|
private
|
45
49
|
|
50
|
+
def hot_reload(files)
|
51
|
+
paths = files.map(&:relative_path)
|
52
|
+
@streams.broadcast(JSON.generate(modified: paths))
|
53
|
+
@ctx.debug("[HotReload] Modified #{paths.join(", ")}")
|
54
|
+
end
|
55
|
+
|
56
|
+
def remote_reload(files)
|
57
|
+
files.each do |file|
|
58
|
+
@remote_file_reloader.reload(file)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
46
62
|
def request_is_html?(headers)
|
47
63
|
headers["content-type"]&.start_with?("text/html")
|
48
64
|
end
|
@@ -43,9 +43,8 @@ module ShopifyCLI
|
|
43
43
|
headers["Accept-Encoding"] = "none"
|
44
44
|
headers["User-Agent"] = "Shopify CLI"
|
45
45
|
|
46
|
-
query = URI.decode_www_form(env["QUERY_STRING"])
|
46
|
+
query = URI.decode_www_form(env["QUERY_STRING"])
|
47
47
|
replace_templates = build_replace_templates_param(env)
|
48
|
-
|
49
48
|
response = if replace_templates.any?
|
50
49
|
# Pass to SFR the recently modified templates in `replace_templates` body param
|
51
50
|
headers["Authorization"] = "Bearer #{bearer_token}"
|
@@ -158,7 +157,7 @@ module ShopifyCLI
|
|
158
157
|
def secure_session_id
|
159
158
|
if secure_session_id_expired?
|
160
159
|
@ctx.debug("Refreshing preview _secure_session_id cookie")
|
161
|
-
response = request("HEAD", "/", query:
|
160
|
+
response = request("HEAD", "/", query: [[:preview_theme_id, @theme.id]])
|
162
161
|
@secure_session_id = extract_secure_session_id_from_response_headers(response)
|
163
162
|
@last_session_cookie_refresh = Time.now
|
164
163
|
end
|
@@ -189,9 +188,9 @@ module ShopifyCLI
|
|
189
188
|
response_headers
|
190
189
|
end
|
191
190
|
|
192
|
-
def request(method, path, headers: nil, query:
|
191
|
+
def request(method, path, headers: nil, query: [], form_data: nil, body_stream: nil)
|
193
192
|
uri = URI.join("https://#{@theme.shop}", path)
|
194
|
-
uri.query = URI.encode_www_form(query
|
193
|
+
uri.query = URI.encode_www_form(query + [[:_fd, 0], [:pb, 0]])
|
195
194
|
|
196
195
|
@ctx.debug("Proxying #{method} #{uri}")
|
197
196
|
|
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: 2.11.
|
4
|
+
version: 2.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -469,6 +469,7 @@ files:
|
|
469
469
|
- lib/shopify_cli/theme/dev_server/header_hash.rb
|
470
470
|
- lib/shopify_cli/theme/dev_server/hot-reload.js
|
471
471
|
- lib/shopify_cli/theme/dev_server/hot_reload.rb
|
472
|
+
- lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb
|
472
473
|
- lib/shopify_cli/theme/dev_server/local_assets.rb
|
473
474
|
- lib/shopify_cli/theme/dev_server/proxy.rb
|
474
475
|
- lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb
|