Class: Upgrade
- Inherits:
-
Object
- Object
- Upgrade
- Defined in:
- lib/upgrade.rb
Overview
Processes upgrade for a C# code repositoryy
Constant Summary collapse
- UPGRADE_BRANCH =
'upgrade'
- BACKUP_BRANCH =
'upgradeBackupDoNotDelete'
- VERSION_UPGRADE_COMMIT =
'Versions updated'
- VERSION_UPGRADE_FAIL_BUILD_COMMIT =
'Versions updated, build failed'
Instance Method Summary collapse
- #checkout_upgrade_branch ⇒ Object
- #clear_project_env_vars ⇒ Object
- #create_upgrade_tag ⇒ Object
- #Do(config_map, nuget_targets, is_local_run = false) ⇒ Object
- #id_from_hint_path(path) ⇒ Object
- #increment_semver_if_publish(is_local_run) ⇒ Object
-
#initialize(versions, rollback = false) ⇒ Upgrade
constructor
A new instance of Upgrade.
- #replace_package_versions(pkg_files) ⇒ Object
-
#replace_project_versions(proj_files) ⇒ Object
Typical block of reference node change looks like: Before: <Reference Include=“MassTransit, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b8e0e9f2f1e657fa, processorArchitecture=MSIL”> <HintPath>..packagesMassTransit.3.0.14libnet45MassTransit.dll</HintPath> <Private>True</Private> </Reference> After: (file version removed, hint path version number updated) <Reference Include=“MassTransit”> <HintPath>..packagesMassTransit.3.0.15libnet45MassTransit.dll</HintPath> <Private>True</Private> </Reference>.
- #set_local_nuget_target(nuget_targets) ⇒ Object
- #set_project_env_vars(envs) ⇒ Object
- #update_branch ⇒ Object
- #update_version_map(path) ⇒ Object
Constructor Details
#initialize(versions, rollback = false) ⇒ Upgrade
Returns a new instance of Upgrade.
14 15 16 17 |
# File 'lib/upgrade.rb', line 14 def initialize versions, rollback=false @versions = versions @rollback = rollback end |
Instance Method Details
#checkout_upgrade_branch ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/upgrade.rb', line 19 def checkout_upgrade_branch # obtain an upgrade branch if (GithubApi.DoesBranchExist('origin', UPGRADE_BRANCH) != GlobalConstants::EMPTY) puts 'Checking out existing upgrade branch...' return false if !GithubApi.CheckoutExistingBranch(UPGRADE_BRANCH) == GlobalConstants::EMPTY else puts 'Checking out new upgrade branch...' return false if !GithubApi.CheckoutNewBranch(UPGRADE_BRANCH) == GlobalConstants::EMPTY end return true end |
#clear_project_env_vars ⇒ Object
288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/upgrade.rb', line 288 def clear_project_env_vars ENV['AI_InstrumentationKey'] = '' if ENV.respond_to? 'AI_InstrumentationKey' ENV['AppClientId'] = '' if ENV.respond_to? 'AppClientId' ENV['ConfigSettingsTable'] = '' if ENV.respond_to? 'ConfigSettingsTable' ENV['env'] = '' if ENV.respond_to? 'env' ENV['RuntimePath'] = '' if ENV.respond_to? 'RuntimePath' ENV['ServiceName'] = '' if ENV.respond_to? 'ServiceName' ENV['SettingsAccount'] = '' if ENV.respond_to? 'SettingsAccount' ENV['SettingsAccountKey'] = '' if ENV.respond_to? 'SettingsAccountKey' ENV['should_update_settings_connstr'] = '' if ENV.respond_to? 'should_update_settings_connstr' ENV['unitestconnectionString'] = '' if ENV.respond_to? 'unitestconnectionString' end |
#create_upgrade_tag ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/upgrade.rb', line 33 def create_upgrade_tag versioning = SemverVersioning.new semver_file = @config_map..semver.file if @config_map..should_publish_nuget && semver_file != nil && semver_file != GlobalConstants::EMPTY semver_file.capitalize ver_tag = versioning.get_current_version @config_map..semver.location, semver_file return "upgrade-#{ver_tag}" else utc_now = DateTime.now.utc date_tag = utc_now.strftime(DATE_FORMAT) return "upgrade-#{date_tag}" end end |
#Do(config_map, nuget_targets, is_local_run = false) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/upgrade.rb', line 47 def Do config_map, nuget_targets, is_local_run=false @config_map = config_map @repo_url = @config_map..repo_url @branch = @config_map..branch # checkout repo and branch return false if !GithubApi.CheckoutRepoAfresh @repo_url, @branch tag_creator = method(:create_upgrade_tag) # TODO: Need to check if node has failed before invoking rollback if @rollback puts "Starting Rollback..." rollback = new Rollback @repo_url, 'origin', @branch, BACKUP_BRANCH, @config_map. tag_creator = rollback.method(:create_rollback_tag) return false if !rollback.Do end # When upgrade branch exists we are coming from some failure state and dont need to backup the branch again if (GithubApi.DoesBranchExist('origin', UPGRADE_BRANCH) == GlobalConstants::EMPTY) GithubApi.CreateNewBranch(BACKUP_BRANCH, @branch) GithubApi.ForcePushBranch('origin', BACKUP_BRANCH) end # make upgrade branch return false if !checkout_upgrade_branch # use local nuget path for restore if provided set_local_nuget_target nuget_targets # replace versions in package config files puts GlobalConstants::UPGRADE_PROGRESS + 'Replacing package versions...' pkg_files = Dir.glob '**/packages.config' if !replace_package_versions(pkg_files) puts GlobalConstants::UPGRADE_PROGRESS + 'Package version replacement failed.' return false end # replace versions in project references puts GlobalConstants::UPGRADE_PROGRESS + 'Replacing project versions...' proj_files = Dir.glob '**/*.csproj' if !replace_project_versions(proj_files) puts GlobalConstants::UPGRADE_PROGRESS + 'Project version replacement failed.' return false end # Check in manifest if project publish nuget? If yes, increment .semver # QUESTION: Should this method increment semver even if there is no nuget published? puts GlobalConstants::UPGRADE_PROGRESS + 'Upgrading semver...' semver_inc_done = increment_semver_if_publish is_local_run nuget_targets << Dir.pwd + '/build_artifacts' if @config_map..should_publish_nuget # Tag commit recent_commit_hash = GithubApi.GetRecentCommitHash(@branch) #rollback_tag = tag_creator.call() #GithubApi.TagLocal(recent_commit_hash, rollback_tag, "Autoupgrade Tag") # do rake build to test for compilation errors. This needs ENV vars set, passed in via config set_project_env_vars @config_map..env_vars output = system 'rake' if output.to_s == 'false' puts GlobalConstants::UPGRADE_PROGRESS + ' Rake Error: There were errors during rake run.' # save state GithubApi.CommitChanges( VERSION_UPGRADE_FAIL_BUILD_COMMIT) clear_project_env_vars return false end clear_project_env_vars # update version map with nuget versions after build success if semver_inc_done nuget_versions = update_version_map '/build_artifacts/*.nupkg' @versions.merge! nuget_versions puts GlobalConstants::UPGRADE_PROGRESS + 'Semver upgraded. Version map updated.' end if is_local_run puts GlobalConstants::UPGRADE_PROGRESS + 'Local run. No branch update or teamcity build triggered' else puts GlobalConstants::UPGRADE_PROGRESS + 'Branch update in progress...' return false if !update_branch # kick off teamcity build puts GlobalConstants::UPGRADE_PROGRESS + 'Teamcity Project being triggered...' TeamCityApi.trigger_build @config_map..build_configuration_id, ENV['tc_un'], ENV['tc_pwd'] end true end |
#id_from_hint_path(path) ⇒ Object
266 267 268 269 270 271 272 273 |
# File 'lib/upgrade.rb', line 266 def id_from_hint_path path name = path.split('\\')[2].split GlobalConstants::DOT name_without_ver = GlobalConstants::EMPTY name.all? {|i| name_without_ver += i.to_s + GlobalConstants::DOT if i.to_i == 0 } name_without_ver.chomp GlobalConstants::DOT end |
#increment_semver_if_publish(is_local_run) ⇒ Object
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/upgrade.rb', line 301 def increment_semver_if_publish is_local_run if is_local_run auto_update_semver @config_map.project_name, @config_map..semver.location, @config_map..semver.file, @config_map..semver.dimension return true else if @config_map..should_publish_nuget semver_file = @config_map..semver.file semver_file.capitalize if (semver_file != nil && semver_file != GlobalConstants::EMPTY) auto_update_semver @config_map.project_name, @config_map..semver.location, semver_file, @config_map..semver.dimension return true else puts GlobalConstants::UPGRADE_PROGRESS + 'Project does not publish nuget.' end end false end |
#replace_package_versions(pkg_files) ⇒ Object
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/upgrade.rb', line 191 def replace_package_versions pkg_files begin # iterate each package file, replace version numbers and save pkg_files.each{ |file| puts "Finding packages in: #{Dir.pwd}/#{file}..." doc = Nokogiri::XML File.read(file) nodes = doc.xpath "//*[@id]" nodes.each { |node| node['version'] = @versions[node['id']] if @versions.has_key?(node['id']) } File.write file, doc.to_xml } rescue puts $! return false end return true end |
#replace_project_versions(proj_files) ⇒ Object
Typical block of reference node change looks like:
Before:
<Reference Include="MassTransit, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b8e0e9f2f1e657fa, processorArchitecture=MSIL">
<HintPath>..\packages\MassTransit.3.0.14\lib\net45\MassTransit.dll</HintPath>
<Private>True</Private>
</Reference>
After: (file version removed, hint path version number updated)
<Reference Include="MassTransit">
<HintPath>..\packages\MassTransit.3.0.15\lib\net45\MassTransit.dll</HintPath>
<Private>True</Private>
</Reference>
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/upgrade.rb', line 226 def replace_project_versions proj_files begin # iterate each package file, replace version numbers and save proj_files.each{ |file| puts "Updating references in: #{file}..." doc = Nokogiri::XML File.read file nodes = doc.search 'Reference' nodes.each { |node| ref_val = node['Include'] # grab the identifier id = ref_val.split(',')[0] # clean out file version node['Include'] = id # replace version in hint path hint_path = node.search 'HintPath' if hint_path && hint_path[0] != nil hint_path_value = hint_path[0].children.to_s # this identifier is not the same as the node['Include'] one. # For ex., Runtime, Core and Storage assemblies will be referred to from within other packages like Management, Test etc hint_path_id = id_from_hint_path hint_path_value if @versions.has_key? hint_path_id hint_path_parts = hint_path_value.split '\\' hint_path_parts[2] = hint_path_id + GlobalConstants::DOT + @versions[hint_path_id] hint_path[0].children = hint_path_parts.join '\\' end end } File.write file, doc.to_xml } rescue puts $! return false end return true end |
#set_local_nuget_target(nuget_targets) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/upgrade.rb', line 139 def set_local_nuget_target nuget_targets num_paths = 1; nuget_targets.each { |target| nuget_targets_file = Dir.pwd + '/src/.nuget/Nuget.Config' doc = Nokogiri::XML(File.read nuget_targets_file) node_parent = doc.at_css 'packageSources' node = Nokogiri::XML::Node.new('add', doc) node['key'] = "local_nuget_source#{num_paths}" node['value'] = target node_parent.add_child node File.write nuget_targets_file, doc.to_xml num_paths += 1 } end |
#set_project_env_vars(envs) ⇒ Object
275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/upgrade.rb', line 275 def set_project_env_vars envs ENV['AI_InstrumentationKey'] = envs.AI_InstrumentationKey if envs.respond_to? 'AI_InstrumentationKey' ENV['AppClientId'] = envs.AppClientId if envs.respond_to? 'AppClientId' ENV['ConfigSettingsTable'] = envs.ConfigSettingsTable if envs.respond_to? 'ConfigSettingsTable' ENV['env'] = envs.env if envs.respond_to? 'env' ENV['RuntimePath'] = envs.RuntimePath if envs.respond_to? 'RuntimePath' ENV['ServiceName'] = envs.ServiceName if envs.respond_to? 'ServiceName' ENV['SettingsAccount'] = envs.SettingsAccount if envs.respond_to? 'SettingsAccount' ENV['SettingsAccountKey'] = envs.SettingsAccountKey if envs.respond_to? 'SettingsAccountKey' ENV['should_update_settings_connstr'] = envs.should_update_settings_connstr if envs.respond_to? 'should_update_settings_connstr' ENV['unitestconnectionString'] = envs.unitestconnectionString if envs.respond_to? 'unitestconnectionString' end |
#update_branch ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/upgrade.rb', line 154 def update_branch # see if any files changed and commit git_status = GithubApi.HaveLocalChanges git_status = git_status != nil || git_status != GlobalConstants::EMPTY puts GlobalConstants::UPGRADE_PROGRESS + "Local changes are present: #{git_status}" if git_status puts GlobalConstants::UPGRADE_PROGRESS + 'Local version changes are being committed' return false if !GithubApi.CommitChanges('Versions updated') end # rebase and push the branch puts GlobalConstants::UPGRADE_PROGRESS + 'Rebasing and pushing update branch...' GithubApi.CheckoutLocal @branch GithubApi.RebaseLocal UPGRADE_BRANCH # if push fails, do a pull --rebase of the branch and fail the upgrade. # Upstream commits need to accounted for and full upgrade cycle must be triggered # Build failure email will inform concerned team git_status = GithubApi.PushBranch(@repo_url, @branch) == GlobalConstants::EMPTY if git_status puts GlobalConstants::UPGRADE_PROGRESS + "Version upgrade changes have been rebased with #{@repo_url}/#{@branch} and pushed" else GithubApi.PullWithRebase @repo_url, @branch GithubApi.PushBranch @repo_url, @branch puts GlobalConstants::UPGRADE_PROGRESS + "Push after version upgrade failed for #{@repo_url}/#{@branch}. Pull with rebase done and pushed" return false end # delete upgrade branch both local and remote GithubApi.DeleteLocalBranch UPGRADE_BRANCH GithubApi.DeleteRemoteBranch @repo_url, UPGRADE_BRANCH true end |
#update_version_map(path) ⇒ Object
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
# File 'lib/upgrade.rb', line 321 def update_version_map path path = File.join(Dir.pwd, path) nugets = Dir.glob path versions = {} nugets.each { |nuget| full_name = File.basename nuget full_name = full_name.sub! '.nupkg', '' full_name = full_name.sub! '.symbols', '' if full_name.include? '.symbols' dot_pos = full_name.index GlobalConstants::DOT nuget_name = full_name[0..dot_pos-1] nuget_version = full_name[dot_pos+1..full_name.length] versions[nuget_name] = nuget_version } versions end |