shopify-cli 2.16.1 → 2.17.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +1 -1
  4. data/lib/project_types/extension/cli.rb +1 -0
  5. data/lib/project_types/extension/commands/build.rb +0 -2
  6. data/lib/project_types/extension/commands/serve.rb +8 -3
  7. data/lib/project_types/extension/features/argo_serve.rb +1 -1
  8. data/lib/project_types/extension/models/server_config/capabilities.rb +11 -0
  9. data/lib/project_types/extension/models/server_config/extension.rb +10 -3
  10. data/lib/project_types/extension/models/specification_handlers/checkout_ui_extension.rb +1 -1
  11. data/lib/project_types/extension/tasks/convert_server_config.rb +7 -3
  12. data/lib/project_types/extension/tasks/merge_server_config.rb +4 -2
  13. data/lib/project_types/script/cli.rb +1 -0
  14. data/lib/project_types/script/config/extension_points.yml +15 -3
  15. data/lib/project_types/script/graphql/app_script_set.graphql +2 -0
  16. data/lib/project_types/script/layers/application/push_script.rb +1 -0
  17. data/lib/project_types/script/layers/domain/app_bridge.rb +16 -0
  18. data/lib/project_types/script/layers/domain/script_project.rb +1 -0
  19. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +12 -0
  20. data/lib/project_types/script/layers/infrastructure/script_service.rb +5 -0
  21. data/lib/project_types/theme/commands/serve.rb +27 -0
  22. data/lib/project_types/theme/messages/messages.rb +13 -0
  23. data/lib/shopify_cli/admin_api.rb +1 -1
  24. data/lib/shopify_cli/commands/login.rb +2 -2
  25. data/lib/shopify_cli/context.rb +1 -1
  26. data/lib/shopify_cli/theme/dev_server/hot_reload/sections_index.rb +5 -6
  27. data/lib/shopify_cli/theme/dev_server/watcher.rb +2 -1
  28. data/lib/shopify_cli/theme/dev_server.rb +1 -1
  29. data/lib/shopify_cli/theme/development_theme.rb +11 -1
  30. data/lib/shopify_cli/theme/file.rb +9 -0
  31. data/lib/shopify_cli/theme/theme_admin_api.rb +3 -1
  32. data/lib/shopify_cli/version.rb +1 -1
  33. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 671c2f790725e98a8ff2cd52ba3e82bfba8602119b9438e935f5762b2369944d
4
- data.tar.gz: 3636ef6682230d30d507f1e721771a52230fa6dedda9537b56ecd133729d5ddf
3
+ metadata.gz: e3acc31975c1b9d6478fe3f5d39ebf4ca0550b5956dc22dd4710103ae77bb0b4
4
+ data.tar.gz: 2cbf01bd46b9d3d175b6b4f534f28b52ce69972125169a243788d922a68bf19a
5
5
  SHA512:
