shopify-cli 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/Gemfile.lock +1 -1
  4. data/bin/shopify +13 -0
  5. data/docs/users/installation.md +1 -44
  6. data/lib/project_types/extension/commands/build.rb +0 -3
  7. data/lib/project_types/extension/commands/check.rb +0 -1
  8. data/lib/project_types/extension/commands/create.rb +0 -1
  9. data/lib/project_types/extension/commands/push.rb +13 -1
  10. data/lib/project_types/extension/commands/serve.rb +0 -1
  11. data/lib/project_types/extension/loaders/project.rb +28 -8
  12. data/lib/project_types/extension/messages/messages.rb +10 -2
  13. data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +114 -0
  14. data/lib/project_types/extension/models/specification_handlers/theme_app_extension.rb +7 -1
  15. data/lib/project_types/script/cli.rb +2 -0
  16. data/lib/project_types/script/commands/create.rb +2 -2
  17. data/lib/project_types/script/commands/push.rb +4 -6
  18. data/lib/project_types/script/config/extension_points.yml +0 -4
  19. data/lib/project_types/script/forms/create.rb +1 -14
  20. data/lib/project_types/script/layers/application/connect_app.rb +3 -2
  21. data/lib/project_types/script/layers/application/create_script.rb +1 -1
  22. data/lib/project_types/script/layers/application/push_script.rb +1 -1
  23. data/lib/project_types/script/layers/infrastructure/errors.rb +11 -0
  24. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +2 -6
  25. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +30 -26
  26. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +35 -9
  27. data/lib/project_types/script/layers/infrastructure/languages/tool_version_checker.rb +26 -0
  28. data/lib/project_types/script/layers/infrastructure/languages/typescript_project_creator.rb +3 -6
  29. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +31 -27
  30. data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +3 -7
  31. data/lib/project_types/script/loaders/project.rb +8 -7
  32. data/lib/project_types/script/messages/messages.rb +14 -13
  33. data/lib/project_types/script/ui/error_handler.rb +13 -0
  34. data/lib/project_types/theme/commands/check.rb +0 -1
  35. data/lib/project_types/theme/commands/common/root_helper.rb +65 -0
  36. data/lib/project_types/theme/commands/delete.rb +0 -1
  37. data/lib/project_types/theme/commands/init.rb +2 -1
  38. data/lib/project_types/theme/commands/language_server.rb +0 -1
  39. data/lib/project_types/theme/commands/package.rb +0 -1
  40. data/lib/project_types/theme/commands/publish.rb +0 -1
  41. data/lib/project_types/theme/commands/pull.rb +18 -9
  42. data/lib/project_types/theme/commands/push.rb +16 -11
  43. data/lib/project_types/theme/commands/serve.rb +6 -3
  44. data/lib/project_types/theme/conversions/base_glob.rb +50 -0
  45. data/lib/project_types/theme/conversions/ignore_glob.rb +15 -0
  46. data/lib/project_types/theme/conversions/include_glob.rb +15 -0
  47. data/lib/project_types/theme/messages/messages.rb +5 -5
  48. data/lib/shopify_cli/command.rb +11 -3
  49. data/lib/shopify_cli/commands/app/create/node.rb +1 -0
  50. data/lib/shopify_cli/commands/app/create/php.rb +1 -0
  51. data/lib/shopify_cli/commands/app/create/rails.rb +2 -1
  52. data/lib/shopify_cli/commands/app/create.rb +0 -3
  53. data/lib/shopify_cli/commands/app/deploy.rb +1 -1
  54. data/lib/shopify_cli/commands/app/serve.rb +0 -1
  55. data/lib/shopify_cli/constants.rb +2 -2
  56. data/lib/shopify_cli/environment.rb +45 -45
  57. data/lib/shopify_cli/git.rb +9 -1
  58. data/lib/shopify_cli/messages/messages.rb +23 -2
  59. data/lib/shopify_cli/tasks/ensure_git_dependency.rb +14 -0
  60. data/lib/shopify_cli/tasks.rb +1 -0
  61. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +63 -0
  62. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +22 -6
  63. data/lib/shopify_cli/theme/dev_server/proxy.rb +18 -7
  64. data/lib/shopify_cli/theme/dev_server.rb +1 -3
  65. data/lib/shopify_cli/theme/development_theme.rb +11 -0
  66. data/lib/shopify_cli/theme/file.rb +4 -0
  67. data/lib/shopify_cli/theme/include_filter.rb +4 -2
  68. data/lib/shopify_cli/theme/syncer.rb +13 -4
  69. data/lib/shopify_cli/theme/theme.rb +0 -4
  70. data/lib/shopify_cli/version.rb +1 -1
  71. metadata +9 -2
@@ -4,17 +4,16 @@ module Script
4
4
  module Layers
5
5
  module Infrastructure
6
6
  module Languages
7
- class AssemblyScriptTaskRunner
7
+ class AssemblyScriptTaskRunner < TaskRunner
8
+ NODE_MIN_VERSION = "14.15.0"
9
+ NPM_MIN_VERSION = "5.2.0"
10
+
8
11
  BYTECODE_FILE = "build/script.wasm"
9
12
  METADATA_FILE = "build/metadata.json"
10
13
  SCRIPT_SDK_BUILD = "npm run build"
11
-
12
- attr_reader :ctx, :script_name
13
-
14
- def initialize(ctx, script_name)
15
- @ctx = ctx
16
- @script_name = script_name
17
- end
14
+ NPM_SET_REGISTRY_COMMAND = "npm --userconfig ./.npmrc config set @shopify:registry https://registry.npmjs.com"
15
+ NPM_SET_ENGINE_STRICT_COMMAND = "npm --userconfig ./.npmrc config set engine-strict true"
16
+ NPM_INSTALL_COMMAND = "npm install --no-audit --no-optional --legacy-peer-deps --loglevel error"
18
17
 
19
18
  def build
20
19
  compile
@@ -22,10 +21,10 @@ module Script
22
21
  end
23
22
 
24
23
  def install_dependencies
25
- check_node_version!
24
+ run_cmd_with_env_check(NPM_INSTALL_COMMAND)
26
25
 
27
- output, status = ctx.capture2e("npm install --no-audit --no-optional --legacy-peer-deps --loglevel error")
28
- raise Errors::DependencyInstallError, output unless status.success?
26
+ rescue Errors::SystemCallFailureError => e
27
+ raise Errors::DependencyInstallError, e.out
29
28
  end
30
29
 
31
30
  def dependencies_installed?
@@ -38,14 +37,32 @@ module Script
38
37
  end
39
38
 
40
39
  def library_version(library_name)
41
- output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
40
+ output = JSON.parse(run_cmd_with_env_check("npm -s list --json"))
42
41
  library_version_from_npm_list(output, library_name)
43
42
  rescue Errors::SystemCallFailureError => error
44
43
  library_version_from_npm_list_error_output(error, library_name)
45
44
  end
46
45
 
46
+ def set_npm_config
47
+ run_cmd_with_env_check(NPM_SET_REGISTRY_COMMAND)
48
+ run_cmd_with_env_check(NPM_SET_ENGINE_STRICT_COMMAND)
49
+ end
50
+
47
51
  private
48
52
 
53
+ def ensure_environment
54
+ return if defined?(@environment_checked)
55
+ @environment_checked = true
56
+
57
+ ToolVersionChecker.check_node(minimum_version: NODE_MIN_VERSION)
58
+ ToolVersionChecker.check_npm(minimum_version: NPM_MIN_VERSION)
59
+ end
60
+
61
+ def run_cmd_with_env_check(cmd)
62
+ ensure_environment
63
+ CommandRunner.new(ctx: ctx).call(cmd)
64
+ end
65
+
49
66
  def library_version_from_npm_list_error_output(error, library_name)
50
67
  # npm list can return a failure status code, even when returning the correct data.
51
68
  # This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
@@ -64,22 +81,9 @@ module Script
64
81
  end
65
82
  end
66
83
 
67
- def check_node_version!
68
- output, status = @ctx.capture2e("node", "--version")
69
- raise Errors::DependencyInstallError, output unless status.success?
70
-
71
- require "semantic/semantic"
72
- version = ::Semantic::Version.new(output[1..-1])
73
- unless version >= ::Semantic::Version.new(AssemblyScriptProjectCreator::MIN_NODE_VERSION)
74
- raise Errors::DependencyInstallError,
75
- "Node version must be >= v#{AssemblyScriptProjectCreator::MIN_NODE_VERSION}. "\
76
- "Current version: #{output.strip}."
77
- end
78
- end
79
-
80
84
  def compile
81
85
  check_compilation_dependencies!
82
- CommandRunner.new(ctx: ctx).call(SCRIPT_SDK_BUILD)
86
+ run_cmd_with_env_check(SCRIPT_SDK_BUILD)
83
87
  end
84
88
 
85
89
  def check_compilation_dependencies!
@@ -5,15 +5,41 @@ module Script
5
5
  module Infrastructure
6
6
  module Languages
7
7
  class TaskRunner
8
- TASK_RUNNERS = {
9
- "assemblyscript" => AssemblyScriptTaskRunner,
10
- "typescript" => TypeScriptTaskRunner,
11
- "wasm" => WasmTaskRunner,
12
- }
13
-
14
- def self.for(ctx, language, script_name)
15
- raise Errors::TaskRunnerNotFoundError unless TASK_RUNNERS[language]
16
- TASK_RUNNERS[language].new(ctx, script_name)
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
@@ -0,0 +1,26 @@
1
+ module Script
2
+ module Layers
3
+ module Infrastructure
4
+ module Languages
5
+ class ToolVersionChecker
6
+ class << self
7
+ def check_node(minimum_version:)
8
+ check_version("node", ShopifyCLI::Environment.node_version, minimum_version)
9
+ end
10
+
11
+ def check_npm(minimum_version:)
12
+ check_version("npm", ShopifyCLI::Environment.npm_version, minimum_version)
13
+ end
14
+
15
+ private
16
+
17
+ def check_version(tool, env_version, minimum_version)
18
+ return if env_version >= ::Semantic::Version.new(minimum_version)
19
+ raise Errors::InvalidEnvironmentError.new(tool, env_version, minimum_version)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -5,18 +5,15 @@ module Script
5
5
  module Infrastructure
6
6
  module Languages
7
7
  class TypeScriptProjectCreator < ProjectCreator
8
- MIN_NODE_VERSION = "14.15.0"
9
- NPM_SET_REGISTRY_COMMAND = "npm --userconfig ./.npmrc config set @shopify:registry https://registry.npmjs.com"
10
- NPM_SET_ENGINE_STRICT_COMMAND = "npm --userconfig ./.npmrc config set engine-strict true"
11
-
12
8
  def self.config_file
13
9
  "package.json"
14
10
  end
15
11
 
16
12
  def setup_dependencies
13
+ task_runner = Infrastructure::Languages::TypeScriptTaskRunner.new(ctx)
14
+ task_runner.set_npm_config
15
+
17
16
  super
18
- command_runner.call(NPM_SET_REGISTRY_COMMAND)
19
- command_runner.call(NPM_SET_ENGINE_STRICT_COMMAND)
20
17
 
21
18
  if ctx.file_exist?("yarn.lock")
22
19
  ctx.rm("yarn.lock")
@@ -4,18 +4,17 @@ module Script
4
4
  module Layers
5
5
  module Infrastructure
6
6
  module Languages
7
- class TypeScriptTaskRunner
7
+ class TypeScriptTaskRunner < TaskRunner
8
+ NODE_MIN_VERSION = "14.15.0"
9
+ NPM_MIN_VERSION = "5.2.0"
10
+
8
11
  BYTECODE_FILE = "build/index.wasm"
9
12
  METADATA_FILE = "build/metadata.json"
10
13
  SCRIPT_SDK_BUILD = "npm run build"
11
14
  GEN_METADATA = "npm run gen-metadata"
12
-
13
- attr_reader :ctx, :script_name
14
-
15
- def initialize(ctx, script_name)
16
- @ctx = ctx
17
- @script_name = script_name
18
- end
15
+ NPM_SET_REGISTRY_COMMAND = "npm --userconfig ./.npmrc config set @shopify:registry https://registry.npmjs.com"
16
+ NPM_SET_ENGINE_STRICT_COMMAND = "npm --userconfig ./.npmrc config set engine-strict true"
17
+ NPM_INSTALL_COMMAND = "npm install --no-audit --no-optional --legacy-peer-deps --loglevel error"
19
18
 
