Skip to content

Commit a8b9338

Browse files
committed
Squashed commits
1 parent 6b490ad commit a8b9338

File tree

14 files changed

+393
-44
lines changed

14 files changed

+393
-44
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
@file:Suppress("UnstableApiUsage")
2+
3+
package com.gabrielfeo
4+
5+
plugins {
6+
id("org.jetbrains.kotlin.jvm")
7+
}
8+
9+
testing {
10+
suites {
11+
register<JvmTestSuite>("examplesTest") {
12+
useKotlinTest()
13+
}
14+
}
15+
}
16+
17+
kotlin {
18+
target {
19+
val main by compilations.getting
20+
val examplesTest by compilations.getting
21+
examplesTest.associateWith(main)
22+
}
23+
}
24+
25+
val examples = fileTree(rootDir) {
26+
include("examples/**")
27+
exclude("**/build", "**/.*")
28+
}
29+
30+
tasks.named("processExamplesTestResources", ProcessResources::class) {
31+
from(examples)
32+
}
33+
34+
val downloadPipRequirements by tasks.registering(Exec::class) {
35+
val requirementsFiles = examples.filter { it.name == "requirements.txt" }
36+
inputs.files(requirementsFiles)
37+
.withPropertyName("requirementsFiles")
38+
.withPathSensitivity(PathSensitivity.NONE)
39+
.skipWhenEmpty()
40+
val downloadDir = layout.buildDirectory.dir("pip-requirements")
41+
outputs.dir(downloadDir)
42+
commandLine("pip3", "download")
43+
workingDir(downloadDir)
44+
argumentProviders += CommandLineArgumentProvider {
45+
requirementsFiles.files.flatMap { listOf("-r", it.absolutePath) }
46+
}
47+
}
48+
49+
tasks.named<Test>("examplesTest") {
50+
inputs.files(downloadPipRequirements)
51+
.withPropertyName("downloadedPipRequirements")
52+
.withPathSensitivity(PathSensitivity.NONE)
53+
systemProperty(
54+
"downloaded-requirements-path",
55+
downloadPipRequirements.map { it.outputs.files.singleFile }.get().relativeTo(workingDir).path,
56+
)
57+
}
58+
59+
tasks.named("check") {
60+
dependsOn("examplesTest")
61+
}

build-logic/src/main/kotlin/com/gabrielfeo/test-suites.gradle.kts renamed to build-logic/src/main/kotlin/com/gabrielfeo/integration-test-suite.gradle.kts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ plugins {
77

88
testing {
99
suites {
10-
// 'test' is registered by default
11-
register<JvmTestSuite>("integrationTest")
12-
withType<JvmTestSuite>().configureEach {
10+
register<JvmTestSuite>("integrationTest") {
1311
useKotlinTest()
1412
}
1513
}

build-logic/src/main/kotlin/com/gabrielfeo/kotlin-jvm-library.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@file:Suppress("UnstableApiUsage")
2+
13
package com.gabrielfeo
24

35
plugins {
@@ -14,3 +16,12 @@ java {
1416
useRuntimeClasspathVersions()
1517
}
1618
}
19+
20+
@Suppress("unused")
21+
testing {
22+
suites {
23+
val test by getting(JvmTestSuite::class) {
24+
useKotlinTest()
25+
}
26+
}
27+
}

examples/build.gradle.kts

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,9 @@ exampleTestTasks += tasks.register("runExampleProject") {
3030
dependsOn(":examples:example-project:run")
3131
}
3232

33-
val notebooksDir = file("example-notebooks")
34-
val notebooks = fileTree(notebooksDir) { include("*.ipynb") }
35-
val venvDir = project.layout.buildDirectory.asFile.map { File(it, "venv") }
36-
37-
val createPythonVenv by tasks.registering(Exec::class) {
38-
val requirements = File(notebooksDir, "requirements.txt")
39-
val venv = venvDir.get()
40-
commandLine(
41-
"bash", "-c",
42-
"python3 -m venv --upgrade-deps $venv "
43-
+ "&& source $venv/bin/activate "
44-
+ "&& pip install --upgrade pip"
45-
+ "&& pip install -r $requirements"
46-
)
47-
}
48-
49-
exampleTestTasks += notebooks.map { notebook ->
50-
val buildDir = project.layout.buildDirectory.asFile.get()
51-
tasks.register<Exec>("run${notebook.nameWithoutExtension}Notebook") {
52-
group = "Application"
53-
description = "Runs the '${notebook.name}' notebook with 'jupyter nbconvert --execute'"
54-
val venv = venvDir.get()
55-
dependsOn(createPythonVenv)
56-
commandLine(
57-
"bash", "-c",
58-
"source $venv/bin/activate "
59-
+ "&& jupyter nbconvert --execute --to ipynb --output-dir='$buildDir' '$notebook'"
60-
)
61-
}
62-
}
63-
6433
val runAll = tasks.register("runAll") {
6534
group = "Application"
66-
description = "Runs everything in 'examples' directory"
35+
description = "Runs everything in 'examples' directory, except for notebooks (moved to exampleTests suite)"
6736
dependsOn(exampleTestTasks)
6837
}
6938

examples/example-notebooks/MostFrequentBuilds.ipynb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@
121121
" }.toList(LinkedList())\n",
122122
"}\n",
123123
"\n",
124-
"println(\"${builds.size} builds\")\n",
124+
"println(\"Collected ${builds.size} builds from the API\")\n",
125125
"check(builds.isNotEmpty()) { \"No builds found. Adjust query and try again.\" }"
126126
]
127127
},
@@ -840,9 +840,7 @@
840840
}
841841
},
842842
"outputs": [],
843-
"source": [
844-
"%use kandy(v=0.6.0)"
845-
]
843+
"source": "%use kandy(v=0.6.0)"
846844
},
847845
{
848846
"cell_type": "code",

library/build.gradle.kts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
12
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
23
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
34

45
plugins {
56
id("com.gabrielfeo.published-kotlin-jvm-library")
67
id("com.gabrielfeo.develocity-api-code-generation")
7-
id("com.gabrielfeo.test-suites")
8+
id("com.gabrielfeo.integration-test-suite")
9+
id("com.gabrielfeo.examples-test-suite")
810
alias(libs.plugins.kotlin.jupyter)
911
}
1012

@@ -14,10 +16,6 @@ tasks.processJupyterApiResources {
1416
)
1517
}
1618

