diff --git a/README.md b/README.md index 9fca0788..3b534751 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,28 @@ [![Docs.rs](https://docs.rs/workspace-node-tools/badge.svg)](https://docs.rs/workspace-node-tools) [![CI](https://github.com/websublime/workspace-node-tools/workflows/CI/badge.svg)](https://github.com/websublime/workspace-node-tools/actions) +## About + +This is a tool to help manage packages in a monorepo style. It can give info about packages existence, package manager defined (node), git helpers to check which package as changes, manage those changes thur a file (.changes.json), give output of conventional commit and changelog generation. + ## Installation `cargo install workspace-node-tools` ### Cargo -* Install the rust toolchain in order to have cargo installed by following +- Install the rust toolchain in order to have cargo installed by following [this](https://www.rust-lang.org/tools/install) guide. -* run `cargo install workspace-node-tools` +- run `cargo install workspace-node-tools` ## License Licensed under either of - * Apache License, Version 2.0 - ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license - ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +- Apache License, Version 2.0 + ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +- MIT license + ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. @@ -35,4 +39,4 @@ See [CONTRIBUTING.md](CONTRIBUTING.md). ## Info -Template from [here](https://rust-github.github.io/) \ No newline at end of file +Template from [here](https://rust-github.github.io/) diff --git a/src/conventional.rs b/src/conventional.rs index 7fd3a407..d0a8a461 100644 --- a/src/conventional.rs +++ b/src/conventional.rs @@ -13,6 +13,7 @@ use git_cliff_core::{ use regex::Regex; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; +use std::fs::read_to_string; use std::path::PathBuf; use super::git::{ @@ -263,6 +264,30 @@ fn generate_changelog( String::from_utf8(changelog_output).unwrap_or_default() } +/// Prepend changelog output +fn prepend_generate_changelog( + commits: &Vec, + config: &Config, + changelog_content: &String, + version: Option, +) -> String { + let releases = Release { + version, + commits: commits.to_vec().to_owned(), + ..Release::default() + }; + + let changelog = Changelog::new(vec![releases], config); + let mut changelog_output = Vec::new(); + + changelog + .unwrap() + .prepend(changelog_content.to_string(), &mut changelog_output) + .unwrap(); + + String::from_utf8(changelog_output).unwrap_or_default() +} + /// Give info about commits in a package, generate changelog output pub fn get_conventional_for_package( package_info: &PackageInfo, @@ -275,6 +300,9 @@ pub fn get_conventional_for_package( None => get_project_root_path(None).unwrap(), }; + let changelog_dir = + PathBuf::from(package_info.package_path.to_string()).join(String::from("CHANGELOG.md")); + if no_fetch_all.is_some() { git_fetch_all(Some(current_working_dir.to_string()), no_fetch_all).expect("Fetch all"); } @@ -349,11 +377,22 @@ pub fn get_conventional_for_package( let conventional_commits = process_commits(&commits_since, &conventional_config.git); - let changelog = generate_changelog( - &conventional_commits, - &conventional_config, - conventional_default_options.version, - ); + let changelog = match changelog_dir.exists() { + true => { + let changelog_content = read_to_string(&changelog_dir).unwrap(); + prepend_generate_changelog( + &conventional_commits, + &conventional_config, + &changelog_content, + conventional_default_options.version, + ) + } + false => generate_changelog( + &conventional_commits, + &conventional_config, + conventional_default_options.version, + ), + }; let changelog_output = &changelog.to_string(); conventional_package.changelog_output = changelog_output.to_string(); diff --git a/src/git.rs b/src/git.rs index e5d6af0e..1ed46b39 100644 --- a/src/git.rs +++ b/src/git.rs @@ -33,6 +33,7 @@ pub struct Commit { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Deserialize, Serialize)] +/// A struct that represents a commit information pub struct Commit { pub hash: String, pub author_name: String, @@ -51,6 +52,7 @@ pub struct RemoteTags { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Deserialize, Serialize)] +/// A struct that represents a remote tag information pub struct RemoteTags { pub hash: String, pub tag: String, @@ -67,12 +69,14 @@ pub struct PublishTagInfo { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Deserialize, Serialize)] +/// A struct that represents a publish tag information pub struct PublishTagInfo { pub hash: String, pub tag: String, pub package: String, } +/// Fetch everything from origin including tags pub fn git_fetch_all( cwd: Option, fetch_tags: Option, @@ -421,7 +425,7 @@ pub fn git_all_files_changed_since_sha(sha: String, cwd: Option) -> Vec< .arg("--no-pager") .arg("diff") .arg("--name-only") - .arg(format!("{}..", sha)); + .arg(format!("{}", sha)); command.current_dir(¤t_working_dir); command.stdout(Stdio::piped()); diff --git a/src/manager.rs b/src/manager.rs index 85e5f8df..3ede1012 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -18,6 +18,7 @@ pub enum PackageManager { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Copy, PartialEq)] +/// Package manager used in the monorepo. pub enum PackageManager { Npm, Yarn, diff --git a/src/packages.rs b/src/packages.rs index 31a74ed7..0fce5fbd 100644 --- a/src/packages.rs +++ b/src/packages.rs @@ -19,6 +19,7 @@ use super::manager::{detect_package_manager, PackageManager}; use super::paths::get_project_root_path; #[derive(Debug, Deserialize, Serialize)] +/// A struct that represents a pnpm workspace. struct PnpmInfo { pub name: String, pub path: String, @@ -26,6 +27,7 @@ struct PnpmInfo { } #[derive(Debug, Deserialize, Serialize)] +/// A struct that represents a yarn workspace. struct PkgJson { pub workspaces: Vec, } @@ -49,6 +51,7 @@ pub struct PackageInfo { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +/// A struct that represents a package in the monorepo. pub struct PackageInfo { pub name: String, pub private: bool, @@ -74,6 +77,7 @@ pub struct PackageRepositoryInfo { #[cfg(not(feature = "napi"))] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)] +/// A struct that represents the repository information of a package. pub struct PackageRepositoryInfo { pub domain: String, pub orga: String, @@ -81,14 +85,17 @@ pub struct PackageRepositoryInfo { } impl PackageInfo { + /// Pushes a changed file to the list of changed files. pub fn push_changed_file(&mut self, file: String) { self.changed_files.push(file); } + /// Returns the list of changed files. pub fn get_changed_files(&self) -> Vec { self.changed_files.to_vec() } + /// Extends the list of changed files with the provided list. pub fn extend_changed_files(&mut self, files: Vec) { let founded_files = files .iter() @@ -99,12 +106,14 @@ impl PackageInfo { self.changed_files.extend(founded_files); } + /// Updates the version of the package. pub fn update_version(&mut self, version: String) { self.version = version.to_string(); self.pkg_json["version"] = Value::String(version.to_string()); } } +/// Returns package info domain, scope and repository name. fn get_package_repository_info(url: &String) -> PackageRepositoryInfo { let regex = Regex::new( r"(?m)((?[a-z]+)://)((?[^/]*)/)(?([^/]*)/)(?(.*))(\.git)?", diff --git a/src/utils.rs b/src/utils.rs index 62215dab..8bd708b1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] use regex::Regex; +use serde::{Deserialize, Serialize}; #[cfg(test)] use std::path::Path; @@ -29,7 +30,8 @@ use std::process::Command; #[cfg(test)] use std::process::Stdio; -#[derive(Debug)] +#[derive(Debug, Clone, Serialize, Deserialize)] +/// Package scope metadata extracted from a package name. pub struct PackageScopeMetadata { pub full: String, pub name: String, @@ -57,6 +59,7 @@ pub(crate) fn package_scope_name_version(pkg_name: &str) -> Option String { input .strip_suffix("\r\n")