shopify-cli 2.9.0 → 2.11.0

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.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.yaml +117 -0
  3. data/.github/ISSUE_TEMPLATE/enhancement.yaml +38 -0
  4. data/.github/ISSUE_TEMPLATE/feature.yaml +47 -0
  5. data/.github/ISSUE_TEMPLATE.md +18 -0
  6. data/CHANGELOG.md +38 -5
  7. data/Gemfile.lock +1 -1
  8. data/dev.yml +3 -0
  9. data/lib/project_types/extension/commands/build.rb +3 -0
  10. data/lib/project_types/extension/commands/check.rb +3 -0
  11. data/lib/project_types/extension/commands/create.rb +3 -0
  12. data/lib/project_types/extension/commands/push.rb +3 -0
  13. data/lib/project_types/extension/commands/serve.rb +3 -0
  14. data/lib/project_types/extension/models/specification_handlers/default.rb +1 -1
  15. data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
  16. data/lib/project_types/script/cli.rb +5 -0
  17. data/lib/project_types/script/commands/connect.rb +3 -1
  18. data/lib/project_types/script/commands/create.rb +2 -0
  19. data/lib/project_types/script/commands/push.rb +6 -0
  20. data/lib/project_types/script/config/extension_points.yml +12 -0
  21. data/lib/project_types/script/graphql/app_script_set.graphql +2 -0
  22. data/lib/project_types/script/graphql/module_upload_url_generate.graphql +5 -1
  23. data/lib/project_types/script/layers/application/build_script.rb +6 -3
  24. data/lib/project_types/script/layers/application/project_dependencies.rb +1 -1
  25. data/lib/project_types/script/layers/application/push_script.rb +38 -30
  26. data/lib/project_types/script/layers/domain/errors.rb +10 -3
  27. data/lib/project_types/script/layers/domain/extension_point.rb +2 -2
  28. data/lib/project_types/script/layers/domain/push_package.rb +0 -3
  29. data/lib/project_types/script/layers/domain/script_config.rb +6 -4
  30. data/lib/project_types/script/layers/domain/script_project.rb +1 -0
  31. data/lib/project_types/script/layers/infrastructure/errors.rb +47 -24
  32. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +2 -12
  33. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +1 -0
  34. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +1 -0
  35. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +2 -12
  36. data/lib/project_types/script/layers/infrastructure/languages/wasm_project_creator.rb +15 -0
  37. data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +36 -0
  38. data/lib/project_types/script/layers/infrastructure/metadata_repository.rb +18 -0
  39. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +7 -8
  40. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +45 -54
  41. data/lib/project_types/script/layers/infrastructure/script_service.rb +35 -12
  42. data/lib/project_types/script/layers/infrastructure/script_uploader.rb +22 -9
  43. data/lib/project_types/script/loaders/project.rb +2 -1
  44. data/lib/project_types/script/messages/messages.rb +94 -88
  45. data/lib/project_types/script/ui/error_handler.rb +75 -38
  46. data/lib/project_types/theme/commands/check.rb +3 -0
  47. data/lib/project_types/theme/commands/delete.rb +3 -0
  48. data/lib/project_types/theme/commands/init.rb +3 -0
  49. data/lib/project_types/theme/commands/language_server.rb +3 -0
  50. data/lib/project_types/theme/commands/package.rb +3 -0
  51. data/lib/project_types/theme/commands/publish.rb +3 -0
  52. data/lib/project_types/theme/commands/pull.rb +12 -1
  53. data/lib/project_types/theme/commands/push.rb +12 -1
  54. data/lib/project_types/theme/commands/serve.rb +3 -0
  55. data/lib/project_types/theme/messages/messages.rb +4 -0
  56. data/lib/shopify_cli/command/sub_command.rb +2 -0
  57. data/lib/shopify_cli/command.rb +66 -0
  58. data/lib/shopify_cli/commands/app/create/node.rb +3 -0
  59. data/lib/shopify_cli/commands/app/create/rails.rb +3 -0
  60. data/lib/shopify_cli/commands/app/create.rb +3 -0
  61. data/lib/shopify_cli/commands/app/deploy.rb +3 -0
  62. data/lib/shopify_cli/commands/app/serve.rb +3 -0
  63. data/lib/shopify_cli/commands/login.rb +4 -10
  64. data/lib/shopify_cli/constants.rb +18 -2
  65. data/lib/shopify_cli/core/executor.rb +4 -4
  66. data/lib/shopify_cli/environment.rb +61 -16
  67. data/lib/shopify_cli/exception_reporter.rb +9 -0
  68. data/lib/shopify_cli/github/issue_url_generator.rb +19 -8
  69. data/lib/shopify_cli/identity_auth/env_auth_token.rb +34 -0
  70. data/lib/shopify_cli/identity_auth.rb +36 -18
  71. data/lib/shopify_cli/messages/messages.rb +2 -2
  72. data/lib/shopify_cli/method_object.rb +21 -9
  73. data/lib/shopify_cli/partners_api.rb +7 -2
  74. data/lib/shopify_cli/result.rb +61 -59
  75. data/lib/shopify_cli/services/app/create/rails_service.rb +37 -13
  76. data/lib/shopify_cli/task.rb +5 -3
  77. data/lib/shopify_cli/theme/file.rb +2 -2
  78. data/lib/shopify_cli/theme/filter/path_matcher.rb +38 -0
  79. data/lib/shopify_cli/theme/ignore_filter.rb +14 -18
  80. data/lib/shopify_cli/theme/include_filter.rb +65 -0
  81. data/lib/shopify_cli/theme/syncer.rb +17 -2
  82. data/lib/shopify_cli/utilities.rb +7 -0
  83. data/lib/shopify_cli/version.rb +1 -1
  84. data/lib/shopify_cli.rb +3 -1
  85. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +11 -6
  86. data/vendor/deps/cli-kit/lib/cli/kit/util.rb +5 -1
  87. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +6 -4
  88. data/vendor/deps/ruby2_keywords/LICENSE +22 -0
  89. data/vendor/deps/ruby2_keywords/README.md +67 -0
  90. data/vendor/deps/ruby2_keywords/Rakefile +54 -0
  91. data/vendor/deps/ruby2_keywords/lib/ruby2_keywords.rb +57 -0
  92. data/vendor/deps/ruby2_keywords/ruby2_keywords.gemspec +18 -0
  93. data/vendor/deps/ruby2_keywords/test/test_keyword.rb +41 -0
  94. data/vendor/lib/semantic/version.rb +0 -1
  95. metadata +18 -3
  96. data/lib/project_types/rails/commands/create.rb +0 -210
