Jenkins持續部署-自動生成版本號

Jenkins持續部署-自動生成版本號


目錄

Jenkins持續集成學習-Windows環境進行.Net開發1
Jenkins持續集成學習-Windows環境進行.Net開發2
Jenkins持續集成學習-Windows環境進行.Net開發3
Jenkins持續集成學習-Windows環境進行.Net開發4
Jenkins持續集成學習-搭建jenkins問題彙總
Jenkins持續部署-Windows環境持續部署探究1
Jenkins持續部署-自動生成版本號shell

前言

在上一篇以前的文章開始對Windows環境下持續部署的方案進行學習與研究。上一篇文章主要介紹關於持續部署須要的一些技術方案的實現,在本篇文章開始對持續部署的一些細節實現展開討論。
本篇文章先對版本號的自動更新流程進行梳理和說明。後續須要經過版本號比較建立差量更新包。c#

目的

本章文章主要是經過調用svn客戶端命令和powershell腳本實現徹底無需人工干預自動生成版本號。bash

詳細流程

若程序須要定義版本號,則能夠將版本號記錄在程序集的AssemblyInfo.cs文件中app

[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyFileVersion("1.0.0")]

也能夠在程序集右鍵選擇屬性(或者經過快捷鍵Alt + Enter),在Application點擊Assembly Infomation...按鈕修改程序集版本號和文件版本號。svn

20190629173644.png

AssemblyVersion是程序集的版本,.NET的CLR用於標識出該dll的版本信息,用於定義強名稱的版本號,該版本號每一位最大爲16位長度,即最大爲65535,超過期編譯不經過。
AssemblyFileVersion是文件版本號,僅僅是文件版本號,給人看的,沒有實際什麼做用,也沒有長度限制。工具

獲取SVN Reversion

咱們規定程序的版本號爲需求版本號1.0.0加上SVN的Reversion作爲修訂號。這樣就能直接關聯上該程序集是哪一個版本的代碼。
關於修訂號,在《TortoiseSVN》文檔中有相關的說明。我看的是《TortoiseSVN 1.8.10》的文檔,在第五章介紹了SubWCRev程序。經過SubWCRev程序能夠執行關鍵字$WCREV$替換。同時咱們須要提供一個版本號模板文件,經過替換版本號模板文件的關鍵字生成咱們須要的版本號文件。post

首先咱們根據程序集下AssemblyInfo.cs文件複製出一個AssemblyInfo.template.cs文件。visual-studio

因爲咱們僅僅是爲了修改版本號信息,後面就稱之爲版本號模板文件學習

而後將其[assembly: AssemblyFileVersion("1.0.0.0")]修改成[assembly: AssemblyFileVersion("1.0.0.$WCREV$")]。這樣咱們就能夠經過SubWCRev程序替換修訂號。

20190629221330.png

因爲AssemblyVersion有大小限制,不容許超過65535,而SVN修訂號頗有可能會超過該值,所以CLR的程序集版本號不用改修訂號。只須要修改文件版本號便可。

因爲在編譯時,VS會編譯AssemblyInfo文件提取出程序集信息放入到程序集內。咱們直接複製出來的版本號模板文件默認也會進行編譯。而咱們建立的版本號模板文件用於生成版本號文件,無需編譯。咱們須要的是經過版本號模板文件生成版本號文件,即經過AssemblyInfo.template.cs生成AssemblyInfo.cs。所以在版本號模板文件右鍵屬性中將Build ActionCompile修改成None

20190629221252.png

此時咱們已經有了版本號模板文件,接下來要作的是在編譯的以前先根據版本號模板文件建立咱們須要的版本號文件。
VS編譯的時候提供了編譯前預處理功能和編譯後處理功能。在程序集屬性中,咱們選擇Build Event裏面有Pre-build event command line,經過在裏面輸入指令能夠實如今編譯前執行咱們想要的命令。

20190629181431.png

同時VS內部也提供了一些宏指令供咱們使用,經過點擊Edit Pre-build按鈕,會彈出一個編輯框

20190629181601.png

點擊Macros能夠查看全部VS支持的宏指令

20190629181733.png

SubWCRev程序命令格式爲SubWCRev WorkingCopyPath [SrcVersionFile DstVersionFile] [-nmdfe],WorkingCopyPath爲SVN的工做副本,SrcVersionFile爲原始版本文件,即版本模板文件。DstVersionFile爲替換關鍵子後保存的版本文件。
在VS環境變量中咱們能夠經過$(ProjectDir)獲取到當前程序集路徑,經過$(SolutionDir)獲取到解決方案路徑。

宏指令爲$(指令名)格式

在預編譯事件中輸入如下指令SubWCRev $(SolutionDir) $(ProjectDir)Properties\AssemblyInfo.template.cs $(ProjectDir)Properties\AssemblyInfo.cs便可在編譯前獲取到SVN的reversion填充到修訂號中。

編譯後能夠在輸出窗口看到關鍵字替換的信息

1>------ Build started: Project: FGMain, Configuration: Debug Any CPU ------
1>  SubWCRev: 'F:\工做\SVN\Platform\trunk\FGMain\FGMain\'
1>  Last committed at revision 100268
1>  Mixed revision range 100267:100268
1>  Local modifications found
1>  Unversioned items found

獲取需求號

在實際工做中,咱們每次發版都會有一個需求版本號。當產生需求時整個版本都會使用這個版本號。所以咱們能夠在開發的時候就在開發分支上建立該版本號的需求分支。分支名稱以版本號命名,這樣程序就能夠獲取到URL的版本號信息填充到版本號模板號模板文件中。而省去了人爲修改版本號的麻煩。

好比當前版本號爲1.32.0,則在SVN程序的分支上建立一個1.32.0的版本。branches/FGMain/1.32.0

接下來在咱們使用SubWCRev程序關鍵字替換以前須要先獲取到分支的版本號填充到版本號模板文件中。這樣在編譯前就會將版本號和SVN的修訂號一同生成。
咱們還須要提早判斷當前SVN工做目錄是否有修改,只有在工做目錄有修改時,才須要更新版本號,工做目錄沒有修改時,則無需修改版本號。

當咱們安裝了SVN客戶端後(同時須要選擇安裝命令行工具),咱們能夠經過SVN執行執行命令,經過SVN help查看支持的全部參數。

SVN客戶端安裝時須要勾選命令行工具,以下截圖
20190701100831.png

獲取版本號

咱們須要獲取url的版本號。而版本號只有在分支目錄上纔有,所以咱們能夠經過正則解析如下url,提取版本號。若提取不到則無需執行後續邏輯

經過svn info獲取當前目錄的svn信息,經過svn info 路徑獲取指定路徑的svn信息。

F:\工做\SVN\Platform\trunk\FGMain>svn info
Path: .
Working Copy Root Path: F:\工做\SVN\Platform\trunk\FGMain
URL: http://inner.svn.com:81/ATS_Code/Platform/branches/FGMain/1.32.0
Relative URL: ^/Platform/branches/FGMain/1.32.0
Repository Root: http://inner.svn.com:81/ATS_Code
Repository UUID: 2fd9d0ce-2897-f849-b9e2-af1303b08de7
Revision: 99512
Node Kind: directory
Schedule: normal
Last Changed Author: wish
Last Changed Rev: 99512
Last Changed Date: 2019-06-14 17:54:47 +0800 (週五, 14 6月 2019)

命令會返回多行信息,我使用的時SVN 1.11 版本的客戶端,其餘版本可能會有不一樣。咱們解析第二行的URL從而解析出URL的版本號。

$svnInfo = svn info $projectDir
$urlInfo = $svnInfo[2]
$url = $urlInfo.Replace("URL: ","");
$urlMatchStr= 'branches/(.*?)/(.*?)/(.*?)'
if($url -notmatch $urlMatchStr)
{
    # 主線再也不處理
    Write-Host "$url not match $urlMatchStr"
    return 
}

這裏須要注意因爲咱們當前目錄不必定就是解決方案目錄,在VS中咱們實在解決方案調用的編譯工做,可是在jenkins咱們的目錄可能會是bin/releasebin/debug,所以匹配URL時須要用非貪婪匹配。這樣不管路徑爲branches/FGMain/1.32.0/FGBussness仍是branches/FGMain/1.32.0/FGMain/bin/Debug 第二項均可以匹配到版本號。
如今同$matches[2]便可獲取到咱們獲取到的版本號。

獲取當前工做副本狀態

當獲取到版本號時,代表當前實在分支目錄,則須要判斷工做副本是否有修改。有修改則須要更新版本號。經過svn status 查看路徑的svn狀態,經過svn status 路徑能夠查看指定路徑的SVN狀態。

PS F:\工做\SVN\Platform\trunk\FGMain> svn status FGBussness
    ?       FGBussness\FGClientBussness.csproj.user
    M       FGBussness\MainWorkServer.cs
    ?       FGBussness\app.config
    ?       FGBussness\bin

命令返回了一個集合,每一行是一個文件或文件夾的SVN狀態。SVN共包含如下狀態

  • " ": 無修改
  • "A": 新增
  • "C": 衝突
  • "D": 刪除
  • "G": 合併
  • "I": 忽略
  • "M": 改變
  • "R": 替換
  • "X": 未歸入版本控制,但被外部定義所用
  • "?": 未歸入版本控制
  • "!": 該項目已遺失 (被非 svn 命令所刪除) 或是不完整
  • "~": 版本控制下的項目與其它類型的項目重名
  • "L": 鎖定
  • "S": 已切換
  • "K": 存在鎖定標記

能夠看到" "、"X"、"?"能夠認爲是本地無修改。其餘狀態都有修改,須要更新版本號。當有衝突時,編譯也會出錯,同時編輯完衝突有可能就沒有修改了,所以狀態爲"C"時也認爲時無修改。

$svnStatuses = svn status $projectDir
#遍歷每一個文件狀態
foreach($svnStatus in $svnStatuses)
{
    $status = $svnStatus.SubString(0,1)
    if(($status -ne " ") -and ($status -ne "X") -and ($status -ne "?") -and ($status -ne "C"))
    {
        #存在編輯
        Write-Host $svnStatus.SubString(1).Trim()"Modified"
        $modified = $true
        break
    }
}

經過$modified記錄當前工做副本的是否修改。同時只要一個文件修改了就無需判斷其餘文件。

更新版本號模板

接下來咱們讀取版本號模板文件,首先咱們須要確認一下VS保存的文件編碼,咱們按照VS的編碼讀取並保存文件。
文件-高級保存選項中能夠看到設置的文本編碼

20190629200536.png

$versionContent = Get-Content $versionFile -encoding UTF8

for($count = 0 ; $count -lt $versionContent.Length; $count++)
{
    if(($versionContent[$count] -match '\[assembly: AssemblyVersion\(\"(\d*
    \.\d*\.\d*)\"\)\]') -or
    ($versionContent[$count] -match '\[assembly: AssemblyFileVersion\(\"(\d*\.\d*\.\d*)\.\$WCREV\$\"\)\]'))
    {
        #版本號不一致則更新版本號
        if($matches[1] -ne $marjorVersion)
        {
            Write-Host "Change Version"$matches[1]"To $marjorVersion"
            $versionContent[$count] = $versionContent[$count] -replace $matches[1],$marjorVersion
        }
        continue
    }
}

\d*\.\d*\.\d*匹配3位版本號,如1.32.0

遍歷文件的每一行進行匹配,若匹配上了則將匹配的版本號替換爲新的版本號。
最後更新版本號模板文件
Set-Content $versionContent -Path $versionFile -encoding UTF8

同時因爲咱們程序只能獲取一個程序集看成整個程序的版本號,所以咱們每次編譯的時候能夠將啓動項強制更新版本號。咱們能夠添加一個$force 當設置爲true的時候無論本地是否有修改都更新版本號。

完整的腳本以下:

param([string] $projectDir,[string]$versionFile, $force)

Write-Host "current path:"$projectDir

try
{
    # 指定路徑
    $svnInfo = svn info $projectDir
    $urlInfo = $svnInfo[2]
    $url = $urlInfo.Replace("URL: ","");

    Write-Host "url:$url"

    $urlMatchStr= 'branches/(.*?)/(.*?)/(.*?)'
    if($url -notmatch $urlMatchStr)
    {
        # 主線再也不處理
        
        Write-Host "$url not match $urlMatchStr"
        return 
    }
    # 分支
    # PS F:\工做\SVN\Platform\trunk\FGMain> $matches
    # Name                           Value
    # ----                           -----
    # 3                              FGBussness
    # 2                              1.32.0
    # 1                              FGMain
    # 0                              branches/FGMain/1.32.0/FGBussness
    $marjorVersion = $matches[2]
    Write-Host "Current Working Copy Version:$marjorVersion"

    # 沒有強制修改,則須要判斷當前工做路徑是否編輯過。
    $modified = $force 

    if($modified)
    {
        Write-Host "Force Modified"
    }
    else
    {
        #當路徑含有中文時,參數傳入會亂碼。暫時獲取當前路徑狀態
        $svnStatuses = svn status $projectDir
        #遍歷每一個文件狀態
        foreach($svnStatus in $svnStatuses)
        {
            $status = $svnStatus.SubString(0,1)
            if(($status -ne "X") -and ($status -ne "?"))
            {
                #存在編輯
                Write-Host $svnStatus.SubString(1).Trim()"Modified"
                $modified = $true
                break
            }
        }
    }
    # 若當前工做目錄沒有修改過的文件則無需修改版本號
    # 查找模板文件的路徑
    if($modified)
    {
        Write-Host "Version File :$versionFile"
        $versionContent = Get-Content $versionFile -encoding UTF8

        for($count = 0 ; $count -lt $versionContent.Length; $count++)
        {
            if(($versionContent[$count] -match '\[assembly: AssemblyVersion\(\"(\d*\.\d*\.\d*)\"\)\]') -or
            ($versionContent[$count] -match '\[assembly: AssemblyFileVersion\(\"(\d*\.\d*\.\d*)\.\$WCREV\$\"\)\]'))
            {
                #版本號不一致則更新版本號
                if($matches[1] -ne $marjorVersion)
                {
                    Write-Host "Change Version"$matches[1]"To $marjorVersion"
                    $versionContent[$count] = $versionContent[$count] -replace $matches[1],$marjorVersion
                }
                continue
            }
        }
        # 編輯過則將模板的版本號替換掉
        # 在VS的菜單-文件-高級保存選項中默認的文件編碼是使用UTF8 With BOM的格式
        Set-Content $versionContent -Path $versionFile -encoding UTF8
    }
    else
    {
        Write-Host "No Modified"
    }
}
catch
{
    $Error
}

設置編譯前讀取版本號

腳本編寫好,咱們將腳本放到項目根目錄下,這樣全部的程序集都能經過解決文件夾獲取到該腳本。

powershell -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(SolutionDir)Update-Version.ps1 $(ProjectDir) $(ProjectDir)Properties\AssemblyInfo.template.cs

Pre-build event command line 添加以上命令調用更新版本號的腳本。

  • -ExecutionPolicy Bypass表示容許該腳本執行,不然可能沒有權限執行本地腳本文件。
  • -NoProfile 表示不加載powershell的配置文件。默認會加powershell全部的配置文件。
  • -NonInteractive 表示不向用戶顯示交互式提示。

如今完整的Pre-build命令以下

powershell -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(SolutionDir)Update-Version.ps1 $(ProjectDir) $(ProjectDir)Properties\AssemblyInfo.template.cs
SubWCRev $(SolutionDir) $(ProjectDir)Properties\AssemblyInfo.template.cs $(ProjectDir)Properties\AssemblyInfo.cs

若啓動項默認須要強制更新版本號,則使用如下命令

powershell -ExecutionPolicy Bypass -NoProfile -NonInteractive -File $(SolutionDir)Update-Version.ps1 $(ProjectDir) $(ProjectDir) $true

若當前版本文件的版本號爲1.31.0,在1.32.0的分支上進行編譯,則會在輸出窗口輸出如下日誌

1>------ Build started: Project: FGMain, Configuration: Debug Any CPU ------
1>  current path: F:\工做\SVN\Platform\trunk\FGMain\FGMain\
1>  url:http://124.160.27.118:81/ATS_Code/Platform/branches/FGMain/1.32.0/FGMain
1>  Current Working Copy Version:1.32.0
1>  Force Modified
1>  Version File :F:\工做\SVN\Platform\trunk\FGMain\FGMain\Properties\AssemblyInfo.template.cs
1>  Change Version 1.31.0 To 1.32.0
1>  Change Version 1.31.0 To 1.32.0
...

總結

在腳本編寫的時候遇到了如下錯誤

  1. 咱們能夠在傳入參數設置$force爲bool類型,可是在外部調用powershell腳本傳參傳入bool類型會報如下錯誤
    沒法處理對參數「force」的參數轉換。沒法將值「System.String」轉換爲類型「System.Boolean」。布爾參數僅接受布爾值和數字,例如 $True、$False、1 或 0。
    可是經過提示的傳入值仍然會報錯,所以咱們只能將[bool]顯示的類型去掉,避免強制轉換時出現錯誤。

  2. 外部傳入路徑含有中文會致使powershell因爲亂碼處理不了

參考文獻

  1. 給PowerShell腳本傳遞一個布爾值
  2. Using PowerShell in post/pre build action in Visual Studio
  3. How to pass boolean values to a PowerShell script from a command prompt
  4. Always Use -NoProfile To Launch Scripts

本文地址:http://www.javashuo.com/article/p-bxznawmj-ky.html 做者博客:傑哥很忙 歡迎轉載,請在明顯位置給出出處及連接

相關文章
相關標籤/搜索