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

本文关键字:循环 项目 解决方案 MSBuild | 更新日期: 2023-09-27 18:03:55

在我工作的地方,我们有一个'核心'解决方案,其中包含许多提供不同实用功能的项目,这些项目通过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目录下,所以应该是微不足道的?)

EDIT:其他问题涉及在循环中执行msbuild任务的问题,但解决方案涉及在ItemGroup中手动枚举要循环的项,因此将导致稍微简单但仍然非常冗长的代码。我想尽量避免手工列举项目

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

您可以使用属性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中的项目,如您所希望的。