boxen 0.2.4 → 0.3.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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "boxen"
5
- gem.version = "0.2.4"
5
+ gem.version = "0.3.0"
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)."
@@ -0,0 +1,25 @@
1
+ module Boxen
2
+ class Checkout
3
+ attr_reader :config
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ end
8
+
9
+ def sha
10
+ Dir.chdir(config.repodir) { `git rev-parse HEAD`.strip }
11
+ end
12
+
13
+ def master?
14
+ Dir.chdir(config.repodir) { `git symbolic-ref HEAD`.strip == 'refs/heads/master' }
15
+ end
16
+
17
+ def dirty?
18
+ !changes.empty?
19
+ end
20
+
21
+ def changes
22
+ Dir.chdir(config.repodir) { `git status --porcelain`.strip }
23
+ end
24
+ end
25
+ end
@@ -1,8 +1,10 @@
1
+ require "boxen/checkout"
1
2
  require "boxen/config"
2
3
  require "boxen/flags"
3
4
  require "boxen/postflight"
4
5
  require "boxen/preflight"
5
6
  require "boxen/puppeteer"
7
+ require "boxen/reporter"
6
8
  require "boxen/util"
7
9
 
8
10
  module Boxen
@@ -10,15 +12,18 @@ module Boxen
10
12
  attr_reader :config
11
13
  attr_reader :flags
12
14
  attr_reader :puppet
15
+ attr_reader :checkout
16
+ attr_reader :reporter
13
17
 
14
18
  def initialize(config, flags)
15
19
  @config = config
16
20
  @flags = flags
17
21
  @puppet = Boxen::Puppeteer.new @config
22
+ @checkout = Boxen::Checkout.new(@config)
23
+ @reporter = Boxen::Reporter.new(@config, @checkout, @puppet)
18
24
  end
19
25
 
20
- def run
21
-
26
+ def process
22
27
  # --env prints out the current BOXEN_ env vars.
23
28
 
24
29
  exec "env | grep ^BOXEN_ | sort" if flags.env?
@@ -38,10 +43,26 @@ module Boxen
38
43
  exit
39
44
  end
40
45
 
41
- # Actually run Puppet and return its exit code. FIX: Here's
42
- # where we'll reintegrate automatic error reporting.
46
+ # Actually run Puppet and return its exit code.
43
47
 
44
- return puppet.run
48
+ puppet.run
49
+ end
50
+
51
+ def run
52
+ report(process)
53
+ end
54
+
55
+ def report(result)
56
+ return result unless issues?
57
+
58
+ if result.zero?
59
+ reporter.close_failures
60
+ else
61
+ warn "Sorry! Creating an issue on #{config.reponame}."
62
+ reporter.record_failure
63
+ end
64
+
65
+ result
45
66
  end
46
67
 
47
68
  # Run Boxen by wiring together the command-line flags, config,
@@ -82,5 +103,11 @@ module Boxen
82
103
 
83
104
  return status
84
105
  end
106
+
107
+ # Should the result of this run have any effect on GitHub issues?
108
+
109
+ def issues?
110
+ !config.stealth? && !config.pretend? && checkout.master?
111
+ end
85
112
  end
86
113
  end
@@ -54,6 +54,7 @@ module Boxen
54
54
  :name => config.name,
55
55
  :puppetdir => config.puppetdir,
56
56
  :repodir => config.repodir,
57
+ :reponame => config.reponame,
57
58
  :srcdir => config.srcdir,
58
59
  :token => config.token,
59
60
  :user => config.user
@@ -100,10 +101,6 @@ module Boxen
100
101
 
101
102
  attr_writer :debug
102
103
 
103
- def dirty?
104
- `git status --porcelain`.strip.empty?
105
- end
106
-
107
104
  # A GitHub user's public email.
108
105
 
109
106
  attr_accessor :email
@@ -151,12 +148,6 @@ module Boxen
151
148
  @login = login
152
149
  end
153
150
 
154
- # Is Boxen running on the `master` branch?
155
-
156
- def master?
157
- `git symbolic-ref HEAD`.chomp == "refs/heads/master"
158
- end
159
-
160
151
  # A GitHub user's profile name.
161
152
 
162
153
  attr_accessor :name
@@ -223,6 +214,26 @@ module Boxen
223
214
 
224
215
  attr_writer :repodir
225
216
 
