Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ jobs:

- run: ./mvnw --batch-mode --no-transfer-progress verify

- name: Verify clean consumer
if: matrix.java == '17'
run: ./scripts/verify-consumer.sh

- name: Run shared conformance harness
run: ./scripts/run-conformance.sh
env:
Expand Down
167 changes: 167 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
name: Release

on:
workflow_dispatch:

concurrency:
group: odp-java-release
cancel-in-progress: false

permissions:
attestations: write
contents: write
id-token: write

jobs:
release:
if: github.repository == 'offering-protocol/odp-java'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0

- name: Validate release
id: release
env:
GH_TOKEN: ${{ github.token }}
run: |
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
echo "Releases must run from main." >&2
exit 1
fi
version=$(./mvnw --batch-mode --no-transfer-progress help:evaluate -Dexpression=project.version -DforceStdout -q)
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "The project version must be a stable semantic version such as 0.1.0." >&2
exit 1
fi
tag="v$version"
if gh release view "$tag" >/dev/null 2>&1; then
echo "Release $tag already exists." >&2
exit 1
fi
if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then
tag_commit=$(git rev-list -n 1 "$tag")
if [[ "$tag_commit" != "$GITHUB_SHA" ]]; then
echo "Tag $tag does not identify the selected main commit." >&2
exit 1
fi
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
artifact="https://repo1.maven.org/maven2/org/offeringprotocol/odp-core/$version/odp-core-$version.pom"
if curl --fail --silent --show-error --head "$artifact" >/dev/null; then
echo "published=true" >> "$GITHUB_OUTPUT"
else
echo "published=false" >> "$GITHUB_OUTPUT"
fi

- name: Check out ODP specifications
uses: actions/checkout@v7
with:
repository: offering-protocol/odp-specs
path: .conformance/odp-specs

- name: Check out Node.js reference implementation
uses: actions/checkout@v7
with:
repository: offering-protocol/odp-node
path: .conformance/odp-node

- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: "17"
cache: maven
server-id: central
server-username-env-var: CENTRAL_USERNAME
server-password-env-var: CENTRAL_PASSWORD

- name: Set up pnpm
uses: pnpm/action-setup@v6
with:
version: 11.1.3

- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 22

- name: Install Node.js reference implementation
run: pnpm --dir .conformance/odp-node install --frozen-lockfile

- name: Verify release
run: ./mvnw --batch-mode --no-transfer-progress verify

- name: Run shared conformance harness
run: ./scripts/run-conformance.sh
env:
ODP_SPECS_DIR: .conformance/odp-specs

- name: Run Node.js interoperability
run: ./scripts/run-node-interoperability.sh
env:
ODP_NODE_DIR: .conformance/odp-node

- name: Verify clean consumer
run: ./scripts/verify-consumer.sh

- name: Publish Maven artifacts
if: steps.release.outputs.published != 'true'
run: ./mvnw --batch-mode --no-transfer-progress -Prelease -Dgpg.signer=bc deploy
env:
CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
MAVEN_GPG_KEY: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}

- name: Attest Maven artifacts
uses: actions/attest-build-provenance@v4
with:
subject-path: |
odp-core/target/odp-core-${{ steps.release.outputs.version }}*.jar
odp-directory/target/odp-directory-${{ steps.release.outputs.version }}*.jar
odp-agent/target/odp-agent-${{ steps.release.outputs.version }}*.jar
odp-service/target/odp-service-${{ steps.release.outputs.version }}*.jar

- name: Wait for Maven Central availability
env:
VERSION: ${{ steps.release.outputs.version }}
run: |
artifact="https://repo1.maven.org/maven2/org/offeringprotocol/odp-core/$VERSION/odp-core-$VERSION.pom"
for attempt in {1..60}; do
if curl --fail --silent --show-error --head "$artifact" >/dev/null; then
exit 0
fi
sleep 10
done
echo "Maven Central did not expose $artifact within 10 minutes." >&2
exit 1

- name: Verify Maven Central consumer
run: ./scripts/verify-consumer.sh
env:
ODP_CONSUMER_SOURCE: central

- name: Create release tag
env:
TAG: ${{ steps.release.outputs.tag }}
run: |
if git rev-parse --verify "refs/tags/$TAG" >/dev/null 2>&1; then
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag --annotate "$TAG" --message "ODP Java $TAG" "$GITHUB_SHA"
git push origin "$TAG"

- name: Publish GitHub release
run: >-
gh release create "${{ steps.release.outputs.tag }}"
.conformance/reports/agent.json#odp-java-agent-conformance.json
.conformance/reports/service.json#odp-java-service-conformance.json
--generate-notes
--title "ODP Java ${{ steps.release.outputs.tag }}"
--verify-tag
env:
GH_TOKEN: ${{ github.token }}
20 changes: 17 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ conformance behavior there before implementing or changing it in Java.

