Skip to content

refactor(hm-config): Replace stringly-typed backend: String with a closed enum#126

Merged
markovejnovic merged 5 commits into
mainfrom
cq/hm-config-replace-stringly-typed-backend-string-wi-23
Jun 10, 2026
Merged

refactor(hm-config): Replace stringly-typed backend: String with a closed enum#126
markovejnovic merged 5 commits into
mainfrom
cq/hm-config-replace-stringly-typed-backend-string-wi-23

Conversation

@markovejnovic

Copy link
Copy Markdown
Contributor

Smell

Config.backend was a stringly-typed String defaulting to "docker" via a default_backend() helper. The set of valid values is closed ("docker", "cloud"), yet it was matched at consumer sites with string-literal comparisons (e.g. cfg.backend == "cloud" in crates/hm/src/commands/init.rs). A typo in either a config.toml file or a comparison would silently compile and mis-dispatch the run to the wrong backend.

Change

  • Introduced a closed enum in crates/hm-config/src/lib.rs:
    #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
    #[serde(rename_all = "lowercase")]
    pub enum Backend { Docker, Cloud }
    impl Default for Backend { fn default() -> Self { Backend::Docker } }
  • Changed the field to #[serde(default)] pub backend: Backend and dropped the default_backend() string helper.
  • Added Backend::as_str + Display so call sites that still operate on the lowercase wire name (the existing --backend/--cloud string resolution in run/mod.rs) keep working unchanged and behavior-preserving.
  • Replaced the literal comparison in init.rs with an exhaustive match the compiler checks.
  • Updated tests in hm-config and crates/hm/tests/cmd_init.rs to assert against the enum.

I deliberately did not add a clap ValueEnum derive: hm-config has no clap dependency today, and the --backend flag in the hm binary remains an Option<String> resolved through the same lowercase names. Wiring clap ValueEnum is left as a follow-up to keep this diff minimal.

Pattern applied

ValueEnum / enum-over-stringly-typed for closed CLI choice sets plus parse-once at the boundary (reference: the fd CLI, which models closed choice sets as enums parsed at the argument/config boundary rather than carrying raw strings through the program). Invalid backend strings are now rejected at deserialize time instead of mis-dispatching later, comparisons become exhaustive matches, and adding a future backend variant forces every call site to be revisited.

CI / verification note

Important

Only cargo check -p hm-config was run locally (per workflow scope). This worktree's base branch has a pre-existing, unrelated compile break in hm-config: save_to and creds.rs call hm_util::os::fs::blocking::write_atomic_restricted with bare integer literals (0o644, 0o700, 0o600) where the current hm-util API expects FileMode/DirMode newtypes. That break exists on the base commit (verified via git stash) and is untouched by this PR. As a result the local cargo check -p hm-config does not go green, but no error is attributable to this refactor — the only diagnostics are the pre-existing newtype mismatch in code this PR does not modify. Opening as draft so a reviewer can confirm the refactor against a green base (full CI runs on this PR).

@markovejnovic markovejnovic marked this pull request as ready for review June 10, 2026 20:35
@markovejnovic markovejnovic merged commit da6e679 into main Jun 10, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant