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