20
19
  def build
21
20
  compile
@@ -23,10 +22,10 @@ module Script
23
22
  end
24
23
 
25
24
  def install_dependencies
26
- check_node_version!
25
+ run_cmd_with_env_check(NPM_INSTALL_COMMAND)
27
26
 
28
- output, status = ctx.capture2e("npm install --no-audit --no-optional --legacy-peer-deps --loglevel error")
29
- raise Errors::DependencyInstallError, output unless status.success?
27
+ rescue Errors::SystemCallFailureError => e
28
+ raise Errors::DependencyInstallError, e.out
30
29
  end
31
30
 
32
31
  def dependencies_installed?
@@ -39,14 +38,32 @@ module Script
39
38
  end
40
39
 
41
40
  def library_version(library_name)
42
- output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
41
+ output = JSON.parse(run_cmd_with_env_check("npm -s list --json"))
43
42
  library_version_from_npm_list(output, library_name)
44
43
  rescue Errors::SystemCallFailureError => error
45
44
  library_version_from_npm_list_error_output(error, library_name)
46
45
  end
47
46
 
47
+ def set_npm_config
48
+ run_cmd_with_env_check(NPM_SET_REGISTRY_COMMAND)
49
+ run_cmd_with_env_check(NPM_SET_ENGINE_STRICT_COMMAND)
50
+ end
51
+
48
52
  private
49
53
 
54
+ def ensure_environment
55
+ return if defined?(@environment_checked)
56
+ @environment_checked = true
57
+
58
+ ToolVersionChecker.check_node(minimum_version: NODE_MIN_VERSION)
59
+ ToolVersionChecker.check_npm(minimum_version: NPM_MIN_VERSION)
60
+ end
61
+
62
+ def run_cmd_with_env_check(cmd)
63
+ ensure_environment
64
+ CommandRunner.new(ctx: ctx).call(cmd)
65
+ end
66
+
50
67
  def library_version_from_npm_list_error_output(error, library_name)
51
68
  # npm list can return a failure status code, even when returning the correct data.
52
69
  # This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
@@ -65,23 +82,10 @@ module Script
65
82
  end
66
83
  end
67
84
 
68
- def check_node_version!
69
- output, status = @ctx.capture2e("node", "--version")
70
- raise Errors::DependencyInstallError, output unless status.success?
71
-
72
- require "semantic/semantic"
73
- version = ::Semantic::Version.new(output[1..-1])
74
- unless version >= ::Semantic::Version.new(TypeScriptProjectCreator::MIN_NODE_VERSION)
75
- raise Errors::DependencyInstallError,
76
- "Node version must be >= v#{TypeScriptProjectCreator::MIN_NODE_VERSION}. "\
77
- "Current version: #{output.strip}."
78
- end
79
- end
80
-
81
85
  def compile
82
86
  check_compilation_dependencies!
83
- CommandRunner.new(ctx: ctx).call(SCRIPT_SDK_BUILD)
84
- CommandRunner.new(ctx: ctx).call(GEN_METADATA)
87
+ run_cmd_with_env_check(SCRIPT_SDK_BUILD)
88
+ run_cmd_with_env_check(GEN_METADATA)
85
89
  end
86
90
 
87
91
  def check_compilation_dependencies!
@@ -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
@@ -20,21 +20,22 @@ module Script
20
20
  project.env = env
21
21
  project
22
22
  rescue SmartProperties::InitializationError, SmartProperties::InvalidValueError => error
23
- handle_error(error, context: context, env_file_present: env_file_present)
23
+ handle_error(error, context: context)
24
24
  end
25
25
 
26
- def self.handle_error(error, context:, env_file_present:)
27
- if env_file_present
26
+ def self.handle_error(error, context:)
27
+ if ShopifyCLI::Environment.interactive?
28
28
  properties_hash = { api_key: "SHOPIFY_API_KEY", secret: "SHOPIFY_API_SECRET" }
29
29
  missing_env_variables = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
