alpacabuildtool 1.0.0

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 (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