codefumes 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/Gemfile +19 -0
  2. data/Gemfile.lock +135 -0
  3. data/History.txt +12 -0
  4. data/LICENSE +20 -0
  5. data/Manifest.txt +40 -19
  6. data/README.txt +11 -29
  7. data/Rakefile +15 -10
  8. data/bin/fumes +214 -0
  9. data/config/website.yml +2 -0
  10. data/cucumber.yml +2 -0
  11. data/features/claiming_a_project.feature +46 -0
  12. data/features/deleting_a_project.feature +32 -0
  13. data/features/releasing_a_project.feature +50 -0
  14. data/features/step_definitions/cli_steps.rb +98 -0
  15. data/features/step_definitions/common_steps.rb +168 -0
  16. data/features/step_definitions/filesystem_steps.rb +19 -0
  17. data/features/storing_user_api_key.feature +41 -0
  18. data/features/support/common.rb +29 -0
  19. data/features/support/env.rb +24 -0
  20. data/features/support/matchers.rb +11 -0
  21. data/features/synchronizing_repository_with_project.feature +33 -0
  22. data/lib/codefumes.rb +10 -8
  23. data/lib/codefumes/api.rb +20 -11
  24. data/lib/codefumes/api/build.rb +139 -0
  25. data/lib/codefumes/api/claim.rb +74 -0
  26. data/lib/codefumes/api/commit.rb +150 -0
  27. data/lib/codefumes/api/payload.rb +93 -0
  28. data/lib/codefumes/api/project.rb +158 -0
  29. data/lib/codefumes/cli_helpers.rb +54 -0
  30. data/lib/codefumes/config_file.rb +3 -2
  31. data/lib/codefumes/errors.rb +21 -0
  32. data/lib/codefumes/exit_codes.rb +10 -0
  33. data/lib/codefumes/harvester.rb +113 -0
  34. data/lib/codefumes/quick_build.rb +43 -0
  35. data/lib/codefumes/quick_metric.rb +20 -0
  36. data/lib/codefumes/source_control.rb +137 -0
  37. data/lib/integrity_notifier/codefumes.haml +11 -0
  38. data/lib/integrity_notifier/codefumes.rb +62 -0
  39. data/spec/codefumes/{build_spec.rb → api/build_spec.rb} +14 -24
  40. data/spec/codefumes/{claim_spec.rb → api/claim_spec.rb} +42 -3
  41. data/spec/codefumes/{commit_spec.rb → api/commit_spec.rb} +34 -24
  42. data/spec/codefumes/api/payload_spec.rb +148 -0
  43. data/spec/codefumes/api/project_spec.rb +286 -0
  44. data/spec/codefumes/api_spec.rb +38 -15
  45. data/spec/codefumes/config_file_spec.rb +69 -13
  46. data/spec/codefumes/harvester_spec.rb +118 -0
  47. data/spec/codefumes/source_control_spec.rb +199 -0
  48. data/spec/codefumes_service_helpers.rb +23 -19
  49. data/spec/fixtures/sample_project_dirs/no_scm/description +4 -0
  50. data/spec/spec_helper.rb +1 -0
  51. data/tasks/cucumber.rake +11 -0
  52. metadata +145 -60
  53. data/bin/cf_claim_project +0 -9
  54. data/bin/cf_release_project +0 -10
  55. data/bin/cf_store_credentials +0 -10
  56. data/lib/cf_claim_project/cli.rb +0 -95
  57. data/lib/cf_release_project/cli.rb +0 -76
  58. data/lib/cf_store_credentials/cli.rb +0 -50
  59. data/lib/codefumes/build.rb +0 -131
  60. data/lib/codefumes/claim.rb +0 -57
  61. data/lib/codefumes/commit.rb +0 -144
  62. data/lib/codefumes/payload.rb +0 -103
  63. data/lib/codefumes/project.rb +0 -129
  64. data/spec/cf_claim_project/cli_spec.rb +0 -17
  65. data/spec/cf_release_project/cli_spec.rb +0 -41
  66. data/spec/cf_store_credentials/cli_spec.rb +0 -28
  67. data/spec/codefumes/payload_spec.rb +0 -155
  68. data/spec/codefumes/project_spec.rb +0 -274
@@ -14,7 +14,7 @@ end
14
14
 
15
15
  describe "ConfigFile" do
16
16
  before(:each) do
17
- @project = Project.new(:public_key => 'public_key_value', :private_key => 'private_key_value')
17
+ @project = Project.new('public_key_value', :private_key => 'private_key_value')
18
18
  end
19
19
 
20
20
  after(:all) do
@@ -53,7 +53,7 @@ describe "ConfigFile" do
53
53
  context "when passed an existing project" do
54
54
  before(:each) do
55
55
  ConfigFile.save_project(@project)
56
- @updated_project = Project.new(:public_key => @project.public_key, :private_key => "updated_private_key")
56
+ @updated_project = Project.new(@project.public_key, :private_key => "updated_private_key")
57
57
  end
58
58
 
59
59
  it "does not create a duplicate entry in the list of projects" do
@@ -67,9 +67,9 @@ describe "ConfigFile" do
67
67
 
68
68
  context "when several projects exist" do
69
69
  before(:each) do
70
- @project1 = Project.new(:public_key => :p1_pub_value, :private_key => "p1_private_key")
71
- @project2 = Project.new(:public_key => :p2_pub_value, :private_key => "p2_private_key")
72
- @project3 = Project.new(:public_key => :p3_pub_value, :private_key => "p3_private_key")
70
+ @project1 = Project.new(:p1_pub_value, :private_key => "p1_private_key")
71
+ @project2 = Project.new(:p2_pub_value, :private_key => "p2_private_key")
72
+ @project3 = Project.new(:p3_pub_value, :private_key => "p3_private_key")
73
73
  ConfigFile.save_project(@project1)
74
74
  ConfigFile.save_project(@project2)
75
75
  ConfigFile.save_project(@project3)
@@ -86,9 +86,9 @@ describe "ConfigFile" do
86
86
  describe "calling 'delete_project'" do
87
87
  context "when the project entry exists in the file" do
88
88
  before(:each) do
89
- @project1 = Project.new(:public_key => "p1_pub_value", :private_key => "p1_private_key")
90
- @project2 = Project.new(:public_key => "p2_pub_value", :private_key => "p2_private_key")
91
- @project3 = Project.new(:public_key => "p3_pub_value", :private_key => "p3_private_key")
89
+ @project1 = Project.new("p1_pub_value", :private_key => "p1_private_key")
90
+ @project2 = Project.new("p2_pub_value", :private_key => "p2_private_key")
91
+ @project3 = Project.new("p3_pub_value", :private_key => "p3_private_key")
92
92
  ConfigFile.save_project(@project1)
93
93
  ConfigFile.save_project(@project2)
94
94
  ConfigFile.save_project(@project3)
@@ -107,7 +107,7 @@ describe "ConfigFile" do
107
107
 
108
108
  context "when the project entry does not exist in the file" do
109
109
  before(:each) do
110
- @project = Project.new(:public_key => "p1_pub_nonexist_value", :private_key => "p1_private_key")
110
+ @project = Project.new("p1_pub_nonexist_value", :private_key => "p1_private_key")
111
111
  end
112
112
 
113
113
  it "does not raise an error" do
@@ -144,7 +144,7 @@ describe "ConfigFile" do
144
144
  end
145
145
  end
146
146
  end
147
-
147
+
148
148
  describe "calling 'save_credentials'" do
149
149
  before(:each) do
150
150
  @api_key = "API_KEY"
@@ -182,7 +182,7 @@ describe "ConfigFile" do
182
182
 
