shopify-cli 1.7.0 → 1.10.0

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +28 -0
  3. data/.rubocop_todo.yml +15 -2
  4. data/CHANGELOG.md +21 -0
  5. data/Gemfile.lock +14 -14
  6. data/README.md +2 -1
  7. data/dev.yml +3 -0
  8. data/lib/docgen/markdown.rb +1 -1
  9. data/lib/graphql/extension_create.graphql +17 -2
  10. data/lib/graphql/fetch_specifications.graphql +14 -0
  11. data/lib/project_types/extension/cli.rb +4 -10
  12. data/lib/project_types/extension/commands/create.rb +2 -2
  13. data/lib/project_types/extension/commands/extension_command.rb +10 -6
  14. data/lib/project_types/extension/commands/push.rb +2 -2
  15. data/lib/project_types/extension/commands/register.rb +6 -5
  16. data/lib/project_types/extension/commands/serve.rb +1 -7
  17. data/lib/project_types/extension/extension_project.rb +19 -4
  18. data/lib/project_types/extension/extension_project_keys.rb +2 -1
  19. data/lib/project_types/extension/features/argo.rb +18 -34
  20. data/lib/project_types/extension/features/argo_renderer_package.rb +47 -0
  21. data/lib/project_types/extension/features/argo_serve.rb +69 -0
  22. data/lib/project_types/extension/features/argo_setup.rb +1 -1
  23. data/lib/project_types/extension/forms/questions/ask_type.rb +16 -5
  24. data/lib/project_types/extension/messages/message_loading.rb +3 -1
  25. data/lib/project_types/extension/messages/messages.rb +6 -6
  26. data/lib/project_types/extension/models/registration.rb +1 -0
  27. data/lib/project_types/extension/models/specification.rb +6 -2
  28. data/lib/project_types/extension/models/specification_handlers/default.rb +9 -1
  29. data/lib/project_types/extension/models/specifications.rb +12 -1
  30. data/lib/project_types/extension/models/version.rb +1 -1
  31. data/lib/project_types/extension/tasks/configure_features.rb +3 -1
  32. data/lib/project_types/extension/tasks/converters/registration_converter.rb +2 -0
  33. data/lib/project_types/extension/tasks/fetch_specifications.rb +8 -28
  34. data/lib/project_types/node/commands/generate.rb +0 -22
  35. data/lib/project_types/node/forms/create.rb +10 -1
  36. data/lib/project_types/node/messages/messages.rb +5 -4
  37. data/lib/project_types/rails/forms/create.rb +11 -1
  38. data/lib/project_types/rails/messages/messages.rb +5 -4
  39. data/lib/project_types/script/cli.rb +7 -7
  40. data/lib/project_types/script/commands/create.rb +2 -7
  41. data/lib/project_types/script/commands/push.rb +3 -3
  42. data/lib/project_types/script/config/extension_points.yml +27 -10
  43. data/lib/project_types/script/errors.rb +0 -35
  44. data/lib/project_types/script/forms/create.rb +3 -14
  45. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +5 -5
  46. data/lib/project_types/script/graphql/get_app_scripts.graphql +6 -0
  47. data/lib/project_types/script/graphql/script_service_proxy.graphql +1 -2
  48. data/lib/project_types/script/layers/application/create_script.rb +32 -22
  49. data/lib/project_types/script/layers/application/extension_points.rb +3 -2
  50. data/lib/project_types/script/layers/application/push_script.rb +6 -3
  51. data/lib/project_types/script/layers/domain/config_ui.rb +16 -0
  52. data/lib/project_types/script/layers/domain/errors.rb +16 -0
  53. data/lib/project_types/script/layers/domain/extension_point.rb +60 -45
  54. data/lib/project_types/script/layers/domain/metadata.rb +18 -25
  55. data/lib/project_types/script/layers/domain/push_package.rb +4 -4
  56. data/lib/project_types/script/layers/domain/script_project.rb +54 -0
  57. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +37 -8
  58. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +5 -40
  59. data/lib/project_types/script/layers/infrastructure/errors.rb +50 -19
  60. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +8 -9
  61. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +1 -1
  62. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +198 -0
  63. data/lib/project_types/script/layers/infrastructure/script_service.rb +27 -66
  64. data/lib/project_types/script/messages/messages.rb +28 -51
  65. data/lib/project_types/script/tasks/ensure_env.rb +77 -0
  66. data/lib/project_types/script/ui/error_handler.rb +63 -47
  67. data/lib/shopify-cli/context.rb +28 -0
  68. data/lib/shopify-cli/js_system.rb +2 -2
  69. data/lib/shopify-cli/messages/messages.rb +3 -2
  70. data/lib/shopify-cli/method_object.rb +1 -1
  71. data/lib/shopify-cli/oauth.rb +2 -2
  72. data/lib/shopify-cli/packager.rb +1 -1
  73. data/lib/shopify-cli/resolve_constant.rb +1 -1
  74. data/lib/shopify-cli/resources/env_file.rb +1 -1
  75. data/lib/shopify-cli/result.rb +3 -3
  76. data/lib/shopify-cli/tasks/ensure_dev_store.rb +1 -1
  77. data/lib/shopify-cli/transform_data_structure.rb +2 -2
  78. data/lib/shopify-cli/version.rb +1 -1
  79. data/lib/shopify_cli.rb +0 -1
  80. data/vendor/deps/smart_properties/REVISION +1 -1
  81. data/vendor/deps/smart_properties/lib/smart_properties/property.rb +7 -1
  82. data/vendor/deps/smart_properties/lib/smart_properties/version.rb +1 -1
  83. metadata +11 -10
  84. data/.travis.yml +0 -14
  85. data/lib/project_types/script/commands/disable.rb +0 -25
  86. data/lib/project_types/script/commands/enable.rb +0 -80
  87. data/lib/project_types/script/graphql/shop_script_delete.graphql +0 -14
  88. data/lib/project_types/script/graphql/shop_script_update_or_create.graphql +0 -28
  89. data/lib/project_types/script/layers/application/disable_script.rb +0 -21
  90. data/lib/project_types/script/layers/application/enable_script.rb +0 -23
  91. data/lib/project_types/script/script_project.rb +0 -85
