Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
celsiusnarhwal committed Dec 7, 2024
0 parents commit ee72494
Show file tree
Hide file tree
Showing 11 changed files with 678 additions and 0 deletions.
163 changes: 163 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

.pdm-build/
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: .
hooks:
- id: ruff
args: [ --fix ]

- id: ruff-format
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
200 changes: 200 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# Hachitool

Hachitool is a set of utilities that make it easier to work with Python scripts in GitHub Actions.

## Installation

Hachitool can be installed persistently like any other Python package:

```shell
pip install hachitool
```

### Inline scripts

Hachitool can be ephemerally installed for inline Python scripts via [uv](https://docs.astral.sh/uv):

```yaml
- uses: astral-sh/setup-uv@v3

- shell: uv run --with hachitool python {0}
run: |
import hachitool
# Do stuff here
```
### External scripts
Hachitool can be emphemerally installed for external scripts via uv and
[inline script metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata):
```python
# script.py

# /// script
# dependencies = [
# "hachitool",
# ]
# ///

import hachitool

# Do stuff here
```

```yaml
# workflow.yml

- uses: astral-sh/setup-uv@v3

- run: uv run script.py
```
## Usage
### `hachitool.set_output`

Set output 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

```python
import hachitool
# All of these are equivalent
hachitool.set_output("key", "value")
hachitool.set_output({"key": "value"})
hachitool.set_output(key="value")
```

### `hachitool.set_env`

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

```python
import hachitool
# All of these are equivalent
hachitool.set_env("key", "value")
hachitool.set_env({"key": "value"})
hachitool.set_env(key="value")
```

### `hachitool.add_path`

Append something to the system path.

```python
import hachitool
hachitool.add_path("/absolute/or/relative/path")
```

### `hachitool.summary`

Add content to
the [step summary](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-job-summary).
You can call this function multiple times; the result is cumulative. Content added to the summary cannot be removed.

```python
import hachitool
hachitool.summary("this is a summary")
```

### `hachitool.mask`

[Mask a value](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#masking-a-value-in-a-log).

```python
import hachitool
hachitool.mask("super secret value")
```

### `hachitool.log`

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.

```python
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))
```

### `hachitool.debug`, `hachitool.notice`, `hachitool.warning`, `hachitool.error`

Print a `debug`, `notice`, `warning`, or `error` message to the console, respectively. Takes the same arguments
as `hachitool.log` excpet for `level`.

```python
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")
```

### `hachitool.fail`

Optionally prints an error-level message, then fails 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.

```python
import hachitool

hachitool.fail("something went wrong", exit_code=1)
```

### `hachitool.log_group`

Anything printed to the log inside this context manager will be printed as
an [expandable group](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#grouping-log-lines).

Takes a mandatory `title` argument.

```python
import hachitool

with hachitool.log_group("group title"):
print("I'm part of a log group!")
print("me too!")
print("me three!")
```

### `hachitool.literal`

Nothing printed to the log inside this context manager will be interpreted as a workflow command.

```python
import hachitool

with hachitool.literal():
hachitool.mask("this doesn't work properly because GitHub won't interpret it as a workflow command")
hachitool.debug("neither does this")
hachitool.notice("or this")
hachitool.warning("or this")
hachitool.error("or this")
hachitool.fail("this will still fail the workflow but the error message won't print correctly")
```
2 changes: 2 additions & 0 deletions hachitool/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .commands import * # noqa: F403
from .files import * # noqa: F403
Loading

0 comments on commit ee72494

Please sign in to comment.