boxen 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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