Skip to content
Open
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
2 changes: 1 addition & 1 deletion bin/docker-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ unzip -d /opt/maven maven.zip
rm maven.zip
mv /opt/maven/*/* /opt/maven

curl -fLo gradle.zip https://services.gradle.org/distributions/gradle-8.14.4-bin.zip
curl -fLo gradle.zip https://services.gradle.org/distributions/gradle-9.4.1-bin.zip
unzip -d /opt/gradle gradle.zip
rm gradle.zip
mv /opt/gradle/*/* /opt/gradle
Expand Down
16 changes: 16 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import org.gradle.plugin.use.PluginDependency

plugins {
`kotlin-dsl`
}

dependencies {
implementation(plugin(libs.plugins.kotlin.jvm))
implementation(plugin(libs.plugins.shadow))
implementation(plugin(libs.plugins.vanniktech.maven.publish))
}

// Maps a version-catalog plugin alias to its plugin-marker dependency so the
// external plugin can be applied by id from the precompiled convention plugins.
fun plugin(dependency: Provider<PluginDependency>): Provider<String> =
dependency.map { "${it.pluginId}:${it.pluginId}.gradle.plugin:${it.version}" }
13 changes: 13 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
dependencyResolutionManagement {
repositories {
gradlePluginPortal()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

rootProject.name = "build-logic"
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.sourcegraph.buildlogic

import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.TaskProvider

/**
* Registers a task that writes [content] (plus a trailing newline) to
* build/generated/[relativePath], tracking the content for up-to-date checks.
*/
fun Project.registerGeneratedFile(
name: String,
relativePath: String,
content: String,
): TaskProvider<Task> {
val output = layout.buildDirectory.file("generated/$relativePath")
return tasks.register(name) {
inputs.property("content", content)
outputs.file(output)
doLast {
val file = output.get().asFile
file.parentFile.mkdirs()
file.writeText("$content\n")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.sourcegraph.buildlogic

import java.io.File
import java.util.Properties

/**
* Reads the JVM flags scip-javac needs to access internal javac APIs on Java 9+, keeping
* gradle/javac-internals.properties the single source of truth.
*/
object JavacInternals {
fun propertiesFile(rootDir: File): File = rootDir.resolve("gradle/javac-internals.properties")

fun jvmOptions(rootDir: File): List<String> {
val file = propertiesFile(rootDir)
val raw =
Properties()
.apply { file.inputStream().use { load(it) } }
.getProperty("javac.jvmOptions") ?: error("Missing javac.jvmOptions in $file")
return raw.split(',').map { it.trim() }.filter { it.isNotEmpty() }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.sourcegraph.buildlogic

import java.io.File
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.compile.JavaCompile

/**
* Wires this [JavaCompile] task to run the scip-javac compiler plugin: puts the shaded plugin jar
* [javacShadowJar] on the compile classpath and forks javac with the internal-API flags from
* gradle/javac-internals.properties, recording [targetroot] as an output directory.
*
* Callers still add the case-specific `-Xplugin:scip ...` arguments and annotation processors.
*/
fun JavaCompile.useScipJavac(
rootDir: File,
javacShadowJar: Configuration,
targetroot: Provider<Directory>,
) {
classpath = classpath.plus(javacShadowJar)
outputs.dir(targetroot)
options.isFork = true
options.forkOptions.jvmArgs =
(options.forkOptions.jvmArgs ?: emptyList()) + JavacInternals.jvmOptions(rootDir)
}

/**
* Registers a `doFirst` action that empties [dir] (deletes then recreates it) before the task runs.
*
* The action lives here, in compiled build logic, rather than in a `.gradle.kts` script: a lambda
* declared in a build script captures a hidden reference to the script object, which the
* configuration cache cannot serialize.
*/
fun Task.cleanDirectoryBeforeRunning(dir: Provider<Directory>) {
doFirst {
val file = dir.get().asFile
file.deleteRecursively()
file.mkdirs()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.sourcegraph.buildlogic

import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.Directory
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.provider.Provider

/**
* Declares a resolvable [Configuration] consuming the [configuration] artifact published by the
* project at [producerPath]. The returned `FileCollection` resolves to that project's output and
* carries the task dependency that builds it, so consumers avoid `evaluationDependsOn` and reaching
* across project boundaries, keeping evaluation order and the configuration cache intact.
*/
fun Project.projectArtifact(
producerPath: String,
configuration: String,
name: String,
): Configuration {
val bucket = configurations.dependencyScope("${name}Classpath")
dependencies.add(
bucket.name,
dependencies.project(mapOf("path" to producerPath, "configuration" to configuration)),
)
return configurations.resolvable(name) { extendsFrom(bucket.get()) }.get()
}

/**
* Resolvable view of another project's shaded jar (the `scip.shadow-producer` convention plugin).
*/
fun Project.shadowJarArtifact(producerPath: String, name: String): Configuration =
projectArtifact(producerPath, "shadowJarElements", name)

/**
* Publishes [directory] (produced by [producedBy]) as a consumable artifact in a [name]
* configuration, so a sibling project can resolve it with [projectArtifact].
*/
fun Project.publishDirectoryArtifact(
name: String,
directory: Provider<Directory>,
producedBy: Any,
) {
val elements = configurations.consumable(name).get()
artifacts.add(elements.name, directory) { builtBy(producedBy) }
}

/**
* Builds the `kotlinc` arguments that load the scip-kotlinc compiler plugin from [pluginClasspath]
* (the resolved shaded jar) and point it at [sourceroot]/[targetroot].
*
* The mapping lives here, in compiled build logic, rather than in a build script: a `.map {}`
* lambda declared in a `.gradle.kts` file captures a hidden reference to the script object, which
* the configuration cache cannot serialize.
*/
fun scipKotlincPluginArgs(
pluginClasspath: Provider<Set<FileSystemLocation>>,
sourceroot: String,
targetroot: String,
): Provider<List<String>> =
pluginClasspath.map { locations ->
listOf(
"-Xplugin=${locations.single().asFile.absolutePath}",
"-P",
"plugin:scip-kotlinc:sourceroot=$sourceroot",
"-P",
"plugin:scip-kotlinc:targetroot=$targetroot",
)
}
32 changes: 32 additions & 0 deletions build-logic/src/main/kotlin/scip.java-base.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import org.gradle.api.artifacts.VersionCatalogsExtension

plugins {
id("scip.project-base")
java
}

val libs = extensions.getByType<VersionCatalogsExtension>().named("libs")

tasks.withType<JavaCompile>().configureEach {
options.encoding = "UTF-8"
options.release.set(17)
}

tasks.withType<Javadoc>().configureEach {
options.encoding = "UTF-8"
(options as StandardJavadocDocletOptions).addStringOption("Xdoclint:none", "-quiet")
}

testing {
suites {
named<JvmTestSuite>("test") {
useJUnitJupiter(libs.findVersion("junit-jupiter").get().requiredVersion)
}
}
}

tasks.withType<Test>().configureEach {
testLogging {
events("failed", "skipped")
}
}
4 changes: 4 additions & 0 deletions build-logic/src/main/kotlin/scip.java-library.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
plugins {
id("scip.java-base")
`java-library`
}
10 changes: 10 additions & 0 deletions build-logic/src/main/kotlin/scip.kotlin-jvm.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("org.jetbrains.kotlin.jvm")
}

tasks.withType<KotlinCompile>().configureEach {
compilerOptions.jvmTarget.set(JvmTarget.JVM_17)
}
34 changes: 34 additions & 0 deletions build-logic/src/main/kotlin/scip.maven-publish.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import com.vanniktech.maven.publish.MavenPublishBaseExtension

plugins {
id("com.vanniktech.maven.publish")
}

extensions.configure<MavenPublishBaseExtension>("mavenPublishing") {
val repositoryUrl = "https://github.com/sourcegraph/scip-java"
publishToMavenCentral()
signAllPublications()

pom {
name.set(project.name)
description.set(provider { project.description ?: project.name })
url.set(repositoryUrl)
licenses {
license {
name.set("Apache-2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0")
}
}
developers {
developer {
id.set("sourcegraph")
name.set("Sourcegraph")
}
}
scm {
connection.set("scm:git:$repositoryUrl.git")
developerConnection.set("scm:git:ssh://git@github.com/sourcegraph/scip-java.git")
url.set(repositoryUrl)
}
}
}
9 changes: 9 additions & 0 deletions build-logic/src/main/kotlin/scip.project-base.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
group = "com.sourcegraph"
version = providers.gradleProperty("releaseVersion").orElse("0.0.0-SNAPSHOT").get()

// Several modules also have Bazel `BUILD` files. On the default macOS
// case-insensitive filesystem, Gradle's default `build/` directory collides
// with those files, so keep Gradle outputs under the already-ignored target/.
if (layout.projectDirectory.file("BUILD").asFile.isFile) {
layout.buildDirectory.set(layout.projectDirectory.dir("target/gradle"))
}
10 changes: 10 additions & 0 deletions build-logic/src/main/kotlin/scip.shadow-producer.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

plugins {
id("com.gradleup.shadow")
}

// Publish the shaded jar as a consumable artifact, resolved by consumers via
// `shadowJarArtifact` (see SharedArtifacts.kt).
val shadowJarElements = configurations.consumable("shadowJarElements").get()
artifacts.add(shadowJarElements.name, tasks.named<ShadowJar>("shadowJar"))
Loading
Loading