mirror of
https://github.com/j178/prek.git
synced 2026-04-09 01:52:24 +02:00
830 lines
25 KiB
Rust
830 lines
25 KiB
Rust
use assert_fs::fixture::{FileWriteStr, PathChild, PathCreateDir};
|
|
|
|
use crate::common::{TestContext, cmd_snapshot};
|
|
|
|
/// Test basic Ruby hook with system Ruby
|
|
#[test]
|
|
fn system_ruby() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Discover the actual system Ruby path
|
|
let ruby_path = which::which("ruby")
|
|
.expect("Ruby not found in PATH")
|
|
.to_string_lossy()
|
|
.to_string();
|
|
|
|
context.write_pre_commit_config(&format!(
|
|
indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: ruby-version
|
|
name: ruby-version
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version-unspecified
|
|
name: ruby-version-unspecified
|
|
language: ruby
|
|
entry: ruby --version
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version-path
|
|
name: ruby-version-path
|
|
language: ruby
|
|
language_version: {}
|
|
entry: ruby --version
|
|
pass_filenames: false
|
|
always_run: true
|
|
"},
|
|
ruby_path
|
|
));
|
|
context.git_add(".");
|
|
|
|
let filters = [(
|
|
r"ruby (\d+\.\d+)\.\d+(?:p\d+)? \(\d{4}-\d{2}-\d{2} revision [0-9a-f]{0,10}\).*?\[.+\]",
|
|
"ruby $1.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]",
|
|
)]
|
|
.into_iter()
|
|
.chain(context.filters())
|
|
.collect::<Vec<_>>();
|
|
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
ruby-version.............................................................Passed
|
|
- hook id: ruby-version
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version-unspecified.................................................Passed
|
|
- hook id: ruby-version-unspecified
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version-path........................................................Passed
|
|
- hook id: ruby-version-path
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
|
|
----- stderr -----
|
|
");
|
|
}
|
|
|
|
/// Test that `language_version: default` works
|
|
#[test]
|
|
fn language_version_default() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: ruby-default
|
|
name: ruby-default
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: default
|
|
pass_filenames: false
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
let filters = [(
|
|
r"ruby (\d+\.\d+)\.\d+(?:p\d+)? \(\d{4}-\d{2}-\d{2} revision [0-9a-f]{0,10}\).*?\[.+\]",
|
|
"ruby $1.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]",
|
|
)]
|
|
.into_iter()
|
|
.chain(context.filters())
|
|
.collect::<Vec<_>>();
|
|
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
ruby-default.............................................................Passed
|
|
- hook id: ruby-default
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
|
|
----- stderr -----
|
|
");
|
|
}
|
|
|
|
/// Test basic Ruby hook with a specified (and available) version of Ruby
|
|
#[test]
|
|
fn specific_ruby_available() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: ruby-version-prefixed
|
|
name: ruby-version-prefixed
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: ruby3.4
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version
|
|
name: ruby-version
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: '3.4'
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version-range-min
|
|
name: ruby-version-range-min
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: '>=3.2'
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version-range-max
|
|
name: ruby-version-range-max
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: '<4.0'
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: ruby-version-constrained-range
|
|
name: ruby-version-constrained-range
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: '>=3.2, <4'
|
|
pass_filenames: false
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
let filters = [(
|
|
r"ruby (\d+\.\d+)\.\d+(?:p\d+)? \(\d{4}-\d{2}-\d{2} revision [0-9a-f]{0,10}\).*?\[.+\]",
|
|
"ruby $1.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]",
|
|
)]
|
|
.into_iter()
|
|
.chain(context.filters())
|
|
.collect::<Vec<_>>();
|
|
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
ruby-version-prefixed....................................................Passed
|
|
- hook id: ruby-version-prefixed
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version.............................................................Passed
|
|
- hook id: ruby-version
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version-range-min...................................................Passed
|
|
- hook id: ruby-version-range-min
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version-range-max...................................................Passed
|
|
- hook id: ruby-version-range-max
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
ruby-version-constrained-range...........................................Passed
|
|
- hook id: ruby-version-constrained-range
|
|
- duration: [TIME]
|
|
|
|
ruby 3.4.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]
|
|
|
|
----- stderr -----
|
|
");
|
|
}
|
|
|
|
/// Test basic Ruby hook with a specified (and unavailable) version of Ruby
|
|
#[test]
|
|
fn specific_ruby_unavailable() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: ruby-version
|
|
name: ruby-version
|
|
language: ruby
|
|
entry: ruby --version
|
|
language_version: 3.1.3
|
|
pass_filenames: false
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
let filters = [(
|
|
r"ruby (\d+\.\d+)\.\d+(?:p\d+)? \(\d{4}-\d{2}-\d{2} revision [0-9a-f]{0,10}\).*?\[.+\]",
|
|
"ruby $1.X ([DATE] revision [HASH]) [FLAGS] [PLATFORM]",
|
|
)]
|
|
.into_iter()
|
|
.chain(context.filters())
|
|
.collect::<Vec<_>>();
|
|
|
|
#[cfg(target_os = "windows")]
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
error: Failed to install hook `ruby-version`
|
|
caused by: Failed to install Ruby
|
|
caused by: No suitable Ruby found for request: 3.1.3
|
|
|
|
Ruby language only supports system Ruby on Windows.
|
|
Please install Ruby from https://rubyinstaller.org/
|
|
");
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
error: Failed to install hook `ruby-version`
|
|
caused by: Failed to install Ruby
|
|
caused by: No suitable Ruby found for request: 3.1.3
|
|
|
|
Detected version manager(s): brew
|
|
|
|
You can install the required Ruby version using:
|
|
brew install ruby # Installs latest version
|
|
# Note: Homebrew typically installs the latest Ruby version.
|
|
# For specific versions, consider using a version manager like rbenv or mise.
|
|
");
|
|
}
|
|
|
|
/// Test Ruby hook with `additional_dependencies` and `require` statement
|
|
#[test]
|
|
fn additional_gem_dependencies() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Create a Ruby script that uses a gem from additional_dependencies
|
|
// Use 'rspec' - a gem that's NOT bundled with Ruby
|
|
context
|
|
.work_dir()
|
|
.child("test_script.rb")
|
|
.write_str(indoc::indoc! {r"
|
|
require 'rspec'
|
|
puts RSpec::Version::STRING
|
|
"})?;
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: test-gem-require
|
|
name: test-gem-require
|
|
language: ruby
|
|
entry: ruby test_script.rb
|
|
language_version: system
|
|
additional_dependencies: ["rspec"]
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: test-gem-require-versioned
|
|
name: test-gem-require-versioned
|
|
language: ruby
|
|
entry: ruby test_script.rb
|
|
language_version: system
|
|
additional_dependencies: ["rspec:3.12.0"]
|
|
pass_filenames: false
|
|
always_run: true
|
|
- id: test-gem-require-missing
|
|
name: test-gem-require-missing
|
|
language: ruby
|
|
entry: ruby test_script.rb
|
|
language_version: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
"#});
|
|
context.git_add(".");
|
|
|
|
let filters = [
|
|
// Normalize unpinned rspec version (only for test-gem-require, not test-gem-require-versioned)
|
|
(
|
|
r"(- hook id: test-gem-require\n- duration: .*?\n\n) \d+\.\d+\.\d+",
|
|
"$1 X.Y.Z",
|
|
),
|
|
// Normalize Ruby internal paths
|
|
(r"<internal:[^>]+>:\d+:in", "<internal:[RUBY_LIB]>:[X]:in"),
|
|
]
|
|
.into_iter()
|
|
.chain(context.filters())
|
|
.collect::<Vec<_>>();
|
|
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
test-gem-require.........................................................Passed
|
|
- hook id: test-gem-require
|
|
- duration: [TIME]
|
|
|
|
X.Y.Z
|
|
test-gem-require-versioned...............................................Passed
|
|
- hook id: test-gem-require-versioned
|
|
- duration: [TIME]
|
|
|
|
3.12.0
|
|
test-gem-require-missing.................................................Failed
|
|
- hook id: test-gem-require-missing
|
|
- duration: [TIME]
|
|
- exit code: 1
|
|
|
|
<internal:[RUBY_LIB]>:[X]:in 'Kernel#require': cannot load such file -- rspec (LoadError)
|
|
from <internal:[RUBY_LIB]>:[X]:in 'Kernel#require'
|
|
from test_script.rb:1:in '<main>'
|
|
|
|
----- stderr -----
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test Ruby hook with gemspec
|
|
#[test]
|
|
fn gemspec_workflow() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Create a simple gemspec
|
|
context
|
|
.work_dir()
|
|
.child("test_gem.gemspec")
|
|
.write_str(indoc::indoc! {r#"
|
|
Gem::Specification.new do |spec|
|
|
spec.name = "test_gem"
|
|
spec.version = "0.1.0"
|
|
spec.authors = ["Test"]
|
|
spec.email = ["test@example.com"]
|
|
spec.summary = "Test gem"
|
|
spec.files = ["lib/test_gem.rb"]
|
|
spec.require_paths = ["lib"]
|
|
end
|
|
"#})?;
|
|
|
|
// Create lib directory and file
|
|
context.work_dir().child("lib").create_dir_all()?;
|
|
context
|
|
.work_dir()
|
|
.child("lib/test_gem.rb")
|
|
.write_str(indoc::indoc! {r#"
|
|
module TestGem
|
|
def self.hello
|
|
"Hello from TestGem"
|
|
end
|
|
end
|
|
"#})?;
|
|
|
|
// Create test script
|
|
context
|
|
.work_dir()
|
|
.child("test_script.rb")
|
|
.write_str(indoc::indoc! {r"
|
|
require 'test_gem'
|
|
puts TestGem.hello
|
|
"})?;
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: test-gemspec
|
|
name: test-gemspec
|
|
language: ruby
|
|
entry: ruby -I lib test_script.rb
|
|
language_version: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
test-gemspec.............................................................Passed
|
|
- hook id: test-gemspec
|
|
- duration: [TIME]
|
|
|
|
Hello from TestGem
|
|
|
|
----- stderr -----
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test environment isolation between Ruby hooks
|
|
#[test]
|
|
fn environment_isolation() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: hook1
|
|
name: hook1
|
|
language: ruby
|
|
entry: ruby -e "puts 'hook1=' + ENV['GEM_HOME']"
|
|
language_version: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
verbose: true
|
|
- id: hook2
|
|
name: hook2
|
|
language: ruby
|
|
entry: ruby -e "puts 'hook2=' + ENV['GEM_HOME']"
|
|
language_version: system
|
|
pass_filenames: false
|
|
always_run: true
|
|
verbose: true
|
|
- id: hook3
|
|
name: hook3
|
|
language: ruby
|
|
entry: ruby -e "puts 'hook3=' + ENV['GEM_HOME']"
|
|
language_version: system
|
|
additional_dependencies: ["rspec"]
|
|
pass_filenames: false
|
|
always_run: true
|
|
verbose: true
|
|
- id: hook4
|
|
name: hook4
|
|
language: ruby
|
|
entry: ruby -e "puts 'hook4=' + ENV['GEM_HOME']"
|
|
language_version: system
|
|
additional_dependencies: ["webrick"]
|
|
pass_filenames: false
|
|
always_run: true
|
|
verbose: true
|
|
- id: hook5
|
|
name: hook5
|
|
language: ruby
|
|
entry: ruby -e "puts 'hook5=' + ENV['GEM_HOME']"
|
|
language_version: system
|
|
additional_dependencies: ["rspec"]
|
|
pass_filenames: false
|
|
always_run: true
|
|
verbose: true
|
|
"#});
|
|
context.git_add(".");
|
|
|
|
let output = context.run().output()?;
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"Command failed\nEXIT CODE: {:?}\nSTDOUT:\n{}\nSTDERR:\n{}",
|
|
output.status.code(),
|
|
stdout,
|
|
stderr
|
|
);
|
|
|
|
// Extract GEM_HOME paths from each hook's output
|
|
let extract_gem_home = |hook_id: &str| -> String {
|
|
let prefix = format!("{hook_id}=");
|
|
stdout
|
|
.lines()
|
|
.find_map(|line| line.trim().strip_prefix(&prefix))
|
|
.unwrap_or_else(|| panic!("Failed to extract GEM_HOME for {hook_id}"))
|
|
.to_string()
|
|
};
|
|
|
|
let hook1_gem_home = extract_gem_home("hook1");
|
|
let hook2_gem_home = extract_gem_home("hook2");
|
|
let hook3_gem_home = extract_gem_home("hook3");
|
|
let hook4_gem_home = extract_gem_home("hook4");
|
|
let hook5_gem_home = extract_gem_home("hook5");
|
|
|
|
// Verify isolation: hook1 == hook2 (same dependencies (none))
|
|
assert_eq!(
|
|
hook1_gem_home, hook2_gem_home,
|
|
"hook1 and hook2 should share the same environment (both have no additional_dependencies)"
|
|
);
|
|
|
|
// Verify isolation: hook3 == hook5 (same dependencies (rspec))
|
|
assert_eq!(
|
|
hook3_gem_home, hook5_gem_home,
|
|
"hook3 and hook5 should share the same environment (both have the same additional_dependencies)"
|
|
);
|
|
|
|
// Verify isolation: hook1 != hook3 (different dependencies)
|
|
assert_ne!(
|
|
hook1_gem_home, hook3_gem_home,
|
|
"hook1 and hook3 should have different environments (hook3 has rspec)"
|
|
);
|
|
|
|
// Verify isolation: hook1 != hook4 (different dependencies)
|
|
assert_ne!(
|
|
hook1_gem_home, hook4_gem_home,
|
|
"hook1 and hook4 should have different environments (hook4 has webrick)"
|
|
);
|
|
|
|
// Verify isolation: hook3 != hook4 (different dependencies)
|
|
assert_ne!(
|
|
hook3_gem_home, hook4_gem_home,
|
|
"hook3 and hook4 should have different environments (different gems)"
|
|
);
|
|
|
|
// Run the command again to check that the environments are reused
|
|
let output = context.run().output()?;
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"Command failed\nEXIT CODE: {:?}\nSTDOUT:\n{}\nSTDERR:\n{}",
|
|
output.status.code(),
|
|
stdout,
|
|
stderr
|
|
);
|
|
|
|
let hook1_gem_home_v2 = extract_gem_home("hook1");
|
|
let hook2_gem_home_v2 = extract_gem_home("hook2");
|
|
let hook3_gem_home_v2 = extract_gem_home("hook3");
|
|
let hook4_gem_home_v2 = extract_gem_home("hook4");
|
|
let hook5_gem_home_v2 = extract_gem_home("hook5");
|
|
|
|
assert_eq!(
|
|
hook1_gem_home, hook1_gem_home_v2,
|
|
"hook1 should reuse the same environment on a second run"
|
|
);
|
|
|
|
assert_eq!(
|
|
hook2_gem_home, hook2_gem_home_v2,
|
|
"hook2 should reuse the same environment on a second run"
|
|
);
|
|
|
|
assert_eq!(
|
|
hook3_gem_home, hook3_gem_home_v2,
|
|
"hook3 should reuse the same environment on a second run"
|
|
);
|
|
|
|
assert_eq!(
|
|
hook4_gem_home, hook4_gem_home_v2,
|
|
"hook4 should reuse the same environment on a second run"
|
|
);
|
|
|
|
assert_eq!(
|
|
hook5_gem_home, hook5_gem_home_v2,
|
|
"hook5 should reuse the same environment on a second run"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test local Ruby hook repository with gemspec build and install
|
|
#[test]
|
|
fn local_hook_with_gemspec() -> anyhow::Result<()> {
|
|
use std::process::Command;
|
|
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Create a local hook repository with a gemspec
|
|
let hook_repo = context.work_dir().child("my-hook-repo");
|
|
hook_repo.create_dir_all()?;
|
|
|
|
// Create the gemspec
|
|
hook_repo
|
|
.child("my_hook.gemspec")
|
|
.write_str(indoc::indoc! {r#"
|
|
Gem::Specification.new do |spec|
|
|
spec.name = "my_hook"
|
|
spec.version = "0.1.0"
|
|
spec.authors = ["Test"]
|
|
spec.email = ["test@example.com"]
|
|
spec.summary = "Test hook gem"
|
|
spec.files = ["bin/my-hook"]
|
|
spec.executables = ["my-hook"]
|
|
spec.bindir = "bin"
|
|
end
|
|
"#})?;
|
|
|
|
// Create executable
|
|
hook_repo.child("bin").create_dir_all()?;
|
|
hook_repo.child("bin/my-hook").write_str(indoc::indoc! {r#"
|
|
#!/usr/bin/env ruby
|
|
puts "Hook executed from gem!"
|
|
"#})?;
|
|
|
|
// Create .pre-commit-hooks.yaml manifest
|
|
hook_repo
|
|
.child(".pre-commit-hooks.yaml")
|
|
.write_str(indoc::indoc! {r"
|
|
- id: my-hook
|
|
name: My Hook
|
|
entry: my-hook
|
|
language: ruby
|
|
pass_filenames: false
|
|
"})?;
|
|
|
|
// Initialize git repo in the hook directory (separate from main project)
|
|
let output = Command::new("git")
|
|
.args(["init"])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
assert!(output.status.success(), "git init failed: {output:?}");
|
|
|
|
// Configure git user for this repo
|
|
Command::new("git")
|
|
.args(["config", "user.name", "Test User"])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
|
|
Command::new("git")
|
|
.args(["config", "user.email", "test@example.com"])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
|
|
let output = Command::new("git")
|
|
.args(["add", "."])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
assert!(output.status.success(), "git add failed: {output:?}");
|
|
|
|
let output = Command::new("git")
|
|
.args(["commit", "-m", "Initial commit"])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
assert!(output.status.success(), "git commit failed: {output:?}");
|
|
|
|
// Get the commit SHA
|
|
let rev_output = Command::new("git")
|
|
.args(["rev-parse", "HEAD"])
|
|
.current_dir(&hook_repo)
|
|
.output()?;
|
|
assert!(rev_output.status.success(), "git rev-parse failed");
|
|
let rev = String::from_utf8_lossy(&rev_output.stdout)
|
|
.trim()
|
|
.to_string();
|
|
|
|
// Configure prek to use this local repo
|
|
context.write_pre_commit_config(&indoc::formatdoc! {r"
|
|
repos:
|
|
- repo: {}
|
|
rev: {}
|
|
hooks:
|
|
- id: my-hook
|
|
name: my-hook
|
|
entry: my-hook
|
|
language: ruby
|
|
pass_filenames: false
|
|
always_run: true
|
|
",
|
|
hook_repo.to_path_buf().display(),
|
|
rev
|
|
});
|
|
context.git_add(".pre-commit-config.yaml");
|
|
|
|
cmd_snapshot!(context.filters(), context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
my-hook..................................................................Passed
|
|
- hook id: my-hook
|
|
- duration: [TIME]
|
|
|
|
Hook executed from gem!
|
|
|
|
----- stderr -----
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test Ruby hook with native gem (C extension)
|
|
#[test]
|
|
fn native_gem_dependency() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Create a Ruby script that uses msgpack (small native gem that compiles quickly)
|
|
context
|
|
.work_dir()
|
|
.child("check_msgpack.rb")
|
|
.write_str(indoc::indoc! {r#"
|
|
#!/usr/bin/env ruby
|
|
require 'msgpack'
|
|
|
|
# Test that the native extension works
|
|
data = { "hello" => "world", "number" => 42 }
|
|
packed = MessagePack.pack(data)
|
|
unpacked = MessagePack.unpack(packed)
|
|
|
|
puts "MessagePack native extension working!"
|
|
puts "Packed size: #{packed.bytesize} bytes"
|
|
"#})?;
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: test-native-gem
|
|
name: test-native-gem
|
|
language: ruby
|
|
entry: ruby check_msgpack.rb
|
|
additional_dependencies: ['msgpack']
|
|
pass_filenames: false
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run().arg("-v"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
test-native-gem..........................................................Passed
|
|
- hook id: test-native-gem
|
|
- duration: [TIME]
|
|
|
|
MessagePack native extension working!
|
|
Packed size: 21 bytes
|
|
|
|
----- stderr -----
|
|
");
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test Ruby hook that processes files
|
|
#[test]
|
|
fn process_files() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
// Create a Ruby script that validates file extensions
|
|
context
|
|
.work_dir()
|
|
.child("check_ruby.rb")
|
|
.write_str(indoc::indoc! {r#"
|
|
ARGV.sort.each do |file|
|
|
unless file.end_with?('.rb')
|
|
puts "Error: #{file} is not a Ruby file"
|
|
exit 1
|
|
end
|
|
puts "OK: #{file}"
|
|
end
|
|
"#})?;
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: check-ruby-files
|
|
name: check-ruby-files
|
|
language: ruby
|
|
entry: ruby check_ruby.rb
|
|
language_version: system
|
|
files: \.rb$
|
|
verbose: true
|
|
"});
|
|
|
|
// Create a Ruby file
|
|
context
|
|
.work_dir()
|
|
.child("test.rb")
|
|
.write_str("puts 'hello'")?;
|
|
// Create a text file
|
|
context.work_dir().child("test.txt").write_str("hello")?;
|
|
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run(), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
check-ruby-files.........................................................Passed
|
|
- hook id: check-ruby-files
|
|
- duration: [TIME]
|
|
|
|
OK: check_ruby.rb
|
|
OK: test.rb
|
|
|
|
----- stderr -----
|
|
");
|
|
|
|
Ok(())
|
|
}
|