17-
tasks.named<Test>("integrationTest") {
18-
environment("DEVELOCITY_API_LOG_LEVEL", "DEBUG")
19-
}
20-
2119
dependencies {
2220
constraints {
2321
implementation(libs.okio)
@@ -81,6 +79,12 @@ publishing {
8179
from(components["java"])
8280
pom(libraryPom)
8381
}
82+
register<MavenPublication>("unsignedSnapshotDevelocityApiKotlin") {
83+
artifactId = "develocity-api-kotlin"
84+
version = "SNAPSHOT"
85+
from(components["java"])
86+
pom(libraryPom)
87+
}
8488
register<MavenPublication>("relocation") {
8589
artifactId = "gradle-enterprise-api-kotlin"
8690
pom {
@@ -102,3 +106,18 @@ tasks.named("compileKotlin", KotlinCompile::class) {
102106
languageVersion = KotlinVersion.KOTLIN_1_8
103107
}
104108
}
109+
110+
tasks.withType<Test>().configureEach {
111+
environment("DEVELOCITY_API_LOG_LEVEL", "DEBUG")
112+
providers.environmentVariablesPrefixedBy("DEVELOCITY_API_").get().forEach { (name, value) ->
113+
inputs.property("${name}.hashCode", value.hashCode())
114+
}
115+
}
116+
117+
val publishUnsignedSnapshotDevelocityApiKotlinPublicationToMavenLocal by tasks.getting
118+
119+
tasks.named<Test>("examplesTest") {
120+
inputs.files(files(publishUnsignedSnapshotDevelocityApiKotlinPublicationToMavenLocal))
121+
.withPropertyName("snapshotPublicationArtifacts")
122+
.withNormalizer(ClasspathNormalizer::class)
123+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.gabrielfeo.develocity.api.example
2+
3+
import com.squareup.moshi.Moshi
4+
import okio.buffer
5+
import okio.source
6+
import java.nio.file.Path
7+
8+
object JsonAdapter {
9+
10+
private val jsonAdapter = Moshi.Builder().build().adapter(Map::class.java)
11+
12+
fun fromJson(path: Path): Map<*, *>? =
13+
jsonAdapter.fromJson(path.source().buffer())
14+
15+
fun toJson(map: Map<*, *>?): String =
16+
jsonAdapter.toJson(map)
17+
18+
fun toPrettyJson(map: Map<*, *>?): String =
19+
jsonAdapter.indent(" ").toJson(map)
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.gabrielfeo.develocity.api.example
2+
3+
import java.nio.file.Path
4+
import kotlin.io.path.ExperimentalPathApi
5+
import kotlin.io.path.copyToRecursively
6+
import kotlin.io.path.createParentDirectories
7+
import kotlin.io.path.div
8+
9+
10+
@OptIn(ExperimentalPathApi::class)
11+
fun Any.copyFromResources(path: String, targetDir: Path) {
12+
val examples = requireNotNull(this::class.java.getResource(path))
13+
val sourcePath = Path.of(examples.toURI())
14+
val destPath = targetDir / path.removePrefix("/")
15+
destPath.createParentDirectories()
16+
sourcePath.copyToRecursively(destPath, followLinks = false, overwrite = true)
17+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.gabrielfeo.develocity.api.example
2+
3+
import kotlinx.coroutines.CoroutineStart
4+
import kotlinx.coroutines.CoroutineStart.*
5+
import kotlinx.coroutines.async
6+
import kotlinx.coroutines.launch
7+
import kotlinx.coroutines.runBlocking
8+
import java.nio.file.Path
9+
10+
fun runInShell(workDir: Path, vararg command: String) =
11+
runInShell(workDir, command.joinToString(" "))
12+
13+
fun runInShell(workDir: Path, command: String): String {
14+
val process = ProcessBuilder("bash", "-c", command).apply {
15+
directory(workDir.toFile())
16+
// Ensure the test's build toolchain is used (not whatever JAVA_HOME is set to)
17+
environment()["JAVA_HOME"] = System.getProperty("java.home")
18+
}.start()
19+
val stdout = runBlocking {
20+
launch(start = UNDISPATCHED) {
21+
process.errorStream.bufferedReader().lineSequence()
22+
.onEach(System.err::println)
23+
.joinToString("\n")
24+
}
25+
async(start = UNDISPATCHED) {
26+
process.inputStream.bufferedReader().lineSequence()
27+
.onEach(System.out::println)
28+
.joinToString("\n")
29+
}.await()
30+
}
31+
val exitCode = process.waitFor()
32+
check(exitCode == 0) { "Exit code '$exitCode' for command: $command" }
33+
return stdout
34+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.gabrielfeo.develocity.api.example.notebook
2+
3+
import com.gabrielfeo.develocity.api.example.copyFromResources
4+
import com.gabrielfeo.develocity.api.example.runInShell
5+
import java.nio.file.Path
6+
import kotlin.io.path.div
7+
import kotlin.io.path.nameWithoutExtension
8+
import kotlin.io.path.notExists
9+
10+
class Jupyter(
11+
val workDir: Path,
12+
val venv: Path,
13+
) {
14+
15+
fun executeNotebook(path: Path): Path {
16+
val outputPath = path.parent / "${path.nameWithoutExtension}-executed.ipynb"
17+
runInShell(
18+
workDir,
19+
"source '${venv / "bin/activate"}' &&",
20+
"jupyter nbconvert '$path'",
21+
"--to ipynb",
22+
"--execute",
23+
"--output='$outputPath'",
24+
)
25+
return outputPath
26+
}
27+
28+
fun replaceMagics(
29+
path: Path,
30+
replacePattern: Regex,
31+
replacement: String
32+
): Path {
33+
if ((workDir / "preprocessors.py").notExists()) {
34+
copyFromResources("/preprocessors.py", workDir)
35+
}
36+
val outputPath = path.parent / "${path.nameWithoutExtension}-processed.ipynb"
37+
runInShell(
38+
workDir,
39+
"source '${venv / "bin/activate"}' &&",
40+
"jupyter nbconvert '$path'",
41+
"--to ipynb",
42+
"--output='$outputPath'",
43+
"--NotebookExporter.preprocessors=preprocessors.ReplaceMagicsPreprocessor",
44+
"--ReplaceMagicsPreprocessor.pattern='$replacePattern'",
45+
"--ReplaceMagicsPreprocessor.replacement='$replacement'",
46+
)
47+
return outputPath
48+
}
49+
}

0 commit comments

Comments
 (0)