Closed blackdwarf closed 4 years ago
There is a functional prototype at https://github.com/DamianEdwards/dotnet-new2
@ajaybhargavb this is for you.
nice having a way for templates outside instead of embedded resources :+1:
I'd like to add the feedback from old thread dotnet/sdk#4695:
Make the common use case short using positional arguments (in addition to named arg)
the most common use case: dotnet new name type
( about --lang, see next comment )
so these are equivalent:
dotnet new hello_world console
dotnet new --name hello_world --type console
some examples in https://github.com/dotnet/cli/pull/1124#issue-129854435
Using another language is ok with --lang
( or -l
)
dotnet new hello_world console --lang f#
or if you want, the old proposal was [lang]/[type]
like
dotnet new hello_world fsharp/console
About other languages support ( just to check my use case ):
--list
should output all templates installed, --list --lang f#
only the templates who support f#--list --lang vb
should show grouped templates ( like aspnetcore
) if at least one of aspnetcore subtemplates support vb (let's filter out useless groups, but i'd like aspnet to support f# :smile: )That's useful not only for people who use only one language, but for poliglot who have multiple languages installed (i use c# and f#, both a lot)
Now the bonus points (suggestions) for a better cross language experience.
The c# is the default language, np about that, there is --lang
and it's ok (was already discussed and it's ok).
But i think we can improve experience for others without changing c# experience:
dotnet-new
for example an env var DOTNET_DEFAULT_LANGUAGE
(see https://github.com/dotnet/cli/issues/1118#issuecomment-188790061 )--list
write name of supported languages near template name~/code> dotnet new --list
MS.DotNetCore.New.Templates 1.0.0
- Console Application [console] (C#, F#)
- Class Library [classlib] (C#, F#)
MS.DotNetCore.New.Templates.AspNetCore 1.0.0
- ASP.NET Core Empty Application [aspnetcore/empty] (C#, VB)
Created C# project "MyApp" in ~/code/MyApp
Created F# project "MyApp" in ~/code/MyApp
about the issue load templates from nuget (last feedback i promise).
TemplatePackageId
? )-u|--uninstall <TemplatePackageId>
should have a [version]
optional argument, because maybe i want to have multiple version of same package (bugfix, stable vs dev) and i want to install/uninstall specific versionsThe following is more a request, and maybe it's already like that.
Not everyone use nuget always, or publish to default nuget.org feed I understand the pro, it's nice for discoverability/versioning/tag/author etc but it's a big requirement a zip files with some static template files inside (and no dependencies).
i see --install <TemplatePackagePath>
i hope that mean i can install from a package directly (using url or file path).
It's possibile to not bind the implementation to nuget packages only? templates are only a zip file with a structure and a template.json, we can consume it as zip file, no need to parse as nuget packages.
It's nice if i can just install a zip from url (from example from a github repo zip like https://github.com/dotnet/cli/archive/rel/1.0.0.zip ) or a local directory zipped.
Offline help a lot too, no need for directory + project.json + dotnet pack
.
Pinging @sayedihashimi just in case he hasn't seen this...(although I'm sure he has)
:eyes:
With dotnew new
we are interested in enabling an experience for users to create new projects from the command line. Creating projects from the command line is not a new concept, it's been around for a while especially on the web development side. One example of a successful command line project generator is yeoman
. Yeoman is a super popular tool for developers, and if dotnet new
is as successful as yeoman, IMO, that would be a really wonderful thing. To enable a meaningful discussion on dotnet new
let's start by taking a look at a typical user experience when using yeoman
to create a new project. Below are typical steps a user would take to create a new project from the command line.
From the set of steps above, we can break this down into the following categories.
I think that dotnet new
should focus on the overall end user experience. Which consists of the following, Template discovery
and Command line interaction
. When the user selects and invokes a template, dotnet new
will handle prompting for project properties and then call the generator (with a consistent way to pass project properties). The template should be able to use any "template generator" that it desires. dotnet new
will have a template generator available out of the box which can be used. For scenarios in which the default template generator doesn't meet the needs, it can always be switched out for a different implementation.
In my case I work on delivering templates in the following areas.
yo aspnet
dotnet new
(future)Today for VS and yo aspnet
we have to author templates once for VS and once for yo aspnet
. In addition the template infrastructure that we use for the VS side is very fragile and difficult to maintain. Once we enable templates in dotnet new
it's yet another place for us to invest in creating templates. Instead of maintaining three different templates I'd like to have one way to create templates from the command line, and then reuse that tool everywhere. So we author templates once in dotnet new
which enables the command line experience with dotnet new
. Then in Visual Studio we create "shim templates" which will allow us to present the UI to gather parameters and then call into dotnet new
for the project creation process. For yo aspnet
we would do a similar thing.
Brokers are decoupled from specific generators via a set of C# interfaces. This will allow us to maximize reusability of generators in different scenarios including; command line, Visual Studio, yeoman, etc.
Here is a typical user session when creating a new project and a high level of what happens.
When dotnet-new
or Visual Studio are installed the following happens.
Users can add additional sources to enable using additional generators.
X
)
X
X
and stops when a match is found (or some other heuristic to find the single generator to use)Q: Does this mean yo aspnet
will go away?
A: Absolutely not. yo aspnet
has had some wonderful success it's not going anywhere. The idea is that we will create a self-contained template tool and then plug that into: VS, dotnet new
, yo aspnet
, etc. By allowing us to author templates once it will allow us to bring a better experience in yo aspnet
. And it will enable us to keep templates in sync at all times across all end-user experiences.
Q: Why not just use yeoman here?
A: Yeoman has a lot of dependencies which are required to use it. It makes sense to have an entry point in yeoman because many people already have it installed (or some of it's dependencies). There are drawbacks from shipping/using yeoman directly by Visual Studio include the following.
@sayedihashimi I like this approach, supporting existing solutions with a new abstraction (dotnet new) and making VS templates easier by providing a shim to dotnet new templates. Also agree Yeoman has too much baggage to be the official solution. Well documented and thought out!
@sayedihashimi can you add some examples of invocation of this new dotnet new
you imagined on the command line? I'm fine with VS, but would love to see how complex/simple this would be in the shell.
@blackdwarf the specific user interaction is orthogonal to my ideas. What you have above should work with my proposal. Since there is an abstraction between the broker (dotnet new) and the template generator, you should be able to define the end user experience completely.
I'd like to make sure the local template story is good, so we may need to add more to what you have.
@sayedihashimi ah, I see. When you say a "local template story", you mean templates that are installed with the SDK/other?
@blackdwarf
@sayedihashimi ah, I see. When you say a "local template story", you mean templates that are installed with the SDK/other?
I should have said "local template dev story". Let me explain by example.
When developing templates in Visual Studio with SideWaffle/TemplateBuilder I can CTRL+F5 (or F5) to start the VS experimental instance with my template vsix loaded.
When developing templates with yeoman I can use npm link
to point to my local copy of yo aspnet
so that I can try the templates via yo aspnet
during development.
When developing templates for dotnet new
there should be a similar story. Requiring users to create a .nupkg to share their templates widely is fine (similar to yo with npm packages), but users shouldn't have to create templates from .nupkg files locally during template development.
I think what we have here is a good start but for a complete template story we need more details like.
dotnet new
picks up the new version)?nuget.config
here or provide users the option of adding specific feeds for dotnet new
?What about "dotnet new http://github/shanselman/whatever/something.git" where a repo has the template
@shanselman Would that effectively be just git clone http://github/shanselman/whatever/something.git && rm .git
?
@svick I'm thinking it'd be more like the Uppercut project years back. You'd say dotnet new "foo" gitrepo and then {{classname}} would be replaced with foo. So a clone, then a global search and replace. Brainstorming.
@shanselman @sayedihashimi's design actually allows for that, I think. Honestly, the more I think about it, the more it sounds like a good idea. But then why not go the full monty here and allow something like dotnet new http://tempuri.org/template/thing
or similar for file shares? Brainstorming (I like this notation :))
@shanselman we can directly use github zip link as url, instead of git repo so is a dumb zip (no deps on git or github). also easier to host in S3. The proposed format define arguments/parameters/questions, so can be used by gui or command line. That's nice (arguments) because it's not bound on a specific language.
@blackdwarf it's something someone is implementing now or can be up-for-grab from community? last time i think i read about was in progress.
Maybe a simple iteration first (zip+url) because it can help a lot to show new developer (new of .netcore) how to do something. atm are embedded in dotnet new
, so each new tempalte is waiting merge (i'd like to merge F# lib for example, it's confusing for new users)
@enricosada at this point we are hashing out the design. Once design is in place, we will figure out the next level of details. :smiley:
But it is interesting to do the ZIP thing. However, do take into account that not all people use GH for hosting, that is, maybe someone would like to point this to a random git repo hosted somewhere/somehow and have it work.
do take into account that not all people use GH for hosting, that is ..
@blackdwarf i was proposing zip from github repo, instead of git repo. I dont understand why we need to add git, because we dont need to manage versions or branch. Just download a zip, unzip, done. If someone doesnt want to use github, can just upload a zip somewhere. Really useful for bootstrap things for new users (i'd like to add http://suave.io template for example).
in v1 we can do unzip only of package. In v2 add arguments/replacements. etc. So it's working asap (i really love do have it :smile: )
We should only do the Zip thing if it's a GIT thing and not a GitHub thing. We don't want a design that is tied to a single provider.
@shanselman it's a github thing ( but git archive
exists). I dont see how a design tied to git
, a versioning tool, instead of a dump zip files may be more complex. btw it's easier to support both scenarios.
dotnet new --from-zip "http://example.com/fable-template.zip"
and
dotnet new --from-git-repo "http://example.com/fable-templates.git"
:-1: on zip simply because it might accidentally imply that someone should throw their code up on a server somewhere in a zip file. This behavior is awful. Use of source control should be encouraged at every opportunity. Free source control providers exist, so this really isn't a test of means.
@factormystic the nuget packages are zip files, the .docx are zip files. It's an artifact. i can create it from git archive
.
clone a git repo mean you need a git command line, and usually you need to specifiy a branch or tag.
I am not against it, but not as the only option.
Thanks for all the great comments. I'm loving the discussions here. We are designing this so that we can accept templates from different sources. We will likely start with:
Hopefully in the long term we can come with a story where 3rd parties can implement different template sources. We have discussed git, and I think that's a very interesting idea, which likely has a lot of potential. With that said we have to make progress in some other areas before we tackle the sources problem fully.
@enricosada
@blackdwarf it's something someone is implementing now or can be up-for-grab from community? last time i think i read about was in progress.
We are just now getting started (we are meeting today to take a deep dive on design) with the RTM (tooling) version of dotnet new
. There is nothing to send a PR to at this time, but hopefully in a few weeks we will have something.
We are designing this so that we can accept templates from different sources. We will likely start with: •NuGet package •.zip file •Folder
Will the NuGet package support include the ability to pass a Uri to a package? My organization (county government), like many I am sure, has its' own internal NuGet server. We already get some benefit by sharing our packaged code internally between dev teams. The ability to post our project & item templates there as well would be a great benefit.
@theBoringCoder the current design relies on the package existing on one of the configured feeds (managable via a nuget.config
file). In your case, the private feed containing the packages of interest would just be present in that file. When the template gets "installed", the .nupkg matching the package id (maximum version) would get copied into the local cache and the contents would be usable from that location for the purposes of template creation. Updates to the templates would work in a similar way - you'd either be notified (or just have the option to update) about newer versions of the template package being discovered on the feed and have the ability to acquire and use the new template content instead of the currently cached version.
I work on the ASP.NET MVC Boilerplate project template which:
All of the above is done after project creation using hooks in VS. I'd love to bring this to dotnet new
but:
dotnet new
.dotnet new
. There must be some sort of UI story there?@RehanSaeed look at eslint for an example of how to implement multi step configuration decisions on the command line. Not having a GUI is fine.
@RehanSaeed good to see you here.
@RehanSaeed your needs are very similar to our own (ASP.NET team). I think everything that you mentioned will be covered, but it may be difficult for me to explain without the code samples to go along with it. We should have that in a few weeks I think but not totally sure. I'll explain how we are planning to approach this from the One ASP.NET side and then you can comment if it makes sense for you.
From a design perspective gathering inputs is on the broker
side of the house. For the CLI there will be a common broker that will be used. It will run through the parameters defined by the template and then prompt the user for the values. This can be done in a generic fashion. For the same template when used in VS, the broker
will be in the form of a custom wizard (we may have one that can be used but miminally we'll provide code samples for the short term and a better plan long term). The custom wizard will be responsible for showing the right UI and getting input from the user. After input is gathered it will call the generator.
Now, how does this work when a template support options like:
So the UI will gather the input. After that it will invoke a generator. In the One ASP.NET case we are planning to create a single template which covers the different auth options. Then in the code we will add sections to indicate whether it should apply for each auth option. For example you may see something like the following in .cs files.
#if NO_AUTH
// code here for no auth
#endif NO_AUTH
#if ORG_AUTH
// code here for org auth
#endif ORG_AUTH
#if WIN_AUTH
// code here for win auth
#endif WIN_AUTH
We will have similar expressions for files that are not code files, so you'll be able to use this same technique across all file types.
Then when you invoke the generator and pass the parameter for Individual Auth the resulting code in the template will be whatever is in the #if for IND_AUTH (minus the #if and #endif lines of course).
We will also support a model where you can have files that are dropped for a specific set of options.
Regarding shared UI code, I'm not sure if that makes sense. For example when plugging in a template into yeoman, you need to run through normal yeoman prompts for gathering input. When running in VS we need to implement with a wizard and maybe custom UI with WPF, when adding it to VS Code you'll need to create an extension which uses HTML/JS/CSS for the UI. So I don't see much benefit in trying to create a shared UI experience. There are technical challanges there as well as user experience consistency issues.
I'm confident that what we are creating will meet your needs.
Hi @sayedihashimi. Agreed it's difficult to discuss without a code sample but a few comments anyway:
If the CLI broker component which asks the user questions is common, it needs to be flexible enough to support Yes/No questions, Multiple choice questions (Looks to be supported according to your Auth example) and perhaps free text questions (I don't use this one yet but I have considered adding something like this to ask for the site name as an example).
So you are using pre-processor directives for conditionally adding/removing logic. I do a lot of this and have some comments. I think it is very important that the project should still compile and be usable even though you have conditional logic in there.
Using your example, a C# or JavaScript file uses:
// $Start-Auth-NoAuth$
// code here for no auth
// $End-Auth-NoAuth$
// $Start-Auth-Org$
// code here for org auth
// $End-Auth-Org$
// $Start-Auth-Windows$
// code here for win auth
// $End-Auth-Windows$
However, a Razor file would oook like this:
@* $Start-Auth-NoAuth$ *@
code here for no auth
@* $End-Auth-NoAuth$ *@
@* $Start-Auth-Org$ *@
code here for org auth
@* $End-Auth-Org$ *@
@* $Start-Auth-Windows$ *@
code here for win auth
@* $End-Auth-Windows$ *@
// $Start-Auth-NoAuth$
int i = 1; // Not commented and used in the development time compilation of the template.
// $End-Auth-NoAuth$
// $Start-Auth-Org$
// int i = 2 // This code is uncommented if Org is selected.
// $End-Auth-Org$
// $Start-Auth-Windows$
int i = 3; // This code is uncommented if Windows is selected.
// $End-Auth-Windows$
If you are creating a manifest of features and the CLI is a shared component, then I suppose that means UI can also be a standard component provided by Microsoft. I'm not sure how I feel about that, it would be nice to have some UI customization:
This all looks great!
One further (but minor) point that you're probably already considered but I didn't see mentioned: restoring dependencies.
Obviously, after creating the initial project file layout, templates will need to invoke dotnet restore
. But also they'll often need to invoke other tools like npm install
or webpack --config <somefile>
so that the generated app will run correctly.
If the templates can execute arbitrary C# code (as in @RehanSaeed's comment above) then that's sufficient. I'm guessing this is pretty inevitable because you couldn't configure something like this declaratively (the actions you need to take might vary according to options chosen by the user).
As @SteveSandersonMS mentions, running arbitrary code is essential.
This https://github.com/ligershark/microsoft-templateengine/issues/56#issuecomment-239863106 issue is also relevant to this topic. In it, I add two more issues that a templating engine must support:
//#if FOO
// Some comment
int i = 0;
//#else
// // Some comment
// int i = 0
//#endif
//
as the default.<!-- -->
for HTML and XML based formats.@* *@
for Razor.#
for text based formats e.g. nginx.conf, robots.txt etc.@RehanSaeed @SteveSandersonMS we're still looking at if and how running arbitrary code during template instantiation specifically should work - in almost all cases, it's a step before the creation (collect some information to supply as parameters to the actual create operation) or a step after (to install dependencies or configure things on the user's machine to give a better development experience). Both of these often would require dependencies to be installed/present on the machine running the command without a particularly clear way of expressing that they're required (or how to obtain/install them - performing some npm commands after the template has been instantiated for example requires npm and would have to either detect it/install it before running it or fail gracefully and provide instructions no matter what OS you're on). That's not to say it won't happen, just that it needs a bit more design before it does.
With regard to the conditional syntaxes, these can be accomplished without running arbitrary code per se. The update that brings the automatic uncommenting of blocks is nearly ready (first commit for it was https://github.com/seancpeters/microsoft-templateengine/commit/60f7f149b7e1e81b9deb0e758002e56f9cdadec8 more tests are being added to make sure it's all right, the default preprocessor markers will be added/updated before it's pulled in)
dupe of dotnet/cli#5387
As it currently stands,
dotnet new
is a good command for people to get started with simple projects. However, it suffers from several things:This issue suggests a new form of
dotnet new
that solves the above problems. It also replaces the old dotnet/sdk#4695 that will be closed in favor of this one./cc @DamianEdwards @piotrpMSFT @Eilon @enricosada
.NET Core CLI: new
The
new
command is used to create new .NET Core projects. Projects are created using templates installed via NuGet packages.Templates are laid out in their NuGet packages in a hierarchical fashion that enables the creation of simple trees of templates with categories that are then merged across the installed template packages to create an overall template tree. This tree allows the display of an interactive menu when creating new projects, while also allowing for direct project creation using a template node's full path, e.g.
dotnet new -t aspnetcore/mvc/empty
As templates are in normal NuGet packages and installed into the standard NuGet packages folder, they can depend on other NuGet packages that are used in their templates, such that when they're installed, all the required packages to create new projects using the contained templates are installed too.
Using the Command Line
Displaying help:
Listing installed templates:
Installing new templates from a package:
Creating a new project with a specific template:
Creating a new project using the template menu:
Authoring Templates
Templates are placed in NuGet packages in the
content/templates
folder. Optionally, in the root of the folder is atemplates.json
file that describes the templates contained and if present is used to enhance the project creation experience.The layout allows for multi-level category nodes with template nodes as the leaves. In the case a category node contains just a single template node, that template will be automatically selected when the category is chosen.
Example templates.json
Example
templates.json
for the default templates:Package Files Layout
The following demonstrates the layout of template NuGet packages. Note how templates from separate packages can share their structure such that they're templates can occupy the same parts of the resultant installed template "tree".