目录html
Jenkins持续集成学习-Windows环境进行.Net开发1
Jenkins持续集成学习-Windows环境进行.Net开发2
Jenkins持续集成学习-Windows环境进行.Net开发3
Jenkins持续集成学习-Windows环境进行.Net开发4
Jenkins持续集成学习-搭建jenkins问题汇总
Jenkins持续部署-Windows环境持续部署探究1
Jenkins持续部署-自动生成版本号
Jenkins持续部署-建立差量更新包shell
上一篇文章介绍关于版本号的自动生成逻辑,本篇文章主要介绍经过脚本跟版本号建立程序的差量包。json
本章主要是经过jenkins持续集成以后经过powershell生成差量更新包与全量更新包,而后将他们上传到FTP上。windows
当jenkins编译完成以后,咱们须要处理如下事项。api
上一章介绍了.net
环境下如何自动生成版本号的逻辑,这里再也不介绍。有兴趣的能够看《Jenkins持续部署-自动生成版本号
》数组
$version =(Get-ChildItem $executeFile).VersionInfo.FileVersion
$executeFile
为可执行的exe文件。经过Get-ChildItem 获取到该文件。经过VersionInfo.FileVersion
或VersionInfo.ProductVersion
获取到文件的文件版本号。服务器
不知道为何和文件右键属性看到的两个版本号有点区别右击属性的文件版本号和产品版本可能不同,可是经过代码获取到的都是同样的函数
为了可以生成程序差量更新包,减小程序更新时的更新包大小,须要能够经过比较当前版本和上一个版本的各个文件的版本号信息。经过将该文件保存成一份文件清单。再比较时直接经过该文件清单进行比对,可以很方便的生成从差量的文件清单。同时文件清单可以清晰的列出每一个须要更新的文件和文件版本号,给人看会比较直观。学习
主要是咱们本身须要用该文件,也能够不用该文件,直接获取全部文件,对比他们的文件名和版本号是否一致也能够。ui
$programFiles = Get-ChildItem *.dll,*.exe $updateListFileName = "FileUpdateList.txt" Create-FileUpdateList -files $programFiles -fileName $updateListFileName function Create-FileUpdateList(){ param([System.IO.FileInfo[]]$files,[string]$fileName) ## 删除原始的清单文件 if(Test-Path $fileName) { Write-Host "Remove Old UpdateList File" Remove-Item $fileName } $array=New-Object System.Collections.ArrayList foreach($file in $files) { ## 获取每一个文件版本号 $fileVersion =(Get-ChildItem $file).VersionInfo.ProductVersion $fileInfo="" | Select-Object -Property FileName,Version $fileInfo.FileName = $file.Name $fileInfo.Version = $fileVersion ## 追加到文件 $null = $array.Add($fileInfo) Write-Host "Update File:"$file.Name ",Version:" $fileVersion } $json = ConvertTo-Json $array.ToArray() $json >> $fileName }
Get-ChildItem *.dll,*.exe
获取当前目录全部的dll和exe文件FileUpdateList.txt
,若已经存在更新清单文件,则删除旧的从新生成。New-Object
建立一个.Net的集合,用于存放每一个文件的文件信息。$fileInfo="" | Select-Object -Property FileName,Version
定义了一个自定义对象类型,包含了文件名和版本号2个属性。因为我须要在powershell2.0
的环境上执行脚本,powershell2.0
没有Json读写的api,这里使用的是别人写的一个脚本生成json格式的字符串。
function ConvertTo-Json { param( $InputObject ) if( $InputObject -is [string]){ "`"{0}`"" -f $InputObject } elseif( $InputObject -is [bool]) { $InputObject.ToString().ToLower() } elseif( $null -eq $InputObject){ "null" } elseif( $InputObject -is [pscustomobject]) { $result = "$space{`r`n" $properties = $InputObject | Get-Member -MemberType NoteProperty | ForEach-Object { "`"{0}`": {1}" -f $_.Name, (ConvertTo-Json $InputObject.($_.Name)) } $result += $properties -join ",`r`n" $result += "$space`r`n}" $result } elseif( $InputObject -is [hashtable]) { $result = "{`r`n" $properties = $InputObject.Keys | ForEach-Object { "`"{0}`": {1}" -f $_, (ConvertTo-Json $InputObject[$_]) } $result += $properties -join ",`r`n" $result += "`r`n}" $result } elseif( $InputObject -is [array]) { $result = "[`r`n" $items = @() for ($i=0;$i -lt $InputObject.length;$i++) { $items += ConvertTo-Json $InputObject[$i] } $result += $items -join ",`r`n" $result += "`r`n]" $result } else{ $InputObject.ToString() } }
将全部文件进行压缩,压缩文件名为版本号。
function New-ZipFile() { param(## The name of the zip archive to create [object[]]$files, $zipName = $(throw "Specify a zip file name"), ## Switch to delete the zip archive if it already exists. [Switch] $Force) ## Check if the file exists already. If it does, check ## for -Force - generate an error if not specified. if(Test-Path $zipName) { if($Force) { Write-Host "Remove File:" $zipName Remove-Item $zipName } else { throw "Item with specified name $zipName already exists." } } ## Add the DLL that helps with file compression Add-Type -Assembly System try { #打开或建立文件流 $compressedFileStream = [System.IO.File]::Open($zipName,[System.IO.FileMode]::OpenOrCreate) #建立压缩文件流 $compressionStream = New-Object ICSharpCode.SharpZipLib.Zip.ZipOutputStream($compressedFileStream) ## Go through each file in the input, adding it to the Zip file ## specified foreach($file in $files) { ## Skip the current file if it is the zip file itself if($file.FullName -eq $zipName) { continue } ## Skip directories if($file.PSIsContainer) { continue } #读取每一个文件进行压缩 try { #打开文件 $originalFileStream = [System.IO.File]::Open($file.FullName,[System.IO.FileMode]::Open) $entry = New-Object ICSharpCode.SharpZipLib.Zip.ZipEntry($file.Name) $compressionStream.PutNextEntry($entry); $bytes = New-Object Byte[] $originalFileStream.Length #读取文件流 $null = $originalFileStream.Read($bytes,0,$bytes.Length) #写入到压缩流 $compressionStream.Write($bytes,0,$bytes.Length) } finally { $originalFileStream.Dispose() } } } catch{ $Error Remove-Item $Path } finally { ## Close the file $compressionStream.Dispose() $compressedFileStream.Dispose() $compressionStream = $null $compressedFileStream = $null } }
powershell2.0
没有内部的压缩解压方法。这里使用.net的ICSharpCode.SharpZipLib.dll
进行压缩。powershell
中能够经过New-Object Byte[]
建立.net的字节数组
,若构造函数须要传参则直接将参数写到后面便可。该脚本不支持带文件夹的压缩。
因为我定义的都是4位版本号,前三位是需求号,最后一位是修订号。所以我直接经过前三位获取上个版本的压缩包文件便可,若没有,则无需建立差量更新包。
function Get-LastPackage($currentVersion,$majorVersion) { #默认上个版本号就是当前版本号 $lastFileName = $null $lastMajorVersion = $null $lastVersion = $null #读取上一个版本的压缩文件 # 获取全部文件夹,程序目录下的目录都是版本号目录 $allFile = Get-ChildItem | Where-Object{ $_.Name -match '(\d*\.\d*\.\d*.\d*)\.zip' } if($null -eq $allFile) { Write-Host "No Last Package" return } ## 获取上一个版本号最新的修改 $allFile = $allFile | Where-Object {$_.Name -lt $majorVersion} | Sort-Object -descending ## 判断是否有比当前版本小的 if($null -eq $allFile) { ## 没有历史的大版本号,则全量更新,和当前版本的主版本号同样 Write-Host "No Last Package" return } #有多个文件如2.25.0,2.24.1,则获取到的是数组 elseif($allFile -is [array]) { ##存在历史更新,则获取上一个版本的更新目录 $lastFileName = $allFile[0] } #只有一个目录,首个版本打包时则获取到的是DirectoryInfo else { $lastFileName = $allFile } ## 获取最新的版本 $lastVersion =[System.IO.Path]::GetFileNameWithoutExtension($lastFileName) $lastMajorVersion = [System.IO.Path]::GetFileNameWithoutExtension($lastVersion) #返回文件名 主版本号 版本号 $lastFileName $lastVersion $lastMajorVersion }
四位数字版本.zip
的文件。我只须要根据两个文件清单进行文件名和版本号的对比,若是同一个文件的版本号同样,则该文件无需更新。
$lastUnpackDir = UnZip $lastZipFullName $lastVersion $currentUpdateObject = Read-Json $currentUpdateListFile $lastUpdateObject = Read-Json $lastUpdateListFile $array = New-Object System.Collections.ArrayList #比较两个清单文件 foreach($currentFile in $currentUpdateObject) { if($currentFile -eq "FileUpdateList.txt") { #跳过清单文件 continue } ##遍历json数组数组对象自己也会遍历,且值为空 if($null -eq $currentFile.FileName) { #跳过清单文件 continue } #当前清单每一个文件去上个版本查找 $lastFile = $lastUpdateObject | Where-Object {$_.FileName -eq $currentFile.FileName} | Select-Object -First 1 #找到文件,判断版本号 if($lastFile.Version -eq $currentFile.Version) { #版本号同样则不须要更新 $sameFile = Join-Path $currentUnpackDir $lastFile.FileName $null = $array.Add($sameFile) continue } }
有了重复文件的列表,接下来就能够将重复文件都删除。最后剩下差量更新的文件
if($array.Count -eq $currentUpdateObject.Length - 1) { #全部都同样,不须要更新 Write-Host "No Modified File" return $false } else { #存在不同的包,则更新全部 foreach($sameFile in $array) { Write-Host "Remove Not Modified File " $sameFile Remove-Item $sameFile #同时删除pdb文件 $pdbFile = [System.IO.Path]::GetFileNameWithoutExtension($sameFile)+".pdb" if(Test-Path $pdbFile) { Remove-Item $pdbFile } } #从新获取解压的目录 $diffFiles = Get-ChildItem *.dll,*.exe #建立新的清单文件 Create-FileUpdateList -files $diffFiles -fileName $currentUpdateListFile #从新压缩全部文件 $files = Get-ChildItem *.dll,*.pdb,*.exe,"FileUpdateList.txt" Write-Host "Need Update File " $files $diffZipFullName = [System.IO.Path]::GetFileNameWithoutExtension($currentZipFullName)+"_diff.zip" New-ZipFile -files $files -Path $diffZipFullName -Force true } #移除上个版本的解压出的压缩文件夹 Write-Host "Remove Last Update Package dir" $lastUnpackDir Get-ChildItem $lastUnpackDir | Remove-Item -Recurse Remove-Item $lastUnpackDir -Recurse $return $true
false
表示没有生成差量更新文件。就不用建立差量更新文件了。不然则删除全部的文件和对应的符号文件。true
表示生成了差量更新文件。全量和差量文件生成完毕后就能够将文件上传到指定的服务器了。我将服务器的配置信息保存到了ServerInfo.Json
文件中,这样想添加其余服务器只要修改一下这个配置文件便可。读取配置的服务器,ServerInfo.Json
包含了服务器的一些信息,包括地址,用户名,及一些路径配置。
$config = Read-Json "ServerInfo.json" foreach($itemConfig in $config) { Remote-CreateDic -userName $itemConfig.UserName -password $itemConfig.Password -address $itemConfig.Address -jobName $ftpFileName -programeDir $itemConfig.ProgramDir -ErrorAction Stop #目标 ftp://host:port/xxx/xxx.zip $destination = "ftp://"+$itemConfig.FTP.Host+":"+$itemConfig.FTP.Port+"/"+$ftpFileName # FTP上传压缩包 FTP-UpdateFile -file $zipFullName -destination $destination -userName $itemConfig.FTP.UserName -password $itemConfig.FTP.Password -ErrorAction Stop if($hasDiffFile ){ $ftpFileName = Join-Path $ENV:JOB_NAME ($version+"_diff.zip") FTP-UpdateFile -file $zipFullName -destination $destination -userName $itemConfig.FTP.UserName -password $itemConfig.FTP.Password -ErrorAction Stop } }
Remote-CreateDic
执行远程建立文件夹的命令。FTP-UpdateFile
将全量更新包和差量更新包都上传到指定的服务器上。在上传到FTP上时,如有必要则须要先在FTP上建立指定的文件夹,避免上传文件夹的时候因为没有文件夹致使上传失败。
因为须要远程调用,所以须要传递用户,密码和服务器地址。同时还要包含jenkins当前的job名称以及远程服务器程序上传路径。上传的路径约定为FTP地址/Job名称/版本号.zip
function Remote-CreateDic() { param([string] $userName=$(throw "Parameter missing: -userName"), [string] $password=$(throw "Parameter missing: -password"), [string] $address=$(throw "Parameter missing: -address"), [string] $jobName=$(throw "Parameter missing: -jobName"), [string] $programeDir=$(throw "Parameter missing: -programeDir")) #非域用户须要添加\,不然远程调用有问题 if(!$userName.StartsWith('\')) { $userName="\"+$userName } $secpwd = convertto-securestring $password -asplaintext -force $cred = new-object System.Management.Automation.PSCredential -argumentlist $userName,$secpwd #程序存放目录和当前的jenkins job目录合并后是服务器锁在的FTP程序存放目录 $zipFile= [System.IO.Path]::Combine($programeDir,$jobName) #备份程序 invoke-command -computername $address -Credential $cred -command { param([string]$file) #获取文件夹路径 $dir = [System.IO.Path]::GetDirectoryName($file) if(Test-Path $dir){ Write-Host "Dic exists :" $dir #文件夹存在 if(Test-Path $file) { #压缩文件已存在.不容许,版本号没变。必须改变 throw $file + "exists,retry after change version" } } else { # 判断文件夹是否存在 # 没有文件夹则建立,不然首次FTP上传没有文件夹时则会上传失败 #防止输出 $null = New-Item -Path $dir -Type Directory } } -ArgumentList $zipFile -ErrorAction Stop }
FTP上传能够调用.Net的WebClient上传文件的方法处理。
function FTP-UpdateFile() { param([String]$file=$(throw "Parameter missing: -name file"), [String]$destination=$(throw "Parameter missing: -name destination"), [String]$userName=$(throw "Parameter missing: -name userName"), [String]$password=$(throw "Parameter missing: -name destination")) $pwd=ConvertTo-SecureString $password -AsPlainText -Force; #111111为密码 $cred=New-Object System.Management.Automation.PSCredential($userName,$pwd); #建立自动认证对象 $wc = New-Object System.Net.WebClient try { $wc.Credentials = $cred Write-Host "upload to ftp. " $file "->" $destination $wc.UploadFile($destination, $file) Write-Host "upload success " } finally { $wc.Dispose() Write-Host "close ftp. " } }
本文对Windows下的持续部署包建立和上传的逻辑继续了说明,主要经过自动生成的版本号继续判断与比较哪些库包须要更新。最终将库包经过FTP上传到各个服务器上。最后就能够调用各个服务器的远程脚本进行服务的卸载与更新了。
本文地址:http://www.javashuo.com/article/p-uangfmlj-kx.html 做者博客:杰哥很忙 欢迎转载,请在明显位置给出出处及连接