a2zdeploy 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|