Skip to content

Instantly share code, notes, and snippets.

@mbleigh
Last active September 25, 2020 04:26
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mbleigh/5be2e807746cdd9549d0c33260871d21 to your computer and use it in GitHub Desktop.
Save mbleigh/5be2e807746cdd9549d0c33260871d21 to your computer and use it in GitHub Desktop.
Automate the deletion of old Firebase Hosting versions.

Firebase Hosting Version Cleanup

This is a simple utility script for cleaning up Firebase Hosting versions, leaving a specified number of versions remaining. This is primarily done to conserve storage usage, but may have other uses.

USE AT YOUR OWN RISK. NO WARRANTY IS PROVIDED. THIS SCRIPT DOES DELETE STUFF PERMANENTLY

Usage

node cleanupVersions.js <site_name> <versions_to_keep> [commit]

The script will delete all except the specified number of versions to keep. It does so by marking the most recently released versions. This means that if I recently rolled back to a version that was created a very long time ago, that version will be kept before a version that I created more recently but didn't release recently.

Installation / Example

To use this script, you must have a signed-in installation of the Firebase CLI.

git clone https://gist.github.com/5be2e807746cdd9549d0c33260871d21.git firebase-hosting-cleanup-script
cd firebase-hosting-cleanup-script
npm install

# perform a dry run, make sure you're not doing something you'll regret
node cleanupVersions.js my-site-here 50
# do the deletion for real
node cleanupVersions.js my-site-here 50 commit
const requireAuth = require('firebase-tools/lib/requireAuth');
const api = require('firebase-tools/lib/api');
const DELETE_DELAY = 200;
const PAGE_SIZE = 100;
const isDryRun = process.argv[4] !== "commit";
if (!process.argv[2] || !process.argv[3]) {
console.error(`
ERROR: Must supply a site name and number of versions to keep. Usage:
node cleanupVersions.js <site_name> <versions_to_keep> [commit]`);
process.exit(1);
}
const site = process.argv[2];
const toKeep = parseInt(process.argv[3]);
if (toKeep < 2) {
console.error('ERROR: Must keep at least 2 versions.');
process.exit(1);
}
function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
function deleteVersions(versionNames) {
if (!versionNames.length) {
return Promise.resolve();
}
const toDelete = versionNames.pop();
if (isDryRun) {
console.log('[DRY RUN] DELETED version', toDelete);
return deleteVersions(versionNames);
}
return api.request('DELETE', '/v1beta1/' + toDelete, {auth: true, origin: api.hostingApiOrigin}).then(() => {
console.log('DELETED version', toDelete);
return wait(DELETE_DELAY).then(() => {
return deleteVersions(versionNames);
});
}).catch(err => {
console.error(`ERROR: Unable to delete version ${toDelete}:`, err.message);
});
}
requireAuth({}, ['https://www.googleapis.com/auth/cloud-platform']).then(() => {
function getAllReleases(releases, token) {
var releases = releases || [];
return api.request('GET', `/v1beta1/sites/${site}/releases?pageSize=${PAGE_SIZE}&pageToken=${token || ''}`, {
auth: true,
origin: api.hostingApiOrigin,
}).then(result => {
releases = releases.concat(result.body.releases);
if (result.body.releases.length >= PAGE_SIZE && result.body.nextPageToken) {
return getAllReleases(releases, result.body.nextPageToken);
}
return releases;
});
}
let uniqueVersionsFound = 0;
const versionMap = {};
const versionsToKeep = [];
const versionsToDelete = [];
return getAllReleases().then(releases => {
console.log('Total Releases:', releases.length);
if (releases.length <= toKeep) {
console.log('Already under',toKeep,'version limit. Nothing to do.');
process.exit(0);
}
releases.forEach(release => {
if (!release.version || release.version.status === 'DELETED') {
return;
}
const vname = release.version.name;
if (!versionMap[vname]) {
versionMap[vname] = true;
if (versionsToKeep.length >= toKeep) {
versionsToDelete.push(vname)
} else {
versionsToKeep.push(vname);
}
}
});
console.log('Unique Versions:', versionsToKeep.length + versionsToDelete.length);
console.log('Versions to Delete:', versionsToDelete.length);
console.log();
return deleteVersions(versionsToDelete);
});
}).catch(err => {
console.error('ERROR:', err.message);
process.exit(1);
});
{
"dependencies": {
"firebase-tools": "^4.2.0"
},
"engines": {
"node": ">= 6.0.0"
}
}
@mflodin
Copy link

mflodin commented Jan 14, 2019

Is it possible to use the script in a CI environment using the login:ci token, i.e. where it is not possible to login through a web browser?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment