diff --git a/.github/renovate-tracked-deps.json b/.github/renovate-tracked-deps.json index 412a82a33..df48df60c 100644 --- a/.github/renovate-tracked-deps.json +++ b/.github/renovate-tracked-deps.json @@ -36,6 +36,11 @@ "mise" ] }, + ".github/workflows/jmx-exporter-compatibility.yml": { + "regex": [ + "mise" + ] + }, ".github/workflows/lint.yml": { "regex": [ "mise" @@ -66,6 +71,16 @@ "mise" ] }, + ".mise/envs/jmx-exporter/mise.toml": { + "mise": [ + "java" + ] + }, + ".mise/envs/micrometer/mise.toml": { + "mise": [ + "java" + ] + }, ".mise/envs/native/mise.toml": { "mise": [ "java" @@ -140,6 +155,11 @@ "taplo", "typos", "zizmor" + ], + "regex": [ + "grafana/docker-otel-lgtm", + "micrometer-metrics/micrometer", + "prometheus/jmx_exporter" ] }, "mvnw": { diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 4284ec290..e7de6a019 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -37,7 +37,16 @@ matchDepNames: ["com.google.protobuf:protobuf-java", "protoc"], groupName: "protobuf", separateMajorMinor: false, - }, + } + ], + customManagers: [ + { + "customType": "regex", + "description": "update _VERSION variables in mise.toml", + "managerFilePatterns": ["/^mise\\.toml$/"], + "matchStrings": [ + "# renovate: datasource=(?[a-z-]+?)(?: depName=(?.+?))?(?: packageName=(?.+?))?(?: versioning=(?[a-z-]+?))?\\s.+?_VERSION\\s*=\\s*\"?(?[^@\"]+?)(?:@(?sha256:[a-f0-9]+))?\"?\\s" + ] + }, ], - customManagers: [], } diff --git a/.github/workflows/jmx-exporter-compatibility.yml b/.github/workflows/jmx-exporter-compatibility.yml new file mode 100644 index 000000000..afdaed42d --- /dev/null +++ b/.github/workflows/jmx-exporter-compatibility.yml @@ -0,0 +1,40 @@ +--- +name: JMX Exporter Compatibility + +on: + pull_request: + workflow_dispatch: + inputs: + repository: + description: JMX Exporter repository to test, in owner/name form + required: false + default: prometheus/jmx_exporter + ref: + description: JMX Exporter branch, tag, or commit to test + required: true + +permissions: {} + +jobs: + jmx-exporter-compatibility: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1 + with: + version: v2026.5.18 + sha256: cfac593469d028d7ae5fe36e37bd7c59118b5238e92d8a876209578464f24a84 + working_directory: .mise/envs/jmx-exporter + - name: Cache local Maven repository + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + - name: Run JMX Exporter compatibility tests + working-directory: .mise/envs/jmx-exporter + env: + JMX_EXPORTER_REPOSITORY: ${{ inputs.repository || 'prometheus/jmx_exporter' }} + JMX_EXPORTER_REF: ${{ inputs.ref }} + run: mise compat-test diff --git a/.github/workflows/micrometer-compatibility.yml b/.github/workflows/micrometer-compatibility.yml index ebbf1f10c..9ad95d807 100644 --- a/.github/workflows/micrometer-compatibility.yml +++ b/.github/workflows/micrometer-compatibility.yml @@ -11,8 +11,7 @@ on: default: micrometer-metrics/micrometer micrometer-ref: description: Micrometer branch, tag, or commit to test - required: false - default: main + required: true permissions: {} @@ -27,13 +26,15 @@ jobs: with: version: v2026.5.18 sha256: cfac593469d028d7ae5fe36e37bd7c59118b5238e92d8a876209578464f24a84 + working_directory: .mise/envs/micrometer - name: Cache local Maven repository uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - name: Run Micrometer compatibility tests + working-directory: .mise/envs/micrometer env: - MICROMETER_REPOSITORY: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.micrometer-repository || 'micrometer-metrics/micrometer' }} - MICROMETER_REF: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.micrometer-ref || 'main' }} - run: mise run micrometer:test + MICROMETER_REPOSITORY: ${{ inputs.micrometer-repository || 'micrometer-metrics/micrometer' }} + MICROMETER_REF: ${{ inputs.micrometer-ref }} + run: mise compat-test diff --git a/.mise/envs/jmx-exporter/mise.toml b/.mise/envs/jmx-exporter/mise.toml new file mode 100644 index 000000000..a04b4948c --- /dev/null +++ b/.mise/envs/jmx-exporter/mise.toml @@ -0,0 +1,10 @@ +# The pinned JMX Exporter release does not build on the primary JDK (Java 25): +# its spotless google-java-format predates JDK 25 support. Build it under an LTS +# JDK the release supports instead. +[tools] +java = "temurin-21.0.11+10.0.LTS" + +[tasks.compat-test] +description = "Run JMX Exporter compatibility tests under a supported JDK" +dir = "../../.." +run = "python3 .mise/tasks/jmx-exporter/test.py" diff --git a/.mise/envs/micrometer/mise.toml b/.mise/envs/micrometer/mise.toml new file mode 100644 index 000000000..e5318c1d6 --- /dev/null +++ b/.mise/envs/micrometer/mise.toml @@ -0,0 +1,10 @@ +# The pinned Micrometer release does not build on the primary JDK (Java 25): +# its bundled Kotlin compiler predates JDK 25 support. Build it under an LTS JDK +# the release supports instead. +[tools] +java = "temurin-21.0.11+10.0.LTS" + +[tasks.compat-test] +description = "Run Micrometer compatibility tests under a supported JDK" +dir = "../../.." +run = "python3 .mise/tasks/micrometer/test.py" diff --git a/.mise/lib/jmx_exporter_compat.py b/.mise/lib/jmx_exporter_compat.py new file mode 100755 index 000000000..607f65aae --- /dev/null +++ b/.mise/lib/jmx_exporter_compat.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import os +import subprocess +import xml.etree.ElementTree as ET +from pathlib import Path +from typing import Optional + + +DEFAULT_JMX_EXPORTER_DIR = Path( + os.environ.get("JMX_EXPORTER_DIR", "/tmp/jmx-exporter-compat") +) +DEFAULT_JMX_EXPORTER_REPOSITORY = os.environ.get( + "JMX_EXPORTER_REPOSITORY", "prometheus/jmx_exporter" +) +DEFAULT_JMX_EXPORTER_REMOTE = os.environ.get("JMX_EXPORTER_REMOTE", "origin") +DEFAULT_JMX_EXPORTER_REF = ( + os.environ.get("JMX_EXPORTER_REF") + or os.environ.get("DEFAULT_JMX_EXPORTER_VERSION") + or "main" +) +DEFAULT_MAVEN_MODULES = os.environ.get( + "JMX_EXPORTER_MAVEN_MODULES", + "jmx_prometheus_common,jmx_prometheus_javaagent,jmx_prometheus_standalone", +) +DEFAULT_PROM_VERSION = os.environ.get("PROM_VERSION") + + +def run_cmd(cmd: list[str], cwd: Optional[Path] = None) -> None: + subprocess.run(cmd, cwd=cwd, check=True) + + +def jmx_exporter_repository_url(repository: str) -> str: + return f"https://github.com/{repository}.git" + + +def check_clean_worktree(jmx_exporter_dir: Path) -> None: + result = subprocess.run( + ["git", "status", "--short"], + cwd=jmx_exporter_dir, + check=True, + capture_output=True, + text=True, + ) + if result.stdout.strip(): + raise RuntimeError( + f"{jmx_exporter_dir} has uncommitted changes; use a clean clone or set " + "JMX_EXPORTER_DIR" + ) + + +def get_prom_version(root_dir: Path = Path.cwd()) -> str: + configured_version = DEFAULT_PROM_VERSION + if configured_version: + return configured_version + pom = ET.parse(root_dir / "pom.xml") + root = pom.getroot() + version = root.findtext("./{*}version") + if not version: + version = root.findtext("./{*}parent/{*}version") + if not version: + raise RuntimeError("could not determine Prometheus version from pom.xml") + return version + + +def prepare_repo( + jmx_exporter_dir: Path = DEFAULT_JMX_EXPORTER_DIR, + repository: str = DEFAULT_JMX_EXPORTER_REPOSITORY, + remote: str = DEFAULT_JMX_EXPORTER_REMOTE, + ref: str = DEFAULT_JMX_EXPORTER_REF, +) -> None: + repository_url = jmx_exporter_repository_url(repository) + if (jmx_exporter_dir / ".git").is_dir(): + check_clean_worktree(jmx_exporter_dir) + run_cmd( + ["git", "remote", "set-url", remote, repository_url], + cwd=jmx_exporter_dir, + ) + run_cmd(["git", "fetch", remote, ref], cwd=jmx_exporter_dir) + else: + run_cmd(["git", "clone", repository_url, str(jmx_exporter_dir)]) + run_cmd(["git", "fetch", remote, ref], cwd=jmx_exporter_dir) + run_cmd( + ["git", "checkout", "-B", "jmx-exporter-compat", "FETCH_HEAD"], + cwd=jmx_exporter_dir, + ) + + +def install_local_artifacts(root_dir: Path = Path.cwd()) -> None: + run_cmd( + [ + "./mvnw", + "install", + # Skip test compilation too (not just execution): downstream needs only + # our main artifacts, and our test sources target a newer release than + # the compatibility JDK supports. + "-Dmaven.test.skip=true", + "-Dcoverage.skip=true", + "-Dcheckstyle.skip=true", + "-Dwarnings=-nowarn", + ], + cwd=root_dir, + ) + + +def run_maven_test( + test_selector: Optional[str] = None, + jmx_exporter_dir: Path = DEFAULT_JMX_EXPORTER_DIR, + maven_modules: str = DEFAULT_MAVEN_MODULES, + prom_version: Optional[str] = None, +) -> None: + if prom_version is None: + prom_version = get_prom_version() + cmd = [ + "./mvnw", + "-B", + "-pl", + maven_modules, + "-am", + f"-Dprometheus.metrics.version={prom_version}", + "-Djacoco.skip=true", + ] + if test_selector: + cmd.append(f"-Dtest={test_selector}") + cmd.append("test") + run_cmd(cmd, cwd=jmx_exporter_dir) diff --git a/.mise/lib/micrometer_compat.py b/.mise/lib/micrometer_compat.py index 808a6f91f..93613c336 100755 --- a/.mise/lib/micrometer_compat.py +++ b/.mise/lib/micrometer_compat.py @@ -16,7 +16,11 @@ "MICROMETER_REPOSITORY", "micrometer-metrics/micrometer" ) DEFAULT_MICROMETER_REMOTE = os.environ.get("MICROMETER_REMOTE", "origin") -DEFAULT_MICROMETER_REF = os.environ.get("MICROMETER_REF", "main") +DEFAULT_MICROMETER_REF = ( + os.environ.get("MICROMETER_REF") + or os.environ.get("DEFAULT_MICROMETER_VERSION") + or "main" +) DEFAULT_INIT_SCRIPT = Path( os.environ.get("MICROMETER_INIT_SCRIPT", "/tmp/micrometer-prom-local.init.gradle") ) @@ -121,7 +125,10 @@ def install_local_artifacts(root_dir: Path = Path.cwd()) -> None: [ "./mvnw", "install", - "-DskipTests", + # Skip test compilation too (not just execution): downstream needs only + # our main artifacts, and our test sources target a newer release than + # the compatibility JDK supports. + "-Dmaven.test.skip=true", "-Dcoverage.skip=true", "-Dcheckstyle.skip=true", "-Dwarnings=-nowarn", diff --git a/.mise/tasks/jmx-exporter/prepare.py b/.mise/tasks/jmx-exporter/prepare.py new file mode 100755 index 000000000..348415f7f --- /dev/null +++ b/.mise/tasks/jmx-exporter/prepare.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +# [MISE] description="Install local artifacts and check out a target JMX Exporter ref" +# [MISE] alias="jmx-exporter:prepare" + +import sys + + +sys.path.insert(0, ".mise/lib") + + +def main() -> int: + from jmx_exporter_compat import install_local_artifacts, prepare_repo + + install_local_artifacts() + prepare_repo() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.mise/tasks/jmx-exporter/test.py b/.mise/tasks/jmx-exporter/test.py new file mode 100755 index 000000000..3e3989300 --- /dev/null +++ b/.mise/tasks/jmx-exporter/test.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +# [MISE] description="Run JMX Exporter tests against a target ref" +# [MISE] alias="jmx-exporter:test" + +import sys + + +sys.path.insert(0, ".mise/lib") + + +def main() -> int: + from jmx_exporter_compat import ( + install_local_artifacts, + prepare_repo, + run_maven_test, + ) + + install_local_artifacts() + prepare_repo() + run_maven_test() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.mise/tasks/micrometer/test-class.py b/.mise/tasks/micrometer/test-class.py deleted file mode 100755 index 89ae436de..000000000 --- a/.mise/tasks/micrometer/test-class.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python3 - -# [MISE] description="Run Micrometer PrometheusMeterRegistryTest against a target Micrometer ref" -# [MISE] alias="micrometer:test-class" - -import sys - - -sys.path.insert(0, ".mise/lib") - - -def main() -> int: - from micrometer_compat import ( - install_local_artifacts, - prepare_repo, - run_gradle_test, - write_init_script, - ) - - install_local_artifacts() - prepare_repo() - write_init_script() - run_gradle_test("io.micrometer.prometheusmetrics.PrometheusMeterRegistryTest") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/mise.toml b/mise.toml index 973ef10a8..b33477fb1 100644 --- a/mise.toml +++ b/mise.toml @@ -27,6 +27,10 @@ zizmor = "1.25.2" FLINT_CONFIG_DIR = ".github/config" # renovate: datasource=github-releases depName=grafana/docker-otel-lgtm LGTM_VERSION = "0.25.0" +# renovate: datasource=github-tags depName=prometheus/jmx_exporter versioning=semver-coerced +DEFAULT_JMX_EXPORTER_VERSION = "1.5.0" +# renovate: datasource=github-tags depName=micrometer-metrics/micrometer versioning=semver-coerced +DEFAULT_MICROMETER_VERSION = "v1.16.5" [tasks.ci] description = "CI Build"