8000 Trying to figure out the best API · Issue #1 · tighten/mise · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Trying to figure out the best API #1

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

Closed
mattstauffer opened this issue Mar 4, 2025 · 29 comments
Closed

Trying to figure out the best API #1

mattstauffer opened this issue Mar 4, 2025 · 29 comments

Comments

@mattstauffer
Copy link
Member

Big questions:

  • Should it be Yaml (cleaner) or PHP (easier to do custom stuff, easier to parse and write)?
  • Does "recipes" of "steps" make sense?
  • How best to distribute steps and recipes that aren't "official"? How do we let people distribute their own?
  • Does namespacing steps make the most sense? e.g. step('duster/install') runs Steps/Duster/Install PHP class?
  • Should it allow for user input?
  • Is there a better way, other than this being a Laravel app, to build this so it can be as useful as possible for other tools (e.g. a modified Laravel installer or something) to use them?

Copied from current README for context (so that future people looking at this can understand the state of thinking at the time of creation):


Vision

I imagine it'll look like this. Once Mise is installed globally with Composer, you'll install a new Laravel app:

Usage

laravel new money-maker
cd money-maker

Then you can use Mise to apply presets:

mise apply preset1 preset2 preset3

Or you can use it interactively, where Prompts will let you choose which you want to apply:

mise apply

How it would work

I can imagine Mise comes with predefined "steps"; for example, a step named "duster" could do the following:

  • composer rqeuire-dev tightenco/duster
  • Run ./vendor/bin/duster github-actions
  • Run git add . && git commit -m "Install Duster"
  • Run ./vendor/bin/duster fix
  • Run git add . && git commit -m "Run Duster"

The definition for this step would be built into code in Mise, using some combination of convenience helpers that make common tasks (e.g. "git commit with message", "composer require dev") easy; then presets would include this step.

How presets/recipes would be defined/loaded

Presets would be defined... that's the hard part. I know some can be defined in Mise. And I know some can be defined locally. But what is a safe way to define presets to be shared?

  • Composer is too heavy, I think, unless one person/group wanted to release a whole pack of steps/recipes
  • Pulling from gists makes it too easy for someone just to update it to something nefarious and then you're running untested bash scripts on your machine
  • Clumsiest but safest is to just have a central site where you can share presets but you have to manually copy to them to your local machine

Also maybe some useful thing where you can set a configuration item so if you run mise default or something, it'll run a predefined set of presets, so you can say "all my new Laravel apps should have these three presets run" as your default.

Building a step

OK, so I'm imagining a step is single file (?), either a PHP class or a procedural PHP file. It could be yaml, which would be cleaner, but wouldn't allow for arbitrary PHP. Maybe allow both?

Let's imagine duster is a step. Maybe this? Will keep working on the API...

namespace Steps/Duster;

class Install extends Step
{
    public function __invoke()
    {
        $this->composer->requireDev('tightenco/duster');
        $this->git->add('.')->commit('Install Duster');
        // or $this->git->addAndCommit('Install Duster'), not sure
        $this->exec('./vendor/bin/duster fix');
        $this->git->add('.')->commit('Run Duster');
    }
}

I can imagine we'll want tooling to create files, replace content in files, rename or move files. More Git tooling, more Composer tooling, NPM tooling.

Some of this will come from having a filesystem component directly available, and, of course, access to the entire Laravel world through the container. Some it'd be nice to have one-off commands or even little suites of tools (e.g this git helper described above) to simplify some of the steps. I'll be looking to Lambo and Valet for at least some inspiration on those.

Building a recipe/preset

Let's imagine we have a preset for creating a new Tighten SaaS. What steps do we want to take after laravel new?

We could have it be a simple YML/JSON file... just with a list of steps... or it can be a PHP file so it can have standalone work outside of steps, or pass configuration items to steps?

class Tighten extends Recipe
{
    public function __invoke()
    {
        $this->step('duster/install');
        $this->step('duster/ci', someParameterHereOrWhatever: true);
    }
}

I don't know if I want any steps to take user input, but if they can, doing it as a class would help that:

class Tighten extends Recipe
{
    public function __invoke()
    {
        $this->step('duster/install');
        $this->step('duster/ci', someParameterHereOrWhatever: true);

        if (confirm(label: 'Do you want to install our frontend tooling?')) {
            $this->step('tighten/prettier');
        }
    }
}

Reference

  • Valet
  • Lambo, especially this PR: WIP Presets work lambo#185
  • Josh Manders announced a tool Skeletor while I was plotting this; his tool is primarily hooking around Composer so I'll consider it a cousin :)
@edgrosvenor
Copy link

"Clumsiest but safest is to just have a central site where you can share presets but you have to manually copy to them to your local machine"

If there's a central site, it could have an api. So maybe the presets get saved there and can be installed with something like

mise:install-preset artisan-build/set-up-pint

Then the preset gets pulled down and stored where it needs to be.

@mattstauffer
8000
Copy link
Member Author

mise:install-preset artisan-build/set-up-pint

Then the preset gets pulled down and stored where it needs to be.

Oh, that's a clever way to handle it. So it's not installing directly from the repo, but instead forcing you to look at it, make sure you like it, etc. Maybe even forces you to look at the code before you accept it.

@mattstauffer
Copy link
Member Author

Also a note: It's possible steps are PHP but recipes are yaml. Just curious whether yaml can actually be good enough to handle things like nested confirmation and taking user input. Probably not, tbh.

@nicodevs
Copy link
Contributor
nicodevs commented Mar 5, 2025

Hey @mattstauffer, here’s my take!

I put it in a separate Gist because it’s kinda long 😅

https://gist.github.com/nicodevs/0cfd8780d5bc952243fb31b07aae665c

Thank you for reading!

@gcavanunez
Copy link

@nicodevs love the Lego it approach! - perhaps even these's steps

curl -L https://mise.com/nicodevs/money-maker-api.txt -o recipe.sh
chmod +x recipe.sh
./recipe.sh

could take the shape of a cli

mise apply nicodevs/money-maker-api

so that it's 2 tools

  • the mise app for discovery of different recipes
  • the mise cli that pulls the recipes and executes plays

@PovilasKorop
Copy link

Hey guys, honored to join the discussion and look at Matt's idea!
Here's my quick first train of thoughts.

It reminded me of a post-create-project-cmd option in new community starter kits, pointed out by Tony: https://x.com/tnylea/status/1897439530573258825 with this example from React starter kit:

        "post-create-project-cmd": [
            "@php artisan key:generate --ansi",
            "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
            "@php artisan migrate --graceful --ansi"
        ],

Also reminds me a bit of GitHub Actions (YAML, then?).

But @nicodevs I like your approach of accessing a Bash file and executing what's inside.

I think this idea would work best as a library of Bash scripts/recipes, because in reality most developers do exactly that: execute some scripts they have internally, prepared from experience with multiple projects.

But if it's a public thing, then, as someone mentioned, the validation becomes a problem. Who would guarantee that those scripts wouldn't break anything? They may do it unintentionally, just by not following some latest convention or something.

Similarly to community starter kits now: they are not checked/validated by core team (and they shouldn't do it, obviously), so who would be trusted that the starter kit is updated, secure, etc?

Also, as the first MVP approach, maybe it's worth to just publish 10 random recipes on GitHub somewhere, that would paint the picture of real examples, and then people would get the idea and contribute? So, potentially, it's maybe even not that technical project about parsing YAML or something else, but rather an idea to gather Bash/other scripts used by people?

Happy to discuss further.

@mattstauffer
Copy link
Member Author

Hey @mattstauffer, here’s my take!

I put it in a separate Gist because it’s kinda long 😅

https://gist.github.com/nicodevs/0cfd8780d5bc952243fb31b07aae665c

Thank you for reading!

Thanks so much for writing that up!

My thoughts:

  • Gosh, you're such a fantastic communicator
  • Why I'm leaning towards PHP, not bash:
    • I've built a lot of command line tooling. The number of people who can write PHP using wrappers around command line tools, vs the number of people who can write bash... testing php vs testing bash.. performing structured updates on PHP vs bash (e.g. "find every project requiring old tailwind and mark it as needing review")... I really want something structured, not just bash
  • I like the idea of us reviewing steps!
  • I like the idea of your private steps in an app
  • I like the idea of step parameters in a recipe

@mattstauffer
Copy link
Member Author

It reminded me of a post-create-project-cmd option in new community starter kits, pointed out by Tony: https://x.com/tnylea/status/1897439530573258825 with this example from React starter kit:

        "post-create-project-cmd": [
            "@php artisan key:generate --ansi",
            "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
            "@php artisan migrate --graceful --ansi"
        ],

There's actually a project out by my friend Josh which uses Comper's post-create-project-cmd:

https://github.com/aniftyco/skeletor

Part of the question of Mise is whether it can offer something that Skeletor doesn't.

But if it's a public thing, then, as someone mentioned, the validation becomes a problem. Who would guarantee that those scripts wouldn't break anything? They may do it unintentionally, just by not following some latest convention or something.

Yah. That's why I like the idea of some official "steps" and also you can bring your own. We'll verify the official steps but nothing else.

Also, as the first MVP approach, maybe it's worth to just publish 10 random recipes on GitHub somewhere, that would paint the pict 8000 ure of real examples, and then people would get the idea and contribute? So, potentially, it's maybe even not that technical project about parsing YAML or something else, but rather an idea to gather Bash/other scripts used by people?

I think that's a good idea. I still don't want them as Bash, though lol.

@mattstauffer
Copy link
Member Author

I think Skeletor is currently a useful tool, albeit new and in progress, for holding on to your recipe you want to always run when you spin up a new app. It's very similar to Lambo's post-install recipes in that way.

There are two things I am excited about that Mise offers:

  • The ability to hook into a centralized system to share steps and recipes
  • The ability to use Mise not just on your personal apps, but as a part of build tooling to do things like re-build your starter kits every time a new Laravel installer comes out, or even possibly to distribute starter kits
  • I could even imagine Mise being used as a part of building and testing processes for starter kits, starter kit listing pages, and other automated tooling

@PovilasKorop
Copy link
  • Why I'm leaning towards PHP, not bash:
    I really want something structured, not just bash

Yeah I get the idea now: you're going for scenarios/recipes more complex than just a one-liner to run some php artisan something. Agree. Good old PHP, then :)

@mattstauffer
Copy link
Member Author

I only had a few minutes to work on this last week, but I started thinking about what the PHP shape would look like. Not done, but here's how far I made it:

#2

@tnylea
Copy link
tnylea commented Mar 17, 2025

Anything that can make Starter kits even better, I'm on board with 👏 This sounds really exciting.

I love the approach of providing developers with useful recipes. @PovilasKorop was right that it would be nice to see an example of a handful of recipes to get a clearer picture.

I'm trying to envision other recipes 🤔 for instance, some of these might be features like:

  • Teams
  • Roles and Permissions
  • Media Manager
  • User Impersonation
  • Billing
  • AI responses

I might be totally off with those 👆, but those are some big-ticket items I was thinking of off the top of my head. What are some of the bigger recipes you envision? Besides duster and linting tools.

The bigger mystery might be how each recipe would be applied/used. For instance, how would they interact with the Media Manager or implement Teams functionality in their app?

I can't wait to see how this progresses 🤘 Really excited about it!

Let me know if there's any way that I can help out.

@mattstauffer
Copy link
Member Author

@tnylea So, most of these things would be steps or components, not recipes.

Let's say you wanted to build a recipe that was a mega-starter-kit like the old Breeze.

The recipe would prompt the user whether they want dark mode, and if so, take the dark mode Tailwind step. It'd ask if they want teams, and if so, take the teams step. etc.

So in that way, Mise could distribute starter kit builders. The user would install Mise, and then run:

laravel new myProject
cd myProject
mise apply likeBreezeButBetter
(follow all the commands)

(we could even, if this was a common use case, have a Mise command that runs the laravel new myProject part for you, then runs apply after.)

But let's say you wanted to go the way starter kits are now: Just distributed repositories.

So let's say one of the starter kits is the "Laravel with React, teams, and user impersonation" starter kit. Good luck keeping that, and 20 other starter kit repos, up to date with every new change to Laravel, right? But you could build a Mise recipe for each of those 20, and every time something happens (new tag, once a week, whatever), you re-build those repos using Mise and, if they're different, push and tag an update.

In that case, there'd be a (CI?) build step somewhere that automatically runs laravel new react-with-teams-and-user-impersonation && cd react-with-teams-and-user-impersonation && mise apply teams-and-user-impersonation && (do git stuff here).

Make sense?

@mattstauffer
Copy link
Member Author

OK, new API point pulled from talking to Tony above:

  • mise apply runs the recipe against an existing Laravel app
  • mise init (or something similar), runs laravel new, CDs into the folder, then runs mise apply

So If I'm spinning up a new Laravel app using the "ai-chat" recipe:

cd Sites
mise init myCleverAiAppName ai-chat

or, if that doesn't feel good, maybe one has to be a param/flag. I dunno.

If you want to do it the standard way, it's:

cd Sites
laravel new myCleverAiAppName
cd myCleverAiAppName
mise apply ai-chat

If you're a starter kit maintainer and you want to distribute this kit using the Laravel standard --using flag on the installer, the first time you push up to the repo you'd follow the steps above. If you're pushing an update of the repo, I'm guessing we'd want to write up a workflow to make it easy to A) wipe out the contents of your directory for this repo, B) laravel new into that directory, C) commit and push.

@benbjurstrom
Copy link

@tnylea So, most of these things would be steps or components, not recipes.

This comment got me thinking, suppose I maintain a package that lets users sign in with magic links. It would be awesome if I could publish a set of mise steps somewhere in the repo that handles installing the package, publishing the blade files, updating the User model, running the migrations, etc.

Then a recipe author who wants to include my package could pull in the repo's steps with something like
artisan mise:add benbjurstrom/magic-links --recipe=LikeBreezeButBetter.

This would download the predefined steps to their local Steps directory and add the step calls to the likeBreezeButBetter recipe.

@mattstauffer
Copy link
Member Author

Oh. The idea of a package publishing its preferred Mise steps in the repo is faassssscinating. I had previously been assuming, as in my Duster examples, that the package author would PR a Mise step to the Mise codebase. And that's still a strong option. But putting those steps directly in the repo is also very interesting, and maybe allows versioning in a different way? Let me think about it a bit!

@mattstauffer
Copy link
Member Author
mattstauffer commented Mar 18, 2025

Talking with @PovilasKorop on a call, and we are brainstorming the first few recipes we should launch with:

  1. Breeze (recreated)
  2. Tighten's preferred stack (Duster, etc.)
  3. Blade starter kit maybe?

I think the initial pitch is probably about using this as an installer you run on your local machine.

composer global require tightenco/mise
cd Sites/
mise init myNewProject breeze
composer global require tightenco/mise
cd Sites/
laravel new myProject
cd myProject
mise apply breeze

We can deal with issues later of whether some recipes are hosted on a SaaS version, etc.

@mattstauffer
Copy link
Member Author
8000

I think the first version will not run laravel new, because I remember building Lambo it was a big pain to pass through all the terminal output of another app. So minimal API:

composer global require tightenco/mise
cd Sites/
laravel new myProject
cd myProject
mise apply breeze

@jonsugar
Copy link
Contributor

I think the first version will not run laravel new, because I remember building Lambo it was a big pain to pass through all the terminal output of another app. So minimal API:

Yep. It was a nightmare.

@jonsugar
Copy link
Contributor

I only had a few minutes to work on this last week, but I started thinking about what the PHP shape would look like. Not done, but here's how far I made it:

#2

I had a go at getting things started: #3

@tnylea
Copy link
tnylea commented Mar 18, 2025

@mattstauffer, totally makes sense. Thanks for clarifying.

Do you envision that each of these will have react, vue, livewire versions for some of the recipes that require a UI?

@mattstauffer
Copy link
Member Author

@jonsugar man you are great. Can't wait to read it over.

@tnylea Great question. It could go a few ways. It could be that someone has a React-specific recipe and it really only makes sense for React. OK. That's a React recipe. But let's someone else makes a recipe that either is very similar regardless of your frontend stack, or they're willing to do the work to maintain it despite there being huge differences between frontend stack. They certainly could publish a single recipe that asks the user which frontend stack they want, and takes different steps depending.

@WyattCast44
Copy link

@mattstauffer I love this general idea - I worked on something similar a few years back (around the time you were building Lambo), I still think the idea has legs.

It leverages the idea of a 'compose' file that you define your steps in. The majority of the API lives in the link below, but the readme also has a good overview:

(Forgive me Taylor for naming this Laravel Hub not Hub for Laravel - I was but a young new Artisan 🥲)

If you (or others) thinks the idea is aligned with your vision - would be happy to dust it off and add more details. :)

