ref:2f5d136126b646b497bbd585b9994989a2672bd1

refactor(runner): drop the redundant `svc-` prefix from service verbs

`anvil runner service svc-restart` stutters — the group is already named `service`. Rename the four verbs to `start`, `stop`, `restart`, and `status`. The `svc-` spellings stay as hidden clap aliases: they are baked into install scripts the server generates, into runbooks, and into whatever operators have in their shell history, so breaking them outright would strand existing runners mid-upgrade. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SHA: 2f5d136126b646b497bbd585b9994989a2672bd1
Author: Cole Christensen <cole.christensen@gmail.com>
Date: 2026-07-30 17:48
Parents: de31c3b
5 files changed +55 -31
Type
src/commands/runner.rs +45 −21
@@ -260,29 +260,31 @@
service_name: Option<String>,
},
/// Start the service
// `svc-start` is the pre-rename spelling; kept as a hidden alias so
// install scripts and runbooks already in the field keep working.
#[command(name = "start", alias = "svc-start")]
#[command(name = "svc-start")]
Start {
/// Logical instance name (default "default")
#[arg(long)]
service_name: Option<String>,
},
/// Stop the service
#[command(name = "stop", alias = "svc-stop")]
#[command(name = "svc-stop")]
Stop {
/// Logical instance name (default "default")
#[arg(long)]
service_name: Option<String>,
},
/// Restart the service (for picking up an upgraded binary)
#[command(name = "svc-restart")]
#[command(name = "restart", alias = "svc-restart")]
Restart {
/// Logical instance name (default "default")
#[arg(long)]
service_name: Option<String>,
},
/// Show service status
#[command(name = "status", alias = "svc-status")]
#[command(name = "svc-status")]
SvcStatus {
Status {
/// Logical instance name (default "default")
#[arg(long)]
service_name: Option<String>,
@@ -1307,7 +1309,7 @@
let instance = resolve_instance(service_name)?;
service_cmd("restart", &instance)
}
ServiceCommand::SvcStatus { service_name } => {
ServiceCommand::Status { service_name } => {
let instance = resolve_instance(service_name)?;
service_cmd("status", &instance)
}
@@ -1492,10 +1494,10 @@
unit_path.display()
));
let start_hint = if opts.instance == runner::service_mode::DEFAULT_INSTANCE {
"Start with: anvil runner service svc-start".to_string()
"Start with: anvil runner service start".to_string()
} else {
format!(
"Start with: anvil runner service start --service-name {}",
"Start with: anvil runner service svc-start --service-name {}",
opts.instance
)
};
@@ -1830,9 +1832,9 @@
)
})?;
runner::service_windows::control(action, &record)?;
// NOTE: `control` writes svc-status to stdout/SCM internally; the
// NOTE: `control` writes status output to stdout/SCM internally; the
// Windows path can't easily capture it to fold into the JSON, so
// svc-status returns an ok envelope rather than a captured log.
// status returns an ok envelope rather than a captured log.
Ok(output::Response::ok(
"service",
serde_json::json!({ "instance": instance, "action": action }),
@@ -1863,7 +1865,7 @@
launchctl_bootstrap(&record)?;
}
"status" => {
// svc-status: capture the child's stdout and echo it as a
// status: capture the child's stdout and echo it as a
// log payload under --json; print it for humans.
let content = launchctl_print(&record)?;
output::line(&content);
@@ -2345,40 +2347,62 @@
}
#[test]
fn svc_start_parses_to_start_variant() {
fn start_parses_to_start_variant() {
assert!(matches!(
parse(&["service", "svc-start"]),
parse(&["service", "start"]),
ServiceCommand::Start { .. }
));
}
#[test]
fn svc_stop_parses_to_stop_variant() {
fn stop_parses_to_stop_variant() {
assert!(matches!(
parse(&["service", "svc-stop"]),
parse(&["service", "stop"]),
ServiceCommand::Stop { .. }
));
}
#[test]
fn svc_restart_parses_to_restart_variant() {
fn restart_parses_to_restart_variant() {
assert!(matches!(
parse(&["service", "restart"]),
parse(&["service", "svc-restart"]),
ServiceCommand::Restart { .. }
));
}
#[test]
fn status_parses_to_status_variant() {
assert!(matches!(
parse(&["service", "status"]),
ServiceCommand::Status { .. }
));
}
/// The `svc-` prefixed spellings predate the rename and are still
/// baked into installed unit files, install scripts, and runbooks.
#[test]
fn legacy_svc_prefixed_aliases_still_parse() {
assert!(matches!(
parse(&["service", "svc-start"]),
ServiceCommand::Start { .. }
fn svc_status_parses_to_status_variant() {
));
assert!(matches!(
parse(&["service", "svc-stop"]),
ServiceCommand::Stop { .. }
));
assert!(matches!(
parse(&["service", "svc-restart"]),
ServiceCommand::Restart { .. }
));
assert!(matches!(
parse(&["service", "svc-status"]),
ServiceCommand::SvcStatus { .. }
ServiceCommand::Status { .. }
));
}
#[test]
fn svc_start_parses_service_name_flag() {
match parse(&["service", "svc-start", "--service-name", "gpu1"]) {
fn start_parses_service_name_flag() {
match parse(&["service", "start", "--service-name", "gpu1"]) {
ServiceCommand::Start { service_name } => {
assert_eq!(service_name.as_deref(), Some("gpu1"));
}
src/runner/service_mode.rs +1 −1
@@ -1,5 +1,5 @@
//! Records which service-manager mode the runner was installed under so
//! `svc-start/stop/restart/status` can target the correct scope without
//! `service start/stop/restart/status` can target the correct scope without
//! the prior brittle "is the current uid 0?" heuristic.
//!
//! Persisted as one file per instance at
src/runner/service_windows.rs +1 −1
@@ -199,7 +199,7 @@
Ok(())
}
/// `svc-start` / `svc-stop` / `svc-restart` / `svc-status`.
/// `start` / `stop` / `restart` / `status`.
pub fn control(action: &str, record: &InstallRecord) -> Result<(), DynErr> {
let manager = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT)?;
let access = ServiceAccess::QUERY_STATUS | ServiceAccess::START | ServiceAccess::STOP;
tests/json_contract.rs +4 −4
@@ -172,10 +172,10 @@
"runner restart",
"runner service install",
"runner service list",
"runner service svc-restart",
"runner service svc-start",
"runner service svc-status",
"runner service svc-stop",
"runner service restart",
"runner service start",
"runner service status",
"runner service stop",
"runner service uninstall",
"runner start",
"runner status",
tests/json_fuzz.rs +4 −4
@@ -39,10 +39,10 @@
"runner logs",
"runner service install",
"runner service uninstall",
"runner service svc-start",
"runner service svc-stop",
"runner service svc-restart",
"runner service svc-status",
"runner service start",
"runner service stop",
"runner service restart",
"runner service status",
"runner service list",
// Mutates the git working tree / clones:
"pr checkout",