runner follow-ups: XDG config path + composite action + docs
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 10s
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 10s
Three fixes surfaced by the 2026-07-13 Gitea Actions wire-up.
## XDG config path
Before: `client_config::user_config_path` only looked at
`~/.claw-cargo/config.toml`. My runner-integration doc initially
told operators to install at `~/.config/claw-cargo/config.toml`
(XDG-style). Config wasn't loaded.
Now: three-way lookup, first hit wins.
1. `$XDG_CONFIG_HOME/claw-cargo/config.toml`
2. `$HOME/.config/claw-cargo/config.toml`
3. `$HOME/.claw-cargo/config.toml` (legacy, still honoured)
+3 tests: XDG env wins when the file exists, .config wins over
legacy dotfile when both present, legacy dotfile returned as
error-message fallback when none exist.
## Composite action
Before: composite action silently no-op'd. Log showed the script
lines echoed but only the `if command -v claw-cargo` fail branch
ran. Root cause: Gitea Actions composite steps run with a stripped
PATH that omits `/usr/local/bin`.
Now: composite step exports PATH defensively:
export PATH="/usr/local/bin:$HOME/.cargo/bin:$PATH"
And it looks for the config at BOTH the XDG-style path and the
legacy dotfile (same order as client_config).
Workflow file back to using the composite action.
## Docs
Runner-integration doc now:
- Explicitly warns that `ubuntu-latest` routes to container mode
even with `:host` suffix on runner labels (field-observed).
- Documents the dedicated `clawstor-cache` label pattern that
works.
- Sample workflow uses `runs-on: clawstor-cache` instead of
`ubuntu-latest`.
+3 tests, 262 total (baseline unchanged).
This commit is contained in:
@@ -3,7 +3,12 @@
|
||||
//!
|
||||
//! Layered defaults:
|
||||
//! 1. Built-in defaults (empty struct).
|
||||
//! 2. `~/.claw-cargo/config.toml` if present.
|
||||
//! 2. XDG-style user config, first hit wins:
|
||||
//! * `$XDG_CONFIG_HOME/claw-cargo/config.toml`
|
||||
//! * `$HOME/.config/claw-cargo/config.toml`
|
||||
//! * `$HOME/.claw-cargo/config.toml` (legacy — from before XDG
|
||||
//! support landed on 2026-07-13; still honoured for existing
|
||||
//! runner installs).
|
||||
//! 3. `<workspace>/.claw-cargo.toml` if present.
|
||||
//! 4. CLI overrides.
|
||||
//!
|
||||
@@ -16,11 +21,43 @@ use serde::{Deserialize, Serialize};
|
||||
use std::net::SocketAddr;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Location of a per-user config file: `<home>/.claw-cargo/config.toml`.
|
||||
/// Ordered list of candidate user-config paths, first-match wins.
|
||||
///
|
||||
/// Field finding 2026-07-13 (Gitea runner deploy): the runner
|
||||
/// integration doc initially told operators to install the config
|
||||
/// under `$HOME/.config/claw-cargo/` (XDG-style), but the code only
|
||||
/// looked at `$HOME/.claw-cargo/`. Both are now honoured so old and
|
||||
/// new installs both work.
|
||||
pub fn user_config_candidates() -> Vec<PathBuf> {
|
||||
let mut out = Vec::with_capacity(3);
|
||||
// Path 1: explicit XDG override.
|
||||
if let Some(xdg) = std::env::var_os("XDG_CONFIG_HOME") {
|
||||
let xdg = PathBuf::from(xdg);
|
||||
if !xdg.as_os_str().is_empty() {
|
||||
out.push(xdg.join("claw-cargo").join("config.toml"));
|
||||
}
|
||||
}
|
||||
// Paths 2 + 3: derived from $HOME.
|
||||
if let Some(home) = std::env::var_os("HOME") {
|
||||
let home = PathBuf::from(home);
|
||||
out.push(home.join(".config").join("claw-cargo").join("config.toml"));
|
||||
out.push(home.join(".claw-cargo").join("config.toml"));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Location of a per-user config file. Returns the first candidate
|
||||
/// that exists on disk, or the *last* candidate (legacy dotfile) when
|
||||
/// none exists — so error messages point at a stable path for
|
||||
/// operators to create.
|
||||
pub fn user_config_path() -> Option<PathBuf> {
|
||||
std::env::var_os("HOME")
|
||||
.map(PathBuf::from)
|
||||
.map(|h| h.join(".claw-cargo").join("config.toml"))
|
||||
let candidates = user_config_candidates();
|
||||
for c in &candidates {
|
||||
if c.is_file() {
|
||||
return Some(c.clone());
|
||||
}
|
||||
}
|
||||
candidates.into_iter().last()
|
||||
}
|
||||
|
||||
/// Location of a workspace-level config file: `<workspace>/.claw-cargo.toml`.
|
||||
@@ -464,15 +501,94 @@ profile = "release"
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_config_path_uses_home() {
|
||||
let saved = std::env::var_os("HOME");
|
||||
std::env::set_var("HOME", "/tmp/test-home");
|
||||
fn user_config_path_falls_back_to_legacy_dotfile_when_none_exist() {
|
||||
// When neither XDG-style path nor the legacy dotfile exists,
|
||||
// `user_config_path` returns the LAST candidate so error
|
||||
// messages point at a stable path. Legacy dotfile is last.
|
||||
let saved_home = std::env::var_os("HOME");
|
||||
let saved_xdg = std::env::var_os("XDG_CONFIG_HOME");
|
||||
std::env::set_var("HOME", "/tmp/test-home-no-config");
|
||||
std::env::remove_var("XDG_CONFIG_HOME");
|
||||
let path = user_config_path().unwrap();
|
||||
assert_eq!(path, PathBuf::from("/tmp/test-home/.claw-cargo/config.toml"));
|
||||
match saved {
|
||||
assert_eq!(
|
||||
path,
|
||||
PathBuf::from("/tmp/test-home-no-config/.claw-cargo/config.toml")
|
||||
);
|
||||
match saved_home {
|
||||
Some(v) => std::env::set_var("HOME", v),
|
||||
None => std::env::remove_var("HOME"),
|
||||
}
|
||||
match saved_xdg {
|
||||
Some(v) => std::env::set_var("XDG_CONFIG_HOME", v),
|
||||
None => std::env::remove_var("XDG_CONFIG_HOME"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_config_path_prefers_xdg_when_that_file_exists() {
|
||||
// Field finding 2026-07-13: runner install placed the config
|
||||
// at the XDG path but the code only looked at the legacy
|
||||
// dotfile. Now XDG is checked FIRST if the file is really there.
|
||||
let saved_home = std::env::var_os("HOME");
|
||||
let saved_xdg = std::env::var_os("XDG_CONFIG_HOME");
|
||||
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let xdg = tmp.path().join("xdg");
|
||||
let home = tmp.path().join("home");
|
||||
std::fs::create_dir_all(xdg.join("claw-cargo")).unwrap();
|
||||
std::fs::write(xdg.join("claw-cargo").join("config.toml"), b"# xdg\n").unwrap();
|
||||
std::env::set_var("HOME", &home);
|
||||
std::env::set_var("XDG_CONFIG_HOME", &xdg);
|
||||
|
||||
let path = user_config_path().unwrap();
|
||||
assert_eq!(path, xdg.join("claw-cargo").join("config.toml"));
|
||||
|
||||
match saved_home {
|
||||
Some(v) => std::env::set_var("HOME", v),
|
||||
None => std::env::remove_var("HOME"),
|
||||
}
|
||||
match saved_xdg {
|
||||
Some(v) => std::env::set_var("XDG_CONFIG_HOME", v),
|
||||
None => std::env::remove_var("XDG_CONFIG_HOME"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_config_path_prefers_home_dot_config_over_legacy_dotfile() {
|
||||
// Between the two `$HOME`-relative paths, `.config/claw-cargo/`
|
||||
// wins over `.claw-cargo/` — matches what most runner installs
|
||||
// will look like going forward.
|
||||
let saved_home = std::env::var_os("HOME");
|
||||
let saved_xdg = std::env::var_os("XDG_CONFIG_HOME");
|
||||
std::env::remove_var("XDG_CONFIG_HOME");
|
||||
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let home = tmp.path();
|
||||
// Create BOTH files; the XDG-style .config path should win.
|
||||
std::fs::create_dir_all(home.join(".config").join("claw-cargo")).unwrap();
|
||||
std::fs::write(
|
||||
home.join(".config").join("claw-cargo").join("config.toml"),
|
||||
b"# xdg-style\n",
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::create_dir_all(home.join(".claw-cargo")).unwrap();
|
||||
std::fs::write(home.join(".claw-cargo").join("config.toml"), b"# legacy\n").unwrap();
|
||||
std::env::set_var("HOME", home);
|
||||
|
||||
let path = user_config_path().unwrap();
|
||||
assert_eq!(
|
||||
path,
|
||||
home.join(".config").join("claw-cargo").join("config.toml")
|
||||
);
|
||||
|
||||
match saved_home {
|
||||
Some(v) => std::env::set_var("HOME", v),
|
||||
None => std::env::remove_var("HOME"),
|
||||
}
|
||||
match saved_xdg {
|
||||
Some(v) => std::env::set_var("XDG_CONFIG_HOME", v),
|
||||
None => std::env::remove_var("XDG_CONFIG_HOME"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user