zaphod 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9716d2d2bc5d2523195132e42ef2cfe697956449
4
- data.tar.gz: 02e7e816192a3437b1a2c6b946ed6a97780bf018
3
+ metadata.gz: eb48ef706b22fe9a2b035380caf5f5e075a6044b
4
+ data.tar.gz: 53636ac34dabeba5d5e9216ce93158c824f7a566
5
5
  SHA512:
6
- metadata.gz: c96b73e834d184a91993a6f95f7a74bb101d7bc2763f1f4a99bcbbf1bf670fbcc8f34172b6fc06ff31365f2223fc6f3f62b750778ee7b91650921d7da95cb15d
7
- data.tar.gz: 7a4d12e3294f2e00b87ab66545f7e6ca9ffbd6ff2d29c10099c2bb5d460f27e28f2a71b2e973f8dd40ad4bafb281f09dd03ee34949705dd92d5fb844e4b07032
6
+ metadata.gz: 4648fbe942eb86ca77f630f6a9c31fd170a075a03105a0d134d407e629c009e905f0e120ef71de259d7f45f09ac5399bd2a521dd10ca5f644f10ffbf025df283
7
+ data.tar.gz: 27cb0eb96188fc4af4e0fa78e0fb44bb21d88d5850d73bc87ca584a8bf7b6848f8240579174fa462b79c4b6f8b76f181c1ad83ffe52c4c57f25051f311e2d289
data/.gitignore CHANGED
@@ -11,3 +11,4 @@ rdoc
11
11
  spec/reports
12
12
  .bundle
13
13
  .ruby-version
