runbook 0.12.1 → 0.13.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.
@@ -0,0 +1,278 @@
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
+
26
+ def init_gem
27
+ bundle_exists = "which bundle 2>&1 1>/dev/null"
28
+ raise "Please ensure bundle is installed" unless system(bundle_exists)
29
+
30
+ inside(parent_options[:root]) do
31
+ test = "--test #{options[:test]}"
32
+ run("bundle gem #{_name} #{test} --no-coc --no-mit")
33
+ end
34
+ end
35
+
36
+ def remove_unneeded_files
37
+ dirs = [
38
+ parent_options[:root],
39
+ _name,
40
+ ]
41
+
42
+ gemspec_file = File.join(*dirs, "#{_name}.gemspec")
43
+ if File.exist?(gemspec_file)
44
+ @gemspec_file_contents = File.readlines(gemspec_file)
45
+ end
46
+ remove_file(gemspec_file)
47
+
48
+ readme = File.join(*dirs, "README.md")
49
+ remove_file(readme)
50
+
51
+ gemfile = File.join(*dirs, "Gemfile")
52
+ remove_file(gemfile)
53
+
54
+ base_file = File.join(*dirs, "lib", "#{_name}.rb")
55
+ remove_file(base_file)
56
+
57
+ version_file_path = [
58
+ "lib",
59
+ _name,
60
+ "version.rb",
61
+ ]
62
+ version_file = File.join(*dirs, *version_file_path)
63
+ remove_file(version_file)
64
+ end
65
+
66
+ def shared_lib_dir
67
+ msg = [
68
+ "Where should shared runbook code live?",
69
+ "Use `lib/#{_name}` for runbook-only projects",
70
+ "Use `lib/#{_name}/runbook` for projects used for non-runbook tasks",
71
+ "Shared runbook code path:",
72
+ ]
73
+
74
+ if options.has_key?("shared-lib-dir")
75
+ @shared_lib_dir = options["shared-lib-dir"]
76
+ else
77
+ @shared_lib_dir = ask(msg.join("\n"))
78
+ end
79
+ end
80
+
81
+ def create_readme
82
+ target = File.join(
83
+ parent_options[:root],
84
+ _name,
85
+ "README.md",
86
+ )
87
+
88
+ template("templates/README.md.tt", target)
89
+ end
90
+
91
+ def create_gemfile
92
+ target = File.join(
93
+ parent_options[:root],
94
+ _name,
95
+ "Gemfile",
96
+ )
97
+
98
+ template("templates/Gemfile.tt", target)
99
+
100
+ # Add development dependencies from gemspec
101
+ return unless @gemspec_file_contents
102
+ gems = @gemspec_file_contents.select do |line|
103
+ line =~ / spec.add_development_dependency/
104
+ end.map do |line|
105
+ line.gsub(/ spec.add_development_dependency/, "gem")
106
+ end.join
107
+
108
+ append_to_file(target, "\n#{gems}", verbose: false)
109
+ end
110
+
111
+ def create_base_file
112
+ target = File.join(
113
+ parent_options[:root],
114
+ _name,
115
+ "lib",
116
+ "#{_name}.rb",
117
+ )
118
+
119
+ template("templates/base_file.rb.tt", target)
120
+ end
121
+
122
+ def modify_rakefile
123
+ target = File.join(
124
+ parent_options[:root],
125
+ _name,
126
+ "Rakefile",
127
+ )
128
+
129
+ gsub_file(target, /^require "bundler\/gem_tasks"\n/, "", verbose: false)
130
+ end
131
+
132
+ def create_ruby_version
133
+ target = File.join(
134
+ parent_options[:root],
135
+ _name,
136
+ ".ruby-version",
137
+ )
138
+
139
+ create_file(target, "ruby-#{RUBY_VERSION}\n")
140
+ end
141
+
142
+ def create_ruby_gemset
143
+ target = File.join(
144
+ parent_options[:root],
145
+ _name,
146
+ ".ruby-gemset",
147
+ )
148
+
149
+ create_file(target, "#{_name}\n")
150
+ end
151
+
152
+ def create_runbookfile
153
+ target = File.join(
154
+ parent_options[:root],
155
+ _name,
156
+ "Runbookfile",
157
+ )
158
+
159
+ template("templates/Runbookfile.tt", target)
160
+ end
161
+
162
+ def create_runbooks_directory
163
+ dirs = [
164
+ parent_options[:root],
165
+ _name,
166
+ "runbooks",
167
+ ]
168
+ target = File.join(*dirs)
169
+
170
+ empty_directory(target)
171
+ _keep_dir(target)
172
+ end
173
+
174
+ def create_extensions_directory
175
+ dirs = [
176
+ parent_options[:root],
177
+ _name,
178
+ "lib",
179
+ "runbook",
180
+ "extensions",
181
+ ]
182
+ target = File.join(*dirs)
183
+
184
+ empty_directory(target)
185
+ _keep_dir(target)
186
+ end
187
+
188
+ def create_generators_directory
189
+ dirs = [
190
+ parent_options[:root],
191
+ _name,
192
+ "lib",
193
+ "runbook",
194
+ "generators",
195
+ ]
196
+ target = File.join(*dirs)
197
+
198
+ empty_directory(target)
199
+ _keep_dir(target)
200
+ end
201
+
202
+ def create_lib_directory
203
+ dirs = [
204
+ parent_options[:root],
205
+ _name,
206
+ @shared_lib_dir,
207
+ ]
208
+ target = File.join(*dirs)
209
+
210
+ empty_directory(target)
211
+ _keep_dir(target)
212
+ end
213
+
214
+ def update_bin_console
215
+ path = [
216
+ parent_options[:root],
217
+ _name,
218
+ "bin",
219
+ "console",
220
+ ]
221
+ target = File.join(*path)
222
+
223
+ old_require = /require "#{_name}"/
224
+ new_require = %Q(require_relative "../lib/#{_name}")
225
+ new_require += "\n\nRunbook::Configuration.load_config"
226
+ gsub_file(target, old_require, new_require, verbose: false)
227
+
228
+ old_require = /require "#{_name}"/
229
+ new_require = %Q(require_relative "../lib/#{_name}")
230
+ gsub_file(target, old_require, new_require, verbose: false)
231
+ end
232
+
233
+ def remove_bad_test
234
+ path = [
235
+ parent_options[:root],
236
+ _name,
237
+ ]
238
+
239
+ case options["test"]
240
+ when "rspec"
241
+ path << "spec"
242
+ path << "#{_name}_spec.rb"
243
+ when "minitest"
244
+ path << "test"
245
+ path << "#{_name}_test.rb"
246
+ end
247
+ target = File.join(*path)
248
+
249
+ bad_test = / .*version.*\n.*\n end\n\n/m
250
+ gsub_file(target, bad_test, "", verbose: false)
251
+ end
252
+
253
+ def runbook_project_overview
254
+ msg = [
255
+ "",
256
+ "Your runbook project was successfully created.",
257
+ "Remember to run `./bin/setup` in your project to install dependencies.",
258
+ "Add runbooks to the `runbooks` directory.",
259
+ "Add shared code to `#{@shared_lib_dir}`.",
260
+ "Execute runbooks using `bundle exec runbook exec <RUNBOOK_PATH>` from your project root.",
261
+ "See the README.md for more details.",
262
+ "\n",
263
+ ]
264
+
265
+ say(msg.join("\n"))
266
+ end
267
+
268
+ private
269
+
270
+ def _name
271
+ @name ||= name.underscore
272
+ end
273
+
274
+ def _keep_dir(dir)
275
+ create_file(File.join(dir, ".keep"), verbose: false)
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
+
4
+ ruby "<%= RUBY_VERSION %>"
5
+
6
+ gem "runbook", "~> <%= Runbook::VERSION %>"
@@ -0,0 +1,29 @@
1
+ # <%= name.titleize %>
2
+
3
+ ## Deployment
4
+
5
+ This code is best deployed by cloning this project using git.
6
+
7
+ ## Usage
8
+
9
+ Set up this repository by running `bin/setup`. This will install all necessary dependencies for your runbooks.
10
+
11
+ Execute your runbooks using `bundle exec runbook exec <PATH_TO_YOUR_RUNBOOK>`
12
+
13
+ Get runbook help executing `bundle exec runbook help` or visiting https://github.com/braintree/runbook
14
+
15
+ ## This Repository
16
+
17
+ Runbook code should live in the following locations:
18
+
19
+ `runbooks` - Place your runbooks in this directory
20
+
21
+ `<%= @shared_lib_dir %>` - Place code shared across your runbooks in this directory
22
+
23
+ `lib/runbook/extensions` - Place code that extends Runbook's functionality here. For example, adding a new statement to Runbook's DSL would live in this directory. Require these files in your `Runbookfile` so Runbook can load them when it is launched. See https://github.com/braintree/runbook#extending-runbook for more details on extending Runbook.
24
+
25
+ `lib/runbook/generators` - Place Runbook generators in this directory. Require these files in your `Runbookfile` to expose the generators via Runbook's command line interface.
26
+
27
+ ## Development
28
+
29
+ Run `bin/setup` to install any necessary dependencies for this project. Run `bin/console` to use your code via an interactive prompt.
@@ -0,0 +1,11 @@
1
+ # Your Runbookfile serves two purposes. Use your Runbookfile to
2
+ # (1) require any runbook plugins, extensions, or generators that
3
+ # you want available to your runbooks and (2) configure Runbook
4
+ # using a `Runbook.configure` block.
5
+
6
+ # Use this block to configure Runbook. See
7
+ # https://github.com/braintree/runbook#configuration for more
8
+ # details.
9
+ #
10
+ # Runbook.configure do |config|
11
+ # end
@@ -0,0 +1,8 @@
1
+ # Require your runbook shared code here so it can easily be
2
+ # included in your runbooks and accessed from the interactive
3
+ # console using `bin/console`.
4
+
5
+ require "runbook"
6
+
7
+ module <%= name.camelize %>
8
+ end
@@ -0,0 +1,22 @@
1
+ module Runbook::Generators
2
+ class Runbook < Thor::Group
3
+ include ::Runbook::Generators::Base
4
+
5
+ source_root File.dirname(__FILE__)
6
+
7
+ def self.usage
8
+ "runbook NAME [options]"
9
+ end
10
+
11
+ def self.description
12
+ "Generate a runbook named NAME, e.x. deploy_nginx"
13
+ end
14
+
15
+ argument :name, desc: "The name of your runbook, e.x. deploy_nginx"
16
+
17
+ def create_runbook
18
+ target = File.join(options[:root], "#{name.underscore}.rb")
19
+ template('templates/runbook.tt', target)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ require "runbook"
3
+
4
+ runbook = Runbook.book "<%= name.titleize %>" do
5
+ description <<-DESC
6
+ This is a runbook that...
7
+ DESC
8
+
9
+ section "SECTION" do
10
+ step "STEP" do
11
+ # Add statements here
12
+ end
13
+ end
14
+ end
15
+
16
+ if __FILE__ == $0
17
+ Runbook::Runner.new(runbook).run
18
+ else
19
+ runbook
20
+ end
@@ -0,0 +1,18 @@
1
+ module Runbook::Generators
2
+ class Statement < Thor::Group
3
+ include ::Runbook::Generators::Base
4
+
5
+ source_root File.dirname(__FILE__)
6
+
7
+ def self.description
8
+ "Generate a statement named NAME (e.x. ruby_command) that can be used in your runbooks"
9
+ end
10
+
11
+ argument :name, desc: "The name of your statement, e.x. ruby_command"
12
+
13
+ def create_statement
14
+ target = File.join(parent_options[:root], "#{name.underscore}.rb")
15
+ template('templates/statement.tt', target)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # Remember to require this file in a runbook config file
2
+ # or in your project so it is available in your runbooks
3
+ module Runbook::Statements
4
+ class <%= name.classify %> < Runbook::Statement
5
+ # Add all attributes for your statement
6
+ attr_reader :attr1, :attr2
7
+
8
+ # Define the initialize method signature to
9
+ # match the method signature of your dsl statement
10
+ def initialize(attr1, attr2)
11
+ @attr1 = attr1
12
+ @attr2 = attr2
13
+ end
14
+ end
15
+ end
16
+
17
+ # scope this module using your project's namespace
18
+ module MyProject::RunbookExtensions
19
+ module <%= "#{name.underscore}_markdown".classify %>
20
+ def runbook__statements__<%= name.underscore %>(object, output, metadata)
21
+ # Format how your statement will be displayed when rendered with markdown
22
+ output << "#{object.attr1}#{object.attr2}"
23
+ end
24
+ end
25
+ Runbook::Views::Markdown.singleton_class.prepend(<%= "#{name.underscore}_markdown".classify %>)
26
+
27
+ module <%= "#{name.underscore}_sshkit".classify %>
28
+ def runbook__statements__<%= name.underscore %>(object, metadata)
29
+ # Execute your behavior using object which is your instantiated statement
30
+ # and the current metadata for this step of the execution
31
+ end
32
+ end
33
+ Runbook::Runs::SSHKit.singleton_class.prepend(<%= "#{name.underscore}_sshkit".classify %>)
34
+ end
@@ -0,0 +1,85 @@
1
+ module Runbook
2
+ class Installer < Thor::Group
3
+ include Thor::Actions
4
+
5
+ source_root File.join(
6
+ File.dirname(__FILE__),
7
+ "generators",
8
+ "project",
9
+ )
10
+
11
+ add_runtime_options!
12
+ check_unknown_options!
13
+
14
+ def create_runbookfile
15
+ template(
16
+ "templates/Runbookfile.tt",
17
+ "Runbookfile",
18
+ )
19
+ end
20
+
21
+ def create_runbooks_directory
22
+ target = "runbooks"
23
+ empty_directory(target)
24
+ _keep_dir(target)
25
+ end
26
+
27
+ def create_lib_directory
28
+ dirs = [
29
+ "lib",
30
+ "runbook",
31
+ ]
32
+ target = File.join(*dirs)
33
+
34
+ empty_directory(target)
35
+ _keep_dir(target)
36
+ end
37
+
38
+ def create_extensions_directory
39
+ dirs = [
40
+ "lib",
41
+ "runbook",
42
+ "extensions",
43
+ ]
44
+ target = File.join(*dirs)
45
+
46
+ empty_directory(target)
47
+ _keep_dir(target)
48
+ end
49
+
50
+ def create_generators_directory
51
+ dirs = [
52
+ "lib",
53
+ "runbook",
54
+ "generators",
55
+ ]
56
+ target = File.join(*dirs)
57
+
58
+ empty_directory(target)
59
+ _keep_dir(target)
60
+ end
61
+
62
+ def runbook_installation_overview
63
+ msg = [
64
+ "",
65
+ "Runbook was successfully installed",
66
+ "Add runbooks to the `runbooks` directory.",
67
+ "Add shared code to `lib/runbook`.",
68
+ "Execute runbooks using `bundle exec runbook exec <RUNBOOK_PATH>`",
69
+ "from your project root.",
70
+ "\n",
71
+ ]
72
+
73
+ say(msg.join("\n"))
74
+ end
75
+
76
+ private
77
+
78
+ def _keep_dir(dir)
79
+ create_file(
80
+ File.join(dir, ".keep"),
81
+ verbose: false,
82
+ )
83
+ end
84
+ end
85
+ end
@@ -11,6 +11,10 @@ module Runbook
11
11
  _child_modules(Runbook::Runs)
