a2zdeploy 1.0.2 → 1.0.3
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 +7 -7
- data/lib/dependency_tree.rb +33 -14
- data/lib/github_api.rb +13 -10
- data/lib/global_constants.rb +22 -0
- data/lib/hash_extensions.rb +9 -0
- data/lib/input_validator.rb +159 -0
- data/lib/teamcity_api.rb +38 -52
- data/lib/upgrade.rb +117 -96
- data/lib/upgradeall.rb +96 -22
- data/lib/version_map.rb +11 -10
- metadata +5 -3
- data/lib/globalconstants.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ed53192adb1971f268124fc20fb11510ee31e06
|
4
|
+
data.tar.gz: b49b25d81f158ae3ad8420761aa5559fd6d2c2bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc2e1fdf5f6d4681709a6c9b6c3d34b4e137708acd381b4317ba168609379c5ad41a1379a0604060644924d73491503258aafe29ef487c56bf804088712550a1
|
7
|
+
data.tar.gz: f83acdd75516f2c3c373b8c5bb26c8cd74bb51a8f2ffdb903c84bb2a55de864d87c97a4a081fe8af86c373796f85634aa7ef6964f4884d5fb5fb90223cfa3adb
|
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 = '
|
3
|
+
s.version = '1.0.3'
|
4
|
+
s.date = '2016-01-19'
|
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['{lib}/**/*'] + ['a2zdeploy.gemspec', 'ReadMe.md']
|
9
|
+
s.files = Dir['{test,lib,rakefile.rb}/**/*'] + ['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
@@ -1,5 +1,5 @@
|
|
1
1
|
require_relative 'dependency_tree'
|
2
|
-
require_relative '
|
2
|
+
require_relative 'global_constants'
|
3
3
|
require_relative 'proget_api.rb'
|
4
4
|
require_relative 'teamcity_api.rb'
|
5
5
|
require_relative 'github_api.rb'
|
@@ -7,15 +7,15 @@ require_relative 'upgrade.rb'
|
|
7
7
|
require_relative 'upgradeall.rb'
|
8
8
|
require_relative 'github_api'
|
9
9
|
require_relative 'version_map'
|
10
|
+
require_relative 'hash_extensions'
|
11
|
+
require_relative 'input_validator'
|
10
12
|
|
11
13
|
require 'addressable/uri'
|
12
|
-
require '
|
14
|
+
require 'azdeploy'
|
15
|
+
require 'builder'
|
13
16
|
require 'fileutils'
|
17
|
+
require 'json'
|
14
18
|
require 'net/http'
|
15
|
-
|
16
19
|
require 'nokogiri'
|
17
|
-
require '
|
18
|
-
require 'builder'
|
19
|
-
require 'json'
|
20
|
-
require 'azdeploy'
|
20
|
+
require 'pathname'
|
21
21
|
require 'semver'
|
data/lib/dependency_tree.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
=begin
|
2
2
|
Defines a simple dependency tree in a has map and allows accessing top and GlobalConstants::NEXT item in the tree.
|
3
|
-
- The keys 'GlobalConstants::ROOT, GlobalConstants::NEXT, GlobalConstants::PREVIOUS and GlobalConstants::
|
3
|
+
- The keys 'GlobalConstants::ROOT, GlobalConstants::NEXT, GlobalConstants::PREVIOUS and GlobalConstants::PROJECTNAME_NAME' are self-descriptive and symbols
|
4
4
|
- GlobalConstants::ROOT's GlobalConstants::PREVIOUS is always nil, so are all leaf node GlobalConstants::NEXT
|
5
5
|
{
|
6
6
|
"GlobalConstants::ROOT" => {
|
7
|
-
"GlobalConstants::
|
7
|
+
"GlobalConstants::PROJECTNAME" => "Ontology",
|
8
8
|
"GlobalConstants::NEXT" => "FhirWalker",
|
9
9
|
"GlobalConstants::PREVIOUS" => nil,
|
10
10
|
"metadata" => "[json or another hash]"
|
11
11
|
},
|
12
12
|
"FhirWalker" => {
|
13
|
-
"GlobalConstants::
|
13
|
+
"GlobalConstants::PROJECTNAME" => "Portal",
|
14
14
|
"GlobalConstants::NEXT" => "EventTracking",
|
15
15
|
"GlobalConstants::PREVIOUS" => "Ontology",
|
16
16
|
"metadata" => "[json or another hash]"
|
@@ -26,40 +26,59 @@ class DependencyTree
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def root
|
29
|
-
return nil if
|
29
|
+
return nil if @dependency_map.nil? || @dependency_map.class.to_s != GlobalConstants::HASH || @dependency_map.empty?
|
30
30
|
|
31
31
|
if @dependency_map.has_key?(GlobalConstants::ROOT)
|
32
|
-
if @dependency_map[GlobalConstants::ROOT].has_key? GlobalConstants::
|
33
|
-
@dependency_map[GlobalConstants::ROOT]
|
32
|
+
if @dependency_map[GlobalConstants::ROOT].has_key? GlobalConstants::PROJECTNAME
|
33
|
+
root_node = Hashit.new @dependency_map[GlobalConstants::ROOT]
|
34
|
+
root_node
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
def next_node current
|
39
40
|
return nil if current.to_s.strip.length == 0
|
40
|
-
return nil if @dependency_map.nil? || @dependency_map.class.to_s != GlobalConstants::HASH
|
41
|
-
return nil if @dependency_map[current] == nil
|
41
|
+
return nil if @dependency_map.nil? || @dependency_map.class.to_s != GlobalConstants::HASH || @dependency_map.empty?
|
42
42
|
|
43
|
+
current = GlobalConstants::ROOT if @dependency_map[GlobalConstants::ROOT][GlobalConstants::PROJECTNAME] == current
|
43
44
|
if @dependency_map[current].has_key? GlobalConstants::NEXT
|
44
|
-
@dependency_map[current][GlobalConstants::NEXT]
|
45
|
+
next_node = @dependency_map[current][GlobalConstants::NEXT]
|
46
|
+
next_node = @dependency_map[next_node]
|
47
|
+
if !next_node.nil?
|
48
|
+
next_node = Hashit.new next_node
|
49
|
+
end
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
48
53
|
def previous_node current
|
49
54
|
return nil if current.to_s.strip.length == 0
|
50
|
-
return nil if
|
55
|
+
return nil if @dependency_map.nil? || @dependency_map.class.to_s != GlobalConstants::HASH || @dependency_map.empty?
|
51
56
|
|
52
57
|
if @dependency_map[current].has_key? GlobalConstants::PREVIOUS
|
53
|
-
@dependency_map[current][GlobalConstants::PREVIOUS]
|
58
|
+
prev_node = @dependency_map[current][GlobalConstants::PREVIOUS]
|
59
|
+
if @dependency_map[GlobalConstants::ROOT][GlobalConstants::PROJECTNAME] == prev_node
|
60
|
+
prev_node = @dependency_map[GlobalConstants::ROOT]
|
61
|
+
else
|
62
|
+
prev_node = @dependency_map[prev_node]
|
63
|
+
end
|
64
|
+
return nil if prev_node.nil?
|
65
|
+
return Hashit.new prev_node
|
54
66
|
end
|
55
67
|
end
|
56
68
|
|
57
69
|
def traverse
|
58
70
|
current = GlobalConstants::ROOT
|
59
|
-
|
71
|
+
current = @dependency_map[current]
|
72
|
+
current = Hashit.new current
|
73
|
+
yield current
|
60
74
|
while current != nil
|
61
|
-
|
62
|
-
|
75
|
+
begin
|
76
|
+
current = next_node current.project_name
|
77
|
+
rescue
|
78
|
+
#puts $!
|
79
|
+
current = nil
|
80
|
+
end
|
81
|
+
yield current if !current.nil?
|
63
82
|
end
|
64
83
|
end
|
65
84
|
|
data/lib/github_api.rb
CHANGED
@@ -59,18 +59,20 @@ module GithubApi
|
|
59
59
|
`git pull --rebase #{@repo_url} #{@branch}`
|
60
60
|
end
|
61
61
|
|
62
|
-
def GithubApi.CommitChanges comment, git_status
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
def GithubApi.CommitChanges comment, git_status = ''
|
63
|
+
if git_status != GlobalConstants::EMPTY
|
64
|
+
val = git_status.split("\n")
|
65
|
+
val.each { |x|
|
66
|
+
value = x.split(' M ').last || x.split('?? ').last
|
66
67
|
if (/.csproj/.match(value) || /packages.config/.match(value))
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
status = `git add #{value}`
|
69
|
+
if status != GlobalConstants::EMPTY
|
70
|
+
return false
|
71
|
+
end
|
71
72
|
end
|
72
|
-
|
73
|
-
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
74
76
|
status = `git commit -m "#{comment}"`
|
75
77
|
return status != GlobalConstants::EMPTY
|
76
78
|
end
|
@@ -114,6 +116,7 @@ module GithubApi
|
|
114
116
|
begin
|
115
117
|
uri = Addressable::URI.parse repo_url
|
116
118
|
rescue
|
119
|
+
puts $!
|
117
120
|
puts "repo_url: #{repo_url} parse failed"
|
118
121
|
return repo
|
119
122
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GlobalConstants
|
2
|
+
|
3
|
+
HASH = 'Hash'
|
4
|
+
|
5
|
+
SPEC = 'spec'
|
6
|
+
|
7
|
+
ROOT = 'root'
|
8
|
+
PREVIOUS = 'previous'
|
9
|
+
NEXT = 'next'
|
10
|
+
PROJECTNAME = 'project_name'
|
11
|
+
DPREPO = 'http://ndhaxpgit01.mckesson.com/Carnegie/RelayHealth.DataPlatform.git'
|
12
|
+
|
13
|
+
UNPROCESSED = 'unprocessed'
|
14
|
+
FAILED = 'failed'
|
15
|
+
SUCCESS = 'success'
|
16
|
+
UPGRADE_PROGRESS = '***Upgrade progress: '
|
17
|
+
|
18
|
+
EMPTY = ''
|
19
|
+
PARENTDIR = '..'
|
20
|
+
DOT = '.'
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Hashit
|
2
|
+
def initialize(hash)
|
3
|
+
hash.each do |k,v|
|
4
|
+
self.instance_variable_set("@#{k}", v.is_a?(Hash) ? Hashit.new(v) : v)
|
5
|
+
self.class.send(:define_method, k, proc{self.instance_variable_get("@#{k}")})
|
6
|
+
self.class.send(:define_method, "#{k}=", proc{|v| self.instance_variable_set("@#{k}", v)})
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
class InputValidator
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
@simple_validator = SimpleValidator.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_mode
|
8
|
+
@test_mode = true
|
9
|
+
end
|
10
|
+
|
11
|
+
# We should do more specific test of which environment variables are we expecting or which metatdata are we expecting
|
12
|
+
#if project publishes nuget we need to check if major /minor/patch incrmeented but not all 3
|
13
|
+
|
14
|
+
def validate_version_map version_map
|
15
|
+
if version_map.nil? || version_map.class.to_s != GlobalConstants::HASH
|
16
|
+
yield 'Version map must be a non-empty ' + GlobalConstants::HASH
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate_manifest m
|
21
|
+
|
22
|
+
manifest = Hashit.new m
|
23
|
+
puts 'Validating upgrade manifest...'
|
24
|
+
|
25
|
+
if manifest.nil? || manifest.class.to_s != 'Hashit'
|
26
|
+
yield 'Config map must be a non-nil class of type Hashit'
|
27
|
+
end
|
28
|
+
|
29
|
+
node_name = 'manifest'
|
30
|
+
yield @simple_validator.method_exists manifest, 'version_source', node_name
|
31
|
+
yield @simple_validator.method_value_not_nil manifest, 'version_source', node_name
|
32
|
+
yield @simple_validator.method_exists manifest.version_source, 'repo_url', node_name
|
33
|
+
yield @simple_validator.method_value_not_nil_or_empty manifest.version_source, 'repo_url', node_name
|
34
|
+
yield @simple_validator.method_exists manifest.version_source, 'branch', node_name
|
35
|
+
yield @simple_validator.method_value_not_nil_or_empty manifest.version_source, 'branch', node_name
|
36
|
+
yield @simple_validator.method_exists manifest, 'projects', node_name
|
37
|
+
yield @simple_validator.method_value_not_nil manifest, 'projects', node_name
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_project_node project
|
41
|
+
|
42
|
+
node_name = 'project'
|
43
|
+
|
44
|
+
yield @simple_validator.method_exists project, 'next', node_name
|
45
|
+
#yield @simple_validator.method_value_not_nil_or_empty project, 'next', node_name
|
46
|
+
|
47
|
+
yield @simple_validator.method_exists project, 'previous', node_name
|
48
|
+
#yield @simple_validator.method_value_not_nil_or_empty project, 'previous', node_name
|
49
|
+
|
50
|
+
node_name = 'project.metadata'
|
51
|
+
yield @simple_validator.method_exists project.metadata, 'repo_url', node_name
|
52
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'repo_url', node_name
|
53
|
+
|
54
|
+
yield @simple_validator.method_exists project.metadata, 'branch', node_name
|
55
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'branch', node_name
|
56
|
+
|
57
|
+
yield @simple_validator.method_exists project.metadata, 'should_upgrade', node_name
|
58
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'should_upgrade', node_name
|
59
|
+
|
60
|
+
yield @simple_validator.method_exists project.metadata, 'is_package_builder', node_name
|
61
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'is_package_builder', node_name
|
62
|
+
|
63
|
+
yield @simple_validator.method_exists project.metadata, 'should_publish_nuget', node_name
|
64
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'should_publish_nuget', node_name
|
65
|
+
|
66
|
+
yield @simple_validator.method_exists project.metadata, 'env_vars', node_name
|
67
|
+
yield @simple_validator.method_value_not_nil project.metadata, 'env_vars', node_name
|
68
|
+
|
69
|
+
yield @simple_validator.method_exists project.metadata, 'status', node_name
|
70
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata, 'status', node_name
|
71
|
+
|
72
|
+
yield @simple_validator.method_exists project.metadata, 'build_configuration_id', node_name
|
73
|
+
|
74
|
+
node_name = 'project.metadata.env_vars'
|
75
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'env', node_name
|
76
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'env', node_name
|
77
|
+
|
78
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'service_name', node_name
|
79
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'service_name', node_name
|
80
|
+
|
81
|
+
if !@test_mode
|
82
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'AI_InstrumentationKey', node_name
|
83
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'AI_InstrumentationKey', node_name
|
84
|
+
|
85
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'AppClientId', node_name
|
86
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'AppClientId', node_name
|
87
|
+
|
88
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'RuntimePath', node_name
|
89
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'RuntimePath', node_name
|
90
|
+
|
91
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'SettingsAccount', node_name
|
92
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'SettingsAccount', node_name
|
93
|
+
|
94
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'SettingsAccountKey', node_name
|
95
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'SettingsAccountKey', node_name
|
96
|
+
|
97
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'unitestconnectionString', node_name
|
98
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'unitestconnectionString', node_name
|
99
|
+
|
100
|
+
yield @simple_validator.method_exists project.metadata.env_vars, 'should_update_settings_connstr', node_name
|
101
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.env_vars, 'should_update_settings_connstr', node_name
|
102
|
+
end
|
103
|
+
|
104
|
+
node_name = 'project.metadata.semver'
|
105
|
+
yield @simple_validator.method_exists project.metadata, 'semver', node_name
|
106
|
+
yield @simple_validator.method_value_not_nil project.metadata, 'semver', node_name
|
107
|
+
yield @simple_validator.method_exists project.metadata.semver, 'file', node_name
|
108
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.semver, 'file', node_name
|
109
|
+
|
110
|
+
yield @simple_validator.method_exists project.metadata.semver, 'dimension', node_name
|
111
|
+
yield @simple_validator.method_value_not_nil_or_empty project.metadata.semver, 'dimension', node_name
|
112
|
+
|
113
|
+
yield @simple_validator.method_exists project.metadata.semver, 'location', node_name
|
114
|
+
#yield @simple_validator.method_value_not_nil_or_empty project.metadata.semver, 'location', node_name
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
# nil return is treated as no error
|
123
|
+
class SimpleValidator
|
124
|
+
|
125
|
+
CANNOT_CONTINUE = '. Cannot continue!'
|
126
|
+
IS_MISSING = ' is missing'
|
127
|
+
|
128
|
+
def method_exists object, method, name
|
129
|
+
begin
|
130
|
+
if !object.respond_to? method
|
131
|
+
"#{name}\'s method: *#{method}*" + IS_MISSING
|
132
|
+
end
|
133
|
+
rescue
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def method_value_not_nil_or_empty object, method, name
|
139
|
+
begin
|
140
|
+
value = object.send method
|
141
|
+
if value == nil || value.to_s.strip.length == 0
|
142
|
+
"#{name}\'s *#{method}* value is empty or" + IS_MISSING
|
143
|
+
end
|
144
|
+
rescue
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def method_value_not_nil object, method, name
|
150
|
+
begin
|
151
|
+
value = object.send method
|
152
|
+
if value == nil
|
153
|
+
"#{name}\'s *#{method}* value" + IS_MISSING
|
154
|
+
end
|
155
|
+
rescue
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/teamcity_api.rb
CHANGED
@@ -19,7 +19,6 @@ module TeamCityApi
|
|
19
19
|
http.request request
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
22
|
def TeamCityApi.create_build_trigger_config buildConfigurationId
|
24
23
|
xml = Builder::XmlMarkup.new :indent => 2
|
25
24
|
xml.build{
|
@@ -27,24 +26,24 @@ module TeamCityApi
|
|
27
26
|
xml.buildType "id" => "#{buildConfigurationId}"
|
28
27
|
}
|
29
28
|
end
|
30
|
-
|
29
|
+
|
31
30
|
#Project Get/Create API
|
32
31
|
def TeamCityApi.get_project_by_id projectId, username, password
|
33
32
|
uri = URI.parse "http://teamcity.relayhealth.com"
|
34
33
|
http = Net::HTTP.new uri.host, uri.port
|
35
34
|
request = Net::HTTP::Get.new "/app/rest/projects/id:#{projectId}", {'Accept' => 'application/json'}
|
36
35
|
request.basic_auth username, password
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
response = http.request request
|
37
|
+
# File handling will be removed and instead use Tempfile for better security
|
38
|
+
target = open("../spec/ProjectConfigByProjectId", 'w')
|
40
39
|
target.truncate(0)
|
41
40
|
target.write(response.body)
|
42
41
|
target.close
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
def TeamCityApi.create_new_project inputFile, username, password
|
46
45
|
file = File.open("../spec/#{inputFile}", "r")
|
47
|
-
requestContent = file.read
|
46
|
+
requestContent = file.read
|
48
47
|
uri = URI.parse "http://localhost:9999/"
|
49
48
|
http = Net::HTTP.new uri.host, uri.port
|
50
49
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/projects", {'Accept' => 'application/json'}
|
@@ -52,26 +51,26 @@ module TeamCityApi
|
|
52
51
|
request.content_type = 'application/json'
|
53
52
|
request.basic_auth username, password
|
54
53
|
response = http.request request
|
55
|
-
|
54
|
+
puts response.body
|
56
55
|
end
|
57
|
-
|
56
|
+
|
58
57
|
#VCS-Root Get/Create API
|
59
58
|
def TeamCityApi.get_vcs_roots_by_id vcsRootId, username, password
|
60
59
|
uri = URI.parse "http://teamcity.relayhealth.com"
|
61
60
|
http = Net::HTTP.new uri.host, uri.port
|
62
61
|
request = Net::HTTP::Get.new "/httpAuth/app/rest/vcs-roots/id:#{vcsRootId}", {'Accept' => 'application/json'}
|
63
62
|
request.basic_auth username, password
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
response = http.request request
|
64
|
+
# File handling will be removed and instead use Tempfile for better security
|
65
|
+
target = open("../spec/VcsRootConfigByVcsRootId", 'w')
|
67
66
|
target.truncate(0)
|
68
67
|
target.write(response.body)
|
69
68
|
target.close
|
70
69
|
end
|
71
|
-
|
70
|
+
|
72
71
|
def TeamCityApi.create_new_vcs_root inputFile, username, password
|
73
72
|
file = File.open("../spec/#{inputFile}", "r")
|
74
|
-
requestContent = file.read
|
73
|
+
requestContent = file.read
|
75
74
|
uri = URI.parse "http://localhost:9999/"
|
76
75
|
http = Net::HTTP.new uri.host, uri.port
|
77
76
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/vcs-roots", {'Accept' => 'application/json'}
|
@@ -79,43 +78,39 @@ module TeamCityApi
|
|
79
78
|
request.content_type = 'application/json'
|
80
79
|
request.basic_auth username, password
|
81
80
|
response = http.request request
|
82
|
-
|
81
|
+
puts response.body
|
83
82
|
end
|
84
|
-
|
83
|
+
|
85
84
|
#Build Config Get/Create API
|
86
|
-
def TeamCityApi.get_build_configs_by_projectId projectId, username, password
|
85
|
+
def TeamCityApi.get_build_configs_by_projectId projectId, username, password
|
87
86
|
uri = URI.parse "http://teamcity.relayhealth.com"
|
88
87
|
http = Net::HTTP.new uri.host, uri.port
|
89
88
|
request = Net::HTTP::Get.new "/app/rest/projects/id:#{projectId}/buildTypes", {'Accept' => 'application/json'}
|
90
89
|
request.basic_auth username, password
|
91
|
-
|
92
|
-
|
93
|
-
|
90
|
+
response = http.request request
|
91
|
+
# File handling will be removed and instead use Tempfile for better security
|
92
|
+
target = open("../spec/BuildConfigsByProjectId", 'w')
|
94
93
|
target.truncate(0)
|
95
94
|
target.write(response.body)
|
96
95
|
target.close
|
97
96
|
end
|
98
|
-
|
97
|
+
|
99
98
|
def TeamCityApi.get_build_configs_by_projectId_and_build_configurationId projectId, buildConfigurationId, username, password
|
100
99
|
uri = URI.parse "http://teamcity.relayhealth.com"
|
101
100
|
http = Net::HTTP.new uri.host, uri.port
|
102
101
|
request = Net::HTTP::Get.new "/app/rest/projects/id:#{projectId}/buildTypes/id:#{buildConfigurationId}", {'Accept' => 'application/json'}
|
103
102
|
request.basic_auth username, password
|
104
|
-
|
105
|
-
|
103
|
+
response = http.request request
|
104
|
+
# File handling will be removed and instead use Tempfile for better security
|
106
105
|
target = open("../spec/BuildConfigByProjectAndBuildConfigurationId", 'w')
|
107
106
|
target.truncate(0)
|
108
107
|
target.write(response.body)
|
109
108
|
target.close
|
110
109
|
end
|
111
110
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
111
|
def TeamCityApi.create_new_build_configuration projectId, inputFile, username, password
|
117
112
|
file = File.open("../spec/#{inputFile}", "r")
|
118
|
-
requestContent = file.read
|
113
|
+
requestContent = file.read
|
119
114
|
uri = URI.parse "http://localhost:9999/"
|
120
115
|
http = Net::HTTP.new uri.host, uri.port
|
121
116
|
|
@@ -125,13 +120,13 @@ module TeamCityApi
|
|
125
120
|
request.content_type = 'application/json'
|
126
121
|
request.basic_auth username, password
|
127
122
|
response = http.request request
|
128
|
-
|
123
|
+
# File handling will be removed and instead use Tempfile for better security
|
129
124
|
target = open("../spec/CreateNewBuildConfigurationResponse", 'w')
|
130
125
|
target.truncate(0)
|
131
126
|
target.write(response.body)
|
132
127
|
target.close
|
133
128
|
end
|
134
|
-
|
129
|
+
|
135
130
|
# Setup build configuration settings
|
136
131
|
def TeamCityApi.set_build_configuration_setting buildConfigurationId, settingName, settingValue, username, password
|
137
132
|
uri = URI.parse "http://localhost:9999/"
|
@@ -142,7 +137,7 @@ module TeamCityApi
|
|
142
137
|
request.basic_auth username, password
|
143
138
|
response = http.request request
|
144
139
|
end
|
145
|
-
|
140
|
+
|
146
141
|
# Setup build configuration parameters
|
147
142
|
def TeamCityApi.set_build_configuration_parameter buildConfigurationId, parameterName, parameterValue, username, password
|
148
143
|
uri = URI.parse "http://localhost:9999/"
|
@@ -153,74 +148,65 @@ module TeamCityApi
|
|
153
148
|
request.basic_auth username, password
|
154
149
|
response = http.request request
|
155
150
|
end
|
156
|
-
|
151
|
+
|
157
152
|
# Setup build configuration Vcs-Root
|
158
153
|
def TeamCityApi.set_build_configuration_vcs_root buildConfigurationId, vcsRootId, username, password
|
159
|
-
|
154
|
+
uri = URI.parse "http://localhost:9999/"
|
160
155
|
http = Net::HTTP.new uri.host, uri.port
|
161
156
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/buildTypes/id:#{buildConfigurationId}/vcs-root-entries/"
|
162
|
-
|
157
|
+
request.body = create_build_config_vcs_root_config vcsRootId
|
163
158
|
request.content_type = 'application/xml'
|
164
159
|
request.basic_auth username, password
|
165
160
|
|
166
161
|
response = http.request request
|
167
162
|
end
|
168
163
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
164
|
def TeamCityApi.create_build_config_vcs_root_config vcsRootId
|
173
165
|
xml = Builder::XmlMarkup.new :indent => 2
|
174
|
-
|
175
|
-
|
176
|
-
|
177
166
|
xml.tag!("vcs-root-entry"){
|
178
167
|
xml.tag!("vcs-root", "id" => "#{vcsRootId}")
|
179
168
|
}
|
180
169
|
end
|
181
|
-
|
182
|
-
|
183
170
|
|
184
171
|
# Setup build configuration step
|
185
172
|
def TeamCityApi.set_build_configuration_build_step buildConfigurationId, inputFile, username, password
|
186
173
|
file = File.open("../spec/#{inputFile}", "r")
|
187
|
-
requestContent = file.read
|
174
|
+
requestContent = file.read
|
188
175
|
uri = URI.parse "http://localhost:9999/"
|
189
176
|
http = Net::HTTP.new uri.host, uri.port
|
190
177
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/buildTypes/id:#{buildConfigurationId}/steps/"
|
191
|
-
|
178
|
+
request.body = requestContent
|
192
179
|
request.content_type = 'application/xml'
|
193
180
|
request.basic_auth username, password
|
194
181
|
response = http.request request
|
195
182
|
end
|
196
|
-
|
197
183
|
|
198
184
|
# Setup build feature step
|
199
185
|
def TeamCityApi.set_build_configuration_feature buildConfigurationId, inputFile, username, password
|
200
186
|
file = File.open("../spec/#{inputFile}", "r")
|
201
|
-
requestContent = file.read
|
187
|
+
requestContent = file.read
|
202
188
|
uri = URI.parse "http://localhost:9999/"
|
203
189
|
http = Net::HTTP.new uri.host, uri.port
|
204
190
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/buildTypes/id:#{buildConfigurationId}/features/"
|
205
|
-
|
191
|
+
request.body = requestContent
|
206
192
|
request.content_type = 'application/xml'
|
207
193
|
request.basic_auth username, password
|
208
194
|
response = http.request request
|
209
195
|
end
|
210
|
-
|
196
|
+
|
211
197
|
# Setup build trigger step
|
212
198
|
def TeamCityApi.set_build_configuration_trigger buildConfigurationId, inputFile, username, password
|
213
199
|
file = File.open("../spec/#{inputFile}", "r")
|
214
|
-
requestContent = file.read
|
200
|
+
requestContent = file.read
|
215
201
|
uri = URI.parse "http://localhost:9999/"
|
216
202
|
http = Net::HTTP.new uri.host, uri.port
|
217
203
|
request = Net::HTTP::Post.new "/httpAuth/app/rest/buildTypes/id:#{buildConfigurationId}/triggers/"
|
218
|
-
|
204
|
+
request.body = requestContent
|
219
205
|
request.content_type = 'application/xml'
|
220
206
|
request.basic_auth username, password
|
221
207
|
response = http.request request
|
222
208
|
end
|
223
|
-
|
209
|
+
|
224
210
|
end
|
225
211
|
|
226
212
|
|
@@ -242,4 +228,4 @@ end
|
|
242
228
|
#TeamCityApi.set_build_configuration_build_step "DataPlatform_DataPlatformOntology_DevelopBuild", "RakeBuildStep", "username", "password"
|
243
229
|
#TeamCityApi.set_build_configuration_feature "DataPlatform_DataPlatformOntology_DevelopBuild", "BuildConfigurationFeature", "username", "password"
|
244
230
|
#TeamCityApi.set_build_configuration_feature "DataPlatform_DataPlatformOntology_DevelopBuild", "BuildConfigurationFeatureForFailureCondition", "username", "password"
|
245
|
-
#TeamCityApi.set_build_configuration_trigger "DataPlatform_DataPlatformOntology_DevelopBuild", "SetupTriggerForBuildStep", "username", "password"
|
231
|
+
#TeamCityApi.set_build_configuration_trigger "DataPlatform_DataPlatformOntology_DevelopBuild", "SetupTriggerForBuildStep", "username", "password"
|
data/lib/upgrade.rb
CHANGED
@@ -1,68 +1,20 @@
|
|
1
1
|
=begin
|
2
2
|
|
3
|
-
Processes upgrade for a
|
4
|
-
|
5
|
-
Inputs:
|
6
|
-
1. Project Manifest that describes repo/project to be processed
|
7
|
-
a. repo name, repo url, branch name
|
8
|
-
b.
|
9
|
-
2. Change Manifest that describes what references have been upgraded due to framework upgrade.
|
10
|
-
Can be as simple as dictionary<string, string> of 'Package:[new version]'
|
11
|
-
example: When TestService is upgraded, we'll know what references have changed.
|
12
|
-
These can be used to replace packages.config and project references
|
13
|
-
=end
|
14
|
-
|
15
|
-
require 'nokogiri'
|
16
|
-
require 'json'
|
17
|
-
require 'azdeploy'
|
3
|
+
Processes upgrade for a C# code repositoryy
|
18
4
|
|
19
|
-
|
20
|
-
require_relative 'globalconstants'
|
5
|
+
=end
|
21
6
|
|
22
7
|
class UpgradePackages
|
23
8
|
|
24
9
|
UPGRADE_BRANCH = 'upgrade'
|
25
10
|
|
26
|
-
|
27
|
-
def initialize repo_url, branch, versions, config_map
|
28
|
-
@repo_url = repo_url
|
29
|
-
@branch = branch
|
11
|
+
def initialize versions
|
30
12
|
@versions = versions
|
31
|
-
@config_map = config_map
|
32
|
-
end
|
33
|
-
|
34
|
-
def validate_inputs
|
35
|
-
return false if @repo_url.to_s.strip.length == 0
|
36
|
-
return false if @branch.to_s.strip.length == 0
|
37
|
-
if (@versions.nil? || @versions.class.to_s != GlobalConstants::HASH)
|
38
|
-
puts 'Version map must be a ' + GlobalConstants::HASH
|
39
|
-
return false
|
40
|
-
end
|
41
|
-
if (@config_map.nil? || @config_map.class.to_s != GlobalConstants::HASH)
|
42
|
-
puts 'Config map must be a ' + GlobalConstants::HASH
|
43
|
-
return false
|
44
|
-
end
|
45
|
-
|
46
|
-
# fail if env vars were not supplied
|
47
|
-
if (!@config_map.has_key? 'env_vars')
|
48
|
-
puts 'Environment variables not supplied. Cannot continue!'
|
49
|
-
return false
|
50
|
-
end
|
51
|
-
|
52
|
-
# fail if metadata was not supplied
|
53
|
-
if (!@config_map.has_key? 'metadata')
|
54
|
-
puts 'Metadata variables not supplied. Cannot continue!'
|
55
|
-
return false
|
56
|
-
end
|
57
|
-
|
58
|
-
# We should do more specific test of which environment variables are we expecting or which metatdata are we expecting
|
59
|
-
#if project publishes nuget we need to check if major /minor/patch incrmeented but not all 3
|
60
|
-
return true
|
61
13
|
end
|
62
14
|
|
63
15
|
def checkout_upgrade_branch
|
16
|
+
|
64
17
|
# obtain an upgrade branch
|
65
|
-
puts 'Getting upgrade branch...'
|
66
18
|
if (GithubApi.DoesBranchExist('origin', UPGRADE_BRANCH) != GlobalConstants::EMPTY)
|
67
19
|
puts 'Checking out existing upgrade branch...'
|
68
20
|
return false if !GithubApi.CheckoutExistingBranch(UPGRADE_BRANCH) == GlobalConstants::EMPTY
|
@@ -74,54 +26,99 @@ class UpgradePackages
|
|
74
26
|
return true
|
75
27
|
end
|
76
28
|
|
77
|
-
def Do
|
78
|
-
|
29
|
+
def Do config_map, nuget_targets, is_local_run=false
|
30
|
+
|
31
|
+
@config_map = config_map
|
32
|
+
@repo_url = @config_map.metadata.repo_url
|
33
|
+
@branch = @config_map.metadata.branch
|
79
34
|
|
80
35
|
# checkout repo and branch
|
81
36
|
return false if !GithubApi.CheckoutRepoAfresh @repo_url, @branch
|
82
37
|
|
38
|
+
# make upgrade branch
|
83
39
|
return false if !checkout_upgrade_branch
|
84
40
|
|
41
|
+
# use local nuget path for restore if provided
|
42
|
+
set_local_nuget_target nuget_targets if is_local_run
|
43
|
+
|
85
44
|
# replace versions in package config files
|
45
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Replacing package versions...'
|
86
46
|
pkg_files = Dir.glob '**/packages.config'
|
87
|
-
if
|
88
|
-
puts
|
47
|
+
if !replace_package_versions(pkg_files)
|
48
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Package version replacement failed.'
|
89
49
|
return false
|
90
50
|
end
|
91
51
|
|
92
52
|
# replace versions in project references
|
53
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Replacing project versions...'
|
93
54
|
proj_files = Dir.glob '**/*.csproj'
|
94
|
-
if
|
95
|
-
puts
|
55
|
+
if !replace_project_versions(proj_files)
|
56
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Project version replacement failed.'
|
96
57
|
return false
|
97
58
|
end
|
98
59
|
|
99
60
|
# Check in manifest if project publish nuget? If yes, increment .semver
|
100
61
|
# QUESTION: Should this method increment semver even if there is no nuget published?
|
101
|
-
|
62
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Upgrading semver...'
|
63
|
+
semver_inc_done = increment_semver_if_publish is_local_run
|
64
|
+
if @config_map.metadata.should_publish_nuget.downcase == 'y'
|
65
|
+
nuget_targets << Dir.pwd + '/build_artifacts'
|
66
|
+
end
|
102
67
|
|
103
68
|
# do rake build to test for compilation errors. This needs ENV vars set, passed in via config
|
104
|
-
set_project_env_vars @config_map
|
69
|
+
set_project_env_vars @config_map.metadata.env_vars
|
105
70
|
output = system 'rake'
|
106
|
-
|
107
|
-
commit_msg = 'Versions updated'
|
108
71
|
if output.to_s == 'false'
|
109
|
-
|
110
|
-
|
111
|
-
|
72
|
+
puts GlobalConstants::UPGRADE_PROGRESS + ' Rake Error: There were errors during rake run.'
|
73
|
+
# save state
|
74
|
+
GithubApi.CommitChanges( 'Versions updated, build failed')
|
75
|
+
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
|
79
|
+
# update version map with nuget versions after build success
|
80
|
+
if semver_inc_done
|
81
|
+
update_version_map
|
82
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Semver upgraded. Version map updated.'
|
112
83
|
end
|
113
84
|
|
85
|
+
if is_local_run
|
86
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Local run. No branch update or teamcity build triggered'
|
87
|
+
else
|
88
|
+
return false if !update_branch
|
89
|
+
# kick off teamcity build
|
90
|
+
TeamCityApi.trigger_build @config_map.build_configuration_id, @config_map.tc_un, @config_map.tc_pwd
|
91
|
+
end
|
92
|
+
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_local_nuget_target nuget_targets
|
97
|
+
num_paths = 1;
|
98
|
+
nuget_targets.each { |target|
|
99
|
+
nuget_targets_file = Dir.pwd + '/src/.nuget/Nuget.Config'
|
100
|
+
doc = Nokogiri::XML(File.read nuget_targets_file)
|
101
|
+
node_parent = doc.at_css 'packageSources'
|
102
|
+
node = Nokogiri::XML::Node.new('add', doc)
|
103
|
+
node['key'] = "local_nuget_source#{num_paths}"
|
104
|
+
node['value'] = target
|
105
|
+
node_parent.add_child node
|
106
|
+
File.write nuget_targets_file, doc.to_xml
|
107
|
+
num_paths += 1
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
def update_branch
|
112
|
+
|
114
113
|
# see if any files changed and commit
|
115
114
|
git_status = GithubApi.HaveLocalChanges
|
116
|
-
if
|
117
|
-
|
118
|
-
|
119
|
-
else
|
120
|
-
puts 'No local changes exist. Nothing to commit'
|
115
|
+
if git_status != nil || git_status != GlobalConstants::EMPTY
|
116
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Local version changes have been committed'
|
117
|
+
return false if !GithubApi.CommitChanges( 'Versions updated')
|
121
118
|
end
|
122
119
|
|
123
120
|
# rebase and push the branch
|
124
|
-
puts 'Rebasing and pushing...'
|
121
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Rebasing and pushing update branch...'
|
125
122
|
GithubApi.CheckoutLocal @branch
|
126
123
|
GithubApi.RebaseLocal UPGRADE_BRANCH
|
127
124
|
|
@@ -130,11 +127,11 @@ class UpgradePackages
|
|
130
127
|
# Build failure email will inform concerned team
|
131
128
|
git_status = GithubApi.PushBranch(@repo_url, @branch) == GlobalConstants::EMPTY
|
132
129
|
if git_status
|
133
|
-
puts "Version upgrade changes have been rebased with #{@repo_url}/#{@branch} and pushed"
|
130
|
+
puts GlobalConstants::UPGRADE_PROGRESS + "Version upgrade changes have been rebased with #{@repo_url}/#{@branch} and pushed"
|
134
131
|
else
|
135
132
|
GithubApi.PullWithRebase @repo_url, @branch
|
136
133
|
GithubApi.PushBranch @repo_url, @branch
|
137
|
-
puts "Push after version upgrade failed for #{@repo_url}/#{@branch}. Pull with rebase done and pushed"
|
134
|
+
puts GlobalConstants::UPGRADE_PROGRESS + "Push after version upgrade failed for #{@repo_url}/#{@branch}. Pull with rebase done and pushed"
|
138
135
|
return false
|
139
136
|
end
|
140
137
|
|
@@ -142,12 +139,11 @@ class UpgradePackages
|
|
142
139
|
GithubApi.DeleteLocalBranch UPGRADE_BRANCH
|
143
140
|
GithubApi.DeleteRemoteBranch @repo_url, UPGRADE_BRANCH
|
144
141
|
|
145
|
-
# handle configuration changes. The settings file, update hash or TeamCity Params list is passed in through Ctor
|
146
|
-
|
147
142
|
true
|
148
143
|
end
|
149
144
|
|
150
145
|
def replace_package_versions pkg_files
|
146
|
+
|
151
147
|
begin
|
152
148
|
# iterate each package file, replace version numbers and save
|
153
149
|
pkg_files.each{ |file|
|
@@ -155,19 +151,17 @@ class UpgradePackages
|
|
155
151
|
doc = Nokogiri::XML File.read(file)
|
156
152
|
nodes = doc.xpath "//*[@id]"
|
157
153
|
nodes.each { |node|
|
158
|
-
if (@versions.has_key?(node['id']))
|
159
|
-
node['version'] = @versions[node['id']]
|
160
|
-
#puts "#{node['id']} #{node['version']} -- #{@versions[node['id']]}"
|
161
|
-
end
|
154
|
+
node['version'] = @versions[node['id']] if (@versions.has_key?(node['id']))
|
162
155
|
}
|
163
|
-
|
164
156
|
File.write file, doc.to_xml
|
165
157
|
}
|
166
158
|
rescue
|
167
159
|
puts $!
|
168
160
|
return false
|
169
161
|
end
|
162
|
+
|
170
163
|
return true
|
164
|
+
|
171
165
|
end
|
172
166
|
|
173
167
|
=begin
|
@@ -184,6 +178,7 @@ class UpgradePackages
|
|
184
178
|
</Reference>
|
185
179
|
=end
|
186
180
|
def replace_project_versions proj_files
|
181
|
+
|
187
182
|
begin
|
188
183
|
# iterate each package file, replace version numbers and save
|
189
184
|
proj_files.each{ |file|
|
@@ -206,7 +201,7 @@ class UpgradePackages
|
|
206
201
|
hint_path_id = id_from_hint_path hint_path_value
|
207
202
|
if @versions.has_key? hint_path_id
|
208
203
|
hint_path_parts = hint_path_value.split '\\'
|
209
|
-
hint_path_parts[2] = hint_path_id +
|
204
|
+
hint_path_parts[2] = hint_path_id + GlobalConstants::DOT + @versions[hint_path_id]
|
210
205
|
hint_path[0].children = hint_path_parts.join '\\'
|
211
206
|
end
|
212
207
|
end
|
@@ -217,42 +212,68 @@ class UpgradePackages
|
|
217
212
|
puts $!
|
218
213
|
return false
|
219
214
|
end
|
215
|
+
|
220
216
|
return true
|
217
|
+
|
221
218
|
end
|
222
219
|
|
223
220
|
def id_from_hint_path path
|
224
|
-
name = path.split('\\')[2].split
|
221
|
+
name = path.split('\\')[2].split GlobalConstants::DOT
|
225
222
|
name_without_ver = GlobalConstants::EMPTY
|
226
223
|
name.all? {|i|
|
227
224
|
if i.to_i == 0
|
228
|
-
name_without_ver += i.to_s +
|
225
|
+
name_without_ver += i.to_s + GlobalConstants::DOT
|
229
226
|
end
|
230
227
|
}
|
231
|
-
name_without_ver.chomp
|
228
|
+
name_without_ver.chomp GlobalConstants::DOT
|
232
229
|
end
|
233
230
|
|
234
231
|
def set_project_env_vars envs
|
235
|
-
envs.
|
236
|
-
|
237
|
-
|
232
|
+
ENV['AI_InstrumentationKey'] = envs.AI_InstrumentationKey if envs.respond_to? 'AI_InstrumentationKey'
|
233
|
+
ENV['AppClientId'] = envs.AppClientId if envs.respond_to? 'AppClientId'
|
234
|
+
ENV['ConfigSettingsTable'] = envs.ConfigSettingsTable if envs.respond_to? 'ConfigSettingsTable'
|
235
|
+
ENV['env'] = envs.env if envs.respond_to? 'env'
|
236
|
+
ENV['RuntimePath'] = envs.RuntimePath if envs.respond_to? 'RuntimePath'
|
237
|
+
ENV['ServiceName'] = envs.ServiceName if envs.respond_to? 'ServiceName'
|
238
|
+
ENV['SettingsAccount'] = envs.SettingsAccount if envs.respond_to? 'SettingsAccount'
|
239
|
+
ENV['SettingsAccountKey'] = envs.SettingsAccountKey if envs.respond_to? 'SettingsAccountKey'
|
240
|
+
ENV['should_update_settings_connstr'] = envs.should_update_settings_connstr if envs.respond_to? 'should_update_settings_connstr'
|
241
|
+
ENV['unitestconnectionString'] = envs.unitestconnectionString if envs.respond_to? 'unitestconnectionString'
|
238
242
|
end
|
239
243
|
|
240
|
-
def increment_semver_if_publish
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
+
def increment_semver_if_publish is_local_run
|
245
|
+
|
246
|
+
if is_local_run
|
247
|
+
auto_update_semver @config_map.project_name, @config_map.metadata.semver.location, @config_map.metadata.semver.file, @config_map.metadata.semver.dimension
|
248
|
+
return true
|
244
249
|
else
|
245
|
-
should_publish_nuget = @config_map
|
250
|
+
should_publish_nuget = @config_map.metadata.should_publish_nuget.downcase
|
246
251
|
if should_publish_nuget.eql? 'y'
|
247
|
-
semver_file = @config_map
|
252
|
+
semver_file = @config_map.metadata.semver.file
|
248
253
|
if (semver_file != nil && semver_file != GlobalConstants::EMPTY)
|
249
254
|
semver_file.capitalize
|
250
255
|
end
|
251
|
-
|
252
|
-
|
256
|
+
auto_update_semver @config_map.project_name, @config_map.metadata.semver.location, semver_file, @config_map.metadata.semver.dimension
|
257
|
+
return true
|
253
258
|
else
|
254
|
-
puts '
|
259
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Project does not publish nuget.'
|
255
260
|
end
|
256
261
|
end
|
262
|
+
|
263
|
+
false
|
264
|
+
end
|
265
|
+
|
266
|
+
def update_version_map
|
267
|
+
path = File.join(Dir.pwd, '/build_artifacts/*.nupkg')
|
268
|
+
nugets = Dir.glob path
|
269
|
+
nugets.each { |nuget|
|
270
|
+
full_name = File.basename nuget
|
271
|
+
full_name = full_name.sub! '.nupkg', ''
|
272
|
+
full_name = full_name.sub! '.symbols', '' if full_name.include? '.symbols'
|
273
|
+
dot_pos = full_name.index GlobalConstants::DOT
|
274
|
+
nuget_name = full_name[0..dot_pos-1]
|
275
|
+
nuget_version = full_name[dot_pos+1..full_name.length]
|
276
|
+
@versions[nuget_name] = nuget_version
|
277
|
+
}
|
257
278
|
end
|
258
279
|
end
|
data/lib/upgradeall.rb
CHANGED
@@ -12,11 +12,21 @@ class UpgradeAll
|
|
12
12
|
MANIFEST_FILE = 'manifest.json'
|
13
13
|
|
14
14
|
# repo_url is where the last known version map and manifest are checked-in
|
15
|
-
def initialize repo_url, branch
|
15
|
+
def initialize repo_url, branch, manifest_path = MANIFEST_FILE
|
16
16
|
|
17
17
|
@repo_url = repo_url
|
18
18
|
@branch = branch
|
19
|
+
@manifest_path = manifest_path
|
19
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
|
20
30
|
end
|
21
31
|
|
22
32
|
def retrieve_artifacts
|
@@ -24,44 +34,99 @@ class UpgradeAll
|
|
24
34
|
return if !GithubApi.CheckoutRepoAfresh @repo_url, @branch
|
25
35
|
|
26
36
|
# JSON files converted to hash
|
27
|
-
if File.exist? VERSION_MAP_FILE
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
if File.exist? MANIFEST_FILE
|
32
|
-
@manifest = JSON.parse File.read(MANIFEST_FILE)
|
33
|
-
end
|
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
|
34
39
|
|
40
|
+
Dir.chdir GlobalConstants::PARENTDIR
|
35
41
|
end
|
36
42
|
|
37
|
-
def Do
|
43
|
+
def Do input_validator, is_local_run=false
|
44
|
+
|
45
|
+
puts "\n"
|
46
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Upgrade All has begun..'
|
38
47
|
|
39
48
|
# retrieve version map and upgrade manifest
|
49
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Retrieving artifacts...'
|
40
50
|
retrieve_artifacts
|
41
51
|
|
42
52
|
return false if @remote_version_map.nil? || @manifest.nil?
|
43
53
|
|
44
54
|
#find version diff. If no changes exist, kick off deploy cycle only
|
45
|
-
puts 'Calculating version diff...'
|
55
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Calculating version diff...'
|
46
56
|
versions_to_update = version_diff
|
47
57
|
|
58
|
+
# nothing to update
|
59
|
+
if versions_to_update.nil? || versions_to_update.length == 0
|
60
|
+
puts 'No version diff, nothing to upgrade!'
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
|
64
|
+
# validate manifest
|
65
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Validating manifest...'
|
66
|
+
validation_errors = []
|
67
|
+
input_validator.validate_manifest(@manifest) do |error|
|
68
|
+
validation_errors << error if !error.nil?
|
69
|
+
end
|
70
|
+
raise StandardError, validation_error_message(validation_errors) if validation_errors.length > 0
|
71
|
+
|
72
|
+
nuget_targets = []
|
73
|
+
upgrader = UpgradePackages.new versions_to_update
|
74
|
+
|
48
75
|
# if changes exist, cycle through dependency tree and kick off upgrades
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
puts "
|
76
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Navigating projects...'
|
77
|
+
dep_tree = DependencyTree.new(@manifest['projects'])
|
78
|
+
dep_tree.traverse do |node|
|
79
|
+
|
80
|
+
if node.metadata.should_upgrade.downcase == 'y'
|
81
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Processing project #{node.project_name}..."
|
82
|
+
|
83
|
+
# validate project node
|
84
|
+
puts GlobalConstants::UPGRADE_PROGRESS + 'Validating project node...'
|
85
|
+
input_validator.validate_project_node(node) do |error|
|
86
|
+
validation_errors << error if !error.nil?
|
87
|
+
end
|
88
|
+
raise StandardError, validation_error_message(validation_errors) if validation_errors.length > 0
|
89
|
+
|
90
|
+
# the upgrade
|
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
|
113
|
+
|
114
|
+
else
|
115
|
+
puts "#{GlobalConstants::UPGRADE_PROGRESS} Skipping upgrade for project #{node.project_name}..."
|
55
116
|
end
|
56
|
-
|
117
|
+
end
|
57
118
|
|
58
|
-
#
|
119
|
+
# upgrade completed successfully, update status as unprocessed and save version map and manifest, push
|
120
|
+
reset_status_unprocessed
|
59
121
|
|
60
|
-
# save the version map and manifest
|
61
122
|
|
62
123
|
true
|
63
124
|
end
|
64
125
|
|
126
|
+
def save version_manifest
|
127
|
+
|
128
|
+
end
|
129
|
+
|
65
130
|
def version_diff
|
66
131
|
|
67
132
|
# create version map afresh to compare
|
@@ -77,15 +142,24 @@ class UpgradeAll
|
|
77
142
|
return hash
|
78
143
|
end
|
79
144
|
|
80
|
-
#p @remote_version_map
|
81
|
-
#p versions
|
82
|
-
|
83
145
|
# compare current and remote versions, obtain changeset
|
84
146
|
hash = Hash[*(versions.to_a - @remote_version_map.to_a).flatten]
|
85
147
|
|
86
148
|
# return changeset hash
|
87
149
|
hash
|
150
|
+
end
|
151
|
+
|
152
|
+
def reset_status_unprocessed
|
153
|
+
@manifest['projects'].each { |proj|
|
154
|
+
proj.each { |item|
|
155
|
+
item['metadata']['status'] = GlobalConstants::UNPROCESSED if item.class.to_s != 'String'
|
156
|
+
}
|
157
|
+
}
|
158
|
+
@manifest
|
159
|
+
end
|
88
160
|
|
161
|
+
def validation_error_message validation_errors
|
162
|
+
"One or more validation errors have occurred: #{validation_errors.join(' ')}"
|
89
163
|
end
|
90
164
|
|
91
165
|
end
|
data/lib/version_map.rb
CHANGED
@@ -33,7 +33,7 @@ class VersionMap
|
|
33
33
|
|
34
34
|
# load old versions
|
35
35
|
old_versions = {}
|
36
|
-
if
|
36
|
+
if File.exists? VERSIONMAPFILE
|
37
37
|
old_versions = JSON.parse File.read(VERSIONMAPFILE)
|
38
38
|
end
|
39
39
|
|
@@ -41,24 +41,25 @@ class VersionMap
|
|
41
41
|
versions = {}
|
42
42
|
pkg_files = Dir.glob '**/packages.config'
|
43
43
|
pkg_files.each{ |file|
|
44
|
-
puts "Finding packages in: #{file}"
|
44
|
+
#puts "Finding packages in: #{file}"
|
45
45
|
doc = Nokogiri::XML File.read(file)
|
46
46
|
nodes = doc.xpath "//*[@id]"
|
47
47
|
nodes.each { |node|
|
48
|
-
|
48
|
+
|
49
|
+
if (!versions[node['id']].nil? && node['version'] != versions[node['id']])
|
49
50
|
puts "======Error: Package #{node['id']} with version #{node['version']} has a different pre-exisiting version: #{versions[node['id']]}"
|
50
51
|
end
|
51
52
|
versions[node['id']] = node['version']
|
52
53
|
}
|
53
54
|
}
|
54
|
-
|
55
|
+
|
55
56
|
if Dir.exist?('versioning')
|
56
|
-
|
57
|
-
else
|
58
|
-
|
59
|
-
end
|
57
|
+
update_platform_multiple_semver_package_versions versions
|
58
|
+
else
|
59
|
+
update_platform_single_semver_package_versions versions
|
60
|
+
end
|
60
61
|
|
61
|
-
Dir.chdir
|
62
|
+
Dir.chdir GlobalConstants::PARENTDIR
|
62
63
|
File.write VERSIONMAPFILE, versions.to_json
|
63
64
|
|
64
65
|
versions
|
@@ -81,7 +82,7 @@ class VersionMap
|
|
81
82
|
|
82
83
|
versions
|
83
84
|
end
|
84
|
-
|
85
|
+
|
85
86
|
def update_platform_multiple_semver_package_versions versions
|
86
87
|
versions['RelayHealth.DataPlatform.Contracts'] = get_semver 'Contracts.semver'
|
87
88
|
versions['RelayHealth.DataPlatform.Framework'] = get_semver 'Framework.semver'
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Suresh Batta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Automated Upgrades Gem. Provides version upgrades, build and deployment
|
14
14
|
configuration management
|
@@ -20,7 +20,9 @@ files:
|
|
20
20
|
- lib/a2zdeploy.rb
|
21
21
|
- lib/dependency_tree.rb
|
22
22
|
- lib/github_api.rb
|
23
|
-
- lib/
|
23
|
+
- lib/global_constants.rb
|
24
|
+
- lib/hash_extensions.rb
|
25
|
+
- lib/input_validator.rb
|
24
26
|
- lib/proget_api.rb
|
25
27
|
- lib/teamcity_api.rb
|
26
28
|
- lib/upgrade.rb
|