runbook 0.14.0 → 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.
- checksums.yaml +4 -4
- data/.dockerignore +17 -0
- data/.gitignore +4 -0
- data/.ruby-version +1 -1
- data/.travis.yml +23 -7
- data/Appraisals +8 -0
- data/CHANGELOG.md +71 -0
- data/README.md +159 -25
- data/Rakefile +7 -1
- data/TODO.md +316 -46
- data/dockerfiles/Dockerfile-runbook +18 -0
- data/dockerfiles/Dockerfile-sshd +4 -0
- data/{samples → examples}/hooks_runbook.rb +0 -0
- data/{samples → examples}/layout_runbook.rb +0 -0
- data/{samples → examples}/restart_nginx.rb +0 -0
- data/{samples → examples}/simple_runbook.rb +0 -0
- data/examples/suppress_capture_output.rb +47 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/activesupport_5.gemfile +7 -0
- data/gemfiles/activesupport_6.gemfile +7 -0
- data/lib/runbook.rb +28 -6
- data/lib/runbook/airbrussh_context.rb +25 -0
- data/lib/runbook/cli.rb +17 -13
- data/lib/runbook/configuration.rb +7 -1
- data/lib/runbook/entities/book.rb +2 -2
- data/lib/runbook/entities/section.rb +2 -2
- data/lib/runbook/entities/setup.rb +7 -0
- data/lib/runbook/entities/step.rb +2 -2
- data/lib/runbook/entity.rb +7 -5
- data/lib/runbook/extensions/add.rb +1 -0
- data/lib/runbook/extensions/sections.rb +6 -2
- data/lib/runbook/extensions/setup.rb +17 -0
- data/lib/runbook/extensions/ssh_config.rb +2 -0
- data/lib/runbook/extensions/statements.rb +6 -1
- data/lib/runbook/extensions/steps.rb +12 -2
- data/lib/runbook/generators/project/project.rb +32 -9
- data/lib/runbook/helpers/tmux_helper.rb +6 -4
- data/lib/runbook/node.rb +10 -0
- data/lib/runbook/run.rb +14 -8
- data/lib/runbook/runner.rb +2 -0
- data/lib/runbook/runs/ssh_kit.rb +20 -13
- data/lib/runbook/statement.rb +0 -2
- data/lib/runbook/statements/ask.rb +3 -2
- data/lib/runbook/statements/assert.rb +11 -2
- data/lib/runbook/toolbox.rb +3 -9
- data/lib/runbook/util/repo.rb +4 -3
- data/lib/runbook/util/runbook.rb +4 -0
- data/lib/runbook/util/stored_pose.rb +4 -3
- data/lib/runbook/version.rb +1 -1
- data/lib/runbook/views/markdown.rb +15 -7
- data/runbook.gemspec +12 -8
- metadata +108 -29
data/lib/runbook.rb
CHANGED
@@ -2,8 +2,10 @@ require "tmpdir"
|
|
2
2
|
require "yaml"
|
3
3
|
require "thread"
|
4
4
|
|
5
|
+
require "active_support/deprecation"
|
5
6
|
require "active_support/inflector"
|
6
7
|
require "method_source"
|
8
|
+
require "ruby2_keywords"
|
7
9
|
require "pastel"
|
8
10
|
require "sshkit"
|
9
11
|
require "sshkit/sudo"
|
@@ -12,6 +14,8 @@ require "tty-progressbar"
|
|
12
14
|
require "tty-prompt"
|
13
15
|
require "thor/group"
|
14
16
|
|
17
|
+
require "runbook/airbrussh_context"
|
18
|
+
|
15
19
|
require "runbook/configuration"
|
16
20
|
|
17
21
|
require "hacks/ssh_kit"
|
@@ -30,6 +34,7 @@ require "runbook/node"
|
|
30
34
|
require "runbook/entity"
|
31
35
|
require "runbook/entities/book"
|
32
36
|
require "runbook/entities/section"
|
37
|
+
require "runbook/entities/setup"
|
33
38
|
require "runbook/entities/step"
|
34
39
|
|
35
40
|
require "runbook/statement"
|
@@ -74,6 +79,7 @@ require "runbook/extensions/add"
|
|
74
79
|
require "runbook/extensions/description"
|
75
80
|
require "runbook/extensions/shared_variables"
|
76
81
|
require "runbook/extensions/sections"
|
82
|
+
require "runbook/extensions/setup"
|
77
83
|
require "runbook/extensions/ssh_config"
|
78
84
|
require "runbook/extensions/statements"
|
79
85
|
require "runbook/extensions/steps"
|
@@ -86,24 +92,36 @@ ActiveSupport::Inflector.inflections(:en) do |inflect|
|
|
86
92
|
end
|
87
93
|
|
88
94
|
module Runbook
|
89
|
-
def self.book(title, &block)
|
95
|
+
def self.book(title, *tags, labels: {}, &block)
|
90
96
|
Configuration.load_config
|
91
|
-
Entities::Book.new(title).tap do |book|
|
97
|
+
Entities::Book.new(title, tags: tags, labels: labels).tap do |book|
|
92
98
|
book.dsl.instance_eval(&block)
|
93
99
|
register(book)
|
94
100
|
end
|
95
101
|
end
|
96
102
|
|
97
|
-
def self.section(title, &block)
|
103
|
+
def self.section(title, *tags, labels: {}, &block)
|
98
104
|
Configuration.load_config
|
99
|
-
Entities::Section.new(title).tap do |section|
|
105
|
+
Entities::Section.new(title, tags: tags, labels: labels).tap do |section|
|
100
106
|
section.dsl.instance_eval(&block)
|
101
107
|
end
|
102
108
|
end
|
103
109
|
|
104
|
-
def self.
|
110
|
+
def self.setup(*tags, labels: {}, &block)
|
105
111
|
Configuration.load_config
|
106
|
-
Entities::
|
112
|
+
Entities::Setup.new(tags: tags, labels: labels).tap do |setup|
|
113
|
+
setup.dsl.instance_eval(&block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.step(title=nil, *tags, labels: {}, &block)
|
118
|
+
if title.is_a?(Symbol)
|
119
|
+
tags.unshift(title)
|
120
|
+
title = nil
|
121
|
+
end
|
122
|
+
|
123
|
+
Configuration.load_config
|
124
|
+
Entities::Step.new(title, tags: tags, labels: labels).tap do |step|
|
107
125
|
step.dsl.instance_eval(&block) if block
|
108
126
|
end
|
109
127
|
end
|
@@ -115,4 +133,8 @@ module Runbook
|
|
115
133
|
def self.books
|
116
134
|
@books ||= []
|
117
135
|
end
|
136
|
+
|
137
|
+
def self.runtime_methods
|
138
|
+
@runtime_methods ||= []
|
139
|
+
end
|
118
140
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Runbook
|
2
|
+
class AirbrusshContext
|
3
|
+
attr_reader :history, :current_task_name
|
4
|
+
|
5
|
+
def initialize(config=Airbrussh.configuration)
|
6
|
+
@history = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def register_new_command(command)
|
10
|
+
hist_entry = command.to_s
|
11
|
+
first_execution = history.last != hist_entry
|
12
|
+
history << hist_entry if first_execution
|
13
|
+
first_execution
|
14
|
+
end
|
15
|
+
|
16
|
+
def position(command)
|
17
|
+
history.rindex(command.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_current_task_name(task_name)
|
21
|
+
@current_task_name = task_name
|
22
|
+
history.clear
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/runbook/cli.rb
CHANGED
@@ -82,17 +82,6 @@ module Runbook
|
|
82
82
|
invoke(Runbook::Initializer)
|
83
83
|
end
|
84
84
|
|
85
|
-
desc "install", "Install Runbook in an existing project", hide: true
|
86
|
-
Runbook::Initializer.class_options.values.each do |co|
|
87
|
-
method_option co.name, desc: co.description, required: co.required,
|
88
|
-
default: co.default, aliases: co.aliases, type: co.type,
|
89
|
-
banner: co.banner, hide: co.hide
|
90
|
-
end
|
91
|
-
def install
|
92
|
-
Runbook.deprecator.deprecation_warning(:install, :init)
|
93
|
-
invoke(Runbook::Initializer)
|
94
|
-
end
|
95
|
-
|
96
85
|
desc "--version", "Print runbook's version"
|
97
86
|
def __print_version
|
98
87
|
puts "Runbook v#{Runbook::VERSION}"
|
@@ -104,8 +93,23 @@ module Runbook
|
|
104
93
|
unless File.exist?(runbook)
|
105
94
|
raise Thor::InvocationError, "#{cmd}: cannot access #{runbook}: No such file or directory"
|
106
95
|
end
|
107
|
-
|
108
|
-
|
96
|
+
|
97
|
+
begin
|
98
|
+
load(runbook)
|
99
|
+
Runbook.books.last || eval(File.read(runbook))
|
100
|
+
rescue NameError => e
|
101
|
+
if Runbook.runtime_methods.include?(e.name)
|
102
|
+
message = (
|
103
|
+
"Runtime method `#{e.name}` cannot be referenced at " \
|
104
|
+
"compile time. Wrap statements referencing it in a " \
|
105
|
+
"`ruby_command` block in order to invoke the code at " \
|
106
|
+
"runtime."
|
107
|
+
)
|
108
|
+
raise e, message, e.backtrace
|
109
|
+
end
|
110
|
+
|
111
|
+
raise e
|
112
|
+
end
|
109
113
|
end
|
110
114
|
end
|
111
115
|
end
|
@@ -19,6 +19,7 @@ module Runbook
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class Configuration
|
22
|
+
attr_accessor :_airbrussh_context
|
22
23
|
attr_accessor :ssh_kit
|
23
24
|
attr_accessor :enable_sudo_prompt
|
24
25
|
attr_reader :use_same_sudo_password
|
@@ -89,11 +90,16 @@ module Runbook
|
|
89
90
|
|
90
91
|
def initialize
|
91
92
|
self.ssh_kit = SSHKit.config
|
92
|
-
|
93
|
+
formatter = Airbrussh::Formatter.new(
|
93
94
|
$stdout,
|
94
95
|
banner: nil,
|
95
96
|
command_output: true,
|
97
|
+
context: AirbrusshContext,
|
96
98
|
)
|
99
|
+
ssh_kit.output = formatter
|
100
|
+
self._airbrussh_context = formatter.formatters.find do |fmt|
|
101
|
+
fmt.is_a?(Airbrussh::ConsoleFormatter)
|
102
|
+
end.context
|
97
103
|
self.enable_sudo_prompt = true
|
98
104
|
self.use_same_sudo_password = true
|
99
105
|
end
|
data/lib/runbook/entity.rb
CHANGED
@@ -7,11 +7,12 @@ module Runbook
|
|
7
7
|
child_class.const_set(:DSL, Runbook::DSL.class)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
attr_reader :title, :dsl
|
10
|
+
attr_reader :title, :tags, :labels, :dsl
|
12
11
|
|
13
|
-
def initialize(title, parent: nil)
|
12
|
+
def initialize(title, tags: [], labels: {}, parent: nil)
|
14
13
|
@title = title
|
14
|
+
@tags = tags
|
15
|
+
@labels = labels
|
15
16
|
@parent = parent
|
16
17
|
@dsl = "#{self.class}::DSL".constantize.new(self)
|
17
18
|
end
|
@@ -25,7 +26,7 @@ module Runbook
|
|
25
26
|
@items ||= []
|
26
27
|
end
|
27
28
|
|
28
|
-
def method_missing(method, *args, &block)
|
29
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
29
30
|
if dsl.respond_to?(method)
|
30
31
|
dsl.send(method, *args, &block)
|
31
32
|
else
|
@@ -92,7 +93,8 @@ module Runbook
|
|
92
93
|
|
93
94
|
def _run_metadata(items, item, metadata, index)
|
94
95
|
pos_index = items.select do |item|
|
95
|
-
item.is_a?(Entity)
|
96
|
+
item.is_a?(Entity) &&
|
97
|
+
!item.is_a?(Runbook::Entities::Setup)
|
96
98
|
end.index(item)
|
97
99
|
|
98
100
|
if pos_index
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module Runbook::Extensions
|
2
2
|
module Sections
|
3
3
|
module DSL
|
4
|
-
def section(title, &block)
|
5
|
-
Runbook::Entities::Section.new(
|
4
|
+
def section(title, *tags, labels: {}, &block)
|
5
|
+
Runbook::Entities::Section.new(
|
6
|
+
title,
|
7
|
+
tags: tags,
|
8
|
+
labels: labels,
|
9
|
+
).tap do |section|
|
6
10
|
parent.add(section)
|
7
11
|
section.dsl.instance_eval(&block)
|
8
12
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Runbook::Extensions
|
2
|
+
module Setup
|
3
|
+
module DSL
|
4
|
+
def setup(*tags, labels: {}, &block)
|
5
|
+
Runbook::Entities::Setup.new(
|
6
|
+
tags: tags,
|
7
|
+
labels: labels,
|
8
|
+
).tap do |setup|
|
9
|
+
parent.add(setup)
|
10
|
+
setup.dsl.instance_eval(&block) if block
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Runbook::Entities::Book::DSL.prepend(Setup::DSL)
|
17
|
+
end
|
@@ -71,6 +71,8 @@ module Runbook::Extensions
|
|
71
71
|
Runbook::Entities::Step::DSL.prepend(SSHConfig::DSL)
|
72
72
|
Runbook::Entities::Section.prepend(SSHConfig)
|
73
73
|
Runbook::Entities::Section::DSL.prepend(SSHConfig::DSL)
|
74
|
+
Runbook::Entities::Setup.prepend(SSHConfig)
|
75
|
+
Runbook::Entities::Setup::DSL.prepend(SSHConfig::DSL)
|
74
76
|
Runbook::Entities::Book.prepend(SSHConfig)
|
75
77
|
Runbook::Entities::Book::DSL.prepend(SSHConfig::DSL)
|
76
78
|
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Runbook::Extensions
|
2
2
|
module Statements
|
3
3
|
module DSL
|
4
|
-
def method_missing(name, *args, &block)
|
4
|
+
ruby2_keywords def method_missing(name, *args, &block)
|
5
5
|
if (klass = Statements::DSL._statement_class(name))
|
6
6
|
klass.new(*args, &block).tap do |statement|
|
7
7
|
parent.add(statement)
|
8
|
+
|
9
|
+
if statement.respond_to?(:into)
|
10
|
+
Runbook.runtime_methods << statement.into
|
11
|
+
end
|
8
12
|
end
|
9
13
|
else
|
10
14
|
super
|
@@ -22,5 +26,6 @@ module Runbook::Extensions
|
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
29
|
+
Runbook::Entities::Setup::DSL.prepend(Statements::DSL)
|
25
30
|
Runbook::Entities::Step::DSL.prepend(Statements::DSL)
|
26
31
|
end
|
@@ -1,8 +1,17 @@
|
|
1
1
|
module Runbook::Extensions
|
2
2
|
module Steps
|
3
3
|
module DSL
|
4
|
-
def step(title=nil, &block)
|
5
|
-
|
4
|
+
def step(title=nil, *tags, labels: {}, &block)
|
5
|
+
if title.is_a?(Symbol)
|
6
|
+
tags.unshift(title)
|
7
|
+
title = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
Runbook::Entities::Step.new(
|
11
|
+
title,
|
12
|
+
tags: tags,
|
13
|
+
labels: labels,
|
14
|
+
).tap do |step|
|
6
15
|
parent.add(step)
|
7
16
|
step.dsl.instance_eval(&block) if block
|
8
17
|
end
|
@@ -10,5 +19,6 @@ module Runbook::Extensions
|
|
10
19
|
end
|
11
20
|
end
|
12
21
|
|
22
|
+
Runbook::Entities::Book::DSL.prepend(Steps::DSL)
|
13
23
|
Runbook::Entities::Section::DSL.prepend(Steps::DSL)
|
14
24
|
end
|
@@ -22,14 +22,23 @@ module Runbook::Generators
|
|
22
22
|
desc: "Target directory for shared runbook code"
|
23
23
|
class_option :test, type: :string, enum: ["rspec", "minitest"],
|
24
24
|
default: "rspec", desc: %Q{Test-suite, "rspec" or "minitest"}
|
25
|
+
class_option :ci, type: :string, enum: ["github", "travis", "gitlab", "circle"],
|
26
|
+
default: "github", desc: %Q{CI Service, "github", "travis", "gitlab", or "circle"}
|
25
27
|
|
26
28
|
def init_gem
|
27
29
|
bundle_exists = "which bundle 2>&1 1>/dev/null"
|
28
30
|
raise "Please ensure bundle is installed" unless system(bundle_exists)
|
31
|
+
bundler_version = Gem::Version.new(Bundler::VERSION)
|
29
32
|
|
30
33
|
inside(parent_options[:root]) do
|
31
34
|
test = "--test #{options[:test]}"
|
32
|
-
|
35
|
+
ci = "--ci #{options[:ci]}"
|
36
|
+
changelog = "--no-changelog" if bundler_version >= Gem::Version.new("2.2.8")
|
37
|
+
continue = (
|
38
|
+
run("bundle gem #{_name} #{test} #{ci} --rubocop #{changelog} --no-coc --no-mit") ||
|
39
|
+
options[:pretend]
|
40
|
+
)
|
41
|
+
exit 1 unless continue
|
33
42
|
end
|
34
43
|
end
|
35
44
|
|
@@ -49,6 +58,9 @@ module Runbook::Generators
|
|
49
58
|
remove_file(readme)
|
50
59
|
|
51
60
|
gemfile = File.join(*dirs, "Gemfile")
|
61
|
+
if File.exist?(gemfile)
|
62
|
+
@gemfile_file_contents = File.readlines(gemfile)
|
63
|
+
end
|
52
64
|
remove_file(gemfile)
|
53
65
|
|
54
66
|
base_file = File.join(*dirs, "lib", "#{_name}.rb")
|
@@ -98,14 +110,25 @@ module Runbook::Generators
|
|
98
110
|
template("templates/Gemfile.tt", target)
|
99
111
|
|
100
112
|
# Add development dependencies from gemspec
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
113
|
+
if @gemspec_file_contents
|
114
|
+
gems = @gemspec_file_contents.select do |line|
|
115
|
+
line =~ / spec.add_development_dependency/
|
116
|
+
end.map do |line|
|
117
|
+
line.gsub(/ spec.add_development_dependency/, "gem")
|
118
|
+
end.join
|
119
|
+
|
120
|
+
append_to_file(target, "\n#{gems}", verbose: false)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Add gemfile gems
|
124
|
+
if @gemfile_file_contents
|
125
|
+
gems = @gemfile_file_contents.select do |line|
|
126
|
+
line =~ /^gem /
|
127
|
+
end.join
|
128
|
+
|
129
|
+
append_to_file(target, "\n#{gems}", verbose: false)
|
130
|
+
end
|
131
|
+
|
109
132
|
end
|
110
133
|
|
111
134
|
def create_base_file
|