shopify-cli 2.7.2 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/workflows/shopify.yml +1 -1
  4. data/.gitignore +1 -0
  5. data/.ruby-version +1 -1
  6. data/CHANGELOG.md +52 -0
  7. data/Codespace.dockerfile +2 -2
  8. data/Gemfile.lock +4 -4
  9. data/RELEASING.md +4 -3
  10. data/Tests.dockerfile +2 -2
  11. data/dev.yml +3 -3
  12. data/ext/javy/hashes/javy-arm-macos-v0.1.0.gz.sha256 +1 -0
  13. data/ext/javy/hashes/javy-x86_64-linux-v0.1.0.gz.sha256 +1 -0
  14. data/ext/javy/hashes/javy-x86_64-macos-v0.1.0.gz.sha256 +1 -0
  15. data/ext/javy/hashes/javy-x86_64-windows-v0.1.0.gz.sha256 +1 -0
  16. data/ext/javy/javy.rb +31 -13
  17. data/lib/graphql/get_extension_registrations.graphql +27 -0
  18. data/lib/project_types/extension/cli.rb +27 -2
  19. data/lib/project_types/extension/commands/build.rb +10 -10
  20. data/lib/project_types/extension/commands/create.rb +2 -3
  21. data/lib/project_types/extension/commands/push.rb +36 -8
  22. data/lib/project_types/extension/extension_project.rb +1 -1
  23. data/lib/project_types/extension/features/argo_serve.rb +6 -5
  24. data/lib/project_types/extension/forms/questions/ask_registration.rb +6 -2
  25. data/lib/project_types/extension/loaders/project.rb +29 -0
  26. data/lib/project_types/extension/loaders/specification_handler.rb +22 -0
  27. data/lib/project_types/extension/messages/messages.rb +4 -0
  28. data/lib/project_types/extension/models/app.rb +1 -1
  29. data/lib/project_types/extension/models/development_server.rb +2 -4
  30. data/lib/project_types/extension/models/specification_handlers/default.rb +4 -0
  31. data/lib/project_types/extension/tasks/convert_server_config.rb +3 -1
  32. data/lib/project_types/extension/tasks/execute_commands/base.rb +13 -0
  33. data/lib/project_types/extension/tasks/execute_commands/build.rb +29 -0
  34. data/lib/project_types/extension/tasks/execute_commands/create.rb +33 -0
  35. data/lib/project_types/extension/tasks/execute_commands/serve.rb +35 -0
  36. data/lib/project_types/extension/tasks/merge_server_config.rb +33 -22
  37. data/lib/project_types/rails/commands/create.rb +1 -1
  38. data/lib/project_types/rails/gem.rb +1 -2
  39. data/lib/project_types/script/cli.rb +8 -1
  40. data/lib/project_types/script/commands/connect.rb +19 -0
  41. data/lib/project_types/script/commands/create.rb +8 -2
  42. data/lib/project_types/script/commands/push.rb +35 -12
  43. data/lib/project_types/script/config/extension_points.yml +10 -2
  44. data/lib/project_types/script/graphql/app_script_set.graphql +2 -2
  45. data/lib/project_types/script/layers/application/connect_app.rb +15 -3
  46. data/lib/project_types/script/layers/application/create_script.rb +17 -17
  47. data/lib/project_types/script/layers/application/extension_points.rb +50 -26
  48. data/lib/project_types/script/layers/application/push_script.rb +6 -3
  49. data/lib/project_types/script/layers/domain/errors.rb +1 -4
  50. data/lib/project_types/script/layers/domain/extension_point.rb +14 -0
  51. data/lib/project_types/script/layers/domain/push_package.rb +3 -3
  52. data/lib/project_types/script/layers/domain/{script_json.rb → script_config.rb} +2 -2
  53. data/lib/project_types/script/layers/domain/script_project.rb +1 -1
  54. data/lib/project_types/script/layers/infrastructure/errors.rb +30 -5
  55. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +2 -2
  56. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +125 -27
  57. data/lib/project_types/script/layers/infrastructure/script_service.rb +11 -11
  58. data/lib/project_types/script/loaders/project.rb +44 -0
  59. data/lib/project_types/script/loaders/specification_handler.rb +22 -0
  60. data/lib/project_types/script/messages/messages.rb +34 -3
  61. data/lib/project_types/script/ui/error_handler.rb +35 -15
  62. data/lib/project_types/theme/commands/pull.rb +39 -16
  63. data/lib/project_types/theme/commands/push.rb +60 -29
  64. data/lib/project_types/theme/commands/serve.rb +5 -0
  65. data/lib/project_types/theme/messages/messages.rb +30 -18
  66. data/lib/shopify_cli/command.rb +6 -0
  67. data/lib/shopify_cli/commands/login.rb +11 -5
  68. data/lib/shopify_cli/commands/switch.rb +1 -1
  69. data/lib/shopify_cli/constants.rb +5 -0
  70. data/lib/shopify_cli/context.rb +66 -11
  71. data/lib/shopify_cli/environment.rb +15 -4
  72. data/lib/shopify_cli/form.rb +2 -0
  73. data/lib/shopify_cli/git.rb +2 -0
  74. data/lib/shopify_cli/identity_auth.rb +1 -0
  75. data/lib/shopify_cli/messages/messages.rb +10 -2
  76. data/lib/shopify_cli/partners_api/app_extensions/job.rb +36 -0
  77. data/lib/shopify_cli/partners_api/app_extensions.rb +46 -0
  78. data/lib/shopify_cli/partners_api/organizations.rb +2 -5
  79. data/lib/shopify_cli/partners_api.rb +1 -0
  80. data/lib/shopify_cli/project.rb +8 -7
  81. data/lib/shopify_cli/resources/env_file.rb +18 -6
  82. data/lib/shopify_cli/services/app/create/rails_service.rb +1 -1
  83. data/lib/shopify_cli/theme/dev_server/cdn_fonts.rb +73 -0
  84. data/lib/shopify_cli/theme/dev_server/hot-reload.js +57 -10
  85. data/lib/shopify_cli/theme/dev_server/hot_reload.rb +18 -2
  86. data/lib/shopify_cli/theme/dev_server/proxy/template_param_builder.rb +84 -0
  87. data/lib/shopify_cli/theme/dev_server/proxy.rb +10 -15
  88. data/lib/shopify_cli/theme/dev_server/reload_mode.rb +34 -0
  89. data/lib/shopify_cli/theme/dev_server.rb +8 -21
  90. data/lib/shopify_cli/theme/theme.rb +26 -4
  91. data/lib/shopify_cli/thread_pool/job.rb +27 -0
  92. data/lib/shopify_cli/thread_pool.rb +37 -0
  93. data/lib/shopify_cli/tunnel.rb +1 -0
  94. data/lib/shopify_cli/version.rb +1 -1
  95. data/lib/shopify_cli.rb +4 -0
  96. data/shopify-cli.gemspec +1 -1
  97. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +3 -1
  98. metadata +26 -7
  99. data/lib/graphql/all_orgs_with_extensions.graphql +0 -37
  100. data/lib/project_types/extension/tasks/run_extension_command.rb +0 -82
@@ -89,6 +89,9 @@ module Extension
89
89
  help: <<~HELP,
90
90
  Push the current extension to Shopify.
91
91
  Usage: {{command:%s extension push}}
92
+ Options:
93
+ {{command:--api-key=API_KEY}} Connect your extension and app by inserting your app's API key (which you can get from your app setup page on shopify.dev).
94
+ {{command:--extension-id=EXTENSION_ID}} The id of the extension's registration.
92
95
  HELP
93
96
  frame_title: "Pushing your extension to Shopify",
94
97
  waiting_text: "Pushing code to Shopify…",
@@ -173,6 +176,7 @@ module Extension
173
176
  errors: {
174
177
  unknown_type: "Unknown extension type %s",
175
178
  package_not_found: "`%s` package not found.",
179
+ missing_api_key: "Missing api_key.",
176
180
  module_not_found: "Unable to find module %s. Ensure your dependencies are up-to-date and try again.",
177
181
  },
178
182
  warnings: {
@@ -6,7 +6,7 @@ module Extension
6
6
  include SmartProperties
7
7
 
8
8
  property! :api_key, accepts: String
9
- property! :secret, accepts: String
9
+ property :secret, accepts: String
10
10
  property :title, accepts: String
11
11
  property :business_name, accepts: String
12
12
  end
@@ -40,7 +40,7 @@ module Extension
40
40
 
41
41
  def serve(context, server_config)
42
42
  CLI::Kit::System.popen3(executable, "serve", "-") do |input, out, err, status|
43
- context.puts("Sending configuration data …")
43
+ context.debug("Sending configuration data to extension development server …")
44
44
  input << server_config.to_yaml
45
45
  input.close
46
46
 
@@ -57,17 +57,15 @@ module Extension
57
57
  private
58
58
 
59
59
  def forward_output_to_user(out, err, ctx)
60
- ctx.puts("Starting monitoring threads …")
60
+ ctx.debug("Starting message processing threads to relay output produced by the extension development server …")
61
61
 
62
62
  Thread.new do
63
- ctx.puts("Ready to process standard output")
64
63
  while (line = out.gets)
65
64
  ctx.puts(line)
66
65
  end
67
66
  end
68
67
 
69
68
  Thread.new do
70
- ctx.puts("Ready to process standard error")
71
69
  while (error = err.gets)
72
70
  ctx.puts(error)
73
71
  end
@@ -103,6 +103,10 @@ module Extension
103
103
  raise NotImplementedError
104
104
  end
105
105
 
106
+ def server_config_path(base_dir = Dir.pwd)
107
+ File.join(base_dir, server_config_file)
108
+ end
109
+
106
110
  def server_config_file
107
111
  "shopifile.yml"
108
112
  end
@@ -9,11 +9,12 @@ module Extension
9
9
  property! :api_key, accepts: String
10
10
  property! :context, accepts: ShopifyCLI::Context
11
11
  property! :hash, accepts: Hash
12
+ property :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
12
13
  property! :registration_uuid, accepts: String
13
14
  property :resource_url, accepts: String
14
15
  property! :store, accepts: String
15
16
  property! :title, accepts: String
16
- property :tunnel_url, accepts: String
17
+ property :tunnel_url, accepts: String
17
18
  property! :type, accepts: String
18
19
 
19
20
  def self.call(*args)
@@ -46,6 +47,7 @@ module Extension
46
47
  end
47
48
  server_config = Models::ServerConfig::Root.new(
48
49
  extensions: [extension],
50
+ port: port,
49
51
  public_url: tunnel_url,
50
52
  store: store
51
53
  )
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ module ExecuteCommands
7
+ class Base
8
+ include SmartProperties
9
+ property! :type, accepts: Models::DevelopmentServerRequirements::SUPPORTED_EXTENSION_TYPES
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ module ExecuteCommands
7
+ class Build < Base
8
+ property! :context, accepts: ShopifyCLI::Context
9
+ property! :config_file_path, accepts: String
10
+
11
+ def call
12
+ ShopifyCLI::Result
13
+ .call(&method(:merge_server_config))
14
+ .then { |server_config| Models::DevelopmentServer.new.build(server_config) }
15
+ end
16
+
17
+ private
18
+
19
+ def merge_server_config
20
+ Tasks::MergeServerConfig.call(
21
+ context: context,
22
+ file_path: config_file_path,
23
+ type: type
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ module ExecuteCommands
7
+ class Create < Base
8
+ property! :template, accepts: Models::ServerConfig::Development::VALID_TEMPLATES
9
+ property! :root_dir, accepts: String
10
+
11
+ def call
12
+ ShopifyCLI::Result.success(generate_config)
13
+ .then { |server_config| Models::DevelopmentServer.new.create(server_config) }
14
+ .unwrap do |error|
15
+ raise error unless error.nil?
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def generate_config
22
+ extension = Models::ServerConfig::Extension.build(
23
+ template: template,
24
+ type: type,
25
+ root_dir: root_dir,
26
+ )
27
+
28
+ Models::ServerConfig::Root.new(extensions: [extension])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ module ExecuteCommands
7
+ class Serve < Base
8
+ property! :context, accepts: ShopifyCLI::Context
9
+ property! :config_file_path, accepts: String
10
+ property :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
11
+ property :resource_url, accepts: String
12
+ property! :tunnel_url, accepts: String
13
+
14
+ def call
15
+ ShopifyCLI::Result
16
+ .call(&method(:merge_server_config))
17
+ .then { |server_config| Models::DevelopmentServer.new.serve(context, server_config) }
18
+ end
19
+
20
+ private
21
+
22
+ def merge_server_config
23
+ Tasks::MergeServerConfig.call(
24
+ context: context,
25
+ file_path: config_file_path,
26
+ port: port,
27
+ resource_url: resource_url,
28
+ tunnel_url: tunnel_url,
29
+ type: type
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,28 +4,39 @@ require "yaml"
4
4
 
5
5
  module Extension
6
6
  module Tasks
7
- class MergeServerConfig < ShopifyCLI::Task
8
- class << self
9
- def call(context:, file_name:, resource_url:, tunnel_url:, type:)
10
- config = YAML.load_file(file_name)
11
- project = ExtensionProject.current
12
- Tasks::ConvertServerConfig.call(
13
- api_key: project.env.api_key,
14
- context: context,
15
- hash: config,
16
- registration_uuid: project.registration_uuid,
17
- resource_url: resource_url || project.resource_url,
18
- store: project.env.shop || "",
19
- title: project.title,
20
- tunnel_url: tunnel_url,
21
- type: type
22
- )
23
- rescue Psych::SyntaxError => e
24
- raise(
25
- ShopifyCLI::Abort,
26
- ShopifyCLI::Context.message("core.yaml.error.invalid", file_name, e.message)
27
- )
28
- end
7
+ class MergeServerConfig
8
+ include SmartProperties
9
+
10
+ property! :context, accepts: ShopifyCLI::Context
11
+ property! :file_path, accepts: ->(path) { Pathname(path).yield_self { |pn| pn.absolute? && pn.file? } }
12
+ property :port, accepts: Integer, default: ShopifyCLI::Constants::Extension::DEFAULT_PORT
13
+ property :resource_url, accepts: String
14
+ property :tunnel_url, accepts: String
15
+ property! :type, accepts: Models::DevelopmentServerRequirements::SUPPORTED_EXTENSION_TYPES
16
+
17
+ def self.call(*args)
18
+ new(*args).call
19
+ end
20
+
21
+ def call
22
+ config = YAML.load_file(file_path)
23
+ project = ExtensionProject.current
24
+ Tasks::ConvertServerConfig.call(
25
+ api_key: project.env.api_key,
26
+ context: context,
27
+ hash: config,
28
+ registration_uuid: project.registration_uuid,
29
+ resource_url: resource_url || project.resource_url,
30
+ store: project.env.shop || "",
31
+ title: project.title,
32
+ tunnel_url: tunnel_url,
33
+ type: type
34
+ )
35
+ rescue Psych::SyntaxError => e
36
+ raise(
37
+ ShopifyCLI::Abort,
38
+ ShopifyCLI::Context.message("core.yaml.error.invalid", file_name, e.message)
39
+ )
29
40
  end
30
41
  end
31
42
  end
@@ -156,10 +156,10 @@ module Rails
156
156
 
157
157
  CLI::UI::Frame.open(@ctx.message("rails.create.generating_app", name)) do
158
158
  new_command = %w(rails new)
159
+ new_command << name
159
160
  new_command += DEFAULT_RAILS_FLAGS
160
161
  new_command << "--database=#{db}"
161
162
  new_command += options.flags[:rails_opts].split unless options.flags[:rails_opts].nil?
162
- new_command << name
163
163
 
164
164
  syscall(new_command)
165
165
  end
@@ -79,8 +79,7 @@ module Rails
79
79
  def install!
80
80
  spin = CLI::UI::SpinGroup.new
81
81
  spin.add(ctx.message("rails.gem.installing", name)) do |spinner|
82
- args = %w(gem install)
83
- args.push(name)
82
+ args = ["#{ENV["RUBY_BINDIR"]}gem", "install", name]
84
83
  unless version.nil?
85
84
  if ctx.windows? && version.include?("~")
86
85
  args.push("-v", "\"#{version}\"")
@@ -13,6 +13,7 @@ module Script
13
13
  hidden_feature(feature_set: :script_project)
14
14
  subcommand :Create, "create", Project.project_filepath("commands/create")
15
15
  subcommand :Push, "push", Project.project_filepath("commands/push")
16
+ subcommand :Connect, "connect", Project.project_filepath("commands/connect")
16
17
  subcommand :Javy, "javy", Project.project_filepath("commands/javy")
17
18
  end
18
19
  ShopifyCLI::Commands.register("Script::Command", "script")
@@ -24,6 +25,7 @@ module Script
24
25
  autoload :AskScriptUuid, Project.project_filepath("forms/ask_script_uuid")
25
26
  autoload :RunAgainstShopifyOrg, Project.project_filepath("forms/run_against_shopify_org")
26
27
  autoload :Create, Project.project_filepath("forms/create")
28
+ autoload :Connect, Project.project_filepath("forms/connect")
27
29
  autoload :ScriptForm, Project.project_filepath("forms/script_form")
28
30
  end
29
31
 
@@ -46,7 +48,7 @@ module Script
46
48
  autoload :PushPackage, Project.project_filepath("layers/domain/push_package")
47
49
  autoload :Metadata, Project.project_filepath("layers/domain/metadata")
48
50
  autoload :ExtensionPoint, Project.project_filepath("layers/domain/extension_point")
49
- autoload :ScriptJson, Project.project_filepath("layers/domain/script_json")
51
+ autoload :ScriptConfig, Project.project_filepath("layers/domain/script_config")
50
52
  autoload :ScriptProject, Project.project_filepath("layers/domain/script_project")
51
53
  end
52
54
 
@@ -90,5 +92,10 @@ module Script
90
92
 
91
93
  autoload :Errors, Project.project_filepath("errors")
92
94
 
95
+ module Loaders
96
+ autoload :Project, Script::Project.project_filepath("loaders/project")
97
+ autoload :SpecificationHandler, Script::Project.project_filepath("loaders/specification_handler")
98
+ end
99
+
93
100
  class ScriptProjectError < StandardError; end
94
101
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ module Script
3
+ class Command
4
+ class Connect < ShopifyCLI::Command::SubCommand
5
+ prerequisite_task :ensure_authenticated
6
+ prerequisite_task ensure_project_type: :script
7
+
8
+ def call(_args, _)
9
+ Layers::Application::ConnectApp.call(ctx: @ctx, force: true)
10
+ rescue StandardError => e
11
+ UI::ErrorHandler.pretty_print_and_raise(e, failed_op: @ctx.message("script.connect.error.operation_failed"))
12
+ end
13
+
14
+ def self.help
15
+ ShopifyCLI::Context.new.message("connect.help", ShopifyCLI::TOOL_NAME, ShopifyCLI::TOOL_NAME)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -33,8 +33,14 @@ module Script
33
33
  end
34
34
 
35
35
  def self.help
36
- allowed_values = Script::Layers::Application::ExtensionPoints.available_types.map { |type| "{{cyan:#{type}}}" }
37
- ShopifyCLI::Context.message("script.create.help", ShopifyCLI::TOOL_NAME, allowed_values.join(", "))
36
+ allowed_apis = Layers::Application::ExtensionPoints.available_types.map { |type| "{{cyan:#{type}}}" }
37
+ allowed_languages = Layers::Application::ExtensionPoints.all_languages.map { |lang| "{{cyan:#{lang}}}" }
38
+ ShopifyCLI::Context.message(
39
+ "script.create.help",
40
+ ShopifyCLI::TOOL_NAME,
41
+ allowed_apis.join(", "),
42
+ allowed_languages.join(", ")
43
+ )
38
44
  end
39
45
  end
40
46
  end
@@ -7,25 +7,48 @@ module Script
7
7
 
8
8
  options do |parser, flags|
9
9
  parser.on("--force") { |t| flags[:force] = t }
10
+ parser.on("--api-key=API_KEY") { |api_key| flags[:api_key] = api_key.gsub('"', "") }
11
+ parser.on("--api-secret=API_SECRET") { |api_secret| flags[:api_secret] = api_secret.gsub('"', "") }
12
+ parser.on("--uuid=UUID") do |uuid|
13
+ flags[:uuid] = uuid.gsub('""', "")
14
+ end
10
15
  end
11
16
 
12
17
  def call(_args, _name)
13
- fresh_env = Layers::Application::ConnectApp.call(ctx: @ctx)
14
-
15
- force = options.flags.key?(:force) || !!fresh_env
18
+ connect_to_app
19
+ project = load_project
20
+ push(project: project)
21
+ rescue StandardError => e
22
+ UI::ErrorHandler.pretty_print_and_raise(e,
23
+ failed_op: @ctx.message("script.push.error.operation_failed_no_api_key"))
24
+ end
16
25
 
17
- api_key = Layers::Infrastructure::ScriptProjectRepository.new(ctx: @ctx).get.api_key
18
- return @ctx.puts(self.class.help) unless api_key
26
+ def push(project:)
27
+ force = options.flags.key?(:force)
28
+ api_key = project.env[:api_key]
29
+ uuid = project.env[:extra]["UUID"]
19
30
 
20
- Layers::Application::PushScript.call(ctx: @ctx, force: force)
21
- @ctx.puts(@ctx.message("script.push.script_pushed", api_key: api_key))
22
- rescue StandardError => e
23
- msg = if api_key
24
- @ctx.message("script.push.error.operation_failed_with_api_key", api_key: api_key)
31
+ if ShopifyCLI::Environment.interactive? || (uuid && !uuid.empty?)
32
+ Layers::Application::PushScript.call(ctx: @ctx, force: force, project: project)
33
+ @ctx.puts(@ctx.message("script.push.script_pushed", api_key: api_key))
25
34
  else
26
- @ctx.message("script.push.error.operation_failed_no_api_key")
35
+ raise ShopifyCLI::Abort, @ctx.message("script.push.error.operation_failed_no_uuid")
36
+ end
37
+ end
38
+
39
+ def load_project
40
+ Script::Loaders::Project.load(
41
+ directory: Dir.pwd,
42
+ api_key: options.flags[:api_key],
43
+ api_secret: options.flags[:api_secret],
44
+ uuid: options.flags[:uuid]
45
+ )
46
+ end
47
+
48
+ def connect_to_app
49
+ if ShopifyCLI::Environment.interactive?
50
+ Layers::Application::ConnectApp.call(ctx: @ctx)
27
51
  end
28
- UI::ErrorHandler.pretty_print_and_raise(e, failed_op: msg)
29
52
  end
30
53
 
31
54
  def self.help
@@ -18,11 +18,19 @@ shipping_methods:
18
18
  beta: true
19
19
  package: "@shopify/scripts-checkout-apis"
20
20
  repo: "https://github.com/Shopify/scripts-apis-examples"
21
- discount_types:
21
+ merchandise_discount_types:
22
22
  beta: true
23
23
  domain: 'discounts'
24
24
  libraries:
25
25
  typescript:
26
26
  beta: true
27
- package: "@shopify/scripts-discount-apis"
27
+ package: "@shopify/scripts-discounts-apis"
28
+ repo: "https://github.com/Shopify/scripts-apis-examples"
29
+ delivery_discount_types:
30
+ beta: true
31
+ domain: 'discounts'
32
+ libraries:
33
+ typescript:
34
+ beta: true
35
+ package: "@shopify/scripts-discounts-apis"
28
36
  repo: "https://github.com/Shopify/scripts-apis-examples"
@@ -6,7 +6,7 @@ mutation AppScriptSet(
6
6
  $force: Boolean,
7
7
  $schemaMajorVersion: String,
8
8
  $schemaMinorVersion: String,
9
- $scriptJsonVersion: String!,
9
+ $scriptConfigVersion: String!,
10
10
  $configurationUi: Boolean!,
11
11
  $configurationDefinition: String!,
12
12
  $moduleUploadUrl: String!,
@@ -20,7 +20,7 @@ mutation AppScriptSet(
20
20
  force: $force
21
21
  schemaMajorVersion: $schemaMajorVersion
22
22
  schemaMinorVersion: $schemaMinorVersion,
23
- scriptJsonVersion: $scriptJsonVersion,
23
+ scriptConfigVersion: $scriptConfigVersion,
24
24
  configurationUi: $configurationUi,
25
25
  configurationDefinition: $configurationDefinition,
26
26
  moduleUploadUrl: $moduleUploadUrl,
@@ -7,10 +7,11 @@ module Script
7
7
  module Application
8
8
  class ConnectApp
9
9
  class << self
10
- def call(ctx:)
10
+ def call(ctx:, force: false)
11
11
  script_project_repo = Layers::Infrastructure::ScriptProjectRepository.new(ctx: ctx)
12
12
  script_project = script_project_repo.get
13
- return false if script_project.env_valid?
13
+
14
+ return false if script_project.env_valid? && !force
14
15
 
15
16
  if ShopifyCLI::Shopifolk.check && Forms::RunAgainstShopifyOrg.ask(ctx, nil, nil).response
16
17
  ShopifyCLI::Shopifolk.act_as_shopify_organization
@@ -37,15 +38,26 @@ module Script
37
38
  extension_point_type = script_project.extension_point_type
38
39
  scripts = script_service.get_app_scripts(extension_point_type: extension_point_type)
39
40
 
40
- uuid = Forms::AskScriptUuid.ask(ctx, scripts, nil).uuid
41
+ uuid = Forms::AskScriptUuid.ask(ctx, scripts, nil)&.uuid
41
42
 
42
43
  script_project_repo.create_env(
43
44
  api_key: app["apiKey"],
44
45
  secret: app["apiSecretKeys"].first["secret"],
45
46
  uuid: uuid
46
47
  )
48
+ ctx.done(ctx.message("script.connect.connected", app["title"]))
47
49
 
48
50
  true
51
+ rescue SmartProperties::InitializationError, SmartProperties::InvalidValueError => error
52
+ handle_error(error, context: ctx)
53
+ end
54
+
55
+ def handle_error(error, context:)
56
+ properties_hash = { api_key: "SHOPIFY_API_KEY", secret: "SHOPIFY_API_SECRET" }
57
+ missing_env_variables = error.properties.map { |p| properties_hash[p.name] }.compact.join(", ")
58
+ raise ShopifyCLI::Abort,
59
+ context.message("script.connect.error.missing_env_file_variables", missing_env_variables,
60
+ ShopifyCLI::TOOL_NAME)
49
61
  end
50
62
 
51
63
  private
@@ -8,11 +8,14 @@ module Script
8
8
  class CreateScript
9
9
  class << self
10
10
  def call(ctx:, language:, sparse_checkout_branch:, script_name:, extension_point_type:)
11
- raise Infrastructure::Errors::ScriptProjectAlreadyExistsError, script_name if ctx.dir_exist?(script_name)
11
+ script_project_repo = Infrastructure::ScriptProjectRepository.new(
12
+ ctx: ctx,
13
+ directory: script_name,
14
+ initial_directory: ctx.root
15
+ )
12
16
 
13
- in_new_directory_context(ctx, script_name) do
17
+ in_new_directory_context(script_project_repo) do
14
18
  extension_point = ExtensionPoints.get(type: extension_point_type)
15
- script_project_repo = Infrastructure::ScriptProjectRepository.new(ctx: ctx)
16
19
  project = script_project_repo.create(
17
20
  script_name: script_name,
18
21
  extension_point_type: extension_point_type,
@@ -36,7 +39,7 @@ module Script
36
39
  )
37
40
 
38
41
  install_dependencies(ctx, language, script_name, project_creator)
39
- script_project_repo.update_or_create_script_json(title: script_name)
42
+ script_project_repo.update_script_config(title: script_name)
40
43
  project
41
44
  end
42
45
  end
@@ -62,19 +65,16 @@ module Script
62
65
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
63
66
  end
64
67
 
65
- def in_new_directory_context(ctx, directory)
66
- initial_directory = ctx.root
67
- begin
68
- ctx.mkdir_p(directory)
69
- ctx.chdir(directory)
70
- yield
71
- rescue
72
- ctx.chdir(initial_directory)
73
- ctx.rm_r(directory)
74
- raise
75
- ensure
76
- ctx.chdir(initial_directory)
77
- end
68
+ def in_new_directory_context(script_project_repo)
69
+ script_project_repo.create_project_directory
70
+ yield
71
+ rescue Infrastructure::Errors::ScriptProjectAlreadyExistsError
72
+ raise
73
+ rescue
74
+ script_project_repo.delete_project_directory
75
+ raise
76
+ ensure
77
+ script_project_repo.change_to_initial_directory
78
78
  end
79
79
  end
80
80
  end
@@ -4,37 +4,61 @@ module Script
4
4
  module Layers
5
5
  module Application
6
6
  class ExtensionPoints
7
- def self.get(type:)
8
- Infrastructure::ExtensionPointRepository.new.get_extension_point(type)
9
- end
7
+ class << self
8
+ def get(type:)
9
+ extension_point_repository.get_extension_point(type)
10
+ end
10
11
 
11
- def self.types
12
- Infrastructure::ExtensionPointRepository.new.extension_point_types
13
- end
12
+ def types
13
+ extension_point_repository.extension_point_types
14
+ end
14
15
 
15
- def self.available_types
16
- Infrastructure::ExtensionPointRepository.new.extension_points.select do |ep|
17
- next false if ep.deprecated?
18
- !ep.beta? || ShopifyCLI::Feature.enabled?(:scripts_beta_extension_points)
19
- end.map(&:type)
20
- end
16
+ def available_types
17
+ available_extension_points.map(&:type)
18
+ end
21
19
 
22
- def self.deprecated_types
23
- Infrastructure::ExtensionPointRepository.new
24
- .extension_points
25
- .select(&:deprecated?)
26
- .map(&:type)
27
- end
20
+ def deprecated_types
21
+ extension_point_repository
22
+ .extension_points
23
+ .select(&:deprecated?)
24
+ .map(&:type)
25
+ end
28
26
 
29
- def self.languages(type:)
30
- get(type: type).libraries.all.map do |library|
31
- next nil if library.beta? && !ShopifyCLI::Feature.enabled?(:scripts_beta_languages)
32
- library.language
33
- end.compact
34
- end
27
+ def all_languages
28
+ available_extension_points
29
+ .map { |ep| ep.library_languages(include_betas: include_beta_languages?) }
30
+ .flatten
31
+ .uniq
32
+ end
33
+
34
+ def languages(type:)
35
+ get(type: type).library_languages(include_betas: include_beta_languages?)
36
+ end
37
+
38
+ def supported_language?(type:, language:)
39
+ languages(type: type).include?(language.downcase)
40
+ end
41
+
42
+ private
43
+
44
+ def available_extension_points
45
+ extension_point_repository.extension_points.select do |ep|
46
+ next false if ep.deprecated?
47
+ ep.stable? || include_beta_extension_points?
48
+ end
49
+ end
50
+
51
+ def extension_point_repository
52
+ Infrastructure::ExtensionPointRepository.new
53
+ end
54
+
55
+ def include_beta_languages?
56
+ ShopifyCLI::Feature.enabled?(:scripts_beta_languages)
57
+ end
35
58
 
36
- def self.supported_language?(type:, language:)
37
- languages(type: type).include?(language.downcase)
59
+ def include_beta_extension_points?
60
+ ShopifyCLI::Feature.enabled?(:scripts_beta_extension_points)
61
+ end
38
62
  end
39
63
  end
40
64
  end