持续集成之 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,一经查实,立即删除!

相关文章

做“是非题”的正确姿势

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

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

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

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

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

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

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

负载均衡及负载均衡器

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

VS Code 摸鱼插件开发小记

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

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

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

Exceptionless使用介绍

一.Exceptionless介绍Exceptionless专注于.net平台提供实时错误和日志报告。主要包括:错误通知、智能分组异常、详细错误报告堆栈跟踪、支持离线、UI查看重要错误和确定优先级、仪表板上的统计信息和趋势、对异常标记为已修复,监视回归、将事件标记为关键…

Net Core DocXCore 实现word模板导出

实际工作中,往往有这样的需求,需要导出word,还有各种各样的样式,于是有了word模板导出。实现以下几个需求:1、表单导出2、表格导出3、表单表格混合导出4、实际用例测试解决方案:实现是基于NET Core 2.1 &am…

密钥分离,.Net程序猿不再背锅

引言互联网每隔一段时间就会爆出 【某程序猿在代码托管平台上传了公司机密配置信息,导致公司核心数据被黑客获取或修改】, 一茬又一茬背锅侠层出不穷。拯救自我软件工程理论早以加粗字体给出 经典原则:Never store production passwords or o…

Chrome让人失望,是时候转到Firefox或Edge?

我们曾报道过谷歌正在移除 Chrome 的关闭其他选项卡,这引起很多用户的讨论,很多用户表现出对 Chrome 浏览器的失望。而在国外,也有很多人认为谷歌这项修改使 Chrome 变得越来越臃肿。还有前段时间,谷歌在 Chrome 76 中隐藏了 “ht…

我认真写下9段如翔一般的代码,只为等你来品鉴

溪源 | 长沙.NET技术社区开篇我们总是很容易就能写出满足某个特定功能的代码,却很难写出优雅代码。又最欣赏那些优雅的代码,因为优雅代码更能体现一个开发者的积累。就像写一篇散文,有的就像初学者不得其门而入,遣词造句都非常困难…

「标签管理」用数据管理思维去管理你的日常电子化资料、文件、笔记等

最近一时兴起,研究了一些文件管理的方法论和笔记管理类的知识,自己想到一些不错的方法及落地方案,可能对一部分朋友来说,这些方法和工具的落地会有一些共鸣,故简单给大家做一下分享。跨界应用:数据表结构应…

Java之JMS

一:JMS简介   JMS即Java消息服务(Java Message Service),是一个Java平台定义的关于面向消息中间件的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。JMS是一个与具体平台无…

程序员过关斩将--更加优雅的Token认证方式JWT

点击上方“蓝字”带你去看小星星菜菜,上次你讲的cookie和session认证方式,我这次面试果然遇到了结果怎么样?结果面试官问我还有没有更好的方式?看来你又挂了别说了,伤心呀。到底还有没有更好的方式呢?你猜&…

Java之JMX

JMX,即Java Management Extensions,Java管理扩展。是一个为应用程序、设备、系统等植入管理功能的框架。   JMX提供了一种简单、基础的方法,用来管理应用、设置、服务等资源。由于JMX是动态的,你可以使用JMX技术来监控和管理处于…

[NewLife.XCode]分表分库(百亿级大数据存储)

NewLife.XCode是一个有15年历史的开源数据中间件,支持netcore/net45/net40,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中&#xf…

你的技术债还了吗?

什么是技术债?技术债是由沃德坎宁安在1992年提出,指我们在软件架构或代码编写过程中有意无意地做了错误的决策。随着时间的累积,这种错误会越来越多,就像背负了很多债务一样。技术债的危害技术债同财务债一样,是有利息…

拿 C# 搞函数式编程

最近闲下来了&#xff0c;准备出一个 C# 搞 FP 的合集。本合集所有代码均以 C# 8 为示例。可能你说&#xff0c;为什么要这么做呢&#xff1f;回答&#xff1a;为了好玩。另外&#xff0c;意义党们请 gun cu ke&#xff01;C# 有委托&#xff0c;而且有 Func<> 和 Action…

CNCF发布K8s项目历程报告,35k贡献者有你吗?

云原生计算基金会 CNCF 首次发布了 Kubernetes 项目历程报告。Kubernetes 托管于 CNCF&#xff0c;它是目前使用最广泛的容器编排平台&#xff0c;通常被称为“云端 Linux”&#xff0c;CNCF 介绍此报告旨在客观地评估 Kubernetes 项目的状态以及 CNCF 如何影响 Kubernetes 的发…