前言
上一篇,我們已經實現了nuget包的打包,釋出到nuget。最近,發現github也有持續整合持續交付部署(CICD)的功能(請原諒我的菜)。原來也沒太關注這塊,主要原來一直專注於寫業務。最近開始系統學習微服務相關的內容,瞭解到是通過jenkins之類的工具來實現的部署。在github上閒逛的時候,發現有個Actions的功能,就嘗試了一番。它是通過一個yml配置檔案來實現,程式碼推送到倉庫後,自動打包釋出到nuget源和github源。這個過程就是在一個docker環境或者虛擬伺服器環境中,將程式碼clone下來,通過nuget.exe這樣的命令列打包上傳工具來實現原本人工的操作過程(我猜的)。所以,本文主要實現的就是當我們的程式碼推送到git倉庫後,自動打包nuget package,並推送到nuget.org和github.com。
準備工作
1.首先,我們先修改一下nuget package的配置檔案,準備一個待發布的新版本原始碼。說明一下,這一步不是必須的,我是為了演示一下這個過程,所以故意把版本號改了。只要你的程式碼是有修改,未推送到git倉庫就行了。
2.通過copy命令將我們打包所需的檔案copy到一個獨立的資料夾中,方便打包。
命令列完整程式碼,這裡copy後的檔案結構和我們在nuget package explorer裡面是一樣的。
copy "$(SolutionDir)Nancy.FixQueryDictionary\bin\Release\Nancy.FixQueryDictionary.dll" "$(SolutionDir)\NugetPublish\Release\lib\Nancy.FixQueryDictionary.dll" copy "$(SolutionDir)Nancy.FixQueryDictionary\bin\Release\Nancy.FixQueryDictionary.xml" "$(SolutionDir)\NugetPublish\Release\lib\Nancy.FixQueryDictionary.xml" copy "$(SolutionDir)Nancy.FixQueryDictionary\bin\Release\Nancy.FixQueryDictionary.pdb" "$(SolutionDir)\NugetPublish\Release\lib\Nancy.FixQueryDictionary.pdb" copy "$(SolutionDir)README.md" "$(SolutionDir)\NugetPublish\Release\README.md"
3.在我們的專案中新建一個yml檔案,我這裡直接上我自己的yml檔案。
name: GitHub Actions on: push: branches: [ publish ] pull_request: branches: [ publish ] jobs: Explore-GitHub-Actions: runs-on: ubuntu-latest steps: - run: echo "該作業由${{github.event_name}}事件自動觸發" - run: echo "此作業現在正在GitHub託管的${{runner.os}}伺服器上執行" - run: echo "分支的名稱是${{github.ref}},儲存庫是${{github.repository}}" - name: 簽出儲存庫程式碼 uses: actions/checkout@v2 - run: echo "${{github.repository}}儲存庫已克隆到執行程式" - name: 列出儲存庫中的檔案 run: | ls ${{ github.workspace }} - name: 列出Release釋出的檔案 run: | ls NugetPublish/Release - name: 安裝nuget uses: nuget/setup-nuget@v1 with: nuget-version: '6.x' - name: 打包nuget package run: | nuget pack NugetPublish/Nancy.FixQueryDictionary.nuspec -OutputDirectory NugetPublish/Release/ - name: 新增Github源 run: | dotnet nuget add source --name github "https://nuget.pkg.github.com/OWNER/index.json" - name: 釋出到Github run: | dotnet nuget push NugetPublish/Release/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source "github" --skip-duplicate - name: 釋出到NuGet run: | dotnet nuget push NugetPublish/Release/Nancy.FixQueryDictionary.1.1.3.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate - run: echo "此作業的狀態為${{job.status}}"
Github工作流yml配置說明
下面就這個yml配置檔案做一下(其)簡(實)單(我)的(也)說(不)明(熟),我是經過了九九54次(見下圖)的嘗試,爬過坑,才最終實現想要的效果。
第一段是定義這個Action(工作流)的名稱,觸發的倉庫分支名稱。
name: GitHub Actions on: push: branches: [ publish ]#這個表示當程式碼推送到publish分支時觸發工作流執行
pull_request:
branches: [ publish ]#這個表示當程式碼合併推送到publish分支時觸發工作流執行(我猜的,等下我們驗證一下)
第二段,定義工作流的job,執行的系統環境,將當前倉庫名稱列印輸出。這些echo的內容並不是必須的,通過這些輸出你可以瞭解到有哪些內建的變數,這些變數通過${{}}來繫結輸出。每個獨立的動作前面都有一個 - ,如果是一個簡單的動作,這個短橫線是直接放在run前面,且有一個空格。
jobs: Explore-GitHub-Actions: runs-on: ubuntu-latest steps: - run: echo "該作業由${{github.event_name}}事件自動觸發" - run: echo "此作業現在正在GitHub託管的${{runner.os}}伺服器上執行" - run: echo "分支的名稱是${{github.ref}},儲存庫是${{github.repository}}"
這裡需要注意空格的數量,多了少了都會報錯,具體見下圖。具體的格式我也沒有仔細去研究,畢竟我們全宇宙第一的IDE會有格式糾錯提示。如果你直接在github上建立這個yml檔案並進行編輯的話,也是有糾錯提示的,多嘗試幾次就好了。
第三段,這一段表示將我們要用來打包的程式碼checkout(簽出),這裡的users是固定寫法(貌似是這樣的,我看好幾個都是這樣的)。後面的echo表示已經job已經執行到這裡了,程式碼已經簽出了。這就像我們在控制檯列印一些自定義的訊息一樣的。
- name: 簽出儲存庫程式碼 uses: actions/checkout@v2 - run: echo "${{github.repository}}儲存庫已克隆到執行程式"
第四段,這一段有兩個動作,用來顯示簽出的原始碼檔案列表和我們要打包的檔案列表。這個ls命令不就是Linux裡面檢視檔案目錄用的嗎?同樣的,這兩段也不是必須的。
- name: 列出儲存庫中的檔案 run: | ls ${{ github.workspace }} - name: 列出Release釋出的檔案 run: | ls NugetPublish/Release
第五段,安裝nuget打包工具,這個工具和我們在nuget.org網站下載的那個nuget.exe命令列工具應該是一樣的(我猜的)。
- name: 安裝nuget uses: nuget/setup-nuget@v1 with: nuget-version: '6.x'
第六段,使用nuget pack命令打包生成nuget package檔案,這個命令我們在nuget.exe執行是一樣的效果,見下圖。
後面的OutputDirectory用來指定輸出的目錄,可以使用相對路徑,不指定這個引數的話,會生成在當前目錄下。
- name: 打包nuget package run: | nuget pack NugetPublish/Nancy.FixQueryDictionary.nuspec -OutputDirectory NugetPublish/Release/
第七段,新增github源,引數name用來指定源的名稱,這個名稱下面會用到。說實話,我是沒搞懂,為啥要設定這個源。這個命令如果你在系統上執行,就是會在你nuget源中新增一個源地址,你可以在vs的nuget package管理器中檢視到這個源,也可以使用nuget命令nuget sources來檢視,見下圖。
- name: 新增GitHub源
run: | dotnet nuget add source --name github "https://nuget.pkg.github.com/OWNER/index.json"
第八段,這才是重點的一步,將nuget package釋出到github上。釋出完成之後,這裡會有顯示,見下圖。
點進去,是這樣的。
這裡使用nuget push命令來推送,引數api-key用來指定github的PAT(Personal access tokens),畢竟你在指令碼中總不能使用明文的github賬戶密碼吧,當然要使用令牌來訪問你的賬戶。引數source用來指定上面的github源,引數skip-duplicate用來指示當上傳已經存在的相同版本的nuget package時就跳過推送,否則會報錯。這裡最大的坑莫過於這個PAT了,坑的我不要不要的。
- name: 釋出到Github run: | dotnet nuget push NugetPublish/Release/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source "github" --skip-duplicates
申請PAT的流程如下所示:Settings>Developer settings>Personal access tokens
選擇 Generate new token,輸入token名稱,選擇有效期,選擇許可權。
我這裡簡單粗暴,直接選擇了永不過期+全部許可權(哈哈)。然後,你就可以得到一個PAT令牌了。原本我以為在指令碼中配置這個令牌應該是這樣的${{secrets.nuget_ApiKey}},結果呢,死活都不行,執行的過程中提示401。然而,我在nuget.exe中執行的時候,輸入的明文令牌是可以的。後來的後來,我才發現,這裡是要這樣寫才行。
${{ secrets.GITHUB_TOKEN }}
真的是坑的我不要不要的!!!你們說,如果我再弄個令牌,想換一個同時還保留這個,應該怎麼辦呢?我們也不知道,我們也不敢問,也不糾結了。
第九段,將nuget package推送到nuget.org,這裡需要配置nuget.org申請的ApiKey,怎麼申請?上一篇已經說過了,這裡我們需要將它作為變數配置在我們的github裡。配置過程,如下所示。
首先,開啟倉庫的Settings。
選擇Secrets,點選New repository secret,輸入ApiKey的名稱和ApiKey儲存即可。
然後,我們在指令碼中使用變數來繫結nuget的ApiKey。
- name: 釋出到NuGet run: | dotnet nuget push NugetPublish/Release/Nancy.FixQueryDictionary.1.1.3.nupkg --api-key ${{secrets.NUGET_API_KEY}} --source https://api.nuget.org/v3/index.json --skip-duplicate
第十段,用一個echo來輸出任務的狀態,檢視任務是否完成。
- run: echo "此作業的狀態為${{job.status}}"
至此,我們已經對yml有了大概的瞭解。當你在Github的Actions裡直接新建工作流yml檔案時,右邊會出現一些推薦的yml檔案,你可以直接點選將其加入到你的yml。甚至,官方還有一個工作流的yml市場,你可以尋找和使用別人已經寫好的各種工作流yml檔案,詳見https://github.com/marketplace?type=actions。工作流的文件地址https://docs.github.com/en/actions/learn-github-actions/creating-starter-workflows-for-your-organization
開始演示
接下來,我們把程式碼push到master分支,並將master合併到publish分支,以此來觸發工作流的job執行。下面,我們介紹如何在Github上進行分支合併。當然,你也可以選擇用git命令列操作或者用VS自帶的管理分支功能進行合併,我比較喜歡這種圖形化的操作,不容易出錯。在Github上進行分支合併,我也是第一次操作,以下操作基於個人的理解和實踐總結。
首先,找到你的倉庫中的Pull requests,點選New pull request。
base選擇publish,compare選擇master。意思就是將master分支合併到publish分支,如果你是publish合併到master,則選擇是相反,你懂得!如果版本之間無程式碼衝突的話,會顯示Able to merge。正常情況來說,這裡不會有衝突。因為我們修改的是master,然後合併到publish,不會單獨修改publish,自然不會衝突。如果出現衝突,自然是需要處理好衝突檔案的,有時間我來試一下github的衝突解決應該怎麼操作。
接下來,點選Create pull request,填寫一下合併原因,變動內容,再次點選Create pull request,即可完成分支合併提交。
這裡,我有個疑問:實際上到此,我們的程式碼已經合併推送到publish分支了,為什麼這裡還需要再次確認合併,有點多此一舉啊?知道的麻煩告訴我一聲,謝謝!
這時候,你開啟Actions,會發現工作流已經準備啟動了,有個黃色的點點標記了我們最新的一次提交。
點進去,可以發現工作流已經處於loading狀態,點選Explore-GitHub-Actions,可以檢視到工作流job每一步的執行過程。
我們可以看見工作流job已經都執行完成了,nuget package也已經成功推送到了github源和nuget.org源。
我們開啟nuget package的主頁,點選Versions,可以發現最新的版本1.1.3已經推送過來了,處於驗證狀態,幾分鐘後就會收到nuget package釋出成功的通知郵件。
我們的最新版nuget package版本也已經處於正常對外發布狀態了。
最後,我們在倉庫code頁面,右側找到Packages,可以發現已經顯示了我們在github源上釋出的nuget package。點進去,可以檢視nuget package的詳情。
至此,我們的nuget package通過工作流job自動打包自動釋出推送就完成了。可是我的疑問還是沒有得到解答,為什麼已經合併推送了程式碼,Pull requests裡還有一個Merge pull request呢?讓我們直接來點一下完事!
結果呢,它又觸發了工作流,job都重新來了一遍。由於推送的版本號已經存在,且push命令增加了相同版本號跳過的引數skip-duplicate,所以自動跳過了,沒有報錯。如果沒有設定引數skip-duplicate,推送已存在的版本號工作流則會報錯。
寫在最後
本文主要簡單介紹通過Github工作流,實現nuget package程式碼更新push到github倉庫後的自動打包,同時推送到github源及nuget源(CI/CD),還有github的分支合併操作簡單演示。對於我的疑問,歡迎大佬給予解答,在此謝過!