| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | // Imports
 | 
					
						
							|  |  |  | import * as fs from 'fs'; | 
					
						
							|  |  |  | import * as path from 'path'; | 
					
						
							|  |  |  | import * as shell from 'shelljs'; | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  | import {HIDDEN_DIR_PREFIX} from '../common/constants'; | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | import {GithubPullRequests} from '../common/github-pull-requests'; | 
					
						
							| 
									
										
										
										
											2017-02-27 21:04:43 +02:00
										 |  |  | import {assertNotMissingOrEmpty} from '../common/utils'; | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Classes
 | 
					
						
							|  |  |  | export class BuildCleaner { | 
					
						
							|  |  |  |   // Constructor
 | 
					
						
							| 
									
										
										
										
											2017-02-27 22:40:13 +02:00
										 |  |  |   constructor(protected buildsDir: string, protected repoSlug: string, protected githubToken: string) { | 
					
						
							| 
									
										
										
										
											2017-02-27 21:04:43 +02:00
										 |  |  |     assertNotMissingOrEmpty('buildsDir', buildsDir); | 
					
						
							|  |  |  |     assertNotMissingOrEmpty('repoSlug', repoSlug); | 
					
						
							| 
									
										
										
										
											2017-02-27 22:40:13 +02:00
										 |  |  |     assertNotMissingOrEmpty('githubToken', githubToken); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Methods - Public
 | 
					
						
							|  |  |  |   public cleanUp(): Promise<void> { | 
					
						
							|  |  |  |     return Promise.all([ | 
					
						
							|  |  |  |       this.getExistingBuildNumbers(), | 
					
						
							|  |  |  |       this.getOpenPrNumbers(), | 
					
						
							|  |  |  |     ]).then(([existingBuilds, openPrs]) => this.removeUnnecessaryBuilds(existingBuilds, openPrs)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Methods - Protected
 | 
					
						
							|  |  |  |   protected getExistingBuildNumbers(): Promise<number[]> { | 
					
						
							|  |  |  |     return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |       fs.readdir(this.buildsDir, (err, files) => { | 
					
						
							|  |  |  |         if (err) { | 
					
						
							|  |  |  |           return reject(err); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const buildNumbers = files. | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  |           map(name => name.replace(HIDDEN_DIR_PREFIX, '')).   // Remove the "hidden dir" prefix
 | 
					
						
							|  |  |  |           map(Number).                                        // Convert string to number
 | 
					
						
							|  |  |  |           filter(Boolean);                                    // Ignore NaN (or 0), because they are not builds
 | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         resolve(buildNumbers); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   protected getOpenPrNumbers(): Promise<number[]> { | 
					
						
							| 
									
										
										
										
											2017-02-28 14:17:20 +02:00
										 |  |  |     const githubPullRequests = new GithubPullRequests(this.githubToken, this.repoSlug); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return githubPullRequests. | 
					
						
							|  |  |  |       fetchAll('open'). | 
					
						
							|  |  |  |       then(prs => prs.map(pr => pr.number)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   protected removeDir(dir: string) { | 
					
						
							|  |  |  |     try { | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  |       if (shell.test('-d', dir)) { | 
					
						
							| 
									
										
										
										
											2018-06-08 12:55:15 +03:00
										 |  |  |         shell.chmod('-R', 'a+w', dir); | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  |         shell.rm('-rf', dir); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     } 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(', ')}`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  |     // Try removing public dirs.
 | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     toRemove. | 
					
						
							|  |  |  |       map(num => path.join(this.buildsDir, String(num))). | 
					
						
							|  |  |  |       forEach(dir => this.removeDir(dir)); | 
					
						
							| 
									
										
										
										
											2017-06-25 01:40:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Try removing hidden dirs.
 | 
					
						
							|  |  |  |     toRemove. | 
					
						
							|  |  |  |       map(num => path.join(this.buildsDir, HIDDEN_DIR_PREFIX + String(num))). | 
					
						
							|  |  |  |       forEach(dir => this.removeDir(dir)); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } |