在MSBuild中使用Task实现自动引用指定版本的NuGet包

需求背景:

桌面应用程序NeverForm依赖于MoreFramework。MoreFramework在维护过程中会经常性地升级版本号 e.g. 从1.00.001.01升级到1.01.022.02 最后两位是build计数。

NeverForm使用CruiseControl.NET来实现持续集成。对MoreFramework的引用有一部分通过MSBuild脚本实现:

-使用NuGet从 指定目录 获取 package.config中指定版本 的 MoreFramework的nuget包 e.g. MoreFramework.1.01.022.02.nupkg

-NuGetInstall指令会把MoreFramework.1.01.022.nupkg编译成dll文件,并安装到packages目录 e.g. \NeverFormSource\packages\MoreFramework.1.01.022.02.nupkg\lib\net40\MoreFramework.dll

-NeverForm对MoreFramework的引用添加是在工程文件里实现的 e.g.NeverForm.csproj。也就是在visual studio里添加引用。这里没有使用MSbuild脚本。

当MoreFramework升级版本号时,目前的流程是:

1)修改package.config文件,将版本号从1.00.001.01改为1.01.022.02 。

<?xml version="1.0" encoding="utf-8"?>
<packages>
   <package id="MoreFramework" version="1.01.022.02" targetFramework="net471" />
</packages>

2)删除文件夹NeverFormSource\packages\MoreFramework.1.00.001.01。

3)新建文件夹NeverFormSource\packages\MoreFramework.1.01.022.02\lib\net40(直接修改文件夹名字也可,但是大多数情况我们都要上传代码,删除+新建更方便trace。)

4)将MoreFramework.dll拷贝到上述新建的文件夹中。

5)在打开NeverForm工程,visualstudio里重新添加对MoreFramework的引用,因为路径变了,所以引用要重新添加。

6)上传代码:package.config+新建的文件夹+修改引用后的工程文件。

7)在CruiseControl.NET中build。

上述流程中2,3,4步骤,完全是为了让重新指定MoreFramework的引用路径。packages文件夹的内容正常都是NuGet生成的。很明显这是一个笨拙的操作。

既然使用了CruiseControl.NET,那么像引用这种操作当然应该在MSBuild里添加,尽可能少的依赖csproj文件,甚至完全脱离它。

可是MoreFramework的路径是随着版本升级而变化的。不可能每次升级都去修改ReferencePath。

有一种解决办法是:

不使用NuGet,而是指定一个固定目录作为ReferencePath。将所有引用的dll都放到这个目录,然后在MSBuild中添加引用。每次升级直接用新的dll覆盖掉旧的就可以了。

这是一个比较常规的做法,很多引用的第三方API都可以这样处理。

但是对于有版本号管理的,公司内部开发的framework,这样简单的做法就会丢失版本号信息。开发者无法从代码层面trace framework的升级轨迹。

换句话说,如果能减少繁琐多余的操作,当然是使用NuGet来管理framework更好。

解决方案:

在NuGetInstall完成后,我们需要msbuild去读取package.config文件,根据读取到的版本号,返回引用路径,然后将该路径下的MoreFramework添加到引用中。

下面是NuGetInstall的MSBuild脚本:

<Target Name="NuGetPackages">
        <CreateItem
              Include="$(SourcePath)\packages.config">
        <Output
            TaskParameter="Include"
            ItemName="PackageConfigs"/>
        </CreateItem> 
        
        <NuGetInstall Package="%(PackageConfigs.FullPath)" OutputDirectory="$(SourcePath)\Packages" ToolPath="D:\Build\Tools" Source="D:\Binaries\NuGet"/>
</Target> 

 使用Task:

<Import Project="$(BuildTools)\Build.Tasks.Never.targets" />

<Target Name="BuildVersion">
     <GetPackageVersionTask PackageConfigFileName="$(SourcePath)\packages.config" PackageID="MoreFramework">
          <Output TaskParameter="Version" PropertyName="MoreFrameworkVersion"/>
     </GetPackageVersionTask>
     <PropertyGroup>
          <MoreFrameworkReferencePath>$(SourcePath)\packages\MoreFramework.$(MoreFrameworkVersion)\lib\net40</MoreFrameworkReferencePath> 
</
PropertyGroup>
</Target>

Task代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using NuGet;

namespace Build.Tasks.Never
{
    public class GetPackageVersionTask : Task
    {
        [Required]
        public string PackageConfigFileName { get; set; }

        [Required]
        public string PackageID { get; set; }

        [Output]
        public string Version { get; private set; }

        public override bool Execute()
        {
            PackageReferenceFile packageFile = new PackageReferenceFile(PackageConfigFileName);
            foreach (PackageReference packageReference in packageFile.GetPackageReferences())
            {
                if (packageReference.Id.Equals(PackageID))
                {
                    Version = packageReference.Version.ToString();
                    this.Log.LogMessage("Package ID = {0},version = {1}", new object[] { PackageID, Version });
                    return true;
                }
            }
            return false;
        }
    }
}

targets文件:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask AssemblyFile="Build.Tasks.Never.dll" TaskName="Build.Tasks.Never.GetPackageVersionTask"/>
</Project>

*.targets文件并不是build出来的,而是manual wirte的。

* GetPackageVersionTask生成的dll必须和.targets在同一个文件夹

posted on 2020-05-12 14:59  不死亡灵首席大元帅  阅读(424)  评论(0编辑  收藏  举报

导航