Report EOL and maintenance status for Gradle versions

This commit is contained in:
Vlad Chesnokov
2026-08-26 12:38:45 +02:00
parent 346a44564f
commit dfc644bc4a
16 changed files with 423 additions and 31 deletions
@@ -6,6 +6,7 @@ import static org.junit.Assume.assumeTrue
class TestBuildResultRecorder extends BaseInitScriptTest {
def initScript = 'gradle-actions.build-result-capture.init.gradle'
String latestGradleMajor
def "produces build results file for build with #testGradleVersion"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
@@ -269,6 +270,63 @@ task expectFailure {
testGradleVersion << SETTINGS_PLUGIN_VERSIONS
}
def "captures version status '#expectedStatus' when the latest released major is #latestMajor"() {
assumeTrue GRADLE_8_X.compatibleWithCurrentJvm
when:
latestGradleMajor = latestMajor
run(GRADLE_8_X.gradleVersion)
then:
assertVersionStatus(expectedStatus)
where:
latestMajor | expectedStatus
'7' | 'active'
'8' | 'active'
'9' | 'maintenance'
'10' | 'eol'
'13' | 'eol'
}
def "captures version status for #testGradleVersion"() {
assumeTrue testGradleVersion.compatibleWithCurrentJvm
when:
latestGradleMajor = '9'
run(testGradleVersion.gradleVersion)
then:
assertVersionStatus(expectedStatus)
where:
testGradleVersion | expectedStatus
GRADLE_6_X | 'eol'
GRADLE_7_X | 'eol'
GRADLE_8_X | 'maintenance'
}
def "captures no version status when the action did not supply the latest released major"() {
assumeTrue GRADLE_8_X.compatibleWithCurrentJvm
when:
run(GRADLE_8_X.gradleVersion)
then:
assertVersionStatus(null)
}
def "captures no version status when the latest released major is not a number"() {
assumeTrue GRADLE_8_X.compatibleWithCurrentJvm
when:
latestGradleMajor = 'not-a-number'
run(GRADLE_8_X.gradleVersion)
then:
assertVersionStatus(null)
}
def run(def args = ['help'], def gradleVersion) {
return run(args, initScript, gradleVersion, jvmArgs, envVars)
}
@@ -278,17 +336,26 @@ task expectFailure {
}
def getJvmArgs() {
[
def jvmArgs = [
"-DRUNNER_TEMP=${testProjectDir.absolutePath}".toString(),
"-DGITHUB_ACTION=github-step-id".toString()
]
if (latestGradleMajor != null) {
jvmArgs << "-DGRADLE_ACTIONS_LATEST_GRADLE_MAJOR=${latestGradleMajor}".toString()
}
jvmArgs
}
def getEnvVars() {
[
def envVars = [
RUNNER_TEMP: testProjectDir.absolutePath,
GITHUB_ACTION: 'github-step-id'
GITHUB_ACTION: 'github-step-id',
GITHUB_OUTPUT: githubOutputFile.absolutePath
]
if (latestGradleMajor != null) {
envVars.GRADLE_ACTIONS_LATEST_GRADLE_MAJOR = latestGradleMajor
}
envVars
}
void assertResults(String task, TestGradleVersion testGradleVersion, boolean hasFailure, boolean configCacheHit = false) {
@@ -308,6 +375,24 @@ task expectFailure {
assert scanResults['buildScanFailed'] == scanUploadFailed
}
void assertVersionStatus(String expectedStatus) {
def results = new JsonSlurper().parse(buildResultFile)
assert results['versionStatus'] == expectedStatus
if (expectedStatus == null) {
assert !githubOutput.contains('gradle-version-status')
} else {
assert githubOutput.contains("gradle-version-status=${expectedStatus}")
}
}
private File getGithubOutputFile() {
new File(testProjectDir, 'github-output')
}
private String getGithubOutput() {
githubOutputFile.exists() ? githubOutputFile.text : ''
}
private File getBuildResultFile() {
def buildResultsDir = new File(testProjectDir, '.gradle-actions/build-results')
assert buildResultsDir.directory
@@ -0,0 +1,109 @@
import {beforeEach, describe, expect, it, jest} from '@jest/globals'
import {BuildResult} from '../../src/build-results'
// Mock @actions/core
const mockWarning = jest.fn<(message: string, properties?: {title?: string}) => void>()
const mockNotice = jest.fn<(message: string, properties?: {title?: string}) => void>()
const mockExportVariable = jest.fn<(name: string, value: string | number) => void>()
jest.unstable_mockModule('@actions/core', () => ({
warning: mockWarning,
notice: mockNotice,
exportVariable: mockExportVariable
}))
const {determineLatestReleasedMajor, exportLatestReleasedMajor, reportSupportStatus} =
await import('../../src/gradle-support-status')
function build(gradleVersion: string, versionStatus?: string): BuildResult {
return {gradleVersion, versionStatus} as BuildResult
}
describe('determineLatestReleasedMajor', () => {
it('ignores pre-releases and snapshots of an unreleased major', () => {
const versions = [
'10.0.0-milestone-1',
'10.0.0-rc-1',
'10.0.0-SNAPSHOT',
'10.0.0-20260101120000+0000',
'9.6.1',
'8.14'
]
expect(determineLatestReleasedMajor(versions)).toBe(9)
})
it('is unaffected by the ordering of the version list', () => {
expect(determineLatestReleasedMajor(['1.0', '9.0.0', '4.10.3'])).toBe(9)
})
it('is undefined when no final release is present', () => {
expect(determineLatestReleasedMajor(['9.0.0-rc-1', '10.0.0-SNAPSHOT'])).toBeUndefined()
})
it('is undefined for an empty version list', () => {
expect(determineLatestReleasedMajor([])).toBeUndefined()
})
})
describe('exportLatestReleasedMajor', () => {
it('exports the boundary the init script needs to classify the running version', () => {
exportLatestReleasedMajor()
expect(mockExportVariable).toHaveBeenCalledWith('GRADLE_ACTIONS_LATEST_GRADLE_MAJOR', expect.any(Number))
})
})
describe('reportSupportStatus', () => {
beforeEach(() => {
jest.clearAllMocks()
})
it('warns about a version recorded as end-of-life', () => {
reportSupportStatus([build('7.6.4', 'eol')])
expect(mockNotice).not.toHaveBeenCalled()
expect(mockWarning).toHaveBeenCalledTimes(1)
const [message, properties] = mockWarning.mock.calls[0]
expect(message).toContain('Gradle 7.6.4 has reached end-of-life')
expect(message).toContain('the 7.x release line')
expect(properties?.title).toBe('Gradle version at end-of-life')
})
it('notices a version recorded as maintenance-only', () => {
reportSupportStatus([build('8.14', 'maintenance')])
expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).toHaveBeenCalledTimes(1)
const [message, properties] = mockNotice.mock.calls[0]
expect(message).toContain('Gradle 8.14 is in maintenance-only support')
expect(properties?.title).toBe('Gradle version in maintenance')
})
it('says nothing about a version recorded as active', () => {
reportSupportStatus([build('9.6.1', 'active')])
expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).not.toHaveBeenCalled()
})
it('says nothing when the init script recorded no status', () => {
reportSupportStatus([build('7.6.4')])
expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).not.toHaveBeenCalled()
})
it('annotates each distinct version once', () => {
reportSupportStatus([build('7.6.4', 'eol'), build('4.10.3', 'eol'), build('7.6.4', 'eol')])
expect(mockWarning).toHaveBeenCalledTimes(2)
})
it('says nothing when no Gradle build ran', () => {
reportSupportStatus([])
expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).not.toHaveBeenCalled()
})
})