diff --git a/.actrc b/.actrc new file mode 100644 index 0000000..28b150f --- /dev/null +++ b/.actrc @@ -0,0 +1,17 @@ +# Map ubuntu-24.04 runner label to catthehacker medium image (24.04 variant). +# Without this, act may not resolve the runner label correctly. +-P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04 + +# Required for macOS arm64 (M-series) — catthehacker images are amd64-only. +# Harmless no-op on native amd64 hosts. +--container-architecture linux/amd64 + +# Disable Docker socket bind-mount into containers. Our workflows don't need +# Docker-in-Docker. Without this, act fails on Rancher Desktop / Colima where +# the socket is not at /var/run/docker.sock. +--container-daemon-socket - + +# Skip TLS verification inside containers. Corporate proxies (Netskope, Zscaler) +# re-sign certificates with their own CA which the container doesn't trust. +# Safe here — this only affects local act runs in throwaway containers. +--env NODE_TLS_REJECT_UNAUTHORIZED=0 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index acfc0a0..3fe3e24 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,7 +29,7 @@ jobs: echo "Generating rockspec..." lx generate-rockspec - ROCKSPEC=$(ls -1 *.rockspec 2>/dev/null | head -1) + ROCKSPEC=$(find . -maxdepth 1 -name '*.rockspec' -print -quit) if [[ -z "$ROCKSPEC" ]]; then echo "::error::No rockspec file generated" exit 1 @@ -46,6 +46,7 @@ jobs: rm -f "$ROCKSPEC" - name: Upload to LuaRocks + if: ${{ !env.ACT }} run: lx --verbose --lua-version 5.1 upload env: LUX_API_KEY: ${{ secrets.LUX_API_KEY }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 0e4da9f..3da11d9 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -18,7 +18,9 @@ jobs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} steps: - - uses: googleapis/release-please-action@v4 + - name: Release Please + if: ${{ !env.ACT }} + uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.PAT }} @@ -186,7 +188,7 @@ jobs: luarocks lint *.rockspec - name: Upload Release Artifacts (with rockspec) - if: matrix.name == 'linux-x86_64' + if: ${{ !env.ACT && matrix.name == 'linux-x86_64' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -194,7 +196,7 @@ jobs: roda-${{ matrix.name }}.tar.gz roda-${{ matrix.name }}.tar.gz.sha256 *.rockspec --clobber - name: Upload Release Artifacts (Linux aarch64) - if: matrix.name == 'linux-aarch64' + if: ${{ !env.ACT && matrix.name == 'linux-aarch64' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -202,7 +204,7 @@ jobs: roda-${{ matrix.name }}.tar.gz roda-${{ matrix.name }}.tar.gz.sha256 --clobber - name: Upload Release Artifacts (Windows) - if: matrix.target == 'windows' + if: ${{ !env.ACT && matrix.target == 'windows' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -210,7 +212,7 @@ jobs: roda-${{ matrix.name }}.zip roda-${{ matrix.name }}.zip.sha256 --clobber - name: Upload Release Artifacts (macOS) - if: matrix.target == 'macos' + if: ${{ !env.ACT && matrix.target == 'macos' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 55aec8a..b9998df 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,7 +56,7 @@ jobs: run: just lint-ci - name: Comment on PR if formatting needed - if: failure() && github.event_name == 'pull_request' + if: ${{ !env.ACT && failure() && github.event_name == 'pull_request' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/.gitignore b/.gitignore index 89d4287..78b88a2 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ luacov.report.out # Demo recording *.cast +# act (local GitHub Actions runner) +.secrets + # Build artifacts .build/ /roda diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18ce6ad..98af456 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,12 +52,58 @@ luarocks install busted --dev ### Git Hooks -We use [Lefthook](https://github.com/evilmartians/lefthook) to manage Git hooks (formatting, linting, tests). After installing lefthook (e.g., via `brew install lefthook` or `npm install -g @evilmartians/lefthook`), set up the hooks by running: +We use [Lefthook](https://github.com/evilmartians/lefthook) to manage Git hooks. After installing lefthook (e.g., via `brew install lefthook`), set up the hooks by running: ```bash lefthook install ``` +Pre-commit hooks run automatically on `git commit`: + +| Hook | Scope | What it does | +|------|-------|-------------| +| format | `*.lua` files | Auto-formats with `lx fmt` | +| lint | `*.lua` files | Lints with `lx lint` | +| justfile | justfile | Auto-formats with `just --fmt` | +| actionlint | `.github/workflows/*.yml` | Lints GitHub Actions workflows (requires [actionlint](https://github.com/rhysd/actionlint): `brew install actionlint`) | + +### Local CI Verification (macOS) + +You can run GitHub Actions workflows locally using [act](https://github.com/nektos/act) and Docker. This lets you validate CI changes without pushing. + +#### Prerequisites + +- [act](https://github.com/nektos/act): `brew install act` +- Docker runtime ([Rancher Desktop](https://rancherdesktop.io/), [OrbStack](https://orbstack.dev/), or Docker Desktop) +- [GitHub CLI](https://cli.github.com/) authenticated: `gh auth login` + +If your Docker socket is not at `/var/run/docker.sock` (e.g., Rancher Desktop without Administrative Access), set `DOCKER_HOST`: + +```bash +# Rancher Desktop default socket path +export DOCKER_HOST="unix://$HOME/.rd/docker.sock" +``` + +The `.actrc` file already includes `--container-daemon-socket -` to disable Docker socket bind-mounting into containers, which avoids mount failures on Rancher Desktop and Colima. If you use actions that require Docker-in-Docker, enable Administrative Access in Rancher Desktop (Preferences > Application > General) so the socket is created at `/var/run/docker.sock`. + +#### Pull the runner image + +```bash +docker pull ghcr.io/catthehacker/ubuntu:act-24.04 +``` + +The `.actrc` file in the repo root maps `ubuntu-24.04` to this image and sets the container architecture for Apple Silicon compatibility. + +#### Available recipes + +```bash +just act-test # Run the test job (apt-get, Lux, just, unit tests) +just act-lint # Run the lint job (formatting check, linter) +just act-publish # Validate rockspec generation (upload step skipped) +``` + +Steps that require GitHub API access or external secrets (PR comments, LuaRocks upload, release-please) are automatically skipped when running under act. + ### Project Structure ``` diff --git a/justfile b/justfile index 4d54591..49c9e77 100644 --- a/justfile +++ b/justfile @@ -253,6 +253,23 @@ publish: release @echo "Publishing to LuaRocks..." lx --lua-version {{ lua_version }} publish +# --- Local CI (act) --- + +[doc("Run test job locally via act (requires: docker, gh auth login)")] +[group('ci')] +act-test: + act push --job test -W .github/workflows/tests.yml -s GITHUB_TOKEN="$(gh auth token)" + +[doc("Run lint job locally via act")] +[group('ci')] +act-lint: + act push --job lint -W .github/workflows/tests.yml -s GITHUB_TOKEN="$(gh auth token)" + +[doc("Run publish validation locally via act (upload step skipped)")] +[group('ci')] +act-publish: + act workflow_dispatch -W .github/workflows/publish.yml -s GITHUB_TOKEN="$(gh auth token)" + # --- Maintenance --- [confirm("Remove all build artifacts and binaries?")] diff --git a/lefthook.yml b/lefthook.yml index b6e0c0f..7a087b7 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -14,3 +14,6 @@ pre-commit: just --fmt fi stage_fixed: true + actionlint: + glob: ".github/workflows/*.yml" + run: actionlint {staged_files}