Skip to content
Closed
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
52 changes: 52 additions & 0 deletions crates/prek/src/cli/run/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ pub(crate) async fn run(
let has_group_filters = group_filters.has_filters();
let workspace = Workspace::discover(store, workspace_root, config, Some(&selectors), refresh)?;

if report_unfrozen_revs(&workspace, printer)? {
return Ok(ExitStatus::Failure);
}

if should_stash {
workspace.check_configs_staged().await?;
}
Expand Down Expand Up @@ -241,6 +245,54 @@ pub(crate) async fn run(
.await
}

fn report_unfrozen_revs(workspace: &Workspace, printer: Printer) -> Result<bool> {
let projects = workspace
.projects()
.iter()
.filter(|project| project.config().requires_frozen_revs())
.filter_map(|project| {
let repos = project
.config()
.repos_with_unfrozen_revs()
.collect::<Vec<_>>();
(!repos.is_empty()).then_some((project, repos))
})
.collect::<Vec<_>>();

if projects.is_empty() {
return Ok(false);
}

writeln!(
printer.stderr(),
"{}: Config contains non-frozen remote hook revisions",
"error".red().bold()
)?;
for (project, repos) in projects {
writeln!(
printer.stderr(),
" in `{}`:",
project.config_file().display()
)?;
for repo in repos {
writeln!(
printer.stderr(),
" - {} uses rev `{}`",
repo.repo.cyan(),
repo.rev.yellow()
)?;
}
}
writeln!(
printer.stderr(),
"{}: run `{}` to replace tags with commit SHAs",
"hint".yellow().bold(),
"prek auto-update --freeze".cyan()
)?;

Ok(true)
}

fn infer_stage_and_input_mode(
explicit_stage: Option<Stage>,
has_group_filters: bool,
Expand Down
67 changes: 55 additions & 12 deletions crates/prek/src/cli/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,44 @@ use anyhow::Result;
use owo_colors::OwoColorize;

use crate::cli::ExitStatus;
use crate::config::{read_config, read_manifest};
use crate::config::{Config, read_config, read_manifest};
use crate::printer::Printer;
use crate::warn_user;

fn write_unfrozen_rev_error(
config: &Config,
config_path: &std::path::Path,
printer: Printer,
) -> Result<bool> {
let repos = config.repos_with_unfrozen_revs().collect::<Vec<_>>();
if repos.is_empty() {
return Ok(false);
}

writeln!(
printer.stderr(),
"{}: Config `{}` contains non-frozen remote hook revisions",
"error".red().bold(),
config_path.display()
)?;
for repo in repos {
writeln!(
printer.stderr(),
" - {} uses rev `{}`",
repo.repo.cyan(),
repo.rev.yellow()
)?;
}
writeln!(
printer.stderr(),
"{}: run `{}` to replace tags with commit SHAs",
"hint".yellow().bold(),
"prek auto-update --freeze".cyan()
)?;

Ok(true)
}

pub(crate) fn validate_configs(configs: Vec<PathBuf>, printer: Printer) -> Result<ExitStatus> {
let mut status = ExitStatus::Success;

Expand All @@ -19,18 +53,27 @@ pub(crate) fn validate_configs(configs: Vec<PathBuf>, printer: Printer) -> Resul
return Ok(ExitStatus::Success);
}

for config in configs {
if let Err(err) = read_config(&config) {
writeln!(printer.stderr(), "{}: {}", "error".red().bold(), err)?;
for source in iter::successors(err.source(), |&err| err.source()) {
writeln!(
printer.stderr(),
" {}: {}",
"caused by".red().bold(),
source
)?;
for config_path in configs {
match read_config(&config_path) {
Ok(config) => {
if config.requires_frozen_revs()
&& write_unfrozen_rev_error(&config, &config_path, printer)?
{
status = ExitStatus::Failure;
}
}
Err(err) => {
writeln!(printer.stderr(), "{}: {}", "error".red().bold(), err)?;
for source in iter::successors(err.source(), |&err| err.source()) {
writeln!(
printer.stderr(),
" {}: {}",
"caused by".red().bold(),
source
)?;
}
status = ExitStatus::Failure;
}
status = ExitStatus::Failure;
}
}

Expand Down
21 changes: 21 additions & 0 deletions crates/prek/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,11 @@ impl RemoteRepo {
}
}

/// Check if a string looks like a frozen git revision.
pub(crate) fn is_frozen_rev(s: &str) -> bool {
looks_like_sha(s)
}

impl Display for RemoteRepo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}@{}", self.repo, self.rev)
Expand Down Expand Up @@ -1175,6 +1180,9 @@ pub(crate) struct Config {
/// Set to true to have prek stop running hooks after the first failure.
/// Default is false.
pub fail_fast: Option<bool>,
/// Set to true to require remote repository revisions to be pinned to commit SHAs.
/// Default is false.
pub require_frozen_revs: Option<bool>,
/// The minimum version of prek required to run this configuration.
#[serde(deserialize_with = "deserialize_and_validate_minimum_version", default)]
pub minimum_prek_version: Option<String>,
Expand All @@ -1189,6 +1197,19 @@ pub(crate) struct Config {
_unused_keys: BTreeMap<String, serde_json::Value>,
}

impl Config {
pub(crate) fn requires_frozen_revs(&self) -> bool {
self.require_frozen_revs.unwrap_or(false)
}

pub(crate) fn repos_with_unfrozen_revs(&self) -> impl Iterator<Item = &RemoteRepo> {
self.repos.iter().filter_map(|repo| match repo {
Repo::Remote(repo) if !is_frozen_rev(&repo.rev) => Some(repo),
Repo::Remote(_) | Repo::Local(_) | Repo::Meta(_) | Repo::Builtin(_) => None,
})
}
}

#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {
#[error(transparent)]
Expand Down
1 change: 1 addition & 0 deletions crates/prek/src/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,7 @@ mod tests {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1959
expression: result
---
Ok(
Expand Down Expand Up @@ -120,6 +121,7 @@ Ok(
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1933
expression: result
---
Config {
Expand Down Expand Up @@ -131,6 +132,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 2365
expression: config
---
Config {
Expand Down Expand Up @@ -52,6 +53,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1838
expression: result
---
Config {
Expand Down Expand Up @@ -51,6 +52,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1684
expression: result
---
Config {
Expand Down Expand Up @@ -57,6 +58,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1695
expression: result
---
Config {
Expand Down Expand Up @@ -52,6 +53,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1725
expression: result
---
Config {
Expand Down Expand Up @@ -52,6 +53,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1641
expression: result
---
Config {
Expand Down Expand Up @@ -51,6 +52,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 2293
expression: config
---
Config {
Expand Down Expand Up @@ -92,6 +93,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 2323
expression: config
---
Config {
Expand Down Expand Up @@ -57,6 +58,7 @@ Config {
files: None,
exclude: None,
fail_fast: None,
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 2001
expression: config
---
Config {
Expand Down Expand Up @@ -129,6 +130,7 @@ Config {
fail_fast: Some(
true,
),
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
source: crates/prek/src/config.rs
assertion_line: 1965
expression: config
---
Config {
Expand Down Expand Up @@ -318,6 +319,7 @@ Config {
fail_fast: Some(
true,
),
require_frozen_revs: None,
minimum_prek_version: None,
orphan: None,
_unused_keys: {},
Expand Down
Loading
Loading