diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c9a8eaa..f5952b81 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,10 @@ on: push: tags: ["v*"] +permissions: + contents: write + id-token: write + jobs: release: runs-on: ubuntu-latest @@ -87,3 +91,113 @@ jobs: spring-data-valkey/target/*.jar spring-boot-starter-data-valkey/target/*.jar generate_release_notes: true + + publish: + needs: release + runs-on: ubuntu-latest + timeout-minutes: 15 + environment: maven-publish + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: "temurin" + + - name: Cache Maven dependencies + uses: actions/cache@v4 + with: + path: ~/.m2/spring-data-valkey + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Configure GPG for non-interactive signing + run: | + mkdir -p ~/.gnupg + echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf + echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf + chmod 700 ~/.gnupg + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ vars.AWS_ROLE_ARN }} + aws-region: us-east-1 + + - name: Fetch Maven Central credentials + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id spring-data-valkey-maven-token \ + --query SecretString --output text) + OSSRH_USERNAME=$(echo "$SECRET" | jq -r '.["maven-central-username"]') + OSSRH_PASSWORD=$(echo "$SECRET" | jq -r '.["maven-central-password"]') + if [ -z "$OSSRH_USERNAME" ] || [ "$OSSRH_USERNAME" = "null" ] || [ -z "$OSSRH_PASSWORD" ] || [ "$OSSRH_PASSWORD" = "null" ]; then + echo "ERROR: Failed to extract Maven credentials from secret" + exit 1 + fi + echo "::add-mask::$OSSRH_USERNAME" + echo "::add-mask::$OSSRH_PASSWORD" + echo "OSSRH_USERNAME=$OSSRH_USERNAME" >> $GITHUB_ENV + echo "OSSRH_PASSWORD=$OSSRH_PASSWORD" >> $GITHUB_ENV + + - name: Fetch GPG passphrase + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id GPGPassword \ + --query SecretString --output text) + GPG_PASSPHRASE=$(echo "$SECRET" | jq -r '.["GPG Password"]') + if [ -z "$GPG_PASSPHRASE" ] || [ "$GPG_PASSPHRASE" = "null" ]; then + echo "ERROR: Failed to extract GPG passphrase from secret" + exit 1 + fi + echo "::add-mask::$GPG_PASSPHRASE" + echo "GPG_PASSPHRASE=$GPG_PASSPHRASE" >> $GITHUB_ENV + + - name: Import GPG private key + run: | + SECRET=$(aws secretsmanager get-secret-value \ + --secret-id PGPPrivateKey \ + --query SecretString --output text) + echo "$SECRET" | jq -r '.PGP_SECRET_KEY' | tr ' ' '\n' | base64 -d | gpg --batch --import + GPG_KEYNAME=$(gpg --list-secret-keys --keyid-format short 2>/dev/null | grep 'sec' | head -1 | sed 's/.*\///' | awk '{print $1}') + if [ -z "$GPG_KEYNAME" ]; then + echo "ERROR: Failed to determine GPG key ID after import" + exit 1 + fi + echo "GPG_KEYNAME=$GPG_KEYNAME" >> $GITHUB_ENV + + - name: Deploy and release to Maven Central + id: deploy + run: | + ./mvnw -s settings.xml \ + -Ddevelocity.storage.directory=$HOME/.develocity-root \ + -Dmaven.repo.local=$HOME/.m2/spring-data-valkey \ + deploy -DskipTests \ + -pl spring-data-valkey,spring-boot-starter-data-valkey \ + -Dmaven.deploy.skip=false \ + -DautoReleaseAfterClose=true \ + -U -B + + - name: Drop staging repository on failure + if: failure() && steps.deploy.outcome == 'failure' + run: | + echo "Deploy failed - attempting to drop staging repository..." + AUTH_HEADER="Bearer $(echo -n "${OSSRH_USERNAME}:${OSSRH_PASSWORD}" | base64)" + # Find any open repositories for our namespace + REPOS=$(curl -s --header "Authorization: ${AUTH_HEADER}" \ + "https://ossrh-staging-api.central.sonatype.com/manual/search/repositories?profile_id=io.valkey.springframework&state=open") + REPO_KEY=$(echo "$REPOS" | jq -r '.repositories[0].key // empty') + if [ -n "$REPO_KEY" ]; then + echo "Dropping repository: $REPO_KEY" + curl --fail --request DELETE \ + --header "Authorization: ${AUTH_HEADER}" \ + "https://ossrh-staging-api.central.sonatype.com/manual/drop/repository/${REPO_KEY}" + echo "Staging repository dropped - safe to retry" + else + echo "No open staging repository found - nothing to clean up" + fi