@@ -66,15 +66,27 @@ module ShopifyCLI
66
66
  # initializer or to `call`. If the keyword argument matches the name of
67
67
  # property, it is forwarded to the initializer, otherwise to call.
68
68
  #
69
- def call(*args, **kwargs, &block)
70
- properties.keys.yield_self do |properties|
71
- instance = new(**kwargs.slice(*properties))
72
- kwargs = kwargs.slice(*(kwargs.keys - properties))
73
- if kwargs.any?
74
- instance.call(*args, **kwargs, &block)
75
- else
76
- instance.call(*args, &block)
77
- end
69
+ ruby2_keywords def call(*args, &block)
70
+ # This is an extremely complicated case of delegation. The method wants
71
+ # to delegate arguments, but to have control over which keyword
72
+ # arguments are delegated. I'm not sure the forward and backward
73
+ # compatibility of this unusual form of delegation has really been
74
+ # explored or there's any good way to support it. So I have done
75
+ # done something hacky here and I'm looking at the last argument and
76
+ # modifying the package of arguments to be delegated in-place.
77
+ if args.last.is_a?(Hash)
78
+ kwargs = args.last
79
+
80
+ initializer_kwargs = kwargs.slice(*properties.keys)
81
+ instance = new(**initializer_kwargs)
82
+
83
+ kwargs.reject! { |key| initializer_kwargs.key?(key) }
84
+ args.pop if kwargs.empty?
85
+ instance.call(*args, &block)
86
+ else
87
+ # Since the former is so complicated - let's have a fast path that
88
+ # is much simpler.
89
+ new.call(*args, &block)
78
90
  end
79
91
  end
80
92
 
@@ -38,7 +38,11 @@ module ShopifyCLI
38
38
  def query(ctx, query_name, **variables)
39
39
  CLI::Kit::Util.begin do
40
40
  api_client(ctx).query(query_name, variables: variables)
41
- end.retry_after(API::APIRequestUnauthorizedError, retries: 1) do
41
+ end.retry_after(
42
+ API::APIRequestUnauthorizedError,
43
+ retries: 1,
44
+ only: -> { !IdentityAuth::EnvAuthToken.partners_token_present? }
45
+ ) do
42
46
  ShopifyCLI::IdentityAuth.new(ctx: ctx).reauthenticate
