-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7cacb19
commit d3b50b4
Showing
3 changed files
with
157 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import fetch from 'node-fetch' | ||
import { backOff } from 'exponential-backoff' | ||
|
||
const CF_API_TOKEN = process.env.CF_API_TOKEN | ||
const CF_ACCOUNT_ID = process.env.CF_ACCOUNT_ID | ||
const CF_PAGES_PROJECT_NAME = process.env.CF_PAGES_PROJECT_NAME | ||
const CF_DELETE_ALIASED_DEPLOYMENTS = process.env.CF_DELETE_ALIASED_DEPLOYMENTS | ||
|
||
const MAX_ATTEMPTS = 5 | ||
|
||
const sleep = (ms) => | ||
new Promise((resolve) => { | ||
setTimeout(resolve, ms) | ||
}) | ||
|
||
const headers = { | ||
Authorization: `Bearer ${CF_API_TOKEN}`, | ||
} | ||
|
||
/** Get the cononical deployment (the live deployment) */ | ||
async function getProductionDeploymentId() { | ||
const response = await fetch( | ||
`https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}`, | ||
{ | ||
method: 'GET', | ||
headers, | ||
} | ||
) | ||
const body = await response.json() | ||
if (!body.success) { | ||
throw new Error(body.errors[0].message) | ||
} | ||
const prodDeploymentId = body.result.canonical_deployment.id | ||
if (!prodDeploymentId) { | ||
throw new Error('Unable to fetch production deployment ID') | ||
} | ||
return prodDeploymentId | ||
} | ||
|
||
async function deleteDeployment(id) { | ||
let params = '' | ||
if (CF_DELETE_ALIASED_DEPLOYMENTS === 'true') { | ||
params = '?force=true' // Forces deletion of aliased deployments | ||
} | ||
const response = await fetch( | ||
`https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}/deployments/${id}${params}`, | ||
{ | ||
method: 'DELETE', | ||
headers, | ||
} | ||
) | ||
const body = await response.json() | ||
if (!body.success) { | ||
throw new Error(body.errors[0].message) | ||
} | ||
console.log(`Deleted deployment ${id} for project ${CF_PAGES_PROJECT_NAME}`) | ||
} | ||
|
||
async function listDeploymentsPerPage(page) { | ||
const response = await fetch( | ||
`https://api.cloudflare.com/client/v4/accounts/${CF_ACCOUNT_ID}/pages/projects/${CF_PAGES_PROJECT_NAME}/deployments?per_page=10&page=${page}`, | ||
{ | ||
method: 'GET', | ||
headers, | ||
} | ||
) | ||
const body = await response.json() | ||
if (!body.success) { | ||
throw new Error(`Could not fetch deployments for ${CF_PAGES_PROJECT_NAME}`) | ||
} | ||
return body.result | ||
} | ||
|
||
async function listAllDeployments() { | ||
let page = 1 | ||
const deploymentIds = [] | ||
|
||
while (true) { | ||
let result | ||
try { | ||
result = await backOff(() => listDeploymentsPerPage(page), { | ||
numOfAttempts: 5, | ||
startingDelay: 1000, // 1s, 2s, 4s, 8s, 16s | ||
retry: (_, attempt) => { | ||
console.warn( | ||
`Failed to list deployments on page ${page}... retrying (${attempt}/${MAX_ATTEMPTS})` | ||
) | ||
return true | ||
}, | ||
}) | ||
} catch (err) { | ||
console.warn(`Failed to list deployments on page ${page}.`) | ||
console.warn(err) | ||
|
||
process.exit(1) | ||
} | ||
|
||
for (const deployment of result) { | ||
deploymentIds.push(deployment.id) | ||
} | ||
|
||
if (result.length) { | ||
page = page + 1 | ||
await sleep(500) | ||
} else { | ||
return deploymentIds | ||
} | ||
} | ||
} | ||
|
||
async function main() { | ||
if (!CF_API_TOKEN) { | ||
throw new Error('Please set CF_API_TOKEN as an env variable to your API Token') | ||
} | ||
|
||
if (!CF_ACCOUNT_ID) { | ||
throw new Error('Please set CF_ACCOUNT_ID as an env variable to your Account ID') | ||
} | ||
|
||
if (!CF_PAGES_PROJECT_NAME) { | ||
throw new Error( | ||
'Please set CF_PAGES_PROJECT_NAME as an env variable to your Pages project name' | ||
) | ||
} | ||
|
||
const productionDeploymentId = await getProductionDeploymentId() | ||
console.log( | ||
`Found live production deployment to exclude from deletion: ${productionDeploymentId}` | ||
) | ||
|
||
console.log('Listing all deployments, this may take a while...') | ||
const deploymentIds = await listAllDeployments() | ||
|
||
for (const id of deploymentIds) { | ||
if (id === productionDeploymentId) { | ||
console.log(`Skipping production deployment: ${id}`) | ||
} else { | ||
try { | ||
await deleteDeployment(id) | ||
} catch (error) { | ||
console.log(error) | ||
} | ||
} | ||
} | ||
} | ||
|
||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters