Module: CiCd::Builder

Defined in:
lib/cicd/builder/version.rb,
lib/cicd/builder.rb,
lib/cicd/builder/mixlib/repo.rb,
lib/cicd/builder/mixlib/build.rb,
lib/cicd/builder/mixlib/utils.rb,
lib/cicd/builder/mixlib/errors.rb,
lib/cicd/builder/mixlib/options.rb,
lib/cicd/builder/mixlib/repo/S3.rb,
lib/cicd/builder/mixlib/constants.rb,
lib/cicd/builder/mixlib/repo/base.rb,
lib/cicd/builder/mixlib/environment.rb,
lib/cicd/builder/mixlib/repo/artifactory.rb

Overview

noinspection ALL

Defined Under Namespace

Modules: Errors, Repo Classes: BuilderBase

Constant Summary collapse

ENV_IGNORED =
%w(LS_COLORS AWS_ACCESS_KEY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SECRET_KEY)
VERSION =
version
MAJOR =
major
MINOR =
minor
TINY =
tiny
PATCH =
TINY
LOGLEVELS =

noinspection RubyStringKeysInHashInspection

{
	'crit'     => :fatal,
	'critical' => :fatal,
	'err'      => :error,
	'error'    => :error,
	'warn'     => :warn,
	'warning'  => :warn,
	'info'     => :info,
	'debug'    => :debug,
}
MYNAME =
File.basename(__FILE__)
CLASS =
'CiCd::Builder'

Instance Method Summary collapse

Instance Method Details

#addArtifact(artifacts, script, prefix, opts = {}) ⇒ Object




32
33
34
35
36
37
38
39
40
# File 'lib/cicd/builder/mixlib/utils.rb', line 32

def addArtifact(artifacts, script, prefix, opts = {})
  key = File.join(File.dirname(getKey()), script.gsub(%r|^#{prefix}|, ''))
  # "#{@vars[:project_name]}/#{@vars[:variant]}/#{@vars[:build_nam]}/#{@vars[:build_mvn]}/#{script.gsub(%r|^#{prefix}|, '')}"
  # Store the artifact - be sure to inherit possible overrides in pkg name and ext but dictate the drawer!
  artifacts << {
      key: key,
      data: {:file => script}.merge(opts),
  }
end

#analyzeInventoryObject




79
80
81
82
# File 'lib/cicd/builder/mixlib/repo.rb', line 79

def analyzeInventory()
  @logger.step CLASS+'::'+__method__.to_s
			performOnRepoInstance(__method__.to_s)
end

#calcLocalETag(etag, local, size = nil) ⇒ Object




180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/cicd/builder/mixlib/build.rb', line 180

def calcLocalETag(etag, local, size = nil)
  if size == nil
    stat = File.stat(local)
    size = stat.size
  end
  @logger.debug "Calculate etag to match #{etag}"
  match = etag.match(%r'-(\d+)$')
  check = if match
            require 's3etag'
            parts = match[1].to_i
            chunk = size.to_f / parts.to_f
            mbs = (chunk.to_f / 1024 /1024 + 0.5).to_i
            part_size = mbs * 1024 * 1024
            chkit = S3Etag.calc(file: local, threshold: part_size, min_part_size: part_size, max_parts: parts)
            @logger.debug "S3Etag Calculated #{chkit} : (#{size} / #{part_size}) <= #{parts}"
            chunks = size / part_size
            while chkit != etag and chunks <= parts and chunks > 0 and (size > part_size)
              # Go one larger if a modulus remains and we have the right number of parts
              mbs += 1
              part_size = mbs * 1024 * 1024
              chunks = size.to_f / part_size
              chkit = S3Etag.calc(file: local, threshold: part_size, min_part_size: part_size, max_parts: parts)
              @logger.debug "S3Etag Calculated #{chkit} : (#{size} / #{part_size}) <= #{parts}"
            end
            @logger.warn "Unable to match etag #{etag}!" if chkit != etag
            chkit
          else
            Digest::MD5.file(local).hexdigest
          end
end

#checkEnvironmentObject




7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/cicd/builder/mixlib/environment.rb', line 7

def checkEnvironment()
    @logger.step CLASS+'::'+__method__.to_s
	# [2013-12-30 Christo] Detect CI ...
	unless ENV.has_key?('JENKINS_HOME')
		@logger.error "Sorry, your CI environment is not supported at this time (2013-12-30) ... Christo De Lange\n"+
		'This script is developed for Jenkins so either you are not using Jenkins or you ran me outside of the CI ecosystem ...'
		return 99
	end

	# Check for the necessary environment variables
	map_keys = {}

	@options[:env_keys].each { |k|
		map_keys[k]= (not ENV.has_key?(k) or ENV[k].empty?)
	}
	missing = map_keys.keys.select{ |k| map_keys[k] }

	if missing.count() > 0
		# ap missing
		#raise Exception.new("Need these environment variables: #{missing}")
		puts("Need these environment variables: #{missing.ai}")
      return 1
    end
    @default_options[:env_unused] = @default_options[:env_keys].select{|k| k !~ /^(WORKSPACE|JENKINS|BUILD_|JOB_|VERSION|RELEASE|VARIANT|BRANCH|GIT_|PROJECT_|REPO_)/}
    @default_options[:env_unused] = @default_options[:env_unused].select{|k| k if ENV.has_key?(k) and ENV[k] != 'faked' }
    0
end

#cleanupAfterUploadObject




226
227
228
229
# File 'lib/cicd/builder/mixlib/build.rb', line 226

def cleanupAfterUpload()
    @logger.info CLASS+'::'+__method__.to_s
	@logger.debug %(Prior to VERSION 0.9.58 there was no #{__method__.to_s} action)
end

#cleanupBuildObject




7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/cicd/builder/mixlib/build.rb', line 7

def cleanupBuild()
    @logger.info CLASS+'::'+__method__.to_s
    [ :build_pkg, :build_chk, :build_mdf, :build_mff ].each do |fil|
      if File.exists?(@vars[fil])
        begin
          FileUtils.rm_f(@vars[fil])
        rescue => e
          @logger.error e.to_s
          #raise e
          return Errors::CLEANUPBUILD_EXCEPTION
        end
      end
    end
	if Dir.exists?(@vars[:build_dir])
		begin
			FileUtils.rm_r(@vars[:build_dir])
		rescue => e
			@logger.error e.to_s
			#raise e
			return Errors::CLEANUPBUILD_EXCEPTION
		end
	end
	0
end

#createMetaDataObject




232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/cicd/builder/mixlib/build.rb', line 232

def ()
  @logger.info CLASS+'::'+__method__.to_s
  @vars[:build_mdd].merge!({
                            :Generation => @options[:gen],
                            :Project => @vars[:project_name],
                            :Variant => @vars[:variant],
                            :Build => @vars[:build_num],
                            :Date => @vars[:build_dte],
                            :Builder => VERSION,

                                  })
  json = JSON.pretty_generate( @vars[:build_mdd], { indent: "\t", space: ' '})
  unless IO.write(@vars[:build_mdf], json) > 0
    @logger.error "Unable to store metadata in '#{@vars[:build_mdf]}'"
    @vars[:return_code] = Errors::STORING_BUILD_METADATA
  end
  @vars[:return_code]
end

#downcaseHashKeys(hash) ⇒ Object




12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/cicd/builder/mixlib/utils.rb', line 12

def downcaseHashKeys(hash)
	down = {}
	hash.each{|k,v|
		if v.is_a?(Hash)
			v = downcaseHashKeys(v)
		end
		if k.to_s.match(/[A-Z]/)
			k = k.to_s.downcase.to_sym
		end
		down[k] = v
	}
	down
end

#downcaseKey(hash, key) ⇒ Object




5
6
7
8
9
# File 'lib/cicd/builder/mixlib/utils.rb', line 5

def downcaseKey(hash,key)
	hash[key.to_s.downcase.to_sym] = hash[key]
	hash.delete(key)
	hash
end

#getArtifactsDefinitionObject




154
155
156
# File 'lib/cicd/builder/mixlib/repo.rb', line 154

def getArtifactsDefinition()
  nil
end

#getKeyObject




27
28
29
# File 'lib/cicd/builder/mixlib/utils.rb', line 27

def getKey
	key = "#{@vars[:project_name]}/#{@vars[:variant]}/#{@vars[:build_nam]}/#{@vars[:build_mvn]}/#{@vars[:build_nmn]}"
end

#getLatestObject




106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/cicd/builder/mixlib/environment.rb', line 106

def getLatest
  ret = 0
  @vars[:vars_fil] = "#{@vars[:build_store]}/#{ENV['JOB_NAME']}-#{@vars[:variant]}.env"
  @vars[:latest_fil] = "#{@vars[:build_store]}/#{ENV['JOB_NAME']}-#{@vars[:variant]}.latest"
  @vars[:latest_ver] = ''
  @vars[:latest_sha] = ''
  @vars[:latest_pkg] = ''
  @vars[:latest_ext] = @vars[:build_ext]
  if @vars[:build_nam]
    @vars[:latest_pkg] = "#{@vars[:build_store]}/#{@vars[:build_nam]}.#{@vars[:latest_ext]}"
    unless File.exists?(@vars[:latest_pkg])
      if File.exists?("#{@vars[:build_store]}/#{@vars[:build_nam]}.tar.gz")
        @vars[:latest_ext] = 'tar.gz'
        @vars[:latest_pkg] = "#{@vars[:build_store]}/#{@vars[:build_nam]}.#{@vars[:latest_ext]}"
      end
    end
  end
  ret = loadLatestVarsFile
  ret
end

#getNamingDefinitionObject




159
160
161
# File 'lib/cicd/builder/mixlib/repo.rb', line 159

def getNamingDefinition()
  nil
end

#getRepoClass(type = nil) ⇒ Object




14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/cicd/builder/mixlib/repo.rb', line 14

def getRepoClass(type = nil)
  @logger.info CLASS+'::'+__method__.to_s
  if type.nil?
    type ||= 'S3'
  end

  @logger.info "#{type} repo interface"
  clazz = Object.const_get("CiCd::Builder::Repo::#{type}")
  if block_given?
    if clazz.is_a?(Class) and not clazz.nil?
      yield
    end
  end

  clazz
end

#getRepoInstance(type = nil) ⇒ Object




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/cicd/builder/mixlib/repo.rb', line 32

def getRepoInstance(type = nil)
  @logger.info CLASS+'::'+__method__.to_s
  if type.nil?
    type ||= 'S3'
    if ENV.has_key?('REPO_TYPE')
      type = ENV['REPO_TYPE']
    end
  end
  clazz = getRepoClass(type)
  if clazz.is_a?(Class) and not clazz.nil?
    @repo = clazz.new(self)
  else
    @logger.error "#{clazz.name.to_s} is not a valid repo class"
    @vars[:return_code] = Errors::BUILDER_REPO_TYPE
  end
  @vars[:return_code]
end

#getVarsObject




36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/cicd/builder/mixlib/environment.rb', line 36

def getVars()
    @logger.step CLASS+'::'+__method__.to_s

    @logger.info "Unused ENV vars: #{@default_options[:env_unused].ai}" if @default_options[:env_unused].size > 0

	@vars                ||= {}
	@vars[:release]      = 'latest'
	@vars[:build_store]  = '/tmp'
	@vars[:variant]      = 'SNAPSHOT'
    @vars[:upload_timer] = ENV.has_key?('ARTIFACT_UPLOAD_TIMER') ? ENV['ARTIFACTORY_UPLOAD_TIMER'].to_i : 300

	if ENV.has_key?('PROJECT_NAME')
      @vars[:product] =
      @vars[:project_name] = ENV['PROJECT_NAME']
	end

	if ENV.has_key?('RELEASE')
		@vars[:release] = ENV['RELEASE']
    elsif File.exists?((version_file=File.join(ENV['REPO_DIR'], 'RELEASE')))
      lines = File.readlines(version_file)
      @vars[:release] = lines.shift.chomp() if lines.count > 0
    else
      raise "'RELEASE' was not provided in either environment or #{version_file} file"
	end

	if ENV.has_key?('VERSION')
		@vars[:version] = ENV['VERSION']
    elsif File.exists?((version_file=File.join(ENV['REPO_DIR'], 'VERSION')))
      lines = File.readlines(version_file)
      @vars[:version] = lines.shift.chomp() if lines.count > 0
    else
      raise "'VERSION' was not provided in either environment or #{version_file} file"
	end

	if ENV.has_key?('BUILD_STORE')
		@vars[:build_store] = "#{ENV['BUILD_STORE']}"
	end

	if ENV.has_key?('GIT_BRANCH')
		@vars[:branch] = "#{ENV['GIT_BRANCH'].gsub(%r'^(refs/[^/]?|origin)/','').gsub(%r'\/','.')}"
    elsif ENV.has_key?('BRANCH')
      @vars[:branch] = "#{ENV['BRANCH'].gsub(%r'\/','.')}"
    end

	if ENV.has_key?('VARIANT')
		@vars[:variant] = "#{ENV['VARIANT']}"
    end

	if ENV.has_key?('BUILD_NUMBER')
		@vars[:build_num] = "#{ENV['BUILD_NUMBER']}"
	end

    if ENV.has_key?('ACTIONS')
      @vars[:actions] = ENV['ACTIONS'].split(%r'[, \t]+')
    else
      @vars[:actions] = %w(prepareBuild makeBuild saveBuild uploadBuildArtifacts cleanupAfterUpload)
    end

    if ENV.has_key?('TREE')
      @vars[:tree] = ENV['TREE']
    end

    if ENV.has_key?('PRUNER')
      @vars[:pruner] = ENV['PRUNER']
    end

    @vars[:return_code] = getLatest()
end

#isSameDirectory(pwd, workspace) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/cicd/builder.rb', line 89

def isSameDirectory(pwd, workspace)
  pwd = File.realdirpath(File.expand_path(pwd))
  workspace = File.realdirpath(File.expand_path(workspace))
  unless pwd == workspace

  end
  return pwd, workspace
end

#loadCheckSumFileObject




165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/cicd/builder/mixlib/build.rb', line 165

def loadCheckSumFile
  if File.exists?(@vars[:build_chk])
    @vars[:build_sha] = IO.readlines(@vars[:build_chk])
    unless @vars[:build_sha].is_a?(Array)
      @logger.error "Unable to parse build checksum from #{@vars[:build_chk]}"
      @vars[:return_code] = Errors::PARSING_BUILD_CHECKSUM
    end
    @vars[:build_sha] = @vars[:build_sha][0].chomp()
  else
    @vars[:build_sha] = ''
  end
  @vars[:return_code]
end

#loadLatestVarsFileObject




128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/cicd/builder/mixlib/environment.rb', line 128

def loadLatestVarsFile
  ret = 0
  if File.exists?(@vars[:latest_fil])
    @vars[:latest_ver] = IO.readlines(@vars[:latest_fil])
    unless @vars[:latest_ver].is_a?(Array)
      @logger.error "Unable to parse latest version from #{@vars[:latest_fil]}"
      ret = Errors::PARSING_LATEST_VERSION
    end
    @vars[:latest_sha] = @vars[:latest_ver][1].chomp() if (@vars[:latest_ver].length > 1)
    @vars[:latest_ver] = @vars[:latest_ver][0].chomp()
    if @vars[:latest_ver] =~ %r'-\d+$'
      @vars[:latest_ver], @vars[:latest_rel] = @vars[:latest_ver].split(/-/)
    end
  end
  ret
end

#makeBuildObject




109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/cicd/builder/mixlib/build.rb', line 109

def makeBuild()
  @logger.step CLASS+'::'+__method__.to_s
  if @vars.has_key?(:build_dir) and @vars.has_key?(:build_pkg)
    begin
      do_build = false
      loadCheckSumFile()
      if 0 == @vars[:return_code]
        do_build = true if @vars[:build_sha].empty?
        do_build = true unless File.exists?(@vars[:build_pkg]) and (Digest::SHA256.file(@vars[:build_pkg]).hexdigest() == @vars[:build_sha])
        if do_build
          @vars[:return_code] = cleanupBuild()
          if 0 == @vars[:return_code]
            @vars[:build_dte] = DateTime.now.strftime('%F %T%:z')
            ()
            if 0 == @vars[:return_code]
              @vars[:return_code] = packageBuild()
              if 0 == @vars[:return_code]
                @vars[:check_sha] = @vars[:build_sha]
                @vars[:build_sha] = if File.exists?(@vars[:build_pkg])
                                      Digest::SHA256.file(@vars[:build_pkg]).hexdigest()
                                    else
                                      '0'
                                    end
                unless IO.write(@vars[:build_chk], @vars[:build_sha]) > 0
                  @logger.error "Unable to store checksum in '#{@vars[:build_chk]}'"
                  @vars[:return_code] = Errors::STORING_BUILD_CHECKSUM
                end
              end
            end
          end
        end
      end

      # Report status regardless of return code.
      reportStatus()

      if do_build
        reportResult()
      else
        # Was no need to build :) or a failure :(
        @logger.info "NO_CHANGE: #{ENV['JOB_NAME']} #{ENV['BUILD_NUMBER']} #{@vars[:build_nam]} #{@vars[:build_pkg]} #{@vars[:build_chk]} [#{@vars[:build_sha]}]"
        # @vars[:return_code] = 0
        return 1
      end
    rescue => e
      @logger.error "makeBuild failure: #{e.class.name} #{e.message}"
      @vars[:return_code] = Errors::MAKEBUILD_EXCEPTION
    end
  else
    @logger.error ':build_dir or :build_pkg is unknown'
    @vars[:return_code] = Errors::MAKEBUILD_PREPARATION
  end
  @vars[:return_code]
end

#manifestMetadataObject




103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/cicd/builder/mixlib/repo.rb', line 103

def 
    @logger.info CLASS+'::'+__method__.to_s
	manifest = @vars[:build_mdd].dup

	manifest[:manifest] = getBuilderVersion

	version_major, version_minor, version_patch = manifest[:Version].split('.')

	manifest[:version] = {
		number: manifest[:Version],
		major:  version_major,
		minor:  version_minor,
		patch:  version_patch,
		build:  @vars[:build_num],
		branch: @vars[:build_bra],
	}
	manifest[:build] = {
		name:     @vars[:build_nmn],
		base:     @vars[:build_nam],
		date:     @vars[:build_dte],
		vrb:      @vars[:build_vrb],
		branch:   @vars[:build_bra],
		checksum: @vars[:build_sha],
	}
	# we want lowercase but if we use the existing key we don't have to delete it afterwards ...
	manifest[:Release] = {
		number:   manifest[:Release],
		branch:   manifest[:Branch],
		date:     manifest[:Date],
		checksum: @vars[:build_mds],
	}
	manifest.delete(:Date)
	# manifest.delete(:api)
	# manifest.delete(:core)
	manifest[:vars] = {}
	@vars.sort.each { |k, v|
		unless %w(build_mdd build_txt).include?(k.to_s)
			manifest[:vars][k.to_s] = v
		end
	}
	manifest = downcaseHashKeys(manifest)
	manifest[:env] = {}
	ENV.to_hash.sort.each { |k, v|
		unless ENV_IGNORED.include?(k.to_s)
			manifest[:env][k.to_s] = v
		end
	}
    JSON.pretty_generate( manifest.to_hash, { indent: "\t", space: ' '})
end

#packageBuildObject




212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/cicd/builder/mixlib/build.rb', line 212

def packageBuild()
    @logger.info CLASS+'::'+__method__.to_s
	excludes=%w(*.iml *.txt *.sh *.md .gitignore .editorconfig .jshintrc *.deprecated adminer doc)
	excludes = excludes.map{ |e| "--exclude=#{@vars[:build_nam]}/#{e}" }.join(' ')
	cmd = %(cd #{ENV['WORKSPACE']}; tar zcvf #{@vars[:build_pkg]} #{excludes} #{@vars[:build_nam]} 1>#{@vars[:build_pkg]}.manifest)
	@logger.info cmd
	logger_info = %x(#{cmd})
	ret = $?.exitstatus
	@logger.info logger_info
	FileUtils.rmtree(@vars[:build_dir])
	ret
end

#parseOptionsObject




5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/cicd/builder/mixlib/options.rb', line 5

def parseOptions()
	# Parse options
	@options = {
                  log_level:      :warn,
                  #dry_run:       false,
                  trace:          false,
                  gen:            '3.0.0',
                }.merge @default_options

	opt_parser = OptionParser.new do |opts|
		opts.banner = "Usage: #{MYNAME} [@options]"

		opts.on('-l', '--log_level LEVEL', '--log-level LEVEL', [:trace, :debug, :info, :step, :warn, :error, :fatal, :todo], 'Log level ([:trace, :debug, :info, :step, :warn, :error, :fatal, :todo])') do |v|
			@options[:log_level] = v
		end
		opts.on('-f', '--inifile FILE', 'INI file with settings') do |v|
			@options[:inifile] = v
		end
		opts.on('-t', '--[no-]trace', 'Print backtrace in log, Default --no-trace') do |v|
			@options[:trace] = v
		end
	end

	opt_parser.parse!

	# Set up logger
	Logging.init :trace, :debug, :info, :note, :step, :warn, :error, :fatal, :todo
	@logger = Logging.logger(STDOUT,
	                         :pattern      => "%#{::Logging::MAX_LEVEL_LENGTH}l: %m\n",
	                         :date_pattern => '%Y-%m-%d %H:%M:%S')
	@logger.level = @options[:log_level]

    unless @options[:inifile]
      if ENV.has_key?('INIFILE')
        @options[:inifile] = ENV['INIFILE']
      end
    end

    if @options.key?(:inifile)
		@options[:inifile] = File.expand_path(@options[:inifile])
		unless File.exist?(@options[:inifile])
			raise StandardError.new("#{@options[:inifile]} not found!")
		end
		begin
			# ENV.each{ |key,_|
			# 	ENV.delete(key)
			# }
			ini = IniFile.load(@options[:inifile])
			ini['global'].each{ |key,value|
				ENV[key]=value.to_s
			}
			def _expand(k,v,regex,rerun)
				matches = v.match(regex)
				if matches
					var = matches[1]
					if ENV.has_key?(var)
						ENV[k]=v.gsub(/\$\{#{var}\}/,ENV[var]).gsub(/\$#{var}/,ENV[var])
					else
						rerun[var] = 1
					end
				end
			end

			pending = nil
			rerun = {}
			begin
				pending = rerun
				rerun = {}
				ENV.to_hash.each{|k,v|
					if v.match(/\$/)
						_expand(k,v,%r'[^\\]\$\{(\w+)\}', rerun)
						_expand(k,v,%r'[^\\]\$(\w+)',     rerun)
					end
				}
				# Should break out the first time that we make no progress!
			end while pending != rerun
		rescue IniFile::Error => e
			# noop
		rescue Exception => e
			@logger.error "#{e.class.name} #{e.message}"
			raise e
		end
	end
	@options
end

#performOnRepoInstance(verb) ⇒ Object




51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/cicd/builder/mixlib/repo.rb', line 51

def performOnRepoInstance(verb)
  @logger.info CLASS+'::'+__method__.to_s
  getRepoInstance()
  if 0 == @vars[:return_code]
    method = @repo.method(verb)
    if @repo.respond_to?(verb)
      unless method.owner == @repo.class
        @logger.warn "#{@repo.class.name} does not override action #{verb}"
      # else
      #   @logger.error "#{clazz.name.to_s} does not implement action #{verb}"
      #   @vars[:return_code] = Errors::BUILDER_REPO_ACTION
      end
      @vars[:return_code] = @repo.send(verb)
    else
      @logger.fatal "'#{verb}' not implemented!"
      @vars[:return_code] = Errors::BUILDER_REPO_ACTION
    end
  end
  @vars[:return_code]
end

#prepareBuildObject




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/cicd/builder/mixlib/build.rb', line 33

def prepareBuild()
  @logger.step CLASS+'::'+__method__.to_s
  meta = {}
  @vars[:return_code] = 0
  %w[ WORKSPACE PROJECT_NAME ].each do |e|
    unless ENV.has_key?(e)
      puts "#{e} environment variable is required"
      @vars[:return_code] = Errors::MISSING_ENV_VAR
    end
  end
  meta[:Version] = @vars[:version]
  meta[:Release] = @vars[:release]

  if @vars[:return_code] == 0

    if File.exists?(ENV['WORKSPACE']) and (File.directory?(ENV['WORKSPACE']) or File.symlink?(ENV['WORKSPACE']))

      place = ''
      begin
        # Assuming we are in the workspace ...
        place = "Git.open('#{ENV['WORKSPACE']}')"
        req = 'require "git"'
        eval req

        git = Git.open(ENV['WORKSPACE'], :log => @logger)
        place = 'git.log'
        meta[:Commit] = git.log[0].sha
        place = 'git.current_branch'
        meta[:Branch] = git.current_branch
        # meta[:Remotes] = git.remotes

        @vars[:build_ext] = 'tar.gz'
        @vars[:build_bra] = @vars[:branch] || meta[:Branch].gsub(%r([/|]),'.')
        @vars[:build_ver] = "#{meta[:Version]}"
        @vars[:build_rel] = "#{meta[:Release]}"
        @vars[:build_vrb] = "#{@vars[:build_ver]}-release-#{meta[:Release]}-#{@vars[:build_bra]}-#{@vars[:variant]}" #
        @vars[:build_nam] = "#{@vars[:project_name]}-#{@vars[:build_vrb]}"
        @vars[:build_nmn] = "#{@vars[:build_nam]}-build-#{@vars[:build_num]}"
        @vars[:build_dir] = "#{ENV['WORKSPACE']}/#{@vars[:build_nmn]}"
        @vars[:latest_pkg]= "#{@vars[:build_store]}/#{@vars[:build_nmn]}.#{@vars[:build_ext]}"
        @vars[:build_pkg] = "#{@vars[:build_nmn]}.#{@vars[:build_ext]}"
        @vars[:build_chk] = "#{@vars[:build_nmn]}.checksum"
        @vars[:build_mff] = "#{@vars[:build_nmn]}.manifest"
        @vars[:build_mdf] = "#{@vars[:build_nmn]}.meta"
        @vars[:build_mvn] = "#{@vars[:build_ver]}-#{@vars[:build_num]}"
        @vars[:build_mdd] = meta.dup
        #noinspection RubyArgCount
        @vars[:build_mds] = Digest::SHA256.hexdigest(meta.to_s)

        @vars[:return_code] = 0

      rescue Exception => e
        @logger.error "#{e.class}:: '#{place}' - #{e.message}"
        @vars[:return_code] = Errors::PREPAREBUILD_EXCEPTION
      end

    else
      puts "Invalid workspace: '#{ENV['WORKSPACE']}'"
      @vars[:return_code] = Errors::INVALID_WORKSPACE
    end
  end

  if @vars[:return_code] == 0
    @vars[:local_dirs] ||= {}
    %w(artifacts latest).each do |dir|
      @vars[:local_dirs][dir] = "#{ENV['WORKSPACE']}/#{dir}"
      unless File.directory?(dir)
        Dir.mkdir(dir)
      end
    end
  end

  @vars[:return_code]
end

#pruneInventoryObject




85
86
87
88
# File 'lib/cicd/builder/mixlib/repo.rb', line 85

def pruneInventory()
  @logger.step CLASS+'::'+__method__.to_s
			performOnRepoInstance(__method__.to_s)
end

#reportResultObject



229
230
231
232
233
234
235
236
# File 'lib/cicd/builder/mixlib/environment.rb', line 229

def reportResult()
  if 0 == @vars[:return_code]
    # NOTE the '.note'!
    @logger.note  "CHANGE:  #{ENV['JOB_NAME']} #{ENV['BUILD_NUMBER']} #{@vars[:build_nam]} (#{@vars[:build_pkg]}) [#{@vars[:check_sha]}] => [#{@vars[:build_sha]}]"
  else
    @logger.error "FAILURE: #{ENV['JOB_NAME']} #{ENV['BUILD_NUMBER']} #{@vars[:build_pkg]} #{@vars[:return_code]}"
  end
end

#reportStatus(ignored = ENV_IGNORED) ⇒ Object




239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/cicd/builder/mixlib/environment.rb', line 239

def reportStatus(ignored=ENV_IGNORED)
    # [2013-12-30 Christo] Report status,environment, etc.

	if @logger.level < ::Logging::LEVELS['warn']
		@logger.info '='*100
		@logger.info Dir.getwd()
		@logger.info '='*100

		@logger.info "Config:"
		@options.each{|k,v|
			unless ignored.include?(k)
				@logger.info sprintf("%25s: %s", "#{k.to_s}",  "#{v.to_s}")
			end
		}

		@logger.info '='*100

		@logger.info "Parameters:"
		@vars.sort.each{|k,v|
			unless ignored.include?(k)
				@logger.info sprintf("%25s: %s", "#{k.to_s}",  "#{v.to_s}")
			end
		}

		@logger.info '='*100
	end

	if @logger.level < ::Logging::LEVELS['info']
		@logger.debug '='*100
		@logger.debug "Environment:"
		ENV.sort.each{|k,v|
			unless ignored.include?(k)
				@logger.debug sprintf("%25s: %s", "#{k.to_s}",  "#{v.to_s}")
			end
		}

		@logger.debug '='*100
	end
end

#saveBuildObject




166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/cicd/builder/mixlib/environment.rb', line 166

def saveBuild()
  @logger.step CLASS+'::'+__method__.to_s
  begin
    raise 'ERROR: Checksum not read'       unless @vars.has_key?(:latest_sha)
    raise 'ERROR: Checksum not calculated' unless @vars.has_key?(:build_sha)
    change = false
    if @vars[:latest_sha] != @vars[:build_sha]
      change = true
      @logger.info "CHANGE: Checksum [#{@vars[:latest_sha]}] => [#{@vars[:build_sha]}]"
    end
    if @vars[:latest_ver] != @vars[:build_ver]
      change = true
      @logger.info "CHANGE: Version [#{@vars[:latest_ver]}] => [#{@vars[:build_ver]}]"
    end
    if @vars[:latest_rel] != @vars[:build_rel]
      change = true
      @logger.info "CHANGE: Release [#{@vars[:latest_rel]}] => [#{@vars[:build_rel]}]"
    end
    unless File.file?(@vars[:build_pkg])
      change = true
      @logger.info "CHANGE: No #{@vars[:build_pkg]}"
    end
    unless File.symlink?(@vars[:latest_pkg])
      change = true
      @logger.info "CHANGE: No #{@vars[:latest_pkg]}"
    end

    if change
      if @vars[:latest_pkg] != @vars[:build_pkg] and  File.file?(@vars[:build_pkg])
        @logger.info "Link #{@vars[:latest_pkg]} to #{@vars[:build_pkg]}"
        begin
          File.unlink(@vars[:latest_pkg])
        rescue
          # noop
        end
        File.symlink(@vars[:build_pkg], @vars[:latest_pkg])
      else
        @logger.warn "Skipping link #{@vars[:latest_pkg]} to missing '#{@vars[:build_pkg]}'"
      end
      @vars[:return_code] = saveLatestVarsFile()
      unless 0 == @vars[:return_code]
        @logger.error "Failed to save latest vars file: #{@vars[:latest_fil]}"
        return @vars[:return_code]
      end
      @vars[:return_code] = saveEnvironment(ENV_IGNORED)
      unless 0 == @vars[:return_code]
        @logger.error "Failed to save environment vars file: #{@vars[:vars_fil]}"
        return @vars[:return_code]
      end
      # NOTE the '.note'!
      @logger.note "CHANGE: #{ENV['JOB_NAME']} (#{@vars[:build_ver]}-#{@vars[:build_rel]}[#{@vars[:build_sha]}])"
    else
      @logger.info "Artifact #{@vars[:latest_pkg]} unchanged (#{@vars[:latest_ver]}-#{@vars[:latest_rel]} [#{@vars[:latest_sha]}])"
      @logger.note "NO_CHANGE: #{ENV['JOB_NAME']} #{@vars[:latest_ver]}"
    end
    @vars[:return_code] = 0
  rescue => e
    @logger.error "#{e.backtrace[0]}: #{e.class.name} #{e.message}"
    @vars[:return_code] = 2
  end
  @vars[:return_code]
end

#saveEnvironment(ignored = ENV_IGNORED) ⇒ Object




153
154
155
156
157
158
159
160
161
162
163
# File 'lib/cicd/builder/mixlib/environment.rb', line 153

def saveEnvironment(ignored=ENV_IGNORED)
    @logger.info CLASS+'::'+__method__.to_s
	@logger.info "Save environment to #{@vars[:vars_fil]}"
	vstr = ['[global]']
	ENV.to_hash.sort.each{|k,v|
		vstr << %(#{k}="#{v}") unless ignored.include?(k)
	}

    @vars[:return_code] = (IO.write(@vars[:vars_fil], vstr.join("\n")) > 0) ? 0 : Errors::SAVE_ENVIRONMENT_VARS
    return @vars[:return_code]
end

#saveLatestVarsFileObject




146
147
148
149
150
# File 'lib/cicd/builder/mixlib/environment.rb', line 146

def saveLatestVarsFile
  @logger.info "Save latest build info to #{@vars[:latest_fil]}"
  wrote = IO.write(@vars[:latest_fil], "#{@vars[:build_ver]}-#{@vars[:build_rel]}\n#{@vars[:build_sha]}")
  ret = (wrote > 0) ? 0 : Errors::SAVE_LATEST_VARS
end

#syncInventoryObject




91
92
93
94
# File 'lib/cicd/builder/mixlib/repo.rb', line 91

def syncInventory()
  @logger.step CLASS+'::'+__method__.to_s
			performOnRepoInstance(__method__.to_s)
end

#syncRepoObject




97
98
99
100
# File 'lib/cicd/builder/mixlib/repo.rb', line 97

def syncRepo()
  @logger.step CLASS+'::'+__method__.to_s
			performOnRepoInstance(__method__.to_s)
end

#uploadBuildArtifactsObject




73
74
75
76
# File 'lib/cicd/builder/mixlib/repo.rb', line 73

def uploadBuildArtifacts()
  @logger.step CLASS+'::'+__method__.to_s
  performOnRepoInstance(__method__.to_s)
end