boxen 2.9.0 → 3.0.0.beta1

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 (69) hide show
  1. data/boxen.gemspec +12 -12
  2. data/lib/boxen/check.rb +8 -39
  3. data/lib/boxen/cli.rb +19 -45
  4. data/lib/boxen/command.rb +142 -0
  5. data/lib/boxen/command/help.rb +40 -0
  6. data/lib/boxen/command/preflight.rb +38 -0
  7. data/lib/boxen/command/project.rb +49 -0
  8. data/lib/boxen/command/project/install.rb +33 -0
  9. data/lib/boxen/command/run.rb +199 -0
  10. data/lib/boxen/command/service.rb +61 -0
  11. data/lib/boxen/command/service/disable.rb +15 -0
  12. data/lib/boxen/command/service/enable.rb +15 -0
  13. data/lib/boxen/command/service/restart.rb +24 -0
  14. data/lib/boxen/command/version.rb +29 -0
  15. data/lib/boxen/command_status.rb +15 -0
  16. data/lib/boxen/config.rb +43 -61
  17. data/lib/boxen/hook.rb +15 -8
  18. data/lib/boxen/keychain.rb +1 -1
  19. data/lib/boxen/postflight/env.rb +1 -1
  20. data/lib/boxen/postflight/github_issue.rb +124 -0
  21. data/lib/boxen/postflight/hooks.rb +16 -0
  22. data/lib/boxen/postflight/web_hook.rb +63 -0
  23. data/lib/boxen/preflight.rb +4 -7
  24. data/lib/boxen/preflight/creds.rb +8 -47
  25. data/lib/boxen/preflight/facts.rb +36 -0
  26. data/lib/boxen/preflight/homebrew.rb +13 -0
  27. data/lib/boxen/preflight/identity.rb +2 -0
  28. data/lib/boxen/preflight/offline.rb +33 -0
  29. data/lib/boxen/preflight/os.rb +1 -1
  30. data/lib/boxen/preflight/update.rb +109 -0
  31. data/lib/boxen/util/logging.rb +59 -0
  32. data/lib/boxen/version.rb +3 -0
  33. data/script/bootstrap +1 -1
  34. data/script/tests +1 -0
  35. data/test/boxen/test.rb +1 -1
  36. data/test/boxen_cli_test.rb +8 -31
  37. data/test/boxen_command_test.rb +93 -0
  38. data/test/boxen_config_test.rb +1 -31
  39. data/test/boxen_directories_test.rb +4 -4
  40. data/test/boxen_hook_test.rb +25 -0
  41. data/test/command/help_test.rb +49 -0
  42. data/test/command/project/install_test.rb +34 -0
  43. data/test/command/project_test.rb +32 -0
  44. data/test/command/run_test.rb +21 -0
  45. data/test/command/service/disable_test.rb +49 -0
  46. data/test/command/service/enable_test.rb +49 -0
  47. data/test/command/service/restart_test.rb +53 -0
  48. data/test/command/service_test.rb +55 -0
  49. data/test/command/version_test.rb +15 -0
  50. data/test/{boxen_postflight_active_test.rb → postflight/boxen_postflight_active_test.rb} +3 -3
  51. data/test/{boxen_postflight_env_test.rb → postflight/boxen_postflight_env_test.rb} +0 -0
  52. data/test/{boxen_hook_github_issue_test.rb → postflight/boxen_postflight_github_issue_test.rb} +72 -82
  53. data/test/{boxen_hook_web_test.rb → postflight/boxen_postflight_web_hook_test.rb} +12 -11
  54. data/test/preflight/boxen_preflight_creds_test.rb +82 -0
  55. data/test/{boxen_preflight_etc_my_cnf_test.rb → preflight/boxen_preflight_etc_my_cnf_test.rb} +1 -1
  56. data/test/preflight/boxen_preflight_homebrew_test.rb +10 -0
  57. data/test/{boxen_preflight_rvm_test.rb → preflight/boxen_preflight_rvm_test.rb} +1 -1
  58. metadata +247 -171
  59. checksums.yaml +0 -7
  60. data/lib/boxen/flags.rb +0 -282
  61. data/lib/boxen/hook/github_issue.rb +0 -120
  62. data/lib/boxen/hook/web.rb +0 -56
  63. data/lib/boxen/puppeteer.rb +0 -121
  64. data/lib/boxen/runner.rb +0 -149
  65. data/test/boxen_check_test.rb +0 -55
  66. data/test/boxen_flags_test.rb +0 -217
  67. data/test/boxen_preflight_creds_test.rb +0 -177
  68. data/test/boxen_puppeteer_test.rb +0 -101
  69. data/test/boxen_runner_test.rb +0 -171
