shopify-cli 1.10.0 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/PULL_REQUEST_TEMPLATE.md +1 -0
  3. data/CHANGELOG.md +9 -1
  4. data/Gemfile.lock +1 -1
  5. data/lib/project_types/extension/cli.rb +6 -2
  6. data/lib/project_types/extension/commands/serve.rb +69 -1
  7. data/lib/project_types/extension/commands/tunnel.rb +3 -1
  8. data/lib/project_types/extension/extension_project.rb +1 -0
  9. data/lib/project_types/extension/features/argo.rb +15 -24
  10. data/lib/project_types/extension/features/argo_runtime.rb +63 -0
  11. data/lib/project_types/extension/features/argo_serve.rb +35 -25
  12. data/lib/project_types/extension/features/argo_serve_options.rb +40 -0
  13. data/lib/project_types/extension/messages/messages.rb +3 -0
  14. data/lib/project_types/extension/models/npm_package.rb +14 -0
  15. data/lib/project_types/extension/models/specification.rb +1 -0
  16. data/lib/project_types/extension/models/specification_handlers/checkout_argo_extension.rb +18 -0
  17. data/lib/project_types/extension/models/specification_handlers/default.rb +28 -3
  18. data/lib/project_types/extension/tasks/choose_next_available_port.rb +36 -0
  19. data/lib/project_types/extension/tasks/configure_features.rb +2 -0
  20. data/lib/project_types/extension/tasks/find_npm_packages.rb +106 -0
  21. data/lib/project_types/script/cli.rb +1 -0
  22. data/lib/project_types/script/layers/domain/errors.rb +0 -2
  23. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +12 -17
  24. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +13 -7
  25. data/lib/project_types/script/layers/infrastructure/command_runner.rb +19 -0
  26. data/lib/project_types/script/layers/infrastructure/errors.rb +12 -3
  27. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +4 -4
  28. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +9 -10
  29. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +5 -6
  30. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +2 -28
  31. data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
  32. data/lib/project_types/script/messages/messages.rb +6 -4
  33. data/lib/project_types/script/tasks/ensure_env.rb +10 -2
  34. data/lib/project_types/script/ui/error_handler.rb +7 -6
  35. data/lib/shopify-cli/messages/messages.rb +47 -43
  36. data/lib/shopify-cli/method_object.rb +4 -4
  37. data/lib/shopify-cli/oauth.rb +7 -1
  38. data/lib/shopify-cli/partners_api/organizations.rb +3 -3
  39. data/lib/shopify-cli/tasks/select_org_and_shop.rb +6 -4
  40. data/lib/shopify-cli/tunnel.rb +22 -1
  41. data/lib/shopify-cli/version.rb +1 -1
  42. metadata +10 -4
  43. data/lib/project_types/extension/features/argo_renderer_package.rb +0 -47
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea41fa5cbfa0eb2bf575fe82111c6be56df6807ed7696e64acc741ef2fa2e6be
4
- data.tar.gz: 899299251ed4b0a50b0c3a5c5ae55324ebd64e92fbb981da7d4a093df94d5596
3
+ metadata.gz: e1ca8221a25313b8cd908a02e4c5c68dc9f74ed38e7472804346419e45d8d9d8
4
+ data.tar.gz: b0658aae7cb7ca368b78aa80f3fab364867bc1d6ae36515c07f3692bb87730cb
5
5
  SHA512:
6
- metadata.gz: 8b757bbf4ef686593f3fe8fdf82da6c83468f40d04bc312476e2bea614d5f75e3d63afe097c149f3de34b35631032c096799f0728b12732dfbbb5bd3e5141384
7
- data.tar.gz: 2059062ef9aff95cad44d2b4bcad442e2cf82636d6733c065bb83544ac4d0b8cef2a5de3c438d5f252a251fa0cf813b03fc064db407940e3469b476a26c35e0d
6
+ metadata.gz: 54fde8fed1098f483c817cfb0dd8d9ab291556da026dabcc7d0e0dc934fb9c2e97dd2865d72257ca75a2c5d1560759e4ece27c8acc76a8a56f299e8f004594f0
7
+ data.tar.gz: b193f5f389c2a03875e98d4636aa3cd16c7bfe212d798defed234233b0aad410382e3f56d83b58f63189b6f8256be762518c4439bfe732961c682db8fd81cb25
@@ -29,3 +29,4 @@ Fixes #0000 <!-- link to issue if one exists -->
29
29
  -->
30
30
  - [ ] I've added a CHANGELOG entry for this PR (if the change is public-facing)
31
31
  - [ ] I've considered possible cross-platform impacts (Mac, Linux, Windows).
32
+ - [ ] I've left the version number as is (we'll handle incrmenting this when releasing).
data/CHANGELOG.md CHANGED
@@ -1,8 +1,16 @@
1
1
  Unreleased
2
2
  ------
3
3
 
4
+ Version 1.11.0
5
+ --------------
6
+ * [#1221](https://github.com/Shopify/shopify-app-cli/pull/1221): Prioritizes returning an HTTPS URL over HTTP from `shopify tunnel status`.
7
+ * [#1223](https://github.com/Shopify/shopify-app-cli/pull/1233): Running `shopify serve` in an extension project now automatically runs `shopify tunnel`.
8
+ * [#1225](https://github.com/Shopify/shopify-app-cli/pull/1225): Improved handling of "account not found" scenario, plus improvements to related tests and UX messaging
9
+ * [#1229](https://github.com/Shopify/shopify-app-cli/pull/1229): Allows Checkout Extensions to specify configuration attributes in their extension.config.yml file.
10
+ * [#1238](https://github.com/Shopify/shopify-app-cli/pull/1238): Auto Tunnel Support for Checkout Extension
11
+
4
12
  Version 1.10.0
5
- -------------
13
+ --------------
6
14
  * Updating internal features in development
7
15
 
8
16
  Version 1.9.1
data/Gemfile.lock CHANGED
@@ -76,4 +76,4 @@ DEPENDENCIES
76
76
  webmock
77
77
 
78
78
  BUNDLED WITH
79
- 1.17.3
79
+ 2.1.4
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Extension
4
- class PackageNotFound < RuntimeError; end
4
+ class PackageResolutionFailed < RuntimeError; end
5
5
 
6
6
  class Project < ShopifyCli::ProjectType
7
7
  hidden_feature
@@ -38,6 +38,8 @@ module Extension
38
38
  autoload :UpdateDraft, Project.project_filepath("tasks/update_draft")
39
39
  autoload :FetchSpecifications, Project.project_filepath("tasks/fetch_specifications")
40
40
  autoload :ConfigureFeatures, Project.project_filepath("tasks/configure_features")
41
+ autoload :ChooseNextAvailablePort, Project.project_filepath("tasks/choose_next_available_port")
42
+ autoload :FindNpmPackages, Project.project_filepath("tasks/find_npm_packages")
41
43
 
42
44
  module Converters
43
45
  autoload :RegistrationConverter, Project.project_filepath("tasks/converters/registration_converter")
@@ -59,13 +61,14 @@ module Extension
59
61
  end
60
62
 
61
63
  module Features
62
- autoload :ArgoRendererPackage, Project.project_filepath("features/argo_renderer_package")
63
64
  autoload :ArgoServe, Project.project_filepath("features/argo_serve")
65
+ autoload :ArgoServeOptions, Project.project_filepath("features/argo_serve_options")
64
66
  autoload :ArgoSetup, Project.project_filepath("features/argo_setup")
65
67
  autoload :ArgoSetupStep, Project.project_filepath("features/argo_setup_step")
66
68
  autoload :ArgoSetupSteps, Project.project_filepath("features/argo_setup_steps")
67
69
  autoload :ArgoDependencies, Project.project_filepath("features/argo_dependencies")
68
70
  autoload :ArgoConfig, Project.project_filepath("features/argo_config")
71
+ autoload :ArgoRuntime, Project.project_filepath("features/argo_runtime")
69
72
  autoload :Argo, Project.project_filepath("features/argo")
70
73
  end
71
74
 
@@ -81,6 +84,7 @@ module Extension
81
84
  autoload :Specification, Project.project_filepath("models/specification")
82
85
  autoload :Specifications, Project.project_filepath("models/specifications")
83
86
  autoload :LazySpecificationHandler, Project.project_filepath("models/lazy_specification_handler")
87
+ autoload :NpmPackage, Project.project_filepath("models/npm_package")
84
88
  end
85
89
 
86
90
  autoload :ExtensionProjectKeys, Project.project_filepath("extension_project_keys")
@@ -3,16 +3,84 @@
3
3
  module Extension
4
4
  module Commands
5
5
  class Serve < ExtensionCommand
6
+ DEFAULT_PORT = 39351
7
+
8
+ options do |parser, flags|
9
+ parser.on("-t", "--[no-]tunnel", "Establish an ngrok tunnel") { |tunnel| flags[:tunnel] = tunnel }
10
+ end
11
+
12
+ class RuntimeConfiguration
13
+ include SmartProperties
14
+
15
+ property! :tunnel_url, accepts: String, default: ""
16
+ property! :tunnel_requested, accepts: [true, false], reader: :tunnel_requested?, default: true
17
+ property! :port, accepts: (1...(2**16)), default: DEFAULT_PORT
18
+ end
19
+
6
20
  def call(_args, _command_name)
7
- specification_handler.serve(@ctx)
21
+ config = RuntimeConfiguration.new(
22
+ tunnel_requested: tunnel_requested?
23
+ )
24
+
25
+ ShopifyCli::Result
26
+ .success(config)
27
+ .then(&method(:find_available_port))
28
+ .then(&method(:start_tunnel_if_required))
29
+ .then(&method(:serve))
30
+ .unwrap { |error| raise error }
8
31
  end
9
32
 
10
33
  def self.help
11
34
  <<~HELP
12
35
  Serve your extension in a local simulator for development.
13
36
  Usage: {{command:#{ShopifyCli::TOOL_NAME} serve}}
37
+ Options:
38
+ {{command:--tunnel=TUNNEL}} Establish an ngrok tunnel (default: false)
14
39
  HELP
15
40
  end
41
+
42
+ private
43
+
44
+ def tunnel_requested?
45
+ tunnel = options.flags[:tunnel]
46
+ tunnel.nil? || !!tunnel
47
+ end
48
+
49
+ def find_available_port(runtime_configuration)
50
+ return runtime_configuration unless specification_handler.choose_port?(@ctx)
51
+
52
+ chosen_port = Tasks::ChooseNextAvailablePort
53
+ .call(from: runtime_configuration.port)
54
+ .unwrap { |_error| @ctx.abort(@ctx.message("serve.no_available_ports_found")) }
55
+ runtime_configuration.tap { |c| c.port = chosen_port }
56
+ end
57
+
58
+ def start_tunnel_if_required(runtime_configuration)
59
+ return runtime_configuration unless specification_handler.establish_tunnel?(@ctx)
60
+ return runtime_configuration unless runtime_configuration.tunnel_requested?
61
+
62
+ return start_tunnel(runtime_configuration) if can_start_tunnel?(runtime_configuration)
63
+ @ctx.abort(@ctx.message("serve.tunnel_already_running"))
64
+ end
65
+
66
+ def can_start_tunnel?(runtime_configuration)
67
+ return true if ShopifyCli::Tunnel.urls.empty?
68
+ ShopifyCli::Tunnel.running_on?(runtime_configuration.port)
69
+ end
70
+
71
+ def start_tunnel(runtime_configuration)
72
+ tunnel_url = ShopifyCli::Tunnel.start(@ctx, port: runtime_configuration.port)
73
+ runtime_configuration.tap { |c| c.tunnel_url = tunnel_url }
74
+ end
75
+
76
+ def serve(runtime_configuration)
77
+ specification_handler.serve(
78
+ context: @ctx,
79
+ tunnel_url: runtime_configuration.tunnel_url,
80
+ port: runtime_configuration.port
81
+ )
82
+ runtime_configuration
83
+ end
16
84
  end
17
85
  end
18
86
  end
@@ -37,7 +37,9 @@ module Extension
37
37
  private
38
38
 
39
39
  def status
40
- tunnel_url = ShopifyCli::Tunnel.urls.first
40
+ tunnel_urls = ShopifyCli::Tunnel.urls
41
+ tunnel_url = tunnel_urls.find { |url| url.start_with?("https://") }
42
+ tunnel_url = tunnel_urls.first if tunnel_url.nil?
41
43
 
42
44
  if tunnel_url.nil?
43
45
  @ctx.puts(@ctx.message("tunnel.no_tunnel_running"))
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "shopify_cli"
3
+ require "securerandom"
3
4
 
4
5
  module Extension
5
6
  class ExtensionProject < ShopifyCli::Project
@@ -13,18 +13,22 @@ module Extension
13
13
 
14
14
  SCRIPT_PATH = %w(build main.js).freeze
15
15
 
16
- NPM_LIST_COMMAND = %w(list).freeze
17
- YARN_LIST_COMMAND = %w(list).freeze
18
- NPM_LIST_PARAMETERS = %w(--prod --depth=1).freeze
19
- YARN_LIST_PARAMETERS = %w(--production).freeze
20
- private_constant :NPM_LIST_COMMAND, :YARN_LIST_COMMAND, :NPM_LIST_PARAMETERS, :YARN_LIST_PARAMETERS
21
-
22
16
  YARN_INSTALL_COMMAND = %w(install).freeze
23
17
  YARN_INSTALL_PARAMETERS = %w(--silent).freeze
24
18
  YARN_RUN_COMMAND = %w(run).freeze
25
19
  YARN_RUN_SCRIPT_NAME = %w(build).freeze
26
20
  private_constant :YARN_INSTALL_COMMAND, :YARN_INSTALL_PARAMETERS, :YARN_RUN_COMMAND, :YARN_RUN_SCRIPT_NAME
27
21
 
22
+ ARGO_CHECKOUT = "@shopify/argo-checkout"
23
+ ARGO_ADMIN = "@shopify/argo-admin"
24
+ ARGO_POST_PURCHASE = "@shopify/argo-post-purchase"
25
+
26
+ PACKAGE_NAMES = [
27
+ ARGO_CHECKOUT,
28
+ ARGO_ADMIN,
29
+ ARGO_POST_PURCHASE,
30
+ ].freeze
31
+
28
32
  def create(directory_name, identifier, context)
29
33
  Features::ArgoSetup.new(git_template: git_template).call(directory_name, identifier, context)
30
34
  end
@@ -48,8 +52,11 @@ module Extension
48
52
  end
49
53
 
50
54
  def renderer_package(context)
51
- Features::ArgoRendererPackage.from_package_manager(run_list_command(context))
52
- rescue Extension::PackageNotFound
55
+ js_system = ShopifyCli::JsSystem.new(ctx: context)
56
+ Tasks::FindNpmPackages
57
+ .exactly_one_of(*PACKAGE_NAMES, js_system: js_system)
58
+ .unwrap { |err| raise err }
59
+ rescue Extension::PackageResolutionFailed
53
60
  context.abort(
54
61
  context.message("features.argo.dependencies.argo_missing_renderer_package_error")
55
62
  )
@@ -57,22 +64,6 @@ module Extension
57
64
 
58
65
  private
59
66
 
60
- def run_list_command(context)
61
- yarn_list = YARN_LIST_COMMAND + YARN_LIST_PARAMETERS
62
- npm_list = NPM_LIST_COMMAND + NPM_LIST_PARAMETERS
63
-
64
- result, _error, _status = ShopifyCli::JsSystem.call(
65
- context,
66
- yarn: yarn_list,
67
- npm: npm_list,
68
- capture_response: true
69
- )
70
- # context.abort(
71
- # context.message("features.argo.dependencies.argo_missing_renderer_package_error", error)
72
- # ) unless status.success?
73
- result
74
- end
75
-
76
67
  def run_yarn_install(context, js_system)
77
68
  _result, error, status = js_system.call(
78
69
  yarn: YARN_INSTALL_COMMAND + YARN_INSTALL_PARAMETERS,
@@ -0,0 +1,63 @@
1
+ module Extension
2
+ module Features
3
+ class ArgoRuntime
4
+ include SmartProperties
5
+
6
+ ARGO_RUN_PACKAGE_NAME = "@shopify/argo-run"
7
+ ARGO_ADMIN_CLI_PACKAGE_NAME = "@shopify/argo-admin-cli"
8
+
9
+ ARGO_RUN_0_4_0 = Models::NpmPackage.new(name: "@shopify/argo-run", version: "0.4.0")
10
+ ARGO_ADMIN_CLI_0_9_3 = Models::NpmPackage.new(name: "@shopify/argo-admin-cli", version: "0.9.3")
11
+ ARGO_ADMIN_CLI_0_11_0 = Models::NpmPackage.new(name: "@shopify/argo-admin-cli", version: "0.11.0")
12
+
13
+ property! :renderer, accepts: Models::NpmPackage
14
+ property! :cli, accepts: Models::NpmPackage
15
+
16
+ def accepts_port?
17
+ case cli
18
+ when admin?
19
+ cli >= ARGO_ADMIN_CLI_0_11_0
20
+ when checkout?
21
+ cli >= ARGO_RUN_0_4_0
22
+ end
23
+ end
24
+
25
+ def accepts_tunnel_url?
26
+ case cli
27
+ when admin?
28
+ cli >= ARGO_ADMIN_CLI_0_11_0
29
+ when checkout?
30
+ cli >= ARGO_RUN_0_4_0
31
+ end
32
+ end
33
+
34
+ def accepts_uuid?
35
+ case cli
36
+ when admin?
37
+ cli >= ARGO_ADMIN_CLI_0_11_0
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ def accepts_argo_version?
44
+ case cli
45
+ when admin?
46
+ cli >= ARGO_ADMIN_CLI_0_9_3
47
+ else
48
+ false
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def admin?
55
+ ->(cli) { cli.name == ARGO_ADMIN_CLI_PACKAGE_NAME }
56
+ end
57
+
58
+ def checkout?
59
+ ->(cli) { cli.name == ARGO_RUN_PACKAGE_NAME }
60
+ end
61
+ end
62
+ end
63
+ end
@@ -4,33 +4,62 @@ module Extension
4
4
  include SmartProperties
5
5
 
6
6
  property! :specification_handler, accepts: Extension::Models::SpecificationHandlers::Default
7
+ property! :argo_runtime, accepts: Features::ArgoRuntime
7
8
  property! :context, accepts: ShopifyCli::Context
8
-
9
- YARN_SERVE_COMMAND = %w(server)
10
- NPM_SERVE_COMMAND = %w(run-script server)
9
+ property! :port, accepts: Integer, default: 39351
10
+ property :tunnel_url, accepts: String, default: ""
11
11
 
12
12
  def call
13
13
  validate_env!
14
14
 
15
15
  CLI::UI::Frame.open(context.message("serve.frame_title")) do
16
- success = ShopifyCli::JsSystem.call(context, yarn: yarn_serve_command, npm: npm_serve_command)
16
+ success = call_js_system(yarn_command: yarn_serve_command, npm_command: npm_serve_command)
17
17
  context.abort(context.message("serve.serve_failure_message")) unless success
18
18
  end
19
19
  end
20
20
 
21
21
  private
22
22
 
23
+ def call_js_system(yarn_command:, npm_command:)
24
+ ShopifyCli::JsSystem.call(context, yarn: yarn_command, npm: npm_command)
25
+ end
26
+
23
27
  def specification
24
28
  specification_handler.specification
25
29
  end
26
30
 
31
+ def renderer_package
32
+ specification_handler.renderer_package(context)
33
+ end
34
+
35
+ def required_fields
36
+ specification.features.argo.required_fields
37
+ end
38
+
39
+ def serve_options
40
+ @options ||= Features::ArgoServeOptions.new(
41
+ argo_runtime: argo_runtime,
42
+ port: port,
43
+ context: context,
44
+ required_fields: required_fields,
45
+ renderer_package: renderer_package,
46
+ public_url: tunnel_url
47
+ )
48
+ end
49
+
50
+ def yarn_serve_command
51
+ serve_options.yarn_serve_command
52
+ end
53
+
54
+ def npm_serve_command
55
+ serve_options.npm_serve_command
56
+ end
57
+
27
58
  def validate_env!
28
59
  ExtensionProject.reload
29
60
 
30
61
  ShopifyCli::Shopifolk.check && ShopifyCli::Feature.enabled?(:argo_admin_beta)
31
62
 
32
- required_fields = specification.features.argo.required_fields
33
-
34
63
  return if required_fields.none?
35
64
 
36
65
  ShopifyCli::Tasks::EnsureEnv.call(context, required: required_fields)
@@ -45,25 +74,6 @@ module Extension
45
74
 
46
75
  context.abort(context.message("serve.serve_missing_information"))
47
76
  end
48
-
49
- def yarn_serve_command
50
- YARN_SERVE_COMMAND + serve_options(specification.features.argo.required_fields)
51
- end
52
-
53
- def npm_serve_command
54
- NPM_SERVE_COMMAND + ["--"] + serve_options(specification.features.argo.required_fields)
55
- end
56
-
57
- def serve_options(required_fields)
58
- renderer_package = specification_handler.renderer_package(context)
59
- project = ExtensionProject.current
60
- @serve_options ||= [].tap do |options|
61
- options << "--shop=#{project.env.shop}" if required_fields.include?(:shop)
62
- options << "--apiKey=#{project.env.api_key}" if required_fields.include?(:api_key)
63
- options << "--argoVersion=#{renderer_package.version}" if renderer_package.admin?
64
- options << "--uuid=#{project.registration_uuid}" if renderer_package.supports_uuid_flag?
65
- end
66
- end
67
77
  end
68
78
  end
69
79
  end
@@ -0,0 +1,40 @@
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
+
29
+ @serve_options ||= [].tap do |options|
30
+ options << "--port=#{port}" if argo_runtime.accepts_port?
31
+ options << "--shop=#{project.env.shop}" if required_fields.include?(:shop)
32
+ options << "--apiKey=#{project.env.api_key}" if required_fields.include?(:api_key)
33
+ options << "--argoVersion=#{renderer_package.version}" if argo_runtime.accepts_argo_version?
34
+ options << "--uuid=#{project.registration_uuid}" if argo_runtime.accepts_uuid?
35
+ options << "--publicUrl=#{public_url}" if argo_runtime.accepts_tunnel_url?
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end