shopify-cli 1.3.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +2 -2
  3. data/.github/CONTRIBUTING.md +9 -1
  4. data/.github/PULL_REQUEST_TEMPLATE.md +10 -1
  5. data/.github/workflows/release.yml +61 -0
  6. data/.github/workflows/triage.yml +22 -0
  7. data/.gitignore +0 -1
  8. data/.rubocop.yml +61 -8
  9. data/.rubocop_todo.yml +11 -0
  10. data/.travis.yml +1 -0
  11. data/CHANGELOG.md +30 -0
  12. data/Gemfile +3 -2
  13. data/Gemfile.lock +39 -37
  14. data/README.md +39 -7
  15. data/RELEASING.md +19 -29
  16. data/Rakefile +2 -0
  17. data/dev.yml +2 -2
  18. data/docs/_config.yml +1 -18
  19. data/docs/app/node/commands/index.md +2 -80
  20. data/docs/app/node/index.md +2 -33
  21. data/docs/app/rails/commands/index.md +2 -78
  22. data/docs/app/rails/index.md +2 -34
  23. data/docs/core/index.md +2 -84
  24. data/docs/getting-started/index.md +2 -25
  25. data/docs/getting-started/install/index.md +1 -118
  26. data/docs/getting-started/migrate/index.md +2 -94
  27. data/docs/getting-started/uninstall/index.md +2 -35
  28. data/docs/getting-started/upgrade/index.md +2 -39
  29. data/docs/help/start-app/index.md +2 -4
  30. data/docs/index.md +2 -24
  31. data/install.sh +1 -1
  32. data/lib/project_types/extension/cli.rb +21 -11
  33. data/lib/project_types/extension/commands/extension_command.rb +2 -2
  34. data/lib/project_types/extension/features/argo.rb +117 -0
  35. data/lib/project_types/extension/forms/create.rb +2 -2
  36. data/lib/project_types/extension/models/specification.rb +35 -0
  37. data/lib/project_types/extension/models/specification_handlers/checkout_post_purchase.rb +19 -0
  38. data/lib/project_types/extension/models/specification_handlers/default.rb +67 -0
  39. data/lib/project_types/extension/models/specifications.rb +77 -0
  40. data/lib/project_types/extension/tasks/configure_features.rb +52 -0
  41. data/lib/project_types/extension/tasks/fetch_specifications.rb +38 -0
  42. data/lib/project_types/node/cli.rb +4 -1
  43. data/lib/project_types/node/commands/connect.rb +15 -0
  44. data/lib/project_types/node/commands/create.rb +10 -4
  45. data/lib/project_types/node/commands/generate.rb +2 -11
  46. data/lib/project_types/node/messages/messages.rb +16 -50
  47. data/lib/project_types/rails/cli.rb +4 -1
  48. data/lib/project_types/rails/commands/connect.rb +15 -0
  49. data/lib/project_types/rails/commands/create.rb +15 -12
  50. data/lib/project_types/rails/forms/create.rb +1 -1
  51. data/lib/project_types/rails/gem.rb +1 -1
  52. data/lib/project_types/rails/messages/messages.rb +8 -5
  53. data/lib/project_types/script/cli.rb +9 -5
  54. data/lib/project_types/script/commands/create.rb +6 -4
  55. data/lib/project_types/script/commands/enable.rb +12 -4
  56. data/lib/project_types/script/commands/push.rb +5 -13
  57. data/lib/project_types/script/config/extension_points.yml +17 -12
  58. data/lib/project_types/script/errors.rb +21 -0
  59. data/lib/project_types/script/forms/create.rb +26 -2
  60. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +10 -1
  61. data/lib/project_types/script/layers/application/build_script.rb +18 -17
  62. data/lib/project_types/script/layers/application/create_script.rb +12 -10
  63. data/lib/project_types/script/layers/application/extension_points.rb +24 -0
  64. data/lib/project_types/script/layers/application/push_script.rb +18 -16
  65. data/lib/project_types/script/layers/domain/errors.rb +7 -0
  66. data/lib/project_types/script/layers/domain/extension_point.rb +62 -7
  67. data/lib/project_types/script/layers/domain/metadata.rb +55 -0
  68. data/lib/project_types/script/layers/domain/push_package.rb +25 -6
  69. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +17 -52
  70. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +42 -11
  71. data/lib/project_types/script/layers/infrastructure/errors.rb +16 -0
  72. data/lib/project_types/script/layers/infrastructure/extension_point_repository.rb +10 -4
  73. data/lib/project_types/script/layers/infrastructure/project_creator.rb +2 -1
  74. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +25 -13
  75. data/lib/project_types/script/layers/infrastructure/rust_project_creator.rb +72 -0
  76. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +59 -0
  77. data/lib/project_types/script/layers/infrastructure/script_service.rb +9 -1
  78. data/lib/project_types/script/layers/infrastructure/task_runner.rb +4 -3
  79. data/lib/project_types/script/messages/messages.rb +55 -4
  80. data/lib/project_types/script/script_project.rb +25 -16
  81. data/lib/project_types/script/ui/error_handler.rb +59 -1
  82. data/lib/project_types/theme/cli.rb +40 -0
  83. data/lib/project_types/theme/commands/connect.rb +54 -0
  84. data/lib/project_types/theme/commands/create.rb +48 -0
  85. data/lib/project_types/theme/commands/deploy.rb +38 -0
  86. data/lib/project_types/theme/commands/generate.rb +20 -0
  87. data/lib/project_types/theme/commands/generate/env.rb +79 -0
  88. data/lib/project_types/theme/commands/push.rb +55 -0
  89. data/lib/project_types/theme/commands/serve.rb +31 -0
  90. data/lib/project_types/theme/forms/connect.rb +34 -0
  91. data/lib/project_types/theme/forms/create.rb +22 -0
  92. data/lib/project_types/theme/messages/messages.rb +147 -0
  93. data/lib/project_types/theme/tasks/ensure_themekit_installed.rb +78 -0
  94. data/lib/project_types/theme/themekit.rb +113 -0
  95. data/lib/shopify-cli/admin_api.rb +42 -2
  96. data/lib/shopify-cli/api.rb +34 -33
  97. data/lib/shopify-cli/commands/config.rb +24 -0
  98. data/lib/shopify-cli/commands/connect.rb +32 -15
  99. data/lib/shopify-cli/commands/system.rb +10 -1
  100. data/lib/shopify-cli/context.rb +23 -2
  101. data/lib/shopify-cli/core/entry_point.rb +1 -1
  102. data/lib/shopify-cli/core/monorail.rb +6 -4
  103. data/lib/shopify-cli/feature.rb +0 -2
  104. data/lib/shopify-cli/http_request.rb +27 -0
  105. data/lib/shopify-cli/js_deps.rb +1 -1
  106. data/lib/shopify-cli/messages/messages.rb +31 -7
  107. data/lib/shopify-cli/method_object.rb +104 -0
  108. data/lib/shopify-cli/partners_api.rb +25 -3
  109. data/lib/shopify-cli/process_supervision.rb +1 -1
  110. data/lib/shopify-cli/project.rb +12 -8
  111. data/lib/shopify-cli/project_type.rb +18 -2
  112. data/lib/shopify-cli/resolve_constant.rb +25 -0
  113. data/lib/shopify-cli/result.rb +432 -0
  114. data/lib/shopify-cli/shopifolk.rb +87 -0
  115. data/lib/shopify-cli/task.rb +8 -0
  116. data/lib/shopify-cli/tasks/create_api_client.rb +13 -2
  117. data/lib/shopify-cli/tasks/ensure_env.rb +3 -0
  118. data/lib/shopify-cli/tasks/select_org_and_shop.rb +10 -5
  119. data/lib/shopify-cli/tunnel.rb +8 -2
  120. data/lib/shopify-cli/version.rb +1 -1
  121. data/lib/shopify_cli.rb +5 -1
  122. data/shopify.fish +1 -1
  123. data/shopify.sh +1 -1
  124. data/vendor/deps/cli-kit/REVISION +1 -1
  125. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +2 -2
  126. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +3 -3
  127. data/vendor/deps/cli-ui/REVISION +1 -1
  128. data/vendor/deps/cli-ui/lib/cli/ui.rb +26 -22
  129. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +4 -6
  130. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -3
  131. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +8 -9
  132. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -1
  133. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +1 -0
  134. data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +15 -3
  135. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +4 -11
  136. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -5
  137. data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +10 -10
  138. data/vendor/deps/cli-ui/lib/cli/ui/version.rb +1 -1
  139. data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +56 -0
  140. data/vendor/deps/webrick/.gitignore +9 -0
  141. data/vendor/deps/webrick/Gemfile +3 -0
  142. data/vendor/deps/webrick/LICENSE.txt +22 -0
  143. data/vendor/deps/webrick/README.md +61 -0
  144. data/vendor/deps/webrick/Rakefile +10 -0
  145. data/vendor/deps/webrick/lib/webrick.rb +232 -0
  146. data/vendor/deps/webrick/lib/webrick/accesslog.rb +157 -0
  147. data/vendor/deps/webrick/lib/webrick/cgi.rb +313 -0
  148. data/vendor/deps/webrick/lib/webrick/compat.rb +36 -0
  149. data/vendor/deps/webrick/lib/webrick/config.rb +158 -0
  150. data/vendor/deps/webrick/lib/webrick/cookie.rb +172 -0
  151. data/vendor/deps/webrick/lib/webrick/htmlutils.rb +30 -0
  152. data/vendor/deps/webrick/lib/webrick/httpauth.rb +96 -0
  153. data/vendor/deps/webrick/lib/webrick/httpauth/authenticator.rb +117 -0
  154. data/vendor/deps/webrick/lib/webrick/httpauth/basicauth.rb +116 -0
  155. data/vendor/deps/webrick/lib/webrick/httpauth/digestauth.rb +395 -0
  156. data/vendor/deps/webrick/lib/webrick/httpauth/htdigest.rb +132 -0
  157. data/vendor/deps/webrick/lib/webrick/httpauth/htgroup.rb +97 -0
  158. data/vendor/deps/webrick/lib/webrick/httpauth/htpasswd.rb +158 -0
  159. data/vendor/deps/webrick/lib/webrick/httpauth/userdb.rb +53 -0
  160. data/vendor/deps/webrick/lib/webrick/httpproxy.rb +354 -0
  161. data/vendor/deps/webrick/lib/webrick/httprequest.rb +636 -0
  162. data/vendor/deps/webrick/lib/webrick/httpresponse.rb +564 -0
  163. data/vendor/deps/webrick/lib/webrick/https.rb +152 -0
  164. data/vendor/deps/webrick/lib/webrick/httpserver.rb +294 -0
  165. data/vendor/deps/webrick/lib/webrick/httpservlet.rb +23 -0
  166. data/vendor/deps/webrick/lib/webrick/httpservlet/abstract.rb +152 -0
  167. data/vendor/deps/webrick/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  168. data/vendor/deps/webrick/lib/webrick/httpservlet/cgihandler.rb +126 -0
  169. data/vendor/deps/webrick/lib/webrick/httpservlet/erbhandler.rb +88 -0
  170. data/vendor/deps/webrick/lib/webrick/httpservlet/filehandler.rb +552 -0
  171. data/vendor/deps/webrick/lib/webrick/httpservlet/prochandler.rb +47 -0
  172. data/vendor/deps/webrick/lib/webrick/httpstatus.rb +194 -0
  173. data/vendor/deps/webrick/lib/webrick/httputils.rb +512 -0
  174. data/vendor/deps/webrick/lib/webrick/httpversion.rb +76 -0
  175. data/vendor/deps/webrick/lib/webrick/log.rb +156 -0
  176. data/vendor/deps/webrick/lib/webrick/server.rb +381 -0
  177. data/vendor/deps/webrick/lib/webrick/ssl.rb +215 -0
  178. data/vendor/deps/webrick/lib/webrick/utils.rb +265 -0
  179. data/vendor/deps/webrick/lib/webrick/version.rb +18 -0
  180. data/vendor/deps/webrick/webrick.gemspec +74 -0
  181. metadata +77 -27
  182. data/docs/Gemfile +0 -5
  183. data/docs/Gemfile.lock +0 -258
  184. data/docs/_data/nav.yml +0 -35
  185. data/docs/_includes/footer.html +0 -15
  186. data/docs/_includes/head.html +0 -19
  187. data/docs/_includes/sidebar_nav.html +0 -22
  188. data/docs/_includes/toc.html +0 -112
  189. data/docs/_layouts/default.html +0 -79
  190. data/docs/css/docs.css +0 -157
  191. data/docs/images/header.png +0 -0
  192. data/docs/installing-ruby.md +0 -28
  193. data/lib/project_types/extension/features/argo/admin.rb +0 -20
  194. data/lib/project_types/extension/features/argo/base.rb +0 -129
  195. data/lib/project_types/extension/features/argo/checkout.rb +0 -20
  196. data/lib/project_types/extension/models/type.rb +0 -81
  197. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +0 -23
  198. data/lib/project_types/extension/models/types/product_subscription.rb +0 -24
  199. data/lib/project_types/node/commands/generate/billing.rb +0 -39
  200. data/lib/project_types/node/commands/generate/page.rb +0 -59
  201. data/lib/project_types/node/commands/generate/webhook.rb +0 -37
  202. data/lib/project_types/script/layers/domain/script.rb +0 -18
  203. data/lib/project_types/script/layers/infrastructure/assemblyscript_tsconfig.rb +0 -38
  204. data/lib/project_types/script/layers/infrastructure/script_repository.rb +0 -59
  205. data/lib/project_types/script/templates/ts/as-pect.config.js +0 -27
  206. data/lib/project_types/script/templates/ts/as-pect.d.ts +0 -1
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ class Project < ShopifyCli::ProjectType
4
+ hidden_feature
5
+
6
+ title('Theme')
7
+ creator('Theme::Commands::Create')
8
+ connector('Theme::Commands::Connect')
9
+
10
+ register_command('Theme::Commands::Deploy', 'deploy')
11
+ register_command('Theme::Commands::Generate', 'generate')
12
+ register_command('Theme::Commands::Push', 'push')
13
+ register_command('Theme::Commands::Serve', 'serve')
14
+
15
+ register_task('Theme::Tasks::EnsureThemekitInstalled', :ensure_themekit_installed)
16
+
17
+ require Project.project_filepath('messages/messages')
18
+ register_messages(Theme::Messages::MESSAGES)
19
+ end
20
+
21
+ module Commands
22
+ autoload :Connect, Project.project_filepath('commands/connect')
23
+ autoload :Create, Project.project_filepath('commands/create')
24
+ autoload :Deploy, Project.project_filepath('commands/deploy')
25
+ autoload :Generate, Project.project_filepath('commands/generate')
26
+ autoload :Push, Project.project_filepath('commands/push')
27
+ autoload :Serve, Project.project_filepath('commands/serve')
28
+ end
29
+
30
+ module Tasks
31
+ autoload :EnsureThemekitInstalled, Project.project_filepath('tasks/ensure_themekit_installed')
32
+ end
33
+
34
+ module Forms
35
+ autoload :Create, Project.project_filepath('forms/create')
36
+ autoload :Connect, Project.project_filepath('forms/connect')
37
+ end
38
+
39
+ autoload :Themekit, Project.project_filepath('themekit')
40
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Commands
4
+ class Connect < ShopifyCli::SubCommand
5
+ prerequisite_task :ensure_themekit_installed
6
+
7
+ options do |parser, flags|
8
+ parser.on('--store=STORE') { |url| flags[:store] = url }
9
+ parser.on('--password=PASSWORD') { |p| flags[:password] = p }
10
+ parser.on('--themeid=THEME_ID') { |id| flags[:themeid] = id }
11
+ parser.on('--env=ENV') { |env| flags[:env] = env }
12
+ end
13
+
14
+ def call(args, _name)
15
+ if ShopifyCli::Project.has_current?
16
+ @ctx.abort(@ctx.message('theme.connect.inside_project'))
17
+ end
18
+
19
+ form = Forms::Connect.ask(@ctx, args, options.flags)
20
+ return @ctx.puts(self.class.help) if form.nil?
21
+
22
+ build(form.store, form.password, form.themeid, form.name, form.env)
23
+ ShopifyCli::Project.write(@ctx,
24
+ project_type: 'theme',
25
+ organization_id: nil)
26
+
27
+ @ctx.done(@ctx.message('theme.connect.connected', form.name, form.store, @ctx.root))
28
+ end
29
+
30
+ def self.help
31
+ ShopifyCli::Context.message('theme.connect.help', ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
32
+ end
33
+
34
+ private
35
+
36
+ def build(store, password, themeid, name, env)
37
+ if @ctx.dir_exist?(name)
38
+ @ctx.abort(@ctx.message('theme.connect.duplicate'))
39
+ end
40
+
41
+ @ctx.mkdir_p(name)
42
+ @ctx.chdir(name)
43
+
44
+ CLI::UI::Frame.open(@ctx.message('theme.connect.connect')) do
45
+ unless Themekit.connect(@ctx, store: store, password: password, themeid: themeid, env: env)
46
+ @ctx.chdir('..')
47
+ @ctx.rm_rf(name)
48
+ @ctx.abort(@ctx.message('theme.connect.failed'))
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Commands
4
+ class Create < ShopifyCli::SubCommand
5
+ prerequisite_task :ensure_themekit_installed
6
+
7
+ options do |parser, flags|
8
+ parser.on('--name=NAME') { |t| flags[:title] = t }
9
+ parser.on('--password=PASSWORD') { |p| flags[:password] = p }
10
+ parser.on('--store=STORE') { |url| flags[:store] = url }
11
+ parser.on('--env=ENV') { |env| flags[:env] = env }
12
+ end
13
+
14
+ def call(args, _name)
15
+ form = Forms::Create.ask(@ctx, args, options.flags)
16
+ return @ctx.puts(self.class.help) if form.nil?
17
+
18
+ build(form.name, form.password, form.store, form.env)
19
+ ShopifyCli::Project.write(@ctx,
20
+ project_type: 'theme',
21
+ organization_id: nil) # private apps are different
22
+
23
+ @ctx.done(@ctx.message('theme.create.info.created', form.name, form.store, @ctx.root))
24
+ end
25
+
26
+ def self.help
27
+ ShopifyCli::Context.message('theme.create.help', ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
28
+ end
29
+
30
+ private
31
+
32
+ def build(name, password, store, env)
33
+ @ctx.abort(@ctx.message('theme.create.duplicate_theme')) if @ctx.dir_exist?(name)
34
+
35
+ @ctx.mkdir_p(name)
36
+ @ctx.chdir(name)
37
+
38
+ CLI::UI::Frame.open(@ctx.message('theme.create.creating_theme', name)) do
39
+ unless Themekit.create(@ctx, name: name, password: password, store: store, env: env)
40
+ @ctx.chdir('..')
41
+ @ctx.rm_rf(name)
42
+ @ctx.abort(@ctx.message('theme.create.failed'))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Commands
4
+ class Deploy < ShopifyCli::Command
5
+ prerequisite_task :ensure_themekit_installed
6
+
7
+ options do |parser, flags|
8
+ parser.on('--env=ENV') { |env| flags[:env] = env }
9
+ parser.on('--allow-live') { flags['allow_live'] = true }
10
+ end
11
+
12
+ def call(*)
13
+ CLI::UI::Frame.open(@ctx.message('theme.deploy.deploying')) do
14
+ unless CLI::UI::Prompt.confirm(@ctx.message('theme.deploy.confirmation'))
15
+ @ctx.abort(@ctx.message('theme.deploy.abort'))
16
+ end
17
+
18
+ if options.flags[:env]
19
+ env = options.flags[:env]
20
+ options.flags.delete(:env)
21
+ end
22
+
23
+ flags = Themekit.add_flags(options.flags)
24
+
25
+ unless Themekit.deploy(@ctx, flags: flags, env: env)
26
+ @ctx.abort(@ctx.message('theme.deploy.error'))
27
+ end
28
+ end
29
+
30
+ @ctx.done(@ctx.message('theme.deploy.info.deployed'))
31
+ end
32
+
33
+ def self.help
34
+ ShopifyCli::Context.message('theme.deploy.help', ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'shopify_cli'
3
+
4
+ module Theme
5
+ module Commands
6
+ class Generate < ShopifyCli::Command
7
+ prerequisite_task :ensure_themekit_installed
8
+
9
+ subcommand :Env, 'env', Project.project_filepath('commands/generate/env')
10
+
11
+ def call(*)
12
+ @ctx.puts(self.class.help)
13
+ end
14
+
15
+ def self.help
16
+ ShopifyCli::Context.message('theme.generate.help', ShopifyCli::TOOL_NAME)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,79 @@
1
+ module Theme
2
+ module Commands
3
+ class Generate
4
+ class Env < ShopifyCli::SubCommand
5
+ options do |parser, flags|
6
+ parser.on('--store=STORE') { |url| flags[:store] = url }
7
+ parser.on('--password=PASSWORD') { |p| flags[:password] = p }
8
+ parser.on('--themeid=THEME_ID') { |id| flags[:themeid] = id }
9
+ parser.on('--env=ENV') { |env| flags[:env] = env }
10
+ end
11
+
12
+ def call(*)
13
+ default_store, default_password = fetch_credentials
14
+ store = ask_store(default_store) || default_store
15
+ password = ask_password(default_password) || default_password
16
+ themeid = ask_theme(store: store, password: password)
17
+ env = options.flags[:env]
18
+
19
+ Themekit.generate_env(@ctx, store: store, password: password, themeid: themeid, env: env)
20
+ end
21
+
22
+ def self.help
23
+ ShopifyCli::Context.message('theme.generate.env.help', ShopifyCli::TOOL_NAME)
24
+ end
25
+
26
+ private
27
+
28
+ def fetch_credentials
29
+ unless File.exist?('config.yml')
30
+ return nil
31
+ end
32
+
33
+ config = YAML.load_file('config.yml')
34
+ store = config['development']['store']
35
+ password = config['development']['password']
36
+
37
+ [store, password]
38
+ end
39
+
40
+ def ask_store(default)
41
+ store = options.flags[:store] ||
42
+ if default
43
+ CLI::UI::Prompt.ask(@ctx.message('theme.generate.env.ask_store_default', default))
44
+ else
45
+ CLI::UI::Prompt.ask(@ctx.message('theme.generate.env.ask_store'), allow_empty: false)
46
+ end
47
+ return nil if store.empty?
48
+ store
49
+ end
50
+
51
+ def ask_password(default)
52
+ password = options.flags[:password] ||
53
+ if default
54
+ CLI::UI::Prompt.ask(@ctx.message('theme.generate.env.ask_password_default', default))
55
+ else
56
+ CLI::UI::Prompt.ask(@ctx.message('theme.generate.env.ask_password'), allow_empty: false)
57
+ end
58
+ return nil if password.empty?
59
+ password
60
+ end
61
+
62
+ def ask_theme(store:, password:)
63
+ theme = options.flags[:themeid]
64
+ return theme if theme
65
+
66
+ themes = Themekit.query_themes(@ctx, store: store, password: password)
67
+
68
+ @ctx.abort(@ctx.message('theme.generate.env.no_themes', ShopifyCli::TOOL_NAME)) if themes.empty?
69
+
70
+ CLI::UI::Prompt.ask(@ctx.message('theme.generate.env.ask_theme')) do |handler|
71
+ themes.each do |name, id|
72
+ handler.option(name) { id }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Commands
4
+ class Push < ShopifyCli::Command
5
+ prerequisite_task :ensure_themekit_installed
6
+
7
+ options do |parser, flags|
8
+ parser.on('--remove') { flags['remove'] = true }
9
+ parser.on('--nodelete') { flags['nodelete'] = true }
10
+ parser.on('--allow-live') { flags['allow-live'] = true }
11
+ parser.on('--env=ENV') { |env| flags[:env] = env }
12
+ end
13
+
14
+ def call(args, _name)
15
+ if options.flags['remove']
16
+ remove = true
17
+ options.flags.delete('remove')
18
+ end
19
+
20
+ if options.flags[:env]
21
+ env = options.flags[:env]
22
+ options.flags.delete(:env)
23
+ end
24
+
25
+ flags = Themekit.add_flags(options.flags)
26
+
27
+ if remove
28
+ CLI::UI::Frame.open(@ctx.message('theme.push.remove')) do
29
+ unless CLI::UI::Prompt.confirm(@ctx.message('theme.push.remove_confirm'))
30
+ @ctx.abort(@ctx.message('theme.push.remove_abort'))
31
+ end
32
+
33
+ unless Themekit.push(@ctx, files: args, flags: flags, remove: remove, env: env)
34
+ @ctx.abort(@ctx.message('theme.push.error.remove_error'))
35
+ end
36
+ end
37
+
38
+ @ctx.done(@ctx.message('theme.push.info.remove', @ctx.root))
39
+ else
40
+ CLI::UI::Frame.open(@ctx.message('theme.push.push')) do
41
+ unless Themekit.push(@ctx, files: args, flags: flags, remove: remove, env: env)
42
+ @ctx.abort(@ctx.message('theme.push.error.push_error'))
43
+ end
44
+ end
45
+
46
+ @ctx.done(@ctx.message('theme.push.info.push', @ctx.root))
47
+ end
48
+ end
49
+
50
+ def self.help
51
+ ShopifyCli::Context.message('theme.push.help', ShopifyCli::TOOL_NAME, ShopifyCli::TOOL_NAME)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Commands
4
+ class Serve < ShopifyCli::Command
5
+ prerequisite_task :ensure_themekit_installed
6
+
7
+ options do |parser, flags|
8
+ parser.on('--env=ENV') { |env| flags[:env] = env }
9
+ parser.on('--allow-live') { flags['allow-live'] = true }
10
+ parser.on('--notify=FILES') { |files| flags['notify'] = files }
11
+ end
12
+
13
+ def call(*)
14
+ if options.flags[:env]
15
+ env = options.flags[:env]
16
+ options.flags.delete(:env)
17
+ end
18
+
19
+ flags = Themekit.add_flags(options.flags)
20
+
21
+ CLI::UI::Frame.open(@ctx.message('theme.serve.serve')) do
22
+ Themekit.serve(@ctx, flags: flags, env: env)
23
+ end
24
+ end
25
+
26
+ def self.help
27
+ ShopifyCli::Context.message('theme.serve.help', ShopifyCli::TOOL_NAME)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ module Theme
2
+ module Forms
3
+ class Connect < ShopifyCli::Form
4
+ attr_accessor :name
5
+ flag_arguments :themeid, :password, :store, :env
6
+
7
+ def ask
8
+ self.store ||= CLI::UI::Prompt.ask(ctx.message('theme.forms.ask_store'), allow_empty: false)
9
+ ctx.puts(ctx.message('theme.forms.connect.private_app', store))
10
+ self.password ||= CLI::UI::Prompt.ask(ctx.message('theme.forms.ask_password'), allow_empty: false)
11
+
12
+ errors = []
13
+ errors << "store" if store.strip.empty?
14
+ errors << "password" if password.strip.empty?
15
+ ctx.abort(ctx.message('theme.forms.errors', errors.join(", ").capitalize)) unless errors.empty?
16
+
17
+ self.themeid, self.name = ask_theme(store: store, password: password, themeid: themeid)
18
+ end
19
+
20
+ private
21
+
22
+ def ask_theme(store:, password:, themeid:)
23
+ themes = Themekit.query_themes(@ctx, store: store, password: password)
24
+
25
+ themeid ||= CLI::UI::Prompt.ask("Select theme") do |handler|
26
+ themes.each do |name, id|
27
+ handler.option(name) { id }
28
+ end
29
+ end
30
+ [themeid, themes.key(themeid.to_i)]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ module Theme
2
+ module Forms
3
+ class Create < ShopifyCli::Form
4
+ attr_accessor :name
5
+ flag_arguments :title, :password, :store, :env
6
+
7
+ def ask
8
+ self.store ||= CLI::UI::Prompt.ask(ctx.message('theme.forms.ask_store'), allow_empty: false)
9
+ ctx.puts(ctx.message('theme.forms.create.private_app', store))
10
+ self.password ||= CLI::UI::Prompt.ask(ctx.message('theme.forms.ask_password'), allow_empty: false)
11
+ self.title ||= CLI::UI::Prompt.ask(ctx.message('theme.forms.create.ask_title'), allow_empty: false)
12
+ self.name = self.title.downcase.split(" ").join("_")
13
+
14
+ errors = []
15
+ errors << "store" if store.strip.empty?
16
+ errors << "password" if password.strip.empty?
17
+ errors << "title" if title.strip.empty?
18
+ ctx.abort(ctx.message('theme.forms.errors', errors.join(", ").capitalize)) unless errors.empty?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+ module Theme
3
+ module Messages
4
+ MESSAGES = {
5
+ theme: {
6
+ connect: {
7
+ duplicate: "Duplicate directory, theme files weren't connected",
8
+ help: <<~HELP,
9
+ {{command:%s connect theme}}: Connects an existing theme in your store to Shopify App CLI. Downloads a copy of the theme files to your local development environment.
10
+ Usage: {{command:%s connect theme}}
11
+ Options:
12
+ {{command:--store=MYSHOPIFYDOMAIN}} Store URL. Must be an existing store with private apps enabled.
13
+ {{command:--password=PASSWORD}} Private app password. App must have Read and Write Theme access.
14
+ {{command:--themeid=THEMEID}} Theme ID. Must be an existing theme on your store.
15
+ HELP
16
+ inside_project: "You are inside an existing theme, theme files weren't connected",
17
+ connect: "Downloading theme files...",
18
+ failed: "Couldn't download theme files from store",
19
+ connected: "{{green:%s}} files were downloaded from {{underline:%s}} to {{green:%s}}",
20
+ },
21
+ create: {
22
+ creating_theme: "Creating theme %s",
23
+ duplicate_theme: "Duplicate theme",
24
+ failed: "Couldn't create the theme",
25
+ help: <<~HELP,
26
+ {{command:%s create theme}}: Creates a theme.
27
+ Usage: {{command:%s create theme}}
28
+ Options:
29
+ {{command:--store=MYSHOPIFYDOMAIN}} Store URL. Must be an existing store with private apps enabled.
30
+ {{command:--password=PASSWORD}} Private app password. App must have Read and Write Theme access.
31
+ {{command:--name=NAME}} Theme name. Any string.
32
+ HELP
33
+ info: {
34
+ created: "{{green:%s}} was created for {{underline:%s}} in {{green:%s}}",
35
+ },
36
+ },
37
+ deploy: {
38
+ abort: "Theme wasn't deployed",
39
+ confirmation: "This will change your live theme. Do you wish to proceed?",
40
+ deploying: "Deploying theme",
41
+ error: "Theme couldn't be deployed",
42
+ help: <<~HELP,
43
+ {{command:%s deploy}}: Uploads your local theme files to Shopify, then sets your theme as the live theme.
44
+ Usage: {{command:%s deploy}}
45
+ HELP
46
+ info: {
47
+ deployed: "Theme was updated and set as the live theme",
48
+ pushed: "All theme files were updated",
49
+ },
50
+ push_fail: "Theme files couldn't be updated",
51
+ },
52
+ forms: {
53
+ ask_password: "Password:",
54
+ ask_store: "Store domain:",
55
+ create: {
56
+ ask_title: "Title:",
57
+ private_app: <<~APP,
58
+ To create a new theme, Shopify App CLI needs to connect with a private app installed on your store. Visit {{underline:%s/admin/apps/private}} to create a new API key and password, or retrieve an existing password.
59
+ If you create a new private app, ensure that it has Read and Write Theme access.
60
+ APP
61
+ },
62
+ connect: {
63
+ private_app: <<~APP,
64
+ To fetch your existing themes, Shopify App CLI needs to connect with your store. Visit {{underline:%s/admin/apps/private}} to create a new API key and password, or retrieve an existing password.
65
+ If you create a new private app, ensure that it has Read and Write Theme access.
66
+ APP
67
+ },
68
+ errors: "%s can't be blank",
69
+ },
70
+ generate: {
71
+ env: {
72
+ ask_password: "Password",
73
+ ask_password_default: "Password (defaults to {{green:%s}})",
74
+ ask_store: "Store",
75
+ ask_store_default: "Store (defaults to {{green:%s}})",
76
+ ask_theme: "Select theme",
77
+ help: <<~HELP,
78
+ Create or update configuration file in the current directory.
79
+ Usage: {{command:%s generate env}}
80
+ Options:
81
+ {{command:--store=MYSHOPIFYDOMAIN}} Store URL. Must be an existing store with private apps enabled.
82
+ {{command:--password=PASSWORD}} Private app password. App must have Read and Write Theme access.
83
+ {{command:--themeid=THEMEID}} Theme ID. Must be an existing theme on your store.
84
+ HELP
85
+ no_themes: "Please create a new theme using %s create theme",
86
+ },
87
+ help: <<~HELP,
88
+ Generate code in your Theme. Currently supports generating new envs.
89
+ Usage: {{command:%s generate [ env ]}}
90
+ HELP
91
+ },
92
+ push: {
93
+ remove_abort: "Theme files weren't deleted",
94
+ remove_confirm: "This will delete the local and remote copies of the theme files. Do you wish to proceed?",
95
+ error: {
96
+ push_error: "Theme files couldn't be pushed to Shopify",
97
+ remove_error: "Theme files couldn't be removed from Shopify",
98
+ },
99
+ help: <<~HELP,
100
+ {{command:%s push}}: Uploads your local theme files to Shopify, overwriting the remote versions. If you specify filenames, separated by a space, only those files will be replaced. Otherwise, the whole theme will be replaced.
101
+ Usage: {{command:%s push}}
102
+ Options:
103
+ {{command:--remove}} Deletes both the local and the remote copies of the specified files. At least one filename must be specified.
104
+ {{command:--allow-live}} Allows Shopify App CLI to replace files on the store's live production theme.
105
+ {{command:--nodelete}} Runs the push command without deleting remote files from Shopify.
106
+ HELP
107
+ info: {
108
+ push: "Theme files were pushed from {{green:%s}} to Shopify",
109
+ remove: "Theme files were deleted from {{green:%s}} and Shopify",
110
+ },
111
+ push: "Pushing theme files to Shopify",
112
+ remove: "Deleting theme files",
113
+ },
114
+ serve: {
115
+ help: <<~HELP,
116
+ Sync your current changes, then view the active store in your default browser. Any theme edits will continue to update in real time. Also prints the active store's URL in your terminal.
117
+ Usage: {{command:%s serve}}
118
+ HELP
119
+ serve: "Viewing theme...",
120
+ open_fail: "Couldn't open the theme",
121
+ },
122
+ tasks: {
123
+ ensure_themekit_installed: {
124
+ auto_update: "Would you like to enable auto-updating?",
125
+ downloading: "Downloading Theme Kit %s",
126
+ errors: {
127
+ digest_fail: "Unable to verify download",
128
+ releases_fail: "Unable to fetch Theme Kit's list of releases",
129
+ update_fail: "Unable to update Theme Kit",
130
+ write_fail: "Unable to download Theme Kit",
131
+ },
132
+ installing_themekit: "Installing Theme Kit",
133
+ successful: "Theme Kit installed successfully",
134
+ updating_themekit: "Updating Theme Kit",
135
+ verifying: "Verifying download...",
136
+ },
137
+ },
138
+ themekit: {
139
+ query_themes: {
140
+ bad_password: "Bad password",
141
+ not_connect: "Couldn't connect to given shop",
142
+ },
143
+ },
144
+ },
145
+ }.freeze
146
+ end
147
+ end