删除 CF Pages 部署
一个处理部署过多的 Python 脚本
当你尝试删除一个拥有超过约 100 次部署的 Pages 项目时(每次构建都算作一次部署,例如你更新了博客中的一篇文章),你可能会遇到以下错误:Your project has too many deployments to be deleted, follow this guide to delete them: https://cfl.re/3CXesln

于是我让大肥鱼(Deepseek)帮我写一个 Python 脚本,自动删除部署,这样我之后就可以删除该项目。cloudflare-bulk-delete 这个仓库已经坏了,因为 Pages API 每页查询的记录上限是 25 条,而该工具每次发送 100 条记录的查询,导致 HTTP 400 错误。
python
1#!/usr/bin/env python3
2"""Bulk delete all Cloudflare Pages deployments in a project."""
3
4import os
5import sys
6import requests
7
8# Config — set these via environment variables or edit inline
9ACCOUNT_ID = os.environ.get("CLOUDFLARE_ACCOUNT_ID", "your_account_id")
10TOKEN = os.environ.get("CLOUDFLARE_API_TOKEN", "cfut_kfcCRAZYthursday")
11PROJECT = os.environ.get("CLOUDFLARE_PROJECT", "hugo")
12
13BASE = f"https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/pages/projects/{PROJECT}/deployments"
14HEADERS = {"Authorization": f"Bearer {TOKEN}"}
15
16
17def fetch_all_deployment_ids():
18 """Fetch all deployment IDs across all pages."""
19 ids = []
20 page = 1
21 while True:
22 resp = requests.get(f"{BASE}?page={page}", headers=HEADERS).json()
23 if not resp["success"]:
24 print(f"Error fetching page {page}: {resp['errors']}", file=sys.stderr)
25 sys.exit(1)
26
27 ids.extend(d["id"] for d in resp["result"])
28 total_pages = resp["result_info"]["total_pages"]
29 print(f" Page {page}/{total_pages} — collected {len(ids)} total")
30
31 if page >= total_pages:
32 break
33 page += 1
34
35 return ids
36
37
38def delete_deployment(dep_id):
39 """Delete a single deployment. Returns (ok, message)."""
40 r = requests.delete(f"{BASE}/{dep_id}", headers=HEADERS)
41 data = r.json()
42 if data.get("success"):
43 return True, "OK"
44 else:
45 err = data.get("errors", [{}])[0].get("message", "unknown error")
46 return False, err
47
48
49def main():
50 print(f"=== Fetching all deployments for project '{PROJECT}' ===")
51 ids = fetch_all_deployment_ids()
52 print(f"\n=== Deleting {len(ids)} deployments ===")
53
54 ok = 0
55 skip = 0
56 for i, dep_id in enumerate(ids, 1):
57 success, msg = delete_deployment(dep_id)
58 if success:
59 ok += 1
60 print(f" [{i}/{len(ids)}] OK {dep_id}")
61 else:
62 skip += 1
63 print(f" [{i}/{len(ids)}] SKIP ({msg}) {dep_id}")
64
65 print(f"\n=== Done! Deleted {ok}, skipped {skip}, total {len(ids)} ===")
66
67
68if __name__ == "__main__":
69 main()