From 9d38d568abdbb09cd3b74b66e688a4cf23fa20e7 Mon Sep 17 00:00:00 2001 From: Prabhu Subramanian Date: Mon, 12 Oct 2026 22:02:27 +0100 Subject: [PATCH 1/2] ci: resolve Maven Central through Google's mirror Maven Central is rate-limited from CI: the sbt launcher failed to download org.scala-sbt:sbt in the musl job with not-found while the artifact demonstrably existed. COURSIER_REPOSITORIES now lists Google's mirror of Central before repo1 and every resolver the build declares, which steers both the sbt launcher and the build's dependency resolution; chen-from-main writes the coursier credentials the GitHub Packages entry needs, and build.sbt keeps the mirror as a resolver for local runs. --- .github/actions/chen-from-main/action.yml | 12 ++++++++++++ .github/workflows/container-tests.yml | 5 +++++ .github/workflows/containers.yml | 4 ++++ .github/workflows/nodejstests.yml | 7 +++++++ .github/workflows/pr.yml | 7 +++++++ .github/workflows/release.yml | 4 ++++ .github/workflows/repotests.yml | 7 +++++++ build.sbt | 7 ++++++- 8 files changed, 52 insertions(+), 1 deletion(-) diff --git a/.github/actions/chen-from-main/action.yml b/.github/actions/chen-from-main/action.yml index 08d4ee33..80ad6f53 100644 --- a/.github/actions/chen-from-main/action.yml +++ b/.github/actions/chen-from-main/action.yml @@ -15,6 +15,18 @@ inputs: runs: using: composite steps: + # Repositories for the sbt launcher are steered by COURSIER_REPOSITORIES in the calling + # workflows, which lists GitHub Packages; coursier needs its own credentials file to + # authenticate against it, independent of the sbt-github-packages plugin. + - name: Coursier credentials for GitHub Packages + shell: bash + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + dir="${COURSIER_CONFIG_DIR:-$HOME/.config/coursier}" + mkdir -p "$dir" + printf 'maven.pkg.github.com x-access-token %s\n' "$GITHUB_TOKEN" > "$dir/credentials.properties" - uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5.7.0 if: inputs.setup-jdk == 'true' with: diff --git a/.github/workflows/container-tests.yml b/.github/workflows/container-tests.yml index 67436ab8..9881a72e 100644 --- a/.github/workflows/container-tests.yml +++ b/.github/workflows/container-tests.yml @@ -7,6 +7,11 @@ concurrency: cancel-in-progress: true permissions: contents: read + # Google's mirror of Maven Central first, repo1 and every resolver the build declares as + # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main + # writes the GitHub Packages credentials coursier needs for the last entry. +env: + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen jobs: lang-container-tests: strategy: diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index d6518267..c00e7cdf 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -16,6 +16,10 @@ permissions: env: REGISTRY: ghcr.io + # Google's mirror of Maven Central first, repo1 and every resolver the build declares as + # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main + # writes the GitHub Packages credentials coursier needs for the last entry. + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen IMAGE_NAME: appthreat/atom jobs: diff --git a/.github/workflows/nodejstests.yml b/.github/workflows/nodejstests.yml index a6f87014..a940d08b 100644 --- a/.github/workflows/nodejstests.yml +++ b/.github/workflows/nodejstests.yml @@ -7,6 +7,13 @@ concurrency: cancel-in-progress: true permissions: contents: read +# Google's mirror of Maven Central first, with repo1 and every resolver the build declares +# (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher +# itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt +# launcher as well as the build's dependency resolution. chen-from-main writes the GitHub +# Packages credentials coursier needs for the last entry. +env: + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen jobs: lang-testing: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 2700db81..1dab5a61 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -11,6 +11,13 @@ concurrency: cancel-in-progress: true permissions: contents: read +# Google's mirror of Maven Central first, with repo1 and every resolver the build declares +# (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher +# itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt +# launcher as well as the build's dependency resolution. chen-from-main writes the GitHub +# Packages credentials coursier needs for the last entry. +env: + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen jobs: # The unit tests and distribution build on the other operating systems, so a merge cannot diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 42ef0cae..87b89de0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,6 +10,10 @@ permissions: env: REGISTRY: ghcr.io + # Google's mirror of Maven Central first, repo1 and every resolver the build declares as + # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main + # writes the GitHub Packages credentials coursier needs for the last entry. + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen IMAGE_NAME: appthreat/atom jobs: release-win: diff --git a/.github/workflows/repotests.yml b/.github/workflows/repotests.yml index c289463a..1c2f892d 100644 --- a/.github/workflows/repotests.yml +++ b/.github/workflows/repotests.yml @@ -11,6 +11,13 @@ concurrency: cancel-in-progress: true permissions: contents: read +# Google's mirror of Maven Central first, with repo1 and every resolver the build declares +# (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher +# itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt +# launcher as well as the build's dependency resolution. chen-from-main writes the GitHub +# Packages credentials coursier needs for the last entry. +env: + COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen jobs: jvm-testing: diff --git a/build.sbt b/build.sbt index 44fb61f4..3d03d458 100644 --- a/build.sbt +++ b/build.sbt @@ -6,7 +6,12 @@ ThisBuild / scalaVersion := "3.9.0" val chenVersion = "4.0.0" lazy val atom = Projects.atom -resolvers += "Google Maven".at("https://maven.google.com/") +resolvers ++= Seq( + // Google's mirror of Maven Central: resolves the same artifacts without repo1's rate + // limiting, which has made CI builds fail while the artifact demonstrably existed. + "gcs-maven-central-mirror".at("https://maven-central.storage-download.googleapis.com/maven2"), + "Google Maven".at("https://maven.google.com/") +) libraryDependencies ++= Seq( "com.github.pathikrit" %% "better-files" % "3.9.2", "com.github.scopt" %% "scopt" % "4.1.0", From 8a6934cc9f86d24130a7ffc4113899dbc3746ec5 Mon Sep 17 00:00:00 2001 From: Prabhu Subramanian Date: Mon, 12 Oct 2026 22:16:06 +0100 Subject: [PATCH 2/2] ci: coursier wants pipe-separated COURSIER_REPOSITORIES With ';' separators coursier treats the whole value as a single repository URL - the coursier/setup-action step in repotests failed with MalformedURLException (no protocol: ivy2-local;maven-local;https://...). Pipes are the documented separator. Also rename ivy2-local to the ivy2Local alias and drop maven-local: it is not a recognized alias, and a single unparseable entry makes coursier ignore the whole variable, silently falling back to repo1-only defaults. chen-from-main publishes to ivy2Local, so that alias stays. --- .github/workflows/container-tests.yml | 5 +++-- .github/workflows/containers.yml | 5 +++-- .github/workflows/nodejstests.yml | 5 +++-- .github/workflows/pr.yml | 5 +++-- .github/workflows/release.yml | 5 +++-- .github/workflows/repotests.yml | 5 +++-- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/container-tests.yml b/.github/workflows/container-tests.yml index 9881a72e..33a6b1cd 100644 --- a/.github/workflows/container-tests.yml +++ b/.github/workflows/container-tests.yml @@ -9,9 +9,10 @@ permissions: contents: read # Google's mirror of Maven Central first, repo1 and every resolver the build declares as # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main - # writes the GitHub Packages credentials coursier needs for the last entry. + # writes the GitHub Packages credentials coursier needs for the last entry. Coursier requires + # pipe-separated entries - a ';' separator or unknown alias makes it ignore the whole list. env: - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" jobs: lang-container-tests: strategy: diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index c00e7cdf..d006200c 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -18,8 +18,9 @@ env: REGISTRY: ghcr.io # Google's mirror of Maven Central first, repo1 and every resolver the build declares as # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main - # writes the GitHub Packages credentials coursier needs for the last entry. - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + # writes the GitHub Packages credentials coursier needs for the last entry. Coursier requires + # pipe-separated entries - a ';' separator or unknown alias makes it ignore the whole list. + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" IMAGE_NAME: appthreat/atom jobs: diff --git a/.github/workflows/nodejstests.yml b/.github/workflows/nodejstests.yml index a940d08b..5785b40e 100644 --- a/.github/workflows/nodejstests.yml +++ b/.github/workflows/nodejstests.yml @@ -11,9 +11,10 @@ permissions: # (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher # itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt # launcher as well as the build's dependency resolution. chen-from-main writes the GitHub -# Packages credentials coursier needs for the last entry. +# Packages credentials coursier needs for the last entry. Coursier requires pipe-separated +# entries - a ';' separator or unknown alias makes it ignore the whole list. env: - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" jobs: lang-testing: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 1dab5a61..7e572002 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -15,9 +15,10 @@ permissions: # (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher # itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt # launcher as well as the build's dependency resolution. chen-from-main writes the GitHub -# Packages credentials coursier needs for the last entry. +# Packages credentials coursier needs for the last entry. Coursier requires pipe-separated +# entries - a ';' separator or unknown alias makes it ignore the whole list. env: - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" jobs: # The unit tests and distribution build on the other operating systems, so a merge cannot diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 87b89de0..737f779c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,8 +12,9 @@ env: REGISTRY: ghcr.io # Google's mirror of Maven Central first, repo1 and every resolver the build declares as # fallbacks (Maven Central is rate-limited from CI); drives the sbt launcher too. chen-from-main - # writes the GitHub Packages credentials coursier needs for the last entry. - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + # writes the GitHub Packages credentials coursier needs for the last entry. Coursier requires + # pipe-separated entries - a ';' separator or unknown alias makes it ignore the whole list. + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" IMAGE_NAME: appthreat/atom jobs: release-win: diff --git a/.github/workflows/repotests.yml b/.github/workflows/repotests.yml index 1c2f892d..e1ed540c 100644 --- a/.github/workflows/repotests.yml +++ b/.github/workflows/repotests.yml @@ -15,9 +15,10 @@ permissions: # (see build.sbt) as fallbacks: Maven Central is rate-limited/flaky from CI - the sbt launcher # itself failed to download org.scala-sbt:sbt while the artifact existed. This drives the sbt # launcher as well as the build's dependency resolution. chen-from-main writes the GitHub -# Packages credentials coursier needs for the last entry. +# Packages credentials coursier needs for the last entry. Coursier requires pipe-separated +# entries - a ';' separator or unknown alias makes it ignore the whole list. env: - COURSIER_REPOSITORIES: ivy2-local;maven-local;https://maven-central.storage-download.googleapis.com/maven2;https://repo1.maven.org/maven2;https://maven.google.com;https://oss.sonatype.org/content/repositories/public;https://packages.atlassian.com/mvn/maven-atlassian-external;https://repo.gradle.org/gradle/libs-releases;https://maven.pkg.github.com/appthreat/chen + COURSIER_REPOSITORIES: "ivy2Local|https://maven-central.storage-download.googleapis.com/maven2|https://repo1.maven.org/maven2|https://maven.google.com|https://oss.sonatype.org/content/repositories/public|https://packages.atlassian.com/mvn/maven-atlassian-external|https://repo.gradle.org/gradle/libs-releases|https://maven.pkg.github.com/appthreat/chen" jobs: jvm-testing: