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,107 @@
1
+ require 'alpacabuildtool/entities/xml'
2
+
3
+ module AlpacaBuildTool
4
+ ##
5
+ # Nuspec creates *.nuspec file content
6
+ #
7
+ # Nuspec.new(id: 'Cool.Package',
8
+ # version: '0.0.1',
9
+ # description: 'something',
10
+ # authors: ['Vasyl', 'Kate'],
11
+ # false).to_s
12
+ # # => <?xml version="1.0"?>
13
+ # # <package>
14
+ # # <metadata>
15
+ # # <id>Cool.Package</id>
16
+ # # <version>0.0.1</version>
17
+ # # <authors>Vasyl,Kate</authors>
18
+ # # <description>something</description>
19
+ # # </metadata>
20
+ # # </package>
21
+ class Nuspec
22
+ OPTIONAL = %w(title licenseUrl projectUrl copyright iconUrl
23
+ requireLicenseAcceptance releaseNotes)
24
+
25
+ ##
26
+ # Creates instance and generate content from *package* config
27
+ #
28
+ # +package+:: package configuration
29
+ # +add_common_files+:: flag to add files like README and CHANGELOG
30
+ def initialize(package, add_common_files = true)
31
+ @content = generate(package, add_common_files)
32
+ end
33
+
34
+ ##
35
+ # Overrides to_s method to create string content from inner Xml object
36
+ def to_s
37
+ @content.to_s
38
+ end
39
+
40
+ ##
41
+ # Returns Xml object representation of package nuspec
42
+ #
43
+ # +config+:: package configuration
44
+ # +add_common_files+:: flag to add common files or not
45
+ def generate(config, add_common_files)
46
+ Xml.new '1.0' do
47
+ node 'package' do |package|
48
+ Nuspec.add_metadata(package, config)
49
+ Nuspec.add_files(package, config) if add_common_files
50
+ end
51
+ end
52
+ end
53
+
54
+ ##
55
+ # Adds metadata entry to nuspec
56
+ #
57
+ # +package+:: XmlNode where to add metadata
58
+ # +config+:: package configuration
59
+ def self.add_metadata(package, config)
60
+ package.node 'metadata' do |metadata|
61
+ Nuspec.add_mandatory_fields(metadata, config)
62
+ Nuspec.add_optional_fields(metadata, config)
63
+ end
64
+ end
65
+
66
+ ##
67
+ # Adds mandatory entries to nuspec like id, version, authors and description
68
+ #
69
+ # +metadata+:: XmlNode where to add entries
70
+ # +config+:: package configuration
71
+ def self.add_mandatory_fields(metadata, config)
72
+ metadata.node 'id', config['id']
73
+ metadata.node 'version', config['version']
74
+ metadata.node 'authors', config['authors'].join(',')
75
+ metadata.node 'description', config['description']
76
+ end
77
+
78
+ ##
79
+ # Adds optional entries to nuspec like owners, tags and so on
80
+ #
81
+ # +metadata+:: XmlNode where to add entries
82
+ # +config+:: package configuration
83
+ def self.add_optional_fields(metadata, config)
84
+ OPTIONAL.each { |name| metadata.node(name, config[name]) if config[name] }
85
+ metadata.node 'owners', config['owners'].join(',') if config['owners']
86
+ metadata.node 'tags', config['tags'].join(' ') if config['tags']
87
+ end
88
+
89
+ ##
90
+ # Adds README.txt and CHANGES.txt files
91
+ #
92
+ # +package+:: XmlNode where to add files entry
93
+ # +config+:: package configuration
94
+ def self.add_files(package, config)
95
+ package.node 'files' do
96
+ node 'file' do
97
+ attribute 'src', 'README.txt'
98
+ attribute 'target', ''
99
+ end if config['readme']
100
+ node 'file' do
101
+ attribute 'src', 'CHANGES.txt'
102
+ attribute 'target', ''
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,54 @@
1
+ module AlpacaBuildTool
2
+ ##
3
+ # VisualStudioProject provides project representation and methods
4
+ # to modify it's AssemblyVersion.cs file
5
+ class Project
6
+ attr_accessor :name, :file, :dir
7
+
8
+ ##
9
+ # Creates instance of class
10
+ #
11
+ # +line+:: line from .sln file with project information
12
+ # +dir+:: solution directory
13
+ #
14
+ # s = AlpacaBuildTool::VisualStudioProject.new(
15
+ # 'Project("{FAE04EC0...5254043711}"'
16
+ # 'd:\')
17
+ # # => #<**:VisualStudioProject:** @file="d:/sln1/some.csproj" **>
18
+ def initialize(line, dir)
19
+ items = line.gsub(/".*?"/).to_a
20
+ _, @name, file, _ = items.map { |item| item.to_s.gsub('"', '') }
21
+ dir = File.expand_path(dir)
22
+ @dir = File.dirname(File.join(dir, file))
23
+ @file = File.join(dir, file)
24
+ end
25
+
26
+ ##
27
+ # Overrides *to_s* method to provide nice convertion to string
28
+ def to_s
29
+ "{#{@name};#{@file}}"
30
+ end
31
+
32
+ ##
33
+ # Updates AssemblyInfo.cs file under the project with new_version
34
+ #
35
+ # +new_version+:: version that need to be used as assembly version
36
+ # and assembly file version
37
+ def update_version(new_version)
38
+ info_file = File.join(@dir, 'Properties', 'AssemblyInfo.cs')
39
+ content = IO.readlines(info_file)
40
+ open(info_file, 'w') do |io|
41
+ content.each { |line| io.write replace_version(line, new_version) }
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def replace_version(line, new_version)
48
+ line = line.gsub(/AssemblyVersion\("(.*?)"\)/,
49
+ "AssemblyVersion(\"#{new_version}\")")
50
+ line.gsub(/AssemblyFileVersion\("(.*?)"\)/,
51
+ "AssemblyFileVersion(\"#{new_version}\")")
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,104 @@
1
+ require 'alpacabuildtool/log/log'
2
+ require 'alpacabuildtool/configuration'
3
+ require 'alpacabuildtool/entities/project'
4
+ require 'alpacabuildtool/versioning/versioning'
5
+
6
+ module AlpacaBuildTool
7
+ ##
8
+ # Solution provides solution representation and it's configuration storage
9
+ class Solution
10
+ include Log
11
+
12
+ attr_reader :file, :dir, :projects
13
+
14
+ ##
15
+ # Creates instance from *.sln file
16
+ # Initializes solution's semantic version and absolute path to it's file
17
+ #
18
+ # +file+:: absolute or relative path to *.sln file
19
+ def initialize(file)
20
+ @file = File.expand_path(file)
21
+ @dir = File.dirname(@file)
22
+ @semver = Versioning.find(@dir)
23
+ end
24
+
25
+ ##
26
+ # Overrides string representation. Spawned to multiple lines
27
+ def to_s
28
+ s = '------------'
29
+ s += "\nFile: #{@file}"
30
+ s += "\nVersion: #{build_version}"
31
+ s += "\nProjects:" unless projects.empty?
32
+ projects.each { |p| s += "\n\t#{p}" }
33
+ s + "\n------------"
34
+ end
35
+
36
+ ##
37
+ # Returns Configuration object for current solution (initialized only once)
38
+ def configuration
39
+ @configuration ||= Configuration.new(self)
40
+ end
41
+
42
+ ##
43
+ # Returns array of it's projects (initialized only once)
44
+ def projects
45
+ return @projects if @projects
46
+ @projects = []
47
+ IO.readlines(@file).each do |line|
48
+ @projects << Project.new(line, @dir) if /^Project.*\.csproj/ =~ line
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Returns specific project by it's name
54
+ #
55
+ # +name+:: project's name
56
+ def project(name)
57
+ @projects.find { |p| p.name == name }
58
+ end
59
+
60
+ ##
61
+ # Updates all projects AssemblyInfo.cs files with specific version
62
+ #
63
+ # +version+:: version to be stored in AssemblyInfo.cs files
64
+ def update_projects_version(version)
65
+ projects.each do |project|
66
+ project.update_version version
67
+ end
68
+ end
69
+
70
+ ##
71
+ # Returns array of projects that correspondes to specific type
72
+ #
73
+ # +type+:: type of project defined in configuration project_types
74
+ def specific_projects(type)
75
+ types = configuration['project_types'].dup
76
+ types.select! { |t| t['type'] == type } unless type == 'all'
77
+ projects.select do |project|
78
+ types.any? { |t| project.name.include? t['name'] }
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Returns true if solution is marked as *nobuild*
84
+ def no_build?
85
+ solution_name = File.basename(@file, '.*')
86
+ (configuration['no_build'] || []).each do |tag|
87
+ return true if solution_name.include?(tag)
88
+ end
89
+ false
90
+ end
91
+
92
+ ##
93
+ # Returns current build version
94
+ def build_version
95
+ @semver.to_s '%M.%m.%p'
96
+ end
97
+
98
+ ##
99
+ # Returns current package version
100
+ def package_version
101
+ @semver.to_s '%M.%m.%p%s'
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,41 @@
1
+ require 'alpacabuildtool/entities/xml_node'
2
+
3
+ module AlpacaBuildTool
4
+ ##
5
+ # Xml represents simple xml document with one root node
6
+ #
7
+ # doc = Xml.new '1.0' do
8
+ # node 'a', 'b'
9
+ # end
10
+ # doc.to_s
11
+ # # => <?xml version="1.0"?>
12
+ # # <a>b</a>
13
+ class Xml
14
+ ##
15
+ # Creates instance
16
+ #
17
+ # +version+:: xml version
18
+ # accepts &block
19
+ def initialize(version, &block)
20
+ @version, @root_node = version, nil
21
+ instance_eval(&block) if block_given?
22
+ end
23
+
24
+ ##
25
+ # Set/override root node
26
+ #
27
+ # +name+:: node name
28
+ # +content+:: node content
29
+ # accepts &block
30
+ def node(name, content = nil, &block)
31
+ @root = XmlNode.new(name, content, &block)
32
+ end
33
+
34
+ ##
35
+ # Overrides string representation to generate xml document content from
36
+ # stored objects
37
+ def to_s
38
+ "<?xml version=\"#{@version}\"?>\n#{@root}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,75 @@
1
+ require 'cgi'
2
+
3
+ module AlpacaBuildTool
4
+ ##
5
+ # XmlNode represents simple xml node that can contain attributes and other
6
+ # nodes or string as a content
7
+ class XmlNode
8
+ attr_reader :name, :content
9
+
10
+ ##
11
+ # Creates an instance
12
+ #
13
+ # +name+:: name of node
14
+ # +content+:: content of node (if set, block is ignored)
15
+ # accepts &block to set content to array of nodes
16
+ def initialize(name, content = nil, &block)
17
+ @name = name
18
+ return @content = content unless content.nil?
19
+ return unless block_given?
20
+ @arity = block.arity
21
+ if @arity <= 0
22
+ @context = eval('self', block.binding)
23
+ instance_eval(&block)
24
+ else
25
+ yield self
26
+ end
27
+ end
28
+
29
+ ##
30
+ # Adds new node into content
31
+ #
32
+ # +name+:: node name
33
+ # +content+:: node content
34
+ # accepts &block for this new node
35
+ #
36
+ # XmlNode.new 'a' do
37
+ # node 'b' do
38
+ # node 'c' do
39
+ # ...
40
+ # end
41
+ # end
42
+ # end
43
+ def node(name, content = nil, &block)
44
+ (@content ||= []) << XmlNode.new(name, content, &block)
45
+ end
46
+
47
+ ##
48
+ # Adds attribute to node
49
+ #
50
+ # +name+:: attribute name
51
+ # +value+:: attribute value
52
+ def attribute(name, value)
53
+ (@attributes ||= {})[name] = value
54
+ end
55
+
56
+ ##
57
+ # Overrides string representation to populate xml pretty formatted content
58
+ def to_s
59
+ return "<#{@name}#{attributes_to_s}/>" if @content.nil?
60
+ content = @content.is_a?(Array) ? array_to_s : CGI.escape_html(@content)
61
+ "<#{@name}#{attributes_to_s}>#{content}</#{@name}>"
62
+ end
63
+
64
+ private
65
+
66
+ def attributes_to_s
67
+ (@attributes || {}).map { |n, v| " #{n}=\"#{v}\"" }.reduce(&:+)
68
+ end
69
+
70
+ def array_to_s
71
+ nodes = @content.map { |n| "\t#{n}".gsub(/\n/, "\n\t") }
72
+ "\n#{nodes.join("\n")}\n"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,92 @@
1
+ module AlpacaBuildTool
2
+ ##
3
+ # Font class provides representation of .flf fonts so they can be used
4
+ class Font
5
+ attr_reader :height, :hard_blank
6
+
7
+ ##
8
+ # Absolute path to data folder where *.flf fonts stored
9
+ FONTPATH = File.expand_path(File.dirname(__FILE__) + '/../data')
10
+
11
+ ##
12
+ # Creates instance of class
13
+ #
14
+ # +name+:: font name(currently 'doom' or 'lean' exist)
15
+ def initialize(name)
16
+ @filename = File.join FONTPATH, name + '.flf'
17
+ File.open(@filename, 'rb') do |f|
18
+ header = f.gets.strip.split(/ /)
19
+ @hard_blank = header[0]
20
+ @height = header[1].to_i
21
+ load_characters f
22
+ end
23
+ end
24
+
25
+ ##
26
+ # Returns true if font have representation for char.ord
27
+ #
28
+ # +ord+:: character code(char.ord)
29
+ def char?(ord)
30
+ @characters.key? ord
31
+ end
32
+
33
+ ##
34
+ # Returns array of lines that represent current character
35
+ #
36
+ # +ord+:: character code(char.ord)
37
+ def [](ord)
38
+ @characters[ord]
39
+ end
40
+
41
+ private
42
+
43
+ def load_characters(file)
44
+ @characters = {}
45
+ load_ascii_characters file
46
+ load_german_characters file
47
+ load_extended_characters file
48
+ end
49
+
50
+ def load_ascii_characters(file)
51
+ (32..126).each { |i| @characters[i] = load_char(file) }
52
+ end
53
+
54
+ def load_german_characters(file)
55
+ [91, 92, 93, 123, 124, 125, 126].each do |i|
56
+ char = load_char(file)
57
+ break unless char
58
+ @characters[i] = char
59
+ end
60
+ end
61
+
62
+ def load_extended_characters(file)
63
+ until file.eof?
64
+ i = file.gets.strip.split(/ /).first
65
+ if i && i.empty?
66
+ next
67
+ else
68
+ char = load_char(file)
69
+ return unless char
70
+ @characters[i] = char
71
+ end
72
+ end
73
+ end
74
+
75
+ def load_char(file)
76
+ char = []
77
+ @height.times do
78
+ return false if file.eof?
79
+ char << load_line(file)
80
+ end
81
+ char
82
+ end
83
+
84
+ def load_line(file)
85
+ line = file.gets.rstrip
86
+ match = /(.){1,2}$/.match(line)
87
+ line.gsub!(match[1], '') if match
88
+ line << "\x00"
89
+ line
90
+ end
91
+ end
92
+ end