Skip to content
Draft
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
16 changes: 5 additions & 11 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,6 @@ default:
# Apache Maven Wrapper supports MVNW_REPOURL for repository-manager downloads:
# https://maven.apache.org/tools/wrapper/#Using_a_Maven_Repository_Manager
- export MVNW_REPOURL=${MAVEN_REPOSITORY_PROXY%/}
# Route Gradle distribution download through MASS pull-through cache
- |
mass_read_host="${MASS_READ_URL#https://}"
mass_read_host="${mass_read_host%/}"
sed -i "/^distributionUrl=/ s|services.gradle.org|${mass_read_host}/internal/artifact/services.gradle.org|" gradle/wrapper/gradle-wrapper.properties
- mkdir -p .mvn/caches
# Redirect Spotless's Equo/Solstice P2 cache into the project tree so it is captured by the GitLab cache.
# Solstice (https://github.com/equodev/equo-ide) defaults to ~/.m2/repository/dev/equo/p2-data, which is outside $CI_PROJECT_DIR.
Expand All @@ -271,6 +266,8 @@ default:
# GitLab's cache helper restores .gradle as root, but we run as non-root-user (uid 1001),
# and Gradle does `chmod 700 .gradle` on startup which requires user ownership.
- sudo chown -R 1001:1001 .gradle
# Bootstrap Gradle through MASS with upstream fallback.
- bootstrap_gradle_distribution
after_script:
- *cgroup_info
- *container_info
Expand Down Expand Up @@ -818,6 +815,7 @@ muzzle-dep-report:
- dependency-lib
unprotect: true
before_script:
- source .gitlab/gitlab-utils.sh
- git config --global --add safe.directory "$CI_PROJECT_DIR"
# Akka token added to SSM from https://account.akka.io/token
- export ORG_GRADLE_PROJECT_akkaRepositoryToken=$(aws ssm get-parameter --region us-east-1 --name ci.dd-trace-java.akka_repo_token --with-decryption --query "Parameter.Value" --out text)
Expand All @@ -838,17 +836,13 @@ muzzle-dep-report:
# Apache Maven Wrapper supports MVNW_REPOURL for repository-manager downloads:
# https://maven.apache.org/tools/wrapper/#Using_a_Maven_Repository_Manager
- export MVNW_REPOURL=${MAVEN_REPOSITORY_PROXY%/}
# Route Gradle distribution download through MASS pull-through cache
- |
mass_read_host="${MASS_READ_URL#https://}"
mass_read_host="${mass_read_host%/}"
sed -i "/^distributionUrl=/ s|services.gradle.org|${mass_read_host}/internal/artifact/services.gradle.org|" gradle/wrapper/gradle-wrapper.properties
- *normalize_node_index
- *prepare_test_env
# Disable CDS in forked JVMs to avoid SIGSEGVs on Linux arm64.
- export GRADLE_OPTS="-Dorg.gradle.jvmargs='-Xshare:off -Xms$GRADLE_MEMORY_MIN -Xmx$GRADLE_MEMORY_MAX -XX:ErrorFile=/tmp/hs_err_pid%p.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Djava.util.prefs.userRoot=/tmp/.java/.userPrefs-${CI_JOB_ID}' -Ddatadog.forkedMinHeapSize=128M -Ddatadog.forkedMaxHeapSize=1024M"
- export GRADLE_ARGS="--build-cache --stacktrace --no-daemon --parallel --max-workers=$GRADLE_WORKERS"
- ./gradlew --version
# Bootstrap Gradle through MASS with upstream fallback.
- bootstrap_gradle_distribution
script:
- *gitlab_base_ref_params
- ./gradlew $GRADLE_TARGET $GRADLE_PARAMS -PtestJvm=$testJvm -Pslot=$CI_NODE_INDEX/$CI_NODE_TOTAL $GRADLE_ARGS --continue
Expand Down
45 changes: 45 additions & 0 deletions .gitlab/gitlab-utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,51 @@ function gitlab_section_end () {
echo -e "section_end:`date +%s`:${section_title}\r\e[0K"
}

# Bootstrap Gradle through MASS, retrying upstream because the wrapper supports only one URL.
# The pinned checksum applies to either source. Call after `.gradle` and the Gradle environment are
# prepared.
function bootstrap_gradle_distribution () {
local props="gradle/wrapper/gradle-wrapper.properties"
local upstream_props="/tmp/gradle-wrapper.upstream.properties"
local mass_read_host

if [ -z "${MASS_READ_URL:-}" ]; then
./gradlew --version
return
fi

mass_read_host="${MASS_READ_URL#https://}"
mass_read_host="${mass_read_host%/}"

# Derive upstream even if an earlier call already routed the URL through MASS.
sed "/^distributionUrl=/ s|${mass_read_host}/internal/artifact/||" "$props" > "$upstream_props"

if grep -q "^distributionUrl=.*${mass_read_host}" "$props"; then
# Avoid nesting the MASS prefix.
echo "Gradle distribution is already routed through ${mass_read_host}"
else
# Redirect because GNU and BSD `sed -i` differ.
sed "/^distributionUrl=/ s|services.gradle.org|${mass_read_host}/internal/artifact/services.gradle.org|" "$props" > "$props.mass" &&
mv "$props.mass" "$props"
fi

if ./gradlew --version; then
rm -f "$upstream_props"
return
fi

if ! grep -q "^distributionUrl=" "$upstream_props"; then
echo -e "${TEXT_RED}Gradle distribution bootstrap failed and no upstream distributionUrl could be derived from ${props} to fall back to${TEXT_CLEAR}" >&2
return 1
fi

# Keep upstream: changing the URL changes the wrapper cache key and would download twice.
echo -e "${TEXT_YELLOW}MASS_FALLBACK gradle-distribution: ${MASS_READ_URL} could not serve the Gradle distribution, retrying via services.gradle.org${TEXT_CLEAR}" >&2
cp "$upstream_props" "$props"
rm -f "$upstream_props"
./gradlew --version
}

