shopify-cli 1.0.2 → 1.1.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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -2
  3. data/CHANGELOG.md +20 -0
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +13 -13
  6. data/bin/load_shopify.rb +3 -1
  7. data/bin/shopify +2 -0
  8. data/docs/Gemfile.lock +23 -13
  9. data/docs/getting-started/index.md +3 -2
  10. data/docs/getting-started/install/index.md +55 -9
  11. data/docs/getting-started/uninstall/index.md +1 -1
  12. data/docs/getting-started/upgrade/index.md +8 -4
  13. data/ext/shopify-cli/extconf.rb +40 -20
  14. data/lib/project_types/extension/cli.rb +1 -1
  15. data/lib/project_types/extension/commands/build.rb +1 -1
  16. data/lib/project_types/extension/models/type.rb +1 -0
  17. data/lib/project_types/extension/tasks/create_extension.rb +1 -1
  18. data/lib/project_types/extension/tasks/get_app.rb +1 -1
  19. data/lib/project_types/extension/tasks/update_draft.rb +1 -1
  20. data/lib/project_types/node/commands/create.rb +4 -4
  21. data/lib/project_types/node/commands/deploy/heroku.rb +6 -1
  22. data/lib/project_types/node/commands/generate/billing.rb +7 -5
  23. data/lib/project_types/node/commands/generate/page.rb +9 -5
  24. data/lib/project_types/node/commands/generate/webhook.rb +5 -1
  25. data/lib/project_types/node/messages/messages.rb +1 -0
  26. data/lib/project_types/rails/cli.rb +0 -1
  27. data/lib/project_types/rails/commands/create.rb +52 -4
  28. data/lib/project_types/rails/commands/generate.rb +1 -0
  29. data/lib/project_types/rails/commands/generate/webhook.rb +3 -2
  30. data/lib/project_types/rails/commands/serve.rb +6 -2
  31. data/lib/project_types/rails/gem.rb +61 -6
  32. data/lib/project_types/rails/messages/messages.rb +27 -11
  33. data/lib/project_types/script/cli.rb +2 -3
  34. data/lib/project_types/script/commands/create.rb +5 -9
  35. data/lib/project_types/script/commands/disable.rb +4 -15
  36. data/lib/project_types/script/commands/enable.rb +37 -13
  37. data/lib/project_types/script/commands/push.rb +8 -13
  38. data/lib/project_types/script/config/extension_points.yml +9 -3
  39. data/lib/project_types/script/errors.rb +8 -0
  40. data/lib/project_types/script/forms/create.rb +1 -1
  41. data/lib/project_types/script/layers/application/create_script.rb +7 -6
  42. data/lib/project_types/script/layers/application/disable_script.rb +9 -7
  43. data/lib/project_types/script/layers/application/enable_script.rb +11 -9
  44. data/lib/project_types/script/layers/application/push_script.rb +6 -4
  45. data/lib/project_types/script/layers/domain/errors.rb +2 -0
  46. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +2 -2
  47. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +1 -1
  48. data/lib/project_types/script/layers/infrastructure/errors.rb +2 -0
  49. data/lib/project_types/script/layers/infrastructure/script_service.rb +8 -2
  50. data/lib/project_types/script/messages/messages.rb +25 -31
  51. data/lib/project_types/script/script_project.rb +6 -2
  52. data/lib/project_types/script/templates/ts/as-pect.config.js +6 -0
  53. data/lib/project_types/script/ui/error_handler.rb +8 -0
  54. data/lib/project_types/script/ui/printing_spinner.rb +75 -0
  55. data/lib/rubygems_plugin.rb +18 -10
  56. data/lib/shopify-cli/admin_api/populate_resource_command.rb +1 -1
  57. data/lib/shopify-cli/admin_api/schema.rb +20 -18
  58. data/lib/shopify-cli/command.rb +14 -11
  59. data/lib/shopify-cli/commands.rb +1 -0
  60. data/lib/shopify-cli/commands/config.rb +44 -0
  61. data/lib/shopify-cli/commands/connect.rb +8 -69
  62. data/lib/shopify-cli/commands/create.rb +2 -2
  63. data/lib/shopify-cli/commands/help.rb +1 -1
  64. data/lib/shopify-cli/commands/system.rb +22 -13
  65. data/lib/shopify-cli/context.rb +28 -0
  66. data/lib/shopify-cli/core.rb +0 -1
  67. data/lib/shopify-cli/core/entry_point.rb +1 -1
  68. data/lib/shopify-cli/core/executor.rb +3 -5
  69. data/lib/shopify-cli/core/monorail.rb +1 -1
  70. data/lib/shopify-cli/db.rb +1 -1
  71. data/lib/shopify-cli/feature.rb +97 -0
  72. data/lib/shopify-cli/heroku.rb +21 -5
  73. data/lib/shopify-cli/js_deps.rb +2 -2
  74. data/lib/shopify-cli/js_system.rb +2 -2
  75. data/lib/shopify-cli/messages/messages.rb +40 -12
  76. data/lib/shopify-cli/partners_api/organizations.rb +7 -7
  77. data/lib/shopify-cli/process_supervision.rb +60 -21
  78. data/lib/shopify-cli/project.rb +14 -6
  79. data/lib/shopify-cli/project_type.rb +5 -7
  80. data/lib/shopify-cli/sub_command.rb +1 -0
  81. data/lib/shopify-cli/task.rb +2 -2
  82. data/lib/shopify-cli/tasks.rb +11 -4
  83. data/lib/shopify-cli/tasks/ensure_env.rb +72 -16
  84. data/lib/shopify-cli/tasks/update_dashboard_urls.rb +4 -3
  85. data/lib/shopify-cli/tunnel.rb +53 -14
  86. data/lib/shopify-cli/version.rb +1 -1
  87. data/lib/shopify_cli.rb +36 -9
  88. data/shopify-cli.gemspec +4 -1
  89. data/vendor/deps/cli-kit/REVISION +1 -1
  90. data/vendor/deps/cli-kit/lib/cli/kit.rb +1 -1
  91. data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +2 -2
  92. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +12 -6
  93. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +9 -11
  94. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +8 -2
  95. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +7 -7
  96. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +48 -17
  97. data/vendor/deps/cli-ui/REVISION +1 -1
  98. data/vendor/deps/cli-ui/lib/cli/ui.rb +5 -4
  99. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +9 -3
  100. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +1 -0
  101. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -2
  102. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -0
  103. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +13 -5
  104. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +29 -2
  105. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +21 -10
  106. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
  107. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +11 -2
  108. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +1 -0
  109. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -3
  110. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +6 -8
  111. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +2 -0
  112. data/vendor/gen/lib/gen.rb +39 -0
  113. data/vendor/gen/lib/gen/commands.rb +18 -0
  114. data/vendor/gen/lib/gen/commands/help.rb +20 -0
  115. data/vendor/gen/lib/gen/commands/new.rb +21 -0
  116. data/vendor/gen/lib/gen/entry_point.rb +10 -0
  117. data/vendor/gen/lib/gen/generator.rb +165 -0
  118. data/vendor/gen/template/.gitignore +2 -0
  119. data/vendor/gen/template/Gemfile +10 -0
  120. data/vendor/gen/template/README.md +1 -0
  121. data/vendor/gen/template/bin/testunit +23 -0
  122. data/vendor/gen/template/bin/update-deps +97 -0
  123. data/vendor/gen/template/dev-gems.yml +3 -0
  124. data/vendor/gen/template/dev-vendor.yml +4 -0
  125. data/vendor/gen/template/exe/__app__-gems +17 -0
  126. data/vendor/gen/template/exe/__app__-vendor +18 -0
  127. data/vendor/gen/template/lib/__app__.rb +33 -0
  128. data/vendor/gen/template/lib/__app__/commands.rb +18 -0
  129. data/vendor/gen/template/lib/__app__/commands/example.rb +19 -0
  130. data/vendor/gen/template/lib/__app__/commands/help.rb +21 -0
  131. data/vendor/gen/template/lib/__app__/entry_point.rb +10 -0
  132. data/vendor/gen/template/test/example_test.rb +17 -0
  133. data/vendor/gen/template/test/test_helper.rb +22 -0
  134. metadata +28 -6
  135. data/Vagrantfile +0 -17
  136. data/lib/project_types/script/forms/enable.rb +0 -24
  137. data/lib/project_types/script/forms/push.rb +0 -19
  138. data/lib/project_types/script/forms/script_form.rb +0 -66
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Extension
4
4
  class Project < ShopifyCli::ProjectType
5
- hidden_project_type
5
+ hidden_feature
6
6
  creator 'App Extension', 'Extension::Commands::Create'
7
7
 
8
8
  register_command('Extension::Commands::Build', "build")
@@ -4,7 +4,7 @@ require 'shopify_cli'
4
4
  module Extension
5
5
  module Commands
6
6
  class Build < ExtensionCommand
7
- hidden_command
7
+ hidden_feature
8
8
 
9
9
  YARN_BUILD_COMMAND = %w(build)
10
10
  NPM_BUILD_COMMAND = %w(run-script build)
@@ -12,6 +12,7 @@ module Extension
12
12
  end
13
13
 
14
14
  def inherited(klass)
15
+ super
15
16
  @all_extension_types ||= []
16
17
  @all_extension_types << klass
17
18
  end
@@ -20,7 +20,7 @@ module Extension
20
20
  extension_context: extension_context,
21
21
  }
22
22
 
23
- response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, input).dig(*RESPONSE_FIELD)
23
+ response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, **input).dig(*RESPONSE_FIELD)
24
24
  context.abort(context.message('tasks.errors.parse_error')) if response.nil?
25
25
 
26
26
  abort_if_user_errors(context, response)
@@ -12,7 +12,7 @@ module Extension
12
12
  def call(context:, api_key:)
