diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 80abfdb..1c7ec3d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,6 +5,13 @@ on: branches: [main] pull_request: branches: [main] + # Daily canary: the action installs from neokapi/neokapi releases, so it can + # break without a commit here (a renamed release asset did exactly that for + # 1.2.0). The schedule catches that class of breakage; the prerelease job + # below catches it while it is still an RC. + schedule: + - cron: "17 5 * * *" + workflow_dispatch: jobs: test-latest: @@ -77,6 +84,52 @@ jobs: echo "Expected: ${EXPECTED}, Actual: ${ACTUAL}" test "${EXPECTED}" = "${ACTUAL}" + # Canary against the newest CLI prerelease. Release packaging changes land + # on RCs first (the kapi_ → kapi-cli_ archive rename shipped on 1.2.0-rc1), + # so installing the newest prerelease here fails weeks before the same + # breakage would reach a stable release and every consumer workflow. + test-prerelease: + name: "Prerelease canary" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Resolve newest CLI prerelease + id: prerelease + shell: bash + env: + GH_TOKEN: ${{ secrets.NEOKAPI_GITHUB_TOKEN }} + # Same tag discipline as resolve-version.sh: only vX.Y.Z-… CLI tags, + # never plugin/app tags (check-v…, asr-v…, bowrain-v…). + run: | + VERSION=$( + gh api "repos/neokapi/neokapi/releases?per_page=100" --paginate \ + --jq '.[] | select(.draft == false and .prerelease == true) | .tag_name' | + grep -E '^v[0-9]+\.[0-9]+\.[0-9]+-' | + sed 's/^v//' | + sort -V | + tail -n 1 + ) || true + if [ -z "${VERSION}" ]; then + echo "No CLI prerelease found — nothing to canary." + else + echo "Newest CLI prerelease: ${VERSION}" + fi + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + + - name: Setup kapi (prerelease) + if: steps.prerelease.outputs.version != '' + id: setup + uses: ./ + with: + token: ${{ secrets.NEOKAPI_GITHUB_TOKEN }} + version: ${{ steps.prerelease.outputs.version }} + + - name: Verify kapi is on PATH + if: steps.prerelease.outputs.version != '' + shell: bash + run: kapi version + test-cache: name: "Cache hit (${{ matrix.os }})" runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index 4e6db16..63ea06b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ GitHub Action for installing the [kapi CLI](https://github.com/neokapi/neokapi) in CI workflows. -Downloads the correct binary for the runner platform, verifies SHA-256 checksums, caches between runs, and optionally installs kapi plugins (such as the bowrain plugin, `kapi-bowrain`) and configures server authentication. +Downloads the correct binary for the runner platform, verifies SHA-256 checksums, caches between runs, installs kapi plugins (the bowrain plugin by default), and configures server authentication. ## Usage @@ -33,13 +33,15 @@ steps: - run: kapi run ``` -### With the bowrain plugin and server auth +### With server auth + +The bowrain plugin is installed by default, so a server-connected project only +needs credentials: ```yaml steps: - uses: neokapi/setup-kapi@v1 with: - plugins: kapi-bowrain auth-token: ${{ secrets.BOWRAIN_AUTH_TOKEN }} server: https://your.bowrain.server @@ -54,7 +56,7 @@ steps: |-------|-------------|---------|----------| | `version` | Kapi CLI version (e.g. `1.1.0`), or `latest` for the newest stable CLI release | `latest` | No | | `token` | GitHub token for release downloads and API rate limits | `${{ github.token }}` | No | -| `plugins` | Newline- or comma-separated plugin refs to install (e.g. `kapi-bowrain`) | — | No | +| `plugins` | Newline- or comma-separated plugin refs to install, as the registry names them (`bowrain`, `okapi-bridge`; a `kapi-` prefix is stripped). Pass `''` to install nothing | `bowrain` | No | | `auth-token` | Bowrain server JWT, exported as `BOWRAIN_AUTH_TOKEN` | — | No | | `server` | Bowrain server URL, exported as `BOWRAIN_SERVER_URL` | — | No | @@ -72,7 +74,7 @@ steps: 3. **Download + verify** (on cache miss) — downloads the archive and `checksums.txt` from the GitHub release, verifies the SHA-256 checksum, and extracts the binary. 4. **Add to PATH** — makes `kapi` available to all subsequent steps. 5. **Configure auth** (optional) — exports `BOWRAIN_AUTH_TOKEN`/`BOWRAIN_SERVER_URL` when `auth-token` is set. -6. **Install plugins** (optional) — installs each ref in `plugins` via `kapi plugins install`, cached keyed on the plugin set + OS + arch. +6. **Install plugins** — installs each ref in `plugins` (default: `bowrain`) via `kapi plugins install`, cached keyed on the plugin set + OS + arch. Refs use the registry names; a `kapi-` binary prefix is stripped (`kapi-bowrain` → `bowrain`). ## Caching diff --git a/action.yml b/action.yml index 146fe5e..9583b12 100644 --- a/action.yml +++ b/action.yml @@ -14,9 +14,14 @@ inputs: required: false default: ${{ github.token }} plugins: - description: "Newline- or comma-separated plugin refs to install (e.g. 'kapi-bowrain')" + description: >- + Newline- or comma-separated plugin refs to install, as the registry + names them (e.g. 'bowrain', 'okapi-bridge'). The 'kapi-' binary prefix + is accepted and stripped ('kapi-bowrain' → 'bowrain'). Defaults to + 'bowrain' so server-connected projects work out of the box; pass '' to + install nothing. required: false - default: "" + default: "bowrain" auth-token: description: "Bowrain server JWT auth token (exported as BOWRAIN_AUTH_TOKEN)" required: false @@ -151,8 +156,11 @@ runs: env: INPUT_PLUGINS: ${{ inputs.plugins }} run: | - # Normalize: replace commas with newlines, trim whitespace, skip empty lines - PLUGINS=$(echo "${INPUT_PLUGINS}" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep -v '^$') + # Normalize: replace commas with newlines, trim whitespace, skip empty + # lines, and strip the 'kapi-' binary prefix — the registry names the + # plugin 'bowrain' while its binary and archives are 'kapi-bowrain', + # so both spellings should install. + PLUGINS=$(echo "${INPUT_PLUGINS}" | tr ',' '\n' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/^kapi-//' | grep -v '^$') while IFS= read -r plugin; do echo "Installing plugin: ${plugin}" kapi plugins install "${plugin}" diff --git a/scripts/download-verify.sh b/scripts/download-verify.sh index 92fba5e..5d4b76f 100755 --- a/scripts/download-verify.sh +++ b/scripts/download-verify.sh @@ -13,21 +13,43 @@ ARCH="${3:?}" EXT="${4:?}" DEST="${5:?}" -ARCHIVE="kapi_${VERSION}_${OS}_${ARCH}.${EXT}" TAG="v${VERSION}" TMPDIR=$(mktemp -d) trap 'rm -rf "${TMPDIR}"' EXIT +# The CLI archive was renamed for 1.2.0: kapi___. became +# kapi-cli___. (scripts/package-cli.sh mirrors the +# Homebrew naming, where the CLI toolchain is kapi-cli). Resolve the actual +# name from checksums.txt — the release's own asset manifest — so the action +# installs both eras: 1.1.0 and earlier ship kapi_, 1.2.0-rc1 and later ship +# kapi-cli_. +echo "Fetching checksums.txt from release ${TAG}..." +gh release download "${TAG}" \ + --repo neokapi/neokapi \ + --pattern "checksums.txt" \ + --dir "${TMPDIR}" + +cd "${TMPDIR}" +ARCHIVE="" +for candidate in "kapi-cli_${VERSION}_${OS}_${ARCH}.${EXT}" "kapi_${VERSION}_${OS}_${ARCH}.${EXT}"; do + if awk -v name="${candidate}" '$2 == name { found = 1 } END { exit !found }' checksums.txt; then + ARCHIVE="${candidate}" + break + fi +done +if [ -z "${ARCHIVE}" ]; then + echo "::error::Release ${TAG} has neither kapi-cli_${VERSION}_${OS}_${ARCH}.${EXT} nor kapi_${VERSION}_${OS}_${ARCH}.${EXT} in checksums.txt" >&2 + exit 1 +fi + echo "Downloading ${ARCHIVE} from release ${TAG}..." gh release download "${TAG}" \ --repo neokapi/neokapi \ --pattern "${ARCHIVE}" \ - --pattern "checksums.txt" \ --dir "${TMPDIR}" # Verify checksum -cd "${TMPDIR}" -EXPECTED=$(grep "${ARCHIVE}" checksums.txt | awk '{print $1}') +EXPECTED=$(awk -v name="${ARCHIVE}" '$2 == name { print $1 }' checksums.txt) if [ -z "${EXPECTED}" ]; then echo "::error::Archive ${ARCHIVE} not found in checksums.txt" >&2 exit 1