Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dotnet publish no-build switch disappeared #7521

Closed
hongdai opened this issue Jan 15, 2017 · 48 comments
Closed

Dotnet publish no-build switch disappeared #7521

hongdai opened this issue Jan 15, 2017 · 48 comments
Assignees
Milestone

Comments

@hongdai
Copy link

hongdai commented Jan 15, 2017

Steps to reproduce

Dotnet publish -no-build

Expected behavior

It is supported

Actual behavior

No longer supported

Environment data

dotnet --info output:

This is a useful switch. We would like to understand why it's removed and if there is a replacement.

@livarcocc
Copy link
Contributor

@dsplaisted @nguerrera @eerhardt Is there a way to trigger a publish without build?

@TheRealPiotrP
Copy link
Contributor

@hongdai It would be useful if you can share how you used this flag. I think there was some debate about whether it is still useful.

@eerhardt
Copy link
Member

It would be useful if you can share how you used this flag

Agreed. Getting all the use cases for why this switch is useful helps us understand whether to put it back or not.

One of the use cases I've recently encountered was the F# team (specifically @KevinRansom) was using this switch to publish a project's references, but he didn't want the project's output (its .dll) published. The replacement in that case is to add the MSBuild property <CopyBuildOutputToPublishDirectory>false</CopyBuildOutputToPublishDirectory> in your .csproj. That way, the current project's .dll isn't published.

FYI - @livarcocc and @piotrpMSFT, we could use this switch in the dotnet/cli ourselves in https://github.com/dotnet/cli/blob/rel/1.0.0/src/redist/redist.csproj. Then we wouldn't need to delete the redist.dll after publish, like we are currently doing.

@codito
Copy link
Contributor

codito commented Feb 10, 2017

It will be great to have --no-build supported.

We do the following in vstest repo:

  1. Build the sln file (all product, tests are built)
  2. Publish only the product projects
  3. Zip the published project for distribution

In step 2, all the product dlls are built again. Depending on the number projects published, some of the common dependencies could be built multiple times.

Update: our build process had a race condition on resources files which was slowing down the process. As @eerhardt notes below, msbuild incremental build does kick in, it is not a significant overhead for us now.

@eerhardt
Copy link
Member

In step 2, all the product dlls are built again.

Why is incremental building not kicking in? MSBuild knows if a project is already built, and doesn't need to build it again.

@hongdai
Copy link
Author

hongdai commented Feb 10, 2017

@piotrpMSFT We used to have our own publish target and run in AfterBuild. Without no-build switch, the publish target will invoke a build and cause a infinite loop, unless we add a condition.

dotnet pack still supports no-build switch. I think the usage should be similar.

@atanasa
Copy link

atanasa commented Mar 13, 2017

+1

As I see it, there should be an option to have the output of a build be the output of what you call "publish". I'd say that this should be the default behavior but that is debatable. As far as I understand it from reading the issues and documentation, this discrepancy is a workaround to speed up the build time of console apps (e.g. use the nuget cache to save on checksum calculations?!).

.Net is used for more than console apps and as such that workaround is not applicable to hosts different than dotnet run. For those cases, the actual dependencies are needed as part of the build output so it is runnable.

For such cases, I've managed to make dotnet publish output what is the real build output. To have it integrated with the VS Run command, I'd like to have the MSBuild Build target run the Publish target logic. This leads me to the infinite loop that @hongdai is talking about.

For me the no-build switch is a workaround. Ideally I would like you to support the case where the output of the build contains all the required runtime dependencies.

@eamodio
Copy link

eamodio commented Apr 28, 2017

Same issue here -- Why wasn't this BREAKING CHANGE announced on the announcement repo? I've just converted all our stuff to csproj and now this broke our whole ci/azure setup.

We have 3 deployments setup on AppVeyor for a single solution, so we have 3 configurations that do the following:

  1. Build all the specific projects for this config
  2. Run all the specific tests for this config
  3. Publish to folder to be deployed by AppVeyor to Azure

@eerhardt
Copy link
Member

eerhardt commented May 1, 2017

@eamodio - same question as above - Why is incremental building not kicking in?

@eamodio
Copy link

eamodio commented May 1, 2017

Let's say it is kicking in (which I think it is) -- just the fact the it has to run msbuild, scan for the project(s), see if they need building, etc -- all takes time; time I don't want to be waiting for my CI to finish. For example, on one of my projects it takes about 23s to build it the first time and then 9s to build it the second time (the one that used to be skipped). Yeah, 9s isn't that long in the scheme of things, but it isn't nothing either.

Also, given this flag is seemingly just a simple -- don't run msbuild -- I don't understand why it is so desirable to not support it?

@dasMulli
Copy link
Contributor

dasMulli commented May 1, 2017

I think this is caused by the current situations that large package graphs (netstandard.library, m.n.app) slow down msbuild projects which is causing project references to slow down linear (1 project 1 sec, 10 projects 10 sec) and has been discussed in https://github.com/dotnet/cli/issues/5918, #1116, dotnet/msbuild#1276 and maybe even more.

Even if build targets are avoided for publish, I believe RunResolvePackageDependencies and ResolveAssemblyReferences would still need to be run to determine the proper publish output (I might be wrong) - and those are the targets that cause the slow incremental builds.

@eerhardt
Copy link
Member

eerhardt commented May 2, 2017

Also, given this flag is seemingly just a simple -- don't run msbuild -- I don't understand why it is so desirable to not support it?

@dasMulli hit the nail on the head.

What does --no-build mean? In reality in project.json world, it really meant something closer to --no-compile. But the Build target in MSBuild does so much more than just Compile your source code.

  • It resolves references
  • It resolves NuGet assets (managed and native libraries, content files, even pre-processed content files)
  • It gathers your project's Content files that need to be copied to the output

Doing a Publish without the things that happen during the Build target in MSBuild is almost pointless. What do you expect to have happened?

Another thing to understand is that dotnet publish really means "run the Publish MSBuild target". So it obviously isn't as simple as "don't run msbuild", since you can't run the Publish target without MSBuild.

So the reason there is push back to supporting it is because it isn't clear what the option is supposed to do/mean. And once we settle on a definition, the next decision to make is - is the scenario we are enabling a high-priority scenario that many customers need?

@eamodio
Copy link

eamodio commented May 2, 2017

From that description why wouldn't --no-build mean don't run the Build target and only run the Publish target. Because if you've already run it without the --no-build flag then the Build target has already been run -- so everything is all prepared for the Publish target?

@eerhardt
Copy link
Member

eerhardt commented May 2, 2017

Like @dasMulli says above, there are shared targets between Build and Publish that will still need to be executed when just executing Publish. And the savings above and beyond an incremental build is usually negligible.

For example, on one of my projects it takes about 23s to build it the first time and then 9s to build it the second time (the one that used to be skipped). Yeah, 9s isn't that long in the scheme of things, but it isn't nothing either.

If you are interested in tracking down why the 2nd time is taking 9s, you can pass /v:diag into both dotnet build and dotnet publish. This will print out a lot of information (you probably want to pipe it to a file), but what you are interested in comes at the end. There is a table that shows where all the time is being spent in the build. For example, here is the table of publishing an ASP.NET 2.0 app on my local machine:

First Time

Project Performance Summary:
     6806 ms  F:\DotNetTest\TestWeb\TestWeb.csproj       1 calls
               6806 ms  Publish                                    1 calls

Target Performance Summary:
        0 ms  _DotNetCLIPrePublish                       1 calls
        0 ms  ComputeAndCopyFilesToPublishDirectory      1 calls
        0 ms  BeforeResGen                               1 calls
        0 ms  PrepareResourceNames                       1 calls
        0 ms  _DotNetCLIPostPublish                      1 calls
        0 ms  ResGen                                     1 calls
        0 ms  AfterBuild                                 1 calls
        0 ms  GetFrameworkPaths                          1 calls
        0 ms  ResolveReferences                          1 calls
        0 ms  GetReferenceAssemblyPaths                  1 calls
        0 ms  PrepareResources                           1 calls
        0 ms  _AspNetCoreProjectSystemPrePublish         1 calls
        0 ms  BeforeBuild                                1 calls
        0 ms  Compile                                    1 calls
        0 ms  AfterResGen                                1 calls
        0 ms  SetWin32ManifestProperties                 1 calls
        0 ms  CreateCustomManifestResourceNames          1 calls
        0 ms  GenerateUserSecretsAttribute               1 calls
        0 ms  CoreBuild                                  1 calls
        0 ms  GenerateAssemblyInfo                       1 calls
        0 ms  BeforePublish                              1 calls
        0 ms  _AspNetCoreProjectSystemPostPublish        1 calls
        0 ms  AfterPublish                               1 calls
        0 ms  _CopySourceItemsToOutputDirectory          1 calls
        0 ms  CreateSatelliteAssemblies                  1 calls
        0 ms  AfterCompile                               1 calls
        0 ms  PrepareForRun                              1 calls
        0 ms  AfterResolveReferences                     1 calls
        0 ms  InjectReference_efa7ce74-36bd-481a-bac0-42e316fc1d57   1 calls
        0 ms  IncludeTransitiveProjectReferences         1 calls
        0 ms  InjectReference_095e2d6d-4484-4c4e-b23a-d4bd8983312a   1 calls
        0 ms  BeforeCompile                              1 calls
        0 ms  BeforeResolveReferences                    1 calls
        0 ms  Build                                      1 calls
        0 ms  CopyFilesToPublishDirectory                1 calls
        0 ms  PrepareProjectReferences                   1 calls
        0 ms  _DefaultMicrosoftNETPlatformLibrary        1 calls
        0 ms  ResolvePackageDependenciesForBuild         1 calls
        0 ms  ResolveSDKReferences                       1 calls
        0 ms  _SetTargetFrameworkMonikerAttribute        1 calls
        0 ms  ResolveLockFileAnalyzers                   1 calls
        0 ms  BuildOnlySettings                          1 calls
        0 ms  PublishWithAspNetCoreTargetManifest        1 calls
        0 ms  ComputePrivateAssetsPackageReferences      1 calls
        0 ms  ExpandSDKReferences                        1 calls
        0 ms  GetInstalledSDKLocations                   1 calls
        0 ms  GetTargetPath                              1 calls
        0 ms  InjectReference_324b1a06-f466-4b33-a9b7-baf91ae299f2   1 calls
        0 ms  ComputeDependencyFileCompilerOptions       1 calls
        0 ms  _CheckForUnsupportedSelfContained          1 calls
        0 ms  _ComputeNetPublishAssets                   1 calls
        0 ms  _GenerateRunCommandFile                    1 calls
        0 ms  _SplitProjectReferencesByFileExistence     1 calls
        0 ms  _GenerateCompileInputs                     1 calls
        0 ms  CoreResGen                                 1 calls
        0 ms  _DetermineProjectType                      1 calls
        0 ms  Publish                                    1 calls
        0 ms  _InitPublishIntermediateOutputPath         1 calls
        0 ms  _InitProjectCapabilityProperties           1 calls
        0 ms  _CheckForCompileOutputs                    1 calls
        0 ms  PrepareForPublish                          1 calls
        0 ms  _GenerateEFSQLScripts                      1 calls
        0 ms  _GenerateSatelliteAssemblyInputs           1 calls
        0 ms  _ComputeLockFileFrameworks                 1 calls
        0 ms  _TransformAppSettings                      1 calls
        0 ms  ResolveProjectReferences                   1 calls
        1 ms  _ComputeNETCoreBuildOutputFiles            1 calls
        1 ms  SplitResourcesByCulture                    1 calls
        1 ms  _SetEmbeddedWin32ManifestProperties        1 calls
        1 ms  ComputeFilesToPublish                      1 calls
        1 ms  GeneratePublishRuntimeConfigurationFile    1 calls
        1 ms  GetAssemblyVersion                         1 calls
        1 ms  GetCopyToOutputDirectoryItems              1 calls
        2 ms  DefaultCopyToPublishDirectoryMetadata      1 calls
        2 ms  _HandlePublishFileConflicts                1 calls
        2 ms  IncrementalClean                           1 calls
        2 ms  AssignTargetPaths                          1 calls
        2 ms  GenerateTargetFrameworkMonikerAttribute    1 calls
        2 ms  _ComputeCopyToPublishDirectoryItems        1 calls
        2 ms  GetCopyToPublishDirectoryItems             1 calls
        2 ms  _ComputeLockFileAnalyzers                  1 calls
        3 ms  CoreGenerateUserSecretsAttribute           1 calls
        3 ms  _ComputeActiveTFMFileDependencies          1 calls
        4 ms  _GetProjectReferenceTargetFrameworkProperties   1 calls
        4 ms  PrepareForBuild                            1 calls
        4 ms  _ComputeTransitiveProjectReferences        1 calls
        4 ms  _CheckForInvalidConfigurationAndPlatform   1 calls
        4 ms  CheckForDuplicateItems                     1 calls
        5 ms  _ComputeTFMOnlyFileDependencies            1 calls
        5 ms  CopyFilesToOutputDirectory                 1 calls
        6 ms  CoreGenerateAssemblyInfo                   1 calls
        6 ms  _CopyOutOfDateSourceItemsToOutputDirectory   1 calls
        6 ms  _ComputeActiveTFMPackageDependencies       1 calls
        7 ms  _CheckForUnsupportedTargetFramework        1 calls
       15 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       19 ms  _TransformWebConfig                        1 calls
       22 ms  _ComputeResolvedFilesToPublishTypes        1 calls
       24 ms  RunResolvePublishAssemblies                1 calls
       26 ms  _GenerateCompileDependencyCache            1 calls
       27 ms  _CleanGetCurrentAndPriorFileWrites         1 calls
       30 ms  _IncludePrePublishGeneratedContent         1 calls
       40 ms  ComputeRefAssembliesToPublish              1 calls
       62 ms  _CopyResolvedFilesToPublishPreserveNewest   1 calls
       64 ms  GenerateBuildRuntimeConfigurationFiles     1 calls
       74 ms  _ComputeLockFileReferences                 1 calls
       81 ms  GeneratePublishDependencyFile              1 calls
       82 ms  ResolveLockFileReferences                  1 calls
       87 ms  RunProduceContentAssets                    1 calls
      148 ms  GenerateBuildDependencyFile                1 calls
      244 ms  _ComputeLockFileCopyLocal                  1 calls
      247 ms  _HandlePackageFileConflicts                1 calls
      249 ms  _CopyResolvedFilesToPublishAlways          1 calls
      276 ms  RunResolvePackageDependencies              1 calls
     1166 ms  CoreCompile                                1 calls
     3721 ms  ResolveAssemblyReferences                  1 calls

Task Performance Summary:
        0 ms  Delete                                     1 calls
        0 ms  ReadLinesFromFile                          1 calls
        0 ms  AssignCulture                              1 calls
        0 ms  RemoveDuplicates                           2 calls
        0 ms  GetFrameworkPath                           1 calls
        1 ms  FindAppConfigFile                          1 calls
        1 ms  FindUnderPath                              5 calls
        1 ms  MSBuild                                    1 calls
        1 ms  GetAssemblyVersion                         1 calls
        1 ms  Message                                    4 calls
        2 ms  AssignTargetPath                           6 calls
        2 ms  WriteLinesToFile                           2 calls
        3 ms  MakeDir                                    2 calls
        4 ms  CheckForDuplicateItems                     3 calls
        7 ms  CheckForImplicitPackageReferenceOverrides   1 calls
        8 ms  WriteCodeFragment                          2 calls
       10 ms  Hash                                       1 calls
       17 ms  TransformWebConfig                         1 calls
       18 ms  ProduceContentAssets                       1 calls
       22 ms  ConvertToAbsolutePath                      2 calls
       24 ms  ResolvePublishAssemblies                   1 calls
       64 ms  GenerateRuntimeConfigurationFiles          2 calls
      144 ms  ResolvePackageFileConflicts                2 calls
      229 ms  GenerateDepsFile                           2 calls
      274 ms  ResolvePackageDependencies                 1 calls
      316 ms  Copy                                       5 calls
     1164 ms  Csc                                        1 calls
     3719 ms  ResolveAssemblyReference                   1 calls

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:07.19

Second Time

Project Performance Summary:
     5923 ms  F:\DotNetTest\TestWeb\TestWeb.csproj       1 calls
               5923 ms  Publish                                    1 calls

Target Performance Summary:
        0 ms  ResGen                                     1 calls
        0 ms  BeforeResGen                               1 calls
        0 ms  PrepareResourceNames                       1 calls
        0 ms  ResolveReferences                          1 calls
        0 ms  Compile                                    1 calls
        0 ms  _DotNetCLIPostPublish                      1 calls
        0 ms  _DotNetCLIPrePublish                       1 calls
        0 ms  ComputeAndCopyFilesToPublishDirectory      1 calls
        0 ms  _AspNetCoreProjectSystemPrePublish         1 calls
        0 ms  AfterBuild                                 1 calls
        0 ms  GetFrameworkPaths                          1 calls
        0 ms  PrepareResources                           1 calls
        0 ms  AfterResGen                                1 calls
        0 ms  SetWin32ManifestProperties                 1 calls
        0 ms  BeforeBuild                                1 calls
        0 ms  PrepareProjectReferences                   1 calls
        0 ms  CreateSatelliteAssemblies                  1 calls
        0 ms  BeforePublish                              1 calls
        0 ms  CreateCustomManifestResourceNames          1 calls
        0 ms  GenerateUserSecretsAttribute               1 calls
        0 ms  BeforeCompile                              1 calls
        0 ms  CoreBuild                                  1 calls
        0 ms  AfterCompile                               1 calls
        0 ms  AfterResolveReferences                     1 calls
        0 ms  GenerateAssemblyInfo                       1 calls
        0 ms  CopyFilesToPublishDirectory                1 calls
        0 ms  _CopySourceItemsToOutputDirectory          1 calls
        0 ms  ResolvePackageDependenciesForBuild         1 calls
        0 ms  InjectReference_efa7ce74-36bd-481a-bac0-42e316fc1d57   1 calls
        0 ms  Build                                      1 calls
        0 ms  BuildOnlySettings                          1 calls
        0 ms  GetReferenceAssemblyPaths                  1 calls
        0 ms  _AspNetCoreProjectSystemPostPublish        1 calls
        0 ms  AfterPublish                               1 calls
        0 ms  BeforeResolveReferences                    1 calls
        0 ms  PrepareForRun                              1 calls
        0 ms  IncludeTransitiveProjectReferences         1 calls
        0 ms  ExpandSDKReferences                        1 calls
        0 ms  ResolveLockFileAnalyzers                   1 calls
        0 ms  _DefaultMicrosoftNETPlatformLibrary        1 calls
        0 ms  InjectReference_095e2d6d-4484-4c4e-b23a-d4bd8983312a   1 calls
        0 ms  _SetTargetFrameworkMonikerAttribute        1 calls
        0 ms  PublishWithAspNetCoreTargetManifest        1 calls
        0 ms  ComputePrivateAssetsPackageReferences      1 calls
        0 ms  ResolveSDKReferences                       1 calls
        0 ms  ComputeDependencyFileCompilerOptions       1 calls
        0 ms  _CheckForUnsupportedSelfContained          1 calls
        0 ms  _ComputeNetPublishAssets                   1 calls
        0 ms  GetTargetPath                              1 calls
        0 ms  _SplitProjectReferencesByFileExistence     1 calls
        0 ms  PrepareForPublish                          1 calls
        0 ms  _GenerateRunCommandFile                    1 calls
        0 ms  GetInstalledSDKLocations                   1 calls
        0 ms  CoreResGen                                 1 calls
        0 ms  InjectReference_324b1a06-f466-4b33-a9b7-baf91ae299f2   1 calls
        0 ms  _DetermineProjectType                      1 calls
        0 ms  _CheckForCompileOutputs                    1 calls
        0 ms  _InitProjectCapabilityProperties           1 calls
        0 ms  _GenerateSatelliteAssemblyInputs           1 calls
        0 ms  GenerateBuildDependencyFile                1 calls
        0 ms  _GenerateCompileInputs                     1 calls
        0 ms  _InitPublishIntermediateOutputPath         1 calls
        0 ms  Publish                                    1 calls
        0 ms  ResolveProjectReferences                   1 calls
        0 ms  _GenerateEFSQLScripts                      1 calls
        0 ms  _ComputeLockFileFrameworks                 1 calls
        0 ms  _TransformAppSettings                      1 calls
        1 ms  _ComputeNETCoreBuildOutputFiles            1 calls
        1 ms  SplitResourcesByCulture                    1 calls
        1 ms  IncrementalClean                           1 calls
        1 ms  _SetEmbeddedWin32ManifestProperties        1 calls
        1 ms  DefaultCopyToPublishDirectoryMetadata      1 calls
        1 ms  GetCopyToOutputDirectoryItems              1 calls
        1 ms  _HandlePublishFileConflicts                1 calls
        1 ms  GeneratePublishRuntimeConfigurationFile    1 calls
        2 ms  CoreGenerateUserSecretsAttribute           1 calls
        2 ms  ComputeFilesToPublish                      1 calls
        2 ms  CoreGenerateAssemblyInfo                   1 calls
        2 ms  CopyFilesToOutputDirectory                 1 calls
        2 ms  _ComputeLockFileAnalyzers                  1 calls
        2 ms  AssignTargetPaths                          1 calls
        2 ms  GenerateTargetFrameworkMonikerAttribute    1 calls
        2 ms  GetAssemblyVersion                         1 calls
        3 ms  PrepareForBuild                            1 calls
        3 ms  _GetProjectReferenceTargetFrameworkProperties   1 calls
        3 ms  _ComputeActiveTFMFileDependencies          1 calls
        3 ms  _ComputeCopyToPublishDirectoryItems        1 calls
        3 ms  CheckForDuplicateItems                     1 calls
        3 ms  GetCopyToPublishDirectoryItems             1 calls
        4 ms  _ComputeTFMOnlyFileDependencies            1 calls
        4 ms  _CheckForInvalidConfigurationAndPlatform   1 calls
        4 ms  _ComputeTransitiveProjectReferences        1 calls
        6 ms  _ComputeActiveTFMPackageDependencies       1 calls
        8 ms  _CheckForUnsupportedTargetFramework        1 calls
       13 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       14 ms  CoreCompile                                1 calls
       16 ms  _TransformWebConfig                        1 calls
       16 ms  _ComputeResolvedFilesToPublishTypes        1 calls
       24 ms  _CleanGetCurrentAndPriorFileWrites         1 calls
       25 ms  RunResolvePublishAssemblies                1 calls
       36 ms  _CopyOutOfDateSourceItemsToOutputDirectory   1 calls
       41 ms  ComputeRefAssembliesToPublish              1 calls
       50 ms  _GenerateCompileDependencyCache            1 calls
       72 ms  _IncludePrePublishGeneratedContent         1 calls
       72 ms  _ComputeLockFileReferences                 1 calls
       80 ms  GenerateBuildRuntimeConfigurationFiles     1 calls
       83 ms  ResolveLockFileReferences                  1 calls
       86 ms  RunProduceContentAssets                    1 calls
      159 ms  GeneratePublishDependencyFile              1 calls
      202 ms  _CopyResolvedFilesToPublishAlways          1 calls
      228 ms  _HandlePackageFileConflicts                1 calls
      236 ms  _ComputeLockFileCopyLocal                  1 calls
      273 ms  _CopyResolvedFilesToPublishPreserveNewest   1 calls
      275 ms  RunResolvePackageDependencies              1 calls
     3835 ms  ResolveAssemblyReferences                  1 calls

