diff --git a/.github/workflows/publish-api.yml b/.github/workflows/publish-api.yml
new file mode 100644
index 000000000..ec5beebcc
--- /dev/null
+++ b/.github/workflows/publish-api.yml
@@ -0,0 +1,45 @@
+name: Publish API
+
+on:
+ push:
+ tags:
+ - "api-v*"
+
+permissions:
+ contents: read
+
+jobs:
+ publish:
+ name: Publish liquidjava-api to Maven Central
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Ensure tag is on main
+ run: |
+ git fetch origin main
+ TAG_COMMIT="$(git rev-list -n 1 "$GITHUB_REF_NAME")"
+ git merge-base --is-ancestor "$TAG_COMMIT" origin/main
+
+ - name: Set up JDK 20
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: "20"
+ cache: maven
+ server-id: central
+ server-username: CENTRAL_USERNAME
+ server-password: CENTRAL_PASSWORD
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase: GPG_PASSPHRASE
+
+ - name: Publish API
+ run: ./mvnw -f liquidjava-api/pom.xml -B --fail-fast -Dgpg.skip=false -Dmaven.deploy.skip=false clean deploy
+ env:
+ CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
+ CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
diff --git a/.github/workflows/publish-verifier.yml b/.github/workflows/publish-verifier.yml
new file mode 100644
index 000000000..9a1ec390b
--- /dev/null
+++ b/.github/workflows/publish-verifier.yml
@@ -0,0 +1,45 @@
+name: Publish verifier
+
+on:
+ push:
+ tags:
+ - "v*"
+
+permissions:
+ contents: read
+
+jobs:
+ publish:
+ name: Publish liquidjava-verifier to Maven Central
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Ensure tag is on main
+ run: |
+ git fetch origin main
+ TAG_COMMIT="$(git rev-list -n 1 "$GITHUB_REF_NAME")"
+ git merge-base --is-ancestor "$TAG_COMMIT" origin/main
+
+ - name: Set up JDK 20
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: "20"
+ cache: maven
+ server-id: central
+ server-username: CENTRAL_USERNAME
+ server-password: CENTRAL_PASSWORD
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase: GPG_PASSPHRASE
+
+ - name: Publish verifier
+ run: ./mvnw -f liquidjava-verifier/pom.xml -B --fail-fast -Dgpg.skip=false -Dmaven.deploy.skip=false clean deploy
+ env:
+ CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }}
+ CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 04cd61886..0d379bc34 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
{
- "java.configuration.updateBuildConfiguration": "automatic"
+ "java.configuration.updateBuildConfiguration": "automatic",
+ "java.autobuild.enabled": false
}
diff --git a/liquidjava-api/pom.xml b/liquidjava-api/pom.xml
index 037ae5d1e..9e366b0ba 100644
--- a/liquidjava-api/pom.xml
+++ b/liquidjava-api/pom.xml
@@ -142,7 +142,8 @@
central
${maven.deploy.skip}
-
+ true
+ published
@@ -163,4 +164,4 @@
true
true
-
\ No newline at end of file
+
diff --git a/liquidjava-verifier/pom.xml b/liquidjava-verifier/pom.xml
index db87d2122..13efeb1a0 100644
--- a/liquidjava-verifier/pom.xml
+++ b/liquidjava-verifier/pom.xml
@@ -213,7 +213,8 @@
central
${maven.deploy.skip}
-
+ true
+ published
diff --git a/release.sh b/release.sh
index bf6c3d857..3ac4ce2c3 100755
--- a/release.sh
+++ b/release.sh
@@ -1,20 +1,67 @@
-#!/bin/bash
+#!/usr/bin/env bash
-if [ -z "$1" ]; then
- echo "Usage: $0 "
+set -euo pipefail
+
+if [ $# -ne 2 ]; then
+ echo "Usage: $0 "
exit 1
fi
MODULE=$1
+VERSION=$2
if [ "$MODULE" != "api" ] && [ "$MODULE" != "verifier" ]; then
echo "Invalid module: $MODULE"
- echo "Usage: $0 "
+ echo "Usage: $0 "
+ exit 1
+fi
+
+if ! [[ "$VERSION" =~ ^[0-9]+(\.[0-9]+){1,2}(-[A-Za-z0-9.-]+)?$ ]]; then
+ echo "Invalid version: $VERSION"
+ echo "Expected format: 1.2.3"
exit 1
fi
MODULE_DIR="liquidjava-$MODULE"
+POM="$MODULE_DIR/pom.xml"
+
+if [ "$MODULE" = "api" ]; then
+ TAG="api-v$VERSION"
+else
+ TAG="v$VERSION"
+fi
+
+CURRENT_BRANCH=$(git branch --show-current)
+if [ "$CURRENT_BRANCH" != "main" ]; then
+ echo "Release must be run from main. Current branch: $CURRENT_BRANCH"
+ exit 1
+fi
+
+if [ -n "$(git status --porcelain)" ]; then
+ echo "Worktree must be clean before releasing."
+ git status --short
+ exit 1
+fi
+
+if git rev-parse "$TAG" >/dev/null 2>&1; then
+ echo "Tag already exists: $TAG"
+ exit 1
+fi
+
+perl -0pi -e "s#($MODULE_DIR\\s*)[^<]+()#\${1}$VERSION\${2}#" "$POM"
+
+if git diff --quiet -- "$POM"; then
+ echo "$POM is already at version $VERSION"
+ exit 1
+fi
+
+./mvnw -f "$POM" -B --fail-fast -Dgpg.skip=true -Dmaven.deploy.skip=true clean verify
+
+git add "$POM"
+git commit -m "Release $MODULE_DIR $VERSION"
+git tag "$TAG"
+
+git push origin main
+git push origin "$TAG"
-cd "$MODULE_DIR"
-mvn -Dgpg.skip=false -Dmaven.deploy.skip=false clean deploy
-cd ..
+echo "Created and pushed $TAG. GitHub Actions will publish $MODULE_DIR to Maven Central."