a2zdeploy 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/a2zdeploy.gemspec +3 -3
- data/lib/a2zdeploy.rb +2 -0
- data/lib/dependency_tree.rb +1 -3
- data/lib/github_api.rb +85 -0
- data/lib/global_constants.rb +1 -1
- data/lib/rollback.rb +63 -0
- data/lib/rollbackall.rb +163 -0
- data/lib/teamcity_api.rb +43 -7
- data/lib/upgrade.rb +44 -6
- data/lib/upgradeall.rb +88 -43
- data/lib/version_map.rb +1 -4
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71b4475b48254171a7f88017f9dd1a66631c77c2
|
4
|
+
data.tar.gz: 5c2a54aabb1f19b8fc3c1f8ac9b06b58b38a83e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1976a841d9bab7db8db8e0d686bf168bcdce832f42e7f8d3e5588188cd7985e80d02aaa44a62295c249e128af12be442ad51f10f5eab6895ce60756b8691bb5
|
7
|
+
data.tar.gz: d743465fd4489912e8448244b7182475fd369374c3de8007ee7d810f530d970550bcfb56d0e1d1690160341069aa821a37a65a768a8aa1e46e8f74cd7c3eb38d
|
data/a2zdeploy.gemspec
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'a2zdeploy'
|
3
|
-
s.version = '1.0.
|
4
|
-
s.date = '2016-
|
3
|
+
s.version = '1.0.4'
|
4
|
+
s.date = '2016-02-08'
|
5
5
|
s.summary = 'Given a project dependency chain, updates versions, builds, tests, manages service and cloud settings as well as build environment configuration'
|
6
6
|
s.description = 'Automated Upgrades Gem. Provides version upgrades, build and deployment configuration management'
|
7
7
|
s.authors = ['Suresh Batta']
|
8
8
|
s.email = 'subatta@hotmail.com'
|
9
|
-
s.files = Dir['{
|
9
|
+
s.files = Dir['{lib}/**/*'] + ['a2zdeploy.gemspec', 'ReadMe.md']
|
10
10
|
s.homepage = 'http://rubygems.org/gems/a2zdeploy'
|
11
11
|
s.license = 'MIT'
|
12
12
|
end
|
data/lib/a2zdeploy.rb
CHANGED
@@ -9,7 +9,9 @@ require_relative 'github_api'
|
|
9
9
|
require_relative 'version_map'
|
10
10
|
require_relative 'hash_extensions'
|
11
11
|
require_relative 'input_validator'
|
12
|
+
require_relative 'rollback'
|
12
13
|
|
14
|
+
require 'rake'
|
13
15
|
require 'addressable/uri'
|
14
16
|
require 'azdeploy'
|
15
17
|
require 'builder'
|
data/lib/dependency_tree.rb
CHANGED
@@ -44,9 +44,7 @@ class DependencyTree
|
|
44
44
|
if @dependency_map[current].has_key? GlobalConstants::NEXT
|
45
45
|
next_node = @dependency_map[current][GlobalConstants::NEXT]
|
46
46
|
next_node = @dependency_map[next_node]
|
47
|
-
if !next_node.nil?
|
48
|
-
next_node = Hashit.new next_node
|
49
|
-
end
|
47
|
+
next_node = Hashit.new next_node if !next_node.nil?
|
50
48
|
end
|
51
49
|
end
|
52
50
|
|
data/lib/github_api.rb
CHANGED
@@ -6,6 +6,11 @@
|
|
6
6
|
|
7
7
|
module GithubApi
|
8
8
|
|
9
|
+
def GithubApi.CreateNewBranch new_branch, branch
|
10
|
+
puts "Creating new branch #{new_branch} from #{branch}..."
|
11
|
+
`git branch #{new_branch} #{branch}`
|
12
|
+
end
|
13
|
+
|
9
14
|
def GithubApi.CheckoutNewBranch branch
|
10
15
|
puts "Checking out new branch #{branch}..."
|
11
16
|
`git checkout -b #{branch}`
|
@@ -37,7 +42,49 @@ module GithubApi
|
|
37
42
|
`git checkout #{branch}`
|
38
43
|
end
|
39
44
|
|
45
|
+
# Reverts commits from commit_hashes, expected order is newest to oldest
|
46
|
+
def GithubApi.RevertLocal branch, commit_hashes
|
47
|
+
puts "Reverting commits on local branch: #{branch}..."
|
48
|
+
`git checkout #{branch}`
|
49
|
+
recent_hash = commit_hashes[0]
|
50
|
+
past_hash = commit_hashes[-1]
|
51
|
+
`git --no-edit revert #{past_hash}^..#{recent_hash}`
|
52
|
+
end
|
53
|
+
|
54
|
+
def GithubApi.TagLocal commit_hash, tag_name, message
|
55
|
+
puts "Tagging commit hash: #{commit_hash} with #{tag_name}..."
|
56
|
+
`git tag -a #{tag_name} #{commit_hash} -m #{message}`
|
57
|
+
end
|
58
|
+
|
59
|
+
def GithubApi.GetRecentCommitHash branch
|
60
|
+
git_log_raw = `git log -1 #{branch}`
|
61
|
+
return GithubApi.GetCommitHashesFromLog(git_log_raw).first
|
62
|
+
end
|
63
|
+
|
64
|
+
def GithubApi.ShowCommitInfoLocal commit_hash
|
65
|
+
`git show --name-only #{commit_hash}`
|
66
|
+
end
|
67
|
+
|
68
|
+
def GithubApi.ForcePushBranch remote, branch
|
69
|
+
# use url substituted with un/pwd
|
70
|
+
#remote_url = GithubApi.InsertCredsInRemote remote
|
71
|
+
puts "Force Pushing #{branch} to #{remote}..."
|
72
|
+
`git push #{remote} #{branch} -f`
|
73
|
+
end
|
74
|
+
|
75
|
+
def GithubApi.InsertCredsInRemote remote_name
|
76
|
+
url = `git config --get remote.#{remote_name}.url`
|
77
|
+
url = GithubApi.InsertCredsInUrl(url) if !url.include? '@'
|
78
|
+
url
|
79
|
+
end
|
80
|
+
|
81
|
+
def GithubApi.InsertCredsInUrl url
|
82
|
+
url = url.sub('http://', "http://#{ENV['un']}:#{ENV['pwd']}@")
|
83
|
+
url
|
84
|
+
end
|
85
|
+
|
40
86
|
def GithubApi.PushBranch remote, branch
|
87
|
+
#remote_url = GithubApi.InsertCredsInRemote remote
|
41
88
|
puts "Pushing #{branch} to #{remote}..."
|
42
89
|
`git push #{remote} #{branch}`
|
43
90
|
end
|
@@ -59,8 +106,22 @@ module GithubApi
|
|
59
106
|
`git pull --rebase #{@repo_url} #{@branch}`
|
60
107
|
end
|
61
108
|
|
109
|
+
def GithubApi.CommitAllLocalAndPush comment
|
110
|
+
|
111
|
+
`git add .`
|
112
|
+
|
113
|
+
status = `git commit -m "#{comment}"`
|
114
|
+
return false if status != GlobalConstants::EMPTY
|
115
|
+
|
116
|
+
#todo: ensure push defaults are set up
|
117
|
+
status = `git push`
|
118
|
+
return status != GlobalConstants::EMPTY
|
119
|
+
|
120
|
+
end
|
121
|
+
|
62
122
|
def GithubApi.CommitChanges comment, git_status = ''
|
63
123
|
if git_status != GlobalConstants::EMPTY
|
124
|
+
#gotcha: line breaks need to be in double-quotes
|
64
125
|
val = git_status.split("\n")
|
65
126
|
val.each { |x|
|
66
127
|
value = x.split(' M ').last || x.split('?? ').last
|
@@ -77,8 +138,27 @@ module GithubApi
|
|
77
138
|
return status != GlobalConstants::EMPTY
|
78
139
|
end
|
79
140
|
|
141
|
+
# Returns commits in order of newest to oldest
|
142
|
+
def GithubApi.BranchCommitDiff base_branch, derived_branch
|
143
|
+
puts "Getting commit diff from #{base_branch} to #{derived_branch}"
|
144
|
+
commit_diff_raw = `git log #{base_branch}..#{derived_branch}`
|
145
|
+
puts commit_diff_raw
|
146
|
+
|
147
|
+
return GithubApi.GetCommitHashesFromLog commit_diff_raw
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns commits in order of newest to oldest
|
151
|
+
def GithubApi.GetCommitHashesFromLog git_log
|
152
|
+
matches = git_log.scan /^commit [a-zA-Z0-9]*$/
|
153
|
+
commit_len = 'commit '.length
|
154
|
+
commit_hashes = matches.map { |v| v[commit_len, v.length-1] }
|
155
|
+
return commit_hashes
|
156
|
+
end
|
157
|
+
|
158
|
+
|
80
159
|
# we do NOT want to switch to parent folder but stay in current repo dir when we exit this method
|
81
160
|
def GithubApi.CheckoutRepoAfresh repo_url, branch
|
161
|
+
|
82
162
|
repo = GithubApi.ProjectNameFromRepo repo_url
|
83
163
|
return false if repo == GlobalConstants::EMPTY
|
84
164
|
|
@@ -88,6 +168,7 @@ module GithubApi
|
|
88
168
|
FileUtils.rm_rf repo
|
89
169
|
end
|
90
170
|
|
171
|
+
#repo_url = GithubApi.InsertCredsInUrl repo_url
|
91
172
|
# clone to local
|
92
173
|
puts 'Cloning repo to local...'
|
93
174
|
begin
|
@@ -137,4 +218,8 @@ module GithubApi
|
|
137
218
|
|
138
219
|
repo
|
139
220
|
end
|
221
|
+
|
222
|
+
def GithubApi.SetPushDefaultSimple
|
223
|
+
`git config --global push.default simple`
|
224
|
+
end
|
140
225
|
end
|
data/lib/global_constants.rb
CHANGED
data/lib/rollback.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
=begin
|
2
|
+
rollback flow:
|
3
|
+
|
4
|
+
check rollback command
|
5
|
+
avoid replacing backup branch
|
6
|
+
|
7
|
+
commit diff on backup vs current
|
8
|
+
at least one commit should be version upgrade
|
9
|
+
create revert commits on commit diff
|
10
|
+
|
11
|
+
tag commit with nuget version if it publishes nuget
|
12
|
+
tag commit with timestamp if it is a service
|
13
|
+
|
14
|
+
replace backup branch
|
15
|
+
=end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
class RollbackUpgrade
|
20
|
+
|
21
|
+
DATE_FORMAT = 'date_%m-%d-%Y_time_%H.%M.%S'
|
22
|
+
|
23
|
+
def initialize repo_url, remote, current_branch, rollback_branch, metadata
|
24
|
+
@repo_url = repo_url
|
25
|
+
@remote = remote
|
26
|
+
@current_branch = current_branch
|
27
|
+
@rollback_branch = rollback_branch
|
28
|
+
@metadata = metadata
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_rollback_tag
|
32
|
+
versioning = SemverVersioning.new
|
33
|
+
semver_file = @config_map.metadata.semver.file
|
34
|
+
if @config_map.metadata.should_publish_nuget.downcase == 'y' && semver_file != nil && semver_file != GlobalConstants::EMPTY
|
35
|
+
semver_file.capitalize
|
36
|
+
ver_tag = versioning.get_current_version @config_map.metadata.semver.location, semver_file
|
37
|
+
return "rollback-#{ver_tag}"
|
38
|
+
else
|
39
|
+
utc_now = DateTime.now.utc
|
40
|
+
date_tag = utc_now.strftime(DATE_FORMAT)
|
41
|
+
return "rollback-#{date_tag}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def Do
|
46
|
+
commit_hashes = GithubApi.BranchCommitDiff(@rollback_branch, @current_branch)
|
47
|
+
if commit_hashes.length == 0
|
48
|
+
puts `No difference between branches #{current_branch} and #{rollback_branch}, aborting rollback.`
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
# check hashes for version upgrade commit message
|
53
|
+
if !commit_hashes.any?{ |c_hash| GithubApi.ShowCommitInfoLocal(c_hash).include? UpgradePackages::VERSION_UPGRADE_COMMIT }
|
54
|
+
puts `No version upgrade commit detected to roll back, aborting rollback.`
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
GithubApi.RevertLocal(@current_branch, commit_hashes)
|
59
|
+
|
60
|
+
puts `@<--- Rollback branch revert completed. @<---`
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
end
|
data/lib/rollbackall.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Uses project dependency map and configuration to process a DataPlatform Service's
|
4
|
+
code repository level framework upgrade and service deployments
|
5
|
+
|
6
|
+
=end
|
7
|
+
|
8
|
+
class RollbackAll
|
9
|
+
|
10
|
+
VERSION_MAP_FILE = 'versionmap.json'
|
11
|
+
# todo: remove the up one level path
|
12
|
+
MANIFEST_FILE = 'manifest.json'
|
13
|
+
|
14
|
+
# repo_url is where the last known version map and manifest are checked-in
|
15
|
+
def initialize repo_url, branch, manifest_path = MANIFEST_FILE
|
16
|
+
|
17
|
+
@repo_url = repo_url
|
18
|
+
@branch = branch
|
19
|
+
@manifest_path = manifest_path
|
20
|
+
|
21
|
+
@manifest = JSON.parse File.read(@manifest_path) if File.exist? @manifest_path
|
22
|
+
end
|
23
|
+
|
24
|
+
def manifest
|
25
|
+
@manifest
|
26
|
+
end
|
27
|
+
|
28
|
+
def version_map
|
29
|
+
@remote_version_map
|
30
|
+
end
|
31
|
+
|
32
|
+
def retrieve_artifacts
|
33
|
+
|
34
|
+
return if !GithubApi.CheckoutRepoAfresh @repo_url, @branch
|
35
|
+
|
36
|
+
# JSON files converted to hash
|
37
|
+
@remote_version_map = JSON.parse File.read(VERSION_MAP_FILE) if File.exist? VERSION_MAP_FILE
|
38
|
+
@manifest = JSON.parse File.read(@manifest_path) if File.exist? @manifest_path
|
39
|
+
|
40
|
+
Dir.chdir GlobalConstants::PARENTDIR
|
41
|
+
end
|
42
|
+
|
43
|
+
def version_exists
|
44
|
+
|
45
|
+
# create version map afresh to compare
|
46
|
+
vm = VersionMap.new
|
47
|
+
version_repo_url = @manifest['version_source']['repo_url']
|
48
|
+
versions = vm.version_map version_repo_url, @manifest['version_source']['branch']
|
49
|
+
|
50
|
+
# If remote version doesn't exist, save it
|
51
|
+
if @remote_version_map.nil?
|
52
|
+
File.write VERSIONMAPFILE, versions.to_json
|
53
|
+
GithubApi.PushBranch @repo_url, @branch
|
54
|
+
|
55
|
+
return hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def Do input_validator, is_local_run=false
|
60
|
+
|
61
|
+
puts "\n"
|
62
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Rollback All has begun..'
|
63
|
+
|
64
|
+
# retrieve version map and upgrade manifest
|
65
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Retrieving artifacts...'
|
66
|
+
retrieve_artifacts
|
67
|
+
|
68
|
+
return false if @remote_version_map.nil? || @manifest.nil?
|
69
|
+
|
70
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Ensuring version map exists...'
|
71
|
+
version_exists
|
72
|
+
|
73
|
+
|
74
|
+
# validate manifest
|
75
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Validating manifest...'
|
76
|
+
validation_errors = []
|
77
|
+
input_validator.validate_manifest(@manifest) do |error|
|
78
|
+
validation_errors << error if !error.nil?
|
79
|
+
end
|
80
|
+
raise StandardError, validation_error_message(validation_errors) if validation_errors.length > 0
|
81
|
+
|
82
|
+
nuget_targets = []
|
83
|
+
|
84
|
+
# TODO: This validation could probably go in an input validator specifically for rollback
|
85
|
+
rollback_config = @manifest['projects']['root']['metadata'].IsRollback
|
86
|
+
rollback = !rollback_config.nil? and rollback_config.downcase == 'y'
|
87
|
+
if !rollback
|
88
|
+
puts 'IsRollback not set in manifest, aborting rollback.'
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
upgrader = UpgradePackages.new versions_to_update, rollback
|
92
|
+
|
93
|
+
# if changes exist, cycle through dependency tree and kick off upgrades
|
94
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Navigating projects...'
|
95
|
+
dep_tree = DependencyTree.new(@manifest['projects'])
|
96
|
+
dep_tree.traverse do |node|
|
97
|
+
|
98
|
+
if node.metadata.should_upgrade.downcase == 'y'
|
99
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Processing project #{node.project_name}..."
|
100
|
+
|
101
|
+
# validate project node
|
102
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Validating project node...'
|
103
|
+
input_validator.validate_project_node(node) do |error|
|
104
|
+
validation_errors << error if !error.nil?
|
105
|
+
end
|
106
|
+
raise StandardError, validation_error_message(validation_errors) if validation_errors.length > 0
|
107
|
+
|
108
|
+
# the upgrade
|
109
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Rolling back project #{node.project_name}..."
|
110
|
+
upgrade_status = upgrader.Do node, nuget_targets, is_local_run
|
111
|
+
|
112
|
+
# save node name to use for status update
|
113
|
+
node_name = node.project_name
|
114
|
+
if (node.respond_to?('is_root') && node.is_root == 'true')
|
115
|
+
node_name = GlobalConstants::ROOT
|
116
|
+
end
|
117
|
+
|
118
|
+
# project status set in json
|
119
|
+
if upgrade_status
|
120
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Rollback of #{node.project_name} succeeded"
|
121
|
+
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::SUCCESS
|
122
|
+
Dir.chdir GlobalConstants::PARENTDIR
|
123
|
+
else
|
124
|
+
# either cycle was unterrupted, a step in upgrade failed or full cycle successfully completed
|
125
|
+
# save the version map and manifest
|
126
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Rollback of #{node.project_name} failed"
|
127
|
+
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::FAILED
|
128
|
+
# no more processing after failure
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
|
132
|
+
else
|
133
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Skipping Rollback for project #{node.project_name}..."
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# upgrade completed successfully, set rollback to 'n' state, update status as unprocessed and save version map and manifest, push
|
138
|
+
@manifest['projects']['root']['metadata'].IsRollback = 'n'
|
139
|
+
reset_status_unprocessed
|
140
|
+
|
141
|
+
|
142
|
+
true
|
143
|
+
end
|
144
|
+
|
145
|
+
def save version_manifest
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def reset_status_unprocessed
|
151
|
+
@manifest['projects'].each { |proj|
|
152
|
+
proj.each { |item|
|
153
|
+
item['metadata']['status'] = GlobalConstants::UNPROCESSED if item.class.to_s != 'String'
|
154
|
+
}
|
155
|
+
}
|
156
|
+
@manifest
|
157
|
+
end
|
158
|
+
|
159
|
+
def validation_error_message validation_errors
|
160
|
+
"One or more validation errors have occurred: #{validation_errors.join(' ')}"
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
data/lib/teamcity_api.rb
CHANGED
@@ -7,23 +7,37 @@ require 'builder'
|
|
7
7
|
|
8
8
|
module TeamCityApi
|
9
9
|
|
10
|
+
def TeamCityApi.get_teamcity_creds
|
11
|
+
file = File.open(Dir.pwd + '/spec/p.txt', 'r')
|
12
|
+
content = file.read
|
13
|
+
content.gsub!(/\r\n?/, "\n")
|
14
|
+
line_num = 0
|
15
|
+
creds = []
|
16
|
+
content.each_line do |line|
|
17
|
+
creds << line
|
18
|
+
end
|
19
|
+
creds
|
20
|
+
end
|
21
|
+
|
10
22
|
#Build trigger API
|
11
|
-
def TeamCityApi.trigger_build buildConfigurationId
|
23
|
+
def TeamCityApi.trigger_build buildConfigurationId
|
24
|
+
|
12
25
|
configContent = create_build_trigger_config buildConfigurationId
|
13
|
-
uri = URI.parse
|
26
|
+
uri = URI.parse 'http://teamcity.relayhealth.com'
|
14
27
|
http = Net::HTTP.new uri.host, uri.port
|
15
|
-
request = Net::HTTP::Post.new
|
28
|
+
request = Net::HTTP::Post.new '/httpAuth/app/rest/buildQueue'
|
16
29
|
request.body = configContent
|
17
30
|
request.content_type = 'application/xml'
|
18
31
|
request.basic_auth username, password
|
19
|
-
http.request request
|
32
|
+
response = http.request request
|
33
|
+
p response
|
20
34
|
end
|
21
35
|
|
22
36
|
def TeamCityApi.create_build_trigger_config buildConfigurationId
|
23
37
|
xml = Builder::XmlMarkup.new :indent => 2
|
24
38
|
xml.build{
|
25
|
-
xml.triggeringOptions
|
26
|
-
xml.buildType
|
39
|
+
xml.triggeringOptions 'cleanSources' => 'true', 'rebuildAllDependencies' => 'true', 'queueAtTop' => 'true'
|
40
|
+
xml.buildType 'id' => "#{buildConfigurationId}"
|
27
41
|
}
|
28
42
|
end
|
29
43
|
|
@@ -207,9 +221,31 @@ module TeamCityApi
|
|
207
221
|
response = http.request request
|
208
222
|
end
|
209
223
|
|
210
|
-
|
224
|
+
def TeamCityApi.get_build_status projectId
|
225
|
+
# list queued builds per project
|
226
|
+
uri = URI.parse 'http://teamcity.relayhealth.com'
|
227
|
+
http = Net::HTTP.new uri.host, uri.port
|
228
|
+
request = Net::HTTP::Get.new "/app/rest/buildQueue?locator=project:#{projectId}", {'Accept' => 'application/json'}
|
229
|
+
creds = TeamCityApi.get_teamcity_creds
|
230
|
+
request.basic_auth creds[0].delete("\n"), creds[1].delete("\n")
|
231
|
+
response = http.request request
|
232
|
+
end
|
211
233
|
|
234
|
+
end
|
212
235
|
|
236
|
+
=begin
|
237
|
+
creds = TeamCityApi.get_teamcity_creds
|
238
|
+
configContent = create_build_trigger_config buildConfigurationId
|
239
|
+
uri = URI.parse 'http://teamcity.relayhealth.com'
|
240
|
+
http = Net::HTTP.new uri.host, uri.port
|
241
|
+
request = Net::HTTP::Post.new '/httpAuth/app/rest/buildQueue'
|
242
|
+
request.body = configContent
|
243
|
+
request.content_type = 'application/xml'
|
244
|
+
request.basic_auth creds[0].delete("\n"), creds[1].delete("\n")
|
245
|
+
response = http.request request
|
246
|
+
p response.body
|
247
|
+
end
|
248
|
+
=end
|
213
249
|
# Sample Usage
|
214
250
|
#TeamCityApi.trigger_build("DataPlatform_DataPlatformOntology_ADevelopBuildDataPlatformOntology_2", "username", "password")
|
215
251
|
|
data/lib/upgrade.rb
CHANGED
@@ -7,9 +7,13 @@ Processes upgrade for a C# code repositoryy
|
|
7
7
|
class UpgradePackages
|
8
8
|
|
9
9
|
UPGRADE_BRANCH = 'upgrade'
|
10
|
+
BACKUP_BRANCH = 'upgradeBackupDoNotDelete'
|
11
|
+
VERSION_UPGRADE_COMMIT = 'Versions updated'
|
12
|
+
VERSION_UPGRADE_FAIL_BUILD_COMMIT = 'Versions updated, build failed'
|
10
13
|
|
11
|
-
def initialize versions
|
14
|
+
def initialize versions, rollback=false
|
12
15
|
@versions = versions
|
16
|
+
@rollback = rollback
|
13
17
|
end
|
14
18
|
|
15
19
|
def checkout_upgrade_branch
|
@@ -26,6 +30,20 @@ class UpgradePackages
|
|
26
30
|
return true
|
27
31
|
end
|
28
32
|
|
33
|
+
def create_upgrade_tag
|
34
|
+
versioning = SemverVersioning.new
|
35
|
+
semver_file = @config_map.metadata.semver.file
|
36
|
+
if @config_map.metadata.should_publish_nuget.downcase == 'y' && semver_file != nil && semver_file != GlobalConstants::EMPTY
|
37
|
+
semver_file.capitalize
|
38
|
+
ver_tag = versioning.get_current_version @config_map.metadata.semver.location, semver_file
|
39
|
+
return "upgrade-#{ver_tag}"
|
40
|
+
else
|
41
|
+
utc_now = DateTime.now.utc
|
42
|
+
date_tag = utc_now.strftime(DATE_FORMAT)
|
43
|
+
return "upgrade-#{date_tag}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
29
47
|
def Do config_map, nuget_targets, is_local_run=false
|
30
48
|
|
31
49
|
@config_map = config_map
|
@@ -35,6 +53,22 @@ class UpgradePackages
|
|
35
53
|
# checkout repo and branch
|
36
54
|
return false if !GithubApi.CheckoutRepoAfresh @repo_url, @branch
|
37
55
|
|
56
|
+
tag_creator = method(:create_upgrade_tag)
|
57
|
+
|
58
|
+
# TODO: Need to check if node has failed before invoking rollback
|
59
|
+
if @rollback
|
60
|
+
puts "Starting Rollback."
|
61
|
+
rollback = new Rollback @repo_url, 'origin', @branch, BACKUP_BRANCH, @config_map.metadata
|
62
|
+
tag_creator = rollback.method(:create_rollback_tag)
|
63
|
+
return false if !rollback.Do
|
64
|
+
end
|
65
|
+
|
66
|
+
# When upgrade branch exists we are coming from some failure state and dont need to backup the branch again
|
67
|
+
if (GithubApi.DoesBranchExist('origin', UPGRADE_BRANCH) == GlobalConstants::EMPTY)
|
68
|
+
GithubApi.CreateNewBranch(BACKUP_BRANCH, @branch)
|
69
|
+
GithubApi.ForcePushBranch('origin', BACKUP_BRANCH)
|
70
|
+
end
|
71
|
+
|
38
72
|
# make upgrade branch
|
39
73
|
return false if !checkout_upgrade_branch
|
40
74
|
|
@@ -61,9 +95,13 @@ class UpgradePackages
|
|
61
95
|
# QUESTION: Should this method increment semver even if there is no nuget published?
|
62
96
|
puts GlobalConstants::UPGRADE_PROGRESS + 'Upgrading semver...'
|
63
97
|
semver_inc_done = increment_semver_if_publish is_local_run
|
64
|
-
if @config_map.metadata.should_publish_nuget.downcase == 'y'
|
65
|
-
|
66
|
-
|
98
|
+
nuget_targets << Dir.pwd + '/build_artifacts' if @config_map.metadata.should_publish_nuget.downcase == 'y'
|
99
|
+
|
100
|
+
# Tag commit
|
101
|
+
recent_commit_hash = GithubApi.GetRecentCommitHash(@branch)
|
102
|
+
#rollback_tag = tag_creator.call()
|
103
|
+
|
104
|
+
#GithubApi.TagLocal(recent_commit_hash, rollback_tag, "Autoupgrade Tag")
|
67
105
|
|
68
106
|
# do rake build to test for compilation errors. This needs ENV vars set, passed in via config
|
69
107
|
set_project_env_vars @config_map.metadata.env_vars
|
@@ -71,7 +109,7 @@ class UpgradePackages
|
|
71
109
|
if output.to_s == 'false'
|
72
110
|
puts GlobalConstants::UPGRADE_PROGRESS + ' Rake Error: There were errors during rake run.'
|
73
111
|
# save state
|
74
|
-
GithubApi.CommitChanges(
|
112
|
+
GithubApi.CommitChanges( VERSION_UPGRADE_FAIL_BUILD_COMMIT)
|
75
113
|
|
76
114
|
return false
|
77
115
|
end
|
@@ -87,7 +125,7 @@ class UpgradePackages
|
|
87
125
|
else
|
88
126
|
return false if !update_branch
|
89
127
|
# kick off teamcity build
|
90
|
-
TeamCityApi.trigger_build @config_map.build_configuration_id,
|
128
|
+
TeamCityApi.trigger_build @config_map.build_configuration_id, ENV['tc_un'], ENV['tc_pwd']
|
91
129
|
end
|
92
130
|
|
93
131
|
true
|
data/lib/upgradeall.rb
CHANGED
@@ -10,6 +10,7 @@ class UpgradeAll
|
|
10
10
|
VERSION_MAP_FILE = 'versionmap.json'
|
11
11
|
# todo: remove the up one level path
|
12
12
|
MANIFEST_FILE = 'manifest.json'
|
13
|
+
MAX_CHECKS = 12
|
13
14
|
|
14
15
|
# repo_url is where the last known version map and manifest are checked-in
|
15
16
|
def initialize repo_url, branch, manifest_path = MANIFEST_FILE
|
@@ -17,8 +18,8 @@ class UpgradeAll
|
|
17
18
|
@repo_url = repo_url
|
18
19
|
@branch = branch
|
19
20
|
@manifest_path = manifest_path
|
20
|
-
|
21
21
|
@manifest = JSON.parse File.read(@manifest_path) if File.exist? @manifest_path
|
22
|
+
|
22
23
|
end
|
23
24
|
|
24
25
|
def manifest
|
@@ -26,15 +27,14 @@ class UpgradeAll
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def version_map
|
29
|
-
@
|
30
|
+
@version_map
|
30
31
|
end
|
31
32
|
|
32
33
|
def retrieve_artifacts
|
33
|
-
|
34
34
|
return if !GithubApi.CheckoutRepoAfresh @repo_url, @branch
|
35
35
|
|
36
36
|
# JSON files converted to hash
|
37
|
-
@
|
37
|
+
@version_map = JSON.parse File.read(VERSION_MAP_FILE) if File.exist? VERSION_MAP_FILE
|
38
38
|
@manifest = JSON.parse File.read(@manifest_path) if File.exist? @manifest_path
|
39
39
|
|
40
40
|
Dir.chdir GlobalConstants::PARENTDIR
|
@@ -42,6 +42,8 @@ class UpgradeAll
|
|
42
42
|
|
43
43
|
def Do input_validator, is_local_run=false
|
44
44
|
|
45
|
+
GithubApi.SetPushDefaultSimple
|
46
|
+
|
45
47
|
puts "\n"
|
46
48
|
puts GlobalConstants::UPGRADE_PROGRESS + 'Upgrade All has begun..'
|
47
49
|
|
@@ -49,7 +51,7 @@ class UpgradeAll
|
|
49
51
|
puts GlobalConstants::UPGRADE_PROGRESS + 'Retrieving artifacts...'
|
50
52
|
retrieve_artifacts
|
51
53
|
|
52
|
-
return false if @
|
54
|
+
return false if @version_map.nil? || @manifest.nil?
|
53
55
|
|
54
56
|
#find version diff. If no changes exist, kick off deploy cycle only
|
55
57
|
puts GlobalConstants::UPGRADE_PROGRESS + 'Calculating version diff...'
|
@@ -77,53 +79,84 @@ class UpgradeAll
|
|
77
79
|
dep_tree = DependencyTree.new(@manifest['projects'])
|
78
80
|
dep_tree.traverse do |node|
|
79
81
|
|
80
|
-
if node
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
puts "#{GlobalConstants::UPGRADE_PROGRESS} Upgrading project #{node.project_name}..."
|
92
|
-
upgrade_status = upgrader.Do node, nuget_targets, is_local_run
|
93
|
-
|
94
|
-
# save node name to use for status update
|
95
|
-
node_name = node.project_name
|
96
|
-
if (node.respond_to?('is_root') && node.is_root == 'true')
|
97
|
-
node_name = GlobalConstants::ROOT
|
98
|
-
end
|
99
|
-
|
100
|
-
# project status set in json
|
101
|
-
if upgrade_status
|
102
|
-
puts "#{GlobalConstants::UPGRADE_PROGRESS} Upgrade of #{node.project_name} succeeded"
|
103
|
-
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::SUCCESS
|
104
|
-
Dir.chdir GlobalConstants::PARENTDIR
|
105
|
-
else
|
106
|
-
# either cycle was unterrupted, a step in upgrade failed or full cycle successfully completed
|
107
|
-
# save the version map and manifest
|
108
|
-
puts "#{GlobalConstants::UPGRADE_PROGRESS} Upgrade of #{node.project_name} failed"
|
109
|
-
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::FAILED
|
110
|
-
# no more processing after failure
|
111
|
-
return false
|
112
|
-
end
|
82
|
+
next if !check_should_upgrade node
|
83
|
+
next if check_success_state node
|
84
|
+
|
85
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Processing project #{node.project_name}..."
|
86
|
+
|
87
|
+
# validate project node
|
88
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Validating project node...'
|
89
|
+
input_validator.validate_project_node(node) do |error|
|
90
|
+
validation_errors << error if !error.nil?
|
91
|
+
end
|
92
|
+
raise StandardError, validation_error_message(validation_errors) if validation_errors.length > 0
|
113
93
|
|
94
|
+
# the upgrade
|
95
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Upgrading project #{node.project_name}..."
|
96
|
+
upgrade_status = upgrader.Do node, nuget_targets, is_local_run
|
97
|
+
|
98
|
+
# save node name to use for status update
|
99
|
+
node_name = node.project_name
|
100
|
+
node_name = GlobalConstants::ROOT if (node.respond_to?('is_root') && node.is_root == 'true')
|
101
|
+
|
102
|
+
# project status set in json
|
103
|
+
if upgrade_status
|
104
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Upgrade of #{node.project_name} succeeded"
|
105
|
+
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::SUCCESS
|
106
|
+
Dir.chdir GlobalConstants::PARENTDIR
|
107
|
+
|
108
|
+
# if publishing nuget package, wait for a minute for publish to finish
|
109
|
+
waitfor if node.should_publish_nuget
|
114
110
|
else
|
115
|
-
|
111
|
+
# either cycle was unterrupted, a step in upgrade failed or full cycle successfully completed
|
112
|
+
# save the version map and manifest
|
113
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Upgrade of #{node.project_name} failed"
|
114
|
+
@manifest['projects'][node_name]['metadata']['status'] = GlobalConstants::FAILED
|
115
|
+
# no more processing after failure
|
116
|
+
return false
|
116
117
|
end
|
118
|
+
|
117
119
|
end
|
118
120
|
|
119
121
|
# upgrade completed successfully, update status as unprocessed and save version map and manifest, push
|
120
122
|
reset_status_unprocessed
|
121
123
|
|
124
|
+
save_version_manifest versions_to_update if !is_local_run
|
122
125
|
|
123
126
|
true
|
124
127
|
end
|
125
128
|
|
126
|
-
def
|
129
|
+
def check_should_upgrade node
|
130
|
+
status = node.metadata.should_upgrade.downcase == 'y'
|
131
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Skipping upgrade for project #{node.project_name}..." if !status
|
132
|
+
status
|
133
|
+
end
|
134
|
+
|
135
|
+
def check_success_state node
|
136
|
+
status = node.metadata.status == GlobalConstants::SUCCESS
|
137
|
+
puts GlobalConstants::UPGRADE_PROGRESS + " Project #{node.project_name} already in #{GlobalConstants::SUCCESS} state. Skipping upgrade..." if status
|
138
|
+
status
|
139
|
+
end
|
140
|
+
|
141
|
+
def save_version_manifest versions_to_update
|
142
|
+
|
143
|
+
# cd to directory where versions/manifest is present
|
144
|
+
repo_folder = GithubApi.ProjectNameFromRepo @repo_url
|
145
|
+
Dir.chdir repo_folder
|
146
|
+
|
147
|
+
# update files
|
148
|
+
File.open(MANIFEST_FILE, 'w') do |f|
|
149
|
+
f.write @manifest.to_json
|
150
|
+
end
|
151
|
+
|
152
|
+
# merge updated versions with known version map
|
153
|
+
@version_map = @version_map.merge versions_to_update
|
154
|
+
File.open(VERSION_MAP_FILE, 'w') do |f|
|
155
|
+
f.write @version_map.to_json
|
156
|
+
end
|
157
|
+
|
158
|
+
# save branch
|
159
|
+
GithubApi.CommitAllLocalAndPush 'Updated manifest and version map'
|
127
160
|
|
128
161
|
end
|
129
162
|
|
@@ -135,15 +168,15 @@ class UpgradeAll
|
|
135
168
|
versions = vm.version_map version_repo_url, @manifest['version_source']['branch']
|
136
169
|
|
137
170
|
# If remote version doesn't exist, save it
|
138
|
-
if @
|
139
|
-
File.write
|
171
|
+
if @version_map.nil?
|
172
|
+
File.write VERSION_MAP_FILE, versions.to_json
|
140
173
|
GithubApi.PushBranch @repo_url, @branch
|
141
174
|
|
142
175
|
return hash
|
143
176
|
end
|
144
177
|
|
145
178
|
# compare current and remote versions, obtain changeset
|
146
|
-
hash = Hash[*(versions.to_a - @
|
179
|
+
hash = Hash[*(versions.to_a - @version_map.to_a).flatten]
|
147
180
|
|
148
181
|
# return changeset hash
|
149
182
|
hash
|
@@ -162,4 +195,16 @@ class UpgradeAll
|
|
162
195
|
"One or more validation errors have occurred: #{validation_errors.join(' ')}"
|
163
196
|
end
|
164
197
|
|
198
|
+
def waitfor
|
199
|
+
checks = 0
|
200
|
+
|
201
|
+
until checks > MAX_CHECKS
|
202
|
+
sleep 5
|
203
|
+
checks += 1
|
204
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Waiting for 5 seconds...'
|
205
|
+
end
|
206
|
+
|
207
|
+
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 > MAX_CHECKS
|
208
|
+
end
|
209
|
+
|
165
210
|
end
|
data/lib/version_map.rb
CHANGED
@@ -45,10 +45,7 @@ class VersionMap
|
|
45
45
|
doc = Nokogiri::XML File.read(file)
|
46
46
|
nodes = doc.xpath "//*[@id]"
|
47
47
|
nodes.each { |node|
|
48
|
-
|
49
|
-
if (!versions[node['id']].nil? && node['version'] != versions[node['id']])
|
50
|
-
puts "======Error: Package #{node['id']} with version #{node['version']} has a different pre-exisiting version: #{versions[node['id']]}"
|
51
|
-
end
|
48
|
+
puts "======Error: Package #{node['id']} with version #{node['version']} has a different pre-exisiting version: #{versions[node['id']]}" if (!versions[node['id']].nil? && node['version'] != versions[node['id']])
|
52
49
|
versions[node['id']] = node['version']
|
53
50
|
}
|
54
51
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: a2zdeploy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Suresh Batta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Automated Upgrades Gem. Provides version upgrades, build and deployment
|
14
14
|
configuration management
|
@@ -24,6 +24,8 @@ files:
|
|
24
24
|
- lib/hash_extensions.rb
|
25
25
|
- lib/input_validator.rb
|
26
26
|
- lib/proget_api.rb
|
27
|
+
- lib/rollback.rb
|
28
|
+
- lib/rollbackall.rb
|
27
29
|
- lib/teamcity_api.rb
|
28
30
|
- lib/upgrade.rb
|
29
31
|
- lib/upgradeall.rb
|