Task Performance Summary:
        0 ms  Delete                                     1 calls
        0 ms  AssignCulture                              1 calls
        0 ms  RemoveDuplicates                           2 calls
        1 ms  GetFrameworkPath                           1 calls
        1 ms  FindAppConfigFile                          1 calls
        1 ms  ReadLinesFromFile                          1 calls
        1 ms  MSBuild                                    1 calls
        1 ms  FindUnderPath                              5 calls
        1 ms  WriteLinesToFile                           1 calls
        1 ms  Message                                    4 calls
        2 ms  MakeDir                                    2 calls
        2 ms  AssignTargetPath                           6 calls
        2 ms  GetAssemblyVersion                         1 calls
        3 ms  CheckForDuplicateItems                     3 calls
        6 ms  CheckForImplicitPackageReferenceOverrides   1 calls
       10 ms  Hash                                       1 calls
       14 ms  TransformWebConfig                         1 calls
       18 ms  ProduceContentAssets                       1 calls
       20 ms  ConvertToAbsolutePath                      2 calls
       25 ms  ResolvePublishAssemblies                   1 calls
       81 ms  GenerateRuntimeConfigurationFiles          2 calls
      143 ms  ResolvePackageFileConflicts                2 calls
      159 ms  GenerateDepsFile                           1 calls
      204 ms  Copy                                       3 calls
      268 ms  ResolvePackageDependencies                 1 calls
     3833 ms  ResolveAssemblyReference                   1 calls

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:06.18

As you can see, CSC is only taking a little over 1s the first time. However, even in the 2nd time ResolveAssemblyReference is taking ~65% of the time (3835 ms / 5923 ms). As I asked above, do you expect that when you dotnet publish --no-build that you shouldn't get any referenced assemblies copied to your output directory?

(Now granted, we probably have some sort of perf bug in ResolveAssemblyReference, but that is a different discussion.)

Anyway, I'd be interested in learning what you find is taking 9s on your 2nd build. I'm sure you would be too 😉.

@eamodio
Copy link

eamodio commented May 2, 2017

Thanks for the information! I will try that out and see what the bottleneck is.

As for the ResolveAssemblyReference -- If that isn't done as part of the Build task, then I would expect it to be done, but if it isn't done as part of the Build task, then I would expect it to be done.

Basically I just want to avoid doing duplicate work.

@eerhardt
Copy link
Member

eerhardt commented May 2, 2017

The result of ResolveAssemblyReference isn't saved to disk after the call to Build. So when a new process comes along for dotnet publish, it needs to be run again.

@eerhardt
Copy link
Member

eerhardt commented May 2, 2017

(Now granted, we probably have some sort of perf bug in ResolveAssemblyReference, but that is a different discussion.)

That different discussion is here; dotnet/msbuild#2015

@BennieCopeland
Copy link

Here is my use case. I'm working on adding CI to our process for an ASP.Net Core site we are building. I want to be able to build once, test those binaries, and then publish the tested binaries as part of the CI workflow. This flag still works with package, which we are using for publishing internal nuget packages in our CI workflow.

@dazinator
Copy link

dazinator commented Jun 7, 2017

To my mind, publishing a project should operate on it's built assets - therefore publishing is obviously dependent on a build having occurred! I think it would be rare in the world of CI that you would want to publish something from a vanilla state (i.e without already having just done a build to test the assets you are publishing). So the reason for wanting to specify "no build" is because at the point of the workflow you want to publish you have already done the build - mixed in with the fact that an "incremental build" doesn't seem to be as fast as it should be. If an incremental build truly was neglible (i.e zero overhead if build already done) then I don't think this would be such an issue. I guess it's debatable what an acceptable level of overhead would be. I'd be ok if, for large projects, an incremental build didn't incur more than a couple of seconds penalty when nothing has changed. If it takes more than that, and you know ahead of time nothing has changed then you can see why people would be looking to use that "no build" flag if it's available.

