shopify-cli 2.13.0 → 2.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +5 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +1 -1
  4. data/CHANGELOG.md +18 -0
  5. data/Gemfile.lock +6 -6
  6. data/Rakefile +16 -0
  7. data/ext/javy/hashes/javy-arm-macos-v0.2.1.gz.sha256 +1 -0
  8. data/ext/javy/hashes/javy-x86_64-linux-v0.2.1.gz.sha256 +1 -0
  9. data/ext/javy/hashes/javy-x86_64-macos-v0.2.1.gz.sha256 +1 -0
  10. data/ext/javy/hashes/javy-x86_64-windows-v0.2.1.gz.sha256 +1 -0
  11. data/ext/javy/version +1 -1
  12. data/lib/project_types/extension/models/npm_package.rb +19 -1
  13. data/lib/project_types/extension/models/server_config/development_renderer.rb +4 -3
  14. data/lib/project_types/script/cli.rb +0 -4
  15. data/lib/project_types/script/config/extension_points.yml +0 -6
  16. data/lib/project_types/script/layers/application/build_script.rb +3 -18
  17. data/lib/project_types/script/layers/application/push_script.rb +12 -10
  18. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +0 -1
  19. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +0 -1
  20. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +2 -10
  21. data/lib/project_types/script/layers/infrastructure/languages/wasm_task_runner.rb +1 -1
  22. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -23
  23. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +1 -1
  24. data/lib/project_types/script/messages/messages.rb +2 -2
  25. data/lib/project_types/theme/commands/package.rb +1 -0
  26. data/lib/project_types/theme/messages/messages.rb +2 -0
  27. data/lib/shopify_cli/commands/app/deploy.rb +0 -1
  28. data/lib/shopify_cli/context.rb +2 -2
  29. data/lib/shopify_cli/core/entry_point.rb +1 -1
  30. data/lib/shopify_cli/core/monorail.rb +14 -6
  31. data/lib/shopify_cli/exception_reporter.rb +2 -0
  32. data/lib/shopify_cli/packager.rb +1 -1
  33. data/lib/shopify_cli/result.rb +14 -0
  34. data/lib/shopify_cli/theme/dev_server/hot_reload/remote_file_reloader.rb +5 -5
  35. data/lib/shopify_cli/theme/dev_server/watcher.rb +10 -2
  36. data/lib/shopify_cli/theme/development_theme.rb +2 -5
  37. data/lib/shopify_cli/theme/syncer.rb +20 -25
  38. data/lib/shopify_cli/theme/theme.rb +16 -27
  39. data/lib/shopify_cli/theme/theme_admin_api.rb +71 -0
  40. data/lib/shopify_cli/transform_data_structure.rb +3 -2
  41. data/lib/shopify_cli/version.rb +1 -1
  42. data/shipit.yml +3 -0
  43. data/shopify-cli.gemspec +9 -2
  44. metadata +12 -8
  45. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +0 -36
  46. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +0 -109
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e54fd77e2aa3b1721ea02cd7cad4a84afdae67a3c73510e6ee8b01e44bfc5949
4
- data.tar.gz: a92380f94b7a33cea4eae04d2d528ef09a51d161a5b77a900a294e7176ee89e9
3
+ metadata.gz: be8f00a6bb6d3e7059a63e77ff74327d9e11474cc34b156ec54da33080119e11
4
+ data.tar.gz: ed986614e2b2c0b9b9ca70a175c2133a3130643f3678bbf17148556be4f39f86
5
5
  SHA512:
6
- metadata.gz: 3a55cc0e5a57ab4a842411667dfca871140ef324d17c537157e3913cce383c84ae70ebd26cbf8f14a020b94283c9d6264ab71af5f55c37255fbe7966ee8f46f5
7
- data.tar.gz: 24328c051c6795d7c4778fdaea861cc77d3337a886126074bce4ae3073b635b6bcd878457e8cad4399c5982b0be5d168a3f6f3c86c5e3bbbe7b7b2ce192e4d58
6
+ metadata.gz: cc1c384e33b5bc316e38ab1ab58b978ab56e811309c82746f9218fc8de2cd4d57b243414f324421baff1abdc69829d952840e2c2bd94049963858ca3700c5600
7
+ data.tar.gz: d065d5a10be15c0f79c800798fb0302e9b2519b7b22fea5879ae321297e8bd0859d8b21756b40ae8abe78387e1e3e62b600d0e796a5848545b1c8e5c37af4cd2
data/.github/CODEOWNERS CHANGED
@@ -3,3 +3,8 @@
3
3
 
4
4
  /lib/project_types/script/ @shopify/scripts-platform
5
5
  /test/project_types/script/ @shopify/scripts-platform
6
+
7
+ /lib/project_types/theme/ @shopify/theme-platform-dev-experience
8
+ /lib/shopify_cli/theme/ @shopify/theme-platform-dev-experience
9
+ /test/project_types/theme/ @shopify/theme-platform-dev-experience
10
+ /test/shopify-cli/theme/ @shopify/theme-platform-dev-experience
@@ -40,4 +40,4 @@ Fixes #0000 <!-- link to issue if one exists -->
40
40
  - [ ] I've added a CHANGELOG entry for this PR (if the change is public-facing)
41
41
  - [ ] I've considered possible cross-platform impacts (Mac, Linux, Windows).
42
42
  - [ ] I've left the version number as is (we'll handle incrementing this when releasing).
