// Imports import * as fs from 'fs'; import * as path from 'path'; import * as shell from 'shelljs'; import {GithubPullRequests} from '../common/github-pull-requests'; // Classes export class BuildCleaner { // Constructor constructor(protected buildsDir: string, protected repoSlug: string, protected githubToken?: string) { if (!buildsDir) { throw new Error('Missing required parameter \'buildsDir\'!'); } else if (!repoSlug) { throw new Error('Missing required parameter \'repoSlug\'!'); } } // Methods - Public public cleanUp(): Promise { return Promise.all([ this.getExistingBuildNumbers(), this.getOpenPrNumbers(), ]).then(([existingBuilds, openPrs]) => this.removeUnnecessaryBuilds(existingBuilds, openPrs)); } // Methods - Protected protected getExistingBuildNumbers(): Promise { return new Promise((resolve, reject) => { fs.readdir(this.buildsDir, (err, files) => { if (err) { return reject(err); } const buildNumbers = files. map(Number). // Convert string to number filter(Boolean); // Ignore NaN (or 0), because they are not builds resolve(buildNumbers); }); }); } protected getOpenPrNumbers(): Promise { const githubPullRequests = new GithubPullRequests(this.repoSlug, this.githubToken); return githubPullRequests. fetchAll('open'). then(prs => prs.map(pr => pr.number)); } protected removeDir(dir: string) { try { // Undocumented signature (see https://github.com/shelljs/shelljs/pull/663). (shell as any).chmod('-R', 'a+w', dir); shell.rm('-rf', dir); } catch (err) { console.error(`ERROR: Unable to remove '${dir}' due to:`, err); } } protected removeUnnecessaryBuilds(existingBuildNumbers: number[], openPrNumbers: number[]) { const toRemove = existingBuildNumbers.filter(num => !openPrNumbers.includes(num)); console.log(`Existing builds: ${existingBuildNumbers.length}`); console.log(`Open pull requests: ${openPrNumbers.length}`); console.log(`Removing ${toRemove.length} build(s): ${toRemove.join(', ')}`); toRemove. map(num => path.join(this.buildsDir, String(num))). forEach(dir => this.removeDir(dir)); } }