Skip to content

Commit eee2313

Browse files
authored
Implements #318 - better Windows installer support (#331)
1 parent 5fce5b1 commit eee2313

17 files changed

Lines changed: 623 additions & 273 deletions

.github/workflows/do-release.yml

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@ env:
1515
GIT_AUTHOR_EMAIL: <>
1616
GIT_COMMITTER_NAME: Terminator the Kitty
1717
GIT_COMMITTER_EMAIL: <>
18+
1819
jobs:
1920
do-release:
2021
runs-on: ubuntu-latest
22+
outputs:
23+
tag: ${{ steps.maven_release.outputs.TAG }}
24+
version: ${{ steps.maven_release.outputs.VERSION }}
2125
steps:
2226
- name: Checkout
2327
uses: actions/checkout@v6
@@ -60,16 +64,13 @@ jobs:
6064
mvn -P release --batch-mode release:perform \
6165
-DstagingProgressTimeoutMinutes=30 -Dmaven.wagon.rto=7200000 \
6266
-Dmaven.wagon.httpconnectionManager.maxPerRoute=60 -Dmaven.wagon.httpconnectionManager.maxTotal=100
63-
docker run --rm -v "$(pwd):/mnt" \
64-
-u $(id -u):$(id -g) kwart/innosetup \
65-
/mnt/distribution/windows/create-jsignpdf-installer.sh
6667
cd distribution/target
6768
ls -R
6869
mkdir "JSignPdf-$VERSION"
69-
mv *.zip *.exe "$FULL_VERSION/"
70+
mv *.zip "$FULL_VERSION/"
7071
cp generated-docs/JSignPdf.pdf "$FULL_VERSION/$FULL_VERSION.pdf"
7172
cp "../doc/release-notes/${BASE_VERSION}.md" "$FULL_VERSION/README.md"
72-
73+
7374
echo "${{ secrets.SSH_PRIVATE_KEY }}" >> private_key
7475
chmod 600 private_key
7576
sftp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i private_key kwart@frs.sourceforge.net:/home/frs/project/jsignpdf/stable <<EOF
@@ -78,6 +79,7 @@ jobs:
7879
EOF
7980
mv "$FULL_VERSION" upload
8081
echo "TAG=$TAG" >> $GITHUB_OUTPUT
82+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
8183
echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_OUTPUT
8284
env:
8385
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
@@ -92,3 +94,49 @@ jobs:
9294
tag: ${{ steps.maven_release.outputs.TAG }}
9395
overwrite: true
9496
body_path: distribution/doc/release-notes/${{ steps.maven_release.outputs.BASE_VERSION }}.md
97+
98+
- name: Publish PDF guide for downstream jobs
99+
uses: actions/upload-artifact@v4
100+
with:
101+
name: jsignpdf-pdf-guide
102+
path: distribution/target/generated-docs/JSignPdf.pdf
103+
if-no-files-found: error
104+
retention-days: 1
105+
106+
windows-installers:
107+
needs: do-release
108+
runs-on: windows-latest
109+
steps:
110+
- name: Checkout release tag
111+
uses: actions/checkout@v6
112+
with:
113+
ref: ${{ needs.do-release.outputs.tag }}
114+
115+
- name: Set up JDK 21
116+
uses: actions/setup-java@v5
117+
with:
118+
java-version: 21
119+
distribution: 'temurin'
120+
cache: 'maven'
121+
122+
- name: Build jsignpdf and installcert jars
123+
shell: bash
124+
run: mvn -B -DskipTests -pl jsignpdf,installcert -am package
125+
126+
- name: Download PDF guide from the release job
127+
uses: actions/download-artifact@v4
128+
with:
129+
name: jsignpdf-pdf-guide
130+
path: distribution/target/pdf-guide
131+
132+
- name: Build Windows installers (EXE / MSI / ZIP)
133+
shell: pwsh
134+
run: ./distribution/windows/build-windows-installers.ps1 -Version ${{ needs.do-release.outputs.version }}
135+
136+
- name: Upload Windows installers to release
137+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de
138+
with:
139+
file: distribution/target/upload/*
140+
file_glob: true
141+
tag: ${{ needs.do-release.outputs.tag }}
142+
overwrite: true
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Replace InnoSetup+launch4j+Ant with jpackage for the Windows installer
2+
3+
## Context
4+
5+
The old Windows installer was produced by a Docker image (`kwart/innosetup`) that
6+
ran Ant + Launch4j to wrap the shaded jar into `.exe` launchers, copied bundled
7+
JREs from `/opt/jre32` and `/opt/jre64`, and ran `iscc` (InnoSetup) under Wine to
8+
produce a single fat `.exe` installer that selected 32- or 64-bit at install
9+
time. This setup was brittle — it depended on a custom Docker image, Wine, Ant,
10+
Launch4j, and prebuilt JREs.
11+
12+
It has been replaced with `jpackage`, running natively on a `windows-latest`
13+
GitHub Actions runner. Three artifact types (EXE, MSI, ZIP) are produced for
14+
x64 only. 32-bit Windows is dropped (Temurin no longer ships 32-bit JDKs),
15+
but the existing cross-arch no-JRE distribution zip (`jsignpdf-${VERSION}.zip`)
16+
is kept so that 32-bit users (and Linux/Mac users) can run JSignPdf with their
17+
own JRE.
18+
19+
## Final artifact set per release
20+
21+
Produced by the ubuntu Maven job:
22+
23+
- `jsignpdf-${VERSION}.zip` — cross-arch, no JRE (existing assembly, unchanged)
24+
25+
Produced by the windows-latest jpackage job:
26+
27+
- `JSignPdf-${VERSION}-win-x64.exe` — WiX-based EXE installer with MPL-2.0 license page
28+
- `JSignPdf-${VERSION}-win-x64.msi` — WiX-based MSI installer with MPL-2.0 license page
29+
- `JSignPdf-${VERSION}-win-x64.zip` — zipped jpackage app-image (portable, bundled JRE)
30+
31+
All four are uploaded to the same GitHub Release tag. The cross-arch zip also
32+
goes to SourceForge.
33+
34+
## Source tree layout
35+
36+
### `distribution/jpackage/` — configuration
37+
38+
- **`common-jvm-options.txt`** — single source of truth for JVM module
39+
exports/opens shared across all launchers. One option per line, `#` comments
40+
supported. The heap settings (`-Xms1g`/`-Xmx1g`) were intentionally removed
41+
to let the JVM use its defaults. Current contents:
42+
```
43+
--add-exports=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
44+
--add-exports=jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED
45+
--add-exports=java.base/sun.security.action=ALL-UNNAMED
46+
--add-exports=java.base/sun.security.rsa=ALL-UNNAMED
47+
--add-opens=java.base/sun.security.util=ALL-UNNAMED
48+
```
49+
50+
- **`JSignPdfC.properties`** — console add-launcher; contains only
51+
`win-console=true`. All other settings (java-options, icon) are inherited
52+
from the main JSignPdf launcher.
53+
54+
Two additional add-launcher files are **generated at build time** by the
55+
PowerShell script into `distribution/target/jpackage-generated/`:
56+
57+
- **`JSignPdf-swing.properties`** — Swing GUI. Generated because it must
58+
override `java-options` to add `-Djsignpdf.swing=true` alongside the common
59+
options (jpackage replaces rather than merges java-options). Generating it
60+
from `common-jvm-options.txt` avoids duplicating the option list.
61+
62+
- **`InstallCert.properties`** — console launcher for `InstallCert.jar`.
63+
Generated so it can carry an absolute path to `Certificate.ico` (jpackage
64+
resolves add-launcher icon paths against the working directory, which varies
65+
between CI and local builds).
66+
67+
The legacy `-Djsignpdf.home="%EXEDIR%"` flag was intentionally dropped. jpackage
68+
sets the working directory itself; if a regression surfaces during testing, it
69+
can be re-added via `--java-options "-Djsignpdf.home=$APPDIR"`.
70+
71+
### `distribution/windows/build-windows-installers.ps1` — build script
72+
73+
PowerShell script invoked by the workflow. Lives in the repo so it can be
74+
tested locally on a Windows box. Key responsibilities:
75+
76+
1. **Version sanitization**: `$Version` is split into a jpackage-compatible
77+
numeric `$appVersion` (strips `-RC1`, `-SNAPSHOT`, `.Final` etc., keeps up
78+
to three numeric components). `$Version` is preserved for release-aligned
79+
filenames; `$appVersion` is what jpackage receives via `--app-version`.
80+
81+
2. **WiX fallback**: checks for `light.exe` on PATH; if absent, installs WiX
82+
3.14 via `choco install wixtoolset` and adds its bin directory to the
83+
session PATH.
84+
85+
3. **Artifact cleanup**: removes `JSignPdf-*-win-x64.*` from `upload/` so
86+
repeat local runs don't accumulate stale artifacts.
87+
88+
4. **Jar staging**: copies the shaded `JSignPdf.jar` and `InstallCert.jar`
89+
from module target directories.
90+
91+
5. **PDF guide**: if `distribution/target/pdf-guide/*.pdf` exists (downloaded
92+
from the ubuntu job's workflow artifact in CI), stages it into
93+
`jpackage-app-content/docs/JSignPdf.pdf` and passes it as
94+
`--app-content` to jpackage. The PDF ends up at `<install>/app/docs/`
95+
in the installed tree. If absent (local builds), logs a warning and
96+
proceeds without it.
97+
98+
6. **Common JVM options**: reads `common-jvm-options.txt` and expands into
99+
`--java-options` pairs for the main launcher. Also generates the Swing
100+
and InstallCert add-launcher `.properties` files from the same source.
101+
102+
7. **App-image build**: `jpackage --type app-image` with four launchers
103+
(JSignPdf as main, plus JSignPdf-swing, JSignPdfC, InstallCert as
104+
add-launchers). Icons: `icons.ico` for the main + console + swing
105+
launchers, `Certificate.ico` for InstallCert.
106+
107+
8. **Zip**: `Compress-Archive` of the app-image directory (includes the
108+
`JSignPdf/` parent folder at the zip root).
109+
110+
9. **EXE + MSI**: `jpackage --type exe` and `--type msi` from the app-image,
111+
with `--license-file` (MPL-2.0), `--win-menu`, `--win-shortcut`,
112+
`--win-dir-chooser`, and a stable `--win-upgrade-uuid`.
113+
114+
10. **Rename + move**: jpackage output files use `$appVersion` in the
115+
filename; the script renames them to `$Version` for release-tag alignment
116+
and moves them into `distribution/target/upload/`.
117+
118+
### `.github/workflows/do-release.yml` — release workflow
119+
120+
Two jobs:
121+
122+
- **`do-release`** (ubuntu-latest, JDK 11):
123+
- Verifies per-version release notes file exists
124+
(`distribution/doc/release-notes/${BASE_VERSION}.md`).
125+
- Maven Central deploy via `release:prepare` / `release:perform`.
126+
- Organizes artifacts and uploads to SourceForge + GitHub Release (with
127+
`body_path` pointing at the release notes markdown).
128+
- Publishes `distribution/target/generated-docs/JSignPdf.pdf` as a workflow
129+
artifact (`jsignpdf-pdf-guide`) for the windows job.
130+
- Outputs: `tag`, `version`, `base_version`.
131+
132+
- **`windows-installers`** (windows-latest, JDK 21, `needs: do-release`):
133+
- Checks out the release tag.
134+
- Builds `jsignpdf` and `installcert` jars
135+
(`mvn -B -DskipTests -pl jsignpdf,installcert -am package`).
136+
- Downloads the PDF guide workflow artifact into
137+
`distribution/target/pdf-guide/`.
138+
- Runs `build-windows-installers.ps1 -Version <version>`.
139+
- Uploads the EXE/MSI/ZIP to the same GitHub Release.
140+
141+
Only `jsignpdf` and `installcert` modules are built in the windows job —
142+
the distribution module (with asciidoctor) is skipped to keep the job fast.
143+
The PDF guide is passed via workflow artifact instead.
144+
145+
## Deleted files
146+
147+
- `distribution/windows/JSignPdf.iss`
148+
- `distribution/windows/ant-build-create-launchers.xml`
149+
- `distribution/windows/create-jsignpdf-installer.sh`
150+
- `distribution/windows/launch4j-template.l4j.ini`
151+
- `distribution/windows/JSignPdf-swing.l4j.ini`
152+
- `distribution/doc/icon/splash08.bmp`
153+
- `distribution/doc/icon/splash08.xcf`
154+
- `distribution/doc/icon/splash_1.0.0.bmp`
155+
- `distribution/doc/icon/splash_1.0.0.xcf`
156+
157+
## Important constraints
158+
159+
- **`--win-upgrade-uuid` is fixed** (`7b3d6e4c-9a51-4a8b-9b1c-7e8c1a4d2f10`).
160+
It must remain stable across releases so MSI upgrades work correctly (single
161+
entry in Add/Remove Programs). Do NOT regenerate it.
162+
163+
- **WiX 3.x required**. jpackage on JDK 17+ uses WiX 3 for both EXE and MSI.
164+
GitHub `windows-latest` runners ship WiX 3 preinstalled. The script falls
165+
back to `choco install wixtoolset --version=3.14.0` if `light.exe` is
166+
missing.
167+
168+
- **Version format**: jpackage `--app-version` accepts only
169+
`MAJOR[.MINOR[.MICRO]]` (numeric). The script strips non-numeric suffixes
170+
automatically, but future releases should use clean version numbers.
171+
172+
## Verification
173+
174+
1. **Local Windows smoke test** (JDK 21 + WiX 3):
175+
```
176+
mvn -B -DskipTests -pl jsignpdf,installcert -am package
177+
pwsh ./distribution/windows/build-windows-installers.ps1 -Version 3.0.0
178+
```
179+
Confirm `distribution/target/upload/` contains
180+
`JSignPdf-3.0.0-win-x64.{exe,msi,zip}`.
181+
182+
2. **Install + launch test**:
183+
- EXE installer: verify MPL-2.0 license page, Start menu entries, JSignPdf
184+
launches.
185+
- MSI installer: same.
186+
- Portable zip: extract, run `JSignPdf.exe`, `JSignPdf-swing.exe`,
187+
`JSignPdfC.exe --help`, `InstallCert.exe`.
188+
- Verify InstallCert has the Certificate.ico icon.
189+
- Sign a sample PDF from both JavaFX and Swing UIs.
190+
191+
3. **Upgrade test**: install version N via MSI, then install N+ε over the top,
192+
confirm a single entry in Add/Remove Programs.
193+
194+
4. **PDF guide**: after installing, confirm `<install>/app/docs/JSignPdf.pdf`
195+
exists (when built in CI with the workflow artifact).
196+
197+
5. **Artifact set on GitHub Release**: confirm the release page shows
198+
`jsignpdf-${VERSION}.zip` (cross-arch) plus the three Windows artifacts,
199+
with release notes as the body.
200+
201+
## Out of scope
202+
203+
- 32-bit Windows installers.
204+
- macOS / Linux installer packaging.
205+
- Code-signing the EXE/MSI (no certificate set up; can be added later via
206+
`signtool sign` in the workflow).

distribution/doc/icon/splash08.bmp

-257 KB
Binary file not shown.

distribution/doc/icon/splash08.xcf

-250 KB
Binary file not shown.
-387 KB
Binary file not shown.
-3.11 MB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
win-console=true
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Shared JVM options for every JSignPdf launcher.
2+
#
3+
# Single source of truth consumed by distribution/windows/build-windows-installers.ps1:
4+
# * Main launcher (JSignPdf) — passed as --java-options on the jpackage command line.
5+
# * JSignPdfC / InstallCert — inherited automatically from the main launcher
6+
# because their add-launcher .properties files leave java-options unset.
7+
# * JSignPdf-swing — the build script generates the add-launcher .properties file
8+
# at build time, concatenating these options with the Swing-specific ones.
9+
#
10+
# Format: one option per line; blank lines and lines starting with '#' are ignored.
11+
--add-exports=jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED
12+
--add-exports=jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED
13+
--add-exports=java.base/sun.security.action=ALL-UNNAMED
14+
--add-exports=java.base/sun.security.rsa=ALL-UNNAMED
15+
--add-opens=java.base/sun.security.util=ALL-UNNAMED

distribution/src/assembly/assembly.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,9 @@
5050
<include>*.pdf</include>
5151
</includes>
5252
</fileSet>
53+
<fileSet>
54+
<directory>demo</directory>
55+
<outputDirectory>/demo/</outputDirectory>
56+
</fileSet>
5357
</fileSets>
5458
</assembly>

distribution/windows/JSignPdf-swing.l4j.ini

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)