Skip to content

cleanup-stale-resources #6

cleanup-stale-resources

cleanup-stale-resources #6

name: cleanup-stale-resources
permissions:
actions: write
contents: write
on:
schedule:
- cron: "17 3 * * 0"
workflow_dispatch:
inputs:
retention_days:
description: "Delete workflow runs and artifacts older than this many days"
required: false
default: "30"
type: string
keep_releases:
description: "Keep this many newest mcp-server releases"
required: false
default: "10"
type: string
release_tag_prefix:
description: "Only cleanup releases with tags starting with this prefix"
required: false
default: "mcp-server-v"
type: string
dry_run:
description: "List resources that would be deleted without deleting"
required: false
default: false
type: boolean
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Cleanup stale workflow runs
uses: actions/github-script@v7
env:
RETENTION_DAYS: ${{ github.event.inputs.retention_days || '30' }}
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
with:
script: |
const retentionDays = Number(process.env.RETENTION_DAYS);
const dryRun = process.env.DRY_RUN === 'true';
const msPerDay = 24 * 60 * 60 * 1000;
const cutoff = Date.now() - retentionDays * msPerDay;
const runs = await github.paginate(github.rest.actions.listWorkflowRunsForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
status: 'completed'
});
const staleRuns = runs.filter(run => new Date(run.created_at).getTime() < cutoff);
core.info(`Found ${staleRuns.length} stale workflow runs older than ${retentionDays} days.`);
for (const run of staleRuns) {
core.info(`${dryRun ? '[dry-run] ' : ''}Deleting workflow run #${run.id} (${run.name}) created ${run.created_at}`);
if (!dryRun) {
await github.rest.actions.deleteWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: run.id
});
}
}
- name: Cleanup stale artifacts
uses: actions/github-script@v7
env:
RETENTION_DAYS: ${{ github.event.inputs.retention_days || '30' }}
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
with:
script: |
const retentionDays = Number(process.env.RETENTION_DAYS);
const dryRun = process.env.DRY_RUN === 'true';
const msPerDay = 24 * 60 * 60 * 1000;
const cutoff = Date.now() - retentionDays * msPerDay;
const artifacts = await github.paginate(github.rest.actions.listArtifactsForRepo, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
const staleArtifacts = artifacts.filter(artifact => new Date(artifact.created_at).getTime() < cutoff);
core.info(`Found ${staleArtifacts.length} stale artifacts older than ${retentionDays} days.`);
for (const artifact of staleArtifacts) {
core.info(`${dryRun ? '[dry-run] ' : ''}Deleting artifact #${artifact.id} (${artifact.name}) created ${artifact.created_at}`);
if (!dryRun) {
await github.rest.actions.deleteArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id
});
}
}
- name: Cleanup stale releases
uses: actions/github-script@v7
env:
KEEP_RELEASES: ${{ github.event.inputs.keep_releases || '10' }}
RELEASE_TAG_PREFIX: ${{ github.event.inputs.release_tag_prefix || 'mcp-server-v' }}
DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }}
with:
script: |
const keepReleases = Number(process.env.KEEP_RELEASES);
const prefix = process.env.RELEASE_TAG_PREFIX;
const dryRun = process.env.DRY_RUN === 'true';
const releases = await github.paginate(github.rest.repos.listReleases, {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
const matchingReleases = releases
.filter(release => release.tag_name?.startsWith(prefix))
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
const staleReleases = matchingReleases.slice(keepReleases);
core.info(`Found ${staleReleases.length} stale releases for prefix '${prefix}' after keeping ${keepReleases}.`);
for (const release of staleReleases) {
core.info(`${dryRun ? '[dry-run] ' : ''}Deleting release #${release.id} (${release.tag_name})`);
if (!dryRun) {
await github.rest.repos.deleteRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: release.id
});
try {
await github.rest.git.deleteRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: `tags/${release.tag_name}`
});
} catch (error) {
core.warning(`Could not delete tag '${release.tag_name}': ${error.message}`);
}
}
}