rake-funnel 0.0.1.pre
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/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +21 -0
- data/Gemfile +29 -0
- data/Guardfile +24 -0
- data/README.md +29 -0
- data/Rakefile +77 -0
- data/build.cmd +30 -0
- data/bundle.cmd +26 -0
- data/config/.gitignore +1 -0
- data/config/.local.yaml.example +9 -0
- data/config/default.yaml +5 -0
- data/config/dev.yaml +0 -0
- data/config/production.yaml +3 -0
- data/lib/rake/funnel/ambiguous_file_error.rb +29 -0
- data/lib/rake/funnel/execution_error.rb +26 -0
- data/lib/rake/funnel/extensions/camel_case.rb +19 -0
- data/lib/rake/funnel/extensions/common_path.rb +52 -0
- data/lib/rake/funnel/extensions/disable_colors.rb +27 -0
- data/lib/rake/funnel/extensions/rexml.rb +23 -0
- data/lib/rake/funnel/extensions/shell.rb +56 -0
- data/lib/rake/funnel/framework.rb +15 -0
- data/lib/rake/funnel/integration/progress_report.rb +70 -0
- data/lib/rake/funnel/integration/sync_output.rb +8 -0
- data/lib/rake/funnel/integration/teamcity/nunit_plugin.rb +59 -0
- data/lib/rake/funnel/integration/teamcity/progress_report.rb +33 -0
- data/lib/rake/funnel/integration/teamcity/service_messages.rb +40 -0
- data/lib/rake/funnel/integration/teamcity/teamcity.rb +15 -0
- data/lib/rake/funnel/integration/teamcity.rb +5 -0
- data/lib/rake/funnel/support/finder.rb +51 -0
- data/lib/rake/funnel/support/mapper.rb +81 -0
- data/lib/rake/funnel/support/mapper_styles/default.rb +31 -0
- data/lib/rake/funnel/support/mapper_styles/msbuild.rb +33 -0
- data/lib/rake/funnel/support/mapper_styles/msdeploy.rb +47 -0
- data/lib/rake/funnel/support/mapper_styles/nunit.rb +33 -0
- data/lib/rake/funnel/support/mono.rb +17 -0
- data/lib/rake/funnel/support/patch.rb +37 -0
- data/lib/rake/funnel/support/template_engine.rb +26 -0
- data/lib/rake/funnel/support/which.rb +15 -0
- data/lib/rake/funnel/tasks/bin_path.rb +34 -0
- data/lib/rake/funnel/tasks/copy.rb +54 -0
- data/lib/rake/funnel/tasks/environments.rb +74 -0
- data/lib/rake/funnel/tasks/environments_support/loader.rb +37 -0
- data/lib/rake/funnel/tasks/msbuild.rb +52 -0
- data/lib/rake/funnel/tasks/msbuild_support/build_tool.rb +28 -0
- data/lib/rake/funnel/tasks/msdeploy.rb +58 -0
- data/lib/rake/funnel/tasks/msdeploy_support/registry_patch.rb +84 -0
- data/lib/rake/funnel/tasks/nunit.rb +46 -0
- data/lib/rake/funnel/tasks/paket.rb +39 -0
- data/lib/rake/funnel/tasks/quick_template.rb +45 -0
- data/lib/rake/funnel/tasks/side_by_side_specs.rb +33 -0
- data/lib/rake/funnel/tasks/side_by_side_specs_support/remover.rb +62 -0
- data/lib/rake/funnel/tasks/timing.rb +100 -0
- data/lib/rake/funnel/tasks/timing_support/report.rb +89 -0
- data/lib/rake/funnel/tasks/timing_support/statistics.rb +26 -0
- data/lib/rake/funnel/tasks/zip.rb +66 -0
- data/lib/rake/funnel/version.rb +5 -0
- data/lib/rake/funnel.rb +7 -0
- data/rake-funnel.gemspec +28 -0
- data/spec/rake/funnel/execution_error_spec.rb +67 -0
- data/spec/rake/funnel/extensions/camel_case_spec.rb +17 -0
- data/spec/rake/funnel/extensions/common_path_spec.rb +56 -0
- data/spec/rake/funnel/extensions/disable_colors_spec.rb +33 -0
- data/spec/rake/funnel/extensions/rexml_spec.rb +20 -0
- data/spec/rake/funnel/extensions/shell_spec.rb +237 -0
- data/spec/rake/funnel/integration/progress_report_spec.rb +149 -0
- data/spec/rake/funnel/integration/sync_output_spec.rb +16 -0
- data/spec/rake/funnel/integration/teamcity/nunit_plugin_spec.rb +112 -0
- data/spec/rake/funnel/integration/teamcity/progress_report_spec.rb +174 -0
- data/spec/rake/funnel/integration/teamcity/service_messages_spec.rb +136 -0
- data/spec/rake/funnel/integration/teamcity/teamcity_spec.rb +34 -0
- data/spec/rake/funnel/support/finder_spec.rb +210 -0
- data/spec/rake/funnel/support/mapper_spec.rb +87 -0
- data/spec/rake/funnel/support/mapper_styles/msdeploy_spec.rb +222 -0
- data/spec/rake/funnel/support/mapper_styles/nunit_spec.rb +25 -0
- data/spec/rake/funnel/support/mapper_styles/styles_spec.rb +214 -0
- data/spec/rake/funnel/support/mono_spec.rb +57 -0
- data/spec/rake/funnel/support/patch_spec.rb +108 -0
- data/spec/rake/funnel/support/template_engine_spec.rb +65 -0
- data/spec/rake/funnel/support/which_spec.rb +65 -0
- data/spec/rake/funnel/tasks/bin_path_spec.rb +40 -0
- data/spec/rake/funnel/tasks/copy_spec.rb +101 -0
- data/spec/rake/funnel/tasks/environments_spec.rb +237 -0
- data/spec/rake/funnel/tasks/environments_support/loader_spec.rb +114 -0
- data/spec/rake/funnel/tasks/msbuild_spec.rb +91 -0
- data/spec/rake/funnel/tasks/msbuild_support/build_tool_spec.rb +21 -0
- data/spec/rake/funnel/tasks/msdeploy_spec.rb +243 -0
- data/spec/rake/funnel/tasks/msdeploy_support/registry_patch_spec.rb +139 -0
- data/spec/rake/funnel/tasks/nunit_spec.rb +76 -0
- data/spec/rake/funnel/tasks/paket_spec.rb +184 -0
- data/spec/rake/funnel/tasks/quick_template_spec.rb +89 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_spec.rb +58 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/FooCode.cs +0 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/FooSpecs.cs +0 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/Sample.csproj +28 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/Specs.cs +0 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/subdir/BarCode.cs +0 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/example/subdir/BarSpecs.cs +0 -0
- data/spec/rake/funnel/tasks/side_by_side_specs_support/remover_spec.rb +116 -0
- data/spec/rake/funnel/tasks/timing_spec.rb +133 -0
- data/spec/rake/funnel/tasks/timing_support/report_spec.rb +129 -0
- data/spec/rake/funnel/tasks/zip_spec.rb +119 -0
- data/spec/spec_helper.rb +32 -0
- data/tools/MSDeploy/Microsoft.Web.Delegation.dll +0 -0
- data/tools/MSDeploy/Microsoft.Web.Deployment.Tracing.dll +0 -0
- data/tools/MSDeploy/Microsoft.Web.Deployment.dll +0 -0
- data/tools/MSDeploy/en/msdeploy.resources.dll +0 -0
- data/tools/MSDeploy/msdeploy.exe +0 -0
- data/tools/MSDeploy/msdeploy.exe.config +6 -0
- metadata +253 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'zip'
|
4
|
+
|
5
|
+
module Rake::Funnel::Tasks
|
6
|
+
class Zip < Rake::TaskLib
|
7
|
+
attr_accessor :name, :source, :target, :zip_root
|
8
|
+
|
9
|
+
def initialize(name = :package)
|
10
|
+
@name = name
|
11
|
+
|
12
|
+
@source = []
|
13
|
+
@target = nil
|
14
|
+
@zip_root = nil
|
15
|
+
|
16
|
+
yield self if block_given?
|
17
|
+
define
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def define
|
22
|
+
target && CLEAN.include(target)
|
23
|
+
|
24
|
+
desc "Zip #{files.join(', ')} to #{target}"
|
25
|
+
task name do
|
26
|
+
raise 'Target not defined' unless target
|
27
|
+
|
28
|
+
RakeFileUtils.mkdir_p(File.dirname(target))
|
29
|
+
|
30
|
+
configure_zip
|
31
|
+
create_zip(files, target)
|
32
|
+
|
33
|
+
Rake.rake_output_message("Created #{target}")
|
34
|
+
end
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def files
|
40
|
+
Rake::Funnel::Support::Finder.new(source, self, 'No files to zip.').all_or_default
|
41
|
+
end
|
42
|
+
|
43
|
+
def configure_zip
|
44
|
+
::Zip.unicode_names = true
|
45
|
+
::Zip.default_compression = Zlib::BEST_COMPRESSION
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_zip(files, target)
|
49
|
+
::Zip::File.open(target, ::Zip::File::CREATE) do |zip|
|
50
|
+
common_path = files.common_path
|
51
|
+
|
52
|
+
files.each do |file|
|
53
|
+
zipped_file = get_zipped_path(common_path, file)
|
54
|
+
|
55
|
+
zip.add(zipped_file, file)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_zipped_path(common_path, file)
|
61
|
+
file = Pathname.new(file).relative_path_from(Pathname.new(common_path)).to_s unless common_path.nil?
|
62
|
+
file = File.join(zip_root, file) unless zip_root.nil? || zip_root.empty?
|
63
|
+
file
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/rake/funnel.rb
ADDED
data/rake-funnel.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rake/funnel/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'rake-funnel'
|
7
|
+
s.version = Rake::Funnel::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Alexander Groß']
|
10
|
+
s.email = ['agross@therightstuff.de']
|
11
|
+
s.homepage = 'http://grossweber.com'
|
12
|
+
s.license = 'BSD'
|
13
|
+
s.description = %q{A standardized build pipeline}
|
14
|
+
s.summary = %q{The build pipeline}
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 2.0.0'
|
17
|
+
|
18
|
+
s.add_dependency 'rake'
|
19
|
+
s.add_dependency 'rubyzip', '~> 1.0'
|
20
|
+
s.add_dependency 'smart_colored'
|
21
|
+
s.add_dependency 'configatron', '~> 4.5'
|
22
|
+
|
23
|
+
git = ENV['TEAMCITY_GIT_PATH'] || 'git'
|
24
|
+
s.files = `"#{git}" ls-files -z`.split("\x0")
|
25
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
26
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
27
|
+
s.require_paths = ['lib']
|
28
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
describe Rake::Funnel::ExecutionError do
|
2
|
+
its(:to_s) { should == described_class.to_s }
|
3
|
+
|
4
|
+
context 'with command' do
|
5
|
+
subject { described_class.new('command') }
|
6
|
+
|
7
|
+
its(:command) { should == 'command' }
|
8
|
+
its(:exit_code) { should be_nil }
|
9
|
+
its(:output) { should be_nil }
|
10
|
+
its(:description) { should be_nil }
|
11
|
+
its(:to_s) { should =~ /^Error executing:\scommand/ }
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with command and exit code' do
|
15
|
+
subject { described_class.new('command', 127) }
|
16
|
+
|
17
|
+
its(:command) { should == 'command' }
|
18
|
+
its(:exit_code) { should == 127 }
|
19
|
+
its(:output) { should be_nil }
|
20
|
+
its(:description) { should be_nil }
|
21
|
+
its(:to_s) { should =~ /^Error executing:\scommand/ }
|
22
|
+
its(:to_s) { should =~ /^Exit code: 127/ }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with command and exit code and output' do
|
26
|
+
subject { described_class.new('command', 127, 'output') }
|
27
|
+
|
28
|
+
its(:command) { should == 'command' }
|
29
|
+
its(:exit_code) { should == 127 }
|
30
|
+
its(:output) { should == 'output' }
|
31
|
+
its(:description) { should be_nil }
|
32
|
+
its(:to_s) { should =~ /^Error executing:\scommand/ }
|
33
|
+
its(:to_s) { should =~ /^Exit code: 127/ }
|
34
|
+
its(:to_s) { should =~ /^Command output \(last 10 lines\):\soutput/ }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with command and exit code and output and message' do
|
38
|
+
subject { described_class.new('command', 127, 'output', 'description') }
|
39
|
+
|
40
|
+
its(:command) { should == 'command' }
|
41
|
+
its(:exit_code) { should == 127 }
|
42
|
+
its(:output) { should == 'output' }
|
43
|
+
its(:description) { should == 'description' }
|
44
|
+
its(:to_s) { should =~ /^description/ }
|
45
|
+
its(:to_s) { should =~ /^Error executing:\scommand/ }
|
46
|
+
its(:to_s) { should =~ /^Exit code: 127/ }
|
47
|
+
its(:to_s) { should =~ /^Command output \(last 10 lines\):\soutput/ }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with output longer than 10 lines' do
|
51
|
+
let(:output) {
|
52
|
+
output = []
|
53
|
+
|
54
|
+
11.times.each do |i|
|
55
|
+
output << "output #{i}"
|
56
|
+
end
|
57
|
+
|
58
|
+
output.join("\n")
|
59
|
+
}
|
60
|
+
|
61
|
+
subject { described_class.new(nil, nil, output) }
|
62
|
+
|
63
|
+
it 'should display the last 10 lines of output' do
|
64
|
+
expect(subject.to_s).not_to match(/^output 0/)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Rake::Funnel::Extensions::CamelCase do
|
2
|
+
it 'should not touch values without underscores' do
|
3
|
+
expect('foo'.camelize).to eq('foo')
|
4
|
+
end
|
5
|
+
|
6
|
+
it 'should convert strings with underscores' do
|
7
|
+
expect('foo_bar'.camelize).to eq('fooBar')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should convert symbols to string' do
|
11
|
+
expect(:foo.camelize).to eq('foo')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should convert symbols with underscores' do
|
15
|
+
expect(:foo_bar.camelize).to eq('fooBar')
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
describe Rake::Funnel::Extensions::CommonPath do
|
2
|
+
describe 'Manual debugging test case' do
|
3
|
+
it 'should work' do
|
4
|
+
expect(%w(/common/one /com/two).common_path).to be
|
5
|
+
|
6
|
+
skip('for manual testing only')
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'modification of FileList' do
|
11
|
+
it 'should not modify the input' do
|
12
|
+
input = FileList[File.join(File.dirname(__FILE__), '**/*')]
|
13
|
+
duped = input.dup
|
14
|
+
|
15
|
+
expect(input.common_path).to be
|
16
|
+
expect(input).to match_array(duped)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
{
|
21
|
+
array: [
|
22
|
+
{ input: [], expected: '' },
|
23
|
+
{ input: %w(one two), expected: '' },
|
24
|
+
{ input: %w(1-common 2-common), expected: '' },
|
25
|
+
{ input: %w(common.1 common-2), expected: '' },
|
26
|
+
{ input: %w(common-1 common-2), expected: '' },
|
27
|
+
{ input: %w(/common common), expected: '' },
|
28
|
+
{ input: %w(/ /foo), expected: '/' },
|
29
|
+
{ input: %w(/common/one /com/two), expected: '/' },
|
30
|
+
{ input: %w(/common/1 /common/2), expected: '/common' },
|
31
|
+
{ input: %w(/common/1 /common/2 /common/3/4), expected: '/common' },
|
32
|
+
{ input: %w(/common /common), expected: '/common' },
|
33
|
+
{ input: %w(/common /common/), expected: '/common' },
|
34
|
+
{ input: %w(/common/ /common/), expected: '/common' },
|
35
|
+
{ input: ['common/ 1', 'common/ 2'], expected: 'common' },
|
36
|
+
{ input: ['com mon/1', 'com mon/2'], expected: 'com mon' },
|
37
|
+
{ input: [' common/1', ' common/2'], expected: ' common' },
|
38
|
+
{ input: ['common /1', 'common /2'], expected: 'common ' },
|
39
|
+
{ input: [''], expected: '' },
|
40
|
+
{ input: ['', nil], expected: '' }
|
41
|
+
],
|
42
|
+
file_list: [
|
43
|
+
{ input: FileList.new, expected: '' },
|
44
|
+
{ input: FileList['lib/*', 'spec/*'], expected: '' },
|
45
|
+
{ input: FileList['spec/*'], expected: 'spec' }
|
46
|
+
]
|
47
|
+
}.each do |group, pairs|
|
48
|
+
describe group do
|
49
|
+
pairs.each do |pair|
|
50
|
+
it "#{pair[:input]} should equal '#{pair[:expected]}'" do
|
51
|
+
expect(pair[:input].common_path).to eq(pair[:expected])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
describe Rake::Funnel::Extensions::DisableColors do
|
2
|
+
context 'when connected to a terminal' do
|
3
|
+
before { allow($stdout).to receive(:tty?).and_return(true) }
|
4
|
+
|
5
|
+
it 'should color strings' do
|
6
|
+
expect('foo'.colored.green).to eq("\e[32mfoo\e[0m")
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should color strings with extension' do
|
10
|
+
expect('foo'.green).to eq("\e[32mfoo\e[0m")
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should support combinators' do
|
14
|
+
expect('foo'.green.inverse.bold).to eq("\e[1;7;32mfoo\e[0m")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when not connected to a terminal' do
|
19
|
+
before { allow($stdout).to receive(:tty?).and_return(false) }
|
20
|
+
|
21
|
+
it 'should not color strings' do
|
22
|
+
expect('foo'.colored.green).to eq('foo')
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should not color strings with extension' do
|
26
|
+
expect('foo'.green).to eq('foo')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should support combinators' do
|
30
|
+
expect('foo'.green.inverse.bold).to eq('foo')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe Rake::Funnel::Extensions::REXML::Functions do
|
2
|
+
let(:xml) { <<EOF
|
3
|
+
<editors xmlns="http://example.com">
|
4
|
+
<editor id="emacs">EMACS</editor>
|
5
|
+
<editor id="vi">VIM</editor>
|
6
|
+
<editor id="notepad">Notepad</editor>
|
7
|
+
</editors>
|
8
|
+
EOF
|
9
|
+
}
|
10
|
+
|
11
|
+
subject { REXML::Document.new(xml) }
|
12
|
+
|
13
|
+
it 'should support lower-case function' do
|
14
|
+
expect(REXML::XPath.match(subject, "//editor[lower-case(text())='vim']").first.to_s).to match(/VIM/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should support matches function' do
|
18
|
+
expect(REXML::XPath.match(subject, "//editor[matches(@id, '*pad')]").first.to_s).to match(/Notepad/)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
include Rake::Funnel
|
4
|
+
|
5
|
+
describe Rake::Funnel::Extensions::Shell do
|
6
|
+
before {
|
7
|
+
allow(Open3).to receive(:popen2e).and_yield(nil, stdout_and_stderr, exit)
|
8
|
+
|
9
|
+
allow($stdout).to receive(:puts)
|
10
|
+
allow($stderr).to receive(:puts)
|
11
|
+
allow(Rake).to receive(:rake_output_message)
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:exit) { OpenStruct.new(value: OpenStruct.new(success?: true, exitstatus: 0)) }
|
15
|
+
|
16
|
+
let(:stdout_and_stderr) { StringIO.new("output 1\noutput 2\n") }
|
17
|
+
|
18
|
+
subject { Object.new.extend(described_class) }
|
19
|
+
|
20
|
+
after { stdout_and_stderr.close }
|
21
|
+
|
22
|
+
describe 'command' do
|
23
|
+
it 'should accept simple commands' do
|
24
|
+
arg = 'simple'
|
25
|
+
|
26
|
+
subject.shell(arg)
|
27
|
+
|
28
|
+
expect(Open3).to have_received(:popen2e).with(arg)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should accept commands with arguments as array' do
|
32
|
+
args = %w(simple 1 2)
|
33
|
+
|
34
|
+
subject.shell(args)
|
35
|
+
|
36
|
+
expect(Open3).to have_received(:popen2e).with(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should accept commands with arguments' do
|
40
|
+
subject.shell('1', 2)
|
41
|
+
|
42
|
+
expect(Open3).to have_received(:popen2e).with('1', 2)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should reject nil' do
|
46
|
+
subject.shell(1, nil)
|
47
|
+
|
48
|
+
expect(Open3).to have_received(:popen2e).with(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should accept nested arrays' do
|
52
|
+
subject.shell([1, 2, [3]])
|
53
|
+
|
54
|
+
expect(Open3).to have_received(:popen2e).with(1, 2, 3)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should reject nested nils' do
|
58
|
+
subject.shell([1, nil, [3]])
|
59
|
+
|
60
|
+
expect(Open3).to have_received(:popen2e).with(1, 3)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should echo the command' do
|
64
|
+
arg = '1', 2
|
65
|
+
|
66
|
+
subject.shell(arg)
|
67
|
+
|
68
|
+
expect(Rake).to have_received(:rake_output_message).with(arg.join(' '))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should return nil' do
|
73
|
+
expect(subject.shell('foo')).to be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'output redirection' do
|
77
|
+
before { subject.shell('foo') }
|
78
|
+
|
79
|
+
it 'should redirect command output to stdout' do
|
80
|
+
expect($stdout).to have_received(:puts).with(/output 1/)
|
81
|
+
expect($stdout).to have_received(:puts).with(/output 2/)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should colorize lines' do
|
85
|
+
expect($stdout).to have_received(:puts).with('output 1'.green)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'log file' do
|
90
|
+
before {
|
91
|
+
allow(subject).to receive(:mkdir_p)
|
92
|
+
allow(File).to receive(:open)
|
93
|
+
}
|
94
|
+
|
95
|
+
let(:log_file) { nil }
|
96
|
+
|
97
|
+
before { subject.shell('foo', log_file: log_file) }
|
98
|
+
|
99
|
+
context 'no log file' do
|
100
|
+
it 'should not create path to log file' do
|
101
|
+
expect(subject).to_not have_received(:mkdir_p)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should not write log file' do
|
105
|
+
expect(subject).to_not have_received(:mkdir_p)
|
106
|
+
expect(File).to_not have_received(:open)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with log file' do
|
111
|
+
let(:log_file) { 'tmp/log.txt' }
|
112
|
+
|
113
|
+
it 'should create path to log file' do
|
114
|
+
expect(subject).to have_received(:mkdir_p).with(File.dirname(log_file))
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should append to log file' do
|
118
|
+
expect(File).to have_received(:open).with(log_file, 'a').at_least(:once)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'error detection' do
|
124
|
+
let(:error_lines) { /error/ }
|
125
|
+
|
126
|
+
before {
|
127
|
+
begin
|
128
|
+
subject.shell('foo', error_lines: error_lines)
|
129
|
+
rescue ExecutionError
|
130
|
+
end
|
131
|
+
}
|
132
|
+
|
133
|
+
context 'no lines indicating errors' do
|
134
|
+
it 'should not log to stderr' do
|
135
|
+
expect($stderr).to_not have_received(:puts)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'lines indicating errors' do
|
140
|
+
let(:stdout_and_stderr) { StringIO.new("output 1\nerror\noutput 2\n") }
|
141
|
+
|
142
|
+
it 'should log to stdout before error' do
|
143
|
+
expect($stdout).to have_received(:puts).with(/output 1/)
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'should log to stderr on error' do
|
147
|
+
expect($stderr).to have_received(:puts).with(/error/)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'should not log to stdout on error' do
|
151
|
+
expect($stdout).to_not have_received(:puts).with(/error/)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should colorize error lines' do
|
155
|
+
expect($stderr).to have_received(:puts).with('error'.bold.red)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should log to stdout after error' do
|
159
|
+
expect($stdout).to have_received(:puts).with(/output 2/)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'callback block' do
|
165
|
+
it 'should yield' do
|
166
|
+
expect { |b| subject.shell('foo', &b) }.to yield_control
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should yield the success status' do
|
170
|
+
expect { |b| subject.shell('foo', &b) }.to yield_with_args(true, be, be, be)
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should yield the command' do
|
174
|
+
expect { |b| subject.shell('foo', &b) }.to yield_with_args(be, 'foo', be, be)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should yield the exit code' do
|
178
|
+
expect { |b| subject.shell('foo', &b) }.to yield_with_args(be, be, 0, be)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should yield the log' do
|
182
|
+
expect { |b| subject.shell('foo', &b) }.to yield_with_args(be, be, be, /output/)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'failure' do
|
187
|
+
context 'error lines logged' do
|
188
|
+
context 'without block' do
|
189
|
+
it 'should fail' do
|
190
|
+
expect { subject.shell('foo', error_lines: /.*/) }.to raise_error(ExecutionError)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'with block' do
|
195
|
+
it 'should not fail' do
|
196
|
+
expect { subject.shell('foo', error_lines: /.*/) {} }.not_to raise_error
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should yield the error' do
|
200
|
+
expect { |b| subject.shell('foo', error_lines: /.*/, &b) }.to yield_with_args(false, 'foo', 0, /output/)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'error exit' do
|
206
|
+
let(:exit) { OpenStruct.new(value: OpenStruct.new(success?: false, exitstatus: 1)) }
|
207
|
+
|
208
|
+
context 'without block' do
|
209
|
+
it 'should fail' do
|
210
|
+
expect { subject.shell('foo') }.to raise_error(ExecutionError)
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'should report the exit code' do
|
214
|
+
expect { subject.shell('foo') }.to raise_error { |e| expect(e.exit_code).to eq(exit.value.exitstatus) }
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should report the command that was run' do
|
218
|
+
expect { subject.shell('foo') }.to raise_error { |e| expect(e.command).to eq('foo') }
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should report logged lines' do
|
222
|
+
expect { subject.shell('foo') }.to raise_error { |e| expect(e.output).to eq(stdout_and_stderr.string) }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context 'with block' do
|
227
|
+
it 'should not fail' do
|
228
|
+
expect { subject.shell('foo') {} }.not_to raise_error
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should yield the error' do
|
232
|
+
expect { |b| subject.shell('foo', error_lines: /.*/, &b) }.to yield_with_args(false, 'foo', 1, /output/)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
include Rake
|
2
|
+
include Rake::Funnel::Integration
|
3
|
+
|
4
|
+
describe Rake::Funnel::Integration::ProgressReport do
|
5
|
+
include DSL
|
6
|
+
|
7
|
+
let(:teamcity_running?) { false }
|
8
|
+
|
9
|
+
before {
|
10
|
+
allow($stdout).to receive(:puts)
|
11
|
+
allow(TeamCity).to receive(:running?).and_return(teamcity_running?)
|
12
|
+
|
13
|
+
Task.clear
|
14
|
+
}
|
15
|
+
|
16
|
+
after {
|
17
|
+
subject.disable!
|
18
|
+
}
|
19
|
+
|
20
|
+
describe 'defaults' do
|
21
|
+
subject! {
|
22
|
+
described_class.new
|
23
|
+
}
|
24
|
+
|
25
|
+
before {
|
26
|
+
task :task
|
27
|
+
|
28
|
+
Task[:task].invoke
|
29
|
+
}
|
30
|
+
|
31
|
+
context 'not on TeamCity' do
|
32
|
+
it 'should write task name in square brackets' do
|
33
|
+
expect($stdout).to have_received(:puts).with("\n[task]")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'on TeamCity' do
|
38
|
+
let(:teamcity_running?) { true }
|
39
|
+
|
40
|
+
it 'should not write task name in square brackets since it would clutter the output' do
|
41
|
+
expect($stdout).to_not have_received(:puts).with("\n[task]")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when progess report was disabled' do
|
47
|
+
subject! {
|
48
|
+
described_class.new
|
49
|
+
}
|
50
|
+
|
51
|
+
before {
|
52
|
+
subject.disable!
|
53
|
+
|
54
|
+
task :task
|
55
|
+
|
56
|
+
Task[:task].invoke
|
57
|
+
}
|
58
|
+
|
59
|
+
it 'should not write' do
|
60
|
+
expect($stdout).to_not have_received(:puts).with("\n[task]")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'custom event handlers' do
|
65
|
+
let(:receiver) { double.as_null_object }
|
66
|
+
|
67
|
+
subject! {
|
68
|
+
described_class.new do |r|
|
69
|
+
r.task_starting do |task, args|
|
70
|
+
receiver.starting({
|
71
|
+
task: task,
|
72
|
+
args: args
|
73
|
+
})
|
74
|
+
end
|
75
|
+
|
76
|
+
r.task_finished do |task, args, error|
|
77
|
+
receiver.finished({
|
78
|
+
task: task,
|
79
|
+
args: args,
|
80
|
+
error: error
|
81
|
+
})
|
82
|
+
end
|
83
|
+
end
|
84
|
+
}
|
85
|
+
|
86
|
+
context 'when task succeeds' do
|
87
|
+
before {
|
88
|
+
task :task
|
89
|
+
|
90
|
+
Task[:task].invoke
|
91
|
+
}
|
92
|
+
|
93
|
+
describe 'starting handler' do
|
94
|
+
it 'should run' do
|
95
|
+
expect(receiver).to have_received(:starting)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should receive task' do
|
99
|
+
expect(receiver).to have_received(:starting).with(hash_including({ task: kind_of(Task) }))
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should receive task arguments' do
|
103
|
+
expect(receiver).to have_received(:starting).with(hash_including({ args: kind_of(TaskArguments) }))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'finished handler' do
|
108
|
+
it 'should run' do
|
109
|
+
expect(receiver).to have_received(:finished)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should receive task' do
|
113
|
+
expect(receiver).to have_received(:finished).with(hash_including({ task: kind_of(Task) }))
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should receive task arguments' do
|
117
|
+
expect(receiver).to have_received(:finished).with(hash_including({ args: kind_of(TaskArguments) }))
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should not receive error' do
|
121
|
+
expect(receiver).to have_received(:finished).with(hash_including({ error: nil }))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when task fails' do
|
127
|
+
class SpecificError < StandardError; end
|
128
|
+
|
129
|
+
let(:error) { SpecificError.new('task error') }
|
130
|
+
|
131
|
+
before {
|
132
|
+
task :task do
|
133
|
+
raise error
|
134
|
+
end
|
135
|
+
|
136
|
+
begin
|
137
|
+
Task[:task].invoke
|
138
|
+
rescue SpecificError
|
139
|
+
end
|
140
|
+
}
|
141
|
+
|
142
|
+
describe 'finished handler' do
|
143
|
+
it 'should receive error' do
|
144
|
+
expect(receiver).to have_received(:finished).with(hash_including({ error: error }))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|