From 5e811d88537f34581836b53c64c67f62709f48c7 Mon Sep 17 00:00:00 2001 From: Ewerton Scaboro da Silva Date: Tue, 29 Sep 2026 15:08:34 +0000 Subject: [PATCH 1/2] [CI] Delete the Actions caches of closed pull requests A closed pull request's caches serve nothing but count against the 10 GB quota until unused for 7 days. ci-c-yocto saves ~450 MB of sstate per run that built something, so they could evict main's entry. - On close: delete that pull request's caches (same-repository only; a fork's token is read-only). - Nightly and manual sweep: delete the caches of every closed pull request. Covers forks, entries saved after close, and older pull requests. Manual runs can dry-run. --- .github/workflows/cleanup-pr-caches.yml | 78 +++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 .github/workflows/cleanup-pr-caches.yml diff --git a/.github/workflows/cleanup-pr-caches.yml b/.github/workflows/cleanup-pr-caches.yml new file mode 100644 index 000000000..a5c36916d --- /dev/null +++ b/.github/workflows/cleanup-pr-caches.yml @@ -0,0 +1,78 @@ +# Copyright (c) Microsoft. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + +# Deletes the Actions caches of closed pull requests. +# +# A pull request's caches (ref refs/pull//merge) serve only that pull +# request, yet count against the repository's 10 GB cache quota until they go +# unused for 7 days. ci-c-yocto saves a ~450 MB sstate entry per run that built +# something, so closed pull requests could push main's entry out. +# +# - On close: deletes that pull request's caches. Same-repository pull requests +# only: a fork's token is read-only. +# - Nightly (and manual): deletes the caches of every closed pull request. Covers +# forks, entries saved by a run still going when the pull request closed, and +# pull requests closed before this workflow existed. + +name: cleanup-pr-caches + +on: + pull_request: + types: [ closed ] + schedule: + - cron: '30 2 * * *' + workflow_dispatch: + inputs: + dry-run: + description: List what would be deleted, delete nothing. + type: boolean + default: false + +permissions: {} + +jobs: + on-close: + name: delete this pull request's caches + if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + actions: write + steps: + - name: Delete caches of refs/pull/${{ github.event.pull_request.number }}/merge + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + REF: refs/pull/${{ github.event.pull_request.number }}/merge + run: | + gh cache list --ref "$REF" --limit 1000 + gh cache delete --all --ref "$REF" --succeed-on-no-caches + + sweep: + name: delete caches of closed pull requests + if: github.event_name != 'pull_request' + runs-on: ubuntu-24.04 + timeout-minutes: 15 + permissions: + actions: write + pull-requests: read + steps: + - name: Delete caches of closed pull requests + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + DRY_RUN: ${{ inputs.dry-run || false }} + run: | + set -euo pipefail + prs="$(gh cache list --limit 10000 --json ref --jq '.[].ref' \ + | sed -n 's|^refs/pull/\([0-9][0-9]*\)/merge$|\1|p' | sort -un)" + for pr in $prs; do + state="$(gh pr view "$pr" --json state --jq .state)" + echo "#$pr: $state" + [ "$state" = OPEN ] && continue + if [ "$DRY_RUN" = true ]; then + gh cache list --ref "refs/pull/$pr/merge" --limit 1000 + else + gh cache delete --all --ref "refs/pull/$pr/merge" --succeed-on-no-caches + fi + done From a9d25a9a60ed0a9d4518d28fb4f1bd5fc5e7e0a2 Mon Sep 17 00:00:00 2001 From: Ewerton Scaboro da Silva Date: Sat, 10 Oct 2026 07:00:12 +0000 Subject: [PATCH 2/2] [CI] cleanup-pr-caches: list caches as JSON gh cache list --json returns an empty array with exit status 0 when a ref has no caches, whatever the gh version. --- .github/workflows/cleanup-pr-caches.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cleanup-pr-caches.yml b/.github/workflows/cleanup-pr-caches.yml index a5c36916d..3539060fa 100644 --- a/.github/workflows/cleanup-pr-caches.yml +++ b/.github/workflows/cleanup-pr-caches.yml @@ -45,7 +45,7 @@ jobs: GH_REPO: ${{ github.repository }} REF: refs/pull/${{ github.event.pull_request.number }}/merge run: | - gh cache list --ref "$REF" --limit 1000 + gh cache list --ref "$REF" --limit 1000 --json id,key,sizeInBytes --jq '.[] | "\(.id) \(.key) \(.sizeInBytes)"' gh cache delete --all --ref "$REF" --succeed-on-no-caches sweep: @@ -71,7 +71,7 @@ jobs: echo "#$pr: $state" [ "$state" = OPEN ] && continue if [ "$DRY_RUN" = true ]; then - gh cache list --ref "refs/pull/$pr/merge" --limit 1000 + gh cache list --ref "refs/pull/$pr/merge" --limit 1000 --json id,key,sizeInBytes --jq '.[] | "\(.id) \(.key) \(.sizeInBytes)"' else gh cache delete --all --ref "refs/pull/$pr/merge" --succeed-on-no-caches fi