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
@@ -0,0 +1,2 @@
1
+ host: tomkersten@rubyforge.org
2
+ remote_dir: /var/www/gforge-projects/codefumes
data/cucumber.yml ADDED
@@ -0,0 +1,2 @@
1
+ default: --format pretty features
2
+ html_report: --format progress --format html --out=features_report.html features
@@ -0,0 +1,46 @@
1
+ Feature: Claiming a project
2
+ As the owner of a project, if I have decided I want to use the CodeFumes
3
+ service, I don't want to have to remember the public key for my project(s).
4
+ The gem must provide a simple method of "claiming" a project and associating
5
+ it with an account.
6
+
7
+
8
+ Scenario: Specified project does not exist on CodeFumes.com
9
+ Given valid user credentials have been stored in the CodeFumes config file
10
+ When I run "#{@bin_path}/fumes claim -p bad-public-key"
11
+ Then the output should contain "Not Found"
12
+ And the exit status should be 0
13
+
14
+ Scenario: Attempting to claim a project without having an API key entry in the CodeFumes config file
15
+ Given I have cloned and synchronized 1 project
16
+ When I claim the project
17
+ Then the output should contain instructions about storing your API key
18
+ And the exit status should be 3
19
+
20
+ Scenario: Attempting to claim a project with an invalid API key entry in the user's CodeFumes config file
21
+ Given invalid user credentials have been stored in the CodeFumes config file
22
+ And I have cloned and synchronized 1 project
23
+ When I claim the project
24
+ Then the output should contain "Denied"
25
+ And the exit status should be 0
26
+
27
+ Scenario: Claim a project using the key stored in a CodeFumes project directory
28
+ Given valid user credentials have been stored in the CodeFumes config file
29
+ And I have cloned and synchronized 1 project
30
+ When I claim the project
31
+ Then the output should contain "Success"
32
+ And the exit status should be 0
33
+
34
+ Scenario: Claiming one of multiple projects in your CodeFumes config file
35
+ Given valid user credentials have been stored in the CodeFumes config file
36
+ And I have cloned and synchronized 2 projects
37
+ When I claim the 1st project
38
+ Then the output should contain 1 successful claim message
39
+ And the exit status should be 0
40
+
41
+ Scenario: Claim all projects in your CodeFumes config file
42
+ Given valid user credentials have been stored in the CodeFumes config file
43
+ And I have cloned and synchronized 2 projects
44
+ And I run "#{@bin_path}/fumes claim -a"
45
+ Then the output should contain 2 successful claim messages
46
+ And the exit status should be 0
@@ -0,0 +1,32 @@
1
+ Feature: Deleting a project
2
+ The process of deleting a project must be both
3
+ available and simple in order to reduce the number
4
+ of barriers to testing out the service.
5
+
6
+
7
+ Scenario: The specified project does not exist on CodeFumes.com
8
+ When I run "#{@bin_path}/fumes delete -p bad-public-key"
9
+ Then the output should contain "Not Found"
10
+ And the exit status should be 0
11
+
12
+ Scenario: Attempting to delete a project without having an API key entry in the CodeFumes config file
13
+ Given I have cloned and synchronized 1 project
14
+ And I have claimed the project
15
+ When I delete the project
16
+ Then the output should contain 1 successful delete messages
17
+ And the exit status should be 0
18
+
19
+ Scenario: Deleting one of multiple projects in your CodeFumes config file
20
+ Given I have cloned and synchronized 2 projects
21
+ And I have claimed the 1st project
22
+ When I delete the 1st project
23
+ Then the output should contain 1 successful delete messages
24
+ And the exit status should be 0
25
+
26
+ Scenario: Releasing all projects in your CodeFumes config file
27
+ Given valid user credentials have been stored in the CodeFumes config file
28
+ And I have cloned and synchronized 2 projects
29
+ And I run "#{@bin_path}/fumes claim -a"
30
+ When I run "#{@bin_path}/fumes delete -a"
31
+ Then the output should contain 2 successful delete messages
32
+ And the exit status should be 0
@@ -0,0 +1,50 @@
1
+ Feature: Claiming a project
2
+ As the owner of a project, the process of relinquishing ownership
3
+ of a project must be both available and simple.
4
+
5
+
6
+ Scenario: Specified project does not exist on CodeFumes.com
7
+ Given valid user credentials have been stored in the CodeFumes config file
8
+ When I run "#{@bin_path}/fumes release -p bad-public-key"
9
+ Then the output should contain "Not Found"
10
+ And the exit status should be 0
11
+
12
+ Scenario: Attempting to claim a project without having an API key entry in the CodeFumes config file
13
+ And I have cloned and synchronized 1 project
14
+ And I have claimed the project
15
+ When I release the project
16
+ Then the output should contain instructions about storing your API key
17
+ And the exit status should be 3
18
+
19
+ Scenario: Attempting to release a project with an invalid API key entry in the user's CodeFumes config file
20
+ Given invalid user credentials have been stored in the CodeFumes config file
21
+ And I have cloned and synchronized 1 project
22
+ And I have claimed the project
23
+ And invalid user credentials have been stored in the CodeFumes config file
24
+ When I release the project
25
+ Then the output should contain "Denied"
26
+ And the exit status should be 0
27
+
28
+ Scenario: Releasing a project using the key stored in a CodeFumes project directory
29
+ Given valid user credentials have been stored in the CodeFumes config file
30
+ And I have cloned and synchronized 1 project
31
+ And I have claimed the project
32
+ When I release the project
33
+ Then the output should contain "Success"
34
+ And the exit status should be 0
35
+
36
+ Scenario: Releasing one of multiple projects in your CodeFumes config file
37
+ Given valid user credentials have been stored in the CodeFumes config file
38
+ And I have cloned and synchronized 2 projects
39
+ And I have claimed the 1st project
40
+ When I release the 1st project
41
+ Then the output should contain 1 successful release message
42
+ And the exit status should be 0
43
+
44
+ Scenario: Releasing all projects in your CodeFumes config file
45
+ Given valid user credentials have been stored in the CodeFumes config file
46
+ And I have cloned and synchronized 2 projects
47
+ And I run "#{@bin_path}/fumes claim -a"
48
+ When I run "#{@bin_path}/fumes release -a"
49
+ Then the output should contain 2 successful release messages
50
+ And the exit status should be 0
@@ -0,0 +1,98 @@
1
+ # still a super-hack...but at least it's not duplicated, right?
2
+ # ...
3
+ # ...right?
4
+ def output_message_qty(action)
5
+ combined_output.scan(/#{action}\.\.\.'.*': Success/).count
6
+ end
7
+
8
+ def clone_fixture_repo_into(dir_name)
9
+ Given "I run \"git clone git@github.com:cosyn/git_fixture_repository.git #{dir_name}\""
10
+ end
11
+
12
+ # TODO: Get a better way of testing this...output is horrible
13
+ Then /^the output should contain (\d+) successful claim message[s]?$/ do |count|
14
+ output_message_qty("Claiming").should == count.to_i
15
+ end
16
+
17
+ # TODO: Get a better way of testing this...output is horrible
18
+ Then /^the output should contain (\d+) successful release message[s]?$/ do |count|
19
+ output_message_qty("Releasing").should == count.to_i
20
+ end
21
+
22
+ # TODO: Get a better way of testing this...output is horrible
23
+ Then /^the output should contain (\d+) successful delete message[s]?$/ do |count|
24
+ output_message_qty("Deleting").should == count.to_i
25
+ end
26
+
27
+ Then /^the output should contain instructions about storing your API key$/ do
28
+ Then "the output should contain \"fumes setup\""
29
+ end
30
+
31
+ Given /^I have cloned and synchronized (\d+) project[s]?$/ do |qty|
32
+ (1..qty.to_i).each do |index|
33
+ dir_name = "project_#{index}"
34
+ clone_fixture_repo_into(dir_name)
35
+ And "I synchronize project #{index}"
36
+ end
37
+ end
38
+
39
+ Given /^I have cloned (\d+) project[s]?$/ do |qty|
40
+ (1..qty.to_i).each do |index|
41
+ dir_name = "project_#{index}"
42
+ clone_fixture_repo_into(dir_name)
43
+ end
44
+ end
45
+
46
+ When /^I (?:have )?synchronize[d]? project (\d+)$/ do |index|
47
+ When "I cd to \"project_#{index}/\""
48
+ And "I run \"#{@bin_path}/fumes sync\""
49
+ And "I cd to \"../\""
50
+ end
51
+
52
+ # convenience step...assumes only one project
53
+ When /^I (?:have)?synchronize[d]? the project$/ do
54
+ When "I synchronize project 1"
55
+ end
56
+
57
+ Given /^I (?:have )?claim(?:ed)? the (\d+)st project$/ do |index|
58
+ dir_name = "project_#{index}"
59
+ And "I cd to \"#{dir_name}/\""
60
+ And "I run \"#{@bin_path}/fumes claim\""
61
+ And "I cd to \"../\""
62
+ end
63
+
64
+ # convenience step...assumes only one project
65
+ Given /^I (?:have )?claim(?:ed)? the project$/ do
66
+ Given "I have claimed the 1st project"
67
+ end
68
+
69
+ Given /^I (?:have )?release[d]? the (\d+)(?:st|nd|rd|th) project$/ do |index|
70
+ dir_name = "project_#{index}"
71
+ And "I cd to \"#{dir_name}/\""
72
+ And "I run \"#{@bin_path}/fumes release\""
73
+ And "I cd to \"../\""
74
+ end
75
+
76
+ # TODO: Refactor w/ other actions
77
+ Given /^I (?:have )?delete[d]? the (\d+)(?:st|nd|rd|th) project$/ do |index|
78
+ dir_name = "project_#{index}"
79
+ And "I cd to \"#{dir_name}/\""
80
+ And "I run \"#{@bin_path}/fumes delete\""
81
+ And "I cd to \"../\""
82
+ end
83
+
84
+ # convenience step...assumes only one project
85
+ Given /^I (?:have )?delete(?:ed)? the project$/ do
86
+ Given "I have deleted the 1st project"
87
+ end
88
+
89
+
90
+ # convenience step...assumes only one project
91
+ Given /^I (?:have )?release[d]? the project$/ do
92
+ Given "I have released the 1st project"
93
+ end
94
+
95
+ Then /^the API key in the config file should be ("[^"]*"|cleared)$/ do |api_key_value|
96
+ expected_value = api_key_value == 'cleared' ? nil : api_key_value.gsub(/"/,'')
97
+ ConfigFile.api_key.should == expected_value
98
+ end
@@ -0,0 +1,168 @@
1
+ Given /^this project is active project folder/ do
2
+ @active_project_folder = File.expand_path(File.dirname(__FILE__) + "/../..")
3
+ end
4
+
5
+ Given /^env variable \$([\w_]+) set to "(.*)"/ do |env_var, value|
6
+ ENV[env_var] = value
7
+ end
8
+
9
+ Given /"(.*)" folder is deleted/ do |folder|
10
+ in_project_folder { FileUtils.rm_rf folder }
11
+ end
12
+
13
+ When /^I invoke "(.*)" generator with arguments "(.*)"$/ do |generator, arguments|
14
+ @stdout = StringIO.new
15
+ in_project_folder do
16
+ if Object.const_defined?("APP_ROOT")
17
+ APP_ROOT.replace(FileUtils.pwd)
18
+ else
19
+ APP_ROOT = FileUtils.pwd
20
+ end
21
+ run_generator(generator, arguments.split(' '), SOURCES, :stdout => @stdout)
22
+ end
23
+ File.open(File.join(@tmp_root, "generator.out"), "w") do |f|
24
+ @stdout.rewind
25
+ f << @stdout.read
26
+ end
27
+ end
28
+
29
+ When /^I run executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
30
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
31
+ in_project_folder do
32
+ system "#{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
33
+ end
34
+ end
35
+
36
+ When /^I run project executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
37
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
38
+ in_project_folder do
39
+ system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
40
+ end
41
+ end
42
+
43
+ When /^I run local executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
44
+ @stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
45
+ executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin", executable))
46
+ in_project_folder do
47
+ system "ruby #{executable} #{arguments} > #{@stdout} 2> #{@stdout}"
48
+ end
49
+ end
50
+
51
+ When /^I invoke task "rake (.*)"/ do |task|
52
+ @stdout = File.expand_path(File.join(@tmp_root, "tests.out"))
53
+ in_project_folder do
54
+ system "rake #{task} --trace > #{@stdout} 2> #{@stdout}"
55
+ end
56
+ end
57
+
58
+ Then /^folder "(.*)" (is|is not) created/ do |folder, is|
59
+ in_project_folder do
60
+ File.exists?(folder).should(is == 'is' ? be_true : be_false)
61
+ end
62
+ end
63
+
64
+ Then /^file "(.*)" (is|is not) created/ do |file, is|
65
+ in_project_folder do
66
+ File.exists?(file).should(is == 'is' ? be_true : be_false)
67
+ end
68
+ end
69
+
70
+ Then /^file with name matching "(.*)" is created/ do |pattern|
71
+ in_project_folder do
72
+ Dir[pattern].should_not be_empty
73
+ end
74
+ end
75
+
76
+ Then /^file "(.*)" contents (does|does not) match \/(.*)\// do |file, does, regex|
77
+ in_project_folder do
78
+ actual_output = File.read(file)
79
+ (does == 'does') ?
80
+ actual_output.should(match(/#{regex}/)) :
81
+ actual_output.should_not(match(/#{regex}/))
82
+ end
83
+ end
84
+
85
+ Then /gem file "(.*)" and generated file "(.*)" should be the same/ do |gem_file, project_file|
86
+ File.exists?(gem_file).should be_true
87
+ File.exists?(project_file).should be_true
88
+ gem_file_contents = File.read(File.dirname(__FILE__) + "/../../#{gem_file}")
89
+ project_file_contents = File.read(File.join(@active_project_folder, project_file))
90
+ project_file_contents.should == gem_file_contents
91
+ end
92
+
93
+ Then /^(does|does not) invoke generator "(.*)"$/ do |does_invoke, generator|
94
+ actual_output = File.read(@stdout)
95
+ does_invoke == "does" ?
96
+ actual_output.should(match(/dependency\s+#{generator}/)) :
97
+ actual_output.should_not(match(/dependency\s+#{generator}/))
98
+ end
99
+
100
+ Then /help options "(.*)" and "(.*)" are displayed/ do |opt1, opt2|
101
+ actual_output = File.read(@stdout)
102
+ actual_output.should match(/#{opt1}/)
103
+ actual_output.should match(/#{opt2}/)
104
+ end
105
+
106
+ Then /^I should see "([^\"]*)"$/ do |text|
107
+ actual_output = File.read(@stdout)
108
+ actual_output.should contain(text)
109
+ end
110
+
111
+ Then /^I should see$/ do |text|
112
+ actual_output = File.read(@stdout)
113
+ actual_output.should contain(text)
114
+ end
115
+
116
+ Then /^I should not see$/ do |text|
117
+ actual_output = File.read(@stdout)
118
+ actual_output.should_not contain(text)
119
+ end
120
+
121
+ Then /^I should see exactly$/ do |text|
122
+ actual_output = File.read(@stdout)
123
+ actual_output.should == text
124
+ end
125
+
126
+ Then /^I should see all (\d+) tests pass/ do |expected_test_count|
127
+ expected = %r{^#{expected_test_count} tests, \d+ assertions, 0 failures, 0 errors}
128
+ actual_output = File.read(@stdout)
129
+ actual_output.should match(expected)
130
+ end
131
+
132
+ Then /^I should see all (\d+) examples pass/ do |expected_test_count|
133
+ expected = %r{^#{expected_test_count} examples?, 0 failures}
134
+ actual_output = File.read(@stdout)
135
+ actual_output.should match(expected)
136
+ end
137
+
138
+ Then /^yaml file "(.*)" contains (\{.*\})/ do |file, yaml|
139
+ in_project_folder do
140
+ yaml = eval yaml
141
+ YAML.load(File.read(file)).should == yaml
142
+ end
143
+ end
144
+
145
+ Then /^Rakefile can display tasks successfully/ do
146
+ @stdout = File.expand_path(File.join(@tmp_root, "rakefile.out"))
147
+ in_project_folder do
148
+ system "rake -T > #{@stdout} 2> #{@stdout}"
149
+ end
150
+ actual_output = File.read(@stdout)
151
+ actual_output.should match(/^rake\s+\w+\s+#\s.*/)
152
+ end
153
+
154
+ Then /^task "rake (.*)" is executed successfully/ do |task|
155
+ @stdout.should_not be_nil
156
+ actual_output = File.read(@stdout)
157
+ actual_output.should_not match(/^Don't know how to build task '#{task}'/)
158
+ actual_output.should_not match(/Error/i)
159
+ end
160
+
161
+ Then /^gem spec key "(.*)" contains \/(.*)\// do |key, regex|
162
+ in_project_folder do
163
+ gem_file = Dir["pkg/*.gem"].first
164
+ gem_spec = Gem::Specification.from_yaml(`gem spec #{gem_file}`)
165
+ spec_value = gem_spec.send(key.to_sym)
166
+ spec_value.to_s.should match(/#{regex}/)
167
+ end
168
+ end
@@ -0,0 +1,19 @@
1
+ Given /^I am in the CodeFumes gem's root directory$/ do
2
+ cd("/" + File.expand_path(__FILE__) + "/../")
3
+ end
4
+
5
+ Given /^(in)?valid user credentials have been stored in the CodeFumes config file$/ do |invalid_text|
6
+ # Fragile, as this user is not set up to be re-added after wiping test db on CodeFumes.com
7
+ # TODO: update deployment for test site to reload this information:
8
+ # login: test-user
9
+ # password: password
10
+ # email: test.user@codefumes.com
11
+ # api_key: eX2Kue_6YoEIWAvV1VCx
12
+
13
+ unless ConfigFile.path.match(/#{File.expand_path(@tmp_root)}/)
14
+ raise "###NOTE### ConfigFile path not set to use temp file. Check CODEFUMES_CONFIG_FILE settings!"
15
+ end
16
+
17
+ api_key = invalid_text.blank? ? 'eX2Kue_6YoEIWAvV1VCx' : 'invalid-key-here'
18
+ ConfigFile.save_credentials(api_key)
19
+ end
@@ -0,0 +1,41 @@
1
+ Feature: Storing a User's API key
2
+ Adding an API key to a user's CodeFumes config file allows
3
+ them to perform actions which require user-authentication,
4
+ such as associating a project with an account.
5
+
6
+
7
+ Scenario: Issuing 'api-key' without an argument
8
+ When I run "#{@bin_path}/fumes api-key"
9
+ Then it should fail with:
10
+ """
11
+ No API key specified
12
+ """
13
+ And the exit status should be 5
14
+
15
+ Scenario: Issuing 'api-key' with an argument
16
+ When I run "#{@bin_path}/fumes api-key userkey"
17
+ Then it should pass with:
18
+ """
19
+ Your API key has been saved to your CodeFumes config file
20
+ """
21
+ And the API key in the config file should be "userkey"
22
+ And the exit status should be 0
23
+
24
+ Scenario: Issuing 'api-key' with the --clear flag
25
+ When I run "#{@bin_path}/fumes api-key --clear"
26
+ Then it should pass with:
27
+ """
28
+ Your API key has been removed from your CodeFumes config file
29
+ """
30
+ And the API key in the config file should be cleared
31
+ And the exit status should be 0
32
+
33
+ Scenario: Issuing 'api-key' with the --clear flag and an argument
34
+ When I run "#{@bin_path}/fumes api-key userkey1"
35
+ And I run "#{@bin_path}/fumes api-key --clear userkey2"
36
+ Then it should pass with:
37
+ """
38
+ Your API key has been removed from your CodeFumes config file
39
+ """
40
+ And the API key in the config file should be cleared
41
+ And the exit status should be 0