@mattstauffer
Copy link
Member Author

@WyattCast44 I already responded on Twitter, but I like the idea!

I think the main thing I want to think about is, and you can see me mention it above: is the choice to use a static configuration (Yaml) limiting when it comes to asking for user input or any other things that using PHP for config makes possible? I assume so, but curious whether you solved that problem.

@alexandersix
Copy link

Jumping in here a bit in the middle of the discussion, but as far as the configuration language goes, I'd 100% be in favor of PHP.

I have a handful of reasons:

  1. You get a level of control with PHP that you wouldn't get with YAML. Now, whether that is useful to everyone who uses this or not remains to be seen, but I think giving people a high ceiling to hit with regards to what is possible in the configuration is a big win over using a more concise, but limiting approach with static configuration.
  2. People using mise should know PHP, so there's no worry about the additional overhead of learning a new language, even if it is just for templating.
  3. Using PHP for config files lines up more with how Laravel handles configuration rather than how infrastructure systems (Docker comes to mind) handle configuration with YAML. Considering that this is a project that is closely tied to Laravel development as a whole, I feel like it's worth staying close to the Laravel style of configuration file if possible.
  4. Personally, languages that use whitespace to denote nested logic drive me crazy. This is 10000% a me problem.

Admittedly, these are just a handful of thoughts that have been bumping around in the back of my head for a few days, but hopefully they get the point across!

