codespicuous 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/LICENSE +29 -0
- data/README.md +2 -0
- data/Rakefile +6 -0
- data/bin/codespicuous +4 -0
- data/bin/filezilla/codespicuous.yaml +23 -0
- data/bin/filezilla/committers.csv +4 -0
- data/bin/filezilla/svnlog/filezilla.log +3939 -0
- data/bin/filezilla/svnlog/python.log +3 -0
- data/bin/filezilla/svnlog/xiph.log +265 -0
- data/codespicuous.gemspec +22 -0
- data/lib/codespicuous.rb +38 -0
- data/lib/codespicuous/codespicuous.rb +55 -0
- data/lib/codespicuous/codespicuous_config.rb +35 -0
- data/lib/codespicuous/codespicuousconfigurator.rb +136 -0
- data/lib/codespicuous/commandrunner.rb +13 -0
- data/lib/codespicuous/commithistory.rb +71 -0
- data/lib/codespicuous/commithistory_builder.rb +49 -0
- data/lib/codespicuous/commits.rb +147 -0
- data/lib/codespicuous/commitstatistics.rb +245 -0
- data/lib/codespicuous/committer.rb +105 -0
- data/lib/codespicuous/danielparser.rb +31 -0
- data/lib/codespicuous/dateutil.rb +18 -0
- data/lib/codespicuous/metrics_generator.rb +22 -0
- data/lib/codespicuous/metrics_generator_csv.rb +67 -0
- data/lib/codespicuous/metrics_generator_daniel.rb +13 -0
- data/lib/codespicuous/participantsparser_from_csv.rb +37 -0
- data/lib/codespicuous/repositories.rb +80 -0
- data/lib/codespicuous/repository_lister.rb +8 -0
- data/lib/codespicuous/svn_client.rb +14 -0
- data/lib/codespicuous/svn_data_collector.rb +50 -0
- data/lib/codespicuous/svn_log_parser.rb +100 -0
- data/lib/codespicuous/teams.rb +99 -0
- data/lib/codespicuous/version.rb +4 -0
- data/spec/codespicuous_spec.rb +81 -0
- data/spec/codespicuousconfigurator_spec.rb +202 -0
- data/spec/commithistories_data.rb +46 -0
- data/spec/commithistory_spec.rb +57 -0
- data/spec/commits_spec.rb +93 -0
- data/spec/committers_spec.rb +66 -0
- data/spec/danielparser_spec.rb +12 -0
- data/spec/integration_filezilla_spec.rb +41 -0
- data/spec/metrics_generator_csv_spec.rb +91 -0
- data/spec/metrics_generator_daniel_spec.rb +10 -0
- data/spec/metrics_generator_spec.rb +35 -0
- data/spec/repositories_spec.rb +29 -0
- data/spec/svn_client_spec.rb +16 -0
- data/spec/svn_data_collector_spec.rb +93 -0
- data/spec/svn_log_parser_spec.rb +141 -0
- data/spec/teams_spec.rb +16 -0
- metadata +142 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
class Committer
|
3
|
+
|
4
|
+
attr_reader :commits
|
5
|
+
attr_accessor :username, :first_name, :last_name, :email, :team
|
6
|
+
|
7
|
+
def initialize(username)
|
8
|
+
@username = username
|
9
|
+
@commits = Commits.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create_committer(login, firstname, lastname, email, team)
|
13
|
+
committer = Committer.new(login)
|
14
|
+
committer.first_name = firstname
|
15
|
+
committer.last_name = lastname
|
16
|
+
committer.email = email
|
17
|
+
committer.team = team
|
18
|
+
committer
|
19
|
+
end
|
20
|
+
|
21
|
+
def in_team_with_name?(team_name)
|
22
|
+
@team.name == team_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_commit commit
|
26
|
+
@commits.add(commit)
|
27
|
+
commit.committer = self
|
28
|
+
end
|
29
|
+
|
30
|
+
def amount_of_commits
|
31
|
+
@commits.amount
|
32
|
+
end
|
33
|
+
|
34
|
+
def amount_of_commits_to_repository name
|
35
|
+
@commits.amount_of_commits_to_repository name
|
36
|
+
end
|
37
|
+
|
38
|
+
def amount_of_weeks_committed_to_repository name
|
39
|
+
@commits.amount_of_weeks_committed_in_repository(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def amount_of_commits_in_week(week_start)
|
43
|
+
@commits.amount_of_commits_in_week(week_start)
|
44
|
+
end
|
45
|
+
|
46
|
+
def amount_of_commits_to_repository_in_week(name, week_start)
|
47
|
+
@commits.amount_of_commits_to_repository_in_week(name, week_start)
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(committer)
|
51
|
+
username == committer.username &&
|
52
|
+
first_name == committer.first_name &&
|
53
|
+
last_name == committer.last_name &&
|
54
|
+
email == committer.email &&
|
55
|
+
team.name == committer.team.name
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class Committers
|
61
|
+
|
62
|
+
attr_reader :committers
|
63
|
+
|
64
|
+
def initialize(initial_committers_usernames = [])
|
65
|
+
@committers = {}
|
66
|
+
|
67
|
+
[initial_committers_usernames].flatten.each { |username|
|
68
|
+
@committers[username] = Committer.new(username)
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def add(committer)
|
73
|
+
@committers[committer.username] = committer
|
74
|
+
end
|
75
|
+
|
76
|
+
def committer(name)
|
77
|
+
@committers[name] ||= Committer.new(name)
|
78
|
+
end
|
79
|
+
|
80
|
+
def amount
|
81
|
+
@committers.size
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_by_username username
|
85
|
+
@committers[username]
|
86
|
+
end
|
87
|
+
|
88
|
+
def include? username
|
89
|
+
@committers.keys.include?(username)
|
90
|
+
end
|
91
|
+
|
92
|
+
def select(&block)
|
93
|
+
@committers.values.select(&block)
|
94
|
+
end
|
95
|
+
|
96
|
+
def empty?
|
97
|
+
@committers.empty?
|
98
|
+
end
|
99
|
+
|
100
|
+
def ==(committers)
|
101
|
+
@committers == committers.committers
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
class DanielFormatParser
|
3
|
+
|
4
|
+
def parse committers_daniel_format
|
5
|
+
|
6
|
+
commit_history = CommitHistory.new
|
7
|
+
|
8
|
+
current_repository = current_author = ""
|
9
|
+
|
10
|
+
committers_daniel_format.each_line { |line|
|
11
|
+
|
12
|
+
if /repository: (.*)/.match(line)
|
13
|
+
current_repository = Repository.new($~[1], "")
|
14
|
+
elsif /\*\*\* (.*)/.match(line)
|
15
|
+
current_author = $~[1]
|
16
|
+
elsif /team:(.*)/.match(line)
|
17
|
+
commit_history.add_team_member($~[1].strip, current_author)
|
18
|
+
elsif / (.*): (.*) commits/.match(line)
|
19
|
+
amount_of_commits = $~[2]
|
20
|
+
amount_of_commits.to_i.times {
|
21
|
+
commit = Commit.new
|
22
|
+
commit.author = current_author
|
23
|
+
commit.repository = current_repository
|
24
|
+
commit.date = DateTime.parse($~[1])
|
25
|
+
commit_history.add_commit(commit)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
}
|
29
|
+
commit_history
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module DateUtil
|
3
|
+
|
4
|
+
def begin_of_week(date)
|
5
|
+
date - (date.cwday-1)
|
6
|
+
end
|
7
|
+
|
8
|
+
def string_date(date)
|
9
|
+
date.strftime("%Y-%m-%d")
|
10
|
+
end
|
11
|
+
|
12
|
+
def for_each_week(start_date, end_date)
|
13
|
+
(begin_of_week(start_date)..begin_of_week(end_date)).step(7) { |week|
|
14
|
+
yield week
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class MetricsGenerator
|
4
|
+
|
5
|
+
attr_accessor :commit_history
|
6
|
+
|
7
|
+
def generate(commit_history)
|
8
|
+
@commit_history = commit_history
|
9
|
+
generate_daniel
|
10
|
+
generate_csv
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_daniel
|
14
|
+
daniel = MetricsGeneratorDaniel.new(@commit_history)
|
15
|
+
daniel.generate
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_csv
|
19
|
+
csv = MetricsGeneratorCsv.new(@commit_history)
|
20
|
+
csv.generate
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class MetricsGeneratorCsv
|
4
|
+
|
5
|
+
include DateUtil
|
6
|
+
|
7
|
+
def initialize(commit_history)
|
8
|
+
@commit_history = commit_history
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_commit_table_row_for_committer_with_repository_info committer
|
16
|
+
[committer.username, committer.team.name, @commit_history.repository_names.map { |repository|
|
17
|
+
committer.amount_of_commits_to_repository(repository)}, committer.amount_of_commits].flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_commit_table_rows_with_committers_and_repository_info(team_to_select)
|
21
|
+
@commit_history.team(team_to_select.name).members.map { |committer|
|
22
|
+
create_commit_table_row_for_committer_with_repository_info(committer) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_commit_table_with_committers_and_repository_info
|
26
|
+
CSV.generate do |csv|
|
27
|
+
csv << ["Committer", "Team", @commit_history.repository_names, "Total"].flatten
|
28
|
+
@commit_history.teams.each { |team|
|
29
|
+
create_commit_table_rows_with_committers_and_repository_info(team).each { |row| csv << row }
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_commit_table_with_weeks_and_team_commits
|
35
|
+
CSV.generate do |csv|
|
36
|
+
csv << ["Week", @commit_history.teams.team_names].flatten
|
37
|
+
for_each_week(@commit_history.earliest_commit_date, @commit_history.latest_commit_date) { |week|
|
38
|
+
csv << [string_date(week), @commit_history.teams.map { |team|
|
39
|
+
@commit_history.amount_of_commits_for_team_in_week(team.name, week)
|
40
|
+
} ].flatten
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_commit_table_with_week_and_repository_info
|
46
|
+
CSV.generate do |csv|
|
47
|
+
csv << ["Week", @commit_history.repository_names].flatten
|
48
|
+
for_each_week(@commit_history.earliest_commit_date, @commit_history.latest_commit_date) { |week|
|
49
|
+
csv << [string_date(week), @commit_history.repositories.map { |repository|
|
50
|
+
repository.amount_of_commits_in_week(week)
|
51
|
+
} ].flatten
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def create_commit_table_with_weeks_and_committers(team=nil)
|
57
|
+
CSV.generate do |csv|
|
58
|
+
csv << ["Week", @commit_history.teams.member_usernames(team) ].flatten
|
59
|
+
for_each_week(@commit_history.earliest_commit_date, @commit_history.latest_commit_date) { |week|
|
60
|
+
csv << [string_date(week), @commit_history.teams.member_usernames(team).map { |name|
|
61
|
+
@commit_history.committers.find_by_username(name).amount_of_commits_in_week(week)
|
62
|
+
}].flatten
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class CommittersParserFromCsv
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@committers = Committers.new
|
7
|
+
@teams = Teams.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse csv_string
|
11
|
+
CSV.parse(csv_string, headers: true) { |row|
|
12
|
+
parse_row row
|
13
|
+
}
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_row row
|
18
|
+
committer = Committer.new(row["Login"])
|
19
|
+
committer.first_name = row["First Name"]
|
20
|
+
committer.last_name = row["Last Name"]
|
21
|
+
committer.email = row["Email"]
|
22
|
+
team = @teams.team(row["Team"])
|
23
|
+
committer.team = team
|
24
|
+
team.add_member(committer)
|
25
|
+
@committers.add(committer)
|
26
|
+
end
|
27
|
+
|
28
|
+
def committers
|
29
|
+
@committers
|
30
|
+
end
|
31
|
+
|
32
|
+
def teams
|
33
|
+
@teams
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class SameRepositoriesWithDifferentCommitsError < Exception
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
class Repository
|
8
|
+
|
9
|
+
attr_reader :commits
|
10
|
+
attr_accessor :url, :name
|
11
|
+
|
12
|
+
def initialize(name, url)
|
13
|
+
@name = name
|
14
|
+
@url = url
|
15
|
+
@commits = Commits.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_commit commit
|
19
|
+
@commits.add(commit)
|
20
|
+
end
|
21
|
+
|
22
|
+
def amount_of_commits_in_week(week_start)
|
23
|
+
@commits.amount_of_commits_to_repository_in_week(name, week_start)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ==(repository)
|
27
|
+
is_equal = @name == repository.name && @url == repository.url
|
28
|
+
|
29
|
+
raise SameRepositoriesWithDifferentCommitsError.new if is_equal && @commits != repository.commits
|
30
|
+
is_equal
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Repositories
|
35
|
+
|
36
|
+
attr_reader :repositories
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
@repositories = {}
|
40
|
+
end
|
41
|
+
|
42
|
+
def add repository
|
43
|
+
@repositories[repository.name] = repository
|
44
|
+
end
|
45
|
+
|
46
|
+
def repository name
|
47
|
+
@repositories[name]
|
48
|
+
end
|
49
|
+
|
50
|
+
def repository_names
|
51
|
+
@repositories.keys
|
52
|
+
end
|
53
|
+
|
54
|
+
def amount
|
55
|
+
@repositories.size
|
56
|
+
end
|
57
|
+
|
58
|
+
def each
|
59
|
+
@repositories.values.each { |repository|
|
60
|
+
yield repository
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def empty?
|
65
|
+
@repositories.empty?
|
66
|
+
end
|
67
|
+
|
68
|
+
def map(&block)
|
69
|
+
@repositories.values.map(&block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def [](index)
|
73
|
+
@repositories.values[index]
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(repositories)
|
77
|
+
@repositories == repositories.repositories
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require 'attempt_to'
|
3
|
+
class SVNClient
|
4
|
+
|
5
|
+
def repository(repository)
|
6
|
+
@repository = repository
|
7
|
+
end
|
8
|
+
|
9
|
+
def log_xml(from, to)
|
10
|
+
AttemptTo.attempt_to('svn log: "' + @repository + '"', 5) {
|
11
|
+
CommandRunner.run("svn log #{@repository} -r{#{from.strftime("%Y-%m-%d")}}:{#{to.strftime("%Y-%m-%d")}} --xml")
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class SVNDataCollector
|
4
|
+
|
5
|
+
attr_reader :config
|
6
|
+
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def retrieve_svn_log_from(repository)
|
12
|
+
if config.offline
|
13
|
+
File.read(config.path_to_cached_svn_log(repository.name))
|
14
|
+
else
|
15
|
+
svn = SVNClient.new
|
16
|
+
svn.repository(repository.url)
|
17
|
+
now = DateTime.now
|
18
|
+
svn.log_xml(now.prev_year, now)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def retrieve_commits_from_log(xmllog)
|
23
|
+
parser = SVNLogParser.new
|
24
|
+
parser.parse(xmllog)
|
25
|
+
parser.commits
|
26
|
+
end
|
27
|
+
|
28
|
+
def save_svn_log(repository, xmllog)
|
29
|
+
Dir.mkdir(config.path_to_cached_svn_log_dir) unless Dir.exists?(config.path_to_cached_svn_log_dir)
|
30
|
+
File.write(config.path_to_cached_svn_log(repository.name), xmllog)
|
31
|
+
end
|
32
|
+
|
33
|
+
def collect_commits_for_repository(repository)
|
34
|
+
puts "Getting svn log from repository: " + repository.name
|
35
|
+
xmllog = retrieve_svn_log_from(repository)
|
36
|
+
save_svn_log(repository, xmllog)
|
37
|
+
commits_in_repository = retrieve_commits_from_log(xmllog)
|
38
|
+
commits_in_repository.set_repository(repository)
|
39
|
+
commits_in_repository
|
40
|
+
end
|
41
|
+
|
42
|
+
def collect_commit_history(repositories)
|
43
|
+
commit_history = CommitHistory.new
|
44
|
+
repositories.each { | repository|
|
45
|
+
commit_history.add_commits(collect_commits_for_repository(repository))
|
46
|
+
}
|
47
|
+
commit_history
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|