1
1
mirror of https://github.com/orhun/git-cliff.git synced 2025-01-05 23:15:53 +03:00

feat(changelog): support generating a changelog scoped to a directory (#11)

This commit is contained in:
orhun 2021-09-09 00:34:25 +03:00
parent 0d793ad9db
commit 0bb7c910b4
No known key found for this signature in database
GPG Key ID: B928720AEC532117
4 changed files with 57 additions and 21 deletions

View File

@ -124,7 +124,8 @@ git-cliff [FLAGS] [OPTIONS] [RANGE]
```
-c, --config <PATH> Sets the configuration file [env: CONFIG=] [default: cliff.toml]
-w, --workdir <PATH> Sets the working directory [env: WORKDIR=]
-r, --repository <PATH> Sets the repository to parse commits from [env: REPOSITORY=]
-r, --repository <PATH> Sets the git repository [env: REPOSITORY=]
--commit-path <PATH> Sets the directory to parse commits from [env: COMMIT_PATH=]
-p, --prepend <PATH> Prepends entries to the given changelog file [env: PREPEND=]
-o, --output <PATH> Writes output to the given file [env: OUTPUT=]
-t, --tag <TAG> Sets the tag for the latest version [env: TAG=]
@ -161,7 +162,7 @@ Set a tag for the "unreleased" changes:
git cliff --tag 1.0.0
```
Create a changelog for a certain part of git history:
Generate a changelog for a certain part of git history:
```sh
# only takes the latest tag into account
@ -178,6 +179,12 @@ git cliff 4c7b043..HEAD
git cliff HEAD~2..
```
Generate a changelog scoped to a specific directory (useful for monorepos):
```sh
git cliff --commit-path project1/
```
Save the changelog file to the specified file:
```sh

View File

@ -36,7 +36,11 @@ impl Repository {
/// Parses and returns the commits.
///
/// Sorts the commits by their time.
pub fn commits(&self, range: Option<String>) -> Result<Vec<Commit>> {
pub fn commits(
&self,
range: Option<String>,
path: Option<String>,
) -> Result<Vec<Commit>> {
let mut revwalk = self.inner.revwalk()?;
revwalk.set_sorting(Sort::TIME | Sort::TOPOLOGICAL)?;
if let Some(range) = range {
@ -44,10 +48,32 @@ impl Repository {
} else {
revwalk.push_head()?;
}
Ok(revwalk
let mut commits: Vec<Commit> = revwalk
.filter_map(|id| id.ok())
.filter_map(|id| self.inner.find_commit(id).ok())
.collect())
.collect();
if let Some(commit_path) = path {
commits = commits
.into_iter()
.filter(|commit| {
if let Ok(prev_commit) = commit.parent(0) {
if let Ok(diff) = self.inner.diff_tree_to_tree(
commit.tree().ok().as_ref(),
prev_commit.tree().ok().as_ref(),
None,
) {
return diff.deltas().any(|delta| {
delta.new_file().path().map_or(false, |path| {
path.starts_with(&commit_path)
})
});
}
}
false
})
.collect()
}
Ok(commits)
}
/// Parses and returns a commit-tag map.
@ -125,7 +151,7 @@ mod test {
.unwrap()
.to_path_buf(),
)?;
let commits = repository.commits(None)?;
let commits = repository.commits(None, None)?;
let last_commit = AppCommit::from(&commits.first().unwrap().clone());
assert_eq!(get_last_commit_hash()?, last_commit.id);
if let Err(e) = last_commit.into_conventional() {

View File

@ -20,7 +20,7 @@ use structopt::StructOpt;
pub struct Opt {
/// Increases the logging verbosity.
#[structopt(short, long, parse(from_occurrences), alias = "debug")]
pub verbose: u8,
pub verbose: u8,
/// Sets the configuration file.
#[structopt(
short,
@ -29,22 +29,25 @@ pub struct Opt {
value_name = "PATH",
default_value = DEFAULT_CONFIG,
)]
pub config: PathBuf,
pub config: PathBuf,
/// Sets the working directory.
#[structopt(short, long, env, value_name = "PATH")]
pub workdir: Option<PathBuf>,
/// Sets the repository to parse commits from.
pub workdir: Option<PathBuf>,
/// Sets the git repository.
#[structopt(short, long, env, value_name = "PATH")]
pub repository: Option<PathBuf>,
pub repository: Option<PathBuf>,
/// Sets the directory to parse commits from.
#[structopt(long, env, value_name = "PATH")]
pub commit_path: Option<String>,
/// Prepends entries to the given changelog file.
#[structopt(short, long, env, value_name = "PATH")]
pub prepend: Option<PathBuf>,
pub prepend: Option<PathBuf>,
/// Writes output to the given file.
#[structopt(short, long, env, value_name = "PATH")]
pub output: Option<PathBuf>,
pub output: Option<PathBuf>,
/// Sets the tag for the latest version.
#[structopt(short, long, env, value_name = "TAG", allow_hyphen_values = true)]
pub tag: Option<String>,
pub tag: Option<String>,
/// Sets the template for the changelog body.
#[structopt(
short,
@ -53,16 +56,16 @@ pub struct Opt {
value_name = "TEMPLATE",
allow_hyphen_values = true
)]
pub body: Option<String>,
pub body: Option<String>,
/// Writes the default configuration file to cliff.toml
#[structopt(short, long)]
pub init: bool,
pub init: bool,
/// Processes the commits starting from the latest tag.
#[structopt(short, long)]
pub latest: bool,
pub latest: bool,
/// Processes the commits that do not belong to a tag.
#[structopt(short, long)]
pub unreleased: bool,
pub unreleased: bool,
/// Strips the given parts from the changelog.
#[structopt(
short,
@ -70,8 +73,8 @@ pub struct Opt {
value_name = "PART",
possible_values = &["header", "footer", "all"]
)]
pub strip: Option<String>,
pub strip: Option<String>,
/// Sets the commit range to process.
#[structopt(value_name = "RANGE")]
pub range: Option<String>,
pub range: Option<String>,
}

View File

@ -122,7 +122,7 @@ pub fn run(mut args: Opt) -> Result<()> {
commit_range = Some(format!("{}..{}", tag1, tag2));
}
}
let commits = repository.commits(commit_range)?;
let commits = repository.commits(commit_range, args.commit_path)?;
// Update tags.
if let Some(tag) = args.tag {