chefrepo-manifest-builder 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler."
10
+ exit -1
11
+ end
12
+
13
+ begin
14
+ Bundler.setup(:development)
15
+ rescue Bundler::BundlerError => e
16
+ warn e.message
17
+ warn "Run `bundle install` to install missing gems."
18
+ exit e.status_code
19
+ end
20
+
21
+ require 'rake'
22
+
23
+ require 'rubygems/tasks'
24
+ Gem::Tasks.new
25
+
26
+ require 'rspec/core/rake_task'
27
+ RSpec::Core::RakeTask.new
28
+
29
+ task :test => :spec
30
+ task :default => :spec
31
+
32
+ require 'cucumber/rake/task'
33
+
34
+ Cucumber::Rake::Task.new do |t|
35
+ t.cucumber_opts = %w[--format pretty]
36
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ path = File.dirname(__FILE__)
6
+ if File.exists?("#{path}/../.gitignore")
7
+ %w(chefrepo-builder cicd-builder).each do |mod|
8
+ add_path = File.expand_path(File.join(path, "../../#{mod}", "lib"))
9
+ $:.unshift(add_path)
10
+ end
11
+ else
12
+ # Borrowing from "whiches" gem ...
13
+ cmd = File.basename(__FILE__, '.rb')
14
+ exes = []
15
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
16
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |pth|
17
+ exts.each { |ext|
18
+ exe = File.join(pth, "#{cmd}#{ext}")
19
+ exes << exe if File.executable? exe
20
+ }
21
+ end
22
+ if exes.size > 0
23
+ path = File.dirname(exes[0])
24
+ end
25
+
26
+ end
27
+ add_path = File.expand_path(File.join(path, "..", "lib"))
28
+ $:.unshift(add_path)
29
+
30
+ require 'cicd/builder/chefrepo-manifest'
31
+
32
+ # =====================================================================================================================
33
+ exit CiCd::Builder::ChefRepoManifest::Runner.new().run()
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/cicd/builder/chefrepo-manifest/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'chefrepo-manifest-builder'
7
+ gem.version = CiCd::Builder::ChefRepoManifest::VERSION
8
+ gem.summary = %q{ChefRepo builder for a software manifest}
9
+ gem.description = %q{ChefRepo builder of the software manifest for Continuous Integration/Continuous Delivery artifact promotion style deployments}
10
+ gem.license = "Apachev2"
11
+ gem.authors = ["Christo De Lange"]
12
+ gem.email = "rubygems@dldinternet.com"
13
+ gem.homepage = "https://rubygems.org/gems/manifest-builder"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_dependency 'manifest-builder', '>= 0.6.2', '< 1.1'
21
+ # gem.add_dependency 'cicd-builder', '>= 0.9.48', '< 1.1'
22
+ # gem.add_dependency 'chefrepo-builder', '>= 0.9.31', '< 1.1'
23
+ gem.add_dependency 'json', '>= 1.8.1', '< 1.9'
24
+ gem.add_dependency 's3etag', '>= 0.0.1', '< 0.1.0'
25
+ gem.add_dependency 'archive-tar-minitar', '= 0.5.2'
26
+
27
+ gem.add_development_dependency 'bundler', '>= 1.7', '< 2.0'
28
+ gem.add_development_dependency 'rake', '>= 10.3', '< 11'
29
+ gem.add_development_dependency 'rubygems-tasks', '>= 0.2', '< 1.1'
30
+ gem.add_development_dependency 'cucumber', '>= 0.10.7', '< 0.11'
31
+ gem.add_development_dependency 'rspec', '>= 2.99', '< 3.0'
32
+ end
data/features/.gitkeep ADDED
File without changes
@@ -0,0 +1 @@
1
+ Feature: Blah blah blah
File without changes
@@ -0,0 +1,62 @@
1
+
2
+ module CiCd
3
+ module Builder
4
+ # noinspection RubySuperCallWithoutSuperclassInspection
5
+ module ChefRepoManifest
6
+ module Build
7
+
8
+ # ---------------------------------------------------------------------------------------------------------------
9
+ # noinspection RubyHashKeysTypesInspection
10
+ def prepareBuild()
11
+ super
12
+ if @vars[:return_code] == 0
13
+ end
14
+ @vars[:return_code]
15
+ end
16
+
17
+ # ---------------------------------------------------------------------------------------------------------------
18
+ def packageBuild()
19
+ @logger.step __method__.to_s
20
+ if isSameDirectory(Dir.pwd, ENV['WORKSPACE'])
21
+ if @vars.has_key?(:components) and not @vars[:components].empty?
22
+ @vars[:return_code] = 0
23
+
24
+ clazz = getRepoClass('S3')
25
+ @logger.debug "Repo class == '#{clazz}'"
26
+ if clazz.is_a?(Class) and not clazz.nil?
27
+ @repo = clazz.new(self)
28
+
29
+ if @vars[:return_code] == 0
30
+ lines = []
31
+ @vars[:artifacts] = []
32
+ # Deal with all artifacts of each component
33
+ @vars[:components].each { |comp|
34
+ processComponent(comp, lines)
35
+ }
36
+ if @vars[:return_code] == 0
37
+ cleanupAfterPackaging(lines)
38
+ end
39
+
40
+ else
41
+ @logger.fatal "S3 repo error: Bucket #{ENV['AWS_S3_BUCKET']}"
42
+ end
43
+ else
44
+ @logger.error "CiCd::Builder::Repo::#{type} is not a valid repo class"
45
+ @vars[:return_code] = Errors::BUILDER_REPO_TYPE
46
+ end
47
+ else
48
+ @logger.error 'No components found during preparation?'
49
+ @vars[:return_code] = Errors::NO_COMPONENTS
50
+ end
51
+ else
52
+ @logger.error "Not in WORKSPACE? '#{pwd}' does not match WORKSPACE='#{workspace}'"
53
+ @vars[:return_code] = Errors::WORKSPACE_DIR
54
+ end
55
+
56
+ @vars[:return_code]
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,323 @@
1
+ require 'artifactory'
2
+ require 'tmpdir'
3
+
4
+ module CiCd
5
+ module Builder
6
+ # noinspection RubySuperCallWithoutSuperclassInspection
7
+ module Manifest
8
+ module Repo
9
+ class Artifactory < CiCd::Builder::Repo::Artifactory
10
+ # include ::Artifactory::Resource
11
+
12
+ # ---------------------------------------------------------------------------------------------------------------
13
+ def initialize(builder)
14
+ super
15
+ end
16
+
17
+ # ---------------------------------------------------------------------------------------------------------------
18
+ def uploadToRepo(artifacts)
19
+ @manifest = {}
20
+ super
21
+ if @vars[:return_code] == 0
22
+ # Preserve the manifest (maybeUploadArtifactoryObject will add everything we upload to the instance var)
23
+ manifest = @manifest.dup
24
+ # Create a manifest for each product and store it.
25
+ createProductManifests(manifest)
26
+ # Get a super manifest of all products and store as learning-manifest
27
+ createSuperManifest(manifest) # -#{@vars[:variant]}
28
+ @manifest = manifest
29
+ end
30
+ # If we are asked to produce a PROJECTS_FILE then we do that from the manifest and components.
31
+ unless ENV['PROJECTS_FILE'].nil?
32
+ if @vars[:return_code] == 0
33
+ if File.directory?(File.realdirpath(File.dirname(ENV['PROJECTS_FILE'])))
34
+ createProjectsFile
35
+ else
36
+ @logger.error "The path to the PROJECTS_FILE (#{File.dirname(ENV['PROJECTS_FILE'])}) does not exist!"
37
+ @vars[:return_code] = Errors::NO_PROJECTS_PATH
38
+ end
39
+ end
40
+ end
41
+ @vars[:artifacts].each do |art|
42
+ if art[:data][:temp].is_a?(FalseClass)
43
+ if File.exists?(art[:data][:file])
44
+ File.unlink(art[:data][:file]) if File.exists?(art[:data][:file])
45
+ art[:data].delete(:file)
46
+ art[:data].delete(:temp)
47
+ else
48
+ @logger.warn "Temporary file disappeared: #{data.ai}"
49
+ @vars[:return_code] = Errors::TEMP_FILE_MISSING
50
+ end
51
+ end
52
+ end
53
+ @vars[:return_code]
54
+ end
55
+
56
+ # ---------------------------------------------------------------------------------------------------------------
57
+ def createProjectsFile
58
+ @logger.info __method__.to_s
59
+ projects = {}
60
+ project_names = loadProjectNames()
61
+ exts = {}
62
+ exts = Hash[@vars[:artifacts].map { |a| [a[:data][:name], File.basename(a[:data][:file]).match(CiCd::Builder::Manifest::Build::EXT_RGX)[1]] }]
63
+
64
+ createClassesFile()
65
+
66
+ @vars[:artifacts].each do |art|
67
+ prod = art[:data][:name]
68
+ mod = art[:data][:module]
69
+ projects[prod] = {
70
+ name: project_names[prod] || prod,
71
+ module: mod,
72
+ ext: exts[prod],
73
+ class_filter: @vars[:filters][prod] || @vars[:filters][prod.gsub(/-manifest$/, '')],
74
+ }
75
+ end
76
+
77
+ require 'chef/mash'
78
+ require 'chef/mixin/deep_merge'
79
+
80
+ projects_hash = File.exists?(ENV['PROJECTS_FILE']) ? loadConfigFile(ENV['PROJECTS_FILE']) : {}
81
+ old_projects = ::Chef::Mash.new(projects_hash)
82
+ projects = ::Chef::Mash.new(projects)
83
+ projects = ::Chef::Mash.new(::Chef::Mixin::DeepMerge.deep_merge(projects, old_projects))
84
+ saveConfigFile(ENV['PROJECTS_FILE'], projects)
85
+ data = {
86
+ name: 'projects-file',
87
+ module: 'projects-file',
88
+ file: ENV['PROJECTS_FILE'],
89
+ version: @vars[:build_ver],
90
+ build: @vars[:build_num],
91
+ properties: @properties_matrix,
92
+ temp: false,
93
+ sha1: Digest::SHA1.file(ENV['PROJECTS_FILE']).hexdigest,
94
+ md5: Digest::MD5.file(ENV['PROJECTS_FILE']).hexdigest,
95
+ }
96
+
97
+ maybeUploadArtifactoryObject(
98
+ data: data,
99
+ artifact_module: data[:name],
100
+ artifact_version: data[:version] || @vars[:version],
101
+ file_name: '',
102
+ file_ext: (ENV['PROJECTS_FILE'] and ENV['PROJECTS_FILE'].downcase.match(/\.ya?ml$/)) ? 'yaml' : 'json'
103
+ )
104
+ end
105
+
106
+ # ---------------------------------------------------------------------------------------------------------------
107
+ # noinspection RubyHashKeysTypesInspection
108
+ def createClassesFile()
109
+ @logger.info __method__.to_s
110
+ project_names = loadProjectNames()
111
+
112
+ @vars[:classes] = YAML.load(IO.read(ENV['CLASSES_MANIFEST_FILE']))
113
+ # keys = Hash[classes.keys.map.with_index.to_a].keys.sort
114
+
115
+ @vars[:filters] = {}
116
+ filters = {}
117
+ @vars[:classes].each do |role,apps|
118
+ apps.map{ |app|
119
+ filters[app] ||= []
120
+ filters[app] << role
121
+ }
122
+ end
123
+ filters.each do |app,roles|
124
+ @vars[:filters][app] = Hash[roles.map.with_index.to_a].keys.join('|')
125
+ end
126
+
127
+ saveConfigFile(ENV['CLASSES_FILE'],@vars[:classes])
128
+ data = {
129
+ name: 'classes-file',
130
+ module: 'classes-file',
131
+ file: ENV['CLASSES_FILE'],
132
+ version: @vars[:build_ver],
133
+ build: @vars[:build_num],
134
+ properties: @properties_matrix,
135
+ temp: false,
136
+ sha1: Digest::SHA1.file(ENV['CLASSES_FILE']).hexdigest,
137
+ md5: Digest::MD5.file(ENV['CLASSES_FILE']).hexdigest,
138
+ }
139
+
140
+ maybeUploadArtifactoryObject(
141
+ data: data,
142
+ artifact_module: data[:name],
143
+ artifact_version: data[:version] || @vars[:version],
144
+ file_name: '',
145
+ file_ext: 'yaml'
146
+ )
147
+ end
148
+
149
+ def saveConfigFile(file, projects)
150
+ @logger.info "Save config file: #{file}"
151
+ ext = file.gsub(/\.(\w+)$/, '\1')
152
+ IO.write(file, case ext.downcase
153
+ when /ya?ml/
154
+ projects.to_hash.to_yaml line_width: 1024, indentation: 4, canonical: false
155
+ when /json|js/
156
+ JSON.pretty_generate(projects.to_hash, {indent: "\t", space: ' '})
157
+ else
158
+ raise "Unsupported extension: #{ext}"
159
+ end)
160
+ end
161
+
162
+ def loadConfigFile(file)
163
+ ext = file.gsub(/\.(\w+)$/, '\1')
164
+ hash = case ext.downcase
165
+ when /ya?ml/
166
+ YAML.load_file(ENV['PROJECTS_FILE'])
167
+ when /json|js/
168
+ JSON.load(IO.read(ENV['PROJECTS_FILE']))
169
+ else
170
+ raise "Unsupported extension: #{ext}"
171
+ end
172
+ end
173
+
174
+ def loadProjectNames(fresh=false)
175
+ if fresh
176
+ @project_names = nil
177
+ end
178
+ unless @project_names
179
+ @project_names = {}
180
+ unless ENV['PROJECT_NAMES'].nil?
181
+ if File.exists?(ENV['PROJECT_NAMES'])
182
+ @logger.info "Load PROJECT_NAMES: #{ENV['PROJECT_NAMES']}"
183
+ @project_names = JSON.load(IO.read(ENV['PROJECT_NAMES'])) || {}
184
+ else
185
+ @logger.error "The PROJECT_NAMES file (#{ENV['PROJECT_NAMES']}) does not exist!"
186
+ @vars[:return_code] = Errors::NO_PROJECT_NAMES
187
+ end
188
+ end
189
+ end
190
+ @project_names
191
+ end
192
+
193
+ def createSuperManifest(manifest)
194
+ manifest_data = ''
195
+ manifest.each do |mod, man|
196
+ man.each do |k, v|
197
+ manifest_data += "#{k}=#{v}\n"
198
+ end
199
+ end
200
+ amn = artifactory_manifest_name # Just using a local iso invoking method_missing repeatedly ... ;)
201
+ data = {module: amn, data: manifest_data, version: @vars[:build_ver], build: @vars[:build_num], properties: @properties_matrix}
202
+ # tempArtifactFile(amn, data)
203
+
204
+ data[:file] = Dir::Tmpname.create(amn) do |tmpnam, n, opts|
205
+ mode = File::RDWR|File::CREAT|File::EXCL
206
+ perm = 0600
207
+ opts = perm
208
+ end + '.properties'
209
+ IO.write(data[:file], data[:data])
210
+ data[:temp] = false
211
+ data[:sha1] = Digest::SHA1.file(data[:file]).hexdigest
212
+ data[:md5] = Digest::MD5.file(data[:file]).hexdigest
213
+ data[:name] = amn
214
+ @vars[:artifacts] << {
215
+ key: amn,
216
+ data: data.dup,
217
+ }
218
+ # manifest[amn]={ amn => "#{@vars[:build_ver]}-#{@vars[:build_num]}" }
219
+
220
+ maybeUploadArtifactoryObject(data: data, artifact_module: amn, artifact_version: data[:version] || @vars[:version], file_name: '', file_ext: 'properties')
221
+ end
222
+
223
+ # ---------------------------------------------------------------------------------------------------------------
224
+ def createProductManifests(manifest)
225
+ manifest.dup.each do |mod, man|
226
+ manifest_data = ''
227
+ man.each do |k, v|
228
+ manifest_data += "#{k}=#{v}\n"
229
+ end
230
+ data = {
231
+ name: "#{mod}-manifest",
232
+ module: "#{mod}-manifest",
233
+ component: mod,
234
+ data: manifest_data,
235
+ version: @vars[:build_ver],
236
+ build: @vars[:build_num],
237
+ properties: @properties_matrix
238
+ }
239
+ # tempArtifactFile("#{mod}-manifest", data)
240
+
241
+ data[:file] = Dir::Tmpname.create("#{mod}-manifest") do |tmpnam, n, opts|
242
+ mode = File::RDWR|File::CREAT|File::EXCL
243
+ perm = 0600
244
+ opts = perm
245
+ end + '.properties'
246
+ IO.write(data[:file], data[:data])
247
+ data[:temp] = false
248
+ data[:sha1] = Digest::SHA1.file(data[:file]).hexdigest
249
+ data[:md5] = Digest::MD5.file(data[:file]).hexdigest
250
+ @vars[:artifacts] << {
251
+ key: "#{mod}-manifest",
252
+ data: data.dup,
253
+ }
254
+ # noinspection RubyStringKeysInHashInspection
255
+ # manifest["#{mod}-manifest"]={ "#{mod}-manifest" => "#{@vars[:build_ver]}-#{@vars[:build_num]}" }
256
+
257
+ maybeUploadArtifactoryObject(data: data, artifact_module: data[:name], artifact_version: data[:version] || @vars[:version], file_name: '', file_ext: 'properties') # -#{@vars[:variant]}
258
+ end
259
+ end
260
+
261
+ # ---------------------------------------------------------------------------------------------------------------
262
+ def maybeUploadArtifactoryObject(args)
263
+ super
264
+ if @vars[:return_code] == 0
265
+ data = args[:data]
266
+ artifact_module = args[:artifact_module]
267
+ artifact_version = args[:artifact_version]
268
+ # file_ext = args[:file_ext]
269
+ # file_name = args[:file_name]
270
+ if @manifest[artifact_module].nil?
271
+ @manifest[artifact_module] = {}
272
+ file_name = artifact_module
273
+ else
274
+ file_name, _ = get_artifact_file_name_ext(data)
275
+ if file_name.empty?
276
+ file_name = artifact_module
277
+ else
278
+ file_name = "#{artifact_module}#{file_name}"
279
+ end
280
+ end
281
+ @manifest[artifact_module][file_name] = artifact_version
282
+ end
283
+
284
+ @vars[:return_code]
285
+ end
286
+
287
+ private :createProductManifests, :createProjectsFile, :createSuperManifest
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
293
+
294
+ =begin
295
+
296
+ {
297
+ "test-project": {
298
+ "name": "test-project",
299
+ "module": "test-server",
300
+ "ext": "war",
301
+ "class_filter": "role.role-1"
302
+ },
303
+ "test-project-2": {
304
+ "name": "test-project-2",
305
+ "module": "test-server2",
306
+ "ext": "zip",
307
+ "class_filter": "role.role-2"
308
+ },
309
+ "test-manifest": {
310
+ "name": "test-manifest",
311
+ "module": "test-manifest",
312
+ "ext": "properties",
313
+ "class_filter": ""
314
+ },
315
+ "test-manifest2": {
316
+ "name": "test-manifest2",
317
+ "module": "test-manifest2",
318
+ "ext": "properties",
319
+ "class_filter": ""
320
+ }
321
+ }
322
+
323
+ =end
@@ -0,0 +1,10 @@
1
+ module CiCd
2
+ module Builder
3
+ module ChefRepoManifest
4
+ # chefrepo-manifest-builder version
5
+ VERSION = '0.1.1'
6
+ MAJOR, MINOR, TINY = VERSION.split('.')
7
+ PATCH = TINY
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,39 @@
1
+ require 'cicd/builder/manifest'
2
+
3
+ module CiCd
4
+ module Builder
5
+ _lib=File.dirname(__FILE__)
6
+ $:.unshift(_lib) unless $:.include?(_lib)
7
+
8
+ require 'cicd/builder/chefrepo-manifest/version'
9
+
10
+ module ChefRepoManifest
11
+ class Runner < Manifest::Runner
12
+
13
+ # ---------------------------------------------------------------------------------------------------------------
14
+ def initialize()
15
+ super
16
+ @default_options[:builder] = VERSION
17
+ end
18
+
19
+ # ---------------------------------------------------------------------------------------------------------------
20
+ def getBuilderVersion
21
+ {
22
+ version: VERSION,
23
+ major: MAJOR,
24
+ minor: MINOR,
25
+ patch: PATCH,
26
+ }
27
+ end
28
+
29
+ # ---------------------------------------------------------------------------------------------------------------
30
+ def setup()
31
+ $stdout.write("ChefRepoManifestBuilder v#{CiCd::Builder::ChefRepoManifest::VERSION}\n")
32
+ super
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ end
39
+ end
data/openssl ADDED
File without changes
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'cicd/builder'
3
+
4
+ describe ManifestBuilder::Builder do
5
+ it "should have a VERSION constant" do
6
+ subject.const_get('VERSION').should_not be_empty
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ require 'rspec'
2
+ require 'cicd/builder/version'
3
+
4
+ include ManifestBuilder::Builder