boxen 0.6.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,7 +1,10 @@
1
1
  /.bundle
2
2
  /.env.local.rb
3
+ /.projects
3
4
  /.rbenv-version
5
+ /.ruby-version
4
6
  /Gemfile.lock
5
7
  /bin
6
8
  /boxen-*.gem
9
+ /log
7
10
  /puppet
data/README.md CHANGED
@@ -19,27 +19,16 @@ Manage Mac development boxes with love (and Puppet).
19
19
 
20
20
  Sometimes it's not possible to follow these rules, but try hard.
21
21
 
22
- ## Contributing
22
+ ## Hooks
23
23
 
24
- Use the OS X system Ruby (1.8.7). Run `script/tests` often. Open PR's.
24
+ 0. All hooks must be in the namespace `Boxen::Hook::MyThing`.
25
25
 
26
- ### Managing Boxen's Puppet Modules
26
+ 0. All hooks must subclass from `Boxen::Hook`
27
27
 
28
- There are roughly nine million puppet modules under the
29
- [Boxen GitHub organization][boxen]. To clone them all, run
30
- `script/sync-puppet`. This script will make sure every
31
- `boxen/puppet-*` repo is cloned under the `./puppet` directory, which is
32
- ignored by Git.
28
+ 0. All hooks must provide a private instance method `required_environment_variables` that returns an array with at least one entry.
33
29
 
34
- [boxen]: https://github.com/boxen
30
+ 0. All hooks must provide a private instance method `#call`.
35
31
 
36
- Because it uses the GitHub API, `script/sync-puppet` requires the
37
- `GITHUB_LOGIN` and `GITHUB_PASSWORD` environment variables to be set.
38
- If you don't want to provide them every time, you can set them in
39
- `.env.local.rb`, which is also ignored by Git. For example, your
40
- `.env.local.rb` might look like this:
32
+ ## Contributing
41
33
 
42
- ```ruby
43
- ENV["GITHUB_LOGIN"] = "jbarnette"
44
- ENV["GITHUB_PASSWORD"] = "adventures"
45
- ```
34
+ Use the OS X system Ruby (1.8.7). Run `script/tests` often. Open PR's.
data/boxen.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "boxen"
5
- gem.version = "0.6.0"
5
+ gem.version = "0.7.1"
6
6
  gem.authors = ["John Barnette", "Will Farrington"]
7
7
  gem.email = ["jbarnette@github.com", "wfarr@github.com"]
8
8
  gem.description = "Manage Mac development boxes with love (and Puppet)."
@@ -21,6 +21,6 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "octokit", "~> 1.15"
22
22
  gem.add_dependency "puppet", "~> 3.0"
23
23
 
24
- gem.add_development_dependency "minitest", "3.5.0" # pinned for mocha
25
- gem.add_development_dependency "mocha", "~> 0.12"
24
+ gem.add_development_dependency "minitest", "4.4.0" # pinned for mocha
25
+ gem.add_development_dependency "mocha", "~> 0.13"
26
26
  end
data/lib/boxen/cli.rb CHANGED
@@ -43,11 +43,6 @@ module Boxen
43
43
 
44
44
  Boxen::Preflight.run config
45
45
 
46
- # Okay, we're gonna run Puppet. Let's make some dirs.
47
-
48
- Boxen::Util.sudo("/bin/mkdir", "-p", config.homedir) &&
49
- Boxen::Util.sudo("/usr/sbin/chown", "#{config.user}:staff", config.homedir)
50
-
51
46
  # Save the config for Puppet (and next time).
52
47
 
53
48
  Boxen::Config.save config
