Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,20 @@ jobs:
- name: Compile
run: mix compile --warnings-as-errors

- name: Checkout panel API contract
uses: actions/checkout@v4
with:
repository: cleat-cloud/cleat-deploy
path: .panel
sparse-checkout: priv/api_contract.json
sparse-checkout-cone-mode: false

- name: Fixture matches canonical panel contract
run: scripts/check_panel_contract.sh
env:
CLEAT_DEPLOY_CONTRACT: ${{ github.workspace }}/.panel/priv/api_contract.json

- name: Test
run: mix test
env:
CLEAT_DEPLOY_CONTRACT: ${{ github.workspace }}/.panel/priv/api_contract.json
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,31 @@ mix install
`mix install /usr/local/bin` or `CLEAT_INSTALL_DIR`). Make sure the destination
is on your `PATH`, then check `cleat version`.

## API contract

The panel is the source of truth: `cleat-deploy` `priv/api_contract.json`
(`CleatDeployWeb.Api.Contract`). This repo vendors a copy at
`test/fixtures/api_contract.json`.

CI checks the fixture against `cleat-cloud/cleat-deploy` `main`. Locally:

```bash
# sibling checkout of the panel
mix test test/cleat/contract_test.exs
scripts/check_panel_contract.sh

# or point at a specific file
CLEAT_DEPLOY_CONTRACT=/path/to/cleat-web/priv/api_contract.json mix test
```

When the panel adds a resource or key (compatible change): merge the panel PR
first, then copy `priv/api_contract.json` into the fixture and list the new
resource in `test/cleat/contract_test.exs` `@used`.

When the panel renames or drops a key the CLI reads (breaking change): update
the CLI in the same window as the panel merge. `mix test` fails on missing
keys even before the full-file diff.

## Quick start

```bash
Expand Down
47 changes: 47 additions & 0 deletions scripts/check_panel_contract.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Compare the vendored CLI fixture with the canonical panel contract.
# Usage: scripts/check_panel_contract.sh
# Optional: CLEAT_DEPLOY_CONTRACT=/path/to/priv/api_contract.json
set -euo pipefail

root="$(cd "$(dirname "$0")/.." && pwd)"
fixture="$root/test/fixtures/api_contract.json"
canonical="${CLEAT_DEPLOY_CONTRACT:-}"

if [[ -z "$canonical" && -f "$root/../cleat-web/priv/api_contract.json" ]]; then
canonical="$root/../cleat-web/priv/api_contract.json"
fi

if [[ -z "$canonical" ]]; then
canonical="$(mktemp)"
trap 'rm -f "$canonical"' EXIT
curl -fsSL "https://raw.githubusercontent.com/cleat-cloud/cleat-deploy/main/priv/api_contract.json" \
-o "$canonical"
fi

if [[ ! -f "$fixture" ]]; then
echo "missing CLI fixture: $fixture" >&2
exit 1
fi

if [[ ! -f "$canonical" ]]; then
echo "missing panel contract: $canonical" >&2
exit 1
fi

python3 - "$fixture" "$canonical" <<'PY'
import json, sys
fixture_path, canonical_path = sys.argv[1], sys.argv[2]
with open(fixture_path) as fh:
fixture = json.load(fh)
with open(canonical_path) as fh:
canonical = json.load(fh)
if fixture != canonical:
print(
f"CLI fixture {fixture_path} drifted from panel contract {canonical_path}",
file=sys.stderr,
)
sys.exit(1)
print(f"ok: {fixture_path} matches {canonical_path}")
PY
35 changes: 35 additions & 0 deletions test/cleat/contract_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,39 @@ defmodule Cleat.ContractTest do
assert unknown == [],
"new panel resources are not covered by the CLI contract test: #{inspect(unknown)}"
end

test "vendored fixture matches the canonical panel contract" do
case panel_contract_path() do
nil ->
if System.get_env("CI") in ["true", "1"] do
flunk("""
CI must compare the fixture against cleat-deploy priv/api_contract.json.
Set CLEAT_DEPLOY_CONTRACT to that file.
""")
else
:ok
end

path ->
panel = path |> File.read!() |> Jason.decode!()
fixture = @fixture |> File.read!() |> Jason.decode!()

assert fixture == panel, """
CLI fixture drifted from the panel contract at #{path}.
Copy priv/api_contract.json from cleat-cloud/cleat-deploy into
test/fixtures/api_contract.json and update @used in this test.
"""
end
end

defp panel_contract_path do
env = System.get_env("CLEAT_DEPLOY_CONTRACT")
sibling = Path.expand("../../../cleat-web/priv/api_contract.json", __DIR__)

cond do
is_binary(env) and env != "" -> env
File.exists?(sibling) -> sibling
true -> nil
end
end
end
Loading