217
+ # The repo on GitHub to use for error reports and automatic
218
+ # updates, in `owner/repo` format. Default is the `origin` of a
219
+ # Git repo in `repodir`, if it exists and points at GitHub.
220
+ # Respects the `BOXEN_REPO_NAME` environment variable.
221
+
222
+ def reponame
223
+ override = @reponame || ENV["BOXEN_REPO_NAME"]
224
+ return override unless override.nil?
225
+
226
+ if File.directory? repodir
227
+ url = Dir.chdir(repodir) { `git config remote.origin.url`.strip }
228
+
229
+ if $?.success? && %r|github\.com[/:]([^/]+/[^/]+)| =~ url
230
+ @reponame = $1.sub /\.git$/, ""
231
+ end
232
+ end
233
+ end
234
+
235
+ attr_writer :reponame
236
+
226
237
  # The directory where repos live. Default is
227
238
  # `"/Users/#{user}/src"`.
228
239
 
@@ -7,7 +7,7 @@ class Boxen::Postflight::Env < Boxen::Postflight
7
7
  def self.checksum
8
8
 
9
9
  # We can't get this from config 'cause it's static (gotta happen
10
- # on load), and GH_HOME might not be set.
10
+ # on load), and BOXEN_HOME might not be set.
11
11
 
12
12
  home = ENV["BOXEN_HOME"] || "/opt/boxen"
13
13
  return unless File.file? "#{home}/env.sh"
@@ -0,0 +1,90 @@
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
+ title = "Failed for #{config.user}"
36
+ config.api.create_issue(config.reponame, title, failure_details,
37
+ :labels => [failure_label])
38
+ end
39
+
40
+ def close_failures
41
+ comment = "Succeeded at version #{checkout.sha}."
42
+ failures.each do |issue|
43
+ config.api.add_comment(config.reponame, issue.number, comment)
44
+ config.api.close_issue(config.reponame, issue.number)
45
+ end
46
+ end
47
+
48
+ def failures
49
+ issues = config.api.list_issues(config.reponame, :state => 'open',
50
+ :labels => failure_label, :creator => config.login)
51
+ issues.reject! {|i| i.labels.collect(&:name).include?(ongoing_label)}
52
+ issues
53
+ end
54
+
55
+ def failure_details
56
+ body = ''
57
+ body << "Running on `#{hostname}` (OS X #{os}) under `#{shell}`, "
58
+ body << "version #{checkout.sha} ([compare to master](#{compare_url}))."
59
+ body << "\n\n"
60
+
61
+ if checkout.dirty?
62
+ body << "### Changes"
63
+ body << "\n\n"
64
+ body << "```\n#{checkout.changes}\n```"
65
+ body << "\n\n"
66
+ end
67
+
68
+ body << "### Puppet Command"
69
+ body << "\n\n"
70
+ body << "```\n#{puppet.command.join(' ')}\n```"
71
+ body << "\n\n"
72
+
73
+ body << "### Output (from #{config.logfile})"
74
+ body << "\n\n"
75
+ body << "```\n#{log}\n```\n"
76
+
77
+ body
78
+ end
79
+
80
+ def failure_label
81
+ @failure_label ||= 'failure'
82
+ end
83
+ attr_writer :failure_label
84
+
85
+ def ongoing_label
86
+ @ongoing_label ||= 'ongoing'
87
+ end
88
+ attr_writer :ongoing_label
89
+ end
90
+ end
@@ -0,0 +1,13 @@
1
+ # Faraday helpfully reminds you to install `system_timer` if you're
2
+ # running Ruby 1.8, since Timeout can give unreliable results. We
3
+ # can't do this during first-time runs, since there's no C compiler
4
+ # available.
5
+ #
6
+ # To squash the message and stop confusing people, this shim just
7
+ # exposes Timeout as SystemTimer. I'm a bad person.
8
+
9
+
10
+ if (!defined?(RUBY_ENGINE) || "ruby" == RUBY_ENGINE) && RUBY_VERSION < '1.9'
11
+ require "timeout"
12
+ SystemTimer = Timeout
13
+ end
@@ -34,4 +34,5 @@ git fetch -t origin
34
34
 
35
35
  # Tag it and bag it.
36
36
 
37
- gem push boxen-*.gem && git tag "$tag" && git push origin --tags
37
+ gem push boxen-*.gem && git tag "$tag" &&
38
+ git push origin master && git push origin "$tag"
@@ -16,6 +16,7 @@ load ".env.local.rb" if File.file? ".env.local.rb"
16
16
 
17
17
  abort "Bootstrap failed." unless system "script/bootstrap"
18
18
 
19
+ require "rubygems"
19
20
  require "bundler/setup"
20
21
  require "octokit"
21
22
 
