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.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +29 -0
  6. data/Guardfile +24 -0
  7. data/README.md +29 -0
  8. data/Rakefile +77 -0
  9. data/build.cmd +30 -0
  10. data/bundle.cmd +26 -0
  11. data/config/.gitignore +1 -0
  12. data/config/.local.yaml.example +9 -0
  13. data/config/default.yaml +5 -0
  14. data/config/dev.yaml +0 -0
  15. data/config/production.yaml +3 -0
  16. data/lib/rake/funnel/ambiguous_file_error.rb +29 -0
  17. data/lib/rake/funnel/execution_error.rb +26 -0
  18. data/lib/rake/funnel/extensions/camel_case.rb +19 -0
  19. data/lib/rake/funnel/extensions/common_path.rb +52 -0
  20. data/lib/rake/funnel/extensions/disable_colors.rb +27 -0
  21. data/lib/rake/funnel/extensions/rexml.rb +23 -0
  22. data/lib/rake/funnel/extensions/shell.rb +56 -0
  23. data/lib/rake/funnel/framework.rb +15 -0
  24. data/lib/rake/funnel/integration/progress_report.rb +70 -0
  25. data/lib/rake/funnel/integration/sync_output.rb +8 -0
  26. data/lib/rake/funnel/integration/teamcity/nunit_plugin.rb +59 -0
  27. data/lib/rake/funnel/integration/teamcity/progress_report.rb +33 -0
  28. data/lib/rake/funnel/integration/teamcity/service_messages.rb +40 -0
  29. data/lib/rake/funnel/integration/teamcity/teamcity.rb +15 -0
  30. data/lib/rake/funnel/integration/teamcity.rb +5 -0
  31. data/lib/rake/funnel/support/finder.rb +51 -0
  32. data/lib/rake/funnel/support/mapper.rb +81 -0
  33. data/lib/rake/funnel/support/mapper_styles/default.rb +31 -0
  34. data/lib/rake/funnel/support/mapper_styles/msbuild.rb +33 -0
  35. data/lib/rake/funnel/support/mapper_styles/msdeploy.rb +47 -0
  36. data/lib/rake/funnel/support/mapper_styles/nunit.rb +33 -0
  37. data/lib/rake/funnel/support/mono.rb +17 -0
  38. data/lib/rake/funnel/support/patch.rb +37 -0
  39. data/lib/rake/funnel/support/template_engine.rb +26 -0
  40. data/lib/rake/funnel/support/which.rb +15 -0
  41. data/lib/rake/funnel/tasks/bin_path.rb +34 -0
  42. data/lib/rake/funnel/tasks/copy.rb +54 -0
  43. data/lib/rake/funnel/tasks/environments.rb +74 -0
  44. data/lib/rake/funnel/tasks/environments_support/loader.rb +37 -0
  45. data/lib/rake/funnel/tasks/msbuild.rb +52 -0
  46. data/lib/rake/funnel/tasks/msbuild_support/build_tool.rb +28 -0
  47. data/lib/rake/funnel/tasks/msdeploy.rb +58 -0
  48. data/lib/rake/funnel/tasks/msdeploy_support/registry_patch.rb +84 -0
  49. data/lib/rake/funnel/tasks/nunit.rb +46 -0
  50. data/lib/rake/funnel/tasks/paket.rb +39 -0
  51. data/lib/rake/funnel/tasks/quick_template.rb +45 -0
  52. data/lib/rake/funnel/tasks/side_by_side_specs.rb +33 -0
  53. data/lib/rake/funnel/tasks/side_by_side_specs_support/remover.rb +62 -0
  54. data/lib/rake/funnel/tasks/timing.rb +100 -0
  55. data/lib/rake/funnel/tasks/timing_support/report.rb +89 -0
  56. data/lib/rake/funnel/tasks/timing_support/statistics.rb +26 -0
  57. data/lib/rake/funnel/tasks/zip.rb +66 -0
  58. data/lib/rake/funnel/version.rb +5 -0
  59. data/lib/rake/funnel.rb +7 -0
  60. data/rake-funnel.gemspec +28 -0
  61. data/spec/rake/funnel/execution_error_spec.rb +67 -0
  62. data/spec/rake/funnel/extensions/camel_case_spec.rb +17 -0
  63. data/spec/rake/funnel/extensions/common_path_spec.rb +56 -0
  64. data/spec/rake/funnel/extensions/disable_colors_spec.rb +33 -0
  65. data/spec/rake/funnel/extensions/rexml_spec.rb +20 -0
  66. data/spec/rake/funnel/extensions/shell_spec.rb +237 -0
  67. data/spec/rake/funnel/integration/progress_report_spec.rb +149 -0
  68. data/spec/rake/funnel/integration/sync_output_spec.rb +16 -0
  69. data/spec/rake/funnel/integration/teamcity/nunit_plugin_spec.rb +112 -0
  70. data/spec/rake/funnel/integration/teamcity/progress_report_spec.rb +174 -0
  71. data/spec/rake/funnel/integration/teamcity/service_messages_spec.rb +136 -0
  72. data/spec/rake/funnel/integration/teamcity/teamcity_spec.rb +34 -0
  73. data/spec/rake/funnel/support/finder_spec.rb +210 -0
  74. data/spec/rake/funnel/support/mapper_spec.rb +87 -0
  75. data/spec/rake/funnel/support/mapper_styles/msdeploy_spec.rb +222 -0
  76. data/spec/rake/funnel/support/mapper_styles/nunit_spec.rb +25 -0
  77. data/spec/rake/funnel/support/mapper_styles/styles_spec.rb +214 -0
  78. data/spec/rake/funnel/support/mono_spec.rb +57 -0
  79. data/spec/rake/funnel/support/patch_spec.rb +108 -0
  80. data/spec/rake/funnel/support/template_engine_spec.rb +65 -0
  81. data/spec/rake/funnel/support/which_spec.rb +65 -0
  82. data/spec/rake/funnel/tasks/bin_path_spec.rb +40 -0
  83. data/spec/rake/funnel/tasks/copy_spec.rb +101 -0
  84. data/spec/rake/funnel/tasks/environments_spec.rb +237 -0
  85. data/spec/rake/funnel/tasks/environments_support/loader_spec.rb +114 -0
  86. data/spec/rake/funnel/tasks/msbuild_spec.rb +91 -0
  87. data/spec/rake/funnel/tasks/msbuild_support/build_tool_spec.rb +21 -0
  88. data/spec/rake/funnel/tasks/msdeploy_spec.rb +243 -0
  89. data/spec/rake/funnel/tasks/msdeploy_support/registry_patch_spec.rb +139 -0
  90. data/spec/rake/funnel/tasks/nunit_spec.rb +76 -0
  91. data/spec/rake/funnel/tasks/paket_spec.rb +184 -0
  92. data/spec/rake/funnel/tasks/quick_template_spec.rb +89 -0
  93. data/spec/rake/funnel/tasks/side_by_side_specs_spec.rb +58 -0
  94. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/FooCode.cs +0 -0
  95. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/FooSpecs.cs +0 -0
  96. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/Sample.csproj +28 -0
  97. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/Specs.cs +0 -0
  98. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/subdir/BarCode.cs +0 -0
  99. data/spec/rake/funnel/tasks/side_by_side_specs_support/example/subdir/BarSpecs.cs +0 -0
  100. data/spec/rake/funnel/tasks/side_by_side_specs_support/remover_spec.rb +116 -0
  101. data/spec/rake/funnel/tasks/timing_spec.rb +133 -0
  102. data/spec/rake/funnel/tasks/timing_support/report_spec.rb +129 -0
  103. data/spec/rake/funnel/tasks/zip_spec.rb +119 -0
  104. data/spec/spec_helper.rb +32 -0
  105. data/tools/MSDeploy/Microsoft.Web.Delegation.dll +0 -0
  106. data/tools/MSDeploy/Microsoft.Web.Deployment.Tracing.dll +0 -0
  107. data/tools/MSDeploy/Microsoft.Web.Deployment.dll +0 -0
  108. data/tools/MSDeploy/en/msdeploy.resources.dll +0 -0
  109. data/tools/MSDeploy/msdeploy.exe +0 -0
  110. data/tools/MSDeploy/msdeploy.exe.config +6 -0
  111. 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
@@ -0,0 +1,5 @@
1
+ module Rake
2
+ module Funnel
3
+ VERSION = '0.0.1.pre'
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+
3
+ module Rake
4
+ module Funnel; end
5
+ end
6
+
7
+ require "#{File.dirname(__FILE__)}/funnel/framework.rb"
@@ -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