183
183
  it "does not affect existing project content" do
184
184
  public_key = "pub_value"
185
- project = Project.new(:public_key => public_key, :private_key => "private_key")
185
+ project = Project.new(public_key, :private_key => "private_key")
186
186
  ConfigFile.save_project(project)
187
187
  ConfigFile.save_credentials(@api_key)
188
188
  ConfigFile.serialized[:projects][public_key.to_sym].should_not be_nil
@@ -215,7 +215,7 @@ describe "ConfigFile" do
215
215
 
216
216
  context "when projects exist in the file" do
217
217
  before(:each) do
218
- create_uniq_project = lambda {|index| Project.new(:public_key => "pub_key_#{index}", :private_key => 'pk')}
218
+ create_uniq_project = lambda {|index| Project.new("pub_key_#{index}", :private_key => 'pk')}
219
219
  @projects = 5.times.map {|i| create_uniq_project.call(i)}
220
220
  @projects.each {|project| ConfigFile.save_project(project)}
221
221
  end
@@ -237,9 +237,65 @@ describe "ConfigFile" do
237
237
  end
238
238
 
239
239
  context "when no credentials exist in the file" do
240
- it "returns an empty Hash" do
240
+ it "returns nil" do
241
241
  ConfigFile.api_key.should == nil
242
242
  end
243
243
  end
244
244
  end
245
+
246
+ describe "#options_for_project" do
247
+ let(:private_key) {'private_key'}
248
+ let(:public_key) {'public_key'}
249
+ let(:project_instance) {Project.new(public_key, private_key)}
250
+
251
+ context "when passing in an Project instance" do
252
+ let(:param) {project_instance}
253
+
254
+ context "and no projects have been saved before" do
255
+ it "returns an empty Hash" do
256
+ delete_config_file
257
+ ConfigFile.options_for_project(param).should == {}
258
+ end
259
+ end
260
+
261
+ context "and the specified project has not been saved before" do
262
+ it "returns an empty Hash" do
263
+ ConfigFile.save_project(Project.new('public_key1'))
264
+ ConfigFile.options_for_project(param).should == {}
265
+ end
266
+ end
267
+
268
+ context "and the specified project has been saved before" do
269
+ it "returns a Hash of the project information" do
270
+ ConfigFile.save_project(project_instance)
271
+ ConfigFile.options_for_project(param).should include(:private_key => private_key)
272
+ end
273
+ end
274
+ end
275
+
276
+ context "when passing in the public key" do
277
+ let(:param) {public_key}
278
+
279
+ context "and no projects have been saved before" do
280
+ it "returns an empty Hash" do
281
+ delete_config_file
282
+ ConfigFile.options_for_project(param).should == {}
283
+ end
284
+ end
285
+
286
+ context "and the specified project has not been saved before" do
287
+ it "returns an empty Hash" do
288
+ ConfigFile.save_project(Project.new('public_key1'))
289
+ ConfigFile.options_for_project(param).should == {}
290
+ end
291
+ end
292
+
293
+ context "and the specified project has been saved before" do
294
+ it "returns a Hash of the project information" do
295
+ ConfigFile.save_project(project_instance)
296
+ ConfigFile.options_for_project(param).should include(:private_key => private_key)
297
+ end
298
+ end
299
+ end
300
+ end
245
301
  end
@@ -0,0 +1,118 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ #TODO: clean this up
4
+ include CodeFumesServiceHelpers::Shared
5
+ include CodeFumesServiceHelpers::ProjectHelpers
6
+
7
+ def raise_if_users_config_file
8
+ if ConfigFile.path == File.expand_path('~/.codefumes_config')
9
+ raise "Set a custom config file path"
10
+ end
11
+ end
12
+
13
+ def delete_config_file
14
+ unless ConfigFile.path == File.expand_path('~/.codefumes_config')
15
+ File.delete(ConfigFile.path) if File.exist?(ConfigFile.path)
16
+ end
17
+ end
18
+
19
+ describe Harvester do
20
+ after(:all) do
21
+ delete_config_file
22
+ FakeWeb.allow_net_connect = false
23
+ FakeWeb.clean_registry
24
+ end
25
+
26
+
27
+ let(:no_scm_path) {"#{File.dirname(__FILE__)}/../fixtures/sample_project_dirs/no_scm"}
28
+ let(:git_scm_path) {"#{File.dirname(__FILE__)}/../fixtures/sample_project_dirs/git_repository"}
29
+
30
+
31
+ before(:each) do
32
+ raise_if_users_config_file
33
+ setup_fixture_base
34
+ register_create_uri #For project creation
35
+ @repository = Grit::Repo.new(git_scm_path)
36
+ end
37
+
38
+ describe "#new" do
39
+ context "with a path to a directory that is using git" do
40
+ before(:each) do
41
+ Grit::Repo.stub!(:new).with(File.expand_path(git_scm_path)).and_return(@repository)
42
+ end
43
+
44
+ it "initializes a new Grit::Repo instance with the specified directory path" do
45
+ Grit::Repo.should_receive(:new).with(File.expand_path(git_scm_path)).and_return(@repository)
46
+ Harvester.new(:path => git_scm_path)
47
+ end
48
+ end
49
+
50
+ context "with a path to a directory that is not using a supported SCM" do
51
+ it "raises an UnsupportedScmToolError" do
52
+ lambda {
53
+ Harvester.new(:path => no_scm_path)
54
+ }.should raise_error(Errors::UnsupportedScmToolError)
55
+ end
56
+ end
57
+
58
+ context "when specifying the public/private keys" do
59
+ let(:public_key) {@pub_key}
60
+ let(:private_key) {@priv_key}
61
+
62
+ it "ignores the configuration saved in the underlying repository" do
63
+ register_show_uri
64
+ @repository.should_not_receive(:public_key)
65
+ @repository.should_not_receive(:private__key)
66
+ lambda {Harvester.new(:public_key => public_key, :private_key => private_key)}
67
+ end
68
+
69
+ context "if the specified project is not found on the server" do
70
+ before(:each) {register_show_uri(["404", "Not found"])}
71
+
72
+ it "raises an UnknownProjectError" do
73
+ lambda {
74
+ Harvester.new(:public_key => public_key, :private_key => private_key)
75
+ }.should raise_error(Errors::UnknownProjectError)
76
+ end
77
+
78
+ it "does not attempt to create a new project on the CodeFumes site" do
79
+ Project.should_not_receive(:create)
80
+ lambda {Harvester.new(:public_key => public_key, :private_key => private_key)}
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ describe "#path" do
87
+ it "returns the full path to a project" do
88
+ harvester = Harvester.new(:path => git_scm_path)
89
+ harvester.path.should == File.expand_path(git_scm_path)
90
+ end
91
+ end
92
+
93
+ describe "#publish_data!" do
94
+ include CodeFumesServiceHelpers::CommitHelpers
95
+ include CodeFumesServiceHelpers::ProjectHelpers
96
+
97
+ before(:each) do
98
+ delete_config_file
99
+ register_latest_uri
100
+ register_update_uri
101
+ @harvester = Harvester.new(:path => git_scm_path)
102
+ @payload = mock("Payload instance", :save => true)
103
+ Payload.stub!(:new).and_return(@payload)
104
+ end
105
+
106
+ it "saves the Payload to the website" do
107
+ pending "Need to figure out a better way to test this..."
108
+ @payload.should_receive(:save).and_return(true)
109
+ @harvester.publish_data!
110
+ end
111
+
112
+ it "updates the config file's project information" do
113
+ pending "Need to figure out a better way to test this..."
114
+ ConfigFile.should_receive(:save_project)
115
+ @harvester.publish_data!
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,199 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe SourceControl do
4
+ after(:each) do
5
+ SourceControl.new(GIT_FIXTURE_REPO_PATH).unlink_from_codefumes!
6
+ unless ConfigFile.path == File.expand_path('~/.codefumes_config')
7
+ File.delete(ConfigFile.path) if File.exists?(ConfigFile.path)
8
+ end
9
+ end
10
+
11
+ describe "creation" do
12
+ context "with a path to a directory that is not a git repository" do
13
+ it "raises an error" do
14
+ invalid_path = File.dirname(__FILE__)
15
+ lambda {SourceControl.new(invalid_path)}.should raise_error(Errors::UnsupportedScmToolError)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe "#supported_systems" do
21
+ it "includes :git" do
22
+ SourceControl.supported_systems.should include(:git)
23
+ end
24
+ end
25
+
26
+ describe "#supported_system?" do
27
+ SourceControl.supported_systems.each do |scm_tool|
28
+ it "returns true for the string '#{scm_tool.to_s}'" do
29
+ SourceControl.supported_system?(scm_tool.to_s)
30
+ end
31
+
32
+ it "returns true for the symbol ':#{scm_tool.to_s}'" do
33
+ SourceControl.supported_system?(scm_tool.to_sym)
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#initial_commit_identifier" do
39
+ before(:each) do
40
+ git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
41
+ @repository = SourceControl.new(git_repo_path)
42
+ end
43
+
44
+ it "returns the identifer (sha/commit #) of the first commit" do
45
+ @repository.initial_commit_identifier.should == "a8b3e73fc5e4bc46bbdf5c1cab38cb2ce47ba2d0"
46
+ end
47
+ end
48
+
49
+ describe "#payload_between" do
50
+ before(:each) do
51
+ git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
52
+ @repository = SourceControl.new(git_repo_path)
53
+ end
54
+
55
+ it "returns a Hash containing the key ':commits'" do
56
+ @repository.payload_between.keys.should include(:commits)
57
+ end
58
+
59
+ it "is aliased to 'payload'" do
60
+ @repository.payload_between.keys.should == @repository.payload.keys
61
+ # FIXME: Improve this...not a complete test. Object ids getting in the way
62
+ @repository.payload_between[:commits].each_with_index do |commit, index|
63
+ commit[:identifier].should == @repository.payload[:commits][index][:identifier]
64
+ end
65
+ end
66
+
67
+ it "returns the commits in the same order a standard 'log view' of the repository would" do
68
+ first_commit = @repository.payload_between[:commits].last
69
+ first_commit[:identifier].should == "a8b3e73fc5e4bc46bbdf5c1cab38cb2ce47ba2d0"
70
+ end
71
+
72
+ context "the ':commits' key returned" do
73
+ context "contains a list of data for each commit" do
74
+ before(:each) do
75
+ @first_commit = @repository.payload_between[:commits].last
76
+ end
77
+
78
+ it "contains 'id', which is the 'sha' of the commit" do
79
+ @first_commit[:identifier].should == "a8b3e73fc5e4bc46bbdf5c1cab38cb2ce47ba2d0"
80
+ end
81
+
82
+ it "contains 'author', which points to the 'email' & the 'name' of the commit (in a Hash)" do
83
+ @first_commit[:author_email].should == "tkersten@obtiva.com"
84
+ @first_commit[:author_name].should == "Tom Kersten"
85
+ end
86
+
87
+ it "contains 'committer', which points to the 'email' & the 'name' of the commit (in a Hash)" do
88
+ @first_commit[:committer_email].should == "tkersten@obtiva.com"
89
+ @first_commit[:committer_name].should == "Tom Kersten"
90
+ end
91
+
92
+ it "contains 'message', which holds the full message of the commit" do
93
+ @first_commit[:message].should == "Initial commit with description of directory"
94
+ end
95
+
96
+ it "contains 'short_message', which holds the first line of the message of the commit" do
97
+ @first_commit[:short_message].should == "Initial commit with description of directory"
98
+ end
99
+
100
+ it "contains 'committed_date' of the commit" do
101
+ @first_commit[:committed_at].should == Chronic.parse("Sat May 09 08:52:14 -0500 2009")
102
+ end
103
+
104
+ it "contains 'authored_date' of the commit" do
105
+ @first_commit[:authored_at].should == Chronic.parse("Sat May 09 08:52:14 -0500 2009")
106
+ end
107
+
108
+ it "contains 'parent_commits' of the commit" do
109
+ @first_commit[:parent_identifiers].should_not be_nil
110
+ end
111
+
112
+ it "contains a 'line_additions' key" do
113
+ @first_commit[:line_additions].should_not be_nil
114
+ end
115
+
116
+ it "contains an 'line_deletions' key" do
117
+ @first_commit[:line_deletions].should_not be_nil
118
+ end
119
+
120
+ it "contains an 'line_total' key" do
121
+ @first_commit[:line_total].should_not be_nil
122
+ end
123
+
124
+ it "contains a 'affected_file_count' key" do
125
+ @first_commit[:affected_file_count].should_not be_nil
126
+ end
127
+ end
128
+ end
129
+
130
+ context "when 'from' is specified but the value is nil" do
131
+ it "defaults to the initial commit identifier of the repository" do
132
+ @repository.should_receive(:commits_between).with("a8b3e73fc5e4bc46bbdf5c1cab38cb2ce47ba2d0", anything()).and_return([])
133
+ @repository.payload_between(nil, "something")
134
+ end
135
+ end
136
+
137
+ context "when 'to' is specified but the value is nil" do
138
+ it "defaults to the 'HEAD' commit identifier of the repository" do
139
+ @repository.should_receive(:commits_between).with(anything(), "HEAD").and_return([])
140
+ @repository.payload_between("something", nil)
141
+ end
142
+ end
143
+
144
+ context "when there is no new information to send up" do
145
+ it "returns an empty object" do
146
+ @repository.payload_between("HEAD", "HEAD").should be_empty
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#public_key=" do
152
+ before(:each) do
153
+ git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
154
+ @public_key = "public_key_specified"
155
+ @repository = SourceControl.new(git_repo_path)
156
+ @project = Project.new(:public_key => @public_key)
157
+ end
158
+
159
+ it "stores the supplied public key in the SCM tool's repository-specific configuration" do
160
+ @repository.store_public_key(@public_key)
161
+ @repository.public_key.should == @public_key
162
+ end
163
+ end
164
+
165
+ describe "#public_key" do
166
+ before(:each) do
167
+ @public_key = "original_value"
168
+ git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
169
+ @repository = SourceControl.new(git_repo_path)
170
+ @repository.store_public_key(@public_key)
171
+ end
172
+
173
+ it "returns the current value of 'codometer.public_key' from the repository-specific configuration" do
174
+ @repository.public_key.should == @public_key
175
+ end
176
+ end
177
+
178
+ describe "#local_commit_identifier" do
179
+ before(:each) do
180
+ git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
181
+ @repository = SourceControl.new(git_repo_path)
182
+ end
183
+
184
+ it "returns the current commit identifier for the local repository" do
185
+ @repository.local_commit_identifier.should == "7dc0e73fea4625204b7c1e6a48e9a57025be4d7e"
186
+ end
187
+ end
188
+
189
+ describe "#path" do
190
+ before(:each) do
191
+ @git_repo_path = File.expand_path(File.dirname(__FILE__) + '/../fixtures/sample_project_dirs/git_repository')
192
+ @repository = SourceControl.new(@git_repo_path)
193
+ end
194
+
195
+ it "returns the full path to the .git directory of the repository" do
196
+ @repository.path.should == @git_repo_path + '/.git'
197
+ end
198
+ end
199
+ end