diff --git a/.github/actions/ccache-clear/action.yml b/.github/actions/ccache-clear/action.yml index d20f6bf848..2420045edf 100644 --- a/.github/actions/ccache-clear/action.yml +++ b/.github/actions/ccache-clear/action.yml @@ -1,23 +1,88 @@ # note: place this as the last step of the job, so the new cache is saved by "Post ccache" right after the old one is cleared name: "ccache-clear" -description: "Delete all GitHub Actions caches matching a key prefix" +description: "Delete GitHub Actions caches matching a key prefix, oldest first" inputs: key: description: "Cache key prefix to match and delete" required: true + older: + description: "Only delete caches created more than this long ago (e.g. 90m, 1h, 1d). By default all matching caches are deleted" + required: false + default: "" + min: + description: "Stop deleting if fewer than this many caches would remain (e.g. 1). By default there is no minimum" + required: false + default: "0" + dry-run: + description: "Only print the caches that would be deleted, without deleting them" + required: false + default: "false" runs: using: "composite" steps: - name: Clear caches shell: bash + env: + CLEAR_KEY: ${{ inputs.key }} + CLEAR_OLDER: ${{ inputs.older }} + CLEAR_MIN: ${{ inputs.min }} + CLEAR_DRY_RUN: ${{ inputs.dry-run }} run: | - CACHES=$(gh cache list --key "ccache-${{ inputs.key }}" --json id,key --jq '.[] | "\(.id) \(.key)"' 2>/dev/null) + # Convert a duration (e.g. 90m, 1h, 1d, plain seconds) to seconds + to_seconds() { + local val="$1" + [[ "$val" =~ ^[0-9]+$ ]] && { echo "$val"; return 0; } + local num="${val%?}" unit="${val: -1}" mult + [[ "$num" =~ ^[0-9]+$ ]] || return 1 + case "$unit" in + s) mult=1 ;; + m) mult=60 ;; + h) mult=3600 ;; + d) mult=86400 ;; + *) return 1 ;; + esac + echo $((num * mult)) + } + + [[ "$CLEAR_MIN" =~ ^[0-9]+$ ]] || { echo "Invalid min value: $CLEAR_MIN" >&2; exit 1; } + [[ "$CLEAR_DRY_RUN" =~ ^(true|false)$ ]] || { echo "Invalid dry-run value: $CLEAR_DRY_RUN" >&2; exit 1; } + + CACHES=$(gh cache list --key "ccache-$CLEAR_KEY" --json id,key,createdAt --jq '.[] | [.createdAt, .id, .key] | @tsv' 2>/dev/null | LC_ALL=C sort) if [ -z "$CACHES" ]; then - echo "No caches found with key prefix: ${{ inputs.key }}" + echo "No caches found with key prefix: $CLEAR_KEY" exit 0 fi - while read -r id key; do - echo "Deleting cache: $id ($key)" - gh cache delete "$id" + + TOTAL=$(( $(wc -l <<< "$CACHES") )) + + echo "Found $TOTAL cache(s) with key prefix: $CLEAR_KEY (oldest first):" + while IFS=$'\t' read -r CREATED ID KEY; do + printf ' %s %s %s\n' "$CREATED" "$ID" "$KEY" + done <<< "$CACHES" + + CUTOFF="" + if [ -n "$CLEAR_OLDER" ]; then + OLDER_SECONDS=$(to_seconds "$CLEAR_OLDER") || { echo "Invalid older value: $CLEAR_OLDER (expected e.g. 90m, 1h, 1d)" >&2; exit 1; } + CUTOFF=$(( $(date +%s) - OLDER_SECONDS )) + fi + + # Caches are sorted oldest first + DELETED=0 + while IFS=$'\t' read -r CREATED ID KEY; do + if [ -n "$CUTOFF" ] && [ "$(date -d "$CREATED" +%s)" -ge "$CUTOFF" ]; then + echo "Rest are not older than $CLEAR_OLDER, stopping" + break + fi + if [ $((TOTAL - DELETED - 1)) -lt "$CLEAR_MIN" ]; then + echo "Keeping at least $CLEAR_MIN cache(s), stopping" + break + fi + if [ "$CLEAR_DRY_RUN" = "true" ]; then + echo "Would delete cache: $ID ($KEY)" + else + echo "Deleting cache: $ID ($KEY)" + gh cache delete "$ID" + fi + DELETED=$((DELETED + 1)) done <<< "$CACHES" diff --git a/.github/workflows/build-cpu.yml b/.github/workflows/build-cpu.yml index ffced86c6a..f39304cabf 100644 --- a/.github/workflows/build-cpu.yml +++ b/.github/workflows/build-cpu.yml @@ -117,6 +117,18 @@ jobs: ./bin/llama-convert-llama2c-to-ggml --copy-vocab-from-model ./tok512.bin --llama2c-model stories260K.bin --llama2c-output-model stories260K.gguf ./bin/llama-completion -m stories260K.gguf -p "One day, Lily met a Shoggoth" -n 500 -c 256 + # note: real deletion only on push to master (same condition as the ccache save), + # dry-run otherwise (the token is read-only on PRs from forks) + - name: ccache-clear + uses: ./.github/actions/ccache-clear + env: + GH_TOKEN: ${{ github.token }} + with: + key: cpu-${{ matrix.os }} + older: 1h + min: 1 + dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }} + windows: name: windows / ${{ matrix.build }} runs-on: windows-2025 diff --git a/.pi/gg/SYSTEM.md b/.pi/gg/SYSTEM.md index 6a757c8694..47883081cf 100644 --- a/.pi/gg/SYSTEM.md +++ b/.pi/gg/SYSTEM.md @@ -17,6 +17,7 @@ Coding: Pull requests (PRs): - New branch names are prefixed with "gg/" - Before opening a pull request, ask the user to confirm the description +- Don't explicitly wrap lines in the PR description (each paragraph and bullet is a single line) - When creating a pull request, look for the repository's PR template and follow it - For the AI usage disclosure section, write "YES. pi:llama.cpp/[MODEL]" - Ask the user to tell you what model was used and write it in place of [MODEL]