blob: 01e1d3bb224f681a2e86aca64fde7bebad91f060 [file] [log] [blame]
//! An interface to github actions workflow commands.
use std::{
fmt::{Debug, Write},
num::NonZeroUsize,
};
/// Shows an error message directly in a github diff view on drop.
pub struct Error {
file: String,
line: usize,
title: String,
message: String,
}
impl Error {
/// Set a line for this error. By default the message is shown at the top of the file.
pub fn line(mut self, line: NonZeroUsize) -> Self {
self.line = line.get();
self
}
}
/// Create an error to be shown for the given file and with the given title.
pub fn error(file: impl std::fmt::Display, title: impl Into<String>) -> Error {
Error {
file: file.to_string(),
line: 0,
title: title.into(),
message: String::new(),
}
}
impl Write for Error {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.message.write_str(s)
}
}
impl Drop for Error {
fn drop(&mut self) {
if std::env::var_os("GITHUB_ACTION").is_some() {
let Error {
file,
line,
title,
message,
} = self;
let message = message.trim();
let message = if message.is_empty() {
"::no message".into()
} else {
format!("::{}", github_action_multiline_escape(message))
};
println!("::error file={file},line={line},title={title}{message}");
}
}
}
/// Append to the summary file that will be shown for the entire CI run.
pub fn summary() -> Option<impl std::io::Write> {
let path = std::env::var_os("GITHUB_STEP_SUMMARY")?;
Some(std::fs::OpenOptions::new().append(true).open(path).unwrap())
}
fn github_action_multiline_escape(s: &str) -> String {
s.replace('%', "%25")
.replace('\n', "%0A")
.replace('\r', "%0D")
}
/// All github actions log messages from this call to the Drop of the return value
/// will be grouped and hidden by default in logs. Note that nesting these does
/// not really work.
pub fn group(name: impl std::fmt::Display) -> Group {
if std::env::var_os("GITHUB_ACTION").is_some() {
println!("::group::{name}");
}
Group(())
}
/// A guard that closes the current github actions log group on drop.
pub struct Group(());
impl Debug for Group {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("a handle that will close the github action group on drop")
}
}
impl Drop for Group {
fn drop(&mut self) {
if std::env::var_os("GITHUB_ACTION").is_some() {
println!("::endgroup::");
}
}
}