diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74ca8ce2..a7395539 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: # testing module + the engine test-jar on the classpath and so cannot # live in the engine's own test scope). -am pulls the fonts / emoji # upstreams; render-docx / bundle / examples / benchmarks are excluded. - run: ./mvnw -B -ntp -f aggregator/pom.xml clean verify -pl :graph-compose,:graph-compose-testing,:graph-compose-qa -am + run: ./mvnw -B -ntp -f aggregator/pom.xml clean verify -pl :graph-compose-core,:graph-compose-testing,:graph-compose-qa -am - name: Generate Javadoc # Run only on the baseline JDK — Javadoc output is identical @@ -116,9 +116,15 @@ jobs: # Central, so install it into the local repo before building examples. run: ./mvnw -B -ntp -f emoji/pom.xml -DskipTests install - - name: Install root artifact + - name: Install root artifact (graph-compose-core) run: ./mvnw -B -ntp -DskipTests install -pl . + - name: Install graph-compose (the compat wrapper, consumed by the examples module) + # examples depends on the graph-compose coordinate — the empty jar wrapper + # over graph-compose-core. Install it after the core so the examples build + # resolves it (and the engine classes transitively). + run: ./mvnw -B -ntp -f wrapper/pom.xml -DskipTests install + - name: Install graph-compose-render-docx (consumed by the examples module) # The DOCX export example depends on the render-docx backend module, which # is not on Central. Install it after the engine (its graph-compose diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 69f6974f..293e23b5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -99,6 +99,16 @@ jobs: CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Publish graph-compose (compat wrapper) to Maven Central + # The empty jar that keeps the `graph-compose` coordinate a drop-in: it + # depends on graph-compose-core, resolved from the local repo installed by + # the engine (core) deploy above. Ships on the same v* tag, lockstep. + run: ./mvnw -B -ntp -f wrapper/pom.xml -P release -DskipTests -Dgpg.skip=false deploy + env: + CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} + CENTRAL_TOKEN: ${{ secrets.CENTRAL_TOKEN }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + - name: Publish render-docx to Maven Central # The semantic DOCX/PPTX backend, lockstep-versioned with the engine # (ships on the same v* tag). graph-compose resolves from the local repo diff --git a/CHANGELOG.md b/CHANGELOG.md index f3a72e20..f398db6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,16 +30,17 @@ for this cycle. ### Packaging -- 2.0 splits the single `graph-compose` jar into modules: a lean core - (`graph-compose`), pluggable render backends (`graph-compose-render-pdf`, - `graph-compose-render-docx`), `graph-compose-templates`, and - `graph-compose-testing`, with render backends discovered via a `ServiceLoader` - SPI. The `graph-compose` artifact keeps its coordinate but no longer contains - the PDF backend or the templates — add `graph-compose-render-pdf` for PDF - output, or depend on `graph-compose-bundle` for a batteries-included coordinate - (core + render-pdf + templates + fonts + emoji). The optional - `graph-compose-fonts` and `graph-compose-emoji` artifacts are unchanged. Full - install guidance ships with 2.0.0. +- 2.0 splits the monolithic engine into modules. The engine now builds under a new + **`graph-compose-core`** coordinate, and the original **`graph-compose` coordinate + becomes a thin drop-in aggregator** that depends on `graph-compose-core` — so an + existing `graph-compose` dependency keeps compiling and rendering PDF unchanged. + Consumer-testing support (`graph-compose-testing`) and the semantic DOCX/PPTX + backend (`graph-compose-render-docx`) are already separate artifacts; the PDF + render backend and the built-in templates move into their own modules over the + rest of the 2.0 cycle, at which point `graph-compose` aggregates the PDF backend + and `graph-compose-core` becomes the lean, bring-your-own-backend coordinate. The + optional `graph-compose-fonts` / `graph-compose-emoji` artifacts are unchanged. + Full install guidance ships with 2.0.0. - `graph-compose-render-docx` is now a separate artifact: the semantic DOCX/PPTX backend and Apache POI leave the `graph-compose` jar. `DocxSemanticBackend` moves to `com.demcha.compose.document.backend.semantic.docx` and `PptxSemanticBackend` diff --git a/aggregator/pom.xml b/aggregator/pom.xml index e1b7814b..860cab11 100644 --- a/aggregator/pom.xml +++ b/aggregator/pom.xml @@ -58,6 +58,7 @@ --> .. + ../wrapper ../fonts ../emoji ../render-docx diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 760c1c13..473ea724 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -50,7 +50,7 @@ io.github.demchaav - graph-compose + graph-compose-core ${graphcompose.version} @@ -74,7 +74,7 @@ --> io.github.demchaav - graph-compose + graph-compose-core ${graphcompose.version} test-jar tests diff --git a/jitpack.yml b/jitpack.yml index 503c23c3..c0859639 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,14 +1,15 @@ -# JitPack builds the published library artifact -# (com.github.DemchaAV:GraphCompose) from the standalone root pom.xml. +# JitPack builds the published library coordinates +# (com.github.DemchaAV:GraphCompose) from the standalone poms. # # JDK is pinned to 17 — the project's compile baseline # (maven.compiler.release=17) and the JDK the release verify/javadoc gate # runs on — so the jar consumers download is built on the same JDK CI # validates, not a drifting newer one. # -# install is scoped to the root module (-pl .) so JitPack builds only the -# library, never the examples/benchmarks reactor siblings. +# install is scoped to the two published coordinates — graph-compose-core (the +# engine, at the root pom) and graph-compose (the drop-in wrapper in wrapper/) — so +# JitPack serves both, never the examples/benchmarks reactor siblings. jdk: - openjdk17 install: - - ./mvnw -DskipTests install -pl . + - ./mvnw -DskipTests -f aggregator/pom.xml install -pl :graph-compose-core,:graph-compose diff --git a/pom.xml b/pom.xml index 7156bc88..e362ae08 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,11 @@ 4.0.0 io.github.demchaav - graph-compose + graph-compose-core 2.0.0-SNAPSHOT - GraphCompose - A declarative layout engine for programmatic document generation, implemented primarily in Java. + GraphCompose Core + A declarative layout engine for programmatic document generation, implemented primarily in Java. This is the lean engine coordinate; depend on the `graph-compose` artifact for the drop-in, PDF-capable install. https://github.com/DemchaAV/GraphCompose @@ -400,7 +400,7 @@ Build a tests-classifier jar so the sibling `benchmarks/` module can reuse the test-only fixtures (com.demcha.mock.*, etc.) without duplicating them. The artifact is - graph-compose-${version}-tests.jar in the local repository + graph-compose-core-${version}-tests.jar in the local repository after `mvn install`. It is a LOCAL build aid only: the `release` profile disables this execution (phase=none) so the tests jar is never attached and therefore never deployed to @@ -463,7 +463,7 @@ io.github.demchaav - graph-compose + graph-compose-core ${project.version} test-jar tests diff --git a/render-docx/pom.xml b/render-docx/pom.xml index 8b535b4a..ddb3fedd 100644 --- a/render-docx/pom.xml +++ b/render-docx/pom.xml @@ -78,7 +78,7 @@ io.github.demchaav - graph-compose + graph-compose-core ${project.version} diff --git a/scripts/cut-release.ps1 b/scripts/cut-release.ps1 index 8ab94050..aa1f97f7 100644 --- a/scripts/cut-release.ps1 +++ b/scripts/cut-release.ps1 @@ -304,7 +304,7 @@ function Run-ShowcaseSync { $execProp = '"-Dexec.mainClass=com.demcha.examples.support.ShowcaseSync"' # The examples module depends on these bumped SNAPSHOT siblings (not on # Central); each must be installed before exec:java can resolve them. - $exampleSnapshotSiblings = @('render-docx/pom.xml', 'testing/pom.xml') + $exampleSnapshotSiblings = @('wrapper/pom.xml', 'render-docx/pom.xml', 'testing/pom.xml') if ($DryRun) { Write-Host " [DRY RUN] $mvnw -B -ntp -DskipTests install -pl ." -ForegroundColor Yellow foreach ($modulePom in $exampleSnapshotSiblings) { @@ -504,6 +504,9 @@ try { # automatically). graph-compose-qa is an aggregator child (its version is # inherited) and is never published, so it needs no explicit bump. Update-PomVersion (Join-Path $repoRoot 'testing/pom.xml') $Version + # graph-compose (the graph-compose compat wrapper (wrapper/)) tracks the engine line lockstep; + # its graph-compose-core dep is ${project.version} (follows automatically). + Update-PomVersion (Join-Path $repoRoot 'wrapper/pom.xml') $Version # Bundle tracks the engine line: its project bumps here; its # graph-compose dep is ${project.version} (follows automatically) and its # graph-compose-fonts dep is ${graphcompose.fonts.version} (stays pinned — @@ -574,6 +577,7 @@ try { 'bundle/pom.xml', 'render-docx/pom.xml', 'testing/pom.xml', + 'wrapper/pom.xml', 'examples/pom.xml', 'benchmarks/pom.xml', 'README.md', diff --git a/src/test/java/com/demcha/documentation/VersionConsistencyGuardTest.java b/src/test/java/com/demcha/documentation/VersionConsistencyGuardTest.java index 955d6494..8cbf68e6 100644 --- a/src/test/java/com/demcha/documentation/VersionConsistencyGuardTest.java +++ b/src/test/java/com/demcha/documentation/VersionConsistencyGuardTest.java @@ -67,6 +67,9 @@ void everyModuleResolvesToTheRootProjectVersion() throws Exception { assertThat(effectiveVersion(PROJECT_ROOT.resolve("testing/pom.xml"))) .describedAs("testing (graph-compose-testing) tracks the engine line and must equal the root version (%s)", root) .isEqualTo(root); + assertThat(effectiveVersion(PROJECT_ROOT.resolve("wrapper/pom.xml"))) + .describedAs("wrapper (the graph-compose compat wrapper) tracks the engine line and must equal the root version (%s)", root) + .isEqualTo(root); // NOTE: fonts/pom.xml (graph-compose-fonts) is intentionally NOT checked // here. It carries an independent version line (it ships on its own @@ -103,6 +106,25 @@ void childModulesInheritVersionInsteadOfDeclaringTheirOwn() throws Exception { .isFalse(); } + @Test + void graphComposeWrapperStaysAJarOverCore() throws Exception { + Element project = parse(PROJECT_ROOT.resolve("wrapper/pom.xml")).getDocumentElement(); + + // Packaging MUST stay jar (the default when is absent). A pom + // would force every existing graph-compose consumer to add pom + // and break their build — the entire point of the wrapper is a drop-in jar. + Element packaging = directChild(project, "packaging"); + assertThat(packaging == null ? "jar" : packaging.getTextContent().trim()) + .describedAs("wrapper/pom.xml (the graph-compose coordinate) must stay a jar, never pom — a pom would force consumers to add pom") + .isEqualTo("jar"); + + // And it must aggregate the engine: the dependency on graph-compose-core is + // what makes a bare `graph-compose` bring the engine transitively. + assertThat(declaresDependencyOn(project, "graph-compose-core")) + .describedAs("wrapper/pom.xml must depend on graph-compose-core so `graph-compose` still brings the engine") + .isTrue(); + } + @Test void benchmarksDependencyDerivesVersionAndIsNotHardcoded() throws IOException { String pom = Files.readString(PROJECT_ROOT.resolve("benchmarks/pom.xml")); @@ -283,6 +305,24 @@ private static String effectiveVersion(Path pom) throws Exception { throw new IllegalStateException("No / or inherited / in " + pom); } + private static boolean declaresDependencyOn(Element project, String artifactId) { + Element deps = directChild(project, "dependencies"); + if (deps == null) { + return false; + } + NodeList children = deps.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node node = children.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("dependency")) { + Element aid = directChild((Element) node, "artifactId"); + if (aid != null && artifactId.equals(aid.getTextContent().trim())) { + return true; + } + } + } + return false; + } + private static Element directChild(Element parent, String name) { NodeList children = parent.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { diff --git a/testing/pom.xml b/testing/pom.xml index 7f9925be..7701ce1e 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -78,7 +78,7 @@ io.github.demchaav - graph-compose + graph-compose-core ${project.version} diff --git a/wrapper/pom.xml b/wrapper/pom.xml new file mode 100644 index 00000000..4002d888 --- /dev/null +++ b/wrapper/pom.xml @@ -0,0 +1,179 @@ + + + 4.0.0 + + + io.github.demchaav + graph-compose + 2.0.0-SNAPSHOT + + GraphCompose + The graph-compose coordinate: a drop-in aggregator over graph-compose-core for a PDF-capable install. + https://github.com/DemchaAV/GraphCompose + + + + MIT License + https://opensource.org/licenses/MIT + repo + + + + + + DemchaAV + Artem Demchyshyn + demchishynartem@gmail.com + https://github.com/DemchaAV + + Lead Developer + Architect + + UTC 0 + + + + + scm:git:https://github.com/DemchaAV/GraphCompose.git + scm:git:ssh://git@github.com/DemchaAV/GraphCompose.git + https://github.com/DemchaAV/GraphCompose/tree/main + + + + UTF-8 + 17 + + 3.15.0 + 3.5.0 + 3.4.0 + 3.12.0 + 3.2.8 + 0.11.0 + + + true + + + + + + io.github.demchaav + graph-compose-core + ${project.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${maven.compiler.release} + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven.jar.plugin.version} + + + + + + + + release + + + + org.apache.maven.plugins + maven-source-plugin + ${maven.source.plugin.version} + + + attach-sources + package + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven.javadoc.plugin.version} + + + attach-javadocs + package + + jar + + + false + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + + + sign-artifacts + verify + + sign + + + ${gpg.skip} + + --pinentry-mode + loopback + + + + + + + org.sonatype.central + central-publishing-maven-plugin + ${central.publishing.plugin.version} + true + + central + false + validated + + + + + + +