持续集成之 Nuget 进阶

持续集成之 Nuget 进阶

Intro

之前介绍了一篇基于 Azure pipeline 的 nuget 包的持续集成配置,但是比较粗糙,这里介绍一下结合 Cake 实现更优雅的 nuget 包发布流程。

实现目标:

  1. 分支(除master/preview)有代码 push 或者 pr 时 自动 build

  2. preview 分支有代码 push 的时候将 build 并将发布 preview 版的 nuget 包

  3. master 分支有代码 push 的时候将 build 并将发布稳定版的 nuget 包

什么是Cake?为什么要使用 Cake?

Cake 是C# Make的缩写,是一个基于C# DSL的自动化构建系统。它可以用来编译代码,复制文件以及文件夹,运行单元测试,压缩文件以及构建Nuget包等等。

熟悉大名鼎鼎的Make的小伙伴,应该已经知道Cake大致是个什么样的工具了,Cake具有以下几个特点:

  1. 方便编写:使用基于C#的DSL,非常易于编写自动化的脚本。

  2. 跨平台: 基于Roslyn和Mono来编译我们写的自动化脚本,使得它可以运行在windows,linux,mac上。

  3. 可靠的:可以建立在自己的机器上,也可以建立在像AppVeyor,TeamCity,TFS,VSTS或Jenkins这样的CI系统上,都可以以相同的方式运行。

  4. 丰富的工具集:支持MSBuild,MSTest,xUnit,NUnit,Nuget,ILMerge,Wix和SignTool等等,以及支持丰富的插件(Cake Addins)。

  5. 开源:基于MIT开放源代码(Cake on Github),并且是.NET 基金会支持的一个项目(Cake on dotnet foundation)。

最初做自动化发布的时候自己尝试去写 powershell 和 bash shell 脚本,但是写的多了一点会发现,很多语法不太一致,往往写一个功能要写一个 powershell 脚本 再写一个 bash shell 脚本,徒然增加自己的工作量,而且有时候会发生一些奇怪的问题,在Windows上的路径和Linux的路径有时候会不同,使用了 Cake,我们就只需要专注于脚本要执行的过程,不需要关注 powershell 和 bashshell 的不同,不需要太多关注于 windows 和 linux 的差异。

  • Cake 文档

  • Cake api

使用 Cake

Cake 有 Visual Studio Code 插件,可以基于 VSCode 来编辑 cake 脚本

Cake 脚本示例

cake 主要文件:

  • build.ps1/build.sh 启动脚本,build.ps1 为 Windows 系统上要执行的 powershell 脚本,build.sh 为 *nix 上要执行的 shell 脚本

  • build.cake 实际执行的脚本,定义各种 build 需要的 task

  • tools/packages.config 启动脚本需要的 nuget 包

添加 cake 支持之后,你可能需要修改 .gitignore,官方推荐的 gitignore 是这样的

tools/**	
!tools/package.config

实际使用下来,即使没有 package.config 也是可以正常工作的,可以简化为一条

tools/**

示例项目

这里以我的一个个人开源项目 WeihanLi.Redis 为例

cake 脚本

///	
// ARGUMENTS	
///	
var target = Argument("target", "Default");	
var configuration = Argument("configuration", "Release");	
var solutionPath = "./WeihanLi.Redis.sln";	
var srcProjects  = GetFiles("./src/**/*.csproj");	
var testProjects  = GetFiles("./test/**/*.csproj");	
var artifacts = "./artifacts/packages";	
var isWindowsAgent = (EnvironmentVariable("Agent_OS") ?? "Windows_NT") == "Windows_NT";	
var branchName = EnvironmentVariable("BUILD_SOURCEBRANCHNAME") ?? "local";	
///	
// SETUP / TEARDOWN	
///	
Setup(ctx =>	
{	// Executed BEFORE the first task.	Information("Running tasks...");	PrintBuildInfo();	
});	
Teardown(ctx =>	
{	// Executed AFTER the last task.	Information("Finished running tasks.");	
});	
///	
// TASKS	
///	
Task("clean")	.Description("Clean")	.Does(() =>	{	var deleteSetting = new DeleteDirectorySettings()	{	Force = true,	Recursive = true	};	if (DirectoryExists(artifacts))	{	DeleteDirectory(artifacts, deleteSetting);	}	});	
Task("restore")	.Description("Restore")	.Does(() => 	{	foreach(var project in srcProjects)	{	DotNetCoreRestore(project.FullPath);	}	});	
Task("build")    	.Description("Build")	.IsDependentOn("clean")	.IsDependentOn("restore")	.Does(() =>	{	var buildSetting = new DotNetCoreBuildSettings{	NoRestore = true,	Configuration = configuration	};	foreach(var project in srcProjects)	{	DotNetCoreBuild(project.FullPath, buildSetting);	}	});	
Task("test")    	.Description("Test")	.IsDependentOn("build")	.Does(() =>	{	var testSettings = new DotNetCoreTestSettings{	NoRestore = true,	Configuration = configuration	};	foreach(var project in testProjects)	{	DotNetCoreTest(project.FullPath, testSettings);	}	});	
Task("pack")	.Description("Pack package")	.IsDependentOn("test")	.Does(() =>	{	var settings = new DotNetCorePackSettings	{	Configuration = configuration,	OutputDirectory = artifacts,	VersionSuffix = "",	NoRestore = true,	NoBuild = true	};	if(branchName != "master"){	settings.VersionSuffix = $"preview-{DateTime.UtcNow:yyyyMMdd-HHmmss}";	}	foreach (var project in srcProjects)	{	DotNetCorePack(project.FullPath, settings);	}	PublishArtifacts();	});	
bool PublishArtifacts()	
{	if(!isWindowsAgent)	{	return false;	}	if(branchName == "master" || branchName == "preview")	{	var pushSetting =new DotNetCoreNuGetPushSettings	{	Source = EnvironmentVariable("Nuget__SourceUrl") ?? "https://api.nuget.org/v3/index.json",	ApiKey = EnvironmentVariable("Nuget__ApiKey")	};	var packages = GetFiles($"{artifacts}/*.nupkg");	foreach(var package in packages)	{	DotNetCoreNuGetPush(package.FullPath, pushSetting);	}	return true;	}	return false;	
}	
void PrintBuildInfo(){	Information($@"branch:{branchName}, agentOs={EnvironmentVariable("Agent_OS")}	BuildID:{EnvironmentVariable("BUILD_BUILDID")},BuildNumber:{EnvironmentVariable("BUILD_BUILDNUMBER")},BuildReason:{EnvironmentVariable("BUILD_REASON")}	");	
}	
Task("Default")	.IsDependentOn("pack");	
RunTarget(target);

我这里使用 Azure pipeline 来实现持续集成,上面的里面有一些Azure pipeline 的变量,实际执行 build.ps1 脚本

Azure pipeline config

trigger:	
- '*'	
pool:	vmImage: 'vs2017-win2016'	
steps:	
- script: dotnet --info	displayName: 'dotnet info'	
- powershell: ./build.ps1	displayName: 'Powershell Script'	env:	Nuget__ApiKey: $(nugetApiKey)	Nuget__SourceUrl: $(nugetSourceUrl)

nugetApiKey 是比较敏感的信息,在 Azure Pipeline 里的 Variables 的 Secret 变量,这里需要转换一下,不然,直接从环境变量读取是读取不到的,详细参考:https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch&viewFallbackFrom=vsts#secret-variables

通过以上脚本可以本文开篇提到的目标:

  1. 分支(除master/preview)有代码 push 或者 pr 时 自动 build

  2. preview 分支有代码 push 的时候将 build 并将发布 preview 版的 nuget 包

  3. master 分支有代码 push 的时候将 build 并将发布稳定版的 nuget 包

preview 和 master 分支可以设置 branch policy,设置只能由 pull request 合并,不能直接 push 代码,如果必须要先发布 preview 再发布稳定版 nuget 包,可以添加自定以限制,限制 master 分支的代码只能从 preview 分支通过 pr 合并

Reference

  • https://www.cnblogs.com/linianhui/p/cake-overview.html

  • https://www.cakebuild.net/

  • https://github.com/cake-build/cake

  • https://github.com/WeihanLi/WeihanLi.Redis

  • https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch&viewFallbackFrom=vsts#secret-variables

640?wx_fmt=jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/313948.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

#3771. Triple(生成函数 + 容斥)

#3771. Triple 考虑只有一个损失时,损失值的生成函数为A(x)A(x)A(x)。 如果不考虑无序方案,有两个损失的生成函数为B(x)A(x)A(x)B(x) A(x)A(x)B(x)A(x)A(x),同理有三个的时候C(x)A(x)A(x)A(x)C(x) A(x)A(x)A(x)C(x)A(x)A(x)A(x)。 考虑如…

计数质数

题目描述 统计所有小于非负整数 n 的质数的数量。 示例: 输入: 10 输出: 4 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。解法 思路1:暴力法 /***暴力法* 时间复杂度O(n2)* 空间复杂度(O(1))* param n* return*/ public int countPrimes(int n) {if(n&…

做“是非题”的正确姿势

这里是Z哥的个人公众号每周五11:45 按时送达有时也会有感而发,来加个餐~我的第「107」篇原创敬上大家好,我是Z哥。这两天中国男篮的事,让我有感而发。不知道你有没有留意到,我们身边总有类似下面这样的事情…

3的幂

题目描述 给定一个整数,写一个函数来判断它是否是 3 的幂次方。 示例 1: 输入: 27 输出: true示例 2: 输入: 0 输出: false示例 3: 输入: 9 输出: true示例 4: 输入: 45 输出: false进阶: 你能不使用循环或者递归来完成本题吗? 解法1&a…

E. The Child and Binary Tree(生成函数 + 多项式)

E. The Child and Binary Tree 不难写出一个递推式fn∑i1ngi∑j0n−ifjfn−i−jf_n \sum\limits_{i 1} ^{n}g_i \sum\limits_{j 0} ^{n - i}f_jf_{n - i - j}fn​i1∑n​gi​j0∑n−i​fj​fn−i−j​,其中gig_igi​表示ccc中有没有iii这个数。 设F(x)F(x)F(x)…

依赖倒置原则(DIP)、控制反转(IoC)、依赖注入(DI)(C#)

象的控制权交由配置文件控制,然后根据配置文件中的信息(程序集类型),通过反射来获取对象,而不是直接new对象,这也是控制反转的一种体现。IoC容器会连接程序中的所有模块,模块将所需对象的控制权…

汉明距离

题目描述 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 给出两个整数 x 和 y&#xff0c;计算它们之间的汉明距离。 注意&#xff1a; 0 ≤ x, y < 231. 示例: 输入: x 1, y 4输出: 2解释: 1 (0 0 0 1) 4 (0 1 0 0)↑ ↑上面的箭头指…

P3978 [TJOI2015]概率论(生成函数)

P3978 [TJOI2015]概率论 设fif_ifi​表示节点数为iii的二叉树有多少&#xff0c;gig_igi​表示节点数为iii的二叉树有多少叶子节点。 fn∑i0n−1fifn−1−if_n \sum\limits_{i 0} ^{n - 1}f_if_{n - 1 - i}fn​i0∑n−1​fi​fn−1−i​&#xff0c;f01f_0 1f0​1。 对于g…

四种为HttpClient添加默认请求报头的解决方案

HttpClient在Web调用中具有广泛的应用&#xff0c;而为它添加默认请求头是我们经常遇到的需求&#xff0c;本文介绍4种为HttpClient添加默认请求头的方式。直接在创建的HttpClient对象的DefaultRequestHeaders集合中添加报头。class Program{static Task Main()> SendAsync…

Java位运算

java中位运算^,&,<<,>>,<<<,>>>总结 1.^(亦或运算) &#xff0c;针对二进制&#xff0c;相同的为0&#xff0c;不同的为1 public static void main(String[] args) {System.out.println("2^3运算的结果是 :"(2^3));//打印的结果是…

#3456. 城市规划(生成函数,多项式求逆)

#3456. 城市规划 设fnf_nfn​为nnn个点的的点的简单无向连通图数目&#xff0c;gng_ngn​为nnn个点的简单无向图个数&#xff08;不要求联通&#xff09;。 对于gng_ngn​显然有gn2n(n−1)2g_n 2 ^{\frac{n(n - 1)}{2}}gn​22n(n−1)​&#xff0c;共有n(n1)2\frac{n(n 1)}…

【盛派内部分享资料】本期主题:使用JavaScript HTML CSS构建跨平台桌面应用

先上录制视频友情提示&#xff1a;如果公众号内视频无法显示高清视频&#xff0c;您也可以在小程序内观看高清视频&#xff0c;点击下方按钮观看&#xff1a;【盛派内部分享资料】本期主题&#xff1a;使用JavaScript HTML CSS构建跨平台桌面应用本次活动由盛派技术人员伏允坤主…

负载均衡及负载均衡器

负载均衡在分布式系统中&#xff0c;负载均衡&#xff08;load balancing&#xff09;是一种有效的将网络请求分配到多个服务器的过程。通过将负载进行负载均衡&#xff0c;可以有效地改进系统响应时间&#xff0c;提高系统的可用性。随着系统变的愈发复杂&#xff0c;用户增多…

Sequence II (HDU 5919)(主席树)

Sequence II 题目大意是有mmm次询问&#xff0c;每次询问一段区间[l,r][l, r][l,r]&#xff0c;从左到右&#xff0c;如果这个数是在这个区间第一次出现&#xff0c;则记录下其下标&#xff0c; 我们会得到一个新的数组&#xff0c;要求这个数组的中位数是什么。 考虑使用主…

VS Code 摸鱼插件开发小记

插件地址&#xff1a;https://marketplace.visualstudio.com/items?itemNamebugbreeder.vscode-readhub原文链接&#xff1a;https://github.com/alex-yh99/vscode-readhub/blob/master/docs/develop-note.md一、关于插件在 VSCode 中快捷查阅科技动态、开发者资讯等 Readhub …

帕斯卡三角形杨辉三角

给定一个非负整数 numRows&#xff0c;生成杨辉三角的前 numRows 行。 在杨辉三角中&#xff0c;每个数是它左上方和右上方的数的和。 示例: 输入: 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1] ]解法 思路1&#xff1a;循环遍历 public List<List<Integer>…

ICPC 南昌现场赛 K:Tree(dsu on tree + 动态开点线段树)

Tree 让我们找满足一下五个条件的(x,y(x, y(x,y)点对有多少&#xff1a; x≠yx \neq yx​yxxx不是yyy的祖先yyy不是xxx的祖先dis(x,y)≤kdis(x, y)\leq kdis(x,y)≤kzzz是x,yx, yx,y的最近公共祖先&#xff0c;valuexvaluey2valuezvalue_x value_y 2value_zvaluex​valuey…

缺失数字

题目描述 给定一个包含 0, 1, 2, …, n 中 n 个数的序列&#xff0c;找出 0 … n 中没有出现在序列中的那个数。 示例 1: 输入: [3,0,1] 输出: 2示例 2: 输入: [9,6,4,2,3,5,7,0,1] 输出: 8解法 思路1&#xff1a;使用额外数组存储0~n&#xff0c;遍历数组&#xff0c;缺失…

9月数据库排行:Microsoft SQL Server分数罕见下滑

DB-Engines 数据库流行度排行榜 9 月更新已发布&#xff0c;排名前二十如下&#xff1a;明显能看出来&#xff0c;整体排名和上个月的保持一致。而上个月出现分数下跌的 PostgreSQL 和 MongoDB 终于“回归正道”&#xff0c;分数有了稍微的上升。与上个月相比&#xff0c;Postg…

P4175 [CTSC2008]网络管理(树状数组套主席树)

P4175 [CTSC2008]网络管理 每次询问两点间的第kkk大&#xff0c;考虑建立nnn棵主席树&#xff0c;每棵主席树记录的是从根节点到当前节点的状态&#xff0c; 由于主席树是一种类似前缀和的数据结构&#xff0c;可以使用差分的方式得到(u,v)(u, v)(u,v)点对之间的主席树为uv−…