This brings me to another point - the willingness to remove this and break peoples CI's processes to seemingly force some feedback on the issue seems a little bit hostile :-/ don't you think?

@eerhardt

As I asked above, do you expect that when you dotnet publish --no-build that you shouldn't get any referenced assemblies copied to your output directory?

I am wondering why it should need to look at references at this point? If the build has already occurred, then the build output (including referenced assemblies / content files etc that had "copy to output") has already been produced. In other words, the assets are already all produced and publish just needs to do something with those existing assets. Why would it need to check references?

@BennieCopeland
Copy link

@dazinator Exactly. Even if the "incremental build" is negligible, that is still shipping a different set of compiled binaries than the ones that were tested, and in some environments that is unacceptable.

@nguerrera
Copy link
Contributor

nguerrera commented Jun 14, 2017

I think we should add the --no-build. I encountered an issue internally where the build portion of publish overwrote binaries that were signed in the build output directory with unsigned copies.

I worked around it with:

    <Target Name="PublishWithoutBuilding"
            DependsOnTargets="PreventProjectReferencesFromBuilding;
                              ResolveReferences;
                              ComputeAndCopyFilesToPublishDirectory;
                              GeneratePublishDependencyFile;
                              GeneratePublishRuntimeConfigurationFile" />                                                           

    <Target Name="PreventProjectReferencesFromBuilding">
      <PropertyGroup>
        <BuildProjectReferences>false</BuildProjectReferences>
      </PropertyGroup>
    </Target>

which is the same as the real Publish, with PreventProjectReferencesFromBuilding;ResolveReferences replacing Build.

cc @jaredpar @agocke

@jaredpar
Copy link
Member

I think we should add the --no-build.

Strongly agree. Build is basically a composition of two operations: compile and deploy. Once I've compiled there is simply no need to re-compile when I want to deploy for a new platform. Compiling is just wasting CPU cycles and developer time at that point.

@agocke
Copy link
Member

agocke commented Jun 14, 2017

I'll note, for the case where publish was overwriting binaries that had a separate post-build step applied: the incremental build is a perf optimization and shouldn't be relied on for semantic guarantees. so it should never be used as a solution to this problem.

@nguerrera
Copy link
Contributor

The PublishWithoutBuilding above won't be materially faster than an up-to-date incremental build (compile step would no-op but we still need to resolve references in both cases), so it is really more about semantics than speed.

The fact that reference resolution can be slow is orthogonal and something that is being worked on. It will benefit both incremental builds and things that resolve but don't build.

dotnet/msbuild#2015

@agocke
Copy link
Member

agocke commented Jun 14, 2017

@nguerrera Not sure you can make that assertion without knowing the writeread speed of the user's output directory, which could theoretically be on a remote network share.

@nguerrera
Copy link
Contributor

You mean read speed to determine what's up to date?

@agocke
Copy link
Member

agocke commented Jun 14, 2017

@nguerrera Yes :)

@nguerrera
Copy link
Contributor

My assertion should have had more qualifications, but my main point was that you need the semantics of --no-build even more importantly than the speed.

@jaredpar
Copy link
Member

My assertion should have had more qualifications, but my main point was that you need the semantics of --no-build even more importantly than the speed.

100% agree.

@JohnRusk
Copy link

Is it possible to approximate the semantics of --no-build by using publish earlier in the build process. I.e.

  1. Run publish (instead of build)
  2. Run unit tests
  3. If they pass, then actually use the output from the publish

