Merge branch '4.0.x' into 4.1.x

This commit is contained in:
Phillip Webb
2026-08-20 15:27:07 -07:00
31 changed files with 691 additions and 400 deletions
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Community Support
url: https://stackoverflow.com/tags/spring-boot
about: Please ask and answer questions on StackOverflow with the tag `spring-boot`.
+37
View File
@@ -0,0 +1,37 @@
---
name: General
about: Bugs, enhancements, documentation, tasks.
title: ''
labels: ''
assignees: ''
---
<!--
Thanks for raising a Spring Boot issue. Please take the time to review the following
categories as some of them do not apply here.
🙅 "Please DO NOT Raise an Issue" Cases
- Question
STOP!! Please ask questions about how to use something, or to understand why something isn't
working as you expect it to, on Stack Overflow using the spring-boot tag.
- Security Vulnerability
STOP!! Please don't raise security vulnerabilities here. Head over to https://spring.io/security-policy to learn how to disclose them responsibly.
- Managed Dependency Upgrade
You DO NOT need to raise an issue for a managed dependency version upgrade as there's a semi-automatic process for checking managed dependencies for new versions before a release. BUT pull requests for upgrades that are more involved than just a version property change are still most welcome.
- With an Immediate Pull Request
An issue will be closed as a duplicate of the immediate pull request, so you don't have to raise an issue if you plan to create a pull request immediately.
🐞 Bug report (please don't include this emoji/text, just add your details)
Please provide details of the problem, including the version of Spring Boot that you
are using. If possible, please provide a test case or sample application that reproduces
the problem. This makes it much easier for us to diagnose the problem and to verify that
we have fixed it.
🎁 Enhancement (please don't include this emoji/text, just add your details)
Please start by describing the problem that you are trying to solve. There may already
be a solution, or there may be a way to solve it that you hadn't considered.
TIP: You can always edit your issue if it isn't formatted correctly.
See https://guides.github.com/features/mastering-markdown
-->
+29
View File
@@ -0,0 +1,29 @@
<!--
Thanks for contributing to Spring Boot. Please review the following notes before
submitting a pull request.
Please submit only genuine pull-requests. Do not use this repository as a GitHub
playground.
Security Vulnerabilities
STOP! If your contribution fixes a security vulnerability, please do not submit it.
Instead, please head over to https://spring.io/security-policy to learn how to disclose a
vulnerability responsibly.
Dependency Upgrades
Please do not open a pull request for a straightforward dependency upgrade (one that
only updates the version property). We have a semi-automated process for such upgrades
that we prefer to use. However, if the upgrade is more involved (such as requiring
changes for removed or deprecated API) your pull request is most welcome.
Describing Your Changes
If, having reviewed the notes above, you're ready to submit your pull request, please
provide a brief description of the proposed changes. If they fix a bug, please
describe the broken behaviour and how the changes fix it. If they make an enhancement,
please describe the new functionality and why you believe it's useful. If your pull
request relates to any existing issues, please reference them by using the issue number
prefixed with #.
-->
@@ -0,0 +1,20 @@
name: Await HTTP Resource
description: 'Waits for an HTTP resource to be available (a HEAD request succeeds)'
inputs:
url:
description: 'URL of the resource to await'
required: true
runs:
using: composite
steps:
- name: Await HTTP resource
shell: bash
run: |
url=${{ inputs.url }}
echo "Waiting for $url"
until curl --fail --head --silent ${{ inputs.url }} > /dev/null
do
echo "."
sleep 60
done
echo "$url is available"
@@ -0,0 +1,34 @@
name: Create GitHub Release
description: 'Create the release on GitHub with a changelog'
inputs:
commercial:
description: 'Whether to generate the changelog for the commercial release'
required: true
latest:
description: 'Whether the release is the latest release'
required: false
default: 'false'
milestone:
description: 'Name of the GitHub milestone for which a release will be created'
required: true
pre-release:
description: 'Whether the release is a pre-release (a milestone or release candidate)'
required: false
default: 'false'
token:
description: 'Token to use for authentication with GitHub'
required: true
runs:
using: composite
steps:
- name: Generate Changelog
uses: spring-io/github-changelog-generator@f7d7a87a3e7c627ecb8c26cf086c38ac5a939721 #v0.0.14
with:
config-file: ${{ inputs.commercial && '.github/actions/create-github-release/changelog-generator-commercial.yml' || '.github/actions/create-github-release/changelog-generator-oss.yml' }}
milestone: ${{ inputs.milestone }}
token: ${{ inputs.token }}
- name: Create GitHub Release
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.token }}
run: gh release create ${{ format('v{0}', inputs.milestone) }} --notes-file changelog.md ${{ inputs.pre-release == 'true' && '--prerelease' || format('--latest={0}', inputs.latest) }}
@@ -0,0 +1,30 @@
changelog:
sections:
- title: ":warning: Attention Required"
labels:
- "for: upgrade-attention"
summary:
mode: "member-comment"
config:
prefix: "Attention required:"
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
issues:
generate_links: false
ports:
- label: "status: forward-port"
bodyExpression: 'Forward port of issue #(\d+).*'
- label: "status: back-port"
bodyExpression: 'Back port of issue #(\d+).*'
@@ -0,0 +1,34 @@
changelog:
sections:
- title: ":warning: Attention Required"
labels:
- "for: upgrade-attention"
summary:
mode: "member-comment"
config:
prefix: "Attention required:"
- title: ":star: New Features"
labels:
- "type: enhancement"
- title: ":lady_beetle: Bug Fixes"
labels:
- "type: bug"
- "type: regression"
- title: ":notebook_with_decorative_cover: Documentation"
labels:
- "type: documentation"
- title: ":hammer: Dependency Upgrades"
sort: "title"
labels:
- "type: dependency-upgrade"
summary:
mode: "body-regex"
config:
expression: '(Upgrade to \[.*\]\(.*\)).*'
issues:
generate_links: true
ports:
- label: "status: forward-port"
bodyExpression: 'Forward port of issue #(\d+).*'
- label: "status: back-port"
bodyExpression: 'Back port of issue #(\d+).*'
@@ -0,0 +1,69 @@
name: Prepare Gradle Build
description: 'Prepares a Gradle build. Sets up Java and Gradle and configures Gradle properties'
inputs:
cache-read-only:
description: 'Whether Gradle''s cache should be read only'
required: false
default: 'true'
develocity-access-key:
description: 'Access key for authentication with ge.spring.io'
required: false
java-distribution:
description: 'Java distribution to use'
required: false
default: 'liberica'
java-early-access:
description: 'Whether the Java version is in early access. When true, forces java-distribution to temurin'
required: false
default: 'false'
java-toolchain:
description: 'Whether a Java toolchain should be used'
required: false
default: 'false'
java-version:
description: 'Java version to use for the build'
required: false
default: '25'
runs:
using: composite
steps:
- name: Free Disk Space
if: ${{ runner.os == 'Linux' }}
uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1
with:
tool-cache: true
docker-images: false
- name: Set Up Java
uses: actions/setup-java@v5
with:
distribution: ${{ inputs.java-early-access == 'true' && 'temurin' || (inputs.java-distribution || 'liberica') }}
java-version: |
${{ inputs.java-early-access == 'true' && format('{0}-ea', inputs.java-version) || inputs.java-version }}
${{ inputs.java-toolchain == 'true' && '25' || '' }}
- name: Set Up Gradle With Read/Write Cache
if: ${{ inputs.cache-read-only == 'false' }}
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic
cache-read-only: false
develocity-access-key: ${{ inputs.develocity-access-key }}
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic
develocity-access-key: ${{ inputs.develocity-access-key }}
develocity-token-expiry: 4
- name: Configure Gradle Properties
shell: bash
run: |
echo 'systemProp.user.name=spring-builds+github' >> $GRADLE_USER_HOME/gradle.properties
echo 'systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false' >> $GRADLE_USER_HOME/gradle.properties
echo 'org.gradle.daemon=false' >> $GRADLE_USER_HOME/gradle.properties
- name: Configure Toolchain Properties
if: ${{ inputs.java-toolchain == 'true' }}
shell: bash
run: |
echo toolchainVersion=${{ inputs.java-version }} >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.auto-detect=false >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.auto-download=false >> $GRADLE_USER_HOME/gradle.properties
echo systemProp.org.gradle.java.installations.paths=${{ format('$JAVA_HOME_{0}_X64', inputs.java-version) }} >> $GRADLE_USER_HOME/gradle.properties
@@ -0,0 +1,17 @@
name: Print JVM thread dumps
description: 'Prints a thread dump for all running JVMs'
runs:
using: composite
steps:
- if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
for jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem); do
jcmd $jvm_pid Thread.print
done
- if: ${{ runner.os == 'Windows' }}
shell: powershell
run: |
foreach ($jvm_pid in $(jps -q -J-XX:+PerfDisableSharedMem)) {
jcmd $jvm_pid Thread.print
}
@@ -0,0 +1,38 @@
name: Publish Gradle Plugin
description: 'Publishes Spring Boot''s Gradle plugin to the Plugin Portal'
inputs:
build-number:
description: 'Build number to use when downloading plugin artifacts'
required: false
default: ${{ github.run_number }}
gradle-plugin-publish-key:
description: 'Gradle publishing key'
required: true
gradle-plugin-publish-secret:
description: 'Gradle publishing secret'
required: true
jfrog-cli-config-token:
description: 'Config token for the JFrog CLI'
required: true
plugin-version:
description: 'Version of the plugin'
required: true
runs:
using: composite
steps:
- name: Set Up JFrog CLI
uses: jfrog/setup-jfrog-cli@deda456d982fc5e9a7a020b63eb0d2968aedd33e # v5.1.0
env:
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 }}'
- name: Set Up Java
uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: '17'
- name: Publish
shell: bash
working-directory: ${{ github.action_path }}
run: ${{ github.workspace }}/gradlew publishExisting -Pgradle.publish.key=${{ inputs.gradle-plugin-publish-key }} -Pgradle.publish.secret=${{ inputs.gradle-plugin-publish-secret }} -PbootVersion=${{ inputs.plugin-version }} -PrepositoryRoot=${{ github.workspace }}/repository
@@ -0,0 +1,20 @@
{
"files": [
{
"aql": {
"items.find": {
"$and": [
{
"@build.name": "${buildName}",
"@build.number": "${buildNumber}",
"path": {
"$match": "org/springframework/boot/spring-boot-gradle-plugin/*"
}
}
]
}
},
"target": "repository/"
}
]
}
@@ -0,0 +1,30 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id "com.gradle.plugin-publish" version "1.2.1"
}
tasks.register("publishExisting", com.gradle.publish.PublishExistingTask) {
pluginId = "org.springframework.boot"
fileRepositoryRoot = new File("${repositoryRoot}")
pluginVersion = "${bootVersion}"
pluginCoordinates = "org.springframework.boot:spring-boot-gradle-plugin:${bootVersion}"
displayName = "Spring Boot Gradle Plugin"
pluginDescription = "Spring Boot Gradle Plugin"
website = "https://spring.io/projects/spring-boot"
vcsUrl = "https://github.com/spring-projects/spring-boot"
}
@@ -0,0 +1,16 @@
/*
* Copyright 2012-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -0,0 +1,40 @@
name: Publish to SDKMAN!
description: 'Publishes the release as a new candidate version on SDKMAN!'
inputs:
make-default:
description: 'Whether the release should be made the default version'
required: false
default: 'false'
sdkman-consumer-key:
description: 'Key for publishing to SDKMAN!'
required: true
sdkman-consumer-token:
description: 'Token for publishing to SDKMAN!'
required: true
spring-boot-version:
description: 'Version to publish'
required: true
runs:
using: composite
steps:
- name: Publish Release
shell: bash
run: >
curl -X POST \
-H "Consumer-Key: ${{ inputs.sdkman-consumer-key }}" \
-H "Consumer-Token: ${{ inputs.sdkman-consumer-token }}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"candidate": "springboot", "version": "${{ inputs.spring-boot-version }}", "url": "${{ format('https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/{0}/spring-boot-cli-{0}-bin.zip', inputs.spring-boot-version) }}"}' \
https://vendors.sdkman.io/release
- name: Flag Release as Default
if: ${{ inputs.make-default == 'true' }}
shell: bash
run: >
curl -X PUT \
-H "Consumer-Key: ${{ inputs.sdkman-consumer-key }}" \
-H "Consumer-Token: ${{ inputs.sdkman-consumer-token }}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"candidate": "springboot", "version": "${{ inputs.spring-boot-version }}"}' \
https://vendors.sdkman.io/default
@@ -1,7 +0,0 @@
name: Build Release
runs:
using: composite
steps:
- name: Build Release
shell: bash
run: ./gradlew -PdeploymentRepository=$(pwd)/deployment-repository publishAllPublicationsToDeploymentRepository
@@ -1,7 +0,0 @@
name: Test Release
runs:
using: composite
steps:
- name: Test Release
shell: bash
run: ./gradlew build -x dockerTest -x reclaimDockerSpace
@@ -0,0 +1,39 @@
name: Send Notification
description: 'Sends a Google Chat message as a notification of the job''s outcome'
inputs:
build-scan-url:
description: 'URL of the build scan to include in the notification'
required: false
run-name:
description: 'Name of the run to include in the notification'
required: false
default: ${{ format('{0} {1}', github.ref_name, github.job) }}
status:
description: 'Status of the job'
required: true
webhook-url:
description: 'Google Chat Webhook URL'
required: true
runs:
using: composite
steps:
- name: Prepare Variables
shell: bash
run: |
echo "BUILD_SCAN=${{ inputs.build-scan-url == '' && ' [build scan unavailable]' || format(' [<{0}|Build Scan>]', inputs.build-scan-url) }}" >> "$GITHUB_ENV"
echo "RUN_URL=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> "$GITHUB_ENV"
- name: Success Notification
if: ${{ inputs.status == 'success' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was successful ${{ env.BUILD_SCAN }}"}' || true
- name: Failure Notification
if: ${{ inputs.status == 'failure' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<users/all> *<${{ env.RUN_URL }}|${{ inputs.run-name }}> failed* ${{ env.BUILD_SCAN }}"}' || true
- name: Cancel Notification
if: ${{ inputs.status == 'cancelled' }}
shell: bash
run: |
curl -X POST '${{ inputs.webhook-url }}' -H 'Content-Type: application/json' -d '{ text: "<${{ env.RUN_URL }}|${{ inputs.run-name }}> was cancelled"}' || true
@@ -0,0 +1,36 @@
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@deda456d982fc5e9a7a020b63eb0d2968aedd33e # v5.1.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) }}
@@ -0,0 +1,20 @@
{
"files": [
{
"aql": {
"items.find": {
"$and": [
{
"@build.name": "${buildName}",
"@build.number": "${buildNumber}",
"path": {
"$nmatch": "org/springframework/boot/spring-boot-docs/*"
}
}
]
}
},
"target": "nexus/"
}
]
}
@@ -0,0 +1,36 @@
name: Update Homebrew Tap
description: Updates the Homebrew Tap for the Spring Boot CLI
inputs:
spring-boot-version:
description: 'The version to publish'
required: true
token:
description: 'Token to use for GitHub authentication'
required: true
runs:
using: composite
steps:
- name: Check Out Homebrew Tap Repo
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: updated-homebrew-tap-repo
repository: spring-io/homebrew-tap
token: ${{ inputs.token }}
- name: Await Formula
uses: ./.github/actions/await-http-resource
with:
url: https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${{ inputs.spring-boot-version }}/spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb
- name: Update Homebrew Tap
shell: bash
run: |
pushd updated-homebrew-tap-repo > /dev/null
curl https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${{ inputs.spring-boot-version }}/spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb --output spring-boot-cli-${{ inputs.spring-boot-version }}-homebrew.rb
rm spring-boot.rb
mv spring-boot-cli-*.rb spring-boot.rb
git config user.name "Spring Builds" > /dev/null
git config user.email "spring-builds@users.noreply.github.com" > /dev/null
git add spring-boot.rb > /dev/null
git commit -m "Upgrade to Spring Boot ${{ inputs.spring-boot-version }}" > /dev/null
git push
echo "DONE"
popd > /dev/null
+2
View File
@@ -0,0 +1,2 @@
require:
members: false
+16
View File
@@ -0,0 +1,16 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "type: task"
- "status: waiting-for-triage"
- package-ecosystem: "npm"
directory: "/antora"
schedule:
interval: "weekly"
labels:
- "type: task"
- "status: waiting-for-triage"
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
echo "Reclaiming Docker Disk Space"
echo
docker image ls --format "{{.Size}} {{.ID}} {{.Repository}} {{.Tag}}" | LANG=en_US sort -rh | while read line; do
size=$( echo "$line" | cut -d' ' -f1 | sed -e 's/\.[0-9]*//' | sed -e 's/MB/000000/' | sed -e 's/GB/000000000/' )
image=$( echo "$line" | cut -d' ' -f2 )
repository=$( echo "$line" | cut -d' ' -f3 )
tag=$( echo "$line" | cut -d' ' -f4 )
echo "Considering $image $repository:$tag $size"
if [[ "$tag" =~ ^[a-f0-9]{32}$ ]]; then
echo "Ignoring GitHub action image $image $repository:$tag"
elif [[ "$tag" == "<none>" ]]; then
echo "Ignoring untagged image $image $repository:$tag"
elif [[ "$size" -lt 200000000 ]]; then
echo "Ignoring small image $image $repository:$tag"
else
echo "Cleaning $image $repository:$tag"
docker image rm $image
fi
done
echo "Finished cleanup, leaving the following containers:"
echo
docker image ls --format "{{.Size}} {{.ID}} {{.Repository}}:{{.Tag}}" | LANG=en_US sort -rh
echo
df -h
echo
-20
View File
@@ -1,20 +0,0 @@
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
-93
View File
@@ -1,93 +0,0 @@
# 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 }}
-55
View File
@@ -1,55 +0,0 @@
# 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
-46
View File
@@ -1,46 +0,0 @@
# 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
-47
View File
@@ -1,47 +0,0 @@
# 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
-34
View File
@@ -1,34 +0,0 @@
# 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 }}
-91
View File
@@ -1,91 +0,0 @@
# 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"
+94
View File
@@ -0,0 +1,94 @@
name: Verify
on:
workflow_call:
inputs:
staging:
description: 'Whether the release to verify is in the staging repository'
required: false
default: false
type: boolean
version:
description: 'Version to verify'
required: true
type: string
secrets:
commercial-repository-password:
description: 'Password for authentication with the commercial repository'
required: false
commercial-repository-username:
description: 'Username for authentication with the commercial repository'
required: false
google-chat-webhook-url:
description: 'Google Chat Webhook URL'
required: true
opensource-repository-password:
description: 'Password for authentication with the open-source repository'
required: false
opensource-repository-username:
description: 'Username for authentication with the open-source repository'
required: false
token:
description: 'Token to use for authentication with GitHub'
required: true
permissions:
contents: read
jobs:
verify:
name: Verify
runs-on: ${{ vars.UBUNTU_SMALL || 'ubuntu-latest' }}
steps:
- name: Check Out Release Verification Tests
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: 'v0.0.15'
repository: spring-projects/spring-boot-release-verification
token: ${{ secrets.token }}
- name: Check Out Send Notification Action
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: send-notification
sparse-checkout: .github/actions/send-notification
- name: Set Up Java
uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: 17
- name: Set Up Homebrew
if: ${{ !vars.COMMERCIAL }}
uses: Homebrew/actions/setup-homebrew@c8707045ccae42888fe98e86f2ee8938bc7cc193
with:
stable: true
- name: Set Up Gradle
uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0
with:
cache-provider: basic
cache-read-only: false
- name: Configure Gradle Properties
shell: bash
run: |
mkdir -p $HOME/.gradle
echo 'org.gradle.daemon=false' >> $HOME/.gradle/gradle.properties
- name: Run Release Verification Tests
env:
RVT_COMMERCIAL_REPOSITORY_PASSWORD: ${{ secrets.commercial-repository-password }}
RVT_COMMERCIAL_REPOSITORY_USERNAME: ${{ secrets.commercial-repository-username }}
RVT_OSS_REPOSITORY_PASSWORD: ${{ secrets.opensource-repository-password }}
RVT_OSS_REPOSITORY_USERNAME: ${{ secrets.opensource-repository-username }}
RVT_RELEASE_TYPE: ${{ vars.COMMERCIAL && 'commercial' || 'oss' }}
RVT_STAGING: ${{ inputs.staging }}
RVT_VERSION: ${{ inputs.version }}
HOMEBREW_NO_SANDBOX_LINUX: "1"
run: ./gradlew spring-boot-release-verification-tests:test
- name: Upload Build Reports on Failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: build-reports
path: '**/build/reports/'
- name: Send Notification
if: always()
uses: ./send-notification/.github/actions/send-notification
with:
run-name: ${{ format('{0} | Verification | {1}', github.ref_name, inputs.version) }}
status: ${{ job.status }}
webhook-url: ${{ secrets.google-chat-webhook-url }}