shopify-cli 2.6.5 → 2.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -1
  3. data/CONTRIBUTING.md +9 -1
  4. data/Dockerfile +11 -3
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +3 -1
  7. data/lib/project_types/extension/cli.rb +1 -0
  8. data/lib/project_types/extension/commands/create.rb +1 -0
  9. data/lib/project_types/extension/features/argo.rb +1 -8
  10. data/lib/project_types/extension/features/argo_serve.rb +1 -1
  11. data/lib/project_types/extension/forms/create.rb +1 -1
  12. data/lib/project_types/extension/forms/questions/ask_template.rb +2 -1
  13. data/lib/project_types/extension/messages/messages.rb +1 -0
  14. data/lib/project_types/extension/models/server_config/extension.rb +2 -0
  15. data/lib/project_types/extension/tasks/converters/server_config_converter.rb +4 -5
  16. data/lib/project_types/extension/tasks/find_package_from_json.rb +37 -0
  17. data/lib/project_types/extension/tasks/load_server_config.rb +6 -1
  18. data/lib/project_types/rails/commands/create.rb +45 -16
  19. data/lib/project_types/rails/forms/create.rb +0 -1
  20. data/lib/project_types/script/commands/create.rb +1 -4
  21. data/lib/project_types/script/config/extension_points.yml +3 -0
  22. data/lib/project_types/script/errors.rb +0 -18
  23. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  24. data/lib/project_types/script/layers/domain/script_json.rb +1 -1
  25. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +0 -4
  26. data/lib/project_types/script/layers/infrastructure/errors.rb +0 -2
  27. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +1 -1
  28. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +25 -0
  29. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +3 -4
  30. data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
  31. data/lib/project_types/script/messages/messages.rb +3 -18
  32. data/lib/project_types/script/ui/error_handler.rb +0 -26
  33. data/lib/project_types/theme/commands/serve.rb +1 -0
  34. data/lib/project_types/theme/messages/messages.rb +1 -0
  35. data/lib/shopify_cli/exception_reporter.rb +5 -2
  36. data/lib/shopify_cli/migrator.rb +9 -11
  37. data/lib/shopify_cli/theme/dev_server.rb +2 -1
  38. data/lib/shopify_cli/version.rb +1 -1
  39. data/shopify-cli.gemspec +1 -5
  40. data/utilities/docker/container.rb +23 -2
  41. data/utilities/docker.rb +1 -0
  42. metadata +6 -7
  43. data/ext/shopify-cli/extconf.rb +0 -60
  44. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e55157b78cbbd9cd86e3d2e8c542241d7064de3fc4e37768f207dc8ee124f4c
4
- data.tar.gz: 7b5aa9ae10f96a7724d4a0b0dd79712254ce3f99273a88c7e9198ec03f17ba7c
3
+ metadata.gz: bb41d18df964832b9ebc6be79e80006c4750c8d416c9550cbcc625d190bf26b9
4
+ data.tar.gz: d5c6b523faf27c0a6b3c53ccaadd1c4f47e932d7e0c2520e7f0bfcb2f7f7b820
5
5
  SHA512:
