Skip to content

Support dotnet pack file.cs #50168

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

Conversation

jjonescz
Copy link
Member

Resolves #49369.

@jjonescz jjonescz added the Area-run-file Items related to the "dotnet run <file>" effort label Aug 11, 2025
@jjonescz jjonescz marked this pull request as ready for review August 11, 2025 19:11
@Copilot Copilot AI review requested due to automatic review settings August 11, 2025 19:11
@jjonescz jjonescz requested a review from a team as a code owner August 11, 2025 19:11
@jjonescz jjonescz requested a review from a team August 11, 2025 19:11
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements support for dotnet pack file.cs to enable packing file-based programs directly from C# source files. The change allows users to create NuGet packages from standalone C# files without requiring a traditional project file structure.

Key changes:

  • Modified the PackCommand to detect and handle file-based programs using the virtual project building infrastructure
  • Updated command completion descriptions to include C# files as valid inputs
  • Added test coverage for the new functionality

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Cli/dotnet/Commands/Pack/PackCommand.cs Refactored to use CommandFactory pattern and support file-based programs through VirtualProjectBuildingCommand
src/Cli/dotnet/Commands/Pack/PackCommandParser.cs Updated argument name and description to include C# files as valid inputs
src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs Added PackageOutputPath property and updated runtime config logic to exclude Pack target
test/dotnet.Tests/CommandTests/Run/RunFileTests.cs Added comprehensive test for pack functionality and updated virtual project templates
test/dotnet.Tests/CommandTests/MSBuild/GivenDotnetPackInvocation.cs Fixed cast to handle new return type from PackCommand.FromArgs
documentation/general/dotnet-run-file.md Updated documentation to reflect pack support and clarify behavior
test/dotnet.Tests/CompletionTests/snapshots/zsh/DotnetCliSnapshotTests.VerifyCompletions.verified.zsh Updated completion description to include C# files
Comments suppressed due to low confidence (1)

Copy link
Member

@zivkan zivkan Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the end-to-end scenario for packing file based project?

My understanding is that file based apps are always console apps, is that right? If so, should they be packed as tools, rather than packed as class libraries?

Tools are installed and used with dotnet tool install, whereas class libraries can only be used by PackageReference or equivilent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, tools are the likely scenario. But you could actually pack a library as well if you wanted; like:

#:property OutputType=Library
public class C;

(you just couldn't dotnet run such file-based app)

Copy link
Member

@zivkan zivkan Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the tests were updated to do #:property PackAsTool=true. I don't know why the default for csproj console apps is still PackAsTool=false, maybe we've just been so busy with other work we haven't considered changing the default. IMO it would be nice for the default to be true when the SDK knows it's a console app. But since file based apps is a new thing, should we consider changing the default to true for them, if we think that most customers will want that, so that it's not a breaking change in the future?

Normally .NET does breaking changes based on project TFM, so customers should feel safe to update the SDK and their projects keep working. What is the breaking change story for file based apps, since they don't have a TFM?

I'm still wondering what the scope is for file based apps. Reading the dotnet-run-file.md docs, it talks about projects needing to "grow up" under some scenarios, like when build customizations are needed. Is pack one of these scenarios that customers should need a project file for? This PR shows that technically we can support pack without a project file, but my question is should we?

The top of the document says file-based programs are intended to be an alternative to other scripting languages in .NET repos, and also to be easier for new customers. Pack isn't needed to be an alternative to other scripting languages. Being able to pack a file or directory without a project file certainly makes it easier for people new to .NET, I just want to make sure that we're doing this for the right reasons and minimise risk of needing breaking changes in the future.

Since NuGet treats packages as immutable, once a package has been extracted into the global packages folder, then NuGet will not check for "updates". The developer will either need to increment the package version number or manually delete the directory from the global packages folder. A bunch of customers have filed issues on NuGet saying they find this hard to test their packages. Is being able to pack without a project file going to make this easier, harder, or the same to experience this issue? I think if people start trying to use nupkgs as an alternative to projects and project references, then they're much more likely to encounter the problem.

But you could actually pack a library as well if you wanted; like: #:property OutputType=Library

Is it inappropriate for me to be so opinionated as to think that class libraries should have unit tests, and therefore being able to pack a "file-based class library" is actually a bad thing for the ecosystem? Maybe I'm just being too stubborn, as there's nothing preventing customers from doing dotnet new classlib ; dotnet pack and pushing without any tests. But at least there's a project file for a test project to reference.

Other ecosystems have ceremony (create a manifest file) that the package author must do to create a package. Maybe packing without a project would be a competitive advantage for .NET. Or maybe it's precedent to say it's ok for customers to need to grow into a project file if they want to create a package.

Sorry for the long, rambly comment. I don't have context for what discussions and plans were made for file based apps already. I just saw this PR adding a NuGet scenario and nobody else from my team commented, so I did.

@baronfel is my go to for any ".NET SDK end to end scenario" questions, though I don't know if there's a different PM who owns the file based app scenario.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is pack one of these scenarios that customers should need a project file for? This PR shows that technically we can support pack without a project file, but my question is should we?

One of the scenarios for file based apps is tool publishing which is why pack support is being added. #49369 discusses a bit of the motivation here.

A bunch of customers have filed issues on NuGet saying they find this hard to test their packages. Is being able to pack without a project file going to make this easier, harder, or the same to experience this issue?

I agree that testing NuGet packages today, particularly when they in the global cache, can be challenging at times. I cannot see though how file based and project based apps are significantly different here.

Is it inappropriate for me to be so opinionated as to think that class libraries should have unit tests, and therefore being able to pack a "file-based class library" is actually a bad thing for the ecosystem?

How is this any different than running pack on a project based class lib that has no unit tests? As much as I believe in unit testing (personally and professionally) I don't think it's a requirement that we should be enforcing on customers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the scenarios for file based apps is tool publishing which is why pack support is being added. #49369 discusses a bit of the motivation here.

Thanks, I haven't seen this before. The original comment in the issue says:

We should consider supporting them with dotnet pack so that .NET SDK Tools can be made out of them.

So, that comes back to my original question: Would we be giving customers a better experience if we default PackAsTool to true, rather than making customers add #:property PackAsTool=true in their code file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PackAsTool=true by default for file-based apps would make sense to me. But any defaults that differ from project-based apps make the converted project file noisier. We currently only have one such difference (PublishAot). I'd be cautious before liberally adding more. If we could make PackAsTool=true the default for all console apps, that would be much nicer. But I guess it's too late in .NET 10 cycle now to do that. Perhaps we can do that in .NET 11?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly lean that we should make PackAsTool=true the default for file-based apps; if you are packing a single file then it seems extremely likely that the intent is to create a .NET tool, rather than a class library.

I also see the issue with drifting from the defaults when we convert to a project. Controversially my suggestion here is simple: don't add the property as part of grow up. Yes, it means that if you grow up a project and then pack it you get a different behavior, but it seems extremely noisy to add this to every project file when most of them won't need it. The number of users it will impact seems small. Instead, we just document the difference as an annoying paper cut and move on with our lives. IMHO the benefit of packing files as tools outweighs the pain of a small divergence.

@jjonescz jjonescz requested a review from 333fred August 15, 2025 10:23
@RikkiGibson RikkiGibson removed their request for review August 15, 2025 21:47
@RikkiGibson
Copy link
Member

Removing my assignment since I speculate Fred and Chris's sign off will be enough. Let me know if I misunderstood something. Thanks

@jjonescz
Copy link
Member Author

@333fred for another look, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-run-file Items related to the "dotnet run <file>" effort
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support packing file-based apps
7 participants