Skip to content

One build product per library, and a library-aware download page (#112) - #115

Merged
ctgnz merged 3 commits into
masterfrom
feat/112-library-build-products
Sep 26, 2026
Merged

ctgnz merged 3 commits into
masterfrom
feat/112-library-build-products

Conversation

@ctgnz

@ctgnz ctgnz commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Closes #112.

Neither application compiles against a symbology library since #76 and #93, so which one it ships with was the only thing still hard-coded. Now it's a profile in jmsfx-viewer, and both applications inherit whichever is active:

mvn -Pstandard verify
mvn -Phallux   verify

No default, and naming none fails

No activeByDefault, for the reason the issue gives: it switches off the moment any other profile is named, and #103 put mvn -Prelease deploy in the release workflow — a defaulted standard would have silently deactivated during a release and published an application with no library in it, which starts and then 500s on every request.

An enforcer rule makes that immediate instead:

[ERROR] No symbology library was named, so this build has nothing to render with.
[ERROR]     mvn -Pstandard verify        the APP-6E library
[ERROR]     mvn -Phallux   verify        the hallux extension

mvn verify alone no longer works. That's the deliberate cost. CI, the release workflow, deploy.sh and the docs all name a library now.

Distinguishable products

jmsfx-server's fat jar carries the library as a classifier — jmsfx-server-2.0.0-standard.jar — so you can tell what's in a jar without remembering how it was built. deploy.sh takes the library as its first argument and names that classifier exactly, so a stale build from another library can't be shipped by accident.

optional is gone from the creator's library dependency. It existed to stop runtime scope reaching consumers, but #109 removed the last consumer — and the same declaration next door produced a server jar that started and 500'd, because spring-boot:repackage drops optional dependencies from BOOT-INF/lib. Having it in one and not the other was a trap.

The download page

Windows/macOS/Linux buttons pointing at the bundles for the library and version that instance is running, so a visitor to a hallux subdomain gets the hallux creator. The packaging matrix crosses library with platform to produce them — six jobs now, nine when #81 brings jmsfx-battleorder in.

Two bugs found that would otherwise have shipped

The manifest carries no Implementation-Version. #112 assumed Spring Boot writes it; it doesn't here. maven-jar-plugin writes those entries only when addDefaultImplementationEntries is set, which spring-boot-starter-parent does and jmsfx-parent doesn't — the fat jar has no Implementation-* at all. So reading it returned null on every real deployment, while the unit tests, which pass a version in, looked perfectly healthy. Now uses the build-info goal and Spring's BuildProperties.

A snapshot is not a release. You deploy to Lightsail straight from the working tree, so the live server reports 2.0.0-SNAPSHOT — there's no such GitHub release, and every button would have been a 404 on the live site. A snapshot now falls back to the releases page, as does a missing version.

One thing you should know about, separate from this issue

mvn versions:set has been quietly broken since #102. This workflow's header said to edit poms by hand because the plugin "has picked up drifted per-module versions before" — I hit it here and found the cause: since #102 split the parent from the aggregator, no module declares the aggregator as its parent, so the default parent-chain walk bumps the aggregator alone and leaves the other nine poms behind. It needs -DprocessAllModules=true, verified both ways on this branch, and that's now written into the workflow header and CLAUDE.md with a grep to check before tagging. Worth knowing before the 2.0.0 release.

Verification

-Pstandard verify, -Phallux verify and -Pstandard,release verify all green; 6 new tests in CreatorDownloadsTest, which spells the bundle filenames out in full rather than rebuilding them from the same parts the production code uses.

Both server jars run and were checked at runtime:

/info/library /download offers
-standard.jar {"name":"Standard","symbolSets":23} jmsfx-creator-2.0.0-standard-{windows,macos,linux}
-hallux.jar {"name":"Hallux","symbolSets":23} jmsfx-creator-2.0.0-hallux-{windows,macos,linux}

Each creator bundle's target/lib was checked to contain exactly one library, which is what confirms dropping optional didn't break copy-dependencies.

Not done

No battleorder profile — its model is an overlay and there's no generated library to depend on until #81. Adding it is a copy of the hallux profile, a jmsfx.battleorder.version property, and one word in the workflow matrix.

Both libraries' bundles still unpack to a directory called JMSFX Icon Creator, so extracting two of them side by side collides. The archive filenames distinguish them and the issue didn't ask for more; say the word if you want the app name to carry the library too.

🤖 Generated with Claude Code

ctgnz and others added 3 commits September 26, 2026 14:35
…112)