@@ -0,0 +1,47 @@
1
+ module Extension
2
+ module Features
3
+ class ArgoRendererPackage
4
+ include SmartProperties
5
+
6
+ ARGO_CHECKOUT = "@shopify/argo-checkout"
7
+ ARGO_ADMIN = "@shopify/argo-admin"
8
+ ARGO_POST_PURCHASE = "@shopify/argo-post-purchase"
9
+
10
+ PACKAGE_NAMES = [
11
+ ARGO_CHECKOUT,
12
+ ARGO_ADMIN,
13
+ ARGO_POST_PURCHASE,
14
+ ].freeze
15
+ MINIMUM_ARGO_VERSION = "0.9.3".freeze
16
+
17
+ property! :package_name, accepts: PACKAGE_NAMES
18
+ property! :version, accepts: String
19
+
20
+ class << self
21
+ def from_package_manager(package_manager_output)
22
+ pattern = /(?<name>#{PACKAGE_NAMES.join("|")})@(?<version>\d.*)$/
23
+ match = package_manager_output.match(pattern)
24
+ raise PackageNotFound, package_manager_output if match.nil?
25
+ new(package_name: match[:name], version: match[:version].strip)
26
+ end
27
+ end
28
+
29
+ def checkout?
30
+ package_name == ARGO_CHECKOUT
31
+ end
32
+
33
+ def admin?
34
+ package_name == ARGO_ADMIN
35
+ end
36
+
37
+ ##
38
+ # Temporarily returns false in all cases as the argo webpack server is
39
+ # unable to handle the UUID flag.
40
+ def supports_uuid_flag?
41
+ false
42
+ # return false if checkout?
43
+ # Gem::Version.new(version) > Gem::Version.new(MINIMUM_ARGO_VERSION)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,69 @@
1
+ module Extension
2
+ module Features
3
+ class ArgoServe
4
+ include SmartProperties
5
+
6
+ property! :specification_handler, accepts: Extension::Models::SpecificationHandlers::Default
7
+ property! :context, accepts: ShopifyCli::Context
8
+
9
+ YARN_SERVE_COMMAND = %w(server)
10
+ NPM_SERVE_COMMAND = %w(run-script server)
11
+
12
+ def call
13
+ validate_env!
14
+
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)
17
+ context.abort(context.message("serve.serve_failure_message")) unless success
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def specification
24
+ specification_handler.specification
25
+ end
26
+
27
+ def validate_env!
28
+ ExtensionProject.reload
29
+
30
+ ShopifyCli::Shopifolk.check && ShopifyCli::Feature.enabled?(:argo_admin_beta)
31
+
32
+ required_fields = specification.features.argo.required_fields
33
+
34
+ return if required_fields.none?
35
+
36
+ ShopifyCli::Tasks::EnsureEnv.call(context, required: required_fields)
37
+ ShopifyCli::Tasks::EnsureDevStore.call(context) if required_fields.include?(:shop)
38
+
39
+ project = ExtensionProject.current
40
+
41
+ return if required_fields.all? do |field|
42
+ value = project.env.public_send(field)
43
+ value && !value.strip.empty?
44
+ end
45
+
46
+ context.abort(context.message("serve.serve_missing_information"))
47
+ 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
+ end
68
+ end
69
+ end
@@ -9,7 +9,7 @@ module Extension
9
9
  SCRIPTS_DIRECTORY = "scripts"