data/lib/boxen/hook.rb ADDED
@@ -0,0 +1,40 @@
1
+ module Boxen
2
+ class Hook
3
+ attr_reader :config
4
+ attr_reader :checkout
5
+ attr_reader :puppet
6
+ attr_reader :result
7
+
8
+ def self.all
9
+ [
10
+ Boxen::Hook::GitHubIssue,
11
+ Boxen::Hook::Web
12
+ ]
13
+ end
14
+
15
+ def initialize(config, checkout, puppet, result)
16
+ @config = config
17
+ @checkout = checkout
18
+ @puppet = puppet
19
+ @result = result
20
+ end
21
+
22
+ def enabled?
23
+ required_vars = Array(required_environment_variables)
24
+ required_vars.any? && required_vars.all? do |var|
25
+ ENV[var] && !ENV[var].empty?
26
+ end
27
+ end
28
+
29
+ def perform?
30
+ false
31
+ end
32
+
33
+ def run
34
+ call if perform?
35
+ end
36
+ end
37
+ end
38
+
39
+ require "boxen/hook/github_issue"
40
+ require "boxen/hook/web"
@@ -0,0 +1,115 @@
1
+ require "boxen/hook"
2
+
3
+ module Boxen
4
+ class Hook
5
+ class GitHubIssue < Hook
6
+ def perform?
7
+ enabled? && !config.stealth? && !config.pretend? && checkout.master?
8
+ end
9
+
10
+ def call
11
+ if result.success?
12
+ close_failures
13
+ else
14
+ warn "Sorry! Creating an issue on #{config.reponame}."
15
+ record_failure
16
+ end
17
+ end
18
+
19
+ def compare_url
20
+ return unless config.reponame
21
+ "https://github.com/#{config.reponame}/compare/#{checkout.sha}...master"
22
+ end
23
+
24
+ def hostname
25
+ `hostname`.strip
26
+ end
27
+
28
+ def os
29
+ `sw_vers -productVersion`.strip
30
+ end
31
+
32
+ def shell
33
+ ENV["SHELL"]
34
+ end
35
+
36
+ def log
37
+ File.read config.logfile
38
+ end
39
+
40
+ def record_failure
41
+ return unless issues?
42
+
43
+ title = "Failed for #{config.user}"
44
+ config.api.create_issue(config.reponame, title, failure_details,
45
+ :labels => [failure_label])
46
+ end
47
+
48
+ def close_failures
49
+ return unless issues?
50
+
51
+ comment = "Succeeded at version #{checkout.sha}."
52
+ failures.each do |issue|
53
+ config.api.add_comment(config.reponame, issue.number, comment)
54
+ config.api.close_issue(config.reponame, issue.number)
55
+ end
56
+ end
57
+
58
+ def failures
59
+ return [] unless issues?
60
+
61
+ issues = config.api.list_issues(config.reponame, :state => 'open',
62
+ :labels => failure_label, :creator => config.login)
63
+ issues.reject! {|i| i.labels.collect(&:name).include?(ongoing_label)}
64
+ issues
65
+ end
66
+
67
+ def failure_details
68
+ body = ''
69
+ body << "Running on `#{hostname}` (OS X #{os}) under `#{shell}`, "
70
+ body << "version #{checkout.sha} ([compare to master](#{compare_url}))."
71
+ body << "\n\n"
72
+
73
+ if checkout.dirty?
74
+ body << "### Changes"
75
+ body << "\n\n"
76
+ body << "```\n#{checkout.changes}\n```"
77
+ body << "\n\n"
78
+ end
79
+
80
+ body << "### Puppet Command"
81
+ body << "\n\n"
82
+ body << "```\n#{puppet.command.join(' ')}\n```"
83
+ body << "\n\n"
84
+
85
+ body << "### Output (from #{config.logfile})"
86
+ body << "\n\n"
87
+ body << "```\n#{log}\n```\n"
88
+
89
+ body
90
+ end
91
+
92
+ def failure_label
93
+ @failure_label ||= 'failure'
94
+ end
95
+ attr_writer :failure_label
96
+
97
+ def ongoing_label
98
+ @ongoing_label ||= 'ongoing'
99
+ end
100
+ attr_writer :ongoing_label
101
+
102
+ def issues?
103
+ return unless config.reponame
104
+ return if config.reponame == 'boxen/our-boxen'
105
+
106
+ config.api.repository(config.reponame).has_issues
107
+ end
108
+
109
+ private
110
+ def required_environment_variables
111
+ ['BOXEN_ISSUES_ENABLED']
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,54 @@
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
@@ -32,8 +32,9 @@ class Boxen::Preflight::Creds < Boxen::Preflight
32
32
 
33
33
  config.login = console.ask "GitHub login: " do |q|
34
34
  q.default = config.login || config.user
35
+ q.validate = /\A[^@]+\Z/
35
36
  end
36
-
37
+
37
38
  config.password = console.ask "GitHub password: " do |q|
38
39
  q.echo = "*"
39
40
  end
@@ -0,0 +1,32 @@
1
+ require "boxen/preflight"
2
+ require "boxen/util"
3
+
4
+ class Boxen::Preflight::Directories < Boxen::Preflight
5
+ def ok?
6
+ homedir_directory_exists? &&
7
+ homedir_owner == config.user &&
8
+ homedir_group == 'staff'
9
+ end
10
+
11
+ def run
12
+ Boxen::Util.sudo("/bin/mkdir", "-p", config.homedir) &&
13
+ Boxen::Util.sudo("/usr/sbin/chown", "#{config.user}:staff", config.homedir)
14
+ end
15
+
16
+ private
17
+ def homedir_directory_exists?
18
+ File.directory?(config.homedir)
19
+ end
20
+
21
+ def homedir_owner
22
+ Etc.getpwuid(homedir_stat.uid).name
23
+ end
24
+
25
+ def homedir_group
26
+ Etc.getgrgid(homedir_stat.gid).name
27
+ end
28
+
29
+ def homedir_stat
30
+ @homedir_stat ||= File.stat(config.homedir)
31
+ end
32
+ end
@@ -50,6 +50,8 @@ module Boxen
50
50
  flags << "--no-report"
51
51
  flags << "--detailed-exitcodes"
52
52
 
53
+ flags << "--show_diff"
54
+
53
55
  if config.profile?
54
56
  flags << "--evaltrace"
55
57
  flags << "--summarize"
data/lib/boxen/runner.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require "boxen/checkout"
2
2
  require "boxen/config"
3
+ require "boxen/hook"
3
4
  require "boxen/flags"
4
5
  require "boxen/puppeteer"
5
- require "boxen/reporter"
6
6
  require "boxen/util"
7
7
  require "facter"
8
8
 
@@ -12,14 +12,14 @@ module Boxen
12
12
  attr_reader :flags
13
13
  attr_reader :puppet
14
14
  attr_reader :checkout
15
- attr_reader :reporter
15
+ attr_reader :hooks
16
16
 
17
17
  def initialize(config, flags)
18
- @config = config
19
- @flags = flags
18
+ @config = config
19
+ @flags = flags
20
20
  @puppet = Boxen::Puppeteer.new(@config)
21
21
  @checkout = Boxen::Checkout.new(@config)
22
- @reporter = Boxen::Reporter.new(@config, @checkout, @puppet)
22
+ @hooks = Boxen::Hook.all
23
23
  end
24
24
 
