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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
java-version: 25

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
Expand All @@ -33,11 +33,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
java-version: 25

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
Expand Down
16 changes: 5 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: default help clean build lint format detekt detekt-baseline tests uberjar uber \
cc run heroku logs versions upgrade-wrapper
cc run versions upgrade-wrapper

GRADLE_VERSION := $(shell sed -n 's/^gradle-wrapper = "\(.*\)"/\1/p' gradle/libs.versions.toml)

Expand Down Expand Up @@ -42,19 +42,13 @@ cc: ## Continuous compilation (watches for changes)
run: ## Start the content server locally (port 8080)
./gradlew run

heroku: ## Deploy by pushing master to Heroku
git push heroku master

logs: ## Tail Heroku logs
heroku logs --tail

versions: ## Check for dependency updates
./gradlew dependencyUpdates --no-configuration-cache --no-parallel

# Gradle's documented upgrade procedure: the first run rewrites
# gradle-wrapper.properties using the *old* wrapper jar; the second run
# regenerates the wrapper itself with the new version.
upgrade-wrapper: _require-gradle-version ## Upgrade Gradle wrapper to version in libs.versions.toml
upgrade-wrapper: _require-gradle-version ## Upgrade the Gradle wrapper to the catalog version
# Gradle's documented upgrade procedure: the first run rewrites
# gradle-wrapper.properties using the *old* wrapper jar; the second run
# regenerates the wrapper itself with the new version.
./gradlew wrapper --gradle-version=$(GRADLE_VERSION) --distribution-type=bin
./gradlew wrapper --gradle-version=$(GRADLE_VERSION) --distribution-type=bin

Expand Down
120 changes: 91 additions & 29 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.gradle.kotlin.dsl.named
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
application
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.versions)
alias(libs.plugins.ktor.plugin)
alias(libs.plugins.detekt)
alias(libs.plugins.kotlinter)
}

// This is for ./gradlew run
description = "ReadingBat Site"

application {
mainClass = "ContentServerKt"
}

description = "ReadingBat Site"

dependencies {
implementation(libs.readingbat.core)
implementation(libs.core.utils)
Expand All @@ -24,43 +27,102 @@ dependencies {
testImplementation(libs.bundles.testing)
}

kotlin {
jvmToolchain(libs.versions.jvm.get().toInt())
tasks.register("stage") {
group = "distribution"
description = "Clean-builds the project for deployment."
dependsOn("clean", "build")
}

detekt {
source.setFrom("src/main/kotlin", "src/test/kotlin")
buildUponDefaultConfig = true
parallel = true
tasks.named("build") {
mustRunAfter("clean")
}

kotlinter {
ignoreFormatFailures = false
ignoreLintFailures = false
reporters = arrayOf("checkstyle", "plain")
configureKotlin()
configureDetekt()
configureKotlinter()
configureKtor()
configureShadowJar()
configureTest()
configureVersions()

fun Project.configureKotlin() {
kotlin {
jvmToolchain(libs.versions.jvm.get().toInt())
}

// Run the unused-return-value checker over production code only. Kotest's
// assertion DSL (e.g. shouldBe) returns its receiver, and tests intentionally
// discard that result, so applying the checker to the test source set would
// emit only false-positive warnings.
tasks.named<KotlinCompile>("compileKotlin") {
compilerOptions {
freeCompilerArgs.add("-Xreturn-value-checker=check")
}
}
}

tasks.register("stage") {
dependsOn("clean", "build")
fun Project.configureDetekt() {
detekt {
source.setFrom("src/main/kotlin", "src/test/kotlin")
buildUponDefaultConfig = true
parallel = true
}
}

tasks.named("build") {
mustRunAfter("clean")
fun Project.configureKotlinter() {
kotlinter {
ignoreFormatFailures = false
ignoreLintFailures = false
reporters = arrayOf("checkstyle", "plain")
}
}

tasks.shadowJar {
archiveFileName.set("server.jar")
isZip64 = true
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
listOf("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "LICENSE*").forEach(::exclude)
fun Project.configureKtor() {
ktor {
fatJar {
archiveFileName = "server.jar"
}
}
}

tasks.test {
useJUnitPlatform()
fun Project.configureShadowJar() {
// Ktor's `buildFatJar` task delegates to shadow; this block configures that output.
tasks.shadowJar {
isZip64 = true
duplicatesStrategy = DuplicatesStrategy.WARN
exclude("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
}
}

fun Project.configureTest() {
tasks.test {
useJUnitPlatform()

testLogging {
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_ERROR)
exceptionFormat = TestExceptionFormat.FULL
showStandardStreams = false
}
}
}

fun Project.configureVersions() {
// A pre-release qualifier is a `.` or `-` delimiter followed by a known unstable
// keyword. `m\d` matches milestones (`-M1`/`.M2`) without catching stable classifiers
// like `-macos`/`-MR1`, and the `[.-]` delimiter catches both dash-style (`-alpha`)
// and dot-style (Netty's `.Beta1`) qualifiers while leaving `-jre`/`.Final` stable.
val preReleaseQualifier =
Regex("""[.-](rc|beta|alpha|m\d|cr|snapshot|eap|dev|milestone|pre)""", RegexOption.IGNORE_CASE)

fun isNonStable(version: String): Boolean = preReleaseQualifier.containsMatchIn(version)

testLogging {
events = setOf(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_ERROR)
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showStandardStreams = false
tasks.withType<DependencyUpdatesTask>().configureEach {
notCompatibleWithConfigurationCache("the dependency updates plugin is not compatible with the configuration cache")
// Reject a pre-release candidate only when the current version is stable. For
// dependencies we intentionally track on a pre-release line (e.g. a detekt
// alpha), newer pre-releases are still surfaced as available updates.
rejectVersionIf {
isNonStable(candidate.version) && !isNonStable(currentVersion)
}
}
}
14 changes: 7 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[versions]
detekt = "2.0.0-alpha.3"
gradle-wrapper = "9.5.1"
jvm = "17"
kotest = "6.1.11"
detekt = "2.0.0-alpha.5"
gradle-wrapper = "9.6.1"
jvm = "25"
kotest = "6.2.1"
kotlin = "2.4.0"
kotlinter = "5.5.0"
ktor = "3.5.0"
ktor = "3.5.1"
logging = "8.0.4"
readingbat = "3.1.8"
utils = "2.9.0"
readingbat = "3.2.1"
utils = "2.9.3"
versions = "0.54.0"

[libraries]
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
Expand Down
4 changes: 2 additions & 2 deletions gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/test/kotlin/ContentTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class ContentTests : StringSpec() {
forEachGroup {
forEachChallenge {
forEachAnswer {
it shouldHaveAnswer correctAnswers[it.index]
it shouldHaveAnswer correctAnswers()[it.index]
}
}
}
Expand Down
Loading