I don't know if that pattern has a name, but I really love that on my team if there is a script it should be runnable through the Makefile. I know some people are very good a remembering commands, but I'm not and being able to do `make docker`, `make init`, `make eval`, etc... really simplifies my workflow.
There can definitely be some downsides to this approach. For example, let me see what the CI script does to deploy. "make deploy", ok let me checkout the Makefile. Ok, that calls some python module "deploy.py". I tend to get frustrated with all the indirection and would prefer to just see the deploy steps in the CI script itself.
I mean that example is frustrating because obviously `make deploy` and `python deploy.py` are both pretty simple so they are easy to remember.
One common pattern that I'll see though is deploy.py not being top level so `python deploy.py` becomes `python scripts/deployments/staging/deploy.py` so you still get the benefit of not wondering where `deploy.py` is.
Another is the configuration file also having a default version that is not obvious. Something like `configuration/deployments/staging.yaml`.
Now you might argue that I'm exaggerating (and I think it's fair to say that some refactoring could be valuable), but the simple `python deploy.py` now actually is.
`python scripts/deployments/staging/deploy.py -c configuration/deployments/staging.yaml` which is significantly harder to remember than `make deploy-staging` for example.
I am a big advocate for and user of this pattern with Make.
However there is one non-trivial downside with (GNU) Make, and that is the non-visibility of env vars set with `export` when running `make -n`. That is, if your Makefile looks like this:
Then `make -n do-it` will not show the exported FOOBAR variable. This makes it somewhat more difficult to audit or inspect with `make -n`.
The output from `make -np` is incredibly verbose and isn't easy to filter with standard CLI tools, which makes this doubly frustrating. You basically need to write an AWK/Perl/Python program to parse it. If there was one feature I'd pay good money to add to a new version of GNU Make, it's an option to emit more-easily machine-readable output from `make -p`, or to ship a script in the GNU Make package that parses it into something standard like JSON or XML.
It's nice to be able to run the same commands locally as you do in CI. Having the deployment logic outside of the pipeline specific format will allow you to do this.
Make is great because its usually installed everywhere. The downside is that it has a lot of edge cases. Breaking out right away into a better language for the more complex tasks can make sense.
I can certainly sympathize with not liking the extra layers, but if you put the steps directly in CI then you either duplicate local/CI steps (and they inevitably get out of sync), or CI becomes the only way to deploy (which, depending on your situation might be fine). It can be a reasonable thing to do, but it's a pretty sharp tradeoff.
I don't think that depending on CI for deployments is the worst thing you can do. You get two good signals; 1) this compiled on my machine, and it compiles on some other random machine, so it's looking likely that this binary will start up on the prod servers ok. 2) there is some proof that the test suite passed before you ship your thing to production.
I'm really pretty OK with "if CI is down, and there's a prod emergency, and the test suite is broken", not everyone on the team can fix that. Escalate to someone who can, the 0.5 times this happens a year; the rest of the time, everyone clicks "merge" on their pull request and the code filters out into production quickly and efficiently. They don't want to think about it, but the customer gets their features as soon as possible. Not the worst thing. Way better than "our release person is on vacation, we'll restore your outage next week".
Even better, make this recipe's dependencies work so it doesn't do anything if you don't need to run init, then have everything else depend on init. That way no one needs to remember to run init first.