careacademy-runbook 1.2.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 +7 -0
- data/.dockerignore +17 -0
- data/.github/workflows/ruby.yml +43 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Appraisals +8 -0
- data/CHANGELOG.md +143 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +1272 -0
- data/Rakefile +12 -0
- data/TODO.md +316 -0
- data/bin/console +16 -0
- data/bin/setup +8 -0
- data/dockerfiles/Dockerfile-runbook +18 -0
- data/dockerfiles/Dockerfile-sshd +4 -0
- data/examples/hooks_runbook.rb +72 -0
- data/examples/layout_runbook.rb +26 -0
- data/examples/restart_nginx.rb +26 -0
- data/examples/simple_runbook.rb +41 -0
- data/examples/suppress_capture_output.rb +47 -0
- data/exe/runbook +5 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/activesupport_5.gemfile +7 -0
- data/gemfiles/activesupport_6.gemfile +7 -0
- data/images/runbook_anatomy_diagram.png +0 -0
- data/images/runbook_example.gif +0 -0
- data/images/runbook_execution_modes.png +0 -0
- data/lib/hacks/ssh_kit.rb +58 -0
- data/lib/runbook/airbrussh_context.rb +25 -0
- data/lib/runbook/cli.rb +115 -0
- data/lib/runbook/cli_base.rb +38 -0
- data/lib/runbook/configuration.rb +120 -0
- data/lib/runbook/dsl.rb +21 -0
- data/lib/runbook/entities/book.rb +17 -0
- data/lib/runbook/entities/section.rb +7 -0
- data/lib/runbook/entities/setup.rb +7 -0
- data/lib/runbook/entities/step.rb +7 -0
- data/lib/runbook/entity.rb +129 -0
- data/lib/runbook/errors.rb +7 -0
- data/lib/runbook/extensions/add.rb +14 -0
- data/lib/runbook/extensions/description.rb +14 -0
- data/lib/runbook/extensions/sections.rb +19 -0
- data/lib/runbook/extensions/setup.rb +17 -0
- data/lib/runbook/extensions/shared_variables.rb +51 -0
- data/lib/runbook/extensions/ssh_config.rb +78 -0
- data/lib/runbook/extensions/statements.rb +31 -0
- data/lib/runbook/extensions/steps.rb +24 -0
- data/lib/runbook/extensions/tmux.rb +13 -0
- data/lib/runbook/generator.rb +38 -0
- data/lib/runbook/generators/base.rb +45 -0
- data/lib/runbook/generators/dsl_extension/dsl_extension.rb +29 -0
- data/lib/runbook/generators/dsl_extension/templates/dsl_extension.tt +25 -0
- data/lib/runbook/generators/generator/generator.rb +43 -0
- data/lib/runbook/generators/generator/templates/generator.tt +53 -0
- data/lib/runbook/generators/project/project.rb +301 -0
- data/lib/runbook/generators/project/templates/Gemfile.tt +6 -0
- data/lib/runbook/generators/project/templates/README.md.tt +29 -0
- data/lib/runbook/generators/project/templates/Runbookfile.tt +11 -0
- data/lib/runbook/generators/project/templates/base_file.rb.tt +8 -0
- data/lib/runbook/generators/runbook/runbook.rb +22 -0
- data/lib/runbook/generators/runbook/templates/runbook.tt +20 -0
- data/lib/runbook/generators/statement/statement.rb +18 -0
- data/lib/runbook/generators/statement/templates/statement.tt +34 -0
- data/lib/runbook/helpers/format_helper.rb +11 -0
- data/lib/runbook/helpers/ssh_kit_helper.rb +143 -0
- data/lib/runbook/helpers/tmux_helper.rb +176 -0
- data/lib/runbook/hooks.rb +88 -0
- data/lib/runbook/initializer.rb +85 -0
- data/lib/runbook/node.rb +33 -0
- data/lib/runbook/run.rb +290 -0
- data/lib/runbook/runner.rb +66 -0
- data/lib/runbook/runs/ssh_kit.rb +193 -0
- data/lib/runbook/statement.rb +20 -0
- data/lib/runbook/statements/ask.rb +12 -0
- data/lib/runbook/statements/assert.rb +34 -0
- data/lib/runbook/statements/capture.rb +14 -0
- data/lib/runbook/statements/capture_all.rb +14 -0
- data/lib/runbook/statements/command.rb +11 -0
- data/lib/runbook/statements/confirm.rb +10 -0
- data/lib/runbook/statements/description.rb +9 -0
- data/lib/runbook/statements/download.rb +12 -0
- data/lib/runbook/statements/layout.rb +10 -0
- data/lib/runbook/statements/note.rb +10 -0
- data/lib/runbook/statements/notice.rb +10 -0
- data/lib/runbook/statements/ruby_command.rb +9 -0
- data/lib/runbook/statements/tmux_command.rb +11 -0
- data/lib/runbook/statements/upload.rb +12 -0
- data/lib/runbook/statements/wait.rb +10 -0
- data/lib/runbook/toolbox.rb +37 -0
- data/lib/runbook/util/repo.rb +57 -0
- data/lib/runbook/util/runbook.rb +43 -0
- data/lib/runbook/util/sticky_hash.rb +26 -0
- data/lib/runbook/util/stored_pose.rb +55 -0
- data/lib/runbook/version.rb +3 -0
- data/lib/runbook/view.rb +24 -0
- data/lib/runbook/viewer.rb +24 -0
- data/lib/runbook/views/markdown.rb +117 -0
- data/lib/runbook.rb +140 -0
- data/runbook.gemspec +53 -0
- metadata +419 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Runbook::Extensions
|
|
2
|
+
module SSHConfig
|
|
3
|
+
def self.blank_ssh_config
|
|
4
|
+
{
|
|
5
|
+
servers: [],
|
|
6
|
+
parallelization: {},
|
|
7
|
+
}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ssh_config
|
|
11
|
+
@ssh_config ||= Runbook::Extensions::SSHConfig.blank_ssh_config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module DSL
|
|
15
|
+
def ssh_config(&block)
|
|
16
|
+
config = Class.new do
|
|
17
|
+
attr_reader :dsl
|
|
18
|
+
prepend Runbook::Extensions::SSHConfig
|
|
19
|
+
end.new
|
|
20
|
+
dsl_class = Runbook::DSL.class(
|
|
21
|
+
Runbook::Extensions::SSHConfig::DSL,
|
|
22
|
+
)
|
|
23
|
+
config.instance_variable_set(:@dsl, dsl_class.new(config))
|
|
24
|
+
config.dsl.instance_eval(&block)
|
|
25
|
+
config.ssh_config
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def parallelization(strategy: , limit: 2, wait: 2)
|
|
29
|
+
parent.ssh_config[:parallelization] = {
|
|
30
|
+
strategy: strategy,
|
|
31
|
+
limit: limit,
|
|
32
|
+
wait: wait,
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def server(server)
|
|
37
|
+
parent.ssh_config[:servers].clear
|
|
38
|
+
parent.ssh_config[:servers] << server
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def servers(*servers)
|
|
42
|
+
parent.ssh_config[:servers].clear
|
|
43
|
+
servers.flatten.each do |server|
|
|
44
|
+
parent.ssh_config[:servers] << server
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def path(path)
|
|
49
|
+
parent.ssh_config[:path] = path
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def user(user)
|
|
53
|
+
parent.ssh_config[:user] = user
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def group(group)
|
|
57
|
+
parent.ssh_config[:group] = group
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def env(env)
|
|
61
|
+
parent.ssh_config[:env] = env
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def umask(umask)
|
|
65
|
+
parent.ssh_config[:umask] = umask
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
Runbook::Entities::Step.prepend(SSHConfig)
|
|
71
|
+
Runbook::Entities::Step::DSL.prepend(SSHConfig::DSL)
|
|
72
|
+
Runbook::Entities::Section.prepend(SSHConfig)
|
|
73
|
+
Runbook::Entities::Section::DSL.prepend(SSHConfig::DSL)
|
|
74
|
+
Runbook::Entities::Setup.prepend(SSHConfig)
|
|
75
|
+
Runbook::Entities::Setup::DSL.prepend(SSHConfig::DSL)
|
|
76
|
+
Runbook::Entities::Book.prepend(SSHConfig)
|
|
77
|
+
Runbook::Entities::Book::DSL.prepend(SSHConfig::DSL)
|
|
78
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Runbook::Extensions
|
|
2
|
+
module Statements
|
|
3
|
+
module DSL
|
|
4
|
+
ruby2_keywords def method_missing(name, *args, &block)
|
|
5
|
+
if (klass = Statements::DSL._statement_class(name))
|
|
6
|
+
klass.new(*args, &block).tap do |statement|
|
|
7
|
+
parent.add(statement)
|
|
8
|
+
|
|
9
|
+
if statement.respond_to?(:into)
|
|
10
|
+
Runbook.runtime_methods << statement.into
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def respond_to?(name, include_private = false)
|
|
19
|
+
!!(Statements::DSL._statement_class(name) || super)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self._statement_class(name)
|
|
23
|
+
"Runbook::Statements::#{name.to_s.camelize}".constantize
|
|
24
|
+
rescue NameError
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
Runbook::Entities::Setup::DSL.prepend(Statements::DSL)
|
|
30
|
+
Runbook::Entities::Step::DSL.prepend(Statements::DSL)
|
|
31
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Runbook::Extensions
|
|
2
|
+
module Steps
|
|
3
|
+
module DSL
|
|
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|
|
|
15
|
+
parent.add(step)
|
|
16
|
+
step.dsl.instance_eval(&block) if block
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Runbook::Entities::Book::DSL.prepend(Steps::DSL)
|
|
23
|
+
Runbook::Entities::Section::DSL.prepend(Steps::DSL)
|
|
24
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Runbook
|
|
2
|
+
class Generator < Thor
|
|
3
|
+
include Runbook::CLIBase
|
|
4
|
+
include Thor::Actions
|
|
5
|
+
|
|
6
|
+
Runbook::Generators::Base.set_base_options(self)
|
|
7
|
+
|
|
8
|
+
def self._unique_class_options(generator)
|
|
9
|
+
generator.class_options.values.reject do |class_option|
|
|
10
|
+
class_option.group == "Runtime" ||
|
|
11
|
+
class_option.group == "Base"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Runbook.generators.each do |generator|
|
|
16
|
+
desc(generator.usage, generator.description, generator.options)
|
|
17
|
+
|
|
18
|
+
long_desc(generator.long_description)
|
|
19
|
+
|
|
20
|
+
_unique_class_options(generator).each do |co|
|
|
21
|
+
method_option(
|
|
22
|
+
co.name,
|
|
23
|
+
desc: co.description,
|
|
24
|
+
required: co.required,
|
|
25
|
+
default: co.default,
|
|
26
|
+
aliases: co.aliases,
|
|
27
|
+
type: co.type,
|
|
28
|
+
banner: co.banner,
|
|
29
|
+
hide: co.hide,
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
define_method(generator.command) do |*args|
|
|
34
|
+
invoke(generator, args)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Runbook::Generators
|
|
2
|
+
module Base
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend(ClassMethods)
|
|
5
|
+
base.include(Thor::Actions)
|
|
6
|
+
|
|
7
|
+
set_base_options(base)
|
|
8
|
+
base.check_unknown_options!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.set_base_options(base)
|
|
12
|
+
base.class_option(
|
|
13
|
+
:root,
|
|
14
|
+
group: :base,
|
|
15
|
+
default: ".",
|
|
16
|
+
desc: "The root directory for your generated code",
|
|
17
|
+
)
|
|
18
|
+
base.add_runtime_options!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module ClassMethods
|
|
22
|
+
def command
|
|
23
|
+
self.to_s.gsub("Runbook::Generators::", "").underscore
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def usage
|
|
27
|
+
args = arguments.map(&:banner).join(" ")
|
|
28
|
+
args += " " unless args.empty?
|
|
29
|
+
"#{command} #{args}[options]"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def description
|
|
33
|
+
"Generate a #{command}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def long_description
|
|
37
|
+
description
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def options
|
|
41
|
+
{}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Runbook::Generators
|
|
2
|
+
class DslExtension < Thor::Group
|
|
3
|
+
include ::Runbook::Generators::Base
|
|
4
|
+
|
|
5
|
+
source_root File.dirname(__FILE__)
|
|
6
|
+
|
|
7
|
+
def self.description
|
|
8
|
+
"Generate a dsl_extension for adding custom runbook DSL functionality"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.long_description
|
|
12
|
+
<<-LONG_DESC
|
|
13
|
+
This generator provides a template for extending Runbook's DSL. Using a
|
|
14
|
+
DSL extension, you can add custom commands to a book, section, or step
|
|
15
|
+
that can be used in your runbooks.
|
|
16
|
+
LONG_DESC
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
argument :name, desc: "The name of your dsl_extension, e.x. rollback_section"
|
|
20
|
+
|
|
21
|
+
def create_dsl_extension
|
|
22
|
+
target = File.join(
|
|
23
|
+
parent_options[:root],
|
|
24
|
+
"#{name.underscore}.rb",
|
|
25
|
+
)
|
|
26
|
+
template('templates/dsl_extension.tt', target)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Remember to require this file in a runbook config file
|
|
2
|
+
# or in your project so it is available in your runbooks
|
|
3
|
+
# See https://github.com/braintree/runbook/tree/master/lib/runbook/extensions
|
|
4
|
+
# for examples of DSL extensions
|
|
5
|
+
module MyProject::RunbookExtensions
|
|
6
|
+
module <%= name.classify %>
|
|
7
|
+
module DSL
|
|
8
|
+
# def description(msg)
|
|
9
|
+
# Runbook::Statements::Description.new(msg).tap do |desc|
|
|
10
|
+
# # All DSLs can reference their parent object using
|
|
11
|
+
# # the parent method. This allows you to modify the
|
|
12
|
+
# # parent book, section, or step of the DSL
|
|
13
|
+
# parent.add(desc)
|
|
14
|
+
# end
|
|
15
|
+
# end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Uncomment the below statements to add the the DSL methods to
|
|
20
|
+
# Book, Section, and Step DSLs respectively. Now this method can
|
|
21
|
+
# be called from the corresponding DSL in your runbooks
|
|
22
|
+
# Runbook::Entities::Book::DSL.prepend(<%= name.classify %>::DSL)
|
|
23
|
+
# Runbook::Entities::Section::DSL.prepend(<%= name.classify %>::DSL)
|
|
24
|
+
# Runbook::Entities::Step::DSL.prepend(<%= name.classify %>::DSL)
|
|
25
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Runbook::Generators
|
|
2
|
+
class Generator < Thor::Group
|
|
3
|
+
include ::Runbook::Generators::Base
|
|
4
|
+
|
|
5
|
+
source_root File.dirname(__FILE__)
|
|
6
|
+
|
|
7
|
+
def self.usage
|
|
8
|
+
"generator NAME [options]"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.description
|
|
12
|
+
"Generate a runbook generator named NAME, e.x. acme_runbook"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
argument :name, desc: "The name of your generator for populating boilerplate"
|
|
16
|
+
|
|
17
|
+
def create_generator_directory
|
|
18
|
+
target = File.join(
|
|
19
|
+
parent_options[:root],
|
|
20
|
+
name.underscore,
|
|
21
|
+
)
|
|
22
|
+
empty_directory(target)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create_templates_directory
|
|
26
|
+
target = File.join(
|
|
27
|
+
parent_options[:root],
|
|
28
|
+
name.underscore,
|
|
29
|
+
"templates",
|
|
30
|
+
)
|
|
31
|
+
empty_directory(target)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_generator
|
|
35
|
+
target = File.join(
|
|
36
|
+
parent_options[:root],
|
|
37
|
+
name.underscore,
|
|
38
|
+
"#{name.underscore}.rb",
|
|
39
|
+
)
|
|
40
|
+
template('templates/generator.tt', target)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Runbook::Generators
|
|
2
|
+
# Remember to require this class in a runbook config file such as your
|
|
3
|
+
# Runbookfile so it can be used from the command line. Note that you cannot
|
|
4
|
+
# require this generator from a config file specified on the command line.
|
|
5
|
+
class <%= name.classify %> < Thor::Group
|
|
6
|
+
include ::Runbook::Generators::Base
|
|
7
|
+
|
|
8
|
+
source_root File.dirname(__FILE__)
|
|
9
|
+
|
|
10
|
+
# Uncomment this method to customize the generator's usage
|
|
11
|
+
# description in runbook's help description.
|
|
12
|
+
#
|
|
13
|
+
# def self.usage
|
|
14
|
+
# args = arguments.map(&:banner).join(" ")
|
|
15
|
+
# args += " " unless args.empty?
|
|
16
|
+
# "<%= name.underscore %> #{args}[options]"
|
|
17
|
+
# end
|
|
18
|
+
|
|
19
|
+
# Uncomment this method to customize the generator's
|
|
20
|
+
# description in runbook's help message.
|
|
21
|
+
#
|
|
22
|
+
# def self.description
|
|
23
|
+
# "Generate a <%= name %>"
|
|
24
|
+
# end
|
|
25
|
+
|
|
26
|
+
# Uncomment this method to customize the generator's
|
|
27
|
+
# long description in runbook's help message.
|
|
28
|
+
#
|
|
29
|
+
# def self.long_description
|
|
30
|
+
# <<-LONG_DESC
|
|
31
|
+
# Here you can fully describe the options of your generator.
|
|
32
|
+
# LONG_DESC
|
|
33
|
+
# end
|
|
34
|
+
|
|
35
|
+
# Argument example
|
|
36
|
+
# argument :name, desc: "The name of your <%= name.underscore %>, e.x. deploy_nginx"
|
|
37
|
+
|
|
38
|
+
# Option example
|
|
39
|
+
# class_option :include-readme, default: true, type: :boolean
|
|
40
|
+
|
|
41
|
+
# Example of a generator step
|
|
42
|
+
# See: https://github.com/erikhuda/thor/wiki/Generators
|
|
43
|
+
# for further documentation on using thor generators.
|
|
44
|
+
#
|
|
45
|
+
# def create_<%= name.underscore %>
|
|
46
|
+
# target = File.join(
|
|
47
|
+
# parent_options[:root],
|
|
48
|
+
# "#{name.underscore}.rb",
|
|
49
|
+
# )
|
|
50
|
+
# template('templates/<%= name.underscore %>.tt', target)
|
|
51
|
+
# end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
module Runbook::Generators
|
|
2
|
+
class Project < Thor::Group
|
|
3
|
+
include ::Runbook::Generators::Base
|
|
4
|
+
|
|
5
|
+
source_root File.dirname(__FILE__)
|
|
6
|
+
|
|
7
|
+
def self.description
|
|
8
|
+
"Generate a project for your runbooks"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.long_description
|
|
12
|
+
<<-LONG_DESC
|
|
13
|
+
This generator generates a project for your runbooks. It creates a
|
|
14
|
+
project skeleton to hold your runbooks, runbook extensions, shared
|
|
15
|
+
code, configuration, tests, and dependencies.
|
|
16
|
+
LONG_DESC
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
argument :name, desc: "The name of your project, e.x. acme_runbooks"
|
|
20
|
+
|
|
21
|
+
class_option :"shared-lib-dir", type: :string,
|
|
22
|
+
desc: "Target directory for shared runbook code"
|
|
23
|
+
class_option :test, type: :string, enum: ["rspec", "minitest"],
|
|
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"}
|
|
27
|
+
|
|
28
|
+
def init_gem
|
|
29
|
+
bundle_exists = "which bundle 2>&1 1>/dev/null"
|
|
30
|
+
raise "Please ensure bundle is installed" unless system(bundle_exists)
|
|
31
|
+
bundler_version = Gem::Version.new(Bundler::VERSION)
|
|
32
|
+
|
|
33
|
+
inside(parent_options[:root]) do
|
|
34
|
+
test = "--test #{options[:test]}"
|
|
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
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def remove_unneeded_files
|
|
46
|
+
dirs = [
|
|
47
|
+
parent_options[:root],
|
|
48
|
+
_name,
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
gemspec_file = File.join(*dirs, "#{_name}.gemspec")
|
|
52
|
+
if File.exist?(gemspec_file)
|
|
53
|
+
@gemspec_file_contents = File.readlines(gemspec_file)
|
|
54
|
+
end
|
|
55
|
+
remove_file(gemspec_file)
|
|
56
|
+
|
|
57
|
+
readme = File.join(*dirs, "README.md")
|
|
58
|
+
remove_file(readme)
|
|
59
|
+
|
|
60
|
+
gemfile = File.join(*dirs, "Gemfile")
|
|
61
|
+
if File.exist?(gemfile)
|
|
62
|
+
@gemfile_file_contents = File.readlines(gemfile)
|
|
63
|
+
end
|
|
64
|
+
remove_file(gemfile)
|
|
65
|
+
|
|
66
|
+
base_file = File.join(*dirs, "lib", "#{_name}.rb")
|
|
67
|
+
remove_file(base_file)
|
|
68
|
+
|
|
69
|
+
version_file_path = [
|
|
70
|
+
"lib",
|
|
71
|
+
_name,
|
|
72
|
+
"version.rb",
|
|
73
|
+
]
|
|
74
|
+
version_file = File.join(*dirs, *version_file_path)
|
|
75
|
+
remove_file(version_file)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def shared_lib_dir
|
|
79
|
+
msg = [
|
|
80
|
+
"Where should shared runbook code live?",
|
|
81
|
+
"Use `lib/#{_name}` for runbook-only projects",
|
|
82
|
+
"Use `lib/#{_name}/runbook` for projects used for non-runbook tasks",
|
|
83
|
+
"Shared runbook code path:",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
if options.has_key?("shared-lib-dir")
|
|
87
|
+
@shared_lib_dir = options["shared-lib-dir"]
|
|
88
|
+
else
|
|
89
|
+
@shared_lib_dir = ask(msg.join("\n"))
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def create_readme
|
|
94
|
+
target = File.join(
|
|
95
|
+
parent_options[:root],
|
|
96
|
+
_name,
|
|
97
|
+
"README.md",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
template("templates/README.md.tt", target)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def create_gemfile
|
|
104
|
+
target = File.join(
|
|
105
|
+
parent_options[:root],
|
|
106
|
+
_name,
|
|
107
|
+
"Gemfile",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
template("templates/Gemfile.tt", target)
|
|
111
|
+
|
|
112
|
+
# Add development dependencies from gemspec
|
|
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
|
+
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def create_base_file
|
|
135
|
+
target = File.join(
|
|
136
|
+
parent_options[:root],
|
|
137
|
+
_name,
|
|
138
|
+
"lib",
|
|
139
|
+
"#{_name}.rb",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
template("templates/base_file.rb.tt", target)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def modify_rakefile
|
|
146
|
+
target = File.join(
|
|
147
|
+
parent_options[:root],
|
|
148
|
+
_name,
|
|
149
|
+
"Rakefile",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
gsub_file(target, /^require "bundler\/gem_tasks"\n/, "", verbose: false)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def create_ruby_version
|
|
156
|
+
target = File.join(
|
|
157
|
+
parent_options[:root],
|
|
158
|
+
_name,
|
|
159
|
+
".ruby-version",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
create_file(target, "ruby-#{RUBY_VERSION}\n")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def create_ruby_gemset
|
|
166
|
+
target = File.join(
|
|
167
|
+
parent_options[:root],
|
|
168
|
+
_name,
|
|
169
|
+
".ruby-gemset",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
create_file(target, "#{_name}\n")
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def create_runbookfile
|
|
176
|
+
target = File.join(
|
|
177
|
+
parent_options[:root],
|
|
178
|
+
_name,
|
|
179
|
+
"Runbookfile",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
template("templates/Runbookfile.tt", target)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def create_runbooks_directory
|
|
186
|
+
dirs = [
|
|
187
|
+
parent_options[:root],
|
|
188
|
+
_name,
|
|
189
|
+
"runbooks",
|
|
190
|
+
]
|
|
191
|
+
target = File.join(*dirs)
|
|
192
|
+
|
|
193
|
+
empty_directory(target)
|
|
194
|
+
_keep_dir(target)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def create_extensions_directory
|
|
198
|
+
dirs = [
|
|
199
|
+
parent_options[:root],
|
|
200
|
+
_name,
|
|
201
|
+
"lib",
|
|
202
|
+
"runbook",
|
|
203
|
+
"extensions",
|
|
204
|
+
]
|
|
205
|
+
target = File.join(*dirs)
|
|
206
|
+
|
|
207
|
+
empty_directory(target)
|
|
208
|
+
_keep_dir(target)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def create_generators_directory
|
|
212
|
+
dirs = [
|
|
213
|
+
parent_options[:root],
|
|
214
|
+
_name,
|
|
215
|
+
"lib",
|
|
216
|
+
"runbook",
|
|
217
|
+
"generators",
|
|
218
|
+
]
|
|
219
|
+
target = File.join(*dirs)
|
|
220
|
+
|
|
221
|
+
empty_directory(target)
|
|
222
|
+
_keep_dir(target)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def create_lib_directory
|
|
226
|
+
dirs = [
|
|
227
|
+
parent_options[:root],
|
|
228
|
+
_name,
|
|
229
|
+
@shared_lib_dir,
|
|
230
|
+
]
|
|
231
|
+
target = File.join(*dirs)
|
|
232
|
+
|
|
233
|
+
empty_directory(target)
|
|
234
|
+
_keep_dir(target)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def update_bin_console
|
|
238
|
+
path = [
|
|
239
|
+
parent_options[:root],
|
|
240
|
+
_name,
|
|
241
|
+
"bin",
|
|
242
|
+
"console",
|
|
243
|
+
]
|
|
244
|
+
target = File.join(*path)
|
|
245
|
+
|
|
246
|
+
old_require = /require "#{_name}"/
|
|
247
|
+
new_require = %Q(require_relative "../lib/#{_name}")
|
|
248
|
+
new_require += "\n\nRunbook::Configuration.load_config"
|
|
249
|
+
gsub_file(target, old_require, new_require, verbose: false)
|
|
250
|
+
|
|
251
|
+
old_require = /require "#{_name}"/
|
|
252
|
+
new_require = %Q(require_relative "../lib/#{_name}")
|
|
253
|
+
gsub_file(target, old_require, new_require, verbose: false)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def remove_bad_test
|
|
257
|
+
path = [
|
|
258
|
+
parent_options[:root],
|
|
259
|
+
_name,
|
|
260
|
+
]
|
|
261
|
+
|
|
262
|
+
case options["test"]
|
|
263
|
+
when "rspec"
|
|
264
|
+
path << "spec"
|
|
265
|
+
path << "#{_name}_spec.rb"
|
|
266
|
+
when "minitest"
|
|
267
|
+
path << "test"
|
|
268
|
+
path << "#{_name}_test.rb"
|
|
269
|
+
end
|
|
270
|
+
target = File.join(*path)
|
|
271
|
+
|
|
272
|
+
bad_test = / .*version.*\n.*\n end\n\n/m
|
|
273
|
+
gsub_file(target, bad_test, "", verbose: false)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def runbook_project_overview
|
|
277
|
+
msg = [
|
|
278
|
+
"",
|
|
279
|
+
"Your runbook project was successfully created.",
|
|
280
|
+
"Remember to run `./bin/setup` in your project to install dependencies.",
|
|
281
|
+
"Add runbooks to the `runbooks` directory.",
|
|
282
|
+
"Add shared code to `#{@shared_lib_dir}`.",
|
|
283
|
+
"Execute runbooks using `bundle exec runbook exec <RUNBOOK_PATH>` from your project root.",
|
|
284
|
+
"See the README.md for more details.",
|
|
285
|
+
"\n",
|
|
286
|
+
]
|
|
287
|
+
|
|
288
|
+
say(msg.join("\n"))
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
private
|
|
292
|
+
|
|
293
|
+
def _name
|
|
294
|
+
@name ||= name.underscore
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def _keep_dir(dir)
|
|
298
|
+
create_file(File.join(dir, ".keep"), verbose: false)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|