name: 'Clawstor cargo cache' description: > Wraps `cargo build` with a peer-cache lookup: HIT restores the target dir from the runner-local clawstor daemon (skipping dep compile); MISS runs cargo build then captures + uploads the target dir to the daemon. Config comes from `~/.config/claw-cargo/config.toml` on the runner host — provisioned by the fleet-admin, not from the workflow. inputs: workspace: description: 'Path to the cargo workspace root' required: false default: '.' profile: description: 'Cargo profile (dev, release, custom)' required: false default: 'dev' no-upload: description: > When "true", skip capture + upload on a miss. Useful for read-only CI jobs (PR builds, forks). Defaults to false so main-branch jobs populate the cache. required: false default: 'false' parallel-restore: description: > Concurrent chunk fetches on cache HIT. Default 1 (sequential BlobGetStream) — measured faster than parallel on loopback. Set to 8+ on cross-node deployments where per-stream throughput caps bite. required: false default: '1' outputs: cache-outcome: description: 'One of: HIT, MISS, POPULATED, SKIPPED' value: ${{ steps.build.outputs.cache-outcome }} fingerprint: description: 'The fingerprint claw-cargo computed for this build' value: ${{ steps.build.outputs.fingerprint }} elapsed-seconds: description: 'Wall-clock seconds elapsed in the build step' value: ${{ steps.build.outputs.elapsed-seconds }} runs: using: 'composite' steps: - name: Preflight check (claw-cargo + config) shell: bash run: | set -euo pipefail if ! command -v claw-cargo >/dev/null 2>&1; then echo "::error::claw-cargo not on PATH — fleet admin needs to install /usr/local/bin/claw-cargo on this runner" exit 1 fi claw-cargo --version # The daemon config is per-runner; the action expects it to # exist under $HOME/.config/claw-cargo/config.toml. We do not # ship secrets from the workflow. cfg="${HOME}/.config/claw-cargo/config.toml" if [ ! -s "$cfg" ]; then echo "::error::missing $cfg — fleet admin needs to provision peer + tls_dir for this runner" exit 1 fi - name: Build with clawstor cache id: build shell: bash env: WS: ${{ inputs.workspace }} PROFILE: ${{ inputs.profile }} NO_UPLOAD: ${{ inputs.no-upload }} PAR_RESTORE: ${{ inputs.parallel-restore }} run: | set -euo pipefail args=(build --workspace "$WS" --profile "$PROFILE" --parallel-restore "$PAR_RESTORE") if [ "$NO_UPLOAD" = "true" ]; then args+=(--no-upload) fi started=$SECONDS # Tee the summary so we can grep the outcome out for the output. set +e claw-cargo "${args[@]}" 2>&1 | tee /tmp/clawstor-build.out rc=${PIPESTATUS[0]} set -e elapsed=$((SECONDS - started)) # Parse `cache:` line. Shapes we handle: # cache: HIT (... bytes downloaded) # cache: MISS # cache: MISS -> populated (... bytes uploaded) # cache: MISS (no upload performed) outcome="SKIPPED" if grep -q 'cache: *HIT' /tmp/clawstor-build.out; then outcome="HIT" elif grep -q 'cache: *MISS -> populated' /tmp/clawstor-build.out \ || grep -q 'cache: *MISS → populated' /tmp/clawstor-build.out; then outcome="POPULATED" elif grep -q 'cache: *MISS' /tmp/clawstor-build.out; then outcome="MISS" fi fingerprint="$(grep -oE 'fingerprint: [0-9a-f]+' /tmp/clawstor-build.out | head -1 | awk '{print $2}')" echo "cache-outcome=$outcome" >> "$GITHUB_OUTPUT" echo "fingerprint=${fingerprint:-unknown}" >> "$GITHUB_OUTPUT" echo "elapsed-seconds=$elapsed" >> "$GITHUB_OUTPUT" echo "::notice::clawstor $outcome fingerprint=${fingerprint:-unknown} elapsed=${elapsed}s" exit "$rc"