shopify-cli 1.0.5 → 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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/bin/load_shopify.rb +3 -1
  4. data/bin/shopify +2 -0
  5. data/ext/shopify-cli/extconf.rb +40 -20
  6. data/lib/project_types/node/commands/create.rb +4 -4
  7. data/lib/project_types/node/commands/deploy/heroku.rb +6 -1
  8. data/lib/project_types/node/commands/generate/billing.rb +6 -5
  9. data/lib/project_types/node/commands/generate/page.rb +8 -5
  10. data/lib/project_types/node/commands/generate/webhook.rb +4 -1
  11. data/lib/project_types/node/messages/messages.rb +1 -0
  12. data/lib/project_types/rails/commands/create.rb +52 -4
  13. data/lib/project_types/rails/commands/generate.rb +1 -0
  14. data/lib/project_types/rails/commands/generate/webhook.rb +3 -2
  15. data/lib/project_types/rails/commands/serve.rb +6 -2
  16. data/lib/project_types/rails/gem.rb +61 -6
  17. data/lib/project_types/rails/messages/messages.rb +27 -11
  18. data/lib/project_types/script/config/extension_points.yml +3 -3
  19. data/lib/project_types/script/forms/create.rb +1 -1
  20. data/lib/rubygems_plugin.rb +18 -10
  21. data/lib/shopify-cli/admin_api/populate_resource_command.rb +1 -1
  22. data/lib/shopify-cli/commands/connect.rb +1 -1
  23. data/lib/shopify-cli/commands/system.rb +9 -8
  24. data/lib/shopify-cli/context.rb +28 -0
  25. data/lib/shopify-cli/heroku.rb +18 -2
  26. data/lib/shopify-cli/js_deps.rb +2 -2
  27. data/lib/shopify-cli/js_system.rb +2 -2
  28. data/lib/shopify-cli/process_supervision.rb +52 -15
  29. data/lib/shopify-cli/project.rb +14 -6
  30. data/lib/shopify-cli/tunnel.rb +10 -4
  31. data/lib/shopify-cli/version.rb +1 -1
  32. data/lib/shopify_cli.rb +6 -2
  33. data/shopify-cli.gemspec +4 -1
  34. data/vendor/deps/cli-kit/REVISION +1 -1
  35. data/vendor/deps/cli-kit/lib/cli/kit.rb +1 -1
  36. data/vendor/deps/cli-kit/lib/cli/kit/autocall.rb +2 -2
  37. data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +12 -6
  38. data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +9 -11
  39. data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +8 -2
  40. data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +7 -7
  41. data/vendor/deps/cli-kit/lib/cli/kit/system.rb +48 -17
  42. data/vendor/deps/cli-ui/REVISION +1 -1
  43. data/vendor/deps/cli-ui/lib/cli/ui.rb +5 -4
  44. data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +9 -3
  45. data/vendor/deps/cli-ui/lib/cli/ui/color.rb +1 -0
  46. data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +3 -2
  47. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +1 -0
  48. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +13 -5
  49. data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +29 -2
  50. data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +21 -10
  51. data/vendor/deps/cli-ui/lib/cli/ui/os.rb +63 -0
  52. data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +11 -2
  53. data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +1 -0
  54. data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +3 -3
  55. data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +6 -8
  56. data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +2 -0
  57. data/vendor/gen/lib/gen.rb +39 -0
  58. data/vendor/gen/lib/gen/commands.rb +18 -0
  59. data/vendor/gen/lib/gen/commands/help.rb +20 -0
  60. data/vendor/gen/lib/gen/commands/new.rb +21 -0
  61. data/vendor/gen/lib/gen/entry_point.rb +10 -0
  62. data/vendor/gen/lib/gen/generator.rb +165 -0
  63. data/vendor/gen/template/.gitignore +2 -0
  64. data/vendor/gen/template/Gemfile +10 -0
  65. data/vendor/gen/template/README.md +1 -0
  66. data/vendor/gen/template/bin/testunit +23 -0
  67. data/vendor/gen/template/bin/update-deps +97 -0
  68. data/vendor/gen/template/dev-gems.yml +3 -0
  69. data/vendor/gen/template/dev-vendor.yml +4 -0
  70. data/vendor/gen/template/exe/__app__-gems +17 -0
  71. data/vendor/gen/template/exe/__app__-vendor +18 -0
  72. data/vendor/gen/template/lib/__app__.rb +33 -0
  73. data/vendor/gen/template/lib/__app__/commands.rb +18 -0
  74. data/vendor/gen/template/lib/__app__/commands/example.rb +19 -0
  75. data/vendor/gen/template/lib/__app__/commands/help.rb +21 -0
  76. data/vendor/gen/template/lib/__app__/entry_point.rb +10 -0
  77. data/vendor/gen/template/test/example_test.rb +17 -0
  78. data/vendor/gen/template/test/test_helper.rb +22 -0
  79. metadata +25 -4
  80. data/Vagrantfile +0 -17
  81. data/lib/project_types/script/forms/script_form.rb +0 -69
