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
@@ -0,0 +1,155 @@
1
+ require "semantic/semantic"
2
+
3
+ module ShopifyCLI
4
+ module Services
5
+ module App
6
+ module Create
7
+ class NodeService < BaseService
8
+ attr_reader :context, :name, :organization_id, :store_domain, :type, :verbose
9
+
10
+ def initialize(name:, organization_id:, store_domain:, type:, verbose:, context:)
11
+ @name = name
12
+ @organization_id = organization_id
13
+ @store_domain = store_domain
14
+ @type = type
15
+ @verbose = verbose
16
+ @context = context
17
+ super()
18
+ end
19
+
20
+ def call
21
+ form = form_data({
22
+ name: name,
23
+ organization_id: organization_id,
24
+ shop_domain: store_domain,
25
+ type: type,
26
+ verbose: verbose,
27
+ })
28
+
29
+ raise ShopifyCLI::AbortSilent if form.nil?
30
+
31
+ check_node
32
+ check_npm
33
+ build(form.name)
34
+
35
+ ShopifyCLI::Project.write(
36
+ context,
37
+ project_type: "node",
38
+ organization_id: form.organization_id,
39
+ )
40
+
41
+ api_client = if ShopifyCLI::Environment.acceptance_test?
42
+ {
43
+ "apiKey" => "public_api_key",
44
+ "apiSecretKeys" => [
45
+ {
46
+ "secret" => "api_secret_key",
47
+ },
48
+ ],
49
+ }
50
+ else
51
+ ShopifyCLI::Tasks::CreateApiClient.call(
52
+ context,
53
+ org_id: form.organization_id,
54
+ title: form.name,
55
+ type: form.type,
56
+ )
57
+ end
58
+
59
+ ShopifyCLI::Resources::EnvFile.new(
60
+ api_key: api_client["apiKey"],
61
+ secret: api_client["apiSecretKeys"].first["secret"],
62
+ shop: form.shop_domain,
63
+ scopes: "write_products,write_customers,write_draft_orders",
64
+ ).write(context)
65
+
66
+ partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form.organization_id, api_client["id"])
67
+
68
+ context.puts(context.message("apps.create.info.created", form.name, partners_url))
69
+ context.puts(context.message("apps.create.info.serve", form.name, ShopifyCLI::TOOL_NAME))
70
+ unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
71
+ context.puts(context.message("apps.create.info.install", partners_url, form.name))
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def form_data(form_options)
78
+ if ShopifyCLI::Environment.acceptance_test?
79
+ Struct.new(:name, :organization_id, :type, :shop_domain, keyword_init: true).new(
80
+ name: form_options[:name],
81
+ organization_id: form_options[:organization_id] || "123",
82
+ shop_domain: form_options[:shop_domain] || "test.shopify.io",
83
+ type: form_options[:type] || "public",
84
+ )
85
+ else
86
+ Node::Forms::Create.ask(context, [], form_options)
87
+ end
88
+ end
89
+
90
+ def check_node
91
+ cmd_path = context.which("node")
92
+ context.abort(context.message("core.app.create.node.error.node_required")) if cmd_path.nil?
93
+
94
+ version, stat = context.capture2e("node", "-v")
95
+ unless stat.success?
96
+ context.abort(context.message("core.app.create.node.error.node_version_failure"))
97
+ end
98
+
99
+ context.done(context.message("core.app.create.node.node_version", version))
100
+ end
101
+
102
+ def check_npm
103
+ cmd_path = context.which("npm")
104
+ context.abort(context.message("core.app.create.node.error.npm_required")) if cmd_path.nil?
105
+
106
+ version, stat = context.capture2e("npm", "-v")
107
+ context.abort(context.message("core.app.create.node.error.npm_version_failure")) unless stat.success?
108
+
109
+ context.done(context.message("core.app.create.node.npm_version", version))
110
+ end
111
+
112
+ def set_npm_config
113
+ # check available npmrc (either user or system) for production registry
114
+ registry, _ = context.capture2("npm config get @shopify:registry")
115
+ return if registry.include?("https://registry.yarnpkg.com")
116
+
117
+ # available npmrc doesn't have production registry =>
118
+ # set a project-based .npmrc
119
+ context.system(
120
+ "npm",
121
+ "--userconfig",
122
+ "./.npmrc",
123
+ "config",
124
+ "set",
125
+ "@shopify:registry",
126
+ "https://registry.yarnpkg.com",
127
+ chdir: context.root
128
+ )
129
+ end
130
+
131
+ def build(name)
132
+ ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-node.git", name)
133
+
134
+ context.root = File.join(context.root, name)
135
+
136
+ set_npm_config
137
+ ShopifyCLI::JsDeps.install(context, verbose)
138
+
139
+ begin
140
+ context.rm_r(".git")
141
+ context.rm_r(".github")
142
+ context.rm(File.join("server", "handlers", "client.js"))
143
+ context.rename(
144
+ File.join("server", "handlers", "client.cli.js"),
145
+ File.join("server", "handlers", "client.js")
146
+ )
147
+ rescue Errno::ENOENT => e
148
+ context.debug(e)
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,152 @@
1
+ require "semantic/semantic"
2
+
3
+ module ShopifyCLI
4
+ module Services
5
+ module App
6
+ module Create
7
+ class PHPService < BaseService
8
+ attr_reader :name, :organization_id, :store_domain, :type, :verbose, :context
9
+
10
+ def initialize(name:, organization_id:, store_domain:, type:, verbose:, context:)
11
+ @name = name
12
+ @organization_id = organization_id
13
+ @store_domain = store_domain
14
+ @type = type
15
+ @verbose = verbose
16
+ @context = context
17
+ super()
18
+ end
19
+
20
+ def call
21
+ form = PHP::Forms::Create.ask(context, [], {
22
+ name: name,
23
+ organization_id: organization_id,
24
+ shop_domain: store_domain,
25
+ type: type,
26
+ verbose: verbose,
27
+ })
28
+ raise ShopifyCLI::AbortSilent if form.nil?
29
+
30
+ check_php
31
+ check_composer
32
+ check_npm
33
+ app_id = build(form)
34
+
35
+ ShopifyCLI::Project.write(
36
+ context,
37
+ project_type: "php",
38
+ organization_id: form.organization_id,
39
+ )
40
+
41
+ partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form.organization_id, app_id)
42
+
43
+ context.puts(context.message("apps.create.info.created", form.name, partners_url))
44
+ context.puts(context.message("apps.create.info.serve", form.name, ShopifyCLI::TOOL_NAME))
45
+ unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
46
+ context.puts(context.message("apps.create.info.install", partners_url, form.name))
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def check_php
53
+ cmd_path = context.which("php")
54
+ context.abort(context.message("core.app.create.php.error.php_required")) if cmd_path.nil?
55
+
56
+ version, stat = context.capture2e("php", "-r", "echo phpversion();")
57
+ context.abort(context.message("core.app.create.php.error.php_version_failure")) unless stat.success?
58
+
59
+ if ::Semantic::Version.new(version) < ::Semantic::Version.new("7.3.0")
60
+ context.abort(context.message("core.app.create.php.error.php_version_too_low", "7.3"))
61
+ end
62
+
63
+ context.done(context.message("core.app.create.php.php_version", version))
64
+ end
65
+
66
+ def check_composer
67
+ cmd_path = context.which("composer")
68
+ context.abort(context.message("core.app.create.php.error.composer_required")) if cmd_path.nil?
69
+ end
70
+
71
+ def check_npm
72
+ cmd_path = context.which("npm")
73
+ context.abort(context.message("core.app.create.php.error.npm_required")) if cmd_path.nil?
74
+
75
+ version, stat = context.capture2e("npm", "-v")
76
+ context.abort(context.message("core.app.create.php.error.npm_version_failure")) unless stat.success?
77
+
78
+ context.done(context.message("core.app.create.php.npm_version", version))
79
+ end
80
+
81
+ def build(form)
82
+ ShopifyCLI::Git.clone("https://github.com/Shopify/shopify-app-php.git", form.name)
83
+
84
+ context.root = File.join(context.root, form.name)
85
+ context.chdir(context.root)
86
+
87
+ api_client = ShopifyCLI::Tasks::CreateApiClient.call(
88
+ context,
89
+ org_id: form.organization_id,
90
+ title: form.name,
91
+ type: form.type,
92
+ )
93
+
94
+ # Override the example settings with our own
95
+ context.cp(".env.example", ".env")
96
+
97
+ env_file = ShopifyCLI::Resources::EnvFile.read
98
+ env_file.api_key = api_client["apiKey"]
99
+ env_file.secret = api_client["apiSecretKeys"].first["secret"]
100
+ env_file.shop = form.shop_domain
101
+ env_file.host = "localhost"
102
+ env_file.scopes = "write_products,write_draft_orders,write_customers"
103
+ env_file.extra["DB_DATABASE"] = File.join(context.root, env_file.extra["DB_DATABASE"])
104
+ env_file.write(context)
105
+
106
+ ShopifyCLI::PHPDeps.install(context, verbose)
107
+
108
+ set_npm_config
109
+ ShopifyCLI::JsDeps.install(context, verbose)
110
+
111
+ title = context.message("core.app.create.php.app_setting_up")
112
+ success = context.message("core.app.create.php.app_set_up")
113
+ failure = context.message("core.app.create.php.error.app_setup")
114
+ CLI::UI::Frame.open(title, success_text: success, failure_text: failure) do
115
+ FileUtils.touch(env_file.extra["DB_DATABASE"])
116
+ context.system("php", "artisan", "key:generate")
117
+ context.system("php", "artisan", "migrate")
118
+ end
119
+
120
+ begin
121
+ context.rm_r(".git")
122
+ context.rm_r(".github")
123
+ rescue Errno::ENOENT => e
124
+ context.debug(e)
125
+ end
126
+
127
+ api_client["id"]
128
+ end
129
+
130
+ def set_npm_config
131
+ # check available npmrc (either user or system) for production registry
132
+ registry, _ = context.capture2("npm config get @shopify:registry")
133
+ return if registry.include?("https://registry.yarnpkg.com")
134
+
135
+ # available npmrc doesn't have production registry =>
136
+ # set a project-based .npmrc
137
+ context.system(
138
+ "npm",
139
+ "--userconfig",
140
+ "./.npmrc",
141
+ "config",
142
+ "set",
143
+ "@shopify:registry",
144
+ "https://registry.yarnpkg.com",
145
+ chdir: context.root
146
+ )
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,215 @@
1
+ require "semantic/semantic"
2
+
3
+ module ShopifyCLI
4
+ module Services
5
+ module App
6
+ module Create
7
+ class RailsService < BaseService
8
+ USER_AGENT_CODE = <<~USERAGENT
9
+ module ShopifyAPI
10
+ class Base < ActiveResource::Base
11
+ self.headers['User-Agent'] << " | ShopifyApp/\#{ShopifyApp::VERSION} | Shopify CLI"
12
+ end
13
+ end
14
+ USERAGENT
15
+
16
+ DEFAULT_RAILS_FLAGS = %w(--skip-spring)
17
+
18
+ attr_reader :name, :organization_id, :store_domain, :type, :db, :rails_opts, :context
19
+
20
+ def initialize(name:, organization_id:, store_domain:, type:, db:, rails_opts:, context:)
21
+ @name = name
22
+ @organization_id = organization_id
23
+ @store_domain = store_domain
24
+ @type = type
25
+ @db = db
26
+ @rails_opts = rails_opts
27
+ @context = context
28
+ super()
29
+ end
30
+
31
+ def call
32
+ form_options = {
33
+ name: name,
34
+ organization_id: organization_id,
35
+ shop_domain: store_domain,
36
+ type: type,
37
+ }
38
+ form_options[:db] = db unless db.nil?
39
+ form_options[:rails_opts] = rails_opts unless rails_opts.nil?
40
+ form = form_data(form_options)
41
+
42
+ raise ShopifyCLI::AbortSilent if form.nil?
43
+
44
+ ruby_version = Rails::Ruby.version(context)
45
+ context.abort(context.message("core.app.create.rails.error.invalid_ruby_version")) unless
46
+ ruby_version.satisfies?("~>2.5") || ruby_version.satisfies?("~>3.0.0")
47
+
48
+ check_node
49
+ check_yarn
50
+
51
+ build(form.name, form.db)
52
+ set_custom_ua
53
+ ShopifyCLI::Project.write(
54
+ context,
55
+ project_type: "rails",
56
+ organization_id: form.organization_id,
57
+ )
58
+
59
+ api_client = if ShopifyCLI::Environment.acceptance_test?
60
+ {
61
+ "apiKey" => "public_api_key",
62
+ "apiSecretKeys" => [
63
+ {
64
+ "secret" => "api_secret_key",
65
+ },
66
+ ],
67
+ }
68
+ else
69
+ ShopifyCLI::Tasks::CreateApiClient.call(
70
+ context,
71
+ org_id: form.organization_id,
72
+ title: form.name,
73
+ type: form.type,
74
+ )
75
+ end
76
+
77
+ ShopifyCLI::Resources::EnvFile.new(
78
+ api_key: api_client["apiKey"],
79
+ secret: api_client["apiSecretKeys"].first["secret"],
80
+ shop: form.shop_domain,
81
+ scopes: "write_products,write_customers,write_draft_orders",
82
+ ).write(context)
83
+
84
+ partners_url = ShopifyCLI::PartnersAPI.partners_url_for(form.organization_id, api_client["id"])
85
+
86
+ context.puts(context.message("apps.create.info.created", form.name, partners_url))
87
+ context.puts(context.message("apps.create.info.serve", form.name, ShopifyCLI::TOOL_NAME))
88
+ unless ShopifyCLI::Shopifolk.acting_as_shopify_organization?
89
+ context.puts(context.message("apps.create.info.install", partners_url, form.name))
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def form_data(form_options)
96
+ if ShopifyCLI::Environment.acceptance_test?
97
+ Struct.new(:name, :organization_id, :type, :shop_domain, :db, keyword_init: true).new(
98
+ name: form_options[:name],
99
+ organization_id: "123",
100
+ shop_domain: "test.shopify.io",
101
+ type: "public",
102
+ db: form_options[:db]
103
+ )
104
+ else
105
+ Rails::Forms::Create.ask(context, [], form_options)
106
+ end
107
+ end
108
+
109
+ def check_node
110
+ cmd_path = context.which("node")
111
+ if cmd_path.nil?
112
+ context.abort(context.message("core.app.create.rails.error.node_required")) unless context.windows?
113
+ context.puts("{{x}} {{red:" + context.message("core.app.create.rails.error.node_required") + "}}")
114
+ context.puts(context.message("core.app.create.rails.info.open_new_shell", "node"))
115
+ raise ShopifyCLI::AbortSilent
116
+ end
117
+
118
+ version, stat = context.capture2e("node", "-v")
119
+ unless stat.success?
120
+ context.abort(context.message("core.app.create.rails.error.node_version_failure")) unless context.windows?
121
+ # execution stops above if not Windows
122
+ context.puts("{{x}} {{red:" + context.message("core.app.create.rails.error.node_version_failure") + "}}")
123
+ context.puts(context.message("core.app.create.rails.info.open_new_shell", "node"))
124
+ raise ShopifyCLI::AbortSilent
125
+ end
126
+
127
+ context.done(context.message("core.app.create.rails.node_version", version))
128
+ end
129
+
130
+ def check_yarn
131
+ cmd_path = context.which("yarn")
132
+ if cmd_path.nil?
133
+ context.abort(context.message("core.app.create.rails.error.yarn_required")) unless context.windows?
134
+ context.puts("{{x}} {{red:" + context.message("core.app.create.rails.error.yarn_required") + "}}")
135
+ context.puts(context.message("core.app.create.rails.info.open_new_shell", "yarn"))
136
+ raise ShopifyCLI::AbortSilent
137
+ end
138
+
139
+ version, stat = context.capture2e("yarn", "-v")
140
+ unless stat.success?
141
+ context.abort(context.message("core.app.create.rails.error.yarn_version_failure")) unless context.windows?
142
+ context.puts("{{x}} {{red:" + context.message("core.app.create.rails.error.yarn_version_failure") + "}}")
143
+ context.puts(context.message("core.app.create.rails.info.open_new_shell", "yarn"))
144
+ raise ShopifyCLI::AbortSilent
145
+ end
146
+
147
+ context.done(context.message("core.app.create.rails.yarn_version", version))
148
+ end
149
+
150
+ def build(name, db)
151
+ context.abort(context.message("core.app.create.rails.error.install_failure",
152
+ "rails")) unless install_gem("rails",
153
+ "<6.1")
154
+ context.abort(context.message("core.app.create.rails.error.install_failure", "bundler ~>2.0")) unless
155
+ install_gem("bundler", "~>2.0")
156
+
157
+ full_path = File.join(context.root, name)
158
+ context.abort(context.message("core.app.create.rails.error.dir_exists", name)) if Dir.exist?(full_path)
159
+
160
+ CLI::UI::Frame.open(context.message("core.app.create.rails.generating_app", name)) do
161
+ new_command = %w(rails new)
162
+ new_command += DEFAULT_RAILS_FLAGS
163
+ new_command << "--database=#{db}"
164
+ new_command += rails_opts.split unless rails_opts.nil?
165
+ new_command << name
166
+
167
+ syscall(new_command)
168
+ end
169
+
170
+ context.root = full_path
171
+
172
+ File.open(File.join(context.root, ".gitignore"), "a") { |f| f.write(".env") }
173
+
174
+ context.puts(context.message("core.app.create.rails.adding_shopify_gem"))
175
+ File.open(File.join(context.root, "Gemfile"), "a") do |f|
176
+ f.puts "\ngem 'shopify_app', '>=17.0.3'"
177
+ end
178
+ CLI::UI::Frame.open(context.message("core.app.create.rails.running_bundle_install")) do
179
+ syscall(%w(bundle install))
180
+ end
181
+
182
+ CLI::UI::Frame.open(context.message("core.app.create.rails.running_generator")) do
183
+ syscall(%w(rails generate shopify_app --new-shopify-cli-app))
184
+ end
185
+
186
+ CLI::UI::Frame.open(context.message("core.app.create.rails.running_migrations")) do
187
+ syscall(%w(rails db:create))
188
+ syscall(%w(rails db:migrate RAILS_ENV=development))
189
+ end
190
+
191
+ unless File.exist?(File.join(context.root, "config/webpacker.yml"))
192
+ CLI::UI::Frame.open(context.message("core.app.create.rails.running_webpacker_install")) do
193
+ syscall(%w(rails webpacker:install))
194
+ end
195
+ end
196
+ end
197
+
198
+ def set_custom_ua
199
+ ua_path = File.join("config", "initializers", "user_agent.rb")
200
+ context.write(ua_path, USER_AGENT_CODE)
201
+ end
202
+
203
+ def syscall(args)
204
+ args[0] = Rails::Gem.binary_path_for(context, args[0])
205
+ context.system(*args, chdir: context.root)
206
+ end
207
+
208
+ def install_gem(name, version = nil)
209
+ Rails::Gem.install(context, name, version)
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,101 @@
1
+ module ShopifyCLI
2
+ module Services
3
+ module App
4
+ module Deploy
5
+ module Heroku
6
+ class NodeService < BaseService
7
+ attr_reader :context
8
+
9
+ def initialize(context:)
10
+ @context = context
11
+ super()
12
+ end
13
+
14
+ def call
15
+ spin_group = CLI::UI::SpinGroup.new
16
+ heroku_service = ShopifyCLI::Heroku.new(context)
17
+
18
+ spin_group.add(context.message("core.app.deploy.heroku.downloading")) do |spinner|
19
+ heroku_service.download
20
+ spinner.update_title(context.message("core.app.deploy.heroku.downloaded"))
21
+ end
22
+ spin_group.wait
23
+
24
+ install_message = context.message(
25
+ context.windows? ? "core.app.deploy.heroku.installing_windows" : "core.app.deploy.heroku.installing"
26
+ )
27
+ spin_group.add(install_message) do |spinner|
28
+ heroku_service.install
29
+ spinner.update_title(context.message("core.app.deploy.heroku.installed"))
30
+ end
31
+ spin_group.wait
32
+
33
+ spin_group.add(context.message("core.app.deploy.heroku.git.checking")) do |spinner|
34
+ ShopifyCLI::Git.init(context)
35
+ spinner.update_title(context.message("core.app.deploy.heroku.git.initialized"))
36
+ end
37
+ spin_group.wait
38
+
39
+ if (account = heroku_service.whoami)
40
+ context.puts(context.message("core.app.deploy.heroku.authenticated_with_account", account))
41
+ else
42
+ CLI::UI::Frame.open(
43
+ context.message("core.app.deploy.heroku.authenticating"),
44
+ success_text: context.message("core.app.deploy.heroku.authenticated")
45
+ ) do
46
+ heroku_service.authenticate
47
+ end
48
+ end
49
+
50
+ if (app_name = heroku_service.app)
51
+ context.puts(context.message("core.app.deploy.heroku.app.selected", app_name))
52
+ else
53
+ app_type = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.no_apps_found")) do |handler|
54
+ handler.option(context.message("core.app.deploy.heroku.app.create")) { :new }
55
+ handler.option(context.message("core.app.deploy.heroku.app.select")) { :existing }
56
+ end
57
+
58
+ if app_type == :existing
59
+ app_name = CLI::UI::Prompt.ask(context.message("core.app.deploy.heroku.app.name"))
60
+ CLI::UI::Frame.open(
61
+ context.message("core.app.deploy.heroku.app.selecting", app_name),
62
+ success_text: context.message("core.app.deploy.heroku.app.selected", app_name)
63
+ ) do
64
+ heroku_service.select_existing_app(app_name)
65
+ end
66
+ elsif app_type == :new
67
+ CLI::UI::Frame.open(
68
+ context.message("core.app.deploy.heroku.app.creating"),
69
+ success_text: context.message("core.app.deploy.heroku.app.created")
70
+ ) do
71
+ heroku_service.create_new_app
72
+ end
73
+ end
74
+ end
75
+
76
+ branches = ShopifyCLI::Git.branches(context)
77
+ if branches.length == 1
78
+ branch_to_deploy = branches[0]
79
+ context.puts(context.message("core.app.deploy.heroku.git.branch_selected", branch_to_deploy))
80
+ else
81
+ prompt_question = context.message("core.app.deploy.heroku.git.what_branch")
82
+ branch_to_deploy = CLI::UI::Prompt.ask(prompt_question) do |handler|
83
+ branches.each do |branch|
84
+ handler.option(branch) { branch }
85
+ end
86
+ end
87
+ end
88
+
89
+ CLI::UI::Frame.open(
90
+ context.message("core.app.deploy.heroku.deploying"),
91
+ success_text: context.message("core.app.deploy.heroku.deployed")
92
+ ) do
93
+ heroku_service.deploy(branch_to_deploy)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end