Hachitool is a set of utilities that make it easier to work with Python scripts in GitHub Actions.
Hachitool can be installed like any other Python package:
- run: pip install hachitool
Hachitool can be ephemerally installed for inline Python scripts via uv:
- uses: astral-sh/setup-uv@v3
- shell: uv run --with hachitool python {0}
run: |
import hachitool
# Do stuff here
Hachitool can be emphemerally installed for external scripts via uv and inline script metadata:
# script.py
# /// script
# dependencies = [
# "hachitool",
# ]
# ///
import hachitool
# Do stuff here
# workflow.yml
- uses: astral-sh/setup-uv@v3
- run: uv run script.py
Set output parameters for a step. Takes either:
- a key as its first argument and a value as its second
- a set of key-value pairs as either a dictionary or keyword arguments
import hachitool
# All of these are equivalent
hachitool.set_output("key", "value")
hachitool.set_output({"key": "value"})
hachitool.set_output(key="value")
Set environment variables. Takes either:
- a key as its first argument and a value as its second
- a set of key-value pairs as either a dictionary or keyword arguments
import hachitool
# All of these are equivalent
hachitool.set_env("key", "value")
hachitool.set_env({"key": "value"})
hachitool.set_env(key="value")
Append something to the system path.
import hachitool
hachitool.add_path("/absolute/or/relative/path")
Add content to the step summary. Supports GitHub-flavored Markdown.
import hachitool
hachitool.summary.add("this is a summary")
Tip
Calling hachitool.summary
directly does the same thing:
import hachitool
hachitool.summary("this is a summary")
If the keyword-only overwrite
argument is True
, existing summary content will be erased:
import hachitool
hachitool.summary.add("this is a summary", overwrite=True)
Clear the step summary.
import hachitool
hachitool.summary.clear()
import hachitool
hachitool.mask("super secret value")
Print a message to the log. Takes the following arguments:
Argument | Type | Description | Required? |
---|---|---|---|
level |
"debug" | "notice" | "warning" | "error" |
The log level of the message. | Yes |
message |
str |
The message to print. | Yes |
file |
str |
The path to a file to annotate with the message. | No |
line |
int | tuple[int, int] |
The line(s) of file to annotate with the message. A tuple will be interpreted as a pair of starting and ending lines. |
No |
column |
int | tuple[int, int] |
The column(s) of file to annotate with the message. A tuple will be interpreted as a pair of starting and ending columns. |
No |
level
and message
are the first and second positional arguments, respectively.
file
, line
, and column
are keyword-only.
import hachitool
hachitool.log("notice", "this is a notice message", file="main.py", line=1, column=6)
# Using tuples for `line` and `column`
hachitool.log("notice", "this is a notic message", file="main.py", line=(1, 5), column=(6, 10))
Print a debug
, notice
, warning
, or error
message to the log, respectively. Takes all arguments of
hachitool.log
except for level
.
import hachitool
hachitool.debug("this is a debug message")
hachitool.notice("this is a notice message")
hachitool.warning("this is a warning message")
hachitool.error("this is an error message")
Optionally print an error-level message, then fail the workflow. Takes an optional exit_code
argument
that must be an integer greater than or equal to 1. Additionally takes all arguments of hachitool.error
,
except message
is optional.
import hachitool
hachitool.fail("something went wrong", exit_code=1)
Anything printed to the log inside this context manager will be nested inside an expandable group.
Takes a mandatory title
argument.
import hachitool
with hachitool.log_group(title="group title"):
print("I'm part of a log group!")
print("me too!")
print("me three!")
Nothing printed to the log inside this context manager will be interpreted as a workflow command.
import hachitool
hachitool.warning("this is a warning message to show that commands are being processed")
with hachitool.literal():
hachitool.warning("this will not render as a warning because commands are not being processed")
hachitool.warning("this will render as a warning since commands are being processed again")