diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..8740716 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,39 @@ +name: Run Tests + +on: + pull_request: + + +jobs: + test: + runs-on: ubuntu-latest + name: Run Tests + steps: + - uses: actions/checkout@v4 + + - name: Cache cargo registry + uses: actions/cache@v4 + with: + path: ~/.cargo/registry + key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-registry- + + - name: Cache cargo index + uses: actions/cache@v4 + with: + path: ~/.cargo/git + key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-index- + + - name: Cache cargo build + uses: actions/cache@v4 + with: + path: target + key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-build- + + - name: Run Tests + run: cargo test diff --git a/action.yaml b/action.yaml index 9a484fd..2b9a743 100644 --- a/action.yaml +++ b/action.yaml @@ -20,7 +20,7 @@ runs: - name: Get Binary shell: bash run: | - BIN_URL=$(curl https://api.github.com/repos/LuisLiraC/git-diff/releases/tags/v1.0.0 | jq -r '.assets[0].browser_download_url') + BIN_URL=$(curl https://api.github.com/repos/LuisLiraC/git-diff/releases/tags/v1.0.1 | jq -r '.assets[0].browser_download_url') curl -s -L $BIN_URL -o rust-binary.tgz tar -xzvf rust-binary.tgz mv ./Linux/git-diff ./git-diff diff --git a/src/main.rs b/src/main.rs index 0c808a7..944c7f7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,9 +14,6 @@ fn main() { let args: Vec = env::args().collect(); let mut patterns_filters: Vec = Vec::new(); - let mut exclude_patterns_filters: Vec = Vec::new(); - let mut include_patterns_filters: Vec = Vec::new(); - for arg in args.iter() { if arg.starts_with("--patterns=") { patterns_filters = create_patterns_filters(&arg); @@ -28,41 +25,19 @@ fn main() { return; } - patterns_filters.iter().for_each(|pattern_filter| { - if pattern_filter.exclude { - exclude_patterns_filters.push(pattern_filter.clone()); - } else { - include_patterns_filters.push(pattern_filter.clone()); - } - }); + let (include_patterns_filters, exclude_patterns_filters) = categorize_filters(patterns_filters); let start = Instant::now(); let changed_files = get_changed_files(); let duration = start.elapsed(); println!("Getting changed files done in: {:?}", duration); - let mut filtered_files: Vec = Vec::new(); - let start = Instant::now(); - for pattern in include_patterns_filters.iter() { - filtered_files.extend(filter_files_by_pattern(&pattern, changed_files.clone())); - } + let filtered_files = filter(changed_files, include_patterns_filters, exclude_patterns_filters); let duration = start.elapsed(); println!("Filtering files done in: {:?}", duration); - let start = Instant::now(); - for pattern in exclude_patterns_filters.iter() { - filtered_files = filtered_files - .iter() - .filter(|file| !Pattern::new(&pattern.pattern).expect("Failed to create pattern").matches(file)) - .map(|file| file.to_string()) - .collect(); - } - let duration = start.elapsed(); - println!("Excluding files done in: {:?}", duration); - - println!("DIFF_FILES: {:?}", filtered_files); - println!("DIFF_COUNT: {}", filtered_files.len()); + let count = get_count(filtered_files.clone()); Command::new("sh") .arg("-c") @@ -72,7 +47,7 @@ fn main() { Command::new("sh") .arg("-c") - .arg(format!("echo \"DIFF_COUNT={}\" >> $GITHUB_OUTPUT", filtered_files.len())) + .arg(format!("echo \"DIFF_COUNT={}\" >> $GITHUB_OUTPUT", count)) .output() .expect("Failed to execute DIFF_COUNT command"); } @@ -144,15 +119,57 @@ fn get_changed_files() -> Vec { changed_files } -fn filter_files_by_pattern(pattern_filter: &PatternFilter, files: Vec) -> Vec { +fn filter(changed_files: Vec, include_patterns_filters: Vec, exclude_patterns_filters: Vec) -> Vec { + let filtered_files: Vec = include_patterns_filters + .iter() + .flat_map(|pattern| filter_files_by_pattern(pattern, &changed_files, &exclude_patterns_filters)) + .collect(); + + filtered_files +} + +fn filter_files_by_pattern(pattern_filter: &PatternFilter, files: &Vec, exclude_patterns: &Vec) -> Vec { let pattern = Pattern::new(&pattern_filter.pattern).expect("Failed to create pattern"); - let filtered_files: Vec = files + let mut filtered_files: Vec = files .iter() .filter(|file| pattern.matches(file)) .filter(|_| pattern_filter.exclude == false) .map(|file| file.to_string()) .collect(); + for exclude_pattern in exclude_patterns.iter() { + filtered_files = filtered_files + .iter() + .filter(|file| !Pattern::new(&exclude_pattern.pattern).expect("Failed to create pattern").matches(file)) + .map(|file| file.to_string()) + .collect(); + } + filtered_files +} + +fn get_count(filtered_files: Vec) -> usize { + filtered_files.len() +} + +fn categorize_filters(filters: Vec) -> (Vec, Vec) { + let mut exclude_patterns_filters: Vec = Vec::new(); + let mut include_patterns_filters: Vec = Vec::new(); + + filters.iter().for_each(|pattern_filter| { + if pattern_filter.exclude { + exclude_patterns_filters.push(pattern_filter.clone()); + } else { + include_patterns_filters.push(pattern_filter.clone()); + } + }); + + (include_patterns_filters, exclude_patterns_filters) +} + +#[cfg(test)] +mod tests { + mod unit; + mod integration; } \ No newline at end of file diff --git a/src/tests/integration.rs b/src/tests/integration.rs new file mode 100644 index 0000000..7594924 --- /dev/null +++ b/src/tests/integration.rs @@ -0,0 +1,30 @@ +use crate::*; + +#[cfg(test)] +mod integration { + use super::*; + + #[test] + fn test_filter() { + let arg = "--patterns=*.rs,!*..txt"; + let files = vec![ + String::from("main.rs"), + String::from("lib.rs"), + String::from("test.txt"), + ]; + + let filters = create_patterns_filters(arg); + + let (include_patterns_filters, exclude_patterns_filters) = categorize_filters(filters); + + let filtered_files = filter(files, include_patterns_filters, exclude_patterns_filters); + + let count = get_count(filtered_files.clone()); + + assert_eq!( + filtered_files, + vec![String::from("main.rs"), String::from("lib.rs")] + ); + assert_eq!(count, 2); + } +} diff --git a/src/tests/unit.rs b/src/tests/unit.rs new file mode 100644 index 0000000..ee114f7 --- /dev/null +++ b/src/tests/unit.rs @@ -0,0 +1,134 @@ +use crate::*; + +#[cfg(test)] +mod unit { + use super::*; + + #[test] + fn test_create_patterns_filters() { + let arg = "--patterns=*.rs,!test/*.rs"; + let filters = create_patterns_filters(arg); + assert_eq!(filters.len(), 2); + assert_eq!(filters[0].pattern, "*.rs"); + assert_eq!( + filters[0].exclude, false, + "Expected 'exclude' to be false for pattern '*.rs'" + ); + assert_eq!(filters[1].pattern, "test/*.rs"); + assert_eq!(filters[1].exclude, true); + } + + #[test] + fn test_categorize_filters() { + let filters = vec![ + PatternFilter { + pattern: String::from("*.rs"), + exclude: false, + }, + PatternFilter { + pattern: String::from("test/*.rs"), + exclude: true, + }, + ]; + let (include_patterns_filters, exclude_patterns_filters) = categorize_filters(filters); + assert_eq!(include_patterns_filters.len(), 1); + assert_eq!(exclude_patterns_filters.len(), 1); + assert_eq!(include_patterns_filters[0].pattern, "*.rs"); + assert_eq!(exclude_patterns_filters[0].pattern, "test/*.rs"); + } + + #[test] + fn test_filter() { + let files = vec![ + String::from("main.rs"), + String::from("lib.rs"), + String::from("test.txt"), + ]; + let include_patterns_filters = vec![ + PatternFilter { + pattern: String::from("*.rs"), + exclude: false, + }, + PatternFilter { + pattern: String::from("*.txt"), + exclude: false, + }, + ]; + let exclude_patterns_filters = vec![PatternFilter { + pattern: String::from("test.txt"), + exclude: true, + }]; + let filtered_files = filter(files, include_patterns_filters, exclude_patterns_filters); + assert_eq!( + filtered_files, + vec![String::from("main.rs"), String::from("lib.rs")] + ); + } + + #[test] + fn test_filter_files_by_pattern() { + let pattern_filter = PatternFilter { + pattern: String::from("*.rs"), + exclude: false, + }; + let files = vec![ + String::from("main.rs"), + String::from("lib.rs"), + String::from("test.txt"), + ]; + let filtered = filter_files_by_pattern(&pattern_filter, &files, &Vec::new()); + assert_eq!( + filtered, + vec![String::from("main.rs"), String::from("lib.rs")] + ); + } + + #[test] + fn test_filter_exclude_files_exclusion() { + let mut filtered_files: Vec = Vec::new(); + let mut exclude_patterns_filters: Vec = Vec::new(); + let mut include_patterns_filters: Vec = Vec::new(); + + include_patterns_filters.push(PatternFilter { + pattern: String::from("*.rs"), + exclude: false, + }); + + include_patterns_filters.push(PatternFilter { + pattern: String::from("*.txt"), + exclude: false, + }); + + exclude_patterns_filters.push(PatternFilter { + pattern: String::from("test.txt"), + exclude: true, + }); + + let files = vec![ + String::from("main.rs"), + String::from("lib.rs"), + String::from("version.txt"), + String::from("test.txt"), + ]; + + for pattern in include_patterns_filters.iter() { + filtered_files.extend(filter_files_by_pattern(&pattern, &files, &exclude_patterns_filters)); + } + + assert_eq!( + filtered_files, + vec![String::from("main.rs"), String::from("lib.rs"), String::from("version.txt")] + ); + } + + #[test] + fn test_get_count() { + let files = vec![ + String::from("main.rs"), + String::from("lib.rs"), + String::from("version.txt"), + ]; + let count = get_count(files); + assert_eq!(count, 3); + } +}