shopify-cli 1.9.1 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/.github/workflows/build.yml +28 -0
  4. data/.github/workflows/release.yml +2 -4
  5. data/CHANGELOG.md +28 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +2 -1
  8. data/lib/project_types/extension/cli.rb +6 -2
  9. data/lib/project_types/extension/commands/serve.rb +69 -1
  10. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  11. data/lib/project_types/extension/extension_project.rb +1 -0
  12. data/lib/project_types/extension/features/argo.rb +15 -24
  13. data/lib/project_types/extension/features/argo_runtime.rb +91 -0
  14. data/lib/project_types/extension/features/argo_serve.rb +35 -27
  15. data/lib/project_types/extension/features/argo_serve_options.rb +42 -0
  16. data/lib/project_types/extension/messages/messages.rb +5 -1
  17. data/lib/project_types/extension/models/npm_package.rb +14 -0
  18. data/lib/project_types/extension/models/specification.rb +1 -0
  19. data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
  20. data/lib/project_types/extension/models/specification_handlers/default.rb +33 -3
  21. data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
  22. data/lib/project_types/extension/tasks/configure_features.rb +2 -0
  23. data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
  24. data/lib/project_types/script/cli.rb +17 -12
  25. data/lib/project_types/script/commands/push.rb +6 -2
  26. data/lib/project_types/script/config/extension_points.yml +2 -3
  27. data/lib/project_types/script/graphql/get_app_scripts.graphql +6 -0
  28. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  29. data/lib/project_types/script/layers/application/push_script.rb +2 -1
  30. data/lib/project_types/script/layers/domain/errors.rb +0 -2
  31. data/lib/project_types/script/layers/domain/script_project.rb +17 -1
  32. data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
  33. data/lib/project_types/script/layers/infrastructure/errors.rb +12 -3
  34. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_project_creator.rb +97 -0
  35. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +103 -0
  36. data/lib/project_types/script/layers/infrastructure/languages/project_creator.rb +26 -0
  37. data/lib/project_types/script/layers/infrastructure/languages/rust_project_creator.rb +73 -0
  38. data/lib/project_types/script/layers/infrastructure/languages/rust_task_runner.rb +60 -0
  39. data/lib/project_types/script/layers/infrastructure/languages/task_runner.rb +21 -0
  40. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -5
  41. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +22 -29
  42. data/lib/project_types/script/layers/infrastructure/script_service.rb +7 -1
  43. data/lib/project_types/script/messages/messages.rb +14 -4
  44. data/lib/project_types/script/tasks/ensure_env.rb +104 -0
  45. data/lib/project_types/script/ui/error_handler.rb +7 -6
  46. data/lib/shopify-cli/admin_api.rb +7 -4
  47. data/lib/shopify-cli/messages/messages.rb +48 -43
  48. data/lib/shopify-cli/method_object.rb +4 -4
  49. data/lib/shopify-cli/oauth.rb +7 -1
  50. data/lib/shopify-cli/partners_api.rb +7 -4
  51. data/lib/shopify-cli/partners_api/organizations.rb +3 -3
  52. data/lib/shopify-cli/resources/env_file.rb +1 -1
  53. data/lib/shopify-cli/shopifolk.rb +1 -1
  54. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
  55. data/lib/shopify-cli/tunnel.rb +22 -1
  56. data/lib/shopify-cli/version.rb +1 -1
  57. data/lib/shopify_cli.rb +0 -1
  58. metadata +19 -11
  59. data/.travis.yml +0 -14
  60. data/lib/project_types/extension/features/argo_renderer_package.rb +0 -47
  61. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +0 -100
  62. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +0 -95
  63. data/lib/project_types/script/layers/infrastructure/project_creator.rb +0 -24
  64. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +0 -72
  65. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +0 -59
  66. data/lib/project_types/script/layers/infrastructure/task_runner.rb +0 -19
@@ -0,0 +1,42 @@
1
+ module Extension
2
+ module Features
3
+ class ArgoServeOptions
4
+ include SmartProperties
5
+
6
+ property! :argo_runtime, accepts: Features::ArgoRuntime
7
+ property! :context, accepts: ShopifyCli::Context
8
+ property :port, accepts: Integer, default: 39351
9
+ property :public_url, accepts: String, default: ""
10
+ property! :required_fields, accepts: Array, default: -> { [] }
11
+ property! :renderer_package, accepts: Models::NpmPackage
12
+
13
+ YARN_SERVE_COMMAND = %w(server)
14
+ NPM_SERVE_COMMAND = %w(run-script server)
15
+
16
+ def yarn_serve_command
17
+ YARN_SERVE_COMMAND + options
18
+ end
19
+
20
+ def npm_serve_command
21
+ NPM_SERVE_COMMAND + ["--"] + options
22
+ end
23
+
24
+ private
25
+
26
+ def options
27
+ project = ExtensionProject.current
28
+ api_key = project.env.api_key
29
+
30
+ @serve_options ||= [].tap do |options|
31
+ options << "--port=#{port}" if argo_runtime.accepts_port?
32
+ options << "--shop=#{project.env.shop}" if required_fields.include?(:shop) && argo_runtime.accepts_shop?
33
+ options << "--apiKey=#{api_key}" if required_fields.include?(:api_key) && argo_runtime.accepts_api_key?
34
+ options << "--argoVersion=#{renderer_package.version}" if argo_runtime.accepts_argo_version?
35
+ options << "--uuid=#{project.registration_uuid}" if argo_runtime.accepts_uuid?
36
+ options << "--publicUrl=#{public_url}" if argo_runtime.accepts_tunnel_url?
37
+ options << "--name=#{project.title}" if argo_runtime.accepts_name?
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -56,8 +56,10 @@ module Extension
56
56
  },
57
57
  serve: {
58
58
  frame_title: "Serving extension...",
59
+ no_available_ports_found: "No available ports found to run extension.",
59
60
  serve_failure_message: "Failed to run extension code.",
60
61
  serve_missing_information: "Missing shop or api_key.",
62
+ tunnel_already_running: "A tunnel running on another port has been detected. Close the tunnel and try again.",
61
63
  },
62
64
  tunnel: {
63
65
  missing_token: "{{x}} {{red:auth requires a token argument}}. "\
@@ -98,7 +100,8 @@ module Extension
98
100
  node_not_installed: "Node must be installed to create this extension.",
99
101
  version_too_low: "Your node version %s does not meet the minimum required version %s",
100
102
  },
101
- argo_missing_renderer_package_error: "Extension template references invalid renderer package please contact Shopify for help.",
103
+ argo_missing_renderer_package_error: "Extension template references invalid renderer package "\
104
+ "please contact Shopify for help.",
102
105
  yarn_install_error: "Something went wrong while running 'yarn install'. %s.",
103
106
  yarn_run_script_error: "Something went wrong while running script. %s.",
104
107
  },
@@ -114,6 +117,7 @@ module Extension
114
117
  },
115
118
  errors: {
116
119
  unknown_type: "Unknown extension type %s",
120
+ package_not_found: "`%s` package not found.",
117
121
  },
118
122
  }
119
123
 
@@ -0,0 +1,14 @@
1
+ require "semantic/semantic"
2
+
3
+ module Extension
4
+ module Models
5
+ NpmPackage = Struct.new(:name, :version, keyword_init: true) do
6
+ include Comparable
7
+
8
+ def <=>(other)
9
+ return nil unless name == other.name
10
+ Semantic::Version.new(version) <=> Semantic::Version.new(other.version)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -12,6 +12,7 @@ module Extension
12
12
  property! :git_template, converts: :to_str
13
13
  property! :required_fields, accepts: Array, default: -> { [] }
14
14
  property! :required_shop_beta_flags, accepts: Array, default: -> { [] }
15
+ property! :cli_package_name, accepts: String, converts: :to_str, default: ""
15
16
  end
16
17
 
17
18
  def self.build(feature_set_attributes)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Extension
4
+ module Models
5
+ module SpecificationHandlers
6
+ class CheckoutArgoExtension < Default
7
+ PERMITTED_CONFIG_KEYS = [:metafields, :extension_points]
8
+
9
+ def config(context)
10
+ {
11
+ **Features::ArgoConfig.parse_yaml(context, PERMITTED_CONFIG_KEYS),
12
+ **argo.config(context),
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -42,20 +42,50 @@ module Extension
42
42
  []
43
43
  end
44
44
 
45
- def serve(context)
46
- Features::ArgoServe.new(specification_handler: self, context: context).call
45
+ def choose_port?(context)
46
+ argo_runtime(context).accepts_port?
47
+ end
48
+
49
+ def establish_tunnel?(context)
50
+ argo_runtime(context).accepts_tunnel_url?
51
+ end
52
+
53
+ def serve(context:, port:, tunnel_url:)
54
+ Features::ArgoServe.new(
55
+ specification_handler: self,
56
+ argo_runtime: argo_runtime(context),
57
+ context: context,
58
+ port: port,
59
+ tunnel_url: tunnel_url,
60
+ ).call
47
61
  end
48
62
 
49
63
  def renderer_package(context)
50
64
  argo.renderer_package(context)
51
65
  end
52
66
 
67
+ def argo_runtime(context)
68
+ @argo_runtime ||= Features::ArgoRuntime.new(
69
+ renderer: renderer_package(context),
70
+ cli: cli_package(context),
71
+ )
72
+ end
73
+
74
+ def cli_package(context)
75
+ cli_package_name = specification.features.argo&.cli_package_name
76
+ return unless cli_package_name
77
+
78
+ js_system = ShopifyCli::JsSystem.new(ctx: context)
79
+ Tasks::FindNpmPackages.exactly_one_of(cli_package_name, js_system: js_system)
80
+ .unwrap { |_e| context.abort(context.message("errors.package_not_found", cli_package_name)) }
81
+ end
82
+
53
83
  protected
54
84
 
55
85
  def argo
56
86
  Features::Argo.new(
57
87
  git_template: specification.features.argo.git_template,
58
- renderer_package_name: specification.features.argo.renderer_package_name,
88
+ renderer_package_name: specification.features.argo.renderer_package_name
59
89
  )
60
90
  end
61
91
 
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+ require "socket"
4
+
5
+ module Extension
6
+ module Tasks
7
+ class ChooseNextAvailablePort
8
+ include ShopifyCli::MethodObject
9
+
10
+ property! :from
11
+ property! :to, default: -> { from + 10 }
12
+ property! :host, default: "localhost"
13
+
14
+ def call
15
+ available_port = port_range(from: from, to: to).find { |p| available?(host, p) }
16
+ raise ArgumentError, "Ports between #{from} and #{to} are unavailable" if available_port.nil?
17
+ available_port
18
+ end
19
+
20
+ private
21
+
22
+ def port_range(from:, to:)
23
+ (from..to)
24
+ end
25
+
26
+ def available?(host, port)
27
+ Socket.tcp(host, port, connect_timeout: 1) do |socket|
28
+ socket.close
29
+ false
30
+ end
31
+ rescue Errno::ECONNREFUSED
32
+ true
33
+ end
34
+ end
35
+ end
36
+ end
@@ -42,10 +42,12 @@ module Extension
42
42
  renderer_package_name: "@shopify/argo-admin",
43
43
  required_fields: [:shop, :api_key],
44
44
  required_shop_beta_flags: [:argo_admin_beta],
45
+ cli_package_name: "@shopify/argo-admin-cli",
45
46
  },
46
47
  checkout: {
47
48
  git_template: "https://github.com/Shopify/argo-checkout-template.git",
48
49
  renderer_package_name: "@shopify/argo-checkout",
50
+ cli_package_name: "@shopify/argo-run",
49
51
  },
50
52
  }
51
53
  end
