From c59b38775b9da30b4697471485be98ce11bb917e Mon Sep 17 00:00:00 2001 From: Lemon-miaow Date: Thu, 24 Sep 2026 00:19:56 +0800 Subject: [PATCH] ci(plugins): run the plugin self-tests and build the shipped plugin jars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The three framework-free test mains under plugins/*/test were never run by anything — not CI, not the plugin builds — and the velocity/paper/limbo jars were only ever compiled by deploy/bootstrap.sh on a live host. CI gains a 'plugins' job (JDK 21 plus the Gradle 8.14 the plugin Dockerfiles pin) running plugins/test.sh: the three mains (InviteCardTest's jars fetched from Maven Central, pinned and digest-checked) and the three production builds. The first real run surfaced and fixed two untested assumptions: InviteCardTest's documented javac line omitted examination-api (adventure-api's Component signatures reference Examinable, so javac needs it too), and limbo's '+' version default cannot resolve — LOOHP's repository serves no maven-metadata — so the script resolves the current release off the Limbo CI artifact name (the same source bootstrap reads) and plugins/README.md stops advertising a bare 'gradle -p plugins/limbo build' that can never work. Verified in gradle:8.14-jdk21 on the VM: mains OK (32/36/48 checks); velocity/paper/limbo BUILD SUCCESSFUL. --- .github/workflows/ci.yml | 20 ++++ plugins/README.md | 7 +- plugins/test.sh | 100 ++++++++++++++++++ .../felis/velocity/InviteCardTest.java | 10 +- 4 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 plugins/test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd8da21..b6d17aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,3 +98,23 @@ jobs: - run: npm run typecheck working-directory: panel + + plugins: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # The other jobs never touch the Java layer: the plugin jars were only ever + # compiled by bootstrap on a live host, and the three test mains under + # plugins/*/test were run by hand. JDK 21 plus the Gradle major the plugin + # Dockerfiles pin (8.14) is that same toolchain, in CI. + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + + - uses: gradle/actions/setup-gradle@v4 + with: + gradle-version: '8.14' + + - run: bash plugins/test.sh diff --git a/plugins/README.md b/plugins/README.md index 291dc82..68400b4 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -198,9 +198,12 @@ preference): # Velocity — system Gradle is fine gradle -p plugins/velocity build -# Paper and limbo — system Gradle too, but both compile on a Java-21 toolchain (see table) +# Paper and limbo — system Gradle too, but both compile on a Java-21 toolchain (see table). +# limbo also needs the LOOHP/Limbo API release it compiles against: the module's `+` +# default cannot resolve (LOOHP's repository publishes no maven-metadata), so pass the +# release that matches the Limbo.jar you bundle, exactly as deploy/bootstrap.sh does: gradle -p plugins/paper build -gradle -p plugins/limbo build +gradle -p plugins/limbo build -PlimboVersion= # Fabric / Forge / NeoForge — use the per-module wrapper. Nothing installs these; the jar you # want is the one this produces. diff --git a/plugins/test.sh b/plugins/test.sh new file mode 100644 index 0000000..ff3c98d --- /dev/null +++ b/plugins/test.sh @@ -0,0 +1,100 @@ +#!/bin/bash +# Self-tests for the Java plugin layer. +# +# bash plugins/test.sh +# +# Two gates, both runnable on any machine with a JDK 21 and Gradle: +# +# 1. The three hand-written, framework-free test mains under shared/test and +# velocity/test. They check what "compiles" cannot: the felis:control codec +# round-trips every frame kind (spec §12), /invite prompts cannot double-fire +# or outlive their TTL, and the invite card really is a green/red clickable +# prompt. InviteCardTest needs the adventure jars the velocity plugin compiles +# against; they are fetched from Maven Central below, pinned by version and +# checked by digest (a test run against silently-substituted bytes is not a +# test of what we ship). +# +# 2. Production compile gates: the velocity/paper/limbo plugin jars — the three +# bootstrap bakes into the proxy and the game images — are built with the same +# Gradle major the plugin Dockerfiles pin, so a compile break is a red check +# here instead of an install-time surprise. limbo compiles against the API +# release bootstrap would bundle (resolved below, same source the installer +# reads), because the module's `+` default cannot resolve on its own. +# +# No test framework and no wrapper: the mains are the same javac one-liners their +# javadocs document, so a local run and CI run the same bytes. +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT + +# --- 1. hermetic test mains ---------------------------------------------------- + +# adventure-api 4.26.1 is what velocity-api 3.5.1 resolves through its adventure-bom. +# Pinned with digests because these exact bytes go on the compile/run classpath. +fetch() { # url sha256 -> path + local url="$1" want="$2" file + file="$work/$(basename "$url")" + curl -fsSL --retry 5 --retry-delay 2 -o "$file" "$url" + printf '%s %s\n' "$want" "$file" | sha256sum -c - >&2 + printf '%s\n' "$file" +} +central=https://repo1.maven.org/maven2/net/kyori +adventure_api="$(fetch "$central/adventure-api/4.26.1/adventure-api-4.26.1.jar" \ + 551e536b9ea868f30e72c7900a309b35124ee7d4889fa3b3aed0910299751a26)" +adventure_key="$(fetch "$central/adventure-key/4.26.1/adventure-key-4.26.1.jar" \ + eec172d63db77b40eb7abeeb25f65eedea89bd30264d057b68b12fecb731be5e)" +examination_api="$(fetch "$central/examination-api/1.3.0/examination-api-1.3.0.jar" \ + c9237ffecb05428f6eff86216246ac70ce0b47b04c08ea7ca35020fde57f8492)" + +echo "==> ControlRoundTripTest (felis:control codec, shared)" +mkdir -p "$work/shared-classes" +javac -d "$work/shared-classes" \ + plugins/shared/src/main/java/best/lolicon/felis/link/*.java \ + plugins/shared/test/best/lolicon/felis/link/ControlRoundTripTest.java +java -cp "$work/shared-classes" best.lolicon.felis.link.ControlRoundTripTest + +echo "==> InviteBookTest (/invite prompt store, velocity)" +mkdir -p "$work/velocity-classes" +javac -d "$work/velocity-classes" \ + plugins/velocity/src/main/java/best/lolicon/felis/velocity/InviteBook.java \ + plugins/velocity/test/best/lolicon/felis/velocity/InviteBookTest.java +java -cp "$work/velocity-classes" best.lolicon.felis.velocity.InviteBookTest + +echo "==> InviteCardTest (/invite card, velocity)" +mkdir -p "$work/card-classes" +# examination-api is on the compile classpath too: adventure-api 4.26.1's Component +# signatures reference Examinable, so javac needs the class even though the test +# never names it. adventure-key rides along for ClickEvent/HoverEvent payloads. +javac -cp "$adventure_api:$adventure_key:$examination_api" -d "$work/card-classes" \ + plugins/velocity/src/main/java/best/lolicon/felis/velocity/InviteCard.java \ + plugins/velocity/test/best/lolicon/felis/velocity/InviteCardTest.java +java -cp "$work/card-classes:$adventure_api:$adventure_key:$examination_api" \ + best.lolicon.felis.velocity.InviteCardTest + +# --- 2. production compile gates ------------------------------------------------ + +for module in velocity paper; do + echo "==> gradle --no-daemon -p plugins/$module build" + gradle --no-daemon -p "plugins/$module" build +done + +# limbo is special: it compiles against the LOOHP/Limbo API release that the +# installer bundles, and that release is published nowhere except the CI artifact +# name (Limbo--.jar) — the same place deploy/bootstrap.sh reads it. +# The module's `+` version default cannot resolve (LOOHP's repository serves no +# maven-metadata.xml), so a bare `gradle -p plugins/limbo build` is never a valid +# command; the version must come from here or from bootstrap. +echo "==> resolving the newest LOOHP/Limbo CI build (for -PlimboVersion)" +limbo_meta="$(curl -fsSL --retry 5 --retry-delay 2 \ + https://ci.loohpjames.com/job/Limbo/lastSuccessfulBuild/api/json)" \ + || { echo "cannot read the LOOHP/Limbo CI build metadata; the limbo gate cannot pick a version" >&2; exit 1; } +limbo_file="$(printf '%s' "$limbo_meta" | grep -o 'Limbo-[0-9A-Za-z._-]*\.jar' || true)" +limbo_file="${limbo_file%%$'\n'*}" +[ -n "$limbo_file" ] || { echo "no Limbo jar in the LOOHP/Limbo CI artifact list" >&2; exit 1; } +limbo_version="${limbo_file%.jar}"; limbo_version="${limbo_version%-*}"; limbo_version="${limbo_version#Limbo-}" +[ -n "$limbo_version" ] || { echo "cannot parse the Limbo version out of ${limbo_file}" >&2; exit 1; } +echo "==> gradle --no-daemon -p plugins/limbo build (Limbo ${limbo_version})" +gradle --no-daemon -p plugins/limbo -PlimboVersion="$limbo_version" build diff --git a/plugins/velocity/test/best/lolicon/felis/velocity/InviteCardTest.java b/plugins/velocity/test/best/lolicon/felis/velocity/InviteCardTest.java index b6553d4..727c254 100644 --- a/plugins/velocity/test/best/lolicon/felis/velocity/InviteCardTest.java +++ b/plugins/velocity/test/best/lolicon/felis/velocity/InviteCardTest.java @@ -15,13 +15,15 @@ import java.util.List; * — a proxy console cannot render either, and a screenshot is not a check. * *

Hermetic and framework-free like {@link InviteBookTest}: it lives outside - * {@code src/main/java} so it never ships in the plugin jar, needs only adventure-api on - * the classpath, and a failed assertion throws so the process exits non-zero. + * {@code src/main/java} so it never ships in the plugin jar, needs only the Kyori jars + * on the classpath, and a failed assertion throws so the process exits non-zero. * - *

Run: {@code javac -cp -d + *

Run (all three jars on both classpaths — adventure-api's Component signatures + * reference Examinable, so javac needs examination-api too, not just the runtime): + * {@code javac -cp :: -d * velocity/src/main/java/best/lolicon/felis/velocity/InviteCard.java * velocity/test/best/lolicon/felis/velocity/InviteCardTest.java && java -cp - * ;;; + * ::: * best.lolicon.felis.velocity.InviteCardTest}. */ public final class InviteCardTest {