go-actions-toolkit

🐿️ GitHub Actions toolkit for your Go-based GitHub Actions

MIT License

Stars
0
Committers
2
  • Create go-actions-toolkit
  • ⭐ github.com/jcbhmr/go-actions-toolkit/core
  • 🤢 github.com/jcbhmr/go-actions-toolkit/exec
  • github.com/jcbhmr/go-actions-toolkit/glob
  • 🤢 github.com/jcbhmr/go-actions-toolkit/http-client
  • 🤢 github.com/jcbhmr/go-actions-toolkit/io
  • ⭐ github.com/jcbhmr/go-actions-toolkit/tool-cache
  • ⭐ github.com/jcbhmr/go-actions-toolkit/github
  • github.com/jcbhmr/go-actions-toolkit/artifact
  • github.com/jcbhmr/go-actions-toolkit/cache
  • configure-executable-action
  • configure-wasmtime-action
  • hello-world-go-action

GitHub Actions Toolkit for Go

🐿️ 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. 🚀

  • actions-core2: ✅ Get inputs, set outputs, and other basic operations for GitHub Actions
  • actions-exec: 🏃‍♂️ Easier interface for running subprocesses in GitHub Actions
  • actions-glob: 🍦 Glob expression library for GitHub Actions
  • actions-http-client: 📞 An HTTP client optimized for GitHub Actions
  • actions-io: ✏️ Common I/O utilities as a single package for GitHub Actions
  • actions-tool-cache: 🔨 Functions for downloading and caching tools in GitHub Actions
  • actions-github: :octocat: Provides an Octokit.rs client already setup in the GitHub Actions context
  • actions-artifact: 💾 Functions to interact with Actions artifacts
  • actions-cache: 🎯 Functions to cache dependencies and build outputs for GitHub Actions
  • actions-attest: 🔏 Functions to write attestations for workflow artifacts

Installation

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.

Usage

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.

Alternatives

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.

Development

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 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. 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.

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. 😉