Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/update-gradle-versions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Update Gradle Versions

on:
schedule:
- cron: '0 9 * * 1'
workflow_dispatch:

permissions:
contents: write
pull-requests: write

jobs:
update-gradle-versions:
runs-on: ubuntu-latest
timeout-minutes: 60

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '21'

- name: Update bundled Gradle wrappers
run: ./scripts/update_gradle_versions.sh

- name: Run tests
run: ./gradlew :project-generator:test :cli:test

- name: Create pull request
uses: peter-evans/create-pull-request@v7
with:
commit-message: Update bundled Gradle versions
title: Update bundled Gradle versions
body: |
Updates the bundled Gradle wrapper resources and README to the latest three minor lines for Gradle 9 and Gradle 8 from the official Gradle versions feed.
branch: codex/update-gradle-versions
delete-branch: true
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Then, you can use the versions.yaml in the `generate-project` command:
- `--classes-module-type`: fixed (default), random
- `--type-of-string-resources`: normal (default), large
- `--generate-unit-test`: Generate unit tests (default: false)
- `--gradle`: gradle_8_14_3, gradle_9_1_0, gradle_9_2_0, gradle_9_3_0, gradle_9_3_1, gradle_9_4_0 (default: gradle_9_4_0)
- `--gradle`: gradle_9_4_1, gradle_9_3_1, gradle_9_2_1, gradle_8_14_4, gradle_8_13, gradle_8_12_1 (default: gradle_9_4_1)
- `--develocity`: Enables the Develocity build scan plugin (default: false). If --develocity-url is not specified, the build scan will be published to Gradle Scans.
- `--develocity-url`: Specify Develocity URL
- `--versions-file`: Path to a custom YAML file with dependency versions
Expand Down Expand Up @@ -77,7 +77,7 @@ ProjectGenerator(
typeOfStringResources = TypeOfStringResources.LARGE,
layers = 5,
generateUnitTest = true,
gradle = GradleWrapper(Gradle.GRADLE_9_3_1),
gradle = GradleWrapper(Gradle.fromValue("9.3.1")),
projectRootPath = file.path
).write()

Expand Down Expand Up @@ -200,12 +200,15 @@ If enabled, each module will generate n unit tests, where n is the argument `cla
```
## Gradle
Gradle used, versions supported:
* Gradle 8.14.3
* Gradle 9.1.0
* Gradle 9.2.0
* Gradle 9.3.0
* Gradle 9.3.1
* Gradle 9.4.0 **default**
* Gradle 9.x
* 9.4.1
* 9.3.1
* 9.2.1
* Gradle 8.x
* 8.14.4
* 8.13
* 8.12.1
* The newest bundled version is the default.

##### Example
```kotlin
Expand Down
4 changes: 2 additions & 2 deletions backend/server.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ app.post('/api/generate', upload.single('versions-file'), async (req, res) => {
`--type`, type,
`--classes-module`, classesModule,
`--classes-module-type`, body['classes-module-type'] || 'fixed',
`--type-of-string-resources`, body['type-of-string-resources'] || 'normal',
`--gradle`, body.gradle || 'GRADLE_9_4_0'
`--type-of-string-resources`, body['type-of-string-resources'] || 'normal'
];

if (body.gradle) args.push('--gradle', body.gradle);
// Add project name if provided
if (body['project-name']) { args.push('--project-name', body['project-name']);}
if (toBool(body['generate-unit-test']) || toBool(body.generateUnitTest)) args.push('--generate-unit-test');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class GenerateVersionsYaml {
val file = File("versions.yaml")
val versions = Versions()
val content = """
|gradle: ${Gradle.GRADLE_9_4_0.version}
|gradle: ${Gradle.latest().version}
|project:
| develocity: ${versions.project.develocity}
| develocityUrl: ${versions.project.develocityUrl}
Expand Down
17 changes: 8 additions & 9 deletions cli/src/main/kotlin/io/github/cdsap/projectgenerator/cli/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,13 @@ class GenerateProjects : CliktCommand(name = "generate-project") {
private val typeOfStringResources: String by option().choice("large", "normal").default("normal")
private val layers by option().int().default(5)
private val generateUnitTest by option().flag(default = false)
private val gradle: String? by option().choice(
"gradle_8_14_3",
"gradle_9_1_0",
"gradle_9_2_0",
"gradle_9_3_0",
"gradle_9_3_1",
"gradle_9_4_0"
)
private val gradle: String? by option()
.convert {
if (!Gradle.isSupportedValue(it)) {
fail("Unknown Gradle version: $it. Supported versions: ${Gradle.supportedDisplayValues()}")
}
it
}
private val develocity by option().flag(default = false)
private val versionsFile by option().file()
private val outputDir by option("--output-dir")
Expand Down Expand Up @@ -151,7 +150,7 @@ internal fun resolveProjectRootPath(outputDir: String?, language: Language, proj
internal fun resolveGradle(cliGradle: String?, versionsFile: VersionsFile?): Gradle {
return cliGradle?.let(Gradle::fromValue)
?: versionsFile?.gradle
?: Gradle.GRADLE_9_4_0
?: Gradle.latest()
}

class GenerateYaml : CliktCommand(name = "generate-yaml-versions") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.github.cdsap.projectgenerator.model.AdditionalPlugin
import io.github.cdsap.projectgenerator.model.Android
import io.github.cdsap.projectgenerator.model.DependencyInjection
import io.github.cdsap.projectgenerator.model.Gradle
import io.github.cdsap.projectgenerator.model.Kotlin
import io.github.cdsap.projectgenerator.model.Project
import io.github.cdsap.projectgenerator.model.Testing
import io.github.cdsap.projectgenerator.model.VersionsFile
import java.io.File

Expand All @@ -28,15 +34,25 @@ object VersionsParser {
val tree = mapper.readTree(file)
normalizeGradleVersion(tree)
normalizeProjectDefaults(tree)
return mapper.treeToValue(tree, VersionsFile::class.java)
val payload = mapper.treeToValue(tree, VersionsFilePayload::class.java)
return VersionsFile(
gradle = payload.gradle?.let(Gradle::fromValue),
kotlin = payload.kotlin,
android = payload.android,
testing = payload.testing,
project = payload.project,
di = payload.di,
additionalBuildGradleRootPlugins = payload.additionalBuildGradleRootPlugins,
additionalSettingsPlugins = payload.additionalSettingsPlugins
)
}

private fun normalizeGradleVersion(tree: com.fasterxml.jackson.databind.JsonNode) {
if (tree !is ObjectNode) return
val gradleNode = tree.get("gradle") ?: return
if (!gradleNode.isTextual) return

val normalized = Gradle.fromValue(gradleNode.asText()).name
val normalized = Gradle.fromValue(gradleNode.asText()).version
tree.put("gradle", normalized)
}

Expand All @@ -49,4 +65,15 @@ object VersionsParser {
projectNode.put("develocityUrl", "")
}
}

private data class VersionsFilePayload(
val gradle: String? = null,
val kotlin: Kotlin = Kotlin(),
val android: Android = Android(),
val testing: Testing = Testing(),
val project: Project = Project(),
val di: DependencyInjection = DependencyInjection.HILT,
val additionalBuildGradleRootPlugins: List<AdditionalPlugin>? = null,
val additionalSettingsPlugins: List<AdditionalPlugin>? = null
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,41 @@ class GenerateProjectsCliTest {
assertTrue(error.message?.contains("classes per module must be >= 10") == true)
}

@Test
fun `unsupported gradle version lists supported values`() {
val error = assertThrows<UsageError> {
GenerateProjects().parse(
listOf(
"--modules", "6",
"--gradle", "9.9.9"
)
)
}

assertTrue(error.message?.contains("Unknown Gradle version: 9.9.9") == true)
assertTrue(error.message?.contains(Gradle.supportedDisplayValues()) == true)
}

@Test
fun `gradle from versions file is used when flag is absent`() {
val resolved = resolveGradle(null, VersionsFile(gradle = Gradle.GRADLE_9_3_1))
val configured = Gradle.supported()[1]
val resolved = resolveGradle(null, VersionsFile(gradle = configured))

assertEquals(Gradle.GRADLE_9_3_1, resolved)
assertEquals(configured, resolved)
}

@Test
fun `gradle flag overrides versions file`() {
val resolved = resolveGradle("gradle_9_4_0", VersionsFile(gradle = Gradle.GRADLE_9_3_1))
val resolved = resolveGradle(Gradle.latest().cliValue, VersionsFile(gradle = Gradle.oldest()))

assertEquals(Gradle.GRADLE_9_4_0, resolved)
assertEquals(Gradle.latest(), resolved)
}

@Test
fun `latest gradle is used when neither flag nor versions file provide one`() {
val resolved = resolveGradle(null, null)

assertEquals(Gradle.GRADLE_9_4_0, resolved)
assertEquals(Gradle.latest(), resolved)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,24 +148,24 @@ class VersionsParserTest {
@Test
fun `parses gradle from YAML case insensitively`() {
val yaml = """
gradle: 9.3.1
gradle: ${Gradle.supported()[1].version}
""".trimIndent()

val file = File(tempDir.toFile(), "versions.yaml").apply { writeText(yaml) }
val versionsFile = VersionsParser.fromFile(file)

assertEquals(Gradle.GRADLE_9_3_1, versionsFile.gradle)
assertEquals(Gradle.supported()[1], versionsFile.gradle)
}

@Test
fun `parses legacy gradle enum name from YAML for backwards compatibility`() {
val yaml = """
gradle: GRADLE_9_3_1
gradle: ${Gradle.supported()[1].legacyEnumName}
""".trimIndent()

val file = File(tempDir.toFile(), "versions.yaml").apply { writeText(yaml) }
val versionsFile = VersionsParser.fromFile(file)

assertEquals(Gradle.GRADLE_9_3_1, versionsFile.gradle)
assertEquals(Gradle.supported()[1], versionsFile.gradle)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ProjectGenerator(
private val typeOfStringResources: TypeOfStringResources = TypeOfStringResources.NORMAL,
private val layers: Int,
private val generateUnitTest: Boolean = false,
private val gradle: GradleWrapper = GradleWrapper(Gradle.GRADLE_9_4_0),
private val gradle: GradleWrapper = GradleWrapper(Gradle.latest()),
private val projectRootPath: String = "projects_generated/generated_project/project_kts",
private val develocity: Boolean = false,
private val layerNames: List<String> = DefaultNames.layerNames,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,59 @@
package io.github.cdsap.projectgenerator.model

enum class Gradle(val version: String) {
GRADLE_8_14_3("8.14.3"),
GRADLE_9_1_0("9.1.0"),
GRADLE_9_2_0("9.2.0"),
GRADLE_9_3_0("9.3.0"),
GRADLE_9_3_1("9.3.1"),
GRADLE_9_4_0("9.4.0");
data class Gradle(val version: String) {

val cliValue: String
get() = "gradle_${version.replace('.', '_')}"

val legacyEnumName: String
get() = cliValue.uppercase()

val resourceZipName: String
get() = "${cliValue.lowercase()}.zip"

companion object {
private const val SUPPORTED_VERSIONS_RESOURCE = "supported-gradle-versions.txt"

private val supportedVersions: List<Gradle> by lazy {
val stream = requireNotNull(Gradle::class.java.classLoader.getResourceAsStream(SUPPORTED_VERSIONS_RESOURCE)) {
"Missing resource: $SUPPORTED_VERSIONS_RESOURCE"
}
stream.bufferedReader().useLines { lines ->
lines
.map(String::trim)
.filter { it.isNotEmpty() && !it.startsWith("#") }
.map(::Gradle)
.toList()
}
}

private val supportedLookup: Map<String, Gradle> by lazy {
supportedVersions.flatMap { gradle ->
listOf(
gradle.version.lowercase() to gradle,
gradle.cliValue.lowercase() to gradle,
gradle.legacyEnumName.lowercase() to gradle
)
}.toMap()
}

fun supported(): List<Gradle> = supportedVersions

fun latest(): Gradle = supported().first()

fun oldest(): Gradle = supported().last()

fun supportedCliChoices(): List<String> = supported().flatMap { listOf(it.cliValue, it.version) }

fun supportedDisplayValues(): String = supported().joinToString(", ") { "${it.cliValue} (${it.version})" }

fun isSupportedValue(value: String): Boolean = supportedLookup.containsKey(value.lowercase())

fun fromValue(value: String): Gradle {
return entries.firstOrNull { it.version == value }
?: entries.firstOrNull { it.name.equals(value, ignoreCase = true) }
?: throw IllegalArgumentException("Unknown Gradle version: $value")
return supportedLookup[value.lowercase()]
?: throw IllegalArgumentException(
"Unknown Gradle version: $value. Supported versions: ${supportedDisplayValues()}"
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import java.util.zip.ZipInputStream
class GradleWrapper(val gradle: Gradle) {

fun installGradleVersion(path: String) {
val zipFileName = "${gradle.name.lowercase()}.zip"
val zipFileName = gradle.resourceZipName
val outputDir = path
unzipResourceFile(zipFileName, outputDir)

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
9.4.1
9.3.1
9.2.1
8.14.4
8.13
8.12.1
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.github.cdsap.projectgenerator.model.Versions

class DefaultTestVersions {
companion object {
val LATEST_GRADLE = Gradle.GRADLE_9_4_0
val LATEST_GRADLE = Gradle.latest()
val OLDEST_SUPPORTED_GRADLE = Gradle.oldest()
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.github.cdsap.projectgenerator

import io.github.cdsap.projectgenerator.DefaultTestVersions.Companion.LATEST_GRADLE
import io.github.cdsap.projectgenerator.DefaultTestVersions.Companion.OLDEST_SUPPORTED_GRADLE
import io.github.cdsap.projectgenerator.model.Android
import io.github.cdsap.projectgenerator.model.ClassesPerModule
import io.github.cdsap.projectgenerator.model.ClassesPerModuleType
import io.github.cdsap.projectgenerator.model.Gradle
import io.github.cdsap.projectgenerator.model.Language
import io.github.cdsap.projectgenerator.model.Project
import io.github.cdsap.projectgenerator.model.Shape
Expand Down Expand Up @@ -88,7 +88,7 @@ class ProjectGeneratorE2ETest {
TypeOfStringResources.LARGE,
5,
true,
GradleWrapper(Gradle.GRADLE_8_14_3),
GradleWrapper(OLDEST_SUPPORTED_GRADLE),
projectRootPath = "${tempDir.toFile().path}/${shape.name.lowercase().capitalize()}$modules/project_kts",
develocity = false,
projectName = "${shape.name.lowercase().capitalize()}$modules"
Expand Down
Loading
Loading