Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7ac2e8f
feat: add version resolution script with tests
markovejnovic May 25, 2026
5f65496
feat: add hm install script with platform detection and fallback chain
markovejnovic May 25, 2026
b158b0e
feat: add setup sub-action for hm CLI installation
markovejnovic May 25, 2026
3eb33a1
feat: add cache-restore sub-action wrapping hm cache restore
markovejnovic May 25, 2026
58ee526
feat: add cache-save sub-action with content-addressed keys
markovejnovic May 25, 2026
7a23ab9
feat: add all-in-one root action composing setup + cache + run
markovejnovic May 25, 2026
2d39e90
feat: add integration test workflow with fixture pipeline
markovejnovic May 25, 2026
d6836ba
chore: add YAML validation to CI
markovejnovic May 25, 2026
accfdee
fix: harden against script injection and improve cache/auth reliability
markovejnovic May 25, 2026
fc86837
feat: cache hm binary between runs, remove Python DSL install
markovejnovic May 25, 2026
938ee61
feat: add registry-based Docker image caching (GHCR)
markovejnovic May 25, 2026
8a1927a
feat: registry-only caching with automatic stale image cleanup
markovejnovic May 25, 2026
73e5c3d
docs: add README with usage examples, inputs reference, and migration…
markovejnovic May 25, 2026
d600295
feat(cache-save): add hm-path input for custom binary location
markovejnovic May 27, 2026
e8e4d41
feat: wire hm-path through root action, skip setup when provided
markovejnovic May 27, 2026
97fa847
test: add integration test for custom hm-path (dogfood pattern)
markovejnovic May 27, 2026
f900711
docs: add custom binary / dogfood usage example to README
markovejnovic May 27, 2026
88dedb9
docs: add implementation and migration plans
markovejnovic May 27, 2026
4b1005f
Merge remote-tracking branch 'origin/main' into initial-setup
markovejnovic May 27, 2026
13e24f1
cleanup slop
markovejnovic May 27, 2026
d55f6c5
deslop
markovejnovic May 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/test-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,53 @@ jobs:
run: |
echo "Cache hit: ${{ steps.setup.outputs.cache-hit }}"
hm --version

custom-binary:
name: Custom hm-path (dogfood pattern)
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4

- name: Create mock hm binary
run: |
mkdir -p /tmp/mock-hm
cat > /tmp/mock-hm/hm << 'SCRIPT'
#!/bin/bash
case "$1" in
--version) echo "mock-0.0.1" ;;
cache)
case "$2" in
save)
mkdir -p "$3"
echo '{"images":{}}' > "$3/manifest.json"
echo "abc123"
;;
restore) echo "restored" ;;
esac
;;
run) echo "ran pipeline: $2" ;;
esac
SCRIPT
chmod +x /tmp/mock-hm/hm

- name: Cache restore (no manifest yet, cold start)
uses: ./cache-restore
with:
working-directory: tests/fixtures

- name: Run with custom binary
working-directory: tests/fixtures
env:
HM_NONINTERACTIVE: '1'
run: /tmp/mock-hm/hm run hello

- name: Cache save with custom binary
if: always()
uses: ./cache-save
with:
working-directory: tests/fixtures
hm-path: /tmp/mock-hm/hm
41 changes: 11 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
# actions-hm

[![CI](https://img.shields.io/github/actions/workflow/status/harmont-dev/actions-hm/ci.yml?branch=main&logo=github&label=CI)](https://github.com/harmont-dev/actions-hm/actions)
[![GitHub release](https://img.shields.io/github/v/release/harmont-dev/actions-hm?logo=github)](https://github.com/harmont-dev/actions-hm/releases)
[![Marketplace](https://img.shields.io/badge/marketplace-harmont-purple?logo=github)](https://github.com/marketplace/actions/harmont)
> [!WARNING]
>
> This repo is currently considered experimental.

Run [harmont](https://harmont.dev) pipelines in GitHub Actions. One step. Automatic Docker image caching via your container registry.
Run [harmont](https://harmont.dev) pipelines in GitHub Actions.

```yaml
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: ci
```

That's it. This installs `hm`, pulls cached Docker images from GHCR, runs your pipeline, and pushes updated images back — with automatic cleanup of stale cache entries.

## Why

You already define your CI with harmont. This action lets you run it on GitHub Actions without boilerplate:

- **Zero config caching** — Docker images cached in GHCR with native layer deduplication
- **One step** — no separate setup, login, cache-restore, cache-save dance
- **Fast repeat runs** — `hm` binary cached between runs, images pulled only when changed
- **Auto cleanup** — stale registry images pruned automatically (configurable retention)
- **Granular control** — use sub-actions individually when you need custom steps between them

## Usage

### Minimal (all-in-one)
Expand Down Expand Up @@ -55,15 +43,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: lint

test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: test
parallelism: 4
Expand Down Expand Up @@ -95,14 +83,6 @@ jobs:
if: always()
```

### Pin to specific version

```yaml
- uses: harmont-dev/actions-hm@v1
with:
version: 0.5.0
```

## Inputs

| Input | Default | Description |
Expand All @@ -116,6 +96,7 @@ jobs:
| `cache-registry-prefix` | *(auto)* | Registry path prefix. Default: `ghcr.io/<owner>/<repo>/harmont-cache` |
| `cache-cleanup` | `true` | Delete stale images from registry after save |
| `cache-cleanup-keep` | `2` | Number of old image versions to keep per step |
| `hm-path` | | Path to a locally-built `hm` binary (skips install; used for dogfooding) |
| `extra-args` | | Additional arguments passed to `hm run` |
| `token` | `github.token` | GitHub token (needs `packages:write`, `packages:delete` for cleanup) |

Expand Down Expand Up @@ -212,7 +193,7 @@ steps:
```yaml
steps:
- uses: actions/checkout@v4
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: ci
```
Expand All @@ -234,7 +215,7 @@ macOS runners have Docker available via colima/lima. Windows runners are not cur
Yes. Set `cache-registry` to your registry hostname and provide a token with push/pull access:

```yaml
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: ci
cache-registry: registry.example.com
Expand All @@ -244,7 +225,7 @@ Yes. Set `cache-registry` to your registry hostname and provide a token with pus
### How do I disable caching entirely?

```yaml
- uses: harmont-dev/actions-hm@v1
- uses: harmont-dev/actions-hm@main
with:
pipeline: ci
cache: 'false'
Expand Down
11 changes: 10 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ inputs:
description: Additional arguments passed to 'hm run'
required: false
default: ''
hm-path:
description: >
Path to the hm binary. Use when testing a locally-built binary
instead of an installed release. Overrides setup step.
required: false
default: ''
token:
description: >
GitHub token (needs packages:write for cache, packages:delete for cleanup)
Expand All @@ -70,6 +76,7 @@ runs:
steps:
# --- Setup ---
- name: Setup Harmont
if: inputs.hm-path == ''
id: setup
uses: ./setup
with:
Expand All @@ -92,6 +99,7 @@ runs:
working-directory: ${{ inputs.working-directory }}
env:
HM_NONINTERACTIVE: '1'
INPUT_HM_PATH: ${{ inputs.hm-path || 'hm' }}
INPUT_PIPELINE: ${{ inputs.pipeline }}
INPUT_PARALLELISM: ${{ inputs.parallelism }}
INPUT_EXTRA_ARGS: ${{ inputs.extra-args }}
Expand All @@ -107,7 +115,7 @@ runs:
read -ra extra <<< "$INPUT_EXTRA_ARGS"
args+=("${extra[@]}")
fi
hm run "${args[@]}"
"$INPUT_HM_PATH" run "${args[@]}"

# --- Cache Save ---
- name: Save Docker cache
Expand All @@ -119,4 +127,5 @@ runs:
working-directory: ${{ inputs.working-directory }}
cleanup: ${{ inputs.cache-cleanup }}
cleanup-keep: ${{ inputs.cache-cleanup-keep }}
hm-path: ${{ inputs.hm-path || 'hm' }}
token: ${{ inputs.token }}
11 changes: 8 additions & 3 deletions cache-save/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ description: >
Push Docker images to a container registry after a harmont pipeline run.
Automatically cleans up stale images no longer in the current manifest.
Use with 'if: always()' to save cache even when the pipeline fails.

inputs:
registry:
description: Container registry to push to
Expand Down Expand Up @@ -36,7 +35,12 @@ inputs:
Token for registry auth (needs packages:write, packages:delete for cleanup).
required: false
default: ${{ github.token }}

hm-path:
description: >
Path to the hm binary. Defaults to 'hm' (assumes it's on PATH).
Use './target/debug/hm' or similar when testing a locally-built binary.
required: false
default: hm
runs:
using: composite
steps:
Expand All @@ -54,13 +58,14 @@ runs:
env:
INPUT_REGISTRY_PREFIX: ${{ inputs.registry-prefix }}
INPUT_REGISTRY: ${{ inputs.registry }}
INPUT_HM_PATH: ${{ inputs.hm-path }}
GITHUB_REPOSITORY: ${{ github.repository }}
working-directory: ${{ inputs.working-directory }}
run: |
prefix="${INPUT_REGISTRY_PREFIX:-${INPUT_REGISTRY}/${GITHUB_REPOSITORY}/harmont-cache}"

echo "::group::Exporting image manifest"
hm cache save .harmont-cache/ > /dev/null
"$INPUT_HM_PATH" cache save .harmont-cache/ > /dev/null
echo "::endgroup::"

if [ ! -f .harmont-cache/manifest.json ]; then
Expand Down
Loading
Loading