Skip to content

Purge Workflows — Reporting Guide

This guide explains how to access, interpret, and use the detailed reports generated by purge workflows.

Overview

Each purge workflow run generates three types of reports:

  1. Step Summary (Markdown) — Human-readable overview in GitHub Actions UI
  2. Structured Output (JSON) — Machine-readable stats for analysis
  3. Artifact Report (JSON) — Historical record stored for 30 days

Finding Reports

Method 1: GitHub Actions UI

  1. Go to ActionsMaintenance
  2. Click the latest run
  3. Expand the Purge Summary & Report job
  4. Step Summary shows formatted overview
  5. Artifacts section has purge-report-json for download

Method 2: Per-Workflow Reports

For detailed breakdown, check individual maintenance jobs:

  1. Go to ActionsMaintenance
  2. Click any successful run
  3. Expand each job:
    • purge-deployments / Purge old deployments
    • purge-workflow-runs / Purge old workflow runs
    • purge-caches / Purge old caches
  4. Each shows a detailed step summary table

Interpreting Reports

Step Summary (Markdown)

Each purge job displays a formatted table with results:

### 🧹 Workflow Runs Purge (dry run)

**Keep:** `10` most recent per workflow

| Workflow | Total | Deleted |
|----------|-------|---------|
| `ci-node.yml` | 45 | 35 |
| `ci-python.yml` | 20 | 10 |
| `deploy-docker.yml` | 8 | 0 |

> ℹ️ Dry-run mode — no runs were deleted.

Column meanings:

  • Workflow — Workflow filename or environment/cache key
  • Total — Total items found in repository
  • Deleted — Items that were (or would be) deleted

Footer:

  • Dry-run mode → Nothing was actually deleted; this was a preview
  • [N] run(s) deleted → This many items were actually deleted

Structured Output (JSON)

Each purge job outputs stats as JSON. Example from workflow-runs purge:

json
{
  "config": {
    "keep": 10,
    "dry_run": false
  },
  "workflows": [
    {
      "file": "ci-node.yml",
      "name": "CI — Node.js",
      "total": 45,
      "deleted": 35
    }
  ],
  "summary": {
    "total_deleted": 45,
    "total_skipped": 0,
    "total_workflows_processed": 27
  }
}

Key fields:

  • config.keep — Retention threshold used
  • config.dry_run — Was this a dry run?
  • workflows[] — Per-workflow breakdown
  • summary — Aggregated totals

Deployment Report

json
{
  "config": {
    "keep": 10,
    "max_age_days": 30,
    "dry_run": false
  },
  "environments": [
    {
      "name": "production",
      "total": 25,
      "deleted": 5
    }
  ],
  "summary": {
    "total_deleted": 5,
    "total_environments_processed": 2
  }
}

Cache Report

json
{
  "config": {
    "keep": 10,
    "dry_run": false
  },
  "caches": [
    {
      "key": "node-modules-v1",
      "ref": "refs/heads/main",
      "size_bytes": 524288000,
      "last_accessed": "2026-03-17T12:00:00Z"
    }
  ],
  "summary": {
    "total_deleted": 3,
    "total_bytes_freed": 1572864000,
    "total_caches_found": 15
  }
}

Using JSON Reports

Download Artifact

  1. From run page, scroll to Artifacts section
  2. Download purge-report-json.zip
  3. Extract purge_report.json

Parse with jq

Total items deleted across all purge types:

bash
jq '.maintenance_runs[].jobs[] | select(.conclusion == "success") | .name' purge_report.json

Extract cache storage freed:

bash
jq '.maintenance_runs[].jobs[] | select(.name | contains("cache")) | .stats.summary.total_bytes_freed' purge_report.json

Load into Analytics

Use structured output for:

  • Dashboard tracking (storage freed over time)
  • Compliance audits (retention policy enforcement)
  • Cost analysis (storage optimization)

Reading Dry-run Results

When dry-run: true, reports show what would be deleted:

### 🧹 Workflow Runs Purge (dry run)

> ℹ️ Dry-run mode — no runs were deleted.

The table still shows:

  • Total — items found
  • Deleted — items that would be deleted (if dry-run were false)

Never deletes on dry-run:

  • Use dry-run to preview before execution
  • Check results carefully
  • Adjust keep threshold if needed
  • Run again with dry-run: false to execute

Common Questions

Q: How do I know what was actually deleted?

A: When dry-run: false, the step summary shows:

> Deleted **45** run(s) across all workflows.

Individual item logs appear earlier in the step output:

[log] Deleted run 23213245940
[log] Deleted run 23213245941

Q: Can I export deletion history?

A: Yes! The purge-report-json artifact persists for 30 days. Download after each run to build a history:

bash
# Collect reports monthly
for month in jan feb mar; do
  gh run download <run-id> -n purge-report-json -D reports/$month/
done

Q: What counts toward the keep threshold?

Workflow runs: Newest-first (by creation date) Deployments: Newest-first (by creation date), then age-filtered Caches: Most-recently-used-first (by last access time)

Q: Why weren't items deleted?

Possible reasons:

  1. dry-run: true → was a preview
  2. Items within retention limit (e.g., only 5 runs but keep: 10)
  3. Deployments: within max-age-days (too recent)
  4. Filters too restrictive (e.g., status: failure but no failed runs)

Check step summary for "Within retention limit" messages.


Monitoring & Alerts

Set Up Regular Reporting

Schedule purge orchestrator weekly with dry-run:

yaml
on:
  schedule:
    - cron: '0 3 * * 0'  # Weekly Sunday 3 AM UTC

jobs:
  purge-preview:
    uses: ./.github/workflows/purge-all-repos.yml
    with:
      keep: 10
      dry-run: true  # Always preview first

Review Reports

  1. Each week, check the run summary
  2. Note trends (increasing storage, more deletions)
  3. Adjust keep threshold if needed
  4. When satisfied, manually trigger with dry-run: false

Track Storage Freed

From cache reports, sum total_bytes_freed:

bash
jq '[.maintenance_runs[].jobs[] | select(.name | contains("cache"))
     | .stats.summary.total_bytes_freed] | add' purge_report.json

Examples

Example 1: Dry-run Review

Run: Purge All Repos with keep: 5, dry-run: true

Report shows:

  • Workflow Runs: 150 total, 130 would be deleted
  • Deployments: 30 total, 15 would be deleted
  • Caches: 20 total, 10 would be deleted

Decision: Threshold seems reasonable. Next step: run with dry-run: false

Example 2: Storage Optimization

Problem: Repository storage is high

Action: Lower keep threshold from 20 → 5

Report shows (after execution):

  • Previously: 2 runs/deployment/cache retained
  • Now: ~80 items deleted, ~5 GB freed

Benefit: Ongoing monthly savings if run on schedule

Example 3: Compliance Audit

Requirement: Prove 90-day deployment retention for production

Report artifact shows:

  • max-age-days: 90 enforced
  • Only deployments >90 days deleted
  • Deletion logs timestamped in artifacts

Proof: JSON report + step summary uploaded to audit trail


See Also