This is an automated email from the ASF dual-hosted git repository. ppkarwasz pushed a commit to branch doc/build-lifecycle in repository https://gitbox.apache.org/repos/asf/logging-parent.git
commit fea04d02f231d3992d3d155e9730c6e08375d285 Author: Piotr P. Karwasz <[email protected]> AuthorDate: Fri Jul 3 20:51:02 2026 +0200 Document the build lifecycle and troubleshooting Add two Antora pages describing what the Logging Parent POM adds to the Maven build: - `build-lifecycle.adoc`: the checks, generated artifacts, and POM transformations bound to `./mvnw verify`; the opt-in profiles (build modifiers and commands); and what is inherited from the ASF Parent POM. - `troubleshooting.adoc`: recipes for the two checks that are hardest to diagnose, the BND baseline API-compatibility check and the `requireUpperBoundDeps` dependency-convergence check, using real captured error output. Wire both pages into the site navigation under a new "Build" group. Assisted-By: Claude Opus 4.8 (1M context) <[email protected]> --- src/site/antora/modules/ROOT/nav.adoc | 4 + .../antora/modules/ROOT/pages/build-lifecycle.adoc | 430 +++++++++++++++++++++ .../antora/modules/ROOT/pages/troubleshooting.adoc | 168 ++++++++ 3 files changed, 602 insertions(+) diff --git a/src/site/antora/modules/ROOT/nav.adoc b/src/site/antora/modules/ROOT/nav.adoc index 513c689..a32360a 100644 --- a/src/site/antora/modules/ROOT/nav.adoc +++ b/src/site/antora/modules/ROOT/nav.adoc @@ -20,6 +20,10 @@ * xref:workflows.adoc[] * xref:release-notes.adoc[] +.Build +* xref:build-lifecycle.adoc[] +* xref:troubleshooting.adoc[] + .Release support * xref:release-review-instructions.adoc[] * xref:release-instructions-project.adoc[] diff --git a/src/site/antora/modules/ROOT/pages/build-lifecycle.adoc b/src/site/antora/modules/ROOT/pages/build-lifecycle.adoc new file mode 100644 index 0000000..e8d532a --- /dev/null +++ b/src/site/antora/modules/ROOT/pages/build-lifecycle.adoc @@ -0,0 +1,430 @@ +//// + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +//// + +:asf-parent-url: https://maven.apache.org/pom/asf/ + +[#build-lifecycle] += Build lifecycle + +{project-name} extends the standard Maven _default_ (build) lifecycle that runs on a plain + +[source,bash] +---- +./mvnw verify +---- + +with three kinds of additions: + +* <<checks>> that fail the build when a rule is violated, +* <<artifacts>> that are generated and attached or embedded into your JARs, and +* <<transformations>> applied to the POM before it is published. + +Some of these additions come from {project-name} itself, some are inherited from the +{asf-parent-url}[ASF Parent POM], and some are activated only when a particular _activator file_ is present in your project. +Each origin is called out below. + +Beyond a plain `./mvnw verify`, the parent also offers two opt-in mechanisms: + +* <<optional-extensions>> that you enable on the command line to modify a build, and +* <<commands>> whose default goal performs a single task on its own. + +[#phase-map] +== Overview + +The following table maps each addition to the Maven phase it binds to. +Everything listed here is triggered by a plain `./mvnw verify`, unless it is marked as conditional on an activator file. + +[cols="2m,2,5a",options="header"] +|=== +| Phase | Origin | Additions + +| validate +| {asf-parent-url}[ASF Parent POM] +| +* <<check-build-environment>> + +| validate +| {project-name} +| +* <<check-dependency-convergence>> +* <<check-code-style>> _(no wildcard imports)_ +* <<check-changelog>> + +| generate-resources +| {asf-parent-url}[ASF Parent POM] +| +* <<artifacts-asf>> + +| process-resources +| {project-name} +| +* <<transformations-pom>> + +| compile +| {project-name} +| +* <<check-static-analysis>> _(ErrorProne)_ + +| process-classes +| {project-name} +| +* <<artifacts-osgi>> +* <<artifacts-jpms>> +* <<artifacts-services>> + +| package +| {project-name} +| +* <<artifacts-sbom,CycloneDX SBOM>> + +| verify +| {project-name} +| +* <<check-code-style>> (Spotless) +* <<check-license>> +* <<check-static-analysis>> _(SpotBugs + FindSecBugs)_ +* <<check-api-compatibility,API compatibility (BND baseline)>> +|=== + +[#checks] +== Additional checks + +The checks below run automatically during `./mvnw verify`. +The trickier ones link to a debugging recipe in xref:troubleshooting.adoc[]. + +[#check-build-environment] +=== Maven & Java version + +_Phase:_ `validate`. +_Enforced by the {asf-parent-url}[ASF Parent POM]._ + +To build an Apache Logging Services project you need: + +* a *JDK 17* (the build pins the major version `17`, not a later one), and +* *Maven 3.8.1 or later*, most conveniently through the bundled Maven Wrapper (`./mvnw`). + +Both requirements are checked by the `maven-enforcer-plugin` inherited from the ASF Parent POM, through its `requireJavaVersion` and `requireMavenVersion` rules. +These rules can be modified using the properties below: + +[cols="2m,3,1m",options="header"] +|=== +| Property | Controls | Default + +| minimalJavaBuildVersion +| Range of JDK versions allowed to run the build +| {java-compiler-version} + +| minimalMavenBuildVersion +| Range of Maven versions allowed to run the build +| 3.8.1 + +| maven.compiler.release +| Java bytecode level the sources are compiled to +| 8 +|=== + +Although most artifacts still target Java 8 bytecode (through the `javac --release 8` flag), JDK 17 is required to run the Maven plugins in use and to keep builds reproducible. +Bytecode generation can differ between JDK major versions, so pinning a single one keeps the output byte-for-byte stable. + +[NOTE] +==== +JDK 17 also requires the `--add-exports` and `--add-opens` flags declared in `.mvn/jvm.config`, needed by tools that reach into JDK compiler internals (such as Error Prone). +See xref:usage.adoc[]. +==== + +Some projects (currently only Log4j) additionally run their test suites against a real *JDK 8* through +https://maven.apache.org/guides/mini/guide-using-toolchains.html[Maven Toolchains] +in CI. +This proves runtime compatibility with the Java 8 platform, beyond the bytecode and API-surface guarantees that `--release 8` provides on its own. + +[#check-dependency-convergence] +=== Order-independent dependency resolution + +_Phase:_ `validate`. + +Maven's default conflict _mediation_ (nearest-wins, ties broken by declaration order) can resolve a dependency to a version _lower_ than some transitive dependency requires, and the outcome can shift when dependencies are reordered. +The `maven-enforcer-plugin` `requireUpperBoundDeps` rule forbids this: it fails whenever a resolved version is lower than the highest one required across the graph. + +The fix is to pin that dependency to at least the highest required version, making resolution order-independent. +See xref:troubleshooting.adoc#require-upper-bound-deps[the Order-independent dependency resolution recipe] for how to read the error and adjust the pin. + +[IMPORTANT] +==== +Pinning a transitive dependency in your `<dependencyManagement>` only affects _your_ build. +It has *no* influence on the versions resolved by downstream consumers of your artifacts. +==== + +[#check-code-style] +=== Code style + +Code style is enforced by the `spotless-maven-plugin` in the `verify` phase, with one exception: the ban on wildcard imports is a `maven-enforcer-plugin` rule that runs earlier, in the `validate` phase. +The following rules apply: + +All files:: ++ +Line endings are normalized to UNIX (`LF`) and the ASF license header is required. +Set a `.gitattributes` file so that Git checks files out with `LF` on every platform. + +Java:: ++ +Sources follow the +https://github.com/palantir/palantir-java-format[Palantir Java format], and imports must be explicit (wildcard imports are banned). + +XML, POM, `.properties` & YAML:: ++ +`pom.xml` is sorted with the Spotless https://github.com/Ekryd/sortpom[sortPom] step; XML and YAML files also have trailing whitespace trimmed and a final newline enforced. + +Most violations are fixed automatically by: + +[source,bash] +---- +./mvnw spotless:apply +---- + +Anything the formatter cannot fix must be corrected by hand. + +[NOTE] +==== +The Spotless configuration must stay in sync with the project's `.editorconfig`. +==== + +[#check-changelog] +=== Changelog validation + +_Phase:_ `validate`. +_Activated by `src/changelog/`._ + +Apache Logging Services projects track their release notes as individual XML files under `src/changelog/`, managed by the https://github.com/apache/logging-log4j-tools/tree/main/log4j-changelog-maven-plugin[`log4j-changelog-maven-plugin`]. +When that directory is present, the `xml-maven-plugin` validates every entry against the Log4j Changelog schema, so a malformed entry fails the build early instead of breaking release-note generation later. + +The schema is documented on the {logging-services-url}/xml/ns/#log4j-changelog[Log4j XML schema page]. + +[#check-static-analysis] +=== Static analysis + +Two static analysis tools scan the code on every build. + +Error Prone:: ++ +_Phase:_ `compile`. +Bundled into the `maven-compiler-plugin` (alongside `-Xlint:all`), it catches common Java mistakes as the code compiles. +Its checks are fixed by {project-name} and are not configurable per project. + +SpotBugs + FindSecBugs:: ++ +_Phase:_ `verify`. +The `spotbugs-maven-plugin` runs SpotBugs together with the https://find-sec-bugs.github.io/[FindSecBugs] plugin for security-oriented bug patterns. +False positives can be suppressed by adding a `spotbugs-exclude.xml` file to the project root; its presence alone activates the exclusion filter. + +[#check-license] +=== License validation + +_Phase:_ `verify`. + +The https://creadur.apache.org/rat[`apache-rat-plugin`] verifies that the project complies with the +https://www.apache.org/legal/src-headers.html[ASF Source Header and Copyright Notice Policy], failing the build when a file is missing the required ASF license header. + +Files that legitimately cannot carry a header or have been exempted from carrying one have been added to an exclude list. + +[#check-api-compatibility] +=== API compatibility + +_Phase:_ `verify`. + +Public APIs must not change without an *explicit* version bump. +The `bnd-baseline-maven-plugin` compares each module's exported packages against their last release and enforces https://docs.osgi.org/whitepaper/semantic-versioning/[OSGi semantic versioning]: a backward-compatible addition needs a _minor_ increment, a breaking change a _major_ one, and an internal-only fix a _micro_ one. +Package versions are declared with the `@Version` annotation in each package's `package-info.java`. + +When a change is not matched by the right increment, the build fails with a table reporting the detected _delta_ (`MICRO`, `MINOR`, or `MAJOR`) and the version the plugin suggests. +The rules for choosing the increment, and how to resolve such a failure, are explained in xref:troubleshooting.adoc#bnd-baseline[the API compatibility recipe]. + +[#artifacts] +== Additional generated artifacts + +Beyond the main JAR, the build attaches or embeds the following. + +[#artifacts-osgi] +=== OSGi manifest + +_Phase:_ `process-classes`. + +The `bnd-maven-plugin` generates an OSGi `META-INF/MANIFEST.MF` and hands it to the `maven-jar-plugin`, which packages it instead of its own default manifest. +BND derives the manifest from the compiled bytecode: + +* `Bundle-SymbolicName` is computed from the `groupId` and `artifactId`; +* `Export-Package` lists the packages annotated with `org.osgi.annotation.bundle.Export` in their `package-info.java`; +* `Import-Package` is inferred from the packages the code actually references. + +This automatic inference is correct in the vast majority of cases, but a few situations must be declared explicitly, for example an _optional_ dependency, whose import BND marks as mandatory unless told otherwise. +Such cases can be tuned through the following properties, without redefining the whole BND configuration: + +[cols="2m,4,2",options="header"] +|=== +| Property | Purpose | Default + +| bnd-extra-package-options +| Extra `Import-Package` instructions. +| _(empty)_ + +| bnd-bundle-symbolicname +| Override the computed `Bundle-SymbolicName` +| derived from `groupId` and `artifactId` + +| bnd-multi-release +| Value of the `Multi-Release` manifest header +| `false` + +| bnd-extra-config +| Arbitrary extra BND instructions, appended last. +| _(empty)_ +|=== + +For the full set of `bnd-*` properties and worked examples, see xref:usage.adoc[]. + +[#artifacts-jpms] +=== JPMS module descriptor + +_Phase:_ `process-classes`. + +The same `bnd-maven-plugin` execution that produces the <<artifacts-osgi,OSGi manifest>> also synthesizes a JPMS `module-info` descriptor from the same metadata. +This gives each module a proper, stable module name and its `requires`, `exports`, `provides`, and `uses` directives without a hand-written `module-info.java`, which could not target Java 8 anyway. + +The module name defaults to the `Bundle-SymbolicName`, and the `requires` directives are inferred from the imported packages. +When that inference needs adjusting, use the following properties: + +[cols="2m,4,1",options="header"] +|=== +| Property | Purpose | Default + +| bnd-module-name +| Override the generated JPMS module name +| the `Bundle-SymbolicName` + +| bnd-extra-module-options +| Refine the computed `requires` directives (see the https://bnd.bndtools.org/chapters/330-jpms.html#advanced-options[BND JPMS options]); use only when `bnd-extra-package-options` cannot express the change +| _(empty)_ +|=== + +[TIP] +==== +To keep incremental recompiles working, a `maven-clean-plugin` execution deletes any stale +`module-info.class` from the output directory before each compilation. +This works around a `javac` limitation and is not something you need to configure. + +The same deletion, however, makes the classes folder look modified on every invocation. +Use `-Dbnd.skip` to suppress the BND processing when you do not need to modify the descriptors. +==== + +[#artifacts-services] +=== ServiceLoader descriptor + +_Phase:_ `process-classes`. + +`java.util.ServiceLoader` requires a provider-registration file under `META-INF/services/` and, on the module path, matching `provides` and `uses` directives in `module-info`. +Rather than maintaining these by hand, {project-name} lets BND generate them from two annotations: + +`aQute.bnd.annotation.spi.ServiceProvider`:: ++ +Placed on a service _implementation_, it registers the class in the appropriate `META-INF/services/<service>` file and adds a `provides <service> with <implementation>` directive to the JPMS descriptor. + +`aQute.bnd.annotation.spi.ServiceConsumer`:: ++ +Placed on a type that looks services up through `ServiceLoader`, it adds the matching `uses <service>` directive to the JPMS descriptor. + +Driving both the class-path (`META-INF/services/`) and module-path (`module-info`) registrations from a single annotation keeps the two representations from drifting apart. + +[#artifacts-sbom] +=== CycloneDX SBOM + +_Phase:_ `package`. + +The `cyclonedx-maven-plugin` generates a +https://cyclonedx.org/capabilities/vdr[CycloneDX Software Bill of Materials (SBOM)] for every module, describing its resolved dependencies. +Each SBOM is attached as an XML artifact with the `cyclonedx` classifier (`<artifactId>-<version>-cyclonedx.xml`) and carries a `vulnerability-assertion` external reference to the shared Apache Logging Services VDR. +See xref:features.adoc#cyclonedx-sbom[] for details. + +[#artifacts-asf] +=== Embedded LICENSE, NOTICE, and DEPENDENCIES + +_Phase:_ `generate-resources`. + +The `maven-remote-resources-plugin`, configured by the {asf-parent-url}[ASF Parent POM] and its shared resource bundle, contributes three files under the `META-INF/` directory of every produced JAR: + +`META-INF/LICENSE`:: the Apache License 2.0 text; +`META-INF/NOTICE`:: the artifact's attribution notices; +`META-INF/DEPENDENCIES`:: a list of the module's transitive dependencies, grouped by organization and annotated with their licenses. + +`META-INF/DEPENDENCIES` is always generated from the resolved dependency tree. +`META-INF/LICENSE` and `META-INF/NOTICE`, on the other hand, are only _defaults_: a module's own `src/main/resources/META-INF/LICENSE` or `META-INF/NOTICE` takes precedence, so a module that records third-party attributions ships its curated files instead of the generated ones. + +[#transformations] +== Artifact transformations + +[#transformations-pom] +=== POM flattening + +_Phase:_ `process-resources`. + +The POM you write is not the POM that gets published. +{project-name} uses https://maven.apache.org/maven-ci-friendly.html[CI-friendly versioning], so the project version is the `$\{revision}` property, and a POM still holding an unresolved `$\{revision}` is not consumable by Maven. +The `flatten-maven-plugin` therefore rewrites the POM into a `.flattened-pom.xml`, which is the file actually installed and deployed. +The rewrite runs in one of two modes: + +Default (`resolveCiFriendliesOnly`):: ++ +Only the CI-friendly properties (`$\{revision}` and friends) are resolved; the rest of the POM, including its `parent`, is preserved as-is. + +BOM (`bom`):: ++ +_Activated by `.logging-parent-bom-activator`._ +The POM is reduced to a self-contained Bill of Materials: besides resolving the version, the `parent`, `build`, `properties`, and `profiles` sections are removed, leaving only the managed dependencies. +This keeps consumers of the BOM free of unrelated build configuration. ++ +A BOM must therefore *not* reference a property defined solely in an ancestor POM: `bom`-mode interpolation resolves variables from the module's own POM only, so an inherited property would be left unresolved after flattening. + +[#optional-extensions] +== Optional lifecycle extensions + +The following profiles are not activated automatically; you enable them on the command line to add behavior to an otherwise normal build. + +`-Prelease`:: +Generates the additional artifacts a release requires: it attaches the `-sources` JAR and enforces that neither the project version nor any of its dependencies is a SNAPSHOT. ++ +NOTE: Apache Logging Service projects do *not* use the ASF Parent POM's `apache-release` profile; this `release` profile, together with the `deploy` or `distribution` commands, replace it. + +`-Pcoverage`:: +Runs the `jacoco-maven-plugin` to collect test coverage during the build and write an HTML report under `target/site/jacoco`. + +`-Dapache.snapshots`:: +Activates the ASF Parent POM's `use-apache-snapshots` profile, adding the https://repository.apache.org/snapshots[Apache snapshots repository]. +It lets you build only some modules of a project and resolve the rest from the regularly published SNAPSHOT artifacts, instead of building every upstream module locally. + +[#commands] +== Additional commands + +A few profiles are not lifecycle extensions but _commands_: each carries a `defaultGoal`, so enabling the profile without naming a phase runs a single task and nothing else. +They are normally invoked by the reusable deployment workflows, but can also be run by hand. + +`./mvnw -Pchangelog-release`:: +Moves the pending changelog entries from `src/changelog/.<version>.x.x/` into the released version's directory and regenerates the release notes. + +`./mvnw -Pdistribution`:: +Builds the source (`src.zip`) and binary (`bin.zip`) distribution archives from the Git-tracked files. +Requires the `attachmentFilepathPattern` and `attachmentCount` properties and a prior `package`. + +`./mvnw -Pdeploy`:: +Signs the artifacts and deploys them to the Apache Nexus staging repository via the `nexus-staging-maven-plugin` (skipping tests, SpotBugs, and Spotless). diff --git a/src/site/antora/modules/ROOT/pages/troubleshooting.adoc b/src/site/antora/modules/ROOT/pages/troubleshooting.adoc new file mode 100644 index 0000000..ef7851d --- /dev/null +++ b/src/site/antora/modules/ROOT/pages/troubleshooting.adoc @@ -0,0 +1,168 @@ +//// + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +//// + +[#troubleshooting] += Troubleshooting + +This page collects debugging recipes for the build checks that are not self-explanatory. + +[#bnd-baseline] +== API compatibility (BND baseline) + +The xref:build-lifecycle.adoc#check-api-compatibility[API compatibility check] (`bnd-baseline-maven-plugin`) fails a build when the public API of a module changed in a way that is not reflected in its version numbers. +When it trips, `./mvnw verify` prints a report (also written to `target/baseline/<artifactId>-<version>.txt`) similar to: + +[source] +---- +=============================================================== + Name Type Delta New Old Suggest + org.apache.logging.log4j.api BUNDLE MAJOR 2.27.0.SNAPSHOT 2.26.1 - +=============================================================== + Name Type Delta New Old Suggest If Prov. +* org.apache.logging.log4j PACKAGE MINOR 2.20.2 2.20.2 2.21.0 - + MINOR PACKAGE org.apache.logging.log4j + MINOR CLASS org.apache.logging.log4j.MarkerManager + ADDED METHOD triggerBaselineError() + ADDED ACCESS static + ADDED RETURN int + org.apache.logging.log4j.message PACKAGE UNCHANGED 2.24.2 2.24.2 ok - + ... +---- + +Read it as follows: + +* The rows marked with `*` are the ones you must fix. +* `Delta` is the kind of change BND detected in that package: `MICRO`, `MINOR`, or `MAJOR`. +* `Old` is the version of the package in the last release, `New` is the version you currently declare. +* `Suggest` is the *minimal* version that would satisfy the detected change. ++ +[IMPORTANT] +==== +The `Suggest` value is only BND's _minimal_ acceptable version; we do not always adopt it verbatim. +For a `MICRO` change we follow the suggestion, but for a `MINOR` change we align the package version with the project version instead. +See <<bnd-baseline-why>> for the rationale. +==== +* The indented tree below a package explains _why_ that delta was computed (here, a `static` method `triggerBaselineError()` was `ADDED`). + +Package versions are declared with the `@Version` annotation of the package's `package-info.java`: + +[source,java] +---- +@Version("2.20.2") +package org.apache.logging.log4j; +---- + +How you resolve the failure depends on the `Delta`. + +[#bnd-baseline-micro] +=== `MICRO` + +A change that is both binary- and source-compatible but that BND still detects, most commonly an annotation added to or removed from an API member and retained in its bytecode. + +Bump the *patch* component of the package version to the value in the `Suggest` column, *not* to the upcoming project version, by editing its `package-info.java`: + +[source,java] +---- +@Version("2.20.3") +package org.apache.logging.log4j; +---- + +Here we keep the suggested `2.20.3`, regardless of the upcoming project version; see <<bnd-baseline-why>>. + +[#bnd-baseline-minor] +=== `MINOR` + +A backward-compatible addition to the public API: a new method, class, field, or constant. +In the report above, adding the `triggerBaselineError()` method produced a `MINOR` delta on `org.apache.logging.log4j`. + +Resolve it in three steps: + +. *Make the project version a minor upgrade over the last release.* +Adding API requires a new minor release, so the project version must reflect it. +If the `<revision>` property is only a patch upgrade (for example `2.26.1-SNAPSHOT` after the `2.26.0` release), raise it to the next minor version (`2.27.0-SNAPSHOT`). +. *Record the change in the changelog.* +Add an entry of type `added` (or `changed` / `deprecated`, as appropriate) so the addition appears in the release notes. +. *Bump the package version.* +Set the `@Version` in the package's `package-info.java` to the upcoming project version, **not** to the minimal value in the `Suggest` column: ++ +[source,java] +---- +@Version("2.27.0") +package org.apache.logging.log4j; +---- ++ +Using `2.27.0` rather than the suggested `2.21.0` is deliberate; see <<bnd-baseline-why>>. + +[#bnd-baseline-major] +=== `MAJOR` + +A breaking change: a public member was removed, renamed, or changed in an incompatible way. +On a stable branch (for example Log4j `2.x`) this is *not* accepted, and bumping the package major version is not an option. + +Instead of changing the version, rework the change so that it stays backward-compatible, for example by deprecating a member instead of removing it, or by adding an overload instead of altering an existing signature. + +If you are convinced the report is a false positive (for example, the member you removed was documented as private), ask the development team before overriding the check. + +[#bnd-baseline-why] +=== Why these rules? + +These conventions make a package's `@Version` tell you, at a glance, when its public API last changed. + +Because a `MINOR` change sets the package version to the project version, while a `MICRO` change only increments the patch component, a package version such as `2.34.5` reads as: + +* its public API last changed in release `2.34.0`, and +* `5` smaller, API-compatible revisions have been published since. + +Had we used BND's minimal `Suggest` value instead, the minor component would not line up with any release, and the version would carry no such meaning. + +[#require-upper-bound-deps] +== Order-independent dependency resolution + +The xref:build-lifecycle.adoc#check-dependency-convergence[Order-independent dependency resolution check] (the `maven-enforcer-plugin` `requireUpperBoundDeps` rule) fails when the version Maven resolves for a dependency is lower than a version required elsewhere in the graph. + +A failure looks like this: + +[source] +---- +Rule 0: ...RequireUpperBoundDeps failed with message: +Failed while enforcing RequireUpperBoundDeps. The error(s) are [ +Require upper bound dependencies error for commons-codec:commons-codec:1.10. Paths to dependency are: ++-test:upperbound-test:1.0 + +-commons-codec:commons-codec:1.10 +and ++-test:upperbound-test:1.0 + +-org.apache.httpcomponents:httpclient:4.5.13 + +-commons-codec:commons-codec:1.11 +] +---- + +Read it as follows: + +* The header names the *resolved* version that is too low (`commons-codec:1.10`). +* Each `Paths to dependency` block is one route through the tree. +The first route shows how the low version was selected (here `commons-codec` is declared directly); the others show who requires a higher version (`httpclient:4.5.13` needs `1.11`). + +To fix it, find where the too-low version is defined, usually in the project's parent POM, where all dependency versions are managed. + +If the parent POM does *not* pin `commons-codec`:: +Add it to the parent's `<dependencyManagement>` at a version at least as high as the highest one required (`1.11` here). + +If the parent POM already pins `commons-codec`:: +The pin is what forced the lower version, so it is the cause of the failure. +Bump it to at least the required minimum (`1.11`). ++ +It is also worth trying to *remove* the pin altogether: the direct dependencies that once needed it may have since upgraded to mutually compatible versions, making the pin unnecessary.
