Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/prek-consts/src/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ impl EnvVars {
pub const PREK_NO_CONCURRENCY: &'static str = "PREK_NO_CONCURRENCY";
pub const PREK_CONCURRENT_HOOKS: &'static str = "PREK_CONCURRENT_HOOKS";
pub const PREK_CONCURRENT_BATCHES: &'static str = "PREK_CONCURRENT_BATCHES";
pub const PREK_MAX_CONCURRENCY: &'static str = "PREK_MAX_CONCURRENCY";
pub const PREK_NO_FAST_PATH: &'static str = "PREK_NO_FAST_PATH";
pub const PREK_UV_SOURCE: &'static str = "PREK_UV_SOURCE";
pub const PREK_NATIVE_TLS: &'static str = "PREK_NATIVE_TLS";
Expand Down
2 changes: 1 addition & 1 deletion crates/prek/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ pub(crate) enum Command {
/// Generate a sample prek configuration file.
SampleConfig(SampleConfigArgs),
/// Update configured repositories.
#[command(aliases = ["auto-update", "autoupdate"])]
#[command(alias = "autoupdate")]
Update(UpdateArgs),
/// Manage the prek cache.
Cache(CacheNamespace),
Expand Down
16 changes: 0 additions & 16 deletions crates/prek/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ use crate::warn_user_once;
)]
pub(crate) struct Config {
/// Default settings for `prek update` in this project.
#[serde(alias = "auto_update")]
pub update: Option<UpdateOptions>,
/// Configuration-local aliases for numeric hook priorities.
#[serde(default)]
Expand Down Expand Up @@ -873,21 +872,6 @@ mod tests {
"#);
}

#[test]
fn parse_legacy_update_key_alias() {
let yaml = indoc::indoc! {r"
auto_update:
cooldown_days: 7
repos: []
"};
let result = serde_saphyr::from_str::<Config>(yaml).unwrap();

assert_eq!(
result.update.and_then(|options| options.cooldown_days),
Some(7)
);
}

#[test]
fn test_read_yaml_config() -> Result<()> {
let config = read_config(Path::new("tests/fixtures/uv-pre-commit-config.yaml"))?;
Expand Down
49 changes: 8 additions & 41 deletions crates/prek/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,16 @@ fn resolve_concurrency(env_vars: &impl EnvVarsRead, primary_env_var: &str) -> us
return 1;
}

let primary = env_vars.var(primary_env_var).ok();
let legacy_max = env_vars.var(EnvVars::PREK_MAX_CONCURRENCY).ok();
let (name, value) = if let Some(primary) = primary.as_deref() {
(primary_env_var, Some(primary))
} else {
(EnvVars::PREK_MAX_CONCURRENCY, legacy_max.as_deref())
};

let cpu = cpu_count();
if let Some(value) = value {
if let Ok(cap) = value.parse::<usize>() {
return cap.max(1);
}
warn_user!(
"Invalid value for {name}: {value:?}. Expected a positive integer; using default ({cpu})"
);
let Ok(value) = env_vars.var(primary_env_var) else {
return cpu;
};
if let Ok(cap) = value.parse::<usize>() {
return cap.max(1);
}
warn_user!(
"Invalid value for {primary_env_var}: {value:?}. Expected a positive integer; using default ({cpu})"
);

cpu
}
Expand Down Expand Up @@ -474,39 +467,13 @@ mod tests {
&[
(EnvVars::PREK_NO_CONCURRENCY, "1"),
(EnvVars::PREK_CONCURRENT_HOOKS, "8"),
(EnvVars::PREK_MAX_CONCURRENCY, "4"),
],
EnvVars::PREK_CONCURRENT_HOOKS,
),
1
);
}

#[test]
fn test_resolve_concurrency_uses_legacy_max() {
assert_eq!(
resolve_concurrency_from_map(
&[(EnvVars::PREK_MAX_CONCURRENCY, "4")],
EnvVars::PREK_CONCURRENT_HOOKS,
),
4
);
}

#[test]
fn test_resolve_concurrency_prefers_new_env_over_legacy_max() {
assert_eq!(
resolve_concurrency_from_map(
&[
(EnvVars::PREK_CONCURRENT_BATCHES, "2"),
(EnvVars::PREK_MAX_CONCURRENCY, "4"),
],
EnvVars::PREK_CONCURRENT_BATCHES,
),
2
);
}

#[test]
fn test_partitions_respects_cli_length_limit() {
// Create files that will exceed CLI length limit
Expand Down
29 changes: 1 addition & 28 deletions crates/prek/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,32 +120,6 @@ fn strip_null_acceptance(schema: &mut schemars::Schema) {
}
}

fn add_compatibility_aliases(schema: &mut schemars::Schema) {
use serde_json::Value;

let Some(properties) = schema
.as_object_mut()
.and_then(|schema| schema.get_mut("properties"))
.and_then(Value::as_object_mut)
else {
return;
};

let Some(update_schema) = properties.get("update").cloned() else {
return;
};
let mut auto_update_schema = update_schema;
if let Some(obj) = auto_update_schema.as_object_mut() {
obj.insert(
"description".to_string(),
Value::String(
"Compatibility alias for `update`. Prefer `update` in new configs.".to_string(),
),
);
}
properties.insert("auto_update".to_string(), auto_update_schema);
}

impl schemars::JsonSchema for Stages {
fn inline_schema() -> bool {
true
Expand Down Expand Up @@ -471,8 +445,7 @@ mod _gen {
.with_transform(schemars::transform::RestrictFormats::default())
.with_transform(super::RemoveNullTypes);
let generator = schemars::SchemaGenerator::new(settings);
let mut schema = generator.into_root_schema_for::<Config>();
super::add_compatibility_aliases(&mut schema);
let schema = generator.into_root_schema_for::<Config>();
serde_json::to_string_pretty(&schema).unwrap() + "\n"
}

Expand Down
17 changes: 0 additions & 17 deletions crates/prek/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ impl Deref for FilesystemOptions {
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default, rename_all = "snake_case")]
pub(crate) struct Options {
#[serde(alias = "auto_update")]
update: Option<GlobalUpdateOptions>,
}

Expand Down Expand Up @@ -260,22 +259,6 @@ mod tests {
"#);
}

#[test]
fn options_deserializes_legacy_update_key_alias() {
let options: Options = toml::from_str(
r"
[auto_update]
cooldown_days = 7
",
)
.unwrap();

assert_eq!(
options.update.and_then(|options| options.cooldown_days),
Some(7)
);
}

#[test]
fn update_settings_uses_global_freeze() {
let filesystem = FilesystemOptions(
Expand Down
22 changes: 4 additions & 18 deletions crates/prek/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::fs::{LockedFile, expand_tilde};
use crate::git::{self, TerminalPrompt};
use crate::run::INTERNAL_CONCURRENCY;
use crate::warn_user;
use crate::workspace::{HookInitReporter, WorkspaceCache};
use crate::workspace::HookInitReporter;

struct PendingClone<'a> {
repo: &'a RemoteRepo,
Expand Down Expand Up @@ -347,33 +347,19 @@ impl Store {
}

/// Get all tracked config files.
///
/// Seed `config-tracking.json` from the workspace discovery cache if it doesn't exist.
/// This is a one-time upgrade helper: it only does work when the tracking file is absent.
pub(crate) fn tracked_configs(&self) -> Result<FxHashSet<PathBuf>, Error> {
let tracking_file = self.config_tracking_file();
match fs_err::read_to_string(&tracking_file) {
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => return Err(e.into()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(FxHashSet::default()),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve configs discovered before tracking starts

When config-tracking.json is absent but workspace caches already exist, returning an empty set here causes the next run or exec to write only its own selected configs. Other entry points, notably install --install-hooks through prepare_hooks, initialize repositories and hook environments and save a workspace cache without calling track_configs; after a run in another workspace creates the tracking file, cache gc treats those still-used resources as unreferenced and removes them. Preserve the migration seeding or make every resource-producing path track its configs before removing it.

Useful? React with 👍 / 👎.

Err(e) => Err(e.into()),
Ok(content) => {
let tracked = serde_json::from_str(&content).unwrap_or_else(|e| {
warn!("Failed to parse config tracking file: {e}, resetting");
FxHashSet::default()
});
return Ok(tracked);
Ok(tracked)
}
}

let tracked = WorkspaceCache::cached_config_paths(self);
if !tracked.is_empty() {
debug!(
count = tracked.len(),
"Bootstrapping config tracking from workspace cache"
);
self.update_tracked_configs(&tracked)?;
}

Ok(tracked)
}

/// Track new config files for GC.
Expand Down
60 changes: 0 additions & 60 deletions crates/prek/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,66 +600,6 @@ impl WorkspaceCache {
fs_err::write(&cache_path, content)?;
Ok(())
}

/// Best-effort source of config paths for bootstrapping config tracking.
///
/// This is used on upgrades from older versions that didn't track configs yet.
/// It reads all cached workspace discovery entries under `cache/prek/workspace/*`
/// and collects any config file paths they mention.
pub(crate) fn cached_config_paths(store: &Store) -> FxHashSet<PathBuf> {
let mut paths: FxHashSet<PathBuf> = FxHashSet::default();

let workspace_cache_root = store.cache_path(CacheBucket::Prek).join("workspace");
let entries = match fs_err::read_dir(&workspace_cache_root) {
Ok(entries) => entries,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return paths,
Err(err) => {
debug!(path = %workspace_cache_root.display(), %err, "Failed to read workspace cache directory for tracking bootstrap");
return paths;
}
};

for entry in entries {
let entry = match entry {
Ok(entry) => entry,
Err(err) => {
debug!(%err, "Failed to read workspace cache entry for tracking bootstrap");
continue;
}
};

let path = entry.path();
if !path.is_file() {
continue;
}

let content = match fs_err::read_to_string(&path) {
Ok(content) => content,
Err(err) => {
debug!(path = %path.display(), %err, "Failed to read workspace cache file for tracking bootstrap");
continue;
}
};

let cache: WorkspaceCache = match serde_json::from_str(&content) {
Ok(cache) => cache,
Err(err) => {
debug!(path = %path.display(), %err, "Failed to parse workspace cache file for tracking bootstrap");
continue;
}
};

if cache.version != WorkspaceCache::CURRENT_VERSION {
continue;
}

for file in cache.config_files {
paths.insert(file.path);
}
}

paths
}
}

pub(crate) struct Workspace {
Expand Down
66 changes: 0 additions & 66 deletions crates/prek/tests/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,72 +809,6 @@ fn write_patch_file(path: &ChildPath, content: &str, modified: SystemTime) -> an
Ok(())
}

fn write_workspace_cache_file(
home: &ChildPath,
workspace_root: &std::path::Path,
) -> anyhow::Result<()> {
use std::hash::{Hash as _, Hasher as _};
use std::time::SystemTime;

let config_path = workspace_root.join(PRE_COMMIT_CONFIG_YAML);
let metadata = fs_err::metadata(&config_path)?;
let modified = metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH);
let size = metadata.len();

let mut hasher = std::collections::hash_map::DefaultHasher::new();
workspace_root.hash(&mut hasher);
let digest = hex::encode(hasher.finish().to_le_bytes());

let cache_path = home.child("cache/prek/workspace").child(digest);
let parent = cache_path.parent().expect("cache path has parent");
fs_err::create_dir_all(parent)?;

let content = json!({
"version": 1u32,
"workspace_root": workspace_root,
"created_at": serde_json::to_value(SystemTime::now())?,
"config_files": [
{
"path": config_path,
"modified": serde_json::to_value(modified)?,
"size": size,
}
],
});

cache_path.write_str(&serde_json::to_string_pretty(&content)?)?;
Ok(())
}

#[test]
fn cache_gc_bootstraps_tracking_from_workspace_cache() -> anyhow::Result<()> {
let context = TestEnv::new().with_config("repos: []\n");
context.git_add_all();

let home = context.home_dir();
write_workspace_cache_file(home, context.work_dir().path())?;

// Seed store entries that should be swept, even if `config-tracking.json` is missing.
home.child("repos/deadbeef").create_dir_all()?;
home.child("hooks/hook-env-dead").create_dir_all()?;

cmd_snapshot!(context, context.command().arg("cache").arg("gc"), @r#"
success: true
exit_code: 0
----- stdout -----
Removed 1 repo, 1 hook env ([SIZE])

----- stderr -----
"#);

home.child("repos/deadbeef")
.assert(predicates::path::missing());
home.child("hooks/hook-env-dead")
.assert(predicates::path::missing());

Ok(())
}

#[test]
fn cache_gc_drops_missing_tracked_config() -> anyhow::Result<()> {
let context = TestEnv::new().with_config("repos: []\n");
Expand Down
4 changes: 2 additions & 2 deletions crates/prek/tests/global_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ fn global_config_ignores_unknown_options() {
}

#[test]
fn update_command_accepts_legacy_command_alias() {
fn update_command_accepts_upstream_alias() {
let context = TestEnv::new().with_config("repos: []");

cmd_snapshot!(context, context.command().arg("auto-update"), @"
cmd_snapshot!(context, context.command().arg("autoupdate"), @"
success: true
exit_code: 0
----- stdout -----
Expand Down
Loading
Loading