boxen 3.0.0.beta1 → 3.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 +7 -0
- data/.travis.yml +0 -1
- data/README.md +1 -1
- data/boxen.gemspec +13 -13
- data/lib/boxen/check.rb +39 -8
- data/lib/boxen/cli.rb +45 -19
- data/lib/boxen/config.rb +61 -43
- data/lib/boxen/flags.rb +282 -0
- data/lib/boxen/hook.rb +8 -15
- data/lib/boxen/hook/github_issue.rb +120 -0
- data/lib/boxen/hook/web.rb +56 -0
- data/lib/boxen/keychain.rb +1 -1
- data/lib/boxen/postflight/env.rb +1 -1
- data/lib/boxen/preflight.rb +7 -4
- data/lib/boxen/preflight/creds.rb +47 -8
- data/lib/boxen/preflight/identity.rb +0 -2
- data/lib/boxen/preflight/os.rb +6 -2
- data/lib/boxen/puppeteer.rb +121 -0
- data/lib/boxen/runner.rb +149 -0
- data/script/bootstrap +1 -1
- data/script/tests +0 -1
- data/test/boxen/test.rb +1 -1
- data/test/boxen_check_test.rb +55 -0
- data/test/boxen_cli_test.rb +31 -8
- data/test/boxen_config_test.rb +31 -1
- data/test/boxen_directories_test.rb +4 -4
- data/test/boxen_flags_test.rb +217 -0
- data/test/{postflight/boxen_postflight_github_issue_test.rb → boxen_hook_github_issue_test.rb} +82 -72
- data/test/{postflight/boxen_postflight_web_hook_test.rb → boxen_hook_web_test.rb} +11 -12
- data/test/{postflight/boxen_postflight_active_test.rb → boxen_postflight_active_test.rb} +3 -3
- data/test/{postflight/boxen_postflight_env_test.rb → boxen_postflight_env_test.rb} +0 -0
- data/test/boxen_preflight_creds_test.rb +177 -0
- data/test/{preflight/boxen_preflight_etc_my_cnf_test.rb → boxen_preflight_etc_my_cnf_test.rb} +1 -1
- data/test/{preflight/boxen_preflight_rvm_test.rb → boxen_preflight_rvm_test.rb} +1 -1
- data/test/boxen_puppeteer_test.rb +101 -0
- data/test/boxen_runner_test.rb +171 -0
- metadata +172 -251
- data/lib/boxen/command.rb +0 -142
- data/lib/boxen/command/help.rb +0 -40
- data/lib/boxen/command/preflight.rb +0 -38
- data/lib/boxen/command/project.rb +0 -49
- data/lib/boxen/command/project/install.rb +0 -33
- data/lib/boxen/command/run.rb +0 -199
- data/lib/boxen/command/service.rb +0 -61
- data/lib/boxen/command/service/disable.rb +0 -15
- data/lib/boxen/command/service/enable.rb +0 -15
- data/lib/boxen/command/service/restart.rb +0 -24
- data/lib/boxen/command/version.rb +0 -29
- data/lib/boxen/command_status.rb +0 -15
- data/lib/boxen/postflight/github_issue.rb +0 -124
- data/lib/boxen/postflight/hooks.rb +0 -16
- data/lib/boxen/postflight/web_hook.rb +0 -63
- data/lib/boxen/preflight/facts.rb +0 -36
- data/lib/boxen/preflight/homebrew.rb +0 -13
- data/lib/boxen/preflight/offline.rb +0 -33
- data/lib/boxen/preflight/update.rb +0 -109
- data/lib/boxen/util/logging.rb +0 -59
- data/lib/boxen/version.rb +0 -3
- data/lib/system_timer.rb +0 -13
- data/test/boxen_command_test.rb +0 -93
- data/test/boxen_hook_test.rb +0 -25
- data/test/command/help_test.rb +0 -49
- data/test/command/project/install_test.rb +0 -34
- data/test/command/project_test.rb +0 -32
- data/test/command/run_test.rb +0 -21
- data/test/command/service/disable_test.rb +0 -49
- data/test/command/service/enable_test.rb +0 -49
- data/test/command/service/restart_test.rb +0 -53
- data/test/command/service_test.rb +0 -55
- data/test/command/version_test.rb +0 -15
- data/test/preflight/boxen_preflight_creds_test.rb +0 -82
- data/test/preflight/boxen_preflight_homebrew_test.rb +0 -10
- data/test/system_timer.rb +0 -10
@@ -0,0 +1,56 @@
|
|
1
|
+
require "boxen/hook"
|
2
|
+
require "json"
|
3
|
+
require "net/http"
|
4
|
+
|
5
|
+
module Boxen
|
6
|
+
class Hook
|
7
|
+
class Web < Hook
|
8
|
+
def perform?
|
9
|
+
enabled?
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def call
|
14
|
+
payload = {
|
15
|
+
:login => config.user,
|
16
|
+
:sha => checkout.sha,
|
17
|
+
:status => result.success? ? 'success' : 'failure',
|
18
|
+
:time => "#{Time.now.utc.to_i}"
|
19
|
+
}
|
20
|
+
|
21
|
+
post_web_hook payload
|
22
|
+
end
|
23
|
+
|
24
|
+
def post_web_hook(payload)
|
25
|
+
headers = { 'Content-Type' => 'application/json' }
|
26
|
+
|
27
|
+
uri = URI.parse(URI.escape(ENV['BOXEN_WEB_HOOK_URL']))
|
28
|
+
|
29
|
+
user, pass, host, port, path = \
|
30
|
+
uri.user, uri.pass, uri.host, uri.port, uri.path
|
31
|
+
|
32
|
+
request = Net::HTTP::Post.new(path, initheader = headers)
|
33
|
+
|
34
|
+
if uri.scheme =~ /https/
|
35
|
+
http.use_ssl = true
|
36
|
+
end
|
37
|
+
|
38
|
+
if user && pass
|
39
|
+
request.basic_auth user, pass
|
40
|
+
end
|
41
|
+
|
42
|
+
request.body = payload.to_json
|
43
|
+
|
44
|
+
response = Net::HTTP.new(host, port).start do |http|
|
45
|
+
http.request(request)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def required_environment_variables
|
50
|
+
['BOXEN_WEB_HOOK_URL']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Boxen::Hook.register Boxen::Hook::Web
|
data/lib/boxen/keychain.rb
CHANGED
data/lib/boxen/postflight/env.rb
CHANGED
data/lib/boxen/preflight.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require "boxen/check"
|
2
2
|
|
3
3
|
module Boxen
|
4
|
+
|
5
|
+
# The superclass for preflight checks.
|
6
|
+
|
4
7
|
class Preflight < Boxen::Check
|
5
|
-
end
|
6
|
-
end
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
# Load all available preflight checks.
|
10
|
+
|
11
|
+
register File.expand_path("../preflight", __FILE__)
|
12
|
+
end
|
10
13
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "boxen/preflight"
|
2
2
|
require "highline"
|
3
3
|
require "octokit"
|
4
|
+
require "digest"
|
5
|
+
require "socket"
|
4
6
|
|
5
7
|
# HACK: Unless this is `false`, HighLine has some really bizarre
|
6
8
|
# problems with empty/expended streams at bizarre intervals.
|
@@ -12,8 +14,6 @@ class Boxen::Preflight::Creds < Boxen::Preflight
|
|
12
14
|
attr :password
|
13
15
|
|
14
16
|
def ok?
|
15
|
-
return true if config.offline?
|
16
|
-
|
17
17
|
if config.token && config.api.user
|
18
18
|
# There was a period of time when login wasn't geting set on first run.
|
19
19
|
# This should correct that.
|
@@ -70,12 +70,27 @@ class Boxen::Preflight::Creds < Boxen::Preflight
|
|
70
70
|
fetch_login_and_password
|
71
71
|
tokens = get_tokens
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
73
|
+
# Boxen now supports the updated GitHub Authorizations API by using a unique
|
74
|
+
# `fingerprint` for each Boxen installation for a user. We delete any older
|
75
|
+
# authorization that does not make use of `fingerprint` so that the "legacy"
|
76
|
+
# authorization doesn't persist in the user's list of personal access
|
77
|
+
# tokens.
|
78
|
+
legacy_auth = tokens.detect { |a| a.note == "Boxen" && a.fingerprint == nil }
|
79
|
+
tmp_api.delete_authorization(legacy_auth.id, :headers => headers) if legacy_auth
|
80
|
+
|
81
|
+
# The updated GitHub authorizations API, in order to improve security, no
|
82
|
+
# longer returns a plaintext `token` for existing authorizations. So, if an
|
83
|
+
# authorization already exists for this machine we need to first delete it
|
84
|
+
# so that we can create a new one.
|
85
|
+
auth = tokens.detect { |a| a.note == note && a.fingerprint == fingerprint }
|
86
|
+
tmp_api.delete_authorization(auth.id, :headers => headers) if auth
|
87
|
+
|
88
|
+
auth = tmp_api.create_authorization(
|
89
|
+
:note => note,
|
90
|
+
:scopes => %w(repo user),
|
91
|
+
:fingerprint => fingerprint,
|
92
|
+
:headers => headers
|
93
|
+
)
|
79
94
|
|
80
95
|
config.token = auth.token
|
81
96
|
|
@@ -107,4 +122,28 @@ class Boxen::Preflight::Creds < Boxen::Preflight
|
|
107
122
|
warn "Oh, looks like you've provided your #{thing} as environmental variable..."
|
108
123
|
found
|
109
124
|
end
|
125
|
+
|
126
|
+
def fingerprint
|
127
|
+
@fingerprint ||= begin
|
128
|
+
# See Apple technical note TN1103, "Uniquely Identifying a Macintosh
|
129
|
+
# Computer."
|
130
|
+
serial_number_match_data = IO.popen(
|
131
|
+
["ioreg", "-c", "IOPlatformExpertDevice", "-d", "2"]
|
132
|
+
).read.match(/"IOPlatformSerialNumber" = "([[:alnum:]]+)"/)
|
133
|
+
if serial_number_match_data
|
134
|
+
# The fingerprint must be unique across all personal access tokens for a
|
135
|
+
# given user. We prefix the serial number with the application name to
|
136
|
+
# differentiate between any other personal access token that uses the
|
137
|
+
# Mac serial number for the fingerprint.
|
138
|
+
Digest::SHA256.hexdigest("Boxen: #{serial_number_match_data[1]}")
|
139
|
+
else
|
140
|
+
abort "Sorry, I was unable to obtain your Mac's serial number.",
|
141
|
+
"Boxen requires access to your Mac's serial number in order to generate a unique GitHub personal access token."
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def note
|
147
|
+
@note ||= "Boxen: #{Socket.gethostname}"
|
148
|
+
end
|
110
149
|
end
|
data/lib/boxen/preflight/os.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require "boxen/preflight"
|
2
2
|
|
3
3
|
class Boxen::Preflight::OS < Boxen::Preflight
|
4
|
-
SUPPORTED_RELEASES = %w(10.8 10.9)
|
4
|
+
SUPPORTED_RELEASES = %w(10.8 10.9 10.10 10.11 10.12)
|
5
5
|
|
6
6
|
def ok?
|
7
|
-
osx? && supported_release?
|
7
|
+
osx? && (skip_os_check? || supported_release?)
|
8
8
|
end
|
9
9
|
|
10
10
|
def run
|
@@ -26,4 +26,8 @@ class Boxen::Preflight::OS < Boxen::Preflight
|
|
26
26
|
def current_release
|
27
27
|
@current_release ||= `sw_vers -productVersion`
|
28
28
|
end
|
29
|
+
|
30
|
+
def skip_os_check?
|
31
|
+
ENV['SKIP_OS_CHECK'] == '1'
|
32
|
+
end
|
29
33
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "boxen/util"
|
3
|
+
|
4
|
+
module Boxen
|
5
|
+
|
6
|
+
# Manages an invocation of puppet.
|
7
|
+
|
8
|
+
class Puppeteer
|
9
|
+
|
10
|
+
class Status < Struct.new(:code)
|
11
|
+
# Puppet's detailed exit codes reserves 2 for a successful run with changes
|
12
|
+
def success?
|
13
|
+
[0,2].include?(code)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :config
|
18
|
+
|
19
|
+
def initialize(config)
|
20
|
+
@config = config
|
21
|
+
end
|
22
|
+
|
23
|
+
def command
|
24
|
+
manifestdir = "#{config.repodir}/manifests"
|
25
|
+
puppet = "#{config.repodir}/bin/puppet"
|
26
|
+
|
27
|
+
[puppet, "apply", flags, manifestdir].flatten
|
28
|
+
end
|
29
|
+
|
30
|
+
def hiera_config
|
31
|
+
if File.exist? "#{config.repodir}/config/hiera.yaml"
|
32
|
+
"#{config.repodir}/config/hiera.yaml"
|
33
|
+
else
|
34
|
+
"/dev/null"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def flags
|
39
|
+
flags = []
|
40
|
+
root = File.expand_path "../../..", __FILE__
|
41
|
+
|
42
|
+
flags << ["--group", "admin"]
|
43
|
+
flags << ["--confdir", "#{config.puppetdir}/conf"]
|
44
|
+
flags << ["--vardir", "#{config.puppetdir}/var"]
|
45
|
+
flags << ["--libdir", "#{config.repodir}/lib"]#:#{root}/lib"]
|
46
|
+
flags << ["--libdir", "#{root}/lib"]
|
47
|
+
flags << ["--modulepath", "#{config.repodir}/modules:#{config.repodir}/shared"]
|
48
|
+
|
49
|
+
# Don't ever complain about Hiera to me
|
50
|
+
flags << ["--hiera_config", hiera_config]
|
51
|
+
|
52
|
+
# Log to both the console and a file.
|
53
|
+
|
54
|
+
flags << ["--logdest", config.logfile]
|
55
|
+
flags << ["--logdest", "console"]
|
56
|
+
|
57
|
+
# For some reason Puppet tries to set up a bunch of rrd stuff
|
58
|
+
# (user, group) unless reports are completely disabled.
|
59
|
+
|
60
|
+
flags << "--no-report" unless config.report?
|
61
|
+
flags << "--detailed-exitcodes"
|
62
|
+
|
63
|
+
flags << "--graph" if config.graph?
|
64
|
+
|
65
|
+
flags << "--show_diff"
|
66
|
+
|
67
|
+
if config.profile?
|
68
|
+
flags << "--evaltrace"
|
69
|
+
flags << "--summarize"
|
70
|
+
end
|
71
|
+
|
72
|
+
if config.future_parser?
|
73
|
+
flags << "--parser=future"
|
74
|
+
end
|
75
|
+
|
76
|
+
flags << "--debug" if config.debug?
|
77
|
+
flags << "--noop" if config.pretend?
|
78
|
+
|
79
|
+
flags << "--color=false" unless config.color?
|
80
|
+
|
81
|
+
flags.flatten
|
82
|
+
end
|
83
|
+
|
84
|
+
def run
|
85
|
+
FileUtils.mkdir_p config.puppetdir
|
86
|
+
|
87
|
+
FileUtils.rm_f config.logfile
|
88
|
+
|
89
|
+
FileUtils.rm_rf "#{config.puppetdir}/var/reports" if config.report?
|
90
|
+
|
91
|
+
FileUtils.rm_rf "#{config.puppetdir}/var/state/graphs" if config.graph?
|
92
|
+
|
93
|
+
FileUtils.mkdir_p File.dirname config.logfile
|
94
|
+
FileUtils.touch config.logfile
|
95
|
+
|
96
|
+
if File.file? "Puppetfile"
|
97
|
+
librarian = "#{config.repodir}/bin/librarian-puppet"
|
98
|
+
|
99
|
+
unless config.enterprise?
|
100
|
+
# Set an environment variable for librarian-puppet's
|
101
|
+
# github_tarball source strategy.
|
102
|
+
ENV["GITHUB_API_TOKEN"] = config.token
|
103
|
+
end
|
104
|
+
|
105
|
+
librarian_command = [librarian, "install", "--path=#{config.repodir}/shared"]
|
106
|
+
librarian_command << "--verbose" if config.debug?
|
107
|
+
|
108
|
+
warn librarian_command.join(" ") if config.debug?
|
109
|
+
unless system *librarian_command
|
110
|
+
abort "Can't run Puppet, fetching dependencies with librarian failed."
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
warn command.join(" ") if config.debug?
|
115
|
+
|
116
|
+
Boxen::Util.sudo *command
|
117
|
+
|
118
|
+
Status.new($?.exitstatus)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/boxen/runner.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require "boxen/checkout"
|
2
|
+
require "boxen/config"
|
3
|
+
require "boxen/hook"
|
4
|
+
require "boxen/flags"
|
5
|
+
require "boxen/puppeteer"
|
6
|
+
require "boxen/service"
|
7
|
+
require "boxen/util"
|
8
|
+
require "facter"
|
9
|
+
|
10
|
+
module Boxen
|
11
|
+
class Runner
|
12
|
+
attr_reader :config
|
13
|
+
attr_reader :flags
|
14
|
+
attr_reader :puppet
|
15
|
+
attr_reader :checkout
|
16
|
+
attr_reader :hooks
|
17
|
+
|
18
|
+
def initialize(config, flags)
|
19
|
+
@config = config
|
20
|
+
@flags = flags
|
21
|
+
@puppet = Boxen::Puppeteer.new(@config)
|
22
|
+
@checkout = Boxen::Checkout.new(@config)
|
23
|
+
@hooks = Boxen::Hook.all
|
24
|
+
end
|
25
|
+
|
26
|
+
def process
|
27
|
+
# --env prints out the current BOXEN_ env vars.
|
28
|
+
|
29
|
+
exec "env | grep ^BOXEN_ | sort" if flags.env?
|
30
|
+
|
31
|
+
process_flags
|
32
|
+
|
33
|
+
process_args
|
34
|
+
|
35
|
+
# Actually run Puppet and return its result
|
36
|
+
|
37
|
+
puppet.run
|
38
|
+
end
|
39
|
+
|
40
|
+
def run
|
41
|
+
report(process)
|
42
|
+
end
|
43
|
+
|
44
|
+
def report(result)
|
45
|
+
hooks.each { |hook| hook.new(config, checkout, puppet, result).run }
|
46
|
+
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_flags
|
51
|
+
|
52
|
+
# --projects prints a list of available projects and exits.
|
53
|
+
|
54
|
+
if flags.projects?
|
55
|
+
puts "You can install any of these projects with `#{$0} <project-name>`:\n"
|
56
|
+
|
57
|
+
config.projects.each do |project|
|
58
|
+
puts " #{project.name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
|
64
|
+
# --disable-services stops all services
|
65
|
+
|
66
|
+
if flags.disable_services?
|
67
|
+
Boxen::Service.list.each do |service|
|
68
|
+
puts "Disabling #{service}..."
|
69
|
+
service.disable
|
70
|
+
end
|
71
|
+
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
|
75
|
+
# --enable-services starts all services
|
76
|
+
|
77
|
+
if flags.enable_services?
|
78
|
+
Boxen::Service.list.each do |service|
|
79
|
+
puts "Enabling #{service}..."
|
80
|
+
service.enable
|
81
|
+
end
|
82
|
+
|
83
|
+
exit
|
84
|
+
end
|
85
|
+
|
86
|
+
# --disable-service [name] stops a service
|
87
|
+
|
88
|
+
if flags.disable_service?
|
89
|
+
service = Boxen::Service.new(flags.disable_service)
|
90
|
+
puts "Disabling #{service}..."
|
91
|
+
service.disable
|
92
|
+
|
93
|
+
exit
|
94
|
+
end
|
95
|
+
|
96
|
+
# --enable-service [name] starts a service
|
97
|
+
|
98
|
+
if flags.enable_service?
|
99
|
+
service = Boxen::Service.new(flags.enable_service)
|
100
|
+
puts "Enabling #{service}..."
|
101
|
+
service.enable
|
102
|
+
|
103
|
+
exit
|
104
|
+
end
|
105
|
+
|
106
|
+
# --restart-service [name] starts a service
|
107
|
+
|
108
|
+
if flags.restart_service?
|
109
|
+
service = Boxen::Service.new(flags.restart_service)
|
110
|
+
puts "Restarting #{service}..."
|
111
|
+
service.disable
|
112
|
+
service.enable
|
113
|
+
|
114
|
+
exit
|
115
|
+
end
|
116
|
+
|
117
|
+
# --list-services lists all services
|
118
|
+
|
119
|
+
if flags.list_services?
|
120
|
+
Boxen::Service.list.each do |service|
|
121
|
+
puts service
|
122
|
+
end
|
123
|
+
|
124
|
+
exit
|
125
|
+
end
|
126
|
+
|
127
|
+
# --restart-services restarts all services
|
128
|
+
|
129
|
+
if flags.restart_services?
|
130
|
+
Boxen::Service.list_enabled.each do |service|
|
131
|
+
puts "Restarting #{service}..."
|
132
|
+
service.disable
|
133
|
+
service.enable
|
134
|
+
end
|
135
|
+
|
136
|
+
exit
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_args
|
142
|
+
projects = flags.args.join(',')
|
143
|
+
File.open("#{config.repodir}/.projects", "w+") do |f|
|
144
|
+
f.truncate 0
|
145
|
+
f.write projects
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|