## Releases

The Maven reactor produces independently publishable artifacts under `org.offeringprotocol`.
Release publication requires sources, Javadocs, signatures, provenance, shared conformance, and
clean external-consumer verification.
All publishable modules share the parent reactor's stable semantic version. A release publishes the
`odp-java` parent and the `odp-core`, `odp-directory`, `odp-agent`, and `odp-service` artifacts to
Maven Central. Examples and conformance tooling remain repository-only modules.

The Release workflow runs manually from `main`. It requires the `org.offeringprotocol` Maven Central
namespace and these repository secrets:

- `CENTRAL_USERNAME`: Central Portal user-token username.
- `CENTRAL_PASSWORD`: Central Portal user-token password.
- `MAVEN_GPG_PRIVATE_KEY`: ASCII-armored private signing key.
- `MAVEN_GPG_PASSPHRASE`: signing-key passphrase.

Before publication, the workflow requires a stable project version, the complete Maven gate, shared
Agent and Service conformance, Node.js interoperability, and isolated consumer compilation. It then
creates the matching `v<version>` tag, publishes signed binary, source, Javadoc, and POM artifacts,
attests the Maven artifacts, verifies Maven Central consumption, and creates the GitHub release with
conformance evidence.
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Offering Discovery Protocol for Java

[![CI](https://github.com/offering-protocol/odp-java/actions/workflows/ci.yml/badge.svg)](https://github.com/offering-protocol/odp-java/actions/workflows/ci.yml)
[![Maven Central](https://img.shields.io/maven-central/v/org.offeringprotocol/odp-agent)](https://central.sonatype.com/namespace/org.offeringprotocol)
[![Java](https://img.shields.io/badge/Java-17%2B-ED8B00?logo=openjdk&logoColor=white)](https://openjdk.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)

Expand All @@ -27,6 +28,37 @@ directory behavior.

All artifacts use the Maven group `org.offeringprotocol` and require Java 17 or newer.

## Installation

Applications should depend on the module matching their role. Maven resolves its required ODP
modules transitively.

For an Agent application:

```xml
<dependency>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-agent</artifactId>
<version>0.1.0</version>
</dependency>
```

For a Service integration:

```xml
<dependency>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-service</artifactId>
<version>0.1.0</version>
</dependency>
```

Gradle applications use the same coordinates:

```kotlin
implementation("org.offeringprotocol:odp-agent:0.1.0")
```

## Examples

Run the small Service and Agent examples in separate terminals:
Expand All @@ -48,6 +80,12 @@ The Maven Wrapper provides the complete merge gate:
./mvnw verify
```

Verify the published module boundaries from an isolated consumer project with:

```sh
./scripts/verify-consumer.sh
```

Format Java sources with:

```sh
Expand Down
2 changes: 1 addition & 1 deletion examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
</parent>

<artifactId>odp-examples</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion odp-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
</parent>

<artifactId>odp-agent</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion odp-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
</parent>

<artifactId>odp-core</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion odp-directory/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
</parent>

<artifactId>odp-directory</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion odp-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
</parent>

<artifactId>odp-service</artifactId>
Expand Down
69 changes: 68 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.offeringprotocol</groupId>
<artifactId>odp-java</artifactId>
<version>0.1.0-SNAPSHOT</version>
<version>0.1.0</version>
<packaging>pom</packaging>

<name>Offering Discovery Protocol for Java</name>
Expand Down Expand Up @@ -56,6 +56,10 @@
<json-schema-validator.version>3.0.7</json-schema-validator.version>
<jacoco.version>0.8.15</jacoco.version>
<exec-maven-plugin.version>3.6.3</exec-maven-plugin.version>
<central-publishing-maven-plugin.version>0.11.0</central-publishing-maven-plugin.version>
<maven-gpg-plugin.version>3.2.8</maven-gpg-plugin.version>
<maven-javadoc-plugin.version>3.12.0</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.4.0</maven-source-plugin.version>
<palantir-java-format.version>2.97.0</palantir-java-format.version>

<maven-checkstyle-plugin.version>3.6.0</maven-checkstyle-plugin.version>
Expand Down Expand Up @@ -271,4 +275,67 @@
</plugins>
</build>

<profiles>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>${central-publishing-maven-plugin.version}</version>
<extensions>true</extensions>
<configuration>
<autoPublish>true</autoPublish>
<deploymentName>ODP Java ${project.version}</deploymentName>
<excludeArtifacts>odp-conformance,odp-examples</excludeArtifacts>
<publishingServerId>central</publishingServerId>
<waitUntil>published</waitUntil>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Loading