Skip to content

Commit fddca9e

Browse files
committed
avoid fast fail in post_feedback()
ensures the patch is printed before an error short-circuits the function.
1 parent dd034a3 commit fddca9e

2 files changed

Lines changed: 82 additions & 57 deletions

File tree

‎cpp-linter/src/error.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ pub enum ClientError {
7070
#[source]
7171
source: std::io::Error,
7272
},
73+
74+
/// Error when failing to write to stdout.
75+
#[error("Failed to write to stdout: {0}")]
76+
StdoutWriteFailed(#[source] std::io::Error),
7377
}
7478

7579
/// Errors related to invoking clang tools and processing their output.

‎cpp-linter/src/rest_client.rs‎

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{
44
env,
5-
io::BufRead,
5+
io::{BufRead, Write, stdout},
66
path::PathBuf,
77
sync::{Arc, Mutex},
88
};
@@ -147,21 +147,21 @@ impl RestClient {
147147
if feedback_inputs.step_summary {
148148
self.client.append_step_summary(&summary)?;
149149
}
150-
if let Some(summary_output_file) = feedback_inputs.summary_output_file {
150+
if let Some(summary_output_file) = &feedback_inputs.summary_output_file {
151151
let output_file = if summary_output_file.is_absolute() {
152152
summary_output_file
153153
} else {
154-
feedback_inputs.repo_root.join(&summary_output_file)
154+
&feedback_inputs.repo_root.join(summary_output_file)
155155
};
156156
if let Some(parent) = output_file.parent() {
157157
std::fs::create_dir_all(parent).map_err(|e| ClientError::MkDirFailed {
158158
file_path: output_file.clone(),
159159
source: e,
160160
})?;
161161
}
162-
std::fs::write(&output_file, &summary).map_err(|e| {
162+
std::fs::write(output_file, &summary).map_err(|e| {
163163
ClientError::SummaryOutputFileWriteFailed {
164-
file_path: output_file,
164+
file_path: output_file.to_owned(),
165165
source: e,
166166
}
167167
})?;
@@ -184,35 +184,6 @@ impl RestClient {
184184
];
185185
self.client.write_output_variables(&output_vars)?;
186186

187-
if feedback_inputs.thread_comments != ThreadComments::Off {
188-
// post thread comment for PR or push event
189-
if comment.as_ref().is_none_or(|c| c.len() > u16::MAX as usize) {
190-
comment = Some(Self::make_comment(
191-
files,
192-
format_checks_failed,
193-
tidy_checks_failed,
194-
&clang_versions,
195-
Some(u16::MAX as u64),
196-
)?);
197-
}
198-
let options = ThreadCommentOptions {
199-
policy: if feedback_inputs.thread_comments == ThreadComments::Update {
200-
CommentPolicy::Update
201-
} else {
202-
// feedback_inputs.thread_comments is not Off and not Update, so it must be just On.
203-
CommentPolicy::Anew
204-
},
205-
comment: comment.unwrap_or_default(),
206-
kind: if format_checks_failed == 0 && tidy_checks_failed == 0 {
207-
CommentKind::Lgtm
208-
} else {
209-
CommentKind::Concerns
210-
},
211-
marker: COMMENT_MARKER.to_string(),
212-
no_lgtm: feedback_inputs.no_lgtm,
213-
};
214-
self.client.post_thread_comment(options).await?;
215-
}
216187
if self.client.is_pr_event() && feedback_inputs.pr_review {
217188
let summary_only = ["true", "on", "1"].contains(
218189
&env::var("CPP_LINTER_PR_REVIEW_SUMMARY_ONLY")
@@ -230,6 +201,7 @@ impl RestClient {
230201
&feedback_inputs.repo_root,
231202
)?;
232203
}
204+
self.show_patch(&feedback_inputs)?;
233205

234206
let mut options = ReviewOptions {
235207
marker: COMMENT_MARKER.to_string(),
@@ -267,32 +239,37 @@ impl RestClient {
267239
.map_err(|e| ClientError::MutexPoisoned(e.to_string()))?;
268240
file.maybe_append_patch(&feedback_inputs.repo_root)?;
269241
}
242+
self.show_patch(&feedback_inputs)?;
270243
}
271-
let auto_fix_patch_path = feedback_inputs
272-
.repo_root
273-
.join(ClangParams::CACHE_DIR)
274-
.join(ClangParams::AUTO_FIX_PATCH);
275-
if let Ok(patch_file) = std::fs::File::open(&auto_fix_patch_path) {
276-
self.client.write_output_variables(&[OutputVariable {
277-
name: "fix-patch-path".to_string(),
278-
value: auto_fix_patch_path.to_string_lossy().replace("\\", "/"),
279-
}])?;
280244

281-
log::info!("Generated patch content:");
282-
let mut reader = std::io::BufReader::new(patch_file);
283-
let mut line_buf = String::new();
284-
while let Ok(bytes_read) = reader.read_line(&mut line_buf)
285-
&& bytes_read > 0
286-
{
287-
if line_buf.starts_with('+') {
288-
print!("{}", line_buf.green()); // Green for additions
289-
} else if line_buf.starts_with('-') {
290-
print!("{}", line_buf.red()); // Red for deletions
291-
} else {
292-
print!("{line_buf}"); // Default style for context lines
293-
}
294-
line_buf.clear();
245+
if feedback_inputs.thread_comments != ThreadComments::Off {
246+
// post thread comment for PR or push event
247+
if comment.as_ref().is_none_or(|c| c.len() > u16::MAX as usize) {
248+
comment = Some(Self::make_comment(
249+
files,
250+
format_checks_failed,
251+
tidy_checks_failed,
252+
&clang_versions,
253+
Some(u16::MAX as u64),
254+
)?);
295255
}
256+
let options = ThreadCommentOptions {
257+
policy: if feedback_inputs.thread_comments == ThreadComments::Update {
258+
CommentPolicy::Update
259+
} else {
260+
// feedback_inputs.thread_comments is not Off and not Update, so it must be just On.
261+
CommentPolicy::Anew
262+
},
263+
comment: comment.unwrap_or_default(),
264+
kind: if format_checks_failed == 0 && tidy_checks_failed == 0 {
265+
CommentKind::Lgtm
266+
} else {
267+
CommentKind::Concerns
268+
},
269+
marker: COMMENT_MARKER.to_string(),
270+
no_lgtm: feedback_inputs.no_lgtm,
271+
};
272+
self.client.post_thread_comment(options).await?;
296273
}
297274
Ok(format_checks_failed + tidy_checks_failed)
298275
}
@@ -427,6 +404,50 @@ impl RestClient {
427404
comment.push_str(USER_OUTREACH);
428405
Ok(comment)
429406
}
407+
408+
/// Show the generated patch content in the console output.
409+
///
410+
/// And also write the patch path to the output variable `fix-patch-path` for CI platforms.
411+
fn show_patch(&self, feedback_inputs: &FeedbackInput) -> Result<(), ClientError> {
412+
let auto_fix_patch_path = feedback_inputs
413+
.repo_root
414+
.join(ClangParams::CACHE_DIR)
415+
.join(ClangParams::AUTO_FIX_PATCH);
416+
if let Ok(patch_file) = std::fs::File::open(&auto_fix_patch_path) {
417+
self.client.write_output_variables(&[OutputVariable {
418+
name: "fix-patch-path".to_string(),
419+
value: auto_fix_patch_path.to_string_lossy().replace("\\", "/"),
420+
}])?;
421+
422+
log::info!("Generated patch content:");
423+
let stdout_handle = stdout();
424+
let mut reader = std::io::BufReader::new(patch_file);
425+
let mut line_buf = String::new();
426+
let mut stdout_lock = stdout_handle.lock();
427+
while let Ok(bytes_read) = reader.read_line(&mut line_buf)
428+
&& bytes_read > 0
429+
{
430+
if line_buf.starts_with('+') {
431+
// Green for additions
432+
stdout_lock
433+
.write_all(line_buf.green().to_string().as_bytes())
434+
.map_err(ClientError::StdoutWriteFailed)?;
435+
} else if line_buf.starts_with('-') {
436+
// Red for deletions
437+
stdout_lock
438+
.write_all(line_buf.red().to_string().as_bytes())
439+
.map_err(ClientError::StdoutWriteFailed)?;
440+
} else {
441+
// Default style for context lines
442+
stdout_lock
443+
.write_all(line_buf.as_bytes())
444+
.map_err(ClientError::StdoutWriteFailed)?;
445+
}
446+
line_buf.clear();
447+
}
448+
}
449+
Ok(())
450+
}
430451
}
431452

432453
/// A closing tag for details blocks in markdown comments.

0 commit comments

Comments
 (0)