Skip to content

Instantly share code, notes, and snippets.

@mbleigh mbleigh/README.md
Last active Feb 24, 2019

Embed
What would you like to do?
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"
}
}
@whollacsek

This comment has been minimized.

Copy link

whollacsek commented Aug 27, 2018

@mbleigh could make the script work with npx? Thanks :)

package.json

{
  "name": "cleanupVersions",
  "version": "1.0.0",
  "bin": "./cleanupVersions.js",
  "dependencies": {
    "firebase-tools": "^4.2.0"
  },
  "engines": {
    "node": ">= 6.0.0"
  }
}

And add #!/usr/bin/env node to the script file.

@lucafaggianelli

This comment has been minimized.

Copy link

lucafaggianelli commented Jan 3, 2019

Great script! thanks @mbleigh

Just note that i got an error running the script as it seems that api.hostingApiOrigin is undefined. Looking at firebase-tools code, I tried with no luck this:

export FIREBASE_HOSTING_API_URL=https://firebasehosting.googleapis.com

I brutally fixed with:

origin: api.hostingApiOrigin || 'https://firebasehosting.googleapis.com'
@mflodin

This comment has been minimized.

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
You can’t perform that action at this time.