-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
108 lines (93 loc) · 3.16 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
const docker = require('docker-hub-api');
const inquirer = require('inquirer');
const pLimit = require('p-limit');
const semver = require('semver');
const cliProgress = require('cli-progress');
docker.setCacheOptions({ enabled: false });
(async () => {
let username = process.env.DOCKER_HUB_USERNAME;
let password = process.env.DOCKER_HUB_PASSWORD;
if (!username) {
const answer = await inquirer.prompt({ type: 'input', name: 'username', message: 'Docker hub username' });
username = answer.username;
}
if (!password) {
const answer = await inquirer.prompt({ type: 'password', name: 'password', message: 'Docker hub password' });
password = answer.password;
}
await docker.login(username, password);
while (true) {
const answer = await inquirer.prompt(({ type: 'input', name: 'image', message: 'Image' }));
image = answer.image;
if (!image) {
break;
}
let [imageUsername, imageName] = image.split('/');
if (!imageName) {
imageUsername = username;
imageName = image;
}
// Load all tags
let tags = [];
let page = 1;
let shouldContinue = false;
do {
console.log(`Loading page ${page}`);
const newTags = await docker.tags(imageUsername, imageName, {
page,
perPage: 25,
});
shouldContinue = newTags.length > 0;
tags = tags.concat(newTags);
page += 1;
} while (shouldContinue);
if (tags.length === 0) {
console.log("No tags to delete. Done for this image.");
continue;
}
const { keepChoices } = await inquirer.prompt({
type: 'checkbox',
message: 'Keep tags with',
name: 'keepChoices',
choices: [
{ name: 'Valid Semver (eg. 2.3.0)', value: 'semver', checked: true },
{ name: 'Short invalid Semver (eg. 2 or 2.3)', value: 'shortsemver', checked: true },
{ name: 'Latest (eg. branch-latest)', value: 'latest', checked: true },
],
});
const keep = keepChoices.reduce((obj, name) => (obj[name] = true, obj), {});
const tagsToRemove = tags.filter(({ name }) =>
!((!name)
|| (keep.semver && semver.valid(name))
|| (keep.shortsemver && /^\d+(\.\d+|)$/.test(name))
|| (keep.latest && name.includes('latest'))));
if (tagsToRemove.length === 0) {
console.log("No tags to delete. Done for this image.");
continue;
}
const { tagsConfirmedToRemove, confirmed } = await inquirer.prompt([{
type: 'checkbox',
message: 'Remove tags',
name: 'tagsConfirmedToRemove',
choices: tagsToRemove.map(({ name }) => ({ name, checked: true })),
}, {
type: 'confirm',
name: 'confirmed',
message: 'Are you sure ?',
default: false,
}]);
if (!confirmed) {
continue;
}
console.log("Deleting tags");
const progressBar = new cliProgress.SingleBar();
progressBar.start(tagsConfirmedToRemove.length, 0);
const limit = pLimit(4);
await Promise.all(tagsConfirmedToRemove.map((tag) => limit(async () => {
await docker.deleteTag(imageUsername, imageName, tag);
progressBar.increment();
})));
progressBar.stop();
console.log("All tags deleted.");
}
})();