Skip to main content

Context

Struct Context 

Source
pub struct Context;
Expand description

Typed, lazily-read accessors for the workflow run context.

This is a zero-sized handle; every method reads the corresponding environment variable on call, so values reflect the current process environment. Per the design decision, the webhook payload is exposed only as the path (Context::event_path) — parsing the JSON would require a serde dependency and is out of scope.

§Examples

let ctx = actions_rs::Context::new();
// Each accessor is `Option`: `None` outside Actions, `Some` on a runner.
match ctx.repository() {
    Some(repo) => println!("running for {repo}"),
    None => println!("not in GitHub Actions"),
}

Implementations§

Source§

impl Context

Source

pub fn new() -> Self

Construct a context handle.

§Examples
let ctx = actions_rs::Context::new();
let _ = ctx.sha(); // each accessor is a fresh env read
Examples found in repository?
examples/demo.rs (line 21)
13fn main() {
14    log::info(format!(
15        "in GitHub Actions: {} | CI: {} | step-debug: {}",
16        env::is_github_actions(),
17        env::is_ci(),
18        log::is_debug()
19    ));
20
21    let ctx = actions_rs::Context::new();
22    log::info(format!(
23        "repo={:?} ref={:?} sha={:?}",
24        ctx.repository(),
25        ctx.ref_name(),
26        ctx.sha()
27    ));
28
29    // Located annotation with a line range — should print:
30    // ::warning title=demo,file=src/lib.rs,line=10,endLine=12::heads up
31    Annotation::new()
32        .file("src/lib.rs")
33        .line(10)
34        .end_line(12)
35        .title("demo")
36        .warning("heads up: this span looks suspicious");
37
38    // Escaping check: newline in data, colon/comma in a property.
39    Annotation::new()
40        .title("type: mismatch, really")
41        .error("line one\nline two");
42
43    let total = log::group("expensive step", || {
44        log::info("...working...");
45        2 + 2
46    });
47    log::info(format!("group returned {total}"));
48
49    actions_rs::warning!("formatted macro: {} items left", 7);
50
51    output::set_output("answer", 42).expect("set_output");
52    match output::export_var("DEMO_FLAG", true) {
53        Ok(()) => {}
54        Err(actions_rs::Error::UnavailableFileCommand {
55            var: "GITHUB_ENV", ..
56        }) => {
57            log::info("GITHUB_ENV unset; skipping export_var in local demo");
58        }
59        Err(err) => panic!("export_var: {err}"),
60    }
61
62    let mut summary = Summary::new();
63    summary
64        .heading("Demo Report", 2)
65        .raw("Built by the `demo` example.", true)
66        .table([
67            vec![Cell::header("Check"), Cell::header("Result")],
68            vec![Cell::new("clippy"), Cell::new("pass")],
69            vec![Cell::new("tests"), Cell::new("36 pass")],
70        ])
71        .code_block("cargo test", Some("sh"));
72    summary.write().expect("write summary");
73    log::info("summary written (if GITHUB_STEP_SUMMARY was set)");
74}
Source

pub fn repository(&self) -> Option<String>

owner/repo, if set.

§Examples
let ctx = actions_rs::Context::new();
if let Some(repo) = ctx.repository() {
    assert!(repo.contains('/'));
}
Examples found in repository?
examples/demo.rs (line 24)
13fn main() {
14    log::info(format!(
15        "in GitHub Actions: {} | CI: {} | step-debug: {}",
16        env::is_github_actions(),
17        env::is_ci(),
18        log::is_debug()
19    ));
20
21    let ctx = actions_rs::Context::new();
22    log::info(format!(
23        "repo={:?} ref={:?} sha={:?}",
24        ctx.repository(),
25        ctx.ref_name(),
26        ctx.sha()
27    ));
28
29    // Located annotation with a line range — should print:
30    // ::warning title=demo,file=src/lib.rs,line=10,endLine=12::heads up
31    Annotation::new()
32        .file("src/lib.rs")
33        .line(10)
34        .end_line(12)
35        .title("demo")
36        .warning("heads up: this span looks suspicious");
37
38    // Escaping check: newline in data, colon/comma in a property.
39    Annotation::new()
40        .title("type: mismatch, really")
41        .error("line one\nline two");
42
43    let total = log::group("expensive step", || {
44        log::info("...working...");
45        2 + 2
46    });
47    log::info(format!("group returned {total}"));
48
49    actions_rs::warning!("formatted macro: {} items left", 7);
50
51    output::set_output("answer", 42).expect("set_output");
52    match output::export_var("DEMO_FLAG", true) {
53        Ok(()) => {}
54        Err(actions_rs::Error::UnavailableFileCommand {
55            var: "GITHUB_ENV", ..
56        }) => {
57            log::info("GITHUB_ENV unset; skipping export_var in local demo");
58        }
59        Err(err) => panic!("export_var: {err}"),
60    }
61
62    let mut summary = Summary::new();
63    summary
64        .heading("Demo Report", 2)
65        .raw("Built by the `demo` example.", true)
66        .table([
67            vec![Cell::header("Check"), Cell::header("Result")],
68            vec![Cell::new("clippy"), Cell::new("pass")],
69            vec![Cell::new("tests"), Cell::new("36 pass")],
70        ])
71        .code_block("cargo test", Some("sh"));
72    summary.write().expect("write summary");
73    log::info("summary written (if GITHUB_STEP_SUMMARY was set)");
74}
Source