6
- metadata.gz: b526446476543316cdd68a40cc5e28af1a0bd0d823757b53901c39b9e2f510a8fb9e9edd52f7fc967df44603d17d9092e95b375e12618f86f6261f45217b4802
7
- data.tar.gz: 7ee68c03b039974c59d0cbc50ad866faf52ec436fe66b17c1a79e801c4ed1854ddf13fb82274e79e2917c5d63c0066b048d1255d4a3019349dd559b402d12cd8
6
+ metadata.gz: 396c3c47f510e78d67775fc6b6a091849ce8c3955d2c91ec516659ef4377df44a00a3faaa70facdd0649763b2a3b69f96ab4f859a003b23becd6baf3202d4b64
7
+ data.tar.gz: 1514e2a4c8f1841e8714a30f4e05450c5116863cc2c14cf5655143a43a49e1b5f6f2da1b8ffc2af6acd683359ea970920090ba55c6f82213e91de1cd4aeb7b87
data/CHANGELOG.md CHANGED
@@ -1,6 +1,19 @@
1
1
  From version 2.6.0, the sections in this file adhere to the [keep a changelog](https://keepachangelog.com/en/1.0.0/) specification.
2
2
  ## [Unreleased]
3
3
 
4
+ ## Version 2.6.6
5
+ ### Added
6
+ * [#1609](https://github.com/Shopify/shopify-cli/pull/1609): Add `--bind=HOST` option to `shopify theme serve`.
7
+
8
+ ### Fixed
9
+ * [#1678](https://github.com/Shopify/shopify-cli/pull/1678): Fix migrator's incompatibility with Ruby 2.5.
10
+ * [#1690](https://github.com/Shopify/shopify-cli/pull/1690): Fix `extension push` command for `PRODUCT_SUBSCRIPTION` extensions
11
+
12
+ ### Changed
13
+ * [#1678](https://github.com/Shopify/shopify-cli/pull/1678): Change the `@shopify/scripts-checkout-apis-temp` package name to `@shopify/scripts-discount-apis`.
14
+
15
+ ### Removed
16
+ * [#1664](https://github.com/Shopify/shopify-cli/pull/1664): Remove ruby-locking extension
4
17
  ## Version 2.6.5
5
18
  ### Fixed
6
19
  * [#1661](https://github.com/Shopify/shopify-cli/pull/1661): Handle npm list non-zero exit status when pushing scripts
@@ -24,7 +37,7 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h
24
37
 
25
38
  ## Version 2.6.2
26
39
  * Fix broken installation due to a missing variable in `extconf.rb`
27
-
40
+
28
41
  ## Version 2.6.1
29
42
  * [#1608](https://github.com/Shopify/shopify-cli/pull/1608): Fix errors not being reported.
30
43
  ## Version 2.6.0
data/CONTRIBUTING.md CHANGED
@@ -13,7 +13,7 @@ Most of the internal components the project uses have unit tests to thoroughly t
13
13
 
14
14
  Acceptance tests run the built `shopify` command line against a wide range of fixtures and verify its output and results. They are the slowest to run however provide the most coverage. The idea is to test a few complete scenarios for each major feature.
15
15
 
16
- Those are written in [Cucumber](https://cucumber.io/) and Ruby and can be found in the [`features/`](/features) directory. They can be executed by running
16
+ Those are written in [Cucumber](https://cucumber.io/) and Ruby and can be found in the [`features/`](/features) directory. They can be executed by running:
17
17
 
18
18
  ```bash
19
19
  bundle exec cucumber
@@ -21,3 +21,11 @@ bundle exec cucumber features/theme.feature:3 # A specific test
21
21
  ```
22
22
 
23
23
  > **Note** that we currently don't have an approach for stubbing the interactions with the GraphQL APIs and that therefore we can't write acceptance tests for commands that interact with APIs.
24
+
25
+ #### Debugging acceptance tests
26
+ When developing acceptance tests, it can be helpful to see the outputs of running commands.
27
+ To see outputs, append `--verbose` when running an acceptance test. Example:
28
+
29
+ ```sh
30
+ bundle exec cucumber features/theme.feature --verbose
31
+ ```
data/Dockerfile CHANGED
@@ -6,8 +6,7 @@ FROM cimg/ruby:2.7.1
6
6
  RUN git config --global user.email "development-lifecycle@shopify.com"
7
7
  RUN git config --global user.name "Development Lifecycle"
8
8
 
9
- # throw errors if Gemfile has been modified since Gemfile.lock
10
- RUN bundle config --global frozen 1
9
+ RUN gem update bundler
11
10
 
12
11
  WORKDIR /usr/src/app
13
12
 
@@ -24,4 +23,13 @@ RUN sudo apt-get install git -y
24
23
  # Install the latest version of NodeJS
25
24
  RUN sudo apt-get install ca-certificates -y
26
25
  RUN curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
27
- RUN sudo apt-get install -y nodejs
26
+ RUN sudo apt-get install -y nodejs
27
+
28
+ # Install the latest version of Yarn
29
+ RUN sudo npm install --global yarn
30
+
31
+ # Python is necessary to compile NPM packages with native extensions through node-gyp
32
+ RUN sudo apt install python-minimal -y
33
+
34
+ # Install sqlite3
35
+ RUN sudo apt-get install libsqlite3-dev -y
data/Gemfile CHANGED
@@ -14,6 +14,7 @@ group :development, :test do
14
14
  gem "rubocop-minitest", require: false
15
15
  gem "rubocop-rake", require: false
16
16
  gem "iniparse", "~> 1.5"
17
+ gem "colorize", "~> 0.8.1"
17
18
  end
18
19
 
19
20
  group :test do
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify-cli (2.6.5)
4
+ shopify-cli (2.6.6)
5
5
  bugsnag (~> 6.22)
6
6
  listen (~> 3.7.0)
7
7
  theme-check (~> 1.7.2)
@@ -18,6 +18,7 @@ GEM
18
18
  builder (3.2.4)
19
19
  byebug (11.1.3)
20
20
  coderay (1.1.3)
21
+ colorize (0.8.1)
21
22
  concurrent-ruby (1.1.9)
22
23
  crack (0.4.5)
23
24
  rexml
@@ -135,6 +136,7 @@ PLATFORMS
135
136
  DEPENDENCIES
136
137
  bundler (~> 2.2.2)
137
138
  byebug
139
+ colorize (~> 0.8.1)
138
140
  cucumber (~> 7.0)
139
141
  fakefs (>= 1.0)
140
142
  iniparse (~> 1.5)
@@ -43,6 +43,7 @@ module Extension
43
43
  autoload :GetProduct, Project.project_filepath("tasks/get_product")
44
44
  autoload :RunExtensionCommand, Project.project_filepath("tasks/run_extension_command")
45
45
  autoload :LoadServerConfig, Project.project_filepath("tasks/load_server_config")
46
+ autoload :FindPackageFromJson, Project.project_filepath("tasks/find_package_from_json.rb")
46
47
 
47
48
  module Converters
48
49
  autoload :RegistrationConverter, Project.project_filepath("tasks/converters/registration_converter")
@@ -11,6 +11,7 @@ module Extension
11
11
 
12
12
  options do |parser, flags|
13
13
  parser.on("--name=NAME") { |name| flags[:name] = name }
14
+ parser.on("--template=TEMPLATE") { |template| flags[:template] = template }
14
15
  parser.on("--type=TYPE") { |type| flags[:type] = type.upcase }
15
16
  parser.on("--api-key=KEY") { |key| flags[:api_key] = key.downcase }
16
17
  parser.on("--getting-started") { flags[:getting_started] = true }
@@ -48,14 +48,7 @@ module Extension
48
48
  end
49
49
 
50
50
  def renderer_package(context)
51
- js_system = ShopifyCLI::JsSystem.new(ctx: context)
52
- Tasks::FindNpmPackages
53
- .exactly_one_of(renderer_package_name, js_system: js_system, production_only: true)
54
- .unwrap { |err| raise err }
55
- rescue Extension::PackageResolutionFailed
56
- context.abort(
57
- context.message("features.argo.dependencies.argo_missing_renderer_package_error")
58
- )
51
+ Tasks::FindPackageFromJson.call(renderer_package_name, context: context)
59
52
  end
60
53
 
61
54
  private
@@ -63,7 +63,7 @@ module Extension
63
63
  ShopifyCLI::Tasks::EnsureDevStore.call(context) if required_fields.include?(:shop)
64
64
 
65
65
  project = ExtensionProject.current
66
- ensure_resource_resource_url! if specification_handler.supplies_resource_url?
66
+ ensure_resource_resource_url! if specification_handler.supplies_resource_url? && !supports_development_server?
67
67
 
68
68
  return if required_fields.all? do |field|
69
69
  value = project.env.public_send(field)
@@ -24,7 +24,7 @@ module Extension
24
24
  ShopifyCLI::Result.wrap(ExtensionProjectDetails.new)
25
25
  .then(&Questions::AskApp.new(ctx: ctx, api_key: api_key))
26
26
  .then(&Questions::AskType.new(ctx: ctx, type: type))
27
- .then(&Questions::AskTemplate.new(ctx: ctx))
27
+ .then(&Questions::AskTemplate.new(ctx: ctx, template: template))
28
28
  .then(&Questions::AskName.new(ctx: ctx, name: name))
29
29
  .unwrap { |e| raise e }
30
30
  .tap do |project_details|
@@ -9,13 +9,14 @@ module Extension
9
9
  ]
10
10
 
11
11
  property! :ctx
12
+ property :template, accepts: Models::ServerConfig::Development::VALID_TEMPLATES
12
13
  property :prompt,
13
14
  accepts: ->(prompt) { prompt.respond_to?(:call) },
14
15
  default: -> { CLI::UI::Prompt.method(:ask) }
15
16
 
16
17
  def call(project_details)
17
18
  return project_details unless template_required?(project_details)
18
- project_details.template = choose_interactively
19
+ project_details.template = template || choose_interactively
19
20
  project_details
20
21
  end
21
22
 
@@ -175,6 +175,7 @@ module Extension
175
175
  errors: {
176
176
  unknown_type: "Unknown extension type %s",
177
177
  package_not_found: "`%s` package not found.",
178
+ module_not_found: "Unable to find module %s. Ensure your dependencies are up-to-date and try again.",
178
179
  },
179
180
  warnings: {
180
181
  resource_url_auto_generation_failed: "{{*}} {{yellow:Warning:}} Unable to auto generate " \
@@ -5,10 +5,12 @@ module Extension
5
5
  module ServerConfig
6
6
  class Extension < Base
7
7
  include SmartProperties
8
+
8
9
  property! :uuid, accepts: String
9
10
  property! :type, accepts: String
10
11
  property! :user, accepts: ServerConfig::User
11
12
  property! :development, accepts: ServerConfig::Development
13
+ property :extension_points, accepts: Array
12
14
 
13
15
  def self.build(uuid: "", template:, type:, root_dir:)
14
16
  renderer = ServerConfig::DevelopmentRenderer.find(type)
@@ -5,13 +5,11 @@ module Extension
5
5
  module Tasks
6
6
  module Converters
7
7
  module ServerConfigConverter
8
- def self.from_hash(hash, type)
8
+ def self.from_hash(hash:, type:, registration_uuid:)
9
9
  context.abort(context.message("tasks.errors.parse_error")) if hash.nil?
10
10
 
11
- project = ExtensionProject.current
12
-
13
11
  extension = Models::ServerConfig::Extension.new(
14
- uuid: project.registration_uuid,
12
+ uuid: registration_uuid,
15
13
  type: type.upcase,
16
14
  user: Models::ServerConfig::User.new,
17
15
  development: Models::ServerConfig::Development.new(
@@ -20,7 +18,8 @@ module Extension
20
18
  entries: Models::ServerConfig::DevelopmentEntries.new(
21
19
  main: hash.dig("development", "entries", "main")
22
20
  )
23
- )
21
+ ),
22
+ extension_points: hash.dig("extension_points")
24
23
  )
25
24
 
26
25
  Models::ServerConfig::Root.new(extensions: [extension])
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+
4
+ module Extension
5
+ module Tasks
6
+ class FindPackageFromJson < ShopifyCLI::Task
7
+ include SmartProperties
8
+
9
+ property! :context, accepts: ShopifyCLI::Context
10
+
11
+ def self.call(package_name, **config)
12
+ new(**config).call(package_name)
13
+ end
14
+
15
+ def call(package_name)
16
+ ShopifyCLI::Result.success(resolve_package_json(package_name))
17
+ .then { |file| File.read(file) }
18
+ .then { |file| JSON.parse(file) }
19
+ .then { |file| file.dig("version") }
20
+ .then { |version| return Models::NpmPackage.new(name: package_name, version: version) }
21
+ .unwrap do |error|
22
+ context.debug(error)
23
+ context.abort(context.message("errors.module_not_found", package_name))
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def resolve_package_json(package_name)
30
+ path = "path.join(require.resolve('#{package_name}'), '../package.json')"
31
+ package_json, error, _ = CLI::Kit::System.capture3("node", "-p", path)
32
+ return error unless !error.nil?
33
+ package_json.chomp
34
+ end
35
+ end
36
+ end
37
+ end
@@ -10,7 +10,12 @@ module Extension
10
10
  class << self
11
11
  def call(file_name:, type:)
12
12
  config = YAML.load_file(file_name)
13
- Tasks::Converters::ServerConfigConverter.from_hash(config, type)
13
+ project = ExtensionProject.current
14
+ Tasks::Converters::ServerConfigConverter.from_hash(
15
+ hash: config,
16
+ type: type,
17
+ registration_uuid: project.registration_uuid
18
+ )
14
19
  rescue Psych::SyntaxError => e
15
20
  raise(
16
21
  ShopifyCLI::Abort,
@@ -2,7 +2,9 @@
2
2
  module Rails
3
3
  class Command
4
4
  class Create < ShopifyCLI::SubCommand
5
- prerequisite_task :ensure_authenticated
5
+ unless ShopifyCLI::Environment.acceptance_test?
6
+ prerequisite_task :ensure_authenticated
7
+ end
6
8
 
7
9
  USER_AGENT_CODE = <<~USERAGENT
8
10
  module ShopifyAPI
@@ -31,8 +33,8 @@ module Rails
31
33
  end
32
34
 
33
35
  def call(args, _name)
34
- form = Forms::Create.ask(@ctx, args, options.flags)
35
- return @ctx.puts(self.class.help) if form.nil?
36
+ form_data = self.form_data(args)
37
+ return @ctx.puts(self.class.help) if form_data.nil?
36
38
 
37
39
  ruby_version = Ruby.version(@ctx)
38
40
  @ctx.abort(@ctx.message("rails.create.error.invalid_ruby_version")) unless
@@ -41,34 +43,61 @@ module Rails
41
43
  check_node
42
44
  check_yarn
43
45
 
44
- build(form.name, form.db)
46
+ build(form_data.name, form_data.db)
47
+
45
48
  set_custom_ua
46
49
  ShopifyCLI::Project.write(
47
50
  @ctx,
48
51
  project_type: "rails",
49
- organization_id: form.organization_id,
52
+ organization_id: form_data.organization_id,
50
53
  )
51
54
 
52
- api_client = ShopifyCLI::Tasks::CreateApiClient.call(
53
- @ctx,
54
- org_id: form.organization_id,
55
- title: form.title,
56
- type: form.type,
57
- )
55
+ api_client = if ShopifyCLI::Environment.acceptance_test?
56
+ {
57
+ "apiKey" => "public_api_key",
58
+ "apiSecretKeys" => [
59
+ {
60
+ "secret" => "api_secret_key",
61
+ },
62
+ ],
63
+ }
64
+ else
65
+ ShopifyCLI::Tasks::CreateApiClient.call(
66
+ @ctx,
67
+ org_id: form_data.organization_id,
68
+ title: form_data.title,
69
+ type: form_data.type,
70
+ )
71
+ end
58
72
 
59
73
  ShopifyCLI::Resources::EnvFile.new(
60
74
  api_key: api_client["apiKey"],
61
75
  secret: api_client["apiSecretKeys"].first["secret"],
62
- shop: form.shop_domain,
76
+ shop: form_data.shop_domain,
63
77
  scopes: "write_products,write_customers,write_draft_orders",
64
78
  ).write(@ctx)
65
79
 
66
- partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form.organization_id, api_client["id"])
80
+ partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form_data.organization_id, api_client["id"])
67
81
 
68
- @ctx.puts(@ctx.message("apps.create.info.created", form.title, partners_url))
69
- @ctx.puts(@ctx.message("apps.create.info.serve", form.name, ShopifyCLI::TOOL_NAME, "rails"))
82
+ @ctx.puts(@ctx.message("apps.create.info.created", form_data.title, partners_url))
83
+ @ctx.puts(@ctx.message("apps.create.info.serve", form_data.name, ShopifyCLI::TOOL_NAME, "rails"))
70
84
  unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
71
- @ctx.puts(@ctx.message("apps.create.info.install", partners_url, form.title))
85
+ @ctx.puts(@ctx.message("apps.create.info.install", partners_url, form_data.title))
86
+ end
87
+ end
88
+
89
+ def form_data(args)
90
+ if ShopifyCLI::Environment.acceptance_test?
91
+ Struct.new(:title, :name, :organization_id, :type, :shop_domain, :db, keyword_init: true).new(
92
+ title: options.flags[:title],
93
+ name: options.flags[:title],
94
+ organization_id: "123",
95
+ shop_domain: "test.shopify.io",
96
+ type: "public",
97
+ db: options.flags[:db]
98
+ )
99
+ else
100
+ Forms::Create.ask(@ctx, args, options.flags)
72
101
  end
73
102
  end
74
103
 
@@ -8,7 +8,6 @@ module Rails
8
8
  VALID_DB_TYPES = ["sqlite3",
9
9
  "mysql",
10
10
  "postgresql",
11
- "sqlite3",
12
11
  "oracle",
13
12
  "frontbase",
14
13
  "ibm_db",
@@ -9,11 +9,9 @@ module Script
9
9
 
10
10
  options do |parser, flags|
11
11
  parser.on("--name=NAME") { |name| flags[:name] = name }
12
- parser.on("--extension_point=EP_NAME") { |ep_name| flags[:extension_point] = ep_name }
13
- parser.on("--extension-point=EP_NAME") { |ep_name| flags[:extension_point] = ep_name }
12
+ parser.on("--api=API_NAME") { |ep_name| flags[:extension_point] = ep_name }
14
13
  parser.on("--language=LANGUAGE") { |language| flags[:language] = language }
15
14
  parser.on("--branch=BRANCH") { |branch| flags[:branch] = branch }
16
- parser.on("--no-config-ui") { |no_config_ui| flags[:no_config_ui] = no_config_ui }
17
15
  end
18
16
 
19
17
  def call(args, _name)
@@ -30,7 +28,6 @@ module Script
30
28
  sparse_checkout_branch: options.flags[:branch] || "master",
31
29
  script_name: form.name,
32
30
  extension_point_type: form.extension_point,
33
- no_config_ui: options.flags.key?(:no_config_ui)
34
31
  )
35
32
  @ctx.puts(@ctx.message("script.create.change_directory_notice", project.script_name))
36
33
  rescue StandardError => e
@@ -32,6 +32,7 @@ payment_methods:
32
32
  package: "@shopify/scripts-checkout-apis"
33
33
  typescript:
34
34
  beta: true
35
+ package: "@shopify/scripts-checkout-apis-temp"
35
36
  repo: "https://github.com/Shopify/scripts-apis-examples"
36
37
  shipping_methods:
37
38
  domain: 'checkout'
@@ -41,6 +42,7 @@ shipping_methods:
41
42
  package: "@shopify/scripts-checkout-apis"
42
43
  typescript:
43
44
  beta: true
45
+ package: "@shopify/scripts-checkout-apis-temp"
44
46
  repo: "https://github.com/Shopify/scripts-apis-examples"
45
47
  discount_types:
46
48
  beta: true
@@ -48,4 +50,5 @@ discount_types:
48
50
  libraries:
49
51
  typescript:
50
52
  beta: true
53
+ package: "@shopify/scripts-discount-apis"
51
54
  repo: "https://github.com/Shopify/scripts-apis-examples"
@@ -6,23 +6,5 @@ module Script
6
6
 
7
7
  class NoExistingAppsError < ScriptProjectError; end
8
8
  class NoExistingOrganizationsError < ScriptProjectError; end
9
-
10
- class NoExistingStoresError < ScriptProjectError
11
- attr_reader :organization_id
12
- def initialize(organization_id)
13
- super()
14
- @organization_id = organization_id
15
- end
16
- end
17
-
18
- class InvalidConfigProps < ScriptProjectError; end
19
-
20
- class InvalidConfigYAMLError < ScriptProjectError
21
- attr_reader :config_file
22
- def initialize(config_file)
23
- super()
24
- @config_file = config_file
25
- end
26
- end
27
9
  end
28
10
  end
@@ -7,7 +7,7 @@ module Script
7
7
  module Application
8
8
  class CreateScript
9
9
  class << self
10
- def call(ctx:, language:, sparse_checkout_branch:, script_name:, extension_point_type:, no_config_ui:)
10
+ def call(ctx:, language:, sparse_checkout_branch:, script_name:, extension_point_type:)
11
11
  raise Infrastructure::Errors::ScriptProjectAlreadyExistsError, script_name if ctx.dir_exist?(script_name)
12
12
 
13
13
  in_new_directory_context(ctx, script_name) do
@@ -36,7 +36,7 @@ module Script
36
36
  )
37
37
 
38
38
  install_dependencies(ctx, language, script_name, project_creator)
39
- script_project_repo.update_or_create_script_json(title: script_name, configuration_ui: !no_config_ui)
39
+ script_project_repo.update_or_create_script_json(title: script_name)
40
40
  project
41
41
  end
42
42
  end
@@ -15,7 +15,7 @@ module Script
15
15
  @version = @content["version"].to_s
16
16
  @title = @content["title"]
17
17
  @description = @content["description"]
18
- @configuration_ui = @content["configurationUi"]
18
+ @configuration_ui = @content.fetch("configurationUi", true)
19
19
  @configuration = @content["configuration"]
20
20
  end
21
21
 
@@ -27,10 +27,6 @@ module Script
27
27
  case error_code(response["errors"])
28
28
  when "forbidden"
29
29
  raise Errors::ForbiddenError
30
- when "forbidden_on_shop"
31
- raise Errors::ShopAuthenticationError
32
- when "app_not_installed_on_shop"
33
- raise Errors::AppNotInstalledError
34
30
  else
35
31
  raise Errors::GraphqlError, response["errors"]
36
32
  end
@@ -4,7 +4,6 @@ module Script
4
4
  module Layers
5
5
  module Infrastructure
6
6
  module Errors
7
- class AppNotInstalledError < ScriptProjectError; end
8
7
  class BuildError < ScriptProjectError; end
9
8
  class ScriptJsonSyntaxError < ScriptProjectError; end
10
9
 
@@ -101,7 +100,6 @@ module Script
101
100
  end
102
101
 
103
102
  class ScriptProjectAlreadyExistsError < ScriptProjectError; end
104
- class ShopAuthenticationError < ScriptProjectError; end
105
103
  class TaskRunnerNotFoundError < ScriptProjectError; end
106
104
  class BuildScriptNotFoundError < ScriptProjectError; end
107
105
  class InvalidBuildScriptError < ScriptProjectError; end
@@ -48,7 +48,7 @@ module Script
48
48
  end
49
49
 
50
50
  def library_version(library_name)
51
- output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm list --json"))
51
+ output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
52
52
  library_version_from_npm_list(output, library_name)
53
53
  rescue Errors::SystemCallFailureError => error
54
54
  library_version_from_npm_list_error_output(error, library_name)
@@ -48,8 +48,33 @@ module Script
48
48
  Domain::Metadata.create_from_json(@ctx, raw_contents)
49
49
  end
50
50
 
51
+ def library_version(library_name)
52
+ output = JSON.parse(CommandRunner.new(ctx: ctx).call("npm -s list --json"))
53
+ library_version_from_npm_list(output, library_name)
54
+ rescue Errors::SystemCallFailureError => error
55
+ library_version_from_npm_list_error_output(error, library_name)
56
+ end
57
+
51
58
  private
52
59
 
60
+ def library_version_from_npm_list_error_output(error, library_name)
61
+ # npm list can return a failure status code, even when returning the correct data.
62
+ # This causes the CommandRunner to throw a SystemCallFailure error that contains the data.
63
+ # In here, we check that the output contains `npm list`'s structure and extract the version.
64
+ output = JSON.parse(error.out)
65
+ raise error unless output.key?("dependencies")
66
+
67
+ library_version_from_npm_list(output, library_name)
68
+ rescue JSON::ParserError
69
+ raise error
70
+ end
71
+
72
+ def library_version_from_npm_list(output, library_name)
73
+ output.dig("dependencies", library_name, "version").tap do |version|
74
+ raise Errors::APILibraryNotFoundError, library_name unless version
75
+ end
76
+ end
77
+
53
78
  def check_node_version!
54
79
  output, status = @ctx.capture2e("node", "--version")
55
80
  raise Errors::DependencyInstallError, output unless status.success?
@@ -81,10 +81,10 @@ module Script
81
81
  )
82
82
  end
83
83
 
84
- def update_or_create_script_json(title:, configuration_ui: false)
84
+ def update_or_create_script_json(title:)
85
85
  script_json = ScriptJsonRepository
86
86
  .new(ctx: ctx)
87
- .update_or_create(title: title, configuration_ui: configuration_ui)
87
+ .update_or_create(title: title)
88
88
 
89
89
  Domain::ScriptProject.new(
90
90
  id: ctx.root,
@@ -148,11 +148,10 @@ module Script
148
148
  current_script_json || raise(Domain::Errors::NoScriptJsonFile)
149
149
  end
150
150
 
151
- def update_or_create(title:, configuration_ui:)
151
+ def update_or_create(title:)
152
152
  json = current_script_json&.content || {}
153
153
  json["version"] ||= "1"
154
154
  json["title"] = title
155
- json["configurationUi"] = !!configuration_ui
156
155
 
157
156
  ctx.write(SCRIPT_JSON_FILENAME, JSON.pretty_generate(json))
158
157
 
@@ -46,7 +46,7 @@ module Script
46
46
 
47
47
  if user_errors.any? { |e| e["tag"] == "already_exists_error" }
48
48
  raise Errors::ScriptRepushError, uuid
49
- elsif (e = user_errors.any? { |err| err["tag"] == "configuration_syntax_error" })
49
+ elsif (e = user_errors.any? { |err| err["tag"] == "configuration_definition_syntax_error" })
50
50
  raise Errors::ScriptJsonSyntaxError
51
51
  elsif (e = user_errors.find { |err| err["tag"] == "configuration_definition_missing_keys_error" })
52
52
  raise Errors::ScriptJsonMissingKeysError, e["message"]
@@ -27,10 +27,6 @@ module Script
27
27
  "extension_point_type or script_name.",
28
28
  invalid_context_help: "Add these values and try again.",
29
29
 
30
- invalid_config_props_cause: "{{command:--config-props}} is formatted incorrectly.",
31
- invalid_config_props_help: "Try again using this format: "\
32
- "{{cyan:--config-props='name1:value1, name2:value2'}}",
33
-
34
30
  invalid_script_name_cause: "Invalid script name.",
35
31
  invalid_script_name_help: "Replace or remove unsupported characters. Valid characters "\
36
32
  "are numbers, letters, hyphens, or underscores.",
@@ -42,9 +38,6 @@ module Script
42
38
  no_existing_orgs_cause: "You don't have any partner organizations.",
43
39
  no_existing_orgs_help: "Visit https://partners.shopify.com/ to create a partners account.",
44
40
 
45
- no_existing_stores_cause: "You don't have any stores in your Partner Dashboard.",
46
- no_existing_stores_help: "Visit https://partners.shopify.com/%{organization_id}/stores/ to create one.",
47
-
48
41
  project_exists_cause: "A directory with this same name already exists.",
49
42
  project_exists_help: "Try again and enter a different name for the script.",
50
43
 
@@ -54,9 +47,6 @@ module Script
54
47
  invalid_language_cause: "Invalid language %s.",
55
48
  invalid_language_help: "Allowed values: %s.",
56
49
 
57
- invalid_config: "Can't change the configuration values because %1$s is missing or "\
58
- "it isn't formatted properly.",
59
-
60
50
  missing_script_json_field_cause: "The script.json file is missing the required %s field.",
61
51
  missing_script_json_field_help: "Add the field and try again.",
62
52
 
@@ -91,8 +81,8 @@ module Script
91
81
  system_call_failure_cause: "An error was returned while running {{command:%{cmd}}}.",
92
82
  system_call_failure_help: "Review the following error and try again.\n{{red:%{out}}}",
93
83
 
94
- metadata_validation_cause: "Invalid Script API metadata.",
95
- metadata_validation_help: "Ensure the 'shopify/scripts-toolchain-as' package is up to date.",
84
+ metadata_validation_cause: "The Script API metadata is incorrect.",
85
+ metadata_validation_help: "The 'schemaVersions.major' field contains an unsupported version.",
96
86
 
97
87
  metadata_schema_versions_missing: "Invalid Script metadata:" \
98
88
  " 'schemaVersions' field is missing",
@@ -107,7 +97,6 @@ module Script
107
97
  metadata_not_found_help: "Ensure the 'shopify/scripts-toolchain-as' package is up to date and " \
108
98
  "'package.json' contains a 'scripts/build' entry with a " \
109
99
  "'--metadata build/metadata.json' argument",
110
- app_not_installed_cause: "App not installed on store.",
111
100
 
112
101
  build_error_cause: "Something went wrong while building the script.",
113
102
  build_error_help: "Correct the errors and try again.",
@@ -126,9 +115,6 @@ module Script
126
115
  script_repush_cause: "A version of this script already exists on the app.",
127
116
  script_repush_help: "Use {{cyan:--force}} to replace the existing script.",
128
117
 
129
- shop_auth_cause: "Unable to authenticate with the store.",
130
- shop_auth_help: "Try again.",
131
-
132
118
  invalid_build_script: "The root package.json contains an invalid build command that " \
133
119
  "is needed to compile your script to WebAssembly.",
134
120
  build_script_not_found: "The root package.json is missing the build command that " \
@@ -162,8 +148,7 @@ module Script
162
148
  Usage: {{command:%1$s script create}}
163
149
  Options:
164
150
  {{command:--name=NAME}} Script project name. Use any string.
165
- {{command:--extension-point=TYPE}} Script API name. Allowed values: %2$s.
166
- {{command:--no-config-ui}} Specify this option when you don’t want your script to render an interface in Shopify admin.
151
+ {{command:--api=TYPE}} Script API name. Allowed values: %2$s.
167
152
  HELP
168
153
 
169
154
  error: {
@@ -44,15 +44,6 @@ module Script
44
44
  cause_of_error: ShopifyCLI::Context.message("script.error.invalid_context_cause"),
45
45
  help_suggestion: ShopifyCLI::Context.message("script.error.invalid_context_help"),
46
46
  }
47
- when Errors::InvalidConfigProps
48
- {
49
- cause_of_error: ShopifyCLI::Context.message("script.error.invalid_config_props_cause"),
50
- help_suggestion: ShopifyCLI::Context.message("script.error.invalid_config_props_help"),
51
- }
52
- when Errors::InvalidConfigYAMLError
53
- {
54
- cause_of_error: ShopifyCLI::Context.message("script.error.invalid_config", e.config_file),
55
- }
56
47
  when Layers::Infrastructure::Errors::InvalidLanguageError
57
48
  {
58
49
  cause_of_error: ShopifyCLI::Context.message("script.error.invalid_language_cause", e.language),
@@ -76,14 +67,6 @@ module Script
76
67
  cause_of_error: ShopifyCLI::Context.message("script.error.no_existing_orgs_cause"),
77
68
  help_suggestion: ShopifyCLI::Context.message("script.error.no_existing_orgs_help"),
78
69
  }
79
- when Errors::NoExistingStoresError
80
- {
81
- cause_of_error: ShopifyCLI::Context.message("script.error.no_existing_stores_cause"),
82
- help_suggestion: ShopifyCLI::Context.message(
83
- "script.error.no_existing_stores_help",
84
- organization_id: e.organization_id
85
- ),
86
- }
87
70
  when Layers::Infrastructure::Errors::ScriptProjectAlreadyExistsError
88
71
  {
89
72
  cause_of_error: ShopifyCLI::Context.message("script.error.project_exists_cause"),
@@ -135,10 +118,6 @@ module Script
135
118
  cause_of_error: ShopifyCLI::Context.message("script.error.no_script_json_file_cause"),
136
119
  help_suggestion: ShopifyCLI::Context.message("script.error.no_script_json_file_help"),
137
120
  }
138
- when Layers::Infrastructure::Errors::AppNotInstalledError
139
- {
140
- cause_of_error: ShopifyCLI::Context.message("script.error.app_not_installed_cause"),
141
- }
142
121
  when Layers::Infrastructure::Errors::BuildError
143
122
  {
144
123
  cause_of_error: ShopifyCLI::Context.message("script.error.build_error_cause"),
@@ -217,11 +196,6 @@ module Script
217
196
  cause_of_error: ShopifyCLI::Context.message("script.error.script_repush_cause"),
218
197
  help_suggestion: ShopifyCLI::Context.message("script.error.script_repush_help"),
219
198
  }
220
- when Layers::Infrastructure::Errors::ShopAuthenticationError
221
- {
222
- cause_of_error: ShopifyCLI::Context.message("script.error.shop_auth_cause"),
223
- help_suggestion: ShopifyCLI::Context.message("script.error.shop_auth_help"),
224
- }
225
199
  when Layers::Infrastructure::Errors::BuildScriptNotFoundError
226
200
  {
227
201
  cause_of_error: ShopifyCLI::Context.message("script.error.build_script_not_found"),
@@ -5,6 +5,7 @@ module Theme
5
5
  class Command
6
6
  class Serve < ShopifyCLI::SubCommand
7
7
  options do |parser, flags|
8
+ parser.on("--bind=HOST") { |bind| flags[:bind] = bind.to_s }
8
9
  parser.on("--port=PORT") { |port| flags[:port] = port.to_i }
9
10
  parser.on("--poll") { flags[:poll] = true }
10
11
  end
@@ -94,6 +94,7 @@ module Theme
94
94
  Options:
95
95
  {{command:--port=PORT}} Local port to serve theme preview from
96
96
  {{command:--poll}} Force polling to detect file changes
97
+ {{command:--bind=HOST}} Set which network interface the web server listens on
97
98
  HELP
98
99
  serve: "Viewing theme…",
99
100
  open_fail: "Couldn't open the theme",
@@ -31,9 +31,12 @@ module ShopifyCLI
31
31
  config.auto_capture_sessions = false
32
32
  end
33
33
 
34
- metadata = {}
34
+ metadata = { rubyPlatform: RUBY_PLATFORM }
35
35
  metadata.merge!(custom_metadata)
36
- Bugsnag.notify(error, metadata)
36
+
37
+ Bugsnag.notify(error) do |event|
38
+ event.add_metadata(:device, metadata)
39
+ end
37
40
  end
38
41
 
39
42
  def self.report?(context:)
@@ -9,23 +9,21 @@ module ShopifyCLI
9
9
  migrations_directory: File.expand_path("migrator/migrations", __dir__)
10
10
  )
11
11
  baseline_date = last_migration_date
12
- unless baseline_date.nil?
13
- migrations = migrations(migrations_directory: migrations_directory)
14
- .select { |m|
15
- m.date > baseline_date.to_i
16
- }
17
- .each { |m| m.run }
12
+ unless baseline_date.nil?
13
+ migrations(migrations_directory: migrations_directory)
14
+ .select do |m|
15
+ m.date > baseline_date.to_i
16
+ end
17
+ .each(&:run)
18
18
  end
19
19
 
20
20
  store_last_migration_date
21
21
  end
22
22
 
23
- private
24
-
25
23
  def self.store_last_migration_date
26
24
  ShopifyCLI::DB.set(ShopifyCLI::Constants::StoreKeys::LAST_MIGRATION_DATE => Time.now.to_i)
27
25
  end
28
-
26
+
29
27
  def self.last_migration_date
30
28
  ShopifyCLI::DB.get(ShopifyCLI::Constants::StoreKeys::LAST_MIGRATION_DATE)
31
29
  end
@@ -35,7 +33,7 @@ module ShopifyCLI
35
33
  file_name = File.basename(file_path).gsub(".rb", "")
36
34
  file_name_components = file_name.split("_")
37
35
  date_timestamp = file_name_components[0].to_i
38
- migration_name = file_name_components[1...].join("_")
36
+ migration_name = file_name_components.drop(1).join("_")
39
37
 
40
38
  Migrator::Migration.new(
41
39
  name: migration_name,
@@ -45,4 +43,4 @@ module ShopifyCLI
45
43
  end
46
44
  end
47
45
  end
48
- end
46
+ end
@@ -20,7 +20,7 @@ module ShopifyCLI
20
20
  class << self
21
21
  attr_accessor :ctx
22
22
 
23
- def start(ctx, root, port: 9292, poll: false)
23
+ def start(ctx, root, bind: "127.0.0.1", port: 9292, poll: false)
24
24
  @ctx = ctx
25
25
  theme = DevelopmentTheme.new(ctx, root: root)
26
26
  ignore_filter = IgnoreFilter.from_path(root)
@@ -74,6 +74,7 @@ module ShopifyCLI
74
74
  watcher.start
75
75
  WebServer.run(
76
76
  @app,
77
+ BindAddress: bind,
77
78
  Port: port,
78
79
  Logger: logger,
79
80
  AccessLog: [],
@@ -1,3 +1,3 @@
1
1
  module ShopifyCLI
2
- VERSION = "2.6.5"
2
+ VERSION = "2.6.6"
3
3
  end
data/shopify-cli.gemspec CHANGED
@@ -33,11 +33,7 @@ Gem::Specification.new do |spec|
33
33
  end
34
34
  spec.bindir = "bin"
35
35
  spec.require_paths = ["lib", "vendor"]
36
- spec.extensions = ["ext/shopify-cli/extconf.rb"]
37
- # Do NOT include `shopify` as a listed executable via `spec.executables`.
38
- # `ext/shopify-cli/extconf.rb` will dynamically create a script and soft-link
39
- # `/usr/local/bin/shopify` to that script, in order to "lock" the Ruby used to
40
- # a single Ruby (useful for debugging in multi-Ruby environments)
36
+ spec.executables << "shopify"
41
37
 
42
38
  spec.add_development_dependency("bundler", "~> 2.2.2")
43
39
  spec.add_development_dependency("rake", "~> 12.3", ">= 12.3.3")
@@ -1,8 +1,10 @@
1
1
  require "open3"
2
+ require "colorize"
2
3
 
3
4
  module Utilities
4
5
  module Docker
5
6
  class Container
7
+ SHOPIFY_PATH = "/usr/src/app"
6
8
  SHOPIFY_BIN_PATH = "/usr/src/app/bin/shopify"
7
9
 
8
10
  Error = Class.new(StandardError)
@@ -55,6 +57,10 @@ module Utilities
55
57
  end
56
58
 
57
59
  def exec(*args, relative_dir: nil)
60
+ if ARGV.include?("--verbose")
61
+ running_prefix = "Running command: #{args.join(" ")}"
62
+ STDOUT.puts(running_prefix.colorize(:yellow).bold)
63
+ end
58
64
  command = ["docker", "exec"]
59
65
  cwd = if relative_dir.nil?
60
66
  @cwd
@@ -68,8 +74,23 @@ module Utilities
68
74
  command << @id
69
75
  command += args
70
76
 
71
- out, stat = Open3.capture2e(*command)
72
- raise Error, out unless stat.success?
77
+ docker_prefix = "Docker (#{args.first}):"
78
+
79
+ if ARGV.include?("--verbose")
80
+ stat = Open3.popen3(*command) do |stdin, stdout, stderr, wait_thread|
81
+ Thread.new do
82
+ stdout.each { |l| STDOUT.puts("#{docker_prefix.colorize(:cyan).bold} #{l}") }
83
+ stderr.each { |l| STDERR.puts("#{docker_prefix.colorize(:red).bold} #{l}") }
84
+ end
85
+ stdin.close
86
+
87
+ wait_thread.value
88
+ end
89
+ raise StandardError, "The command #{args.first} failed" unless stat.success?
90
+ else
91
+ out, stat = Open3.capture2e(*command)
92
+ raise Error, out unless stat.success?
93
+ end
73
94
  end
74
95
  end
75
96
  end
data/utilities/docker.rb CHANGED
@@ -57,6 +57,7 @@ module Utilities
57
57
 
58
58
  def build_image_if_needed
59
59
  unless image_exists?(image_tag)
60
+ puts "Rebuilding the Docker image..."
60
61
  _, err, stat = Open3.capture3(
61
62
  "docker", "build", root_dir, "-t", image_tag
62
63
  )
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.6.5
4
+ version: 2.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-20 00:00:00.000000000 Z
11
+ date: 2021-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -107,9 +107,9 @@ description: |
107
107
  and webhooks.
108
108
  email:
109
109
  - dev-tools-education@shopify.com
110
- executables: []
111
- extensions:
112
- - ext/shopify-cli/extconf.rb
110
+ executables:
111
+ - shopify
112
+ extensions: []
113
113
  extra_rdoc_files: []
114
114
  files:
115
115
  - ".github/CODEOWNERS"
@@ -155,7 +155,6 @@ files:
155
155
  - docs/getting-started/upgrade/index.md
156
156
  - docs/help/start-app/index.md
157
157
  - docs/index.md
158
- - ext/shopify-cli/extconf.rb
159
158
  - ext/shopify-extensions/extconf.rb
160
159
  - ext/shopify-extensions/shopify_extensions.rb
161
160
  - ext/shopify-extensions/version
@@ -250,6 +249,7 @@ files:
250
249
  - lib/project_types/extension/tasks/create_extension.rb
251
250
  - lib/project_types/extension/tasks/fetch_specifications.rb
252
251
  - lib/project_types/extension/tasks/find_npm_packages.rb
252
+ - lib/project_types/extension/tasks/find_package_from_json.rb
253
253
  - lib/project_types/extension/tasks/get_app.rb
254
254
  - lib/project_types/extension/tasks/get_apps.rb
255
255
  - lib/project_types/extension/tasks/get_extensions.rb
@@ -300,7 +300,6 @@ files:
300
300
  - lib/project_types/script/errors.rb
301
301
  - lib/project_types/script/forms/create.rb
302
302
  - lib/project_types/script/graphql/app_script_set.graphql
303
- - lib/project_types/script/graphql/app_script_update_or_create.graphql
304
303
  - lib/project_types/script/graphql/get_app_scripts.graphql
305
304
  - lib/project_types/script/graphql/module_upload_url_generate.graphql
306
305
  - lib/project_types/script/graphql/script_service_proxy.graphql
@@ -1,60 +0,0 @@
1
- require "rbconfig"
2
- require "fileutils"
3
- require "date"
4
-
5
- gem = File.expand_path("../../../", __FILE__)
6
- exe = File.join(gem, "bin", "shopify")
7
-
8
- # `--skip-cli-build` will be passed from the brew `shopify-cli.rb` formula, so
9
- # as to prevent this extension builder doing the script and sym-link creation;
10
- # the brew install process takes care of these itself - see
11
- # https://github.com/Shopify/homebrew-shopify/shopify-cli.rb
12
- if ARGV && ARGV[0]&.match(/skip-cli-build/)
13
- makefile_content = <<~MAKEFILE
14
- .PHONY: clean
15
-
16
- clean: ;
17
-
18
- install: ;
19
- MAKEFILE
20
- elsif RUBY_PLATFORM.match(/mswin|mingw|cygwin/)
21
- bat_path = File.dirname(RbConfig.ruby)
22
- bat = "#{bat_path}\\shopify.bat"
23
-
24
- script_content = "#{RbConfig.ruby} -I '#{gem}' '#{exe}' %*"
25
-
26
- FileUtils.mkdir_p(bat_path)
27
- makefile_content = <<~MAKEFILE
28
- .PHONY: clean install
29
-
30
- clean:
31
- \t rm -f "#{bat}"
32
-
33
- install: clean
34
- \t echo "@ECHO OFF"> "#{bat}"
35
- \t echo "#{script_content}">> "#{bat}"
36
- MAKEFILE
37
- else
38
- script = exe + ".sh"
39
- symlink = "/usr/local/bin/shopify"
40
-
41
- script_content = <<~SCRIPT
42
- #!/usr/bin/env bash
43
- #{RbConfig.ruby} -I #{gem} #{exe} $@
44
- SCRIPT
45
-
46
- File.write(script, script_content)
47
- FileUtils.chmod("+x", script)
48
-
49
- makefile_content = <<~MAKEFILE
50
- .PHONY: clean install
51
-
52
- clean:
53
- \t@sudo rm -f #{symlink}
54
-
55
- install: clean
56
- \t@sudo ln -s #{script} #{symlink}
57
- MAKEFILE
58
- end
59
-
60
- File.write("Makefile", makefile_content)