43
- - [ ] I've included any post-release steps in the section above.
43
+ - [ ] I've included any post-release steps in the section above (if needed).
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@ 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.14.0
6
+
7
+ ### Changed
8
+ * [#2126](https://github.com/Shopify/shopify-cli/pull/2126): Use javy version 0.2.1
9
+
10
+ ### Added
11
+ * [#2103](https://github.com/Shopify/shopify-cli/pull/2103): Improve `shopify theme package` to include the `release-notes.md` file
12
+
13
+ ### Fixed
14
+ * [#2112](https://github.com/Shopify/shopify-cli/pull/2112): Fix intermittent error ("can't add a new key into hash during iteration") in the `theme push` command
15
+ * [#2088](https://github.com/Shopify/shopify-cli/pull/2088): Update theme-check to 1.10.1
16
+ * [#2130](https://github.com/Shopify/shopify-cli/pull/2130): Fix Homebrew installation.
17
+ * [#2133](https://github.com/Shopify/shopify-cli/pull/2133): Fix ignore file handling in DevServer::Watcher.
18
+
5
19
  ## Version 2.13.0
6
20
 
7
21
  ### Added
@@ -11,6 +25,10 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h
11
25
  ### Fixed
12
26
  * [#2092](https://github.com/Shopify/shopify-cli/pull/2092): Fix `RootHelper` parse logic to support options with an equal (e.g.: `option=value`)
13
27
  * [#2089](https://github.com/Shopify/shopify-cli/pull/2089): Use javy version 0.2.0
28
+ * [#2114](https://github.com/Shopify/shopify-cli/pull/2114): Fix `theme` command error messaging with `ThemeAdminAPI` wrapper
29
+
30
+ ### Removed
31
+ * [#2102](https://github.com/Shopify/shopify-cli/pull/2102): Remove AssemblyScript as a supported script language.
14
32
 
15
33
  ## Version 2.12.0
16
34
  ### Added
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify-cli (2.13.0)
4
+ shopify-cli (2.14.0)
5
5
  bugsnag (~> 6.22)
6
6
  listen (~> 3.7.0)
7
- theme-check (~> 1.9.0)
7
+ theme-check (~> 1.10.1)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
@@ -81,7 +81,7 @@ GEM
81
81
  mini_portile2 (~> 2.8.0)
82
82
  racc (~> 1.4)
83
83
  parallel (1.21.0)
84
- parser (3.1.0.0)
84
+ parser (3.1.1.0)
85
85
  ast (~> 2.4.1)
86
86
  pry (0.13.1)
87
87
  coderay (~> 1.1)
@@ -119,7 +119,7 @@ GEM
119
119
  ruby-progressbar (1.11.0)
120
120
  sys-uname (1.2.2)
121
121
  ffi (~> 1.1)
122
- theme-check (1.9.0)
122
+ theme-check (1.10.1)
123
123
  liquid (>= 5.1.0)
124
124
  nokogiri (>= 1.12)
125
125
  parser (~> 3)
@@ -134,7 +134,7 @@ PLATFORMS
134
134
  ruby
135
135
 
136
136
  DEPENDENCIES
137
- bundler (~> 2.2.2)
137
+ bundler (~> 2.3.8)
138
138
  byebug
139
139
  colorize (~> 0.8.1)
140
140
  cucumber (~> 7.0)
@@ -155,4 +155,4 @@ DEPENDENCIES
155
155
  webmock
156
156
 
157
157
  BUNDLED WITH
158
- 2.2.29
158
+ 2.3.8
data/Rakefile CHANGED
@@ -2,6 +2,8 @@ ENV["SHOPIFY_CLI_TEST"] = "1"
2
2
 
3
3
  require_relative "bin/load_shopify"
4
4
  require_relative "utilities/utilities"
5
+ require_relative "lib/shopify_cli/constants"
6
+ require_relative "lib/shopify_cli/version"
5
7
  require "rake/testtask"
6
8
  require "rubocop/rake_task"
7
9
  require "bundler/gem_tasks"
@@ -33,6 +35,20 @@ task :console do
33
35
  exec("irb", "-r", "./bin/load_shopify.rb", "-r", "byebug")
34
36
  end
35
37
 
38
+ desc("Notifies a new version to Bugsnag")
39
+ task :notify_version_to_bugsnag do
40
+ # This task runs at deployment time to notify
41
+ # Bugsnag about new versions. Because the deployment
42
+ # environment has Node, we can run the Bugsnag CLI
43
+ # through npx.
44
+ system(
45
+ { "npm_config_yes" => "true" },
46
+ "npx", "-q", "bugsnag-build-reporter",
47
+ "-k", ShopifyCLI::Constants::Bugsnag::API_KEY,
48
+ "-v", ShopifyCLI::VERSION
49
+ ) || abort
50
+ end
51
+
36
52
  namespace :rdoc do
37
53
  repo = "https://github.com/Shopify/shopify-cli.wiki.git"
38
54
  intermediate = "markdown_intermediate"
@@ -0,0 +1 @@
1
+ 80576fe617d6e093a72bc826f041207ddc57605381f0db6451ba27310e57e830
@@ -0,0 +1 @@
1
+ 6b7b6f6745594c2e8efcaf948c0ef367911446101d2b8a7c8138ce2aca868cbd
@@ -0,0 +1 @@
1
+ 4010c2d154f1ef7ebf1f8c49621a0742ab75c60fd77746a5fa175878d07f16ef
@@ -0,0 +1 @@
1
+ c12418f7b3e4edead87ade1f44bd7280626a92d8d1238d7f8eb91b1122f20f20
data/ext/javy/version CHANGED
@@ -1 +1 @@
1
- v0.2.0
1
+ v0.2.1
@@ -2,9 +2,27 @@ require "semantic/semantic"
2
2
 
3
3
  module Extension
4
4
  module Models
5
- NpmPackage = Struct.new(:name, :version, keyword_init: true) do
5
+ class NpmPackage
6
+ include SmartProperties
6
7
  include Comparable
7
8
 
9
+ property :name
10
+ property :version
11
+ property :scripts, accepts: Hash
12
+ property :dependencies, accepts: Hash
13
+ property :dev_dependencies, accepts: Hash
14
+
15
+ def initialize(**config)
16
+ super(**config.select { |property_name, _| self.class.properties.key?(property_name) })
17
+ end
18
+
19
+ def self.parse(io)
20
+ ShopifyCLI::Result.call { JSON.parse(io.read) }
21
+ .then(&ShopifyCLI::TransformDataStructure.new(underscore_keys: true, symbolize_keys: true, shallow: true))
22
+ .then { |specification| new(**specification) }
23
+ .unwrap { |error| raise "Failed to parse NPM package specification: #{error}" }
24
+ end
25
+
8
26
  def <=>(other)
9
27
  return nil unless name == other.name
10
28
  Semantic::Version.new(version) <=> Semantic::Version.new(other.version)
@@ -13,15 +13,16 @@ module Extension
13
13
  ]
14
14
 
15
15
  property! :name, accepts: VALID_RENDERERS
16
+ property! :version, accepts: String, default: "latest"
16
17
 
17
18
  def self.find(type)
18
19
  case type.downcase
19
20
  when "product_subscription"
20
- new(name: "@shopify/admin-ui-extensions")
21
+ new(name: "@shopify/admin-ui-extensions", version: "^1.0.1")
21
22
  when "checkout_ui_extension"
22
- new(name: "@shopify/checkout-ui-extensions")
23
+ new(name: "@shopify/checkout-ui-extensions", version: "^0.14.0")
23
24
  when "checkout_post_purchase"
24
- new(name: "@shopify/post-purchase-ui-extensions")
25
+ new(name: "@shopify/post-purchase-ui-extensions", version: "^0.13.2")
25
26
  end
26
27
  end
27
28
  end
@@ -64,10 +64,6 @@ module Script
64
64
  autoload :ServiceLocator, Project.project_filepath("layers/infrastructure/service_locator")
65
65
 
66
66
  module Languages
67
- autoload :AssemblyScriptProjectCreator,
68
- Project.project_filepath("layers/infrastructure/languages/assemblyscript_project_creator")
69
- autoload :AssemblyScriptTaskRunner,
70
- Project.project_filepath("layers/infrastructure/languages/assemblyscript_task_runner")
71
67
  autoload :ProjectCreator, Project.project_filepath("layers/infrastructure/languages/project_creator")
72
68
  autoload :TaskRunner, Project.project_filepath("layers/infrastructure/languages/task_runner")
73
69
  autoload :TypeScriptProjectCreator,
@@ -1,9 +1,6 @@
1
1
  payment_methods:
2
2
  domain: 'checkout'
3
3
  libraries:
4
- assemblyscript:
5
- repo: "https://github.com/Shopify/scripts-apis-examples"
6
- package: "@shopify/scripts-checkout-apis"
7
4
  typescript:
8
5
  beta: true
9
6
  package: "@shopify/scripts-checkout-apis"
@@ -13,9 +10,6 @@ payment_methods:
13
10
  shipping_methods:
14
11
  domain: 'checkout'
15
12
  libraries:
16
- assemblyscript:
17
- repo: "https://github.com/Shopify/scripts-apis-examples"
18
- package: "@shopify/scripts-checkout-apis"
19
13
  typescript:
20
14
  beta: true
21
15
  package: "@shopify/scripts-checkout-apis"
@@ -5,31 +5,16 @@ module Script
5
5
  module Application
6
6
  class BuildScript
7
7
  class << self
8
- def call(ctx:, task_runner:, script_project:, library:)
8
+ def call(ctx:, task_runner:)
9
9
  CLI::UI::Frame.open(ctx.message("script.application.building")) do
10
10
  UI::StrictSpinner.spin(ctx.message("script.application.building_script")) do |spinner|
11
- script_content = task_runner.build
12
- metadata_file_location = task_runner.metadata_file_location
13
- metadata = Infrastructure::MetadataRepository.new(ctx: ctx).get_metadata(metadata_file_location)
14
-
15
- Infrastructure::PushPackageRepository.new(ctx: ctx).create_push_package(
16
- script_project: script_project,
17
- script_content: script_content,
18
- metadata: metadata,
19
- library: library,
20
- )
11
+ task_runner.build
21
12
  spinner.update_title(ctx.message("script.application.built"))
22
13
  end
23
- rescue StandardError => e
14
+ rescue Infrastructure::Errors::BuildError => e
24
15
  CLI::UI::Frame.with_frame_color_override(:red) do
25
16
  ctx.puts("\n{{red:#{e.message}}}")
26
17
  end
27
- errors = [
28
- Infrastructure::Errors::BuildScriptNotFoundError,
29
- Infrastructure::Errors::WebAssemblyBinaryNotFoundError,
30
- ]
31
-
32
- raise Infrastructure::Errors::BuildError unless errors.any? { |err| e.is_a?(err) }
33
18
  raise
34
19
  end
35
20
  end
@@ -21,30 +21,32 @@ module Script
21
21
  api: script_project.extension_point_type
22
22
  ) if library.nil? && (script_project.language != "wasm")
23
23
 
24
- library_name = library&.package
25
- library_data = {
26
- language: script_project.language,
27
- version: task_runner.library_version(library_name),
28
- } if library_name
29
-
30
24
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
31
- BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project, library: library_data)
32
-
33
- metadata_file_location = task_runner.metadata_file_location
34
- metadata = Infrastructure::MetadataRepository.new(ctx: ctx).get_metadata(metadata_file_location)
25
+ BuildScript.call(ctx: ctx, task_runner: task_runner)
35
26
 
36
27
  CLI::UI::Frame.open(ctx.message("script.application.pushing")) do
37
28
  UI::PrintingSpinner.spin(ctx, ctx.message("script.application.pushing_script")) do |p_ctx, spinner|
29
+ library_name = library&.package
30
+ library_data = {
31
+ language: script_project.language,
32
+ version: task_runner.library_version(library_name),
33
+ } if library_name
34
+
35
+ metadata_file_location = task_runner.metadata_file_location
36
+ metadata = Infrastructure::MetadataRepository.new(ctx: ctx).get_metadata(metadata_file_location)
37
+
38
38
  package = Infrastructure::PushPackageRepository.new(ctx: p_ctx).get_push_package(
39
39
  script_project: script_project,
40
40
  metadata: metadata,
41
41
  library: library_data,
42
42
  )
43
+
43
44
  script_service = Infrastructure::ServiceLocator.script_service(
44
45
  ctx: p_ctx,
45
46
  api_key: script_project.api_key
46
47
  )
47
48
  module_upload_url = Infrastructure::ScriptUploader.new(script_service).upload(package.script_content)
49
+
48
50
  uuid = script_service.set_app_script(
49
51
  uuid: package.uuid,
50
52
  extension_point_type: package.extension_point_type,
@@ -26,7 +26,6 @@ module Script
26
26
  )
27
27
 
28
28
  project_creators = {
29
- "assemblyscript" => AssemblyScriptProjectCreator,
30
29
  "typescript" => TypeScriptProjectCreator,
31
30
  "wasm" => WasmProjectCreator,
32
31
  }
@@ -9,7 +9,6 @@ module Script
9
9
 
10
10
  def self.for(ctx, language)
11
11
  task_runners = {
12
- "assemblyscript" => AssemblyScriptTaskRunner,
13
12
  "typescript" => TypeScriptTaskRunner,
14
13
  "wasm" => WasmTaskRunner,
15
14
  }
@@ -18,7 +18,8 @@ module Script
18
18
 
19
19
  def build
20
20
  compile
21
- bytecode
21
+ rescue Errors::SystemCallFailureError => e
22
+ raise Errors::BuildError, e.out
22
23
  end
23
24
 
24
25
  def install_dependencies
@@ -95,15 +96,6 @@ module Script
95
96
  raise Errors::BuildScriptNotFoundError,
96
97
  "Build script not found" if build_script.nil?
97
98
  end
98
-
99
- def bytecode
100
- raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
101
-
102
- contents = ctx.binread(BYTECODE_FILE)
103
- ctx.rm(BYTECODE_FILE)
104
-
105
- contents
106
- end
107
99
  end
108
100
  end
109
101
  end
@@ -5,7 +5,7 @@ module Script
5
5
  module Infrastructure
6
6
  module Languages
7
7
  class WasmTaskRunner < TaskRunner
8
- BYTECODE_FILE = "script.wasm"
8
+ BYTECODE_FILE = "build/index.wasm"
9
9
 
10
10
  def dependencies_installed?
11
11
  true
@@ -7,23 +7,6 @@ module Script
7
7
  include SmartProperties
8
8
  property! :ctx, accepts: ShopifyCLI::Context
9
9
 
10
- def create_push_package(script_project:, script_content:, metadata:, library:)
11
- build_file_path = file_path(script_project.id)
12
- write_to_path(build_file_path, script_content)
13
-
14
- Domain::PushPackage.new(
15
- id: build_file_path,
16
- uuid: script_project.uuid,
17
- extension_point_type: script_project.extension_point_type,
18
- title: script_project.title,
19
- description: script_project.description,
20
- script_content: script_content,
21
- metadata: metadata,
22
- script_config: script_project.script_config,
23
- library: library
24
- )
25
- end
26
-
27
10
  def get_push_package(script_project:, metadata:, library:)
28
11
  build_file_path = file_path(script_project.id)
29
12
  raise Domain::Errors::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
@@ -44,13 +27,8 @@ module Script
44
27
 
45
28
  private
46
29
 
47
- def write_to_path(path, content)
48
- ctx.mkdir_p(File.dirname(path))
49
- ctx.binwrite(path, content)
50
- end
51
-
52
30
  def file_path(path_to_script)
53
- "#{path_to_script}/build/script.wasm"
31
+ "#{path_to_script}/build/index.wasm"
54
32
  end
55
33
  end
56
34
  end
@@ -136,7 +136,7 @@ module Script
136
136
  end
137
137
 
138
138
  def default_language
139
- "assemblyscript"
139
+ "wasm"
140
140
  end
141
141
 
142
142
  def validate_metadata!(extension_point_type, language)
@@ -135,8 +135,8 @@ module Script
135
135
  "\nbuild: npx shopify-scripts-toolchain-as build --src src/shopify_main.ts --binary build/<script_name>.wasm --metadata build/metadata.json -- --lib node_modules --optimize --use Date=",
136
136
 
137
137
  web_assembly_binary_not_found: "Wasm binary not found.",
138
- web_assembly_binary_not_found_suggestion: "Check that there is a valid Wasm binary in the root directory" \
139
- "Your Wasm binary should match the script name: <script_name>.wasm",
138
+ web_assembly_binary_not_found_suggestion: "Check that a valid Wasm binary is present. " \
139
+ "The Wasm binary's filepath must be 'build/index.wasm'.",
140
140
 
141
141
  project_config_not_found: "Internal error - Script can't be created because the project's config file is missing from the repository.",
142
142
 
@@ -15,6 +15,7 @@ module Theme
15
15
  sections
16
16
  snippets
17
17
  templates
18
+ release-notes.md
18
19
  ]
19
20
 
20
21
  def call(args, _name)
@@ -7,6 +7,8 @@ module Theme
7
7
  Suite of commands for developing Shopify themes. See {{command:%1$s theme <command> --help}} for usage of each command.
8
8
  Usage: {{command:%1$s theme [ %2$s ]}}
9
9
  HELP
10
+ ensure_user_error: "You are not authorized to edit themes on %s.",
11
+ ensure_user_try_this: "Make sure you are a user of that store, and allowed to edit themes.",
10
12
 
11
13
  init: {
12
14
  help: <<~HELP,
@@ -2,7 +2,6 @@ module ShopifyCLI
2
2
  module Commands
3
3
  class App
4
4
  class Deploy < ShopifyCLI::Command::AppSubCommand
5
- subcommand :Heroku, "heroku", "shopify_cli/commands/app/deploy/heroku"
6
5
  prerequisite_task :ensure_git_dependency
7
6
 
8
7
  recommend_default_ruby_range
@@ -103,7 +103,7 @@ module ShopifyCLI
103
103
  # any command run by the context.
104
104
  attr_accessor :env
105
105
 
106
- def initialize(root: Dir.pwd, env: ($original_env || ENV).clone) # :nodoc:
106
+ def initialize(root: Dir.pwd, env: ($original_env || ENV).to_h) # :nodoc:
107
107
  self.root = root
108
108
  self.env = env
109
109
  end
@@ -164,7 +164,7 @@ module ShopifyCLI
164
164
 
165
165
  # will return true while tests are running, either locally or on CI
166
166
  def testing?
167
- ci? || ENV["TEST"]
167
+ ci? || ENV["SHOPIFY_CLI_TEST"]
168
168
  end
169
169
 
170
170
  ##
@@ -5,7 +5,7 @@ module ShopifyCLI
5
5
  module EntryPoint
6
6
  class << self
7
7
  def call(args, ctx = Context.new)
8
- if ctx.development?
8
+ if ctx.development? && !ctx.testing?
9
9
  ctx.warn(
10
10
  ctx.message("core.warning.development_version", File.join(ShopifyCLI::ROOT, "bin", ShopifyCLI::TOOL_NAME))
11
11
  )
@@ -17,11 +17,7 @@ module ShopifyCLI
17
17
 
18
18
  def log(name, args, &block) # rubocop:disable Lint/UnusedMethodArgument
19
19
  command, command_name = Commands::Registry.lookup_command(name)
20
- final_command = [command_name]
21
- if command
22
- subcommand, subcommand_name = command.subcommand_registry.lookup_command(args.first)
23
- final_command << subcommand_name if subcommand
24
- end
20
+ full_command = self.full_command(command, args, resolved_command: [command_name])
25
21
 
26
22
  start_time = now_in_milliseconds
27
23
  err = nil
@@ -35,9 +31,21 @@ module ShopifyCLI
35
31
  # If there's an error, we don't prompt from here and we let the exception
36
32
  # reporter do that.
37
33
  if report?(prompt: err.nil?)
38
- send_event(start_time, final_command, args - final_command, err&.message)
34
+ send_event(start_time, full_command, args - full_command, err&.message)
35
+ end
36
+ end
37
+ end
38
+
39
+ def full_command(command, args, resolved_command:)
40
+ resolved_command = resolved_command.dup
41
+ if command
42
+ subcommand, subcommand_name = command.subcommand_registry.lookup_command(args.first)
43
+ resolved_command << subcommand_name if subcommand
44
+ if subcommand&.subcommand_registry
45
+ resolved_command = full_command(subcommand, args.drop(1), resolved_command: resolved_command)
39
46
  end
40
47
  end
48
+ resolved_command
41
49
  end
42
50
 
43
51
  private
@@ -46,6 +46,8 @@ module ShopifyCLI
46
46
  Bugsnag.notify(error) do |event|
47
47
  event.add_metadata(:device, metadata)
48
48
  end
49
+ rescue
50
+ nil
49
51
  end
50
52
 
51
53
  def self.report?(context:)
@@ -81,7 +81,7 @@ module ShopifyCLI
81
81
  puts "Grabbing sha256 checksum from Rubygems.org"
82
82
  require "digest/sha2"
83
83
  require "open-uri"
84
- gem_checksum = open("https://rubygems.org/downloads/shopify-cli-#{ShopifyCLI::VERSION}.gem") do |io|
84
+ gem_checksum = URI.open("https://rubygems.org/downloads/shopify-cli-#{ShopifyCLI::VERSION}.gem") do |io|
85
85
  Digest::SHA256.new.hexdigest(io.read)
86
86
  end
87
87
 
@@ -181,6 +181,13 @@ module ShopifyCLI
181
181
  self
182
182
  end
183
183
 
184
+ ##
185
+ # returns the value this success represents
186
+ #
187
+ def unwrap!
188
+ value
189
+ end
190
+
184
191
  ##
185
192
  # returns the success value and ignores the fallback value that was either
186
193
  # provided as a method argument or by passing a block. However, the caller
@@ -339,6 +346,13 @@ module ShopifyCLI
339
346
  raise ArgumentError, "expected either a fallback value or a block" unless (args.length == 1) ^ block
340
347
  block ? block.call(@error) : args.pop
341
348
  end
349
+
350
+ ##
351
+ # raises the error this failure represents
352
+ #
353
+ def unwrap!
354
+ raise error
355
+ end
342
356
  end
343
357
 
344
358
  ##
@@ -28,6 +28,10 @@ module ShopifyCLI
28
28
 
29
29
  private
30
30
 
31
+ def api_client
32
+ @api_client ||= ThemeAdminAPI.new(@ctx, @theme.shop)
33
+ end
34
+
31
35
  def updated_file?(body, file)
32
36
  remote_checksum = body.dig("asset", "checksum")
33
37
  local_checksum = file.checksum
@@ -45,12 +49,8 @@ module ShopifyCLI
45
49
  end
46
50
 
47
51
  def fetch_asset(file)
48
- ShopifyCLI::AdminAPI.rest_request(
49
- @ctx,
50
- shop: @theme.shop,
52
+ api_client.get(
51
53
  path: "themes/#{@theme.id}/assets.json",
52
- method: "GET",
53
- api_version: "unstable",
54
54
  query: URI.encode_www_form("asset[key]" => file.relative_path.to_s),
55
55
  )
56
56
  rescue ShopifyCLI::API::APIRequestNotFoundError
@@ -45,13 +45,21 @@ module ShopifyCLI
45
45
  def filter_theme_files(files)
46
46
  files
47
47
  .select { |file| @theme.theme_file?(file) }
48
- .reject { |file| @ignore_filter&.ignore?(file) }
48
+ .map { |file| @theme[file] }
49
+ .reject { |file| ignore_file?(file) }
49
50
  end
50
51
 
51
52
  def filter_remote_files(files)
52
53
  files
53
54
  .select { |file| @syncer.remote_file?(file) }
54
- .reject { |file| @ignore_filter&.ignore?(file) }
55
+ .map { |file| @theme[file] }
56
+ .reject { |file| ignore_file?(file) }
57
+ end
58
+
59
+ private
60
+
61
+ def ignore_file?(file)
62
+ @ignore_filter&.ignore?(file.relative_path.to_s)
55
63
  end
56
64
  end
57
65
  end
@@ -45,11 +45,8 @@ module ShopifyCLI
45
45
  def exists?
46
46
  return false unless id
47
47
 
48
- ShopifyCLI::AdminAPI.rest_request(
49
- @ctx,
50
- shop: shop,
51
- path: "themes/#{id}.json",
52
- api_version: "unstable",
48
+ api_client.get(
49
+ path: "themes/#{id}.json"
53
50
  )
54
51
  rescue ShopifyCLI::API::APIRequestNotFoundError
55
52
  false
@@ -7,15 +7,15 @@ require "forwardable"
7
7
  require_relative "syncer/error_reporter"
8
8
  require_relative "syncer/standard_reporter"
9
9
  require_relative "syncer/operation"
10
+ require_relative "theme_admin_api"
10
11
 
11
12
  module ShopifyCLI
12
13
  module Theme
13
14
  class Syncer
14
15
  extend Forwardable
15
16
 
16
- API_VERSION = "unstable"
17
-
18
17
  attr_reader :checksums
18
+ attr_reader :checksums_mutex
19
19
  attr_accessor :include_filter
20
20
  attr_accessor :ignore_filter
21
21
 
@@ -39,6 +39,9 @@ module ShopifyCLI
39
39
  # Mutex used to pause all threads when backing-off when hitting API rate limits
40
40
  @backoff_mutex = Mutex.new
41
41
 
42
+ # Mutex used to coordinate changes in the checksums (shared accross all threads)
43
+ @checksums_mutex = Mutex.new
44
+
42
45
  # Latest theme assets checksums. Updated on each upload.
43
46
  @checksums = {}
44
47
 
@@ -46,6 +49,10 @@ module ShopifyCLI
46
49
  @error_checksums = []
47
50
  end
48
51
 
52
+ def api_client
53
+ @api_client ||= ThemeAdminAPI.new(@ctx, @theme.shop)
54
+ end
55
+
49
56
  def lock_io!
50
57
  @reporters.each(&:disable!)
51
58
  end
@@ -96,11 +103,8 @@ module ShopifyCLI
96
103
  end
97
104
 
98
105
  def fetch_checksums!
99
- _status, response = ShopifyCLI::AdminAPI.rest_request(
100
- @ctx,
101
- shop: @theme.shop,
102
- path: "themes/#{@theme.id}/assets.json",
103
- api_version: API_VERSION,
106
+ _status, response = api_client.get(
107
+ path: "themes/#{@theme.id}/assets.json"
104
108
  )
105
109
  update_checksums(response)
106
110
  end
@@ -239,12 +243,8 @@ module ShopifyCLI
239
243
  asset[:attachment] = Base64.encode64(file.read)
240
244
  end
241
245
 
242
- _status, body, response = ShopifyCLI::AdminAPI.rest_request(
243
- @ctx,
244
- shop: @theme.shop,
246
+ _status, body, response = api_client.put(
245
247
  path: "themes/#{@theme.id}/assets.json",
246
- method: "PUT",
247
- api_version: API_VERSION,
248
248
  body: JSON.generate(asset: asset)
249
249
  )
250
250
 
@@ -272,16 +272,12 @@ module ShopifyCLI
272
272
  end
273
273
 
274
274
  def ignored_by_include_filter?(path)
275
- include_filter && !include_filter.match?(path)
275
+ !!include_filter && !include_filter.match?(path)
276
276
  end
277
277
 
278
278
  def get(file)
279
- _status, body, response = ShopifyCLI::AdminAPI.rest_request(
280
- @ctx,
281
- shop: @theme.shop,
279
+ _status, body, response = api_client.get(
282
280
  path: "themes/#{@theme.id}/assets.json",
283
- method: "GET",
284
- api_version: API_VERSION,
285
281
  query: URI.encode_www_form("asset[key]" => file.relative_path.to_s),
286
282
  )
287
283
 
@@ -298,12 +294,8 @@ module ShopifyCLI
298
294
  end
299
295
 
300
296
  def delete(file)
301
- _status, _body, response = ShopifyCLI::AdminAPI.rest_request(
302
- @ctx,
303
- shop: @theme.shop,
297
+ _status, _body, response = api_client.delete(
304
298
  path: "themes/#{@theme.id}/assets.json",
305
- method: "DELETE",
306
- api_version: API_VERSION,
307
299
  body: JSON.generate(asset: {
308
300
  key: file.relative_path.to_s,
309
301
  })
@@ -314,14 +306,17 @@ module ShopifyCLI
314
306
 
315
307
  def update_checksums(api_response)
316
308
  api_response.values.flatten.each do |asset|
317
- if asset["key"]
309
+ next unless asset["key"]
310
+ checksums_mutex.synchronize do
318
311
  @checksums[asset["key"]] = asset["checksum"]
319
312
  end
320
313
  end
321
314
  # Generate .liquid asset files are reported twice in checksum:
322
315
  # once of generated, once for .liquid. We only keep the .liquid, that's the one we have
323
316
  # on disk.
324
- @checksums.reject! { |key, _| @checksums.key?("#{key}.liquid") }
317
+ checksums_mutex.synchronize do
318
+ @checksums.reject! { |key, _| @checksums.key?("#{key}.liquid") }
319
+ end
325
320
  end
326
321
 
327
322
  def file_has_changed?(file)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative "file"
3
+ require_relative "theme_admin_api"
3
4
 
4
5
  require "pathname"
5
6
  require "time"
@@ -59,7 +60,7 @@ module ShopifyCLI
59
60
  end
60
61
 
61
62
  def shop
62
- AdminAPI.get_shop_or_abort(@ctx)
63
+ api_client.get_shop_or_abort
63
64
  end
64
65
 
65
66
  def editor_url
@@ -101,9 +102,7 @@ module ShopifyCLI
101
102
  def create
102
103
  raise InvalidThemeRole, "Can't create live theme. Use publish." if live?
103
104
 
104
- _status, body = ShopifyCLI::AdminAPI.rest_request(
105
- @ctx,
106
- shop: shop,
105
+ _status, body = api_client.post(
107
106
  path: "themes.json",
108
107
  body: JSON.generate({
109
108
  theme: {
@@ -111,31 +110,21 @@ module ShopifyCLI
111
110
  role: role,
112
111
  },
113
112
  }),
114
- method: "POST",
115
- api_version: "unstable",
116
113
  )
117
114
 
118
115
  @id = body["theme"]["id"]
119
116
  end
120
117
 
121
118
  def delete
122
- AdminAPI.rest_request(
123
- @ctx,
124
- shop: shop,
125
- method: "DELETE",
126
- path: "themes/#{id}.json",
127
- api_version: "unstable",
119
+ api_client.delete(
120
+ path: "themes/#{id}.json"
128
121
  )
129
122
  end
130
123
 
131
124
  def publish
132
125
  return if live?
133
- AdminAPI.rest_request(
134
- @ctx,
135
- shop: shop,
136
- method: "PUT",
126
+ api_client.put(
137
127
  path: "themes/#{id}.json",
138
- api_version: "unstable",
139
128
  body: JSON.generate(theme: {
140
129
  role: "main",
141
130
  })
@@ -205,23 +194,23 @@ module ShopifyCLI
205
194
  end
206
195
 
207
196
  def fetch_themes(ctx)
208
- AdminAPI.rest_request(
209
- ctx,
210
- shop: AdminAPI.get_shop_or_abort(ctx),
211
- path: "themes.json",
212
- api_version: "unstable",
197
+ api_client = ThemeAdminAPI.new(ctx)
198
+
199
+ api_client.get(
200
+ path: "themes.json"
213
201
  )
214
202
  end
215
203
  end
216
204
 
217
205
  private
218
206
 
207
+ def api_client
208
+ @api_client ||= ThemeAdminAPI.new(@ctx)
209
+ end
210
+
219
211
  def load_info_from_api
220
- _status, body = AdminAPI.rest_request(
221
- @ctx,
222
- shop: shop,
223
- path: "themes/#{id}.json",
224
- api_version: "unstable",
212
+ _status, body = api_client.get(
213
+ path: "themes/#{id}.json"
225
214
  )
226
215
 
227
216
  @name = body.dig("theme", "name")
@@ -0,0 +1,71 @@
1
+ module ShopifyCLI
2
+ module Theme
3
+ class ThemeAdminAPI
4
+ API_VERSION = "unstable"
5
+
6
+ attr_reader :shop
7
+
8
+ def initialize(ctx, shop = nil)
9
+ @ctx = ctx
10
+ @shop = shop || get_shop_or_abort
11
+ end
12
+
13
+ def get(path:, **args)
14
+ rest_request(
15
+ method: "GET",
16
+ path: path,
17
+ **args
18
+ )
19
+ end
20
+
21
+ def put(path:, **args)
22
+ rest_request(
23
+ method: "PUT",
24
+ path: path,
25
+ **args
26
+ )
27
+ end
28
+
29
+ def post(path:, **args)
30
+ rest_request(
31
+ method: "POST",
32
+ path: path,
33
+ **args
34
+ )
35
+ end
36
+
37
+ def delete(path:, **args)
38
+ rest_request(
39
+ method: "DELETE",
40
+ path: path,
41
+ **args
42
+ )
43
+ end
44
+
45
+ def get_shop_or_abort # rubocop:disable Naming/AccessorMethodName
46
+ ShopifyCLI::AdminAPI.get_shop_or_abort(@ctx)
47
+ end
48
+
49
+ private
50
+
51
+ def rest_request(**args)
52
+ ShopifyCLI::AdminAPI.rest_request(
53
+ @ctx,
54
+ shop: @shop,
55
+ api_version: API_VERSION,
56
+ **args.compact
57
+ )
58
+ rescue ShopifyCLI::API::APIRequestForbiddenError,
59
+ ShopifyCLI::API::APIRequestUnauthorizedError
60
+ handle_permissions_error
61
+ end
62
+
63
+ def handle_permissions_error
64
+ ensure_user_error = @ctx.message("theme.ensure_user_error", get_shop_or_abort)
65
+ ensure_user_try_this = @ctx.message("theme.ensure_user_try_this")
66
+
67
+ @ctx.abort(ensure_user_error, ensure_user_try_this)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -40,6 +40,7 @@ module ShopifyCLI
40
40
 
41
41
  property! :underscore_keys, accepts: [true, false], default: false, reader: :underscore_keys?
42
42
  property! :symbolize_keys, accepts: [true, false], default: false, reader: :symbolize_keys?
43
+ property! :shallow, accepts: [true, false], default: false, reader: :shallow?
43
44
  property! :associative_array_container,
44
45
  accepts: ->(c) { c.respond_to?(:new) && c.method_defined?(:[]=) },
45
46
  default: -> { Hash }
@@ -47,10 +48,10 @@ module ShopifyCLI
47
48
  def call(object)
48
49
  case object
49
50
  when Array
50
- object.map(&self).map(&:value)
51
+ shallow? ? object.dup : object.map(&self).map(&:value)
51
52
  when Hash
52
53
  object.each.with_object(associative_array_container.new) do |(key, value), result|
53
- result[transform_key(key)] = call(value).value
54
+ result[transform_key(key)] = shallow? ? value : call(value).value
54
55
  end
55
56
  else
56
57
  ShopifyCLI::Result.success(object)
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.13.0"
2
+ VERSION = "2.14.0"
3
3
  end
data/shipit.yml ADDED
@@ -0,0 +1,3 @@
1
+ deploy:
2
+ post:
3
+ - bundle exec rake notify_version_to_bugsnag
data/shopify-cli.gemspec CHANGED
@@ -35,11 +35,18 @@ Gem::Specification.new do |spec|
35
35
  spec.require_paths = ["lib", "vendor"]
36
36
  spec.executables << "shopify"
37
37
 
38
- spec.add_development_dependency("bundler", "~> 2.2.2")
38
+ spec.add_development_dependency("bundler", "~> 2.3.8")
39
39
  spec.add_development_dependency("rake", "~> 12.3", ">= 12.3.3")
40
40
  spec.add_development_dependency("minitest", "~> 5.0")
41
41
 
42
42
  spec.add_dependency("bugsnag", "~> 6.22")
43
43
  spec.add_dependency("listen", "~> 3.7.0")
44
- spec.add_dependency("theme-check", "~> 1.9.0")
44
+
45
+ # We prefer being more strict here with the version range to have a more deterministic build.
46
+ # The added benefit is that, if the user upgrades the CLI, and we have "~> 1.10.1" version range,
47
+ # they will get a theme-check update.
48
+ # Whereas if we were to have "~> 1.9", that version would still be satisfied and thus not upgraded.
49
+ # Both shopify-cli and theme-check gems are owned and developed by Shopify.
50
+ # These gems are currently being actively developed and it's easiest to update them together.
51
+ spec.add_dependency("theme-check", "~> 1.10.1")
45
52
  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.13.0
4
+ version: 2.14.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-03-02 00:00:00.000000000 Z
11
+ date: 2022-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.2.2
19
+ version: 2.3.8
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.2.2
26
+ version: 2.3.8
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -92,14 +92,14 @@ dependencies:
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: 1.9.0
95
+ version: 1.10.1
96
96
  type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: 1.9.0
102
+ version: 1.10.1
103
103
  description: |
104
104
  Shopify CLI helps you build Shopify apps faster. It quickly scaffolds Node.js
105
105
  and Ruby on Rails embedded apps. It also automates many common tasks in the
@@ -155,12 +155,16 @@ files:
155
155
  - docs/users/migrate-from-themekit.md
156
156
  - ext/javy/hashes/javy-arm-macos-v0.1.0.gz.sha256
157
157
  - ext/javy/hashes/javy-arm-macos-v0.2.0.gz.sha256
158
+ - ext/javy/hashes/javy-arm-macos-v0.2.1.gz.sha256
158
159
  - ext/javy/hashes/javy-x86_64-linux-v0.1.0.gz.sha256
159
160
  - ext/javy/hashes/javy-x86_64-linux-v0.2.0.gz.sha256
161
+ - ext/javy/hashes/javy-x86_64-linux-v0.2.1.gz.sha256
160
162
  - ext/javy/hashes/javy-x86_64-macos-v0.1.0.gz.sha256
161
163
  - ext/javy/hashes/javy-x86_64-macos-v0.2.0.gz.sha256
164
+ - ext/javy/hashes/javy-x86_64-macos-v0.2.1.gz.sha256
162
165
  - ext/javy/hashes/javy-x86_64-windows-v0.1.0.gz.sha256
163
166
  - ext/javy/hashes/javy-x86_64-windows-v0.2.0.gz.sha256
167
+ - ext/javy/hashes/javy-x86_64-windows-v0.2.1.gz.sha256
164
168
  - ext/javy/javy.rb
165
169
  - ext/javy/version
166
170
  - ext/shopify-extensions/extconf.rb
@@ -317,8 +321,6 @@ files:
317
321
  - lib/project_types/script/layers/infrastructure/command_runner.rb
318
322
  - lib/project_types/script/layers/infrastructure/errors.rb
319
323
  - lib/project_types/script/layers/infrastructure/extension_point_repository.rb
320
- - lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb
321
- - lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb
322
324
  - lib/project_types/script/layers/infrastructure/languages/project_creator.rb
323
325
  - lib/project_types/script/layers/infrastructure/languages/task_runner.rb
324
326
  - lib/project_types/script/layers/infrastructure/languages/tool_version_checker.rb
@@ -502,12 +504,14 @@ files:
502
504
  - lib/shopify_cli/theme/syncer/operation.rb
503
505
  - lib/shopify_cli/theme/syncer/standard_reporter.rb
504
506
  - lib/shopify_cli/theme/theme.rb
507
+ - lib/shopify_cli/theme/theme_admin_api.rb
505
508
  - lib/shopify_cli/thread_pool.rb
506
509
  - lib/shopify_cli/thread_pool/job.rb
507
510
  - lib/shopify_cli/transform_data_structure.rb
508
511
  - lib/shopify_cli/tunnel.rb
509
512
  - lib/shopify_cli/utilities.rb
510
513
  - lib/shopify_cli/version.rb
514
+ - shipit.yml
511
515
  - shopify-cli.gemspec
512
516
  - shopify-dev
513
517
  - utilities/constants.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Script
4
- module Layers
5
- module Infrastructure
6
- module Languages
7
- class AssemblyScriptProjectCreator < ProjectCreator
8
- def setup_dependencies
9
- task_runner = Infrastructure::Languages::AssemblyScriptTaskRunner.new(ctx)
10
- task_runner.set_npm_config
11
- super
12
-
13
- update_package_json_name
14
- end
15
-
16
- private
17
-
18
- def update_package_json_name
19
- file_content = ctx.read("package.json")
20
- hash = file_content_to_hash(file_content)
21
- hash["name"] = project_name
22
- ctx.write("package.json", hash_to_file_content(hash))
23
- end
24
-
25
- def file_content_to_hash(content)
26
- JSON.parse(content)
27
- end
28
-
29
- def hash_to_file_content(hash)
30
- JSON.pretty_generate(hash)
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Script
4
- module Layers
5
- module Infrastructure
6
- module Languages
7
- class AssemblyScriptTaskRunner < TaskRunner
8
- NODE_MIN_VERSION = "14.15.0"
9
- NPM_MIN_VERSION = "5.2.0"
10
-
11
- BYTECODE_FILE = "build/script.wasm"
12
- METADATA_FILE = "build/metadata.json"
13
- SCRIPT_SDK_BUILD = "npm run build"
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"
17
-
18
- def build
19
- compile
20
- bytecode
21
- end
22
-
23
- def install_dependencies
24
- run_cmd_with_env_check(NPM_INSTALL_COMMAND)
25
-
26
- rescue Errors::SystemCallFailureError => e
27
- raise Errors::DependencyInstallError, e.out
28
- end
29
-
30
- def dependencies_installed?
31
- # Assuming if node_modules folder exist at root of script folder, all deps are installed
32
- ctx.dir_exist?("node_modules")
33
- end
34
-
35
- def metadata_file_location
36
- METADATA_FILE
37
- end
38
-
39
- def library_version(library_name)
40
- output = JSON.parse(run_cmd_with_env_check("npm -s list --json"))
41
- library_version_from_npm_list(output, library_name)
42
- rescue Errors::SystemCallFailureError => error
43
- library_version_from_npm_list_error_output(error, library_name)
44
- end
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
-
51
- private
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
-
66
- def library_version_from_npm_list_error_output(error, library_name)
67
- # npm list can return a failure status code, even when returning the correct data.
68
- # This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
69
- # In here, we check that the output contains `npm list`'s structure and extract the version.
70
- output = JSON.parse(error.out)
71
- raise error unless output.key?("dependencies")
72
-
73
- library_version_from_npm_list(output, library_name)
74
- rescue JSON::ParserError
75
- raise error
76
- end
77
-
78
- def library_version_from_npm_list(output, library_name)
79
- output.dig("dependencies", library_name, "version").tap do |version|
80
- raise Errors::APILibraryNotFoundError, library_name unless version
81
- end
82
- end
83
-
84
- def compile
85
- check_compilation_dependencies!
86
- run_cmd_with_env_check(SCRIPT_SDK_BUILD)
87
- end
88
-
89
- def check_compilation_dependencies!
90
- pkg = JSON.parse(File.read("package.json"))
91
- build_script = pkg.dig("scripts", "build")
92
-
93
- raise Errors::BuildScriptNotFoundError,
94
- "Build script not found" if build_script.nil?
95
- end
96
-
97
- def bytecode
98
- raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(BYTECODE_FILE)
99
-
100
- contents = ctx.binread(BYTECODE_FILE)
101
- ctx.rm(BYTECODE_FILE)
102
-
103
- contents
104
- end
105
- end
106
- end
107
- end
108
- end
109
- end