From 00f8780fc447cb0a8cae4bd5b401aff9a932c801 Mon Sep 17 00:00:00 2001 From: Roman Kitaev Date: Fri, 21 Aug 2026 20:07:05 +0300 Subject: [PATCH 1/2] ci: skip the codecov upload when no token is available Dependabot PRs run against the Dependabot secret store, which does not carry CODECOV_TOKEN, so the uploader ran with an empty token and codecov rejected it ("Token required because branch is protected"). With fail_ci_if_error: true that failed the coverage job, and with it the "CI ok" gate, on every dependabot PR. Coverage is still measured on those runs; only the upload is skipped, with a notice annotation saying so. --- .github/workflows/CI.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 2cbcbd3..9680a94 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -84,6 +84,12 @@ jobs: name: "coverage" runs-on: ubuntu-latest timeout-minutes: 20 + env: + # Dependabot PRs run against the Dependabot secret store, which does not + # carry CODECOV_TOKEN. Compute the flag here (job-level env is visible to + # a step's own `if:`, step-level env is not) and skip the upload rather + # than failing the whole run. + HAS_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN != '' }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: @@ -112,6 +118,7 @@ jobs: run: pytest tests/ --ignore=tests/test_benches.py --ignore=tests/test_wasm.py --cov --cov-report=xml - name: "Upload coverage to Codecov" + if: env.HAS_CODECOV_TOKEN == 'true' uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: files: coverage.xml @@ -119,6 +126,10 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: "Skipped coverage upload (no CODECOV_TOKEN)" + if: env.HAS_CODECOV_TOKEN != 'true' + run: echo "::notice::CODECOV_TOKEN is not available to this run; coverage was measured but not uploaded." + tests: uses: ./.github/workflows/tests.yaml From 964f5d86ac856d521313fa3ccae6a84d10c7b5d2 Mon Sep 17 00:00:00 2001 From: Roman Kitaev Date: Fri, 21 Aug 2026 20:07:05 +0300 Subject: [PATCH 2/2] docs: make the eviction-listener example deterministic The example filled a capacity-2 cache with three keys and then removed one of them, so whether a "size" eviction was ever recorded depended on when moka happened to run its pending maintenance. It passed only because moka 0.12.15 leaked a phantom entry slot per insert/remove race, which effectively shrank the capacity; moka 0.12.16 fixes that leak and the example started failing. Overflow the cache well past its capacity and drive maintenance with run_pending_tasks() instead of guessing, which also matches what the notes below the example say about lazy delivery. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 949a697..b5d0086 100644 --- a/README.md +++ b/README.md @@ -354,11 +354,15 @@ events: list[tuple[str, list[int], str]] = [] moka: Moka[str, list[int]] = Moka(2, eviction_listener=key_evicted, ttl=0.5) moka.set("hello", [1, 2, 3]) moka.set("hello", [3, 2, 1]) # replaced -moka.set("foo", [4]) # expired -moka.set("baz", "size") +moka.set("foo", [4]) moka.remove("foo") # explicit +for i in range(10): + moka.set(f"overflow-{i}", [i]) # over capacity, so most of these go away with "size" + +# Maintenance is lazy, so ask for it explicitly instead of guessing when it happens +moka.run_pending_tasks() sleep(1.0) -moka.get("anything") # this will trigger eviction for expired +moka.run_pending_tasks() # whatever survived is past its TTL by now: "expired" causes = {c for _, _, c in events} assert causes == {"size", "expired", "replaced", "explicit"}, events