shopify-cli 1.1.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CONTRIBUTING.md +1 -1
  3. data/CHANGELOG.md +20 -0
  4. data/docs/core/index.md +16 -0
  5. data/docs/getting-started/index.md +3 -2
  6. data/docs/getting-started/install/index.md +55 -9
  7. data/docs/getting-started/uninstall/index.md +1 -1
  8. data/docs/getting-started/upgrade/index.md +8 -4
  9. data/lib/project_types/extension/cli.rb +6 -1
  10. data/lib/project_types/extension/commands/register.rb +1 -1
  11. data/lib/project_types/extension/features/argo/admin.rb +20 -0
  12. data/lib/project_types/extension/features/argo/base.rb +129 -0
  13. data/lib/project_types/extension/features/argo/checkout.rb +20 -0
  14. data/lib/project_types/extension/features/argo_config.rb +60 -0
  15. data/lib/project_types/extension/messages/messages.rb +11 -2
  16. data/lib/project_types/extension/models/type.rb +4 -0
  17. data/lib/project_types/extension/models/types/checkout_post_purchase.rb +6 -3
  18. data/lib/project_types/extension/models/types/product_subscription.rb +24 -0
  19. data/lib/project_types/node/commands/generate/billing.rb +1 -0
  20. data/lib/project_types/node/commands/generate/page.rb +1 -0
  21. data/lib/project_types/node/commands/generate/webhook.rb +1 -0
  22. data/lib/project_types/node/commands/serve.rb +5 -5
  23. data/lib/project_types/node/messages/messages.rb +4 -1
  24. data/lib/project_types/rails/commands/create.rb +4 -1
  25. data/lib/project_types/rails/commands/serve.rb +5 -5
  26. data/lib/project_types/rails/messages/messages.rb +5 -1
  27. data/lib/project_types/script/config/extension_points.yml +4 -4
  28. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +36 -1
  29. data/lib/project_types/script/layers/infrastructure/errors.rb +7 -0
  30. data/lib/project_types/script/layers/infrastructure/script_service.rb +6 -2
  31. data/lib/project_types/script/messages/messages.rb +12 -37
  32. data/lib/project_types/script/ui/error_handler.rb +13 -5
  33. data/lib/shopify-cli/commands/config.rb +33 -1
  34. data/lib/shopify-cli/context.rb +40 -0
  35. data/lib/shopify-cli/core/entry_point.rb +3 -0
  36. data/lib/shopify-cli/git.rb +1 -1
  37. data/lib/shopify-cli/heroku.rb +1 -1
  38. data/lib/shopify-cli/js_system.rb +22 -5
  39. data/lib/shopify-cli/messages/messages.rb +39 -11
  40. data/lib/shopify-cli/project.rb +3 -3
  41. data/lib/shopify-cli/tunnel.rb +11 -2
  42. data/lib/shopify-cli/version.rb +1 -1
  43. metadata +7 -4
  44. data/lib/project_types/extension/features/argo.rb +0 -48
  45. data/lib/project_types/extension/models/types/subscription_management.rb +0 -20
@@ -6,6 +6,7 @@ module ShopifyCli
6
6
  hidden_feature(feature_set: :debug)
7
7
 
8
8
  subcommand :Feature, 'feature'
9
+ subcommand :Analytics, 'analytics'
9
10
 
10
11
  def call(*)
11
12
  @ctx.puts(self.class.help)
@@ -16,6 +17,10 @@ module ShopifyCli
16
17
  end
17
18
 
18
19
  class Feature < ShopifyCli::SubCommand
20
+ def self.help
21
+ ShopifyCli::Context.message('core.config.feature.help', ShopifyCli::TOOL_NAME)
22
+ end
23
+
19
24
  options do |parser, flags|
20
25
  parser.on('--enable') { flags[:action] = 'enable' }
21
26
  parser.on('--disable') { flags[:action] = 'disable' }
@@ -28,7 +33,7 @@ module ShopifyCli
28
33
  is_enabled = ShopifyCli::Feature.enabled?(feature_name)
29
34
  if options.flags[:action] == 'disable' && is_enabled
30
35
  ShopifyCli::Feature.disable(feature_name)
31
- @ctx.puts(@ctx.message('core.config.feature.disabled', is_enabled))
36
+ @ctx.puts(@ctx.message('core.config.feature.disabled', feature_name))
32
37
  elsif options.flags[:action] == 'enable' && !is_enabled
33
38
  ShopifyCli::Feature.enable(feature_name)
34
39
  @ctx.puts(@ctx.message('core.config.feature.enabled', feature_name))
@@ -39,6 +44,33 @@ module ShopifyCli
39
44
  end
40
45
  end
41
46
  end
47
+
48
+ class Analytics < ShopifyCli::SubCommand
49
+ def self.help
50
+ ShopifyCli::Context.message('core.config.analytics.help', ShopifyCli::TOOL_NAME)
51
+ end
52
+
53
+ options do |parser, flags|
54
+ parser.on('--enable') { flags[:action] = 'enable' }
55
+ parser.on('--disable') { flags[:action] = 'disable' }
56
+ parser.on('--status') { flags[:action] = 'status' }
57
+ end
58
+
59
+ def call(_args, _name)
60
+ is_enabled = ShopifyCli::Config.get_bool('analytics', 'enabled')
61
+ if options.flags[:action] == 'disable' && is_enabled
62
+ ShopifyCli::Config.set('analytics', 'enabled', false)
63
+ @ctx.puts(@ctx.message('core.config.analytics.disabled'))
64
+ elsif options.flags[:action] == 'enable' && !is_enabled
65
+ ShopifyCli::Config.set('analytics', 'enabled', true)
66
+ @ctx.puts(@ctx.message('core.config.analytics.enabled'))
67
+ elsif is_enabled
68
+ @ctx.puts(@ctx.message('core.config.analytics.is_enabled'))
69
+ else
70
+ @ctx.puts(@ctx.message('core.config.analytics.is_disabled'))
71
+ end
72
+ end
73
+ end
42
74
  end
43
75
  end
44
76
  end
@@ -2,6 +2,8 @@
2
2
  require 'shopify_cli'
3
3
  require 'fileutils'
4
4
  require 'rbconfig'
5
+ require 'net/http'
6
+ require 'json'
5
7
 
6
8
  module ShopifyCli
7
9
  ##
@@ -11,6 +13,11 @@ module ShopifyCli
11
13
  # resoures.
12
14
  #
13
15
  class Context
16
+ GEM_LATEST_URI = URI.parse('https://rubygems.org/api/v1/versions/shopify-cli/latest.json')
17
+ VERSION_CHECK_SECTION = 'versioncheck'
18
+ LAST_CHECKED_AT_FIELD = 'last_checked_at'
19
+ VERSION_CHECK_INTERVAL = 86400
20
+
14
21
  class << self
15
22
  attr_reader :messages
16
23
 
@@ -446,6 +453,23 @@ module ShopifyCli
446
453
  nil
447
454
  end
448
455
 
456
+ # Checks if there's a newer version of the CLI available and returns version string if
457
+ # this should be conveyed to the user (i.e., if it's been over 24 hours since last check)
458
+ #
459
+ # #### Parameters
460
+ #
461
+ # #### Returns
462
+ # - `version`: string of newer version available, IFF new version is available AND it's time to inform user,
463
+ # : nil otherwise
464
+ #
465
+ def new_version
466
+ if (time_of_last_check + VERSION_CHECK_INTERVAL) < (now = Time.now.to_i)
467
+ update_time_of_last_check(now)
468
+ latest_version = retrieve_latest_gem_version
469
+ latest_version unless latest_version == ShopifyCli::VERSION
470
+ end
471
+ end
472
+
449
473
  private
450
474
 
451
475
  def ctx_path(fname)
@@ -456,5 +480,21 @@ module ShopifyCli
456
480
  File.join(root, fname)
457
481
  end
458
482
  end
483
+
484
+ def retrieve_latest_gem_version
485
+ response = Net::HTTP.get_response(GEM_LATEST_URI)
486
+ latest = JSON.parse(response.body)
487
+ latest["version"]
488
+ rescue
489
+ nil
490
+ end
491
+
492
+ def time_of_last_check
493
+ (val = ShopifyCli::Config.get(VERSION_CHECK_SECTION, LAST_CHECKED_AT_FIELD)) ? val.to_i : 0
494
+ end
495
+
496
+ def update_time_of_last_check(time)
497
+ ShopifyCli::Config.set(VERSION_CHECK_SECTION, LAST_CHECKED_AT_FIELD, time)
498
+ end
459
499
  end
460
500
  end
@@ -28,6 +28,9 @@ module ShopifyCli
28
28
  ctx.puts(
29
29
  ctx.message('core.warning.development_version', File.join(ShopifyCli::ROOT, 'bin', ShopifyCli::TOOL_NAME))
30
30
  )
31
+ else
32
+ new_version = ctx.new_version
33
+ ctx.puts(ctx.message('core.warning.new_version', ShopifyCli::VERSION, new_version)) unless new_version.nil?
31
34
  end
32
35
 
33
36
  ProjectType.load_type(Project.current_project_type)
@@ -125,13 +125,13 @@ module ShopifyCli
125
125
 
126
126
  success = Open3.popen3('git', *git_command, '--progress') do |_stdin, _stdout, stderr, thread|
127
127
  while (line = stderr.gets)
128
+ msg << line.chomp
128
129
  next unless line.strip.start_with?('Receiving objects:')
129
130
  percent = (line.match(/Receiving objects:\s+(\d+)/)[1].to_f / 100).round(2)
130
131
  bar.tick(set_percent: percent)
131
132
  next
132
133
  end
133
134
 
134
- msg << stderr
135
135
  thread.value
136
136
  end.success?
137
137
 
@@ -45,7 +45,7 @@ module ShopifyCli
45
45
  return if installed?
46
46
 
47
47
  result = if @ctx.windows?
48
- @ctx.system(download_path)
48
+ @ctx.system("\"#{download_path}\"")
49
49
  else
50
50
  @ctx.system('tar', '-xf', download_path, chdir: ShopifyCli.cache_dir)
51
51
  end
@@ -76,23 +76,40 @@ module ShopifyCli
76
76
  # - `ctx`: running context from your command
77
77
  # - `yarn`: The proc, array, or string command to run if yarn is available
78
78
  # - `npm`: The proc, array, or string command to run if npm is available
79
+ # - `capture_response`: The boolean flag to capture the output of the running command if it is set to true
79
80
  #
80
81
  # #### Example
81
82
  #
82
- # ShopifyCli::JsSystem.new(ctx: ctx).call(yarn: ['install', '--silent'], npm: ['install', '--no-audit'])
83
+ # ShopifyCli::JsSystem.new(ctx: ctx).call(
84
+ # yarn: ['install', '--silent'],
85
+ # npm: ['install', '--no-audit'],
86
+ # capture_response: false
87
+ # )
83
88
  #
84
- def call(yarn:, npm:)
85
- yarn? ? call_command(yarn, YARN_CORE_COMMAND) : call_command(npm, NPM_CORE_COMMAND)
89
+ def call(yarn:, npm:, capture_response: false)
90
+ if yarn?
91
+ call_command(yarn, YARN_CORE_COMMAND, capture_response)
92
+ else
93
+ call_command(npm, NPM_CORE_COMMAND, capture_response)
94
+ end
86
95
  end
87
96
 
88
97
  private
89
98
 
90
- def call_command(command, core_command)
99
+ def call_command(command, core_command, capture_response)
91
100
  if command.is_a?(String) || command.is_a?(Array)