12
12
  end
13
13
 
14
+ def self.generators
15
+ _child_classes(Runbook::Generators)
16
+ end
17
+
14
18
  def self._child_classes(mod)
15
19
  mod.constants.map { |const|
16
20
  "#{mod.to_s}::#{const}".constantize
@@ -1,3 +1,3 @@
1
1
  module Runbook
2
- VERSION = "0.12.1"
2
+ VERSION = "0.13.0"
3
3
  end
data/lib/runbook.rb CHANGED
@@ -10,6 +10,7 @@ require "sshkit/sudo"
10
10
  require "airbrussh"
11
11
  require "tty-progressbar"
12
12
  require "tty-prompt"
13
+ require "thor/group"
13
14
 
14
15
  require "runbook/configuration"
15
16
 
@@ -62,6 +63,13 @@ require "runbook/viewer"
62
63
  require "runbook/view"
63
64
  require "runbook/views/markdown"
64
65
 
66
+ require "runbook/generators/base"
67
+ require "runbook/generators/dsl_extension/dsl_extension"
68
+ require "runbook/generators/generator/generator"
69
+ require "runbook/generators/project/project"
70
+ require "runbook/generators/runbook/runbook"
71
+ require "runbook/generators/statement/statement"
72
+
65
73
  require "runbook/extensions/add"
66
74
  require "runbook/extensions/description"
67
75
  require "runbook/extensions/shared_variables"
data/runbook.gemspec CHANGED
@@ -9,10 +9,11 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["pblesi"]
10
10
  spec.email = ["code@getbraintree.com"]
11
11
 
12
- spec.summary = %q{Write beautiful, executable runbooks for conducting production operations.}
13
- spec.description = %q{Runbook provides a DSL for specifying production operations. This DSL is used to generate formatted runbooks as well as interactive runbooks to be executed on the command line.}
12
+ spec.summary = %q{Write beautiful, executable runbooks for conducting system operations.}
13
+ spec.description = %q{Runbook provides a DSL for specifying system operations. This DSL is used to generate formatted runbooks as well as interactive runbooks to be executed on the command line.}
14
14
  spec.homepage = "https://github.com/braintree/runbook/"
15
15
  spec.license = "MIT"
16
+ spec.required_ruby_version = '>= 2.2.3'
16
17
 
17
18
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
19
  # to allow pushing to a single host or delete this section to allow pushing to any host.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pblesi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-13 00:00:00.000000000 Z
11
+ date: 2019-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -212,8 +212,8 @@ dependencies:
212
212
  - - "~>"
213
213
  - !ruby/object:Gem::Version
214
214
  version: '3.0'
215
- description: Runbook provides a DSL for specifying production operations. This DSL
216
- is used to generate formatted runbooks as well as interactive runbooks to be executed
215
+ description: Runbook provides a DSL for specifying system operations. This DSL is
216
+ used to generate formatted runbooks as well as interactive runbooks to be executed
217
217
  on the command line.
218
218
  email:
219
219
  - code@getbraintree.com
@@ -243,6 +243,7 @@ files:
243
243
  - lib/hacks/ssh_kit.rb
244
244
  - lib/runbook.rb
245
245
  - lib/runbook/cli.rb
246
+ - lib/runbook/cli_base.rb
246
247
  - lib/runbook/configuration.rb
247
248
  - lib/runbook/dsl.rb
248
249
  - lib/runbook/entities/book.rb
@@ -258,10 +259,26 @@ files:
258
259
  - lib/runbook/extensions/statements.rb
259
260
  - lib/runbook/extensions/steps.rb
260
261
  - lib/runbook/extensions/tmux.rb
262
+ - lib/runbook/generator.rb
263
+ - lib/runbook/generators/base.rb
264
+ - lib/runbook/generators/dsl_extension/dsl_extension.rb
265
+ - lib/runbook/generators/dsl_extension/templates/dsl_extension.tt
266
+ - lib/runbook/generators/generator/generator.rb
267
+ - lib/runbook/generators/generator/templates/generator.tt
268
+ - lib/runbook/generators/project/project.rb
269
+ - lib/runbook/generators/project/templates/Gemfile.tt
270
+ - lib/runbook/generators/project/templates/README.md.tt
271
+ - lib/runbook/generators/project/templates/Runbookfile.tt
272
+ - lib/runbook/generators/project/templates/base_file.rb.tt
273
+ - lib/runbook/generators/runbook/runbook.rb
274
+ - lib/runbook/generators/runbook/templates/runbook.tt
275
+ - lib/runbook/generators/statement/statement.rb
276
+ - lib/runbook/generators/statement/templates/statement.tt
261
277
  - lib/runbook/helpers/format_helper.rb
262
278
  - lib/runbook/helpers/ssh_kit_helper.rb
263
279
  - lib/runbook/helpers/tmux_helper.rb
264
280
  - lib/runbook/hooks.rb
281
+ - lib/runbook/installer.rb
265
282
  - lib/runbook/node.rb
266
283
  - lib/runbook/run.rb
267
284
  - lib/runbook/runner.rb
@@ -309,16 +326,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
309
326
  requirements:
310
327
  - - ">="
311
328
  - !ruby/object:Gem::Version
312
- version: '0'
329
+ version: 2.2.3
313
330
  required_rubygems_version: !ruby/object:Gem::Requirement
314
331
  requirements:
315
332
  - - ">="
316
333
  - !ruby/object:Gem::Version
317
334
  version: '0'
318
335
  requirements: []
319
- rubyforge_project:
320
- rubygems_version: 2.7.8
336
+ rubygems_version: 3.0.4
321
337
  signing_key:
322
338
  specification_version: 4
323
- summary: Write beautiful, executable runbooks for conducting production operations.
339
+ summary: Write beautiful, executable runbooks for conducting system operations.
324
340
  test_files: []