Clean workflow run logs based on configuration with advanced features like retry logic, circuit breaker, rate limiting, and workflow filtering.
- 🎯 Workflow Filtering: Filter deletions by specific workflow names
- 🔄 Automatic Retries: Exponential backoff retry logic for transient failures
- 🛡️ Circuit Breaker: Prevents cascading failures with automatic recovery
- ⏱️ Rate Limiting: Built-in API rate limit handling with retry-after support
- 📊 Detailed Metrics: Comprehensive API metrics exported as action outputs
- 🧪 Dry Run Mode: Test your configuration without actually deleting runs
- 📈 High Test Coverage: Over 95% code coverage with unit and integration tests
- ⚡ Modern Tooling: Built with TypeScript, Biome.js, and Vitest
Please be aware of the GitHub's API rate limit.
| Parameter | Description | Default | Required |
|---|---|---|---|
token |
GitHub token for API access | github.token |
No |
owner |
Repository owner | github.repository_owner |
No |
repo |
Repository name | Extracted from github.repository |
No |
runs_older_than |
Days old for a workflow run to be considered old | 7 |
No |
runs_to_keep |
Number of latest workflow runs to keep per workflow | 0 |
No |
workflow_names |
Comma-separated list of workflow names to filter (empty = all workflows) | "" |
No |
dry_run |
Preview deletions without actually deleting | false |
No |
| Output | Description |
|---|---|
total-runs-found |
Total number of workflow runs found |
runs-deleted |
Number of runs successfully deleted |
runs-failed |
Number of runs that failed to delete |
total-api-requests |
Total number of API requests made |
successful-requests |
Number of successful API requests |
failed-requests |
Number of failed API requests |
retry-attempts |
Number of retry attempts |
rate-limit-hits |
Number of times rate limit was hit |
circuit-breaker-trips |
Number of times circuit breaker opened |
This workflow needs write permissions on your actions. Be sure to add the correct permissions as follows:
permissions:
actions: writejobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
token: ${{ github.token }} # optional
owner: ${{ github.repository_owner }} # optional
repo: ${{ github.repository }} # optional
runs_older_than: 7 # optional
runs_to_keep: 0 # optionalClean only specific workflows by name:
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
workflow_names: "CI, Tests, Deploy" # Only clean these workflows
runs_older_than: 14
runs_to_keep: 5Preview what would be deleted without actually deleting:
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
dry_run: true # Preview mode
runs_older_than: 7Use the exported metrics for monitoring or alerting:
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- name: Clean workflow runs
id: clean
uses: igorjs/gh-actions-clean-workflow@v7
with:
runs_older_than: 7
runs_to_keep: 10
- name: Display metrics
run: |
echo "Total runs found: ${{ steps.clean.outputs.total-runs-found }}"
echo "Runs deleted: ${{ steps.clean.outputs.runs-deleted }}"
echo "Runs failed: ${{ steps.clean.outputs.runs-failed }}"
echo "API requests: ${{ steps.clean.outputs.total-api-requests }}"
echo "Rate limit hits: ${{ steps.clean.outputs.rate-limit-hits }}"name: Clean Workflow Logs
on:
workflow_dispatch:
inputs:
runs_older_than:
description: "The amount of days old to delete"
default: "7"
required: false
runs_to_keep:
description: "The amount of latest workflows runs to keep"
default: "0"
required: false
workflow_names:
description: "Comma-separated workflow names (empty = all)"
default: ""
required: false
dry_run:
description: "Dry run mode (preview only)"
type: boolean
default: false
required: false
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
runs_older_than: ${{ github.event.inputs.runs_older_than }}
runs_to_keep: ${{ github.event.inputs.runs_to_keep }}
workflow_names: ${{ github.event.inputs.workflow_names }}
dry_run: ${{ github.event.inputs.dry_run }}name: Clean Workflow Logs
on:
schedule:
- cron: "0 0 * * 1" # Runs "At 00:00 on Monday." (see https://crontab.guru)
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
runs_older_than: "14"
runs_to_keep: "20"name: Clean Workflow Logs
on:
schedule:
- cron: "0 0 * * 1" # Runs "At 00:00 on Monday." (see https://crontab.guru)
workflow_dispatch:
inputs:
runs_older_than:
description: "The amount of days old to delete"
default: "7"
required: false
dry_run:
description: "Dry run mode"
type: boolean
default: false
required: false
env:
SCHEDULED_RUNS_OLDER_THAN: "7"
SCHEDULED_RUNS_TO_KEEP: "20"
jobs:
clean-logs:
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- uses: igorjs/gh-actions-clean-workflow@v7
with:
runs_older_than: ${{ github.event.inputs.runs_older_than || env.SCHEDULED_RUNS_OLDER_THAN }}
runs_to_keep: ${{ github.event.inputs.runs_to_keep || env.SCHEDULED_RUNS_TO_KEEP }}
dry_run: ${{ github.event.inputs.dry_run || false }}The action automatically retries failed API requests with exponential backoff:
- Maximum 3 retry attempts
- Exponential backoff: 1s, 2s, 4s
- Retries on: 5xx errors, rate limits (429), network failures
- No retries on: 4xx client errors (except 429)
Prevents cascading failures and API abuse:
- Opens after 5 consecutive failures
- Automatically recovers after 60 seconds
- Transitions through CLOSED → OPEN → HALF_OPEN states
- Metrics tracked via
circuit-breaker-tripsoutput
Built-in rate limit handling:
- Respects GitHub API rate limits
- Honors
Retry-Afterheaders - 100ms delay between deletions
- Metrics tracked via
rate-limit-hitsoutput
Filter deletions to specific workflows:
- Comma-separated workflow names
- Case-sensitive matching
- Supports alphanumeric, spaces, dashes, and underscores
- Example:
workflow_names: "CI, Deploy, Tests"
- Node.js >= 24.0.0
- npm >= 10.0.0
npm installnpm run check # Run Biome linting and formatting checks
npm run check:fix # Auto-fix Biome issues
npm run test # Run tests
npm run test:coverage # Run tests with coverage report
npm run build # Build the action
npm run all # Run all checks, tests, and buildThe project has comprehensive test coverage (98.93%):
- 113 tests across 4 test suites
- Unit tests for all components
- Integration tests for API interactions
- Circuit breaker state transition tests
- Retry logic and error handling tests
v7 is a major version with breaking changes and new features:
Breaking Changes:
- Minimum Node.js version increased to 24.0.0
- Migrated from ESLint + Prettier to Biome.js
- Logger class converted to individual functions (internal)
New Features:
- Workflow filtering via
workflow_namesparameter - Dry run mode via
dry_runparameter - 9 new metric outputs for monitoring
- Circuit breaker pattern for fault tolerance
- Automatic retry with exponential backoff
- Rate limit handling with retry-after support
Migration:
# Old (v6)
- uses: igorjs/gh-actions-clean-workflow@v6
with:
runs_older_than: 7
# New (v7)
- uses: igorjs/gh-actions-clean-workflow@v7
with:
runs_older_than: 7
# Optional new features:
workflow_names: "CI, Deploy" # Filter by workflows
dry_run: false # Dry run modeMIT
Contributions are welcome! Please feel free to submit a Pull Request.
If you encounter any issues or have questions, please open an issue.