Maven Publish #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 | |
| # This workflow uses actions that are not certified by GitHub. | |
| # They are provided by a third-party and are governed by | |
| # separate terms of service, privacy policy, and support | |
| # documentation. | |
| name: Maven Publish | |
| on: | |
| push: | |
| branches: [ 'release' ] | |
| workflow_dispatch: | |
| inputs: | |
| revision: | |
| description: 'The version to publish' | |
| required: true | |
| default: '${major}.${minor}.${patch}' | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| if: ${{ inputs.revision }} | |
| steps: | |
| - name: Validate version format | |
| run: | | |
| if ! echo "${{ inputs.revision }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "Error: version '${{ inputs.revision }}' does not match the required pattern major.minor.patch" | |
| exit 1 | |
| fi | |
| - name: Checkout Source | |
| uses: actions/checkout@v5 | |
| - name: Setup Maven Central Repository | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: '11' | |
| distribution: 'temurin' | |
| server-id: ossrh | |
| server-username: MAVEN_USERNAME | |
| server-password: MAVEN_PASSWORD | |
| cache: maven | |
| - name: Publish package | |
| run: mvn | |
| --batch-mode | |
| --update-snapshots | |
| --file pom.xml | |
| -Drevision=${{ inputs.revision }} | |
| -Dgpg.skip=true | |
| deploy | |
| --activate-profiles publish,ci | |
| env: | |
| MAVEN_USERNAME: ${{ secrets.OSS_SONATYPE_USERNAME }} | |
| MAVEN_PASSWORD: ${{ secrets.OSS_SONATYPE_PASSWORD }} | |
| SIGN_KEY_ID: ${{ secrets.OSS_SIGNING_KEY_ID_LONG }} | |
| SIGN_KEY: ${{ secrets.OSS_SIGNING_KEY }} | |
| SIGN_KEY_PASS: ${{ secrets.OSS_SIGNING_PASSWORD }} | |
| release: | |
| runs-on: ubuntu-latest | |
| needs: build | |
| permissions: | |
| contents: write | |
| models: read | |
| steps: | |
| - name: Checkout Source | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Create Tag | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| if git rev-parse "${{ inputs.revision }}" >/dev/null 2>&1; then | |
| echo "Tag ${{ inputs.revision }} already exists, skipping." | |
| else | |
| git tag ${{ inputs.revision }} | |
| git push origin ${{ inputs.revision }} | |
| fi | |
| - name: Generate Release Notes with Copilot | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| CURRENT_TAG="${{ inputs.revision }}" | |
| # Find the previous tag (the one before the current tag) | |
| PREV_TAG=$(git describe --tags --abbrev=0 --exclude="${CURRENT_TAG}" HEAD 2>/dev/null || echo "") | |
| # Collect commits between the previous tag and HEAD | |
| if [ -n "$PREV_TAG" ]; then | |
| COMMITS=$(git log --oneline "${PREV_TAG}..HEAD" 2>/dev/null || echo "No commits found") | |
| SINCE_LABEL="$PREV_TAG" | |
| else | |
| COMMITS=$(git log --oneline -50 2>/dev/null || echo "No commits found") | |
| SINCE_LABEL="the beginning" | |
| fi | |
| # Export for Python (avoids shell-escaping issues with multiline content) | |
| export CURRENT_TAG_DATA="$CURRENT_TAG" | |
| export PREV_TAG_DATA="$SINCE_LABEL" | |
| export COMMITS_DATA="$COMMITS" | |
| # Call GitHub Copilot via GitHub Models API and capture the summary | |
| SUMMARY=$(python3 << 'PYEOF' | |
| import json, os, urllib.request, sys | |
| current_tag = os.environ['CURRENT_TAG_DATA'] | |
| prev_tag = os.environ['PREV_TAG_DATA'] | |
| commits = os.environ['COMMITS_DATA'] | |
| token = os.environ['GH_TOKEN'] | |
| prompt = ( | |
| f"Generate concise release notes for version {current_tag}.\n\n" | |
| f"Commits since {prev_tag}:\n{commits}\n\n" | |
| "Format the output as markdown with sections if present for New Features, Bug Fixes, " | |
| "Documentations, Dependency Updates, Test Improvements, Build and Workflow Enhancements " | |
| "and Other Changes(excludes Full Changelog).\n\n" | |
| "Be concise and clear." | |
| ) | |
| payload = json.dumps({ | |
| "model": "gpt-4o", | |
| "messages": [{"role": "user", "content": prompt}] | |
| }).encode() | |
| req = urllib.request.Request( | |
| "https://models.inference.ai.azure.com/chat/completions", | |
| data=payload, | |
| headers={ | |
| "Content-Type": "application/json", | |
| "Authorization": f"Bearer {token}" | |
| } | |
| ) | |
| try: | |
| with urllib.request.urlopen(req) as resp: | |
| data = json.loads(resp.read()) | |
| print(data["choices"][0]["message"]["content"]) | |
| except Exception as e: | |
| print(f"Failed to generate summary via Copilot: {e}", file=sys.stderr) | |
| print(f"_Release notes generation failed. Raw commits since {prev_tag}:_\n\n```\n{commits}\n```") | |
| PYEOF | |
| ) | |
| # Append the summary (with version header) to release-notes.md | |
| NOTES_FILE="release-notes.md" | |
| if [ ! -f "$NOTES_FILE" ]; then | |
| printf "# Release Notes\n\n" > "$NOTES_FILE" | |
| fi | |
| FULL_CHANGELOG="**Full Changelog**: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/compare/$PREV_TAG...$CURRENT_TAG" | |
| printf "## v%s\n\n%s\n\n" "$CURRENT_TAG" "$SUMMARY" >> "$NOTES_FILE" | |
| printf "%s" "$FULL_CHANGELOG" >> "$NOTES_FILE" | |
| # Write the current release notes to a temp file for the Create Release step | |
| printf "%s\n\n" "$SUMMARY" > /tmp/current-release-notes.md | |
| printf "%s" "$FULL_CHANGELOG" >> /tmp/current-release-notes.md | |
| echo "Release notes generated and appended to $NOTES_FILE" | |
| - name: Create Release | |
| run: | | |
| if gh release view "${{ inputs.revision }}" >/dev/null 2>&1; then | |
| echo "Release ${{ inputs.revision }} already exists, skipping." | |
| else | |
| gh release create ${{ inputs.revision }} \ | |
| --title "${{ inputs.revision }}" \ | |
| --notes-file /tmp/current-release-notes.md \ | |
| --latest | |
| fi | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Increment patch version | |
| run: | | |
| CURRENT="${{ inputs.revision }}" | |
| MAJOR=$(echo "$CURRENT" | cut -d. -f1) | |
| MINOR=$(echo "$CURRENT" | cut -d. -f2) | |
| PATCH=$(echo "$CURRENT" | cut -d. -f3) | |
| NEXT_PATCH=$((PATCH + 1)) | |
| NEXT_VERSION="${MAJOR}.${MINOR}.${NEXT_PATCH}-SNAPSHOT" | |
| sed -i "s|^\( *\)<revision>[^<]*</revision>|\1<revision>${NEXT_VERSION}</revision>|" pom.xml | |
| echo "Bumped version from ${CURRENT} to ${NEXT_VERSION}" | |
| - name: Commit and push next version | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add pom.xml release-notes.md | |
| git diff --cached --quiet && echo "No changes to commit" || \ | |
| git commit -m "chore: bump version to next patch after publishing ${{ inputs.revision }}" && git push | |
| - name: Merge release into main | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| if ! git checkout main; then | |
| echo "::error::Branch 'main' does not exist. Skipping merge." | |
| exit 1 | |
| fi | |
| if ! git merge --no-ff origin/release -m "chore: merge release into main [skip ci]"; then | |
| echo "::error::Merge conflict detected when merging release into main. Manual intervention required." | |
| exit 1 | |
| fi | |
| git push origin main |