s3-cache/README.md
Maximilian Jugl b04a255b4c
All checks were successful
Check build / check-dist (push) Successful in 1m24s
Run tests / Run vitest integration tests (push) Successful in 1m29s
feat: initial
2026-04-23 09:49:39 +02:00

148 lines
5.8 KiB
Markdown

# S3 Cache Action
This action allows caching dependencies and build outputs to improve workflow execution time using S3-compatible storage (like MinIO, Ceph, AWS S3, etc.).
The interface, inputs, outputs, and internal behavior of this action are intentionally designed to be identical to the official `actions/cache`. This ensures that it can be used as a seamless drop-in replacement in self-hosted environments where the official GitHub Actions cache might not be available or suitable.
## Inputs
- `path` (Required): A list of files, directories, and wildcard patterns to cache and restore.
- `key` (Required): An explicit key for restoring and saving the cache.
- `restore-keys` (Optional): An ordered list of keys to use for restoring stale cache if no cache hit occurred for key. Note `cache-hit` returns false in this case.
- `lookup-only` (Optional): Check if a cache entry exists for the given input(s) (key, restore-keys) without downloading the cache. Default is `false`.
- `fail-on-cache-miss` (Optional): Fail the workflow if cache entry is not found. Default is `false`.
- `s3-endpoint` (Required): The endpoint URL of your S3-compatible storage.
- `s3-bucket` (Required): The name of the S3 bucket to store the cache in.
- `s3-access-key` (Required): The S3 access key.
- `s3-secret-key` (Required): The S3 secret key.
- `s3-region` (Optional): The S3 region. Default is `us-east-1`.
## Outputs
- `cache-hit`: A boolean value to indicate an exact match was found for the primary key.
## Examples
### npm
```yaml
steps:
- name: Get npm cache directory
id: npm-cache-dir
run: echo "dir=$(npm config get cache)" >> "$GITHUB_OUTPUT"
- name: Cache npm
uses: https://stackit-solutions.git.onstackit.cloud/actions/s3-cache@v1
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
s3-endpoint: https://object.storage.eu01.onstackit.cloud
s3-region: eu01
s3-bucket: ${{ vars.S3_BUCKET }}
s3-access-key: ${{ vars.S3_ACCESS_KEY }}
s3-secret-key: ${{ secrets.S3_SECRET_KEY }}
```
### OpenTofu
```yaml
env:
TF_PLUGIN_CACHE_DIR: /opt/.terraform.d/plugin-cache
steps:
- name: Install OpenTofu
uses: opentofu/setup-opentofu@v2
with:
tofu_wrapper: false
- name: Setup OpenTofu provider cache
shell: bash
run: mkdir -p "$TF_PLUGIN_CACHE_DIR"
- name: Cache OpenTofu providers
uses: https://stackit-solutions.git.onstackit.cloud/actions/s3-cache@v1
with:
path: ${{ env.TF_PLUGIN_CACHE_DIR }}
key: ${{ runner.os }}-opentofu-${{ hashFiles('**/terraform.lock.hcl') }}
restore-keys: |
${{ runner.os }}-opentofu-
s3-endpoint: https://object.storage.eu01.onstackit.cloud
s3-region: eu01
s3-bucket: ${{ vars.S3_BUCKET }}
s3-access-key: ${{ vars.S3_ACCESS_KEY }}
s3-secret-key: ${{ secrets.S3_SECRET_KEY }}
- name: Initialize OpenTofu
shell: bash
run: tofu init
```
## Cache Strategies
This action supports the same caching strategies as the official cache action:
### Exact Match
An exact match occurs when the primary `key` exactly matches a previously saved cache in the S3 bucket. When this happens, the action downloads the cache, and the `cache-hit` output is set to `true`. Because an exact match was found, the `post` step will skip uploading the cache again at the end of the workflow.
### Prefix Match (Fallback)
If there is no exact match for the `key`, the action evaluates the `restore-keys`. It uses these keys as prefixes to search the S3 bucket. If multiple caches match the prefix, it will download the most recently created one.
In this case, the `cache-hit` output is set to `false` (because there was no exact match), but the cache is still restored. Since the primary `key` was a miss, the `post` step will pack and upload a fresh cache using the new primary `key` at the end of the job.
## S3 Store Configuration
This action relies on the underlying S3 storage to manage the lifecycle of the cache files. The action creates and reads objects but never deletes them. To prevent your bucket from growing indefinitely, it is highly recommended to configure a Lifecycle Policy on your S3 bucket to automatically remove objects after a certain period (e.g., 7 days).
### Example: Setting a 7-day expiration using s3cmd
Create a file named `lifecycle.xml`:
```xml
<LifecycleConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Rule>
<ID>ExpireOldCaches</ID>
<Prefix>runner-cache/</Prefix>
<Status>Enabled</Status>
<Expiration>
<Days>7</Days>
</Expiration>
</Rule>
</LifecycleConfiguration>
```
Apply the policy to your bucket:
```bash
s3cmd setlifecycle lifecycle.xml s3://your-s3-cache-bucket
```
## Developer Notes
### Setup
To set up the development environment, clone the repository and install the dependencies:
```bash
npm install
```
### Git Hooks (Husky)
The project uses `husky` to manage Git hooks. Upon running `npm install`, the `prepare` script will automatically configure Husky. This ensures that formatting, linting, and other quality checks are executed before you commit your code.
### Testing on macOS with Colima
The integration tests utilize `testcontainers` to spin up a local Adobe S3Mock instance. If you are developing on macOS and using Colima as your Docker runtime, `testcontainers` needs to know where to find the Docker socket inside the virtual machine.
Before running the tests, export the following environment variable:
```bash
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
npm run test
```
### Local Workflow Testing with act
You can test the entire GitHub Actions workflow locally using `act`.
```bash
act --workflows .github/workflows/test.yaml -P stackit-docker=registry.onstackit.cloud/devex-images/ubuntu:act-latest
```