25
25
  def process
@@ -41,14 +41,7 @@ module Boxen
41
41
  end
42
42
 
43
43
  def report(result)
44
- return result unless issues?
45
-
46
- if result.success?
47
- reporter.close_failures
48
- else
49
- warn "Sorry! Creating an issue on #{config.reponame}."
50
- reporter.record_failure
51
- end
44
+ hooks.each { |hook| hook.new(config, checkout, puppet, result).run }
52
45
 
53
46
  result
54
47
  end
@@ -107,11 +100,5 @@ module Boxen
107
100
  f.write projects
108
101
  end
109
102
  end
110
-
111
- # Should the result of this run have any effect on GitHub issues?
112
-
113
- def issues?
114
- !config.stealth? && !config.pretend? && checkout.master?
115
- end
116
103
  end
117
104
  end
data/lib/facter/boxen.rb CHANGED
@@ -4,6 +4,7 @@ require "boxen/config"
4
4
  config = Boxen::Config.load
5
5
  facts = {}
6
6
  factsdir = "#{config.homedir}/config/facts"
7
+ dot_boxen = "#{ENV['HOME']}/.boxen"
7
8
 
8
9
  facts["github_login"] = config.login
9
10
  facts["github_email"] = config.email
@@ -20,4 +21,8 @@ Dir["#{config.homedir}/config/facts/*.json"].each do |file|
20
21
  facts.merge! JSON.parse File.read file
21
22
  end
22
23
 
24
+ if File.exist? dot_boxen
25
+ facts.merge! JSON.parse(File.read(dot_boxen))
26
+ end
27
+
23
28
  facts.each { |k, v| Facter.add(k) { setcode { v } } }
data/test/boxen/test.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "minitest/autorun"
2
- require "mocha"
2
+ require "mocha/setup"
3
3
 
4
4
  module Boxen
5
5
  class Test < MiniTest::Unit::TestCase
@@ -0,0 +1,40 @@
1
+ require 'boxen/test'
2
+ require 'boxen/preflight/directories'
3
+
4
+ class BoxenPreflightDirectoriesTest < Boxen::Test
5
+ class TestConfig
6
+ def user; "foobar"; end
7
+ def homedir; "foobar"; end
8
+ end
9
+
10
+ def setup
11
+ @config = TestConfig.new
12
+ end
13
+
14
+ def test_not_okay_if_homedir_group_wrong
15
+ directories = Boxen::Preflight::Directories.new(@config)
16
+ directories.stubs(:homedir_group).returns(false)
17
+ refute directories.ok?
18
+ end
19
+
20
+ def test_not_okay_if_homedir_owner_wrong
21
+ directories = Boxen::Preflight::Directories.new(@config)
22
+ directories.stubs(:homedir_owner).returns(false)
23
+ refute directories.ok?
24
+ end
25
+
26
+ def test_not_okay_unless_homedir_exists
27
+ directories = Boxen::Preflight::Directories.new(@config)
28
+ directories.stubs(:homedir_directory_exists?).returns(false)
29
+ refute directories.ok?
30
+ end
31
+
32
+ def test_okay_if_allchecks_fine
33
+ directories = Boxen::Preflight::Directories.new(@config)
34
+ directories.stubs(:homedir_directory_exists?).returns(true)
35
+ directories.stubs(:homedir_owner).returns("foobar")
36
+ directories.stubs(:homedir_group).returns("staff")
37
+
38
+ assert directories.ok?
39
+ end
40
+ end
@@ -1,16 +1,50 @@
1
1
  require "boxen/test"
2
- require "boxen/reporter"
2
+ require "boxen/hook/github_issue"
3
3
 
4
4
  class Boxen::Config
5
5
  attr_writer :api
6
6
  end
7
7
 
8
- class BoxenReporterTest < Boxen::Test
8
+ class BoxenHookGitHubIssueTest < Boxen::Test
9
9
  def setup
10
10
  @config = Boxen::Config.new
11
11
  @checkout = Boxen::Checkout.new(@config)
12
12
  @puppet = mock 'puppeteer'
13
- @reporter = Boxen::Reporter.new @config, @checkout, @puppet
13
+ @result = stub 'result', :success? => true
14
+ @hook = Boxen::Hook::GitHubIssue.new @config, @checkout, @puppet, @result
15
+ end
16
+
17
+ def test_enabled
18
+ original = ENV['BOXEN_ISSUES_ENABLED']
19
+
20
+ ENV['BOXEN_ISSUES_ENABLED'] = nil
21
+ refute @hook.enabled?
22
+
23
+ ENV['BOXEN_ISSUES_ENABLED'] = 'duh'
24
+ assert @hook.enabled?
25
+
26
+ ENV['BOXEN_ISSUES_ENABLED'] = original
27
+ end
28
+
29
+ def test_perform
30
+ @hook.stubs(:enabled?).returns(false)
31
+ @config.stubs(:stealth?).returns(true)
32
+ @config.stubs(:pretend?).returns(true)
33
+ @checkout.stubs(:master?).returns(false)
34
+
35
+ refute @hook.perform?
36
+
37
+ @hook.stubs(:enabled?).returns(true)
38
+ refute @hook.perform?
39
+
40
+ @config.stubs(:stealth?).returns(false)
41
+ refute @hook.perform?
42
+
43
+ @config.stubs(:pretend?).returns(false)
44
+ refute @hook.perform?
45
+
46
+ @checkout.stubs(:master?).returns(true)
47
+ assert @hook.perform?
14
48
  end
