Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
8 changes: 7 additions & 1 deletion .github/workflows/maven-publish.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# DEPRECATED: This workflow is kept for backward compatibility only
#
# Please use the automated release process instead:
# 1. Create a new release in GitHub UI with tag format vX.Y.Z
# 2. The "Automated Release" workflow will handle the rest
#
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven

name: Maven Release
name: Maven Release (Manual - Deprecated)

on: workflow_dispatch
jobs:
Expand Down
158 changes: 158 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# This workflow automates the release process when a release is created on GitHub
# It uses Maven release plugin to manage versions and deploys to Maven Central
#
# Usage:
# 1. Create a new release in GitHub UI with tag format: vX.Y.Z (e.g., v1.2.0)
# - Select the target branch (typically main)
# 2. This workflow will automatically:
# - Use Maven release:prepare to update versions and create release commits
# - Use Maven release:perform to build and deploy artifacts to Maven Central
# - Move the tag to point to the actual release commit
# - Push commits back to the originating branch

name: Automated Release

on:
release:
types: [created] # Trigger when release is created

permissions:
contents: write # Required to push commits and update tags

jobs:
release:
runs-on: ubuntu-latest

steps:
- name: Validate release tag format
id: validate_tag
run: |
TAG_NAME="${{ github.event.release.tag_name }}"
echo "Release tag: $TAG_NAME"

# Validate tag format (should be vX.Y.Z)
if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid tag format. Expected format: vX.Y.Z (e.g., v1.2.0)"
exit 1
fi

# Remove 'v' prefix to get the version number
VERSION="${TAG_NAME#v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"

# Calculate next development version (increment patch version)
IFS='.' read -ra VERSION_PARTS <<< "$VERSION"
MAJOR="${VERSION_PARTS[0]}"
MINOR="${VERSION_PARTS[1]}"
PATCH="${VERSION_PARTS[2]}"
NEXT_PATCH=$((PATCH + 1))
NEXT_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}-SNAPSHOT"
echo "next_version=${NEXT_VERSION}" >> $GITHUB_OUTPUT
echo "Next development version: $NEXT_VERSION"

- name: Determine target branch
id: target_branch
run: |
# Use target_commitish to determine the originating branch
TARGET="${{ github.event.release.target_commitish }}"

# If target_commitish is empty or a SHA, default to main
if [[ -z "$TARGET" ]] || [[ "$TARGET" =~ ^[0-9a-f]{40}$ ]]; then
TARGET="main"
fi

echo "target_branch=${TARGET}" >> $GITHUB_OUTPUT
echo "Target branch: $TARGET"

- name: Checkout repository
uses: actions/checkout@v3
with:
ref: ${{ steps.target_branch.outputs.target_branch }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
Comment thread
thomasturrell marked this conversation as resolved.

- name: Delete user-created tag
run: |
TAG_NAME="${{ github.event.release.tag_name }}"

# Delete the tag created by the user (will be recreated by release:prepare)
git tag -d "$TAG_NAME" || true
git push origin ":refs/tags/$TAG_NAME" || true

echo "Deleted user-created tag $TAG_NAME"

- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: "17"
distribution: "temurin"
cache: maven
server-id: central
Comment thread
thomasturrell marked this conversation as resolved.
Outdated
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
gpg-passphrase: MAVEN_GPG_PASSPHRASE

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Run Maven release:prepare
run: |
VERSION="${{ steps.validate_tag.outputs.version }}"
NEXT_VERSION="${{ steps.validate_tag.outputs.next_version }}"
TAG_NAME="${{ github.event.release.tag_name }}"

echo "Preparing release version: $VERSION"
echo "Next development version: $NEXT_VERSION"
echo "Tag name: $TAG_NAME"

# Run release:prepare with explicit versions
./mvnw -B release:prepare \
-DreleaseVersion="${VERSION}" \
-DdevelopmentVersion="${NEXT_VERSION}" \
Comment thread
thomasturrell marked this conversation as resolved.
Outdated
-Dtag="${TAG_NAME}" \
-DpushChanges=false \
-DremoteTagging=false
Comment thread
thomasturrell marked this conversation as resolved.
Outdated
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}

- name: Run Maven release:perform
run: |
echo "Performing release and deploying to Maven Central"

# Run release:perform to build and deploy
./mvnw -B release:perform \
-DlocalCheckout=true \
-DeployAtEnd=true
env:
MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}

