Skip to content

Commit 045a7b5

Browse files
committed
Add cleanup logic
1 parent c29a96a commit 045a7b5

File tree

7 files changed

+227
-10
lines changed

7 files changed

+227
-10
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Cleanup Stale PR Resources
2+
3+
permissions:
4+
contents: read
5+
pull-requests: read
6+
7+
on:
8+
schedule:
9+
# Run daily at 2 AM UTC
10+
- cron: '0 2 * * *'
11+
workflow_dispatch: # Allow manual triggering
12+
13+
jobs:
14+
cleanup-stale:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 15
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- uses: actions/setup-node@v4
22+
with:
23+
node-version: 24
24+
cache: "npm"
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Cleanup stale PR resources
30+
run: |
31+
echo "=== Checking for stale PR resources ==="
32+
33+
# Get current timestamp (in seconds)
34+
CURRENT_TIME=$(date +%s)
35+
STALE_THRESHOLD=$((24 * 60 * 60)) # 24 hours in seconds
36+
37+
# List all workers and filter for PR test workers
38+
WORKERS=$(npx wrangler workers list --json 2>/dev/null || echo "[]")
39+
40+
echo "$WORKERS" | jq -r '.[] | select(.name | test("^sandbox-e2e-test-worker-pr-[0-9]+$")) | .name' | while read -r WORKER_NAME; do
41+
if [ -z "$WORKER_NAME" ]; then
42+
continue
43+
fi
44+
45+
# Extract PR number from worker name
46+
PR_NUMBER=$(echo "$WORKER_NAME" | sed 's/sandbox-e2e-test-worker-pr-//')
47+
48+
echo ""
49+
echo "Checking worker: $WORKER_NAME (PR #$PR_NUMBER)"
50+
51+
# Check if PR exists and get its last update time
52+
PR_INFO=$(gh pr view "$PR_NUMBER" --json state,updatedAt 2>/dev/null || echo "")
53+
54+
if [ -z "$PR_INFO" ]; then
55+
echo " ⚠️ PR #$PR_NUMBER not found - will clean up"
56+
SHOULD_CLEANUP=true
57+
else
58+
PR_STATE=$(echo "$PR_INFO" | jq -r '.state')
59+
PR_UPDATED=$(echo "$PR_INFO" | jq -r '.updatedAt')
60+
PR_UPDATED_SECONDS=$(date -d "$PR_UPDATED" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$PR_UPDATED" +%s 2>/dev/null)
61+
62+
TIME_SINCE_UPDATE=$((CURRENT_TIME - PR_UPDATED_SECONDS))
63+
HOURS_SINCE_UPDATE=$((TIME_SINCE_UPDATE / 3600))
64+
65+
echo " State: $PR_STATE"
66+
echo " Last updated: $HOURS_SINCE_UPDATE hours ago"
67+
68+
if [ "$PR_STATE" = "CLOSED" ] || [ "$PR_STATE" = "MERGED" ]; then
69+
echo " ✓ PR is closed/merged - will clean up"
70+
SHOULD_CLEANUP=true
71+
elif [ "$TIME_SINCE_UPDATE" -gt "$STALE_THRESHOLD" ]; then
72+
echo " ✓ PR is stale (>24h inactive) - will clean up"
73+
SHOULD_CLEANUP=true
74+
else
75+
echo " ✗ PR is active - skipping"
76+
SHOULD_CLEANUP=false
77+
fi
78+
fi
79+
80+
# Cleanup if needed
81+
if [ "$SHOULD_CLEANUP" = true ]; then
82+
echo " Deleting worker: $WORKER_NAME"
83+
npx wrangler delete --name "$WORKER_NAME" 2>/dev/null || echo " Failed to delete worker"
84+
85+
# Also delete associated container
86+
CONTAINER_ID=$(npx wrangler containers list --json 2>/dev/null | jq -r ".[] | select(.name==\"$WORKER_NAME\") | .id")
87+
if [ -n "$CONTAINER_ID" ]; then
88+
echo " Deleting container: $CONTAINER_ID"
89+
npx wrangler containers delete "$CONTAINER_ID" 2>/dev/null || echo " Failed to delete container"
90+
fi
91+
92+
echo " ✅ Cleanup complete"
93+
fi
94+
done
95+
96+
echo ""
97+
echo "=== Stale resource cleanup complete ==="
98+
working-directory: tests/e2e/test-worker
99+
env:
100+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
101+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
102+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/cleanup.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Cleanup PR Resources
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
pull_request:
8+
types: [closed]
9+
10+
jobs:
11+
cleanup:
12+
runs-on: ubuntu-latest
13+
timeout-minutes: 5
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: 24
21+
cache: "npm"
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Set worker name
27+
id: worker-name
28+
run: |
29+
echo "worker_name=sandbox-e2e-test-worker-pr-${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
30+
31+
- name: Delete test worker
32+
continue-on-error: true
33+
run: |
34+
npx wrangler delete --name ${{ steps.worker-name.outputs.worker_name }} || echo "Worker already deleted or doesn't exist"
35+
working-directory: tests/e2e/test-worker
36+
env:
37+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
38+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
39+
40+
- name: Delete test container
41+
continue-on-error: true
42+
run: |
43+
# Get container ID for this worker and delete it
44+
CONTAINER_ID=$(npx wrangler containers list --json | jq -r '.[] | select(.name=="${{ steps.worker-name.outputs.worker_name }}") | .id')
45+
if [ -n "$CONTAINER_ID" ]; then
46+
echo "Deleting container: $CONTAINER_ID"
47+
npx wrangler containers delete "$CONTAINER_ID" || echo "Failed to delete container"
48+
else
49+
echo "No container found for worker ${{ steps.worker-name.outputs.worker_name }}"
50+
fi
51+
working-directory: tests/e2e/test-worker
52+
env:
53+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
54+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

.github/workflows/pullrequest.yml

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,6 @@ jobs:
8484
- name: Build packages
8585
run: npm run build
8686

87-
# Build Docker image for test worker (needed before deployment)
88-
- name: Build test worker Docker image
89-
run: npm run docker:local -w @cloudflare/sandbox
90-
9187
# Set environment name (pr-X for PRs, branch name for pushes)
9288
- name: Set environment name
9389
id: env-name
@@ -100,6 +96,16 @@ jobs:
10096
echo "worker_name=sandbox-e2e-test-worker-${{ github.ref_name }}" >> $GITHUB_OUTPUT
10197
fi
10298
99+
# Generate unique wrangler config for this PR/branch
100+
- name: Generate wrangler config
101+
run: |
102+
cd tests/e2e/test-worker
103+
./generate-config.sh ${{ steps.env-name.outputs.worker_name }}
104+
105+
# Build Docker image for test worker (needed before deployment)
106+
- name: Build test worker Docker image
107+
run: npm run docker:local -w @cloudflare/sandbox
108+
103109
# Deploy test worker using official Cloudflare action
104110
- name: Deploy test worker
105111
id: deploy
@@ -123,12 +129,22 @@ jobs:
123129
TEST_WORKER_URL: ${{ steps.get-url.outputs.worker_url }}
124130
CI: true
125131

126-
# Cleanup: Delete test worker deployment (only for PR environments)
132+
# Cleanup: Delete test worker and container (only for PR environments)
127133
- name: Cleanup test deployment
128134
if: always() && github.event_name == 'pull_request'
129135
continue-on-error: true
130136
run: |
137+
# Delete worker (this also removes the worker's binding to the container)
131138
npx wrangler delete --name ${{ steps.env-name.outputs.worker_name }} || echo "Worker already deleted or doesn't exist"
139+
140+
# Get container ID for this worker and delete it
141+
CONTAINER_ID=$(npx wrangler containers list --json | jq -r '.[] | select(.name=="${{ steps.env-name.outputs.worker_name }}") | .id')
142+
if [ -n "$CONTAINER_ID" ]; then
143+
echo "Deleting container: $CONTAINER_ID"
144+
npx wrangler containers delete "$CONTAINER_ID" || echo "Failed to delete container"
145+
else
146+
echo "No container found for worker ${{ steps.env-name.outputs.worker_name }}"
147+
fi
132148
working-directory: tests/e2e/test-worker
133149
env:
134150
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

.github/workflows/release.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,20 @@ jobs:
8787
- name: Build packages
8888
run: npm run build
8989

90-
- name: Build test worker Docker image
91-
run: npm run docker:local -w @cloudflare/sandbox
92-
9390
- name: Set worker name
9491
id: worker-name
9592
run: |
9693
echo "worker_name=sandbox-e2e-test-worker-release-${{ github.run_number }}" >> $GITHUB_OUTPUT
9794
95+
# Generate unique wrangler config for this release
96+
- name: Generate wrangler config
97+
run: |
98+
cd tests/e2e/test-worker
99+
./generate-config.sh ${{ steps.worker-name.outputs.worker_name }}
100+
101+
- name: Build test worker Docker image
102+
run: npm run docker:local -w @cloudflare/sandbox
103+
98104
- name: Deploy test worker
99105
uses: cloudflare/wrangler-action@v3
100106
with:
@@ -118,7 +124,17 @@ jobs:
118124
if: always()
119125
continue-on-error: true
120126
run: |
127+
# Delete worker (this also removes the worker's binding to the container)
121128
npx wrangler delete --name ${{ steps.worker-name.outputs.worker_name }} || echo "Worker already deleted or doesn't exist"
129+
130+
# Get container ID for this worker and delete it
131+
CONTAINER_ID=$(npx wrangler containers list --json | jq -r '.[] | select(.name=="${{ steps.worker-name.outputs.worker_name }}") | .id')
132+
if [ -n "$CONTAINER_ID" ]; then
133+
echo "Deleting container: $CONTAINER_ID"
134+
npx wrangler containers delete "$CONTAINER_ID" || echo "Failed to delete container"
135+
else
136+
echo "No container found for worker ${{ steps.worker-name.outputs.worker_name }}"
137+
fi
122138
working-directory: tests/e2e/test-worker
123139
env:
124140
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ dist
132132
.wrangler
133133
.dev.vars
134134

135+
# Generated wrangler config (use wrangler.template.jsonc as source of truth)
136+
tests/e2e/test-worker/wrangler.jsonc
137+
135138
.DS_Store
136139

137140
# Turborepo cache
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Generate wrangler.jsonc from template
5+
# Usage: ./generate-config.sh <worker-name> [container-name]
6+
#
7+
# If container-name is not provided, it defaults to worker-name
8+
9+
WORKER_NAME="${1:-sandbox-e2e-test-worker-local}"
10+
CONTAINER_NAME="${2:-$WORKER_NAME}"
11+
12+
if [ -z "$WORKER_NAME" ]; then
13+
echo "Error: WORKER_NAME is required"
14+
echo "Usage: ./generate-config.sh <worker-name> [container-name]"
15+
exit 1
16+
fi
17+
18+
echo "Generating wrangler.jsonc..."
19+
echo " Worker name: $WORKER_NAME"
20+
echo " Container name: $CONTAINER_NAME"
21+
22+
# Read template and replace placeholders
23+
sed "s/{{WORKER_NAME}}/$WORKER_NAME/g; s/{{CONTAINER_NAME}}/$CONTAINER_NAME/g" \
24+
wrangler.template.jsonc > wrangler.jsonc
25+
26+
echo "✅ Generated wrangler.jsonc"

tests/e2e/test-worker/wrangler.jsonc renamed to tests/e2e/test-worker/wrangler.template.jsonc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "sandbox-e2e-test-worker",
2+
"name": "{{WORKER_NAME}}",
33
"main": "index.ts",
44
"compatibility_date": "2025-05-06",
55
"compatibility_flags": ["nodejs_compat"],
@@ -13,7 +13,7 @@
1313
{
1414
"class_name": "Sandbox",
1515
"image": "./Dockerfile",
16-
"name": "sandbox"
16+
"name": "{{CONTAINER_NAME}}"
1717
}
1818
],
1919

0 commit comments

Comments
 (0)