@@ -1,30 +1,30 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ $:.unshift File.expand_path("../lib", __FILE__)
4
+ require "boxen/version"
5
+
3
6
  Gem::Specification.new do |gem|
4
7
  gem.name = "boxen"
5
- gem.version = "2.9.0"
6
- # Thanks go out to the previous maintainers John Barnette, Will
7
- # Farrington, David Goodlad and Mike McQuaid for getting this project
8
- # to where it is today.
9
- gem.authors = ["Jacob Bednarz"]
10
- gem.email = ["jacob.bednarz@gmail.com"]
8
+ gem.version = Boxen::VERSION
9
+ gem.authors = ["John Barnette", "Will Farrington", "David Goodlad"]
10
+ gem.email = ["jbarnette@github.com", "wfarr@github.com", "dgoodlad@github.com"]
11
11
  gem.description = "Manage Mac development boxes with love (and Puppet)."
12
12
  gem.summary = "You know, for laptops and stuff."
13
13
  gem.homepage = "https://github.com/boxen/boxen"
14
- gem.license = 'MIT'
15
14
 
16
- gem.files = `git ls-files`.split $/
17
- gem.test_files = gem.files.grep /^test/
15
+ gem.files = `git ls-files`.split( $/)
16
+ gem.test_files = gem.files.grep(/^test/)
17
+ gem.executables = gem.files.grep(/^bin/).map { |bin| File.basename(bin) }
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_dependency "ansi", "~> 1.4"
21
21
  gem.add_dependency "hiera", "~> 1.0"
22
- gem.add_dependency "highline", "~> 1.6.0"
22
+ gem.add_dependency "highline", "~> 1.6"
23
23
  gem.add_dependency "json_pure", [">= 1.7.7", "< 2.0"]
24
24
  gem.add_dependency "librarian-puppet", "~> 1.0.0"
25
25
  gem.add_dependency "octokit", "~> 2.7", ">= 2.7.1"
26
- gem.add_dependency "puppet", "~> 3.7"
26
+ gem.add_dependency "puppet", "~> 3.0"
27
27
 
28
- gem.add_development_dependency "minitest", "4.4.0" # pinned for mocha
28
+ gem.add_development_dependency "minitest", "~> 5.0" # pinned for mocha
29
29
  gem.add_development_dependency "mocha", "~> 0.13"
30
30
  end
@@ -1,20 +1,11 @@
1
- require "ansi"
1
+ require "boxen/util/logging"
2
2
 
3
3
  module Boxen
4
4
 
5
5
  # The superclass for preflight and postflight sanity checks.
6
6
 
7
7
  class Check
8
-
9
- # A collection of preflight instances for `config`. An instance is
10
- # created for every constant under `self` that's also a
11
- # subclass of `self`.
12
-
13
- def self.checks(config)
14
- constants.map { |n| const_get n }.
15
- select { |c| c < self }.
16
- map { |c| c.new config }
17
- end
8
+ include Boxen::Util::Logging
18
9
 
19
10
  # Search `dir` and load all Ruby files under it.
20
11
 
@@ -22,16 +13,12 @@ module Boxen
22
13
  Dir["#{dir}/*.rb"].sort.each { |f| load f }
23
14
  end
24
15
 
25
- # Check each instance against `config`.
26
-
27
- def self.run(config)
28
- checks(config).each { |check| check.run unless check.ok? }
29
- end
30
-
31
16
  attr_reader :config
17
+ attr_reader :command
32
18
 
33
- def initialize(config)
34
- @config = config
19
+ def initialize(config, command)
20
+ @config = config
21
+ @command = command
35
22
  end
36
23
 
37
24
  # Is everything good to go? Implemented by subclasses.
@@ -46,27 +33,9 @@ module Boxen
46
33
  raise "Subclasses must implement this method."
47
34
  end
48
35
 
49
- # A fancier `abort` and `warn`. This will probably really annoy
50
- # someone at some point because it's overriding a Kernel method,
51
- # but it's limited to checks.
52
-
53
- def abort(message, *extras)
54
- extras << { :color => :red }
55
- warn message, *extras
56
- exit 1
57
- end
58
-
59
- def warn(message, *extras)
60
- options = Hash === extras.last ? extras.pop : {}
61
- color = options[:color] || :yellow
62
-
63
- $stderr.puts ANSI.send(color) { "--> #{message}" }
64
-
65
- unless extras.empty?
66
- extras.each { |line| $stderr.puts " #{line}" }
67
- end
68
36
 
69
- $stderr.puts
37
+ def debug?
38
+ @config.debug?
70
39
  end
71
40
  end
72
41
  end
@@ -1,61 +1,35 @@
1
+ require "boxen/command"
1
2
  require "boxen/config"
2
- require "boxen/flags"
3
- require "boxen/postflight"
4
- require "boxen/preflight"
5
- require "boxen/runner"
6
- require "boxen/util"
3
+ require "boxen/util/logging"
7
4
 
8
5
  module Boxen
9
6
  class CLI
10
- attr_reader :config
11
- attr_reader :flags
12
- attr_reader :runner
13
-
14
- def initialize(config, flags)
15
- @config = config
16
- @flags = flags
17
- @runner = Boxen::Runner.new(@config, @flags)
18
- end
19
-
20
- def run
21
- if flags.help?
22
- puts flags
23
- exit
24
- end
7
+ include Boxen::Util::Logging
25
8
 
26
- runner.run
9
+ def self.run(*args)
10
+ new.run(*args)
27
11
  end
28
12
 
29
- # Run Boxen by wiring together the command-line flags, config,
30
- # preflights, Puppet execution, and postflights. Returns Puppet's
31
- # exit code.
32
-
33
- def self.run(*args)
34
- config = Boxen::Config.load
35
- flags = Boxen::Flags.new args
13
+ def initialize
14
+ end
36
15
 
37
- # Apply command-line flags to the config in case we're changing or
38
- # overriding anything.
39
- flags.apply config
16
+ def run(*args)
17
+ cmd, *cmd_args = args.flatten
40
18
 
41
- if flags.run?
42
- # Run the preflight checks.
43
- Boxen::Preflight.run config
19
+ with_friendly_errors do
20
+ config = Boxen::Config.load
21
+ status = Boxen::Command.invoke cmd, config, *cmd_args
44
22
 
45
- # Save the config for Puppet (and next time).
46
- Boxen::Config.save config
23
+ status.code
47
24
  end
25
+ end
48
26
 
49
- # Make the magic happen.
50
- status = Boxen::CLI.new(config, flags).run
51
-
52
- if flags.run?
53
- # Run the postflight checks.
54
- Boxen::Postflight.run config if status.success?
55
- end
27
+ private
56
28
 
57
- # Return Puppet's exit status.
58
- return status.code
29
+ def with_friendly_errors(&block)
30
+ yield
31
+ rescue => e
32
+ abort "#{e.class.name}: #{e.message}"
59
33
  end
60
34
  end
61
35
  end
@@ -0,0 +1,142 @@
1
+ require "boxen/command_status"
2
+
3
+ # Pulled in so the others don't have to
4
+ require "boxen/preflight"
5
+ require "boxen/postflight"
6
+ require "boxen/util/logging"
7
+
8
+ class Boxen::Command
9
+ include Boxen::Util::Logging
10
+
11
+ class UnknownCommandError < StandardError; end
12
+ class CommandNotRunError < StandardError; end
13
+
14
+ attr_reader :config
15
+
16
+ def self.help
17
+ raise "You should define this"
18
+ end
19
+
20
+ def self.detailed_help
21
+ raise "You should definitely define this"
22
+ end
23
+
24
+ def self.preflight(*klasses)
25
+ preflights.replace preflights | klasses.flatten
26
+ end
27
+
28
+ def self.preflights
29
+ @preflights ||= []
30
+ end
31
+
32
+ def self.postflight(*klasses)
33
+ postflights.replace postflights | klasses.flatten
34
+ end
35
+
36
+ def self.postflights
37
+ @postflights ||= []
38
+ end
39
+
40
+ def self.all
41
+ @commands
42
+ end
43
+
44
+ def self.register(name, klass, *aliases)
45
+ unless defined?(@commands)
46
+ @commands = {}
47
+ end
48
+ unless defined?(@aliases)
49
+ @aliases = {}
50
+ end
51
+
52
+ @commands[name] = klass
53
+ aliases.each { |a| @aliases[a] = name }
54
+ end
55
+
56
+ def self.reset!
57
+ @commands = {}
58
+ end
59
+
60
+ def self.invoke(name, *args)
61
+ if @commands && name && @commands.has_key?(name.to_sym)
62
+ @commands[name.to_sym].new(*args).invoke
63
+ elsif @aliases && name && @aliases.has_key?(name.to_sym)
64
+ invoke(@aliases[name.to_sym], *args)
65
+ else
66
+ raise UnknownCommandError,
67
+ "could not find `#{name.inspect.to_s}` in the list of registered commands"
68
+ end
69
+ end
70
+
71
+ def initialize(config, *args)
72
+ @config = config
73
+ @args = args
74
+ end
75
+
76
+ def invoke
77
+ if preflights?
78
+ @cmd_status = self.run
79
+
80
+ postflights
81
+
82
+ @cmd_status
83
+ end
84
+ end
85
+
86
+ def run
87
+ raise "So your command #{self.class.name} hasn't defined a run method, so we dunno what to do. Sorry."
88
+ end
89
+
90
+ def preflights?
91
+ if self.class.preflights.any?
92
+ info "Performing preflight checks"
93
+ end
94
+
95
+ self.class.preflights.all? do |p|
96
+
97
+ debug "Performing preflight check: #{p.name}"
98
+
99
+ p = p.new(@config, self)
100
+ status = p.ok?
101
+
102
+ if status
103
+ debug "Passed preflight check: #{p.class.name}"
104
+ else
105
+ p.run
106
+ end
107
+
108
+ status
109
+ end
110
+ end
111
+
112
+ def postflights
113
+ if self.class.postflights.any?
114
+ info "Performing postflight checks"
115
+ end
116
+
117
+ self.class.postflights.each do |p|
118
+ p = p.new(@config, self)
119
+ p.run unless p.ok?
120
+ end
121
+ end
122
+
123
+ def debug?
124
+ @config.debug?
125
+ end
126
+
127
+ def success?
128
+ if @cmd_status
129
+ @cmd_status.success?
130
+ else
131
+ raise CommandNotRunError,
132
+ "the command hasn't been run, so we can't know if it was successful"
133
+ end
134
+ end
135
+ end
136
+
137
+ require "boxen/command/help"
138
+ require "boxen/command/version"
139
+ require "boxen/command/run"
140
+ require "boxen/command/preflight"
141
+ require "boxen/command/project"
142
+ require "boxen/command/service"
@@ -0,0 +1,40 @@
1
+ require "boxen/command"
2
+
3
+ class Boxen::Command::Help < Boxen::Command
4
+ def self.help
5
+ "Displays help, obviously"
6
+ end
7
+
8
+ def self.detailed_help
9
+ <<-EOS
10
+
11
+ boxen help [<command>]
12
+
13
+ With no arguments, displays short help information for all commands.
14
+
15
+ Given a command name as an argument, displays detailed help about that command.
16
+
17
+ EOS
18
+ end
19
+
20
+ def run
21
+ if @args.any?
22
+ puts Boxen::Command.all[@args.first.to_sym].detailed_help
23
+ else
24
+ Boxen::Command.all.each do |name, _|
25
+ display_help_for_command name
26
+ end
27
+ end
28
+
29
+ Boxen::CommandStatus.new(0)
30
+ end
31
+
32
+ def display_help_for_command(name)
33
+ # only shows top-level commands, not subcommands
34
+ unless name =~ /:/
35
+ puts " #{name.to_s.ljust(16)} #{Boxen::Command.all[name.to_sym].help}"
36
+ end
37
+ end
38
+ end
39
+
40
+ Boxen::Command.register :help, Boxen::Command::Help, :"--help"
@@ -0,0 +1,38 @@
1
+ require "boxen/command"
2
+
3
+ class Boxen::Command::Preflight < Boxen::Command
4
+ def self.help
5
+ "Run a single preflight and return whether or not it's ok."
6
+ end
7
+
8
+ def self.detailed_help
9
+ <<-EOS
10
+
11
+ boxen preflight <check>
12
+
13
+ Run preflight named <check> and return whether or not it's ok.
14
+
15
+ EOS
16
+ end
17
+
18
+ def run
19
+ if defined?(preflight)
20
+ info "#{preflight.name}: #{preflight.new(@config).ok?.inspect}"
21
+ return Boxen::CommandStatus.new(0)
22
+ else
23
+ fail("Could not find a preflight named: #{preflight_name}")
24
+ end
25
+ rescue => e
26
+ fail("Command failed: #{e.message} #{e.backtrace}")
27
+ end
28
+
29
+ def preflight
30
+ Object.const_get(preflight_name)
31
+ end
32
+
33
+ def preflight_name
34
+ "Boxen::Preflight::#{ARGV[1].capitalize}"
35
+ end
36
+ end
37
+
38
+ Boxen::Command.register :preflight, Boxen::Command::Preflight
@@ -0,0 +1,49 @@
1
+ require "boxen/command"
2
+ #require "boxen/service"
3
+
4
+ class Boxen::Command::Project < Boxen::Command
5
+ def self.detailed_help
6
+ <<-EOS
7
+
8
+ boxen project
9
+
10
+ Display all projects Boxen knows about.
11
+
12
+ boxen project:install <project1> [<project2> ...]
13
+
14
+ Install a Boxen-managed project.
15
+
16
+ NOTE: 'boxen project' is aliased to 'projects' for convenience
17
+
18
+ EOS
19
+ end
20
+
21
+ def self.help
22
+ "Show and install Boxen-managed projects"
23
+ end
24
+
25
+ def run
26
+ @args = [] # we don't care about args here
27
+
28
+ puts "Boxen knows about the following projects:"
29
+ puts
30
+
31
+ projects.each do |project|
32
+ puts " #{project.name}"
33
+ end
34
+
35
+ puts
36
+ puts "You can install any of them by running \"boxen project:install <project>\""
37
+ puts
38
+
39
+ Boxen::CommandStatus.new(0)
40
+ end
41
+
42
+ def projects
43
+ @projects ||= @config.projects
44
+ end
45
+ end
46
+
47
+ require "boxen/command/project/install"
48
+
49
+ Boxen::Command.register :project, Boxen::Command::Project, :projects