@@ -106,7 +106,9 @@ module CLI
106
106
  # * +n+ - The column to move to
107
107
  #
108
108
  def self.cursor_horizontal_absolute(n = 1)
109
- control(n.to_s, 'G')
109
+ cmd = control(n.to_s, 'G')
110
+ cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
111
+ cmd
110
112
  end
111
113
 
112
114
  # Show the cursor
@@ -136,13 +138,17 @@ module CLI
136
138
  # Move to the next line
137
139
  #
138
140
  def self.next_line
139
- cursor_down + control('1', 'G')
141
+ cmd = cursor_down + control('1', 'G')
142
+ cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
143
+ cmd
140
144
  end
141
145
 
142
146
  # Move to the previous line
143
147
  #
144
148
  def self.previous_line
145
- cursor_up + control('1', 'G')
149
+ cmd = cursor_up + control('1', 'G')
150
+ cmd += control('1', 'D') if CLI::UI::OS.current.shift_cursor_on_line_reset?
151
+ cmd
146
152
  end
147
153
 
148
154
  def self.clear_to_end_of_line
@@ -48,6 +48,7 @@ module CLI
48
48
 
49
49
  class InvalidColorName < ArgumentError
50
50
  def initialize(name)
51
+ super
51
52
  @name = name
52
53
  end
53
54
 
@@ -227,11 +227,12 @@ module CLI
227
227
  end
228
228
 
229
229
  # The width of a prefix given the number of Frames in the stack
230
- # Does _not_ account for the space at the end of the final prefix
231
230
  def prefix_width
232
- FrameStack.items.reduce(0) do |width, item|
231
+ w = FrameStack.items.reduce(0) do |width, item|
233
232
  width + item.frame_style.prefix_width
234
233
  end
234
+
235
+ w.zero? ? w : w + 1
235
236
  end
236
237
 
237
238
  # Override a color for a given thread.
@@ -32,6 +32,7 @@ module CLI
32
32
 
33
33
  class InvalidFrameStyleName < ArgumentError
34
34
  def initialize(name)
35
+ super
35
36
  @name = name
36
37
  end
37
38
 
@@ -20,10 +20,6 @@ module CLI
20
20
  VERTICAL
21
21
  end
22
22
 
23
- def prefix_width
24
- CLI::UI::ANSI.printing_width(prefix)
25
- end
26
-
27
23
  # Draws the "Open" line for this frame style
28
24
  #
29
25
  # ==== Attributes
@@ -103,7 +99,10 @@ module CLI
103
99
 
104
100
  preamble_width = CLI::UI::ANSI.printing_width(preamble)
105
101
  preamble_start = Frame.prefix_width
106
- preamble_end = preamble_start + preamble_width
102
+ # If prefix_width is non-zero, we need to subtract the width of
103
+ # the final space, since we're going to write over it.
104
+ preamble_start -= 1 unless preamble_start.zero?
105
+ preamble_end = preamble_start + preamble_width
107
106
 
108
107
  suffix_width = CLI::UI::ANSI.printing_width(suffix)
109
108
  suffix_end = termwidth - 2
@@ -139,6 +138,15 @@ module CLI
139
138
  # reset to column 1 so that things like ^C don't ruin formatting
140
139
  o << "\r"
141
140
 
141
+ # This code will print out a full line with the given preamble and
142
+ # suffix, as exemplified below.
143
+ #
144
+ # preamble_start suffix_start
145
+ # | preamble_end | suffix_end
146
+ # | | | | termwidth
147
+ # | | | | |
148
+ # V V V V V
149
+ # --- Preamble text --------------------- suffix text --
142
150
  o << color.code
143
151
  o << print_at_x(preamble_start, HORIZONTAL * (termwidth - preamble_start)) # draw a full line
144
152
  o << print_at_x(preamble_start, preamble)
@@ -97,8 +97,35 @@ module CLI
97
97
 
98
98
  o = +''
99
99
 
100
- o << color.code << preamble
101
- o << color.code << suffix
100
+ # Shopify's CI system supports terminal emulation, but not some of
101
+ # the fancier features that we normally use to draw frames
102
+ # extra-reliably, so we fall back to a less foolproof strategy. This
103
+ # is probably better in general for cases with impoverished terminal
104
+ # emulators and no active user.
105
+ unless [0, '', nil].include?(ENV['CI'])
106
+ o << color.code << preamble
107
+ o << color.code << suffix
108
+ o << CLI::UI::Color::RESET.code
109
+ o << "\n"
110
+
111
+ return o
112
+ end
113
+
114
+ preamble_start = Frame.prefix_width
115
+
116
+ # If prefix_width is non-zero, we need to subtract the width of
117
+ # the final space, since we're going to write over it.
118
+ preamble_start -= 1 unless preamble_start.zero?
119
+
120
+ # Prefix_width includes the width of the terminal space, which we
121
+ # want to remove. The clamping is done to avoid a negative
122
+ # preamble start which can occur for the first frame.
123
+ o << CLI::UI::ANSI.hide_cursor
124
+
125
+ # reset to column 1 so that things like ^C don't ruin formatting
126
+ o << "\r"
127
+ o << color.code
128
+ o << print_at_x(preamble_start, preamble + color.code + suffix)
102
129
  o << CLI::UI::Color::RESET.code
103
130
  o << "\n"
104
131
 
@@ -5,6 +5,7 @@ module CLI
5
5
  class Glyph
6
6
  class InvalidGlyphHandle < ArgumentError
7
7
  def initialize(handle)
8
+ super
8
9
  @handle = handle
9
10
  end
10
11
 
@@ -15,7 +16,7 @@ module CLI
15
16
  end
16
17
  end
17
18
 
18
- attr_reader :handle, :codepoint, :color, :char, :to_s, :fmt
19
+ attr_reader :handle, :codepoint, :color, :to_s, :fmt
19
20
 
20
21
  # Creates a new glyph
21
22
  #
@@ -23,12 +24,14 @@ module CLI
23
24
  #
24
25
  # * +handle+ - The handle in the +MAP+ constant
25
26
  # * +codepoint+ - The codepoint used to create the glyph (e.g. +0x2717+ for a ballot X)
27
+ # * +plain+ - A fallback plain string to be used in case glyphs are disabled
26
28
  # * +color+ - What color to output the glyph. Check +CLI::UI::Color+ for options.
27
29
  #
28
- def initialize(handle, codepoint, color)
30
+ def initialize(handle, codepoint, plain, color)
29
31
  @handle = handle
30
32
  @codepoint = codepoint
31
33
  @color = color
