shopify-cli 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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/install/index.md +37 -1
  10. data/docs/getting-started/migrate/index.md +34 -1
  11. data/ext/shopify-cli/extconf.rb +40 -20
  12. data/lib/project_types/extension/cli.rb +1 -1
  13. data/lib/project_types/extension/commands/build.rb +1 -1
  14. data/lib/project_types/extension/models/type.rb +1 -0
  15. data/lib/project_types/extension/tasks/create_extension.rb +1 -1
  16. data/lib/project_types/extension/tasks/get_app.rb +1 -1
  17. data/lib/project_types/extension/tasks/update_draft.rb +1 -1
  18. data/lib/project_types/node/commands/create.rb +4 -4
  19. data/lib/project_types/node/commands/deploy/heroku.rb +6 -1
  20. data/lib/project_types/node/commands/generate/billing.rb +6 -5
  21. data/lib/project_types/node/commands/generate/page.rb +8 -5
  22. data/lib/project_types/node/commands/generate/webhook.rb +4 -1
  23. data/lib/project_types/node/messages/messages.rb +3 -2
  24. data/lib/project_types/rails/cli.rb +0 -1
  25. data/lib/project_types/rails/commands/create.rb +52 -4
  26. data/lib/project_types/rails/commands/generate.rb +1 -0
  27. data/lib/project_types/rails/commands/generate/webhook.rb +3 -2
  28. data/lib/project_types/rails/commands/serve.rb +6 -2
  29. data/lib/project_types/rails/gem.rb +61 -6
  30. data/lib/project_types/rails/messages/messages.rb +29 -13
  31. data/lib/project_types/script/cli.rb +2 -3
  32. data/lib/project_types/script/commands/create.rb +5 -9
  33. data/lib/project_types/script/commands/disable.rb +4 -15
  34. data/lib/project_types/script/commands/enable.rb +37 -13
  35. data/lib/project_types/script/commands/push.rb +8 -13
  36. data/lib/project_types/script/config/extension_points.yml +9 -3
  37. data/lib/project_types/script/errors.rb +8 -0
  38. data/lib/project_types/script/forms/create.rb +1 -1
  39. data/lib/project_types/script/layers/application/create_script.rb +7 -6
  40. data/lib/project_types/script/layers/application/disable_script.rb +9 -7
  41. data/lib/project_types/script/layers/application/enable_script.rb +11 -9
  42. data/lib/project_types/script/layers/application/push_script.rb +6 -4
  43. data/lib/project_types/script/layers/domain/errors.rb +2 -0
  44. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +2 -2
  45. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +2 -2
  46. data/lib/project_types/script/layers/infrastructure/errors.rb +2 -0
  47. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +1 -1
  48. data/lib/project_types/script/layers/infrastructure/script_repository.rb +1 -1
  49. data/lib/project_types/script/layers/infrastructure/script_service.rb +2 -0
  50. data/lib/project_types/script/messages/messages.rb +25 -31
  51. data/lib/project_types/script/script_project.rb +8 -4
  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 -8
  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 +38 -1
  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 +37 -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 +44 -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
@@ -3,7 +3,7 @@ module ShopifyCli
3
3
  DOWNLOAD_URLS = {
4
4
  linux: 'https://cli-assets.heroku.com/heroku-linux-x64.tar.gz',
5
5
  mac: 'https://cli-assets.heroku.com/heroku-darwin-x64.tar.gz',
6
- windows: 'https://cli-assets.heroku.com/heroku-win32-x64.tar.gz',
6
+ windows: 'https://cli-assets.heroku.com/heroku-x64.exe',
7
7
  }
8
8
 
9
9
  def initialize(ctx)
@@ -36,7 +36,7 @@ module ShopifyCli
36
36
  def download
37
37
  return if installed?
38
38
 
39
- result = @ctx.system('curl', '-o', download_path, DOWNLOAD_URLS[@ctx.os], chdir: ShopifyCli::CACHE_DIR)
39
+ result = @ctx.system('curl', '-o', download_path, DOWNLOAD_URLS[@ctx.os], chdir: ShopifyCli.cache_dir)
40
40
  @ctx.abort(@ctx.message('core.heroku.error.download')) unless result.success?
41
41
  @ctx.abort(@ctx.message('core.heroku.error.download')) unless File.exist?(download_path)
42
42
  end
@@ -44,7 +44,11 @@ module ShopifyCli
44
44
  def install
45
45
  return if installed?
46
46
 
47
- result = @ctx.system('tar', '-xf', download_path, chdir: ShopifyCli::CACHE_DIR)
47
+ result = if @ctx.windows?
48
+ @ctx.system(download_path)
49
+ else
50
+ @ctx.system('tar', '-xf', download_path, chdir: ShopifyCli.cache_dir)
51
+ end
48
52
  @ctx.abort(@ctx.message('core.heroku.error.install')) unless result.success?
49
53
 
50
54
  @ctx.rm(download_path)
@@ -70,7 +74,7 @@ module ShopifyCli
70
74
  end
71
75
 
72
76
  def download_path
73
- File.join(ShopifyCli::CACHE_DIR, download_filename)
77
+ File.join(ShopifyCli.cache_dir, download_filename)
74
78
  end
75
79
 
76
80
  def git_remote
@@ -79,9 +83,21 @@ module ShopifyCli
79
83
  end
80
84
 
81
85
  def heroku_command
82
- local_path = File.join(ShopifyCli::CACHE_DIR, 'heroku', 'bin', 'heroku').to_s
86
+ local_path = File.join(ShopifyCli.cache_dir, 'heroku', 'bin', 'heroku').to_s
83
87
  if File.exist?(local_path)
84
88
  local_path
89
+ elsif @ctx.windows?
90
+ # Check if Heroku exists in the Windows registry and run it from there
91
+ require 'win32/registry'
92
+ begin
93
+ windows_path = Win32::Registry::HKEY_CURRENT_USER.open('SOFTWARE\heroku') do |reg|
94
+ reg[''] # This reads the 'Default' registry key
95
+ end
96
+
97
+ File.join(windows_path, 'bin', 'heroku').to_s
98
+ rescue
99
+ 'heroku'
100
+ end
85
101
  else
86
102
  'heroku'
87
103
  end
@@ -69,7 +69,7 @@ module ShopifyCli
69
69
  deps = parse_dependencies
70
70
  errors = nil
71
71
 
72
- spinner_title = ctx.message('core.js_deps.installing_deps', deps.size)
72
+ spinner_title = ctx.message('core.js_deps.installing', @system.package_manager)
73
73
  success = CLI::UI::Spinner.spin(spinner_title, auto_debrief: false) do |spinner|
74
74
  _, errors, status = CLI::Kit::System.capture3(*cmd, env: @ctx.env, chdir: ctx.root)
75
75
  update_spinner_title_and_status(spinner, status, deps)
@@ -81,7 +81,7 @@ module ShopifyCli
81
81
 
82
82
  def update_spinner_title_and_status(spinner, status, deps)
83
83
  if status.success?
84
- spinner.update_title(ctx.message('core.js_deps.installed_deps', deps.size))
84
+ spinner.update_title(ctx.message('core.js_deps.installed', deps.size))
85
85
  else
86
86
  spinner.update_title(ctx.message('core.js_deps.error.install_spinner_error', deps.size))
87
87
  CLI::UI::Spinner::TASK_FAILED
@@ -64,8 +64,8 @@ module ShopifyCli
64
64
  #
65
65
  def yarn?
66
66
  @has_yarn ||= begin
67
- _, status = CLI::Kit::System.capture2('which', 'yarn')
68
- File.exist?(File.join(ctx.root, 'yarn.lock')) && status.success?
67
+ cmd_path = @ctx.which('yarn')
68
+ File.exist?(File.join(ctx.root, 'yarn.lock')) && !cmd_path.nil?
69
69
  end
70
70
  end
71
71
 
@@ -16,13 +16,6 @@ module ShopifyCli
16
16
  already_connected_warning: "{{yellow:! This app appears to be already connected}}",
17
17
  connected: "{{v}} Project now connected to {{green:%s}}",
18
18
  project_type_select: "What type of project would you like to connect?",
19
- organization_select: "To which partner organization does this project belong?",
20
- app_select: "To which app does this project belong?",
21
- no_development_stores: <<~MESSAGE,
22
- No development stores available.
23
- Visit {{underline:https://partners.shopify.com/%d/stores}} to create one
24
- MESSAGE
25
- development_store_select: "Which development store would you like to use?",
26
19
  cli_yml_saved: ".shopify-cli.yml saved to project root",
27
20
  },
28
21
 
@@ -52,6 +45,19 @@ module ShopifyCli
52
45
  saved: "%s saved to project root",
53
46
  },
54
47
 
48
+ config: {
49
+ help: <<~HELP,
50
+ Change configuration of how the CLI operates
51
+ Usage: {{command:%s config [ feature ] [ feature_name ] }}
52
+ HELP
53
+ feature: {
54
+ enabled: "{{v}} feature {{green:%s}} was enabled",
55
+ disabled: "{{v}} feature {{green:%s}} was disabled",
56
+ is_enabled: "{{v}} feature {{green:%s}} is enabled",
57
+ is_disabled: "{{v}} feature {{green:%s}} is disabled",
58
+ },
59
+ },
60
+
55
61
  git: {
56
62
  error: {
57
63
  directory_exists: "Project directory already exists. Please create a project with a new name.",
@@ -232,9 +238,21 @@ module ShopifyCli
232
238
 
233
239
  tasks: {
234
240
  ensure_env: {
235
- api_key_question: "What is your Shopify API key?",
236
- api_secret_key_question: "What is your Shopify API secret key?",
237
- development_store_question: "What is your development store URL? (Example: my-dev-store.myshopify.com)",
241
+ organization_select: "To which partner organization does this project belong?",
242
+ no_development_stores: <<~MESSAGE,
243
+ No development stores available.
244
+ Visit {{underline:https://partners.shopify.com/%d/stores}} to create one
245
+ MESSAGE
246
+ development_store_select: "Which development store would you like to use?",
247
+ app_select: "To which app does this project belong?",
248
+ no_apps: 'You have no apps to connect to, creating a new app.',
249
+ app_name: "App name",
250
+ app_type: {
251
+ select: "What type of app are you building?",
252
+ select_public: "Public: An app built for a wide merchant audience.",
253
+ select_custom: "Custom: An app custom built for a single client.",
254
+ selected: "App type {{green:%s}}",
255
+ },
238
256
  },
239
257
  ensure_dev_store: {
240
258
  could_not_verify_store: "Couldn't verify your store %s",
@@ -273,10 +291,17 @@ module ShopifyCli
273
291
  url_fetch_failure: "Unable to fetch external url",
274
292
  },
275
293
 
276
- stopped: "{{green:x}} ngrok tunnel stopped",
277
294
  not_running: "{{green:x}} ngrok tunnel not running",
278
- start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
295
+ signup_suggestion: <<~MESSAGE,
296
+ {{*}} To avoid tunnels that timeout, it is recommended to signup for a free ngrok
297
+ account at {{underline:https://ngrok.com/signup}}. After you signup, install your
298
+ personalized authorization token using {{command:%s tunnel auth <token>}}.
299
+ MESSAGE
279
300
  start: "{{v}} ngrok tunnel running at {{underline:%s}}",
301
+ start_with_account: "{{v}} ngrok tunnel running at {{underline:%s}}, with account %s",
302
+ stopped: "{{green:x}} ngrok tunnel stopped",
303
+ timed_out: "{{x}} ngrok tunnel has timed out, restarting ...",
304
+ will_timeout: "{{*}} This tunnel will timeout in {{red:%s}}",
280
305
  },
281
306
 
282
307
  version: {
@@ -4,25 +4,25 @@ module ShopifyCli
4
4
  class << self
5
5
  def fetch_all(ctx)
6
6
  resp = PartnersAPI.query(ctx, 'all_organizations')
7
- resp['data']['organizations']['nodes'].map do |org|
8
- org['stores'] = org['stores']['nodes']
7
+ (resp.dig('data', 'organizations', 'nodes') || []).map do |org|
8
+ org['stores'] = (org.dig('stores', 'nodes') || [])
9
9
  org
10
10
  end
11
11
  end
12
12
 
13
13
  def fetch(ctx, id:)
14
14
  resp = PartnersAPI.query(ctx, 'find_organization', id: id)
15
- org = resp['data']['organizations']['nodes'].first
15
+ org = resp.dig('data', 'organizations', 'nodes').first
16
16
  return nil if org.nil?
17
- org['stores'] = org['stores']['nodes']
17
+ org['stores'] = (org.dig('stores', 'nodes') || [])
18
18
  org
19
19
  end
20
20
 
21
21
  def fetch_with_app(ctx)
22
22
  resp = PartnersAPI.query(ctx, 'all_orgs_with_apps')
23
- resp['data']['organizations']['nodes'].map do |org|
24
- org['stores'] = org['stores']['nodes']
25
- org['apps'] = org['apps']['nodes']
23
+ (resp.dig('data', 'organizations', 'nodes') || []).map do |org|
24
+ org['stores'] = (org.dig('stores', 'nodes') || [])
25
+ org['apps'] = (org.dig('apps', 'nodes') || [])
26
26
  org
27
27
  end
28
28
  end
@@ -5,13 +5,10 @@ module ShopifyCli
5
5
  # ProcessSupervision wraps a running process spawned by `exec` and keeps track
6
6
  # if its `pid` and keeps a log file for it as well
7
7
  class ProcessSupervision
8
- # is the directory where the pid and logfile are kept
9
- RUN_DIR = File.join(ShopifyCli::CACHE_DIR, 'sv')
10
-
11
8
  # a string or a symbol to identify this process by
12
9
  attr_reader :identifier
13
10
  # process ID for the running process
14
- attr_reader :pid
11
+ attr_accessor :pid
15
12
  # starttime of the process
16
13
  attr_reader :time
17
14
  # filepath to the pidfile for this process
@@ -20,6 +17,11 @@ module ShopifyCli
20
17
  attr_reader :log_path
21
18
 
22
19
  class << self
20
+ def run_dir
21
+ # is the directory where the pid and logfile are kept
22
+ File.join(ShopifyCli.cache_dir, 'sv')
23
+ end
24
+
23
25
  ##
24
26
  # Will find and create a new instance of ProcessSupervision for a running process
25
27
  # if it is currently running. It will return nil if the process is not running.
@@ -34,7 +36,7 @@ module ShopifyCli
34
36
  # will be nil if the process is not running.
35
37
  #
36
38
  def for_ident(identifier)
37
- pid, time = File.read(File.join(RUN_DIR, "#{identifier}.pid")).split(':')
39
+ pid, time = File.read(File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.pid")).split(':')
38
40
  new(identifier, pid: Integer(pid), time: time)
39
41
  rescue Errno::ENOENT
40
42
  nil
@@ -56,15 +58,37 @@ module ShopifyCli
56
58
  #
57
59
  def start(identifier, args)
58
60
  return for_ident(identifier) if running?(identifier)
59
- fork do
60
- pid_file = new(identifier, pid: Process.pid)
61
+
62
+ # Windows doesn't support forking process without extra gems, so we resort to spawning a new child process -
63
+ # that means that it dies along with the original process if it is interrupted. On UNIX, we fork the process so
64
+ # that it doesn't have to be restarted on every run.
65
+ if Context.new.windows?
66
+ pid_file = new(identifier)
67
+
68
+ # Make sure the file exists and is empty, otherwise Windows fails
69
+ File.open(pid_file.log_path, 'w') {}
70
+ pid = Process.spawn(
71
+ *args,
72
+ out: pid_file.log_path,
73
+ err: pid_file.log_path,
74
+ in: Context.new.windows? ? "nul" : "/dev/null",
75
+ )
76
+ pid_file.pid = pid
61
77
  pid_file.write
62
- STDOUT.reopen(pid_file.log_path, "w")
63
- STDERR.reopen(pid_file.log_path, "w")
64
- STDIN.reopen("/dev/null", "r")
65
- Process.setsid
66
- exec(*args)
78
+
79
+ Process.detach(pid)
80
+ else
81
+ fork do
82
+ pid_file = new(identifier, pid: Process.pid)
83
+ pid_file.write
84
+ STDOUT.reopen(pid_file.log_path, "w")
85
+ STDERR.reopen(pid_file.log_path, "w")
86
+ STDIN.reopen("/dev/null", "r")
87
+ Process.setsid
88
+ exec(*args)
89
+ end
67
90
  end
91
+
68
92
  sleep(0.1)
69
93
  for_ident(identifier)
70
94
  end
@@ -104,24 +128,29 @@ module ShopifyCli
104
128
  end
105
129
  end
106
130
 
107
- def initialize(identifier, pid:, time: Time.now.strftime('%s')) # :nodoc:
131
+ def initialize(identifier, pid: nil, time: Time.now.strftime('%s')) # :nodoc:
108
132
  @identifier = identifier
109
133
  @pid = pid
110
134
  @time = time
111
- @pid_path = File.join(RUN_DIR, "#{identifier}.pid")
112
- @log_path = File.join(RUN_DIR, "#{identifier}.log")
135
+ FileUtils.mkdir_p(ShopifyCli::ProcessSupervision.run_dir)
136
+ @pid_path = File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.pid")
137
+ @log_path = File.join(ShopifyCli::ProcessSupervision.run_dir, "#{identifier}.log")
113
138
  end
114
139
 
115
140
  ##
116
141
  # will attempt to shutdown a running process
117
142
  #
143
+ # #### Parameters
144
+ #
145
+ # * `ctx` - the context of this command
146
+ #
118
147
  # #### Returns
119
148
  #
120
149
  # * `stopped` - [true, false]
121
150
  #
122
151
  def stop
123
- unlink
124
152
  kill_proc
153
+ unlink
125
154
  true
126
155
  rescue
127
156
  false
@@ -157,7 +186,11 @@ module ShopifyCli
157
186
  end
158
187
 
159
188
  def kill_proc
160
- kill(-pid) # process group
189
+ if Context.new.windows?
190
+ kill(pid)
191
+ else
192
+ kill(-pid) # process group
193
+ end
161
194
  rescue Errno::ESRCH
162
195
  begin
163
196
  kill(pid)
@@ -167,12 +200,18 @@ module ShopifyCli
167
200
  end
168
201
 
169
202
  def kill(id)
170
- Process.kill('TERM', id)
171
- 50.times do
172
- sleep 0.1
173
- break unless stat(id)
203
+ ctx = Context.new
204
+
205
+ # Windows does not handle SIGTERM, go straight to SIGKILL
206
+ unless ctx.windows?
207
+ Process.kill('TERM', id)
208
+ 50.times do
209
+ sleep 0.1
210
+ break unless stat(id)
211
+ end
174
212
  end
175
213
  Process.kill('KILL', id) if stat(id)
214
+ sleep(0.1) if ctx.windows? # Give Windows a second to actually close the process
176
215
  end
177
216
 
178
217
  def stat(id)
@@ -15,6 +15,10 @@ module ShopifyCli
15
15
  # will get an instance of the project that the user is currently operating
16
16
  # on. This is used for access to project resources.
17
17
  #
18
+ # #### Parameters
19
+ #
20
+ # * `force_reload` - whether to force a reload of the project files
21
+ #
18
22
  # #### Returns
19
23
  #
20
24
  # * `project` - a Project instance if the user is currently in the project.
@@ -29,8 +33,8 @@ module ShopifyCli
29
33
  #
30
34
  # project = ShopifyCli::Project.current
31
35
  #
32
- def current
33
- at(Dir.pwd)
36
+ def current(force_reload: false)
37
+ at(Dir.pwd, force_reload: force_reload)
34
38
  end
35
39
 
36
40
  ##
@@ -93,13 +97,17 @@ module ShopifyCli
93
97
 
94
98
  private
95
99
 
96
- def directory(dir)
100
+ def directory(dir, force_reload: false)
101
+ @dir = nil if force_reload
102
+
97
103
  @dir ||= Hash.new { |h, k| h[k] = __directory(k) }
98
104
  @dir[dir]
99
105
  end
100
106
 
101
- def at(dir)
102
- proj_dir = directory(dir)
107
+ def at(dir, force_reload: false)
108
+ @at = nil if force_reload
109
+
110
+ proj_dir = directory(dir, force_reload: force_reload)
103
111
  unless proj_dir
104
112
  raise(ShopifyCli::Abort, Context.message('core.project.error.not_in_project'))
105
113
  end
@@ -109,7 +117,7 @@ module ShopifyCli
109
117
 
110
118
  def __directory(curr)
111
119
  loop do
112
- return nil if curr == '/'
120
+ return nil if curr == '/' || /^[A-Z]:\/$/.match?(curr)
113
121
  file = File.join(curr, '.shopify-cli.yml')
114
122
  return curr if File.exist?(file)
115
123
  curr = File.dirname(curr)
@@ -1,11 +1,12 @@
1
1
  module ShopifyCli
2
2
  class ProjectType
3
+ extend Feature::Set
4
+
3
5
  class << self
4
6
  attr_accessor :project_type,
5
7
  :project_name,
6
8
  :project_creator_command_class,
7
9
  :project_load_shallow
8
- attr_reader :hidden
9
10
 
10
11
  def repository
11
12
  @repository ||= []
@@ -13,6 +14,7 @@ module ShopifyCli
13
14
  alias_method :all_loaded, :repository
14
15
 
15
16
  def inherited(klass)
17
+ super
16
18
  repository << klass
17
19
  klass.project_type = @current_type
18
20
  klass.project_load_shallow = @shallow_load
@@ -31,7 +33,7 @@ module ShopifyCli
31
33
 
32
34
  def load_all
33
35
  Dir.glob(File.join(ShopifyCli::ROOT, 'lib', 'project_types', '*', 'cli.rb')).map do |filepath|
34
- load_type(filepath.split(File::Separator)[-2], true)
36
+ load_type(filepath.split(File::Separator)[-2].to_sym, true)
35
37
  end
36
38
  end
37
39
 
@@ -53,10 +55,6 @@ module ShopifyCli
53
55
  const_get(@project_creator_command_class)
54
56
  end
55
57
 
56
- def hidden_project_type
57
- @hidden = true
58
- end
59
-
60
58
  def register_command(const, cmd)
61
59
  return if project_load_shallow
62
60
  Context.new.abort(
@@ -67,7 +65,7 @@ module ShopifyCli
67
65
 
68
66
  def register_task(task, name)
69
67
  return if project_load_shallow
70
- Task::Registry.add(const_get(task), name)
68
+ ShopifyCli::Task.register(task, name)
71
69
  end
72
70
 
73
71
  def register_messages(messages)