From 2d3ea9afbd3f39f7e97c1bae85af3cdde86a5e96 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 23 Jan 2026 15:15:11 +0100 Subject: [PATCH] feat(runner): add go-runner-version CLI argument --- src/executor/config.rs | 9 +++++++++ src/executor/helpers/env.rs | 12 ++++++++++-- src/executor/helpers/introspected_golang/go.sh | 13 ++++++++++++- src/executor/memory/executor.rs | 7 +++++-- src/executor/valgrind/measure.rs | 1 + src/executor/wall_time/executor.rs | 7 +++++-- src/project_config/merger.rs | 3 +++ src/run/mod.rs | 11 +++++++++++ 8 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/executor/config.rs b/src/executor/config.rs index 6b769390..616cd4ab 100644 --- a/src/executor/config.rs +++ b/src/executor/config.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::run::{RunArgs, UnwindingMode}; use crate::run_environment::RepositoryProvider; use crate::runner_mode::RunnerMode; +use semver::Version; use std::path::PathBuf; use url::Url; @@ -34,6 +35,8 @@ pub struct Config { pub skip_setup: bool, /// If true, allow execution even when no benchmarks are found pub allow_empty: bool, + /// The version of go-runner to install (if None, installs latest) + pub go_runner_version: Option, } #[derive(Debug, PartialEq, Clone)] @@ -85,6 +88,7 @@ impl Config { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, } } } @@ -121,6 +125,7 @@ impl TryFrom for Config { skip_run: args.shared.skip_run, skip_setup: args.shared.skip_setup, allow_empty: args.shared.allow_empty, + go_runner_version: args.shared.go_runner_version, }) } } @@ -154,6 +159,7 @@ impl Config { skip_run: args.shared.skip_run, skip_setup: args.shared.skip_setup, allow_empty: args.shared.allow_empty, + go_runner_version: args.shared.go_runner_version, }) } } @@ -188,6 +194,7 @@ mod tests { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: false, perf_unwinding_mode: None, @@ -226,6 +233,7 @@ mod tests { skip_run: true, skip_setup: true, allow_empty: true, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: false, perf_unwinding_mode: Some(UnwindingMode::FramePointer), @@ -308,6 +316,7 @@ mod tests { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: false, perf_unwinding_mode: None, diff --git a/src/executor/helpers/env.rs b/src/executor/helpers/env.rs index e337bb70..51b6f714 100644 --- a/src/executor/helpers/env.rs +++ b/src/executor/helpers/env.rs @@ -1,10 +1,12 @@ use std::{collections::HashMap, env::consts::ARCH, path::Path}; +use crate::executor::Config; use crate::runner_mode::RunnerMode; pub fn get_base_injected_env( mode: RunnerMode, profile_folder: &Path, + config: &Config, ) -> HashMap<&'static str, String> { let runner_mode_internal_env_value = match mode { // While the runner now deprecates the usage of instrumentation with a message, we @@ -17,7 +19,7 @@ pub fn get_base_injected_env( RunnerMode::Walltime => "walltime", RunnerMode::Memory => "memory", }; - HashMap::from([ + let mut env = HashMap::from([ ("PYTHONHASHSEED", "0".into()), ( "PYTHON_PERF_JIT_SUPPORT", @@ -37,7 +39,13 @@ pub fn get_base_injected_env( "CODSPEED_PROFILE_FOLDER", profile_folder.to_string_lossy().to_string(), ), - ]) + ]); + + if let Some(version) = &config.go_runner_version { + env.insert("CODSPEED_GO_RUNNER_VERSION", version.to_string()); + } + + env } pub fn is_codspeed_debug_enabled() -> bool { diff --git a/src/executor/helpers/introspected_golang/go.sh b/src/executor/helpers/introspected_golang/go.sh index d77fc70c..30c6abd1 100755 --- a/src/executor/helpers/introspected_golang/go.sh +++ b/src/executor/helpers/introspected_golang/go.sh @@ -39,7 +39,18 @@ if [ "$1" = "test" ]; then # Find go-runner or install if not found GO_RUNNER=$(which codspeed-go-runner 2>/dev/null || true) if [ -z "$GO_RUNNER" ]; then - curl -fsSL http://github.com/CodSpeedHQ/codspeed-go/releases/latest/download/codspeed-go-runner-installer.sh | bash -s -- --quiet + # Build the installer URL with the specified version or use latest + INSTALLER_VERSION="${CODSPEED_GO_RUNNER_VERSION:-latest}" + if [ "$INSTALLER_VERSION" = "latest" ]; then + DOWNLOAD_URL="http://github.com/CodSpeedHQ/codspeed-go/releases/latest/download/codspeed-go-runner-installer.sh" + echo "WARNING: Installing the latest version of codspeed-go-runner. This can silently introduce breaking changes." >&2 + echo "We recommend pinning a specific version via the `go-runner-version` option in the action." >&2 + else + DOWNLOAD_URL="http://github.com/CodSpeedHQ/codspeed-go/releases/download/v${INSTALLER_VERSION}/codspeed-go-runner-installer.sh" + fi + + debug_log "Installing go-runner from: $DOWNLOAD_URL" + curl -fsSL "$DOWNLOAD_URL" | bash -s -- --quiet GO_RUNNER=$(which codspeed-go-runner 2>/dev/null || true) fi diff --git a/src/executor/memory/executor.rs b/src/executor/memory/executor.rs index 6f790ad8..6927c6c3 100644 --- a/src/executor/memory/executor.rs +++ b/src/executor/memory/executor.rs @@ -49,8 +49,11 @@ impl MemoryExecutor { cmd_builder.arg(get_bench_command(&execution_context.config)?); // Wrap command with environment forwarding - let extra_env = - get_base_injected_env(RunnerMode::Memory, &execution_context.profile_folder); + let extra_env = get_base_injected_env( + RunnerMode::Memory, + &execution_context.profile_folder, + &execution_context.config, + ); let (cmd_builder, env_file) = wrap_with_env(cmd_builder, &extra_env)?; Ok((ipc_server, cmd_builder, env_file)) diff --git a/src/executor/valgrind/measure.rs b/src/executor/valgrind/measure.rs index 03fa01e2..cac1f4e6 100644 --- a/src/executor/valgrind/measure.rs +++ b/src/executor/valgrind/measure.rs @@ -89,6 +89,7 @@ pub async fn measure( cmd.envs(get_base_injected_env( RunnerMode::Simulation, profile_folder, + config, )); // Only set PYTHONMALLOC=malloc for non-free-threaded Python builds. diff --git a/src/executor/wall_time/executor.rs b/src/executor/wall_time/executor.rs index 7bb4faac..d436f089 100644 --- a/src/executor/wall_time/executor.rs +++ b/src/executor/wall_time/executor.rs @@ -105,8 +105,11 @@ impl WallTimeExecutor { path_env ); - let mut extra_env = - get_base_injected_env(RunnerMode::Walltime, &execution_context.profile_folder); + let mut extra_env = get_base_injected_env( + RunnerMode::Walltime, + &execution_context.profile_folder, + &execution_context.config, + ); extra_env.insert("PATH", path_value); // We have to write the benchmark command to a script, to ensure proper formatting diff --git a/src/project_config/merger.rs b/src/project_config/merger.rs index 636c5e90..d7b730aa 100644 --- a/src/project_config/merger.rs +++ b/src/project_config/merger.rs @@ -163,6 +163,7 @@ mod tests { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: true, perf_unwinding_mode: None, @@ -195,6 +196,7 @@ mod tests { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: true, perf_unwinding_mode: None, @@ -229,6 +231,7 @@ mod tests { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: false, perf_unwinding_mode: None, diff --git a/src/run/mod.rs b/src/run/mod.rs index 35fe827d..404a15f4 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -120,10 +120,20 @@ pub struct ExecAndRunSharedArgs { #[arg(long, default_value = "false", hide = true)] pub allow_empty: bool, + /// The version of the go-runner to use (e.g., 1.2.3, 1.0.0-beta.1) + /// If not specified, the latest version will be installed + #[arg(long, env = "CODSPEED_GO_RUNNER_VERSION", value_parser = parse_version)] + pub go_runner_version: Option, + #[command(flatten)] pub perf_run_args: PerfRunArgs, } +/// Parser for go-runner version that validates semver format +fn parse_version(s: &str) -> Result { + semver::Version::parse(s).map_err(|e| format!("Invalid semantic version: {e}")) +} + #[derive(Args, Debug)] pub struct RunArgs { #[command(flatten)] @@ -182,6 +192,7 @@ impl RunArgs { skip_run: false, skip_setup: false, allow_empty: false, + go_runner_version: None, perf_run_args: PerfRunArgs { enable_perf: false, perf_unwinding_mode: None,