1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

feat(publish): respect .gitignore during deno publish (#22514)

Files from `.gitignore`, global git config, `.git/info/exclude` and
`deno.json`'s `exclude` are ignored.
This commit is contained in:
Divy Srivastava 2024-02-23 07:56:34 +05:30 committed by GitHub
parent ae703041b1
commit f49abcc1ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 156 additions and 19 deletions

51
Cargo.lock generated
View file

@ -499,6 +499,16 @@ dependencies = [
"alloc-stdlib", "alloc-stdlib",
] ]
[[package]]
name = "bstr"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.14.0" version = "3.14.0"
@ -1060,6 +1070,7 @@ dependencies = [
"glibc_version", "glibc_version",
"glob", "glob",
"hex", "hex",
"ignore",
"import_map", "import_map",
"indexmap", "indexmap",
"jsonc-parser", "jsonc-parser",
@ -2847,6 +2858,19 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata",
"regex-syntax",
]
[[package]] [[package]]
name = "glow" name = "glow"
version = "0.13.0" version = "0.13.0"
@ -3314,6 +3338,23 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed"
[[package]]
name = "ignore"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492"
dependencies = [
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
"thread_local",
"walkdir",
"winapi-util",
]
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.7" version = "0.24.7"
@ -6482,6 +6523,16 @@ dependencies = [
"syn 2.0.48", "syn 2.0.48",
] ]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.30" version = "0.3.30"

View file

@ -106,6 +106,7 @@ flate2.workspace = true
fs3.workspace = true fs3.workspace = true
glob = "0.3.1" glob = "0.3.1"
hex.workspace = true hex.workspace = true
ignore = "0.4"
import_map = { version = "=0.18.3", features = ["ext"] } import_map = { version = "=0.18.3", features = ["ext"] }
indexmap.workspace = true indexmap.workspace = true
jsonc-parser = { version = "=0.23.0", features = ["serde"] } jsonc-parser = { version = "=0.23.0", features = ["serde"] }

View file

@ -3,12 +3,14 @@
use bytes::Bytes; use bytes::Bytes;
use deno_ast::MediaType; use deno_ast::MediaType;
use deno_config::glob::FilePatterns; use deno_config::glob::FilePatterns;
use deno_config::glob::PathOrPattern;
use deno_core::anyhow::Context; use deno_core::anyhow::Context;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::url::Url; use deno_core::url::Url;
use ignore::overrides::OverrideBuilder;
use ignore::WalkBuilder;
use sha2::Digest; use sha2::Digest;
use std::collections::HashSet; use std::collections::HashSet;
use std::ffi::OsStr;
use std::fmt::Write as FmtWrite; use std::fmt::Write as FmtWrite;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
@ -46,27 +48,45 @@ pub fn create_gzipped_tarball(
let mut paths = HashSet::new(); let mut paths = HashSet::new();
let mut iterator = walkdir::WalkDir::new(dir).follow_links(false).into_iter(); let mut ob = OverrideBuilder::new(dir);
while let Some(entry) = iterator.next() { ob.add("!.git")?.add("!node_modules")?.add("!.DS_Store")?;
for pattern in file_patterns.as_ref().iter().flat_map(|p| p.include.iter()) {
for path_or_pat in pattern.inner() {
match path_or_pat {
PathOrPattern::Path(p) => ob.add(p.to_str().unwrap())?,
PathOrPattern::Pattern(p) => ob.add(p.as_str())?,
PathOrPattern::RemoteUrl(_) => continue,
};
}
}
let overrides = ob.build()?;
let iterator = WalkBuilder::new(dir)
.follow_links(false)
.require_git(false)
.git_ignore(true)
.git_global(true)
.git_exclude(true)
.overrides(overrides)
.filter_entry(move |entry| {
let matches_pattern = file_patterns
.as_ref()
.map(|p| p.matches_path(entry.path()))
.unwrap_or(true);
matches_pattern
})
.build();
for entry in iterator {
let entry = entry?; let entry = entry?;
let path = entry.path(); let path = entry.path();
let file_type = entry.file_type(); let Some(file_type) = entry.file_type() else {
// entry doesnt have a file type if it corresponds to stdin.
let matches_pattern = file_patterns
.as_ref()
.map(|p| p.matches_path(path))
.unwrap_or(true);
if !matches_pattern
|| path.file_name() == Some(OsStr::new(".git"))
|| path.file_name() == Some(OsStr::new("node_modules"))
|| path.file_name() == Some(OsStr::new(".DS_Store"))
{
if file_type.is_dir() {
iterator.skip_current_dir();
}
continue; continue;
} };
let Ok(specifier) = Url::from_file_path(path) else { let Ok(specifier) = Url::from_file_path(path) else {
diagnostics_collector diagnostics_collector

View file

@ -215,6 +215,43 @@ itest!(config_flag {
http_server: true, http_server: true,
}); });
#[test]
fn ignores_gitignore() {
let context = publish_context_builder().build();
let temp_dir = context.temp_dir().path();
temp_dir.join("deno.json").write_json(&json!({
"name": "@foo/bar",
"version": "1.0.0",
"exports": "./main.ts"
}));
temp_dir.join("main.ts").write("import './sub_dir/b.ts';");
let gitignore = temp_dir.join(".gitignore");
gitignore.write("ignored.ts\nsub_dir/ignored.wasm");
let sub_dir = temp_dir.join("sub_dir");
sub_dir.create_dir_all();
sub_dir.join("ignored.wasm").write("");
sub_dir.join("b.ts").write("export default {}");
temp_dir.join("ignored.ts").write("");
let output = context
.new_command()
.arg("publish")
.arg("--dry-run")
.arg("--token")
.arg("sadfasdf")
.run();
output.assert_exit_code(0);
let output = output.combined_output();
assert_contains!(output, "b.ts");
assert_contains!(output, "main.ts");
assert_not_contains!(output, "ignored.ts");
assert_not_contains!(output, "ignored.wasm");
}
#[test] #[test]
fn ignores_directories() { fn ignores_directories() {
let context = publish_context_builder().build(); let context = publish_context_builder().build();
@ -260,6 +297,35 @@ fn ignores_directories() {
assert_not_contains!(output, "ignored.ts"); assert_not_contains!(output, "ignored.ts");
} }
#[test]
fn includes_directories_with_gitignore() {
let context = publish_context_builder().build();
let temp_dir = context.temp_dir().path();
temp_dir.join("deno.json").write_json(&json!({
"name": "@foo/bar",
"version": "1.0.0",
"exports": "./main.ts",
"publish": {
"include": [ "deno.json", "main.ts" ]
}
}));
temp_dir.join(".gitignore").write("main.ts");
temp_dir.join("main.ts").write("");
temp_dir.join("ignored.ts").write("");
let output = context
.new_command()
.arg("publish")
.arg("--token")
.arg("sadfasdf")
.run();
output.assert_exit_code(0);
let output = output.combined_output();
assert_contains!(output, "main.ts");
assert_not_contains!(output, "ignored.ts");
}
#[test] #[test]
fn includes_directories() { fn includes_directories() {
let context = publish_context_builder().build(); let context = publish_context_builder().build();
@ -279,7 +345,6 @@ fn includes_directories() {
let output = context let output = context
.new_command() .new_command()
.arg("publish") .arg("publish")
.arg("--log-level=debug")
.arg("--token") .arg("--token")
.arg("sadfasdf") .arg("sadfasdf")
.run(); .run();