企业 NuGet:持续集成自动生成系统中的NuGet

[原文发表地址]NuGet for the Enterprise: NuGet in a Continuous Integration Automated Build System

[原文发表时间]2011-05-24 05:48 PM

clip_image003

很荣幸在上周召开的亚特兰大TechEd 2011 North America会上发言。你可以在Channel 9观看所有会议的所有视频。顺便提一句,你可能注意到在https://channel9.msdn.com/Events上,正在组织所有Microsoft开发者的事件视频档案。如果你喜欢的话,还可以通过https://channel9.msdn.com/Events/Speakers上的Speaker观看PDC 1999或会议。这是我所有的谈话,还有张可怕的头像,我打算请Duncan尽快替换。

我最喜欢的谈话是NuGet: Microsoft .NET Package Management for the Enterprise。我谈论了NuGet 除了TechEd谈话更多地关注NuGet怎样适应一个多样化企业(或者是大而无聊的公司,如果你喜欢这么说的话)环境的软件开发生命周期,其他就像几周前我在荷兰说的一样

这里是视频下载,或者你可以点击右边的幻灯片。

clip_image001幻灯片(无用)

clip_image001[1] MP4 (iPod, Zune HD)

clip_image001[2] 中等质量 WMV (低频,可移动设备)

clip_image001[3] 高质量 WMV (PC, XBox, MCE)

在前一个公司,我们用Subversion进行资源控制,用CruiseControl做连续集成(CI)。我认为用最新的免费(以及大部分免费)的工具建立一个类似的的系统是不错的。注意,你都可以用TFS做这一切,以及源代码和内部版本。稍后我会发帖。现在,我给你:

当推送到本地Orchard NuGet Gallery 服务器时, 对内部版本设置 NuGet ,把Mercurial用于Source Control JetBrains TeamCity用于Continuous Integration

是的,这是一个很长的H3流程,但这是描述性的,不是吗?这儿是总体思路:clip_image005

这当然不是NuGet独有的,因为NuGet只是一个构建伪像。在我任职的前一个公司,我们有几个东西超出这个构建。不仅DLL,还有一个ZIP文件,MSI安装程序,甚至完整配置和预备的虚拟机供销售人员使用并展示我们最新成果。你可以设置Continuous Integration系统,让其成为你喜欢的那么棒或那么简单。你要考虑哪些库和组件将会创建NuGet软件包。

另一个需要考虑的事情是日常(或者每个版本)的软件包与稳定的或者发布的软件包。在NuGet网站 为理解“-beta”转换和内在支持,有一些围绕稳定与不稳定的版本的讨论。现在,为你的版本考虑两个位置,一个是给每个版本,一个是给“被保佑”。对一些人来说,这可能意味着一个文件夹对应每日版本,而只有被保佑的才会连接到服务器。

这是我做的演示。你可以改变你想改变的,变成你最喜欢的工具。我会指出我已经遇到而你可能遇到的一些陷阱和问题。它不完美,但是我们正在朝正确的方向前进。

第0步-准备东西

其中的一些步骤是“确保X已安装”这样的,并且可能随时出现,所以不要认为步骤顺序非常关键。下面是我使用和安装的。

如果喜欢的话,给VS弄个NuGet,但至少要弄NuGet.exe命令行,放在你的路径下。

获取任何你想要的 SCM (Source Control Management)系统。我正在用Mercurial 和 TortoiseHg,因为它感觉像我习惯的Subversion。

安装TeamCity Continuous Integration Server。他们有个小团队的免费版本。

你可以为“可怜人的NuGet服务器”使用网络共享或本地文件夹,或者安装一个完全基于Orchard的NuGet Gallery。

o 安装Orcgard NuGet Gallery的完整(草稿)说明在docs.nuget.org上 很快我们会更新图片和更明确的细节。如果在这被卡住了,不用担心,用一个本地文件夹,或者甚至一个基本NuGet.Server 安装,像Phil向你展示如何创建它。

第一步 - 确定你的项目版本, 并且你可以建一个NuGet包(nupkg)

所有的这些我都是在一台笔记本上做的,但在公司里你可能摊得更开。做你高兴做的。

我做了个名为TechEdLibrary的很小的类库,确认它用如下MSBuild建立:

C:\dev\techedlibrary\TechEdLibrary>msbuild TechEdLibrary.csproj
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.225]
Copyright (C) Microsoft Corporation 2007. All rights reserved.
Build started 5/24/2011 4:52:54 PM.
..snip...
Done Building Project "C:\dev\techedlibrary\TechEdLibrary\TechEdLibrary.csproj"
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.13

最重要的部分是确保你的AssemblyInfo.cs 是真正文件出来而不仅仅是默认。这是因为我们想用来自DLL和项目的值更新NuGet的规范文件。基本上,我们想用项目的元数据来驱动NuGet包(否则我们不得不手动更新)。

我需要一个规范文件。我有几种方法来实现。我可以只用“nuget规范”手动完成,我可以从"nuget spec -assemblyPath bin\debug\techedlibrary.dll"产生的DLL结果构建,或者从"nuget spec techedlibrary.csproj"的csproject构建。

如果我从csproj构建,NuGet规范文件会有一些$标记$,这写标记在打包时会用文件显示出来。

C:\dev\techedlibrary\TechEdLibrary>nuget spec TechEdLibrary.csproj
Created 'TechEdLibrary.nuspec' successfully.

在TechEd的谈话上,我错误地从DLL创建,以硬编码这些版本为结束。在持续集成系统,你会想更新你的规范版本为编译版本。你可以像我在这一样用标记完成,也可以把版本(经常是从一个环境变量)传递到命令行,像"NuGet Pack -version 1.0.1.0"。

你也可以用很多年前Matt Griffith和我更新的UpdateVersion.exe改变你的AssemblyInfo.cs,这样NuGet包就可以获取它。再说一下,没有正确答案,关键是有策略。是什么驱动该版本,以及NuGet如何了解它

我刚做的TechEdLibrary.nuspec,它看起来这样:

  1: <?xml version="1.0"?>
  2: <package xmlns="https://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  3: <metadata>
  4: <id>$id$</id>
  5: <version>$version$</version>
  6: <authors>$author$</authors>
  7: <owners>$author$</owners>
  8: <iconUrl>https://www.hanselman.com/images/nugeticon.png
  9: </iconUrl>
  10: <requireLicenseAcceptance>false</requireLicenseAcceptance>
  11: <description>$description$</description>
  12: </metadata>
  13: </package>

我的AssemblyInfo.cs(删节的)是这样。来自DLL的属性会被复制到$标记$并打包。

  1: [assembly: AssemblyTitle("TechEdLibrary")]
  2: [assembly: AssemblyDescription("This is my cool library")]
  3: [assembly: AssemblyCompany("Scott Hanselman")]
  4: [assembly: AssemblyProduct("TechEdLibrary")]
  5: [assembly: AssemblyVersion("0.9.*")] //The * means I'll get an automatic version bump
  6: //and more...

现在,我可以用NuGet Pack TechEdLibrary.csproj将其打包。注意命令行输出找到规范并做标记/元数据替换了了吗?

C:\dev\techedlibrary\TechEdLibrary>nuget pack TechEdLibrary.csproj
Attempting to build package from 'TechEdLibrary.csproj'.
Building project for target framework '.NETFramework,Version=v4.0'.
Packing files from 'C:\dev\techedlibrary\TechEdLibrary\bin\Release'.
Using 'TechEdLibrary.nuspec' for metadata.
Successfully created package 'C:\dev\techedlibrary\TechEdLibrary\TechEdLibrary.0.9.4161.28882.nupkg'.

现在,我可以打开.nupkg 进入 the NuGet Package Explorer并查看版本,作者,ID(从Title)描述和版本全都在那里,从属性导入并与我的NuSpec结合。只要保持我想要的$标记$,我就可以凭喜好编辑NuSpec。

My package in the NuGet Package Explorer

现在如果我重新建立程序库,我会从.NET版本系统得到一个新的版本,这会导致一个新版本的新的NuPkg将被建立。我改变了我应用程序的源,重新建立,然后重新打包。注意:在我做出小更改,建立,打包之后目录中的结果。

C:\dev\techedlibrary\TechEdLibrary>msbuild TechEdLibrary.csproj
Microsoft (R) Build Engine Version 4.0.30319.1
Build started 5/24/2011 5:07:58 PM.
blah build blah
Done Building Project "C:\dev\techedlibrary\TechEdLibrary\TechEdLibrary.csproj" (rebuild target(s))
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.32
C:\dev\techedlibrary\TechEdLibrary>nuget pack TechEdLibrary.csproj
Attempting to build package from 'TechEdLibrary.csproj'.
Building project for target framework '.NETFramework,Version=v4.0'.
Packing files from 'C:\dev\techedlibrary\TechEdLibrary\bin\Release'.
Using 'TechEdLibrary.nuspec' for metadata.
Successfully created package 'C:\dev\techedlibrary\TechEdLibrary\TechEdLibrary.0.9.4161.29041.nupkg'
.
C:\dev\techedlibrary\TechEdLibrary>dir *.nupkg
05/24/2011 05:07 PM 4,770 TechEdLibrary.0.9.4161.28882.nupkg
05/24/2011 05:08 PM 4,763 TechEdLibrary.0.9.4161.29041.nupkg
2 File(s) 9,533 bytes

除了版本计划,规范文件和打包工作时的检查,没有真正设置任何东西,我在此就得到一个小系统,希望你可以看到它是怎么工作的。

怪诞提醒:我们确实有一个双重构建在运行。因为一些奇怪的原因,NuGet.exe 再次为我们运行MSBuild。那是有缺陷的,是个已经知道的错误。令人惊奇的是,.NET

和 Java世界的许多CI系统,“双重创建”很常见。有缺陷,但很常见。尽管如此,没有任何借口。它很快会在NuGet. Exe中被修复。

第二步 – 原始码登记

我喜欢在小型私人项目用BitBucket,公共开源项目用CodePlex。两个都支持Hg(Mercurial 中"Mercury"的元素符号),CodePlex支持Source and Work Items的TFS。因为我的演示是私人的,而BitBucket 支持无限制私人项目,这是个不错的选择。

我把我的项目URL从BitBucket复制到一个文件夹,然后添加,承诺,推送我的文件到BitBucket Site:

C:\dev\something>hg clone https://shanselman@bitbucket.org/shanselman/techedlibrary
...move my files in...
C:\dev\something>hg add
...yada yada yada...
C:\dev\something>hg commit
...yada yada yada...
C:\dev\something>hg push
...yada yada yada...

它很有用,以确保我能让我的源代码进入到另一个文件夹并建立。错过一两个文件是正常的。因为CI Server会把代码放入一个临时文件夹,你真正需要确保源会原样建立,直接从你的SCM里获取最新的。

第三步- 设置你的版本服务器

我在https://localhost:8111/上用同一台机器上的一个“版本代理”(可以有多个)本地运行TeamCity。访问 Administration ,做一个新项目,然后弄一个新 Build Configuration (像Debug 或者Release)。

你需要在TeamCity做一个VCS根(Version Control System-版本控制系统大约有60个不同缩写。如果你在其它地方看到你不认识的TLA(三个字母缩写),它的大概意思是TeamCity 中的“Source Control”)。注意我选择Mercurial并设置HG Command Path为到HG.EXE的完整路径,因为CI会调用它从BitBucket检测代码。也请注意在路径中我没用“导入变化”名字和密码,因为我把名字和密码放在稍下边了。

Editing a VCS Root in TeamCity

回到Administration,选择你项目下的Edit。注意右边不错的步骤清单。

The 7 steps in TeamCity

我们需要两步,一步是为MSBuild,一步是为NuGet包的“自定义命令行”。第一步很简单,我们在TechEdLibrary.csproj 调用MSBuild。

第二步是暂时的黑客。说暂时是因为JetBrains TeamCity 正在直接建立NuGet支持 (内部构建屏幕截图如下!)

TeamCity Custom Scripts

自定义脚本基本上是一个批处理文件,看起来这样:

del *.nupkg

NuGet pack techedlibrary.csproj

forfiles /m *.nupkg /c "cmd /c NuGet.exe push @FILE yourapikey -source https://localhost:81/

这里还有一些有趣的事情。

首先,我删除CI文件夹中的所有nupkg文件,因为它是暂时的,我们不想不小心推出旧东西。

其次,就像我们先前看到的那样,我整理了NuGet包。

最后,我不知道新建的*.nupkg文件名,所以我通过做一个DOS 批处理“循环”来欺骗,它只有一个项目,新建的nupkg文件!然后我调用cmd.exe用新文件作为参数执行NuGet.exe。确保你有尾部的反斜杠。

注意:你也可以用NuGet SetApiKey yourapikey-source https://localhost:81在本地存储保存API Key,并且它会以每个源的基础保存。

因为我有个本地运行的Orchard NuGet Gallery,所以我有个服务器的API key。我在81端口本地运行我的gallery服务器(它持有软件包,服务OData Feed), Orchard Site本身在80端口。

My personal NuGet Gallery

我设置版本每60秒检查Source Control,如果检测到变化,源就会被检索,构建,然后打包NuGet,并发布到我的本地服务器(或者公用服务器)。

TeamCity是我喜欢在我周围得到的额外硬件上运行的东西。你可以有多达20个免费版本的项目,所以当与我保存项目的BitBucket 和CodePlex结合时,我可以在几个小时内设置我的持续集成系统,并且对我的代码也更有信心。你甚至可以用Amazon EC2镜像运行你的版本或者只是一个版本代理。

预览 – 集成NuGet的TeamCity

我继续与对NuGet狂热的公司和软件供应商谈话。如果你是其中一员,观看我的讲座的想法,作为商业软件实体你可以做什么,并参与关于CodePlex的讨论。

这是一些JetBrains正在为TeamCity计划的模型。这只是想法,还不可用,所以不要紧张 。;)

这是TeamCity中可能的Build Step的一个NuGet模型。

This is a mockup of NuGet as a possible Build Step within TeamCity.

这是Build Feature的一个模型,在这TeamCity下载版本需要的具体软件包。

Here's a mockup of a Build Feature where TeamCity downloads specific packages that will be needed by the build.

这是TFS团队的Martin Woodward早期工作的屏幕截图,团队的工作是确保NuGet 和 Team Foundation Server在持续集成系统环境中协同运作良好。欢迎通过他的博客联系Martin,并在https://nuget.codeplex.com上继续讨论。

TFS and NuGet

不管喜欢与否,希望这有助于你将NuGet融入到贵公司。