shopify-cli 2.6.4 → 2.7.1

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer.json +5 -0
  3. data/.github/DESIGN.md +1 -1
  4. data/.github/ISSUE_TEMPLATE.md +7 -0
  5. data/.gitignore +1 -0
  6. data/.vscode/extensions.json +5 -0
  7. data/.vscode/settings.json +9 -0
  8. data/CHANGELOG.md +35 -3
  9. data/CONTRIBUTING.md +1 -21
  10. data/{Dockerfile → Codespace.dockerfile} +11 -3
  11. data/Gemfile +1 -0
  12. data/Gemfile.lock +6 -4
  13. data/README.md +20 -99
  14. data/Rakefile +27 -0
  15. data/Tests.dockerfile +35 -0
  16. data/assets/logo.png +0 -0
  17. data/dev.yml +0 -3
  18. data/docs/README.md +13 -0
  19. data/docs/contributors/testing.md +27 -0
  20. data/docs/users/installation.md +46 -0
  21. data/{THEMEKIT_MIGRATION.md → docs/users/migrate-from-themekit.md} +1 -1
  22. data/ext/javy/javy.rb +186 -0
  23. data/ext/javy/version +1 -0
  24. data/lib/project_types/extension/cli.rb +7 -3
  25. data/lib/project_types/extension/commands/build.rb +1 -0
  26. data/lib/project_types/extension/commands/create.rb +6 -6
  27. data/lib/project_types/extension/commands/extension_command.rb +1 -1
  28. data/lib/project_types/extension/features/argo.rb +1 -8
  29. data/lib/project_types/extension/features/argo_serve.rb +9 -23
  30. data/lib/project_types/extension/forms/create.rb +1 -1
  31. data/lib/project_types/extension/forms/questions/ask_template.rb +3 -6
  32. data/lib/project_types/extension/messages/messages.rb +1 -0
  33. data/lib/project_types/extension/models/development_server_requirements.rb +2 -3
  34. data/lib/project_types/extension/models/server_config/app.rb +13 -0
  35. data/lib/project_types/extension/models/server_config/development.rb +5 -4
  36. data/lib/project_types/extension/models/server_config/development_renderer.rb +1 -1
  37. data/lib/project_types/extension/models/server_config/development_resource.rb +13 -0
  38. data/lib/project_types/extension/models/server_config/extension.rb +4 -0
  39. data/lib/project_types/extension/models/server_config/root.rb +4 -1
  40. data/lib/project_types/extension/tasks/convert_server_config.rb +65 -0
  41. data/lib/project_types/extension/tasks/ensure_resource_url.rb +39 -0
  42. data/lib/project_types/extension/tasks/find_package_from_json.rb +37 -0
  43. data/lib/project_types/extension/tasks/merge_server_config.rb +32 -0
  44. data/lib/project_types/extension/tasks/run_extension_command.rb +11 -10
  45. data/lib/project_types/node/cli.rb +0 -16
  46. data/lib/project_types/node/forms/create.rb +5 -5
  47. data/lib/project_types/node/messages/messages.rb +2 -144
  48. data/lib/project_types/php/cli.rb +0 -11
  49. data/lib/project_types/php/forms/create.rb +5 -6
  50. data/lib/project_types/php/messages/messages.rb +2 -161
  51. data/lib/project_types/rails/cli.rb +0 -16
  52. data/lib/project_types/rails/commands/create.rb +46 -17
  53. data/lib/project_types/rails/forms/create.rb +5 -7
  54. data/lib/project_types/rails/messages/messages.rb +6 -151
  55. data/lib/project_types/script/cli.rb +2 -1
  56. data/lib/project_types/script/commands/create.rb +2 -5
  57. data/lib/project_types/script/commands/javy.rb +31 -0
  58. data/lib/project_types/script/commands/push.rb +1 -1
  59. data/lib/project_types/script/config/extension_points.yml +3 -0
  60. data/lib/project_types/script/errors.rb +0 -18
  61. data/lib/project_types/script/layers/application/create_script.rb +2 -2
  62. data/lib/project_types/script/layers/domain/script_json.rb +1 -1
  63. data/lib/project_types/script/layers/infrastructure/api_clients/partners_proxy_api_client.rb +0 -4
  64. data/lib/project_types/script/layers/infrastructure/errors.rb +8 -3
  65. data/lib/project_types/script/layers/infrastructure/languages/assemblyscript_task_runner.rb +22 -3
  66. data/lib/project_types/script/layers/infrastructure/languages/typescript_task_runner.rb +25 -0
  67. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +3 -4
  68. data/lib/project_types/script/layers/infrastructure/script_service.rb +1 -1
  69. data/lib/project_types/script/messages/messages.rb +16 -22
  70. data/lib/project_types/script/ui/error_handler.rb +1 -27
  71. data/lib/project_types/theme/cli.rb +1 -1
  72. data/lib/project_types/theme/commands/check.rb +1 -1
  73. data/lib/project_types/theme/commands/delete.rb +1 -1
  74. data/lib/project_types/theme/commands/init.rb +1 -1
  75. data/lib/project_types/theme/commands/language_server.rb +1 -1
  76. data/lib/project_types/theme/commands/package.rb +1 -1
  77. data/lib/project_types/theme/commands/publish.rb +1 -1
  78. data/lib/project_types/theme/commands/pull.rb +1 -1
  79. data/lib/project_types/theme/commands/push.rb +1 -1
  80. data/lib/project_types/theme/commands/serve.rb +9 -2
  81. data/lib/project_types/theme/messages/messages.rb +30 -1
  82. data/lib/shopify_cli/admin_api/populate_resource_command.rb +1 -1
  83. data/lib/shopify_cli/api.rb +7 -2
  84. data/lib/shopify_cli/app_type_detector.rb +24 -20
  85. data/lib/shopify_cli/command/app_sub_command.rb +10 -0
  86. data/lib/shopify_cli/command/project_command.rb +18 -0
  87. data/lib/shopify_cli/command/sub_command.rb +19 -0
  88. data/lib/shopify_cli/command.rb +7 -2
  89. data/lib/shopify_cli/commands/app/connect.rb +22 -0
  90. data/lib/shopify_cli/commands/app/create/node.rb +38 -0
  91. data/lib/shopify_cli/commands/app/create/php.rb +36 -0
  92. data/lib/shopify_cli/commands/app/create/rails.rb +40 -0
  93. data/lib/shopify_cli/commands/app/create.rb +28 -0
  94. data/lib/shopify_cli/commands/app/deploy.rb +49 -0
  95. data/lib/shopify_cli/commands/app/open.rb +19 -0
  96. data/lib/shopify_cli/commands/app/serve.rb +49 -0
  97. data/lib/shopify_cli/commands/app/tunnel.rb +43 -0
  98. data/lib/shopify_cli/commands/app.rb +29 -0
  99. data/lib/shopify_cli/commands/config.rb +2 -2
  100. data/lib/shopify_cli/commands.rb +1 -0
  101. data/lib/shopify_cli/constants.rb +4 -0
  102. data/lib/shopify_cli/exception_reporter.rb +8 -6
  103. data/lib/shopify_cli/git.rb +12 -1
  104. data/lib/shopify_cli/github/issue_url_generator.rb +19 -0
  105. data/lib/shopify_cli/github.rb +5 -0
  106. data/lib/shopify_cli/messages/messages.rb +253 -9
  107. data/lib/shopify_cli/migrator.rb +9 -11
  108. data/lib/shopify_cli/project.rb +5 -1
  109. data/lib/shopify_cli/project_commands.rb +1 -1
  110. data/lib/shopify_cli/services/app/connect_service.rb +25 -0
  111. data/lib/shopify_cli/services/app/create/node_service.rb +155 -0
  112. data/lib/shopify_cli/services/app/create/php_service.rb +152 -0
  113. data/lib/shopify_cli/services/app/create/rails_service.rb +215 -0
  114. data/lib/shopify_cli/services/app/deploy/heroku/node_service.rb +101 -0
  115. data/lib/shopify_cli/services/app/deploy/heroku/php_service.rb +135 -0
  116. data/lib/shopify_cli/services/app/deploy/heroku/rails_service.rb +120 -0
  117. data/lib/shopify_cli/services/app/open_service.rb +19 -0
  118. data/lib/shopify_cli/services/app/serve/node_service.rb +42 -0
  119. data/lib/shopify_cli/services/app/serve/php_service.rb +46 -0
  120. data/lib/shopify_cli/services/app/serve/rails_service.rb +48 -0
  121. data/lib/shopify_cli/services/app/tunnel/auth_service.rb +21 -0
  122. data/lib/shopify_cli/services/app/tunnel/start_service.rb +20 -0
  123. data/lib/shopify_cli/services/app/tunnel/stop_service.rb +20 -0
  124. data/lib/shopify_cli/services.rb +31 -0
  125. data/lib/shopify_cli/theme/dev_server/local_assets.rb +1 -1
  126. data/lib/shopify_cli/theme/dev_server.rb +35 -17
  127. data/lib/shopify_cli/tunnel.rb +25 -20
  128. data/lib/shopify_cli/version.rb +1 -1
  129. data/lib/shopify_cli.rb +1 -2
  130. data/shopify-cli.gemspec +2 -6
  131. data/shopify-dev +18 -0
  132. data/utilities/constants.rb +7 -0
  133. data/utilities/docker/container.rb +30 -2
  134. data/utilities/docker.rb +3 -2
  135. data/utilities/utilities.rb +1 -0
  136. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +1 -1
  137. metadata +56 -53
  138. data/docs/_config.yml +0 -2
  139. data/docs/app/node/commands/index.md +0 -4
  140. data/docs/app/node/index.md +0 -4
  141. data/docs/app/rails/commands/index.md +0 -4
  142. data/docs/app/rails/index.md +0 -4
  143. data/docs/core/index.md +0 -4
  144. data/docs/getting-started/index.md +0 -4
  145. data/docs/getting-started/install/index.md +0 -4
  146. data/docs/getting-started/migrate/index.md +0 -4
  147. data/docs/getting-started/uninstall/index.md +0 -4
  148. data/docs/getting-started/upgrade/index.md +0 -4
  149. data/docs/help/start-app/index.md +0 -4
  150. data/docs/index.md +0 -4
  151. data/ext/shopify-cli/extconf.rb +0 -60
  152. data/install.sh +0 -7
  153. data/lib/project_types/extension/tasks/converters/server_config_converter.rb +0 -31
  154. data/lib/project_types/extension/tasks/load_server_config.rb +0 -23
  155. data/lib/project_types/node/commands/connect.rb +0 -21
  156. data/lib/project_types/node/commands/create.rb +0 -125
  157. data/lib/project_types/node/commands/deploy/heroku.rb +0 -96
  158. data/lib/project_types/node/commands/deploy.rb +0 -32
  159. data/lib/project_types/node/commands/generate.rb +0 -22
  160. data/lib/project_types/node/commands/open.rb +0 -18
  161. data/lib/project_types/node/commands/serve.rb +0 -45
  162. data/lib/project_types/node/commands/tunnel.rb +0 -41
  163. data/lib/project_types/php/commands/connect.rb +0 -19
  164. data/lib/project_types/php/commands/create.rb +0 -143
  165. data/lib/project_types/php/commands/deploy/heroku.rb +0 -129
  166. data/lib/project_types/php/commands/deploy.rb +0 -32
  167. data/lib/project_types/php/commands/open.rb +0 -16
  168. data/lib/project_types/php/commands/serve.rb +0 -48
  169. data/lib/project_types/php/commands/tunnel.rb +0 -37
  170. data/lib/project_types/rails/commands/connect.rb +0 -21
  171. data/lib/project_types/rails/commands/deploy/heroku.rb +0 -115
  172. data/lib/project_types/rails/commands/deploy.rb +0 -32
  173. data/lib/project_types/rails/commands/generate/webhook.rb +0 -42
  174. data/lib/project_types/rails/commands/generate.rb +0 -60
  175. data/lib/project_types/rails/commands/open.rb +0 -18
  176. data/lib/project_types/rails/commands/serve.rb +0 -51
  177. data/lib/project_types/rails/commands/tunnel.rb +0 -41
  178. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -0
  179. data/lib/shopify_cli/sub_command.rb +0 -17
  180. data/shopify.fish +0 -12
  181. data/shopify.sh +0 -11