30
- raise ShopifyCLI::Abort,
31
- context.message("script.error.missing_env_file_variables", missing_env_variables, ShopifyCLI::TOOL_NAME)
30
+ message = context.message("script.error.missing_env_file_variables", missing_env_variables)
31
+ message += context.message("script.error.missing_env_file_variables_solution", ShopifyCLI::TOOL_NAME)
32
32
  else
33
33
  properties_hash = { api_key: "--api-key", secret: "--api-secret" }
34
34
  missing_options = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
35
- raise ShopifyCLI::Abort, context.message("script.error.missing_push_options", missing_options,
36
- ShopifyCli::TOOL_NAME)
35
+ message = context.message("script.error.missing_push_options_ci", missing_options)
36
+ message += context.message("script.error.missing_push_options_ci_solution", ShopifyCLI::TOOL_NAME)
37
37
  end
38
+ raise ShopifyCLI::Abort, message
38
39
  end
39
40
 
40
41
  def self.env_file_exists?(directory)
@@ -113,6 +113,10 @@ module Script
113
113
  dependency_install_cause: "Something went wrong while installing the needed dependencies.",
114
114
  dependency_install_help: "Correct the errors.",
115
115
 
116
+ invalid_environment_cause: "Your environment %{tool} version, %{env_version}, "\
117
+ "is too low. It must be at least %{minimum_version}.",
118
+ invalid_environment_help: "Update %{tool}.",
119
+
116
120
  failed_api_request_cause: "Something went wrong while communicating with Shopify.",
117
121
  failed_api_request_help: "Try again.",
118
122
 
@@ -149,12 +153,14 @@ module Script
149
153
 
150
154
  language_library_for_api_not_found_cause: "Script can’t be pushed because the %{language} library for API %{api} is missing.",
151
155
  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. Create them first on the partners' dashboard.",
153
- missing_env_file_variables: "The following variables are missing in the .env file: %s."\
154
- " This can occur when the script hasn't been connected to an app."\
155
- " To connect the script to an app, run {{command:%s script connect}}",
156
- missing_push_options: "The following options are missing from .env: %s."\
157
- " Run {{command:%s script connect}} to connect the script to an app and generate these options.",
156
+ no_scripts_found_in_app: "The selected apps have no scripts. Please, create them first on the partners' dashboard.",
157
+ missing_push_options_ci: "The following are missing: %s. ",
158
+ missing_push_options_ci_solution: "To add them to a CI environment:\n\t1. Run a connect command " \
159
+ "({{command:%1$s script connect}})\n\t2. Navigate to the .env file at the root of your project\n\t" \
160
+ "3. Copy the missing values and pass them through as arguments in {{command:%1$s script push}}",
161
+ missing_env_file_variables: "The following are missing in the .env file: %s. ",
162
+ missing_env_file_variables_solution: "To add it, connect your script with " \
163
+ "{{command:%1$s script connect}} ",
158
164
  },
159
165
 
160
166
  create: {
@@ -164,7 +170,7 @@ module Script
164
170
  Options:
165
171
  {{command:--name=NAME}} Script project name.
166
172
  {{command:--api=TYPE}} Script API name. Supported values: %2$s.
167
- {{command:--language=LANGUAGE}} Programming language. Supported values: %3$s.
173
+ {{command:--language=LANGUAGE}} Programming language. Defaults to wasm. Supported values: %3$s.
168
174
  HELP
169
175
 
170
176
  error: {
@@ -191,9 +197,7 @@ module Script
191
197
  HELP
192
198
 
193
199
  error: {
194
- operation_failed_no_uuid: "UUID is required to push in a CI environment.",
195
- operation_failed_with_api_key: "Couldn't push script to app (API key: %{api_key}).",
196
- operation_failed_no_api_key: "Couldn't push script to app.",
200
+ operation_failed: "Couldn't push script to app.",
197
201
  },
198
202
 
199
203
  script_pushed: "{{v}} Script pushed to app (API key: %{api_key}).",
@@ -206,8 +210,6 @@ module Script
206
210
  HELP
207
211
  error: {
208
212
  operation_failed: "Couldn't connect script to app.",
209
- missing_env_file_variables: "The following variables are missing in the .env file: %s."\
210
- " To connect the script to an app, enter the value into the .env file or delete the .env file, and then run {{command:%s script connect}}",
211
213
  },
212
214
  },
213
215
  javy: {
@@ -233,7 +235,6 @@ module Script
233
235
  forms: {
234
236
  create: {
235
237
  select_extension_point: "Which Script API do you want to use?",
236
- select_language: "Which language do you want to use?",
237
238
  script_name: "What do you want to name your script?",
238
239
  },
239
240
  },
@@ -237,6 +237,19 @@ module Script
237
237
  ),
238
238
  help_suggestion: ShopifyCLI::Context.message("script.error.graphql_error_help"),
239
239
  }
