use assert_fs::fixture::{FileWriteStr, PathChild};
use prek_consts::PRE_COMMIT_CONFIG_YAML;
use crate::common::{TestContext, cmd_snapshot};
mod common;
#[test]
fn validate_config() -> anyhow::Result<()> {
let context = TestContext::new();
cmd_snapshot!(context.filters(), context.validate_config(), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: No configs to check
");
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-json
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
success: All configs are valid
");
context
.work_dir()
.child("config-1.yaml")
.write_str(indoc::indoc! {r"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
"})?;
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML).arg("config-1.yaml"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to parse `config-1.yaml`
caused by: error: line 2 column 5: missing field `rev`
--> <input>:2:5
|
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
| ^ missing field `rev`
");
Ok(())
}
#[test]
fn mutable_revision_warning_has_actionable_guidance() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: https://example.com/hooks
rev: main
hooks: []
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The following repositories use mutable `rev` values (branches or moving tags):
https://example.com/hooks: main
`prek` does not automatically detect changes to these references after the first install.
Use a tag or commit SHA for each `rev`, or run `prek update` to select the latest eligible tag.
See https://prek.j178.dev/reference/configuration/#rev for details.
success: All configs are valid
");
}
#[test]
fn invalid_config_error() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-json
rev: 1.0
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
success: All configs are valid
");
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: local
hooks:
- name: check-json
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to parse `.pre-commit-config.yaml`
caused by: error: line 9 column 9: missing field `id`
--> <input>:9:9
|
7 | - repo: local
8 | hooks:
9 | - name: check-json
| ^ missing field `id`
");
}
#[test]
fn unknown_priority_alias_is_invalid() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r"
priorities:
checks: 10
repos:
- repo: local
hooks:
- id: format
name: Format
entry: ruff format
language: system
priority: formatting
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Priority alias `formatting` referenced by hook `format` is not declared in `priorities`
");
}
#[test]
fn priority_aliases_cannot_contain_whitespace() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r#"
priorities:
"static checks": 10
repos: []
"#});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r#"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to parse `.pre-commit-config.yaml`
caused by: error: line 2 column 3: priority alias `static checks` cannot contain whitespace
--> <input>:2:3
|
1 | priorities:
2 | "static checks": 10
| ^ priority alias `static checks` cannot contain whitespace
3 | repos: []
|
"#);
}
#[test]
fn duplicate_and_unused_priority_aliases_are_valid() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r"
priorities:
checks: 10
verification: 10
unused: 20
repos:
- repo: local
hooks:
- id: check
name: Check
entry: check
language: system
priority: checks
- id: verify
name: Verify
entry: verify
language: system
priority: verification
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
success: All configs are valid
");
}
#[test]
fn validate_manifest() -> anyhow::Result<()> {
let context = TestContext::new();
cmd_snapshot!(context.filters(), context.validate_manifest(), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: No manifests to check
");
context
.work_dir()
.child(".pre-commit-hooks.yaml")
.write_str(indoc::indoc! {r"
- id: check-added-large-files
name: check for added large files
description: prevents giant files from being committed.
entry: check-added-large-files
language: python
stages: [pre-commit, pre-push, manual]
minimum_pre_commit_version: 3.2.0
"})?;
cmd_snapshot!(context.filters(), context.validate_manifest().arg(".pre-commit-hooks.yaml"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
success: All manifests are valid
");
context
.work_dir()
.child("hooks-1.yaml")
.write_str(indoc::indoc! {r"
- id: check-added-large-files
name: check for added large files
description: prevents giant files from being committed.
language: python
stages: [pre-commit, pre-push, manual]
minimum_pre_commit_version: 3.2.0
"})?;
cmd_snapshot!(context.filters(), context.validate_manifest().arg(".pre-commit-hooks.yaml").arg("hooks-1.yaml"), @"
success: false
exit_code: 1
----- stdout -----
----- stderr -----
error: Failed to parse `hooks-1.yaml`
caused by: error: line 6 column 5: missing field `entry`
--> <input>:6:5
|
4 | language: python
5 | stages: [pre-commit, pre-push, manual]
6 | minimum_pre_commit_version: 3.2.0
| ^ missing field `entry`
");
Ok(())
}
#[test]
fn unexpected_keys_warning() {
let context = TestContext::new();
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: local
unexpected_repo_key: some_value
hooks:
- id: test-hook
name: Test Hook
entry: echo test
language: system
unexpected_top_level_key: some_value
another_unknown: test
minimum_pre_commit_version: 1.0.0
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: Ignored unexpected keys in `.pre-commit-config.yaml`: `another_unknown`, `unexpected_top_level_key`, `repos[0].unexpected_repo_key`
success: All configs are valid
");
context.write_pre_commit_config(indoc::indoc! {r"
repos:
- repo: local
unexpected_repo_key: some_value
hooks:
- id: test-hook
name: Test Hook
entry: echo test
language: system
unexpected_hook_key_1: some_value
unexpected_hook_key_2: some_value
unexpected_hook_key_3: some_value
unexpected_hook_key_4: some_value
unexpected_top_level_key: some_value
another_unknown: test
minimum_pre_commit_version: 1.0.0
"});
cmd_snapshot!(context.filters(), context.validate_config().arg(PRE_COMMIT_CONFIG_YAML), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: Ignored unexpected keys in `.pre-commit-config.yaml`:
- `another_unknown`
- `unexpected_top_level_key`
- `repos[0].unexpected_repo_key`
- `repos[0].hooks[0].unexpected_hook_key_1`
- `repos[0].hooks[0].unexpected_hook_key_2`
- `repos[0].hooks[0].unexpected_hook_key_3`
- `repos[0].hooks[0].unexpected_hook_key_4`
success: All configs are valid
");
}