data/ext/javy/javy.rb ADDED
@@ -0,0 +1,186 @@
1
+ require "rbconfig"
2
+ require "open-uri"
3
+ require "zlib"
4
+ require "open3"
5
+
6
+ module Javy
7
+ ROOT = __dir__
8
+ BIN_FOLDER = File.join(ROOT, "bin")
9
+ VERSION = File.read(File.join(ROOT, "version")).strip
10
+ TARGET = File.join(BIN_FOLDER, "javy-#{VERSION}")
11
+
12
+ class << self
13
+ def install
14
+ ShopifyCLI::Result
15
+ .wrap { Installer.call(target: target, platform: platform, version: VERSION) }
16
+ .call
17
+ end
18
+
19
+ def build(source:, dest: nil)
20
+ ensure_installed
21
+
22
+ optional_args = []
23
+ optional_args += ["-o", dest] unless dest.nil?
24
+
25
+ ShopifyCLI::Result
26
+ .wrap { exec(source, *optional_args) }
27
+ .call
28
+ end
29
+
30
+ private
31
+
32
+ def exec(*args, **kwargs)
33
+ out_and_err, stat = CLI::Kit::System.capture2e(target, *args, **kwargs)
34
+ raise ExecutionError, out_and_err unless stat.success?
35
+ true
36
+ end
37
+
38
+ def platform
39
+ Platform.new
40
+ end
41
+
42
+ def target
43
+ platform.format_executable_path(TARGET)
44
+ end
45
+
46
+ def ensure_installed
47
+ delete_outdated_installations
48
+ install unless Installer.installed?(target: target)
49
+ end
50
+
51
+ def delete_outdated_installations
52
+ installed_binaries
53
+ .reject { |v| v == target }
54
+ .each { |file| File.delete(file) }
55
+ end
56
+
57
+ def installed_binaries
58
+ Dir[File.join(BIN_FOLDER, "javy-*")]
59
+ end
60
+
61
+ module Installer
62
+ def self.call(target:, platform:, version:)
63
+ asset = Asset.new(
64
+ platform: platform,
65
+ version: version,
66
+ owner: "Shopify",
67
+ repository: "javy",
68
+ basename: "javy"
69
+ )
70
+
71
+ downloaded = asset.download(target: target)
72
+ raise InstallationError.asset_not_found(platform: platform, version: version, url: asset.url) unless downloaded
73
+
74
+ true
75
+ end
76
+
77
+ def self.installed?(target:)
78
+ File.executable?(target)
79
+ end
80
+ end
81
+ end
82
+
83
+ class Error < RuntimeError; end
84
+ class ExecutionError < Error; end
85
+
86
+ class InstallationError < Error
87
+ def self.cpu_unsupported
88
+ new("Javy is not supported on this CPU")
89
+ end
90
+
91
+ def self.asset_not_found(platform:, version:, url:)
92
+ new(format(
93
+ "Unable to download javy %{version} for %{os} (%{cpu}) at %{url}",
94
+ version: version,
95
+ os: platform.os,
96
+ cpu: platform.cpu,
97
+ url: url
98
+ ))
99
+ end
100
+ end
101
+
102
+ Asset = Struct.new(:platform, :version, :owner, :repository, :basename, keyword_init: true) do
103
+ def download(target:)
104
+ FileUtils.mkdir_p(BIN_FOLDER)
105
+
106
+ Dir.chdir(File.dirname(target)) do
107
+ File.open(File.basename(target), "wb") do |target_file|
108
+ decompress(url.open, target_file)
109
+ end
110
+ File.chmod(0755, target)
111
+ end
112
+
113
+ true
114
+ rescue OpenURI::HTTPError
115
+ false
116
+ end
117
+
118
+ def url
119
+ URI.parse(format(
120
+ "https://github.com/%{owner}/%{repository}/releases/download/%{version}/%{filename}",
121
+ owner: owner,
122
+ repository: repository,
123
+ version: version,
124
+ filename: filename
125
+ ))
126
+ end
127
+
128
+ def filename
129
+ format(
130
+ "%{basename}-%{cpu}-%{os}-%{version}.gz",
131
+ basename: basename,
132
+ cpu: platform.cpu,
133
+ os: platform.os,
134
+ version: version
135
+ )
136
+ end
137
+
138
+ private
139
+
140
+ def decompress(source, target)
141
+ zlib = Zlib::GzipReader.new(source)
142
+ target << zlib.read
143
+ ensure
144
+ zlib.close
145
+ end
146
+ end
147
+
148
+ Platform = Struct.new(:ruby_config) do
149
+ def initialize(ruby_config = RbConfig::CONFIG)
150
+ super(ruby_config)
151
+ end
152
+
153
+ def to_s
154
+ format("%{cpu}-%{os}", cpu: cpu, os: os)
155
+ end
156
+
157
+ def os
158
+ case ruby_config.fetch("host_os")
159
+ when /linux/
160
+ "linux"
161
+ when /darwin/
162
+ "macos"
163
+ else
164
+ "windows"
165
+ end
166
+ end
167
+
168
+ def cpu
169
+ case ruby_config.fetch("host_cpu")
170
+ when "x64", "x86_64"
171
+ "x86_64"
172
+ else
173
+ raise InstallationError.cpu_unsupported
174
+ end
175
+ end
176
+
177
+ def format_executable_path(path)
178
+ case os
179
+ when "windows"
180
+ File.extname(path) != ".exe" ? path + ".exe" : path
181
+ else
182
+ path
183
+ end
184
+ end
185
+ end
186
+ end
data/ext/javy/version ADDED
@@ -0,0 +1 @@
1
+ v0.1.0
@@ -12,7 +12,7 @@ module Extension
12
12
  register_messages(Extension::Messages::MessageLoading.load)
13
13
  end
14
14
 
15
- class Command < ShopifyCLI::ProjectCommands
15
+ class Command < ShopifyCLI::Command::ProjectCommand
16
16
  hidden_feature
17
17
  autoload :ExtensionCommand, Project.project_filepath("commands/extension_command")
18
18
 
@@ -42,7 +42,10 @@ module Extension
42
42
  autoload :GetExtensions, Project.project_filepath("tasks/get_extensions")
43
43
  autoload :GetProduct, Project.project_filepath("tasks/get_product")
44
44
  autoload :RunExtensionCommand, Project.project_filepath("tasks/run_extension_command")
45
- autoload :LoadServerConfig, Project.project_filepath("tasks/load_server_config")
45
+ autoload :MergeServerConfig, Project.project_filepath("tasks/merge_server_config")
46
+ autoload :FindPackageFromJson, Project.project_filepath("tasks/find_package_from_json.rb")
47
+ autoload :EnsureResourceUrl, Project.project_filepath("tasks/ensure_resource_url.rb")
48
+ autoload :ConvertServerConfig, Project.project_filepath("tasks/convert_server_config")
46
49
 
47
50
  module Converters
48
51
  autoload :RegistrationConverter, Project.project_filepath("tasks/converters/registration_converter")
@@ -50,7 +53,6 @@ module Extension
50
53
  autoload :ValidationErrorConverter, Project.project_filepath("tasks/converters/validation_error_converter")
51
54
  autoload :AppConverter, Project.project_filepath("tasks/converters/app_converter")
52
55
  autoload :ProductConverter, Project.project_filepath("tasks/converters/product_converter")
53
- autoload :ServerConfigConverter, Project.project_filepath("tasks/converters/server_config_converter")
54
56
  end
55
57
  end
56
58
 
@@ -93,9 +95,11 @@ module Extension
93
95
 
94
96
  module ServerConfig
95
97
  autoload :Base, Project.project_filepath("models/server_config/base")
98
+ autoload :App, Project.project_filepath("models/server_config/app")
96
99
  autoload :Development, Project.project_filepath("models/server_config/development")
97
100
  autoload :DevelopmentEntries, Project.project_filepath("models/server_config/development_entries")
98
101
  autoload :DevelopmentRenderer, Project.project_filepath("models/server_config/development_renderer")
102
+ autoload :DevelopmentResource, Project.project_filepath("models/server_config/development_resource")
99
103
  autoload :Extension, Project.project_filepath("models/server_config/extension")
100
104
  autoload :Root, Project.project_filepath("models/server_config/root")
101
105
  autoload :User, Project.project_filepath("models/server_config/user")
@@ -28,6 +28,7 @@ module Extension
28
28
  type: project.specification_identifier.downcase,
29
29
  command: "build",
30
30
  config_file_name: specification_handler.server_config_file,
31
+ context: @ctx,
31
32
  ).call
32
33
 
33
34
  @ctx.puts(@ctx.message("build.build_success_message"))
@@ -2,15 +2,14 @@
2
2
 
3
3
  module Extension
4
4
  class Command
5
- class Create < ShopifyCLI::SubCommand
6
- DEVELOPMENT_SERVER_SUPPORTED_TYPES = [
7
- "checkout_ui_extension",
8
- ]
9
-
10
- prerequisite_task :ensure_authenticated
5
+ class Create < ShopifyCLI::Command::SubCommand
6
+ unless ShopifyCLI::Environment.acceptance_test?
7
+ prerequisite_task :ensure_authenticated
8
+ end
11
9
 
12
10
  options do |parser, flags|
13
11
  parser.on("--name=NAME") { |name| flags[:name] = name }
12
+ parser.on("--template=TEMPLATE") { |template| flags[:template] = template }
14
13
  parser.on("--type=TYPE") { |type| flags[:type] = type.upcase }
15
14
  parser.on("--api-key=KEY") { |key| flags[:api_key] = key.downcase }
16
15
  parser.on("--getting-started") { flags[:getting_started] = true }
@@ -65,6 +64,7 @@ module Extension
65
64
  @ctx.chdir(form.directory_name)
66
65
  write_env_file(form)
67
66
  rescue => error
67
+ @ctx.debug(error)
68
68
  raise error
69
69
  end
70
70
 
@@ -3,7 +3,7 @@ require "shopify_cli"
3
3
 
4
4
  module Extension
5
5
  class Command
6
- class ExtensionCommand < ShopifyCLI::SubCommand
6
+ class ExtensionCommand < ShopifyCLI::Command::SubCommand
7
7
  def project
8
8
  @project ||= ExtensionProject.current
9
9
  end
@@ -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,9 @@ 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
+ if resource_url_required?
67
+ Tasks::EnsureResourceUrl.call(context: context, specification_handler: specification_handler)
68
+ end
67
69
 
68
70
  return if required_fields.all? do |field|
69
71
  value = project.env.public_send(field)
@@ -73,6 +75,10 @@ module Extension
73
75
  context.abort(context.message("serve.serve_missing_information"))
74
76
  end
75
77
 
78
+ def resource_url_required?
79
+ specification_handler.supplies_resource_url? && resource_url.nil?
80
+ end
81
+
76
82
  def options
77
83
  project = ExtensionProject.current
78
84
 
@@ -88,28 +94,6 @@ module Extension
88
94
  end
89
95
  end
90
96
 
91
- def ensure_resource_resource_url!
92
- project = ExtensionProject.current(force_reload: true)
93
-
94
- ShopifyCLI::Result
95
- .wrap(project.resource_url)
96
- .rescue { specification_handler.build_resource_url(shop: project.env.shop, context: context) }
97
- .then(&method(:persist_resource_url))
98
- .unwrap do |nil_or_exception|
99
- case nil_or_exception
100
- when nil
101
- context.warn(context.message("warnings.resource_url_auto_generation_failed", project.env.shop))
102
- else
103
- context.abort(nil_or_exception)
104
- end
105
- end
106
- end
107
-
108
- def persist_resource_url(resource_url)
109
- ExtensionProject.update_env_file(context: context, resource_url: resource_url)
110
- resource_url
111
- end
112
-
113
97
  def new_serve_flow