92
- CLI::Kit::System.system(core_command, *command, chdir: ctx.root).success?
101
+ capture_response ? call_with_capture(command, core_command) : call_without_capture(command, core_command)
93
102
  else
94
103
  command.call
95
104
  end
96
105
  end
106
+
107
+ def call_with_capture(command, core_command)
108
+ CLI::Kit::System.capture3(core_command, *command, chdir: ctx.root)
109
+ end
110
+
111
+ def call_without_capture(command, core_command)
112
+ CLI::Kit::System.system(core_command, *command, chdir: ctx.root).success?
113
+ end
97
114
  end
98
115
  end
@@ -48,13 +48,27 @@ module ShopifyCli
48
48
  config: {
49
49
  help: <<~HELP,
50
50
  Change configuration of how the CLI operates
51
- Usage: {{command:%s config [ feature ] [ feature_name ] }}
51
+ Usage: {{command:%s config [ feature | analytics ] }}
52
52
  HELP
53
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",
54
+ help: <<~HELP,
55
+ Change configuration of various features
56
+ Usage: {{command:%s config [ feature ] [ feature_name ] }}
57
+ HELP
58
+ enabled: "{{v}} feature {{green:%s}} has been enabled",
59
+ disabled: "{{v}} feature {{green:%s}} has been disabled",
60
+ is_enabled: "{{v}} feature {{green:%s}} is currently enabled",
61
+ is_disabled: "{{v}} feature {{green:%s}} is currently disabled",
62
+ },
63
+ analytics: {
64
+ help: <<~HELP,
65
+ Opt in/out of anonymous usage reporting
66
+ Usage: {{command:%s config [ analytics ] }}
67
+ HELP
68
+ enabled: "{{v}} analytics have been enabled",
69
+ disabled: "{{v}} analytics have been disabled",
70
+ is_enabled: "{{v}} analytics are currently enabled",
71
+ is_disabled: "{{v}} analytics are currently disabled",
58
72
  },
59
73
  },
60
74
 
@@ -184,11 +198,14 @@ module ShopifyCli
184
198
  {{x}} You are not in a Shopify app project
185
199
  {{yellow:{{*}}}}{{reset: Run}}{{cyan: shopify create}}{{reset: to create your app}}
186
200
  MESSAGE
187
- cli_yaml: {
188
- not_hash: "{{x}} .shopify-cli.yml was not a proper YAML file. Expecting a hash.",
189
- invalid: "{{x}} %s contains invalid YAML: %s",
190
- not_found: "{{x}} %s not found",
191
- },
201
+ },
202
+ },
203
+
204
+ yaml: {
205
+ error: {
206
+ not_hash: "{{x}} %s was not a proper YAML file. Expecting a hash.",
207
+ invalid: "{{x}} %s contains invalid YAML: %s",
208
+ not_found: "{{x}} %s not found",
192
209
  },
193
210
  },
194
211
 
@@ -289,6 +306,8 @@ module ShopifyCli
289
306
  error: {
290
307
  stop: "ngrok tunnel could not be stopped. Try running {{command:killall -9 ngrok}}",
291
308
  url_fetch_failure: "Unable to fetch external url",
309
+ prereq_command_required: "%1$s is required for installing ngrok. Please install %1$s using the appropriate"\
310
+ " package manager for your system.",
292
311
  },
293
312
 
294
313
  not_running: "{{green:x}} ngrok tunnel not running",
@@ -302,6 +321,7 @@ module ShopifyCli
302
321
  stopped: "{{green:x}} ngrok tunnel stopped",
303
322
  timed_out: "{{x}} ngrok tunnel has timed out, restarting ...",
304
323
  will_timeout: "{{*}} This tunnel will timeout in {{red:%s}}",
324
+ prereq_command_location: "%s @ %s",
305
325
  },
306
326
 
307
327
  version: {
@@ -314,7 +334,7 @@ module ShopifyCli
314
334
  warning: {
315
335
  development_version: <<~DEVELOPMENT,
316
336
  {{*}} {{yellow:You are running a development version of the CLI at:}}
317
- {{yellow:%s}}
337
+ {{yellow:%s}}
318
338
 
319
339
  DEVELOPMENT
320
340
 
@@ -325,6 +345,14 @@ module ShopifyCli
325
345
  {{underline:https://shopify.github.io/shopify-app-cli/migrate/}}
326
346
 
327
347
  MESSAGE
348
+
349
+ new_version: <<~MESSAGE,
350
+ {{*}} {{yellow:A new version of the Shopify App CLI is available! You have version %s and the latest version is %s.
351
+
352
+ To upgrade, follow the instructions for the package manager you’re using:
353
+ {{underline:https://shopify.github.io/shopify-app-cli/getting-started/upgrade/}}}}
354
+
355
+ MESSAGE
328
356
  },
329
357
  },
330
358
  }.freeze
@@ -166,7 +166,7 @@ module ShopifyCli
166
166
  @config ||= begin
167
167
  config = load_yaml_file('.shopify-cli.yml')
168
168
  unless config.is_a?(Hash)
169
- raise ShopifyCli::Abort, Context.message('core.project.error.cli_yaml.not_hash')
169
+ raise ShopifyCli::Abort, Context.message('core.yaml.error.not_hash', '.shopify-cli.yml')
170
170
  end
171
171
 
172
172
  # The app_type key was deprecated in favour of project_type, so replace it
@@ -187,12 +187,12 @@ module ShopifyCli
187
187
  begin
188
188
  YAML.load_file(f)
189
189
  rescue Psych::SyntaxError => e
190
- raise(ShopifyCli::Abort, Context.message('core.project.error.cli_yaml.invalid', relative_path, e.message))
190
+ raise(ShopifyCli::Abort, Context.message('core.yaml.error.invalid', relative_path, e.message))
191
191
  # rescue Errno::EACCES => e
192
192
  # TODO
193
193
  # Dev::Helpers::EaccesHandler.diagnose_and_raise(f, e, mode: :read)
194
194
  rescue Errno::ENOENT
195
- raise ShopifyCli::Abort, Context.message('core.project.error.cli_yaml.not_found', f)
195
+ raise ShopifyCli::Abort, Context.message('core.yaml.error.not_found', f)
196
196
  end
197
197
  end
198
198
  end
@@ -124,6 +124,8 @@ module ShopifyCli
124
124
 
125
125
  def install(ctx)
126
126
  return if File.exist?(File.join(ShopifyCli.cache_dir, ctx.windows? ? 'ngrok.exe' : 'ngrok'))
127
+ check_prereq_command(ctx, 'curl')
128
+ check_prereq_command(ctx, ctx.linux? ? 'unzip' : 'tar')
127
129
  spinner = CLI::UI::SpinGroup.new
128
130
  spinner.add('Installing ngrok...') do
129
131
  zip_dest = File.join(ShopifyCli.cache_dir, 'ngrok.zip')
@@ -149,7 +151,7 @@ module ShopifyCli
149
151
  end
150
152
 
151
153
  def ngrok_command(port)
152
- "#{File.join(ShopifyCli.cache_dir, 'ngrok')} http -inspect=false -log=stdout -log-level=debug #{port}"
154
+ "\"#{File.join(ShopifyCli.cache_dir, 'ngrok')}\" http -inspect=false -log=stdout -log-level=debug #{port}"
153
155
  end
154
156
 
155
157
  def seconds_to_hm(seconds)
@@ -169,6 +171,13 @@ module ShopifyCli
169
171
  end
170
172
  start_ngrok(ctx, port)
171
173
  end
174
+
175
+ def check_prereq_command(ctx, command)
176
+ cmd_path = ctx.which(command)
177
+ ctx.abort(ctx.message('core.tunnel.error.prereq_command_required', command)) if cmd_path.nil?
178
+ ctx.done(ctx.message('core.tunnel.prereq_command_location', command, cmd_path))
179
+ end
180
+
172
181
  class LogParser # :nodoc:
173
182
  TIMEOUT = 10
174
183
 
@@ -201,7 +210,7 @@ module ShopifyCli
201
210
  end
202
211
 
203
212
  def parse_account
204
- account, timeout, _ = @log.match(/AccountName:([\w\s\d@._\-]*) SessionDuration:([\d]+) PlanName/)&.captures
213
+ account, timeout, _ = @log.match(/AccountName:(.*)\s+SessionDuration:([\d]+) PlanName/)&.captures
205
214
  @account = account&.empty? ? nil : account
206
215
  @timeout = timeout&.empty? ? 0 : timeout.to_i
207
216
  end
@@ -1,3 +1,3 @@
1
1
  module ShopifyCli
2
- VERSION = '1.1.0'
2
+ VERSION = '1.3.1'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-24 00:00:00.000000000 Z
11
+ date: 2020-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -147,7 +147,10 @@ files:
147
147
  - lib/project_types/extension/commands/tunnel.rb
148
148
  - lib/project_types/extension/extension_project.rb
149
149
  - lib/project_types/extension/extension_project_keys.rb
150
- - lib/project_types/extension/features/argo.rb
150
+ - lib/project_types/extension/features/argo/admin.rb
151
+ - lib/project_types/extension/features/argo/base.rb
152
+ - lib/project_types/extension/features/argo/checkout.rb
153
+ - lib/project_types/extension/features/argo_config.rb
151
154
  - lib/project_types/extension/features/argo_dependencies.rb
152
155
  - lib/project_types/extension/features/argo_setup.rb
153
156
  - lib/project_types/extension/features/argo_setup_step.rb
@@ -161,7 +164,7 @@ files:
161
164
  - lib/project_types/extension/models/registration.rb
162
165
  - lib/project_types/extension/models/type.rb
163
166
  - lib/project_types/extension/models/types/checkout_post_purchase.rb
164
- - lib/project_types/extension/models/types/subscription_management.rb
167
+ - lib/project_types/extension/models/types/product_subscription.rb
165
168
  - lib/project_types/extension/models/validation_error.rb
166
169
  - lib/project_types/extension/models/version.rb
167
170
  - lib/project_types/extension/tasks/converters/app_converter.rb
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'base64'
3
-
4
- module Extension
5
- module Features
6
- class Argo
7
- include SmartProperties
8
-
9
- GIT_ADMIN_TEMPLATE = 'https://github.com/Shopify/argo-admin-template.git'
10
- GIT_CHECKOUT_TEMPLATE = 'https://github.com/Shopify/argo-checkout-template.git'
11
- SCRIPT_PATH = %w(build main.js).freeze
12
-
13
- class << self
14
- def admin
15
- @admin ||= Argo.new(setup: ArgoSetup.new(git_template: GIT_ADMIN_TEMPLATE))
16
- end
17
-
18
- def checkout
19
- @checkout ||= Argo.new(
20
- setup: ArgoSetup.new(
21
- git_template: GIT_CHECKOUT_TEMPLATE,
22
- dependency_checks: [ArgoDependencies.node_installed(min_major: 10, min_minor: 16)]
23
- )
24
- )
25
- end
26
- end
27
-
28
- property! :setup, accepts: Features::ArgoSetup
29
-
30
- def create(directory_name, identifier, context)
31
- setup.call(directory_name, identifier, context)
32
- end
33
-
34
- def config(context)
35
- filepath = File.join(context.root, SCRIPT_PATH)
36
- context.abort(context.message('features.argo.missing_file_error')) unless File.exist?(filepath)
37
-
38
- begin
39
- {
40
- serialized_script: Base64.strict_encode64(File.open(filepath).read.chomp),
41
- }
42
- rescue StandardError
43
- context.abort(context.message('features.argo.script_prepare_error'))
44
- end
45
- end
46
- end
47
- end
48
- end