fisheye-crucible 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ === 0.0.1 2010-07-15
2
+
3
+ * Added support for Fisheye/Crucible's Legacy API. Methods supported:
4
+ * login
5
+ * logout
6
+ * fisheye_version
7
+ * crucible_version
8
+ * repositories
9
+ * paths
10
+ * revision
11
+ * tags
12
+ * path_history
13
+ * changeset
14
+ * changesets
15
+ * query
@@ -0,0 +1,30 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ features/authenticate.feature
7
+ features/client_legacy.feature
8
+ features/development.feature
9
+ features/step_definitions/authenticate_steps.rb
10
+ features/step_definitions/client_legacy_steps.rb
11
+ features/step_definitions/common_steps.rb
12
+ features/support/common.rb
13
+ features/support/config.yaml
14
+ features/support/env.rb
15
+ features/support/hooks.rb
16
+ features/support/matchers.rb
17
+ lib/fisheye-crucible.rb
18
+ lib/fisheye-crucible/client.rb
19
+ lib/fisheye-crucible/client/legacy.rb
20
+ lib/fisheye-crucible/type_converter.rb
21
+ lib/fisheye_crucible_exception.rb
22
+ script/console
23
+ script/destroy
24
+ script/generate
25
+ spec/client/legacy_spec.rb
26
+ spec/client_spec.rb
27
+ spec/fisheye-crucible_spec.rb
28
+ spec/spec.opts
29
+ spec/spec_helper.rb
30
+ tasks/rspec.rake
@@ -0,0 +1,6 @@
1
+
2
+ Thanks for installing fisheye-crucible, I hope you get some good use out of it.
3
+
4
+ For more information on fisheye-crucible, see http://github.com/turboladen/fisheye-crucible
5
+
6
+
@@ -0,0 +1,75 @@
1
+ = fisheye-crucible
2
+
3
+ * http://github.com/turboladen/fisheye-crucible
4
+
5
+ == DESCRIPTION:
6
+
7
+ This gem is a wrapper around the REST API for Atlassian's {Fisheye}[http://www.atlassian.com/software/fisheye/] and {Crucible}[http://www.atlassian.com/software/crucible/]. It currently only provides access to their {legacy API}[http://confluence.atlassian.com/display/FECRUDEV/FishEye+Legacy+Remote+API];
8
+ wrapping of the current API is in the works.
9
+
10
+ I want to keep the dependency list low, so at this point XML parsing is all done
11
+ with REXML.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Legacy API (<=1.6.x) calls work
16
+ * Current API (2.x) calls no workie (yet!), although 2.x installs with legacy support turned on can use the legacy API just fine.
17
+ * Access methods via Ruby style method calls _or_ the API function name:
18
+
19
+ Ruby style:
20
+
21
+ fc.repositories
22
+
23
+ Fisheye/Crucible API style:
24
+
25
+ fc.listRepositories
26
+
27
+
28
+ == SYNOPSIS:
29
+
30
+ A quick example:
31
+
32
+ require 'fisheye-crucible/client/legacy'
33
+
34
+ server = 'http://sandbox.fisheye.atlassian.com'
35
+ fc = FisheyeCrucible::Client::Legacy.new(server)
36
+ fc.login 'guy', 'smiley'
37
+ fc.fisheye_version # => "2.2.4"
38
+ fc.repositories # => ['antlr', 'google-guice', 'rails']
39
+
40
+
41
+ == REQUIREMENTS:
42
+
43
+ * Ruby
44
+ * 1.8.7
45
+ * 1.9.1
46
+ * rest-client
47
+
48
+ == INSTALL:
49
+
50
+ * (sudo) gem install fisheye-crucible
51
+
52
+ == LICENSE:
53
+
54
+ (The MIT License)
55
+
56
+ Copyright (c) 2010 Steve Loveless
57
+
58
+ Permission is hereby granted, free of charge, to any person obtaining
59
+ a copy of this software and associated documentation files (the
60
+ 'Software'), to deal in the Software without restriction, including
61
+ without limitation the rights to use, copy, modify, merge, publish,
62
+ distribute, sublicense, and/or sell copies of the Software, and to
63
+ permit persons to whom the Software is furnished to do so, subject to
64
+ the following conditions:
65
+
66
+ The above copyright notice and this permission notice shall be
67
+ included in all copies or substantial portions of the Software.
68
+
69
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
70
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
72
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
73
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
74
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
75
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,124 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/fisheye-crucible'
6
+ require 'metric_fu'
7
+
8
+ Hoe.plugin :newgem
9
+ Hoe.plugin :yard
10
+ # Hoe.plugin :website
11
+ Hoe.plugin :cucumberfeatures
12
+ Hoe.plugin :rubyforge
13
+
14
+ # Gets the description from the main README file
15
+ def get_descr_from_readme
16
+ paragraph_count = 0
17
+ File.readlines('README.rdoc', '').each do |paragraph|
18
+ paragraph_count += 1
19
+ if paragraph_count == 4
20
+ return paragraph
21
+ end
22
+ end
23
+ end
24
+
25
+ # Generate all the Rake tasks
26
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
27
+ $hoe = Hoe.spec 'fisheye-crucible' do
28
+ self.summary = "REST wrapper around Atlassian's Fisheye/Crucible's API"
29
+ self.developer 'Steve Loveless', 'steve.loveless@gmail.com'
30
+ self.post_install_message = File.readlines 'PostInstall.txt'
31
+ self.rubyforge_name = self.name
32
+ self.version = FisheyeCrucible::VERSION
33
+ self.url = FisheyeCrucible::WWW
34
+ self.description = get_descr_from_readme
35
+ self.readme_file = 'README.rdoc'
36
+ self.history_file = 'History.txt'
37
+ self.rspec_options = ['--color', '--format', 'specdoc']
38
+ self.extra_deps += [
39
+ ['rest-client']
40
+ ]
41
+ self.extra_dev_deps += [
42
+ ['rspec'],
43
+ ['yard'],
44
+ ['hoe-yard'],
45
+ ['cucumber']
46
+ ]
47
+ self.test_globs = 'spec/*.rb'
48
+
49
+ # Extra Yard options
50
+ self.yard_title = "#{self.name} Documentation (#{self.version})"
51
+ self.yard_markup = :rdoc
52
+ self.yard_opts += ['--main', self.readme_file]
53
+ self.yard_opts += ['--output-dir', 'doc']
54
+ self.yard_opts += ['--private']
55
+ self.yard_opts += ['--protected']
56
+ self.yard_opts += ['--verbose']
57
+ self.yard_opts += ['--files',
58
+ ['Manifest.txt', 'History.txt']
59
+ ]
60
+ end
61
+
62
+ #-------------------------------------------------------------------------------
63
+ # Overwrite the :clobber_docs Rake task so that it doesn't destroy our docs
64
+ # directory.
65
+ #-------------------------------------------------------------------------------
66
+ class Rake::Task
67
+ def overwrite(&block)
68
+ @actions.clear
69
+ enhance(&block)
70
+ end
71
+ end
72
+
73
+ Rake::Task[:clobber_docs].overwrite do
74
+ end
75
+
76
+ # Now define the tasks
77
+ require 'newgem/tasks'
78
+ #Dir['tasks/**/*.rake'].each { |t| load t }
79
+
80
+ # TODO - want other tests/tasks run by default? Add them to the list
81
+ # remove_task :default
82
+ # task :default => [:spec, :features]
83
+
84
+ MetricFu::Configuration.run do |config|
85
+ #define which metrics you want to use
86
+ #config.metrics = [:churn, :flog, :flay, :reek, :roodi, :rcov, :stats]
87
+ config.metrics = [:churn, :flog, :reek, :roodi, :rcov, :stats]
88
+ #config.graphs = [:flog, :flay, :reek, :roodi]
89
+ config.graphs = [:flog, :reek, :roodi]
90
+ config.flay = { :dirs_to_flay => ['lib/fisheye-crucible'],
91
+ :minimum_score => 10 }
92
+ config.flog = { :dirs_to_flog => ['lib/fisheye-crucible'] }
93
+ config.reek = { :dirs_to_reek => ['lib/fisheye-crucible'] }
94
+ config.roodi = { :dirs_to_roodi => ['lib/fisheye-crucible'] }
95
+ config.churn = { :start_date => "1 year ago", :minimum_churn_count => 10}
96
+ config.rcov = { :environment => 'test',
97
+ :test_files => ['spec/*_spec.rb',
98
+ 'spec/**/*_spec.rb'],
99
+ :rcov_opts => ["--sort coverage",
100
+ "--no-html",
101
+ "--text-coverage",
102
+ "--no-color",
103
+ "--profile",
104
+ "--exclude /gems/,/Library/"]}
105
+ config.graph_engine = :bluff
106
+ end
107
+
108
+ STATS_DIRECTORIES = [
109
+ %w(Library lib/),
110
+ %w(Unit\ tests spec/)
111
+ ].collect { |name, dir| [ name, "#{dir}" ] }.select { |name, dir| File.directory?(dir) }
112
+
113
+ begin
114
+ gem 'rails'
115
+
116
+ desc "Report code statistics (KLOCs, etc) from the application"
117
+ task :stats do
118
+ require 'code_statistics'
119
+ CodeStatistics.new(*STATS_DIRECTORIES).to_s
120
+ end
121
+ rescue LoadError
122
+ puts "Rails is needed in order to check stats."
123
+ end
124
+
@@ -0,0 +1,28 @@
1
+ Feature: Authenticate as a Fisheye/Crucible user
2
+ As I Fisheye/Crucible user
3
+ I want to be able to login
4
+ So that I can programmatically interact with Fisheye and Crucible
5
+
6
+ @negative
7
+ Scenario: Login with a bad password
8
+ Given a valid user, "gemtest" and password "gemtest1"
9
+ When I login with that user's credentials
10
+ Then I receive an authentication error
11
+
12
+ @positive
13
+ Scenario: Login as a valid user
14
+ Given a valid user, "gemtest" and password "gemtest"
15
+ When I login with that user's credentials
16
+ Then I receive a token back from the server
17
+
18
+ @positive
19
+ Scenario: Logout from valid session
20
+ Given I have logged in
21
+ When I logout
22
+ Then I receive confirmation that I have logged out
23
+
24
+ @negative
25
+ Scenario: Logout when not logged in
26
+ Given I have not logged in
27
+ When I logout
28
+ Then I receive an error telling me I'm not logged in
@@ -0,0 +1,73 @@
1
+ Feature: Client to the legacy API
2
+ As a user
3
+ I want to be able to call the legacy Fisheye/Crucible API
4
+ So that I can find out information on my server
5
+
6
+ @positive
7
+ Scenario: fisheyeVersion (==fisheye_version)
8
+ Given I have logged in
9
+ When I call "fisheyeVersion"
10
+ Then I should receive a "String"
11
+ And that String should be in the form x.x.x
12
+
13
+ @positive
14
+ Scenario: crucibleVersion (==crucible_version)
15
+ Given I have logged in
16
+ When I call "crucibleVersion"
17
+ Then I should receive a "String"
18
+ And that String should be in the form x.x.x
19
+
20
+ @positive
21
+ Scenario: listPaths (==list_paths_from)
22
+ Given I have logged in
23
+ And I have a list of repositories
24
+ When I call "listPaths" for the first repository
25
+ Then I should receive an "Array"
26
+ And that Array should contain Strings
27
+
28
+ Scenario Outline: Make method calls
29
+ Given I have logged in
30
+ When I call "<api_method>" with parameters "<parameters>"
31
+ Then I should receive a "<return_type>"
32
+
33
+ @positive
34
+ Scenarios: Calls return proper types
35
+ | api_method | parameters | return_type |
36
+ | fisheyeVersion | | String |
37
+ | crucibleVersion | | String |
38
+ | listRepositories | | Array |
39
+ | listPaths | 'antlr' | Hash |
40
+ | listPaths | 'antlr','tool' | Hash |
41
+ | getRevision | 'antlr','BUILD.txt',5847 | Hash |
42
+ | pathHistory | 'antlr','BUILD.txt' | Array |
43
+ | getChangeset | 'antlr',5847 | Hash |
44
+ | listChangesets | 'antlr' | Hash |
45
+ | listChangesets | 'antlr','tool' | Hash |
46
+ | listChangesets | 'antlr','tool',1 | Hash |
47
+ | listChangesets | 'antlr','tool',1,'2008-07-05T07:08:16-07:00'| Hash|
48
+ | listChangesets | 'antlr','tool',1,'2008-07-05T07:08:16-07:00', '2009-07-05T07:08:16-07:00'| Hash |
49
+ | query | 'antlr','select revisions from dir /tool' | Array |
50
+ | query | 'antlr','select revisions from dir /tool return path' | Array |
51
+ | query | 'antlr','select revisions from dir /tool return path as test' | Array |
52
+
53
+ @negative
54
+ Scenario Outline: Raise exceptions
55
+ Given I have logged in
56
+ When I call "<api_method>" with parameters "<parameters>"
57
+ Then I should receive an exception of type "<exception_type>"
58
+
59
+ Scenarios: Calls throw exception when passed invalid parameters
60
+ | api_method | parameters | exception_type |
61
+ | fisheyeVersion | 'test' | ArgumentError |
62
+ | crucibleVersion | 'test' | ArgumentError |
63
+ | listRepositories | 'test' | ArgumentError |
64
+ | listPaths | 'blahblahblah' | FisheyeCrucibleError |
65
+ | listPaths | 'antlr','blahblahblah' | FisheyeCrucibleError |
66
+ | getRevision | 'blahblahblah','BUILD.txt',5847 | FisheyeCrucibleError |
67
+ | getRevision | 'antlr','blahblahblah',5847 | FisheyeCrucibleError |
68
+ | getRevision | 'antlr','BUILD.txt',9999999 | FisheyeCrucibleError |
69
+ | getRevision | 'antlr','BUILD.txt','blahblahblah' | RestClient::InternalServerError |
70
+ | pathHistory | 'blahblahblah','BUILD.txt' | FisheyeCrucibleError |
71
+ | pathHistory | 'antlr','blahblahblah' | FisheyeCrucibleError |
72
+ | pathHistory | 'antlr',123456789 | FisheyeCrucibleError |
73
+
@@ -0,0 +1,13 @@
1
+ Feature: Development processes of newgem itself (rake tasks)
2
+
3
+ As a Newgem maintainer or contributor
4
+ I want rake tasks to maintain and release the gem
5
+ So that I can spend time on the tests and code, and not excessive time on maintenance processes
6
+
7
+ Scenario: Generate RubyGem
8
+ Given this project is active project folder
9
+ And "pkg" folder is deleted
10
+ When I invoke task "rake gem"
11
+ Then folder "pkg" is created
12
+ And file with name matching "pkg/*.gem" is created else you should run "rake manifest" to fix this
13
+ And gem spec key "rdoc_options" contains /(--mainREADME.rdoc|\[\"--main\", \"README.rdoc\"\])/
@@ -0,0 +1,35 @@
1
+ require 'net/ping/tcp'
2
+
3
+ Given /^a valid user, "(\w+)" and password "(.+)"$/ do |user, password|
4
+ @user = user
5
+ @password = password
6
+ end
7
+
8
+ When /^I login with that user\'s credentials$/ do
9
+ @login = lambda { @fc.login(@user, @password) }
10
+ @login.should_not be_nil
11
+ end
12
+
13
+ Then /^I receive a token back from the server$/ do
14
+ @token = @login.call
15
+ @token.class.should.eql? 'String'
16
+ @token.should match(/^\w+:\d{3,}:\w{32}$/)
17
+ end
18
+
19
+ Then /^I receive an authentication error$/ do
20
+ @login.should raise_error(FisheyeCrucibleError)
21
+ end
22
+
23
+ When /^I logout$/ do
24
+ @logout = lambda { @fc.logout }
25
+ @logout.should_not be_nil
26
+ end
27
+
28
+ Then /^I receive confirmation that I have logged out$/ do
29
+ result = @logout.call
30
+ result.should be_true
31
+ end
32
+
33
+ Then /^I receive an error telling me I'm not logged in$/ do
34
+ @logout.should raise_error(FisheyeCrucibleError)
35
+ end
@@ -0,0 +1,28 @@
1
+ When /^I call "([^"]*)" with parameters "([^"]*)"$/ do |api_method, parameters|
2
+ @method = lambda { eval("@fc.#{api_method}(#{parameters})") }
3
+ @method.should_not be_nil
4
+ end
5
+
6
+ Then /^I should receive an? "([^"]*)"$/ do |result_type|
7
+ result = @method.call
8
+ result.class.should == eval("#{result_type}")
9
+ end
10
+
11
+ Then /^I should receive an exception of type "([^"]*)"$/ do |exception_type|
12
+ result = @method.should raise_error(eval("#{exception_type}"))
13
+ end
14
+
15
+ Then /^that String should be in the form x\.x\.x$/ do
16
+ @result.should match(/\d\.\d(\.\d)?/)
17
+ end
18
+
19
+ Then /^that Array should contain Strings$/ do
20
+ @result.each do |r|
21
+ r.class.should == eval('String')
22
+ end
23
+ end
24
+
25
+ Given /^I have a list of repositories$/ do
26
+ @repos = @fc.repositories
27
+ @result.should_not be_empty
28
+ 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