Skip to content

Commit 68b2482

Browse files
committed
fix: apply pattern matching to relative paths instead of absolute paths
Config file ignore/include patterns were not working correctly because pattern matching was performed against absolute paths instead of relative paths. This caused patterns like "agents/git-*" to never match because they were compared against full filesystem paths like "/home/user/project/agents/git-commit.md". Changes: - Move relative path calculation before pattern matching in orchestrator - Apply pattern filters to relative paths (strip_prefix before matching) - Add test case to verify wildcard patterns work with relative paths - Update integration tests to use contains() instead of len() checks to handle additional patterns from global config This ensures that pattern-based filtering works as users expect when specifying relative paths in their configuration files.
1 parent b9bd19d commit 68b2482

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

crates/ccsync-core/src/config/integration_tests.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ include = true
3333
let _manager = ConfigManager::new();
3434
let config = ConfigManager::load(Some(&config_file)).unwrap();
3535

36-
assert_eq!(config.ignore.len(), 2);
37-
assert_eq!(config.include.len(), 1);
36+
// Check that expected patterns are present (may include additional patterns from global config)
37+
assert!(config.ignore.contains(&"*.tmp".to_string()));
38+
assert!(config.ignore.contains(&"*.log".to_string()));
39+
assert!(config.include.contains(&"important.tmp".to_string()));
3840
assert!(config.follow_symlinks != Some(true));
3941
assert_eq!(config.rules.len(), 1);
4042
assert_eq!(config.rules[0].direction, Some(SyncDirection::ToLocal));

crates/ccsync-core/src/config/patterns.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,17 @@ mod tests {
9999
assert!(!matcher.should_include(&PathBuf::from("node_modules"), true));
100100
assert!(matcher.should_include(&PathBuf::from("src"), true));
101101
}
102+
103+
#[test]
104+
fn test_relative_path_wildcards() {
105+
let matcher = PatternMatcher::with_patterns(&["agents/git-*".to_string()], &[]).unwrap();
106+
107+
// Should match agents/git-* pattern
108+
assert!(!matcher.should_include(&PathBuf::from("agents/git-commit.md"), false));
109+
assert!(!matcher.should_include(&PathBuf::from("agents/git-helper.md"), false));
110+
111+
// Should NOT match agents/git-* pattern
112+
assert!(matcher.should_include(&PathBuf::from("agents/other-agent.md"), false));
113+
assert!(matcher.should_include(&PathBuf::from("skills/test.md"), false));
114+
}
102115
}

crates/ccsync-core/src/sync.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,37 @@ mod integration_tests {
260260
assert!(summary.contains("✗ Completed with errors"));
261261
assert!(!result.is_success());
262262
}
263+
264+
#[test]
265+
fn test_sync_pattern_matching_with_relative_paths() {
266+
let (source_dir, dest_dir) = setup_test_dirs();
267+
268+
// Create multiple files with git-* pattern in agents/
269+
create_test_file(source_dir.path(), "agents/git-commit.md", "git commit agent");
270+
create_test_file(source_dir.path(), "agents/git-helper.md", "git helper agent");
271+
create_test_file(source_dir.path(), "agents/other-agent.md", "other agent");
272+
// Create a skill (skills/test-skill/SKILL.md is the expected structure)
273+
create_test_file(source_dir.path(), "skills/test-skill/SKILL.md", "test skill");
274+
275+
// Configure to ignore agents/git-* pattern (relative path)
276+
let mut config = Config::default();
277+
config.ignore = vec!["agents/git-*".to_string()];
278+
279+
let engine = SyncEngine::new(config, SyncDirection::ToLocal).unwrap();
280+
let result = engine.sync(source_dir.path(), dest_dir.path()).unwrap();
281+
282+
// Should create 2 files (other-agent.md and skills/test-skill/SKILL.md)
283+
// Should skip 2 files (git-commit.md and git-helper.md)
284+
assert_eq!(result.created, 2);
285+
assert_eq!(result.skipped, 2);
286+
assert!(result.is_success());
287+
288+
// Verify git-* files were NOT created
289+
assert!(!dest_dir.path().join("agents/git-commit.md").exists());
290+
assert!(!dest_dir.path().join("agents/git-helper.md").exists());
291+
292+
// Verify other files WERE created
293+
assert!(dest_dir.path().join("agents/other-agent.md").exists());
294+
assert!(dest_dir.path().join("skills/test-skill/SKILL.md").exists());
295+
}
263296
}

crates/ccsync-core/src/sync/orchestrator.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,21 +83,21 @@ impl SyncEngine {
8383
let conflict_strategy = self.get_conflict_strategy();
8484

8585
for file in &scan_result.files {
86-
// Apply pattern filter
86+
// Get relative path first (needed for pattern matching)
87+
let rel_path = file
88+
.path
89+
.strip_prefix(source_root)
90+
.with_context(|| format!("Failed to strip prefix from {}", file.path.display()))?;
91+
92+
// Apply pattern filter to relative path
8793
let is_dir = file.path.is_dir();
8894
if let Some(ref matcher) = self.pattern_matcher
89-
&& !matcher.should_include(&file.path, is_dir)
95+
&& !matcher.should_include(rel_path, is_dir)
9096
{
9197
result.skipped += 1;
9298
continue;
9399
}
94100

95-
// Get relative path
96-
let rel_path = file
97-
.path
98-
.strip_prefix(source_root)
99-
.with_context(|| format!("Failed to strip prefix from {}", file.path.display()))?;
100-
101101
let dest_path = dest_root.join(rel_path);
102102

103103
// Compare files

0 commit comments

Comments
 (0)