pub struct WorkflowCommand { /* private fields */ }Expand description
A single GitHub Actions workflow command: ::name key=val,...::message.
Properties are kept in insertion order to produce deterministic output
(which the test-suite and @actions/core both rely on).
The Display implementation performs all required percent-encoding, so the rendered string is
always safe to write to stdout.
§Examples
use actions_rs::WorkflowCommand;
let cmd = WorkflowCommand::new("error")
.property("file", "src/a,b.rs") // `,` is property-encoded
.message("bad: x\ny"); // `\n` is data-encoded
assert_eq!(cmd.to_string(), "::error file=src/a%2Cb.rs::bad: x%0Ay");Implementations§
Source§impl WorkflowCommand
impl WorkflowCommand
Sourcepub fn new(name: &'static str) -> Self
pub fn new(name: &'static str) -> Self
Create a command with the given name and an empty message.
§Examples
use actions_rs::WorkflowCommand;
assert_eq!(WorkflowCommand::new("endgroup").to_string(), "::endgroup::");Sourcepub fn message(self, message: impl Into<String>) -> Self
pub fn message(self, message: impl Into<String>) -> Self
Set the command message (the segment after the final ::).
§Examples
use actions_rs::WorkflowCommand;
let c = WorkflowCommand::new("warning").message("low disk");
assert_eq!(c.to_string(), "::warning::low disk");Sourcepub fn property(self, key: &'static str, value: impl Into<String>) -> Self
pub fn property(self, key: &'static str, value: impl Into<String>) -> Self
Append a property. The value is percent-encoded on render.
§Examples
use actions_rs::WorkflowCommand;
let c = WorkflowCommand::new("notice").property("line", "42").message("m");
assert_eq!(c.to_string(), "::notice line=42::m");Sourcepub fn property_opt(
self,
key: &'static str,
value: Option<impl Into<String>>,
) -> Self
pub fn property_opt( self, key: &'static str, value: Option<impl Into<String>>, ) -> Self
Append a property only when value is Some.
§Examples
use actions_rs::WorkflowCommand;
let c = WorkflowCommand::new("notice")
.property_opt("file", Option::<String>::None) // skipped
.property_opt("line", Some("10"))
.message("m");
assert_eq!(c.to_string(), "::notice line=10::m");Sourcepub fn issue_to<W: Write>(&self, w: W) -> Result<()>
pub fn issue_to<W: Write>(&self, w: W) -> Result<()>
Render and write this command followed by a newline to w.
Used by the test-suite to capture output; the convenience helpers use WorkflowCommand::issue.
§Errors
Propagates any write error from w.
§Examples
use actions_rs::WorkflowCommand;
let mut buf = Vec::new();
WorkflowCommand::new("debug").message("d").issue_to(&mut buf).unwrap();
assert_eq!(buf, b"::debug::d\n");Sourcepub fn issue(&self)
pub fn issue(&self)
Render and write this command to stdout followed by a newline.
Stdout is the runner’s command channel;
a failed write here cannot be meaningfully recovered from inside an action,
so the result is dropped deliberately (matching @actions/core behaviour).
§Examples
use actions_rs::WorkflowCommand;
// Emit a command the higher-level API does not cover.
WorkflowCommand::new("add-matcher").message(".github/pm.json").issue();Examples found in repository?
18fn main() -> ExitCode {
19 let notice = Annotation::new()
20 .file("examples/ci_selfcheck.rs")
21 .span(AnnotationSpan::Line {
22 start: 18,
23 end: Some(24),
24 })
25 .title("ci_selfcheck")
26 .command(
27 AnnotationKind::Notice,
28 "actions-rs self-check ran in this job",
29 );
30 let warning = Annotation::new()
31 .file("src/summary.rs")
32 .span(AnnotationSpan::Column {
33 line: 112,
34 start: 5,
35 end: None,
36 })
37 .title("example warning")
38 .command(
39 AnnotationKind::Warning,
40 "ranged warning annotation covering Summary::code_block",
41 );
42 notice.issue();
43 warning.issue();
44
45 if let Err(e) = output::set_output("answer", "42\nwith newline") {
46 eprintln!("::error::set_output: {e}");
47 return ExitCode::FAILURE;
48 }
49 if let Err(e) = output::export_var("DEMO_FLAG", true)
50 && !matches!(
51 e,
52 actions_rs::Error::UnavailableFileCommand {
53 var: "GITHUB_ENV",
54 ..
55 }
56 )
57 {
58 eprintln!("::error::export_var: {e}");
59 return ExitCode::FAILURE;
60 }
61
62 let gh_output = read_env_file("GITHUB_OUTPUT").unwrap_or_else(|| "<local: unset>".into());
63 let gh_env = read_env_file("GITHUB_ENV").unwrap_or_else(|| "<local: unset>".into());
64
65 // Build the whole report once.
66 let mut report = String::new();
67 for (label, body) in [
68 ("workflow commands (stdout)", format!("{notice}\n{warning}")),
69 ("GITHUB_OUTPUT", gh_output.clone()),
70 ("GITHUB_ENV", gh_env.clone()),
71 ] {
72 let _ = write!(report, "===== {label} =====\n{body}\n");
73 }
74
75 // 1. normal out (the job log).
76 print!("{report}");
77
78 // 2. a tmpfile on the runner.
79 let tmp = std::env::var_os("RUNNER_TEMP")
80 .map(PathBuf::from)
81 .unwrap_or_else(std::env::temp_dir)
82 .join("ci_selfcheck.report.txt");
83 if let Err(e) = std::fs::write(&tmp, &report) {
84 eprintln!("::error::tmpfile write: {e}");
85 return ExitCode::FAILURE;
86 }
87
88 // 3. read the tmpfile back, drop it into the summary as one code block.
89 let captured = match std::fs::read_to_string(&tmp) {
90 Ok(c) => c,
91 Err(e) => {
92 eprintln!("::error::tmpfile read: {e}");
93 return ExitCode::FAILURE;
94 }
95 };
96 let mut summary = Summary::new();
97 summary
98 .heading("actions-rs ci_selfcheck", 2)
99 .code_block(&captured, None);
100 if let Err(e) = summary.write_overwrite() {
101 eprintln!("::error::summary.write_overwrite: {e}");
102 return ExitCode::FAILURE;
103 }
104
105 // round-trip assertions (only meaningful when the runner set the files).
106 let mut exit = ExitCode::SUCCESS;
107 if std::env::var_os("GITHUB_OUTPUT").is_some() {
108 for (var, needle, hay) in [
109 ("GITHUB_OUTPUT", "answer<<", &gh_output),
110 ("GITHUB_ENV", "DEMO_FLAG<<", &gh_env),
111 ] {
112 if !hay.contains(needle) {
113 eprintln!("::error::{var} missing {needle:?}");
114 exit = ExitCode::FAILURE;
115 }
116 }
117 }
118 exit
119}Trait Implementations§
Source§impl Clone for WorkflowCommand
impl Clone for WorkflowCommand
Source§fn clone(&self) -> WorkflowCommand
fn clone(&self) -> WorkflowCommand
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for WorkflowCommand
impl Debug for WorkflowCommand
Source§impl Display for WorkflowCommand
impl Display for WorkflowCommand
Source§impl PartialEq for WorkflowCommand
impl PartialEq for WorkflowCommand
Source§fn eq(&self, other: &WorkflowCommand) -> bool
fn eq(&self, other: &WorkflowCommand) -> bool
self and other values to be equal, and is used by ==.