Neither application compiles against a symbology library any more (#76,
#93), so which one it ships with was the only thing still hard-coded.

Profiles live in jmsfx-viewer, since that is the level a deliverable is
produced at, and both applications inherit whichever is active:

    mvn -Pstandard verify
    mvn -Phallux   verify

No activeByDefault, and naming none now fails. A default-activated
profile switches off the moment any other profile is named, and #103 put
`mvn -Prelease deploy` in the release workflow - so a defaulted standard
would have silently deactivated during a release and published an
application with no library in it, which starts and then answers 500 to
everything. An enforcer rule turns that into an immediate failure that
says what to pass instead. It does mean `mvn verify` alone no longer
works, which is the deliberate cost.

jmsfx-server's fat jar carries the library as a classifier -
jmsfx-server-2.0.0-standard.jar - so a jar can be identified without
remembering how it was built. deploy.sh now takes the library as its
first argument and names that classifier exactly, rather than picking the
newest jar, so a stale build from another library cannot be shipped by
accident.

`optional` is gone from the creator's library dependency. It was there to
stop runtime scope reaching consumers, but #109 removed the last consumer,
and the same declaration next door produced a server jar that started and
500'd - spring-boot:repackage leaves optional dependencies out of
BOOT-INF/lib. Having it in one and not the other was a trap.

The download page now offers Windows/macOS/Linux buttons for the library
and version that instance is running, so a visitor to a hallux subdomain
gets the hallux creator without having to recognise it in a list of nine
files. The release workflow's packaging matrix crosses library with
platform to produce them - six jobs now, nine when #81 brings
jmsfx-battleorder in.

Two things found while doing it, both of which would have shipped:

**The manifest carries no Implementation-Version.** #112 assumed Spring
Boot writes it, and it does not here: maven-jar-plugin writes those
entries only when addDefaultImplementationEntries is set, which
spring-boot-starter-parent does and jmsfx-parent does not. Reading it
returned null on every real deployment while the unit tests, which pass a
version in, looked perfectly healthy. Now uses spring-boot's build-info
goal and Spring's BuildProperties.

**A snapshot is not a release.** The live site is deployed straight from
the working tree, so it reports 2.0.0-SNAPSHOT - for which no GitHub
release exists, making every button a 404. A snapshot now falls back to
the releases page, as does a missing version.

Also here, because this work needed them:
- the junit BOM and hamcrest's version were repeated verbatim in three
  poms; both now sit in jmsfx-parent and modules just name the artefacts
- release.yml's header documented editing poms by hand because
  versions:set "has picked up drifted per-module versions before". The
  cause is #102: no module declares the aggregator as its parent, so the
  default parent-chain walk bumps the aggregator alone. It needs
  -DprocessAllModules=true, which is now written down where it is needed.

mvn -Pstandard verify, -Phallux verify and -Pstandard,release verify all
green. Both server jars checked at runtime: each reports its own library
from /info/library and offers its own bundles on /download.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Noticed while explaining the two-pom layout: the root aggregator declared
jmsfx-parent as its parent, and had no use for it. It has no sources, so
nothing it inherited acted on anything - and the <parent> block was a
second place jmsfx-parent's version had to be written, which is half of
what splitting the parent from the aggregator was meant to stop.

jmsfx-parent is still listed as a module, because this reactor builds it.
That is a different relationship from inheritance, and conflating the two
is what made the layout confusing to read.

Five modules now declare jmsfx-parent as their parent, and nothing else
references its version.

mvn -Pstandard clean verify and -Pstandard,release verify both green -
the release profile still activates from the modules that define it, and
every javadoc and sources jar still builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An extension library is a library: a consumer renders with it exactly as
they would with jmsfx-standard, so Central is where it belongs.

It was held out of the publish set until someone decided, rather than
going out because nobody had looked. #106 brought it into this reactor
after 1.5.0 shipped, so the release profile had never run with it
present, and the next -Prelease deploy would have published it by
default - which is not how an irrevocable publication should happen.

Now settled, so the exclusion goes.

The published set is jmsfx-parent, jmsfx-core, jmsfx-standard and
jmsfx-hallux. Checked that hallux carries everything Central validates -
name, description, url, licenses, developers, scm, all inherited - and
that the release profile produces its javadoc and sources jars, which it
does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ctgnz
ctgnz merged commit b4e0fca into master Sep 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

One build product per library for jmsfx-creator and jmsfx-server

1 participant