Development and Releasing¶
For maintainers of the framework: how the repository is built and tested, and how a release reaches Maven Central. Exam authors do not need this page.
Building and testing¶
# framework unit tests + Maven example under Ares 2, against the framework source of this checkout
./mvnw -B verify
# Gradle example under Ares 2, against the framework source of this checkout
(cd example-gradle && ./gradlew test)
# the failing example solution (fails on purpose; shows the students' messages)
./mvnw -B verify -Dassignment.dir=assignment-failing
(cd example-gradle && ./gradlew test -PassignmentDir=assignment-failing)
# + sources, javadoc, GPG signature (needs a key)
./mvnw -B -P release -pl framework verify
# mutation testing of the framework with PIT (report: framework/target/pit-reports/index.html)
./mvnw -B -f framework/pom.xml -P mutation verify
Inside this repository both examples compile the framework source (../framework/src/main/java) together with
the tests, so the framework can be debugged directly. The examples are exam templates: a copy without
../framework uses the newest framework release from Maven Central, release candidates included
(levenshteinVersion in build.gradle, levenshtein.version in pom.xml, both overridable). CI installs the
SNAPSHOT and passes it to standalone copies of both examples.
The framework is built and published with Maven only (publishing with Gradle is more trouble than it is worth). The Gradle module is a consumer of it, like an exam repository.
Mutation testing (PIT)¶
The framework's own tests are checked with PIT mutation testing: PIT changes the framework
code in small ways (e.g. < to <=, a condition to true) and reruns the tests; a change no test notices
("surviving mutant") points to a missing test or a bug. Only framework classes are mutated, never the examples.
CI's mutation job fails below mutationThreshold in the mutation profile of framework/pom.xml and uploads
the HTML report as the pit-report artifact. Raise the threshold when new tests kill more mutants; never lower it
to make a change pass.
Releases¶
A version on Maven Central can never be changed or removed, so every release goes through a release candidate first.
The Publish workflow builds and deploys the framework when a GitHub release is published; the version comes from
the tag (2026.11.1 or 2026.11.1-RC1, as with the existing tags; a leading v would be stripped). framework/pom.xml is the only place that
holds the framework version.
The version number¶
The only version in the code is <version> in framework/pom.xml. It always holds a -SNAPSHOT of the next
release (e.g. 2026.11.1-SNAPSHOT for the release 2026.11.1).
- Before a release: change nothing. Do not remove
-SNAPSHOTand do not commit the release version.Publishtakes the version from the tag and sets it in the build only; CI'srelease-dry-runjob tests the SNAPSHOT without the suffix. Choose the tag so that it equals the SNAPSHOT without-SNAPSHOT(or deliberately choose a different version, then the next step sets it). - After the final release: set
<version>to the next-SNAPSHOT(e.g.2026.11.1released, then2026.12.0-SNAPSHOT) and commit it tomain. This is the last step of the checklist. Do not bump after an RC: the RC belongs to the same SNAPSHOT. - Never change: the version ranges in the examples (
levenshtein.version=[2000.0.0,)inexample-maven/pom.xml,levenshteinVersion=latest.releaseinexample-gradle/build.gradle), and the0-SNAPSHOTof the rootpom.xmlandexample-maven/pom.xml. They always take the newest release from Maven Central. - Only on a new major line (a breaking change like 2000.0.0): raise the lower bound
2000.0.0of the example ranges inexample-maven/pom.xmlanddocs/ares-setup.md, and write the breaking changes into Migration.
Checklist¶
-
mainis green: CI passes, including therelease-dry-runjob (it builds sources, javadoc and the version change likepublish.yml, without GPG and without the upload). - Docs match the code: Versions and Migrating lists the new version and its changes; the guides, the README and the examples show current usage (see "Keeping the docs up to date" below).
- Check that the secrets
GPG_PRIVATE_KEY,GPG_PASSPHRASE,OSSRH_USERandOSSRH_TOKENare set and still valid. - Create a pre-release on GitHub with the tag
<version>-RC1onmain. This startsPublish. - Wait for
Publishto succeed and for the artifact to appear on Maven Central (this can take some minutes). - Run the
Smoke testworkflow with the version<version>-RC1: it runs both example templates (Gradle and Maven) against Maven Central. - If a problem shows up: fix it on
mainand publish-RC2(go to step 4). Never re-use a tag. - Create the release on GitHub with the tag
<version>on the commit that passed the smoke test. - Wait for
Publishand runSmoke testonce more without an input (it takes the newest version on Maven Central). - Set
<version>inframework/pom.xmlto the next-SNAPSHOTand commit it tomain. This is the only commit that changes the version.
Documentation site¶
The docs site (docs/ and the Javadoc of framework/src/main) is rebuilt and deployed to GitHub Pages by the
Docs workflow on every push to main that touches them; nothing to do for a release. It shows the state
of main (or of the branch of the last manual run: Actions > Docs > Run workflow deploys any branch, the next
push to main restores it), so merge doc changes for a new version together with the code. Preview it locally with
pip install zensical && zensical serve.
Keeping the docs up to date¶
Every change that users can notice (public API, messages, settings, behaviour, build templates) updates the docs in the same pull request:
- the guide that explains the feature (
docs/*.md), written as the current behaviour, without "since version X" or "before version Y"; - Versions and Migrating: what changed and how to update existing tests;
- the class diagrams in Architecture if public classes or methods change;
- new pages in
navofzensical.toml.
zensical build --clean --strict must pass (the Docs workflow runs it for every pull request). docs/plans/
holds internal implementation plans and is not published.