diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2ed8402 --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +# DuckBrain development harness (branch-only tooling; never published to master). +# +# Workflow: +# make test run the unit test suite (installs dev dependencies first if needed) +# make publish sync develop -> master (human-only; git push origin master afterwards) + +SHELL := /bin/bash + +.PHONY: test publish + +PHPUNIT := vendor/bin/phpunit + +# --- publish configuration ------------------------------------------------- +WHITELIST := src config.php index.php autoload.php .htaccess readme.org +BLACKLIST := +DEVELOP_BRANCH := develop +DEVELOP_REF := refs/heads/$(DEVELOP_BRANCH) +MASTER_BRANCH := master +MASTER_REF := refs/heads/$(MASTER_BRANCH) +LAST_SYNC_TAG := last-sync +MSG ?= sync: $(shell date +%Y-%m-%d) + +test: $(PHPUNIT) + ./$(PHPUNIT) + +$(PHPUNIT): composer.json composer.lock + composer install --no-interaction + +publish: + @if [ "$$(git branch --show-current)" != "$(DEVELOP_BRANCH)" ]; then \ + echo "ABORT: publish must be invoked from $(DEVELOP_BRANCH) (current: '$$(git branch --show-current)')"; \ + exit 1; \ + fi + @if [ -n "$$(git status --porcelain)" ]; then \ + echo "ABORT: working tree is dirty; commit your changes on $(DEVELOP_BRANCH) before publishing:"; \ + git status --short; \ + exit 1; \ + fi + git worktree remove --force .publish/master 2>/dev/null || true + git worktree add --quiet .publish/master $(MASTER_BRANCH) + @test "$$(git -C .publish/master symbolic-ref HEAD)" = "$(MASTER_REF)" || { \ + echo "ABORT: publish worktree HEAD is not attached to $(MASTER_REF)"; \ + git worktree remove --force .publish/master; exit 1; } + @for w in $(WHITELIST); do git -C .publish/master rm -rf --ignore-unmatch --quiet -- $$w; done + git -C .publish/master checkout $(DEVELOP_REF) -- $(WHITELIST) + @for b in $(BLACKLIST); do git -C .publish/master rm -rf --ignore-unmatch --quiet -- $$b; done + git -C .publish/master diff --quiet $(DEVELOP_REF) -- $(WHITELIST) + @if git -C .publish/master diff --cached --quiet; then \ + echo "nothing to publish: master already mirrors $(DEVELOP_BRANCH)"; \ + else \ + set -e; \ + if git rev-parse -q --verify tags/$(LAST_SYNC_TAG) >/dev/null; then \ + RANGE=$(LAST_SYNC_TAG)..$(DEVELOP_REF); \ + else \ + echo "note: no $(LAST_SYNC_TAG) tag yet; summarizing full $(DEVELOP_BRANCH) history"; \ + RANGE=$(DEVELOP_REF); \ + fi; \ + BODY=$$(git log $$RANGE --oneline -- $(WHITELIST)); \ + { printf '%s\n' "$(MSG)"; printf '\n'; printf '%s\n' "$$BODY"; } > .publish/msg.txt; \ + git -C .publish/master commit --quiet -F "$$(pwd)/.publish/msg.txt"; \ + echo "publish commit created; review/edit it (before pushing) with your git tool of choice"; \ + fi + git tag -f $(LAST_SYNC_TAG) $(DEVELOP_REF) >/dev/null + git worktree remove .publish/master + @echo "root entries left behind in $(DEVELOP_BRANCH) (add to WHITELIST if they belong to the artifact):"; \ + comm -23 <(git ls-tree --name-only $(DEVELOP_REF) | sort) \ + <(for x in $(WHITELIST) $(BLACKLIST); do echo $$x; done | sort) | sed 's/^/ - /'