build: align release setup and Apache notices #5

Merged
KofTwentyTwo merged 4 commits from feature/GH-4-qqq41-release-prep into main 2026-10-14 18:54:15 +00:00
5 changed files with 123 additions and 6 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
version: 2.1
orbs:
qqq-orb: kingsrook/qqq-orb@0.5.0
qqq-orb: kingsrook/qqq-orb@0.6.8
commands:
configure-package-install:
+3 -2
View File
@@ -15,5 +15,6 @@ Key orientation facts (details and caveats in the dossier):
README's `io.qrun:qbit-bom` coordinates do not exist on Maven Central.
- v1.6.0 imports `com.kingsrook.qqq:qqq-bom-pom:0.40.0` (Java 21, junit-bom 6.0.1);
develop pins `0.41.0-SNAPSHOT`, which no longer resolves (qqq renumbered to 4.0.x).
- Known licensing inconsistency: LICENSE/NOTICE = Apache-2.0, pom `<licenses>` = AGPL-3.0
(shipped to Central in 1.6.0), README says Proprietary. See dossier "Maturity & risks".
- First-party license declarations in the current source are Apache-2.0, consistent
with LICENSE and NOTICE. Previously published artifacts retain their original
metadata; publish a new version for declaration corrections.
+30 -1
View File
@@ -95,4 +95,33 @@ The running core version is read from `META-INF/maven/com.kingsrook.qqq/qqq-back
## License
See [LICENSE](LICENSE) and [NOTICE](NOTICE).
### Packaged notices
The packaging change in this source tree copies each consumer's own root
`LICENSE` and `NOTICE` into `META-INF` in main/test archives and Maven shared
archive resources used by source/Javadoc archives. Existing main/test resources
remain included. Consumers must adopt a newly published parent version to receive
this change; the existing public 2.0.0 artifact is unchanged.
The default `qbit.noticesDirectory` is `${project.basedir}`. In a nested module
whose files live at the repository root, set it to `${project.basedir}/..` (adjust
for the actual layout). Do not point it at the build-parent checkout: these are
the consuming project's notices. If a child overrides `<resources>` or
`<testResources>`, retain the inherited shared archive resource directory.
After packaging the consumer, explicitly check every produced archive using
Python 3 and the guard from this checkout:
```bash
mvn -Prelease -DskipTests -Dgpg.skip=true clean package
python3 /path/to/qbit-bom/scripts/check-packaged-notices.py --root . target/*.jar
```
For a multi-module consumer, pass each module's actual JAR paths and its repository
root. The guard rejects missing archives, missing/duplicate entries and changed
notice bytes. Packaging-only checks skip runtime tests; existing tests, review
and release requirements still apply. The publishing workflow does not invoke
this guard automatically.
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) and [NOTICE](NOTICE).
+50 -2
View File
@@ -19,8 +19,8 @@
<url>https://github.com/Kingsrook/qbit-bom</url>
<licenses>
<license>
<name>GNU Affero General Public License v3.0</name>
<url>https://www.gnu.org/licenses/agpl-3.0-standalone.html</url>
<name>Apache License, Version 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
<distribution>repo</distribution>
</license>
</licenses>
@@ -44,6 +44,8 @@
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Multi-module consumers override this in modules whose notices live above basedir. -->
<qbit.noticesDirectory>${project.basedir}</qbit.noticesDirectory>
<!-- use revision property in children -->
<revision>2.1.2</revision>
@@ -79,6 +81,52 @@
</dependencyManagement>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>${project.build.directory}/maven-shared-archive-resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
<testResource>
<directory>${project.build.directory}/maven-shared-archive-resources</directory>
</testResource>
</testResources>
<plugins>
<!-- Source and Javadoc archives also consume Maven's shared archive resources. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.4.0</version>
<executions>
<execution>
<id>package-root-notices</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/maven-shared-archive-resources/META-INF</outputDirectory>
<resources>
<resource>
<directory>${qbit.noticesDirectory}</directory>
<filtering>false</filtering>
<includes>
<include>LICENSE</include>
<include>NOTICE</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!-- Compiler -->
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Verify exact project notices in explicitly listed Maven archives."""
import argparse
from pathlib import Path
import sys
from zipfile import BadZipFile, ZipFile
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, required=True,
help="consumer repository containing LICENSE and NOTICE")
parser.add_argument("--prefix", default="META-INF",
help="directory containing the project's archive copies")
parser.add_argument("archives", type=Path, nargs="+")
args = parser.parse_args()
expected = {name: (args.root / name).read_bytes() for name in ("LICENSE", "NOTICE")}
failures = []
for archive in args.archives:
try:
with ZipFile(archive) as jar:
for name, content in expected.items():
entry = f"{args.prefix.rstrip('/')}/{name}"
if jar.namelist().count(entry) != 1:
failures.append(f"{archive}: expected exactly one {entry}")
elif jar.read(entry) != content:
failures.append(f"{archive}: {entry} differs from root {name}")
except (OSError, BadZipFile) as error:
failures.append(f"{archive}: {error}")
if failures:
print("\n".join(failures), file=sys.stderr)
return 1
print(f"PASS: exact LICENSE/NOTICE in {len(args.archives)} archives")
return 0
if __name__ == "__main__":
sys.exit(main())