name: "Java Publish to Maven Central" env: # Disable Husky Git hooks in CI to prevent local development hooks # (e.g., pre-commit formatting checks) from running during automated # workflows that perform git commits and pushes. HUSKY: 0 on: workflow_dispatch: inputs: releaseVersion: description: "Release version (e.g., 1.0.0). If empty, derives from pom.xml by removing -SNAPSHOT" required: false type: string developmentVersion: description: "Next development version (e.g., 1.0.1-SNAPSHOT). If empty, increments patch version" required: false type: string prerelease: description: "Is this a prerelease?" type: boolean required: false default: false permissions: contents: write id-token: write concurrency: group: publish-maven cancel-in-progress: false jobs: publish-maven: name: Publish Java SDK to Maven Central runs-on: ubuntu-latest defaults: run: shell: bash working-directory: ./java outputs: version: ${{ steps.versions.outputs.release_version }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 token: ${{ secrets.JAVA_RELEASE_TOKEN }} - name: Configure Git for Maven Release run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - uses: ./.github/actions/setup-copilot - name: Set up JDK 17 uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: java-version: "17" distribution: "microsoft" cache: "maven" server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD gpg-private-key: ${{ secrets.JAVA_GPG_SECRET_KEY }} gpg-passphrase: JAVA_GPG_PASSPHRASE - name: Determine versions id: versions working-directory: ./java run: | CURRENT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) echo "Current pom.xml version: $CURRENT_VERSION" # Determine release version if [ -n "${{ inputs.releaseVersion }}" ]; then RELEASE_VERSION="${{ inputs.releaseVersion }}" else # Remove -SNAPSHOT suffix if present RELEASE_VERSION="${CURRENT_VERSION%-SNAPSHOT}" fi echo "Release version: $RELEASE_VERSION" # Determine next development version if [ -n "${{ inputs.developmentVersion }}" ]; then DEV_VERSION="${{ inputs.developmentVersion }}" if [[ "$DEV_VERSION" != *-SNAPSHOT ]]; then echo "::error::developmentVersion '${DEV_VERSION}' must end with '-SNAPSHOT' (e.g., '${DEV_VERSION}-SNAPSHOT'). The maven-release-plugin requires the next development version to be a snapshot." exit 1 fi else # Split version: supports "0.1.32", "0.1.32-java.0", and "0.1.32-java-preview.0" formats # Validate RELEASE_VERSION format explicitly to provide clear errors if ! echo "$RELEASE_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-(beta-)?java(-preview)?\.[0-9]+)?$'; then echo "Error: RELEASE_VERSION '$RELEASE_VERSION' is invalid. Expected format: M.M.P, M.M.P-java.N, M.M.P-java-preview.N, M.M.P-beta-java.N, or M.M.P-beta-java-preview.N (e.g., 1.2.3, 1.2.3-java.0, 1.2.3-java-preview.0, 1.2.3-beta-java.0, or 1.2.3-beta-java-preview.0)." >&2 exit 1 fi # Extract the base M.M.P portion (before any qualifier) BASE_VERSION=$(echo "$RELEASE_VERSION" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+') QUALIFIER=$(echo "$RELEASE_VERSION" | sed "s|^${BASE_VERSION}||") IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE_VERSION" NEXT_PATCH=$((PATCH + 1)) DEV_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}${QUALIFIER}-SNAPSHOT" fi echo "Next development version: $DEV_VERSION" echo "release_version=$RELEASE_VERSION" >> $GITHUB_OUTPUT echo "dev_version=$DEV_VERSION" >> $GITHUB_OUTPUT echo "### Version Summary" >> $GITHUB_STEP_SUMMARY echo "- **Release version:** $RELEASE_VERSION" >> $GITHUB_STEP_SUMMARY echo "- **Next development version:** $DEV_VERSION" >> $GITHUB_STEP_SUMMARY - name: Update documentation with release version id: update-docs working-directory: ./java run: | VERSION="${{ steps.versions.outputs.release_version }}" # Update version in README.md (supports any version qualifier like -java.N, -java-preview.N, -beta-java.N) sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|${VERSION}|g" README.md sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|copilot-sdk-java:${VERSION}|g" README.md # Update snapshot version in README.md DEV_VERSION="${{ steps.versions.outputs.dev_version }}" sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*-SNAPSHOT|${DEV_VERSION}|g" README.md # Update version in jbang-example.java sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|copilot-sdk-java:${VERSION}|g" jbang-example.java sed -i 's|copilot-sdk-java:${project\.version}|copilot-sdk-java:'"${VERSION}"'|g' jbang-example.java # Commit the documentation changes before release:prepare (requires clean working directory) git add README.md jbang-example.java git commit -m "docs: update version references to ${VERSION}" # Save the commit SHA for potential rollback echo "docs_commit_sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT git push origin main - name: Prepare Release working-directory: ./java run: | mvn -B release:prepare \ -DreleaseVersion=${{ steps.versions.outputs.release_version }} \ -DdevelopmentVersion=${{ steps.versions.outputs.dev_version }} \ -DtagNameFormat=java/v@{project.version} \ -DpushChanges=true \ -Darguments="-DskipTests" env: MAVEN_USERNAME: ${{ secrets.JAVA_MAVEN_CENTRAL_USERNAME }} MAVEN_PASSWORD: ${{ secrets.JAVA_MAVEN_CENTRAL_PASSWORD }} JAVA_GPG_PASSPHRASE: ${{ secrets.JAVA_GPG_PASSPHRASE }} - name: Perform Release and Deploy to Maven Central working-directory: ./java run: | mvn -B release:perform \ -Dgoals="deploy" \ -Darguments="-DskipTests -Prelease" env: MAVEN_USERNAME: ${{ secrets.JAVA_MAVEN_CENTRAL_USERNAME }} MAVEN_PASSWORD: ${{ secrets.JAVA_MAVEN_CENTRAL_PASSWORD }} JAVA_GPG_PASSPHRASE: ${{ secrets.JAVA_GPG_PASSPHRASE }} - name: Rollback documentation commit on failure if: failure() && steps.update-docs.outputs.docs_commit_sha != '' working-directory: ./java run: | echo "Release failed, rolling back documentation commit..." git revert --no-edit ${{ steps.update-docs.outputs.docs_commit_sha }} git push origin main # Also run Maven release:rollback to clean up any partial release state mvn -B release:rollback || true github-release: name: Create GitHub Release needs: publish-maven if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest defaults: run: shell: bash working-directory: ./java steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - name: Create GitHub Release run: | VERSION="${{ needs.publish-maven.outputs.version }}" GROUP_ID="com.github" ARTIFACT_ID="copilot-sdk-java" CURRENT_TAG="java/v${VERSION}" if gh release view "${CURRENT_TAG}" >/dev/null 2>&1; then echo "Release ${CURRENT_TAG} already exists. Skipping creation." exit 0 fi # Generate release notes from template export VERSION GROUP_ID ARTIFACT_ID RELEASE_NOTES=$(envsubst < $GITHUB_WORKSPACE/.github/workflows/java.notes.template) # Get the previous tag for generating notes PREV_TAG=$(git tag --list 'java/v*' --sort=-version:refname \ | grep -Fxv "${CURRENT_TAG}" \ | head -n 1) echo "Current tag: ${CURRENT_TAG}" echo "Previous tag: ${PREV_TAG}" # Build the gh release command GH_ARGS=("${CURRENT_TAG}") GH_ARGS+=("--title" "GitHub Copilot SDK for Java ${VERSION}") GH_ARGS+=("--notes" "${RELEASE_NOTES}") GH_ARGS+=("--generate-notes") if [ -n "$PREV_TAG" ]; then GH_ARGS+=("--notes-start-tag" "$PREV_TAG") fi ${{ inputs.prerelease == true && 'GH_ARGS+=("--prerelease")' || '' }} gh release create "${GH_ARGS[@]}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Trigger changelog generation run: gh workflow run release-changelog.lock.yml -f tag="java/v${{ needs.publish-maven.outputs.version }}" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}