team-mate-pro/make
team-mate-pro/make is a Laravel/PHP package for make-style scaffolding, helping developers generate common boilerplate files and project structure quickly. It integrates into existing Laravel workflows for faster, consistent code creation.
This is not a Composer package — there is nothing to composer require and no service provider to register. It is a set of .mk fragments you pull into a project and include from your own Makefile. Treat it as vendored infrastructure, not a dependency, and pin it to a commit rather than tracking a branch (the repo has no stars, no dependents, and no release cadence to lean on for stability).
Minimal setup for a Laravel app:
# 1. Vendor it once, pinned to a SHA
git submodule add https://github.com/team-mate-pro/makefile .make
cd .make && git checkout <sha> && cd ..
# 2. Or, if you don't want submodules, copy the fragments in and commit them
mkdir -p .make && curl -fsSL https://raw.githubusercontent.com/team-mate-pro/makefile/<sha>/<fragment>.mk -o .make/<fragment>.mk
Then create (or extend) a root Makefile:
# Project-local variables first — includes read them at parse time
APP_NAME ?= myapp
PHP ?= php
COMPOSE ?= docker compose
include .make/*.mk
.DEFAULT_GOAL := help
.PHONY: help
help: ## Show available targets
@grep -hE '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-22s\033[0m %s\n", $$1, $$2}'
Where to look first. Read the fragments top to bottom before invoking anything — that is the whole documentation. Specifically look for: (a) the ?= vs = variable assignments (these are your override points), (b) any target that runs docker/composer/artisan so you know what it assumes is installed, and (c) hard-coded container names, PHP versions, or paths — those are what you will need to override in your root Makefile before the include.
First use case. Pick one workflow you currently run by hand and let the collection own it, typically make test or make up. Validate the tool actually matches your setup before adopting more of it. A Makefile collection is only worth it if make <thing> replaces a command you'd otherwise fumble from shell history.
Override variables in a per-machine file, not in the committed Makefile. Keep the shared Makefile clean, then add:
# Makefile (committed)
-include .make.local.mk
# .make.local.mk (gitignored) — local port bumps, path tweaks, PHP version
PHP_VERSION = 8.2
APP_PORT = 8081
Use -include (leading dash) for machine-local files so the build doesn't break for the next developer who hasn't created one yet.
Wrap Artisan through the container boundary explicitly. The single most common friction point is targets that assume PHP runs on the host when it actually runs in Compose (or vice versa). Define one indirection and use it everywhere:
ifeq ($(DOCKER),1)
ARTISAN = $(COMPOSE) exec -T app php artisan
PHPUNIT = $(COMPOSE) exec -T app ./vendor/bin/phpunit
else
ARTISAN = $(PHP) artisan
PHPUNIT = ./vendor/bin/phpunit
endif
.PHONY: tinker test
tinker: ; $(ARTISAN) tinker
test: ; $(PHPUNIT) --colors=always
Layer, don't fork. If the collection's test target is 90% right, don't edit the vendored file — shadow the target in your root Makefile after the include, or add a thinner alias (make test-fast → narrower filter) that calls the provided variable rather than the target.
Wire it into CI as the source of truth. The main payoff of a shared Makefile set is that local and CI run identical commands. Have the pipeline call make lint / make test rather than re-declaring the steps in YAML. If a target isn't CI-safe (interactive, writes to a TTY), wrap it with $(COMPOSE) exec -T or add a CI=1 branch — don't create a parallel set of CI-only commands, or the two will drift within a month.
Use ## doc comments on every target you add. The help target above reads $(MAKEFILE_LIST), which includes every fragment, so your local targets and the collection's targets land in one discoverable list. This is the difference between a Makefile the team uses and one nobody remembers the target names for.
Namespace risky targets. Anything that drops the database, reseeds, or prunes volumes deserves a confirm guard rather than relying on muscle memory:
.PHONY: fresh
fresh: ## Drop, migrate, seed (asks first)
@read -p "Destroy local DB? [y/N] " ok && [ "$$ok" = "y" ]
$(ARTISAN) migrate:fresh --seed
Tabs are not negotiable. Recipe lines must begin with a literal tab. Editors that "helpfully" expand tabs, or a copy-paste through a web UI, will produce missing separator on a file that looks fine. Set .editorconfig with [Makefile] indent_style = tab and add *.mk to that rule.
Every recipe line is its own shell. cd app && composer install on one line works; cd app on one line and composer install on the next does not — the cd evaporates. Chain with && or \, and start multi-step recipes with set -e so a mid-recipe failure actually aborts the target instead of silently continuing to the next line.
Variable assignment order matters and the include position is load-bearing. Variables set before include are visible to the fragments; variables set after are not, unless the fragment uses ?= lazily and you get lucky. If an override appears to be ignored, this is almost always why — move the assignment above the include.
?= means "first writer wins," and the command line beats everything. make test PHP=php8.3 always wins over ?=. That's a feature: use it for one-off invocations instead of editing files. But it also means a stray variable in your shell (export APP_PORT=...) can silently change behavior — check make -p | grep '^APP_' when a target behaves differently than expected.
Parallelism will break TTY/interactive targets. If anyone runs make -j, targets that prompt or attach to a container will misbehave or interleave output. Either accept sequential make, or add .NOTPARALLEL: for the interactive ones.
No dependency management, no changelog, no maintainer SLA. With zero stars and zero dependents, nobody outside this repo is filing issues. Practical consequences: pin a SHA, keep a one-line note in your README about where .make/ came from and why, and be prepared to own the fragments if the upstream goes quiet. Budget a small cleanup task to fold the two or three targets you actually use into your own Makefile and drop the submodule — for a handful of targets that is usually a better long-term trade than an unmaintained include.
Debugging: make -n <target> prints the recipe without running it (fastest way to see what variables resolved to), make -p dumps every variable and rule, and make <target> --debug=b traces include parsing. For a collection you didn't write, make -n on every target once is a ten-minute audit that tells you exactly what will touch your machine.
Extension points are just variables and overridable targets. There is no plugin API here — the contract is ?= assignments and .PHONY targets you can shadow. Before adding a feature, check whether the fragment already exposes a variable for it; if not, prefer a wrapper target in your root Makefile over editing the vendored copy, so upgrades stay possible.
How can I help you explore Laravel packages today?