Compare commits

...
Author SHA1 Message Date
Ludy87 05732f5c41 Stage JaCoCo agent jar instead of bind-mounting
Move JaCoCo agent jar from build/jacoco/ to testing/cucumber-coverage/ directory so it survives clean build steps. Update docker-compose-coverage.override.yml volume mount and test.sh to copy the jar to the staging directory before running coverage tests. This ensures the agent is available even after gradlew clean.
2026-07-01 20:13:04 +02:00
Ludy87 4dd642069e Update docker-compose-tests.yml 2026-07-01 19:40:18 +02:00
Ludy87 9a9d9982a7 Enable JaCoCo restore and update compose stop grace
If STIRLING_PDF_TEST_COVERAGE is set and build/jacoco/jacocoagent.jar is missing, attempt to restore it by running gradlew copyJacocoAgent -PnoSpotless and only enable Cucumber JaCoCo coverage if the agent is present; otherwise emit a warning. Also set stop_grace_period: 1m for the stirling-pdf service in the coverage docker-compose override to allow a cleaner shutdown during coverage runs.
2026-07-01 19:18:02 +02:00
Ludy87 92aa5a0f86 Remove coverage artifact download conditionals
Simplify the coverage-aggregate workflow by removing the download_vitest_coverage and download_playwright_coverage inputs. These inputs defaulted to true and added unnecessary complexity. Artifact downloads are now always attempted, and the workflow gracefully handles missing artifacts.
2026-07-01 19:13:03 +02:00
Ludy87 ae3165154d Fix Playwright report paths in CI workflows
Update artifact upload paths from frontend/editor/playwright-report/ to frontend/playwright-report/ in both e2e and enterprise build workflows to match current directory structure.
2026-07-01 18:36:11 +02:00
Ludy87 133e1ef674 Update settingsPendingHelper.ts 2026-07-01 18:25:41 +02:00
Ludy87 d569e3533a Make frontend coverage download conditional
Add inputs to the coverage-aggregate workflow to control downloading frontend coverage artifacts (download_vitest_coverage, download_playwright_coverage) and default them to true. Update build.yml to pass those flags based on frontend-validation and playwright-e2e-live job results. Guard artifact download steps with the new inputs and standardize the Playwright artifact name to a stable value (playwright-frontend-coverage). Continue-on-error behavior retained so backend-only PRs remain resilient.
2026-07-01 18:23:34 +02:00
Ludy87 641b005555 Add NSIS installer bundle to Windows releases
Enable NSIS (.exe) as an additional Windows installer bundle alongside MSI. Adds signature verification for NSIS installer and includes it in artifacts and latest.json metadata. Updates documentation strings to reflect both installer types.
2026-07-01 16:51:32 +02:00
11 changed files with 67 additions and 30 deletions
+1 -1
View File
@@ -285,5 +285,5 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-enterprise-${{ github.run_id }}
path: frontend/editor/playwright-report/
path: frontend/playwright-report/
retention-days: 7
+2 -2
View File
@@ -206,12 +206,12 @@ jobs:
continue-on-error: true
- name: Download Playwright frontend coverage artifact
# e2e-live uploads as `playwright-frontend-coverage-<run_id>`.
# e2e-live uploads the artifact with a stable name.
# Same tolerance as vitest - matrix script handles missing inputs.
if: always()
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v6.0.0
with:
name: playwright-frontend-coverage-${{ github.run_id }}
name: playwright-frontend-coverage
path: matrix-inputs/playwright/
continue-on-error: true
+3 -3
View File
@@ -170,7 +170,7 @@ jobs:
if-no-files-found: warn
- name: Upload Cucumber Report
if: always()
if: always() && hashFiles('testing/cucumber/report.html') != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: cucumber-report
@@ -179,7 +179,7 @@ jobs:
if-no-files-found: warn
- name: Upload Test Reports
if: always()
if: always() && hashFiles('testing/reports/**') != ''
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: docker-compose-test-reports
@@ -188,7 +188,7 @@ jobs:
if-no-files-found: warn
- name: Cucumber Test Report
if: always()
if: always() && hashFiles('testing/cucumber/junit/*.xml') != ''
uses: dorny/test-reporter@a43b3a5f7366b97d083190328d2c652e1a8b6aa2 # v3.0.0
with:
name: Cucumber Tests
+1 -1
View File
@@ -169,7 +169,7 @@ jobs:
if: always() && steps.pw-frontend-coverage.outputs.summary == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-frontend-coverage-${{ github.run_id }}
name: playwright-frontend-coverage
path: |
.test-state/playwright/coverage-pw-summary/
.test-state/playwright/coverage-pw/
+1 -1
View File
@@ -50,5 +50,5 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report-stubbed-${{ github.run_id }}
path: frontend/editor/playwright-report/
path: frontend/playwright-report/
retention-days: 7
+24 -4
View File
@@ -94,7 +94,7 @@ jobs:
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
case "${{ github.event.inputs.platform }}" in
"windows")
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64","jpdfium_platforms":"windows-x64"}]}' >> $GITHUB_OUTPUT
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc --bundles msi,nsis","name":"windows-x86_64","jpdfium_platforms":"windows-x64"}]}' >> $GITHUB_OUTPUT
;;
"macos")
echo 'matrix={"include":[{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"}]}' >> $GITHUB_OUTPUT
@@ -103,12 +103,12 @@ jobs:
echo 'matrix={"include":[{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}]}' >> $GITHUB_OUTPUT
;;
*)
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64","jpdfium_platforms":"windows-x64"},{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}]}' >> $GITHUB_OUTPUT
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc --bundles msi,nsis","name":"windows-x86_64","jpdfium_platforms":"windows-x64"},{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}]}' >> $GITHUB_OUTPUT
;;
esac
else
# For push/release events, build all platforms
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64","jpdfium_platforms":"windows-x64"},{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}]}' >> $GITHUB_OUTPUT
echo 'matrix={"include":[{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc --bundles msi,nsis","name":"windows-x86_64","jpdfium_platforms":"windows-x64"},{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"},{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}]}' >> $GITHUB_OUTPUT
fi
build-jars:
@@ -553,11 +553,24 @@ jobs:
$allSigned = $false
}
$nsisPath = "./dist/Stirling-PDF-${{ matrix.name }}.nsis.exe"
if (Test-Path $nsisPath) {
$sig = Get-AuthenticodeSignature -FilePath $nsisPath
Write-Host "NSIS: Status=$($sig.Status), Signer=$($sig.SignerCertificate.Subject)"
if ($sig.Status -ne "Valid") {
Write-Host "[ERROR] NSIS installer is not signed"
$allSigned = $false
}
} else {
Write-Host "[ERROR] NSIS installer not found at $nsisPath"
$allSigned = $false
}
if (-not $allSigned) {
Write-Host "[ERROR] Signature verification failed"
exit 1
}
Write-Host "[SUCCESS] MSI and installed exe are properly signed"
Write-Host "[SUCCESS] MSI, NSIS installer, and installed exe are properly signed"
# Dump smctl log files on failure. Tauri's signCommand captures smctl output
# but drops stderr when the command exits non-zero, making failures opaque.
@@ -598,7 +611,9 @@ jobs:
# each <bundle> ships with a sibling <bundle>.sig consumed by latest.json.
if [ "${{ matrix.platform }}" = "windows-latest" ]; then
find . -name "*.msi" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.msi" \;
find . -path "*/bundle/nsis/*" -name "*.exe" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.nsis.exe" \;
find . -name "*.msi.sig" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.msi.sig" \;
find . -path "*/bundle/nsis/*" -name "*.exe.sig" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.nsis.exe.sig" \;
elif [ "${{ matrix.platform }}" = "macos-15" ]; then
# DMG = manual install; .app.tar.gz (+ .sig) = updater payload.
# Raw .app is intentionally not shipped (hundreds of MB of uncompressed input).
@@ -713,6 +728,10 @@ jobs:
'bundles': ['Stirling-PDF-windows-x86_64.msi'],
'targets': ['windows-x86_64-msi', 'windows-x86_64'],
},
{
'bundles': ['Stirling-PDF-windows-x86_64.nsis.exe'],
'targets': ['windows-x86_64-nsis'],
},
{
'bundles': ['Stirling-PDF-macos-universal.app.tar.gz'],
'targets': ['darwin-x86_64', 'darwin-aarch64'],
@@ -807,6 +826,7 @@ jobs:
files: |
./artifacts/**/*.jar
./artifacts/**/*.msi
./artifacts/**/*.nsis.exe
./artifacts/**/*.dmg
./artifacts/**/*.app.tar.gz
./artifacts/**/*.deb
+1 -1
View File
@@ -54,7 +54,7 @@ jobs:
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-nightly-${{ github.run_id }}
path: frontend/editor/playwright-report/
path: frontend/playwright-report/
retention-days: 14
# Builds all desktop platforms on a schedule so the Rust dependency cache is
+3 -2
View File
@@ -61,7 +61,7 @@ jobs:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
PLATFORM: ${{ inputs.platform }}
run: |
WINDOWS='{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc","name":"windows-x86_64","jpdfium_platforms":"windows-x64"}'
WINDOWS='{"platform":"windows-latest","args":"--target x86_64-pc-windows-msvc --bundles msi,nsis","name":"windows-x86_64","jpdfium_platforms":"windows-x64"}'
MACOS='{"platform":"macos-15","args":"--target universal-apple-darwin","name":"macos-universal","jpdfium_platforms":"darwin-arm64,darwin-x64"}'
LINUX='{"platform":"ubuntu-22.04","args":"","name":"linux-x86_64","jpdfium_platforms":"linux-x64"}'
@@ -471,6 +471,7 @@ jobs:
# Only ship the MSI installer. The loose exe and WiX toolset exes
# are not the user-facing installer - the MSI contains the signed inner exe.
find . -name "*.msi" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.msi" \;
find . -path "*/bundle/nsis/*" -name "*.exe" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.nsis.exe" \;
elif [ "${{ matrix.platform }}" = "macos-15" ]; then
find . -name "*.dmg" -exec cp {} "$DIST/Stirling-PDF-${{ matrix.name }}.dmg" \;
else
@@ -628,7 +629,7 @@ jobs:
// Map of expected artifact names to display info
const artifactMap = {
'Stirling-PDF-windows-x86_64': { icon: '🪟', platform: 'Windows x64', files: '.exe, .msi' },
'Stirling-PDF-windows-x86_64': { icon: '🪟', platform: 'Windows x64', files: '.exe (NSIS), .msi' },
'Stirling-PDF-macos-universal': { icon: '🍎', platform: 'macOS Universal', files: '.dmg' },
'Stirling-PDF-linux-x86_64': { icon: '🐧', platform: 'Linux x64', files: '.deb, .rpm, .AppImage' }
};
@@ -52,7 +52,7 @@ export function isFieldPending<T extends SettingsWithPending>(
fieldPath: string,
): boolean {
if (!settings?._pending) {
console.log(
console.debug(
`[isFieldPending] No _pending block found for field: ${fieldPath}`,
);
return false;
@@ -63,7 +63,7 @@ export function isFieldPending<T extends SettingsWithPending>(
const isPending = value !== undefined;
if (isPending) {
console.log(
console.debug(
`[isFieldPending] Field ${fieldPath} IS pending with value:`,
value,
);
@@ -1,10 +1,10 @@
# Coverage override applied on top of an existing test compose file via
# `docker compose -f base.yml -f docker-compose-coverage.override.yml up`.
#
# It does NOT modify the production image. The agent jar is bind-mounted in
# from the host's `build/jacoco/jacocoagent.jar` (produced by `./gradlew
# copyJacocoAgent`) so the published Stirling-PDF image stays untouched and
# we cannot accidentally ship the agent to end users.
# It does NOT modify the production image. The agent jar is staged under
# `testing/cucumber-coverage/jacocoagent.jar` (copied there from
# `./gradlew copyJacocoAgent`) so the published Stirling-PDF image stays
# untouched and we cannot accidentally ship the agent to end users.
#
# The container appends the agent to its JVM via `JAVA_CUSTOM_OPTS`, which
# the init script concatenates into `JAVA_TOOL_OPTIONS` for the Spring Boot
@@ -14,11 +14,12 @@
# `jacocoReportFromExec` task converts into HTML+XML.
services:
stirling-pdf:
stop_grace_period: 1m
# docker-compose-security-with-login.yml renames the service container,
# so the volume mounts intentionally land on whichever service uses the
# key "stirling-pdf" in the base file.
volumes:
- ../../build/jacoco/jacocoagent.jar:/jacoco/jacocoagent.jar:ro
- ../cucumber-coverage/jacocoagent.jar:/jacoco/jacocoagent.jar:ro
- ../../testing/cucumber-coverage:/jacoco-out:rw
environment:
# append=false so an aborted re-run starts clean. dumponexit=true is
+23 -8
View File
@@ -874,20 +874,35 @@ main() {
# 3. Regression test with login (test_cicd.yml)
# ==================================================================
# STIRLING_PDF_TEST_COVERAGE=1 layers the JaCoCo agent override over
# the cucumber container ONLY. The agent jar is bind-mounted from
# build/jacoco/jacocoagent.jar so the published image never carries
# it. After behave finishes, we trigger `docker compose down` (further
# down) which sends SIGTERM and lets dumponexit=true flush the .exec
# to testing/cucumber-coverage/cucumber.exec on the host.
# the cucumber container ONLY. We stage the agent jar under
# testing/cucumber-coverage/ so it survives the clean build steps
# above; the published image never carries it. After behave finishes,
# we trigger `docker compose down` (further down) which sends SIGTERM
# and lets dumponexit=true flush the .exec to
# testing/cucumber-coverage/cucumber.exec on the host.
COVERAGE_COMPOSE_FILE=""
COVERAGE_AGENT_SOURCE="$PROJECT_ROOT/build/jacoco/jacocoagent.jar"
COVERAGE_AGENT_TARGET="$PROJECT_ROOT/testing/cucumber-coverage/jacocoagent.jar"
if [ -n "${STIRLING_PDF_TEST_COVERAGE:-}" ]; then
if [ ! -f "$PROJECT_ROOT/build/jacoco/jacocoagent.jar" ]; then
echo "::warning::STIRLING_PDF_TEST_COVERAGE=1 but build/jacoco/jacocoagent.jar is missing - run ./gradlew copyJacocoAgent first"
else
if [ ! -f "$COVERAGE_AGENT_TARGET" ]; then
if [ ! -f "$COVERAGE_AGENT_SOURCE" ]; then
echo "::warning::STIRLING_PDF_TEST_COVERAGE=1 but build/jacoco/jacocoagent.jar is missing - trying to restore it"
"$PROJECT_ROOT/gradlew" copyJacocoAgent -PnoSpotless
fi
if [ -f "$COVERAGE_AGENT_SOURCE" ]; then
mkdir -p "$PROJECT_ROOT/testing/cucumber-coverage"
cp "$COVERAGE_AGENT_SOURCE" "$COVERAGE_AGENT_TARGET"
fi
fi
if [ -f "$COVERAGE_AGENT_TARGET" ]; then
mkdir -p "$PROJECT_ROOT/testing/cucumber-coverage"
rm -f "$PROJECT_ROOT/testing/cucumber-coverage/cucumber.exec"
COVERAGE_COMPOSE_FILE="$PROJECT_ROOT/testing/compose/docker-compose-coverage.override.yml"
echo "Cucumber JaCoCo coverage enabled - exec will land at testing/cucumber-coverage/cucumber.exec"
else
echo "::warning::Unable to enable Cucumber coverage because build/jacoco/jacocoagent.jar is still missing"
fi
fi