240
+ when Layers::Infrastructure::Errors::InvalidEnvironmentError
241
+ {
242
+ cause_of_error: ShopifyCLI::Context.message(
243
+ "script.error.invalid_environment_cause",
244
+ tool: e.tool,
245
+ env_version: e.env_version,
246
+ minimum_version: e.minimum_version,
247
+ ),
248
+ help_suggestion: ShopifyCLI::Context.message(
249
+ "script.error.invalid_environment_help",
250
+ tool: e.tool,
251
+ ),
252
+ }
240
253
  when Layers::Infrastructure::Errors::SystemCallFailureError
241
254
  {
242
255
  cause_of_error: ShopifyCLI::Context
@@ -4,7 +4,6 @@ require "theme_check"
4
4
  module Theme
5
5
  class Command
6
6
  class Check < ShopifyCLI::Command::SubCommand
7
- recommend_default_node_range
8
7
  recommend_default_ruby_range
9
8
 
10
9
  class Options < ShopifyCLI::Options
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Theme
4
+ class Command
5
+ module Common
6
+ module RootHelper
7
+ def root_value(options, name)
8
+ argv = default_argv(options)
9
+ command_index = argv.index(name.to_s)
10
+
11
+ return "." if command_index.nil?
12
+
13
+ next_index = command_index + 1
14
+ option_by_key = options_map(options)
15
+
16
+ while next_index < argv.size
17
+ element = argv[next_index]
18
+ option = option_by_key[element]
19
+
20
+ return element if option.nil?
21
+
22
+ # Skip the option argument
23
+ next_index += 1 unless option.arg.nil?
24
+
25
+ # PATTERN arguments take precedence over the `root`
26
+ if option.arg =~ /PATTERN/
27
+ next_index += 1 while option_argument?(argv, next_index, option_by_key)
28
+ next
29
+ end
30
+
31
+ next_index += 1
32
+ end
33
+
34
+ "."
35
+ end
36
+
37
+ private
38
+
39
+ def default_argv(options)
40
+ options.parser.default_argv
41
+ end
42
+
43
+ def options_map(options)
44
+ map = {}
45
+ options_list(options).each do |option|
46
+ map[option.short.first] = option
47
+ map[option.long.first] = option
48
+ end
49
+ map
50
+ end
51
+
52
+ def options_list(options)
53
+ options.parser.top.list
54
+ end
55
+
56
+ def option_argument?(argv, next_index, option_by_key)
57
+ return false unless next_index < argv.size
58
+
59
+ element = argv[next_index]
60
+ option_by_key[element].nil?
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -5,7 +5,6 @@ require "shopify_cli/theme/development_theme"
5
5
  module Theme
6
6
  class Command
7
7
  class Delete < ShopifyCLI::Command::SubCommand
8
- recommend_default_node_range
9
8
  recommend_default_ruby_range
10
9
 
11
10
  options do |parser, flags|
@@ -3,13 +3,14 @@
3
3
  module Theme
4
4
  class Command
5
5
  class Init < ShopifyCLI::Command::SubCommand
6
- recommend_default_node_range
7
6
  recommend_default_ruby_range
8
7
 
9
8
  options do |parser, flags|
10
9
  parser.on("-u", "--clone-url URL") { |url| flags[:clone_url] = url }
11
10
  end
12
11
 
12
+ prerequisite_task :ensure_git_dependency
13
+
13
14
  DEFAULT_CLONE_URL = "https://github.com/Shopify/dawn.git"
14
15
 
15
16
  def call(args, _name)
@@ -4,7 +4,6 @@ require "theme_check"
4
4
  module Theme
5
5
  class Command
6
6
  class LanguageServer < ShopifyCLI::Command::SubCommand
7
- recommend_default_node_range
8
7
  recommend_default_ruby_range
9
8
 
10
9
  def call(*)
@@ -5,7 +5,6 @@ require "json"
5
5
  module Theme
6
6
  class Command
7
7
  class Package < ShopifyCLI::Command::SubCommand
8
- recommend_default_node_range
9
8
  recommend_default_ruby_range
10
9
 
11
10
  THEME_DIRECTORIES = %w[
@@ -4,7 +4,6 @@ require "shopify_cli/theme/theme"
4
4
  module Theme
5
5
  class Command
6
6
  class Publish < ShopifyCLI::Command::SubCommand
7
- recommend_default_node_range
8
7
  recommend_default_ruby_range
9
8
 
10
9
  options do |parser, flags|
@@ -1,38 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
  require "shopify_cli/theme/theme"
3
+ require "shopify_cli/theme/development_theme"
3
4
  require "shopify_cli/theme/ignore_filter"
4
5
  require "shopify_cli/theme/include_filter"
5
6
  require "shopify_cli/theme/syncer"
7
+ require "project_types/theme/commands/common/root_helper"
8
+ require "project_types/theme/conversions/include_glob"
9
+ require "project_types/theme/conversions/ignore_glob"
6
10
 
7
11
  module Theme
8
12
  class Command
9
13
  class Pull < ShopifyCLI::Command::SubCommand
10
- recommend_default_node_range
14
+ include Common::RootHelper
15
+
11
16
  recommend_default_ruby_range
12
17
 
13
18
  options do |parser, flags|
19
+ Conversions::IncludeGlob.register(parser)
20
+ Conversions::IgnoreGlob.register(parser)
21
+
14
22
  parser.on("-n", "--nodelete") { flags[:nodelete] = true }
15
23
  parser.on("-i", "--themeid=ID") { |theme_id| flags[:theme_id] = theme_id }
16
24
  parser.on("-t", "--theme=NAME_OR_ID") { |theme| flags[:theme] = theme }
17
25
  parser.on("-l", "--live") { flags[:live] = true }
18
26
  parser.on("-d", "--development") { flags[:development] = true }
19
- parser.on("-o", "--only=PATTERN") do |pattern|
27
+ parser.on("-o", "--only=PATTERN", Conversions::IncludeGlob) do |pattern|
20
28
  flags[:includes] ||= []
21
- flags[:includes] << pattern
29
+ flags[:includes] += pattern
22
30
  end
23
- parser.on("-x", "--ignore=PATTERN") do |pattern|
31
+ parser.on("-x", "--ignore=PATTERN", Conversions::IgnoreGlob) do |pattern|
24
32
  flags[:ignores] ||= []
25
- flags[:ignores] << pattern
33
+ flags[:ignores] += pattern
26
34
  end
27
35
  end
28
36
 
29
- def call(args, _name)
30
- root = args.first || "."
37
+ def call(_args, name)
38
+ root = root_value(options, name)
31
39
  delete = !options.flags[:nodelete]
32
40
  theme = find_theme(root, **options.flags)
33
41
  return if theme.nil?
34
42
 
35
- include_filter = ShopifyCLI::Theme::IncludeFilter.new(options.flags[:includes])
43
+ include_filter = ShopifyCLI::Theme::IncludeFilter.new(root, options.flags[:includes])
36
44
  ignore_filter = ShopifyCLI::Theme::IgnoreFilter.from_path(root)
37
45
  ignore_filter.add_patterns(options.flags[:ignores]) if options.flags[:ignores]
38
46
 
@@ -74,7 +82,8 @@ module Theme
74
82
  end
75
83
 
76
84
  if development
77
- return ShopifyCLI::Theme::Theme.development(@ctx, root: root)
85
+ dev_theme = ShopifyCLI::Theme::DevelopmentTheme.find(@ctx, root: root)
86
+ return dev_theme || @ctx.abort(@ctx.message("theme.pull.theme_not_found", "development"))
78
87
  end
79
88
 
80
89
  select_theme(root)