MFOL-bugspots 0.2.1

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.
@@ -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: []