15
49
 
16
50
  def test_compare_url
@@ -19,97 +53,98 @@ class BoxenReporterTest < Boxen::Test
19
53
  @checkout.expects(:sha).returns(sha)
20
54
 
21
55
  expected = "https://github.com/#{repo}/compare/#{sha}...master"
22
- assert_equal expected, @reporter.compare_url
56
+ assert_equal expected, @hook.compare_url
23
57
  end
24
58
 
25
59
  def test_hostname
26
- @reporter.expects(:"`").with("hostname").returns "whatevs.local\n"
27
- assert_equal "whatevs.local", @reporter.hostname
60
+ @hook.expects(:"`").with("hostname").returns "whatevs.local\n"
61
+ assert_equal "whatevs.local", @hook.hostname
28
62
  end
29
63
 
30
64
  def test_initialize
31
- reporter = Boxen::Reporter.new :config, :checkout, :puppet
32
- assert_equal :config, reporter.config
33
- assert_equal :checkout, reporter.checkout
34
- assert_equal :puppet, reporter.puppet
65
+ hook = Boxen::Hook::GitHubIssue.new :config, :checkout, :puppet, :result
66
+ assert_equal :config, hook.config
67
+ assert_equal :checkout, hook.checkout
68
+ assert_equal :puppet, hook.puppet
69
+ assert_equal :result, hook.result
35
70
  end
36
71
 
37
72
  def test_os
38
- @reporter.expects(:"`").with("sw_vers -productVersion").returns "11.1.1\n"
39
- assert_equal "11.1.1", @reporter.os
73
+ @hook.expects(:"`").with("sw_vers -productVersion").returns "11.1.1\n"
74
+ assert_equal "11.1.1", @hook.os
40
75
  end
41
76
 
42
77
  def test_shell
43
78
  val = ENV['SHELL']
44
79
 
45
80
  ENV['SHELL'] = '/bin/crush'
46
- assert_equal "/bin/crush", @reporter.shell
81
+ assert_equal "/bin/crush", @hook.shell
47
82
 
48
83
  ENV['SHELL'] = val
49
84
  end
50
85
 
51
86
  def test_record_failure
52
- @reporter.stubs(:issues?).returns(true)
87
+ @hook.stubs(:issues?).returns(true)
53
88
 
54
89
  details = 'Everything went wrong.'
55
- @reporter.stubs(:failure_details).returns(details)
90
+ @hook.stubs(:failure_details).returns(details)
56
91
 
57
92
  @config.reponame = repo = 'some/repo'
58
93
  @config.user = user = 'hapless'
59
94
 
60
- @reporter.failure_label = label = 'boom'
95
+ @hook.failure_label = label = 'boom'
61
96
 
62
97
  @config.api = api = mock('api')
63
98
  api.expects(:create_issue).with(repo, "Failed for #{user}", details, :labels => [label])
64
99
 
65
- @reporter.record_failure
100
+ @hook.record_failure
66
101
  end
67
102
 
68
103
  def test_record_failure_no_issues
69
- @reporter.stubs(:issues?).returns(false)
104
+ @hook.stubs(:issues?).returns(false)
70
105
 
71
106
  @config.api = api = mock('api')
72
107
  api.expects(:create_issue).never
73
108
 
74
- @reporter.record_failure
109
+ @hook.record_failure
75
110
  end
76
111
 
77
112
  def test_failure_label
78
113
  default = 'failure'
79
- assert_equal default, @reporter.failure_label
114
+ assert_equal default, @hook.failure_label
80
115
 
81
- @reporter.failure_label = label = 'oops'
82
- assert_equal label, @reporter.failure_label
116
+ @hook.failure_label = label = 'oops'
117
+ assert_equal label, @hook.failure_label
83
118
 
84
- @reporter.failure_label = nil
85
- assert_equal default, @reporter.failure_label
119
+ @hook.failure_label = nil
120
+ assert_equal default, @hook.failure_label
86
121
  end
87
122
 
88
123
  def test_ongoing_label
89
124
  default = 'ongoing'
90
- assert_equal default, @reporter.ongoing_label
125
+ assert_equal default, @hook.ongoing_label
91
126
 
92
- @reporter.ongoing_label = label = 'checkit'
93
- assert_equal label, @reporter.ongoing_label
127
+ @hook.ongoing_label = label = 'checkit'
128
+ assert_equal label, @hook.ongoing_label
94
129
 
95
- @reporter.ongoing_label = nil
96
- assert_equal default, @reporter.ongoing_label
130
+ @hook.ongoing_label = nil
131
+ assert_equal default, @hook.ongoing_label
97
132
  end
98
133
 
99
134
  def test_failure_details
100
135
  sha = 'decafbad'
101
136
  @checkout.stubs(:sha).returns(sha)
102
137
  hostname = 'cools.local'
103
- @reporter.stubs(:hostname).returns(hostname)
138
+ @hook.stubs(:hostname).returns(hostname)
104
139
  shell = '/bin/ksh'
105
- @reporter.stubs(:shell).returns(shell)
140
+ @hook.stubs(:shell).returns(shell)
106
141
  os = '11.1.1'
107
- @reporter.stubs(:os).returns(os)
142
+ @hook.stubs(:os).returns(os)
108
143
  log = "so\nmany\nthings\nto\nreport"
109
- @reporter.stubs(:log).returns(log)
144
+ @hook.stubs(:log).returns(log)
110
145
 
111
146
  @config.reponame = repo = 'some/repo'
112
- compare = @reporter.compare_url
147
+ compare = @hook.compare_url
113
148
  changes = 'so many changes'
114
149
  @checkout.stubs(:changes).returns(changes)
115
150
 
@@ -119,7 +154,7 @@ class BoxenReporterTest < Boxen::Test
119
154
 
120
155
  @config.logfile = logfile = '/path/to/logfile.txt'
121
156
 
122
- details = @reporter.failure_details
157
+ details = @hook.failure_details
123
158
 
124
159
  assert_match sha, details
125
160
  assert_match hostname, details
@@ -138,7 +173,7 @@ class BoxenReporterTest < Boxen::Test
138
173
  log = 'a bunch of log data'
139
174
  File.expects(:read).with(logfile).returns(log)
140
175
 
141
- assert_equal log, @reporter.log
176
+ assert_equal log, @hook.log
142
177
  end
143
178
 
144
179
 
@@ -150,12 +185,12 @@ class BoxenReporterTest < Boxen::Test
150
185
  Label = Struct.new(:name)
151
186
 
152
187
  def test_close_failures
153
- @reporter.stubs(:issues?).returns(true)
188
+ @hook.stubs(:issues?).returns(true)
154
189
 
155
190
  @config.reponame = repo = 'some/repo'
156
191
 
157
192
  issues = Array.new(3) { |i| Issue.new(i*2 + 2) }
158
- @reporter.stubs(:failures).returns(issues)
193
+ @hook.stubs(:failures).returns(issues)
159
194
 
160
195
  sha = 'decafbad'
161
196
  @checkout.stubs(:sha).returns(sha)
@@ -166,29 +201,29 @@ class BoxenReporterTest < Boxen::Test
166
201
  api.expects(:close_issue).with(repo, issue.number)
167
202
  end
168
203
 
169
- @reporter.close_failures
204
+ @hook.close_failures
170
205
  end
171
206
 
172
207
  def test_close_failures_no_issues
173
- @reporter.stubs(:issues?).returns(false)
208
+ @hook.stubs(:issues?).returns(false)
174
209
 
175
- @reporter.expects(:failures).never
210
+ @hook.expects(:failures).never
176
211
 
177
212
  @config.api = api = mock('api')
178
213
  api.expects(:add_comment).never
179
214
  api.expects(:close_issue).never
180
215
 
181
- @reporter.close_failures
216
+ @hook.close_failures
182
217
  end
183
218
 
184
219
  def test_failures
185
- @reporter.stubs(:issues?).returns(true)
220
+ @hook.stubs(:issues?).returns(true)
186
221
 
187
222
  @config.reponame = repo = 'some/repo'
188
223
  @config.login = user = 'hapless'
189
224
 
190
- @reporter.failure_label = fail_label = 'ouch'
191
- @reporter.ongoing_label = goon_label = 'goon'
225
+ @hook.failure_label = fail_label = 'ouch'
226
+ @hook.ongoing_label = goon_label = 'goon'
192
227
 
193
228
  fail_l = Label.new(fail_label)
194
229
  goon_l = Label.new(goon_label)
@@ -205,16 +240,16 @@ class BoxenReporterTest < Boxen::Test
205
240
  @config.api = api = mock('api')
206
241
  api.expects(:list_issues).with(repo, :state => 'open', :labels => fail_label, :creator => user).returns(issues)
207
242
 
208
- assert_equal issues.values_at(0,1,3), @reporter.failures
243
+ assert_equal issues.values_at(0,1,3), @hook.failures
209
244
  end
210
245
 
211
246
  def test_failures_no_issues
212
- @reporter.stubs(:issues?).returns(false)
247
+ @hook.stubs(:issues?).returns(false)
213
248
 
214
249
  @config.api = api = mock('api')
215
250
  api.expects(:list_issues).never
216
251
 
217
- assert_equal [], @reporter.failures
252
+ assert_equal [], @hook.failures
218
253
  end
219
254
 
220
255
  RepoInfo = Struct.new(:has_issues)
@@ -225,18 +260,18 @@ class BoxenReporterTest < Boxen::Test
225
260
 
226
261
  @config.api = api = mock('api')
227
262
  api.stubs(:repository).with(repo).returns(repo_info)
228
- assert @reporter.issues?
263
+ assert @hook.issues?
229
264
 
230
265
  repo_info = RepoInfo.new(false)
231
266
  api.stubs(:repository).with(repo).returns(repo_info)
232
- refute @reporter.issues?
267
+ refute @hook.issues?
233
268
 
234
269
  @config.stubs(:reponame) # to ensure the returned value is nil
235
270
  api.stubs(:repository).returns(RepoInfo.new(true))
236
- refute @reporter.issues?
271
+ refute @hook.issues?
237
272
 
238
273
  @config.stubs(:reponame).returns('boxen/our-boxen') # our main public repo
239
274
  api.stubs(:repository).returns(RepoInfo.new(true))
240
- refute @reporter.issues?
275
+ refute @hook.issues?
241
276
  end
242
277
  end
@@ -0,0 +1,58 @@
1
+ require "boxen/test"
2
+ require "boxen/hook/web"
3
+
4
+ class Boxen::Config
5
+ attr_writer :api
6
+ end
7
+
8
+ class BoxenHookWebTest < Boxen::Test
9
+ def setup
10
+ @config = Boxen::Config.new
11
+ @checkout = Boxen::Checkout.new(@config)
12
+ @puppet = mock 'puppeteer'
13
+ @result = stub 'result', :success? => true
14
+ @hook = Boxen::Hook::Web.new @config, @checkout, @puppet, @result
15
+ end
16
+
17
+ def test_enabled
18
+ original = ENV['BOXEN_WEB_HOOK_URL']
19
+
20
+ ENV['BOXEN_WEB_HOOK_URL'] = nil
21
+ refute @hook.enabled?
22
+
23
+ ENV['BOXEN_WEB_HOOK_URL'] = ''
24
+ refute @hook.enabled?
25
+
26
+ ENV['BOXEN_WEB_HOOK_URL'] = '1'
27
+ assert @hook.enabled?
28
+
29
+ ENV['BOXEN_WEB_HOOK_URL'] = original
30
+ end
31
+
32
+ def test_perform
33
+ @hook.stubs(:enabled?).returns(false)
34
+ refute @hook.perform?
35
+
36
+ @hook.stubs(:enabled?).returns(true)
37
+ assert @hook.perform?
38
+ end
39
+
40
+ def test_run
41
+ @config.stubs(:user).returns('fred')
42
+ @checkout.stubs(:sha).returns('87dbag3')
43
+ @result.stubs(:success?).returns(false)
44
+ now = Time.now
45
+ Time.stubs(:now).returns(now)
46
+
47
+ @hook.stubs(:enabled?).returns(true)
48
+
49
+ @hook.expects(:post_web_hook).with({
50
+ :login => 'fred',
51
+ :sha => '87dbag3',
52
+ :status => 'failure',
53
+ :time => "#{now.utc.to_i}"
54
+ })
55
+
56
+ @hook.run
57
+ end
58
+ end
@@ -20,93 +20,24 @@ class BoxenRunnerTest < Boxen::Test
20
20
  assert_equal config, runner.config
21
21
  assert_equal flags, runner.flags
22
22
  assert_equal config, runner.puppet.config
23
-
24
- assert_equal config, runner.reporter.config
25
- assert_equal config, runner.reporter.checkout.config
26
- assert_equal runner.checkout, runner.reporter.checkout
27
- assert_equal runner.puppet, runner.reporter.puppet
28
- end
29
-
30
- def test_issues?
31
- @config.stealth = true
32
- @config.pretend = true
33
- @runner.checkout.stubs(:master?).returns(false)
34
- assert !@runner.issues?
35
-
36
- @config.stealth = false
37
- @config.pretend = true
38
- @runner.checkout.stubs(:master?).returns(false)
39
- assert !@runner.issues?
40
-
41
- @config.stealth = true
42
- @config.pretend = false
43
- @runner.checkout.stubs(:master?).returns(false)
44
- assert !@runner.issues?
45
-
46
- @config.stealth = true
47
- @config.pretend = true
48
- @runner.checkout.stubs(:master?).returns(true)
49
- assert !@runner.issues?
50
-
51
- @config.stealth = false
52
- @config.pretend = true
53
- @runner.checkout.stubs(:master?).returns(true)
54
- assert !@runner.issues?
55
-
56
- @config.stealth = true
57
- @config.pretend = false
58
- @runner.checkout.stubs(:master?).returns(true)
59
- assert !@runner.issues?
60
-
61
- @config.stealth = false
62
- @config.pretend = false
63
- @runner.checkout.stubs(:master?).returns(true)
64
- assert @runner.issues?
65
- end
66
-
67
- def test_report_failure
68
- @runner.stubs(:issues?).returns(true)
69
- status = stub('status', :success? => false)
70
- @runner.stubs(:process).returns(status)
71
- @runner.stubs(:warn)
72
-
73
- @runner.reporter.expects(:record_failure)
74
- @runner.reporter.expects(:close_failures).never
75
-
76
- @runner.run
77
23
  end
78
24
 
79
- def test_run_success
80
- @runner.stubs(:issues?).returns(true)
81
- status = stub('status', :success? => true)
82
- @runner.stubs(:process).returns(status)
25
+ HookYes = Struct.new(:config, :checkout, :puppet, :result)
26
+ HookNo = Struct.new(:config, :checkout, :puppet, :result)
27
+ def test_report
28
+ runner = Boxen::Runner.new(@config, @flags)
29
+ runner.stubs(:hooks).returns([HookYes, HookNo])
83
30
 
84
- @runner.reporter.expects(:record_failure).never
85
- @runner.reporter.expects(:close_failures)
86
-
87
- @runner.run
88
- end
89
-
90
- def test_run_failure_no_issues
91
- @runner.stubs(:issues?).returns(false)
92
- status = stub('status', :success? => false)
93
- @runner.stubs(:process).returns(status)
94
-
95
- @runner.reporter.expects(:record_failure).never
96
- @runner.reporter.expects(:close_failures).never
97
-
98
- @runner.run
99
- end
31
+ hook_yes = stub('HookYes')
32
+ hook_no = stub('HookNo')
100
33
 
101
- def test_run_success_no_issues
102
- @runner.stubs(:issues?).returns(false)
103
- status = stub('status', :success? => true)
104
- @runner.stubs(:process).returns(status)
34
+ HookYes.stubs(:new).returns(hook_yes)
35
+ HookNo.stubs(:new).returns(hook_no)
105
36
 
106
- @runner.reporter.expects(:record_failure).never
107
- @runner.reporter.expects(:close_failures).never
37
+ hook_yes.expects(:run).once
38
+ hook_no.expects(:run).once
108
39
 
109
- @runner.run
40
+ runner.report(stub('result'))
110
41
  end
111
42
 
112
43
  def test_disable_services