43
47
  end
44
48
  rescue API::APIRequestUnauthorizedError => e
@@ -60,9 +64,10 @@ module ShopifyCLI
60
64
  private
61
65
 
62
66
  def api_client(ctx)
67
+ identity_auth = ShopifyCLI::IdentityAuth.new(ctx: ctx)
63
68
  new(
64
69
  ctx: ctx,
65
- token: IdentityAuth.fetch_or_auth_partners_token(ctx: ctx),
70
+ token: identity_auth.fetch_or_auth_partners_token,
66
71
  url: "https://#{Environment.partners_domain}/api/cli/graphql",
67
72
  )
68
73
  end
@@ -363,70 +363,72 @@ module ShopifyCLI
363
363
  Result::Failure.new(error)
364
364
  end
365
365
 
366
- ##
367
- # takes either a value or a block and chooses the appropriate result
368
- # container based on the type of the value or the type of the block's return
369
- # value. If the type is an exception, it is wrapped in a
370
- # `ShopifyCLI::Result::Failure` and otherwise in a
371
- # `ShopifyCLI::Result::Success`. If a block was provided instead of value, a
372
- # `Proc` is returned and the result wrapping doesn't occur until the block
373
- # is invoked.
374
- #
375
- # #### Parameters
376
- #
377
- # * `*args` should be an `Array` with zero or one element
378
- # * `&block` should be a `Proc` that takes zero or one argument
379
- #
380
- # #### Returns
381
- #
382
- # Returns either a `Result::Success`, `Result::Failure` or a `Proc` that
383
- # produces one of the former when invoked.
384
- #
385
- # #### Examples
386
- #
387
- # Result.wrap(1) # => ShopifyCLI::Result::Success
388
- # Result.wrap(RuntimeError.new) # => ShopifyCLI::Result::Failure
389
- #
390
- # Result.wrap { 1 } # => Proc
391
- # Result.wrap { 1 }.call # => ShopifyCLI::Result::Success
392
- # Result.wrap { raise }.call # => ShopifyCLI::Result::Failure
393
- #
394
- # Result.wrap { |s| s.upcase }.call("hello").tap do |result|
395
- # result # => Result::Success
396
- # result.value # => "HELLO"
397
- # end
398
- #
399
- def self.wrap(*values, &block)
400
- raise ArgumentError, "expected either a value or a block" unless (values.length == 1) ^ block
366
+ class << self
367
+ ##
368
+ # takes either a value or a block and chooses the appropriate result
369
+ # container based on the type of the value or the type of the block's return
370
+ # value. If the type is an exception, it is wrapped in a
371
+ # `ShopifyCli::Result::Failure` and otherwise in a
372
+ # `ShopifyCli::Result::Success`. If a block was provided instead of value, a
373
+ # `Proc` is returned and the result wrapping doesn't occur until the block
374
+ # is invoked.
375
+ #
376
+ # #### Parameters
377
+ #
378
+ # * `*args` should be an `Array` with zero or one element
379
+ # * `&block` should be a `Proc` that takes zero or one argument
380
+ #
381
+ # #### Returns
382
+ #
383
+ # Returns either a `Result::Success`, `Result::Failure` or a `Proc` that
384
+ # produces one of the former when invoked.
385
+ #
386
+ # #### Examples
387
+ #
388
+ # Result.wrap(1) # => ShopifyCli::Result::Success
389
+ # Result.wrap(RuntimeError.new) # => ShopifyCli::Result::Failure
390
+ #
391
+ # Result.wrap { 1 } # => Proc
392
+ # Result.wrap { 1 }.call # => ShopifyCli::Result::Success
393
+ # Result.wrap { raise }.call # => ShopifyCli::Result::Failure
394
+ #
395
+ # Result.wrap { |s| s.upcase }.call("hello").tap do |result|
396
+ # result # => Result::Success
397
+ # result.value # => "HELLO"
398
+ # end
399
+ #
400
+ ruby2_keywords def wrap(*values, &block)
401
+ raise ArgumentError, "expected either a value or a block" unless (values.length == 1) ^ block
401
402
 
