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: xdebug tools: pecl, composer - name: Install Composer dependencies uses: ramsey/composer-install@4.0.0 - 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: Apply tests ${{ matrix.php-version }} run: php artisan test 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 release_docker_build: name: 🐳 Release Docker Build if: github.event_name == 'release' needs: - tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v6 with: images: invoiceshelf/invoiceshelf # Pre-release semver (e.g. 3.0.0-beta.1) automatically gets ONLY the exact # {{version}} tag — metadata-action withholds {{major}} / {{major}}.{{minor}}. # The moving stable tags (:latest, etc.) are gated on LATEST_MAJOR so a 2.x # patch can never steal :latest from 3.x after the GA flip, and vice-versa. tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') && startsWith(github.ref_name, format('{0}.', env.LATEST_MAJOR)) }} type=raw,value=beta,enable=${{ contains(github.ref_name, '-beta') }} type=raw,value=next,enable=${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') }} # DEPRECATED transitional alias: keeps existing :nightly deployments converging # onto stable until they migrate. Remove this line at the 3.0.0 GA flip. type=raw,value=nightly,enable=${{ !contains(github.ref_name, '-') && startsWith(github.ref_name, format('{0}.', env.LATEST_MAJOR)) }} - name: Build and push Docker image uses: docker/build-push-action@v7 with: context: . file: docker/production/Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max manual_docker_build: name: 🛠️ Manual Docker Build if: github.event_name == 'workflow_dispatch' needs: - tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v6 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Log in to Docker Hub uses: docker/login-action@v4 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Build and push Docker image uses: docker/build-push-action@v7 with: context: . file: docker/production/Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: invoiceshelf/invoiceshelf:${{ github.event.inputs.tag }} cache-from: type=gha cache-to: type=gha,mode=max