pub fn repo_parts(&self) -> Option<(String, String)>

(owner, repo) split from Context::repository.

§Examples
let ctx = actions_rs::Context::new();
if let Some((owner, repo)) = ctx.repo_parts() {
    assert!(!owner.is_empty() && !repo.is_empty());
}
Source

pub fn repository_owner(&self) -> Option<String>

Repository owner login.

§Examples
if let Some(owner) = actions_rs::Context::new().repository_owner() {
    assert!(!owner.is_empty());
}
Source

pub fn sha(&self) -> Option<String>

Commit SHA that triggered the run.

§Examples
if let Some(sha) = actions_rs::Context::new().sha() {
    assert!(!sha.is_empty());
}
Examples found in repository?
examples/demo.rs (line 26)
13fn main() {
14    log::info(format!(
15        "in GitHub Actions: {} | CI: {} | step-debug: {}",
16        env::is_github_actions(),
17        env::is_ci(),
18        log::is_debug()
19    ));
20
21    let ctx = actions_rs::Context::new();
22    log::info(format!(
23        "repo={:?} ref={:?} sha={:?}",
24        ctx.repository(),
25        ctx.ref_name(),
26        ctx.sha()
27    ));
28
29    // Located annotation with a line range — should print:
30    // ::warning title=demo,file=src/lib.rs,line=10,endLine=12::heads up
31    Annotation::new()
32        .file("src/lib.rs")
33        .line(10)
34        .end_line(12)
35        .title("demo")
36        .warning("heads up: this span looks suspicious");
37
38    // Escaping check: newline in data, colon/comma in a property.
39    Annotation::new()
40        .title("type: mismatch, really")
41        .error("line one\nline two");
42
43    let total = log::group("expensive step", || {
44        log::info("...working...");
45        2 + 2
46    });
47    log::info(format!("group returned {total}"));
48
49    actions_rs::warning!("formatted macro: {} items left", 7);
50
51    output::set_output("answer", 42).expect("set_output");
52    match output::export_var("DEMO_FLAG", true) {
53        Ok(()) => {}
54        Err(actions_rs::Error::UnavailableFileCommand {
55            var: "GITHUB_ENV", ..
56        }) => {
57            log::info("GITHUB_ENV unset; skipping export_var in local demo");
58        }
59        Err(err) => panic!("export_var: {err}"),
60    }
61
62    let mut summary = Summary::new();
63    summary
64        .heading("Demo Report", 2)
65        .raw("Built by the `demo` example.", true)
66        .table([
67            vec![Cell::header("Check"), Cell::header("Result")],
68            vec![Cell::new("clippy"), Cell::new("pass")],
69            vec![Cell::new("tests"), Cell::new("36 pass")],
70        ])
71        .code_block("cargo test", Some("sh"));
72    summary.write().expect("write summary");
73    log::info("summary written (if GITHUB_STEP_SUMMARY was set)");
74}
Source

pub fn git_ref(&self) -> Option<String>

Full git ref, e.g. refs/heads/main.

§Examples
if let Some(r) = actions_rs::Context::new().git_ref() {
    assert!(!r.is_empty());
}
Source

pub fn ref_name(&self) -> Option<String>

Short ref name, e.g. main.