13
13
  input = { api_key: api_key }
14
14
 
15
- response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, input).dig(*RESPONSE_FIELD)
15
+ response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, **input).dig(*RESPONSE_FIELD)
16
16
  context.abort(context.message('tasks.errors.parse_error')) if response.nil?
17
17
 
18
18
  Converters::AppConverter.from_hash(response.dig(APP_FIELD))
@@ -18,7 +18,7 @@ module Extension
18
18
  config: JSON.generate(config),
19
19
  extension_context: extension_context,
20
20
  }
21
- response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, input).dig(*RESPONSE_FIELD)
21
+ response = ShopifyCli::PartnersAPI.query(context, GRAPHQL_FILE, **input).dig(*RESPONSE_FIELD)
22
22
  context.abort(context.message('tasks.errors.parse_error')) if response.nil?
23
23
 
24
24
  abort_if_user_errors(context, response)
@@ -54,8 +54,8 @@ module Node
54
54
  private
55
55
 
56
56
  def check_node
57
- _, stat = @ctx.capture2e('which', 'node')
58
- @ctx.abort(@ctx.message('node.create.error.node_required')) unless stat.success?
57
+ cmd_path = @ctx.which('node')
58
+ @ctx.abort(@ctx.message('node.create.error.node_required')) if cmd_path.nil?
59
59
 
60
60
  version, stat = @ctx.capture2e('node', '-v')
61
61
  @ctx.abort(@ctx.message('node.create.error.node_version_failure')) unless stat.success?
@@ -64,8 +64,8 @@ module Node
64
64
  end
65
65
 
66
66
  def check_npm
67
- _, stat = @ctx.capture2e('which', 'npm')
68
- @ctx.abort(@ctx.message('node.create.error.npm_required')) unless stat.success?
67
+ cmd_path = @ctx.which('npm')
68
+ @ctx.abort(@ctx.message('node.create.error.npm_required')) if cmd_path.nil?
69
69
 
70
70
  version, stat = @ctx.capture2e('npm', '-v')
71
71
  @ctx.abort(@ctx.message('node.create.error.npm_version_failure')) unless stat.success?
@@ -19,10 +19,15 @@ module Node
19
19
  end
20
20
  spin_group.wait
21
21
 
22
- spin_group.add(@ctx.message('node.deploy.heroku.installing')) do |spinner|
22
+ install_message = @ctx.message(
23
+ @ctx.windows? ? 'node.deploy.heroku.installing_windows' : 'node.deploy.heroku.installing'
24
+ )
25
+ spin_group.add(install_message) do |spinner|
23
26
  heroku_service.install
24
27
  spinner.update_title(@ctx.message('node.deploy.heroku.installed'))
25
28
  end
