shopify-cli 2.6.5 → 2.6.6

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 (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)