Skip to content

Commit 67e1743

Browse files
authored
Merge pull request #92 from GitoxideLabs/copilot/check-changelog-untracked
Add untracked CHANGELOG.md files to git before commit
2 parents 8e6b2a1 + 10c7a3e commit 67e1743

File tree

7 files changed

+78
-14
lines changed

7 files changed

+78
-14
lines changed

src/command/release/git.rs

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{convert::TryInto, process::Command};
1+
use std::{convert::TryInto, path::Path, process::Command};
22

33
use anyhow::{anyhow, bail, Context};
44
use cargo_metadata::Package;
@@ -7,15 +7,56 @@ use gix::{bstr::ByteSlice, refs, refs::transaction::PreviousValue, Id};
77
use super::{tag_name, Options};
88
use crate::utils::will;
99

10-
pub(in crate::command::release_impl) fn commit_changes(
10+
pub(in crate::command::release_impl) fn commit_changes<'a>(
1111
message: impl AsRef<str>,
1212
dry_run: bool,
1313
empty_commit_possible: bool,
1414
signoff: bool,
15-
ctx: &crate::Context,
16-
) -> anyhow::Result<Option<Id<'_>>> {
15+
changelog_paths: &[impl AsRef<Path>],
16+
ctx: &'a crate::Context,
17+
) -> anyhow::Result<Option<Id<'a>>> {
1718
// TODO: replace with gitoxide one day
18-
let mut cmd = Command::new("git");
19+
// Add changelog files that are not yet tracked in git index.
20+
// `git commit -am` only stages tracked files, so we need to explicitly add new ones.
21+
if !changelog_paths.is_empty() {
22+
let index = ctx.repo.open_index()?;
23+
let workdir = ctx.repo.workdir().context("Can only work in non-bare repositories")?;
24+
25+
let untracked_paths: Vec<_> = changelog_paths
26+
.iter()
27+
.filter_map(|path| {
28+
// Convert absolute path to worktree-relative path with forward slashes
29+
path.as_ref().strip_prefix(workdir).ok().and_then(|relative_path| {
30+
let relative_path_unix = gix::path::to_unix_separators(gix::path::into_bstr(relative_path));
31+
// Check if the path is NOT tracked in the git index
32+
index
33+
.entry_by_path(relative_path_unix.as_bstr())
34+
.is_none()
35+
.then_some(relative_path)
36+
})
37+
})
38+
.collect();
39+
40+
if !untracked_paths.is_empty() {
41+
let mut git_add = Command::new(gix::path::env::exe_invocation());
42+
git_add.args(["add", "--"]);
43+
for path in &untracked_paths {
44+
git_add.arg(path);
45+
}
46+
log::trace!("{} run {:?}", will(dry_run), git_add);
47+
let output = git_add.output()?;
48+
if !dry_run && !output.status.success() {
49+
let paths: Vec<_> = untracked_paths.iter().map(|p| p.to_string_lossy()).collect();
50+
bail!(
51+
"Failed to add new changelog files to git: {}: {err}",
52+
paths.join(", "),
53+
err = output.stderr.to_str_lossy()
54+
);
55+
}
56+
}
57+
}
58+
59+
let mut cmd = Command::new(gix::path::env::exe_invocation());
1960
cmd.arg("commit").arg("-am").arg(message.as_ref());
2061
if empty_commit_possible {
2162
cmd.arg("--allow-empty");
@@ -96,7 +137,7 @@ pub fn push_tags_and_head(
96137
return Ok(());
97138
}
98139

99-
let mut cmd = Command::new("git");
140+
let mut cmd = Command::new(gix::path::env::exe_invocation());
100141
cmd.arg("push")
101142
.arg({
102143
let remote = repo
@@ -139,8 +180,9 @@ mod tests {
139180
)
140181
.unwrap();
141182
let message = "commit message";
183+
let empty: &[&std::path::Path] = &[];
142184
testing_logger::setup();
143-
let _ = commit_changes(message, true, false, false, &ctx).unwrap();
185+
let _ = commit_changes(message, true, false, false, empty, &ctx).unwrap();
144186
testing_logger::validate(|captured_logs| {
145187
assert_eq!(captured_logs.len(), 1);
146188
assert_eq!(
@@ -162,8 +204,9 @@ mod tests {
162204
)
163205
.unwrap();
164206
let message = "commit message";
207+
let empty: &[&std::path::Path] = &[];
165208
testing_logger::setup();
166-
let _ = commit_changes(message, true, false, true, &ctx).unwrap();
209+
let _ = commit_changes(message, true, false, true, empty, &ctx).unwrap();
167210
testing_logger::validate(|captured_logs| {
168211
assert_eq!(captured_logs.len(), 1);
169212
assert_eq!(

src/command/release/manifest.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates_
9494

9595
preview_changelogs(ctx, &pending_changelogs, opts.clone())?;
9696

97+
// Collect all changelog paths before they are consumed by commit_locks_and_generate_bail_message
98+
let changelog_paths: Vec<std::path::PathBuf> = pending_changelogs
99+
.iter()
100+
.map(|(_, _, lock)| lock.resource_path().to_owned())
101+
.collect();
102+
97103
let bail_message = commit_locks_and_generate_bail_message(
98104
ctx,
99105
pending_changelogs,
@@ -103,7 +109,14 @@ pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates_
103109
opts.clone(),
104110
)?;
105111

106-
let res = git::commit_changes(commit_message, dry_run, !made_change, opts.signoff, &ctx.base)?;
112+
let res = git::commit_changes(
113+
commit_message,
114+
dry_run,
115+
!made_change,
116+
opts.signoff,
117+
&changelog_paths,
118+
&ctx.base,
119+
)?;
107120
if let Some(bail_message) = bail_message {
108121
bail!(bail_message);
109122
} else {
@@ -128,7 +141,7 @@ fn commit_locks_and_generate_bail_message(
128141
..
129142
}: Options,
130143
) -> anyhow::Result<Option<String>> {
131-
let bail_message_after_commit = if !dry_run {
144+
let bail_message = if !dry_run {
132145
let mut packages_whose_changelogs_need_edits = None;
133146
let mut packages_which_might_be_fully_generated = None;
134147
for (idx, (package, _, lock)) in pending_changelogs.into_iter().enumerate() {
@@ -253,7 +266,7 @@ fn commit_locks_and_generate_bail_message(
253266
}
254267
None
255268
};
256-
Ok(bail_message_after_commit)
269+
Ok(bail_message)
257270
}
258271

259272
fn preview_changelogs(

src/git/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ pub fn change_since_last_release(package: &Package, ctx: &crate::Context) -> any
7171
}
7272

7373
pub fn assure_clean_working_tree() -> anyhow::Result<()> {
74-
let tracked_changed = !Command::new("git")
74+
let tracked_changed = !Command::new(gix::path::env::exe_invocation())
7575
.arg("diff")
7676
.arg("HEAD")
7777
.arg("--exit-code")
@@ -82,7 +82,7 @@ pub fn assure_clean_working_tree() -> anyhow::Result<()> {
8282
bail!("Detected working tree changes. Please commit beforehand as otherwise these would be committed as part of manifest changes, or use --allow-dirty to force it.")
8383
}
8484

85-
let untracked = Command::new("git")
85+
let untracked = Command::new(gix::path::env::exe_invocation())
8686
.arg("ls-files")
8787
.arg("--exclude-standard")
8888
.arg("--others")
@@ -104,7 +104,11 @@ pub fn remote_url(repo: &gix::Repository) -> anyhow::Result<Option<gix::Url>> {
104104
}
105105

106106
pub fn author() -> anyhow::Result<gix::actor::Signature> {
107-
let stdout = Command::new("git").arg("var").arg("GIT_AUTHOR_IDENT").output()?.stdout;
107+
let stdout = Command::new(gix::path::env::exe_invocation())
108+
.arg("var")
109+
.arg("GIT_AUTHOR_IDENT")
110+
.output()?
111+
.stdout;
108112
Ok(gix::actor::SignatureRef::from_bytes::<()>(&stdout)
109113
.ok()
110114
.ok_or_else(|| anyhow!("Could not parse author from GIT_AUTHOR_IDENT='{}'", stdout.as_bstr()))?

tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset.
1616
[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: b, c
1717
[WARN ] To fix the changelog manually, run: cargo changelog --write c a
18+
[TRACE] WOULD run "git" "add" "--" "c/CHANGELOG.md"
1819
[TRACE] WOULD run "git" "commit" "-am" "Bump a v0.9.0, b v0.9.0, c v9.0.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0"
1920
[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Refactor (BREAKING)'
2021
[TRACE] WOULD create tag object b-v0.9.0 with changelog message, first line is: '### Commit Statistics'

tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-breaking-change

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset.
1111
[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b
1212
[WARN ] To fix the changelog manually, run: cargo changelog --write c a
13+
[TRACE] WOULD run "git" "add" "--" "c/CHANGELOG.md"
1314
[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0"
1415
[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics'
1516
[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics'

tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-minor-change

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset.
1111
[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b
1212
[WARN ] To fix the changelog manually, run: cargo changelog --write c a
13+
[TRACE] WOULD run "git" "add" "--" "c/CHANGELOG.md"
1314
[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0"
1415
[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics'
1516
[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics'

tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-no-change

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset.
1111
[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b, c
1212
[WARN ] To fix the changelog manually, run: cargo changelog --write c a
13+
[TRACE] WOULD run "git" "add" "--" "c/CHANGELOG.md"
1314
[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0"
1415
[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics'
1516
[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics'

0 commit comments

Comments
 (0)