29
+ spin_group.wait
30
+
26
31
  spin_group.add(@ctx.message('node.deploy.heroku.git.checking')) do |spinner|
27
32
  ShopifyCli::Git.init(@ctx)
28
33
  spinner.update_title(@ctx.message('node.deploy.heroku.git.initialized'))
@@ -5,8 +5,8 @@ module Node
5
5
  class Generate
6
6
  class Billing < ShopifyCli::SubCommand
7
7
  BILLING_TYPES = {
8
- 'recurring-billing' => './node_modules/.bin/generate-node-app recurring-billing',
9
- 'one-time-billing' => './node_modules/.bin/generate-node-app one-time-billing',
8
+ 'recurring-billing' => ['./node_modules/.bin/generate-node-app', 'recurring-billing'],
9
+ 'one-time-billing' => ['./node_modules/.bin/generate-node-app', 'one-time-billing'],
10
10
  }
11
11
  def call(args, _name)
12
12
  selected_type = BILLING_TYPES[args[1]]
@@ -18,11 +18,13 @@ module Node
18
18
  end
19
19
  end
20
20
  billing_type_name = BILLING_TYPES.key(selected_type)
21
+ selected_type[0] = File.join(ShopifyCli::Project.current.directory, selected_type[0])
22
+ selected_type[0] = "\"#{selected_type[0]}\""
23
+ selected_type = selected_type.join(' ')
24
+
21
25
  spin_group = CLI::UI::SpinGroup.new
22
26
  spin_group.add(@ctx.message('node.generate.billing.generating', billing_type_name)) do |spinner|
23
- Node::Commands::Generate.run_generate(
24
- selected_type, billing_type_name, @ctx
25
- )
27
+ Node::Commands::Generate.run_generate(selected_type, billing_type_name, @ctx)
26
28
  spinner.update_title(@ctx.message('node.generate.billing.generated', billing_type_name))
27
29
  end
28
30
  spin_group.wait
@@ -5,10 +5,10 @@ module Node
5
5
  class Generate
6
6
  class Page < ShopifyCli::SubCommand
7
7
  PAGE_TYPES = {
8
- 'empty-state' => './node_modules/.bin/generate-node-app empty-state-page',
9
- 'two-column' => './node_modules/.bin/generate-node-app two-column-page',
10
- 'annotated' => './node_modules/.bin/generate-node-app settings-page',
11
- 'list' => './node_modules/.bin/generate-node-app list-page',
8
+ 'empty-state' => ['./node_modules/.bin/generate-node-app', 'empty-state-page'],
9
+ 'two-column' => ['./node_modules/.bin/generate-node-app', 'two-column-page'],
10
+ 'annotated' => ['./node_modules/.bin/generate-node-app', 'settings-page'],
11
+ 'list' => ['./node_modules/.bin/generate-node-app', 'list-page'],
12
12
  }
13
13
 
14
14
  options do |parser, flags|
@@ -37,9 +37,13 @@ module Node
37
37
  end
38
38
  end
39
39
  end
40
+ page_type_name = PAGE_TYPES.key(selected_type)
41
+ selected_type[0] = File.join(ShopifyCli::Project.current.directory, selected_type[0])
42
+ selected_type[0] = "\"#{selected_type[0]}\""
43
+ selected_type = selected_type.join(' ')
40
44
 
41
45
  spin_group = CLI::UI::SpinGroup.new
42
- spin_group.add(@ctx.message('node.generate.page.generating', selected_type)) do |spinner|
46
+ spin_group.add(@ctx.message('node.generate.page.generating', page_type_name)) do |spinner|
43
47
  Node::Commands::Generate.run_generate("#{selected_type} #{name}", name, @ctx)
44
48
  spinner.update_title(@ctx.message('node.generate.page.generated', name, name))
45
49
  end
@@ -15,9 +15,13 @@ module Node
15
15
  end
16
16
  end
17
17
  end
18
+
19
+ generate_path = File.join(ShopifyCli::Project.current.directory, "node_modules/.bin/generate-node-app")
20
+ generate_path = "\"#{generate_path}\""
21
+
18
22
  spin_group = CLI::UI::SpinGroup.new
19
23
  spin_group.add(@ctx.message('node.generate.webhook.generating', selected_type)) do |spinner|