@@ -0,0 +1,106 @@
1
+ module Extension
2
+ module Tasks
3
+ class FindNpmPackages
4
+ include ShopifyCli::MethodObject
5
+
6
+ property! :js_system, accepts: ShopifyCli::JsSystem
7
+ property! :production_only, accepts: [true, false], default: false, reader: :production_only?
8
+
9
+ def self.at_least_one_of(*package_names, **config)
10
+ new(**config).at_least_one_of(*package_names)
11
+ end
12
+
13
+ def self.all(*package_names, **config)
14
+ new(**config).all(*package_names)
15
+ end
16
+
17
+ def self.exactly_one_of(*package_names, **config)
18
+ new(**config).exactly_one_of(*package_names)
19
+ end
20
+
21
+ def all(*package_names)
22
+ call(*package_names) do |found_packages|
23
+ found_package_names = found_packages.map(&:name)
24
+ next found_packages if Set.new(found_package_names) == Set.new(package_names)
25
+ raise PackageResolutionFailed, format(
26
+ "Missing packages: %s",
27
+ (package_names - found_package_names).join(", ")
28
+ )
29
+ end
30
+ end
31
+
32
+ def at_least_one_of(*package_names)
33
+ call(*package_names) do |found_packages|
34
+ found_package_names = found_packages.map(&:name)
35
+ next found_packages unless (found_package_names & package_names).empty?
36
+ raise PackageResolutionFailed, format(
37
+ "Expected at least one of the following packages: %s",
38
+ package_names.join(", ")
39
+ )
40
+ end
41
+ end
42
+
43
+ def exactly_one_of(*package_names)
44
+ call(*package_names) do |found_packages|
45
+ case found_packages.count
46
+ when 0
47
+ raise PackageResolutionFailed, format(
48
+ "Expected one of the following packages: %s",
49
+ package_names.join(", ")
50
+ )
51
+ when 1
52
+ found_packages.first.tap do |found_package|
53
+ next found_package if package_names.include?(found_package.name)
54
+ raise PackageResolutionFailed, format(
55
+ "Expected the following package: %s",
56
+ found_package.name
57
+ )
58
+ end
59
+ else
60
+ raise PackageResolutionFailed, "Found more than one package"
61
+ end
62
+ end
63
+ end
64
+
65
+ def call(*package_names, &validate)
66
+ validate ||= ->(found_packages) { found_packages }
67
+
68
+ unless package_names.all? { |name| name.is_a?(String) }
69
+ raise ArgumentError, "Expected a list of package names"
70
+ end
71
+
72
+ ShopifyCli::Result
73
+ .call(&method(:list_packages))
74
+ .then(&method(:search_packages).curry[package_names])
75
+ .then(&method(:filter_duplicates))
76
+ .then(&validate)
77
+ end
78
+
79
+ def list_packages
80
+ result, error, status =
81
+ js_system.call(yarn: yarn_list, npm: npm_list, capture_response: true)
82
+ raise error unless status.success?
83
+ result
84
+ end
85
+
86
+ def yarn_list
87
+ production_only? ? %w[list --production] : %w[list]
88
+ end
89
+
90
+ def npm_list
91
+ production_only? ? %w[list --prod --depth=1] : %w[list --depth=1]
92
+ end
93
+
94
+ def search_packages(packages, package_list)
95
+ pattern = /(#{packages.join("|")})@(\d.*)$/
96
+ package_list.scan(pattern).map do |(name, version)|
97
+ Models::NpmPackage.new(name: name, version: version.strip)
98
+ end
99
+ end
100
+
101
+ def filter_duplicates(packages)
102
+ packages.reject { |p| p.version.match(/deduped/) }.uniq
103
+ end
104
+ end
105
+ end
106
+ end
@@ -24,6 +24,10 @@ module Script
24
24
  autoload :ScriptForm, Project.project_filepath("forms/script_form")
25
25
  end
26
26
 
27
+ module Tasks
28
+ autoload :EnsureEnv, Project.project_filepath("tasks/ensure_env")
29
+ end
30
+
27
31
  module Layers
28
32
  module Application
29
33
  autoload :BuildScript, Project.project_filepath("layers/application/build_script")
@@ -44,22 +48,23 @@ module Script
44
48
 
45
49
  module Infrastructure
46
50
  autoload :Errors, Project.project_filepath("layers/infrastructure/errors")
47
- autoload :AssemblyScriptDependencyManager,
48
- Project.project_filepath("layers/infrastructure/assemblyscript_dependency_manager")
49
- autoload :AssemblyScriptProjectCreator,
50
- Project.project_filepath("layers/infrastructure/assemblyscript_project_creator")
51
- autoload :AssemblyScriptTaskRunner, Project.project_filepath("layers/infrastructure/assemblyscript_task_runner")
52
- autoload :AssemblyScriptTsConfig, Project.project_filepath("layers/infrastructure/assemblyscript_tsconfig")
53
- autoload :RustProjectCreator,
54
- Project.project_filepath("layers/infrastructure/rust_project_creator.rb")
55
- autoload :RustTaskRunner, Project.project_filepath("layers/infrastructure/rust_task_runner")
56
-
51
+ autoload :CommandRunner, Project.project_filepath("layers/infrastructure/command_runner")
57
52
  autoload :PushPackageRepository, Project.project_filepath("layers/infrastructure/push_package_repository")
58
53
  autoload :ExtensionPointRepository, Project.project_filepath("layers/infrastructure/extension_point_repository")
59
- autoload :ProjectCreator, Project.project_filepath("layers/infrastructure/project_creator")
60
54
  autoload :ScriptProjectRepository, Project.project_filepath("layers/infrastructure/script_project_repository")
61
55
  autoload :ScriptService, Project.project_filepath("layers/infrastructure/script_service")
62
- autoload :TaskRunner, Project.project_filepath("layers/infrastructure/task_runner")
56
+
57
+ module Languages
58
+ autoload :AssemblyScriptProjectCreator,
59
+ Project.project_filepath("layers/infrastructure/languages/assemblyscript_project_creator")
60
+ autoload :AssemblyScriptTaskRunner,
61
+ Project.project_filepath("layers/infrastructure/languages/assemblyscript_task_runner")
62
+ autoload :ProjectCreator, Project.project_filepath("layers/infrastructure/languages/project_creator")
63
+ autoload :RustProjectCreator,
64
+ Project.project_filepath("layers/infrastructure/languages/rust_project_creator.rb")
65
+ autoload :RustTaskRunner, Project.project_filepath("layers/infrastructure/languages/rust_task_runner")
66
+ autoload :TaskRunner, Project.project_filepath("layers/infrastructure/languages/task_runner")
67
+ end
63
68
  end
64
69
  end
65
70
 
@@ -8,7 +8,7 @@ module Script
8
8
  end
9
9
 
10
10
  def call(_args, _name)
11
- ShopifyCli::Tasks::EnsureEnv.call(@ctx, required: [:api_key, :secret, :shop])
11
+ Tasks::EnsureEnv.call(@ctx)
12
12
 
13
13
  api_key = Layers::Infrastructure::ScriptProjectRepository.new(ctx: @ctx).get.api_key
14
14
  return @ctx.puts(self.class.help) unless api_key
@@ -16,7 +16,11 @@ module Script
16
16
  Layers::Application::PushScript.call(ctx: @ctx, force: options.flags.key?(:force))
17
17
  @ctx.puts(@ctx.message("script.push.script_pushed", api_key: api_key))
18
18
  rescue StandardError => e
19
- msg = @ctx.message("script.push.error.operation_failed", api_key: api_key)
19
+ msg = if api_key
20
+ @ctx.message("script.push.error.operation_failed_with_api_key", api_key: api_key)
21
+ else
22
+ @ctx.message("script.push.error.operation_failed_no_api_key")
23
+ end
20
24
  UI::ErrorHandler.pretty_print_and_raise(e, failed_op: msg)
21
25
  end
22
26
 
@@ -11,6 +11,7 @@ unit_limit_per_order:
11
11
  sdk-version: "^9.0.0"
12
12
  toolchain-version: "^5.0.0"
13
13
  payment_filter:
14
+ deprecated: true
14
15
  assemblyscript:
15
16
  package: "@shopify/extension-point-as-payment-filter"
16
17
  sdk-version: "^9.0.0"
@@ -19,6 +20,7 @@ payment_filter:
19
20
  beta: true
20
21
  package: "https://github.com/Shopify/scripts-apis-rs"
21
22
  shipping_filter:
23
+ deprecated: true
22
24
  assemblyscript:
23
25
  package: "@shopify/extension-point-as-shipping-filter"
24
26
  sdk-version: "^9.0.0"
@@ -34,11 +36,8 @@ payment_methods:
34
36
  assemblyscript:
35
37
  package: "@shopify/scripts-checkout-apis"
36
38
  toolchain-version: "^5.0.0"
37
- sdk-version: "^9.0.0"
38
39
  shipping_methods:
39
40
  domain: 'checkout'
40
41
  assemblyscript:
41
42
  package: "@shopify/scripts-checkout-apis"
42
- sdk-version: "^9.0.0"
43
43
  toolchain-version: "^5.0.0"
44
-
@@ -0,0 +1,6 @@
1
+ query GetAppScripts($appKey: String!, $extensionPointName: ExtensionPointName!) {
2
+ appScripts(appKeys: [$appKey], extensionPointName: $extensionPointName) {
3
+ uuid
4
+ title
5
+ }
6
+ }
@@ -18,7 +18,7 @@ module Script
18
18
  language: language,
19
19
  no_config_ui: no_config_ui
20
20
  )
21
- project_creator = Infrastructure::ProjectCreator
21
+ project_creator = Infrastructure::Languages::ProjectCreator
22
22
  .for(ctx, language, extension_point, script_name, project.id)
23
23
  install_dependencies(ctx, language, script_name, project_creator)
24
24
  bootstrap(ctx, project_creator)
@@ -29,7 +29,7 @@ module Script
29
29
  private
30
30
 
31
31
  def install_dependencies(ctx, language, script_name, project_creator)
32
- task_runner = Infrastructure::TaskRunner.for(ctx, language, script_name)
32
+ task_runner = Infrastructure::Languages::TaskRunner.for(ctx, language, script_name)
33
33
  project_creator.setup_dependencies
34
34
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
35
35
  end