6
- metadata.gz: 90a96e0a4357d43118ed0417e310042327e520ac4ecfc3c6789a66a2acc502f908c99ce54b16768b56975ad8a83ca9e74f23d2f14fa2475083b2e46f126f238d
7
- data.tar.gz: f969943491bee41c44c172984942d8ee406e6e9bbbf95556b93f4843978925b127db0d52f52d961d19fff7ede178b990db25e83ff7a19dd0107f6ce040d50f6d
6
+ metadata.gz: 7999265576034095a1114c3a29a2ab9bbaee62bac8c29b26b79d2c724b8be1dbc045e0da7c94a1863e465545bd7be32851f2f36ae1b020a269346d4417c0008c
7
+ data.tar.gz: e5affc3532841d156305192ad2aa775065a9571a7bbf8ee6ab7b56d7f5d62c7a30407cf25e658bb99283d8429eb1b009ff406651fa7915c9e2a07508923be993
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@ 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.17.0 - 2022-05-12
6
+
7
+ ### Added
8
+ * [#2262](https://github.com/Shopify/shopify-cli/pull/2262): Add `capabilities` permissions to checkout extensions config
9
+ * [#2292](https://github.com/Shopify/shopify-cli/pull/2292): Add support for App Bridge create/details URLs for scripts
10
+
11
+ ### Fixed
12
+ * [#2287](https://github.com/Shopify/shopify-cli/pull/2287): Fix `Encoding::UndefinedConversionError` on `theme serve` and `theme pull`
13
+ * [#2310](https://github.com/Shopify/shopify-cli/pull/2310): Fix live-reload to be resilient and no longer raise an error when a locale file is invalid
14
+ * [#2297](https://github.com/Shopify/shopify-cli/pull/2297): Only show update message when the new version is higher
15
+ * [#2270](https://github.com/Shopify/shopify-cli/pull/2270): Use ignore filter regex in watcher class
16
+
17
+ ### Changed
18
+ * [#2299](https://github.com/Shopify/shopify-cli/pull/2299): Improve the unauthorized API errors when doing theme development
19
+
5
20
  ## Version 2.16.1 - 2022-04-26
6
21
 
7
22
  ### Fixed
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify-cli (2.16.1)
4
+ shopify-cli (2.17.0)
5
5
  bugsnag (~> 6.22)
6
6
  listen (~> 3.7.0)
7
7
  theme-check (~> 1.10.1)
@@ -122,6 +122,7 @@ module Extension
122
122
  module ServerConfig
123
123
  autoload :Base, Project.project_filepath("models/server_config/base")
124
124
  autoload :App, Project.project_filepath("models/server_config/app")
125
+ autoload :Capabilities, Project.project_filepath("models/server_config/capabilities")
125
126
  autoload :Development, Project.project_filepath("models/server_config/development")
126
127
  autoload :DevelopmentEntries, Project.project_filepath("models/server_config/development_entries")
127
128
  autoload :DevelopmentRenderer, Project.project_filepath("models/server_config/development_renderer")
@@ -4,8 +4,6 @@ require "shopify_cli"
4
4
  module Extension
5
5
  class Command
6
6
  class Build < ExtensionCommand
7
- hidden_feature
8
-
9
7
  prerequisite_task ensure_project_type: :extension
10
8
 
11
9
  YARN_BUILD_COMMAND = %w(build)
@@ -14,6 +14,9 @@ module Extension
14
14
  parser.on("--resourceUrl=RESOURCE_URL", "Provide a resource URL") do |resource_url|
15
15
  flags[:resource_url] = resource_url
16
16
  end
17
+ parser.on("-p", "--port=PORT", "Specify the port to use") do |port|
18
+ flags[:port] = port.to_i
19
+ end
17
20
  end
18
21
 
19
22
  class RuntimeConfiguration
@@ -22,13 +25,14 @@ module Extension
22
25
  property :tunnel_url, accepts: String, default: nil
23
26
  property :resource_url, accepts: String, default: nil
24
27
  property! :tunnel_requested, accepts: [true, false], reader: :tunnel_requested?, default: true
25
- property! :port, accepts: (1...(2**16)), default: DEFAULT_PORT
28
+ property :port, accepts: (1...(2**16))
26
29
  end
27
30
 
28
31
  def call(_args, _command_name)
29
32
  config = RuntimeConfiguration.new(
30
33
  tunnel_requested: tunnel_requested?,
31
- resource_url: options.flags[:resource_url]
34
+ resource_url: options.flags[:resource_url],
35
+ port: options.flags[:port]
32
36
  )
33
37
 
34
38
  ShopifyCLI::Result
@@ -51,10 +55,11 @@ module Extension
51
55
  end
52
56
 
53
57
  def find_available_port(runtime_configuration)
58
+ return runtime_configuration unless runtime_configuration.port.nil?
54
59
  return runtime_configuration unless specification_handler.choose_port?(@ctx)
55
60
 
56
61
  chosen_port = Tasks::ChooseNextAvailablePort
57
- .call(from: runtime_configuration.port)
62
+ .call(from: DEFAULT_PORT)
58
63
  .unwrap { |_error| @ctx.abort(@ctx.message("serve.no_available_ports_found")) }
59
64
  runtime_configuration.tap { |c| c.port = chosen_port }
60
65
  end
@@ -9,7 +9,7 @@ module Extension
9
9
  property! :specification_handler, accepts: Extension::Models::SpecificationHandlers::Default
10
10
  property :argo_runtime, accepts: -> (runtime) { runtime.class < Features::Runtimes::Base }
11
11
  property! :context, accepts: ShopifyCLI::Context
12
- property! :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
12
+ property! :port, accepts: Integer
13
13
  property :tunnel_url, accepts: String, default: nil
14
14
  property! :js_system, accepts: ->(jss) { jss.respond_to?(:call) }, default: ShopifyCLI::JsSystem
15
15
  property :resource_url, accepts: String, default: nil
@@ -0,0 +1,11 @@
1
+ module Extension
2
+ module Models
3
+ module ServerConfig
4
+ class Capabilities < Base
5
+ include SmartProperties
6
+
7
+ property :network_access, accepts: [true, false], default: false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -10,11 +10,14 @@ module Extension
10
10
  property! :type, accepts: String
11
11
  property! :user, accepts: ServerConfig::User
12
12
  property! :development, accepts: ServerConfig::Development
13
+ property :capabilities, accepts: ServerConfig::Capabilities
13
14
  property :extension_points, accepts: Array
14
- property :version, accepts: String
15
15
  property :title, accepts: String
16
+ property :description, accepts: String
17
+ property :version, accepts: String
18
+ property :metafields, accepts: Array
16
19
 
17
- def self.build(uuid: "", template:, type:, root_dir:)
20
+ def self.build(uuid: "", template:, type:, root_dir:, **args)
18
21
  renderer = ServerConfig::DevelopmentRenderer.find(type)
19
22
  entry = ServerConfig::DevelopmentEntries.find(template)
20
23
  new(
@@ -26,7 +29,11 @@ module Extension
26
29
  template: template,
27
30
  renderer: renderer,
28
31
  entries: entry
29
- )
32
+ ),
33
+ capabilities: ServerConfig::Capabilities.new(
34
+ network_access: false
35
+ ),
36
+ metafields: args.delete(:metafields)
30
37
  )
31
38
  end
32
39
 
@@ -15,7 +15,7 @@ module Extension
15
15
  (?<region>[a-zA-Z]{2}) # Optional region subtag
16
16
  )?
17
17
  \z}x
18
- PERMITTED_CONFIG_KEYS = [:extension_points, :metafields, :name]
18
+ PERMITTED_CONFIG_KEYS = [:extension_points, :metafields, :name, :capabilities]
19
19
 
20
20
  def config(context)
21
21
  {
@@ -9,13 +9,14 @@ module Extension
9
9
  property! :api_key, accepts: String
10
10
  property! :context, accepts: ShopifyCLI::Context
11
11
  property! :hash, accepts: Hash
12
- property :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
12
+ property! :port, accepts: Integer
13
13
  property! :registration_uuid, accepts: String
14
14
  property :resource_url, accepts: String
15
15
  property! :store, accepts: String
16
16
  property! :title, accepts: String
17
17
  property :tunnel_url, accepts: String
18
18
  property! :type, accepts: String
19
+ property :metafields, accepts: Array
19
20
 
20
21
  DEFAULT_BUILD_DIR = "build"
21
22
 
@@ -27,7 +28,6 @@ module Extension
27
28
  context.abort(context.message("tasks.errors.parse_error")) if hash.nil?
28
29
 
29
30
  renderer = Models::ServerConfig::DevelopmentRenderer.find(type)
30
-
31
31
  extension = Models::ServerConfig::Extension.new(
32
32
  uuid: registration_uuid,
33
33
  type: type.upcase,
@@ -40,8 +40,12 @@ module Extension
40
40
  )
41
41
  ),
42
42
  extension_points: hash.dig("extension_points"),
43
+ capabilities: Models::ServerConfig::Capabilities.new(
44
+ network_access: hash.dig("capabilities", "network_access") || false
45
+ ),
43
46
  version: renderer ? version(renderer.name, context) : nil,
44
- title: title
47
+ title: title,
48
+ metafields: metafields
45
49
  )
46
50
 
47
51
  unless resource_url.nil?
@@ -9,7 +9,7 @@ module Extension
9
9
 
10
10
  property! :context, accepts: ShopifyCLI::Context
11
11
  property! :file_path, accepts: ->(path) { Pathname(path).yield_self(&:absolute?) }
12
- property :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
12
+ property! :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
13
13
  property :resource_url, accepts: String
14
14
  property :tunnel_url, accepts: String
15
15
  property! :type, accepts: Models::DevelopmentServerRequirements::SUPPORTED_EXTENSION_TYPES
@@ -32,7 +32,9 @@ module Extension
32
32
  store: project.env.shop || "",
33
33
  title: project.title,
34
34
  tunnel_url: tunnel_url,
35
- type: type
35
+ type: type,
36
+ port: port,
37
+ metafields: config["metafields"]
36
38
  )
37
39
  rescue Psych::SyntaxError => e
38
40
  raise(
@@ -50,6 +50,7 @@ module Script
50
50
  autoload :ExtensionPoint, Project.project_filepath("layers/domain/extension_point")
51
51
  autoload :ScriptConfig, Project.project_filepath("layers/domain/script_config")
52
52
  autoload :ScriptProject, Project.project_filepath("layers/domain/script_project")
53
+ autoload :AppBridge, Project.project_filepath("layers/domain/app_bridge")
53
54
  end
54
55
 
55
56
  module Infrastructure
@@ -38,21 +38,33 @@ delivery_discount_types:
38
38
  repo: "https://github.com/Shopify/scripts-apis-examples"
39
39
  wasm:
40
40
  repo: "https://github.com/Shopify/scripts-apis-examples"
41
- product_discount_type:
41
+ product_discounts:
42
42
  beta: true
43
43
  domain: 'discounts'
44
44
  libraries:
45
45
  wasm:
46
46
  repo: "https://github.com/Shopify/scripts-apis-examples"
47
- order_discount_type:
47
+ rust:
48
+ repo: "https://github.com/Shopify/scripts-apis-examples"
49
+ order_discounts:
48
50
  beta: true
49
51
  domain: 'discounts'
50
52
  libraries:
51
53
  wasm:
52
54
  repo: "https://github.com/Shopify/scripts-apis-examples"
53
- shipping_discount_type:
55
+ rust:
56
+ repo: "https://github.com/Shopify/scripts-apis-examples"
57
+ shipping_discounts:
54
58
  beta: true
55
59
  domain: 'discounts'
56
60
  libraries:
57
61
  wasm:
58
62
  repo: "https://github.com/Shopify/scripts-apis-examples"
63
+ rust:
64
+ repo: "https://github.com/Shopify/scripts-apis-examples"
65
+ shipping_rates_consolidation:
66
+ beta: true
67
+ domain: 'checkout'
68
+ libraries:
69
+ wasm:
70
+ repo: "https://github.com/Shopify/scripts-apis-examples"
@@ -12,6 +12,7 @@ mutation AppScriptSet(
12
12
  $moduleUploadUrl: String!,
13
13
  $library: LibraryInput,
14
14
  $inputQuery: String,
15
+ $appBridge: AppBridgeInput!,
15
16
  ) {
16
17
  appScriptSet(
17
18
  uuid: $uuid
@@ -27,6 +28,7 @@ mutation AppScriptSet(
27
28
  moduleUploadUrl: $moduleUploadUrl,
28
29
  library: $library,
29
30
  inputQuery: $inputQuery,
31
+ appBridge: $appBridge
30
32
  ) {
31
33
  userErrors {
32
34
  field
@@ -55,6 +55,7 @@ module Script
55
55
  force: force,
56
56
  metadata: package.metadata,
57
57
  script_config: package.script_config,
58
+ app_bridge: script_project.app_bridge,
58
59
  module_upload_url: module_upload_url,
59
60
  library: package.library,
60
61
  input_query: script_project.input_query,
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Domain
6
+ class AppBridge
7
+ attr_reader :create_path, :details_path
8
+
9
+ def initialize(create_path:, details_path:)
10
+ @create_path = create_path
11
+ @details_path = details_path
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -17,6 +17,7 @@ module Script
17
17
  property! :language, accepts: String
18
18
 
19
19
  property :script_config, accepts: ScriptConfig
20
+ property :app_bridge, accepts: AppBridge
20
21
  property :input_query, accepts: String
21
22
 
22
23
  def initialize(*)
@@ -54,6 +54,7 @@ module Script
54
54
  extension_point_type: extension_point_type,
55
55
  language: language,
56
56
  script_config: script_config_repository.get!,
57
+ app_bridge: app_bridge,
57
58
  input_query: read_input_query,
58
59
  )
59
60
  end
@@ -94,6 +95,7 @@ module Script
94
95
  extension_point_type: extension_point_type,
95
96
  language: language,
96
97
  script_config: script_config,
98
+ app_bridge: app_bridge,
97
99
  )
98
100
  end
99
101
 
@@ -121,6 +123,16 @@ module Script
121
123
  project_config_value("language")&.downcase || default_language
122
124
  end
123
125
 
126
+ def app_bridge
127
+ create_path = project_config_value("app_bridge_create_path") || "/"
128
+ details_path = project_config_value("app_bridge_details_path") || "/"
129
+
130
+ Domain::AppBridge.new(
131
+ create_path: create_path,
132
+ details_path: details_path,
133
+ )
134
+ end
135
+
124
136
  def project_config_value(key)
125
137
  return nil unless project.config.key?(key)
126
138
  project.config[key]
@@ -20,6 +20,7 @@ module Script
20
20
  force: false,
21
21
  metadata:,
22
22
  script_config:,
23
+ app_bridge:,
23
24
  module_upload_url:,
24
25
  library:,
25
26
  input_query: nil
@@ -36,6 +37,10 @@ module Script
36
37
  scriptConfigVersion: script_config.version,
37
38
  configurationUi: script_config.configuration_ui,
38
39
  configurationDefinition: script_config.configuration&.to_json,
40
+ appBridge: {
41
+ createPath: app_bridge.create_path,
42
+ detailsPath: app_bridge.details_path,
43
+ },
39
44
  moduleUploadUrl: module_upload_url,
40
45
  inputQuery: input_query,
41
46
  }
@@ -20,9 +20,12 @@ module Theme
20
20
  end
21
21
 
22
22
  def call(_args, name)
23
+ valid_authentication_method!
24
+
23
25
  root = root_value(options, name)
24
26
  flags = options.flags.dup
25
27
  host = flags[:host] || DEFAULT_HTTP_HOST
28
+
26
29
  ShopifyCLI::Theme::DevServer.start(@ctx, root, host: host, **flags) do |syncer|
27
30
  UI::SyncProgressBar.new(syncer).progress(:upload_theme!, delay_low_priority_files: true)
28
31
  end
@@ -38,6 +41,30 @@ module Theme
38
41
  def self.help
39
42
  ShopifyCLI::Context.message("theme.serve.help", ShopifyCLI::TOOL_NAME)
40
43
  end
44
+
45
+ private
46
+
47
+ def valid_authentication_method!
48
+ if exchange_token && !storefront_renderer_token
49
+ ShopifyCLI::Context.abort(error_message, help_message)
50
+ end
51
+ end
52
+
53
+ def error_message
54
+ ShopifyCLI::Context.message("theme.serve.auth.error_message", ShopifyCLI::TOOL_NAME)
55
+ end
56
+
57
+ def help_message
58
+ ShopifyCLI::Context.message("theme.serve.auth.help_message", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
59
+ end
60
+
61
+ def exchange_token
62
+ ShopifyCLI::DB.get(:shopify_exchange_token)
63
+ end
64
+
65
+ def storefront_renderer_token
66
+ ShopifyCLI::DB.get(:storefront_renderer_production_exchange_token)
67
+ end
41
68
  end
42
69
  end
43
70
  end
@@ -8,6 +8,11 @@ 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
+ unauthorized_error: <<~EOD,
12
+ You can't use Shopify CLI with development stores if you only have Partner staff member access. If you want to use Shopify CLI to work on a development store, then you should be the store owner or create a staff account on the store.
13
+
14
+ If you're the store owner, then you need to log in to the store directly using the store URL at least once (for example, using %s.myshopify.com/admin) before you log in using Shopify CLI. Logging in to the Shopify admin directly connects the development store with your Shopify login.
15
+ EOD
11
16
  ensure_user_try_this: <<~ENSURE_USER,
12
17
  Check if your user is activated, has permission to edit themes at the store, and try to re-login.
13
18
  ENSURE_USER
@@ -116,6 +121,14 @@ module Theme
116
121
  viewing_theme: "Viewing theme…",
117
122
  syncing_theme: "Syncing theme #%s on %s",
118
123
  open_fail: "Couldn't open the theme",
124
+ auth: {
125
+ error_message: <<~ERROR_MESSAGE,
126
+ It looks like you are using credentials that do not work with {{command:%s theme serve}}.
127
+ ERROR_MESSAGE
128
+ help_message: <<~HELP_MESSAGE,
129
+ Run {{command:%s logout}} and {{command:%s login --password "" --store STORE}} to force the authentication thought your browser.
130
+ HELP_MESSAGE
131
+ },
119
132
  operation: {
120
133
  status: {
121
134
  error: "ERROR",
@@ -156,7 +156,7 @@ module ShopifyCLI
156
156
  def auth_headers(token)
157
157
  {
158
158
  Authorization: "Bearer #{token}",
159
- "X-Shopify-Access-Token" => token, # TODO: Remove when we no longer need private apps
159
+ "X-Shopify-Access-Token" => token,
160
160
  }
161
161
  end
162
162
  end
@@ -26,8 +26,8 @@ module ShopifyCLI
26
26
  end
27
27
  end
28
28
 
29
- # As password auth will soon be deprecated, we enable only in CI
30
- if @ctx.ci? && (password = options.flags[:password] || @ctx.getenv("SHOPIFY_PASSWORD"))
29
+ password = options.flags[:password] || @ctx.getenv("SHOPIFY_PASSWORD")
30
+ if !password.nil? && !password.empty?
31
31
  ShopifyCLI::DB.set(shopify_exchange_token: password)
32
32
  else
33
33
  IdentityAuth.new(ctx: @ctx).authenticate(spinner: true)
@@ -630,7 +630,7 @@ module ShopifyCLI
630
630
  end
631
631
  end
632
632
  latest_version = ShopifyCLI::Config.get(VERSION_CHECK_SECTION, LATEST_VERSION_FIELD, default: ShopifyCLI::VERSION)
633
- latest_version unless latest_version == ShopifyCLI::VERSION
633
+ latest_version if ::Semantic::Version.new(latest_version) > ::Semantic::Version.new(ShopifyCLI::VERSION)
634
634
  end
635
635
 
636
636
  # Returns file extension depending on OS
@@ -14,13 +14,12 @@ module ShopifyCLI
14
14
 
15
15
  files.each do |file|
16
16
  section_hash(file).each do |key, value|
17
- name = key
18
- type = value&.dig("type")
19
-
20
- next if !name || !type
17
+ next unless key
18
+ next unless value.is_a?(Hash)
19
+ next unless (type = value&.dig("type"))
21
20
 
22
21
  index[type] = [] unless index[type]
23
- index[type] << name
22
+ index[type] << key
24
23
  end
25
24
  end
26
25
 
@@ -42,7 +41,7 @@ module ShopifyCLI
42
41
  end
43
42
 
44
43
  def files
45
- @theme.json_files
44
+ @theme.json_files.filter(&:template?)
46
45
  end
47
46
  end
48
47
  end
@@ -14,7 +14,8 @@ module ShopifyCLI
14
14
  @theme = theme
15
15
  @syncer = syncer
16
16
  @ignore_filter = ignore_filter
17
- @listener = Listen.to(@theme.root, force_polling: poll) do |modified, added, removed|
17
+ @listener = Listen.to(@theme.root, force_polling: poll,
18
+ ignore: @ignore_filter&.regexes) do |modified, added, removed|
18
19
  changed
19
20
  notify_observers(modified, added, removed)
20
21
  end
@@ -32,7 +32,7 @@ module ShopifyCLI
32
32
  theme = DevelopmentTheme.find_or_create!(ctx, root: root)
33
33
  ignore_filter = IgnoreFilter.from_path(root)
34
34
  @syncer = Syncer.new(ctx, theme: theme, ignore_filter: ignore_filter, overwrite_json: !editor_sync)
35
- watcher = Watcher.new(ctx, theme: theme, syncer: @syncer, poll: poll)
35
+ watcher = Watcher.new(ctx, theme: theme, ignore_filter: ignore_filter, syncer: @syncer, poll: poll)
36
36
  remote_watcher = RemoteWatcher.to(theme: theme, syncer: @syncer)
37
37
 
38
38
  # Setup the middleware stack. Mimics Rack::Builder / config.ru, but in reverse order
@@ -79,13 +79,23 @@ module ShopifyCLI
79
79
 
80
80
  theme_name = "Development ()"
81
81
  hostname_character_limit = API_NAME_LIMIT - theme_name.length - hash.length - 1
82
- identifier = "#{hash}-#{hostname[0, hostname_character_limit]}"
82
+ identifier = encode_identifier("#{hash}-#{hostname[0, hostname_character_limit]}")
83
83
  theme_name = "Development (#{identifier})"
84
84
 
85
85
  ShopifyCLI::DB.set(development_theme_name: theme_name)
86
86
 
87
87
  theme_name
88
88
  end
89
+
90
+ ##
91
+ # In some cases, the identifier string encoding may be obfuscated by the hostname,
92
+ # which may be an ASCII string.
93
+ #
94
+ # This method ensures the result identifier is a UTF-8 valid string.
95
+ #
96
+ def encode_identifier(identifier)
97
+ identifier.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "-")
98
+ end
89
99
  end
90
100
  end
91
101
  end
@@ -30,6 +30,15 @@ module ShopifyCLI
30
30
  else
31
31
  path.write(content, 0, mode: "wb")
32
32
  end
33
+ rescue Encoding::UndefinedConversionError
34
+ ##
35
+ # The CLI tries to write the file and normalize EOL characters to avoid
36
+ # errors on Windows when files are shared across different operational systems.
37
+ #
38
+ # The CLI fallbacks any error during the conversion by writing the file
39
+ # in binary mode when the normalization fails (e.g., ASCII files), so no data is lost.
40
+ #
41
+ path.write(content, 0, mode: "wb")
33
42
  end
34
43
 
35
44
  def delete
@@ -53,8 +53,10 @@ module ShopifyCLI
53
53
  # * when an asset operation cannot be performed:
54
54
  # - <APIRequestForbiddenError: 403 {"message":"templates/gift_card.liquid could not be deleted"}>
55
55
  #
56
- if empty_response?(error) || unauthorized_response?(error)
56
+ if empty_response?(error)
57
57
  return permission_error
58
+ elsif unauthorized_response?(error)
59
+ raise ShopifyCLI::Abort, @ctx.message("theme.unauthorized_error", @shop)
58
60
  end
59
61
 
60
62
  raise error
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.16.1"
2
+ VERSION = "2.17.0"
3
3
  end
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.16.1
4
+ version: 2.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-26 00:00:00.000000000 Z
11
+ date: 2022-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -244,6 +244,7 @@ files:
244
244
  - lib/project_types/extension/models/registration.rb
245
245
  - lib/project_types/extension/models/server_config/app.rb
246
246
  - lib/project_types/extension/models/server_config/base.rb
247
+ - lib/project_types/extension/models/server_config/capabilities.rb
247
248
  - lib/project_types/extension/models/server_config/development.rb
248
249
  - lib/project_types/extension/models/server_config/development_entries.rb
249
250
  - lib/project_types/extension/models/server_config/development_renderer.rb
@@ -320,6 +321,7 @@ files:
320
321
  - lib/project_types/script/layers/application/extension_points.rb
321
322
  - lib/project_types/script/layers/application/project_dependencies.rb
322
323
  - lib/project_types/script/layers/application/push_script.rb
324
+ - lib/project_types/script/layers/domain/app_bridge.rb
323
325
  - lib/project_types/script/layers/domain/errors.rb
324
326
  - lib/project_types/script/layers/domain/extension_point.rb
325
327
  - lib/project_types/script/layers/domain/metadata.rb