From 984c11066f28e66a8ec9cc462df1fd6d7fdae08b Mon Sep 17 00:00:00 2001 From: Austin Schaefer Date: Sun, 20 Sep 2026 11:10:00 +0200 Subject: [PATCH] Rename the source module to release_source 'source' read like source code next to the config's source key. The trait file becomes contract.rs to avoid release_source::release_source, and the pipeline's local variables become 'host'. Co-Authored-By: Claude Sonnet 5 --- docs/ARCHITECTURE.md | 6 ++-- docs/SPEC.md | 4 +-- src/checker.rs | 2 +- src/fetcher.rs | 2 +- src/main.rs | 2 +- src/pipeline.rs | 33 ++++++++----------- .../contract.rs} | 0 src/{source => release_source}/forgejo.rs | 0 src/{source => release_source}/github.rs | 0 src/{source => release_source}/mod.rs | 7 ++-- 10 files changed, 25 insertions(+), 31 deletions(-) rename src/{source/release_source.rs => release_source/contract.rs} (100%) rename src/{source => release_source}/forgejo.rs (100%) rename src/{source => release_source}/github.rs (100%) rename src/{source => release_source}/mod.rs (93%) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8e0a9b5..74babdf 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -35,8 +35,8 @@ practice rather than asserted from habit — see Further reading. `helpers/`) tends toward the opposite, and a single feature change ends up touching files scattered across every layer. **Rule**: modules are named after what they do in the pipeline - (`source`, `fetcher`, `verifier`, `builder`, `sanity`, `publisher`, - `state`), not generic buckets. (`source` is a directory module: the + (`release_source`, `fetcher`, `verifier`, `builder`, `sanity`, + `publisher`, `state`), not generic buckets. (`release_source` is a directory module: the `ReleaseSource` trait and one file per host, re-exported from its `mod.rs` so the rest of the crate never names a host's file.) A new pipeline stage gets a new module named after the stage, not a method bolted onto an existing one. @@ -109,7 +109,7 @@ practice rather than asserted from habit — see Further reading. directory, but the same information — why this way and not the obvious alternative — needs to live somewhere a future reader will actually see it: the doc comment on the thing itself. - **Example already here**: `source/github.rs`'s doc comment on + **Example already here**: `release_source/github.rs`'s doc comment on `GithubEndpoints::latest_release` explains why the newest Atom-feed entry isn't trusted outright (scaleway-cli's `-dbg1` tag has no real Release behind it) — the reasoning lives right next to the code it justifies, not in a diff --git a/docs/SPEC.md b/docs/SPEC.md index 02edb5f..dcb3b01 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -373,12 +373,12 @@ Open questions on the schema: likely reuses `nvchecker`'s logic/sources conceptually for non-GitHub sources eventually. For GitHub sources, prefers the `github-atom` feed (see Scaling > Check method) over unconditional REST polling. - *(Implemented for GitHub and Forgejo. `src/source/` defines the + *(Implemented for GitHub and Forgejo. `src/release_source/` defines the `ReleaseSource` trait (latest release + API root); each host implements it in its own file (`github.rs`, `forgejo.rs`), and the module's `for_package` picks one per package, so adding a host doesn't touch existing ones. The rest of the crate imports the trait and hosts from - `crate::source`, which re-exports them. A trait + `crate::release_source`, which re-exports them. A trait rather than an enum match because there are now two real hosts with genuinely different logic. GitHub regex-matches the first `releases/tag/` link in the feed rather than doing a full XML diff --git a/src/checker.rs b/src/checker.rs index 7d1b17c..a32d2fb 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -1,5 +1,5 @@ //! Turns a release tag into a version string. What the latest tag *is* -//! comes from a `ReleaseSource` (see `source`); this is the one piece of +//! comes from a `ReleaseSource` (see `release_source`); this is the one piece of //! the check stage that isn't host-specific. /// Strips a leading `v` from a release tag, e.g. `v2.62.0` -> `2.62.0`. diff --git a/src/fetcher.rs b/src/fetcher.rs index 81f032d..314d394 100644 --- a/src/fetcher.rs +++ b/src/fetcher.rs @@ -1,6 +1,6 @@ //! Downloads a named release asset (from GitHub or Forgejo) to a local //! path. The only module that talks to the releases API for asset bytes — -//! `source` only resolves version tags, never downloads. +//! `release_source` only resolves version tags, never downloads. use anyhow::{Context, Result}; use serde::Deserialize; diff --git a/src/main.rs b/src/main.rs index ac25251..5001beb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,8 @@ mod notifier; mod paths; mod pipeline; mod publisher; +mod release_source; mod sanity; -mod source; mod state; #[cfg(test)] mod test_support; diff --git a/src/pipeline.rs b/src/pipeline.rs index 2723382..97bb471 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -12,8 +12,8 @@ use crate::fetcher::{self, DownloadedAsset}; use crate::notifier::{self, Event}; use crate::paths::Paths; use crate::publisher; +use crate::release_source::{self, ReleaseSource}; use crate::sanity; -use crate::source::{self, ReleaseSource}; use crate::state; use crate::verifier::{self, VerificationResult}; use anyhow::{Context, Result, bail}; @@ -72,15 +72,8 @@ pub fn run_check() -> Result<()> { let mut any_failed = false; for (name, pkg) in &packages { println!("== {name} ({}) ==", pkg.repo); - let result = source::for_package(pkg).and_then(|release_source| { - process_package( - &client, - release_source.as_ref(), - &state_dir, - &work_dir, - name, - pkg, - ) + let result = release_source::for_package(pkg).and_then(|host| { + process_package(&client, host.as_ref(), &state_dir, &work_dir, name, pkg) }); if let Err(err) = result { eprintln!(" error: {err:#}"); @@ -127,13 +120,13 @@ fn decide_tier_action(tier: u8, passed: bool, already_pending_this_version: bool fn process_package( client: &reqwest::blocking::Client, - release_source: &dyn ReleaseSource, + host: &dyn ReleaseSource, state_dir: &Path, work_dir: &Path, name: &str, pkg: &Package, ) -> Result<()> { - let latest = release_source.latest_release(client, &pkg.repo)?; + let latest = host.latest_release(client, &pkg.repo)?; let last_seen = state::load_last_version(state_dir, name); if last_seen.as_deref() == Some(latest.as_str()) { println!(" up to date at {latest}"); @@ -141,7 +134,7 @@ fn process_package( } println!(" new version detected: {latest} (previously: {last_seen:?})"); - let fetched = fetch_and_verify(client, release_source, work_dir, name, pkg, &latest)?; + let fetched = fetch_and_verify(client, host, work_dir, name, pkg, &latest)?; println!(" fetched {}", fetched.asset.path.display()); println!( " verification (tier {}): {} — {}", @@ -214,7 +207,7 @@ struct FetchVerifyResult { /// trusting a possibly-stale flag from an earlier run). fn fetch_and_verify( client: &reqwest::blocking::Client, - release_source: &dyn ReleaseSource, + host: &dyn ReleaseSource, work_dir: &Path, name: &str, pkg: &Package, @@ -224,7 +217,7 @@ fn fetch_and_verify( let asset_name = pkg.asset_pattern.replace("{version}", &version); let dest_dir = work_dir.join(name).join(tag); - let api = release_source.api(); + let api = host.api(); let asset = fetcher::download_asset(client, api, &pkg.repo, tag, &asset_name, &dest_dir)?; let verification = verifier::verify( client, @@ -327,11 +320,11 @@ pub fn run_review(args: &[String]) -> Result<()> { fn approve(state_dir: &Path, work_dir: &Path, name: &str, pkg: &Package, tag: &str) -> Result<()> { let client = build_client()?; - let release_source = source::for_package(pkg)?; + let host = release_source::for_package(pkg)?; // Re-verify rather than trusting the earlier flag: the artifact at // this tag could in principle have changed since it was queued. - let fetched = fetch_and_verify(&client, release_source.as_ref(), work_dir, name, pkg, tag)?; + let fetched = fetch_and_verify(&client, host.as_ref(), work_dir, name, pkg, tag)?; if !fetched.verification.passed { bail!( "re-verification failed on approve: {}", @@ -353,7 +346,7 @@ fn approve(state_dir: &Path, work_dir: &Path, name: &str, pkg: &Package, tag: &s #[cfg(test)] mod tests { use super::*; - use crate::source::{ForgejoEndpoints, GithubEndpoints}; + use crate::release_source::{ForgejoEndpoints, GithubEndpoints}; use crate::test_support::same_origin_package; #[test] @@ -425,14 +418,14 @@ mod tests { /// Runs `process_package` for a package whose checksum is wrong and /// asserts it errors with "verification failed" while leaving no trace /// in state. - fn assert_verification_failure_is_an_error(release_source: &dyn ReleaseSource, pkg: &Package) { + fn assert_verification_failure_is_an_error(host: &dyn ReleaseSource, pkg: &Package) { let client = reqwest::blocking::Client::new(); let state_dir = tempfile::tempdir().unwrap(); let work_dir = tempfile::tempdir().unwrap(); let err = process_package( &client, - release_source, + host, state_dir.path(), work_dir.path(), "thing", diff --git a/src/source/release_source.rs b/src/release_source/contract.rs similarity index 100% rename from src/source/release_source.rs rename to src/release_source/contract.rs diff --git a/src/source/forgejo.rs b/src/release_source/forgejo.rs similarity index 100% rename from src/source/forgejo.rs rename to src/release_source/forgejo.rs diff --git a/src/source/github.rs b/src/release_source/github.rs similarity index 100% rename from src/source/github.rs rename to src/release_source/github.rs diff --git a/src/source/mod.rs b/src/release_source/mod.rs similarity index 93% rename from src/source/mod.rs rename to src/release_source/mod.rs index 615a0bc..2f75e02 100644 --- a/src/source/mod.rs +++ b/src/release_source/mod.rs @@ -2,15 +2,16 @@ //! one file per host implementing it, and `for_package`, which picks the //! implementation for a package from its configured `source`. The //! submodules are private and re-exported here, so the rest of the crate -//! imports everything from `crate::source` and never a host's file. +//! imports everything from `crate::release_source` and never a host's +//! file. +mod contract; mod forgejo; mod github; -mod release_source; +pub use contract::ReleaseSource; pub use forgejo::ForgejoEndpoints; pub use github::GithubEndpoints; -pub use release_source::ReleaseSource; use crate::config::{Package, Source}; use anyhow::{Context, Result};