mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(workspaces/publish): include the license file from the workspace root if not in pkg (#24714)
This commit is contained in:
parent
5f5f662a68
commit
84b7504d0f
7 changed files with 108 additions and 32 deletions
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::io::IsTerminal;
|
use std::io::IsTerminal;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -13,6 +14,7 @@ use base64::Engine;
|
||||||
use deno_ast::ModuleSpecifier;
|
use deno_ast::ModuleSpecifier;
|
||||||
use deno_config::workspace::JsrPackageConfig;
|
use deno_config::workspace::JsrPackageConfig;
|
||||||
use deno_config::workspace::PackageJsonDepResolution;
|
use deno_config::workspace::PackageJsonDepResolution;
|
||||||
|
use deno_config::workspace::Workspace;
|
||||||
use deno_core::anyhow::bail;
|
use deno_core::anyhow::bail;
|
||||||
use deno_core::anyhow::Context;
|
use deno_core::anyhow::Context;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
|
@ -448,7 +450,7 @@ impl PublishPreparer {
|
||||||
move || {
|
move || {
|
||||||
let root_specifier =
|
let root_specifier =
|
||||||
ModuleSpecifier::from_directory_path(&root_dir).unwrap();
|
ModuleSpecifier::from_directory_path(&root_dir).unwrap();
|
||||||
let publish_paths =
|
let mut publish_paths =
|
||||||
paths::collect_publish_paths(paths::CollectPublishPathsOptions {
|
paths::collect_publish_paths(paths::CollectPublishPathsOptions {
|
||||||
root_dir: &root_dir,
|
root_dir: &root_dir,
|
||||||
cli_options: &cli_options,
|
cli_options: &cli_options,
|
||||||
|
@ -464,13 +466,28 @@ impl PublishPreparer {
|
||||||
);
|
);
|
||||||
|
|
||||||
if !has_license_file(publish_paths.iter().map(|p| &p.specifier)) {
|
if !has_license_file(publish_paths.iter().map(|p| &p.specifier)) {
|
||||||
diagnostics_collector.push(PublishDiagnostic::MissingLicense {
|
if let Some(license_path) =
|
||||||
expected_path: root_dir.join("LICENSE"),
|
resolve_license_file(&root_dir, cli_options.workspace())
|
||||||
});
|
{
|
||||||
|
// force including the license file from the package or workspace root
|
||||||
|
publish_paths.push(CollectedPublishPath {
|
||||||
|
specifier: ModuleSpecifier::from_file_path(&license_path)
|
||||||
|
.unwrap(),
|
||||||
|
relative_path: "LICENSE".to_string(),
|
||||||
|
maybe_content: Some(std::fs::read(&license_path).with_context(
|
||||||
|
|| format!("failed reading '{}'.", license_path.display()),
|
||||||
|
)?),
|
||||||
|
path: license_path,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
diagnostics_collector.push(PublishDiagnostic::MissingLicense {
|
||||||
|
expected_path: root_dir.join("LICENSE"),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tar::create_gzipped_tarball(
|
tar::create_gzipped_tarball(
|
||||||
&publish_paths,
|
publish_paths,
|
||||||
LazyGraphSourceParser::new(&source_cache, &graph),
|
LazyGraphSourceParser::new(&source_cache, &graph),
|
||||||
&diagnostics_collector,
|
&diagnostics_collector,
|
||||||
&unfurler,
|
&unfurler,
|
||||||
|
@ -1194,31 +1211,49 @@ async fn check_if_git_repo_dirty(cwd: &Path) -> Option<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SUPPORTED_LICENSE_FILE_NAMES: [&str; 6] = [
|
||||||
|
"LICENSE",
|
||||||
|
"LICENSE.md",
|
||||||
|
"LICENSE.txt",
|
||||||
|
"LICENCE",
|
||||||
|
"LICENCE.md",
|
||||||
|
"LICENCE.txt",
|
||||||
|
];
|
||||||
|
|
||||||
|
fn resolve_license_file(
|
||||||
|
pkg_root_dir: &Path,
|
||||||
|
workspace: &Workspace,
|
||||||
|
) -> Option<PathBuf> {
|
||||||
|
let workspace_root_dir = workspace.root_dir_path();
|
||||||
|
let mut dirs = Vec::with_capacity(2);
|
||||||
|
dirs.push(pkg_root_dir);
|
||||||
|
if workspace_root_dir != pkg_root_dir {
|
||||||
|
dirs.push(&workspace_root_dir);
|
||||||
|
}
|
||||||
|
for dir in dirs {
|
||||||
|
for file_name in &SUPPORTED_LICENSE_FILE_NAMES {
|
||||||
|
let file_path = dir.join(file_name);
|
||||||
|
if file_path.exists() {
|
||||||
|
return Some(file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn has_license_file<'a>(
|
fn has_license_file<'a>(
|
||||||
mut specifiers: impl Iterator<Item = &'a ModuleSpecifier>,
|
mut specifiers: impl Iterator<Item = &'a ModuleSpecifier>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let allowed_license_files = {
|
let supported_license_files = SUPPORTED_LICENSE_FILE_NAMES
|
||||||
let files = HashSet::from([
|
.iter()
|
||||||
"license",
|
.map(|s| s.to_lowercase())
|
||||||
"license.md",
|
.collect::<HashSet<_>>();
|
||||||
"license.txt",
|
|
||||||
"licence",
|
|
||||||
"licence.md",
|
|
||||||
"licence.txt",
|
|
||||||
]);
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
for file in &files {
|
|
||||||
assert_eq!(*file, file.to_lowercase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
files
|
|
||||||
};
|
|
||||||
specifiers.any(|specifier| {
|
specifiers.any(|specifier| {
|
||||||
specifier
|
specifier
|
||||||
.path()
|
.path()
|
||||||
.rsplit_once('/')
|
.rsplit_once('/')
|
||||||
.map(|(_, file)| {
|
.map(|(_, file)| {
|
||||||
allowed_license_files.contains(file.to_lowercase().as_str())
|
supported_license_files.contains(file.to_lowercase().as_str())
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
})
|
})
|
||||||
|
|
|
@ -214,7 +214,10 @@ pub enum PackagePathValidationError {
|
||||||
pub struct CollectedPublishPath {
|
pub struct CollectedPublishPath {
|
||||||
pub specifier: ModuleSpecifier,
|
pub specifier: ModuleSpecifier,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
|
/// Relative path to use in the tarball.
|
||||||
pub relative_path: String,
|
pub relative_path: String,
|
||||||
|
/// Specify the contents for any injected paths.
|
||||||
|
pub maybe_content: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CollectPublishPathsOptions<'a> {
|
pub struct CollectPublishPathsOptions<'a> {
|
||||||
|
@ -307,6 +310,7 @@ pub fn collect_publish_paths(
|
||||||
specifier,
|
specifier,
|
||||||
path,
|
path,
|
||||||
relative_path,
|
relative_path,
|
||||||
|
maybe_content: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub struct PublishableTarball {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_gzipped_tarball(
|
pub fn create_gzipped_tarball(
|
||||||
publish_paths: &[CollectedPublishPath],
|
publish_paths: Vec<CollectedPublishPath>,
|
||||||
source_parser: LazyGraphSourceParser,
|
source_parser: LazyGraphSourceParser,
|
||||||
diagnostics_collector: &PublishDiagnosticsCollector,
|
diagnostics_collector: &PublishDiagnosticsCollector,
|
||||||
unfurler: &SpecifierUnfurler,
|
unfurler: &SpecifierUnfurler,
|
||||||
|
@ -45,15 +45,17 @@ pub fn create_gzipped_tarball(
|
||||||
for path in publish_paths {
|
for path in publish_paths {
|
||||||
let path_str = &path.relative_path;
|
let path_str = &path.relative_path;
|
||||||
let specifier = &path.specifier;
|
let specifier = &path.specifier;
|
||||||
let path = &path.path;
|
|
||||||
|
|
||||||
let content = resolve_content_maybe_unfurling(
|
let content = match path.maybe_content {
|
||||||
path,
|
Some(content) => content.clone(),
|
||||||
specifier,
|
None => resolve_content_maybe_unfurling(
|
||||||
unfurler,
|
&path.path,
|
||||||
source_parser,
|
specifier,
|
||||||
diagnostics_collector,
|
unfurler,
|
||||||
)?;
|
source_parser,
|
||||||
|
diagnostics_collector,
|
||||||
|
)?,
|
||||||
|
};
|
||||||
|
|
||||||
files.push(PublishableTarballFile {
|
files.push(PublishableTarballFile {
|
||||||
path_str: path_str.clone(),
|
path_str: path_str.clone(),
|
||||||
|
@ -65,7 +67,7 @@ pub fn create_gzipped_tarball(
|
||||||
tar
|
tar
|
||||||
.add_file(format!(".{}", path_str), &content)
|
.add_file(format!(".{}", path_str), &content)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("Unable to add file to tarball '{}'", path.display())
|
format!("Unable to add file to tarball '{}'", path.path.display())
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
"args": "publish --token 'sadfasdf'",
|
"args": "publish --token 'sadfasdf'",
|
||||||
"output": "workspace.out"
|
"output": "workspace.out"
|
||||||
},
|
},
|
||||||
|
"workspace_dry_run": {
|
||||||
|
"args": "publish --token 'sadfasdf' --dry-run",
|
||||||
|
"output": "workspace_dry_run.out"
|
||||||
|
},
|
||||||
|
"individual_dry_run": {
|
||||||
|
"cwd": "./foo",
|
||||||
|
"args": "publish --token 'sadfasdf' --dry-run",
|
||||||
|
"output": "foo_dry_run.out"
|
||||||
|
},
|
||||||
"individual": {
|
"individual": {
|
||||||
"cwd": "./bar",
|
"cwd": "./bar",
|
||||||
"args": "publish --token 'sadfasdf'",
|
"args": "publish --token 'sadfasdf'",
|
||||||
|
|
9
tests/specs/publish/workspace/foo_dry_run.out
Normal file
9
tests/specs/publish/workspace/foo_dry_run.out
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Check file:///[WILDLINE]/foo/mod.ts
|
||||||
|
Checking for slow types in the public API...
|
||||||
|
Check file:///[WILDLINE]/foo/mod.ts
|
||||||
|
Simulating publish of @foo/foo@1.0.0 with files:
|
||||||
|
[# notice how this line is including the LICENSE from the root directory]
|
||||||
|
file:///[WILDLINE]/workspace/LICENSE (0B)
|
||||||
|
file:///[WILDLINE]/workspace/foo/deno.json (135B)
|
||||||
|
file:///[WILDLINE]/workspace/foo/mod.ts (118B)
|
||||||
|
Warning Aborting due to --dry-run
|
17
tests/specs/publish/workspace/workspace_dry_run.out
Normal file
17
tests/specs/publish/workspace/workspace_dry_run.out
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Publishing a workspace...
|
||||||
|
Check file:///[WILDLINE]/workspace/bar/mod.ts
|
||||||
|
Check file:///[WILDLINE]/workspace/foo/mod.ts
|
||||||
|
Checking for slow types in the public API...
|
||||||
|
Check file:///[WILDLINE]/workspace/bar/mod.ts
|
||||||
|
Check file:///[WILDLINE]/workspace/foo/mod.ts
|
||||||
|
[UNORDERED_START]
|
||||||
|
Simulating publish of @foo/foo@1.0.0 with files:
|
||||||
|
file:///[WILDLINE]/workspace/LICENSE (0B)
|
||||||
|
file:///[WILDLINE]/workspace/foo/deno.json (135B)
|
||||||
|
file:///[WILDLINE]/workspace/foo/mod.ts (118B)
|
||||||
|
Simulating publish of @foo/bar@1.0.0 with files:
|
||||||
|
file:///[WILDLINE]/workspace/bar/LICENSE (0B)
|
||||||
|
file:///[WILDLINE]/workspace/bar/deno.json (87B)
|
||||||
|
file:///[WILDLINE]/workspace/bar/mod.ts (70B)
|
||||||
|
[UNORDERED_END]
|
||||||
|
Warning Aborting due to --dry-run
|
Loading…
Reference in a new issue