- name: Push changes to originating branch
run: |
TARGET_BRANCH="${{ steps.target_branch.outputs.target_branch }}"
TAG_NAME="${{ github.event.release.tag_name }}"

echo "Pushing changes to branch: $TARGET_BRANCH"

# Push the commits created by release:prepare
git push origin "HEAD:${TARGET_BRANCH}"
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

# Push the tag created by release:prepare
git push origin "$TAG_NAME"

echo "Pushed release commits and tag to $TARGET_BRANCH"

- name: Clean up
Comment thread
thomasturrell marked this conversation as resolved.
Outdated
if: always()
run: |
# Clean up Maven release artifacts
rm -f release.properties pom.xml.releaseBackup
find . -name "pom.xml.releaseBackup" -delete || true
find . -name "pom.xml.tag" -delete || true
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,3 +488,7 @@ public ResponseEntity<Collection<UUID>> postStatements(
}

```

## Contributing

For information about creating releases, see [RELEASING.md](RELEASING.md).
202 changes: 202 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# Release Process

This document describes the automated release process for xAPI Java.

## Overview

The release process is **fully automated** via GitHub Actions. Creating a release is as simple as:
1. Click "Create Release" in GitHub UI
2. Enter tag (e.g., `v1.2.0`)
3. Publish
4. Wait for workflow to complete βœ…

All version management, building, testing, and deployment happens automatically.

## Automated Release Process

The release process is fully automated via GitHub Actions. To create a new release:
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

### Step 1: Create a GitHub Release

1. Navigate to the [Releases page](https://github.com/BerryCloud/xapi-java/releases)
2. Click **"Draft a new release"**
3. **Choose a tag**: Enter the tag version in the format: `vX.Y.Z` (e.g., `v1.2.0`)
- The tag **must** start with `v` followed by semantic version numbers
- Example: `v1.1.16`, `v2.0.0`, `v1.2.3`
4. **Target**: Select the branch to release from (typically `main`)
- The workflow will automatically detect and use this branch
5. Enter a release title (e.g., "Release 1.2.0")
6. Add release notes describing the changes
7. Click **"Publish release"**

### Step 2: Automated Workflow Execution

Once you publish the release, the "Automated Release" workflow will:

1. βœ… Validate the tag format (must be `vX.Y.Z`)
2. βœ… Detect the target branch (auto-detected from release)
3. βœ… Delete the user-created tag (will be recreated properly)
4. βœ… **Run Maven release:prepare** to:
- Update all `pom.xml` files to the release version
- Commit the version change
- Create the release tag pointing to the release commit
- Update `pom.xml` files to the next SNAPSHOT version
- Commit the next development iteration
5. βœ… **Run Maven release:perform** to:
- Check out the release tag
- Build and test the release version
- Deploy artifacts to Maven Central with GPG signatures
6. βœ… Push commits and tag back to the originating branch

**Workflow Diagram:**
```
User Action: Create Release (tag: v1.2.0, target: main)
↓
GitHub: Creates tag v1.2.0 β†’ commit A (from main)
↓
Workflow: Detects target branch (main)
↓
Workflow: Deletes user-created tag v1.2.0
↓
Workflow: Runs release:prepare
↓
- Commit B: pom.xml β†’ 1.2.0 (release version)
- Creates tag v1.2.0 β†’ commit B
- Commit C: pom.xml β†’ 1.2.1-SNAPSHOT (next dev version)
↓
Workflow: Runs release:perform
↓
- Checks out tag v1.2.0 (commit B)
- Builds and tests
- Deploys to Maven Central
↓
Workflow: Pushes commits B & C to main
↓
Workflow: Pushes tag v1.2.0 β†’ commit B
↓
Result:
- Tag v1.2.0 β†’ commit B (release version)
- Main branch β†’ commit C (next SNAPSHOT: 1.2.1-SNAPSHOT)
- Artifacts deployed to Maven Central
```

### Step 3: Verify Release

1. Check the [Actions tab](https://github.com/BerryCloud/xapi-java/actions) to ensure the workflow completed successfully
2. Verify the target branch (e.g., `main`) has two new commits:
- Release commit: `[maven-release-plugin] prepare release vX.Y.Z`
- Development commit: `[maven-release-plugin] prepare for next development iteration`
3. Verify artifacts are available on [Maven Central](https://central.sonatype.com/artifact/dev.learning.xapi/xapi-model)

## Release Branch Strategy

- **Main branch (`main`)** (or other target branch): Contains development code with `-SNAPSHOT` versions
- After each release, receives two commits from Maven release plugin:
1. Release commit: Version update to release version (X.Y.Z)
2. Development commit: Version update to next development version (X.Y.Z+1-SNAPSHOT)
- The HEAD always points to the next development version
- **Release tags (`vX.Y.Z`)**: Created by Maven release plugin
- Points to the release version commit (first commit)
- Used for reproducible builds and deployments
- **No separate release branches**: The release workflow pushes directly to the originating branch

## Version Numbering
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

This project follows [Semantic Versioning](https://semver.org/):

- **MAJOR** version (X): Incompatible API changes
- **MINOR** version (Y): Backward-compatible functionality additions
- **PATCH** version (Z): Backward-compatible bug fixes

The automated workflow increments the **PATCH** version for the next development iteration.

## Manual Override (Not Recommended)
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

For special cases, you can still manually trigger the deprecated "Maven Release (Manual)" workflow:

1. Go to [Actions](https://github.com/BerryCloud/xapi-java/actions)
2. Select "Maven Release (Manual - Deprecated)"
3. Click "Run workflow"

**Note**: This method is deprecated and should only be used if the automated process fails.

## Troubleshooting

### Release Workflow Failed

If the automated release workflow fails:

1. **Check the workflow logs** in the [Actions tab](https://github.com/BerryCloud/xapi-java/actions)
2. **Identify the failed step** and review the error message
3. **Common issues and solutions:**

| Issue | Solution |
|-------|----------|
| Invalid tag format | Use format `vX.Y.Z` (e.g., `v1.2.0`, not `1.2.0` or `v1.2`) |
| Missing secrets | Ensure GPG keys and Maven credentials are configured in repository secrets |
| Build failures | Fix build issues on main branch first, then retry release |
| Test failures | Fix failing tests on main branch first, then retry release |
| Branch already exists | Delete existing branch (see below) before creating new release |
Comment thread
thomasturrell marked this conversation as resolved.
Outdated
| Permission denied | Ensure workflow has `contents: write` permission |
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

4. **After fixing issues:**
- Delete the failed release and tag in GitHub UI
- **Important**: Reset your target branch if commits were already pushed:
```bash
# If release:prepare pushed commits before failure
git fetch origin
git checkout main # or your target branch
git reset --hard origin/main~2 # Remove the 2 release commits
git push -f origin main
```
- Create a new release with the same tag

### Re-releasing the Same Version
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

If you need to re-release the same version after a failed release:

1. Delete the existing release in GitHub UI:
- Go to Releases β†’ Click on the release β†’ Delete release
2. Delete the tag (locally and remotely):
```bash
git tag -d vX.Y.Z
git push origin :refs/tags/vX.Y.Z
```
3. Reset the target branch if commits were pushed:
```bash
git fetch origin
git checkout main # or your target branch
git reset --hard origin/main~2 # Remove the 2 release commits if they exist
git push -f origin main # Only if commits were pushed
```
4. Create a new release with the same version tag

### Workflow Stuck or Taking Too Long

The workflow typically takes 5-10 minutes. If it's taking longer:

1. Check if tests are running (this is the longest step)
2. Check for any hanging processes in the workflow logs
3. You can cancel the workflow run and restart it

### Artifacts Not Appearing on Maven Central

If artifacts don't appear on Maven Central after a successful workflow:

1. Check the Central Portal for deployment status: https://central.sonatype.com/
2. Deployment can take up to 2 hours to sync to Maven Central
3. Check for any deployment errors in the workflow logs
4. Verify GPG signing was successful (check for GPG-related errors)

## Required Secrets
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

The following GitHub secrets must be configured for releases to work:

- `OSSRH_USERNAME`: Sonatype OSSRH username
- `OSSRH_TOKEN`: Sonatype OSSRH token
- `MAVEN_GPG_PRIVATE_KEY`: GPG private key for signing artifacts
- `MAVEN_GPG_PASSPHRASE`: Passphrase for the GPG private key

## Snapshot Releases
Comment thread
thomasturrell marked this conversation as resolved.
Outdated

Snapshot versions are automatically published to Maven Central's snapshot repository when changes are pushed to `release-*` branches. See the "Publish snapshot to the Sonatype OSSRH" workflow.