codespicuous 0.0.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.
- 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
|