§Examples
if let Some(name) = actions_rs::Context::new().ref_name() {
    assert!(!name.is_empty());
}
Examples found in repository?
examples/demo.rs (line 25)
13fn main() {
14    log::info(format!(
15        "in GitHub Actions: {} | CI: {} | step-debug: {}",
16        env::is_github_actions(),
17        env::is_ci(),
18        log::is_debug()
19    ));
20
21    let ctx = actions_rs::Context::new();
22    log::info(format!(
23        "repo={:?} ref={:?} sha={:?}",
24        ctx.repository(),
25        ctx.ref_name(),
26        ctx.sha()
27    ));
28
29    // Located annotation with a line range — should print:
30    // ::warning title=demo,file=src/lib.rs,line=10,endLine=12::heads up
31    Annotation::new()
32        .file("src/lib.rs")
33        .line(10)
34        .end_line(12)
35        .title("demo")
36        .warning("heads up: this span looks suspicious");
37
38    // Escaping check: newline in data, colon/comma in a property.
39    Annotation::new()
40        .title("type: mismatch, really")
41        .error("line one\nline two");
42
43    let total = log::group("expensive step", || {
44        log::info("...working...");
45        2 + 2
46    });
47    log::info(format!("group returned {total}"));
48
49    actions_rs::warning!("formatted macro: {} items left", 7);
50
51    output::set_output("answer", 42).expect("set_output");
52    match output::export_var("DEMO_FLAG", true) {
53        Ok(()) => {}
54        Err(actions_rs::Error::UnavailableFileCommand {
55            var: "GITHUB_ENV", ..
56        }) => {
57            log::info("GITHUB_ENV unset; skipping export_var in local demo");
58        }
59        Err(err) => panic!("export_var: {err}"),
60    }
61
62    let mut summary = Summary::new();
63    summary
64        .heading("Demo Report", 2)
65        .raw("Built by the `demo` example.", true)
66        .table([
67            vec![Cell::header("Check"), Cell::header("Result")],
68            vec![Cell::new("clippy"), Cell::new("pass")],
69            vec![Cell::new("tests"), Cell::new("36 pass")],
70        ])
71        .code_block("cargo test", Some("sh"));
72    summary.write().expect("write summary");
73    log::info("summary written (if GITHUB_STEP_SUMMARY was set)");
74}
Source

pub fn ref_type(&self) -> Option<String>

branch or tag.

§Examples
if let Some(t) = actions_rs::Context::new().ref_type() {
    assert!(t == "branch" || t == "tag");
}
Source

pub fn head_ref(&self) -> Option<String>

PR head ref (empty/None outside pull requests).

§Examples
// `None` for `push` events; `Some(branch)` on a pull request.
let ctx = actions_rs::Context::new();
if let Some(head) = ctx.head_ref() {
    assert!(!head.is_empty());
}
Source

pub fn base_ref(&self) -> Option<String>

PR base ref (empty/None outside pull requests).

§Examples
if let Some(base) = actions_rs::Context::new().base_ref() {
    assert!(!base.is_empty()); // e.g. "main"
}
Source

pub fn event_name(&self) -> Option<String>

Event name, e.g. push, pull_request.

§Examples
let ctx = actions_rs::Context::new();
if ctx.event_name().as_deref() == Some("pull_request") {
    actions_rs::log::info("triggered by a PR");
}
Source

pub fn event_path(&self) -> Option<PathBuf>

Path to the webhook payload JSON file.

§Examples
// The crate is serde-free, so you parse the JSON yourself if needed.
if let Some(path) = actions_rs::Context::new().event_path() {
    let _payload = std::fs::read_to_string(path);
}
Source

pub fn workspace(&self) -> Option<PathBuf>

Workspace directory (checked-out repo root).

§Examples
if let Some(ws) = actions_rs::Context::new().workspace() {
    let _manifest = ws.join("Cargo.toml");
}
Source

pub fn workflow(&self) -> Option<String>

Workflow name.

§Examples
if let Some(wf) = actions_rs::Context::new().workflow() {
    assert!(!wf.is_empty());
}
Source

pub fn job(&self) -> Option<String>

Current job id.

§Examples
if let Some(job) = actions_rs::Context::new().job() {
    assert!(!job.is_empty()); // the `jobs:` map key, not its `name:`
}
Source

pub fn run_id(&self) -> Option<u64>

Unique numeric run id.

§Examples
if let Some(id) = actions_rs::Context::new().run_id() {
    let _url = format!("https://github.com/o/r/actions/runs/{id}");
}
Source

pub fn run_number(&self) -> Option<u64>

Per-workflow incrementing run number.

§Examples
if let Some(n) = actions_rs::Context::new().run_number() {
    let _ = n; // stable across re-runs, unlike `run_id`
}
Source

pub fn actor(&self) -> Option<String>

Login of the triggering user/app.

§Examples
if let Some(actor) = actions_rs::Context::new().actor() {
    assert!(!actor.is_empty());
}
Source

pub fn server_url(&self) -> Option<String>

Server URL (https://github.com or an Enterprise URL).

§Examples
if let Some(url) = actions_rs::Context::new().server_url() {
    assert!(url.starts_with("http"));
}
Source

pub fn api_url(&self) -> Option<String>

REST API base URL.

§Examples
if let Some(api) = actions_rs::Context::new().api_url() {
    assert!(api.starts_with("http"));
}
Source

pub fn graphql_url(&self) -> Option<String>

GraphQL API URL.

§Examples
if let Some(gql) = actions_rs::Context::new().graphql_url() {
    assert!(gql.starts_with("http"));
}

Trait Implementations§

Source§

impl Clone for Context

Source§

fn clone(&self) -> Context

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Context

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Context

Source§

fn default() -> Context

Returns the “default value” for a type. Read more
Source§

impl Copy for Context

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.