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,100 @@
|
|
1
|
+
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
class SVNLogParser
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@commits = Commits.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def xml_to_parse(xml_string)
|
11
|
+
@xml_to_parse = xml_string
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(xml_to_parse = nil)
|
15
|
+
@xml_to_parse = xml_to_parse if xml_to_parse
|
16
|
+
|
17
|
+
xml = REXML::Document.new(@xml_to_parse)
|
18
|
+
validate_xml(xml)
|
19
|
+
|
20
|
+
xml.elements.each( "*/logentry" ) do |logentry|
|
21
|
+
commit = create_commit_from_log_entry(logentry)
|
22
|
+
@commits.add(commit)
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_commit_from_log_entry(logentry)
|
28
|
+
commit = Commit.new
|
29
|
+
commit.revision = logentry.attributes["revision"]
|
30
|
+
commit.author = logentry.elements["author"].text
|
31
|
+
commit.message = logentry.elements["msg"].text
|
32
|
+
commit.date = DateTime.parse(logentry.elements["date"].text)
|
33
|
+
commit.changes = create_commit_changes_from_log_entry(logentry)
|
34
|
+
commit
|
35
|
+
end
|
36
|
+
|
37
|
+
def extract_change_type(path)
|
38
|
+
return :modified if path.attributes["action"] == "M"
|
39
|
+
return :added if path.attributes["action"] == "A"
|
40
|
+
return :deleted if path.attributes["action"] == "D"
|
41
|
+
return :renamed if path.attributes["action"] == "R"
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract_kind(path)
|
45
|
+
return :file if path.attributes["kind"] == "file"
|
46
|
+
return :dir if path.attributes["kind"] == "dir"
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_commit_changes_from_log_entry(logentry)
|
50
|
+
changes = []
|
51
|
+
logentry.elements.each("*/path") { |path|
|
52
|
+
change = Change.new
|
53
|
+
change.type = extract_change_type(path)
|
54
|
+
change.kind = extract_kind(path)
|
55
|
+
change.property_changed if path.attributes["prop-mods"] == "true"
|
56
|
+
change.copyfrom = path.attributes["copyfrom-path"]
|
57
|
+
change.copyrev = path.attributes["copyfrom-rev"]
|
58
|
+
change.file = path.text
|
59
|
+
changes << change
|
60
|
+
}
|
61
|
+
changes
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate_xml(xml)
|
65
|
+
non_logentries = xml.elements["log"].elements.collect { |e| e.name unless e.name == "logentry" }.compact
|
66
|
+
non_logentries.each { |e| raise("Unexpected log entry: " + e) }
|
67
|
+
|
68
|
+
xml.elements.each( "*/logentry" ) do |logentry|
|
69
|
+
validate_log_entry(logentry)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_log_entry logentry
|
74
|
+
invalid_attributes = logentry.attributes.collect { |a| a[0] unless a[0] == "revision" }.compact
|
75
|
+
invalid_attributes.each { |a| raise ("Unexpected attributes log entry: " + a) }
|
76
|
+
|
77
|
+
invalid_elements = logentry.elements.collect { |e| e.name unless ["author", "date", "paths", "msg"].include? e.name }.compact
|
78
|
+
invalid_elements.each { |e| raise ("Unexpected element in log entry: " + e) }
|
79
|
+
|
80
|
+
logentry.elements.each("*/path") { |path|
|
81
|
+
validate_path path
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_path path
|
86
|
+
path.elements.each { |e| raise ("Unexpected element in path: " + e.name) }
|
87
|
+
|
88
|
+
invalid_attributes = path.attributes.collect { |a| a[0] unless ["action", "prop-mods", "text-mods", "kind", "copyfrom-path", "copyfrom-rev"].include? a[0] }.compact
|
89
|
+
invalid_attributes.each { |a| raise ("Unexpected attributes in path: " + a) }
|
90
|
+
|
91
|
+
raise("Unexpected value to attribute action in path: " + path.attributes["action"]) unless ["R", "M", "A", "D"].include?(path.attributes["action"])
|
92
|
+
raise("Unexpected value to attribute kind in path: " + path.attributes["kind"]) unless ["file", "dir"].include?(path.attributes["kind"])
|
93
|
+
|
94
|
+
puts "Unexpected value to attribute text-mods in path: " + path.attributes["text-mods"] if path.attributes["text-mods"] == "false" and not ["D", "R"].include?(path.attributes["action"]) and path.attributes["kind"] != "dir"
|
95
|
+
end
|
96
|
+
|
97
|
+
def commits
|
98
|
+
@commits
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
|
2
|
+
class Team
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
@members = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_member(member)
|
12
|
+
@members[member.username] = member
|
13
|
+
member.team = self
|
14
|
+
end
|
15
|
+
|
16
|
+
def members
|
17
|
+
@members.values
|
18
|
+
end
|
19
|
+
|
20
|
+
def each_member
|
21
|
+
@members.values.each { |member|
|
22
|
+
yield member
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def amount_of_members
|
27
|
+
@members.size
|
28
|
+
end
|
29
|
+
|
30
|
+
def member_usernames
|
31
|
+
@members.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def <=> other
|
35
|
+
@name <=> other.name
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(team)
|
39
|
+
name == team.name && members == team.members
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Teams
|
44
|
+
|
45
|
+
attr_reader :teams
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@teams = {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_by_name(name)
|
52
|
+
@teams[name]
|
53
|
+
end
|
54
|
+
|
55
|
+
def team_names
|
56
|
+
@teams.keys
|
57
|
+
end
|
58
|
+
|
59
|
+
def each
|
60
|
+
@teams.values.sort.each { |team|
|
61
|
+
yield team
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def map(&block)
|
66
|
+
@teams.values.map(&block)
|
67
|
+
end
|
68
|
+
|
69
|
+
def each_member
|
70
|
+
@teams.values.each { |team|
|
71
|
+
team.each_member { |member|
|
72
|
+
yield team, member
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def team(name)
|
78
|
+
@teams[name] ||= Team.new(name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def add(team)
|
82
|
+
@teams[team.name] = team
|
83
|
+
end
|
84
|
+
|
85
|
+
def amount
|
86
|
+
@teams.size
|
87
|
+
end
|
88
|
+
|
89
|
+
def member_usernames(team_name = nil)
|
90
|
+
@teams.values.collect { |team|
|
91
|
+
team.member_usernames if team.name == team_name || team_name == nil
|
92
|
+
}.compact.flatten
|
93
|
+
end
|
94
|
+
|
95
|
+
def ==(teams)
|
96
|
+
@teams == teams.teams
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
describe "Codespicuous command line" do
|
3
|
+
|
4
|
+
subject {Codespicuous.new}
|
5
|
+
|
6
|
+
it "prints an error message when no config it present" do
|
7
|
+
expect(subject).to receive(:puts).with("Stage 1: Configuring")
|
8
|
+
expect($stdout).to receive(:puts).with("** Error: No repositories configured in \"codespicuous.yaml\"")
|
9
|
+
|
10
|
+
expect(subject.run([])).to eq false
|
11
|
+
end
|
12
|
+
|
13
|
+
it "creates a configurator, collect data, and lists the repositories the people committed to" do
|
14
|
+
subject.config.list_repositories = true
|
15
|
+
|
16
|
+
expect(subject).to receive(:puts).with("Stage 1: Configuring")
|
17
|
+
expect(subject).to receive(:configure).and_return(true)
|
18
|
+
expect(subject).to receive(:puts).with("Stage 2: Collecting input data")
|
19
|
+
expect(subject).to receive(:collect)
|
20
|
+
expect(subject).to receive(:puts).with("Stage 3: Listing repositories committed to")
|
21
|
+
expect(subject).to receive(:list_committed_repositories)
|
22
|
+
|
23
|
+
expect(subject.run([])).to eq true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "creates a configurator, collect data, and generate output" do
|
27
|
+
expect(subject).to receive(:puts).with("Stage 1: Configuring")
|
28
|
+
expect(subject).to receive(:configure).and_return(true)
|
29
|
+
expect(subject).to receive(:puts).with("Stage 2: Collecting input data")
|
30
|
+
expect(subject).to receive(:collect)
|
31
|
+
expect(subject).to receive(:puts).with("Stage 3: Generating output")
|
32
|
+
expect(subject).to receive(:generate_output)
|
33
|
+
|
34
|
+
expect(subject.run([])).to eq true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "configures the config data" do
|
38
|
+
configurator = CodespicuousConfigurator.new(subject.config)
|
39
|
+
repositories = Repositories.new
|
40
|
+
committers = Committers.new
|
41
|
+
teams = Teams.new
|
42
|
+
|
43
|
+
expect(CodespicuousConfigurator).to receive(:new).and_return(configurator)
|
44
|
+
expect(configurator).to receive(:configure).with(["argv"]).and_return(true)
|
45
|
+
|
46
|
+
expect(configurator).to receive(:repositories).and_return(repositories)
|
47
|
+
expect(configurator).to receive(:committers).and_return(committers)
|
48
|
+
expect(configurator).to receive(:teams).and_return(teams)
|
49
|
+
|
50
|
+
subject.configure(["argv"])
|
51
|
+
expect(subject.committers).to be committers
|
52
|
+
expect(subject.repositories).to be repositories
|
53
|
+
expect(subject.teams).to be teams
|
54
|
+
end
|
55
|
+
|
56
|
+
it "collects the input data" do
|
57
|
+
collector = SVNDataCollector.new(subject.config)
|
58
|
+
commit_history = CommitHistory.new
|
59
|
+
expect(SVNDataCollector).to receive(:new).and_return(collector)
|
60
|
+
expect(collector).to receive(:collect_commit_history).with(subject.repositories).and_return(commit_history)
|
61
|
+
|
62
|
+
subject.collect
|
63
|
+
|
64
|
+
expect(subject.commit_history).to eq commit_history
|
65
|
+
end
|
66
|
+
|
67
|
+
it "generates output" do
|
68
|
+
generator = MetricsGenerator.new
|
69
|
+
expect(MetricsGenerator).to receive(:new).and_return(generator)
|
70
|
+
expect(generator).to receive(:generate).with(subject.commit_history)
|
71
|
+
subject.generate_output
|
72
|
+
end
|
73
|
+
|
74
|
+
it "lists the repositories" do
|
75
|
+
lister = RepositoryLister.new
|
76
|
+
expect(RepositoryLister).to receive(:new).and_return(lister)
|
77
|
+
expect(lister).to receive(:list).with(subject.commit_history)
|
78
|
+
subject.list_committed_repositories
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
@@ -0,0 +1,202 @@
|
|
1
|
+
|
2
|
+
describe "CodepicuousConfigurator reads all the config files and provides the data needed for running Codespicuous" do
|
3
|
+
|
4
|
+
subject { CodespicuousConfigurator.new(CodespicuousConfig.new) }
|
5
|
+
|
6
|
+
it "Should process the yaml file" do
|
7
|
+
expect(subject).to receive(:parse_command_line_arguments).with(["argv"])
|
8
|
+
expect(subject).to receive(:configure_from_yaml)
|
9
|
+
expect(subject).to receive(:postprocess_yaml_configuration)
|
10
|
+
expect(subject).to receive(:find_alternative_configuration_files)
|
11
|
+
expect(subject).to receive(:validate_configuration)
|
12
|
+
subject.configure(["argv"])
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to handle the -r command line option" do
|
16
|
+
subject.parse_command_line_arguments(["-r"])
|
17
|
+
expect(subject.config.list_repositories).to be true
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Should be able to handle the -i command line option for input directory " do
|
21
|
+
subject.parse_command_line_arguments(["-i", "blah"])
|
22
|
+
expect(subject.config.input_path).to eq Pathname.new("blah")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Should be able to handle the -o command line option for output directory " do
|
26
|
+
subject.parse_command_line_arguments(["-o", "blah"])
|
27
|
+
expect(subject.config.output_path).to eq Pathname.new("blah")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "Should post process the YAML file" do
|
31
|
+
yaml_content = {}
|
32
|
+
|
33
|
+
expect(subject).to receive(:postprocess_yaml_configuration_repositories).with(yaml_content)
|
34
|
+
expect(subject).to receive(:postprocess_yaml_configuration_committers).with(yaml_content)
|
35
|
+
|
36
|
+
subject.postprocess_yaml_configuration(yaml_content)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Should find alternative config files" do
|
40
|
+
expect(subject).to receive(:find_alternative_configuration_files_for_repositories)
|
41
|
+
expect(subject).to receive(:find_alternative_configuration_files_for_committers)
|
42
|
+
|
43
|
+
subject.find_alternative_configuration_files
|
44
|
+
end
|
45
|
+
|
46
|
+
context "Read the YAML file" do
|
47
|
+
|
48
|
+
it "reads the codespicuous configuration from YAML file when the file exists" do
|
49
|
+
expect(File).to receive(:exist?).with("codespicuous.yaml").and_return(true)
|
50
|
+
expect(File).to receive(:read).with("codespicuous.yaml").and_return("offline: true")
|
51
|
+
expect(subject).to receive(:puts).with('** Configuring options with "codespicuous.yaml"')
|
52
|
+
|
53
|
+
subject.configure_from_yaml
|
54
|
+
expect(subject.config.offline).to eq true
|
55
|
+
end
|
56
|
+
|
57
|
+
it "Ignores the missing options file and tries to use defaults" do
|
58
|
+
expect(File).to receive(:exist?).with("codespicuous.yaml").and_return(false)
|
59
|
+
|
60
|
+
subject.configure_from_yaml
|
61
|
+
|
62
|
+
expect(subject.config.offline).to eq false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "Parsing the repositories" do
|
67
|
+
|
68
|
+
it "Processes the repositories out of the options with all selected" do
|
69
|
+
|
70
|
+
yaml_content = {"repositories" => { "name" => "url"}}
|
71
|
+
|
72
|
+
subject.postprocess_yaml_configuration_repositories(yaml_content)
|
73
|
+
|
74
|
+
repositories = Repositories.new
|
75
|
+
repositories.add(Repository.new("name", "url"))
|
76
|
+
|
77
|
+
expect(subject.repositories).to eq repositories
|
78
|
+
expect(subject.repositories_to_check).to eq repositories
|
79
|
+
end
|
80
|
+
|
81
|
+
it "Processes the repositories out of the options, with only the selected one" do
|
82
|
+
|
83
|
+
yaml_content = {"repositories" => { "name" => "url", "name2" => "url2"},
|
84
|
+
"repositories_to_check" => ["name2"]}
|
85
|
+
|
86
|
+
subject.postprocess_yaml_configuration_repositories(yaml_content)
|
87
|
+
|
88
|
+
repositories = Repositories.new
|
89
|
+
repositories.add(Repository.new("name", "url"))
|
90
|
+
repositories.add(Repository.new("name2", "url2"))
|
91
|
+
|
92
|
+
checked_repositories = Repositories.new
|
93
|
+
checked_repositories.add(Repository.new("name2", "url2"))
|
94
|
+
|
95
|
+
expect(subject.repositories).to eq repositories
|
96
|
+
expect(subject.repositories_to_check).to eq checked_repositories
|
97
|
+
end
|
98
|
+
|
99
|
+
it "will not bother checking the CSV file when it found repositories already" do
|
100
|
+
repositories = Repositories.new
|
101
|
+
repositories.add(Repository.new("name", "url"))
|
102
|
+
expect(subject).to receive(:repositories).and_return(repositories)
|
103
|
+
expect(File).not_to receive(:exist?)
|
104
|
+
|
105
|
+
subject.find_alternative_configuration_files_for_repositories
|
106
|
+
end
|
107
|
+
|
108
|
+
it "will check whether there is a CSV file and continue if not found" do
|
109
|
+
expect(File).to receive(:exist?).with("repositories.csv").and_return(false)
|
110
|
+
|
111
|
+
subject.find_alternative_configuration_files_for_repositories
|
112
|
+
|
113
|
+
expect(subject.repositories).to eq Repositories.new
|
114
|
+
end
|
115
|
+
|
116
|
+
it "will read the CSV file when it exists" do
|
117
|
+
expect(File).to receive(:exist?).with("repositories.csv").and_return(true)
|
118
|
+
expect(File).to receive(:read).with("repositories.csv").and_return("name,url\nrepos,https://repos.com")
|
119
|
+
expect(subject).to receive(:puts).with('** Configuring repositories with "repositories.csv"')
|
120
|
+
|
121
|
+
subject.find_alternative_configuration_files_for_repositories
|
122
|
+
|
123
|
+
repositories = Repositories.new
|
124
|
+
repositories.add(Repository.new("repos", "https://repos.com"))
|
125
|
+
|
126
|
+
expect(subject.repositories).to eq repositories
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context "Parsing the teams and committers" do
|
131
|
+
|
132
|
+
before (:each) do
|
133
|
+
@team_wine = Team.new("Wine")
|
134
|
+
@committer_bas = Committer.create_committer("basvodde", "Bas", "Vodde", "basv@wow.com", @team_wine)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "can have no committers and teams. Just empty then" do
|
138
|
+
subject.postprocess_yaml_configuration_committers({})
|
139
|
+
|
140
|
+
expect(subject.committers).to eq Committers.new
|
141
|
+
expect(subject.teams).to eq Teams.new
|
142
|
+
end
|
143
|
+
|
144
|
+
it "can get the team info from the yaml file" do
|
145
|
+
|
146
|
+
yaml_content = {"teams" =>
|
147
|
+
{"Wine" => [{
|
148
|
+
"First Name" => "Bas",
|
149
|
+
"Last Name" => "Vodde",
|
150
|
+
"Email" => "basv@wow.com",
|
151
|
+
"Login" => "basvodde" } ]
|
152
|
+
} }
|
153
|
+
|
154
|
+
subject.postprocess_yaml_configuration_committers(yaml_content)
|
155
|
+
|
156
|
+
committers = Committers.new
|
157
|
+
@team_wine.add_member(@committer_bas)
|
158
|
+
committers.add(@committer_bas)
|
159
|
+
|
160
|
+
teams = Teams.new
|
161
|
+
teams.add(@team_wine)
|
162
|
+
|
163
|
+
expect(subject.committers).to eq committers
|
164
|
+
expect(subject.teams).to eq teams
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
it "will not bother checking the CSV file when it found committers already" do
|
169
|
+
committers = Committers.new
|
170
|
+
committers.add(@committer_bas)
|
171
|
+
expect(subject).to receive(:committers).and_return(committers)
|
172
|
+
expect(File).not_to receive(:exist?)
|
173
|
+
|
174
|
+
subject.find_alternative_configuration_files_for_committers
|
175
|
+
end
|
176
|
+
|
177
|
+
it "will check whether there is a CSV file and continue if not found" do
|
178
|
+
expect(File).to receive(:exist?).with("committers.csv").and_return(false)
|
179
|
+
|
180
|
+
subject.find_alternative_configuration_files_for_committers
|
181
|
+
|
182
|
+
expect(subject.committers).to eq Committers.new
|
183
|
+
end
|
184
|
+
|
185
|
+
it "will read the CSV file when it exists" do
|
186
|
+
expect(File).to receive(:exist?).with("committers.csv").and_return(true)
|
187
|
+
expect(File).to receive(:read).with("committers.csv").and_return("#,First Name,Last Name,Email,Login,Team,Specialization,Manager,day1,day2,day3,Comments,Present,Questionaire send,Answered,Pretest,Dietary,Commits,Blamed lines,Average LOC/Commit
|
188
|
+
#1,Bas,Vodde,basv@wow.com,basvodde,Wine")
|
189
|
+
expect(subject).to receive(:puts).with('** Configuring committers with "committers.csv"')
|
190
|
+
|
191
|
+
subject.find_alternative_configuration_files_for_committers
|
192
|
+
|
193
|
+
committers = Committers.new
|
194
|
+
committers.add(@committer_bas)
|
195
|
+
|
196
|
+
expect(subject.committers).to eq committers
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|