🐿️ GitHub Actions toolkit for your Go-based GitHub Actions
// ✅
name := try1(core.GetInput("name", nil))
core.Notice(fmt.Sprintf("Hello, %s!", name))
// 🐙🐱
token := try1(core.GetInput("token", nil))
client := try1(github.GetGoGithubClient(token, nil))
if github.Context.EventName != "push" {
panic("🤷♂️")
}
actor := github.Context.Actor
repo := github.Context.Payload["repository"](map[string]any)["fullName"](string)
fmt.Printf("%s pushed to %s\n", actor, repo)
// 🔨
url := "https://example.org/tool.tgz";
path := try1(tc.DownloadTool(url, nil, nil, nil))
path = try1(tc.ExtractTar(path, nil, nil))
fmt.Printf("%s extracted to %s\n", url, path)
// 🍦
files := try1(try1(glob.Create("**/*.rs")).Glob());
fmt.Printf("The files are %v\n", files)
hash := try1(glob.HashFiles("*.json"));
fmt.Printf("Config hash is %s\n", hash)
😵 Don't know where to start? Read the 🦀 How to write your GitHub Actions in Rust post. 🚀
Your reading the root monorepo readme. 😉 To install a specific actions-*
package just click one of the links above ☝ and install that package. 🚀
You'll probably also want to create an action.yml
manifest and use configure-executable-action to manage the glue that will invoke your compiled executable.
Here's an example that uses some (not all) of the actions-*
packages in this monorepo listed above. Each package listed above ☝ also has its own readme with specific examples related to its specialty.
use actions_core as core;
use actions_github as github;
use std::error::Error;
use chrono::prelude::*;
fn main() {
let result = || -> Result<(), Box<dyn Error>> {
// The `who-to-greet` input is defined in action metadata file
let who_to_greet = core::get_input_with_options("who-to-greet", GetInputOptions {
required: true,
...Default::default()
})?;
core::info!("Hello, {who_to_greet}!");
// Get the current time and set it as an output
let time = Utc::now().to_string()
core::set_output("time", time);
// Output the payload for debugging
let json = serde_json::to_string_pretty(github::context::payload)?;
core::info!("The event payload: {json}");
Ok(())
}();
if let Err(error) = result {
core::set_failed!("{error}");
}
}
🔰 Based on the hello-world-javascript-action code example.
💡 You'll probably want to use configure-executable-action to manage the glue code to properly run your compiled executable.
There have been a few incomplete attempts to port the GitHub Actions actions/toolkit API to Rust before. kjvalencik/actions published actions-toolkit and actions-core. romnn/action-rs published action-artifact, action-core, action-derive, action-exec, action-github, action-glob, action-http-client, and action-io. Both of these projects appear to be stale that don't have much of an ecosystem surrounding them.
This actions-toolkit.rs project and the accompanying configure-executable-action configurator aim to make Rust-based GitHub Actions a second-class citizen -- an improvement on the current third-class status of relying Bash-based wrapper action configuration to call your Rust binary.
:octocat: Interested in writing your GitHub Action another way? Check out the official guides on Creating a compsite action, Creating a Docker container action, and Creating a JavaScript action.
This project really tries to mirror the API and package surface of [actions/toolkit] as closely as is reasonable. The goal is to replicate the well-known @actions/core and friends API surface so that you only have to learn how to do things one way. This has the convenient side effect of making existing documentation designed for JavaScript-based GitHub Actions "work" for Rust-based GitHub Actions.
To get started tinkering you can clone this repository and run cargo test
to see everything happen! 🤩 There's no current root package so you'll need to specify a --package <package_name>
or -p <package_name>
argument to some cargo
commands.
This is a monorepo where each package independently manages its own version. This means that releasing the release & tag semantics are a bit wacky -- instead of a single tag like Nothing is currently published yet so this doesn't apply. I also want to do some research to see what the convention around monorepo tag naming is.v1.0.0
for each version of the entire project there's now N different tags, one for each actions-*
package, each named according to ${package_name}-${package_version}
convention.
This repository was originally named "toolkit.rs" but since the organization/user name isn't actions-related (@jcbhmr instead of @actions) I added a prefix to clarify the name.
🆘 I'm not a very proficient Rust programmer. If you see something that could be better, please tell me! ❤️ You can open an Issue, Pull Request, or even just comment on a commit. You'll probably be granted write access. 😉