Skip to content

Commit 7a7e165

Browse files
committed
Move gha into its own module
1 parent 34e3c57 commit 7a7e165

File tree

2 files changed

+309
-314
lines changed

2 files changed

+309
-314
lines changed

src/status_emitter.rs

Lines changed: 2 additions & 314 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub mod debug;
1212
mod text;
1313
#[cfg(feature = "gha")]
1414
pub use gha::*;
15+
#[cfg(feature = "gha")]
16+
mod gha;
1517

1618
/// A generic way to handle the output of this crate.
1719
pub trait StatusEmitter: Sync + RefUnwindSafe {
@@ -139,320 +141,6 @@ impl TestStatus for SilentStatus {
139141
}
140142
}
141143

142-
#[cfg(feature = "gha")]
143-
mod gha {
144-
use crate::{diagnostics::Message, display, Error, Errors};
145-
146-
use crate::github_actions;
147-
use bstr::ByteSlice;
148-
use spanned::{Span, Spanned};
149-
use std::{
150-
fmt::{Debug, Write as _},
151-
io::Write as _,
152-
num::NonZeroUsize,
153-
path::{Path, PathBuf},
154-
};
155-
156-
use super::{RevisionStyle, StatusEmitter, Summary, TestStatus};
157-
fn gha_error(error: &Error, test_path: &str, revision: &str) {
158-
let file = Spanned::read_from_file(test_path).unwrap();
159-
let line = |span: &Span| {
160-
let line = file
161-
.lines()
162-
.position(|line| line.span.bytes.contains(&span.bytes.start))
163-
.unwrap();
164-
NonZeroUsize::new(line + 1).unwrap()
165-
};
166-
match error {
167-
Error::ExitStatus {
168-
status,
169-
expected,
170-
reason,
171-
} => {
172-
let mut err = github_actions::error(
173-
test_path,
174-
format!("test{revision} got {status}, but expected {expected}"),
175-
);
176-
err.write_str(reason).unwrap();
177-
}
178-
Error::Command { kind, status } => {
179-
github_actions::error(test_path, format!("{kind}{revision} failed with {status}"));
180-
}
181-
Error::PatternNotFound { pattern, .. } => {
182-
github_actions::error(test_path, format!("Pattern not found{revision}"))
183-
.line(line(&pattern.span));
184-
}
185-
Error::CodeNotFound { code, .. } => {
186-
github_actions::error(test_path, format!("Diagnostic code not found{revision}"))
187-
.line(line(&code.span));
188-
}
189-
Error::NoPatternsFound => {
190-
github_actions::error(
191-
test_path,
192-
format!("expexted error patterns, but found none{revision}"),
193-
);
194-
}
195-
Error::PatternFoundInPassTest { .. } => {
196-
github_actions::error(
197-
test_path,
198-
format!("error pattern found in pass test{revision}"),
199-
);
200-
}
201-
Error::OutputDiffers {
202-
path: output_path,
203-
actual,
204-
expected,
205-
bless_command,
206-
} => {
207-
if expected.is_empty() {
208-
let mut err = github_actions::error(
209-
test_path,
210-
"test generated output, but there was no output file",
211-
);
212-
if let Some(bless_command) = bless_command {
213-
writeln!(
214-
err,
215-
"you likely need to bless the tests with `{bless_command}`"
216-
)
217-
.unwrap();
218-
}
219-
return;
220-
}
221-
222-
let mut line = 1;
223-
for r in
224-
prettydiff::diff_lines(expected.to_str().unwrap(), actual.to_str().unwrap())
225-
.diff()
226-
{
227-
use prettydiff::basic::DiffOp::*;
228-
match r {
229-
Equal(s) => {
230-
line += s.len();
231-
continue;
232-
}
233-
Replace(l, r) => {
234-
let mut err = github_actions::error(
235-
display(output_path),
236-
"actual output differs from expected",
237-
)
238-
.line(NonZeroUsize::new(line + 1).unwrap());
239-
writeln!(err, "this line was expected to be `{}`", r[0]).unwrap();
240-
line += l.len();
241-
}
242-
Remove(l) => {
243-
let mut err = github_actions::error(
244-
display(output_path),
245-
"extraneous lines in output",
246-
)
247-
.line(NonZeroUsize::new(line + 1).unwrap());
248-
writeln!(
249-
err,
250-
"remove this line and possibly later ones by blessing the test"
251-
)
252-
.unwrap();
253-
line += l.len();
254-
}
255-
Insert(r) => {
256-
let mut err = github_actions::error(
257-
display(output_path),
258-
"missing line in output",
259-
)
260-
.line(NonZeroUsize::new(line + 1).unwrap());
261-
writeln!(err, "bless the test to create a line containing `{}`", r[0])
262-
.unwrap();
263-
// Do not count these lines, they don't exist in the original file and
264-
// would thus mess up the line number.
265-
}
266-
}
267-
}
268-
}
269-
Error::ErrorsWithoutPattern { path, msgs } => {
270-
if let Some((path, line)) = path.as_ref() {
271-
let path = display(path);
272-
let mut err =
273-
github_actions::error(path, format!("Unmatched diagnostics{revision}"))
274-
.line(*line);
275-
for Message {
276-
level,
277-
message,
278-
line: _,
279-
span: _,
280-
code: _,
281-
} in msgs
282-
{
283-
writeln!(err, "{level:?}: {message}").unwrap();
284-
}
285-
} else {
286-
let mut err = github_actions::error(
287-
test_path,
288-
format!("Unmatched diagnostics outside the testfile{revision}"),
289-
);
290-
for Message {
291-
level,
292-
message,
293-
line: _,
294-
span: _,
295-
code: _,
296-
} in msgs
297-
{
298-
writeln!(err, "{level:?}: {message}").unwrap();
299-
}
300-
}
301-
}
302-
Error::InvalidComment { msg, span } => {
303-
let mut err = github_actions::error(test_path, format!("Could not parse comment"))
304-
.line(line(span));
305-
writeln!(err, "{msg}").unwrap();
306-
}
307-
Error::MultipleRevisionsWithResults { kind, lines } => {
308-
github_actions::error(test_path, format!("multiple {kind} found"))
309-
.line(line(&lines[0]));
310-
}
311-
Error::Bug(_) => {}
312-
Error::Aux {
313-
path: aux_path,
314-
errors,
315-
} => {
316-
github_actions::error(test_path, format!("Aux build failed"))
317-
.line(line(&aux_path.span));
318-
for error in errors {
319-
gha_error(error, &display(aux_path), "")
320-
}
321-
}
322-
Error::Rustfix(error) => {
323-
github_actions::error(
324-
test_path,
325-
format!("failed to apply suggestions with rustfix: {error}"),
326-
);
327-
}
328-
Error::ConfigError(msg) => {
329-
github_actions::error(test_path, msg.clone());
330-
}
331-
}
332-
}
333-
334-
/// Emits Github Actions Workspace commands to show the failures directly in the github diff view.
335-
/// If the const generic `GROUP` boolean is `true`, also emit `::group` commands.
336-
pub struct Gha<const GROUP: bool> {
337-
/// Show a specific name for the final summary.
338-
pub name: String,
339-
}
340-
341-
#[derive(Clone)]
342-
struct PathAndRev<const GROUP: bool> {
343-
path: PathBuf,
344-
revision: String,
345-
}
346-
347-
impl<const GROUP: bool> TestStatus for PathAndRev<GROUP> {
348-
fn path(&self) -> &Path {
349-
&self.path
350-
}
351-
352-
fn for_revision(&self, revision: &str, _style: RevisionStyle) -> Box<dyn TestStatus> {
353-
Box::new(Self {
354-
path: self.path.clone(),
355-
revision: revision.to_owned(),
356-
})
357-
}
358-
359-
fn for_path(&self, path: &Path) -> Box<dyn TestStatus> {
360-
Box::new(Self {
361-
path: path.to_path_buf(),
362-
revision: self.revision.clone(),
363-
})
364-
}
365-
366-
fn failed_test(&self, _cmd: &str, _stderr: &[u8], _stdout: &[u8]) -> Box<dyn Debug> {
367-
if GROUP {
368-
Box::new(github_actions::group(format_args!(
369-
"{}:{}",
370-
display(&self.path),
371-
self.revision
372-
)))
373-
} else {
374-
Box::new(())
375-
}
376-
}
377-
378-
fn revision(&self) -> &str {
379-
&self.revision
380-
}
381-
}
382-
383-
impl<const GROUP: bool> StatusEmitter for Gha<GROUP> {
384-
fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
385-
Box::new(PathAndRev::<GROUP> {
386-
path,
387-
revision: String::new(),
388-
})
389-
}
390-
391-
fn finalize(
392-
&self,
393-
_failures: usize,
394-
succeeded: usize,
395-
ignored: usize,
396-
filtered: usize,
397-
// Can't aborted on gha
398-
_aborted: bool,
399-
) -> Box<dyn Summary> {
400-
struct Summarizer<const GROUP: bool> {
401-
failures: Vec<String>,
402-
succeeded: usize,
403-
ignored: usize,
404-
filtered: usize,
405-
name: String,
406-
}
407-
408-
impl<const GROUP: bool> Summary for Summarizer<GROUP> {
409-
fn test_failure(&mut self, status: &dyn TestStatus, errors: &Errors) {
410-
let revision = if status.revision().is_empty() {
411-
"".to_string()
412-
} else {
413-
format!(" (revision: {})", status.revision())
414-
};
415-
for error in errors {
416-
gha_error(error, &display(status.path()), &revision);
417-
}
418-
self.failures
419-
.push(format!("{}{revision}", display(status.path())));
420-
}
421-
}
422-
impl<const GROUP: bool> Drop for Summarizer<GROUP> {
423-
fn drop(&mut self) {
424-
if let Some(mut file) = github_actions::summary() {
425-
writeln!(file, "### {}", self.name).unwrap();
426-
for line in &self.failures {
427-
writeln!(file, "* {line}").unwrap();
428-
}
429-
writeln!(file).unwrap();
430-
writeln!(file, "| failed | passed | ignored | filtered out |").unwrap();
431-
writeln!(file, "| --- | --- | --- | --- |").unwrap();
432-
writeln!(
433-
file,
434-
"| {} | {} | {} | {} |",
435-
self.failures.len(),
436-
self.succeeded,
437-
self.ignored,
438-
self.filtered,
439-
)
440-
.unwrap();
441-
}
442-
}
443-
}
444-
445-
Box::new(Summarizer::<GROUP> {
446-
failures: vec![],
447-
succeeded,
448-
ignored,
449-
filtered,
450-
name: self.name.clone(),
451-
})
452-
}
453-
}
454-
}
455-
456144
impl<T: TestStatus, U: TestStatus> TestStatus for (T, U) {
457145
fn done(&self, result: &TestResult, aborted: bool) {
458146
self.0.done(result, aborted);

0 commit comments

Comments
 (0)