114
98
  Tasks::RunExtensionCommand.new(
115
99
  type: specification_handler.specification.identifier,
@@ -117,6 +101,8 @@ module Extension
117
101
  context: context,
118
102
  port: port,
119
103
  config_file_name: specification_handler.server_config_file,
104
+ resource_url: resource_url,
105
+ tunnel_url: tunnel_url
120
106
  ).call
121
107
  end
122
108
 
@@ -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|
@@ -4,18 +4,15 @@ module Extension
4
4
  class AskTemplate
5
5
  include ShopifyCLI::MethodObject
6
6
 
7
- TEMPLATE_REQUIRED_TYPES = [
8
- "checkout_ui_extension",
9
- ]
10
-
11
7
  property! :ctx
8
+ property :template, accepts: Models::ServerConfig::Development::VALID_TEMPLATES
12
9
  property :prompt,
13
10
  accepts: ->(prompt) { prompt.respond_to?(:call) },
14
11
  default: -> { CLI::UI::Prompt.method(:ask) }
15
12
 
16
13
  def call(project_details)
17
14
  return project_details unless template_required?(project_details)
18
- project_details.template = choose_interactively
15
+ project_details.template = template || choose_interactively
19
16
  project_details
20
17
  end
21
18
 
@@ -24,7 +21,7 @@ module Extension
24
21
  def template_required?(project_details)
25
22
  return false unless extension_server_beta?
26
23
  type = project_details&.type&.identifier
27
- TEMPLATE_REQUIRED_TYPES.include?(type.downcase)
24
+ Models::DevelopmentServerRequirements::SUPPORTED_EXTENSION_TYPES.include?(type.downcase)
28
25
  end
29
26
 
30
27
  def extension_server_beta?
@@ -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 " \
@@ -6,11 +6,10 @@ module Extension
6
6
  class DevelopmentServerRequirements
7
7
  SUPPORTED_EXTENSION_TYPES = [
8
8
  "checkout_ui_extension",
9
+ "checkout_post_purchase",
10
+ "product_subscription",
9
11
  ]
10
12
 
11
- UNIX_NAME = "shopify-extensions"
12
- WINDOWS_NAME = "shopify-extensions.exe"
13
-
14
13
  class << self
15
14
  def supported?(type)
16
15
  binary_installed? && type_supported?(type) && beta_enabled?
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Extension
4
+ module Models
5
+ module ServerConfig
6
+ class App < Base
7
+ include SmartProperties
8
+
9
+ property! :api_key, accepts: String
10
+ end
11
+ end
12
+ end
13
+ end
@@ -12,11 +12,12 @@ module Extension
12
12
 
13
13
  CURRENT_DIRECTORY = "."
14
14
 
15
- property :root_dir, accepts: String, default: CURRENT_DIRECTORY
15
+ property :root_dir, accepts: String, default: CURRENT_DIRECTORY
16
16
  property! :build_dir, accepts: String, default: "build"
17
- property :template, accepts: VALID_TEMPLATES
18
- property :renderer, accepts: ServerConfig::DevelopmentRenderer
19
- property :entries, accepts: ServerConfig::DevelopmentEntries
17
+ property :template, accepts: VALID_TEMPLATES
18
+ property :renderer, accepts: ServerConfig::DevelopmentRenderer
19
+ property :entries, accepts: ServerConfig::DevelopmentEntries
20
+ property :resource, accepts: ServerConfig::DevelopmentResource
20
21
  end
21
22
  end
22
23
  end
@@ -16,7 +16,7 @@ module Extension
16
16
 
17
17
  def self.find(type)
18
18
  case type.downcase
19
- when "admin_ui_extension"
19
+ when "product_subscription"
20
20
  new(name: "@shopify/admin-ui-extensions")
21
21
  when "checkout_ui_extension"
22
22
  new(name: "@shopify/checkout-ui-extensions")
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Extension
4
+ module Models
5
+ module ServerConfig
6
+ class DevelopmentResource < Base
7
+ include SmartProperties
8
+
9
+ property! :url, accepts: String
10
+ end
11
+ end
12
+ end
13
+ end
@@ -5,10 +5,14 @@ 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
14
+ property :version, accepts: String
15
+ property :title, accepts: String
12
16
 
13
17
  def self.build(uuid: "", template:, type:, root_dir:)
14
18
  renderer = ServerConfig::DevelopmentRenderer.find(type)
@@ -6,8 +6,11 @@ module Extension
6
6
  class Root < Base
7
7
  include SmartProperties
8
8
 
9
- property! :port, accepts: Integer, default: 39351
9
+ property :app, accepts: ServerConfig::App
10
10
  property! :extensions, accepts: Array, default: -> { [] }
11
+ property! :port, accepts: Integer, default: 39351
12
+ property :public_url, accepts: String
13
+ property :store, accepts: String
11
14
 
12
15
  def to_yaml
13
16
  to_h.to_yaml.gsub("---\n", "")
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ class ConvertServerConfig
7
+ include SmartProperties
8
+
9
+ property! :api_key, accepts: String
10
+ property! :context, accepts: ShopifyCLI::Context
11
+ property! :hash, accepts: Hash
12
+ property! :registration_uuid, accepts: String
13
+ property :resource_url, accepts: String
14
+ property! :store, accepts: String
15
+ property! :title, accepts: String
16
+ property :tunnel_url, accepts: String
17
+ property! :type, accepts: String
18
+
19
+ def self.call(*args)
20
+ new(*args).call
21
+ end
22
+
23
+ def call
24
+ context.abort(context.message("tasks.errors.parse_error")) if hash.nil?
25
+
26
+ renderer = Models::ServerConfig::DevelopmentRenderer.find(type)
27
+
28
+ extension = Models::ServerConfig::Extension.new(
29
+ uuid: registration_uuid,
30
+ type: type.upcase,
31
+ user: Models::ServerConfig::User.new,
32
+ development: Models::ServerConfig::Development.new(
33
+ build_dir: hash.dig("development", "build_dir"),
34
+ renderer: renderer,
35
+ entries: Models::ServerConfig::DevelopmentEntries.new(
36
+ main: hash.dig("development", "entries", "main")
37
+ )
38
+ ),
39
+ extension_points: hash.dig("extension_points"),
40
+ version: version(renderer.name, context),
41
+ title: title
42
+ )
43
+
44
+ unless resource_url.nil?
45
+ extension.development.resource = Models::ServerConfig::DevelopmentResource.new(url: resource_url)
46
+ end
47
+ server_config = Models::ServerConfig::Root.new(
48
+ extensions: [extension],
49
+ public_url: tunnel_url,
50
+ store: store
51
+ )
52
+
53
+ unless api_key.nil?
54
+ server_config.app = Models::ServerConfig::App.new(api_key: api_key)
55
+ end
56
+
57
+ server_config
58
+ end
59
+
60
+ def version(renderer, context)
61
+ Tasks::FindPackageFromJson.call(renderer, context: context).version
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+
4
+ module Extension
5
+ module Tasks
6
+ class EnsureResourceUrl < ShopifyCLI::Task
7
+ include SmartProperties
8
+
9
+ property! :context, accepts: ShopifyCLI::Context
10
+ property! :specification_handler, accepts: Extension::Models::SpecificationHandlers::Default
11
+
12
+ def self.call(*args)
13
+ new(*args).call
14
+ end
15
+
16
+ def call
17
+ project = ExtensionProject.current(force_reload: true)
18
+
19
+ ShopifyCLI::Result
20
+ .wrap(project.resource_url)
21
+ .rescue { specification_handler.build_resource_url(shop: project.env.shop, context: context) }
22
+ .then(&method(:persist_resource_url))
23
+ .unwrap do |nil_or_exception|
24
+ case nil_or_exception
25
+ when nil
26
+ context.warn(context.message("warnings.resource_url_auto_generation_failed", project.env.shop))
27
+ else
28
+ context.abort(nil_or_exception)
29
+ end
30
+ end
31
+ end
32
+
33
+ def persist_resource_url(resource_url)
34
+ ExtensionProject.update_env_file(context: context, resource_url: resource_url)
35
+ resource_url
36
+ end
37
+ end
38
+ end
39
+ end
@@ -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
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require "shopify_cli"
3
+ require "yaml"
4
+
5
+ module Extension
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
29
+ end
30
+ end
31
+ end
32
+ end