-
-
Notifications
You must be signed in to change notification settings - Fork 29
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
Igniter task to install Phoenix #140
Conversation
"" | ||
end | ||
|
||
!String.valid?(Rewrite.Source.get(source, :content)) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some files do not have a valid string content, for eg binary files like favicon.ico
but I think we still need to display that such file will be created. Might need to improve this code to detect updates as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably add it in this or to avoid confusion. Can use changed?
mix.exs
Outdated
@@ -100,6 +100,7 @@ defmodule Igniter.MixProject do | |||
{:spitfire, "~> 0.1 and >= 0.1.3"}, | |||
{:sourceror, "~> 1.4"}, | |||
{:jason, "~> 1.4"}, | |||
{:phx_new, "~> 1.7", runtime: false}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 This one is tough. I don't actually think we need this. IIRC phx_new
will be available as long as the user has the archive installed? Which could mean that we can just at the start say "please install phx_new
to use this task" if the module is not defined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we could have it as a test only dependency in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't actually think we need this. IIRC
phx_new
will be available as long as the user has the archive installed? Which could mean that we can just at the start say "please installphx_new
to use this task" if the module is not defined.
Should we have it as an optional dependency, in that case? That seems like the best of both worlds: It doesn't become a transient dependency that all apps using Igniter are required to fetch, but it still allows Igniter to test against it and specify a version spec that Igniter's compatible with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I think that would make sense, yes. Since we'd be switching in our code on the module being compiled, it wouldn't matter if it's from a dep or the archive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to optional: true
and added a check. Tested in a project, it will ask to install phx_new
if not available.
This is awesome! Having not looked at the code yet, a couple quick thoughts:
|
Not required. You can execute the task in any project, the files are relative to the root path. So that can potentially be used to upgrade Phoenix in your app for example.
I was thinking about it and forgot to propose in this PR 😂 |
- make :phx_new optional and check if it's loaded - add remaining user-facing opts - require Elixir ~> 1.15 - validate %Project{} - use Phoenix extension
This looks great to me! One thing we want to do is see if we can possibly get @josevalim or @chrismccord to chime in. I think this would be an eventual path towards having Phoenix be installable in an existing project, and playing nicely with igniter etc. When I floated the idea by @josevalim before, he wasn't a fan of the idea of us maintaining a separate Phoenix generator. I also don't like it that much, but this is a middle ground since we're mostly calling into Phoenix to generate the results. But it turns out we need the ability to do this because we have to be able to test code generators that work on top of Phoenix (because most or many elixir apps are Phoenix apps). |
The biggest concerns to me are:
Of course, Phoenix is perhaps the most complex example, but that's historically why Phoenix is a installer and not a patcher. |
@josevalim thanks for the feedback! This is going to be a lot, I know, but please bear with me 🙇 I think we should break the discussion into three main parts:
Whether or not the igniter pattern is something that the phoenix team will ever adoptDetermining this is pretty important (from igniter's perspective), because ultimately we are going to need a way at least for testing for us to generate phoenix projects in a way that plays nicely with our testing patterns (working against a "virtual fs" essentially). If Phoenix has no particular interest in adopting these patterns (that interest I'm sure depends on the subsequent steps of what it looks like in practice and how we arrive there gradually), then it actually simplifies things pretty well for us. We can plow forward with these tools and tell folks *only use this for testing, as it may break if phoenix upgrades stuff, at which point we'll have to fix it". What the end result would look likeSo this is where we talk about what it actually looks like to have these composable installers. I really do think that this is very doable, but there are a few things to understand about how igniter works today. For context, Ash already has five composable installers, one of which (ash_postgres) does a complete ecto installation. When run on top of an existing Phoenix app, it only makes the ash_postgres specific changes. This requires careful design, but is quite doable. You can also look at the installers for What it looks like in practice for Phoenix & EctoEcto defines an installer. This is a mix task called This installer looks a lot like what defp install_phoenix_ecto(igniter) do
if Igniter.Project.Deps.has_dep?(igniter, :phoenix) and !Igniter.Project.Deps.has_dep?(igniter, :phoenix_ecto) do
Igniter.install(igniter, :phoenix_ecto)
else
igniter
end
end Phoenix could have the inverse. Now, Additionally, igniter supports a composable design pattern in general, just like I would suggest that adding an igniter installer to ecto might even be a better starting point, even if phoenix doesn't use it (at first or ever). Important: using igniter does not force you to write magical installersThis is something that I think is very important to point out. In many places in our installers, if a certain module already exists (we suggest giving us module names you want to create, and we figure out where they go according to elixir conventions), we don't try to magically install on top of it. We just show a notice to the user "unable to create X.Y.Z, as it already existed". Phoenix could switch its installers to igniter, and only use igniter for things like patching So even without using the patching/code updating side of things, what are the benefits?:
igniter
|> Igniter.compose_task("ash_authentication_phoenix.install")
|> assert_has_patch("lib/test_web/router.ex", """
6 + | use AshAuthentication.Phoenix.Router
""")
|> assert_has_patch("lib/test_web/router.ex", """
15 + | plug(:load_from_session)
""")
|> assert_has_patch("lib/test_web/router.ex", """
15 18 | pipeline :api do
16 19 | plug(:accepts, ["json"])
20 + | plug(:load_from_bearer)
17 21 | end
""") Not only does this testing story help internally with Phoenix, it allows other authors to test their installers on top of the default phoenix installer trivially.
How do we arrive there graduallyIt depends. If Phoenix is interested in this approach, then we could pause what we're doing here and work igniter into Phoenix directly. However, I think there is some risk mitigation that could be done by first proving out the patterns in igniter itself, reusing what we can from Phoenix, and then if everyone is happy we can start a migration out to the packages themselves. Then, we can find things that we are comfortable installing via patches if the relevant files exist already (if there are any), and implement those as modifications. All this will do is increase the likelihood that Thanks for reading my wall of textI know this was a lot of information, but I do genuinely believe that if we as a community can rally around these concepts, it can make a massive difference for QOL for developers |
Also worth noting that the new |
Hey there @josevalim @chrismccord I should probably move this discussion to a mailing list, as this has effectively become the place that I'm pitching igniter 😆 With that said, if its acceptable I'd be happy to talk here, and would love to know your thoughts on the above. |
Hey @leandrocp, would you say this is ready to go? I think we're going to want to merge this, if only to use as a base for testing igniters for now. Whether or not it turns into the basis for supporting igniter in Phoenix is its own question. But I think relying on these private APIs as a testing only tool that we can tell developers to expect to potentially break on subsequent phoenix releases should be fine. I'll happily take on the responsibility of adjusting this code to changes in Phoenix, and we will make it clear what its intended purpose is. Only thing we'll want to do is remove the shortdoc so it doesn't show up in |
Hey @zachdaniel sorry for the late response! Yeah this one should be good to merge to serve as a starting point. A few notes I'd like to highlight:
Those can be addressed in a following PR. |
There are likely a fair few things that would need to be addressed for this ever to be used outside the context of tests (like the way that it overwrites But that isn't really important at the moment. I'm happy to merge this, but would like the task to get its new name before I do. Running So for now, lets just update the task name it get it merged and experiment with using this for testing and go from there. Sound good? |
Sounds good, done 👍🏻 |
🚀 Thank you for your contribution! 🚀 |
Hey @zachdaniel here's the initial draft for
igniter.install_phoenix
. In short it does mimic phx.new.ex by wrapping generator.ex and single.ex to include the Igniter pipeline. With this approach we can reuse the same template files and reuse some functions, for egSingle.render/3
, and also allows us to gradually migrate the generator to use Igniter functions.Before moving forward, I'd like some feedback and review of the current code (see the comments).
To test this PR:
mix deps.get mix igniter.install_phoenix .