Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generateBuildSubstitutions task to bom projects. #3653

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
43 changes: 42 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ It does not support all required rules, so you still have to run `spotlessApply`

* Unit tests target Java 8, so language features such as lambda and streams can be used in tests.

## Common tasks
## Specific tasks

### Updating OTLP proto dependency version

Expand All @@ -151,3 +151,44 @@ The OTLP proto dependency version is defined [here](proto/build.gradle). To bump
2. Download the zip source code archive
3. Run `shasum -a 256 ~/path/to/downloaded.zip` to compute its checksum
4. Update `protoVersion` and `protoChecksum` in the build file with the new version and checksum

### Composing builds

Beware that this section is only meant for developers of opentelemetry-java, or closely related projects.
The steps described here could change at any time and what you do for one version (commit) may break
with the next one already.

Gradle provides a feature called ["composite builds"](https://docs.gradle.org/current/userguide/composite_builds.html)
that allows to replace some normally externally provided dependencies with a project that is built
(included) in the same Gradle invocation. This can be useful to quickly test a new feature or bug fix you are
developing in opentelmetry-java with the examples or the app or instrumentation library where you
Oberon00 marked this conversation as resolved.
Show resolved Hide resolved
need the feature or run into the bug. Unfortunately, opentelemetry-java does not work out of the box
with this feature because Gradle is unable to map the project names to the customized artifact
coordinates (see e.g. [gradle/gradle#18291](https://github.com/gradle/gradle/issues/18291)
and related issues. However, gradle supports manually declaring the mapping between ("substitution of")
artifact coordinates and project names. To ease this tedious task, opentelemetry-java provides a
gradle task `:generateBuildSubstitutions` that generates a code snippet with these substitutions in
kts (Kotlin Script) format.

Example usage could be as follows:

1. Run `./gradlew generateBuildSubstitutions`
2. Two files named `build/substitutions.gradle.kts` are generated in the bom and bom-alpha project's
directory, containing substitutions for the stable and alpha projects respectively.
3. Copy & paste the content of these files to a new `settings.gradle.kts` or the one where you want
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still cumbersome. If anyone knows a better format I could generate that could be used in a more straight-forward way, that would be appreciated.

to include the opentelemetry build into, so that it contains something like the following:

```kotlin
includeBuild("PATH/TO/OPENTELEMETRY-JAVA/ROOT/DIRECTORY") {
// Copy & paste following block from the generated substitutions.gradle.kts, *not* from here!
dependencySubstitution {
substitute(module("io.opentelemetry:opentelemetry-api")).using(project(":api:all"))
substitute(module("io.opentelemetry:opentelemetry-sdk")).using(project(":sdk:all"))
// ...
}
}
```

4. If you now build your project, it will use the included build to supply the opentelemetry-java artifacts,
ignoring any version declarations. Use the prefix `:DIRECTORY:` to refer to tasks/projects within
the included build, where DIRECTORY is the name of the directory in the included build (only the part after the last `/`).
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ Libraries will usually only need `opentelemetry-api`, while applications
will want to use the `opentelemetry-sdk` module which contains our standard implementation
of the APIs.

## Gradle composite builds

For opentelemetry-java developers that need to test the latest source code with another
project, composite builds can be used as an alternative to `publishToMavenLocal`. This
requires some setup which is explained [here](CONTRIBUTING.md#composing-builds).

## Releases

See the [VERSIONING.md](VERSIONING.md) document for our policies for releases and compatibility
Expand Down
25 changes: 2 additions & 23 deletions bom-alpha/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
plugins {
id("java-platform")
id("otel.publish-conventions")
id("otel.bom-conventions")
}

description = "OpenTelemetry Bill of Materials (Alpha)"
group = "io.opentelemetry"
base.archivesBaseName = "opentelemetry-bom-alpha"

rootProject.subprojects.forEach { subproject ->
if (!project.name.startsWith("bom")) {
evaluationDependsOn(subproject.path)
}
}

afterEvaluate {
dependencies {
constraints {
rootProject.subprojects
.sortedBy { it.findProperty("archivesBaseName") as String? }
.filter { !it.name.startsWith("bom") }
.filter { it.findProperty("otel.release") == "alpha" }
.forEach { project ->
project.plugins.withId("maven-publish") {
api(project)
}
}
}
}
}
otelBom.projectFilter.set { it.findProperty("otel.release") == "alpha" }
25 changes: 2 additions & 23 deletions bom/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,30 +1,9 @@
plugins {
id("java-platform")
id("otel.publish-conventions")
id("otel.bom-conventions")
}

description = "OpenTelemetry Bill of Materials"
group = "io.opentelemetry"
base.archivesBaseName = "opentelemetry-bom"

rootProject.subprojects.forEach { subproject ->
if (project != subproject) {
evaluationDependsOn(subproject.path)
}
}

afterEvaluate {
dependencies {
constraints {
rootProject.subprojects
.sortedBy { it.findProperty("archivesBaseName") as String? }
.filter { !it.name.startsWith("bom") }
.filter { !it.hasProperty("otel.release") }
.forEach { project ->
project.plugins.withId("maven-publish") {
api(project)
}
}
}
}
}
otelBom.projectFilter.set { !it.hasProperty("otel.release") }
6 changes: 6 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ nexusPublishing {
}
}

// The BOM projects register dependent tasks that actually do the generating.
tasks.register("generateBuildSubstitutions") {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to copy-paste this.

group = "publishing"
description = "Generate a code snippet that can be copy-pasted for use in composite builds."
}

subprojects {
group = "io.opentelemetry"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.gradle

import org.gradle.api.Project
import org.gradle.api.provider.Property
import java.util.function.Predicate

abstract class OtelBomExtension {
abstract val projectFilter: Property<Predicate<Project>>
}
64 changes: 64 additions & 0 deletions buildSrc/src/main/kotlin/otel.bom-conventions.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import io.opentelemetry.gradle.OtelBomExtension
import org.gradle.kotlin.dsl.create

plugins {
id("otel.publish-conventions")
id("java-platform")
}

if (!project.name.startsWith("bom")) {
throw IllegalStateException("Name of BOM projects must start with 'bom'.")
}

rootProject.subprojects.forEach { subproject ->
if (!subproject.name.startsWith("bom")) {
evaluationDependsOn(subproject.path)
}
}
val otelBom = extensions.create<OtelBomExtension>("otelBom")

val generateBuildSubstitutions by tasks.registering {
group = "publishing"
description = "Generate a code snippet that can be copy-pasted for use in composite builds."
}

tasks.named("publish") {
dependsOn(generateBuildSubstitutions)
}

rootProject.tasks.named(generateBuildSubstitutions.name) {
dependsOn(generateBuildSubstitutions)
}

afterEvaluate {
otelBom.projectFilter.finalizeValue()
val stableProjects = rootProject.subprojects
.sortedBy { it.findProperty("archivesBaseName") as String? }
.filter { !it.name.startsWith("bom") }
.filter(otelBom.projectFilter.get()::test)
.filter { it.plugins.hasPlugin("maven-publish") }

generateBuildSubstitutions {
val outputFile = File(buildDir, "substitutions.gradle.kts")
outputs.file(outputFile)
val substitutionSnippet = stableProjects.joinToString(
separator = "\n",
prefix = "dependencySubstitution {\n",
postfix = "\n}\n"
) { project ->
val publication = project.publishing.publications.getByName("mavenPublication") as MavenPublication
" substitute(module(\"${publication.groupId}:${publication.artifactId}\")).using(project(\"${project.path}\"))"
}
inputs.property("projectPathsAndArtifactCoordinates", substitutionSnippet)
doFirst {
outputFile.writeText(substitutionSnippet)
}
}
stableProjects.forEach { project ->
dependencies {
constraints {
api(project)
}
}
}
}