git_time_extractor 0.2.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.
- data/History.txt +8 -0
- data/README.txt +76 -0
- data/bin/git_time_extractor +45 -0
- data/lib/git_time_extractor.rb +109 -0
- metadata +84 -0
data/History.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
= git_time_extractor
|
2
|
+
|
3
|
+
Project Wiki: https://github.com/rietta/git_time_extractor/wiki
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
EXTRACT REASONABLE TIME RECORDS FROM A GIT REPOSITORY
|
8
|
+
|
9
|
+
git_time_extractor is a free tool that goes through a GIT, the popular revision control system, repository's commit log and produces a Comma Seperated Values (CSV) file that indicates the time spent by each developer, per day.
|
10
|
+
|
11
|
+
The working time estimates are based on three assumptions:
|
12
|
+
|
13
|
+
1. A series of commits within a 3 hour window are part of the same development session
|
14
|
+
2. A single commit (or the first commit of the session) is considered to represent 30 minutes of work time
|
15
|
+
3. The more frequent a developer commits to the repository while working, the more accurate the time report will be
|
16
|
+
|
17
|
+
This script is based on previous code published publicly by Sharad at http://www.tatvartha.com/2010/01/generating-time-entry-from-git-log/. However, it has been adapted to run without Rails from the command line. The portions of the code written by Rietta are licensed under the terms of the BSD license (see section 3 below).
|
18
|
+
|
19
|
+
git_time_extractor is useful for software development companies that want to discover the approximate time spent by developers on particular projects based on real data in the GIT revision control system. This is useful for managers, accountants, and for those who need to back up records for tax purposes.
|
20
|
+
|
21
|
+
For example, in the United States there is a Research & Development (R&D) tax credit available for companies who build or improve software for certain purposes. To claim this credit requires certain types of records. Check with your accountant to see if the results from this program is appropriate in your particular situation. You can learn more information about this particular credit at http://www.irs.gov/businesses/article/0,,id=156366,00.html.
|
22
|
+
|
23
|
+
== BENEFITS:
|
24
|
+
|
25
|
+
* Compute time records based on the timestamps of each code commit by each developer
|
26
|
+
* Compare these results with other time-sheets or metrics to measure the effectiveness of your team members
|
27
|
+
* Save money on taxes by producing documents required by your accountant to properly apply for certain tax credits
|
28
|
+
* It's a Free Open Source Tool
|
29
|
+
|
30
|
+
== FEATURES:
|
31
|
+
|
32
|
+
* Easy command-line operation
|
33
|
+
* Reads from a local GIT branch in the current directory
|
34
|
+
* Writes to a CSV-file that is compatible with Microsoft Excel, OpenOffice Calc, or Google Docs
|
35
|
+
|
36
|
+
== SYNOPSIS:
|
37
|
+
|
38
|
+
cd /path/to/your/repository
|
39
|
+
git_time_extractor > time_log.csv
|
40
|
+
|
41
|
+
== REQUIREMENTS:
|
42
|
+
|
43
|
+
The following GEMS are required as dependencies:
|
44
|
+
* git
|
45
|
+
* logger
|
46
|
+
|
47
|
+
== INSTALL:
|
48
|
+
|
49
|
+
gem install git_time_extractor
|
50
|
+
|
51
|
+
== UNINSTALL:
|
52
|
+
|
53
|
+
gem install git_time_extractor
|
54
|
+
|
55
|
+
== DEVELOPERS:
|
56
|
+
|
57
|
+
After checking out the source, run:
|
58
|
+
|
59
|
+
$ rake newb
|
60
|
+
|
61
|
+
This task will install any missing dependencies, run the tests/specs,
|
62
|
+
and generate the RDoc.
|
63
|
+
|
64
|
+
== LICENSE:
|
65
|
+
|
66
|
+
(The BSD License)
|
67
|
+
|
68
|
+
Copyright (c) 2012 Rietta Inc. All rights reserved.
|
69
|
+
|
70
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
71
|
+
|
72
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
73
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
74
|
+
|
75
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
76
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Extract Reasonable Developer Time Records from a GIT Repository's Commit Log
|
3
|
+
#
|
4
|
+
# This is inspired by a RAKE task publicly posted by Sharad at
|
5
|
+
# http://www.tatvartha.com/2010/01/generating-time-entry-from-git-log/.
|
6
|
+
# However, it has been adapted to run without Rails from the command line.
|
7
|
+
#
|
8
|
+
# Portions (C) 2012 Rietta Inc. and licensed under the terms of the BSD license.
|
9
|
+
|
10
|
+
# Adjust path in case called directly and not through gem
|
11
|
+
$:.unshift "#{File.expand_path(File.dirname(__FILE__))}/../lib"
|
12
|
+
|
13
|
+
require 'git_time_extractor'
|
14
|
+
|
15
|
+
#puts "\n# Arguments #{ARGV.length}\n"
|
16
|
+
|
17
|
+
valid_usage = false
|
18
|
+
|
19
|
+
if ARGV.empty?
|
20
|
+
output_file = "-"
|
21
|
+
path_to_repo = Dir.pwd
|
22
|
+
project_name = ""
|
23
|
+
valid_usage = true
|
24
|
+
elsif "-h" == ARGV[0].downcase || "--help" == ARGV[0].downcase
|
25
|
+
# Show help
|
26
|
+
elsif ARGV.length == 2
|
27
|
+
output_file = ARGV.pop
|
28
|
+
path_to_repo = ARGV.pop
|
29
|
+
valid_usage = true
|
30
|
+
elsif ARGV.length == 1
|
31
|
+
output_file = "-"
|
32
|
+
path_to_repo = ARGV.pop
|
33
|
+
valid_usage = true
|
34
|
+
end
|
35
|
+
|
36
|
+
unless valid_usage
|
37
|
+
puts "Usage: git_time_extractor PROJECT_NAME [PATH_TO_REPO] [OUTPUT_FILE]"
|
38
|
+
puts "Copyright 2012 Rietta Inc. http://www.rietta.com"
|
39
|
+
exit 0
|
40
|
+
else
|
41
|
+
#path_to_repo = File.expand_path(File.dirname(path_to_repo)) if nil != path_to_repo && "" != path_to_repo
|
42
|
+
#puts "\n\nGit Repo Path: #{path_to_repo}\nOutput: #{output_file}\n"
|
43
|
+
GitTimeExtractor.process_git_log_into_time(path_to_repo, output_file)
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#
|
2
|
+
# Extract Reasonable Developer Time Records from a GIT Repository's Commit Log
|
3
|
+
#
|
4
|
+
# This is inspired by a RAKE task publicly posted by Sharad at
|
5
|
+
# http://www.tatvartha.com/2010/01/generating-time-entry-from-git-log/.
|
6
|
+
# However, it has been adapted to run without Rails from the command line.
|
7
|
+
#
|
8
|
+
# Portions (C) 2012 Rietta Inc. and licensed under the terms of the BSD license.
|
9
|
+
#
|
10
|
+
class GitTimeExtractor
|
11
|
+
VERSION = '0.2.0'
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'ostruct'
|
15
|
+
require 'logger'
|
16
|
+
require 'git'
|
17
|
+
require 'csv'
|
18
|
+
|
19
|
+
#
|
20
|
+
# Go through the GIT commit log, to compute the elapsed working time of each committing developer, based
|
21
|
+
# on a few assumptions:
|
22
|
+
#
|
23
|
+
# (1) A series of commits within a 3 hour window are part of the same development session
|
24
|
+
# (2) A single commit (or the first commit of the session) is considered to represent 30 minutes of work time
|
25
|
+
# (3) The more frequent a developer commits to the repository while working, the more accurate the time report will be
|
26
|
+
#
|
27
|
+
#
|
28
|
+
def self.process_git_log_into_time(path_to_git_repo = "./", path_to_output_file = "-", project_name = "")
|
29
|
+
|
30
|
+
if "-" != path_to_output_file
|
31
|
+
raise "Output path not yet implemented. Use a Unix pipe to write to your desired file. For example: git_time_extractor ./ > my_result.csv\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
# Open the GIT Repository for Reading
|
35
|
+
logger = Logger.new(STDOUT)
|
36
|
+
logger.level = Logger::WARN
|
37
|
+
g = Git.open(path_to_git_repo, :log => logger)
|
38
|
+
logs = g.log(1000)
|
39
|
+
log_entries = logs.entries.reverse
|
40
|
+
worklog = {}
|
41
|
+
|
42
|
+
# Go through the GIT commit records and construct the time
|
43
|
+
log_entries.each_with_index do |commit, index|
|
44
|
+
author_date = commit.author_date.to_date
|
45
|
+
daylog = worklog[author_date] || OpenStruct.new(:date => author_date, :duration => 0)
|
46
|
+
daylog.author = commit.author
|
47
|
+
daylog.message = "#{daylog.message} --- #{commit.message}"
|
48
|
+
daylog.duration = daylog.duration + calc_duration_in_minutes(log_entries, index)
|
49
|
+
worklog[author_date] = daylog
|
50
|
+
end # log_entries.each_with_index
|
51
|
+
|
52
|
+
# Print the header row for the CSV
|
53
|
+
puts [
|
54
|
+
'Date',
|
55
|
+
'Minutes',
|
56
|
+
'Hours',
|
57
|
+
'Person',
|
58
|
+
'Email',
|
59
|
+
'Project',
|
60
|
+
'Notes',
|
61
|
+
'Week Number',
|
62
|
+
'Year'
|
63
|
+
].to_csv
|
64
|
+
|
65
|
+
# Go through the work log
|
66
|
+
worklog.keys.sort.each do |date|
|
67
|
+
|
68
|
+
start_time = DateTime.parse(date.to_s)
|
69
|
+
duration_in_seconds = (worklog[date].duration.to_f * 60.0).round(0)
|
70
|
+
duration_in_minutes = worklog[date].duration.to_i
|
71
|
+
duration_in_hours = (worklog[date].duration / 60.0).round(1)
|
72
|
+
|
73
|
+
stop_time = start_time + duration_in_seconds
|
74
|
+
row = [
|
75
|
+
start_time.strftime("%m/%d/%Y"),
|
76
|
+
duration_in_minutes,
|
77
|
+
duration_in_hours,
|
78
|
+
worklog[date].author.name,
|
79
|
+
worklog[date].author.email,
|
80
|
+
project_name,
|
81
|
+
worklog[date].message,
|
82
|
+
start_time.strftime("%W").to_i,
|
83
|
+
start_time.strftime("%Y").to_i]
|
84
|
+
puts row.to_csv
|
85
|
+
end # worklog each
|
86
|
+
|
87
|
+
end # process_git_log_into_time
|
88
|
+
|
89
|
+
# Calculate the duration of work in minutes
|
90
|
+
def self.calc_duration_in_minutes(log_entries, index)
|
91
|
+
commit = log_entries[index]
|
92
|
+
if index > 1
|
93
|
+
previous_commit = log_entries[index-1]
|
94
|
+
# Default duration in Ruby is in seconds
|
95
|
+
duration = commit.author_date - previous_commit.author_date
|
96
|
+
|
97
|
+
# ASSUMPTION: if the gap between 2 commits is more than 3 hours, reduce it to 1/2 hour
|
98
|
+
duration = 30 * 60 if duration > 3 * 3600
|
99
|
+
else
|
100
|
+
# ASSUMPTION: first commit took 1/2 hour
|
101
|
+
duration = 30 * 60
|
102
|
+
end
|
103
|
+
return duration.to_f / 60.0
|
104
|
+
end # calc_duration_in_minutes
|
105
|
+
|
106
|
+
def self.say_hi
|
107
|
+
"hi"
|
108
|
+
end
|
109
|
+
end # class GitTimeExtractor
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: git_time_extractor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Frank Rietta
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: git
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: logger
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: Compute the estimated time spent by developers working on code within
|
47
|
+
a GIT respository. Useful for verifying developer timesheets and for tax purposes.
|
48
|
+
email: products@rietta.com
|
49
|
+
executables:
|
50
|
+
- git_time_extractor
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- bin/git_time_extractor
|
55
|
+
- README.txt
|
56
|
+
- History.txt
|
57
|
+
- lib/git_time_extractor.rb
|
58
|
+
homepage: https://github.com/rietta/git_time_extractor
|
59
|
+
licenses:
|
60
|
+
- BSD
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.24
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Reasonable developer time log extractor that uses a GIT repository's commit
|
83
|
+
log history.
|
84
|
+
test_files: []
|