---
# System prepended metadata

title: 自動打包 nuget package (第二版)
tags: [' CD', CI, ' Nuget']

---

---
tags : CI, CD, Nuget
---
# 自動打包 nuget package (第二版)
2023/01/16 - 因現在的 Library專案都已經升級為 .Net Framework，為了精簡範例的內容，所以將 .Net Framework相關語法移除後，重寫一份新的說明文件。

自動打包的流程大致如下：

* 在 git上面打 tag並且 push回 remote
* 觸發 gitlab runner
* Builder server將 repos拉下來，執行 deploy.ps1
* Powershell script根據 tags決定要將哪一個專案重新建置，並且打上版號後 push到 nuget上面

為了實現這一套流程，我們需要再專案中新增幾個重要的檔案：

* .getlab-ci.yml - push後可以觸發 gitlab-runner
* deploy.ps1 - 用來執行編譯、打包跟上傳到 nuget的語法
* nuget.config - 透過這個檔案讓 nuget指令認得我們的 private nuget server


## 在專案中新增以下檔案

### .gitlab-ci.yml
``` yaml=
stages:
  - nuget_pack
  
# nuget_pack stage
nuget_pack:
  stage: nuget_pack
  only:
    # 只會被 tag觸發
    - tags
  tags:
    # builder server的 gitlan runner的名稱
    - windows
    - netframework
  before_script:
    # 編碼設定為 65001，避免 powershell輸出中文的時候變成亂碼 (只有對 powershell core有效)
    - chcp 65001
    - write-host "Override Before Script"
  script:
    # nuget restore，將專案所需的 package全部還原，這裡我們使用自己的 nuget.conig是為了避免全域的 config被改壞掉，導致 cide失敗
    - nuget restore -PackagesDirectory packages -configfile "nuget.config"
    - .\deploy.ps1 -tag $CI_COMMIT_TAG  
```
### nuget.config
```xml=
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="Microsoft and .NET"
         value="https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/" />
    <add key="ONElab"
         value="http://nuget.owdev.net/api/v2" />
  </packageSources>
</configuration>
```

### deploy.ps1
```shell=
param($tag)

$ErrorActionPreference = "Stop" # stop power shell script on the first error

# 將 tag "RefClient/4.4.1"拆成兩個 string，"RefClient"跟 "4.4.1"
# "RefClient"用來決定專案的位置跟 nuspec file名稱
# "4.4.1"用來決定打上去的版號
$tag_valiable = $tag.Split("/")
$project_name = $tag_valiable[0]
$version = $tag_valiable[1]

Write-Host $project_name
Write-Host $version

msbuild /p:Configuration=Release .\$project_name\$project_name.csproj /p:Version=$version
if ($LASTEXITCODE -ne 0)
{
    throw [System.Exception] "Build fail!"
}

nuget pack .\$project_name.nuspec -Version $version -Symbols
if ($LASTEXITCODE -ne 0)
{
    throw [System.Exception] "Nuget pack fail!"
}

nuget push *.symbols.nupkg -Source http://nuget.owdev.net/api/v2/package/ -ApiKey 3e43484a-5a7d-4e7c-bce2-db2560eef010
if ($LASTEXITCODE -ne 0)
{
    throw [System.Exception] "Nuget push fail!"
}
```

### Nuspec file

這份檔案是用來決定要打包進 nuget package的 package name、description、dependency、files。

**Required elements**有四個：
* id - 表示 package的名字
* versions - 上傳到 nuget上的版本號碼，因為我們會在打包時給予一組新的版號，所以這邊放 0即可
* description - 關於這個 package的說明
* authors - 作者  

**Optional elements**可以用來指定專案的相依性，在安裝 package時會連同 dependencies指定的專案一起安裝。  

**files node**是用來指定那些檔案會被封裝到 package中，一般來說會將 dll、pdb、xml一起打包，如果 library是由許多 project一起組成的，我們會選擇將相關專案一起包進來。
```xml=
<package >
    <metadata>
        <!-- Required elements-->
        <id>RefClient</id>
        <version>0</version>
        <description>Add Redis MiddleWare</description>
        <authors>Service Team</authors>

        <!-- Optional elements -->
		<dependencies>
			<dependency id="Microsoft.Extensions.Caching.Abstractions" version="5.0.0" />
			<dependency id="Newtonsoft.Json" version="12.0.1" />
			<dependency id="Microsoft.Extensions.Http" version="3.1.15" />
			<dependency id="Microsoft.Extensions.Caching.Memory" version="5.0.0.0" />
			<dependency id="LazyCache" version="2.4.0" />
			<dependency id="LanguageEnum" version="1.4.1" />
			<dependency id="StackExchange.Redis" version="2.2.4" />
		</dependencies> 
		
    </metadata>
    <!-- Optional 'files' node -->
	<files>	
		<file src="RefData.Common\bin\Release\netstandard2.0\RefData.Common.dll" target="lib\netstandard2.0" />
		<file src="RefData.Common\bin\Release\netstandard2.0\RefData.Common.pdb" target="lib\netstandard2.0" />
		<file src="RefData.Common\bin\Release\netstandard2.0\RefData.Common.xml" target="lib\netstandard2.0" />
		<file src="RefClient\bin\Release\netstandard2.0\RefClient.dll" target="lib\netstandard2.0" />
		<file src="RefClient\bin\Release\netstandard2.0\RefClient.pdb" target="lib\netstandard2.0" />
		<file src="RefClient\bin\Release\netstandard2.0\RefClient.xml" target="lib\netstandard2.0" />
	</files>
  
</package>
    
```
## 補充，令 MSBuild自動產生 nuget package
由於在 JetBrains Rider上面缺少以下的選項，所以這段落只用來記錄，沒有實際用在專案上面。
在專案上按右鍵，選擇 `Properties`，然後選擇 Package -> General，然後將 `Gemerate Nuget package on build`打勾，以及指定版號到 `Package Version`，最後將專案重建後即可得到打上版號的 nuget package(連同 dll也會有版號)。
![](https://i.imgur.com/nWGz6x3.png)
`Assembly version`和 `File version`只會將版號打在 dll上面，請不要選錯了。
![](https://i.imgur.com/vD8H1vq.png)



## Reference 
[.nuspec 參考](https://learn.microsoft.com/zh-tw/nuget/reference/nuspec#general-form-and-schema)