Skip to content

chore(monorepo): update actions/checkout action to v5 - autoclosed #155

chore(monorepo): update actions/checkout action to v5 - autoclosed

chore(monorepo): update actions/checkout action to v5 - autoclosed #155

name: 🧼 Deploy Preview Environments Cleanup
on:
pull_request:
types:
- closed
workflow_dispatch:
inputs:
pr_number:
description: "Pull Request number to cleanup"
required: true
type: string
force_cleanup:
description: "Force cleanup even if resources are missing"
required: false
type: boolean
default: false
concurrency:
group: cleanup-pr-${{ github.event.number || github.event.inputs.pr_number }}
cancel-in-progress: false
permissions:
contents: read
packages: write
deployments: write
issues: write
pull-requests: write
jobs:
cleanup:
name: Cleanup Preview Resources
runs-on: ubuntu-latest
environment:
name: fly-preview-${{ github.event.number || github.event.inputs.pr_number }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # Needed for consistency with other workflows
- name: Add cleanup pending comment
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '🧹 Starting cleanup of preview environment resources...'
});
- name: Prepare Repository Variables
id: vars
uses: ./.github/actions/prepare-repo-variables
with:
pr_number: ${{ github.event.inputs.pr_number || github.event.number }}
- name: Install Flyctl
uses: superfly/flyctl-actions/setup-flyctl@master
- name: 🗑️ Destroy PR app in Fly.io
id: destroy_app
continue-on-error: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_cleanup == 'true'}}
shell: bash
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN_APP_REVIEW }}
FLY_REGION: ams
FLY_ORG: personal
run: |
set -euo pipefail
APP="${{ steps.vars.outputs.FLY_APP_NAME }}"
echo "Destroying Fly app: ${APP}"
# capture output + exit code of destroy command
destroy_output=$(mktemp)
if flyctl apps destroy "${APP}" -y 2>&1 | tee "${destroy_output}"; then
echo "::notice::Fly app ${APP} destroyed."
else
if grep -qiE "not found|could not resolve" "${destroy_output}"; then
echo "::notice::Fly app ${APP} not found – skipping."
elif [[ "${{ github.event_name }}" != "workflow_dispatch" || "${{ github.event.inputs.force_cleanup }}" != "true" ]]; then
echo "::warning::Failed to destroy Fly app ${APP}."
exit 1
fi
fi
- name: 🗑 Delete deployment environment
id: delete_environment
continue-on-error: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_cleanup == 'true' }}
uses: strumwolf/delete-deployment-environment@v3
with:
token: ${{ secrets.DELETE_DEPLOYMENT_PAT_TOKEN }}
environment: fly-preview-${{ github.event.number || github.event.inputs.pr_number }}
# ----------------------------------------------------------------------------
# GHCR package cleanup (new approach: use actions/delete-package-versions)
# ----------------------------------------------------------------------------
- name: 🔍 Locate package version IDs for this PR
id: find_package_versions
continue-on-error: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_cleanup == 'true' }}
env:
GH_TOKEN: ${{ secrets.DELETE_DEPLOYMENT_PAT_TOKEN }}
PKG_NAME: ${{ steps.vars.outputs.PACKAGE_NAME_PREVIEW }}
PR_NUMBER: ${{ steps.vars.outputs.PR_NUMBER }}
OWNER: ${{ github.repository_owner }}
shell: bash
run: |
set -euo pipefail
HARD_CODED_PATH="/users/suddenlygiovanni/packages/container/suddenlygiovanni.dev%2Fsuddenlygiovanni.dev-preview/versions?per_page=100"
echo "Searching for container versions of '${PKG_NAME}' tagged for PR #${PR_NUMBER} …"
mapfile -t IDS < <(
gh api -H "Accept: application/vnd.github+json" \
"${HARD_CODED_PATH}" \
--paginate \
--jq ".[] |
select(
.metadata.container.tags[]? |
test(\"^pr-${PR_NUMBER}(-[0-9a-f]+)?$\")
) |
.id" | sort -u
)
if [[ ${#IDS[@]} -eq 0 ]]; then
echo "No versions found – nothing to delete."
echo "version_ids=" >> "$GITHUB_OUTPUT"
exit 0
fi
CSV=$(
IFS=,
echo "${IDS[*]}"
)
echo "Found ${#IDS[@]} version(s): ${CSV}"
echo "version_ids=${CSV}" >> "$GITHUB_OUTPUT"
- name: 🗑 Delete GHCR images for this PR only
id: delete_images
if: steps.find_package_versions.outputs.version_ids != ''
continue-on-error: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.force_cleanup == 'true' }}
uses: actions/delete-package-versions@v5
with:
token: ${{ secrets.DELETE_DEPLOYMENT_PAT_TOKEN }}
owner: ${{ github.repository_owner }}
package-type: container
package-name: ${{ steps.vars.outputs.PACKAGE_NAME_PREVIEW }}
package-version-ids: ${{ steps.find_package_versions.outputs.version_ids }}
- name: 📢 Post cleanup notification
if: always()
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.vars.outputs.PR_NUMBER }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr_number = process.env.PR_NUMBER;
const result = "${{ job.status }}";
const emoji = result === "success" ? "✅" : "❌";
// Create detailed status report
let body = `${emoji} Preview environment cleanup ${result.toLowerCase()}.\n\n`;
// Add resource cleanup details
body += "### Cleanup Status:\n";
body += `- Fly App: ${{ steps.destroy_app.outcome || 'skipped' }}\n`;
body += `- GitHub Environment: ${{ steps.delete_environment.outcome || 'skipped' }}\n`;
body += `- Container Images: ${{ steps.delete_images.outcome || 'skipped' }}\n\n`;
if (result !== "success") {
body += "Some resources may require manual cleanup. Check the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.\n";
}
// Post to the PR if it exists
if (pr_number) {
github.rest.issues.createComment({
issue_number: pr_number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
}
// Also create a step summary
core.summary
.addHeading('Preview Environment Cleanup')
.addRaw(body)
.write();