diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afd67dd..4e65ac9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,11 +14,6 @@ concurrency: permissions: contents: read -env: - GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} - GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} - GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} - jobs: # Code-quality gate + the targets whose tests actually EXECUTE on a Linux host: # JVM, JS (Node + headless-Chrome), Wasm (wasmJs/wasmWasi on Node) and the @@ -39,6 +34,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Cache Konan (Kotlin/Native toolchain) uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 @@ -76,6 +73,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Cache Konan (Kotlin/Native toolchain) uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4f18b98..48b4ea4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -40,6 +40,8 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Build documentation run: ./gradlew dokkaGenerate --no-daemon diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index baeab3d..0442163 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,8 @@ jobs: - name: Setup Gradle uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 + with: + develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }} - name: Build, test & API check (all targets) run: ./gradlew build --stacktrace diff --git a/README.md b/README.md index 745af8b..d1f5893 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![codecov](https://codecov.io/gh/meshtastic/kzstd/graph/badge.svg)](https://codecov.io/gh/meshtastic/kzstd) [![License: GPL-3.0](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE) [![Kotlin Multiplatform](https://img.shields.io/badge/Kotlin-Multiplatform-blue.svg?logo=kotlin)](https://kotlinlang.org) +[![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://community.develocity.cloud/scans?search.rootProjectNames=kzstd) A pure-Kotlin, multiplatform [Zstandard](https://facebook.github.io/zstd/) (zstd) codec with dictionary support. It produces and reads **standard zstd frames** that diff --git a/gradle/build-cache.settings.gradle b/gradle/build-cache.settings.gradle deleted file mode 100644 index dd9bfc8..0000000 --- a/gradle/build-cache.settings.gradle +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Shared remote HTTP Gradle build cache for Meshtastic KMP libraries. - * - * Credentials come from the GRADLE_CACHE_URL / GRADLE_CACHE_USERNAME / - * GRADLE_CACHE_PASSWORD environment variables (CI secrets), or a - * local.properties / config.properties entry for local use. Writes to the - * cache happen only from trusted events (local dev, push, merge_group) with - * credentials present, so pull-request runs (and credential-less fork PRs) - * stay pull-only and cannot poison the cache. - */ - -def getMeshProperty(String key) { - def env = System.getenv(key) - if (env) return env - def currentDir = settingsDir - while (currentDir != null) { - for (name in ["local.properties", "config.properties"]) { - def f = new File(currentDir, name) - if (f.exists()) { - def props = new Properties() - f.withInputStream { props.load(it) } - if (props.containsKey(key)) return props.getProperty(key) - } - } - currentDir = currentDir.parentFile - } - return null -} - -buildCache { - local { - enabled = true - } - remote(HttpBuildCache) { - // Some cache servers return 403 on "Expect: 100-continue". - useExpectContinue = false - def cacheUrl = getMeshProperty("GRADLE_CACHE_URL")?.trim() - def cacheUsername = getMeshProperty("GRADLE_CACHE_USERNAME")?.trim() - def cachePassword = getMeshProperty("GRADLE_CACHE_PASSWORD")?.trim() - if (cacheUrl) { - // HTTPS + valid TLS enforced (no allowInsecureProtocol / no - // allowUntrustedServer): the cache server must present a trusted - // certificate over TLS. - url = cacheUrl.endsWith("/") ? cacheUrl : "${cacheUrl}/" - if (cacheUsername && cachePassword) { - credentials { - username = cacheUsername - password = cachePassword - } - } - // Write only from trusted events (local dev, push to a protected - // branch, or the merge queue) with credentials — never from - // pull_request runs, so unmerged code can't poison the cache. - def eventName = System.getenv("GITHUB_EVENT_NAME") - def trustedForPush = eventName == null || eventName == "push" || eventName == "merge_group" - push = (cacheUsername && cachePassword && trustedForPush) - enabled = true - } else { - enabled = false - } - } -} diff --git a/gradle/develocity.settings.gradle b/gradle/develocity.settings.gradle new file mode 100644 index 0000000..f47e727 --- /dev/null +++ b/gradle/develocity.settings.gradle @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + * Develocity — Build Scans and remote Build Cache on the OSS Community instance + * (https://community.develocity.cloud), project `meshtastic`. + * + * Replaces the former self-hosted HttpBuildCache: GRADLE_CACHE_URL / _USERNAME / + * _PASSWORD are no longer read anywhere in this repo. + */ + +def isCI = System.getenv("CI") != null + +develocity { + server = "https://community.develocity.cloud" + projectId = "meshtastic" + buildScan { + uploadInBackground = !isCI + // Unauthenticated builds (fork PRs, developers who never provisioned a key) + // publish nothing rather than failing. + publishing.onlyIf { it.authenticated } + // Fingerprints power cache-miss comparison (CI debugging); skip the payload locally. + capture { fileFingerprints = isCI } + // Public instance: no machine identity. Constants on purpose — scans already + // record OS/CPU and CCUD adds CI metadata. Keep the `if` OUTSIDE the closures: + // capture-free closures are what the configuration cache can serialize. + obfuscation { + ipAddresses { addresses -> addresses.collect { "0.0.0.0" } } + externalProcessName { "external-process" } + if (isCI) { + username { "ci" } + hostname { "ci-runner" } + } else { + username { "local-dev" } + hostname { "local-machine" } + } + } + } +} + +// Resolved outside the buildCache block: inside it the closure delegate is +// BuildCacheConfiguration, which has no `develocity` property. +def develocityBuildCache = develocity.buildCache +def accessKey = System.getenv("DEVELOCITY_ACCESS_KEY")?.trim() + +buildCache { + // Off on CI: runners are ephemeral and every hit comes from the remote anyway. + local { + enabled = !isCI + } + remote(develocityBuildCache) { + enabled = true + // Only authenticated CI writes, so unmerged and fork code cannot poison the cache. + push = isCI && accessKey != null && !accessKey.isEmpty() + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index bac2e36..a252dda 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,6 +6,11 @@ pluginManagement { } } -apply(from = "gradle/build-cache.settings.gradle") +plugins { + id("com.gradle.develocity") version "4.5.0" + id("com.gradle.common-custom-user-data-gradle-plugin") version "2.8.0" +} + +apply(from = "gradle/develocity.settings.gradle") rootProject.name = "kzstd"