34
+ @plain = plain
32
35
  @char = Array(codepoint).pack('U*')
33
36
  @to_s = color.code + char + Color::RESET.code
34
37
  @fmt = "{{#{color.name}:#{char}}}"
@@ -36,16 +39,24 @@ module CLI
36
39
  MAP[handle] = self
37
40
  end
38
41
 
42
+ # Fetches the actual character(s) to be displayed for a glyph, based on the current OS support
43
+ #
44
+ # ==== Returns
45
+ # Returns the glyph string
46
+ def char
47
+ CLI::UI::OS.current.supports_emoji? ? @char : @plain
48
+ end
49
+
39
50
  # Mapping of glyphs to terminal output
40
51
  MAP = {}
41
- STAR = new('*', 0x2b51, Color::YELLOW) # YELLOW SMALL STAR (⭑)
42
- INFO = new('i', 0x1d4be, Color::BLUE) # BLUE MATHEMATICAL SCRIPT SMALL i (𝒾)
43
- QUESTION = new('?', 0x003f, Color::BLUE) # BLUE QUESTION MARK (?)
44
- CHECK = new('v', 0x2713, Color::GREEN) # GREEN CHECK MARK (✓)
45
- X = new('x', 0x2717, Color::RED) # RED BALLOT X (✗)
46
- BUG = new('b', 0x1f41b, Color::WHITE) # Bug emoji (🐛)
47
- CHEVRON = new('>', 0xbb, Color::YELLOW) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (»)
48
- HOURGLASS = new('H', [0x231b, 0xfe0e], Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (⌛︎)
52
+ STAR = new('*', 0x2b51, '*', Color::YELLOW) # YELLOW SMALL STAR (⭑)
53
+ INFO = new('i', 0x1d4be, 'i', Color::BLUE) # BLUE MATHEMATICAL SCRIPT SMALL i (𝒾)
54
+ QUESTION = new('?', 0x003f, '?', Color::BLUE) # BLUE QUESTION MARK (?)
55
+ CHECK = new('v', 0x2713, '√', Color::GREEN) # GREEN CHECK MARK (✓)
56
+ X = new('x', 0x2717, 'X', Color::RED) # RED BALLOT X (✗)
57
+ BUG = new('b', 0x1f41b, '!', Color::WHITE) # Bug emoji (🐛)
58
+ CHEVRON = new('>', 0xbb, '»', Color::YELLOW) # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK (»)
59
+ HOURGLASS = new('H', [0x231b, 0xfe0e], 'H', Color::BLUE) # HOURGLASS + VARIATION SELECTOR 15 (⌛︎)
49
60
 
50
61
  # Looks up a glyph by name
51
62
  #
@@ -0,0 +1,63 @@
1
+ module CLI
2
+ module UI
3
+ module OS
4
+ # Determines which OS is currently running the UI, to make it easier to
5
+ # adapt its behaviour to the features of the OS.
6
+ def self.current
7
+ @current_os ||= case RUBY_PLATFORM
8
+ when /darwin/
9
+ Mac
10
+ when /linux/
11
+ Linux
12
+ when /mingw32/
13
+ Windows
14
+ else
15
+ raise "Could not determine OS from platform #{RUBY_PLATFORM}"
16
+ end
17
+ end
18
+
19
+ class Mac
20
+ class << self
21
+ def supports_emoji?
22
+ true
23
+ end
24
+
25
+ def supports_color_prompt?
26
+ true
27
+ end
28
+
29
+ def supports_arrow_keys?
30
+ true
31
+ end
32
+
33
+ def shift_cursor_on_line_reset?
34
+ false
35
+ end
36
+ end
37
+ end
38
+
39
+ class Linux < Mac
40
+ end
41
+
42
+ class Windows
43
+ class << self
44
+ def supports_emoji?
45
+ false
46
+ end
47
+
48
+ def supports_color_prompt?
49
+ false
50
+ end
51
+
52
+ def supports_arrow_keys?
53
+ false
54
+ end
55
+
56
+ def shift_cursor_on_line_reset?
57
+ true
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -190,7 +190,13 @@ module CLI
190
190
  end
191
191
 
192
192
  raise(ArgumentError, 'insufficient options') if options.nil? || options.empty?
193
- instructions = (multiple ? "Toggle options. " : "") + "Choose with ↑ ↓ ⏎"
193
+ navigate_text = if CLI::UI::OS.current.supports_arrow_keys?
194
+ "Choose with ↑ ↓ ⏎"
195
+ else
196
+ "Navigate up with 'k' and down with 'j', press Enter to select"
197
+ end
198
+
199
+ instructions = (multiple ? "Toggle options. " : "") + navigate_text
194
200
  instructions += ", filter with 'f'" if filter_ui
195
201
  instructions += ", enter option with 'e'" if select_ui && (options.size > 9)
196
202
  puts_question("#{question} {{yellow:(#{instructions})}}")
@@ -256,7 +262,10 @@ module CLI
256
262
  # thread to manage output, but the current strategy feels like a
257
263
  # better tradeoff.
258
264
  prefix = CLI::UI.with_frame_color(:blue) { CLI::UI::Frame.prefix }
259
- prompt = prefix + CLI::UI.fmt('{{blue:> }}') + CLI::UI::Color::YELLOW.code
265
+ # If a prompt is interrupted on Windows it locks the colour of the terminal from that point on, so we should
266
+ # not change the colour here.
267
+ prompt = prefix + CLI::UI.fmt('{{blue:> }}')
268
+ prompt += CLI::UI::Color::YELLOW.code if CLI::UI::OS.current.supports_color_prompt?
260
269
 
261
270
  begin
262
271
  line = Readline.readline(prompt, true)
@@ -273,6 +273,7 @@ module CLI
273
273
  case char
274
274
  when ESC ; @state = :esc
275
275
  when "\r", "\n" ; select_current
276
+ when "\b" ; update_search(BACKSPACE) # Happens on Windows
276
277
  else ; update_search(char)
277
278
  end
278
279
  when :line_select
@@ -10,11 +10,11 @@ module CLI
10
10
  PERIOD = 0.1 # seconds
11
11
  TASK_FAILED = :task_failed
12
12
 
13
- RUNES = %w(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏).freeze
13
+ RUNES = CLI::UI::OS.current.supports_emoji? ? %w(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏).freeze : %w(\\ | / - \\ | / -).freeze
14
14
 
15
15
  begin
16
- colors = [CLI::UI::Color::CYAN.code] * 5 + [CLI::UI::Color::MAGENTA.code] * 5
17
- raise unless RUNES.size == colors.size
16
+ colors = [CLI::UI::Color::CYAN.code] * (RUNES.size / 2).ceil +
17
+ [CLI::UI::Color::MAGENTA.code] * (RUNES.size / 2).to_i
18
18
  GLYPHS = colors.zip(RUNES).map(&:join)
19
19
  end
20
20
 
@@ -98,15 +98,13 @@ module CLI
98
98
  #
99
99
  def render(index, force = true, width: CLI::UI::Terminal.width)
100
100
  @m.synchronize do
101
- begin
102
- if force || @always_full_render || @force_full_render
103
- full_render(index, width)
104
- else
105
- partial_render(index)
106
- end
107
- ensure
108
- @force_full_render = false
101
+ if force || @always_full_render || @force_full_render
102
+ full_render(index, width)
103
+ else
104
+ partial_render(index)
109
105
  end
106
+ ensure
107
+ @force_full_render = false
110
108
  end
111
109
  end
112
110
 
@@ -49,6 +49,7 @@ module CLI
49
49
 
50
50
  class InvalidWidgetHandle < ArgumentError
51
51
  def initialize(handle)
52
+ super
52
53
  @handle = handle
53
54
  end
54
55
 
@@ -61,6 +62,7 @@ module CLI
61
62
 
62
63
  class InvalidWidgetArguments < ArgumentError
63
64
  def initialize(argstring, pattern)
65
+ super
64
66
  @argstring = argstring
65
67
  @pattern = pattern
66
68
  end
@@ -0,0 +1,39 @@
1
+ require 'cli/ui'
2
+ require 'cli/kit'
3
+
4
+ CLI::UI::StdoutRouter.enable
5
+
6
+ module Gen
7
+ extend CLI::Kit::Autocall
8
+
9
+ TOOL_NAME = 'cli-kit'
10
+ ROOT = File.expand_path('../../..', __FILE__)
11
+
12
+ TOOL_CONFIG_PATH = File.expand_path(File.join('~', '.config', TOOL_NAME))
13
+ LOG_FILE = File.join(TOOL_CONFIG_PATH, 'logs', 'log.log')
14
+ DEBUG_LOG_FILE = File.join(TOOL_CONFIG_PATH, 'logs', 'debug.log')
15
+
16
+ autoload(:Generator, 'gen/generator')
17
+
18
+ autoload(:EntryPoint, 'gen/entry_point')
19
+ autoload(:Commands, 'gen/commands')
20
+
21
+ autocall(:Config) { CLI::Kit::Config.new(tool_name: TOOL_NAME) }
22
+ autocall(:Command) { CLI::Kit::BaseCommand }
23
+ autocall(:Logger) { CLI::Kit::Logger.new(debug_log_file: DEBUG_LOG_FILE) }
24
+
25
+ autocall(:Executor) { CLI::Kit::Executor.new(log_file: LOG_FILE) }
26
+ autocall(:Resolver) do
27
+ CLI::Kit::Resolver.new(
28
+ tool_name: TOOL_NAME,
29
+ command_registry: Gen::Commands::Registry
30
+ )
31
+ end
32
+
33
+ autocall(:ErrorHandler) do
34
+ CLI::Kit::ErrorHandler.new(
35
+ log_file: LOG_FILE,
36
+ exception_reporter: nil
37
+ )
38
+ end
39
+ end
@@ -0,0 +1,18 @@
1
+ require 'gen'
2
+
3
+ module Gen
4
+ module Commands
5
+ Registry = CLI::Kit::CommandRegistry.new(
6
+ default: 'help',
7
+ contextual_resolver: nil
8
+ )
9
+
10
+ def self.register(const, cmd, path)
11
+ autoload(const, path)
12
+ Registry.add(->() { const_get(const) }, cmd)
13
+ end
14
+
15
+ register :Help, 'help', 'gen/commands/help'
16
+ register :New, 'new', 'gen/commands/new'
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ require 'gen'
2
+
3
+ module Gen
4
+ module Commands
5
+ class Help < Gen::Command
6
+ def call(_args, _name)
7
+ puts CLI::UI.fmt("{{bold:Available commands}}")
8
+ puts ""
9
+
10
+ Gen::Commands::Registry.resolved_commands.each do |name, klass|
11
+ puts CLI::UI.fmt("{{command:#{Gen::TOOL_NAME} #{name}}}")
12
+ if klass.respond_to?(:help) && (help = klass.help)
13
+ puts CLI::UI.fmt(help)
14
+ end
15
+ puts ""
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'gen'
2
+
3
+ module Gen
4
+ module Commands
5
+ class New < Gen::Command
6
+ def call(args, _name)
7
+ unless args.size == 1
8
+ puts CLI::UI.fmt(self.class.help)
9
+ raise(CLI::Kit::AbortSilent)
10
+ end
11
+ project = args.first
12
+
13
+ Gen::Generator.run(project)
14
+ end
15
+
16
+ def self.help
17
+ "Generate a new cli-kit project.\nUsage: {{command:#{Gen::TOOL_NAME} new <name>}}"
18
+ end
19
+ end
20
+ end
21
+ end