@@ -0,0 +1,42 @@
1
+ require "boxen/test"
2
+ require "boxen/checkout"
3
+
4
+ class BoxenCheckoutTest < Boxen::Test
5
+ def setup
6
+ @config = Boxen::Config.new { |c| c.repodir = 'test/fixtures/repo' }
7
+ @checkout = Boxen::Checkout.new @config
8
+ end
9
+
10
+ def test_initialize
11
+ checkout = Boxen::Checkout.new :config
12
+ assert_equal :config, checkout.config
13
+ end
14
+
15
+ def test_sha
16
+ sha = 'deadbeef'
17
+ @checkout.expects(:"`").with("git rev-parse HEAD").returns("#{sha}\n")
18
+ assert_equal sha, @checkout.sha
19
+ end
20
+
21
+ def test_master?
22
+ @checkout.stubs(:"`").with("git symbolic-ref HEAD").returns("refs/heads/topic\n")
23
+ assert !@checkout.master?
24
+
25
+ @checkout.stubs(:"`").with("git symbolic-ref HEAD").returns("refs/heads/master\n")
26
+ assert @checkout.master?
27
+ end
28
+
29
+ def test_changes
30
+ changes = ' maybe a bunch of stuff happened '
31
+ @checkout.expects(:"`").with("git status --porcelain").returns(changes)
32
+ assert_equal changes.strip, @checkout.changes
33
+ end
34
+
35
+ def test_dirty?
36
+ @checkout.stubs(:changes).returns('stuff happened')
37
+ assert @checkout.dirty?
38
+
39
+ @checkout.stubs(:changes).returns('')
40
+ assert !@checkout.dirty?
41
+ end
42
+ end
@@ -2,14 +2,103 @@ require "boxen/test"
2
2
  require "boxen/cli"
3
3
 
4
4
  class BoxenCLITest < Boxen::Test
5
+ def setup
6
+ @config = Boxen::Config.new
7
+ @flags = Boxen::Flags.new
8
+ @cli = Boxen::CLI.new(@config, @flags)
9
+ end
10
+
5
11
  def test_initialize
6
- config = mock
7
- flags = mock
12
+ config = Boxen::Config.new
13
+ flags = Boxen::Flags.new
8
14
 
9
15
  cli = Boxen::CLI.new config, flags
10
16
 
11
17
  assert_equal config, cli.config
12
18
  assert_equal flags, cli.flags
13
19
  assert_equal config, cli.puppet.config
20
+
21
+ assert_equal config, cli.reporter.config
22
+ assert_equal config, cli.reporter.checkout.config
23
+ assert_equal cli.checkout, cli.reporter.checkout
24
+ assert_equal cli.puppet, cli.reporter.puppet
25
+ end
26
+
27
+ def test_issues?
28
+ @config.stealth = true
29
+ @config.pretend = true
30
+ @cli.checkout.stubs(:master?).returns(false)
31
+ assert !@cli.issues?
32
+
33
+ @config.stealth = false
34
+ @config.pretend = true
35
+ @cli.checkout.stubs(:master?).returns(false)
36
+ assert !@cli.issues?
37
+
38
+ @config.stealth = true
39
+ @config.pretend = false
40
+ @cli.checkout.stubs(:master?).returns(false)
41
+ assert !@cli.issues?
42
+
43
+ @config.stealth = true
44
+ @config.pretend = true
45
+ @cli.checkout.stubs(:master?).returns(true)
46
+ assert !@cli.issues?
47
+
48
+ @config.stealth = false
49
+ @config.pretend = true
50
+ @cli.checkout.stubs(:master?).returns(true)
51
+ assert !@cli.issues?
52
+
53
+ @config.stealth = true
54
+ @config.pretend = false
55
+ @cli.checkout.stubs(:master?).returns(true)
56
+ assert !@cli.issues?
57
+
58
+ @config.stealth = false
59
+ @config.pretend = false
60
+ @cli.checkout.stubs(:master?).returns(true)
61
+ assert @cli.issues?
62
+ end
63
+
64
+ def test_report_failure
65
+ @cli.stubs(:issues?).returns(true)
66
+ @cli.stubs(:process).returns(1)
67
+ @cli.stubs(:warn)
68
+
69
+ @cli.reporter.expects(:record_failure)
70
+ @cli.reporter.expects(:close_failures).never
71
+
72
+ @cli.run
73
+ end
74
+
75
+ def test_run_success
76
+ @cli.stubs(:issues?).returns(true)
77
+ @cli.stubs(:process).returns(0)
78
+
79
+ @cli.reporter.expects(:record_failure).never
80
+ @cli.reporter.expects(:close_failures)
81
+
82
+ @cli.run
83
+ end
84
+
85
+ def test_run_failure_no_issues
86
+ @cli.stubs(:issues?).returns(false)
87
+ @cli.stubs(:process).returns(1)
88
+
89
+ @cli.reporter.expects(:record_failure).never
90
+ @cli.reporter.expects(:close_failures).never
91
+
92
+ @cli.run
93
+ end
94
+
95
+ def test_run_success_no_issues
96
+ @cli.stubs(:issues?).returns(false)
97
+ @cli.stubs(:process).returns(0)
98
+
99
+ @cli.reporter.expects(:record_failure).never
100
+ @cli.reporter.expects(:close_failures).never
101
+
102
+ @cli.run
14
103
  end
15
104
  end
@@ -4,6 +4,7 @@ require "boxen/config"
4
4
  class BoxenConfigTest < Boxen::Test
5
5
  def setup
6
6
  @config = Boxen::Config.new
7
+ @config.repodir = "test/fixtures/repo"
7
8
  end
8
9
 
9
10
  def test_debug?
@@ -28,8 +29,12 @@ class BoxenConfigTest < Boxen::Test
28
29
  end
29
30
 
30
31
  def test_fde_env_var
31
- ENV.expects(:[]).with("BOXEN_NO_FDE").returns "1"
32
+ val = ENV['BOXEN_NO_FDE']
33
+
34
+ ENV['BOXEN_NO_FDE'] = '1'
32
35
  refute @config.fde?
36
+
37
+ ENV['BOXEN_NO_FDE'] = val
33
38
  end
34
39
 
35
40
  def test_homedir
@@ -40,8 +45,12 @@ class BoxenConfigTest < Boxen::Test
40
45
  end
41
46
 
42
47
  def test_homedir_env_var_boxen_home
43
- ENV.expects(:[]).with("BOXEN_HOME").returns "foo"
48
+ val = ENV['BOXEN_NO_FDE']
49
+
50
+ ENV['BOXEN_HOME'] = 'foo'
44
51
  assert_equal "foo", @config.homedir
52
+
53
+ ENV['BOXEN_HOME'] = val
45
54
  end
46
55
 
47
56
  def test_initialize
@@ -60,8 +69,12 @@ def test_initialize
60
69
  end
61
70
 
62
71
  def test_logfile_env_var
63
- ENV.expects(:[]).with("BOXEN_LOG_FILE").returns "foo"
72
+ val = ENV['BOXEN_LOG_FILE']
73
+
74
+ ENV['BOXEN_LOG_FILE'] = 'foo'
64
75
  assert_equal "foo", @config.logfile
76
+
77
+ ENV['BOXEN_LOG_FILE'] = val
65
78
  end
66
79
 
67
80
  def test_login
@@ -100,8 +113,6 @@ def test_initialize
100
113
  end
101
114
 
102
115
  def test_projects
103
- @config.repodir = "test/fixtures/repo"
104
-
105
116
  files = Dir["#{@config.repodir}/modules/projects/manifests/*.pp"]
106
117
  assert_equal files.size, @config.projects.size
107
118
  end
@@ -111,11 +122,16 @@ def test_initialize
111
122
  end
112
123
 
113
124
  def test_puppetdir_env_var
114
- ENV.expects(:[]).with("BOXEN_PUPPET_DIR").returns "foo"
125
+ val = ENV['BOXEN_PUPPET_DIR']
126
+
127
+ ENV['BOXEN_PUPPET_DIR'] = 'foo'
115
128
  assert_equal "foo", @config.puppetdir
129
+
130
+ ENV['BOXEN_PUPPET_DIR'] = val
116
131
  end
117
132
 
118
133
  def test_repodir
134
+ @config.repodir = nil
119
135
  assert_equal Dir.pwd, @config.repodir
120
136
 
121
137
  @config.repodir = "foo"
@@ -123,8 +139,58 @@ def test_initialize
123
139
  end
124
140
 
125
141
  def test_repodir_env_var
126
- ENV.expects(:[]).with("BOXEN_REPO_DIR").returns "foo"
142
+ @config.repodir = nil
143
+
144
+ val = ENV['BOXEN_REPO_DIR']
145
+
146
+ ENV['BOXEN_REPO_DIR'] = 'foo'
127
147
  assert_equal "foo", @config.repodir
148
+
149
+ ENV['BOXEN_REPO_DIR'] = val
150
+ end
151
+
152
+ def test_reponame
153
+ @config.reponame = "something/explicit"
154
+ assert_equal "something/explicit", @config.reponame
155
+ end
156
+
157
+ def test_reponame_env_var
158
+ val = ENV['BOXEN_REPO_NAME']
159
+
160
+ ENV['BOXEN_REPO_NAME'] = 'env/var'
161
+ assert_equal "env/var", @config.reponame
162
+
163
+ ENV['BOXEN_REPO_NAME'] = val
164
+ end
165
+
166
+ def test_reponame_git_config
167
+ @config.expects(:"`").with("git config remote.origin.url").
168
+ returns "https://github.com/some-org/our-boxen\n"
169
+
170
+ assert_equal "some-org/our-boxen", @config.reponame
171
+ end
172
+
173
+ def test_reponame_git_config_bad_exit
174
+ @config.expects(:"`").with("git config remote.origin.url").returns ""
175
+ $?.expects(:success?).returns false
176
+
177
+ assert_nil @config.reponame
178
+ end
179
+
180
+ def test_reponame_git_config_bad_url
181
+ @config.expects(:"`").with("git config remote.origin.url").
182
+ returns "https://spumco.com/some-org/our-boxen\n"
183
+ $?.expects(:success?).returns true
184
+
185
+ assert_nil @config.reponame
186
+ end
187
+
188
+ def test_reponame_git_config_git_extension
189
+ @config.expects(:"`").with("git config remote.origin.url").
190
+ returns "https://github.com/some-org/our-boxen.git\n"
191
+ $?.expects(:success?).returns true
192
+
193
+ assert_equal "some-org/our-boxen", @config.reponame
128
194
  end
129
195
 
130
196
  def test_srcdir
@@ -143,8 +209,12 @@ def test_initialize
143
209
  end
144
210
 
145
211
  def test_stealth_env_var
146
- ENV.expects(:[]).with("BOXEN_NO_ISSUE").returns "1"
212
+ val = ENV['BOXEN_NO_ISSUE']
213
+
214
+ ENV['BOXEN_NO_ISSUE'] = '1'
147
215
  assert @config.stealth?
216
+
217
+ ENV['BOXEN_NO_ISSUE'] = val
148
218
  end
149
219
 
150
220
  def test_token
@@ -155,10 +225,21 @@ def test_initialize
155
225
  end
156
226
 
157
227
  def test_user
158
- ENV.expects(:[]).with("USER").returns "foo"
228
+ ENV['USER'] = 'foo'
159
229
  assert_equal "foo", @config.user
160
230
 
161
231
  @config.user = "bar"
162
232
  assert_equal "bar", @config.user
163
233
  end
234
+
235
+ def test_api
236
+ @config.login = login = 'someuser'
237
+ @config.password = pass = 's3kr!7'
238
+
239
+ api = Object.new
240
+ Octokit::Client.expects(:new).with(:login => login, :password => pass).once.returns(api)
241
+
242
+ assert_equal api, @config.api
243
+ assert_equal api, @config.api # This extra call plus the `once` on the expectation is for the ivar cache.
244
+ end
164
245
  end
@@ -0,0 +1,183 @@
1
+ require "boxen/test"
2
+ require "boxen/reporter"
3
+
4
+ class Boxen::Config
5
+ attr_writer :api
6
+ end
7
+
8
+ class BoxenReporterTest < Boxen::Test
9
+ def setup
10
+ @config = Boxen::Config.new
11
+ @checkout = Boxen::Checkout.new(@config)
12
+ @puppet = mock 'puppeteer'
13
+ @reporter = Boxen::Reporter.new @config, @checkout, @puppet
14
+ end
15
+
16
+ def test_compare_url
17
+ @config.reponame = repo = 'org/repo'
18
+ sha = 'deadbeef'
19
+ @checkout.expects(:sha).returns(sha)
20
+
21
+ expected = "https://github.com/#{repo}/compare/#{sha}...master"
22
+ assert_equal expected, @reporter.compare_url
23
+ end
24
+
25
+ def test_hostname
26
+ @reporter.expects(:"`").with("hostname").returns "whatevs.local\n"
27
+ assert_equal "whatevs.local", @reporter.hostname
28
+ end
29
+
30
+ 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
35
+ end
36
+
37
+ def test_os
38
+ @reporter.expects(:"`").with("sw_vers -productVersion").returns "11.1.1\n"
39
+ assert_equal "11.1.1", @reporter.os
40
+ end
41
+
42
+ def test_shell
43
+ val = ENV['SHELL']
44
+
45
+ ENV['SHELL'] = '/bin/crush'
46
+ assert_equal "/bin/crush", @reporter.shell
47
+
48
+ ENV['SHELL'] = val
49
+ end
50
+
51
+ def test_record_failure
52
+ details = 'Everything went wrong.'
53
+ @reporter.stubs(:failure_details).returns(details)
54
+
55
+ @config.reponame = repo = 'some/repo'
56
+ @config.user = user = 'hapless'
57
+
58
+ @reporter.failure_label = label = 'boom'
59
+
60
+ @config.api = api = mock('api')
61
+ api.expects(:create_issue).with(repo, "Failed for #{user}", details, :labels => [label])
62
+
63
+ @reporter.record_failure
64
+ end
65
+
66
+ def test_failure_label
67
+ default = 'failure'
68
+ assert_equal default, @reporter.failure_label
69
+
70
+ @reporter.failure_label = label = 'oops'
71
+ assert_equal label, @reporter.failure_label
72
+
73
+ @reporter.failure_label = nil
74
+ assert_equal default, @reporter.failure_label
75
+ end
76
+
77
+ def test_ongoing_label
78
+ default = 'ongoing'
79
+ assert_equal default, @reporter.ongoing_label
80
+
81
+ @reporter.ongoing_label = label = 'checkit'
82
+ assert_equal label, @reporter.ongoing_label
83
+
84
+ @reporter.ongoing_label = nil
85
+ assert_equal default, @reporter.ongoing_label
86
+ end
87
+
88
+ def test_failure_details
89
+ sha = 'decafbad'
90
+ @checkout.stubs(:sha).returns(sha)
91
+ hostname = 'cools.local'
92
+ @reporter.stubs(:hostname).returns(hostname)
93
+ shell = '/bin/ksh'
94
+ @reporter.stubs(:shell).returns(shell)
95
+ os = '11.1.1'
96
+ @reporter.stubs(:os).returns(os)
97
+ log = "so\nmany\nthings\nto\nreport"
98
+ @reporter.stubs(:log).returns(log)
99
+
100
+ @config.reponame = repo = 'some/repo'
101
+ compare = @reporter.compare_url
102
+ changes = 'so many changes'
103
+ @checkout.stubs(:changes).returns(changes)
104
+
105
+ commands = %w[/path/to/puppet apply stuff_and_things]
106
+ @puppet.stubs(:command).returns(commands)
107
+ command = commands.join(' ')
108
+
109
+ @config.logfile = logfile = '/path/to/logfile.txt'
110
+
111
+ details = @reporter.failure_details
112
+
113
+ assert_match sha, details
114
+ assert_match hostname, details
115
+ assert_match shell, details
116
+ assert_match os, details
117
+ assert_match compare, details
118
+ assert_match changes, details
119
+ assert_match command, details
120
+ assert_match logfile, details
121
+ assert_match log, details
122
+ end
123
+
124
+ def test_log
125
+ @config.logfile = logfile = '/path/to/logfile.txt'
126
+
127
+ log = 'a bunch of log data'
128
+ File.expects(:read).with(logfile).returns(log)
129
+
130
+ assert_equal log, @reporter.log
131
+ end
132
+
133
+
134
+ Issue = Struct.new(:number, :labels) do
135
+ def labels
136
+ self[:labels] || []
137
+ end
138
+ end
139
+ Label = Struct.new(:name)
140
+
141
+ def test_close_failures
142
+ @config.reponame = repo = 'some/repo'
143
+
144
+ issues = Array.new(3) { |i| Issue.new(i*2 + 2) }
145
+ @reporter.stubs(:failures).returns(issues)
146
+
147
+ sha = 'decafbad'
148
+ @checkout.stubs(:sha).returns(sha)
149
+
150
+ @config.api = api = mock('api')
151
+ issues.each do |issue|
152
+ api.expects(:add_comment).with(repo, issue.number, "Succeeded at version #{sha}.")
153
+ api.expects(:close_issue).with(repo, issue.number)
154
+ end
155
+
156
+ @reporter.close_failures
157
+ end
158
+
159
+ def test_failures
160
+ @config.reponame = repo = 'some/repo'
161
+ @config.login = user = 'hapless'
162
+
163
+ @reporter.failure_label = fail_label = 'ouch'
164
+ @reporter.ongoing_label = goon_label = 'goon'
165
+
166
+ fail_l = Label.new(fail_label)
167
+ goon_l = Label.new(goon_label)
168
+ pop_l = Label.new('popcorn')
169
+
170
+ issues = [
171
+ Issue.new(0, [fail_l]),
172
+ Issue.new(1, [fail_l, pop_l]),
173
+ Issue.new(2, [fail_l, goon_l]),
174
+ Issue.new(3, [fail_l, Label.new('bang')]),
175
+ Issue.new(4, [fail_l, goon_l, pop_l]),
176
+ ]
177
+
178
+ @config.api = api = mock('api')
179
+ api.expects(:list_issues).with(repo, :state => 'open', :labels => fail_label, :creator => user).returns(issues)
180
+
181
+ assert_equal issues.values_at(0,1,3), @reporter.failures
182
+ end
183
+ end
metadata CHANGED
@@ -1,159 +1,176 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: boxen
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 2
8
- - 4
9
- version: 0.2.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - John Barnette
13
9
  - Will Farrington
14
10
  autorequire:
15
11
  bindir: bin
16
12
  cert_chain: []
17
-
18
- date: 2012-10-04 00:00:00 -07:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2012-10-05 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: ansi
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- requirements:
26
- - - ~>
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 1
30
- - 4
31
- version: "1.4"
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '1.4'
32
23
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: hiera
36
24
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ~>
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 1
43
- - 0
44
- - 0
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '1.4'
31
+ - !ruby/object:Gem::Dependency
32
+ name: hiera
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
45
38
  version: 1.0.0
46
39
  type: :runtime
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: highline
50
40
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ~>
54
- - !ruby/object:Gem::Version
55
- segments:
56
- - 1
57
- - 6
58
- version: "1.6"
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.0.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: highline
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
59
55
  type: :runtime
60
- version_requirements: *id003
61
- - !ruby/object:Gem::Dependency
62
- name: json_pure
63
56
  prerelease: false
64
- requirement: &id004 !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ~>
67
- - !ruby/object:Gem::Version
68
- segments:
69
- - 1
70
- - 7
71
- version: "1.7"
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '1.6'
63
+ - !ruby/object:Gem::Dependency
64
+ name: json_pure
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: '1.7'
72
71
  type: :runtime
73
- version_requirements: *id004
74
- - !ruby/object:Gem::Dependency
75
- name: librarian-puppet
76
72
  prerelease: false
77
- requirement: &id005 !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ~>
80
- - !ruby/object:Gem::Version
81
- segments:
82
- - 0
83
- - 9
84
- version: "0.9"
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: '1.7'
79
+ - !ruby/object:Gem::Dependency
80
+ name: librarian-puppet
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: '0.9'
85
87
  type: :runtime
86
- version_requirements: *id005
87
- - !ruby/object:Gem::Dependency
88
- name: octokit
89
88
  prerelease: false
90
- requirement: &id006 !ruby/object:Gem::Requirement
91
- requirements:
92
- - - ~>
93
- - !ruby/object:Gem::Version
94
- segments:
95
- - 1
96
- - 15
97
- version: "1.15"
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: '0.9'
95
+ - !ruby/object:Gem::Dependency
96
+ name: octokit
97
+ requirement: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ~>
101
+ - !ruby/object:Gem::Version
102
+ version: '1.15'
98
103
  type: :runtime
99
- version_requirements: *id006
100
- - !ruby/object:Gem::Dependency
101
- name: puppet
102
104
  prerelease: false
103
- requirement: &id007 !ruby/object:Gem::Requirement
104
- requirements:
105
- - - ~>
106
- - !ruby/object:Gem::Version
107
- segments:
108
- - 3
109
- - 0
110
- version: "3.0"
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.15'
111
+ - !ruby/object:Gem::Dependency
112
+ name: puppet
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ version: '3.0'
111
119
  type: :runtime
112
- version_requirements: *id007
113
- - !ruby/object:Gem::Dependency
114
- name: minitest
115
120
  prerelease: false
116
- requirement: &id008 !ruby/object:Gem::Requirement
117
- requirements:
118
- - - "="
119
- - !ruby/object:Gem::Version
120
- segments:
121
- - 3
122
- - 5
123
- - 0
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ~>
125
+ - !ruby/object:Gem::Version
126
+ version: '3.0'
127
+ - !ruby/object:Gem::Dependency
128
+ name: minitest
129
+ requirement: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - '='
133
+ - !ruby/object:Gem::Version
124
134
  version: 3.5.0
125
135
  type: :development
126
- version_requirements: *id008
127
- - !ruby/object:Gem::Dependency
128
- name: mocha
129
136
  prerelease: false
130
- requirement: &id009 !ruby/object:Gem::Requirement
131
- requirements:
132
- - - ~>
133
- - !ruby/object:Gem::Version
134
- segments:
135
- - 0
136
- - 12
137
- version: "0.12"
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - '='
141
+ - !ruby/object:Gem::Version
142
+ version: 3.5.0
143
+ - !ruby/object:Gem::Dependency
144
+ name: mocha
145
+ requirement: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ~>
149
+ - !ruby/object:Gem::Version
150
+ version: '0.12'
138
151
  type: :development
139
- version_requirements: *id009
152
+ prerelease: false
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ~>
157
+ - !ruby/object:Gem::Version
158
+ version: '0.12'
140
159
  description: Manage Mac development boxes with love (and Puppet).
141
- email:
160
+ email:
142
161
  - jbarnette@github.com
143
162
  - wfarr@github.com
144
163
  executables: []
145
-
146
164
  extensions: []
147
-
148
165
  extra_rdoc_files: []
149
-
150
- files:
166
+ files:
151
167
  - .gitignore
152
168
  - Gemfile
153
169
  - LICENSE
154
170
  - README.md
155
171
  - boxen.gemspec
156
172
  - lib/boxen/check.rb
173
+ - lib/boxen/checkout.rb
157
174
  - lib/boxen/cli.rb
158
175
  - lib/boxen/config.rb
159
176
  - lib/boxen/error.rb
@@ -171,14 +188,17 @@ files:
171
188
  - lib/boxen/preflight/rvm.rb
172
189
  - lib/boxen/project.rb
173
190
  - lib/boxen/puppeteer.rb
191
+ - lib/boxen/reporter.rb
174
192
  - lib/boxen/util.rb
175
193
  - lib/facter/boxen.rb
194
+ - lib/system_timer.rb
176
195
  - script/bootstrap
177
196
  - script/release
178
197
  - script/sync-puppet
179
198
  - script/tests
180
199
  - test/boxen/test.rb
181
200
  - test/boxen_check_test.rb
201
+ - test/boxen_checkout_test.rb
182
202
  - test/boxen_cli_test.rb
183
203
  - test/boxen_config_test.rb
184
204
  - test/boxen_flags_test.rb
@@ -189,43 +209,39 @@ files:
189
209
  - test/boxen_preflight_rvm_test.rb
190
210
  - test/boxen_project_test.rb
191
211
  - test/boxen_puppeteer_test.rb
212
+ - test/boxen_reporter_test.rb
192
213
  - test/boxen_util_test.rb
193
214
  - test/fixtures/repo/modules/projects/manifests/first-project.pp
194
215
  - test/fixtures/repo/modules/projects/manifests/second-project.pp
195
216
  - test/system_timer.rb
196
- has_rdoc: true
197
217
  homepage: https://github.com/boxen/boxen
198
218
  licenses: []
199
-
200
219
  post_install_message:
201
220
  rdoc_options: []
202
-
203
- require_paths:
221
+ require_paths:
204
222
  - lib
205
- required_ruby_version: !ruby/object:Gem::Requirement
206
- requirements:
207
- - - ">="
208
- - !ruby/object:Gem::Version
209
- segments:
210
- - 0
211
- version: "0"
212
- required_rubygems_version: !ruby/object:Gem::Requirement
213
- requirements:
214
- - - ">="
215
- - !ruby/object:Gem::Version
216
- segments:
217
- - 0
218
- version: "0"
223
+ required_ruby_version: !ruby/object:Gem::Requirement
224
+ none: false
225
+ requirements:
226
+ - - ! '>='
227
+ - !ruby/object:Gem::Version
228
+ version: '0'
229
+ required_rubygems_version: !ruby/object:Gem::Requirement
230
+ none: false
231
+ requirements:
232
+ - - ! '>='
233
+ - !ruby/object:Gem::Version
234
+ version: '0'
219
235
  requirements: []
220
-
221
236
  rubyforge_project:
222
- rubygems_version: 1.3.6
237
+ rubygems_version: 1.8.23
223
238
  signing_key:
224
239
  specification_version: 3
225
240
  summary: You know, for laptops and stuff.
226
- test_files:
241
+ test_files:
227
242
  - test/boxen/test.rb
228
243
  - test/boxen_check_test.rb
244
+ - test/boxen_checkout_test.rb
229
245
  - test/boxen_cli_test.rb
230
246
  - test/boxen_config_test.rb
231
247
  - test/boxen_flags_test.rb
@@ -236,6 +252,7 @@ test_files:
236
252
  - test/boxen_preflight_rvm_test.rb
237
253
  - test/boxen_project_test.rb
238
254
  - test/boxen_puppeteer_test.rb
255
+ - test/boxen_reporter_test.rb
239
256
  - test/boxen_util_test.rb
240
257
  - test/fixtures/repo/modules/projects/manifests/first-project.pp
241
258
  - test/fixtures/repo/modules/projects/manifests/second-project.pp