402
- if values.length == 1
403
- values.pop.yield_self do |value|
404
- case value
405
- when Result::Success, Result::Failure
406
- value
407
- when NilClass, Exception
408
- Result.failure(value)
409
- else
410
- Result.success(value)
411
- end
412
- end
413
- else
414
- ->(*args) do
415
- begin
416
- wrap(block.call(*args))
417
- rescue Exception => error # rubocop:disable Lint/RescueException
418
- wrap(error)
403
+ if values.length == 1
404
+ values.pop.yield_self do |value|
405
+ case value
406
+ when Result::Success, Result::Failure
407
+ value
408
+ when NilClass, Exception
409
+ Result.failure(value)
410
+ else
411
+ Result.success(value)
412
+ end
419
413
  end
414
+ else
415
+ ->(*args) do
416
+ begin
417
+ wrap(block.call(*args))
418
+ rescue Exception => error # rubocop:disable Lint/RescueException
419
+ wrap(error)
420
+ end
421
+ end.ruby2_keywords
420
422
  end
421
423
  end
422
- end
423
424
 
424
- ##
425
- # Wraps the given block and invokes it with the passed arguments.
426
- #
427
- def self.call(*args, &block)
428
- raise ArgumentError, "expected a block" unless block
429
- wrap(&block).call(*args)
425
+ ##
426
+ # Wraps the given block and invokes it with the passed arguments.
427
+ #
428
+ ruby2_keywords def call(*args, &block)
429
+ raise ArgumentError, "expected a block" unless block
430
+ wrap(&block).call(*args)
431
+ end
430
432
  end
431
433
  end
432
434
  end
@@ -41,12 +41,7 @@ module ShopifyCLI
41
41
 
42
42
  raise ShopifyCLI::AbortSilent if form.nil?
43
43
 
44
- ruby_version = Rails::Ruby.version(context)
45
- context.abort(context.message("core.app.create.rails.error.invalid_ruby_version")) unless
46
- ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.0.0")
47
-
48
- check_node
49
- check_yarn
44
+ check_dependencies
50
45
 
51
46
  build(form.name, form.db)
52
47
  set_custom_ua
@@ -106,6 +101,18 @@ module ShopifyCLI
106
101
  end
107
102
  end
108
103
 
104
+ def check_dependencies
105
+ check_ruby
106
+ check_node
107
+ check_yarn
108
+ end
109
+
110
+ def check_ruby
111
+ ruby_version = Rails::Ruby.version(context)
112
+ return if ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.0.0")
113
+ context.abort(context.message("core.app.create.rails.error.invalid_ruby_version"))
114
+ end
115
+
109
116
  def check_node
110
117
  cmd_path = context.which("node")
111
118
  if cmd_path.nil?
@@ -148,11 +155,13 @@ module ShopifyCLI
148
155
  end
149
156
 
150
157
  def build(name, db)
151
- context.abort(context.message("core.app.create.rails.error.install_failure",
152
- "rails")) unless install_gem("rails",
153
- "<6.1")
154
- context.abort(context.message("core.app.create.rails.error.install_failure", "bundler ~>2.0")) unless
155
- install_gem("bundler", "~>2.0")
158
+ unless install_gem("rails")
159
+ context.abort(context.message("core.app.create.rails.error.install_failure", "rails"))
160
+ end
161
+
162
+ unless install_gem("bundler", "~>2.0")
163
+ context.abort(context.message("core.app.create.rails.error.install_failure", "bundler ~>2.0"))
164
+ end
156
165
 
157
166
  full_path = File.join(context.root, name)
158
167
  context.abort(context.message("core.app.create.rails.error.dir_exists", name)) if Dir.exist?(full_path)
@@ -173,7 +182,7 @@ module ShopifyCLI
173
182
 
174
183
  context.puts(context.message("core.app.create.rails.adding_shopify_gem"))
175
184
  File.open(File.join(context.root, "Gemfile"), "a") do |f|
176
- f.puts "\ngem 'shopify_app', '>=17.0.3'"
185
+ f.puts "\ngem 'shopify_app', '>=18.1.0'"
177
186
  end
178
187
  CLI::UI::Frame.open(context.message("core.app.create.rails.running_bundle_install")) do
179
188
  syscall(%w(bundle install))
@@ -188,7 +197,7 @@ module ShopifyCLI
188
197
  syscall(%w(rails db:migrate RAILS_ENV=development))
189
198
  end
190
199
 
191
- unless File.exist?(File.join(context.root, "config/webpacker.yml"))
200
+ if install_webpacker?
192
201
  CLI::UI::Frame.open(context.message("core.app.create.rails.running_webpacker_install")) do
