name: Docker Build and Push on: release: types: [published] workflow_dispatch: inputs: tag: description: 'Docker tag' required: true default: 'latest' # Single source of truth for which major owns the moving stable tags # (:latest, :{major}, :{major}.{minor}) and the temporary :nightly alias. # Bump to "3" on BOTH the 2.x and 3.x branches when 3.0.0 GA is tagged, and # drop the :nightly alias tag at the same time (end of the deprecation window). env: LATEST_MAJOR: "2" jobs: php_syntax_errors: name: 1️⃣ PHP Code Style errors if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: - name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: 8.4 - name: Checkout code uses: actions/checkout@v6 - name: Install dependencies uses: ramsey/composer-install@4.0.0 - name: Check source code for syntax errors run: ./vendor/bin/pint --test tests: name: 2️⃣ PHP Tests if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' needs: - php_syntax_errors runs-on: ubuntu-latest strategy: matrix: php-version: - 8.4 env: extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip steps: - name: Checkout code uses: actions/checkout@v6 - name: Setup PHP Action uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php-version }} extensions: ${{ env.extensions }} coverage: none tools: pecl, composer - name: Install Composer dependencies uses: ramsey/composer-install@4.0.0 - name: Apply tests ${{ matrix.php-version }} (parallel) run: php artisan test --parallel --exclude-group=modules - name: Apply module tests ${{ matrix.php-version }} (serial) run: php artisan test --group=modules release_artifact_build: name: 🏗️ Build / Upload - Release File if: github.event_name == 'release' needs: - tests runs-on: ubuntu-latest env: extensions: bcmath, curl, dom, gd, imagick, json, libxml, mbstring, pcntl, pdo, pdo_mysql, zip steps: - name: Checkout code uses: actions/checkout@v6 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: 8.4 extensions: ${{ env.extensions }} coverage: none - name: Install Composer dependencies uses: ramsey/composer-install@4.0.0 with: composer-options: --no-dev - name: Install pnpm uses: pnpm/action-setup@v6 - name: Use Node.js 24 uses: actions/setup-node@v6 with: node-version: 24 cache: pnpm - name: Install run: pnpm install --frozen-lockfile - name: Compile Front-end run: pnpm build - name: Build Dist run: | make clean dist - name: Upload package uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ github.token }} file: InvoiceShelf.zip asset_name: InvoiceShelf.zip tag: ${{ github.ref }} overwrite: true # Auto-register this release on the website updater backend so deployed installs # are offered it. The zip is already built here (./InvoiceShelf.zip) and the checkout # is present for config/installer.php, so this needs no re-download and can't race the # asset upload. Idempotent per version (the endpoint upserts). Release fields are passed # via env (not inline ${{ }}) to avoid shell injection from the release body. - name: Register release on the website updater env: CI_RELEASE_TOKEN: ${{ secrets.WEBSITE_RELEASE_TOKEN }} TAG: ${{ github.event.release.tag_name }} PRERELEASE: ${{ github.event.release.prerelease }} PUBLISHED: ${{ github.event.release.published_at }} BODY: ${{ github.event.release.body }} run: | if [ -z "$CI_RELEASE_TOKEN" ]; then echo "::warning::WEBSITE_RELEASE_TOKEN not set — skipping updater registration for $TAG" exit 0 fi MIN_PHP=$(php -r '$c=require "config/installer.php"; echo $c["core"]["minPhpVersion"] ?? "";') EXTS=$(php -r '$c=require "config/installer.php"; echo implode(", ", $c["requirements"]["php"] ?? []);') printf '%s' "$BODY" > /tmp/changelog.txt case "$TAG" in *-*) CHANNEL=insider ;; *) [ "$PRERELEASE" = "true" ] && CHANNEL=insider || CHANNEL=stable ;; esac echo "Registering $TAG (channel=$CHANNEL, min_php=$MIN_PHP) on the updater" curl -fsS --retry 3 --retry-delay 5 -X POST https://invoiceshelf.com/api/releases \ -H "Authorization: Bearer $CI_RELEASE_TOKEN" \ -F "version=$TAG" \ -F "channel=$CHANNEL" \ -F "released_at=$PUBLISHED" \ -F "min_php_version=$MIN_PHP" \ -F "extensions=$EXTS" \ -F "changelog=