10
10
 
11
11
  property! :git_template, accepts: String
12
- property! :dependency_checks, default: []
12
+ property! :dependency_checks, default: -> { [] }
13
13
 
14
14
  def call(directory_name, identifier, context)
15
15
  steps = [
@@ -11,25 +11,36 @@ module Extension
11
11
  default: -> { CLI::UI::Prompt.method(:ask) }
12
12
 
13
13
  def call(project_details)
14
+ specifications = Models::Specifications.new(
15
+ fetch_specifications: Tasks::FetchSpecifications.new(context: ctx, api_key: project_details.app.api_key)
16
+ )
17
+
14
18
  project_details.tap do |p|
15
- p.type = type.nil? ? choose_type : validate_given_type(type)
19
+ p.type = type.nil? ? choose_type(specifications) : validate_given_type(specifications, type)
16
20
  end
17
21
  end
18
22
 
19
23
  private
20
24
 
21
- def validate_given_type(type)
22
- return Extension.specifications[type] if Extension.specifications.valid?(type)
25
+ def validate_given_type(specifications, type)
26
+ return specifications[type] if specifications.valid?(type)
23
27
  ctx.abort(ctx.message("create.invalid_type")) unless type.nil?
24
28
  end
25
29
 
26
- def choose_type
30
+ def choose_type(specifications)
31
+ abort_due_to_missing_specifications if specifications.none?
32
+
27
33
  prompt.call(ctx.message("create.ask_type")) do |handler|
28
- Extension.specifications.each do |type|
34
+ specifications.each do |type|
29
35
  handler.option("#{type.name} #{type.tagline}") { type }
30
36
  end
31
37
  end
32
38
  end
39
+
40
+ def abort_due_to_missing_specifications
41
+ ctx.puts(@ctx.message("create.no_available_extensions"))
42
+ raise ShopifyCli::AbortSilent
43
+ end
33
44
  end
34
45
  end
35
46
  end
@@ -16,7 +16,9 @@ module Extension
16
16
 
17
17
  def self.load_current_type_messages
18
18
  return unless ShopifyCli::Project.has_current?
19
- messages_for_type(ShopifyCli::Project.current.config[Extension::ExtensionProjectKeys::EXTENSION_TYPE_KEY])
19
+ messages_for_type(
20
+ ShopifyCli::Project.current.config[Extension::ExtensionProjectKeys::SPECIFICATION_IDENTIFIER_KEY]
21
+ )
20
22
  end
21
23
 
22
24
  def self.messages_for_type(type_identifier)
@@ -30,6 +30,7 @@ module Extension
30
30
  learn_about_apps: "{{*}} Learn more about building apps at <https://shopify.dev/concepts/apps>, " \
31
31
  "or try creating a new app using {{command:shopify create}}.",
32
32
  loading_apps: "Loading your apps...",
33
+ no_available_extensions: "{{x}} There are no available extensions for this app.",
33
34
  },
34
35
  build: {
35
36
  frame_title: "Building extension with: %s...",
@@ -40,9 +41,9 @@ module Extension
40
41
  waiting_text: "Registering with Shopify...",
41
42
  already_registered: "Extension is already registered.",
42
43
  confirm_info: "This will create a new extension registration for %s, which can’t be undone.",
43
- confirm_question: "Would you like to register this extension with {{green:%s}}? (y/n)",
44
+ confirm_question: "Would you like to register this extension? (y/n)",
44
45
  confirm_abort: "Extension was not registered.",
45
- success: "{{v}} Registered {{green:%s}} with {{green:%s}}.",
46
+ success: "{{v}} Registered {{green:%s}}.",
46
47
  success_info: "{{*}} Run {{command:shopify push}} to push your extension to Shopify.",
47
48
  },
48
49
  push: {
@@ -56,6 +57,7 @@ module Extension
56
57
  serve: {
57
58
  frame_title: "Serving extension...",
58
59
  serve_failure_message: "Failed to run extension code.",
60
+ serve_missing_information: "Missing shop or api_key.",
59
61
  },
60
62
  tunnel: {
61
63
  missing_token: "{{x}} {{red:auth requires a token argument}}. "\
@@ -96,10 +98,8 @@ module Extension
96
98
  node_not_installed: "Node must be installed to create this extension.",
97
99
  version_too_low: "Your node version %s does not meet the minimum required version %s",
98
100
  },
99
- argo_missing_renderer_package_error: "%s Install the missing package and try again.",
100
- argo_renderer_package_invalid_version_error: <<~MESSAGE,
101
- The renderer package version is not a valid SemVer Version (http://semver.org)
102
- MESSAGE
101
+ argo_missing_renderer_package_error: "Extension template references invalid renderer package "\
102
+ "please contact Shopify for help.",
103
103
  yarn_install_error: "Something went wrong while running 'yarn install'. %s.",
104
104
  yarn_run_script_error: "Something went wrong while running script. %s.",
105
105
  },
@@ -7,6 +7,7 @@ module Extension
7
7
  include SmartProperties
8
8
 
9
9
  property! :id, accepts: Integer
10
+ property! :uuid, accepts: String
10
11
  property! :type, accepts: String
11
12
  property! :title, accepts: String
12
13
  property! :draft_version, accepts: Extension::Models::Version
@@ -7,9 +7,11 @@ module Extension
7
7
  class Argo
8
8
  include SmartProperties
9
9
 
10
- property! :surface_area, converts: :to_str
10
+ property! :surface, converts: :to_str
11
11
  property! :renderer_package_name, converts: :to_str
12
12
  property! :git_template, converts: :to_str
13
+ property! :required_fields, accepts: Array, default: -> { [] }
14
+ property! :required_shop_beta_flags, accepts: Array, default: -> { [] }
13
15
  end
14
16
 
15
17
  def self.build(feature_set_attributes)
@@ -18,14 +20,16 @@ module Extension
18
20
  .call(identifier, namespace: Features)
19
21
  .rescue { OpenStruct }
20
22
  .then { |c| c.new(**feature_attributes) }
21
- .unwrap { |error| raise error }
23
+ .unwrap { |error| raise(error) }
22
24
  end
23
25
  end
24
26
  end
25
27
 
26
28
  property! :identifier
29
+ property :name, converts: :to_str
27
30
  property :graphql_identifier, converts: :to_str
28
31
  property! :features, converts: Features.method(:build), default: -> { [] }
32
+ property! :options, converts: ->(options) { OpenStruct.new(options) }, default: -> { OpenStruct.new }
29
33
 
30
34
  def graphql_identifier
31
35
  super || identifier
@@ -19,7 +19,7 @@ module Extension
19
19
  end
20
20
 
21
21
  def name
22
- message("name")
22
+ message("name") || specification.name
23
23
  end
24
24
 
25
25
  def tagline
@@ -42,6 +42,14 @@ module Extension
42
42
  []
43
43
  end
44
44
 
45
+ def serve(context)
46
+ Features::ArgoServe.new(specification_handler: self, context: context).call
47
+ end
48
+
49
+ def renderer_package(context)
50
+ argo.renderer_package(context)
51
+ end
52
+
45
53
  protected
46
54
 
47
55
  def argo
@@ -26,6 +26,10 @@ module Extension
26
26
  handlers.values.each(&block)
27
27
  end
28
28
 
29
+ def none?
30
+ each.none?
31
+ end
32
+
29
33
  protected
30
34
 
31
35
  def handlers
@@ -37,6 +41,8 @@ module Extension
37
41
  def fetch_specifications_and_build_handlers
38
42
  ShopifyCli::Result
39
43
  .call(&fetch_specifications)
44
+ .map(&ShopifyCli::TransformDataStructure.new(symbolize_keys: true, underscore_keys: true))
45
+ .then(&method(:select_cli_extensions))
40
46
  .then(&Tasks::ConfigureFeatures)
41
47
  .then(&method(:ensure_legacy_compatibility))
42
48
  .then(&method(:build_specifications))
@@ -64,7 +70,8 @@ module Extension
64
70
 
65
71
  def ensure_legacy_compatibility(specification_attribute_sets)
66
72
  specification_attribute_sets.each do |attributes|
67
- next unless attributes.fetch(:identifier) == "product_subscription"
73
+ next unless attributes.fetch(:identifier) == "subscription_management"
74
+ attributes[:identifier] = "product_subscription"
68
75
  attributes[:graphql_identifier] = "SUBSCRIPTION_MANAGEMENT"
69
76
  end
70
77
  end
@@ -72,6 +79,10 @@ module Extension
72
79
  def build_specifications(specification_attribute_sets)
73
80
  specification_attribute_sets.map { |attributes| Models::Specification.new(**attributes) }
74
81
  end
82
+
83
+ def select_cli_extensions(specification_attribute_sets)
84
+ specification_attribute_sets.select { |attributes| attributes.dig(:options, :management_experience) == "cli" }
85
+ end
75
86
  end
76
87
  end
77
88
  end
@@ -9,7 +9,7 @@ module Extension
9
9
  property! :last_user_interaction_at, accepts: Time
10
10
  property :context, accepts: String
11
11
  property :location, accepts: String
12
- property :validation_errors, accepts: Models::ValidationError::IS_VALIDATION_ERROR_LIST, default: []
12
+ property :validation_errors, accepts: Models::ValidationError::IS_VALIDATION_ERROR_LIST, default: -> { [] }
13
13
  end
14
14
  end
15
15
  end
@@ -24,7 +24,7 @@ module Extension
24
24
  end
25
25
 
26
26
  def extract_surface_area(argo_configuration)
27
- argo_configuration.fetch(:surface_area) do
27
+ argo_configuration.fetch(:surface) do
28
28
  raise UnspecifiedSurfaceArea, "Argo configuration does not specify surface area"
29
29
  end
30
30
  end
@@ -40,6 +40,8 @@ module Extension
40
40
  admin: {
41
41
  git_template: "https://github.com/Shopify/argo-admin-template.git",
42
42
  renderer_package_name: "@shopify/argo-admin",
43
+ required_fields: [:shop, :api_key],
44
+ required_shop_beta_flags: [:argo_admin_beta],
43
45
  },
44
46
  checkout: {
45
47
  git_template: "https://github.com/Shopify/argo-checkout-template.git",
@@ -6,6 +6,7 @@ module Extension
6
6
  module Converters
7
7
  module RegistrationConverter
8
8
  ID_FIELD = "id"
9
+ UUID_FIELD = "uuid"
9
10
  TYPE_FIELD = "type"
10
11
  TITLE_FIELD = "title"
11
12
  DRAFT_VERSION_FIELD = "draftVersion"
@@ -15,6 +16,7 @@ module Extension
15
16
 
16
17
  Models::Registration.new(
17
18
  id: hash[ID_FIELD].to_i,
19
+ uuid: hash[UUID_FIELD],
18
20
  type: hash[TYPE_FIELD],
19
21
  title: hash[TITLE_FIELD],
20
22
  draft_version: VersionConverter.from_hash(context, hash[DRAFT_VERSION_FIELD])
@@ -3,35 +3,15 @@ module Extension
3
3
  class FetchSpecifications
4
4
  include ShopifyCli::MethodObject
5
5
 
6
- def call
7
- [
8
- product_subscription_specification,
9
- checkout_post_purchase_specification,
10
- ]
11
- end
12
-
13
- private
6
+ property :context
7
+ property :api_key
14
8
 
15
- def product_subscription_specification
16
- {
17
- identifier: "product_subscription",
18
- features: {
19
- argo: {
20
- surface_area: "admin",
21
- },
22
- },
23
- }
24
- end
25
-
26
- def checkout_post_purchase_specification
27
- {
28
- identifier: "checkout_post_purchase",
29
- features: {
30
- argo: {
31
- surface_area: "checkout",
32
- },
33
- },
34
- }
9
+ def call
10
+ response = ShopifyCli::PartnersAPI
11
+ .query(context, "fetch_specifications", api_key: api_key)
12
+ .dig("data", "extensionSpecifications")
13
+ context.abort(context.message("tasks.errors.parse_error")) if response.nil?
14
+ response
35
15
  end
36
16
  end
37
17
  end
@@ -4,10 +4,6 @@ require "shopify_cli"
4
4
  module Node
5
5
  module Commands
6
6
  class Generate < ShopifyCli::Command
7
- subcommand :Page, "page", Project.project_filepath("commands/generate/page")
8
- subcommand :Billing, "billing", Project.project_filepath("commands/generate/billing")
9
- subcommand :Webhook, "webhook", Project.project_filepath("commands/generate/webhook")
10
-
11
7
  def call(*)
12
8
  @ctx.puts(self.class.help)
13
9
  end
@@ -19,24 +15,6 @@ module Node
19
15
  def self.extended_help
20
16
  help
21
17
  end
22
-
23
- def self.run_generate(script, name, ctx)
24
- stat = ctx.system(script)
25
- unless stat.success?
26
- ctx.abort(response(stat.exitstatus, name, ctx))
27
- end
28
- end
29
-
30
- def self.response(code, name, ctx)
31
- case code
32
- when 1
33
- ctx.message("node.generate.error.generic", name)
34
- when 2
35
- ctx.message("node.generate.error.name_exists", name)
36
- else
37
- ctx.message("node.error.generic")
38
- end
39
- end
40
18
  end
41
19
  end
42
20
  end