azdeploy 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/azdeploy.gemspec +12 -0
- data/lib/azdeploy.rb +24 -0
- data/lib/build.rb +70 -0
- data/lib/install.rb +164 -0
- data/lib/transform.rb +198 -0
- data/test/test_azdeploy.rb +4 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: be5422007de61780aa459e834d63cf996d6fda32
|
4
|
+
data.tar.gz: 601aa46de58bb4eb17158a2e8224630061388fcc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e23c42da14ece36254964e73d03b413ca3807f8bb19e245df3883c2526406142a40a028606c48526444f14158b86fa86a919d7c21b349476470af4d6a1f0a794
|
7
|
+
data.tar.gz: ea6b688efcc233f74c08bf09e901fcd6ea9ca94b975d79220221fa9d7b737a6126ab9871d8b91c905d91348326b0e4256448e814031e464b9bdb805bce4831b9
|
data/azdeploy.gemspec
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'azdeploy'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.date = '2015-02-04'
|
5
|
+
s.summary = 'Setup and scripting support for .Net project builds'
|
6
|
+
s.description = 'Azure Deployment Gem. Provides easy setup and deployment scripting support for .Net project builds'
|
7
|
+
s.authors = ['Suresh Batta']
|
8
|
+
s.email = 'subatta@hotmail.com'
|
9
|
+
s.files = Dir['{test,lib,docs}/**/*'] + ['azdeploy.gemspec']
|
10
|
+
s.homepage = 'http://rubygems.org/gems/azdeploy'
|
11
|
+
s.license = 'MIT'
|
12
|
+
end
|
data/lib/azdeploy.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'install.rb'
|
2
|
+
require_relative 'transform.rb'
|
3
|
+
require_relative 'build.rb'
|
4
|
+
|
5
|
+
# installation
|
6
|
+
installers = [
|
7
|
+
'Ruby', 'Devkit', 'Doxygen', 'Gems'
|
8
|
+
]
|
9
|
+
|
10
|
+
installers.each { |method|
|
11
|
+
exit if !send("check#{method}")
|
12
|
+
}
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'nokogiri'
|
16
|
+
require 'azure'
|
17
|
+
|
18
|
+
# config transform
|
19
|
+
transform
|
20
|
+
|
21
|
+
# includes for rake build
|
22
|
+
include FileTest
|
23
|
+
require 'albacore'
|
24
|
+
require 'semver'
|
data/lib/build.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
def copy_output_files(fromDir, filePattern, outDir)
|
2
|
+
FileUtils.mkdir_p outDir unless exists?(outDir)
|
3
|
+
Dir.glob(File.join(fromDir, filePattern)){|file|
|
4
|
+
copy(file, outDir) if File.file?(file)
|
5
|
+
}
|
6
|
+
end
|
7
|
+
|
8
|
+
def project_outputs(props)
|
9
|
+
props[:projects].map{ |p| "src/#{p}/bin/#{BUILD_CONFIG}/#{p}.dll" }.
|
10
|
+
concat( props[:projects].map{ |p| "src/#{p}/bin/#{BUILD_CONFIG}/#{p}.exe" } ).
|
11
|
+
find_all{ |path| exists?(path) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_commit_hash_and_date
|
15
|
+
begin
|
16
|
+
commit = `git log -1 --pretty=format:%H`
|
17
|
+
git_date = `git log -1 --date=iso --pretty=format:%ad`
|
18
|
+
commit_date = DateTime.parse( git_date ).strftime("%Y-%m-%d %H%M%S")
|
19
|
+
rescue
|
20
|
+
commit = "git unavailable"
|
21
|
+
end
|
22
|
+
|
23
|
+
[commit, commit_date]
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_files stage, what_dlls, nuspec, folder='lib'
|
27
|
+
[['net35', 'net-3.5'], ['net40', 'net-4.0'], ['net45', 'net-4.5']].each{|fw|
|
28
|
+
takeFrom = File.join(stage, fw[1], what_dlls)
|
29
|
+
Dir.glob(takeFrom).each do |f|
|
30
|
+
nuspec.file(f.gsub("/", "\\"), "#{folder}\\#{fw[0]}")
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def commit_data
|
36
|
+
begin
|
37
|
+
commit = `git rev-parse --short HEAD`.chomp()[0,6]
|
38
|
+
git_date = `git log -1 --date=iso --pretty=format:%ad`
|
39
|
+
commit_date = DateTime.parse( git_date ).strftime("%Y-%m-%d %H%M%S")
|
40
|
+
rescue Exception => e
|
41
|
+
puts e.inspect
|
42
|
+
commit = (ENV['BUILD_VCS_NUMBER'] || "000000")[0,6]
|
43
|
+
commit_date = Time.new.strftime("%Y-%m-%d %H%M%S")
|
44
|
+
end
|
45
|
+
[commit, commit_date]
|
46
|
+
end
|
47
|
+
|
48
|
+
def waitfor(&block)
|
49
|
+
checks = 0
|
50
|
+
|
51
|
+
until block.call || checks >10
|
52
|
+
sleep 0.5
|
53
|
+
checks += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
raise 'Waitfor timeout expired. Make sure that you aren\'t running something from the build output folders, or that you have browsed to it through Explorer.' if checks > 10
|
57
|
+
end
|
58
|
+
|
59
|
+
def cleantask(props)
|
60
|
+
|
61
|
+
FileUtils.rm_rf props[:output]
|
62
|
+
waitfor { !exists?(props[:output]) }
|
63
|
+
|
64
|
+
FileUtils.rm_rf props[:artifacts]
|
65
|
+
waitfor { !exists?(props[:artifacts]) }
|
66
|
+
|
67
|
+
Dir.mkdir props[:output]
|
68
|
+
Dir.mkdir props[:artifacts]
|
69
|
+
|
70
|
+
end
|
data/lib/install.rb
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
def downloadFile(sourcePath, filePath, localFileLocation)
|
4
|
+
Net::HTTP.start(sourcePath) do |http|
|
5
|
+
resp = http.get(filePath)
|
6
|
+
f = open(localFileLocation, 'wb')
|
7
|
+
begin
|
8
|
+
requestPath = "http://#{sourcePath}#{filePath}"
|
9
|
+
puts "Downloading #{requestPath}..."
|
10
|
+
http.request_get(requestPath) do |resp|
|
11
|
+
resp.read_body do |segment|
|
12
|
+
f.write(segment)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue
|
16
|
+
puts $!
|
17
|
+
return false
|
18
|
+
ensure
|
19
|
+
f.close()
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
def installFile(cmd, versionedExeFile)
|
26
|
+
begin
|
27
|
+
installerOutput = `#{cmd}`
|
28
|
+
puts installerOutput
|
29
|
+
rescue
|
30
|
+
puts $!
|
31
|
+
return false
|
32
|
+
ensure
|
33
|
+
puts 'Cleaning up...'
|
34
|
+
cmd = "#{versionedExeFile}"
|
35
|
+
installerOutput = `del #{cmd}`
|
36
|
+
puts installerOutput
|
37
|
+
end
|
38
|
+
return true
|
39
|
+
end
|
40
|
+
|
41
|
+
def gemExists(name, version)
|
42
|
+
begin
|
43
|
+
gem name, version
|
44
|
+
rescue Gem::LoadError
|
45
|
+
puts "failed to load gem #{name} -v #{version}"
|
46
|
+
Gem.clear_paths
|
47
|
+
return false
|
48
|
+
end
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
|
52
|
+
# Ruby version check
|
53
|
+
def checkRuby
|
54
|
+
puts 'Checking ruby version...'
|
55
|
+
# check if expected ruby version exists. If not download and install ruby
|
56
|
+
rubyVersion = "#{RUBY_VERSION}"
|
57
|
+
localVersion = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
58
|
+
expectedVersion = '2.0.0-p481'
|
59
|
+
defaultInstallPath = 'Ruby200'
|
60
|
+
if (!rubyVersion.nil? && localVersion != expectedVersion)
|
61
|
+
puts "Uninstall incompatible version of ruby: #{localVersion} and install version: #{expectedVersion}"
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
if (rubyVersion.nil?)
|
65
|
+
puts 'Expected ruby version #{expectedVersion} not found'
|
66
|
+
|
67
|
+
sourcePath = 'dl.bintray.com'
|
68
|
+
versionedExeFile = "rubyinstaller-#{expectedVersion}.exe"
|
69
|
+
filePath = "/oneclick/rubyinstaller/#{versionedExeFile}?direct"
|
70
|
+
return false if !downloadFile(sourcePath, filePath, versionedExeFile)
|
71
|
+
|
72
|
+
puts 'Ruby installation in progress...'
|
73
|
+
cmd = "#{versionedExeFile} /silent /tasks=\"assocfiles,modpath\""
|
74
|
+
puts cmd
|
75
|
+
return false if !installFile(cmd, versionedExeFile)
|
76
|
+
end
|
77
|
+
puts 'Ruby ok'
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
|
81
|
+
### devkit version check
|
82
|
+
def checkDevkit
|
83
|
+
# check if devkit exists
|
84
|
+
puts 'Checking devkit version...'
|
85
|
+
rubyPath = `where.exe ruby.exe`
|
86
|
+
rubyPath['bin\ruby.exe'] = 'devkit'
|
87
|
+
rubyPath = rubyPath.sub("\n", '') #doublequotes required for Line break, gotcha
|
88
|
+
if (!File.directory?(rubyPath))
|
89
|
+
puts 'devkit not found'
|
90
|
+
# if not download, install and setup devkit
|
91
|
+
puts 'Downloading devkit...'
|
92
|
+
|
93
|
+
sourcePath = 'cdn.rubyinstaller.org'
|
94
|
+
versionedExeFile = 'DevKit-mingw64-32-4.7.2-20130224-1151-sfx.exe'
|
95
|
+
filePath = "/archives/devkits/#{versionedExeFile}?direct"
|
96
|
+
return false if !downloadFile(sourcePath, filePath, versionedExeFile)
|
97
|
+
|
98
|
+
puts 'Devkit installation in progress...'
|
99
|
+
cmd = "#{versionedExeFile} -y -o\"#{rubyPath}\"" #no space after -o, gotcha
|
100
|
+
puts cmd
|
101
|
+
return false if !installFile(cmd, versionedExeFile)
|
102
|
+
|
103
|
+
puts 'Setting up devkit...'
|
104
|
+
Dir.chdir "#{rubyPath}"
|
105
|
+
cmd = 'ruby dk.rb init'
|
106
|
+
cmdoutput = `#{cmd}`
|
107
|
+
puts cmdoutput
|
108
|
+
if !cmdoutput.to_s.include?('Initialization complete!')
|
109
|
+
puts 'Error: could not initialize devkit.'
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
|
113
|
+
cmd = 'ruby dk.rb review'
|
114
|
+
cmdoutput = `#{cmd}`
|
115
|
+
puts cmdoutput
|
116
|
+
if !cmdoutput.to_s.include?('DevKit functionality will be injected')
|
117
|
+
puts 'Error: devkit review failed'
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
|
121
|
+
cmd = 'ruby dk.rb install'
|
122
|
+
cmdoutput = `#{cmd}`
|
123
|
+
puts cmdoutput
|
124
|
+
puts 'Restart console since environment variables are now updated'
|
125
|
+
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
puts 'devkit ok'
|
130
|
+
return true
|
131
|
+
end
|
132
|
+
|
133
|
+
# doxygen check
|
134
|
+
def checkDoxygen
|
135
|
+
# download doxygen
|
136
|
+
return true
|
137
|
+
end
|
138
|
+
|
139
|
+
# check and install required gems
|
140
|
+
def checkGems
|
141
|
+
puts 'Checking required gems...'
|
142
|
+
gemlist = {
|
143
|
+
'albacore' => '0.3.6',
|
144
|
+
'semver' => '1.0.1',
|
145
|
+
'nokogiri' => '1.6.4.1',
|
146
|
+
'azure' => '0.6.4'
|
147
|
+
}
|
148
|
+
gemlist.each {|key, value|
|
149
|
+
if !gemExists(key, "=#{value}")
|
150
|
+
begin
|
151
|
+
puts "Installing missing gem: #{key}"
|
152
|
+
cmd = "gem install #{key} -v #{value}"
|
153
|
+
cmdoutput = `#{cmd}`
|
154
|
+
puts cmdoutput
|
155
|
+
rescue
|
156
|
+
puts 'gem install failed'
|
157
|
+
puts $!
|
158
|
+
return false # don't continue if even one gem install fails
|
159
|
+
end
|
160
|
+
end
|
161
|
+
}
|
162
|
+
# all gems installed
|
163
|
+
return true
|
164
|
+
end
|
data/lib/transform.rb
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
def get(key)
|
2
|
+
begin
|
3
|
+
result = @svc.get_entity(@table, @env, key)
|
4
|
+
rescue
|
5
|
+
puts $!
|
6
|
+
puts "key : #{@key}"
|
7
|
+
puts
|
8
|
+
end
|
9
|
+
|
10
|
+
result
|
11
|
+
end
|
12
|
+
|
13
|
+
def getAll
|
14
|
+
begin
|
15
|
+
query = { :filter => "PartitionKey eq '#{@env}'" }
|
16
|
+
result = @svc.query_entities(@table, query)
|
17
|
+
rescue
|
18
|
+
puts $!
|
19
|
+
puts "Env : #{@env}"
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def getValue(key)
|
27
|
+
value = ''
|
28
|
+
@settings.each { |i|
|
29
|
+
if i.properties['RowKey'] == key
|
30
|
+
value = i.properties['setting']
|
31
|
+
break
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
value
|
36
|
+
end
|
37
|
+
|
38
|
+
def transformAppSettings
|
39
|
+
# go to each file and replace value of matching appSettings key
|
40
|
+
@configFiles.each{|file|
|
41
|
+
doc = Nokogiri::XML(File.read(file))
|
42
|
+
puts "Processing file: #{file}"
|
43
|
+
@settings.each { |i|
|
44
|
+
key = i.properties['RowKey']
|
45
|
+
node = doc.at_css "appSettings/add[@key='#{key}']"
|
46
|
+
if !node.nil?
|
47
|
+
oldVal = node['value']
|
48
|
+
#puts "Old value: #{oldVal}"
|
49
|
+
node['value'] = i.properties['setting']
|
50
|
+
newVal = node['value']
|
51
|
+
#puts "New value: #{newVal}"
|
52
|
+
end
|
53
|
+
}
|
54
|
+
File.write(file, doc.to_xml)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def transformServiceModelConfig
|
59
|
+
@configFiles.each{|file|
|
60
|
+
doc = Nokogiri::XML(File.read(file))
|
61
|
+
doc.xpath('//system.serviceModel').each do |node|
|
62
|
+
#puts node
|
63
|
+
if file.end_with?('app.config') || file.end_with?('App.config')
|
64
|
+
node.replace(getValue('system.ServiceModel.Client')) if !node.nil?
|
65
|
+
elsif file.end_with?('Web.config')
|
66
|
+
node.replace(getValue('system.ServiceModel.Service')) if !node.nil?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
File.write(file, doc.to_xml)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def transformSystemWebCompilationAttribs
|
74
|
+
@configFiles.each{|file|
|
75
|
+
doc = Nokogiri::XML(File.read(file))
|
76
|
+
node = doc.at_css "compilation"
|
77
|
+
if !node.nil?
|
78
|
+
#puts node
|
79
|
+
node.xpath('//@debug').remove
|
80
|
+
node.xpath('//@tempDirectory').remove
|
81
|
+
#puts node
|
82
|
+
File.write(file, doc.to_xml)
|
83
|
+
end
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def transformCsdef
|
88
|
+
csdef = Dir.glob("**/*.csdef")
|
89
|
+
csdef.each{ |file|
|
90
|
+
doc = Nokogiri::XML(File.read(file))
|
91
|
+
|
92
|
+
node = doc.at_css "ServiceDefinition"
|
93
|
+
node['name'] = ENV['ServiceName'] if !node.nil?
|
94
|
+
|
95
|
+
node = doc.at_css "WebRole"
|
96
|
+
node['name'] = ENV['ServiceName'] if !node.nil?
|
97
|
+
|
98
|
+
node = doc.at_css "Certificates"
|
99
|
+
node.replace(getValue('Certificates_csdef')) if !node.nil?
|
100
|
+
|
101
|
+
node = doc.at_css "Endpoints"
|
102
|
+
node.replace(getValue('Endpoints')) if !node.nil?
|
103
|
+
|
104
|
+
node = doc.at_css "Bindings"
|
105
|
+
node.replace(getValue('Bindings')) if !node.nil?
|
106
|
+
|
107
|
+
File.write(file, doc.to_xml)
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def transformCscfg
|
112
|
+
csdef = Dir.glob("**/*.cscfg")
|
113
|
+
csdef.each{ |file|
|
114
|
+
doc = Nokogiri::XML(File.read(file))
|
115
|
+
|
116
|
+
node = doc.at_css "ServiceConfiguration"
|
117
|
+
node['serviceName'] = ENV['ServiceName'] if !node.nil?
|
118
|
+
|
119
|
+
node = doc.at_css "Role"
|
120
|
+
node['name'] = ENV['ServiceName'] if !node.nil?
|
121
|
+
|
122
|
+
node = doc.at_css "Certificates"
|
123
|
+
node.replace(getValue('Certificates_cscfg')) if !node.nil?
|
124
|
+
|
125
|
+
File.write(file, doc.to_xml)
|
126
|
+
}
|
127
|
+
end
|
128
|
+
|
129
|
+
def transformDiagnosticsCfg
|
130
|
+
csdef = Dir.glob("**/*.wadcfgx")
|
131
|
+
csdef.each{ |file|
|
132
|
+
doc = Nokogiri::XML(File.read(file))
|
133
|
+
|
134
|
+
node = doc.at_css "PrivateConfig/StorageAccount"
|
135
|
+
node['name'] = getValue('StorageAccount')
|
136
|
+
node['key'] = getValue('StorageAccountKey')
|
137
|
+
node = doc.at_css "StorageAccount"
|
138
|
+
node.content = getValue('StorageAccount')
|
139
|
+
|
140
|
+
File.write(file, doc.to_xml)
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def transform
|
145
|
+
|
146
|
+
# environment invoked
|
147
|
+
@env = ENV['env'] || 'noenv'
|
148
|
+
if @env == 'noenv'
|
149
|
+
puts 'Environment name required to transform. No configuration changes will be done...'
|
150
|
+
return false
|
151
|
+
end
|
152
|
+
puts "Transforming config for environment: #{@env} ..."
|
153
|
+
|
154
|
+
# azure table storage account where settings reside
|
155
|
+
Azure.config.storage_account_name = ENV['StorageAccount']
|
156
|
+
Azure.config.storage_access_key = ENV['StorageAccountKey']
|
157
|
+
@table = ENV['ConfigSettingsTable']
|
158
|
+
|
159
|
+
# table service
|
160
|
+
@svc = Azure::TableService.new
|
161
|
+
|
162
|
+
# get all settings for environment
|
163
|
+
@settings = getAll
|
164
|
+
|
165
|
+
# get config templates
|
166
|
+
puts "Obtaining templates..."
|
167
|
+
csdefTemplate = getValue('ServiceDefinitionTemplate')
|
168
|
+
File.write('ServiceDefinition.csdef', csdefTemplate)
|
169
|
+
cscfgTemplate = getValue('ServiceConfigurationTemplate')
|
170
|
+
File.write('ServiceConfiguration.cscfg', cscfgTemplate)
|
171
|
+
|
172
|
+
# start updating config files
|
173
|
+
|
174
|
+
# find all App.config and web.config files
|
175
|
+
@configFiles = Dir.glob("**/app.config")
|
176
|
+
@configFiles.concat(Dir.glob("**/web.config"))
|
177
|
+
@configFiles.concat(Dir.glob("**/RuntimeWeb/*Web.dll.config"))
|
178
|
+
|
179
|
+
puts "Replacing app settings..."
|
180
|
+
transformAppSettings
|
181
|
+
|
182
|
+
puts "Removing debug compilation attributes..."
|
183
|
+
transformSystemWebCompilationAttribs
|
184
|
+
|
185
|
+
puts "Transforming csdef..."
|
186
|
+
transformCsdef
|
187
|
+
|
188
|
+
puts "Transforming cscfg..."
|
189
|
+
transformCscfg
|
190
|
+
|
191
|
+
puts "Transforming diagnostics cfg..."
|
192
|
+
transformDiagnosticsCfg
|
193
|
+
|
194
|
+
puts "Replacing service model settings..."
|
195
|
+
transformServiceModelConfig
|
196
|
+
|
197
|
+
return true
|
198
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: azdeploy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Suresh Batta
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Azure Deployment Gem. Provides easy setup and deployment scripting support
|
14
|
+
for .Net project builds
|
15
|
+
email: subatta@hotmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- test/test_azdeploy.rb
|
21
|
+
- lib/azdeploy.rb
|
22
|
+
- lib/build.rb
|
23
|
+
- lib/install.rb
|
24
|
+
- lib/transform.rb
|
25
|
+
- azdeploy.gemspec
|
26
|
+
homepage: http://rubygems.org/gems/azdeploy
|
27
|
+
licenses:
|
28
|
+
- MIT
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.0.14
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: Setup and scripting support for .Net project builds
|
50
|
+
test_files: []
|