renuo-cli 4.21.2 → 4.22.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.
- checksums.yaml +4 -4
- data/README.md +10 -0
- data/lib/renuo/cli/commands/configure_semaphore.rb +3 -1
- data/lib/renuo/cli/commands/create_deploio_app.rb +1 -0
- data/lib/renuo/cli/commands/setup_autocompletion.rb +64 -0
- data/lib/renuo/cli/credentials.yml.enc +1 -0
- data/lib/renuo/cli/helpers/commander_introspector.rb +83 -0
- data/lib/renuo/cli/helpers/credentials_helper.rb +14 -0
- data/lib/renuo/cli/helpers/zsh_completion_script.rb +92 -0
- data/lib/renuo/cli/templates/zsh_completion.erb +61 -0
- data/lib/renuo/cli/version.rb +1 -1
- data/lib/renuo/cli.rb +1 -0
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13ccfc20af1ba9cda74f9ffb3a9b8f24cbbf34808a4d94e5baab28f6da384d26
|
|
4
|
+
data.tar.gz: ac1d41b13a258f07268bb78ed0f6b697eaf4abd2ffe4ae324b4c41880bb253df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72fa17d236d416cb18c8f99d1e463ee8e90c6740102348df812090269c996337fad30a48c953f94ad31fc710f835d311dbf45a8190eb9e982398f7d404d88358
|
|
7
|
+
data.tar.gz: d0cf0de0355ae2b5bef63e1209b74fd818a362072054386106c495035df5c67053b3e1e18a79eecb480812dfe801acc1974b9f8e3d97dc9e198231c42db0ad0d
|
data/README.md
CHANGED
|
@@ -14,6 +14,16 @@ gem install renuo-cli
|
|
|
14
14
|
renuo -h
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
### Shell Autocompletion
|
|
18
|
+
|
|
19
|
+
To enable zsh autocompletion for renuo-cli commands:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
renuo setup-autocompletion
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This will install the completion script and provide instructions to add it to your shell configuration.
|
|
26
|
+
|
|
17
27
|
## Development
|
|
18
28
|
|
|
19
29
|
After checking out the repo, run `bin/setup` to install dependencies.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class Renuo::Cli::Commands::ConfigureSemaphore
|
|
4
|
+
include CredentialsHelper
|
|
5
|
+
|
|
4
6
|
attr_accessor :project_name, :environment, :slack_endpoint
|
|
5
7
|
|
|
6
8
|
command "configure-semaphore" do |c|
|
|
@@ -13,7 +15,7 @@ class Renuo::Cli::Commands::ConfigureSemaphore
|
|
|
13
15
|
|
|
14
16
|
def initialize
|
|
15
17
|
@project_name = File.basename(Dir.getwd)
|
|
16
|
-
@slack_endpoint =
|
|
18
|
+
@slack_endpoint = credentials[:slack_endpoint]
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def run # rubocop:disable Metrics/MethodLength
|
|
@@ -175,6 +175,7 @@ class Renuo::Cli::Commands::CreateDeploioApp # rubocop:disable Metrics/ClassLeng
|
|
|
175
175
|
--basic-auth=#{environment == "develop"} \\
|
|
176
176
|
--build-env=SECRET_KEY_BASE="$(rails secret)" \\
|
|
177
177
|
--language=ruby \\
|
|
178
|
+
--buildpack-stack=heroku \\
|
|
178
179
|
--size=mini
|
|
179
180
|
OUTPUT
|
|
180
181
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../helpers/commander_introspector"
|
|
4
|
+
require_relative "../helpers/zsh_completion_script"
|
|
5
|
+
|
|
6
|
+
class Renuo::Cli::Commands::SetupAutocompletion
|
|
7
|
+
include CommandHelper
|
|
8
|
+
|
|
9
|
+
COMPLETION_DIR = File.expand_path("~/.zfunc")
|
|
10
|
+
COMPLETION_FILENAME = "_renuo"
|
|
11
|
+
COMPLETION_FILE_PATH = File.join(COMPLETION_DIR, COMPLETION_FILENAME)
|
|
12
|
+
VERSION_STAMP_PREFIX = "# renuo-cli-version: "
|
|
13
|
+
|
|
14
|
+
command "setup-autocompletion" do |c|
|
|
15
|
+
c.syntax = "renuo setup-autocompletion"
|
|
16
|
+
c.summary = "Sets up zsh autocompletion for renuo-cli"
|
|
17
|
+
c.description = "Installs zsh autocompletion script for renuo-cli commands and options"
|
|
18
|
+
c.example "renuo setup-autocompletion", "Sets up zsh autocompletion"
|
|
19
|
+
c.action { new.run }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.refresh_if_stale
|
|
23
|
+
return unless File.exist?(COMPLETION_FILE_PATH)
|
|
24
|
+
return if File.foreach(COMPLETION_FILE_PATH).first(2).last&.include?("#{VERSION_STAMP_PREFIX}#{Renuo::Cli::VERSION}")
|
|
25
|
+
|
|
26
|
+
new.write_completion_file(silent: true)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def run
|
|
30
|
+
write_completion_file
|
|
31
|
+
print_installation_instructions
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def write_completion_file(silent: false)
|
|
35
|
+
say "Setting up zsh autocompletion for renuo-cli...".colorize(:green) unless silent
|
|
36
|
+
FileUtils.mkdir_p(COMPLETION_DIR)
|
|
37
|
+
File.write(COMPLETION_FILE_PATH, stamped_script)
|
|
38
|
+
say "✓ Completion script installed to #{COMPLETION_FILE_PATH}".colorize(:green) unless silent
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def stamped_script
|
|
44
|
+
script = completion_script
|
|
45
|
+
first_line, rest = script.split("\n", 2)
|
|
46
|
+
"#{first_line}\n#{VERSION_STAMP_PREFIX}#{Renuo::Cli::VERSION}\n#{rest}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def completion_script
|
|
50
|
+
ZshCompletionScript.new(CommanderIntrospector.commands_data).render
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def print_installation_instructions
|
|
54
|
+
say ""
|
|
55
|
+
say "To enable autocompletion, add the following to your ~/.zshrc:".colorize(:blue)
|
|
56
|
+
say ""
|
|
57
|
+
say " # Enable renuo-cli autocompletion"
|
|
58
|
+
say " fpath+=#{COMPLETION_DIR}"
|
|
59
|
+
say ""
|
|
60
|
+
say "Then restart your shell or run:".colorize(:blue)
|
|
61
|
+
say " exec zsh"
|
|
62
|
+
say "On the next renuo-cli update, the completion script will be automatically refreshed".colorize(:cyan)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kQgNz+OSHLaY1YKXAXJi5Nb/qP2N2+2BHy2anqFasu1HBitNqrEfV+rfFKNfzFY1hNtAezy3SiCA3csD3jsIa7Ew/UHcys493oGNF6p9m07y7/gE+sK4fiQVIRMWxVZ7RPy5qszve+E=--emz3hoXKrKnjz9cq--GxOYIZ9IVxnCjhrg/3kHpQ==
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "shellwords"
|
|
4
|
+
|
|
5
|
+
module CommanderIntrospector
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
HELP_FLAGS = ["-h", "--help"].freeze
|
|
9
|
+
|
|
10
|
+
def commands_data
|
|
11
|
+
runner_commands = Commander::Runner.instance.commands
|
|
12
|
+
entries = runner_commands.reject { |name, _| name.to_s == "help" }
|
|
13
|
+
.map { |name, cmd| build_command_data(name.to_s, cmd) }
|
|
14
|
+
(entries + [help_entry]).sort_by { |cmd| cmd[:name] }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def build_command_data(name, command)
|
|
18
|
+
{
|
|
19
|
+
name: name,
|
|
20
|
+
summary: clean(command.summary),
|
|
21
|
+
description: first_line(clean(command.description.to_s)),
|
|
22
|
+
syntax: command.syntax.to_s,
|
|
23
|
+
options: extract_options(command.options),
|
|
24
|
+
examples: extract_examples(name, command.examples)
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def help_entry
|
|
29
|
+
{
|
|
30
|
+
name: "help",
|
|
31
|
+
summary: "Display global or command help documentation",
|
|
32
|
+
description: "Display global or command help documentation",
|
|
33
|
+
syntax: "renuo help [command]",
|
|
34
|
+
options: [], examples: []
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def extract_options(options) # rubocop:disable Metrics/AbcSize
|
|
39
|
+
options.filter_map do |opt|
|
|
40
|
+
switches = opt[:switches]
|
|
41
|
+
next if switches.intersect?(HELP_FLAGS)
|
|
42
|
+
|
|
43
|
+
long = switches.find { |s| s.start_with?("--") }
|
|
44
|
+
next unless long
|
|
45
|
+
|
|
46
|
+
{
|
|
47
|
+
flags: [switches.find { |s| s.match?(/\A-[^-]/) }, long.split.first].compact,
|
|
48
|
+
description: clean(opt[:description]),
|
|
49
|
+
argument: switches.filter_map { |s| s[/<([^>]+)>/, 1] }.first
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def extract_examples(command_name, examples)
|
|
55
|
+
return [] if examples.blank?
|
|
56
|
+
|
|
57
|
+
prefix = ["renuo", *command_name.split]
|
|
58
|
+
examples.filter_map { |pair| pick_command(pair, prefix) }.uniq
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def pick_command(pair, prefix)
|
|
62
|
+
Array(pair).find do |text|
|
|
63
|
+
next false unless text.is_a?(String)
|
|
64
|
+
|
|
65
|
+
tokens = safe_split(text)
|
|
66
|
+
tokens && tokens.first(prefix.size) == prefix
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def safe_split(text)
|
|
71
|
+
Shellwords.split(text)
|
|
72
|
+
rescue ArgumentError
|
|
73
|
+
nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def clean(text)
|
|
77
|
+
text.to_s.gsub(/['\[\]]/, "").strip
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def first_line(text)
|
|
81
|
+
text.split("\n").map(&:strip).reject(&:empty?).first.to_s
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/encrypted_configuration"
|
|
4
|
+
|
|
5
|
+
module CredentialsHelper
|
|
6
|
+
CONFIG = ActiveSupport::EncryptedConfiguration.new(
|
|
7
|
+
config_path: File.expand_path("../credentials.yml.enc", __dir__),
|
|
8
|
+
key_path: "", env_key: "RENUO_CLI_MASTER_KEY", raise_if_missing_key: true
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
def credentials
|
|
12
|
+
CONFIG.config
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
5
|
+
class ZshCompletionScript
|
|
6
|
+
TEMPLATE_PATH = File.expand_path("../templates/zsh_completion.erb", __dir__)
|
|
7
|
+
|
|
8
|
+
def initialize(commands)
|
|
9
|
+
@commands = commands
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def render
|
|
13
|
+
ERB.new(File.read(TEMPLATE_PATH), trim_mode: "-").result(binding)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def namespaced_groups
|
|
19
|
+
groups.select { |_, sub_commands| sub_commands.first[:subname] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def flat_commands
|
|
23
|
+
groups.reject { |_, sub_commands| sub_commands.first[:subname] }.map { |_, sub_commands| sub_commands.first }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def top_level_entries
|
|
27
|
+
groups.map do |name, sub_commands|
|
|
28
|
+
summary = sub_commands.first[:subname] ? "#{name} subcommands" : sub_commands.first[:summary]
|
|
29
|
+
{ name: name, summary: summary }
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def groups
|
|
34
|
+
@groups ||= @commands.each_with_object({}) do |cmd, acc|
|
|
35
|
+
head, sub = cmd[:name].split(" ", 2)
|
|
36
|
+
key = sub ? head : cmd[:name]
|
|
37
|
+
(acc[key] ||= []) << cmd.merge(subname: sub)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def command_body(cmd, indent:)
|
|
42
|
+
pad = " " * indent
|
|
43
|
+
messages = message_blocks(cmd, pad)
|
|
44
|
+
return [arguments_block(cmd, pad), *messages].join("\n") if cmd[:options].any?
|
|
45
|
+
|
|
46
|
+
inner_messages = message_blocks(cmd, "#{pad} ")
|
|
47
|
+
[
|
|
48
|
+
%(#{pad}if [[ "${words[CURRENT]}" == -* ]]; then),
|
|
49
|
+
%(#{pad} _arguments '--help[show help]'),
|
|
50
|
+
"#{pad}else",
|
|
51
|
+
*inner_messages,
|
|
52
|
+
"#{pad}fi"
|
|
53
|
+
].join("\n")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def message_blocks(cmd, pad) # rubocop:disable Metrics/AbcSize
|
|
57
|
+
blocks = []
|
|
58
|
+
blocks << message_block("syntax", [cmd[:syntax]], pad) unless cmd[:syntax].to_s.empty?
|
|
59
|
+
blocks << message_block("description", [cmd[:description]], pad) unless cmd[:description].to_s.empty?
|
|
60
|
+
blocks << message_block("example", cmd[:examples], pad) unless cmd[:examples].empty?
|
|
61
|
+
blocks
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def arguments_block(cmd, pad)
|
|
65
|
+
specs = ["'--help[show help]'"]
|
|
66
|
+
cmd[:options].each { |opt| specs << option_spec(opt) }
|
|
67
|
+
specs << "'*: :( )'"
|
|
68
|
+
"#{pad}_arguments \\\n#{specs.map { |s| "#{pad} #{s}" }.join(" \\\n")}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def option_spec(option)
|
|
72
|
+
flags = option[:flags]
|
|
73
|
+
bracket = "[#{escape_bracket(option[:description])}]"
|
|
74
|
+
arg_part = option[:argument] ? ":#{option[:argument]}:" : ""
|
|
75
|
+
return "'#{flags.first}#{bracket}#{arg_part}'" if flags.size < 2
|
|
76
|
+
|
|
77
|
+
"'(#{flags.join(" ")})'{#{flags.join(",")}}'#{bracket}#{arg_part}'"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def message_block(header, lines, pad)
|
|
81
|
+
payload = (["-- #{header} --"] + lines + [""]).join("\n")
|
|
82
|
+
"#{pad}_message -r '#{escape_single(payload)}'"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def escape_bracket(text)
|
|
86
|
+
text.to_s.gsub("]") { "\\]" }.gsub("'") { "'\\''" }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def escape_single(text)
|
|
90
|
+
text.to_s.gsub("'") { "'\\''" }
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#compdef renuo
|
|
2
|
+
|
|
3
|
+
_renuo() {
|
|
4
|
+
local curcontext="$curcontext" state
|
|
5
|
+
typeset -A opt_args
|
|
6
|
+
|
|
7
|
+
zstyle ":completion:${curcontext}:*:descriptions" format '\n -- %d --'
|
|
8
|
+
zstyle ":completion:${curcontext}:*" group-name ''
|
|
9
|
+
zstyle ":completion:${curcontext}:*" prefix-needed no
|
|
10
|
+
|
|
11
|
+
_arguments -C \
|
|
12
|
+
'--help[show help]' \
|
|
13
|
+
'--version[show version]' \
|
|
14
|
+
'--trace[show backtrace on error]' \
|
|
15
|
+
'1: :_renuo_commands' \
|
|
16
|
+
'*:: :->args' && return 0
|
|
17
|
+
|
|
18
|
+
case $state in
|
|
19
|
+
args)
|
|
20
|
+
local cmd_key="${words[1]}"
|
|
21
|
+
<% namespaced_groups.each do |group, subs| -%>
|
|
22
|
+
if [[ "$cmd_key" == "<%= group %>" ]]; then
|
|
23
|
+
case "${words[2]}" in
|
|
24
|
+
<% subs.each do |sub| -%>
|
|
25
|
+
<%= sub[:subname] %>)
|
|
26
|
+
<%= command_body(sub, indent: 24) %>
|
|
27
|
+
;;
|
|
28
|
+
<% end -%>
|
|
29
|
+
esac
|
|
30
|
+
return
|
|
31
|
+
fi
|
|
32
|
+
<% end -%>
|
|
33
|
+
case "$cmd_key" in
|
|
34
|
+
<% flat_commands.each do |cmd| -%>
|
|
35
|
+
<%= cmd[:name] %>)
|
|
36
|
+
<% if cmd[:name] == "help" -%>
|
|
37
|
+
_arguments \
|
|
38
|
+
'--help[show help]' \
|
|
39
|
+
'*:command:_renuo_commands'
|
|
40
|
+
<% else -%>
|
|
41
|
+
<%= command_body(cmd, indent: 20) %>
|
|
42
|
+
<% end -%>
|
|
43
|
+
;;
|
|
44
|
+
<% end -%>
|
|
45
|
+
esac
|
|
46
|
+
;;
|
|
47
|
+
esac
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_renuo_commands() {
|
|
51
|
+
local commands
|
|
52
|
+
commands=(
|
|
53
|
+
<% top_level_entries.each do |entry| -%>
|
|
54
|
+
'<%= entry[:name] %>:<%= entry[:summary] %>'
|
|
55
|
+
<% end -%>
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
_describe 'commands' commands
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_renuo "$@"
|
data/lib/renuo/cli/version.rb
CHANGED
data/lib/renuo/cli.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: renuo-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.22.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Renuo AG
|
|
@@ -88,11 +88,16 @@ files:
|
|
|
88
88
|
- lib/renuo/cli/commands/heroku_users.rb
|
|
89
89
|
- lib/renuo/cli/commands/list_large_git_files.rb
|
|
90
90
|
- lib/renuo/cli/commands/release.rb
|
|
91
|
+
- lib/renuo/cli/commands/setup_autocompletion.rb
|
|
91
92
|
- lib/renuo/cli/commands/setup_uptimerobot.rb
|
|
92
93
|
- lib/renuo/cli/commands/upgrade_laptop.rb
|
|
94
|
+
- lib/renuo/cli/credentials.yml.enc
|
|
93
95
|
- lib/renuo/cli/helpers/command_helper.rb
|
|
96
|
+
- lib/renuo/cli/helpers/commander_introspector.rb
|
|
97
|
+
- lib/renuo/cli/helpers/credentials_helper.rb
|
|
94
98
|
- lib/renuo/cli/helpers/environments.rb
|
|
95
99
|
- lib/renuo/cli/helpers/renuo_version.rb
|
|
100
|
+
- lib/renuo/cli/helpers/zsh_completion_script.rb
|
|
96
101
|
- lib/renuo/cli/services/cache.rb
|
|
97
102
|
- lib/renuo/cli/services/cloudfront_config_service.rb
|
|
98
103
|
- lib/renuo/cli/services/deploio.rb
|
|
@@ -106,6 +111,7 @@ files:
|
|
|
106
111
|
- lib/renuo/cli/templates/semaphore/semaphore.yml.erb
|
|
107
112
|
- lib/renuo/cli/templates/slidev/README.md.erb
|
|
108
113
|
- lib/renuo/cli/templates/slidev/package.json.erb
|
|
114
|
+
- lib/renuo/cli/templates/zsh_completion.erb
|
|
109
115
|
- lib/renuo/cli/version.rb
|
|
110
116
|
homepage: https://github.com/renuo/renuo-cli
|
|
111
117
|
licenses:
|