Cachefixing test (#5793)

Co-authored-by: Claude Haiku 4.5 <[email protected]>
This commit is contained in:
Anthony Stirling
2026-02-25 13:44:38 +00:00
committed by GitHub
co-authored by Claude Haiku 4.5
parent c8081ac7cd
commit 86072ec91a
14 changed files with 194 additions and 74 deletions
+2
View File
@@ -231,6 +231,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile file: ./docker/embedded/Dockerfile
push: true push: true
cache-from: type=gha,scope=stirling-pdf-latest
cache-to: type=gha,mode=max,scope=stirling-pdf-latest
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }} tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-${{ steps.commit-hash.outputs.app_short }}
build-args: VERSION_TAG=v2-alpha build-args: VERSION_TAG=v2-alpha
platforms: linux/amd64 platforms: linux/amd64
@@ -190,6 +190,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile file: ./docker/embedded/Dockerfile
push: true push: true
cache-from: type=gha,scope=stirling-pdf-latest
cache-to: type=gha,mode=max,scope=stirling-pdf-latest
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }} tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:pr-${{ needs.check-comment.outputs.pr_number }}
build-args: VERSION_TAG=alpha build-args: VERSION_TAG=alpha
platforms: linux/amd64 platforms: linux/amd64
+65 -6
View File
@@ -68,10 +68,20 @@ jobs:
java-version: ${{ matrix.jdk-version }} java-version: ${{ matrix.jdk-version }}
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependency artifacts
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches/modules-2/files-2.1
~/.gradle/caches/modules-2/metadata-2.*
key: gradle-deps-${{ runner.os }}-jdk-${{ matrix.jdk-version }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }}
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
gradle-version: 8.14 gradle-version: 8.14
cache-disabled: true
- name: Build with Gradle and spring security ${{ matrix.spring-security }} - name: Build with Gradle and spring security ${{ matrix.spring-security }}
run: ./gradlew build -PnoSpotless run: ./gradlew build -PnoSpotless
@@ -143,10 +153,20 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependency artifacts
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches/modules-2/files-2.1
~/.gradle/caches/modules-2/metadata-2.*
key: gradle-deps-${{ runner.os }}-jdk-25-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }}
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
gradle-version: 8.14 gradle-version: 8.14
cache-disabled: true
- name: Generate OpenAPI documentation - name: Generate OpenAPI documentation
run: ./gradlew :stirling-pdf:generateOpenApiDocs run: ./gradlew :stirling-pdf:generateOpenApiDocs
@@ -215,10 +235,20 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependency artifacts
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches/modules-2/files-2.1
~/.gradle/caches/modules-2/metadata-2.*
key: gradle-deps-${{ runner.os }}-jdk-25-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }}
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
gradle-version: 8.14 gradle-version: 8.14
cache-disabled: true
- name: check the licenses for compatibility - name: check the licenses for compatibility
# NOTE: --no-parallel is intentional here. Running the checkLicense task in parallel with other # NOTE: --no-parallel is intentional here. Running the checkLicense task in parallel with other
@@ -259,6 +289,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
actions: write
contents: read
checks: write checks: write
steps: steps:
@@ -276,14 +308,28 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependency artifacts
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches/modules-2/files-2.1
~/.gradle/caches/modules-2/metadata-2.*
key: gradle-deps-${{ runner.os }}-jdk-25-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }}
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
gradle-version: 8.14 gradle-version: 8.14
cache-disabled: true
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
# Expose ACTIONS_RUNTIME_TOKEN / ACTIONS_RESULTS_URL for docker buildx type=gha cache backend.
- name: Expose GitHub runtime for Buildx cache
uses: crazy-max/ghaction-github-runtime@v3
- name: Install Docker Compose - name: Install Docker Compose
run: | run: |
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.39.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo curl -SL "https://github.com/docker/compose/releases/download/v2.39.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
@@ -338,12 +384,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
# - docker-rev: docker/embedded/Dockerfile - docker-rev: docker/embedded/Dockerfile
# artifact-suffix: Dockerfile artifact-suffix: Dockerfile
cache-scope: stirling-pdf-latest
- docker-rev: docker/embedded/Dockerfile.ultra-lite - docker-rev: docker/embedded/Dockerfile.ultra-lite
artifact-suffix: Dockerfile.ultra-lite artifact-suffix: Dockerfile.ultra-lite
# - docker-rev: docker/embedded/Dockerfile.fat cache-scope: stirling-pdf-ultra-lite
# artifact-suffix: Dockerfile.fat - docker-rev: docker/embedded/Dockerfile.fat
artifact-suffix: Dockerfile.fat
cache-scope: stirling-pdf-fat
steps: steps:
- name: Harden Runner - name: Harden Runner
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
@@ -366,10 +415,20 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependency artifacts
uses: actions/cache@v4
with:
path: |
~/.gradle/wrapper
~/.gradle/caches/modules-2/files-2.1
~/.gradle/caches/modules-2/metadata-2.*
key: gradle-deps-${{ runner.os }}-jdk-25-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties', '**/*.gradle', '**/*.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'gradle/libs.versions.toml') }}
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
gradle-version: 8.14 gradle-version: 8.14
cache-disabled: true
- name: Build application - name: Build application
run: ./gradlew build run: ./gradlew build
@@ -394,8 +453,8 @@ jobs:
context: . context: .
file: ./${{ matrix.docker-rev }} file: ./${{ matrix.docker-rev }}
push: false push: false
cache-from: type=gha,scope=${{ matrix.artifact-suffix }} cache-from: type=gha,scope=${{ matrix.cache-scope }}
cache-to: type=gha,mode=max,scope=${{ matrix.artifact-suffix }} cache-to: type=gha,mode=max,scope=${{ matrix.cache-scope }}
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
provenance: true provenance: true
sbom: true sbom: true
@@ -97,6 +97,8 @@ jobs:
context: . context: .
file: ./docker/frontend/Dockerfile file: ./docker/frontend/Dockerfile
push: true push: true
cache-from: type=gha,scope=stirling-v2-frontend
cache-to: type=gha,mode=max,scope=stirling-v2-frontend
tags: | tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }} ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-${{ steps.commit-hashes.outputs.frontend_short }}
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-latest ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-frontend-latest
@@ -110,6 +112,8 @@ jobs:
context: . context: .
file: ./docker/backend/Dockerfile file: ./docker/backend/Dockerfile
push: true push: true
cache-from: type=gha,scope=stirling-v2-backend
cache-to: type=gha,mode=max,scope=stirling-v2-backend
tags: | tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }} ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-${{ steps.commit-hashes.outputs.backend_short }}
${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-latest ${{ secrets.DOCKER_HUB_USERNAME }}/test:v2-backend-latest
+10
View File
@@ -48,6 +48,16 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}-
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
+16 -6
View File
@@ -45,6 +45,16 @@ jobs:
java-version: "25" java-version: "25"
distribution: "temurin" distribution: "temurin"
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}-
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1 uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
with: with:
@@ -116,8 +126,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile file: ./docker/embedded/Dockerfile
push: true push: true
cache-from: type=gha cache-from: type=gha,scope=stirling-pdf-latest
cache-to: type=gha,mode=max cache-to: type=gha,mode=max,scope=stirling-pdf-latest
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
@@ -162,8 +172,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile.fat file: ./docker/embedded/Dockerfile.fat
push: true push: true
cache-from: type=gha cache-from: type=gha,scope=stirling-pdf-fat
cache-to: type=gha,mode=max cache-to: type=gha,mode=max,scope=stirling-pdf-fat
tags: ${{ steps.meta-fat.outputs.tags }} tags: ${{ steps.meta-fat.outputs.tags }}
labels: ${{ steps.meta-fat.outputs.labels }} labels: ${{ steps.meta-fat.outputs.labels }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
@@ -206,8 +216,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile.ultra-lite file: ./docker/embedded/Dockerfile.ultra-lite
push: true push: true
cache-from: type=gha cache-from: type=gha,scope=stirling-pdf-ultra-lite
cache-to: type=gha,mode=max cache-to: type=gha,mode=max,scope=stirling-pdf-ultra-lite
tags: ${{ steps.meta-lite.outputs.tags }} tags: ${{ steps.meta-lite.outputs.tags }}
labels: ${{ steps.meta-lite.outputs.labels }} labels: ${{ steps.meta-lite.outputs.labels }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
+1 -2
View File
@@ -15,6 +15,7 @@ on:
- linux - linux
pull_request: pull_request:
branches: [main, V2-tauri-windows] branches: [main, V2-tauri-windows]
types: [opened, reopened, synchronize, ready_for_review]
paths: paths:
- "frontend/src-tauri/**" - "frontend/src-tauri/**"
- "frontend/src/desktop/**" - "frontend/src/desktop/**"
@@ -23,8 +24,6 @@ on:
- "frontend/package-lock.json" - "frontend/package-lock.json"
- "frontend/vite.config.ts" - "frontend/vite.config.ts"
- ".github/workflows/tauri-build.yml" - ".github/workflows/tauri-build.yml"
push:
branches: [main]
permissions: permissions:
contents: read contents: read
+2
View File
@@ -72,6 +72,8 @@ jobs:
context: . context: .
file: ./docker/embedded/Dockerfile file: ./docker/embedded/Dockerfile
push: true push: true
cache-from: type=gha,scope=stirling-pdf-latest
cache-to: type=gha,mode=max,scope=stirling-pdf-latest
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:test-${{ github.sha }} tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:test-${{ github.sha }}
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }} build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
platforms: linux/amd64 platforms: linux/amd64
@@ -100,10 +100,12 @@ public class FileToPdf {
while (entry != null) { while (entry != null) {
Path filePath = Path filePath =
tempUnzippedDir.getPath().resolve(sanitizeZipFilename(entry.getName())); tempUnzippedDir.getPath().resolve(sanitizeZipFilename(entry.getName()));
Path normalizedTargetDir = tempUnzippedDir.getPath().toAbsolutePath().normalize(); Path normalizedTargetDir =
tempUnzippedDir.getPath().toAbsolutePath().normalize();
Path normalizedFilePath = filePath.toAbsolutePath().normalize(); Path normalizedFilePath = filePath.toAbsolutePath().normalize();
if (!normalizedFilePath.startsWith(normalizedTargetDir)) { if (!normalizedFilePath.startsWith(normalizedTargetDir)) {
throw new IOException("Zip entry path escapes target directory: " + entry.getName()); throw new IOException(
"Zip entry path escapes target directory: " + entry.getName());
} }
if (!entry.isDirectory()) { if (!entry.isDirectory()) {
Files.createDirectories(filePath.getParent()); Files.createDirectories(filePath.getParent());
@@ -23,14 +23,14 @@ import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.support.MissingServletRequestPartException; import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.NoHandlerFoundException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.ObjectMapper;
import stirling.software.common.util.ExceptionUtils; import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.ExceptionUtils.*; import stirling.software.common.util.ExceptionUtils.*;
import stirling.software.common.util.RegexPatternUtils; import stirling.software.common.util.RegexPatternUtils;
@@ -874,10 +874,16 @@ public class GlobalExceptionHandler {
errorMap.put("type", "about:blank"); errorMap.put("type", "about:blank");
errorMap.put("title", "Not Acceptable"); errorMap.put("title", "Not Acceptable");
errorMap.put("status", 406); errorMap.put("status", 406);
errorMap.put("detail", "The requested resource could not be returned in an acceptable format. Error responses are returned as JSON."); errorMap.put(
"detail",
"The requested resource could not be returned in an acceptable format. Error responses are returned as JSON.");
errorMap.put("instance", request.getRequestURI()); errorMap.put("instance", request.getRequestURI());
errorMap.put("timestamp", Instant.now().toString()); errorMap.put("timestamp", Instant.now().toString());
errorMap.put("hints", java.util.Arrays.asList("Error responses are always returned as application/json or application/problem+json", "Set Accept header to include application/json for proper error handling")); errorMap.put(
"hints",
java.util.Arrays.asList(
"Error responses are always returned as application/json or application/problem+json",
"Set Accept header to include application/json for proper error handling"));
String errorJson = mapper.writeValueAsString(errorMap); String errorJson = mapper.writeValueAsString(errorMap);
response.getWriter().write(errorJson); response.getWriter().write(errorJson);
+20 -14
View File
@@ -4,7 +4,8 @@ FROM ubuntu:noble AS calibre-build
ARG CALIBRE_VERSION=9.3.1 ARG CALIBRE_VERSION=9.3.1
RUN set -eux; \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
set -eux; \
apt-get update; \ apt-get update; \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
ca-certificates curl xz-utils libnss3 libfontconfig1 \ ca-certificates curl xz-utils libnss3 libfontconfig1 \
@@ -185,12 +186,13 @@ RUN set -eux; \
# Build the Java application and frontend. # Build the Java application and frontend.
FROM gradle:9.3.1-jdk25 AS app-build FROM gradle:9.3.1-jdk25 AS app-build
RUN apt-get update \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \ && apt-get install -y --no-install-recommends curl ca-certificates \
&& update-ca-certificates \ && update-ca-certificates \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \ && apt-get install -y --no-install-recommends nodejs \
&& apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# JDK 25+: --add-exports is no longer accepted via JAVA_TOOL_OPTIONS; use JDK_JAVA_OPTIONS instead # JDK 25+: --add-exports is no longer accepted via JAVA_TOOL_OPTIONS; use JDK_JAVA_OPTIONS instead
ENV JDK_JAVA_OPTIONS="--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ ENV JDK_JAVA_OPTIONS="--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
@@ -232,11 +234,13 @@ RUN java -Djarmode=tools -jar app.jar extract --layers --destination /layers
# Build Ghostscript 10.06.0 from source in an isolated stage (avoids library conflicts). # Build Ghostscript 10.06.0 from source in an isolated stage (avoids library conflicts).
FROM ubuntu:noble AS gs-build FROM ubuntu:noble AS gs-build
ARG GS_VERSION=10.06.0 ARG GS_VERSION=10.06.0
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
build-essential curl ca-certificates libfontconfig1-dev && \ --mount=type=cache,target=/tmp/gs-build \
rm -rf /var/lib/apt/lists/* && \ apt-get update && apt-get install -y --no-install-recommends \
build-essential curl ca-certificates libfontconfig1-dev && rm -rf /var/lib/apt/lists/* && \
GS_TAG="gs$(printf '%s' "${GS_VERSION}" | tr -d '.')" && \ GS_TAG="gs$(printf '%s' "${GS_VERSION}" | tr -d '.')" && \
curl -fsSL "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/${GS_TAG}/ghostscript-${GS_VERSION}.tar.gz" | tar xz && \ cd /tmp/gs-build && \
(test -d "ghostscript-${GS_VERSION}" || curl -fsSL "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/${GS_TAG}/ghostscript-${GS_VERSION}.tar.gz" | tar xz) && \
cd "ghostscript-${GS_VERSION}" && \ cd "ghostscript-${GS_VERSION}" && \
./configure \ ./configure \
--prefix=/usr/local \ --prefix=/usr/local \
@@ -252,19 +256,22 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
FROM ubuntu:noble AS pdf-tools-build FROM ubuntu:noble AS pdf-tools-build
ARG QPDF_VERSION=12.3.2 ARG QPDF_VERSION=12.3.2
ARG IM_VERSION=7.1.2-13 ARG IM_VERSION=7.1.2-13
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/tmp/pdf-tools-build \
apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake libssl-dev libjpeg-dev zlib1g-dev curl ca-certificates pkg-config \ build-essential cmake libssl-dev libjpeg-dev zlib1g-dev curl ca-certificates pkg-config \
libpng-dev libtiff-dev libwebp-dev libxml2-dev libfreetype6-dev liblcms2-dev libzip-dev liblqr-1-0-dev \ libpng-dev libtiff-dev libwebp-dev libxml2-dev libfreetype6-dev liblcms2-dev libzip-dev liblqr-1-0-dev \
libltdl-dev libtool && \ libltdl-dev libtool && rm -rf /var/lib/apt/lists/* && \
cd /tmp/pdf-tools-build && \
# Build QPDF # Build QPDF
curl -fsSL "https://github.com/qpdf/qpdf/releases/download/v${QPDF_VERSION}/qpdf-${QPDF_VERSION}.tar.gz" | tar xz && \ (test -d "qpdf-${QPDF_VERSION}" || curl -fsSL "https://github.com/qpdf/qpdf/releases/download/v${QPDF_VERSION}/qpdf-${QPDF_VERSION}.tar.gz" | tar xz) && \
cd "qpdf-${QPDF_VERSION}" && \ cd "qpdf-${QPDF_VERSION}" && \
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DALLOW_CRYPTO_OPENSSL=ON -DDEFAULT_CRYPTO=openssl && \ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DALLOW_CRYPTO_OPENSSL=ON -DDEFAULT_CRYPTO=openssl && \
cmake --build build --parallel "$(nproc)" && \ cmake --build build --parallel "$(nproc)" && \
cmake --install build && \ cmake --install build && \
cd .. && \ cd .. && \
# Build ImageMagick 7 # Build ImageMagick 7
curl -fsSL "https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IM_VERSION}.tar.gz" | tar xz && \ (test -d "ImageMagick-${IM_VERSION}" || curl -fsSL "https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IM_VERSION}.tar.gz" | tar xz) && \
cd "ImageMagick-${IM_VERSION}" && \ cd "ImageMagick-${IM_VERSION}" && \
./configure --prefix=/usr/local --with-modules --with-perl=no --with-magick-plus-plus=no --with-quantum-depth=16 --disable-static --enable-shared && \ ./configure --prefix=/usr/local --with-modules --with-perl=no --with-magick-plus-plus=no --with-quantum-depth=16 --disable-static --enable-shared && \
make -j"$(nproc)" && \ make -j"$(nproc)" && \
@@ -289,7 +296,8 @@ ENV DEBIAN_FRONTEND=noninteractive \
ARG UNOSERVER_VERSION=3.6 ARG UNOSERVER_VERSION=3.6
RUN set -eux; \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
set -eux; \
apt-get update; \ apt-get update; \
# Add LibreOffice Fresh PPA for latest version (26.2.x) # Add LibreOffice Fresh PPA for latest version (26.2.x)
apt-get install -y --no-install-recommends software-properties-common; \ apt-get install -y --no-install-recommends software-properties-common; \
@@ -351,8 +359,6 @@ RUN set -eux; \
\ \
# Cleanup stage. # Cleanup stage.
\ \
# apt clean needed without cache mounts
apt-get clean; \
rm -rf /var/lib/apt/lists/*; \ rm -rf /var/lib/apt/lists/*; \
\ \
# Docs / man / info / icons / themes / GUI assets (headless server) # Docs / man / info / icons / themes / GUI assets (headless server)
+20 -15
View File
@@ -5,7 +5,8 @@ FROM ubuntu:noble AS calibre-build
ARG CALIBRE_VERSION=9.3.1 ARG CALIBRE_VERSION=9.3.1
RUN set -eux; \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
set -eux; \
apt-get update; \ apt-get update; \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
ca-certificates curl xz-utils libnss3 libfontconfig1 \ ca-certificates curl xz-utils libnss3 libfontconfig1 \
@@ -184,12 +185,13 @@ RUN set -eux; \
# Build the Java application and frontend. # Build the Java application and frontend.
FROM gradle:9.3.1-jdk25 AS app-build FROM gradle:9.3.1-jdk25 AS app-build
RUN apt-get update \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \ && apt-get install -y --no-install-recommends curl ca-certificates \
&& update-ca-certificates \ && update-ca-certificates \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \ && apt-get install -y --no-install-recommends nodejs \
&& apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# JDK 25+: --add-exports is no longer accepted via JAVA_TOOL_OPTIONS; use JDK_JAVA_OPTIONS instead # JDK 25+: --add-exports is no longer accepted via JAVA_TOOL_OPTIONS; use JDK_JAVA_OPTIONS instead
ENV JDK_JAVA_OPTIONS="--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ ENV JDK_JAVA_OPTIONS="--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
@@ -228,7 +230,8 @@ FROM ubuntu:noble AS python-build
ARG UNOSERVER_VERSION=3.6 ARG UNOSERVER_VERSION=3.6
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
python3 python3-venv python3-dev \ python3 python3-venv python3-dev \
python3-packaging \ python3-packaging \
build-essential \ build-essential \
@@ -249,11 +252,13 @@ RUN --mount=type=cache,target=/root/.cache/pip \
# Build Ghostscript 10.06.0 from source in an isolated stage (avoids library conflicts). # Build Ghostscript 10.06.0 from source in an isolated stage (avoids library conflicts).
FROM ubuntu:noble AS gs-build FROM ubuntu:noble AS gs-build
ARG GS_VERSION=10.06.0 ARG GS_VERSION=10.06.0
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
build-essential curl ca-certificates libfontconfig1-dev && \ --mount=type=cache,target=/tmp/gs-build \
rm -rf /var/lib/apt/lists/* && \ apt-get update && apt-get install -y --no-install-recommends \
build-essential curl ca-certificates libfontconfig1-dev && rm -rf /var/lib/apt/lists/* && \
GS_TAG="gs$(printf '%s' "${GS_VERSION}" | tr -d '.')" && \ GS_TAG="gs$(printf '%s' "${GS_VERSION}" | tr -d '.')" && \
curl -fsSL "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/${GS_TAG}/ghostscript-${GS_VERSION}.tar.gz" | tar xz && \ cd /tmp/gs-build && \
(test -d "ghostscript-${GS_VERSION}" || curl -fsSL "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/${GS_TAG}/ghostscript-${GS_VERSION}.tar.gz" | tar xz) && \
cd "ghostscript-${GS_VERSION}" && \ cd "ghostscript-${GS_VERSION}" && \
./configure \ ./configure \
--prefix=/usr/local \ --prefix=/usr/local \
@@ -269,19 +274,22 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
FROM ubuntu:noble AS pdf-tools-build FROM ubuntu:noble AS pdf-tools-build
ARG QPDF_VERSION=12.3.2 ARG QPDF_VERSION=12.3.2
ARG IM_VERSION=7.1.2-13 ARG IM_VERSION=7.1.2-13
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/tmp/pdf-tools-build \
apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake libssl-dev libjpeg-dev zlib1g-dev curl ca-certificates pkg-config \ build-essential cmake libssl-dev libjpeg-dev zlib1g-dev curl ca-certificates pkg-config \
libpng-dev libtiff-dev libwebp-dev libxml2-dev libfreetype6-dev liblcms2-dev libzip-dev liblqr-1-0-dev \ libpng-dev libtiff-dev libwebp-dev libxml2-dev libfreetype6-dev liblcms2-dev libzip-dev liblqr-1-0-dev \
libltdl-dev libtool && \ libltdl-dev libtool && rm -rf /var/lib/apt/lists/* && \
cd /tmp/pdf-tools-build && \
# Build QPDF # Build QPDF
curl -fsSL "https://github.com/qpdf/qpdf/releases/download/v${QPDF_VERSION}/qpdf-${QPDF_VERSION}.tar.gz" | tar xz && \ (test -d "qpdf-${QPDF_VERSION}" || curl -fsSL "https://github.com/qpdf/qpdf/releases/download/v${QPDF_VERSION}/qpdf-${QPDF_VERSION}.tar.gz" | tar xz) && \
cd "qpdf-${QPDF_VERSION}" && \ cd "qpdf-${QPDF_VERSION}" && \
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DALLOW_CRYPTO_OPENSSL=ON -DDEFAULT_CRYPTO=openssl && \ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DALLOW_CRYPTO_OPENSSL=ON -DDEFAULT_CRYPTO=openssl && \
cmake --build build --parallel "$(nproc)" && \ cmake --build build --parallel "$(nproc)" && \
cmake --install build && \ cmake --install build && \
cd .. && \ cd .. && \
# Build ImageMagick 7 # Build ImageMagick 7
curl -fsSL "https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IM_VERSION}.tar.gz" | tar xz && \ (test -d "ImageMagick-${IM_VERSION}" || curl -fsSL "https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IM_VERSION}.tar.gz" | tar xz) && \
cd "ImageMagick-${IM_VERSION}" && \ cd "ImageMagick-${IM_VERSION}" && \
./configure --prefix=/usr/local --with-modules --with-perl=no --with-magick-plus-plus=no --with-quantum-depth=16 --disable-static --enable-shared && \ ./configure --prefix=/usr/local --with-modules --with-perl=no --with-magick-plus-plus=no --with-quantum-depth=16 --disable-static --enable-shared && \
make -j"$(nproc)" && \ make -j"$(nproc)" && \
@@ -307,7 +315,6 @@ ENV DEBIAN_FRONTEND=noninteractive \
ARG UNOSERVER_VERSION=3.6 ARG UNOSERVER_VERSION=3.6
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=cache,target=/root/.cache/pip \ --mount=type=cache,target=/root/.cache/pip \
set -eux; \ set -eux; \
apt-get update; \ apt-get update; \
@@ -354,8 +361,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
\ \
# Cleanup stage. # Cleanup stage.
\ \
# apt clean not strictly needed with cache mounts, but good for reducing layer metadata
apt-get clean; \
rm -rf /var/lib/apt/lists/*; \ rm -rf /var/lib/apt/lists/*; \
\ \
# Docs / man / info / icons / themes / GUI assets (headless server) # Docs / man / info / icons / themes / GUI assets (headless server)
+16 -17
View File
@@ -5,13 +5,13 @@
FROM gradle:9.3.1-jdk25 AS build FROM gradle:9.3.1-jdk25 AS build
# Install Node.js and npm for frontend build # Install Node.js and npm for frontend build
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
curl \ curl \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \ && apt-get install -y --no-install-recommends nodejs \
&& npm --version \ && npm --version \
&& node --version \ && node --version \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
WORKDIR /app WORKDIR /app
@@ -65,18 +65,6 @@ LABEL org.opencontainers.image.title="Stirling-PDF Ultra-Lite" \
org.opencontainers.image.version="${VERSION_TAG}" \ org.opencontainers.image.version="${VERSION_TAG}" \
org.opencontainers.image.keywords="PDF, manipulation, ultra-lite, API, Spring Boot, React" org.opencontainers.image.keywords="PDF, manipulation, ultra-lite, API, Spring Boot, React"
# Copy scripts
COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY scripts/installFonts.sh /scripts/installFonts.sh
COPY scripts/stirling-diagnostics.sh /scripts/stirling-diagnostics.sh
# Copy built JARs from build stage
# Use numeric UID:GID (1000:1000) since the named user doesn't exist yet at COPY time
COPY --from=build --chown=1000:1000 \
/app/app/core/build/libs/*.jar /app.jar
COPY --from=build --chown=1000:1000 \
/app/build/libs/restart-helper.jar /restart-helper.jar
# Environment Variables # Environment Variables
# NOTE: Memory flags (InitialRAMPercentage, MaxRAMPercentage, MaxMetaspaceSize) # NOTE: Memory flags (InitialRAMPercentage, MaxRAMPercentage, MaxMetaspaceSize)
# are computed dynamically by init-without-ocr.sh based on container memory limits. # are computed dynamically by init-without-ocr.sh based on container memory limits.
@@ -96,7 +84,6 @@ ENV VERSION_TAG=$VERSION_TAG \
ENDPOINTS_GROUPS_TO_REMOVE=CLI ENDPOINTS_GROUPS_TO_REMOVE=CLI
# Install minimal dependencies # Install minimal dependencies
# --chown on COPY above removes need to chown JARs here
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \ echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \ echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
@@ -111,10 +98,22 @@ RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/a
su-exec && \ su-exec && \
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf /tmp/stirling-pdf/heap_dumps && \ mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders /tmp/stirling-pdf /tmp/stirling-pdf/heap_dumps && \
mkdir -p /usr/share/fonts/opentype/noto && \ mkdir -p /usr/share/fonts/opentype/noto && \
chmod +x /scripts/*.sh && \
# User permissions # User permissions
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \ addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /configs /customFiles /pipeline /tmp/stirling-pdf chown -R stirlingpdfuser:stirlingpdfgroup $HOME /configs /customFiles /pipeline /tmp/stirling-pdf
# Copy scripts and built artifacts after OS package layer to maximize cache reuse.
COPY --chown=1000:1000 scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY --chown=1000:1000 scripts/installFonts.sh /scripts/installFonts.sh
COPY --chown=1000:1000 scripts/stirling-diagnostics.sh /scripts/stirling-diagnostics.sh
# Copy built JARs from build stage
COPY --from=build --chown=1000:1000 \
/app/app/core/build/libs/*.jar /app.jar
COPY --from=build --chown=1000:1000 \
/app/build/libs/restart-helper.jar /restart-helper.jar
RUN chmod +x /scripts/*.sh
EXPOSE 8080/tcp EXPOSE 8080/tcp
+22 -8
View File
@@ -421,7 +421,7 @@ main() {
should_run_test "Stirling-PDF-Ultra-Lite-Version-Check"; then should_run_test "Stirling-PDF-Ultra-Lite-Version-Check"; then
export DISABLE_ADDITIONAL_FEATURES=true export DISABLE_ADDITIONAL_FEATURES=true
if ! ./gradlew clean build; then if ! ./gradlew clean build -PnoSpotless; then
echo "Gradle build failed with security disabled, exiting script." echo "Gradle build failed with security disabled, exiting script."
exit 1 exit 1
fi fi
@@ -431,11 +431,18 @@ main() {
EXPECTED_VERSION=$(get_expected_version) EXPECTED_VERSION=$(get_expected_version)
echo "Expected version: $EXPECTED_VERSION" echo "Expected version: $EXPECTED_VERSION"
# Build Ultra-Lite image with embedded frontend (GHCR tag, matching docker-compose-latest-ultra-lite.yml) # Build Ultra-Lite image with embedded frontend (matching docker-compose-latest-ultra-lite.yml)
echo "Building ultra-lite image for tests that require it..." echo "Building ultra-lite image for tests that require it..."
docker build --build-arg VERSION_TAG=alpha \ if [ -n "${ACTIONS_RUNTIME_TOKEN}" ] && { [ -n "${ACTIONS_RESULTS_URL}" ] || [ -n "${ACTIONS_CACHE_URL}" ]; }; then
DOCKER_CACHE_ARGS_ULTRA_LITE="--cache-from type=gha,scope=stirling-pdf-ultra-lite --cache-to type=gha,mode=max,scope=stirling-pdf-ultra-lite"
else
DOCKER_CACHE_ARGS_ULTRA_LITE=""
fi
docker buildx build --build-arg VERSION_TAG=alpha \
-t docker.stirlingpdf.com/stirlingtools/stirling-pdf:ultra-lite \ -t docker.stirlingpdf.com/stirlingtools/stirling-pdf:ultra-lite \
-f ./docker/embedded/Dockerfile.ultra-lite . -f ./docker/embedded/Dockerfile.ultra-lite \
--load \
${DOCKER_CACHE_ARGS_ULTRA_LITE} .
else else
echo "Skipping ultra-lite image build - no ultra-lite tests in rerun list" echo "Skipping ultra-lite image build - no ultra-lite tests in rerun list"
fi fi
@@ -482,7 +489,7 @@ main() {
should_run_test "Stirling-PDF-Fat-Disable-Endpoints-Version-Check"; then should_run_test "Stirling-PDF-Fat-Disable-Endpoints-Version-Check"; then
export DISABLE_ADDITIONAL_FEATURES=false export DISABLE_ADDITIONAL_FEATURES=false
if ! ./gradlew clean build; then if ! ./gradlew clean build -PnoSpotless; then
echo "Gradle build failed with security enabled, exiting script." echo "Gradle build failed with security enabled, exiting script."
exit 1 exit 1
fi fi
@@ -491,11 +498,18 @@ main() {
EXPECTED_VERSION=$(get_expected_version) EXPECTED_VERSION=$(get_expected_version)
echo "Expected version with security enabled: $EXPECTED_VERSION" echo "Expected version with security enabled: $EXPECTED_VERSION"
# Build Fat (Security) image with embedded frontend for GHCR tag used in all 'fat' compose files # Build Fat (Security) image with embedded frontend (matching all 'fat' compose files)
echo "Building fat image for tests that require it..." echo "Building fat image for tests that require it..."
docker build --no-cache --pull --build-arg VERSION_TAG=alpha \ if [ -n "${ACTIONS_RUNTIME_TOKEN}" ] && { [ -n "${ACTIONS_RESULTS_URL}" ] || [ -n "${ACTIONS_CACHE_URL}" ]; }; then
DOCKER_CACHE_ARGS_FAT="--cache-from type=gha,scope=stirling-pdf-fat --cache-to type=gha,mode=max,scope=stirling-pdf-fat"
else
DOCKER_CACHE_ARGS_FAT=""
fi
docker buildx build --build-arg VERSION_TAG=alpha \
-t docker.stirlingpdf.com/stirlingtools/stirling-pdf:fat \ -t docker.stirlingpdf.com/stirlingtools/stirling-pdf:fat \
-f ./docker/embedded/Dockerfile.fat . -f ./docker/embedded/Dockerfile.fat \
--load \
${DOCKER_CACHE_ARGS_FAT} .
else else
echo "Skipping fat image build - no fat tests in rerun list" echo "Skipping fat image build - no fat tests in rerun list"
fi fi