Files
InvoiceShelf/.github/workflows/docker.yaml
Darko Gjorgjijoski d0391b9cfc ci: auto-register published release on the website updater (#693)
Append a step to the release_artifact_build job that POSTs the freshly built
InvoiceShelf.zip + metadata to the website updater's /api/releases endpoint
(Bearer WEBSITE_RELEASE_TOKEN) right after the asset upload, so deployed installs
are offered the release automatically instead of a manual kubectl+tinker import.

- Runs only on release events; skips with a warning if WEBSITE_RELEASE_TOKEN is unset
- Channel derived from the prerelease flag / "-" tag suffix (GA->stable, pre->insider)
- min_php + extensions read from config/installer.php; release fields passed via env
  to avoid shell injection from the release body
- Idempotent (the endpoint upserts per version)


Claude-Session: https://claude.ai/code/session_012tpgisKcrC4D4mCbGTeTKz

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 14:33:38 +02:00

247 lines
8.5 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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=<changelog.txt" \
-F "description=<changelog.txt" \
-F "release_file=@InvoiceShelf.zip"
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
secrets: |
composer_auth={"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}
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
secrets: |
composer_auth={"github-oauth":{"github.com":"${{ secrets.GITHUB_TOKEN }}"}}