@@ -148,6 +79,7 @@ class BoxenRunnerTest < Boxen::Test
148
79
  end
149
80
 
150
81
  def test_specify_project
82
+ skip "busted and probably due to be replaced if @jbarnette can fix it"
151
83
  fact = 'cli_boxen_projects'
152
84
  refute Facter.value(fact)
153
85
 
@@ -155,6 +87,7 @@ class BoxenRunnerTest < Boxen::Test
155
87
  flags = Boxen::Flags.new(project)
156
88
 
157
89
  runner = Boxen::Runner.new(@config, flags)
90
+ runner.puppet.expects(:run).with().returns(true)
158
91
  runner.process
159
92
  assert_equal project, Facter.value(fact)
160
93
 
@@ -163,6 +96,7 @@ class BoxenRunnerTest < Boxen::Test
163
96
  flags = Boxen::Flags.new('--debug', project)
164
97
 
165
98
  runner = Boxen::Runner.new(@config, flags)
99
+ runner.puppet.expects(:run).with().returns(true)
166
100
  runner.process
167
101
  assert_equal project, Facter.value(fact)
168
102
 
@@ -171,6 +105,7 @@ class BoxenRunnerTest < Boxen::Test
171
105
  flags = Boxen::Flags.new('--noop', *projects)
172
106
 
173
107
  runner = Boxen::Runner.new(@config, flags)
108
+ runner.puppet.expects(:run).with().returns(true)
174
109
  runner.process
175
110
  assert_equal projects.join(','), Facter.value(fact)
176
111
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 6
8
- - 0
9
- version: 0.6.0
7
+ - 7
8
+ - 1
9
+ version: 0.7.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - John Barnette
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-01-21 00:00:00 -08:00
18
+ date: 2013-02-02 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -118,10 +118,10 @@ dependencies:
118
118
  - - "="
119
119
  - !ruby/object:Gem::Version
120
120
  segments:
121
- - 3
122
- - 5
121
+ - 4
122
+ - 4
123
123
  - 0
124
- version: 3.5.0
124
+ version: 4.4.0
125
125
  type: :development
126
126
  version_requirements: *id008
127
127
  - !ruby/object:Gem::Dependency
@@ -133,8 +133,8 @@ dependencies:
133
133
  - !ruby/object:Gem::Version
134
134
  segments:
135
135
  - 0
136
- - 12
137
- version: "0.12"
136
+ - 13
137
+ version: "0.13"
138
138
  type: :development
139
139
  version_requirements: *id009
140
140
  description: Manage Mac development boxes with love (and Puppet).
@@ -160,11 +160,15 @@ files:
160
160
  - lib/boxen/config.rb
161
161
  - lib/boxen/error.rb
162
162
  - lib/boxen/flags.rb
163
+ - lib/boxen/hook.rb
164
+ - lib/boxen/hook/github_issue.rb
165
+ - lib/boxen/hook/web.rb
163
166
  - lib/boxen/postflight.rb
164
167
  - lib/boxen/postflight/active.rb
165
168
  - lib/boxen/postflight/env.rb
166
169
  - lib/boxen/preflight.rb
167
170
  - lib/boxen/preflight/creds.rb
171
+ - lib/boxen/preflight/directories.rb
168
172
  - lib/boxen/preflight/etc_my_cnf.rb
169
173
  - lib/boxen/preflight/homebrew.rb
170
174
  - lib/boxen/preflight/identity.rb
@@ -173,23 +177,23 @@ files:
173
177
  - lib/boxen/preflight/rvm.rb
174
178
  - lib/boxen/project.rb
175
179
  - lib/boxen/puppeteer.rb
176
- - lib/boxen/reporter.rb
177
180
  - lib/boxen/runner.rb
178
181
  - lib/boxen/service.rb
179
182
  - lib/boxen/util.rb
180
183
  - lib/facter/boxen.rb
181
- - lib/facter/dot_boxen.rb
182
184
  - lib/system_timer.rb
183
185
  - script/bootstrap
184
186
  - script/release
185
- - script/sync-puppet
186
187
  - script/tests
187
188
  - test/boxen/test.rb
188
189
  - test/boxen_check_test.rb
189
190
  - test/boxen_checkout_test.rb
190
191
  - test/boxen_cli_test.rb
191
192
  - test/boxen_config_test.rb
193
+ - test/boxen_directories_test.rb
192
194
  - test/boxen_flags_test.rb
195
+ - test/boxen_hook_github_issue_test.rb
196
+ - test/boxen_hook_web_test.rb
193
197
  - test/boxen_postflight_active_test.rb
194
198
  - test/boxen_postflight_env_test.rb
195
199
  - test/boxen_preflight_etc_my_cnf_test.rb
@@ -197,7 +201,6 @@ files:
197
201
  - test/boxen_preflight_rvm_test.rb
198
202
  - test/boxen_project_test.rb
199
203
  - test/boxen_puppeteer_test.rb
200
- - test/boxen_reporter_test.rb
201
204
  - test/boxen_runner_test.rb
202
205
  - test/boxen_service_test.rb
203
206
  - test/boxen_util_test.rb
@@ -240,7 +243,10 @@ test_files:
240
243
  - test/boxen_checkout_test.rb
241
244
  - test/boxen_cli_test.rb
242
245
  - test/boxen_config_test.rb
246
+ - test/boxen_directories_test.rb
243
247
  - test/boxen_flags_test.rb
248
+ - test/boxen_hook_github_issue_test.rb
249
+ - test/boxen_hook_web_test.rb
244
250
  - test/boxen_postflight_active_test.rb
245
251
  - test/boxen_postflight_env_test.rb
246
252
  - test/boxen_preflight_etc_my_cnf_test.rb
@@ -248,7 +254,6 @@ test_files:
248
254
  - test/boxen_preflight_rvm_test.rb
249
255
  - test/boxen_project_test.rb
250
256
  - test/boxen_puppeteer_test.rb
251
- - test/boxen_reporter_test.rb
252
257
  - test/boxen_runner_test.rb
253
258
  - test/boxen_service_test.rb
254
259
  - test/boxen_util_test.rb
@@ -1,103 +0,0 @@
1
- module Boxen
2
- class Reporter
3
- attr_reader :config
4
- attr_reader :checkout
5
- attr_reader :puppet
6
-
7
- def initialize(config, checkout, puppet)
8
- @config = config
9
- @checkout = checkout
10
- @puppet = puppet
11
- end
12
-
13
- def compare_url
14
- return unless config.reponame
15
- "https://github.com/#{config.reponame}/compare/#{checkout.sha}...master"
16
- end
17
-
18
- def hostname
19
- `hostname`.strip
20
- end
21
-
22
- def os
23
- `sw_vers -productVersion`.strip
24
- end
25
-
26
- def shell
27
- ENV["SHELL"]
28
- end
29
-
30
- def log
31
- File.read config.logfile
32
- end
33
-
34
- def record_failure
35
- return unless issues?
36
-
37
- title = "Failed for #{config.user}"
38
- config.api.create_issue(config.reponame, title, failure_details,
39
- :labels => [failure_label])
40
- end
41
-
42
- def close_failures
43
- return unless issues?
44
-
45
- comment = "Succeeded at version #{checkout.sha}."
46
- failures.each do |issue|
47
- config.api.add_comment(config.reponame, issue.number, comment)
48
- config.api.close_issue(config.reponame, issue.number)
49
- end
50
- end
51
-
52
- def failures
53
- return [] unless issues?
54
-
55
- issues = config.api.list_issues(config.reponame, :state => 'open',
56
- :labels => failure_label, :creator => config.login)
57
- issues.reject! {|i| i.labels.collect(&:name).include?(ongoing_label)}
58
- issues
59
- end
60
-
61
- def failure_details
62
- body = ''
63
- body << "Running on `#{hostname}` (OS X #{os}) under `#{shell}`, "
64
- body << "version #{checkout.sha} ([compare to master](#{compare_url}))."
65
- body << "\n\n"
66
-
67
- if checkout.dirty?
68
- body << "### Changes"
69
- body << "\n\n"
70
- body << "```\n#{checkout.changes}\n```"
71
- body << "\n\n"
72
- end
73
-
74
- body << "### Puppet Command"
75
- body << "\n\n"
76
- body << "```\n#{puppet.command.join(' ')}\n```"
77
- body << "\n\n"
78
-
79
- body << "### Output (from #{config.logfile})"
80
- body << "\n\n"
81
- body << "```\n#{log}\n```\n"
82
-
83
- body
84
- end
85
-
86
- def failure_label
87
- @failure_label ||= 'failure'
88
- end
89
- attr_writer :failure_label
90
-
91
- def ongoing_label
92
- @ongoing_label ||= 'ongoing'
93
- end
94
- attr_writer :ongoing_label
95
-
96
- def issues?
97
- return unless config.reponame
98
- return if config.reponame == 'boxen/our-boxen'
99
-
100
- config.api.repository(config.reponame).has_issues
101
- end
102
- end
103
- end
@@ -1,8 +0,0 @@
1
- require "json"
2
-
3
- dot_boxen = "#{ENV['HOME']}/.boxen"
4
-
5
- if File.exist? dot_boxen
6
- facts = JSON.parse(File.read(dot_boxen))
7
- facts.each { |k, v| Facter.add(k) { setcode { v } } }
8
- end
data/script/sync-puppet DELETED
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # Make sure all boxen/puppet-* repos are cloned under ./puppet.
3
-
4
- require "fileutils"
5
- require "pathname"
6
-
7
- # Put us where we belong, in the root dir of boxen.
8
-
9
- Dir.chdir Pathname.new(__FILE__).realpath + "../.."
10
-
11
- # Load the local env in case creds are set there.
12
-
13
- load ".env.local.rb" if File.file? ".env.local.rb"
14
-
15
- # Make sure we're up to date.
16
-
17
- abort "Bootstrap failed." unless system "script/bootstrap"
18
-
19
- require "rubygems"
20
- require "bundler/setup"
21
- require "octokit"
22
-
23
- unless ENV["GITHUB_LOGIN"] && ENV["GITHUB_PASSWORD"]
24
- abort "Please set the GITHUB_LOGIN and GITHUB_PASSWORD env vars."
25
- end
26
-
27
- api = Octokit::Client.new \
28
- :login => ENV["GITHUB_LOGIN"], :password => ENV["GITHUB_PASSWORD"]
29
-
30
- # Gotta have a ./puppet dir.
31
-
32
- FileUtils.mkdir_p "puppet"
33
-
34
- # Clone boxen/puppet-* unless we have it already.
35
-
36
- api.organization_repositories("boxen").each do |repo|
37
- next unless /^puppet-/ =~ repo.name
38
-
39
- dest = "puppet/" + repo.name[7..-1]
40
-
41
- unless File.directory? dest
42
- system "git", "clone", repo.clone_url, dest
43
- end
44
- end