14
+ log/*
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zaphod (1.0.1)
5
- grit (~> 2.5)
4
+ zaphod (1.1.0)
5
+ git (~> 1.2.6)
6
6
  simplecov (~> 0.8)
7
7
 
8
8
  GEM
@@ -15,11 +15,8 @@ GEM
15
15
  docile (1.1.2)
16
16
  ffi (1.9.3)
17
17
  formatador (0.2.4)
18
- grit (2.5.0)
19
- diff-lcs (~> 1.1)
20
- mime-types (~> 1.15)
21
- posix-spawn (~> 0.3.6)
22
- guard (2.3.0)
18
+ git (1.2.6)
19
+ guard (2.4.0)
23
20
  formatador (>= 0.2.4)
24
21
  listen (~> 2.1)
25
22
  lumberjack (~> 1.0)
@@ -33,16 +30,14 @@ GEM
33
30
  rspec (>= 2.14, < 4.0)
34
31
  guard-shell (0.6.1)
35
32
  guard (>= 1.1.0)
36
- listen (2.4.0)
33
+ listen (2.4.1)
37
34
  celluloid (>= 0.15.2)
38
35
  rb-fsevent (>= 0.9.3)
39
36
  rb-inotify (>= 0.9)
40
37
  lumberjack (1.0.4)
41
38
  method_source (0.8.2)
42
- mime-types (1.25.1)
43
39
  multi_json (1.8.4)
44
- posix-spawn (0.3.8)
45
- pry (0.9.12.4)
40
+ pry (0.9.12.6)
46
41
  coderay (~> 1.0)
47
42
  method_source (~> 0.8)
48
43
  slop (~> 3.4)
@@ -73,7 +68,7 @@ PLATFORMS
73
68
  ruby
74
69
 
75
70
  DEPENDENCIES
76
- guard (~> 2.3)
71
+ guard (~> 2.4)
77
72
  guard-bundler
78
73
  guard-rspec (~> 4.2)
79
74
  guard-shell
data/README.org CHANGED
@@ -6,6 +6,11 @@
6
6
 
7
7
  Catch, and publicly embarrass, untested commits into git.
8
8
 
9
+ Zaphod is a formatter for SimpleCov that compares the current git changes
10
+ with the uncovered source reported by SimpleCov. If any source code appears
11
+ both in the uncovered code and git changes, Zaphod will call an #on_failure
12
+ hook. By default, this exits and fails the build.
13
+
9
14
  ** Installation
10
15
 
11
16
  *** Simple Installation
@@ -15,6 +20,11 @@ Catch, and publicly embarrass, untested commits into git.
15
20
  Zaphod.setup
16
21
  #+END_SRC
17
22
 
23
+ This will set up the Zaphod formatter and start SimpleCov.
24
+
25
+ Be certain that SimpleCov is started before any of your project's source is loaded.
26
+
27
+
18
28
  *** Setup your own SimpleCov Formatters
19
29
 
20
30
  #+BEGIN_SRC ruby
@@ -34,12 +44,14 @@ Catch, and publicly embarrass, untested commits into git.
34
44
  require "pony"
35
45
 
36
46
  Zaphod.setup do |configuration|
37
- configuration.on_failure do
47
+ # Action to take if uncovered changes are found:
48
+ configuration.on_failure do |uncovered_changes|
38
49
  Pony.mail(
39
50
  to: 'your-team@example.com',
40
- subject: "Someone is trying to commit untested code!"
51
+ subject: "Someone is trying to commit untested code!",
52
+ body: uncovered_changes.to_s
41
53
  )
42
- raise SystemExit.new( -1 )
54
+ exit -1 # Abort the build with a failing exit code
43
55
  end
44
56
  end
45
57
  #+END_SRC
@@ -51,9 +63,16 @@ Catch, and publicly embarrass, untested commits into git.
51
63
  ]
52
64
 
53
65
  Zaphod.configure do |configuration|
54
- configuration.on_failure do
66
+ configuration.on_failure do |uncovered_changes|
55
67
  $stderr.puts "What would your mother think?"
68
+ exit -1
56
69
  end
57
70
  end
58
71
  SimpleCov.start
59
72
  #+END_SRC
73
+
74
+ ** Dependencies
75
+
76
+ - Grit
77
+ - SimpleCov
78
+
@@ -25,11 +25,13 @@ module SimpleCov
25
25
  if $DEBUG || ENV["DEBUG"]
26
26
  require "pp"
27
27
  pp(
28
- "--- UNCOVERED ---", uncovered_codeset,
29
- "--- CHANGED ---", changed_codeset,
30
- "--- DIFF ---", diff
28
+ "--- UNCOVERED ---", uncovered_codeset,
29
+ "--- CHANGED ---", changed_codeset,
30
+ "--- INTERSECTION ---"
31
31
  )
32
+ puts diff.to_s, "FAIL?: #{! diff.empty?}"
32
33
  end
34
+
33
35
  unless diff.empty?
34
36
  Zaphod.configuration.on_failure.call diff
35
37
  end
@@ -4,11 +4,11 @@ require "set"
4
4
  module Zaphod
5
5
  class ChangeSet
6
6
  extend Forwardable
7
- attr_reader :changes
7
+ attr_reader :changes, :user
8
8
  def_delegators :@changes, :empty?, :each, :map, :first, :length, :include?, :add, :any?
9
9
 
10
- def initialize( changes=[] )
11
- @changes = Set.new changes
10
+ def initialize( changes=[], user="unknown" )
11
+ @changes, @user = Set.new( changes ), user
12
12
  end
13
13
 
14
14
  def intersection( other )
@@ -20,5 +20,9 @@ module Zaphod
20
20
  def ==( other )
21
21
  changes == other.changes
22
22
  end
23
+
24
+ def to_s()
25
+ ["## #{user}", changes.map( &:to_s )].join "\n"
26
+ end
23
27
  end
24
28
  end
@@ -21,5 +21,9 @@ module Zaphod
21
21
  source.map( &:inspect ).join( ",\n" ) +
22
22
  "])"
23
23
  end
24
+
25
+ def to_s()
26
+ ["### #{path}", source.join].join "\n"
27
+ end
24
28
  end
25
29
  end
@@ -1,4 +1,5 @@
1
- require 'grit'
1
+ require "git"
2
+ require "logger"
2
3
 
3
4
  module Zaphod
4
5
  class Git
@@ -6,7 +7,7 @@ module Zaphod
6
7
  attr_accessor :diff_against
7
8
 
8
9
  def self.from_path( path )
9
- new Grit::Repo.new( path )
10
+ new ::Git.open( path, log: Logger.new( "log/zaphod-git.log" ) )
10
11
  end
11
12
 
12
13
  def initialize( repository, diff_against="HEAD" )
@@ -15,22 +16,33 @@ module Zaphod
15
16
  end
16
17
 
17
18
  def diff()
18
- diffs = repo.git.diff_index( { p: true }, diff_against ).
19
- split( /^diff --git .* b(.*)$/ )
20
-
19
+ path = repo.dir.path
20
+ diffs = repo.diff( diff_against, path )
21
21
  as_hash diffs
22
22
  end
23
23
 
24
+ def user()
25
+ config = repo.config
26
+ [config["user.name"], config["user.email"]].join " "
27
+ end
28
+
24
29
  protected
25
30
 
26
- def as_hash( diff )
27
- diffs = diff.drop_while( &:empty? )
28
- relativize_paths Hash[*diffs]
31
+ def as_hash( diffs )
32
+ pairs = diffs.flat_map { |diff_file|
33
+ [diff_file.path, additions( diff_file.patch )]
34
+ }
35
+ relativize_paths Hash[*pairs]
36
+ end
37
+
38
+ def additions( patch )
39
+ patch.lines.select { |l| l =~ /^[+][^+]/ }.
40
+ map { |l| l.gsub( /^[+]/, "" ) }
29
41
  end
30
42
 
31
43
  def relativize_paths( patch_map )
32
- patch_map.dup.each_with_object( map = {} ) do |pair, h|
33
- h[".#{pair.first}"] = pair.last
44
+ patch_map.each_with_object( map = {} ) do |pair, h|
45
+ h["./#{pair.first}"] = pair.last
34
46
  end
35
47
  map
36
48
  end
@@ -13,19 +13,10 @@ module Zaphod
13
13
  end
14
14
 
15
15
  def changes()
16
- ChangeSet.new repo.diff.map { |path, diff|
17
- CodeChange.new File.expand_path( path ), additions_from( diff.lines )
16
+ cc = repo.diff.map { |path, diff|
17
+ CodeChange.new File.expand_path( path ), diff
18
18
  }
19
- end
20
-
21
- def additions_from( lines )
22
- lines.
23
- select { |l| addition? l }.
24
- map { |l| l.gsub( /^[+]/, "" ) }
25
- end
26
-
27
- def addition?( line )
28
- line =~ /^[+][^+]/
19
+ ChangeSet.new cc, repo.user
29
20
  end
30
21
  end
31
22
  end
@@ -3,5 +3,11 @@ module Zaphod
3
3
  def initialize()
4
4
  @var = "foo"
5
5
  end
6
+
7
+
8
+ def untested_change!()
9
+ puts "untested!"
10
+ end
11
+
6
12
  end
7
13
  end
@@ -1,3 +1,3 @@
1
1
  module Zaphod
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -33,9 +33,14 @@ describe SimpleCov::Formatter::ZaphodFormatter do
33
33
  end
34
34
 
35
35
  before :each do
36
+ @original_failure = Zaphod.configuration.on_failure
36
37
  stub( source_control ).changes { source_changes }
37
38
  end
38
39
 
40
+ after :each do
41
+ Zaphod.configuration.on_failure &@original_failure
42
+ end
43
+
39
44
  it "runs the configured on_failure action, passing uncovered changes" do
40
45
  failed = false
41
46
  Zaphod.configure do |config|
@@ -1,7 +1,11 @@
1
1
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
2
-
3
2
  require 'zaphod'
4
- Zaphod.setup
3
+ Zaphod.setup do |config|
4
+ config.on_failure do
5
+ puts "Untested CHANGES!"
6
+ exit -1
7
+ end
8
+ end
5
9
 
6
10
  RSpec.configure do |config|
7
11
  config.treat_symbols_as_metadata_keys_with_true_values = true
@@ -20,6 +20,10 @@ module Zaphod
20
20
  it "rejects duplicates" do
21
21
  expect( described_class.new( changes ) ).to have( 1 ).item
22
22
  end
23
+
24
+ it "accepts a user string" do
25
+ described_class.new changes, "bob foo"
26
+ end
23
27
  end
24
28
 
25
29
  describe "iteration" do
@@ -84,5 +88,18 @@ module Zaphod
84
88
  end
85
89
  end
86
90
  end
91
+
92
+ describe "#to_s" do
93
+ subject( :set ) do
94
+ described_class.new([
95
+ CodeChange.new( "/dev/null", ["baz"] ),
96
+ CodeChange.new( "./lib/zaphod/spike.rb", ["foo"] )
97
+ ])
98
+ end
99
+
100
+ it do
101
+ expect( set.to_s ).to eq( ["## unknown", set.changes.map( &:to_s )].join( "\n" ) )
102
+ end
103
+ end
87
104
  end
88
105
  end
@@ -98,5 +98,26 @@ module Zaphod
98
98
  end
99
99
  end
100
100
 
101
+ describe "#to_s" do
102
+ subject( :change ) do
103
+ CodeChange.new(
104
+ "/app/controllers/tags_controller.rb", [
105
+ "\n",
106
+ " def uncovered_method\n",
107
+ " puts \"ha HA! I'm a cheater!\"\n",
108
+ " end\n"
109
+ ])
110
+ end
111
+
112
+ it do
113
+ expect( change.to_s ).to eq( <<EOS )
114
+ ### /app/controllers/tags_controller.rb
115
+
116
+ def uncovered_method
117
+ puts "ha HA! I'm a cheater!"
118
+ end
119
+ EOS
120
+ end
121
+ end
101
122
  end
102
123
  end
@@ -2,15 +2,21 @@ require 'spec_helper'
2
2
  require 'zaphod/git'
3
3
 
4
4
  describe Zaphod::Git do
5
- let( :git ) { stub!.diff_index { DIFF }.subject }
6
- let( :grit ) { stub!.git { git }.subject }
5
+ let( :path ) { "." }
6
+ let( :repo ) do
7
+ gitrb = Object.new
8
+ stub( gitrb ) do |allow|
9
+ allow.dir.stub!.path { path }
10
+ allow.diff( "HEAD", path ) { DIFF }
11
+ end
12
+ gitrb
13
+ end
7
14
 
8
- subject { described_class.new grit }
15
+ subject { described_class.new repo }
9
16
 
10
17
  describe "to get current changes in the git repository" do
11
- it "calls :diff_index on the Grit git object" do
12
- mock( git ).diff_index({ p: true }, "HEAD") { DIFF }
13
-
18
+ it "calls #diff on the Git repository object" do
19
+ mock( repo ).diff( "HEAD", "." ) { DIFF }
14
20
  subject.diff
15
21
  end
16
22
 
@@ -20,9 +26,41 @@ describe Zaphod::Git do
20
26
  "./spec/zaphod/source_control_spec.rb"
21
27
  )
22
28
  end
29
+
30
+ it "includes only the additions from the patch" do
31
+ additions = DIFF.first.patch.lines.select { |l| l =~ /^[+][^+]/ }
32
+ expect( subject.diff["./spec/spec_helper.rb"].size ).
33
+ to eq( additions.size )
34
+ end
35
+
36
+ it "strips the '+'" do
37
+ subject.diff.each do |path, additions|
38
+ expect( additions.all? { |l| ! l.start_with?( "+" ) } ).to be_true
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#user" do
44
+ it "retrieves the user info from the git config" do
45
+ mock( repo ).config { Hash.new }
46
+ subject.user
47
+ end
48
+
49
+ it "returns the concatenation of the user name and email" do
50
+ stub( repo ).config do
51
+ {
52
+ "user.name" => "Bob Shlob",
53
+ "user.email" => "bob@mailinator.com"
54
+ }
55
+ end
56
+
57
+ expect( subject.user ).to eq( "Bob Shlob bob@mailinator.com" )
58
+ end
23
59
  end
24
60
 
25
- DIFF = <<-EOS
61
+ DiffFile = Struct.new :path, :patch
62
+ DIFF = [
63
+ DiffFile.new( "spec/spec_helper.rb", <<-EOS ),
26
64
  diff --git /dev/null b/spec/spec_helper.rb
27
65
  --- /dev/null
28
66
  +++ b/spec/spec_helper.rb
@@ -55,6 +93,8 @@ diff --git /dev/null b/spec/spec_helper.rb
55
93
  + # --seed 1234
56
94
  + config.order = 'random'
57
95
  +end
96
+ EOS
97
+ DiffFile.new( "spec/zaphod/source_control_spec.rb", <<-EOS ),
58
98
  diff --git a/spec/zaphod/source_control_spec.rbf b/spec/zaphod/source_control_spec.rb
59
99
  index 73d4e77..8ef378d 100644
60
100
  --- a/spec/zaphod/source_control_spec.rb
@@ -80,5 +120,6 @@ index 73d4e77..8ef378d 100644
80
120
  + let( :repository ) { stub git: git_native }
81
121
 
82
122
  let( :git ) { described_class.new repository }
83
- EOS
123
+ EOS
124
+ ]
84
125
  end
@@ -8,18 +8,25 @@ describe Zaphod::SourceControl do
8
8
 
9
9
  describe "#initialize" do
10
10
  it "accepts a repository" do
11
- described_class.new Grit::Repo.new REPO_PATH
11
+ described_class.new Git.open( REPO_PATH )
12
12
  end
13
13
  end
14
14
 
15
15
  describe "#changes" do
16
16
  let( :patch_map ) do
17
17
  {
18
- "./spec/spec_helper.rb" => "+ require 'rspec'\n",
19
- "./spec/zaphod/source_control_spec.rb" => "+ require 'spec_helper'\n"
18
+ "./spec/spec_helper.rb" => "require 'rspec'\n",
19
+ "./spec/zaphod/source_control_spec.rb" => "require 'spec_helper'\n"
20
20
  }
21
21
  end
22
- let( :repository ) { stub!.diff { patch_map }.subject }
22
+ let( :repository ) do
23
+ repo = Object.new
24
+ stub( repo ) do |allow|
25
+ allow.diff { patch_map }
26
+ allow.user { "bob smith smith@mailinator.com" }
27
+ end
28
+ repo
29
+ end
23
30
 
24
31
  subject { described_class.new repository }
25
32
 
@@ -38,12 +45,12 @@ describe Zaphod::SourceControl do
38
45
 
39
46
  it "passes the additions to each code set" do
40
47
  subject.changes.first.source.length.should eq(
41
- patch_map["./spec/spec_helper.rb"].lines.select { |l| l =~ /^[+][^+]/ }.to_a.size
48
+ patch_map["./spec/spec_helper.rb"].length
42
49
  )
43
50
  end
44
51
 
45
- it "strips the plusses off the lines" do
46
- subject.changes.first.source.first.should_not start_with( "+" )
52
+ it "provides the change set with the name of the alleged slacker" do
53
+ expect( subject.changes.user ).to eq( "bob smith smith@mailinator.com" )
47
54
  end
48
55
  end
49
56
  end
@@ -19,14 +19,14 @@ Gem::Specification.new do |spec|
19
19
  spec.extra_rdoc_files = %w[README.org]
20
20
  spec.rdoc_options = ["--charset=UTF-8"]
21
21
 
22
- spec.add_dependency "grit", "~> 2.5"
22
+ spec.add_dependency "git", "~> 1.2.6"
23
23
  spec.add_dependency "simplecov", "~> 0.8"
24
24
 
25
25
  spec.add_development_dependency "rake", "~> 10.1"
26
26
  spec.add_development_dependency "rr", "~> 1.1"
27
27
  spec.add_development_dependency "rspec", "~> 2.14"
28
28
  spec.add_development_dependency "pry"
29
- spec.add_development_dependency "guard", "~> 2.3"
29
+ spec.add_development_dependency "guard", "~> 2.4"
30
30
  spec.add_development_dependency "guard-rspec", "~> 4.2"
31
31
  spec.add_development_dependency "guard-bundler"
32
32
  spec.add_development_dependency "guard-shell"
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zaphod
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Toby Tripp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-05 00:00:00.000000000 Z
11
+ date: 2014-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: grit
14
+ name: git
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.5'
19
+ version: 1.2.6
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.5'
26
+ version: 1.2.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: simplecov
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '2.3'
103
+ version: '2.4'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.3'
110
+ version: '2.4'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: guard-rspec
113
113
  requirement: !ruby/object:Gem::Requirement