From cb9c9161651796d777f808ee98a12dd8895a485b Mon Sep 17 00:00:00 2001 From: Shihyu Ho Date: Mon, 18 May 2026 11:31:43 +0800 Subject: [PATCH] chore: migrate release-workflow to v2 (release-please) Replace the v1 two-stage flow (bump-version.yml + release.yml + Jenkinsfile-bump-version) with release-please. - add release-please.yml, commitlint.yml, .release-please-config.json, .release-please-manifest.json (manifest pinned to 3.2.2) - seed CHANGELOG.md; add AGENTS.md / CLAUDE.md commit-hygiene hint - bump pom to 3.2.3-SNAPSHOT across parent + mapper + starter - refactor Jenkinsfile-release: drop tagExists / Create Release / draft flip; add parameters{} block, read params.tag / params.ref - fix bump-spring.yml to mint a GitHub App token so its bot PR triggers commitlint and release-please - delete v1 files: bump-version.yml, release.yml, Jenkinsfile-bump-version Co-authored-by: Claude Opus 4.7 --- .github/workflows/bump-spring.yml | 9 +- .github/workflows/bump-version.yml | 82 ---------------- .github/workflows/commitlint.yml | 13 +++ .github/workflows/release-please.yml | 47 +++++++++ .github/workflows/release.yml | 40 -------- .release-please-config.json | 13 +++ .release-please-manifest.json | 3 + AGENTS.md | 10 ++ CHANGELOG.md | 3 + CLAUDE.md | 1 + Jenkinsfile-bump-version | 137 --------------------------- Jenkinsfile-release | 38 ++------ mapper/pom.xml | 2 +- pom.xml | 2 +- starter/pom.xml | 2 +- 15 files changed, 109 insertions(+), 293 deletions(-) delete mode 100644 .github/workflows/bump-version.yml create mode 100644 .github/workflows/commitlint.yml create mode 100644 .github/workflows/release-please.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .release-please-config.json create mode 100644 .release-please-manifest.json create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md delete mode 100644 Jenkinsfile-bump-version diff --git a/.github/workflows/bump-spring.yml b/.github/workflows/bump-spring.yml index 9993befd..bc6356fc 100644 --- a/.github/workflows/bump-spring.yml +++ b/.github/workflows/bump-spring.yml @@ -65,10 +65,17 @@ jobs: cache: 'maven' - name: Bump version run: make bump-spring-boot BOOT=${{ needs.latest-version.outputs.spring-boot }} + - name: Generate app token + id: app-token + uses: actions/create-github-app-token@v3 + with: + client-id: ${{ vars.CI_APP_CLIENT_ID }} + private-key: ${{ secrets.CI_APP_PRIVATE_KEY }} - name: Create Pull Request id: cpr uses: peter-evans/create-pull-request@v8 with: + token: ${{ steps.app-token.outputs.token }} commit-message: "chore: bump spring-boot from ${{ needs.current-version.outputs.spring-boot }} to ${{ needs.latest-version.outputs.spring-boot }}" title: "Bump spring-boot from ${{ needs.current-version.outputs.spring-boot }} to ${{ needs.latest-version.outputs.spring-boot }}" committer: bot πŸ‘Ύ @@ -83,7 +90,7 @@ jobs: if: steps.cpr.outputs.pull-request-operation == 'created' run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" env: - GH_TOKEN: ${{ github.token }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} keepalive: runs-on: ubuntu-latest permissions: diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml deleted file mode 100644 index c53a075b..00000000 --- a/.github/workflows/bump-version.yml +++ /dev/null @@ -1,82 +0,0 @@ -# specification-mapper ι€²η‰ˆ -name: Bump Version - -on: - workflow_dispatch: - inputs: - auto-bump: - type: choice - description: "Auto Bump" - default: "no" - options: - - "no" - - "patch" - - "minor" - version: - description: 'Version, required if "Auto Bump" = no' - type: string - -jobs: - auto-bump: - runs-on: ubuntu-latest - if: inputs.auto-bump != 'no' - steps: - - uses: actions/checkout@v6 - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - java-version: '17' - distribution: 'temurin' - cache: 'maven' - - id: get-current-version - run: echo "current_version=$(make version)" >> "$GITHUB_OUTPUT" - - id: bump - uses: "WyriHaximus/github-action-next-semvers@v1" - with: - version: ${{ steps.get-current-version.outputs.current_version }} - outputs: - bumped_version: ${{ steps.bump.outputs[inputs.auto-bump] }} - ensure-version-not-exists: - runs-on: ubuntu-latest - if: ${{ !failure() }} - needs: auto-bump - outputs: - final_version: ${{ steps.determine-version.outputs.final_version }} - steps: - - id: determine-version - env: - auto_bump_version: ${{needs.auto-bump.outputs.bumped_version}} - input_version: ${{inputs.version}} - run: | - if [[ -n "$auto_bump_version" ]]; then - echo "final_version=$auto_bump_version" >> "$GITHUB_OUTPUT" - elif [[ -n "$input_version" ]]; then - echo "final_version=$input_version" >> "$GITHUB_OUTPUT" - else - echo "Either select auto-bump or input version is required"; - exit 1; - fi - - id: check-version - uses: mukunku/tag-exists-action@v1.7.0 - with: - tag: '${{ steps.determine-version.outputs.final_version }}' - - id: fail-if-version-exists - run: | - if [ "${{ steps.check-version.outputs.exists }}" == "true" ]; then - echo "Version ${{ steps.determine-version.outputs.final_version }} already exists"; - exit 1; - fi - trigger-jenkins: - runs-on: ubuntu-latest - if: ${{ !failure() }} - needs: ensure-version-not-exists - steps: - - id: specification-mapper-bump-version - uses: shihyuho/go-jenkins-trigger@v2 - with: - jenkins-url: "${{ secrets.JENKINS_URL }}" - jenkins-user: "${{ secrets.JENKINS_USER }}" - jenkins-pat: "${{ secrets.JENKINS_PAT }}" - job: "${{ github.action }}" - params: "ref=${{ github.ref }},version=${{ needs.ensure-version-not-exists.outputs.final_version }},actor=${{ github.actor }}" - wait: false diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml new file mode 100644 index 00000000..c4b77924 --- /dev/null +++ b/.github/workflows/commitlint.yml @@ -0,0 +1,13 @@ +name: Commitlint +on: + pull_request: + branches: [jakarta] + +jobs: + commitlint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: wagoid/commitlint-github-action@v6 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..6dcaae92 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,47 @@ +# θ‡ͺε‹•η™Όθ‘Œ release: push to default branch β†’ release-please ι–‹ release PR β†’ δΊΊε·₯ merge +# β†’ θ‡ͺε‹• tag + GitHub Release β†’ trigger Jenkins build & deploy +name: Release Please + +on: + push: + branches: [jakarta] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + issues: write + +# εΊεˆ—εŒ–, ιΏε…ηŸ­ζ™‚ι–“ε€šζ¬‘ push ε°Žθ‡΄ι›™ι–‹ release PR / ι›™θ§Έη™Ό Jenkins +concurrency: + group: release-please-${{ github.ref }} + cancel-in-progress: false + +jobs: + release-please: + runs-on: ubuntu-latest + outputs: + release_created: ${{ steps.rp.outputs.release_created }} + tag_name: ${{ steps.rp.outputs.tag_name }} + sha: ${{ steps.rp.outputs.sha }} + steps: + - uses: googleapis/release-please-action@v5.0.0 + id: rp + with: + config-file: .release-please-config.json + manifest-file: .release-please-manifest.json + + trigger-jenkins: + runs-on: ubuntu-latest + needs: release-please + if: needs.release-please.outputs.release_created == 'true' + steps: + - id: specification-mapper-release + uses: shihyuho/go-jenkins-trigger@v2 + with: + jenkins-url: "${{ secrets.JENKINS_URL }}" + jenkins-user: "${{ secrets.JENKINS_USER }}" + jenkins-pat: "${{ secrets.JENKINS_PAT }}" + job: "${{ github.action }}" + params: "ref=${{ needs.release-please.outputs.sha }},tag=${{ needs.release-please.outputs.tag_name }}," + wait: false diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 7d61b491..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,40 +0,0 @@ -# η™Όδ½ˆη‰ˆζœ¬ -name: Publish a New Release - -on: - workflow_dispatch: - pull_request: - branches: - - jakarta - types: - - closed - -jobs: - get-version: - runs-on: ubuntu-latest - if: startsWith(github.head_ref, 'bot/bump-version') - steps: - - uses: actions/checkout@v6 - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - java-version: '17' - distribution: 'temurin' - cache: 'maven' - - id: get-version - run: echo "version=$(make version)" >> "$GITHUB_OUTPUT" - outputs: - version: ${{ steps.get-version.outputs.version }} - trigger-jenkins: - runs-on: ubuntu-latest - needs: get-version - steps: - - id: specification-mapper-release - uses: shihyuho/go-jenkins-trigger@v2 - with: - jenkins-url: "${{ secrets.JENKINS_URL }}" - jenkins-user: "${{ secrets.JENKINS_USER }}" - jenkins-pat: "${{ secrets.JENKINS_PAT }}" - job: "${{ github.action }}" - params: "ref=${{ github.sha }},tag=${{ needs.get-version.outputs.version }}," - wait: false diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 00000000..db994494 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "packages": { + ".": { + "release-type": "maven", + "package-name": "specification-mapper", + "changelog-path": "CHANGELOG.md", + "include-v-in-tag": false, + "include-component-in-tag": false, + "skip-snapshot": true + } + } +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..9fbc0cc0 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "3.2.2" +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..6cb80e6a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,10 @@ +## Commit hygiene + +CI runs commitlint (`@commitlint/config-conventional`) and blocks merge on violations. Run this right after every `git commit` to catch issues before push (no setup required, cross-platform): + +```bash +npx --yes -p @commitlint/cli -p @commitlint/config-conventional \ + commitlint --last --extends @commitlint/config-conventional +``` + +On failure, fix with `git commit --amend -m ""` and re-run β€” only before the commit is pushed (amending pushed commits is destructive). diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..300258bb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +All notable changes from 3.2.3 onward are tracked here. Releases prior to 3.2.3 lived only as GitHub Releases under the v1 (Bump Version β†’ Publish Release) flow. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..43c994c2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/Jenkinsfile-bump-version b/Jenkinsfile-bump-version deleted file mode 100644 index 81495f18..00000000 --- a/Jenkinsfile-bump-version +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env groovy - -currentBuild.description = "${version} -> ${ref}" -// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string -def semverPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ - -pipeline { - agent { - kubernetes { - cloud 'SLKE' - defaultContainer 'maven' - yaml """ -kind: Pod -spec: - # All containers should have the same UID - securityContext: - runAsUser: 0 - containers: - - name: maven - image: harbor.softleader.com.tw/library/maven:3-eclipse-temurin-17 - imagePullPolicy: Always - command: ['cat'] - tty: true - resources: - limits: - memory: "1Gi" - cpu: "2" - volumeMounts: - - name: m2 - mountPath: /root/.m2 - - name: git - image: harbor.softleader.com.tw/library/git:2 - imagePullPolicy: Always - command: ['cat'] - tty: true - resources: - limits: - memory: "100Mi" - cpu: "100m" - volumes: - - name: m2 - persistentVolumeClaim: - claimName: m2-claim -""" - } - } - - environment { - // 在 Jenkins δΈ­ System Configuration > Manage Credential - // ref: https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-secure-guide/injecting-secrets - CREDENTIAL = credentials("a84db61d-b4a4-4e05-a368-c1b283860090") - MAVEN_OPTS="-Xmx768m -XX:MaxMetaspaceSize=128m" - } - - stages { - - stage('Setup') { - steps { - script { - env.PR_BRANCH = "bot/bump-version-to-${version}" - } - container('git') { - script { - env.GIT_PATH = sh( - script: 'echo $GIT_URL | awk -F"github.com/" "{print \\\$2}"', - returnStdout: true - ).trim() - sh """ - git remote set-url origin https://$CREDENTIAL_USR:"$CREDENTIAL_PSW"@github.com/$GIT_PATH".git" - git config --global user.email "jenkins-bot@softleader.com.tw" - git config --global user.name "jenkins[bot]" - echo $CREDENTIAL_PSW | gh auth login --with-token - """ - } - } - sh 'printenv' - sh 'java -version' - sh 'mvn --version' - echo "${params}" - } - } - - stage ('Preflight Checks') { - steps { - script { - def isSemVer = ("${version}" ==~ semverPattern) - if (!isSemVer) { - error "Tag must matches semantic versioning 2 (https://semver.org/) but got: ${version}"; - } - } - sh "make format" - container('git') { - sh '[ ! -z "$(git status -s)" ] && echo "ζŽ’η‰ˆζͺ’ζŸ₯δΈι€šιŽ!" && exit 1 || echo "Good to go!"' - } - sh "make new-version VERSION=${version}" - container('git') { - sh '[ -z "$(git status -s)" ] && echo "η‰ˆζœ¬θ™Ÿζ²’η•°ε‹•ε–”! ζ˜―δΈζ˜―η”¨εˆ°ι‡θ€‡ηš„η‰ˆζœ¬θ™ŸδΊ†!?" && exit 1 || echo "Good to go!"' - } - } - } - - stage('Unit Testing') { - steps { - sh "make test" - } - post { - always { - junit "**/target/surefire-reports/**/*.xml" - } - } - } - - stage ('Bump New Version') { - steps { - container('git') { - sh """ - git checkout -b ${PR_BRANCH} - git commit -am "chore: bump version to ${version}" - git push --set-upstream origin ${PR_BRANCH} - gh pr create --base ${ref} --title "chore: bump version to ${version}" --body "Bump version to ${version} -> ${ref}" - gh pr merge ${PR_BRANCH} --merge --admin --delete-branch - """ - } - } - } - } - - post { - failure { - slackSend( - color: "danger", - channel: "@matt", - message: "Attention @here, The pipeline <$BUILD_URL|*${env.JOB_NAME} #${env.BUILD_NUMBER}*> has failed! :omg:" - ) - } - } -} diff --git a/Jenkinsfile-release b/Jenkinsfile-release index f73db4ed..cd073cbf 100644 --- a/Jenkinsfile-release +++ b/Jenkinsfile-release @@ -1,6 +1,6 @@ #!/usr/bin/env groovy -currentBuild.description = "${ref} -> ${tag}" +currentBuild.description = "${params.ref} -> ${params.tag}" // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string def semverPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/ @@ -49,6 +49,11 @@ spec: } } + parameters { + string(name: 'tag', defaultValue: '', description: 'Release tag, e.g. 3.2.3') + string(name: 'ref', defaultValue: '', description: 'Release commit SHA') + } + environment { // 在 Jenkins δΈ­ System Configuration > Manage Credential // ref: https://docs.cloudbees.com/docs/cloudbees-ci/latest/cloud-secure-guide/injecting-secrets @@ -85,31 +90,15 @@ spec: steps { container('git') { script { - def isSemVer = ("${tag}" ==~ semverPattern) + def isSemVer = ("${params.tag}" ==~ semverPattern) if (!isSemVer) { - error "Tag must matches semantic versioning 2 (https://semver.org/) but got: ${tag}"; - } - TAG_EXISTS = sh( - script: 'gh release view ${tag} --json name', - returnStatus: true - ) - def tagExists = ("${TAG_EXISTS}" == "0") - if (tagExists) { - error "Tag ${tag} already exists"; + error "Tag must matches semantic versioning 2 (https://semver.org/) but got: ${params.tag}"; } } } } } - stage ('Create Release') { - steps { - container('git') { - sh "gh release create ${tag} --target ${ref} --generate-notes --draft" - } - } - } - stage ('Publish Release') { steps { sh """ @@ -117,17 +106,6 @@ spec: make release """ } - post { - success { - script { - container('git') { - sh """ - gh release edit ${tag} --draft=false --latest - """ - } - } - } - } } } diff --git a/mapper/pom.xml b/mapper/pom.xml index c9939a05..243ec0d1 100644 --- a/mapper/pom.xml +++ b/mapper/pom.xml @@ -4,7 +4,7 @@ tw.com.softleader.data.jakarta specification-mapper-parent - 3.2.2 + 3.2.3-SNAPSHOT specification-mapper diff --git a/pom.xml b/pom.xml index 473b4eec..69630992 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ tw.com.softleader.data.jakarta specification-mapper-parent - 3.2.2 + 3.2.3-SNAPSHOT pom specification-mapper-parent diff --git a/starter/pom.xml b/starter/pom.xml index 4bff007b..097dc65c 100644 --- a/starter/pom.xml +++ b/starter/pom.xml @@ -4,7 +4,7 @@ tw.com.softleader.data.jakarta specification-mapper-parent - 3.2.2 + 3.2.3-SNAPSHOT specification-mapper-starter