I can imagine this could be problematical for users who want to build lots of projects, but only publish some. (E.g. don't publish the unit test projects). Any other issues with it?

BTW, even if this is workable, it still seems like a workaround. I agree with the @nguerrera and @jaredpar that the semantics of --no-build are desirable.

@jaredpar
Copy link
Member

@JohnRusk that works on small projects but not on bigger ones. Consider Roslyn which has ~160+ projects in our solution and eventually will have ~10-20 test projects that in theory need publishing. There is really no way to publish all of them without rebuilding their shared dependencies.

Having an explicit, and supported, no build publish is the only reasonable solution here.

@lukeamcmurray
Copy link

We have a post build script in our dev environments which publishes our service and then restarts a docker container running in a VM which is hosting the service. Without the --no-build switch the post build step causes an infinite loop.

I agree with bringing back the --no-build switch option - unless there is another way to achieve the above?

@anoordende
Copy link

Whatever the solution will be, it seems clear from the comments above that Build -> Test -> Publish is a highly desired workflow, for myself included. Thus, a publish command that can take pre-existing output is a highly desirable requirement, whether this is a --no-build flag or some equivalent. Even more so using a hosted build agent service where build time = money.

@CurlyFire
Copy link

My CI is based on Build, Test and finally publish those binaries that were tested. It made sure that the binaries that were tested were the ones published. Now when I publish, it rebuilds, giving me a brand new set of binaries... Please bring back that switch, it broke my CI.

@jhudsoncedaron
Copy link

jhudsoncedaron commented Aug 11, 2017

Just got here looking for this. Trying to run dotnet publish with visual studio open breaks hard. Using --no-build would work. Incremental build is still broken here for quite unobvious reasons.

In answer to others above, --no-build should assume dotnet build finished and pick up the output binaries from that.

@Listbd
Copy link

Listbd commented Aug 14, 2017

Read through the above posts, and not clear as to what the holdup is.

In my case it broke my CI step and I am now deploying manually.

Can't --no-build be added back in so we can continue to work while the debate goes on? At the very least it should have been deprecated rather than removed, as it is a breaking change.

@nguerrera
Copy link
Contributor

Thanks all for the feedback. As I mentioned above, I'm in strong agreement on this. We will add --no-build in v2.1.0.

@brainwipe
Copy link

Another use case (after the horse has bolted):

We have a .NET Core solution with a number of docker containers with APIs. The solution also includes a developer-only console app for Dev investigation. When a Developer presses F5 and the whole solution builds and runs up docker, I want the console app (and only the console app) to republish itself to a Win 10 x64 target so that the devs can use the console app from Powershell. I would normally put publish in a post-build event in the .csproj but that creates an infinite loop. I need the --no-build parameter to stop that.

I appreciate that my Devs can still do dotnet c:/blah/myapp.dll params but they find that upsetting.

@Eternal21
Copy link

Same problem. Trying to automate publishing Asp.NET Core project. There is no way to force publish after build, so I ended up adding a 'dotnet publish' post-build event. Sadly it results in recursive builds that never end. A --no-build switch would fix something that I will now have to spend hours trying to work around.

@gulbanana
Copy link

try dotnet msbuild /t:publish /p:NoBuild=True

@vineus
Copy link

vineus commented Oct 31, 2017

Hey @gulbanana : thanks for the tip but for me msbuild still rebuilds dependent projects. So it's different than the former --no-build options that didn't even tried to build anything and just assumed the right dll was here.

@dasMulli
Copy link
Contributor

There's also the /p:BuildProjectReferences=false switch that indicates that all dependencies are up-to-date and don't need to be rebuilt (see ProjectReference protocol)

@vineus
Copy link

vineus commented Nov 2, 2017

@dasMulli : thanks a lot! works great! (and I can finally publish my 5 projects without having to rebuild everything all the time :-) )

@mabead
Copy link

mabead commented Jan 24, 2018

Here's how our build process used to look like with the 1.0.4 .NET Core SDK:

dotnet restore
dotnet build /p:Version=6.6.6
dotnet test
dotnet publish 
docker build <using publish output folder>
docker push 

As you can see, we use a /p msbuild option for dotnet build to specify the version that we want for our assembly. This used to work great.

With .NET Core 2, since the dotnet publish does on dotnet build, the result of dotnet publish recompiles the assembly without using the 6.6.6 assembly version. We therefore end-up with a docker container that contains assemblies that:

  1. were not used during the tests
  2. don't have the good assembly version

I can fix this problem using dotnet publish /p:Version=6.6.6. But in fact, the problem is more complex since we also use dotnet lambda package that does an implicit dotnet publish that does not allow me to specify the /p:Version=6.6.6 parameters. See aws/aws-lambda-dotnet#210 for more details.

Please add the --no-build option ;)

gabrielweyer referenced this issue in gabrielweyer/beanstalk-seeder Jan 28, 2018
dotnet publish rebuilds the binaries so we ended up with assemblies with
default version. As `--no-build` switch is not available anymore I had
to use a workaround. Issue is described here:
https://github.com/dotnet/cli/issues/5331
@diegohb
Copy link

diegohb commented Feb 8, 2018

Is there plans to add the no-build option back? Not building the references isn’t quite the same thing.. thanks!

@brainwipe
Copy link

@diegohb At the top of this issue, you can see that it's slated for release with milestone 2.1.3xx.
Check out all the issues in that milestone here: https://github.com/dotnet/cli/milestone/17

@nguerrera
Copy link
Contributor

I will try to get to this soon.

@nguerrera
Copy link
Contributor

#2111 (in PR) implements the dotnet/sdk half of this. After that, we just need to wire --no-build to /p:NoBuild=true here.

@msftgits msftgits transferred this issue from dotnet/cli Jan 31, 2020
@msftgits msftgits added this to the 2.1.3xx milestone Jan 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests