dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.2k stars 1.35k forks source link

Publish projects during build #3138

Open jaredpar opened 6 years ago

jaredpar commented 6 years ago

The rosyln project has a solution with ~160 projects in it of which ~5 need to be published. Today our work flow is to do the following:

Invoking MSBuild this many times is wasteful because every publish has to re-evaluate the state of our build before moving onto the publish step. It would be more efficient if during the build we could publish the set of projects that require publishing.

Chaining targets almost works by using this syntax:

>msbuild /t:Build /t:path\to\project1:Publish /t:path\to\project2:Publish 

However Publish requires that a TargetFramework property also be set. How can that be combined with the target syntax above?

rainersigwald commented 6 years ago

I wanted to recommend using solution extensibility, so I documented that first (MicrosoftDocs/visualstudio-docs#816).

You can add a target to the solution build with AfterTargets="Build" that calls Publish in the desired targets, something like after.Roslyn.sln.targets:

<Project>
 <Target Name="PublishRoslynExecutableProjects"
         AfterTargets="Build">
  <ItemGroup>
   <ProjectsToPublish Include="src/Compilers/CSharp/csc/csc.csproj" />
   <ProjectsToPublish Include="src/Compilers/VisualBasic/vbc/vbc.csproj" />
   <ProjectsToPublish Include="src/Compilers/Server/VBCSCompiler/VBCSCompiler.csproj" />
   <ProjectsToPublish Include="src/Compilers/Core/MSBuildTask/MSBuildTask.csproj" />
  </ItemGroup>

  <Message Importance="high"
           Text="Publishing .NET Core executables ..." />

  <MSBuild Projects="@(ProjectsToPublish)"
           Targets="PublishWithoutBuilding"
           BuildInParallel="true"
           Properties="TargetFramework=netcoreapp2.0" />
 </Target>
</Project>

One thing that complicates this (rather a lot, unfortunately): when building individual projects, the solution passes configuration derived from solution configurations to the projects. That means that if you separately list projects and <MSBuild> into them, as I'm doing here, you'll get a different instance of the project, which might cause rebuilding. Here it won't be a race condition since the build happens after, but it could cause lost time (to rebuilding) or inaccurate builds (especially around things that are signed in place). Ensuring that the custom MSBuild invocation collapses into the default one is quite difficult--you have to set all the same properties that the solution does, plus all the right properties set when going from the "outer" multitargeted project to the TF-specific inner project. I've fought that a bit this afternoon but haven't been able to solve it.

Since Roslyn already defined PublishWithoutBuilding, I used that to avoid this problem--this gives the same experience as separately calling publish on the individual projects on the command line after the build.

gitfool commented 3 years ago

I'm also looking into running the publish step for a project during solution build time. Has there been any work in this area since the above? Intuitively, it would be nice if I could simply add a property to a csproj file to mark it as "publish on build".

sjoerd222888 commented 2 years ago

I agree that a <PublishOnBuild>true</PublishOnBuild> which would be similar to <GeneratePackageOnBuild>true</GeneratePackageOnBuild> from a semantic point of view would be really really helpful. This would make it a lot simpler to work with published resources without need of dedicatet setup in the build.

Actually I wanted to look into PublishWithoutBuilding as @rainersigwald said that would be used in Roslyn. But I could not find this target definition in the repo. Has it disappeared? And how is it done right now? The project is really big, I could not quickly figure it out.

DomenPigeon commented 6 months ago

Are there any improvements on this :) ? Would love to see something like PublishOnBuild>true</PublishOnBuild>

hknielsen commented 6 months ago

Im also looking for a PublishOnBuild feature

arsdragonfly commented 2 months ago

My hack:

  <Target Name="PublishAsBuildAfterTarget" AfterTargets="Build" DependsOnTargets="Publish">
    <!-- placeholder task to force Publish to happen during build -->
  </Target>