在MSBuild中的解决方案中循环项目

时间:2014-05-19 09:17:40

标签: c# .net msbuild

在我的工作地点,我们有一个'核心'解决方案,其中包含许多项目,这些项目提供不同的实用程序功能,这些功能通过nuget打包并发布到内部nuget服务器。为了从我们的CI实现nuget打包,我们目前有一个如下所示的MSBuild脚本:

<Exec Command="nuget pack &quot;$(ProjectRoot)\Domain\Domain.csproj&quot; -Properties Configuration=$(Configuration)" />
<Exec Command="nuget pack &quot;$(ProjectRoot)\Logging\Logging.csproj&quot; -Properties Configuration=$(Configuration)" />
<Exec Command="nuget pack &quot;$(ProjectRoot)\Logging.NLog\Logging.NLog.csproj&quot; -Properties Configuration=$(Configuration)" />
<Exec Command="nuget pack &quot;$(ProjectRoot)\Persistence\Persistence.csproj&quot; -Properties Configuration=$(Configuration)" />
<Exec Command="nuget pack &quot;$(ProjectRoot)\Persistence.NHibernate\Persistence.NHibernate.csproj&quot; -Properties Configuration=$(Configuration)" />

我们有大约20个项目以这种方式打包,每次我们介绍一个要打包的新项目时,我们必须在MSBuild脚本中添加另一行。是否可以使用MSbuild枚举解决方案中的项目,从而将此脚本压缩为类似...

<foreach project in solution>
    <Exec Command="nuget pack project -Properties Configuration=$(Configuration)" />
</foreach>

此外,我们需要能够在循环中查询每个项目以排除测试项目(这些都在Tests目录下,所以应该是微不足道的?)

编辑: Other questions处理循环中执行msbuild任务的问题,但解决方案涉及手动枚举要在ItemGroup中循环的项目,所以会导致稍微简单但仍然非常冗长的代码。如果可能的话,我想避免手工列举项目。

1 个答案:

答案 0 :(得分:1)

您可以使用属性SolutionDirSolutionName找到解决方案文件,然后编写自定义目标以查找解决方案中包含的所有项目。我这样做了:

<Target Name="AfterBuild" DependsOnTargets="PublishNuGetPackages" />
<Target Name="PublishNuGetPackages">
    <CollectNuGetProjects SolutionDir="$(SolutionDir)" SolutionName="$(SolutionName)">
        <Output TaskParameter="NuGetProjects" ItemName="NuGetProjects" />
    </CollectNuGetProjects>
    <Message Text="Collected the following nuget projects: @(NuGetProjects)" Importance="high" />
    <Exec Command="nuget pack &quot;$(SolutionDir)\%(NuGetProjects.Identity)&quot; -Properties Configuration=$(Configuration)" />
    <!-- publish packages etc... -->
</Target>

<UsingTask TaskName="CollectNuGetProjects" 
       TaskFactory="CodeTaskFactory" 
       AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
        <SolutionName ParameterType="System.String" Required="true" />
        <SolutionDir ParameterType="System.String" Required="true" />
        <NuGetProjects ParameterType="System.String[]" Output="true" />
    </ParameterGroup>
    <Task>
        <Reference Include="System.Linq" />
        <Using Namespace="System" />
        <Using Namespace="System.Linq" />
        <Using Namespace="System.Text.RegularExpressions" />
        <Code Type="Fragment" Language="cs">
            <![CDATA[
                var solutionFile = Path.Combine(SolutionDir, SolutionName + ".sln");
                var solutionText = File.ReadAllText(solutionFile);
                NuGetProjects = Regex.Matches(solutionText, @"""(?<projectFile>[^""]+?\.(csproj|wixproj|vcxproj))""")
                    .Cast<Match>()
                    .Select(m => m.Groups["projectFile"].Value)
                    .Where(p => !p.Contains(@"\Tests\"))
                    .ToArray();
        ]]>
        </Code>
    </Task>
</UsingTask>

此外,自定义任务会根据需要过滤掉位于文件夹Tests中的项目。