diff --git a/.github/actions/maven-mirror/action.yml b/.github/actions/maven-mirror/action.yml new file mode 100644 index 0000000..59ef3ab --- /dev/null +++ b/.github/actions/maven-mirror/action.yml @@ -0,0 +1,42 @@ +name: Maven mirror +description: > + Points Gradle at the runners' Maven mirror (Maven Central, the Gradle Plugin + Portal and PaperMC) by installing a Gradle init script. Uses the runner's + MAVEN_MIRROR_URL, which only the self-hosted runners set. Without it, or when + the mirror does not answer, the action warns and changes nothing, so Gradle + resolves from upstream exactly as before. + +outputs: + init-script: + description: > + Path of the installed init script, empty when the mirror is not used. + Pass it to Docker builds as the BuildKit secret `gradle_init`. + value: ${{ steps.install.outputs.init-script }} + +runs: + using: composite + steps: + - name: Install Maven mirror init script + id: install + shell: bash + env: + TEMPLATE: ${{ github.action_path }}/grounds-maven-mirror.init.gradle.kts + run: | + set -euo pipefail + url="${MAVEN_MIRROR_URL:-}" + url="${url%/}" + if [ -z "$url" ]; then + echo "::warning::MAVEN_MIRROR_URL is not set on this runner, resolving from upstream" + exit 0 + fi + probe="$url/releases/org/jetbrains/kotlin/kotlin-stdlib/maven-metadata.xml" + status="$(curl -s -o /dev/null -m 3 -w '%{http_code}' "$probe" || true)" + if [ "$status" != "200" ]; then + echo "::warning::Maven mirror $url unreachable (HTTP ${status:-none}), resolving from upstream" + exit 0 + fi + script="$HOME/.gradle/init.d/grounds-maven-mirror.init.gradle.kts" + mkdir -p "$(dirname "$script")" + sed "s|@MIRROR_URL@|$url|" "$TEMPLATE" > "$script" + echo "init-script=$script" >> "$GITHUB_OUTPUT" + echo "Using Maven mirror $url" diff --git a/.github/actions/maven-mirror/grounds-maven-mirror.init.gradle.kts b/.github/actions/maven-mirror/grounds-maven-mirror.init.gradle.kts new file mode 100644 index 0000000..b106b24 --- /dev/null +++ b/.github/actions/maven-mirror/grounds-maven-mirror.init.gradle.kts @@ -0,0 +1,55 @@ +// Points the public upstream repositories at the CI runners' Maven mirror. +// Installed by the groundsgg/.github maven-mirror action on self-hosted runners only. +// GitHub Packages, mavenLocal() and every other repository stay as the build declares them. +// +// The mirror is plain HTTP inside the cluster, so only the rewritten repositories get +// isAllowInsecureProtocol. + +val mirror = "@MIRROR_URL@".trimEnd('/') +val pluginPortal = "https://plugins.gradle.org/m2" +val rewrites = mapOf( + "https://repo.maven.apache.org/maven2" to "$mirror/releases", + "https://repo1.maven.org/maven2" to "$mirror/releases", + pluginPortal to "$mirror/gradle-plugins", + "https://repo.papermc.io/repository/maven-public" to "$mirror/papermc", +) + +fun RepositoryHandler.useMirror() { + whenObjectAdded { + val repo = this as? MavenArtifactRepository ?: return@whenObjectAdded + val upstream = repo.url.toString().trimEnd('/') + val target = rewrites[upstream] ?: return@whenObjectAdded + if (upstream == pluginPortal) { + // gradlePluginPortal() is a repository Gradle builds itself; swap it for a plain + // maven repository rather than mutating it. Adding here keeps its place in the list. + remove(repo) + maven { + name = "groundsMavenMirrorGradlePlugins" + url = uri(target) + isAllowInsecureProtocol = true + } + } else { + repo.url = uri(target) + repo.isAllowInsecureProtocol = true + } + } +} + +println("Using Maven mirror $mirror") + +beforeSettings { + buildscript.repositories.useMirror() + pluginManagement.repositories.useMirror() + dependencyResolutionManagement.repositories.useMirror() +} + +settingsEvaluated { + // Without any pluginManagement repositories Gradle falls back to an implicit plugin portal + // that never enters this list; declare it so it gets swapped for the mirror. + if (pluginManagement.repositories.isEmpty()) pluginManagement.repositories.gradlePluginPortal() +} + +allprojects { + buildscript.repositories.useMirror() + repositories.useMirror() +} diff --git a/.github/workflows/docker-gradle-build-push.yml b/.github/workflows/docker-gradle-build-push.yml index 3f76081..8e59f1d 100644 --- a/.github/workflows/docker-gradle-build-push.yml +++ b/.github/workflows/docker-gradle-build-push.yml @@ -80,6 +80,14 @@ jobs: echo "github.token=${{ secrets.PACKAGES_TOKEN || secrets.GITHUB_TOKEN }}" } > ~/.gradle/gradle.properties + # Installs the init script on the runner, for the `./gradlew -q properties` + # below, and hands the same file to the image builds as the BuildKit secret + # `gradle_init`. A Dockerfile opts in by mounting it on its Gradle RUN: + # --mount=type=secret,id=gradle_init,target=/root/.gradle/init.d/grounds-maven-mirror.init.gradle.kts,required=false + - name: Use the Maven mirror + id: mirror + uses: groundsgg/.github/.github/actions/maven-mirror@main + - name: Read Gradle project version id: gradle_version run: | @@ -186,6 +194,7 @@ jobs: GITHUB_USER=${{ github.actor }} secrets: | github_token=${{ secrets.PACKAGES_TOKEN || secrets.GITHUB_TOKEN }} + secret-files: ${{ steps.mirror.outputs.init-script && format('gradle_init={0}', steps.mirror.outputs.init-script) || '' }} - name: Build and push image if: github.event_name != 'pull_request' @@ -203,6 +212,7 @@ jobs: GITHUB_USER=${{ github.actor }} secrets: | github_token=${{ secrets.PACKAGES_TOKEN || secrets.GITHUB_TOKEN }} + secret-files: ${{ steps.mirror.outputs.init-script && format('gradle_init={0}', steps.mirror.outputs.init-script) || '' }} - name: Generate SBOM if: github.event_name != 'pull_request' diff --git a/.github/workflows/gradle-ci.yml b/.github/workflows/gradle-ci.yml index bc94e26..b4fe9b3 100644 --- a/.github/workflows/gradle-ci.yml +++ b/.github/workflows/gradle-ci.yml @@ -68,6 +68,9 @@ jobs: with: cache-disabled: ${{ runner.environment != 'github-hosted' }} + - name: Use the Maven mirror + uses: groundsgg/.github/.github/actions/maven-mirror@main + - name: Configure GitHub Packages credentials run: | mkdir -p ~/.gradle diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml index 51158ef..3740421 100644 --- a/.github/workflows/gradle-publish.yml +++ b/.github/workflows/gradle-publish.yml @@ -68,6 +68,9 @@ jobs: with: cache-disabled: ${{ runner.environment != 'github-hosted' }} + - name: Use the Maven mirror + uses: groundsgg/.github/.github/actions/maven-mirror@main + - name: Configure GitHub Packages credentials for resolution run: | mkdir -p ~/.gradle