Files
renovate[bot] 300b021e30 Update composer:2 Docker digest to da624c2 (#4562)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-22 13:06:44 +01:00

172 lines
7.3 KiB
Docker

# syntax=docker/dockerfile:1.28@sha256:bb22d9815c728170f72750f4e5b0d672e06176142e1d602c7e66c050100b7e5b
ARG PHP_VERSION=8.5
ARG NODE_VERSION=24
FROM php:${PHP_VERSION}-apache AS php-base
RUN set -eux; \
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
cron \
curl \
libbz2-dev \
libfreetype6-dev \
libicu-dev \
libjpeg62-turbo-dev \
libpng-dev \
libzip-dev \
unzip \
zlib1g-dev; \
docker-php-ext-configure gd --with-freetype --with-jpeg; \
docker-php-ext-install -j"$(nproc)" bz2 gd intl pdo_mysql zip; \
a2enmod rewrite; \
apt-mark auto '.*' > /dev/null; \
apt-mark manual \
${savedAptMark} \
ca-certificates \
cron \
curl \
unzip; \
find /usr/local -type f \( -perm /0111 -o -name '*.so' \) -exec sh -c 'ldd "$@" 2>/dev/null' sh '{}' + \
| awk 'NF == 4 && $2 == "=>" { print $3 } NF == 2 && $1 ~ /^\// { print $1 }' \
| sort -u \
| while read -r library; do \
library="$(readlink -e "${library}")"; \
dpkg-query --search "${library}" 2>/dev/null | grep -v '^diversion ' | head -n1 | cut -d: -f1; \
done \
| sort -u \
| xargs -r apt-mark manual; \
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
apt-get clean; \
rm -rf /var/lib/apt/lists/* /var/cache/apt/*
FROM php-base AS composer-base
WORKDIR /app
COPY --from=composer:2@sha256:da624c2c705d54e2f5a9bb77a5dc6c7d091711433ebefd7035672e84c2010fee /usr/bin/composer /usr/bin/composer
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/*
FROM composer-base AS php-vendor
COPY composer.json composer.lock ./
COPY src/library ./src/library
COPY src/modules ./src/modules
RUN --mount=type=cache,target=/tmp/composer-cache,id=composer-prod \
set -eux; \
find ./src/modules -type d -name tests -prune -exec rm -rf {} +; \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --no-dev --optimize-autoloader --no-interaction --no-progress
FROM composer-base AS php-dev-vendor
COPY composer.json composer.lock ./
COPY src/library ./src/library
COPY src/modules ./src/modules
RUN --mount=type=cache,target=/tmp/composer-cache,id=composer-dev \
COMPOSER_CACHE_DIR=/tmp/composer-cache \
composer install --prefer-dist --optimize-autoloader --no-interaction --no-progress
FROM node:${NODE_VERSION}-bookworm-slim AS frontend-assets
WORKDIR /app
COPY package.json package-lock.json ./
COPY src/themes/default/admin/package.json src/themes/default/admin/package.json
COPY src/themes/default/client/package.json src/themes/default/client/package.json
RUN --mount=type=cache,target=/root/.npm npm ci
COPY tsconfig.json ./
COPY src/themes/default/admin ./src/themes/default/admin
COPY src/themes/default/client ./src/themes/default/client
COPY src/modules ./src/modules
COPY frontend ./frontend
RUN NODE_ENV=production npm run build
FROM php-base AS release-tree
WORKDIR /app
ARG FOSSBILLING_VERSION=0.0.1
ARG FOSSBILLING_VERSION_TRUNCATE=0
ARG SENTRY_DSN=
ARG INSTALL_TRANSLATIONS=true
ARG TRANSLATIONS_URL=https://github.com/FOSSBilling/locale/releases/latest/download/translations.zip
ARG TRANSLATIONS_SHA256=
COPY --from=composer:2@sha256:da624c2c705d54e2f5a9bb77a5dc6c7d091711433ebefd7035672e84c2010fee /usr/bin/composer /usr/bin/composer
COPY composer.json ./composer.json
COPY src ./src
COPY README.md LICENSE ./src/
COPY --from=php-vendor /app/src/vendor ./src/vendor
COPY --from=frontend-assets /app/src/public/assets ./src/public/assets
COPY --from=frontend-assets /app/src/themes/default/admin/assets/build ./src/themes/default/admin/assets/build
COPY --from=frontend-assets /app/src/themes/default/client/assets/build ./src/themes/default/client/assets/build
RUN set -eux; \
find ./src/modules -type d -name tests -prune -exec rm -rf {} +; \
mkdir -p ./src/locale; \
if [ "${INSTALL_TRANSLATIONS}" = "true" ]; then \
curl -fsSL "${TRANSLATIONS_URL}" -o /tmp/translations.zip; \
if [ -n "${TRANSLATIONS_SHA256}" ]; then \
echo "${TRANSLATIONS_SHA256} /tmp/translations.zip" | sha256sum -c -; \
fi; \
unzip -oq /tmp/translations.zip -d ./src/locale; \
rm /tmp/translations.zip; \
fi; \
FOSSBILLING_VERSION="${FOSSBILLING_VERSION}" \
FOSSBILLING_VERSION_TRUNCATE="${FOSSBILLING_VERSION_TRUNCATE}" \
SENTRY_DSN="${SENTRY_DSN}" \
php -r '$version = getenv("FOSSBILLING_VERSION") ?: "0.0.1"; $truncate = (int) (getenv("FOSSBILLING_VERSION_TRUNCATE") ?: 0); if ($truncate > 0) { $version = substr($version, 0, $truncate); } $versionFile = "./src/library/FOSSBilling/Version.php"; $contents = file_get_contents($versionFile); $quote = chr(39); $pattern = "/public const string VERSION = " . $quote . "[^" . $quote . "]+" . $quote . ";/"; $replacement = "public const string VERSION = " . var_export($version, true) . ";"; $contents = preg_replace($pattern, $replacement, $contents, 1, $count); if ($contents === null || $count !== 1) { fwrite(STDERR, "Failed to replace FOSSBilling version.\n"); exit(1); } file_put_contents($versionFile, $contents); $dsn = getenv("SENTRY_DSN"); if ($dsn !== false && $dsn !== "") { $sentryFile = "./src/library/FOSSBilling/SentryHelper.php"; file_put_contents($sentryFile, str_replace("--replace--this--during--release--process--", $dsn, file_get_contents($sentryFile))); }'; \
php -r '$composer = json_decode(file_get_contents("./composer.json"), true, 512, JSON_THROW_ON_ERROR); $composer["autoload"]["psr-4"]["FOSSBilling\\"] = "library/FOSSBilling/"; $composer["autoload"]["psr-4"]["Box\\Mod\\"] = "modules/"; $composer["autoload"]["classmap"] = ["library/"]; $composer["config"]["vendor-dir"] = "vendor"; file_put_contents("./src/composer.json", json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . PHP_EOL);'; \
composer --no-plugins dump-autoload --working-dir=./src --no-dev --optimize --no-interaction; \
php -r '$class = "FOSSBilling\\Cache\\CacheFactory"; require "./src/vendor/autoload.php"; if (!class_exists($class)) { fwrite(STDERR, "Release Composer autoloader is missing {$class}.\n"); exit(1); }'; \
rm ./composer.json ./src/composer.json; \
chmod -R u=rwX,go=rX ./src
FROM scratch AS release-artifact
COPY --from=release-tree /app/src /
FROM php-base AS runtime
WORKDIR /var/www/html
COPY --from=release-tree --chown=www-data:www-data /app/src/ ./
RUN set -eux; \
mkdir -p data/cache data/log data/uploads; \
touch /var/log/cron.log; \
chown -R www-data:www-data data /var/log/cron.log; \
echo '*/5 * * * * /usr/local/bin/php /var/www/html/cron.php >> /var/log/cron.log 2>&1' > /tmp/www-data.cron; \
crontab -u www-data /tmp/www-data.cron; \
rm /tmp/www-data.cron
CMD ["sh", "-c", "cron & exec apache2-foreground"]
FROM runtime AS test
WORKDIR /workspace
COPY --from=release-tree /app/src ./src
COPY src/modules ./src/modules
COPY --from=php-dev-vendor /app/src/vendor ./src/vendor
COPY composer.json composer.lock phpstan.neon phpunit.xml.dist ./
COPY tests ./tests
COPY tools ./tools
RUN set -eux; \
php -r '$config = require "./src/config-sample.php"; file_put_contents("./src/config.php", "<?php\nreturn " . var_export($config, true) . ";\n");'; \
mkdir -p ./src/data/cache ./src/data/log ./src/data/uploads; \
chown -R www-data:www-data ./src/data ./src/config.php