Regardless of the direction, I think this is going to be an awesome project to have around 🎉

@mattstauffer
Copy link
Member Author

Just got off a call with @WyattCast44. He's been building something similar to this but YAML, which is limiting (no conditionals, etc.), but if we were to think YAML is good enough, he's already much further down this road, even has a rudimentary NovaPackages-style app for sharing configurations and favoring others.

I think I feel safe to say:

  • PHP is the better option for me, for reasons we've discussed and also the reasons @alexandersix mentioned above
  • ... but I never want to build a tool if there's already a similarly excellent tool out there, so the question becomes:
  • Is the added feature set that comes from PHP (and the added "this is how we like to do config in Laravel") instead of YAML worth building an entirely new tool? Or do I just throw my effort at Wyatt's tool?

Of our currently-discussed use cases, here's what you can't do with YAML:

  • Re-build breeze (no conditionals)
  • Have anything where you're storing multiple versions in the same recipe (e.g. you can choose React or Vue at one step)

He did mention that he can add conditionals within a step. So you could potentially have "do you want this or not" inside of a step, and then the yaml just says "run this step". So it would be a React starter kit, but then when you tell yaml to add the Teams step, the teams step's YAML config could have a "confirm" parameter, and if you set that to true, the step asks the user if they want to install teams. So we're getting some conditionality.

I'm gonna think about this for a bit.

@mattstauffer
Copy link
Member Author

We've talked a lot at Tighten and I think, despite wanting to not take on another project if I don't need to, Mise probably has legs. Excited to read through #3 and start digging into what the Mise app will look like. Plus this gives me an excuse to go domain shopping.

Thanks for all your input, everyone!

@mattstauffer
Copy link
Member Author
Image

I'm offended by this price

@alexandersix
Copy link
Image I'm offended by this price

Time to pull out the ol' SaaS playbook and try to register usemise.dev 😅

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

10 participants
0