a2zdeploy 1.0.2 → 1.0.3
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 +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
|