Report patches available for version

This commit is contained in:
Vlad Chesnokov
2026-08-26 15:46:04 +02:00
parent b24d6c9b7e
commit a9692ad11b
5 changed files with 220 additions and 84 deletions
@@ -22,6 +22,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
maintenance-version: ${{ steps.maintenance-version.outputs.version }} maintenance-version: ${{ steps.maintenance-version.outputs.version }}
patch-version: ${{ steps.patch-version.outputs.version }}
newer-patch: ${{ steps.patch-version.outputs.newer }}
steps: steps:
- name: Checkout sources - name: Checkout sources
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -39,6 +41,27 @@ jobs:
echo "Newest release in the maintenance-only line: $version" echo "Newest release in the maintenance-only line: $version"
echo "version=$version" >> "$GITHUB_OUTPUT" echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Determine a version with a newer patch available
id: patch-version
run: |
read -r version newer <<<"$(jq -r '
[.[].version | select(test("^[0-9]+\\.[0-9]+(\\.[0-9]+)?$"))] as $finals
| ($finals | map(split(".")[0] | tonumber) | max) as $latest
| [$finals[] | select((split(".")[0] | tonumber) == $latest)]
| group_by(split(".")[0:2] | join("."))
| map(sort_by(split(".") | if length > 2 then (.[2] | tonumber) else 0 end) | reverse)
| map(select(length > 1))
| first
| if . then "\(.[1]) \(.[0])" else empty end
' sources/src/wrapper-validation/wrapper-checksums.json)"
if [ -z "${version:-}" ]; then
echo "No release line in the current major has more than one release: skipping the patch case"
else
echo "Gradle ${version} is superseded by ${newer}"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "newer=${newer}" >> "$GITHUB_OUTPUT"
fi
- name: Setup Gradle with an end-of-life version - name: Setup Gradle with an end-of-life version
uses: ./setup-gradle uses: ./setup-gradle
with: with:
@@ -57,6 +80,16 @@ jobs:
working-directory: .github/workflow-samples/no-wrapper working-directory: .github/workflow-samples/no-wrapper
run: gradle help "-DgradleVersionCheck=${{ steps.maintenance-version.outputs.version }}" run: gradle help "-DgradleVersionCheck=${{ steps.maintenance-version.outputs.version }}"
- name: Setup Gradle with a version that has a newer patch
if: ${{ steps.patch-version.outputs.version != '' }}
uses: ./setup-gradle
with:
gradle-version: ${{ steps.patch-version.outputs.version }}
- name: Build with the version that has a newer patch
if: ${{ steps.patch-version.outputs.version != '' }}
working-directory: .github/workflow-samples/no-wrapper
run: gradle help "-DgradleVersionCheck=${{ steps.patch-version.outputs.version }}"
verify-annotations: verify-annotations:
needs: report-outdated-versions needs: report-outdated-versions
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -68,6 +101,8 @@ jobs:
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
MAINTENANCE_VERSION: ${{ needs.report-outdated-versions.outputs.maintenance-version }} MAINTENANCE_VERSION: ${{ needs.report-outdated-versions.outputs.maintenance-version }}
PATCH_VERSION: ${{ needs.report-outdated-versions.outputs.patch-version }}
NEWER_PATCH: ${{ needs.report-outdated-versions.outputs.newer-patch }}
run: | run: |
set -euo pipefail set -euo pipefail
@@ -92,3 +127,6 @@ jobs:
assert_logged "##[warning]Gradle 7.6.4 has reached end-of-life" assert_logged "##[warning]Gradle 7.6.4 has reached end-of-life"
assert_logged "##[notice]Gradle ${MAINTENANCE_VERSION} is in maintenance-only support" assert_logged "##[notice]Gradle ${MAINTENANCE_VERSION} is in maintenance-only support"
if [ -n "${PATCH_VERSION}" ]; then
assert_logged "##[notice]Gradle ${PATCH_VERSION} is not the latest patch release: Gradle ${NEWER_PATCH} is available"
fi
+91 -22
View File
@@ -1,60 +1,129 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as semver from 'semver'
import {GradleVersion} from './execution/gradle-version' import {GradleVersion} from './execution/gradle-version'
import wrapperChecksums from './wrapper-validation/wrapper-checksums.json' import wrapperChecksums from './wrapper-validation/wrapper-checksums.json'
const FEATURE_LIFECYCLE_DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support' const FEATURE_LIFECYCLE_DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support'
const LATEST_RELEASED_MAJOR = determineLatestReleasedMajor(wrapperChecksums.map(entry => entry.version)) const RELEASED_VERSIONS = wrapperChecksums
.map(entry => entry.version)
.filter(version => new GradleVersion(version).isFinalRelease())
export type SupportStatus = 'active' | 'maintenance' | 'eol' const LATEST_RELEASED_MAJOR = determineLatestReleasedMajor(RELEASED_VERSIONS)
export function determineLatestReleasedMajor(versions: string[]): number | undefined { const LATEST_PATCHES = latestPatchByMinorLine(RELEASED_VERSIONS)
export enum SupportStatusKind {
Active = 'active',
Maintenance = 'maintenance',
Eol = 'eol',
PatchAvailable = 'patch-available'
}
export type SupportStatus =
| {kind: SupportStatusKind.Active}
| {kind: SupportStatusKind.Maintenance}
| {kind: SupportStatusKind.Eol}
| {kind: SupportStatusKind.PatchAvailable; newerPatch: string}
function determineLatestReleasedMajor(versions: string[]): number {
const releasedMajors = versions const releasedMajors = versions
.map(version => new GradleVersion(version)) .map(version => new GradleVersion(version))
.filter(parsed => parsed.isFinalRelease()) .filter(parsed => parsed.isFinalRelease())
.map(parsed => parsed.major) .map(parsed => parsed.major)
return releasedMajors.length > 0 ? Math.max(...releasedMajors) : undefined return Math.max(0, ...releasedMajors)
} }
export function getSupportStatus(version: GradleVersion, latestMajor: number): SupportStatus { type LatestPatches = Map<string, semver.SemVer>
function getSupportStatus(version: GradleVersion, latestMajor: number, latestPatches: LatestPatches): SupportStatus {
switch (Math.max(0, latestMajor - version.major)) { switch (Math.max(0, latestMajor - version.major)) {
case 0: case 0: {
return 'active' const newerPatch = findNewerPatch(version.version, latestPatches)
return newerPatch ? {kind: SupportStatusKind.PatchAvailable, newerPatch} : {kind: SupportStatusKind.Active}
}
case 1: case 1:
return 'maintenance' return {kind: SupportStatusKind.Maintenance}
default: default:
return 'eol' return {kind: SupportStatusKind.Eol}
} }
} }
export function supportStatusOf(gradleVersion: string): SupportStatus | undefined { function latestPatchByMinorLine(releasedVersions: string[]): LatestPatches {
if (LATEST_RELEASED_MAJOR === undefined) { const latestPatches: LatestPatches = new Map()
for (const released of releasedVersions) {
const version = semver.coerce(released)
if (!version) {
continue
}
const minorLine = `${version.major}.${version.minor}`
const known = latestPatches.get(minorLine)
if (!known || semver.gt(version, known)) {
latestPatches.set(minorLine, version)
}
}
return latestPatches
}
function findNewerPatch(gradleVersion: string, latestPatches: LatestPatches): string | undefined {
const current = semver.coerce(gradleVersion)
if (!current || !new GradleVersion(gradleVersion).isFinalRelease()) {
return undefined return undefined
} }
return getSupportStatus(new GradleVersion(gradleVersion), LATEST_RELEASED_MAJOR)
const latest = latestPatches.get(`${current.major}.${current.minor}`)
return latest && semver.gt(latest, current) ? latest.version : undefined
}
export function supportStatusOf(gradleVersion: string): SupportStatus {
return getSupportStatus(new GradleVersion(gradleVersion), LATEST_RELEASED_MAJOR, LATEST_PATCHES)
}
/** Entry point for tests */
export function supportStatusUsing(gradleVersion: string, releasedVersions: string[]): SupportStatus {
return getSupportStatus(
new GradleVersion(gradleVersion),
determineLatestReleasedMajor(releasedVersions),
latestPatchByMinorLine(releasedVersions)
)
} }
export function reportSupportStatus(gradleVersions: string[]): void { export function reportSupportStatus(gradleVersions: string[]): void {
if (LATEST_RELEASED_MAJOR === undefined) { reportOutdatedVersions(gradleVersions, LATEST_RELEASED_MAJOR, LATEST_PATCHES)
return }
}
/** Entry point for tests */
export function reportSupportStatusUsing(gradleVersions: string[], releasedVersions: string[]): void {
reportOutdatedVersions(
gradleVersions,
determineLatestReleasedMajor(releasedVersions),
latestPatchByMinorLine(releasedVersions)
)
}
function reportOutdatedVersions(gradleVersions: string[], latestMajor: number, latestPatches: LatestPatches): void {
for (const gradleVersion of new Set(gradleVersions)) { for (const gradleVersion of new Set(gradleVersions)) {
const version = new GradleVersion(gradleVersion) const version = new GradleVersion(gradleVersion)
switch (getSupportStatus(version, LATEST_RELEASED_MAJOR)) { const support = getSupportStatus(version, latestMajor, latestPatches)
case 'eol': switch (support.kind) {
core.warning(eolMessage(version, LATEST_RELEASED_MAJOR), {title: 'Gradle version at end-of-life'}) case SupportStatusKind.Eol:
core.warning(eolMessage(version, latestMajor), {title: 'Gradle version at end-of-life'})
break break
case 'maintenance': case SupportStatusKind.Maintenance:
core.notice(maintenanceMessage(version, LATEST_RELEASED_MAJOR), { core.notice(maintenanceMessage(version, latestMajor), {title: 'Gradle version in maintenance'})
title: 'Gradle version in maintenance' break
}) case SupportStatusKind.PatchAvailable:
core.notice(patchMessage(version, support.newerPatch), {title: 'Gradle patch update available'})
break break
} }
} }
} }
function patchMessage(version: GradleVersion, newerPatch: string): string {
return `Gradle ${version.version} is not the latest patch release: Gradle ${newerPatch} is available in the same release line, and upgrading is recommended. See ${FEATURE_LIFECYCLE_DOC}`
}
function eolMessage(version: GradleVersion, latestMajor: number): string { function eolMessage(version: GradleVersion, latestMajor: number): string {
return `Gradle ${version.version} has reached end-of-life: the ${version.major}.x release line no longer receives bug fixes or security fixes. Gradle ${latestMajor}.x is the current release line, and upgrading is recommended. See ${FEATURE_LIFECYCLE_DOC}` return `Gradle ${version.version} has reached end-of-life: the ${version.major}.x release line no longer receives bug fixes or security fixes. Gradle ${latestMajor}.x is the current release line, and upgrading is recommended. See ${FEATURE_LIFECYCLE_DOC}`
} }
+8 -5
View File
@@ -6,7 +6,7 @@ import {CacheReport} from './cache-service'
import {ProviderNote, renderCachingReport} from './caching-report' import {ProviderNote, renderCachingReport} from './caching-report'
import {DependencyGraphConfig, getActionId, getGithubToken, getJobMatrix, SummaryConfig} from './configuration' import {DependencyGraphConfig, getActionId, getGithubToken, getJobMatrix, SummaryConfig} from './configuration'
import {Deprecation, getDeprecations, getErrors} from './deprecation-collector' import {Deprecation, getDeprecations, getErrors} from './deprecation-collector'
import {supportStatusOf} from './gradle-support-status' import {SupportStatusKind, supportStatusOf} from './gradle-support-status'
const FEATURE_LIFECYCLE_DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support' const FEATURE_LIFECYCLE_DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support'
@@ -169,11 +169,14 @@ function renderBuildResultRow(result: BuildResult): string {
} }
function renderGradleVersion(gradleVersion: string): string { function renderGradleVersion(gradleVersion: string): string {
switch (supportStatusOf(gradleVersion)) { const support = supportStatusOf(gradleVersion)
case 'eol': switch (support.kind) {
case SupportStatusKind.Eol:
return `${gradleVersion} <span title="End-of-life: no longer receives bug fixes or security fixes">:warning:</span>` return `${gradleVersion} <span title="End-of-life: no longer receives bug fixes or security fixes">:warning:</span>`
case 'maintenance': case SupportStatusKind.Maintenance:
return `${gradleVersion} <span title="Maintenance only: receives critical bug fixes and security fixes only">:information_source:</span>` return `${gradleVersion} <span title="Maintenance only: receives critical bug fixes and security fixes only">:information_source:</span>`
case SupportStatusKind.PatchAvailable:
return `${gradleVersion} <span title="Patch update available: Gradle ${support.newerPatch}">:information_source:</span>`
default: default:
return gradleVersion return gradleVersion
} }
@@ -182,7 +185,7 @@ function renderGradleVersion(gradleVersion: string): string {
function renderOutdatedVersions(results: BuildResult[]): string { function renderOutdatedVersions(results: BuildResult[]): string {
const hasOutdatedVersion = results const hasOutdatedVersion = results
.map(result => supportStatusOf(result.gradleVersion)) .map(result => supportStatusOf(result.gradleVersion))
.some(status => status === 'eol' || status === 'maintenance') .some(support => support.kind === SupportStatusKind.Eol || support.kind === SupportStatusKind.Maintenance)
if (!hasOutdatedVersion) { if (!hasOutdatedVersion) {
return '' return ''
} }
+61 -44
View File
@@ -8,54 +8,58 @@ jest.unstable_mockModule('@actions/core', () => ({
notice: mockNotice notice: mockNotice
})) }))
const {determineLatestReleasedMajor, getSupportStatus, reportSupportStatus} = const {SupportStatusKind, reportSupportStatusUsing, supportStatusUsing} = await import(
await import('../../src/gradle-support-status') '../../src/gradle-support-status'
const {GradleVersion} = await import('../../src/execution/gradle-version') )
import wrapperChecksums from '../../src/wrapper-validation/wrapper-checksums.json'
const latestReleasedMajor = determineLatestReleasedMajor(wrapperChecksums.map(entry => entry.version)) const RELEASED = ['10.4.2', '10.1.0', '10.0.0', '9.6.1', '9.0.0', '8.14', '1.0']
const MAINTENANCE_VERSION = `${(latestReleasedMajor ?? 0) - 1}.0`
const DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support' const DOC = 'https://docs.gradle.org/current/userguide/feature_lifecycle.html#eol_support'
describe('determineLatestReleasedMajor', () => { describe('supportStatusOf', () => {
it('ignores pre-releases and snapshots of an unreleased major', () => { it.each(['10.0.0', '10.4.2', '11.0.0-milestone-1'])('treats %s as active', version => {
const versions = [ expect(supportStatusUsing(version, RELEASED)).toEqual({kind: SupportStatusKind.Active})
'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('getSupportStatus', () => {
it.each(['10.0.0', '10.4.2', '11.0.0-milestone-1', '12.0.0'])('treats %s as active', version => {
expect(getSupportStatus(new GradleVersion(version), 10)).toBe('active')
}) })
it.each(['9.0.0', '9.6.1', '9.7.0-rc-2'])('treats %s as maintenance-only', version => { it.each(['9.0.0', '9.6.1', '9.7.0-rc-2'])('treats %s as maintenance-only', version => {
expect(getSupportStatus(new GradleVersion(version), 10)).toBe('maintenance') expect(supportStatusUsing(version, RELEASED)).toEqual({kind: SupportStatusKind.Maintenance})
}) })
it.each(['8.14', '8.0.2', '7.6.4', '4.10.3', '1.0'])('treats %s as end-of-life', version => { it.each(['8.14', '8.0.2', '7.6.4', '4.10.3', '1.0'])('treats %s as end-of-life', version => {
expect(getSupportStatus(new GradleVersion(version), 10)).toBe('eol') expect(supportStatusUsing(version, RELEASED)).toEqual({kind: SupportStatusKind.Eol})
})
it('reports a newer patch in the latest release line instead of active', () => {
expect(supportStatusUsing('10.0.0', ['10.1.0', '10.0.1', '10.0.0'])).toEqual({
kind: SupportStatusKind.PatchAvailable,
newerPatch: '10.0.1'
})
})
it('reports the newest patch when several are available', () => {
expect(supportStatusUsing('8.14', ['8.14.5', '8.14.2', '8.14'])).toEqual({
kind: SupportStatusKind.PatchAvailable,
newerPatch: '8.14.5'
})
})
it('ignores a newer minor in the same major', () => {
expect(supportStatusUsing('9.3.0', ['9.4.0', '9.3.0'])).toEqual({kind: SupportStatusKind.Active})
})
it('ignores a newer patch when the release line is already outdated', () => {
const released = ['10.0.0', '9.0.1', '9.0.0', '8.0.1', '8.0']
expect(supportStatusUsing('9.0.0', released)).toEqual({kind: SupportStatusKind.Maintenance})
expect(supportStatusUsing('8.0', released)).toEqual({kind: SupportStatusKind.Eol})
})
it('reports no patch update for a pre-release', () => {
expect(supportStatusUsing('9.3.0-rc-1', ['9.3.1', '9.3.0'])).toEqual({kind: SupportStatusKind.Active})
})
it('treats every version as active when the release data holds no final release', () => {
expect(supportStatusUsing('1.0', ['9.0.0-rc-1', '10.0.0-SNAPSHOT'])).toEqual({kind: SupportStatusKind.Active})
}) })
}) })
@@ -65,43 +69,56 @@ describe('reportSupportStatus', () => {
}) })
it('warns about an end-of-life version', () => { it('warns about an end-of-life version', () => {
reportSupportStatus(['7.6.4']) reportSupportStatusUsing(['7.6.4'], RELEASED)
expect(mockNotice).not.toHaveBeenCalled() expect(mockNotice).not.toHaveBeenCalled()
expect(mockWarning).toHaveBeenCalledTimes(1) expect(mockWarning).toHaveBeenCalledTimes(1)
const [message, properties] = mockWarning.mock.calls[0] const [message, properties] = mockWarning.mock.calls[0]
expect(message).toContain('Gradle 7.6.4 has reached end-of-life') expect(message).toContain('Gradle 7.6.4 has reached end-of-life')
expect(message).toContain('the 7.x release line no longer receives bug fixes or security fixes') expect(message).toContain('the 7.x release line no longer receives bug fixes or security fixes')
expect(message).toContain('Gradle 10.x is the current release line')
expect(message).toContain(DOC) expect(message).toContain(DOC)
expect(properties?.title).toBe('Gradle version at end-of-life') expect(properties?.title).toBe('Gradle version at end-of-life')
}) })
it('notices a maintenance-only version', () => { it('notices a maintenance-only version', () => {
reportSupportStatus([MAINTENANCE_VERSION]) reportSupportStatusUsing(['9.0.0'], RELEASED)
expect(mockWarning).not.toHaveBeenCalled() expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).toHaveBeenCalledTimes(1) expect(mockNotice).toHaveBeenCalledTimes(1)
const [message, properties] = mockNotice.mock.calls[0] const [message, properties] = mockNotice.mock.calls[0]
expect(message).toContain(`Gradle ${MAINTENANCE_VERSION} is in maintenance-only support`) expect(message).toContain('Gradle 9.0.0 is in maintenance-only support')
expect(message).toContain('receives critical bug fixes and security fixes only') expect(message).toContain('receives critical bug fixes and security fixes only')
expect(message).toContain('reaches end-of-life when Gradle 11 is released')
expect(properties?.title).toBe('Gradle version in maintenance') expect(properties?.title).toBe('Gradle version in maintenance')
}) })
it('notices a version with a newer patch available', () => {
reportSupportStatusUsing(['10.0.0'], ['10.0.1', '10.0.0'])
expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).toHaveBeenCalledTimes(1)
const [message, properties] = mockNotice.mock.calls[0]
expect(message).toContain('Gradle 10.0.0 is not the latest patch release')
expect(message).toContain('Gradle 10.0.1 is available')
expect(properties?.title).toBe('Gradle patch update available')
})
it('says nothing about a version in the latest release line', () => { it('says nothing about a version in the latest release line', () => {
reportSupportStatus(['999.0.0']) reportSupportStatusUsing(['10.4.2'], RELEASED)
expect(mockWarning).not.toHaveBeenCalled() expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).not.toHaveBeenCalled() expect(mockNotice).not.toHaveBeenCalled()
}) })
it('annotates each distinct version once', () => { it('annotates each distinct version once', () => {
reportSupportStatus(['7.6.4', '4.10.3', '7.6.4']) reportSupportStatusUsing(['7.6.4', '4.10.3', '7.6.4'], RELEASED)
expect(mockWarning).toHaveBeenCalledTimes(2) expect(mockWarning).toHaveBeenCalledTimes(2)
}) })
it('says nothing when no Gradle build ran', () => { it('says nothing when no Gradle build ran', () => {
reportSupportStatus([]) reportSupportStatusUsing([], RELEASED)
expect(mockWarning).not.toHaveBeenCalled() expect(mockWarning).not.toHaveBeenCalled()
expect(mockNotice).not.toHaveBeenCalled() expect(mockNotice).not.toHaveBeenCalled()
+22 -13
View File
@@ -3,18 +3,22 @@ import * as github from '@actions/github'
import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals' import {afterEach, beforeEach, describe, expect, it, jest} from '@jest/globals'
import {BuildResult} from '../../src/build-results' import {BuildResult} from '../../src/build-results'
import {SupportStatus} from '../../src/gradle-support-status'
const mockSupportStatusOf = jest.fn<(gradleVersion: string) => SupportStatus | undefined>() let releasedVersions = [{version: '8.0', checksum: ''}]
jest.unstable_mockModule('../../src/gradle-support-status', () => ({ jest.unstable_mockModule('../../src/wrapper-validation/wrapper-checksums.json', () => ({
supportStatusOf: mockSupportStatusOf get default() {
return releasedVersions
}
})) }))
const {jobMarker, renderSummaryTable} = await import('../../src/job-summary') const {jobMarker, renderSummaryTable} = await import('../../src/job-summary')
beforeEach(() => { async function renderWith(versions: string[], results: BuildResult[]): Promise<string> {
mockSupportStatusOf.mockReturnValue('active') releasedVersions = versions.map(version => ({version, checksum: ''}))
}) jest.resetModules()
const {renderSummaryTable: render} = await import('../../src/job-summary')
return render(results)
}
const MATRIX_INPUT_ENV = 'INPUT_WORKFLOW-JOB-CONTEXT' const MATRIX_INPUT_ENV = 'INPUT_WORKFLOW-JOB-CONTEXT'
@@ -197,9 +201,8 @@ describe('renderSummaryTable', () => {
}) })
describe('Gradle version support status', () => { describe('Gradle version support status', () => {
it('marks an outdated version and adds a details section', () => { it('marks an outdated version and adds a details section', async () => {
mockSupportStatusOf.mockReturnValue('eol') const table = await renderWith(['10.0.0', '8.0'], [successfulHelpBuild])
const table = renderSummaryTable([successfulHelpBuild])
expect(table.trim()).toBe(dedent` expect(table.trim()).toBe(dedent`
<table> <table>
<tr> <tr>
@@ -233,14 +236,20 @@ describe('Gradle version support status', () => {
</details> </details>
`); `);
}) })
it('marks a maintenance-only version', () => { it('marks a maintenance-only version', async () => {
mockSupportStatusOf.mockReturnValue('maintenance') const table = await renderWith(['9.0.0', '8.0'], [successfulHelpBuild])
const table = renderSummaryTable([successfulHelpBuild])
expect(table).toContain( expect(table).toContain(
`<td align='center'>8.0 <span title="Maintenance only: receives critical bug fixes and security fixes only">:information_source:</span></td>` `<td align='center'>8.0 <span title="Maintenance only: receives critical bug fixes and security fixes only">:information_source:</span></td>`
) )
expect(table).toContain('This Job uses an outdated Gradle version') expect(table).toContain('This Job uses an outdated Gradle version')
}) })
it('marks a version with a newer patch release available', async () => {
const table = await renderWith(['8.0.1', '8.0'], [successfulHelpBuild])
expect(table).toContain(
`<td align='center'>8.0 <span title="Patch update available: Gradle 8.0.1">:information_source:</span></td>`
)
expect(table).not.toContain('outdated Gradle version')
})
}) })
describe('jobMarker', () => { describe('jobMarker', () => {