20
- Node::Commands::Generate.run_generate("./node_modules/.bin/generate-node-app webhook #{selected_type}",
24
+ Node::Commands::Generate.run_generate("#{generate_path} webhook #{selected_type}",
21
25
  selected_type, @ctx)
22
26
  spinner.update_title(@ctx.message('node.generate.webhook.generated', selected_type))
23
27
  end
@@ -54,6 +54,7 @@ module Node
54
54
  downloading: "Downloading Heroku CLI…",
55
55
  downloaded: "Downloaded Heroku CLI",
56
56
  installing: "Installing Heroku CLI…",
57
+ installing_windows: "Running Heroku CLI install wizard…",
57
58
  installed: "Installed Heroku CLI",
58
59
  authenticating: "Authenticating with Heroku…",
59
60
  authenticated: "{{v}} Authenticated with Heroku",
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Rails
3
3
  class Project < ShopifyCli::ProjectType
4
- # hidden_project_type
5
4
  creator 'Ruby on Rails App', 'Rails::Commands::Create'
6
5
 
7
6
  register_command('Rails::Commands::Deploy', "deploy")
@@ -30,6 +30,9 @@ module Rails
30
30
  @ctx.abort(@ctx.message('rails.create.error.invalid_ruby_version')) unless
31
31
  Ruby.version(@ctx).satisfies?('~>2.5')
32
32
 
33
+ check_node
34
+ check_yarn
35
+
33
36
  build(form.name, form.db)
34
37
  set_custom_ua
35
38
  ShopifyCli::Project.write(
@@ -65,12 +68,51 @@ module Rails
65
68
 
66
69
  private
67
70
 
71
+ def check_node
72
+ cmd_path = @ctx.which('node')
73
+ if cmd_path.nil?
74
+ @ctx.abort(@ctx.message('rails.create.error.node_required')) unless @ctx.windows?
75
+ @ctx.puts("{{x}} {{red:" + @ctx.message('rails.create.error.node_required') + "}}")
76
+ @ctx.puts(@ctx.message('rails.create.info.open_new_shell', 'node'))
77
+ raise ShopifyCli::AbortSilent
78
+ end
79
+
80
+ version, stat = @ctx.capture2e('node', '-v')
81
+ unless stat.success?
82
+ @ctx.abort(@ctx.message('rails.create.error.node_version_failure')) unless @ctx.windows?
83
+ # execution stops above if not Windows
84
+ @ctx.puts("{{x}} {{red:" + @ctx.message('rails.create.error.node_version_failure') + "}}")
85
+ @ctx.puts(@ctx.message('rails.create.info.open_new_shell', 'node'))
86
+ raise ShopifyCli::AbortSilent
87
+ end
88
+
89
+ @ctx.done(@ctx.message('rails.create.node_version', version))
90
+ end
91
+
92
+ def check_yarn
93
+ cmd_path = @ctx.which('yarn')
94
+ if cmd_path.nil?
95
+ @ctx.abort(@ctx.message('rails.create.error.yarn_required')) unless @ctx.windows?
96
+ @ctx.puts("{{x}} {{red:" + @ctx.message('rails.create.error.yarn_required') + "}}")
97
+ @ctx.puts(@ctx.message('rails.create.info.open_new_shell', 'yarn'))
98
+ raise ShopifyCli::AbortSilent
99
+ end
100
+
101
+ version, stat = @ctx.capture2e('yarn', '-v')
102
+ unless stat.success?
103
+ @ctx.abort(@ctx.message('rails.create.error.yarn_version_failure')) unless @ctx.windows?
104
+ @ctx.puts("{{x}} {{red:" + @ctx.message('rails.create.error.yarn_version_failure') + "}}")
105
+ @ctx.puts(@ctx.message('rails.create.info.open_new_shell', 'yarn'))
106
+ raise ShopifyCli::AbortSilent
107
+ end
108
+
109
+ @ctx.done(@ctx.message('rails.create.yarn_version', version))
110
+ end
111
+
68
112
  def build(name, db)
69
- install_gem('rails')
70
- CLI::UI::Frame.open(@ctx.message('rails.create.installing_bundler')) do
71
- install_gem('bundler', '~>1.0')
113
+ @ctx.abort(@ctx.message('rails.create.error.install_failure', 'rails')) unless install_gem('rails')
114
+ @ctx.abort(@ctx.message('rails.create.error.install_failure', 'bundler ~>2.0')) unless
72
115
  install_gem('bundler', '~>2.0')
73
- end
74
116
 
75
117
  CLI::UI::Frame.open(@ctx.message('rails.create.generating_app', name)) do
76
118
  new_command = %w(rails new)
@@ -106,6 +148,12 @@ module Rails
106
148
  syscall(%w(rails db:create))
107
149
  syscall(%w(rails db:migrate RAILS_ENV=development))
108
150
  end
151
+
152
+ unless File.exist?(File.join(@ctx.root, 'config/webpacker.yml'))
153
+ CLI::UI::Frame.open(@ctx.message('rails.create.running_webpacker_install')) do
154
+ syscall(%w(rails webpacker:install))
155
+ end
156
+ end
109
157
  end
110
158
 
111
159
  def set_custom_ua
@@ -28,6 +28,7 @@ module Rails
28
28
  end
29
29
 
30
30
  def self.run_generate(script, name, ctx)
31
+ Gem.gem_path(ctx)
31
32
  stat = ctx.system(script)
32
33
  unless stat.success?
33
34
  ctx.abort(response(stat.exitstatus, name, ctx))
@@ -29,9 +29,10 @@ module Rails
29
29
 
30
30
  def generate_command(selected_type)
31
31
  parts = selected_type.downcase.split("_")
32
- env = ShopifyCli::Project.current.env.host
32
+ host = ShopifyCli::Project.current.env.host
33
33
  selected_type = parts[0..-2].join("_") + "/" + parts[-1]
34
- "rails g shopify_app:add_webhook -t #{selected_type} -a #{env}/webhooks/#{selected_type.downcase}"
34
+ command = @ctx.windows? ? "ruby bin\\rails" : "bin/rails"
35
+ "#{command} g shopify_app:add_webhook -t #{selected_type} -a #{host}/webhooks/#{selected_type.downcase}"
35
36
  end
36
37
  end
37
38
  end
@@ -26,12 +26,16 @@ module Rails
26
26
  @ctx.open_url!("#{project.env.host}/login?shop=#{project.env.shop}")
27
27
  end
28
28
  end
29
- Gem.gem_home(@ctx)
30
29
  CLI::UI::Frame.open(@ctx.message('rails.serve.running_server')) do
31
30
  env = ShopifyCli::Project.current.env.to_h
32
31
  env.delete('HOST')
33
32
  env['PORT'] = ShopifyCli::Tunnel::PORT.to_s
34
- @ctx.system('bin/rails server', env: env)
33
+ env['GEM_PATH'] = Gem.gem_path(@ctx)
34
+ if @ctx.windows?
35
+ @ctx.system("ruby bin\\rails server", env: env)
36
+ else
37
+ @ctx.system('bin/rails server', env: env)
38
+ end
35
39
  end
36
40
  end
37
41
 
@@ -15,30 +15,65 @@ module Rails
15
15
  version = args.shift
16
16
  gem = new(ctx: ctx, name: name, version: version)
17
17
  ctx.debug(ctx.message('rails.gem.installed_debug', name, gem.installed?))
18
- gem.install! unless gem.installed?
18
+ gem.installed? ? true : gem.install!
19
19
  end
20
20
 
21
21
  def binary_path_for(ctx, binary)
22
- File.join(gem_home(ctx), 'bin', binary)
22
+ path_to_binary = File.join(gem_home(ctx), 'bin', binary)
23
+ File.exist?(path_to_binary) ? path_to_binary : binary
23
24
  end
24
25
 
25
26
  def gem_home(ctx)
26
27
  ctx.getenv('GEM_HOME') || apply_gem_home(ctx)
27
28
  end
28
29
 
30
+ def gem_path(ctx)
31
+ ctx.getenv('GEM_PATH') || apply_gem_path(ctx)
32
+ end
33
+
29
34
  private
30
35
 
31
36
  def apply_gem_home(ctx)
32
- path = File.join(ctx.getenv('HOME'), '.gem', 'ruby', RUBY_VERSION)
37
+ path = ''
38
+ # extract GEM_HOME from `gem environment home` command
39
+ out, stat = ctx.capture2e('gem', 'environment', 'home')
40
+ path = out&.empty? ? '' : out.strip if stat.success?
41
+ # fallback if return from `gem environment home` is empty (somewhat unlikely)
42
+ path = fallback_gem_home_path(ctx) if path.empty?
43
+ # fallback if path isn't writable (if using a system installed ruby)
44
+ path = fallback_gem_home_path(ctx) unless File.writable?(path)
33
45
  ctx.mkdir_p(path) unless Dir.exist?(path)
46
+ ctx.debug(ctx.message('rails.gem.setting_gem_home', path))
34
47
  ctx.setenv('GEM_HOME', path)
35
48
  end
49
+
50
+ def apply_gem_path(ctx)
51
+ path = ''
52
+ out, stat = ctx.capture2e('gem', 'environment', 'path')
53
+ path = out&.empty? ? '' : out.strip if stat.success?
54
+ # usually GEM_PATH already contains GEM_HOME
55
+ # if gem_home() falls back to our fallback path, we need to add it
56
+ path = gem_home(ctx) + File::PATH_SEPARATOR + path unless path.include?(gem_home(ctx))
57
+ ctx.debug(ctx.message('rails.gem.setting_gem_path', path))
58
+ ctx.setenv('GEM_PATH', path)
59
+ end
60
+
61
+ def fallback_gem_home_path(ctx)
62
+ File.join(ctx.getenv('HOME'), '.gem', 'ruby', RUBY_VERSION)
63
+ end
36
64
  end
37
65
 
38
66
  def installed?
39
- !!Dir.glob("#{self.class.gem_home(ctx)}/gems/#{name}-*").detect do |f|
40
- f =~ %r{/#{Regexp.quote(name)}-\d}
67
+ found = false
68
+ paths = self.class.gem_path(ctx).split(File::PATH_SEPARATOR)
69
+ paths.each do |path|
70
+ ctx.debug(ctx.message('rails.gem.checking_installation_path', "#{path}/gems/", name))
71
+ found = !!Dir.glob("#{path}/gems/#{name}-*").detect do |f|
72
+ gem_satisfies_version?(f)
73
+ end
74
+ break if found
41
75
  end
76
+ found
42
77
  end
43
78
 
44
79
  def install!
@@ -46,11 +81,31 @@ module Rails
46
81
  spin.add(ctx.message('rails.gem.installing', name)) do |spinner|
47
82
  args = %w(gem install)
48
83
  args.push(name)
49
- args.push('-v', version) unless version.nil?
84
+ unless version.nil?
85
+ if ctx.windows? && version.include?('~')
86
+ args.push('-v', "\"#{version}\"")
87
+ else
88
+ args.push('-v', version)
89
+ end
90
+ end
50
91
  ctx.system(*args)
51
92
  spinner.update_title(ctx.message('rails.gem.installed', name))
52
93
  end
53
94
  spin.wait
54
95
  end
96
+
97
+ def gem_satisfies_version?(path)
98
+ if version
99
+ # there was a specific version given during new(), so
100
+ # check version of gem found to determine match
101
+ require 'semantic/semantic'
102
+ found_version, _ = path.match(%r{/#{Regexp.quote(name)}-([\d\.]+)})&.captures
103
+ found_version.nil? ? false : Semantic::Version.new(found_version).satisfies?(version)
104
+ else
105
+ # otherwise ignore the actual version number,
106
+ # just check there's an initial digit
107
+ %r{/#{Regexp.quote(name)}-\d}.match?(path)
108
+ end
109
+ end
55
110
  end
56
111
  end
@@ -9,9 +9,12 @@ module Rails
9
9
  },
10
10
 
11
11
  gem: {
12
+ checking_installation_path: "Checking path %s for gem %s",
13
+ installed: "Installed %s gem",
12
14
  installed_debug: "%s installed: %s",
13
15
  installing: "Installing %s gem...",
14
- installed: "Installed %s gem",
16
+ setting_gem_home: "GEM_HOME being set to %s",
17
+ setting_gem_path: "GEM_PATH being set to %s",
15
18
  },
16
19
 
17
20
  create: {
@@ -33,6 +36,14 @@ module Rails
33
36
  See {{underline:https://github.com/Shopify/shopify-app-cli/blob/master/docs/installing-ruby.md}}
34
37
  for our recommended method of installing ruby.
35
38
  MSG
39
+ install_failure: "Error installing %s gem",
40
+ node_required: "node is required to create a rails project. Download at https://nodejs.org/en/download.",
41
+ node_version_failure: "Failed to get the current node version. Please make sure it is installed as " \
42
+ "per the instructions at https://nodejs.org/en.",
43
+ yarn_required: "yarn is required to create a rails project. Download at " \
44
+ "https://classic.yarnpkg.com/en/docs/install.",
45
+ yarn_version_failure: "Failed to get the current yarn version. Please make sure it is installed as per " \
46
+ "the instructions at https://classic.yarnpkg.com/en/docs/install.",
36
47
  },
37
48
 
38
49
  info: {
@@ -40,13 +51,18 @@ module Rails
40
51
  serve: "{{*}} Change directories to your new project folder {{green:%s}} and run {{command:%s serve}} " \
41
52
  "to start a local server",
42
53
  install: "{{*}} Then, visit {{underline:%s/test}} to install {{green:%s}} on your Dev Store",
54
+ open_new_shell: "{{*}} {{yellow:After installing %s, please open a new Command Prompt or PowerShell " \
55
+ "window to continue.}}",
43
56
  },
44
- installing_bundler: "Installing bundler",
57
+ installing_bundler: "Installing bundler...",
45
58
  generating_app: "Generating new rails app project in %s...",
46
- adding_shopify_gem: "{{v}} Adding shopify_app gem",
59
+ adding_shopify_gem: "{{v}} Adding shopify_app gem...",
60
+ node_version: "node %s",
61
+ yarn_version: "yarn %s",
47
62
  running_bundle_install: "Running bundle install...",
48
63
  running_generator: "Running shopify_app generator...",
49
- running_migrations: "Running migrations",
64
+ running_migrations: "Running migrations...",
65
+ running_webpacker_install: "Running webpacker:install...",
50
66
  },
51
67
 
52
68
  deploy: {
@@ -65,14 +81,14 @@ module Rails
65
81
  Deploy the current Rails project to Heroku
66
82
  Usage: {{command:%s deploy heroku}}
67
83
  HELP
68
- downloading: "Downloading Heroku CLI",
84
+ downloading: "Downloading Heroku CLI...",
69
85
  downloaded: "Downloaded Heroku CLI",
70
- installing: "Installing Heroku CLI",
86
+ installing: "Installing Heroku CLI...",
71
87
  installed: "Installed Heroku CLI",
72
88
  authenticated_with_account: "{{v}} Authenticated with Heroku as `%s`",
73
- authenticating: "Authenticating with Heroku",
89
+ authenticating: "Authenticating with Heroku...",
74
90
  authenticated: "{{v}} Authenticated with Heroku",
75
- deploying: "Deploying to Heroku",
91
+ deploying: "Deploying to Heroku...",
76
92
  deployed: "{{v}} Deployed to Heroku",
77
93
  db_check: {
78
94
  validating: "Validating application...",
@@ -86,7 +102,7 @@ module Rails
86
102
  SQLITE
87
103
  },
88
104
  git: {
89
- checking: "Checking git repo",
105
+ checking: "Checking git repo...",
90
106
  initialized: "Git repo initialized",
91
107
  what_branch: "What branch would you like to deploy?",
92
108
  branch_selected: "{{v}} Git branch `%s` selected for deploy",
@@ -95,10 +111,10 @@ module Rails
95
111
  no_apps_found: "No existing Heroku app found. What would you like to do?",
96
112
  name: "What is your Heroku app’s name?",
97
113
  select: "Specify an existing Heroku app",
98
- selecting: "Selecting Heroku app `%s`…",
114
+ selecting: "Selecting Heroku app `%s`...",
99
115
  selected: "{{v}} Heroku app `%s` selected",
100
116
  create: "Create a new Heroku app",
101
- creating: "Creating new Heroku app",
117
+ creating: "Creating new Heroku app...",
102
118
  created: "{{v}} New Heroku app created",
103
119
  },
104
120
  },