diff options
-rw-r--r-- | cli/util/fs.rs | 25 | ||||
-rw-r--r-- | cli/util/gitignore.rs | 20 | ||||
-rw-r--r-- | tests/integration/publish_tests.rs | 31 |
3 files changed, 69 insertions, 7 deletions
diff --git a/cli/util/fs.rs b/cli/util/fs.rs index f6354097a..352e09999 100644 --- a/cli/util/fs.rs +++ b/cli/util/fs.rs @@ -326,7 +326,30 @@ impl<TFilter: Fn(WalkEntry) -> bool> FileCollector<TFilter> { } let mut maybe_git_ignores = if self.use_gitignore { - Some(GitIgnoreTree::new(Arc::new(deno_runtime::deno_fs::RealFs))) + // Override explicitly specified include paths in the + // .gitignore file. This does not apply to globs because + // that is way too complicated to reason about. + let include_paths = file_patterns + .include + .as_ref() + .map(|include| { + include + .inner() + .iter() + .filter_map(|path_or_pattern| { + if let PathOrPattern::Path(p) = path_or_pattern { + Some(p.clone()) + } else { + None + } + }) + .collect::<Vec<_>>() + }) + .unwrap_or_default(); + Some(GitIgnoreTree::new( + Arc::new(deno_runtime::deno_fs::RealFs), + include_paths, + )) } else { None }; diff --git a/cli/util/gitignore.rs b/cli/util/gitignore.rs index da9065494..f4185aa0d 100644 --- a/cli/util/gitignore.rs +++ b/cli/util/gitignore.rs @@ -38,13 +38,19 @@ impl DirGitIgnores { pub struct GitIgnoreTree { fs: Arc<dyn deno_runtime::deno_fs::FileSystem>, ignores: HashMap<PathBuf, Option<Rc<DirGitIgnores>>>, + include_paths: Vec<PathBuf>, } impl GitIgnoreTree { - pub fn new(fs: Arc<dyn deno_runtime::deno_fs::FileSystem>) -> Self { + pub fn new( + fs: Arc<dyn deno_runtime::deno_fs::FileSystem>, + // paths that should override what's in the gitignore + include_paths: Vec<PathBuf>, + ) -> Self { Self { fs, ignores: Default::default(), + include_paths, } } @@ -94,6 +100,16 @@ impl GitIgnoreTree { for line in text.lines() { builder.add_line(None, line).ok()?; } + // override the gitignore contents to include these paths + for path in &self.include_paths { + if let Ok(suffix) = path.strip_prefix(dir_path) { + let suffix = suffix.to_string_lossy().replace('\\', "/"); + let _ignore = builder.add_line(None, &format!("!/{}", suffix)); + if !suffix.ends_with('/') { + let _ignore = builder.add_line(None, &format!("!/{}/", suffix)); + } + } + } let gitignore = builder.build().ok()?; Some(Rc::new(gitignore)) }); @@ -122,7 +138,7 @@ mod test { "!file.txt\nignore.txt".into(), ), ]); - let mut ignore_tree = GitIgnoreTree::new(Arc::new(fs)); + let mut ignore_tree = GitIgnoreTree::new(Arc::new(fs), Vec::new()); let mut run_test = |path: &str, expected: bool| { let path = PathBuf::from(path); let gitignore = ignore_tree diff --git a/tests/integration/publish_tests.rs b/tests/integration/publish_tests.rs index 53bb6a376..28046d047 100644 --- a/tests/integration/publish_tests.rs +++ b/tests/integration/publish_tests.rs @@ -409,7 +409,7 @@ fn ignores_directories() { } #[test] -fn not_include_gitignored_file_even_if_matched_in_include() { +fn not_include_gitignored_file_unless_exact_match_in_include() { let context = publish_context_builder().build(); let temp_dir = context.temp_dir().path(); temp_dir.join("deno.json").write_json(&json!({ @@ -417,22 +417,45 @@ fn not_include_gitignored_file_even_if_matched_in_include() { "version": "1.0.0", "exports": "./main.ts", "publish": { - // won't match ignored because it needs to be + // won't match ignored.ts because it needs to be // unexcluded via a negated glob in exclude - "include": [ "deno.json", "*.ts" ] + "include": [ + "deno.json", + "*.ts", + "exact_include.ts", + "sub" + ] } })); - temp_dir.join(".gitignore").write("ignored.ts"); + temp_dir + .join(".gitignore") + .write("ignored.ts\nexact_include.ts\nsub/\nsub/ignored\n/sub_ignored\n"); temp_dir.join("main.ts").write(""); temp_dir.join("ignored.ts").write(""); + temp_dir.join("exact_include.ts").write(""); + let sub_dir = temp_dir.join("sub"); + sub_dir.create_dir_all(); + sub_dir.join("sub_included.ts").write(""); + sub_dir.join("ignored.ts").write(""); // this one is gitignored + sub_dir.join("ignored").create_dir_all(); + sub_dir.join("ignored").join("ignored_also.ts").write(""); + let sub_ignored_dir = temp_dir.join("sub_ignored"); + sub_ignored_dir.create_dir_all(); + sub_ignored_dir.join("sub_ignored.ts").write(""); let output = context.new_command().arg("publish").arg("--dry-run").run(); output.assert_exit_code(0); let output = output.combined_output(); assert_contains!(output, "main.ts"); + // will match this exact match + assert_contains!(output, "exact_include.ts"); + // will include this because the sub directory is included + assert_contains!(output, "sub_included.ts"); // it's gitignored assert_not_contains!(output, "ignored.ts"); + assert_not_contains!(output, "ignored_also.ts"); + assert_not_contains!(output, "sub_ignored.ts"); } #[test] |