193
202
  syscall(%w(rails webpacker:install))
194
203
  end
@@ -208,6 +217,21 @@ module ShopifyCLI
208
217
  def install_gem(name, version = nil)
209
218
  Rails::Gem.install(context, name, version)
210
219
  end
220
+
221
+ def install_webpacker?
222
+ rails_version < ::Semantic::Version.new("7.0.0") &&
223
+ !File.exist?(File.join(context.root, "config/webpacker.yml"))
224
+ end
225
+
226
+ def rails_version
227
+ output, status = context.capture2e("rails", "--version")
228
+ unless status.success?
229
+ context.abort(context.message("core.app.create.rails.error.install_failure", "rails"))
230
+ end
231
+
232
+ version = output.scan(/Rails \d+\.\d+\.\d+/).first.split(" ").last
233
+ ::Semantic::Version.new(version)
234
+ end
211
235
  end
212
236
  end
213
237
  end
@@ -2,9 +2,11 @@ require "shopify_cli"
2
2
 
3
3
  module ShopifyCLI
4
4
  class Task
5
- def self.call(*args, **kwargs)
6
- task = new
7
- task.call(*args, **kwargs)
5
+ class << self
6
+ ruby2_keywords def call(*args)
7
+ task = new
8
+ task.call(*args)
9
+ end
8
10
  end
9
11
 
10
12
  private
@@ -18,7 +18,7 @@ module ShopifyCLI
18
18
 
19
19
  def read
20
20
  if text?
21
- path.read
21
+ path.read(universal_newline: true)
22
22
  else
23
23
  path.read(mode: "rb")
24
24
  end
@@ -27,7 +27,7 @@ module ShopifyCLI
27
27
  def write(content)
28
28
  path.parent.mkpath unless path.parent.directory?
29
29
  if text?
30
- path.write(content)
30
+ path.write(content, universal_newline: true)
31
31
  else
32
32
  path.write(content, 0, mode: "wb")
33
33
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ShopifyCLI
4
+ module Theme
5
+ module Filter
6
+ module PathMatcher
7
+ def regex_match?(regex, path)
8
+ regex.match?(path)
9
+ rescue StandardError
10
+ false
11
+ end
12
+
13
+ def glob_match?(glob, path)
14
+ !!::File.fnmatch?(glob, path)
15
+ end
16
+
17
+ def regex?(pattern)
18
+ pattern.start_with?("/") && pattern.end_with?("/")
19
+ end
20
+
21
+ def as_regex(pattern)
22
+ Regexp.new(pattern.gsub(%r{^\/|\/$}, ""))
23
+ end
24
+
25
+ def as_glob(pattern)
26
+ # if specifying a directory, match everything below it
27
+ pattern += "*" if pattern.end_with?("/")
28
+
29
+ # The pattern will be scoped to root directory, so it should match anything
30
+ # within that space
31
+ pattern.prepend("*") unless pattern.start_with?("*")
32
+
33
+ pattern
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "filter/path_matcher"
4
+
3
5
  module ShopifyCLI
4
6
  module Theme
5
7
  class IgnoreFilter
8
+ include Filter::PathMatcher
9
+
6
10
  FILE = ".shopifyignore"
7
11
 
8
12
  DEFAULT_REGEXES = [
@@ -72,11 +76,11 @@ module ShopifyCLI
72
76
  return true if path.empty?
73
77
 
74
78
  regexes.each do |regex|
75
- return true if regex.match(path)
79
+ return true if regex_match?(regex, path)
76
80
  end
77
81
 
78
82
  globs.each do |glob|
79
- return true if ::File.fnmatch?(glob, path)
83
+ return true if glob_match?(glob, path)
80
84
  end
81
85
 
82
86
  false
@@ -91,24 +95,16 @@ module ShopifyCLI
91
95
  new_regexes = DEFAULT_REGEXES.dup
92
96
  new_globs = DEFAULT_GLOBS.dup
93
97
 
94
- patterns.each do |pattern|
95
- pattern = pattern.strip
96
-
97
- if pattern.start_with?("/") && pattern.end_with?("/")
98
- new_regexes << Regexp.new(pattern.gsub(%r{^\/|\/$}, ""))
99
- next
98
+ patterns
99
+ .map(&:strip)
100
+ .each do |pattern|
101
+ if regex?(pattern)
102
+ new_regexes << as_regex(pattern)
103
+ else
104
+ new_globs << as_glob(pattern)
105
+ end
100
106
  end
101
107
 
102
- # if specifying a directory, match everything below it
103
- pattern += "*" if pattern.end_with?("/")
104
-
105
- # The pattern will be scoped to root directory, so it should match anything
106
- # within that space
107
- pattern.prepend("*") unless pattern.start_with?("*")
108
-
109
- new_globs << pattern
110
- end
111
-
112
108
  [new_regexes, new_globs]
113
109
  end
114
110
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "filter/path_matcher"
4
+
5
+ module ShopifyCLI
6
+ module Theme
7
+ class IncludeFilter
8
+ include Filter::PathMatcher
9
+
10
+ attr_reader :globs, :regexes
11
+
12
+ def initialize(patterns = [])
13
+ @patterns = patterns.nil? ? [] : patterns.compact.reject(&:empty?)
14
+
15
+ regexes, globs = patterns_to_regexes_and_globs(@patterns)
16
+
17
+ @regexes = regexes
18
+ @globs = globs
19
+ end
20
+
21
+ def match?(path)
22
+ return true unless present?(@patterns)
23
+
24
+ path = path.to_s
25
+
26
+ return true if path.empty?
27
+
28
+ regexes.each do |regex|
29
+ return true if regex_match?(regex, path)
30
+ end
31
+
32
+ globs.each do |glob|
33
+ return true if glob_match?(glob, path)
34
+ end
35
+
36
+ false
37
+ end
38
+
39
+ private
40
+
41
+ def present?(patterns)
42
+ !patterns.nil? && !patterns.empty?
43
+ end
44
+
45
+ # Take in string patterns and convert them to either
46
+ # regex patterns or glob patterns so that they are handled in an expected manner.
47
+ def patterns_to_regexes_and_globs(patterns)
48
+ new_regexes = []
49
+ new_globs = []
50
+
51
+ patterns
52
+ .map(&:strip)
53
+ .each do |pattern|
54
+ if regex?(pattern)
55
+ new_regexes << as_regex(pattern)
56
+ else
57
+ new_globs << as_glob(pattern)
58
+ end
59
+ end
60
+
61
+ [new_regexes, new_globs]
62
+ end
63
+ end
64
+ end
65
+ end
@@ -16,13 +16,15 @@ module ShopifyCLI
16
16
  API_VERSION = "unstable"
17
17
 
18
18
  attr_reader :checksums
19
+ attr_accessor :include_filter
19
20
  attr_accessor :ignore_filter
20
21
 
21
22
  def_delegators :@error_reporter, :has_any_error?
22
23
 
23
- def initialize(ctx, theme:, ignore_filter: nil)
24
+ def initialize(ctx, theme:, include_filter: nil, ignore_filter: nil)
24
25
  @ctx = ctx
25
26
  @theme = theme
27
+ @include_filter = include_filter
26
28
  @ignore_filter = ignore_filter
27
29
  @error_reporter = ErrorReporter.new(ctx)
28
30
  @standard_reporter = StandardReporter.new(ctx)
@@ -193,7 +195,7 @@ module ShopifyCLI
193
195
  # Already enqueued
194
196
  return if @pending.include?(operation)
195
197
 
196
- if @ignore_filter&.ignore?(operation.file_path)
198
+ if ignore?(operation)
197
199
  @ctx.debug("ignore #{operation.file_path}")
198
200
  return
199
201
  end
@@ -251,6 +253,19 @@ module ShopifyCLI
251
253
  response
252
254
  end
253
255
 
256
+ def ignore?(operation)
257
+ path = operation.file_path
258
+ ignored_by_ignore_filter?(path) || ignored_by_include_filter?(path)
259
+ end
260
+
261
+ def ignored_by_ignore_filter?(path)
262
+ ignore_filter&.ignore?(path)
263
+ end
264
+
265
+ def ignored_by_include_filter?(path)
266
+ include_filter && !include_filter.match?(path)
267
+ end
268
+
254
269
  def get(file)
255
270
  _status, body, response = ShopifyCLI::AdminAPI.rest_request(
256
271
  @ctx,
@@ -0,0 +1,7 @@
1
+ module ShopifyCLI
2
+ module Utilities
3
+ def self.version_dropping_pre_and_build(version)
4
+ Semantic::Version.new("#{version.major}.#{version.minor}.#{version.patch}")
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.9.0"
2
+ VERSION = "2.11.0"
3
3
  end
data/lib/shopify_cli.rb CHANGED
@@ -15,12 +15,13 @@ ENV["PATH"] = ENV["PATH"].split(":").select { |p| p.start_with?("/", "~") }.join
15
15
  vendor_path = File.expand_path("../../vendor/lib", __FILE__)
16
16
  $LOAD_PATH.unshift(vendor_path) unless $LOAD_PATH.include?(vendor_path)
17
17
 
18
- deps = %w(cli-ui cli-kit smart_properties webrick)
18
+ deps = %w(cli-ui cli-kit smart_properties ruby2_keywords webrick)
19
19
  deps.each do |dep|
20
20
  vendor_path = File.expand_path("../../vendor/deps/#{dep}/lib", __FILE__)
21
21
  $LOAD_PATH.unshift(vendor_path) unless $LOAD_PATH.include?(vendor_path)
22
22
  end
23
23
 
24
+ require "ruby2_keywords"
24
25
  require "cli/ui"
25
26
  require "cli/kit"
26
27
  require "smart_properties"
@@ -135,6 +136,7 @@ module ShopifyCLI
135
136
  autoload :Tasks, "shopify_cli/tasks"
136
137
  autoload :TransformDataStructure, "shopify_cli/transform_data_structure"
137
138
  autoload :Tunnel, "shopify_cli/tunnel"
139
+ autoload :Utilities, "shopify_cli/utilities"
138
140
 
139
141
  require "shopify_cli/messages/messages"
140
142
  Context.load_messages(ShopifyCLI::Messages::MESSAGES)
@@ -174,11 +174,16 @@ module CLI
174
174
  end
175
175
 
176
176
  def os
177
- return :mac if /darwin/.match(RUBY_PLATFORM)
178
- return :linux if /linux/.match(RUBY_PLATFORM)
179
- return :windows if /mingw32/.match(RUBY_PLATFORM)
180
-
181
- raise "Could not determine OS from platform #{RUBY_PLATFORM}"
177
+ @current_os ||= case RbConfig::CONFIG['host_os']
178
+ when /darwin/ then :mac
179
+ when /linux/ then :linux
180
+ else
181
+ if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
182
+ :windows
183
+ else
184
+ raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
185
+ end
186
+ end
182
187
  end
183
188
 
184
189
  private
@@ -222,7 +227,7 @@ module CLI
222
227
  end
223
228
 
224
229
  def which(cmd, env)
225
- exts = os == :windows ? env.fetch('PATHEXT', ['']).split(';') : ['']
230
+ exts = (os == :windows && env['PATHEXT']&.split(';')) || ['']
226
231
  env.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |path|
227
232
  exts.each do |ext|
228
233
  exe = File.join(path, "#{cmd}#{ext}")
@@ -168,9 +168,13 @@ module CLI
168
168
  @block_that_might_raise = block_that_might_raise
169
169
  end
170
170
 
171
- def retry_after(exception = StandardError, retries: 1, &before_retry)
171
+ def retry_after(exception = StandardError, retries: 1, only: nil, &before_retry)
172
172
  @block_that_might_raise.call
173
173
  rescue exception => e
174
+ should_retry = only ? only.call : true
175
+
176
+ raise unless should_retry
177
+
174
178
  raise if (retries -= 1) < 0
175
179
  if before_retry
176
180
  if before_retry.arity == 0
@@ -4,15 +4,17 @@ module CLI
4
4
  # Determines which OS is currently running the UI, to make it easier to
5
5
  # adapt its behaviour to the features of the OS.
6
6
  def self.current
7
- @current_os ||= case RUBY_PLATFORM
7
+ @current_os ||= case RbConfig::CONFIG['host_os']
8
8
  when /darwin/
9
9
  Mac
10
10
  when /linux/
11
11
  Linux
12
- when /mingw32/
13
- Windows
14
12
  else
15
- raise "Could not determine OS from platform #{RUBY_PLATFORM}"
13
+ if RUBY_PLATFORM !~ /cygwin/ && ENV['OS'] == 'Windows_NT'
14
+ Windows
15
+ else
16
+ raise "Could not determine OS from host_os #{RbConfig::CONFIG["host_os"]}"
17
+ end
16
18
  end
17
19
  end
18
20
 
@@ -0,0 +1,22 @@
1
+ Copyright 2019-2020 Nobuyoshi Nakada, Yusuke Endoh
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this
7
+ list of conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.