Compare commits

...
3 Commits
Author SHA1 Message Date
Rsclub2_2andClaude Opus 5.5 f165f7d303 fix(aur): build the source packages' launcher with Temurin (#150)
The kst4contest and kst4contest-git packages built jpackage's launcher
with Arch's openjdk, which links libapplauncher.so against the shared
libstdc++. That build aborts now and then on exit with "pure virtual
method called" in a static destructor (SIGABRT, core dump), the failure
Debian describes for non-static libstdc++ builds. Temurin links
libstdc++ statically, like the CI-built packages.

Both PKGBUILDs now fetch a pinned Temurin 21.0.13+9 through
source_x86_64, so aur-publish.yml's rewrite of the sha256sums= line
leaves it alone, and point the Gradle toolchain at it alone.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 01:21:37 +02:00
Rsclub2_2andClaude Opus 5.5 738ae2125e ci: print full stacks of failed tests and keep reports on a cancel (#151)
Nightly #303 named the hanging test, SelectedStationMessageUiVisual-
RenderingTest at scene.render(), but the short exception format showed
only that line, not the call that blocked below it. The job timeout
cancels the run, and the test reports were kept only on failure().

Failed tests now print their full stack, causes included, and the
reports are uploaded on cancelled() as well.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 01:15:56 +02:00
Rsclub2_2andClaude Opus 5.5 af8affda8c ci: fail hanging tests by name instead of holding the job (#149)
Nightly #302 and the PR check for #147 hung in :app-desktop:test for
over an hour, and the log named only the task. Thirteen reruns of the
same commit passed, so the hang is rare and still unidentified.

Every test now gets a two-minute JUnit timeout in a separate thread, so
even an uninterruptible hang fails with the test's name and the stack
where it stood. The test jobs are capped at 20 minutes for a hang
outside any test.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 00:47:25 +02:00
6 changed files with 70 additions and 9 deletions

No files matched your search

+6 -1
View File
@@ -32,6 +32,9 @@ jobs:
test: test:
name: Test (Java 21, headless) name: Test (Java 21, headless)
runs-on: ubuntu-latest runs-on: ubuntu-latest
# A healthy run takes about four minutes. The per-test limit in build.gradle.kts names
# a hanging test; this cap covers a hang outside any test, such as in Gradle itself.
timeout-minutes: 20
steps: steps:
- name: Checkout - name: Checkout
@@ -108,8 +111,10 @@ jobs:
exit 1 exit 1
fi fi
# Also on cancelled(): the job timeout cancels a hanging run, and the reports of the
# classes that did finish carry the timed-out tests' full stacks.
- name: Keep the test reports on a failure - name: Keep the test reports on a failure
if: failure() if: failure() || cancelled()
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: test-results name: test-results
+6 -1
View File
@@ -155,6 +155,9 @@ jobs:
test: test:
name: Test (Java 21, headless) name: Test (Java 21, headless)
runs-on: ubuntu-latest runs-on: ubuntu-latest
# A healthy run takes about four minutes. The per-test limit in build.gradle.kts names
# a hanging test; this cap covers a hang outside any test, such as in Gradle itself.
timeout-minutes: 20
steps: steps:
- name: Checkout - name: Checkout
@@ -283,8 +286,10 @@ jobs:
if-no-files-found: ignore if-no-files-found: ignore
retention-days: 14 retention-days: 14
# Also on cancelled(): the job timeout cancels a hanging run, and the reports of the
# classes that did finish carry the timed-out tests' full stacks.
- name: Keep the test reports on a failure - name: Keep the test reports on a failure
if: failure() if: failure() || cancelled()
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: test-results name: test-results
+6 -1
View File
@@ -24,6 +24,9 @@ jobs:
test: test:
name: Test (Java 21, headless) name: Test (Java 21, headless)
runs-on: ubuntu-latest runs-on: ubuntu-latest
# A healthy run takes about four minutes. The per-test limit in build.gradle.kts names
# a hanging test; this cap covers a hang outside any test, such as in Gradle itself.
timeout-minutes: 20
steps: steps:
- name: Checkout - name: Checkout
@@ -127,8 +130,10 @@ jobs:
exit 1 exit 1
fi fi
# Also on cancelled(): the job timeout cancels a hanging run, and the reports of the
# classes that did finish carry the timed-out tests' full stacks.
- name: Keep the test reports on a failure - name: Keep the test reports on a failure
if: failure() if: failure() || cancelled()
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: test-results name: test-results
+15
View File
@@ -141,6 +141,21 @@ subprojects {
} }
testUserHome.mkdirs() testUserHome.mkdirs()
} }
/*
* A test that never returns must fail by name instead of holding the job until
* GitHub kills it after six hours: Nightly #302 hung in :app-desktop:test for over
* an hour, and the log named only the task. The limit is far above the slowest test
* (under four seconds). SEPARATE_THREAD also ends a test whose thread ignores
* interruption, such as a busy loop or a blocked native call, and the failure's
* cause carries that thread's stack, so it shows where the test stood.
*/
systemProperty("junit.jupiter.execution.timeout.default", "2m")
systemProperty("junit.jupiter.execution.timeout.thread.mode.default", "SEPARATE_THREAD")
// The default short format prints only the first frame of each cause, which for a
// timed-out test is the line it hung in but not the call that blocked there.
testLogging {
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
finalizedBy(checkTestUserHome) finalizedBy(checkTestUserHome)
} }
+19 -3
View File
@@ -7,12 +7,22 @@ arch=('x86_64')
url="https://github.com/HamRadioOnline/kst4contest" url="https://github.com/HamRadioOnline/kst4contest"
license=('GPL-3.0-only') license=('GPL-3.0-only')
depends=('gst-plugins-base' 'gst-plugins-good') depends=('gst-plugins-base' 'gst-plugins-good')
makedepends=('java-environment=21' 'git') makedepends=('git')
provides=('kst4contest') provides=('kst4contest')
conflicts=('kst4contest' 'kst4contest-bin') conflicts=('kst4contest' 'kst4contest-bin')
source=("kst4contest::git+https://github.com/HamRadioOnline/kst4contest.git") source=("kst4contest::git+https://github.com/HamRadioOnline/kst4contest.git")
sha256sums=('SKIP') sha256sums=('SKIP')
# The launcher is built with Temurin, not with the system JDK. Arch's openjdk links
# jpackage's launcher library against the shared libstdc++, and that build aborts
# with "pure virtual method called" (SIGABRT, core dump) in a static destructor when
# the application exits; Temurin links libstdc++ statically, like the CI packages.
# The _x86_64 arrays are deliberate: aur-publish.yml rewrites the plain sha256sums=
# line on every release and would drop a second entry there.
_temurin=21.0.13+9
source_x86_64=("https://github.com/adoptium/temurin21-binaries/releases/download/jdk-${_temurin/+/%2B}/OpenJDK21U-jdk_x64_linux_hotspot_${_temurin/+/_}.tar.gz")
sha256sums_x86_64=('d7f5d5cf865a2902b70ff549b97586a7d3f234e016f041ab447ea740c7d66d1c')
pkgver() { pkgver() {
cd "${srcdir}/kst4contest" cd "${srcdir}/kst4contest"
BASE=$(grep -m1 '^version=' gradle.properties \ BASE=$(grep -m1 '^version=' gradle.properties \
@@ -23,7 +33,7 @@ pkgver() {
build() { build() {
cd "${srcdir}/kst4contest" cd "${srcdir}/kst4contest"
export JAVA_HOME=$(find /usr/lib/jvm -maxdepth 1 -name 'java-21-*' -type d | head -n 1) export JAVA_HOME="${srcdir}/jdk-${_temurin}"
export PATH="${JAVA_HOME}/bin:${PATH}" export PATH="${JAVA_HOME}/bin:${PATH}"
# A Gradle home inside $srcdir keeps the build independent of whatever the # A Gradle home inside $srcdir keeps the build independent of whatever the
@@ -31,7 +41,13 @@ build() {
# cache, every dependency added since the last local build broke the package. # cache, every dependency added since the last local build broke the package.
export GRADLE_USER_HOME="${srcdir}/gradle-home" export GRADLE_USER_HOME="${srcdir}/gradle-home"
./gradlew --no-daemon -S :app-desktop:createDistributable # The Java toolchain, and with it jpackage, would otherwise pick any JDK 21 it
# finds in /usr/lib/jvm, the system one included.
./gradlew --no-daemon -S \
-Porg.gradle.java.installations.auto-detect=false \
-Porg.gradle.java.installations.auto-download=false \
-Porg.gradle.java.installations.paths="${JAVA_HOME}" \
:app-desktop:createDistributable
# package() reads dist/KST4Contest. Application name, icon and the JDK # package() reads dist/KST4Contest. Application name, icon and the JDK
# module list come from app-desktop/build.gradle.kts. # module list come from app-desktop/build.gradle.kts.
+18 -3
View File
@@ -7,16 +7,25 @@ arch=('x86_64')
url="https://github.com/HamRadioOnline/kst4contest" url="https://github.com/HamRadioOnline/kst4contest"
license=('GPL-3.0-only') license=('GPL-3.0-only')
depends=('gst-plugins-base' 'gst-plugins-good') depends=('gst-plugins-base' 'gst-plugins-good')
makedepends=('java-environment=21')
provides=('kst4contest') provides=('kst4contest')
conflicts=('kst4contest-bin' 'kst4contest-git') conflicts=('kst4contest-bin' 'kst4contest-git')
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/HamRadioOnline/kst4contest/archive/refs/tags/v${pkgver}.tar.gz") source=("${pkgname}-${pkgver}.tar.gz::https://github.com/HamRadioOnline/kst4contest/archive/refs/tags/v${pkgver}.tar.gz")
sha256sums=('e702df24a29e6f914a43934df0095bc4adbd00a9f02df3a632816c832272e914') sha256sums=('e702df24a29e6f914a43934df0095bc4adbd00a9f02df3a632816c832272e914')
# The launcher is built with Temurin, not with the system JDK. Arch's openjdk links
# jpackage's launcher library against the shared libstdc++, and that build aborts
# with "pure virtual method called" (SIGABRT, core dump) in a static destructor when
# the application exits; Temurin links libstdc++ statically, like the CI packages.
# The _x86_64 arrays are deliberate: aur-publish.yml rewrites the plain sha256sums=
# line on every release and would drop a second entry there.
_temurin=21.0.13+9
source_x86_64=("https://github.com/adoptium/temurin21-binaries/releases/download/jdk-${_temurin/+/%2B}/OpenJDK21U-jdk_x64_linux_hotspot_${_temurin/+/_}.tar.gz")
sha256sums_x86_64=('d7f5d5cf865a2902b70ff549b97586a7d3f234e016f041ab447ea740c7d66d1c')
build() { build() {
cd "${srcdir}/kst4contest-${pkgver}" cd "${srcdir}/kst4contest-${pkgver}"
export JAVA_HOME=$(find /usr/lib/jvm -maxdepth 1 -name 'java-21-*' -type d | head -n 1) export JAVA_HOME="${srcdir}/jdk-${_temurin}"
export PATH="${JAVA_HOME}/bin:${PATH}" export PATH="${JAVA_HOME}/bin:${PATH}"
# A Gradle home inside $srcdir keeps the build independent of whatever the # A Gradle home inside $srcdir keeps the build independent of whatever the
@@ -24,7 +33,13 @@ build() {
# cache, every dependency added since the last local build broke the package. # cache, every dependency added since the last local build broke the package.
export GRADLE_USER_HOME="${srcdir}/gradle-home" export GRADLE_USER_HOME="${srcdir}/gradle-home"
./gradlew --no-daemon -S :app-desktop:createDistributable # The Java toolchain, and with it jpackage, would otherwise pick any JDK 21 it
# finds in /usr/lib/jvm, the system one included.
./gradlew --no-daemon -S \
-Porg.gradle.java.installations.auto-detect=false \
-Porg.gradle.java.installations.auto-download=false \
-Porg.gradle.java.installations.paths="${JAVA_HOME}" \
:app-desktop:createDistributable
# package() reads dist/KST4Contest. Application name, icon and the JDK # package() reads dist/KST4Contest. Application name, icon and the JDK
# module list come from app-desktop/build.gradle.kts, so this PKGBUILD no # module list come from app-desktop/build.gradle.kts, so this PKGBUILD no