alpacabuildtool 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +48 -0
  3. data/.rubocop.yml +12 -0
  4. data/.semver +6 -0
  5. data/.travis.yml +10 -0
  6. data/CHANGELOG +18 -0
  7. data/Gemfile +7 -0
  8. data/LICENSE +22 -0
  9. data/README.md +235 -0
  10. data/README.rdoc +39 -0
  11. data/Rakefile +74 -0
  12. data/alpacabuildtool.gemspec +34 -0
  13. data/alpacabuildtool.rdoc +5 -0
  14. data/alpacabuildtool.todo +9 -0
  15. data/bin/alpaca +142 -0
  16. data/features/alpaca.feature +8 -0
  17. data/features/step_definitions/alpaca_steps.rb +13 -0
  18. data/features/step_definitions/visual_studio_solutions_steps.rb +47 -0
  19. data/features/support/env.rb +10 -0
  20. data/features/visual_studio_solutions.feature +43 -0
  21. data/lib/alpacabuildtool.rb +4 -0
  22. data/lib/alpacabuildtool/application.rb +195 -0
  23. data/lib/alpacabuildtool/configuration.rb +209 -0
  24. data/lib/alpacabuildtool/data/.alpaca.conf +148 -0
  25. data/lib/alpacabuildtool/data/doom.flf +826 -0
  26. data/lib/alpacabuildtool/data/logo.jpg +0 -0
  27. data/lib/alpacabuildtool/entities/nuspec.rb +107 -0
  28. data/lib/alpacabuildtool/entities/project.rb +54 -0
  29. data/lib/alpacabuildtool/entities/solution.rb +104 -0
  30. data/lib/alpacabuildtool/entities/xml.rb +41 -0
  31. data/lib/alpacabuildtool/entities/xml_node.rb +75 -0
  32. data/lib/alpacabuildtool/log/font.rb +92 -0
  33. data/lib/alpacabuildtool/log/log.rb +15 -0
  34. data/lib/alpacabuildtool/log/rainbowify_formatter.rb +70 -0
  35. data/lib/alpacabuildtool/log/rainbowify_logger.rb +47 -0
  36. data/lib/alpacabuildtool/managers/build_manager.rb +32 -0
  37. data/lib/alpacabuildtool/managers/package_manager.rb +136 -0
  38. data/lib/alpacabuildtool/managers/report_manager.rb +33 -0
  39. data/lib/alpacabuildtool/managers/test_manager.rb +35 -0
  40. data/lib/alpacabuildtool/os.rb +29 -0
  41. data/lib/alpacabuildtool/package_types/project_package.rb +44 -0
  42. data/lib/alpacabuildtool/package_types/tool_package.rb +53 -0
  43. data/lib/alpacabuildtool/tools/git.rb +22 -0
  44. data/lib/alpacabuildtool/tools/msbuild.rb +29 -0
  45. data/lib/alpacabuildtool/tools/nuget.rb +49 -0
  46. data/lib/alpacabuildtool/tools/nunit.rb +28 -0
  47. data/lib/alpacabuildtool/tools/nunit_orange.rb +18 -0
  48. data/lib/alpacabuildtool/tools/open_cover.rb +29 -0
  49. data/lib/alpacabuildtool/tools/report_generator.rb +25 -0
  50. data/lib/alpacabuildtool/tools/tool.rb +84 -0
  51. data/lib/alpacabuildtool/tools/wrapper.rb +66 -0
  52. data/lib/alpacabuildtool/versioning/version.rb +163 -0
  53. data/lib/alpacabuildtool/versioning/versioning.rb +84 -0
  54. data/spec/lib/alpacabuildtool/configuration_spec.rb +201 -0
  55. data/spec/lib/alpacabuildtool/entities/xml_spec.rb +39 -0
  56. data/spec/lib/alpacabuildtool/versioning/version_spec.rb +86 -0
  57. data/spec/lib/alpacabuildtool/versioning/versioning_spec.rb +194 -0
  58. data/spec/spec_helper.rb +3 -0
  59. data/spec/support/coverage.rb +26 -0
  60. data/test_data/sln1/.alpaca.conf +11 -0
  61. data/test_data/sln1/.semver +6 -0
  62. data/test_data/sln1/TestSolution.sln +22 -0
  63. data/test_data/sln1/TestSolution/App.config +6 -0
  64. data/test_data/sln1/TestSolution/Program.cs +16 -0
  65. data/test_data/sln1/TestSolution/Properties/AssemblyInfo.cs +36 -0
  66. data/test_data/sln1/TestSolution/TestSolution.csproj +59 -0
  67. data/test_data/sln2/.alpaca.conf +8 -0
  68. data/test_data/sln2/.semver +6 -0
  69. data/test_data/sln2/ProjectName/ProjectName.csproj +54 -0
  70. data/test_data/sln2/ProjectName/Properties/AssemblyInfo.cs +36 -0
  71. data/test_data/sln2/ProjectName/SomeFolderInProject/SomeClass.cs +16 -0
  72. data/test_data/sln2/ProjectName2/ProjectName2.csproj +58 -0
  73. data/test_data/sln2/ProjectName2/Properties/AssemblyInfo.cs +37 -0
  74. data/test_data/sln2/SolutionName.sln +34 -0
  75. data/test_data/sln2/Unit.Tests/Properties/AssemblyInfo.cs +36 -0
  76. data/test_data/sln2/Unit.Tests/SomeClassTests.cs +21 -0
  77. data/test_data/sln2/Unit.Tests/Unit.Tests.csproj +65 -0
  78. data/test_data/sln2/Unit.Tests/packages.config +4 -0
  79. data/test_data/sln3/TestSolution.nobuild.sln +22 -0
  80. data/test_data/sln3/TestSolution/App.config +6 -0
  81. data/test_data/sln3/TestSolution/Program.cs +16 -0
  82. data/test_data/sln3/TestSolution/Properties/AssemblyInfo.cs +36 -0
  83. data/test_data/sln3/TestSolution/TestSolution.nobuild.csproj +59 -0
  84. metadata +309 -0
@@ -0,0 +1,15 @@
1
+ require 'alpacabuildtool/log/rainbowify_logger'
2
+
3
+ module AlpacaBuildTool
4
+ ##
5
+ # Log adds logger to any class that include it
6
+ module Log
7
+ attr_writer :log
8
+
9
+ ##
10
+ # Method gives access to logger with lazy initialization
11
+ def log
12
+ @log ||= RainbowifyLogger.new
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,70 @@
1
+ require 'date'
2
+ require 'logger'
3
+ require 'rainbow'
4
+ require 'rainbow/ext/string' unless String.method_defined?(:color)
5
+ require 'alpacabuildtool/log/font'
6
+
7
+ module AlpacaBuildTool
8
+ ##
9
+ # RainbowifyFormatter provides formatting for standart
10
+ # ruby logger by adding colors(rainbow gem) and ASCII art headers
11
+ # for HEADER (6) severity
12
+ class RainbowifyFormatter < Logger::Formatter
13
+ ##
14
+ # Provides custom logging implementation
15
+ #
16
+ # +severity+:: severity to log(HEADER, PUTS, INFO, ERROR...)
17
+ # +datetime+:: date time stamp
18
+ # +progname+:: not used here
19
+ # +message+:: message to log
20
+ def call(severity, datetime, _progname, message)
21
+ case severity
22
+ when 'HEADER' then header(message)
23
+ when 'PUTS' then puts(message)
24
+ else usual(message, severity, datetime)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def header(message)
31
+ font = Font.new('doom')
32
+ result = artify_message("\x00#{message}", font)
33
+ result.join("\n").gsub(/\0/, '').gsub(font.hard_blank, ' ')
34
+ .color(:green).bright + "\n"
35
+ end
36
+
37
+ def puts(message)
38
+ message.to_s.color(:blue).bright + "\n"
39
+ end
40
+
41
+ def usual(message, severity, datetime)
42
+ date_format = datetime.strftime('%FT%T.%L')
43
+ "[#{date_format}] #{severity}: #{message}".color(color(severity)) + "\n"
44
+ end
45
+
46
+ def color(severity)
47
+ case severity
48
+ when 'DEBUG' then :cyan
49
+ when 'INFO' then :green
50
+ when 'WARN' then :yellow
51
+ when 'ERROR' then :red
52
+ when 'FATAL' then :magenta
53
+ else :white
54
+ end
55
+ end
56
+
57
+ def artify_message(msg, font)
58
+ result = []
59
+ msg.each_char do |c|
60
+ o = c.ord
61
+ o = '0' unless font.char?(o)
62
+ font.height.times do |j|
63
+ line = font[o][j]
64
+ result[j] = (result[j] ||= '') + line
65
+ end
66
+ end
67
+ result
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+ require 'alpacabuildtool/log/rainbowify_formatter'
3
+
4
+ module AlpacaBuildTool
5
+ ##
6
+ # RainbowifyLogger class is extending ruby logger
7
+ # with _header_ and _puts_ methods and add colors to logs
8
+ class RainbowifyLogger < Logger
9
+ ##
10
+ # Custom severities that current logger support
11
+ SEVERITIES = %w(DEBUG INFO WARN ERROR FATAL PUTS HEADER)
12
+
13
+ ##
14
+ # Creates instance of logger with STDOUT as IO object
15
+ # for logger and adds RainbowifyFormatter as a formatter
16
+ #
17
+ # Creates ruby logger with STDOUT object and rainbowify formatter
18
+ def initialize
19
+ super(STDOUT)
20
+ @formatter = RainbowifyFormatter.new
21
+ end
22
+
23
+ ##
24
+ # Override logger.format_severity in order to use our own severities
25
+ def format_severity(severity)
26
+ SEVERITIES[severity] || 'ANY'
27
+ end
28
+
29
+ ##
30
+ # Log nice ASCII art styled header
31
+ #
32
+ # +progname+:: program name
33
+ # accepts &block
34
+ def puts(progname = nil, &block)
35
+ add(5, nil, progname, &block)
36
+ end
37
+
38
+ ##
39
+ # Log nice ASCII art styled header
40
+ #
41
+ # +progname+:: program name
42
+ # accepts &block
43
+ def header(progname = nil, &block)
44
+ add(6, nil, progname, &block)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,32 @@
1
+ require 'alpacabuildtool/tools/msbuild'
2
+ require 'alpacabuildtool/managers/package_manager'
3
+
4
+ module AlpacaBuildTool
5
+ ##
6
+ # BuildManager provides methods to build *.sln solutions
7
+ class BuildManager
8
+ ##
9
+ # Creates an instance
10
+ #
11
+ # +solution+:: solution to be used to configure build manager and to be
12
+ # built later
13
+ def initialize(solution)
14
+ @solution = solution
15
+ @package_manager = PackageManager.new(@solution)
16
+ @build_tool = MSBuild.new(@solution.configuration['MSBuild'])
17
+ end
18
+
19
+ ##
20
+ # Build solution
21
+ #
22
+ # +debug+:: set to build in debug mode
23
+ # +update_version:: set to update AssemblyInfo.cs files for all solution
24
+ # projects
25
+ def build(debug, update_version)
26
+ @package_manager.restore_packages
27
+ build_version = @solution.build_version
28
+ @solution.update_projects_version(build_version) if update_version
29
+ @build_tool.build(@solution.file, debug)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,136 @@
1
+ require 'alpacabuildtool/entities/nuspec'
2
+ require 'alpacabuildtool/package_types/project_package'
3
+ require 'alpacabuildtool/package_types/tool_package'
4
+ require 'alpacabuildtool/tools/nuget'
5
+ require 'alpacabuildtool/tools/git'
6
+ require 'fileutils'
7
+
8
+ module AlpacaBuildTool
9
+ ##
10
+ # PackageManager provides package management methods for solution
11
+ class PackageManager < Nuget
12
+ ##
13
+ # Defines where packages used by alpaca should be downloaded
14
+ DOWNLOAD_DIR = File.join(File.expand_path('~'), '.download/')
15
+
16
+ ##
17
+ # Creates an instance
18
+ # Use Nuget as package management tool
19
+ #
20
+ # +solution+:: solution to be used to configure build manager and to be
21
+ # used further
22
+ def initialize(solution)
23
+ @solution = solution
24
+ super(@solution.configuration['Nuget'])
25
+ end
26
+
27
+ ##
28
+ # Returns named tool configured from current solution
29
+ #
30
+ # +name+:: tool name
31
+ # +*args+:: arguments for tool creation
32
+ #
33
+ # package_manager.get('NUnit')
34
+ # # => #<AlpacaBuildTool:NUnit **>
35
+ # package_manager.get('OpenCover', @test_tool)
36
+ # # => #<AlpacaBuildTool:OpenCover @tool=..NUnit..**>
37
+ def get(name, *args)
38
+ config = @solution.configuration[name]
39
+ AlpacaBuildTool.const_get(name).new(config, *args) do
40
+ exe_pattern = File.join(DOWNLOAD_DIR, '**', config['exe'])
41
+ unless Dir.glob(exe_pattern).any?
42
+ id, pre = config['package_id'], config['pre_release'] || false
43
+ install(id, DOWNLOAD_DIR, pre)
44
+ end
45
+ Dir.glob(exe_pattern).first
46
+ end
47
+ end
48
+
49
+ ##
50
+ # Restore packages for solution
51
+ def restore_packages
52
+ if Dir.glob(File.dirname(@solution.file) + '/**/packages.config').empty?
53
+ log.info 'no packages.config discovered'
54
+ return
55
+ end
56
+ restore(@solution.file)
57
+ end
58
+
59
+ ##
60
+ # Create and push if requested nuget package
61
+ #
62
+ # +config+:: package configuration from solution local configuration
63
+ # +version+:: package version to be created
64
+ # +options+:: hash with packaging options
65
+ # <tt>options[:debug] = true</tt> is to create packages from debug mode<br\>
66
+ # <tt>options[:push] = true</tt> is to push packages after they are created
67
+ # <br\>
68
+ # <tt>options[:force] = true</tt> is to create/push packages even if it has
69
+ # no changes
70
+ def create_package(config, version, options)
71
+ config = generate_config(config, version)
72
+ project = @solution.project(config['project'])
73
+ changes, changelog = package_changes(config, project.dir)
74
+ log.info "#{config['id']} unchanged..." unless changes
75
+ return unless changes || options[:force]
76
+ generate_package(project, config, options[:debug], changelog)
77
+ push_packages(config) if options[:push]
78
+ end
79
+
80
+ private
81
+
82
+ def generate_config(config, version)
83
+ common = @solution.configuration['all_packages'] || {}
84
+ common.merge(config).merge('version' => version)
85
+ end
86
+
87
+ def package_changes(config, project_dir)
88
+ FileUtils.rm_rf File.join(DOWNLOAD_DIR, config['id'])
89
+ begin
90
+ changes, changelog = latest_package_changes(config, project_dir)
91
+ rescue
92
+ changes = Git.changes(project_dir)
93
+ end
94
+ new_changes = "#{Git.revision}\n---#{config['version']}---\n#{changes}\n"
95
+ [changes != '', new_changes + (changelog || ['']).reduce(:+)]
96
+ end
97
+
98
+ def latest_package_changes(config, project_dir)
99
+ install(config['id'], DOWNLOAD_DIR, config['version'].include?('-'),
100
+ true, config['source'])
101
+ file = File.join(DOWNLOAD_DIR, config['id'], 'CHANGES.txt')
102
+ changelog = IO.readlines(file)
103
+ commit_id = changelog.shift.gsub(/\n/, '')
104
+ [Git.changes(project_dir, commit_id), changelog]
105
+ end
106
+
107
+ def generate_package(project, config, debug, changelog)
108
+ package = typed_package(config['type'], config['id'], project, debug)
109
+ write_mandatory_files(package, config, changelog)
110
+ write_optional_file(package.files[2], config)
111
+ pack(*package.options)
112
+ end
113
+
114
+ def typed_package(type, id, project, debug)
115
+ AlpacaBuildTool.const_get("#{type.capitalize}Package")
116
+ .new(id, project, debug)
117
+ end
118
+
119
+ def write_mandatory_files(package, config, changelog)
120
+ File.write(package.files[0], Nuspec.new(config, package.add_files?).to_s)
121
+ File.write(package.files[1], changelog)
122
+ end
123
+
124
+ def write_optional_file(file, config)
125
+ File.write(file, config['readme']) if config['readme']
126
+ end
127
+
128
+ def push_packages(config)
129
+ output_dir = @configuration['commands']['pack']['OutputDirectory']
130
+ file = File.join(output_dir, "#{config['id']}.#{config['version']}")
131
+ push("#{file}.nupkg", config['source'])
132
+ symbols = "#{file}.symbols.nupkg"
133
+ push(symbols, config['symbol_source']) if File.exist?(symbols)
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,33 @@
1
+ require 'alpacabuildtool/tools/nunit_orange'
2
+ require 'alpacabuildtool/tools/report_generator'
3
+ require 'alpacabuildtool/managers/package_manager'
4
+
5
+ module AlpacaBuildTool
6
+ ##
7
+ # ReportManager provides methods to convert test results to reports
8
+ class ReportManager
9
+ ##
10
+ # Creates an instance
11
+ #
12
+ # +solution+:: solution to be used to configure reports manager
13
+ def initialize(solution)
14
+ package_manager = PackageManager.new(solution)
15
+ @test_tool = package_manager.get('NUnitOrange')
16
+ @coverage_tool = package_manager.get('ReportGenerator')
17
+ end
18
+
19
+ ##
20
+ # Convert results to reports
21
+ #
22
+ # +type+:: type of results to be converted(tests, coverage, all)
23
+ def convert(type)
24
+ case type
25
+ when 'tests' then @test_tool.convert
26
+ when 'coverage' then @coverage_tool.convert
27
+ when 'all'
28
+ @test_tool.convert
29
+ @coverage_tool.convert
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ require 'alpacabuildtool/tools/nunit'
2
+ require 'alpacabuildtool/tools/open_cover'
3
+ require 'alpacabuildtool/managers/package_manager'
4
+
5
+ module AlpacaBuildTool
6
+ ##
7
+ # TestManager provides methods to test *.sln solutions
8
+ class TestManager
9
+ ##
10
+ # Creates an instance
11
+ #
12
+ # +solution+:: solution to be used to configure test manager
13
+ def initialize(solution)
14
+ package_manager = PackageManager.new(solution)
15
+ @test_tool = package_manager.get('NUnit')
16
+ @coverage_tool = package_manager.get('OpenCover', @test_tool)
17
+ end
18
+
19
+ ##
20
+ # Test list of projects
21
+ #
22
+ # +test_projects+:: list of projects with tests
23
+ # +coverage+:: set to run coverage
24
+ # +debug+:: set to run tests with debug configuration
25
+ def test(test_projects, coverage = false, debug = false)
26
+ test_projects.each do |project|
27
+ if coverage
28
+ @coverage_tool.call { |tool| tool.test(project.file, debug) }
29
+ else
30
+ @test_tool.test(project.file, debug)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ require 'rbconfig'
2
+
3
+ module AlpacaBuildTool
4
+ ##
5
+ # Os provides methods to simplify defining host os
6
+ module Os
7
+ ##
8
+ # Returns host os as :windows, :macosx, :linux or :unix
9
+ def self.os
10
+ @os ||= (
11
+ host_os = RbConfig::CONFIG['host_os']
12
+ get_os(host_os)
13
+ )
14
+ end
15
+
16
+ def self.get_os(host_os)
17
+ case host_os
18
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ then :windows
19
+ when /darwin|mac os/ then :macosx
20
+ when /linux/ then :linux
21
+ when /solaris|bsd/ then :unix
22
+ else
23
+ fail "unknown os: #{host_os.inspect}"
24
+ end
25
+ end
26
+
27
+ private_class_method :get_os
28
+ end
29
+ end
@@ -0,0 +1,44 @@
1
+ module AlpacaBuildTool
2
+ ##
3
+ # ProjectPackage provides configuration of normal nuget packages created
4
+ # from projects
5
+ class ProjectPackage
6
+ ##
7
+ # Creates an instance
8
+ #
9
+ # +package_id+:: not used in current class, but need to be here for
10
+ # consistent interface with other package types
11
+ # +project+:: project to be used to create a package
12
+ # +debug+:: is debug configuration should be used to create a package
13
+ def initialize(_, project, debug)
14
+ @nuspec_file = File.join(project.dir, "#{project.name}.nuspec")
15
+ @readme_file = File.join(project.dir, 'README.txt')
16
+ @changelog_file = File.join(project.dir, 'CHANGES.txt')
17
+ @file = project.file
18
+ @debug = debug
19
+ end
20
+
21
+ ##
22
+ # Returns array of files: *.nuspec, CHANGELOG.txt, README.txt
23
+ def files
24
+ [@nuspec_file, @changelog_file, @readme_file]
25
+ end
26
+
27
+ ##
28
+ # Returns options to be passed to Nuget.pack
29
+ def options
30
+ [@file, @debug ? 'Debug' : 'Release']
31
+ end
32
+
33
+ ##
34
+ # Returns true so Nuspec file creation process will store readme and
35
+ # changelog files into <files/> entry
36
+ #
37
+ # This is required for normal packages as they are created from *.csproj
38
+ # but adding them for :tool packages cause missing all other files as
39
+ # :tool package is created from folder and not *.csproj
40
+ def add_files?
41
+ true
42
+ end
43
+ end
44
+ end