diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..03d8c72 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,57 @@ +name: Release + +on: + push: + tags: ['v*'] + +# Required to create the GitHub Release and upload assets via +# softprops/action-gh-release. +permissions: + contents: write + +jobs: + phar: + name: Build + publish PHAR + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP 8.4 + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: dom, json, mbstring, tokenizer, phar + coverage: none + tools: composer:v2 + + - name: Build PHAR + # `make build/phar` strips dev dependencies, downloads + # box.phar lazily into var/, compiles dist/xphp.phar, then + # restores the dev install. See Makefile for the rationale. + run: make build/phar + + - name: Smoke-test the PHAR + # If the PHAR is broken (missing autoload, bad shebang, + # excluded a runtime dep), `list` exits non-zero and the + # release fails BEFORE the asset is uploaded. + run: php dist/xphp.phar list + + - name: Compute SHA256 sum + # `sha256sum` outputs ` `; running it from + # the dist/ directory keeps the filename relative so users + # can `sha256sum -c xphp.phar.sha256sum` after downloading + # both files into the same directory. + working-directory: dist + run: sha256sum xphp.phar > xphp.phar.sha256sum + + - name: Attach assets to GitHub Release + # softprops/action-gh-release creates the release matched by + # tag name if it doesn't already exist, then appends the + # listed files as assets. Release body stays + # auto-generated unless `body:` / `body_path:` is set later. + uses: softprops/action-gh-release@v2 + with: + files: | + dist/xphp.phar + dist/xphp.phar.sha256sum + fail_on_unmatched_files: true diff --git a/Makefile b/Makefile index de5159d..6f222c6 100644 --- a/Makefile +++ b/Makefile @@ -17,3 +17,34 @@ test/unit: # repo is stable enough that no new test gaps are expected. test/mutation: php vendor/bin/infection --show-mutations=max --threads=max --min-covered-msi=95 + +# Humbug Box is the standard tool for compiling a Composer-managed +# PHP project into a single self-contained PHAR. Pinned to a known- +# good release (Box 4.6.6 supports PHP 8.4) so a new Box version +# can't silently break the build. Bump after validating locally. +BOX_VERSION := 4.6.6 +BOX_PHAR := var/box.phar + +$(BOX_PHAR): + @mkdir -p $(dir $(BOX_PHAR)) + @echo "==> Downloading box.phar $(BOX_VERSION)" + @curl -fsSL -o $@ \ + https://github.com/box-project/box/releases/download/$(BOX_VERSION)/box.phar + @chmod +x $@ + +.PHONY: build/phar +# Builds dist/xphp.phar -- the release artifact attached to every +# `v*` tag by .github/workflows/release.yml. Box reads box.json at +# the repo root and auto-discovers what to include from +# composer.json. +# +# `composer install` runs twice on purpose: once with --no-dev to +# strip phpunit/infection/etc. from the PHAR (smaller artifact, no +# test machinery shipped to users), then once more in dev mode so +# the next `make test/unit` keeps working without a separate +# install step. +build/phar: $(BOX_PHAR) + composer install --no-dev --classmap-authoritative --quiet --no-interaction + php -d phar.readonly=0 $(BOX_PHAR) compile --no-interaction + composer install --quiet --no-interaction + @echo "==> Built $$(ls -lh dist/xphp.phar | awk '{print $$5, $$9}')" diff --git a/box.json b/box.json new file mode 100644 index 0000000..8e13ff5 --- /dev/null +++ b/box.json @@ -0,0 +1,7 @@ +{ + "$schema": "vendor/humbug/box/res/schema.json", + "main": "bin/xphp", + "output": "dist/xphp.phar", + "compression": "GZ", + "banner": "xphp -- generic-aware PHP transpiler.\nhttps://github.com/xphp-lang/xphp" +}