MFOL-bugspots 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8954c0d8725adbc49e46c0b41f04baf63ee79c3b
4
+ data.tar.gz: d1ae42eff16eaf6999feb4197ce435b4ef8d66ec
5
+ SHA512:
6
+ metadata.gz: 7f8afae0ea150a481fd8d97d19983cda64d55a55b9b22f9ece1f6e7e7bee8a8efef7fdf3eb3adc72405e7943eedd848266357d8c0d8904acb727daf5a6f35e42
7
+ data.tar.gz: 369da80bdcf592809f7868fc7a2e054e3a23c11e764347a54f355df606aa5cac9aea30523093eb1fa1398b4a436622a28efad872bf5cb1244813ec443d81150c
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rbenv-version
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ #gem 'rugged', git: 'git://github.com/libgit2/rugged.git', branch: 'development', submodules: true
4
+
5
+ # Specify your gem's dependencies in bugspots.gemspec
6
+ gemspec
@@ -0,0 +1,89 @@
1
+ # Bugspots - Bug Prediction Heuristic
2
+
3
+ An implementation of the simple bug prediction heuristic outlined by the Google Engineering team: [Bug Prediction at Google](http://google-engtools.blogspot.com/2011/12/bug-prediction-at-google.html)
4
+
5
+ > Well, we actually have a great, authoritative record of where code has been requiring fixes: our bug tracker and our source control commit log! The research indicates that predicting bugs from the source history works very well, so we decided to deploy it at Google.
6
+
7
+ Point bugspots at any git repo and it will identify the hotspots for you.
8
+
9
+ ## Usage
10
+
11
+ ```bash
12
+ $> gem install bugspots
13
+ $> bugspots /path/to/repo
14
+ $> git bugspots (in root of current git project, --help for options)
15
+ ```
16
+
17
+ ## Results
18
+
19
+ ```bash
20
+ $> cd /your/git/repo
21
+ $> git bugspots -d 500
22
+
23
+ .. example output ..
24
+
25
+ Scanning /git/eventmachine repo
26
+ Found 31 bugfix commits, with 23 hotspots:
27
+
28
+ Fixes:
29
+ - Revert "Write maximum of 16KB of data to an SSL connection per tick (fixes #233)" for #273
30
+ - Do not close attached sockets (fixes #200)
31
+ - Write maximum of 16KB of data to an SSL connection per tick (fixes #233)
32
+ - Merge branch 'master' into close_schedule_fix
33
+ - Remove dependency on readbytes.rb for ruby 1.9 (fixes #167, #234)
34
+ - Fix compilation on MSVC2008 (fixes #253)
35
+ - EM::Deferrable#(callback|errback|timeout) now return self so you can chain them (closes #177)
36
+ - Make EventMachine::Connection#get_peername and #get_sockname valid for IPv6 (closes #132)
37
+ - reconnect DNS socket if closed
38
+ - Use String#bytesize in EM::Connection#send_datagram for 1.9 (closes #153)
39
+ - Fix an issue that would cause the EM process to block when the loopbreak pipe filled up (closes #158)
40
+ - namespace std is already included, so just call min(). fixes vc6 issue with min macro
41
+ - Use close() instead of closesocket() to prevent FD leaks on windows.
42
+ - Stop advertising non-available authentication mechanisms, allow multi-line authentication - fixes compatibility with javamail
43
+ - typo fixes and undef fstat for ruby on Windows
44
+ - Deprecate now aged info, as it's fixed
45
+ - Some fixes for Solaris and Nexenta (opensolaris kernel + linux userland)
46
+ - Some fixes for solaris
47
+ - Minor fixes for rbx compatibility
48
+ - Reduce the size of the RunEpollOnce stack frame by 800kb. This fixes the long-standing epoll+threads issue (#84)
49
+ - Fixed aggregated event handling for kqueue and notify, fixed path for ifconfig.
50
+ - More win32 fixes
51
+ - Added test for reactor_thread? and fixed up EM.schedule for pre-reactor schedules
52
+ - Merge branch 'master' of git@github.com:eventmachine/eventmachine
53
+ - Use read instead of recv in ConnectionDescriptor::Read (fixes EM.attach issues with pipes)
54
+ - Use false to indicated a cancelled timer instead of using an empty proc. Reduces mem usage in certain situations.
55
+ - Inotify fixes: file_delete only fires after fds have been closed, use syscall hackery for older linux distributions (*cough* debian)
56
+ - Clean up deferrable.rb: fixed rdoc, alias method wrappers, remove unnecessary forwardable
57
+ - More solaris build fixes.
58
+ - More solaris build issues fixed
59
+ - fixed a small bug with basic auth (cherry-pick conflict merge from mmmurf (closes #92))
60
+
61
+ Hotspots:
62
+ 0.9723 - ext/ed.cpp
63
+ 0.3311 - ext/ed.h
64
+ 0.3271 - ext/em.cpp
65
+ 0.3034 - lib/eventmachine.rb
66
+ 0.2433 - lib/em/protocols/postgres3.rb
67
+ 0.2403 - ext/project.h
68
+ 0.0431 - lib/em/deferrable.rb
69
+ 0.029 - ext/cmain.cpp
70
+ 0.0278 - ext/rubymain.cpp
71
+ 0.0277 - ext/eventmachine.h
72
+ 0.0241 - lib/em/resolver.rb
73
+ 0.0241 - tests/test_resolver.rb
74
+ 0.0225 - lib/em/connection.rb
75
+ 0.0013 - lib/em/protocols/smtpserver.rb
76
+ 0.0003 - ext/extconf.rb
77
+ 0.0002 - tests/test_basic.rb
78
+ 0.0001 - ext/em.h
79
+ 0.0001 - ext/cplusplus.cpp
80
+ 0.0001 - ext/fastfilereader/extconf.rb
81
+ 0.0 - lib/em/filewatcher.rb
82
+ 0.0 - tests/test_file_watch.rb
83
+ 0.0 - ext/fastfilereader/mapper.cpp
84
+ 0.0 - lib/protocols/httpclient.rb
85
+ ```
86
+
87
+ ### License
88
+
89
+ (MIT License) - Copyright (c) 2011 Ilya Grigorik
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'bugspots'
7
+ require 'optparse'
8
+ require 'rainbow'
9
+ require 'rainbow/ext/string'
10
+
11
+ ARGV << '--help' if ARGV.empty?
12
+
13
+ options = {}
14
+ OptionParser.new do |opts|
15
+ opts.banner = "Usage: bugspots /path/to/git/repo"
16
+
17
+ # Option: Set Branch
18
+ opts.on('-b', '--branch [name]', 'branch to crawl') do |b|
19
+ options[:branch] = b.to_s
20
+ end
21
+
22
+ # Option: Set Bugfix Indicator
23
+ opts.on('-f', '--file [file extension]', 'The type of file to scan') do |f|
24
+ options[:fileExt] = f.to_s
25
+ end
26
+
27
+ # Option: Set Depth
28
+ opts.on('-d', '--depth [depth]', 'depth of log crawl (integer)') do |d|
29
+ options[:depth] = d.to_i
30
+ end
31
+
32
+ # Option: Set Bugfix Indicator
33
+ opts.on('-w', '--words ["w1,w2"]', 'bugfix indicator word list, ie: "fixes,closed"') do |words|
34
+ options[:regex] = Regexp.new(words.split(',').join('|'))
35
+ end
36
+
37
+ # Option: Set Bugfix Indicator
38
+ opts.on('-r', '--regex [regex]', Regexp, 'bugfix indicator regex, ie: "fix(es|ed)?" or "/fixes #(\d+)/i"') do |regex|
39
+ options[:regex] = regex
40
+ end
41
+
42
+ # Option: Set Timestamp Display
43
+ opts.on('--display-timestamps', 'show timestamps of each identified fix commit') do |dt|
44
+ options[:display_timestamps] = true
45
+ end
46
+ end.parse!
47
+
48
+ # Set a reasonable default of depth
49
+ options[:depth] ||= 500
50
+
51
+ # Set master as the default branch
52
+ options[:branch] ||= "master"
53
+
54
+ # Set the default file extionsion to include to be php
55
+ options[:fileExt] ||= ".php"
56
+
57
+ puts "Scanning #{ARGV[0]} repo with #{options[:fileExt]} files".foreground(:green)
58
+
59
+ begin
60
+ fixes, spots = Bugspots.scan(ARGV[0], options[:branch], options[:fileExt], options[:depth], options[:regex])
61
+
62
+ puts "\tFound #{fixes.size} bugfix commits, with #{spots.size} hotspots:".foreground(:yellow)
63
+ puts
64
+
65
+ puts "\tFixes:".foreground(:green).underline
66
+ fixes.each do |fix|
67
+ message = "\t\t- "
68
+ message << "#{fix.date} " if options[:display_timestamps]
69
+ message << "#{fix.message}"
70
+ puts message.foreground(:yellow)
71
+ end
72
+
73
+ puts "\n"
74
+ puts "\tHotspots:".foreground(:green).underline
75
+ spots.each do |spot|
76
+ puts "\t\t#{spot.score}".foreground(:red) + " - #{spot.file}".foreground(:yellow)
77
+ end
78
+
79
+ rescue Rugged::RepositoryError
80
+ puts "Invalid Git repository - please run from or specify the full path to the root of the project.".foreground(:red)
81
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ if ARGV.empty? or not Dir.exists? ARGV[0]
4
+ ARGV.unshift Dir.pwd
5
+ end
6
+
7
+ exec 'bugspots', ARGV.join(' ')
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "bugspots/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.license = "MIT"
7
+ s.name = "MFOL-bugspots"
8
+ s.version = Bugspots::VERSION
9
+ s.authors = ["Xiaoming Cai"]
10
+ s.email = ["ming.cxm@gmail.com"]
11
+ s.homepage = "https://github.com/cxm0000/MFOL-bugspots"
12
+ s.summary = "Implementation of simple bug prediction hotspot heuristic"
13
+ s.description = s.summary
14
+
15
+ s.rubyforge_project = "MFOL-bugspots"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "rugged", ">= 0.21.0"
23
+ s.add_dependency "rainbow"
24
+ end
@@ -0,0 +1,2 @@
1
+ require "bugspots/version"
2
+ require "bugspots/scanner"
@@ -0,0 +1,63 @@
1
+ require "rugged"
2
+
3
+ module Bugspots
4
+ Fix = Struct.new(:message, :date, :files)
5
+ Spot = Struct.new(:file, :score)
6
+
7
+ # Filter all results before this threshold
8
+ ScoreThreshold = 0.01
9
+
10
+ def self.scan(repo, branch = "master", fileExt = ".php", depth = 500, regex = nil)
11
+
12
+ regex ||= /\b(fix(es|ed)?|close(s|d)?)\b/i
13
+ fixes = []
14
+
15
+ repo = Rugged::Repository.new(repo)
16
+ unless repo.branches.each_name(:local).sort.find { |b| b == branch }
17
+ raise ArgumentError, "no such branch in the repo: #{branch}"
18
+ end
19
+
20
+ walker = Rugged::Walker.new(repo)
21
+ walker.sorting(Rugged::SORT_TOPO | Rugged::SORT_REVERSE)
22
+ walker.push(repo.branches[branch].target)
23
+ walker.each do |commit|
24
+ if commit.message =~ regex
25
+ files = commit.diff(commit.parents.first).deltas.collect do |d|
26
+ d.old_file[:path]
27
+ end
28
+ fixes << Fix.new(commit.message.split("\n").first, commit.time, files)
29
+ end
30
+ end
31
+
32
+ hotspots = Hash.new(0)
33
+ fixes.each do |fix|
34
+ fix.files.each do |file|
35
+
36
+ if File.extname(file).eql? fileExt
37
+
38
+ # The timestamp used in the equation is normalized from 0 to 1, where
39
+ # 0 is the earliest point in the code base, and 1 is now (where now is
40
+ # when the algorithm was run). Note that the score changes over time
41
+ # with this algorithm due to the moving normalization; it's not meant
42
+ # to provide some objective score, only provide a means of comparison
43
+ # between one file and another at any one point in time
44
+ t = 1 - ((Time.now - fix.date).to_f / (Time.now - fixes.first.date))
45
+ hotspots[file] += 1/(1+Math.exp((-12*t)+12))
46
+ end
47
+ end
48
+ end
49
+
50
+ # filter out the files with very low scores
51
+ hotspots.each do |file, score|
52
+ if score <= ScoreThreshold
53
+ hotspots.delete(file)
54
+ end
55
+ end
56
+
57
+ spots = hotspots.sort_by {|k,v| v}.reverse.collect do |spot|
58
+ Spot.new(spot.first, sprintf('%.4f', spot.last))
59
+ end
60
+
61
+ return fixes, spots
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Bugspots
2
+ VERSION = "0.2.1"
3
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: MFOL-bugspots
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Xiaoming Cai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rugged
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.21.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.21.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rainbow
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Implementation of simple bug prediction hotspot heuristic
42
+ email:
43
+ - ming.cxm@gmail.com
44
+ executables:
45
+ - bugspots
46
+ - git-bugspots
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - .gitignore
51
+ - Gemfile
52
+ - README.md
53
+ - Rakefile
54
+ - bin/bugspots
55
+ - bin/git-bugspots
56
+ - bugspots.gemspec
57
+ - lib/bugspots.rb
58
+ - lib/bugspots/scanner.rb
59
+ - lib/bugspots/version.rb
60
+ homepage: https://github.com/cxm0000/MFOL-bugspots
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project: MFOL-bugspots
80
+ rubygems_version: 2.0.14
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Implementation of simple bug prediction hotspot heuristic
84
+ test_files: []