mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-10-19 13:53:01 +02:00
classes already runs the generator, so an orphan key, a dropped placeholder or a duplicate fails the compile job with the generator's own message naming the file -- verified by breaking strings_de.properties on purpose. A step summary counts each language against the base, so the author of a translation PR sees what they covered without reading the build log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
186 lines
7.4 KiB
YAML
186 lines
7.4 KiB
YAML
name: PR Compile Check
|
|
|
|
on:
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
|
|
jobs:
|
|
compile:
|
|
name: Compile (Java 21)
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4.1.7
|
|
|
|
- name: Set up Java 21
|
|
uses: actions/setup-java@v4.1.0
|
|
with:
|
|
distribution: temurin
|
|
java-version: "21"
|
|
|
|
- name: Ensure gradlew is executable
|
|
run: chmod +x gradlew
|
|
|
|
# classes + testClasses rather than compileJava + compileTestJava. The old pair did
|
|
# cover Kotlin -- checked with a deliberately broken Kotlin test file, and also in
|
|
# --dry-run: the Kotlin plugin makes compileTestJava depend on compileTestKotlin,
|
|
# because Java has to see the Kotlin output. But that is the plugin's wiring and not
|
|
# this job's statement of intent, and it covered no resources. These two aggregates
|
|
# say "compile everything in all three modules" and do not depend on knowing that.
|
|
#
|
|
# They also run the translation generator, which app-desktop's compileKotlin depends
|
|
# on. That is why a pull request contributing a language needs no workflow of its own:
|
|
# an orphan key, a dropped placeholder or a duplicate fails here, with the generator's
|
|
# own message naming the file.
|
|
- name: Compile
|
|
run: ./gradlew -S classes testClasses
|
|
|
|
# What a translation PR is actually about, put where its author will look. The counts
|
|
# come from the files rather than from Gradle's output, so an up-to-date task cannot
|
|
# make the table disappear.
|
|
- name: Summarise the interface texts
|
|
if: always()
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
|
|
base="app-desktop/src/main/i18n/strings_en.properties"
|
|
if [ ! -f "$base" ]; then
|
|
echo "no base translation file at $base" >&2
|
|
exit 1
|
|
fi
|
|
|
|
count_keys() { grep -cE '^[^#!][^=]*=' "$1" || true; }
|
|
|
|
total=$(count_keys "$base")
|
|
|
|
{
|
|
echo "### Interface texts"
|
|
echo ""
|
|
echo "| language | translated | of | missing |"
|
|
echo "|---|---|---|---|"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
for file in app-desktop/src/main/i18n/strings_*.properties; do
|
|
lang=$(basename "$file" .properties); lang=${lang#strings_}
|
|
have=$(count_keys "$file")
|
|
missing=$(( total - have ))
|
|
[ "$missing" -lt 0 ] && missing=0
|
|
echo "| \`$lang\` | $have | $total | $missing |" >> "$GITHUB_STEP_SUMMARY"
|
|
done
|
|
|
|
{
|
|
echo ""
|
|
echo "A language may be incomplete: a key it leaves out falls back to English,"
|
|
echo "which is what lets a translation be contributed a piece at a time. German is"
|
|
echo "held complete by a test, because it ships."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
worksheets=(app-desktop/build/generated/i18n/todo/*.todo.properties)
|
|
if [ ${#worksheets[@]} -gt 0 ]; then
|
|
{
|
|
echo ""
|
|
echo "The build wrote a worksheet of what is still missing for:"
|
|
echo ""
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
for w in "${worksheets[@]}"; do
|
|
echo "- \`$(basename "$w")\`" >> "$GITHUB_STEP_SUMMARY"
|
|
done
|
|
fi
|
|
|
|
test:
|
|
name: Test (Java 21, headless)
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4.1.7
|
|
|
|
- name: Set up Java 21
|
|
uses: actions/setup-java@v4.1.0
|
|
with:
|
|
distribution: temurin
|
|
java-version: "21"
|
|
|
|
- name: Ensure gradlew is executable
|
|
run: chmod +x gradlew
|
|
|
|
# Skiko's native library links against libGL, so it has to be loadable even though
|
|
# nothing here renders through it: the drawing tests use Skia's software backend and
|
|
# runComposeUiTest never opens a window. Without this the whole Compose half of the
|
|
# suite dies with "libskiko-linux-x64.so: libGL.so.1: cannot open shared object
|
|
# file" -- which reads like a missing display and is not one. Found by running this
|
|
# job under act, where the container has no libGL; GitHub's own runner image happens
|
|
# to ship it, so the step is what makes the job reproducible off GitHub.
|
|
- name: Install the OpenGL client library skiko links against
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends libgl1
|
|
|
|
# No Xvfb, deliberately. Everything that pins behaviour runs without a display:
|
|
# runComposeUiTest reaches the semantics tree headless (measured before this job was
|
|
# written), and the ImageComposeScene drawing tests render in software. The handful
|
|
# of tests that open a real window guard themselves with assumeFalse(isHeadless) and
|
|
# skip here; the summary below prints the skip count, so that is visible rather than
|
|
# assumed.
|
|
#
|
|
# Software GL under Xvfb was considered and rejected: a missing Skia GL context is
|
|
# the hardest failure in this codebase to read, and importing that class of flake
|
|
# into CI would cost more than the few window tests are worth here.
|
|
|
|
# All three modules. The translation generator is a Gradle module and not buildSrc
|
|
# precisely so that its 42 tests run here: buildSrc tests do not run on `./gradlew
|
|
# build` -- measured, not assumed. The summary below globs */build/test-results, so
|
|
# the module was counted the moment it existed.
|
|
- name: Test
|
|
run: ./gradlew -S test
|
|
|
|
- name: Summarise the test results
|
|
if: always()
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
files=(*/build/test-results/test/TEST-*.xml)
|
|
if [ ${#files[@]} -eq 0 ]; then
|
|
echo "No test result XML was produced -- the test task did not run." >&2
|
|
exit 1
|
|
fi
|
|
# Counted from the XML and not from Gradle's console output: this project's own
|
|
# rule is never to infer "all tests passed" from an exit code.
|
|
summary=$(grep -h "<testsuite " "${files[@]}" \
|
|
| sed 's/.*tests="\([0-9]*\)".*skipped="\([0-9]*\)".*failures="\([0-9]*\)".*errors="\([0-9]*\)".*/\1 \2 \3 \4/' \
|
|
| awk '{t+=$1; s+=$2; f+=$3; e+=$4} END {print t" "s" "f" "e}')
|
|
read -r total skipped failures errors <<< "$summary"
|
|
echo "tests=$total skipped=$skipped failures=$failures errors=$errors"
|
|
{
|
|
echo "### Tests"
|
|
echo ""
|
|
echo "| total | skipped | failures | errors |"
|
|
echo "|---|---|---|---|"
|
|
echo "| $total | $skipped | $failures | $errors |"
|
|
echo ""
|
|
echo "Skipped are the tests that need a display, plus the deliberately"
|
|
echo "disabled reference-data generator. This job runs headless on purpose."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
if [ "$failures" != "0" ] || [ "$errors" != "0" ]; then
|
|
echo "The result XML reports failures or errors." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Keep the test reports on a failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: test-results
|
|
path: |
|
|
*/build/test-results/test/
|
|
*/build/reports/tests/test/
|
|
if-no-files-found: ignore
|
|
retention-days: 7
|