前言
由于公司的开发人员越来越多,每个人负责的自己模块开发,需要频繁的提交与发布qa和uat环境,那么搭建持续集成环境就显得十分必要。网上关于持续集成的解释非常多,这边不再多做阐述。对于我来说,我要实现的目的就是,开发人员提交代码到开发分支之后,我把代码合并到qa和uat分支,剩下的事情就交给程序,由程序自动构建发布,从而节省因为频繁的手动构建发布程序的时间,可以将时间用在更有价值的事情上。
关于MSBuild
MSBuild全名Microsoft Build Engine。MSBuild为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。 Visual Studio 会使用 MSBuild,但它不依赖于 Visual Studio。MSBuild 项目文件的格式使开发人员能够充分描述哪些项需要生成,以及如何利用不同的平台和配置生成这些项。另外,项目文件的格式还使开发人员能够创作可重用的生成规则,这些规则可以分解到不同的文件中,以便可以在产品内的不同项目之间一致地执行生成。
MSBuild安装
1.有两种方式可以安装MSBuild
-
直接安装Visual Studio,在安装路径下便能找到MSBuild ,比如我的vs安装在D盘,那么MSBuild的路径就在
D:\Program Files\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin
直接到官网下载MSBuild,下载 MSBuild 且不使用 Visual Studio,向下滚动到"Visual Studio 2019工具",然后选择"Visual Studio 2019 生成工具"
2.将上面的路径添加环境变量
以上两步完成之后,便可以在命令行中进入到对应的程序目录,找到项目的.csproj文件,然后通过msbuild命令来生成,并根据自己的需要,可以传入不同的参数,例如:
msbuild xxxx.csproj /p:Configuration=Debug
注意:是否有安装MSBuild对于接下来的Jenkins来说并不是必要的,Jenkins需要安装自己的MSBuild插件。
Project file
MSBuild使用基于 XML 的项目文件格式,如果有打开看过项目.csproj文件,便可以对这个文件的格式有一点的了解。我们可以根据不同的需求在这个文件里面描述项目要生产的项,并构造成我们想要的目录结构等。一个项目文件的内容应该类似于以下代码:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>MSBuildSample</AssemblyName>
<OutputPath>Bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="helloworld.cs" />
</ItemGroup>
<Target Name="Build">
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
</Target>
<Target Name="Clean" >
<Delete Files="$(OutputPath)$(AssemblyName).exe" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>
在这个文件里面我们可以定义和使用变量(通过Property/PropertyGourp/Item/ItemGroup等元素),可以使用条件分支(通过Choose/When/Otherwise等元素)、能够在运行时给变量赋值(通过执行任务,获取其返回类型参数的方式)、能够定义执行块(通过Target元素,相当于函数)、能够进行异常处理(通过OnError元素)、还可以复用已有工程定义的内容(通过Import元素)。
Properties(属性)
属性以键/值对的方式来定义,主要用于声明生成解决方案的过程所需要的各种参数,如生成路径或者是解决方案配置等等。 属性的声明方式是:创建一个与属性同名的元素,将其指定为 PropertyGroup 元素的子元素。 例如,下面的代码将创建一个名为 OutputPath
的属性,其值为 Bin\
。
<PropertyGroup>
<OutputPath>Bin\</OutputPath>
</PropertyGroup>
通过在属性中加入Condition
还可以有条件的定义属性,在下面的示例中,假如在使用项目文件的时候,未传入Configuration
的值的话,则默认使用Debug
,
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
那么,在接下来的整个项目文件里面,可以使用语法$(PropertyName)
來引用各个属性。例如使用$(OutputPath)
和$(Configuration)
来引用上面定义的两个属性。
Item(项)
Item用来标识项目的引用资源及、源代码文件或者程序集名称等等。可以使用语法@(ItemType)
来引用项类型。同理,类似于PropertyGroup
,可以把相关的Item放在一个ItemGroup
里面。
例如以下代码,Reference标识了项目的依赖库,而Compile声明了需要编译生成的源代码文件。
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="IntagramTagGet.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Target(目标)
Target表示一个需要完成的虚拟的任务单元。每个Project可以包括一个或多个Target,从而完成一系列定制的任务。你需要给每个Target设置一个Name属性(同一Project下的两个Target不能拥有同样的Name)以便引用和区别。
举例来说,在你的项目生成过程中可能需要完成三个阶段的任务:首先check-out源代码,接下来编译这些代码并执行单元测试,最后把它们check-in。那么通常情况下你可以创建三个不同的Target以清晰划分三个不同的阶段:
<Target Name=”CheckOut” ></Target>
<Target Name=”Build” DependsOnTargets=”CheckOut”>
<Task Name=”Build”.../>
<Task Name=”UnitTest” ... />
</Target>
<Target Name=”CheckIn” DependsOnTargets=”CheckOut;Build”>
</Target>
这样,你就可以非常清晰地控制整个生成过程。为了反应不同Target之间的依赖关系(只有Check-in后才能编译,只有编译完成才可能Check-out……),你需要设置Target的DependsOnTargets属性(注意是复数),以表示仅当这些Target执行完成之后才能执行当前的Target。当MSBuild引擎开始执行某项Target时(别忘了Project的DefaultTargets属性),会自动检测它所依赖的那些Target是否已经执行完成,从而避免因为某个生成环节缺失而导致整个生成过程发生意外。
你可以通过Project的DefaultTargets属性指定MSBuild引擎从哪(几)个Target开始执行,也可以在调用MSBuild.exe时使用t开关来手动指定将要运行的Target,方法如下:
MSBuild /t:CheckOut 这样,只有CheckOut(以及它所依赖的Target,在上文中没有)会被执行。
Task(任务)
这可能是整个项目文件中最重要的,因为它才是真正可执行的部分。可以在Target下面放置多个Task来顺序地执行相应的任务。
参考: