diff --git a/.github/actions/publish-gradle-plugin/action.yml b/.github/actions/publish-gradle-plugin/action.yml index 5707761dc5e..b0d006e5a4c 100644 --- a/.github/actions/publish-gradle-plugin/action.yml +++ b/.github/actions/publish-gradle-plugin/action.yml @@ -26,7 +26,7 @@ runs: JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - name: Download Artifacts shell: bash - run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-boot-{0}', inputs.plugin-version) }};buildNumber=${{ inputs.build-number }}' + run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-boot-{0}', inputs.plugin-version) }}' - name: Set Up Java uses: actions/setup-java@v6 with: diff --git a/.github/actions/publish-gradle-plugin/artifacts.spec b/.github/actions/publish-gradle-plugin/artifacts.spec index f84a25bb9b1..163a083f3ac 100644 --- a/.github/actions/publish-gradle-plugin/artifacts.spec +++ b/.github/actions/publish-gradle-plugin/artifacts.spec @@ -6,7 +6,6 @@ "$and": [ { "@build.name": "${buildName}", - "@build.number": "${buildNumber}", "path": { "$match": "org/springframework/boot/spring-boot-gradle-plugin/*" } diff --git a/.github/actions/release-train-build/action.yml b/.github/actions/release-train-build/action.yml new file mode 100644 index 00000000000..c67b712cb7d --- /dev/null +++ b/.github/actions/release-train-build/action.yml @@ -0,0 +1,7 @@ +name: Build Release +runs: + using: composite + steps: + - name: Build Release + shell: bash + run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository publishAllPublicationsToDeploymentRepository diff --git a/.github/actions/release-train-build/deployment-spec.yml b/.github/actions/release-train-build/deployment-spec.yml new file mode 100644 index 00000000000..69cbf8abd9d --- /dev/null +++ b/.github/actions/release-train-build/deployment-spec.yml @@ -0,0 +1,3 @@ +maven-central: + excludes: + - "org/springframework/boot/spring-boot-docs/**" diff --git a/.github/actions/release-train-test/action.yml b/.github/actions/release-train-test/action.yml new file mode 100644 index 00000000000..8351f7635c5 --- /dev/null +++ b/.github/actions/release-train-test/action.yml @@ -0,0 +1,7 @@ +name: Test Release +runs: + using: composite + steps: + - name: Test Release + shell: bash + run: ./gradlew build -x dockerTest -x reclaimDockerSpace diff --git a/.github/actions/sync-to-maven-central/action.yml b/.github/actions/sync-to-maven-central/action.yml deleted file mode 100644 index 2cf780c081d..00000000000 --- a/.github/actions/sync-to-maven-central/action.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Sync to Maven Central -description: 'Syncs a release to Maven Central and waits for it to be available for use' -inputs: - central-token-password: - description: 'Password for authentication with central.sonatype.com' - required: true - central-token-username: - description: 'Username for authentication with central.sonatype.com' - required: true - jfrog-cli-config-token: - description: 'Config token for the JFrog CLI' - required: true - spring-boot-version: - description: 'Version of Spring Boot that is being synced to Central' - required: true -runs: - using: composite - steps: - - name: Set Up JFrog CLI - uses: jfrog/setup-jfrog-cli@68c0efdc951dd2359bbbfa15c48bc67b3ae8e4d6 # v5.2.0 - env: - JF_ENV_SPRING: ${{ inputs.jfrog-cli-config-token }} - - name: Download Release Artifacts - shell: bash - run: jf rt download --spec ${{ format('{0}/artifacts.spec', github.action_path) }} --spec-vars 'buildName=${{ format('spring-boot-{0}', inputs.spring-boot-version) }};buildNumber=${{ github.run_number }}' - - name: Sync - uses: spring-io/central-publish-action@0c03960e9b16fdfe70e2443e1d5393cbc3a35622 # v0.3.0 - with: - token: ${{ inputs.central-token-password }} - token-name: ${{ inputs.central-token-username }} - ignore-already-exists-error: true - timeout: "90m" - - name: Await - uses: ./.github/actions/await-http-resource - with: - url: ${{ format('https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot/{0}/spring-boot-{0}.jar', inputs.spring-boot-version) }} diff --git a/.github/actions/sync-to-maven-central/artifacts.spec b/.github/actions/sync-to-maven-central/artifacts.spec deleted file mode 100644 index ee3d451af33..00000000000 --- a/.github/actions/sync-to-maven-central/artifacts.spec +++ /dev/null @@ -1,20 +0,0 @@ -{ - "files": [ - { - "aql": { - "items.find": { - "$and": [ - { - "@build.name": "${buildName}", - "@build.number": "${buildNumber}", - "path": { - "$nmatch": "org/springframework/boot/spring-boot-docs/*" - } - } - ] - } - }, - "target": "nexus/" - } - ] -} diff --git a/.github/workflow-generator.yml b/.github/workflow-generator.yml new file mode 100644 index 00000000000..d5159bac482 --- /dev/null +++ b/.github/workflow-generator.yml @@ -0,0 +1,20 @@ +workflow: + generator: + project: + java: + versions: + primary: 25 + workflows: + release-train: + build: + env: + COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL + COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME + COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD + test: + env: + COMMERCIAL_RELEASE_REPO_URL: vars.COMMERCIAL_RELEASE_REPO_URL + COMMERCIAL_REPO_USERNAME: secrets.COMMERCIAL_ARTIFACTORY_USERNAME + COMMERCIAL_REPO_PASSWORD: secrets.COMMERCIAL_ARTIFACTORY_PASSWORD + free-disk-space: true + runs-on: ubuntu22-4-16 diff --git a/.github/workflows/distribute.yml b/.github/workflows/distribute.yml deleted file mode 100644 index e8462178fe5..00000000000 --- a/.github/workflows/distribute.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Distribute -on: - workflow_dispatch: - inputs: - build-number: - description: 'Number of the build to use to create the bundle' - required: true - type: string - create-bundle: - description: 'Whether to create the bundle. If unchecked, only the bundle distribution is executed' - required: true - type: boolean - default: true - version: - description: 'Version to bundle and distribute' - required: true - type: string -permissions: - contents: read -jobs: - distribute-spring-enterprise-release-bundle: - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Create Bundle - if: ${{ vars.COMMERCIAL && inputs.create-bundle }} - shell: bash - run: | - curl -s -u "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}:${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}" \ - -X POST -H "X-JFrog-Signing-Key-Name: packagesKey" -H "Content-Type: application/json" \ - "https://usw1.packages.broadcom.com/lifecycle/api/v2/release_bundle?project=spring" \ - -d '{"release_bundle_name": "TNZ-spring-boot-commercial", "release_bundle_version": "${{ inputs.version }}", "skip_docker_manifest_resolution": true, "source_type": "builds", "source": {"builds": [ {"build_repository": "spring-build-info", "build_name": "spring-boot-commercial-${{ inputs.version }}", "build_number": "${{ inputs.build-number }}", "include_dependencies": false}]}}' | \ - jq -e 'if has("repository_key") then . else halt_error end' - - name: Sleep - if: ${{ vars.COMMERCIAL && inputs.create-bundle }} - shell: bash - run: sleep 30 - - name: Distribute Bundle - if: ${{ vars.COMMERCIAL }} - shell: bash - run: | - curl -s -u "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}:${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}" \ - -X POST -H "Content-Type: application/json" \ - "https://usw1.packages.broadcom.com/lifecycle/api/v2/distribution/distribute/TNZ-spring-boot-commercial/${{ inputs.version }}?project=spring" \ - -d '{"auto_create_missing_repositories": "false", "distribution_rules": [{"site_name": "JP-SaaS"}], "modifications": {"mappings": [{"input": "spring-enterprise-maven-prod-local/(.*)", "output": "spring-enterprise/$1"}]}}' | \ - jq -e 'if has("id") then . else halt_error end' diff --git a/.github/workflows/publicize-release.yml b/.github/workflows/publicize-release.yml new file mode 100644 index 00000000000..28a82c38b08 --- /dev/null +++ b/.github/workflows/publicize-release.yml @@ -0,0 +1,98 @@ +name: Publicize Release +on: + push: + tags: + - v4.1.[0-9]+ +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} +jobs: + read-version: + name: Read Version + runs-on: 'ubuntu-latest' + steps: + - name: Check Out Code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Read Version From gradle.properties + id: read-version + shell: bash + run: | + version=$(sed -n 's/version=\(.*\)/\1/p' gradle.properties) + echo "Version is $version" + echo "version=$version" >> $GITHUB_OUTPUT + outputs: + version: ${{ steps.read-version.outputs.version }} + publish-gradle-plugin: + name: Publish Gradle Plugin + if: ${{ !vars.COMMERCIAL }} + needs: + - read-version + runs-on: 'ubuntu-latest' + steps: + - name: Check Out Code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Publish + uses: ./.github/actions/publish-gradle-plugin + with: + build-number: '2026.4' + gradle-plugin-publish-key: ${{ secrets.GRADLE_PLUGIN_PUBLISH_KEY }} + gradle-plugin-publish-secret: ${{ secrets.GRADLE_PLUGIN_PUBLISH_SECRET }} + jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }} + plugin-version: ${{ needs.read-version.outputs.version }} + publish-to-sdkman: + name: Publish to SDKMAN! + needs: + - read-version + runs-on: 'ubuntu-latest' + steps: + - name: Check Out Code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Publish to SDKMAN! + uses: ./.github/actions/publish-to-sdkman + with: + make-default: false + sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }} + sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }} + spring-boot-version: ${{ needs.read-version.outputs.version }} + update-homebrew-tap: + name: Update Homebrew Tap + needs: + - read-version + runs-on: 'ubuntu-latest' + steps: + - name: Check Out Code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Update Homebrew Tap + uses: ./.github/actions/update-homebrew-tap + with: + spring-boot-version: ${{ needs.read-version.outputs.version }} + token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} + trigger-docs-build: + name: Trigger Docs Build + needs: + - read-version + permissions: + actions: write + runs-on: 'ubuntu-latest' + steps: + - name: Run Deploy Docs Workflow + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.read-version.outputs.version }} + create-github-release: + name: Create GitHub Release + needs: + - read-version + - publish-gradle-plugin + - publish-to-sdkman + - trigger-docs-build + - update-homebrew-tap + runs-on: 'ubuntu-latest' + steps: + - name: Check Out Code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Create GitHub Release + uses: ./.github/actions/create-github-release + with: + commercial: ${{ vars.COMMERCIAL }} + milestone: ${{ needs.read-version.outputs.version }} + token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release-milestone.yml b/.github/workflows/release-milestone.yml deleted file mode 100644 index 485e93aeece..00000000000 --- a/.github/workflows/release-milestone.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Release Milestone -on: - push: - tags: - - v4.1.0-M[0-9] - - v4.1.0-RC[0-9] -permissions: - contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} -jobs: - build-and-stage-release: - name: Build and Stage Release - if: ${{ github.repository == 'spring-projects/spring-boot' }} - runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Build and Publish - id: build-and-publish - uses: ./.github/actions/build - with: - develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - gradle-cache-read-only: false - publish: true - - name: Stage Release - uses: spring-io/artifactory-deploy-action@9cb1c7df78cd8d1223de1dde974819fa6378af9f # v0.0.6 - with: - build-name: ${{ format('spring-boot-{0}', steps.build-and-publish.outputs.version)}} - folder: 'deployment-repository' - password: ${{ secrets.ARTIFACTORY_PASSWORD }} - repository: 'libs-staging-local' - signing-key: ${{ secrets.GPG_PRIVATE_KEY }} - signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} - threads: 8 - uri: 'https://repo.spring.io' - username: ${{ secrets.ARTIFACTORY_USERNAME }} - outputs: - version: ${{ steps.build-and-publish.outputs.version }} - verify: - name: Verify - needs: build-and-stage-release - uses: ./.github/workflows/verify.yml - secrets: - commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_PASSWORD }} - commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_RO_USERNAME }} - google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }} - opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }} - opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }} - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - with: - staging: true - version: ${{ needs.build-and-stage-release.outputs.version }} - sync-to-maven-central: - name: Sync to Maven Central - if: ${{ !vars.COMMERCIAL }} - needs: - - build-and-stage-release - - verify - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Sync to Maven Central - uses: ./.github/actions/sync-to-maven-central - with: - central-token-password: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} - central-token-username: ${{ secrets.CENTRAL_TOKEN_USERNAME }} - jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }} - spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }} - promote-release: - name: Promote Release - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Set up JFrog CLI - uses: jfrog/setup-jfrog-cli@68c0efdc951dd2359bbbfa15c48bc67b3ae8e4d6 # v5.2.0 - env: - JF_ENV_SPRING: ${{ secrets.JF_ARTIFACTORY_SPRING }} - - name: Promote build - run: jfrog rt build-promote ${{ format('spring-boot-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-milestone-local - publish-gradle-plugin: - name: Publish Gradle Plugin - if: ${{ !vars.COMMERCIAL }} - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Publish - uses: ./.github/actions/publish-gradle-plugin - with: - gradle-plugin-publish-key: ${{ secrets.GRADLE_PLUGIN_PUBLISH_KEY }} - gradle-plugin-publish-secret: ${{ secrets.GRADLE_PLUGIN_PUBLISH_SECRET }} - jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }} - plugin-version: ${{ needs.build-and-stage-release.outputs.version }} - trigger-docs-build: - name: Trigger Docs Build - needs: - - build-and-stage-release - - promote-release - permissions: - actions: write - runs-on: ubuntu-latest - steps: - - name: Run Deploy Docs Workflow - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-stage-release.outputs.version }} - create-github-release: - name: Create GitHub Release - needs: - - build-and-stage-release - - promote-release - - publish-gradle-plugin - - trigger-docs-build - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Create GitHub Release - uses: ./.github/actions/create-github-release - with: - commercial: ${{ vars.COMMERCIAL }} - milestone: ${{ needs.build-and-stage-release.outputs.version }} - pre-release: true - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} diff --git a/.github/workflows/release-train-build.yml b/.github/workflows/release-train-build.yml new file mode 100644 index 00000000000..e2789a7dc1c --- /dev/null +++ b/.github/workflows/release-train-build.yml @@ -0,0 +1,93 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Build" +run-name: "${{ inputs.callback-ref }} – Build" +"on": + workflow_dispatch: + inputs: + callback: + description: "Repository to which a callback should be made upon completion" + required: true + type: "string" + callback-ref: + description: "Ref in the callback repository to which a callback should be made upon completion" + required: true + type: "string" + release-train-maven-repository-url: + description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train" + required: true + type: "string" +permissions: + contents: "read" +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" +jobs: + build-release: + name: "Build Release" + runs-on: "ubuntu22-2-8" + steps: + - name: "Prevent Re-runs" + id: "prevent-re-runs" + run: |- + if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then + echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry build failures" + exit 1 + fi + - name: "Set up Java" + id: "set-up-java" + uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0 + with: + distribution: "liberica" + java-version: "25" + - name: "Check Out Code" + id: "check-out-code" + uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: "Build Release" + id: "build-release" + uses: "./.github/actions/release-train-build" + env: + COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}" + COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}" + COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}" + - name: "Upload Deployment Repository" + id: "upload-deployment-repository" + uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1 + with: + name: "deployment-repository" + path: "deployment-repository/**" + - name: "Upload Deployment Spec" + id: "upload-deployment-spec" + uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1 + with: + archive: "false" + if-no-files-found: "ignore" + name: "deployment-spec" + path: ".github/actions/release-train-build/deployment-spec.yml" + - name: "Save Build System Caches" + id: "save-build-system-caches" + uses: "actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0 + with: + key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}" + path: |- + ~/.gradle/caches + ~/.gradle/wrapper + - name: "Send Callback" + id: "send-callback" + if: "${{ !cancelled() }}" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + gh workflow run callback \ + --repo ${{ inputs.callback }} \ + --ref ${{ inputs.callback-ref }} \ + --field commit-hash=${{ steps.check-out-code.outputs.commit }} \ + --field deployment-repository-artifact-identifier=${{ steps.upload-deployment-repository.outputs.artifact-id }} \ + --field deployment-spec-artifact-identifier=${{ steps.upload-deployment-spec.outputs.artifact-id }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} \ + --field result=${{ job.status == 'success' && 'built' || 'build-failed' }} \ + --field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/release-train-join.yml b/.github/workflows/release-train-join.yml new file mode 100644 index 00000000000..729914b3f90 --- /dev/null +++ b/.github/workflows/release-train-join.yml @@ -0,0 +1,55 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Join" +run-name: "${{ inputs.release-train }} – Join" +"on": + workflow_dispatch: + inputs: + deployment-destination: + description: "Destination to which the release should be deployed" + options: + - "Maven Central" + - "Spring Enterprise" + required: true + type: "choice" + release-train: + description: "Release train" + required: true + type: "string" + release-train-repository: + default: "spring-io/release-train" + description: "Release train repository" + required: true + type: "string" +permissions: + contents: "none" +jobs: + join-release-train: + name: "Join Release Train" + runs-on: "ubuntu-latest" + steps: + - name: "Join Release Train" + id: "join-release-train" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + run_url=$( + gh workflow run join \ + --repo ${{ inputs.release-train-repository }} \ + --ref ${{ inputs.release-train }} \ + --field commit-hash=${{ github.sha }} \ + --field deployment-destination=${{ inputs.deployment-destination == 'Maven Central' && 'maven-central' || 'spring-enterprise' }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} + ) + echo "Dispatched workflow run. Waiting for $run_url to complete." + run_id=${run_url##*/} + watch_exit_code=0 + gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$? + if [[ $watch_exit_code -eq 0 ]]; then + echo "Workflow run succeeded." + else + echo "Workflow run failed." + fi + exit $watch_exit_code diff --git a/.github/workflows/release-train-leave.yml b/.github/workflows/release-train-leave.yml new file mode 100644 index 00000000000..bc0be6711a7 --- /dev/null +++ b/.github/workflows/release-train-leave.yml @@ -0,0 +1,46 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Leave" +run-name: "${{ inputs.release-train }} – Leave" +"on": + workflow_dispatch: + inputs: + release-train: + description: "Release train" + required: true + type: "string" + release-train-repository: + default: "spring-io/release-train" + description: "Release train repository" + required: true + type: "string" +permissions: + contents: "none" +jobs: + leave: + name: "Leave" + runs-on: "ubuntu-latest" + steps: + - name: "Leave" + id: "leave" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + run_url=$( + gh workflow run leave \ + --repo ${{ inputs.release-train-repository }} \ + --ref ${{ inputs.release-train }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} + ) + echo "Dispatched workflow run. Waiting for $run_url to complete." + run_id=${run_url##*/} + watch_exit_code=0 + gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$? + if [[ $watch_exit_code -eq 0 ]]; then + echo "Workflow run succeeded." + else + echo "Workflow run failed." + fi + exit $watch_exit_code diff --git a/.github/workflows/release-train-ready.yml b/.github/workflows/release-train-ready.yml new file mode 100644 index 00000000000..794a29a6292 --- /dev/null +++ b/.github/workflows/release-train-ready.yml @@ -0,0 +1,47 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Ready" +run-name: "${{ inputs.release-train }} – Ready" +"on": + workflow_dispatch: + inputs: + release-train: + description: "Release train" + required: true + type: "string" + release-train-repository: + default: "spring-io/release-train" + description: "Release train repository" + required: true + type: "string" +permissions: + contents: "none" +jobs: + ready: + name: "Ready" + runs-on: "ubuntu-latest" + steps: + - name: "Ready" + id: "ready" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + run_url=$( + gh workflow run ready \ + --repo ${{ inputs.release-train-repository }} \ + --ref ${{ inputs.release-train }} \ + --field commit-hash=${{ github.sha }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} + ) + echo "Dispatched workflow run. Waiting for $run_url to complete." + run_id=${run_url##*/} + watch_exit_code=0 + gh run watch $run_id --repo ${{ inputs.release-train-repository }} --exit-status --interval=3 > /dev/null 2>&1 || watch_exit_code=$? + if [[ $watch_exit_code -eq 0 ]]; then + echo "Workflow run succeeded." + else + echo "Workflow run failed." + fi + exit $watch_exit_code diff --git a/.github/workflows/release-train-retry.yml b/.github/workflows/release-train-retry.yml new file mode 100644 index 00000000000..539ccfd2504 --- /dev/null +++ b/.github/workflows/release-train-retry.yml @@ -0,0 +1,34 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Retry" +run-name: "${{ inputs.release-train }} – Retry" +"on": + workflow_dispatch: + inputs: + release-train: + description: "Release train" + required: true + type: "string" + release-train-repository: + default: "spring-io/release-train" + description: "Release train repository" + required: true + type: "string" +permissions: + contents: "none" +jobs: + trigger-retry: + name: "Trigger Retry" + runs-on: "ubuntu-latest" + steps: + - name: "Trigger Retry" + id: "trigger-retry" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + gh workflow run retry \ + --repo ${{ inputs.release-train-repository }} \ + --ref ${{ inputs.release-train }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} diff --git a/.github/workflows/release-train-test.yml b/.github/workflows/release-train-test.yml new file mode 100644 index 00000000000..b10767ae6e2 --- /dev/null +++ b/.github/workflows/release-train-test.yml @@ -0,0 +1,91 @@ +# This file was auto-generated by github-actions-workflow-generator 0.0.6. Do not edit. +# To update it, modify .github/workflow-generator.yml as needed and re-run the generator. + +name: "Release Train – Test" +run-name: "${{ inputs.callback-ref }} – Test" +"on": + workflow_dispatch: + inputs: + callback: + description: "Repository to which a callback should be made upon completion" + required: true + type: "string" + callback-ref: + description: "Ref in the callback repository to which a callback should be made upon completion" + required: true + type: "string" + release-train-maven-repository-url: + description: "URL of a Maven repository to be used to resolve artifacts of projects earlier in the train" + required: true + type: "string" +permissions: + contents: "read" +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" +jobs: + test-release: + name: "Test Release" + runs-on: "ubuntu22-4-16" + steps: + - name: "Prevent Re-runs" + id: "prevent-re-runs" + run: |- + if [ "$GITHUB_RUN_ATTEMPT" -gt 1 ]; then + echo "Re-runs are prohibited. Use the 'Release Train – Retry' workflow to retry test failures" + exit 1 + fi + - name: "Free Disk Space" + id: "free-disk-space" + if: "${{ runner.os == 'Linux' }}" + uses: "jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be" # v1.3.1 + with: + docker-images: "false" + tool-cache: "true" + - name: "Set up Java" + id: "set-up-java" + uses: "actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95" # v5.6.0 + with: + distribution: "liberica" + java-version: "25" + - name: "Check Out Code" + id: "check-out-code" + uses: "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0" # v7.0.0 + - name: "Restore Build System Caches" + id: "restore-build-system-caches" + uses: "actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9" # v6.1.0 + with: + key: "release-train-${{ inputs.callback-ref }}-${{ github.ref_name }}" + path: |- + ~/.gradle/caches + ~/.gradle/wrapper + - name: "Test Release" + id: "test-release" + uses: "./.github/actions/release-train-test" + env: + COMMERCIAL_RELEASE_REPO_URL: "${{ vars.COMMERCIAL_RELEASE_REPO_URL }}" + COMMERCIAL_REPO_PASSWORD: "${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}" + COMMERCIAL_REPO_USERNAME: "${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_PASSWORD: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_PASSWORD }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_URL: "${{ inputs.release-train-maven-repository-url }}" + RELEASE_TRAIN_MAVEN_REPOSITORY_USERNAME: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_MAVEN_REPOSITORY_USERNAME }}" + - name: "Send Callback" + id: "send-callback" + if: "${{ !cancelled() }}" + env: + GH_TOKEN: "${{ secrets.RELEASE_TRAIN_PARTICIPANT_GITHUB_TOKEN }}" + run: |- + gh workflow run callback \ + --repo ${{ inputs.callback }} \ + --ref ${{ inputs.callback-ref }} \ + --field commit-hash=${{ steps.check-out-code.outputs.commit }} \ + --field release-branch=${{ github.ref_name }} \ + --field release-repository=${{ github.repository }} \ + --field result=${{ job.status == 'success' && 'tested' || 'test-failed' }} \ + --field workflow-run-url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + - name: "Upload Build System Reports" + id: "upload-build-system-reports" + if: "${{ failure() }}" + uses: "actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" # v7.0.1 + with: + name: "build-system-reports" + path: "**/build/reports" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1c29dbaeaf8..00000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,179 +0,0 @@ -name: Release -on: - push: - tags: - - v4.1.[0-9]+ -permissions: - contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} -jobs: - build-and-stage-release: - name: Build and Stage Release - if: ${{ github.repository == 'spring-projects/spring-boot' || github.repository == 'spring-projects/spring-boot-commercial' }} - runs-on: ${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Build and Publish - id: build-and-publish - uses: ./.github/actions/build - with: - commercial-release-repository-url: ${{ vars.COMMERCIAL_RELEASE_REPO_URL }} - commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }} - commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }} - commercial-snapshot-repository-url: ${{ vars.COMMERCIAL_SNAPSHOT_REPO_URL }} - develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - gradle-cache-read-only: false - publish: true - - name: Stage Release - uses: spring-io/artifactory-deploy-action@9cb1c7df78cd8d1223de1dde974819fa6378af9f # v0.0.6 - with: - build-name: ${{ vars.COMMERCIAL && format('spring-boot-commercial-{0}', steps.build-and-publish.outputs.version) || format('spring-boot-{0}', steps.build-and-publish.outputs.version) }} - folder: 'deployment-repository' - password: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_PASSWORD }} - project: ${{ vars.COMMERCIAL && 'spring' }} - repository: ${{ vars.COMMERCIAL && 'spring-enterprise-maven-stage-local' || 'libs-staging-local' }} - signing-key: ${{ secrets.GPG_PRIVATE_KEY }} - signing-passphrase: ${{ secrets.GPG_PASSPHRASE }} - threads: 8 - uri: ${{ vars.COMMERCIAL_DEPLOY_REPO_URL || 'https://repo.spring.io' }} - username: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_USERNAME }} - - name: Send Notification - if: failure() - uses: ./.github/actions/send-notification - with: - run-name: ${{ format('{0} | Release Staging | {1}', github.ref_name, inputs.version) }} - status: ${{ job.status }} - webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }} - outputs: - version: ${{ steps.build-and-publish.outputs.version }} - verify: - name: Verify - needs: build-and-stage-release - uses: ./.github/workflows/verify.yml - secrets: - commercial-repository-password: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }} - commercial-repository-username: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }} - google-chat-webhook-url: ${{ secrets.GOOGLE_CHAT_WEBHOOK_URL }} - opensource-repository-password: ${{ secrets.ARTIFACTORY_PASSWORD }} - opensource-repository-username: ${{ secrets.ARTIFACTORY_USERNAME }} - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - with: - staging: true - version: ${{ needs.build-and-stage-release.outputs.version }} - sync-to-maven-central: - name: Sync to Maven Central - if: ${{ !vars.COMMERCIAL }} - needs: - - build-and-stage-release - - verify - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Sync to Maven Central - uses: ./.github/actions/sync-to-maven-central - with: - central-token-password: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} - central-token-username: ${{ secrets.CENTRAL_TOKEN_USERNAME }} - jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }} - spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }} - promote-release: - name: Promote Release - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Set up JFrog CLI - uses: jfrog/setup-jfrog-cli@68c0efdc951dd2359bbbfa15c48bc67b3ae8e4d6 # v5.2.0 - env: - JF_ENV_SPRING: ${{ vars.COMMERCIAL && secrets.COMMERCIAL_JF_ARTIFACTORY_SPRING || secrets.JF_ARTIFACTORY_SPRING }} - - name: Promote open source build - if: ${{ !vars.COMMERCIAL }} - run: jfrog rt build-promote ${{ format('spring-boot-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} libs-release-local - - name: Promote commercial build - if: ${{ vars.COMMERCIAL }} - run: jfrog rt build-promote ${{ format('spring-boot-commercial-{0}', needs.build-and-stage-release.outputs.version)}} ${{ github.run_number }} spring-enterprise-maven-prod-local --project spring - publish-gradle-plugin: - name: Publish Gradle Plugin - if: ${{ !vars.COMMERCIAL }} - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Publish - uses: ./.github/actions/publish-gradle-plugin - with: - gradle-plugin-publish-key: ${{ secrets.GRADLE_PLUGIN_PUBLISH_KEY }} - gradle-plugin-publish-secret: ${{ secrets.GRADLE_PLUGIN_PUBLISH_SECRET }} - jfrog-cli-config-token: ${{ secrets.JF_ARTIFACTORY_SPRING }} - plugin-version: ${{ needs.build-and-stage-release.outputs.version }} - publish-to-sdkman: - name: Publish to SDKMAN! - if: ${{ !vars.COMMERCIAL }} - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Publish to SDKMAN! - uses: ./.github/actions/publish-to-sdkman - with: - make-default: true - sdkman-consumer-key: ${{ secrets.SDKMAN_CONSUMER_KEY }} - sdkman-consumer-token: ${{ secrets.SDKMAN_CONSUMER_TOKEN }} - spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }} - update-homebrew-tap: - name: Update Homebrew Tap - needs: - - build-and-stage-release - - sync-to-maven-central - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Update Homebrew Tap - uses: ./.github/actions/update-homebrew-tap - with: - spring-boot-version: ${{ needs.build-and-stage-release.outputs.version }} - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }} - trigger-docs-build: - name: Trigger Docs Build - needs: - - build-and-stage-release - - promote-release - permissions: - actions: write - runs-on: ubuntu-latest - steps: - - name: Run Deploy Docs Workflow - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh workflow run deploy-docs.yml --repo ${{ github.repository }} -r docs-build -f build-refname=${{ github.ref_name }} -f build-version=${{ needs.build-and-stage-release.outputs.version }} - create-github-release: - name: Create GitHub Release - needs: - - build-and-stage-release - - promote-release - - publish-gradle-plugin - - publish-to-sdkman - - trigger-docs-build - - update-homebrew-tap - runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }} - steps: - - name: Check Out Code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Create GitHub Release - uses: ./.github/actions/create-github-release - with: - commercial: ${{ vars.COMMERCIAL }} - latest: true - milestone: ${{ needs.build-and-stage-release.outputs.version }} - token: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}