# A subset of ansi color/formatting codes https://misc.flogisoft.com/bash/tip_colors_and_formatting
export TEXT_RED="\e[31m"
export TEXT_GREEN="\e[32m"
Expand Down
15 changes: 15 additions & 0 deletions build-logic/conventions/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
`kotlin-dsl`
`jvm-test-suite`
}

java {
Expand All @@ -12,3 +13,17 @@ kotlin {
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
}
}

@Suppress("UnstableApiUsage")
testing {
suites {
named<JvmTestSuite>("test") {
useJUnitJupiter(libs.versions.junit5)
dependencies {
implementation(libs.junit.jupiter)
implementation(libs.junit.jupiter.engine)
implementation(libs.assertj.core)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ constructor(objects: ObjectFactory, providers: ProviderFactory) {
val readUrl: Property<String> =
objects.property(String::class.java).convention(providers.environmentVariable("MASS_READ_URL"))

fun artifactUrl(upstreamArtifactUrl: String): String {
val massReadUrl = readUrl.orNull ?: return "https://$upstreamArtifactUrl"
fun artifactUrl(upstreamArtifactUrl: String): String = artifactUrls(upstreamArtifactUrl).first()

/**
* Ordered repository URLs: MASS, then upstream. Gradle advances only for missing artifacts, so
* this covers MASS cache misses, not connection failures. Without MASS, returns only upstream.
*/
fun artifactUrls(upstreamArtifactUrl: String): List<String> {
val upstreamUrl = "https://$upstreamArtifactUrl"
val massReadUrl = readUrl.orNull?.takeIf { it.isNotBlank() } ?: return listOf(upstreamUrl)
val baseUrl = if (massReadUrl.endsWith("/")) massReadUrl else "$massReadUrl/"
return "${baseUrl}internal/artifact/$upstreamArtifactUrl"
return listOf("${baseUrl}internal/artifact/$upstreamArtifactUrl", upstreamUrl)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package datadog.buildlogic.mass

import org.assertj.core.api.Assertions.assertThat
import org.gradle.kotlin.dsl.newInstance
import org.gradle.testfixtures.ProjectBuilder
import org.junit.jupiter.api.Test

class MassExtensionTest {

private fun extension(massReadUrl: String?): MassExtension {
val project = ProjectBuilder.builder().build()
// Empty overrides the environment-backed convention.
return project.objects.newInstance<MassExtension>().also { it.readUrl.set(massReadUrl ?: "") }
}

@Test
fun `routes artifacts through MASS and keeps the upstream host as a second repository`() {
val mass = extension("https://mass.example")

assertThat(mass.artifactUrls("dlcdn.apache.org")).containsExactly(
"https://mass.example/internal/artifact/dlcdn.apache.org",
"https://dlcdn.apache.org",
)
assertThat(mass.artifactUrl("dlcdn.apache.org"))
.isEqualTo("https://mass.example/internal/artifact/dlcdn.apache.org")
}

@Test
fun `tolerates a trailing slash on the MASS read url`() {
val mass = extension("https://mass.example/")

assertThat(mass.artifactUrls("dlcdn.apache.org").first())
.isEqualTo("https://mass.example/internal/artifact/dlcdn.apache.org")
}

@Test
fun `declares the upstream host only once when MASS is not configured`() {
listOf(null, "", " ").forEach { unset ->
val mass = extension(unset)

assertThat(mass.artifactUrls("dlcdn.apache.org"))
.containsExactly("https://dlcdn.apache.org")
assertThat(mass.artifactUrl("dlcdn.apache.org")).isEqualTo("https://dlcdn.apache.org")
}
}

@Test
fun `keeps any path on the upstream artifact url`() {
val mass = extension("https://mass.example")

assertThat(mass.artifactUrls("github.com/wildfly/wildfly/releases/download/")).containsExactly(
"https://mass.example/internal/artifact/github.com/wildfly/wildfly/releases/download/",
"https://github.com/wildfly/wildfly/releases/download/",
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,26 @@ import java.net.URI

internal const val MASS_READ_URL_ENV = "MASS_READ_URL"

/** Public Gradle distribution source. */
internal const val UPSTREAM_DISTRIBUTIONS_BASE_URL = "https://services.gradle.org/distributions"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be read from an ENV instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not really sure, there no other URLs other than https://services.gradle.org/distributions or am I missing something?


internal fun gradleDistributionUri(massReadUrl: String, gradleVersion: String): URI {
val baseUrl = if (massReadUrl.endsWith("/")) massReadUrl else "$massReadUrl/"
return URI.create(
"${baseUrl}internal/artifact/services.gradle.org/distributions/gradle-$gradleVersion-bin.zip",
)
}

internal fun upstreamGradleDistributionUri(gradleVersion: String): URI =
URI.create("$UPSTREAM_DISTRIBUTIONS_BASE_URL/gradle-$gradleVersion-bin.zip")

/** Nested Gradle sources, preferring MASS and falling back upstream. */
internal fun gradleDistributionUris(massReadUrl: String?, gradleVersion: String): List<URI> =
if (massReadUrl.isNullOrBlank()) {
listOf(upstreamGradleDistributionUri(gradleVersion))
} else {
listOf(
gradleDistributionUri(massReadUrl, gradleVersion),
upstreamGradleDistributionUri(gradleVersion),
)
}
Loading