@slango.configs/scripts 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/bin/clean-docker-images.sh +222 -0
- package/package.json +12 -3
- package/CHANGELOG.md +0 -13
- package/lint-staged.config.js +0 -1
package/README.md
CHANGED
|
@@ -13,3 +13,28 @@ Removes all cache artifacts from the current directory and its subdirectories.
|
|
|
13
13
|
## clean-build-artifacts
|
|
14
14
|
|
|
15
15
|
Removes all build artifacts from the current directory and its subdirectories.
|
|
16
|
+
|
|
17
|
+
## clean-docker-images
|
|
18
|
+
|
|
19
|
+
Removes Docker images built from this repo, scoped by the `name` in the repo's `package.json`.
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
clean-docker-images [options]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
-a, --all Remove unused Docker images for this repo name
|
|
31
|
+
-i, --image <image:tag> Remove a specific image by name and tag (scoped)
|
|
32
|
+
-h, --help Show help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Examples:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
clean-docker-images --all
|
|
39
|
+
clean-docker-images --image myimage:1.0.11
|
|
40
|
+
```
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
|
|
3
|
+
# This script removes Docker images from the local machine.
|
|
4
|
+
|
|
5
|
+
color_enabled=false
|
|
6
|
+
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
|
|
7
|
+
color_enabled=true
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
if [ "$color_enabled" = "true" ]; then
|
|
11
|
+
COLOR_RESET="$(printf '\033[0m')"
|
|
12
|
+
COLOR_BOLD="$(printf '\033[1m')"
|
|
13
|
+
COLOR_BLUE="$(printf '\033[34m')"
|
|
14
|
+
COLOR_GREEN="$(printf '\033[32m')"
|
|
15
|
+
COLOR_YELLOW="$(printf '\033[33m')"
|
|
16
|
+
COLOR_RED="$(printf '\033[31m')"
|
|
17
|
+
else
|
|
18
|
+
COLOR_RESET=""
|
|
19
|
+
COLOR_BOLD=""
|
|
20
|
+
COLOR_BLUE=""
|
|
21
|
+
COLOR_GREEN=""
|
|
22
|
+
COLOR_YELLOW=""
|
|
23
|
+
COLOR_RED=""
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
log_step() {
|
|
27
|
+
printf '%s==>%s %s\n' "${COLOR_BLUE}${COLOR_BOLD}" "$COLOR_RESET" "$*"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
log_info() {
|
|
31
|
+
printf '%s[info]%s %s\n' "$COLOR_BLUE" "$COLOR_RESET" "$*"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
log_success() {
|
|
35
|
+
printf '%s[ok]%s %s\n' "$COLOR_GREEN" "$COLOR_RESET" "$*"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
log_warn() {
|
|
39
|
+
printf '%s[warn]%s %s\n' "$COLOR_YELLOW" "$COLOR_RESET" "$*"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
log_error() {
|
|
43
|
+
printf '%s[error]%s %s\n' "$COLOR_RED" "$COLOR_RESET" "$*"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
log_step "Docker image cleanup"
|
|
47
|
+
|
|
48
|
+
# Ensure Docker is available before attempting to prune.
|
|
49
|
+
if ! command -v docker >/dev/null 2>&1; then
|
|
50
|
+
log_warn "Docker CLI not found. Skipping."
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
mode=""
|
|
55
|
+
image_name=""
|
|
56
|
+
|
|
57
|
+
usage() {
|
|
58
|
+
printf '%s\n' "Usage: clean-docker-images --all | --image <image:tag>"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
repo_root() {
|
|
62
|
+
if command -v git >/dev/null 2>&1; then
|
|
63
|
+
git rev-parse --show-toplevel 2>/dev/null || pwd
|
|
64
|
+
else
|
|
65
|
+
pwd
|
|
66
|
+
fi
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
package_name() {
|
|
70
|
+
root="$(repo_root)"
|
|
71
|
+
pkg_file="$root/package.json"
|
|
72
|
+
if [ ! -f "$pkg_file" ]; then
|
|
73
|
+
return 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if command -v node >/dev/null 2>&1; then
|
|
77
|
+
PKG_PATH="$pkg_file" node -p "require(process.env.PKG_PATH).name" 2>/dev/null || true
|
|
78
|
+
else
|
|
79
|
+
awk -F'"' '/"name"[[:space:]]*:/ { print $4; exit }' "$pkg_file"
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
repo_in_scope() {
|
|
84
|
+
repo="${1:-}"
|
|
85
|
+
base="${2:-}"
|
|
86
|
+
repo="${repo%@*}"
|
|
87
|
+
last_segment="${repo##*/}"
|
|
88
|
+
case "$last_segment" in
|
|
89
|
+
*:*)
|
|
90
|
+
repo="${repo%:*}"
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
93
|
+
case "$repo" in
|
|
94
|
+
"$base" | "$base/"* | */"$base" | */"$base/"*)
|
|
95
|
+
return 0
|
|
96
|
+
;;
|
|
97
|
+
esac
|
|
98
|
+
return 1
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
while [ "$#" -gt 0 ]; do
|
|
102
|
+
case "$1" in
|
|
103
|
+
-a|--all)
|
|
104
|
+
mode="all"
|
|
105
|
+
shift
|
|
106
|
+
;;
|
|
107
|
+
-i|--image)
|
|
108
|
+
mode="image"
|
|
109
|
+
image_name="${2:-}"
|
|
110
|
+
shift 2
|
|
111
|
+
;;
|
|
112
|
+
-h|--help)
|
|
113
|
+
usage
|
|
114
|
+
exit 0
|
|
115
|
+
;;
|
|
116
|
+
*)
|
|
117
|
+
echo "Unknown option: $1"
|
|
118
|
+
usage
|
|
119
|
+
exit 1
|
|
120
|
+
;;
|
|
121
|
+
esac
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
if [ -z "$mode" ]; then
|
|
125
|
+
usage
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
repo_name="$(package_name)"
|
|
130
|
+
if [ -z "$repo_name" ]; then
|
|
131
|
+
log_error "Unable to determine package.json name for this repo."
|
|
132
|
+
usage
|
|
133
|
+
exit 1
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
if [ "$mode" = "all" ]; then
|
|
137
|
+
log_info "Scope: $repo_name"
|
|
138
|
+
log_info "Scanning local images..."
|
|
139
|
+
in_use_refs="$(docker ps -a --format '{{.Image}}' | sort -u)"
|
|
140
|
+
images_in_scope="$(docker images --format '{{.Repository}} {{.Tag}}' | while IFS=' ' read -r repo tag; do
|
|
141
|
+
[ -z "$repo" ] && continue
|
|
142
|
+
[ -z "$tag" ] && continue
|
|
143
|
+
[ "$repo" = "<none>" ] && continue
|
|
144
|
+
[ "$tag" = "<none>" ] && continue
|
|
145
|
+
if repo_in_scope "$repo" "$repo_name"; then
|
|
146
|
+
printf '%s:%s\n' "$repo" "$tag"
|
|
147
|
+
fi
|
|
148
|
+
done)"
|
|
149
|
+
|
|
150
|
+
if [ -z "$images_in_scope" ]; then
|
|
151
|
+
log_warn "No images found for repo: $repo_name"
|
|
152
|
+
exit 0
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
removed_count=0
|
|
156
|
+
skipped_count=0
|
|
157
|
+
failed_count=0
|
|
158
|
+
total_count=0
|
|
159
|
+
|
|
160
|
+
while IFS= read -r ref; do
|
|
161
|
+
[ -z "$ref" ] && continue
|
|
162
|
+
total_count=$((total_count + 1))
|
|
163
|
+
if [ -n "$in_use_refs" ] && echo "$in_use_refs" | grep -Fxq "$ref"; then
|
|
164
|
+
skipped_count=$((skipped_count + 1))
|
|
165
|
+
log_warn "In use, skipping: $ref"
|
|
166
|
+
continue
|
|
167
|
+
fi
|
|
168
|
+
remove_output="$(docker rmi "$ref" 2>&1)"
|
|
169
|
+
if [ $? -eq 0 ]; then
|
|
170
|
+
removed_count=$((removed_count + 1))
|
|
171
|
+
log_success "Removed: $ref"
|
|
172
|
+
else
|
|
173
|
+
failed_count=$((failed_count + 1))
|
|
174
|
+
log_error "Failed: $ref"
|
|
175
|
+
if [ -n "$remove_output" ]; then
|
|
176
|
+
printf '%s\n' "$remove_output" | while IFS= read -r line; do
|
|
177
|
+
printf '%s %s%s\n' "$COLOR_RED" "$line" "$COLOR_RESET"
|
|
178
|
+
done
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
done <<EOF
|
|
182
|
+
$images_in_scope
|
|
183
|
+
EOF
|
|
184
|
+
|
|
185
|
+
log_step "Summary"
|
|
186
|
+
log_info "Images in scope: $total_count"
|
|
187
|
+
log_success "Removed: $removed_count"
|
|
188
|
+
log_warn "Skipped (in use): $skipped_count"
|
|
189
|
+
if [ "$failed_count" -gt 0 ]; then
|
|
190
|
+
log_error "Failed: $failed_count"
|
|
191
|
+
else
|
|
192
|
+
log_info "Failed: 0"
|
|
193
|
+
fi
|
|
194
|
+
exit 0
|
|
195
|
+
fi
|
|
196
|
+
|
|
197
|
+
if [ "$mode" = "image" ]; then
|
|
198
|
+
if [ -z "$image_name" ]; then
|
|
199
|
+
log_error "Missing image name."
|
|
200
|
+
usage
|
|
201
|
+
exit 1
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
if ! docker image inspect "$image_name" >/dev/null 2>&1; then
|
|
205
|
+
log_warn "No image found for name: $image_name"
|
|
206
|
+
exit 0
|
|
207
|
+
fi
|
|
208
|
+
|
|
209
|
+
if ! repo_in_scope "$image_name" "$repo_name"; then
|
|
210
|
+
log_error "Image not in scope for repo: $repo_name"
|
|
211
|
+
exit 1
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
log_info "Removing: $image_name"
|
|
215
|
+
docker rmi -f "$image_name"
|
|
216
|
+
|
|
217
|
+
log_success "Removed: $image_name"
|
|
218
|
+
exit 0
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
usage
|
|
222
|
+
exit 1
|
package/package.json
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slango.configs/scripts",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Slango scripts",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/danilupion/slango",
|
|
9
|
+
"directory": "configs/scripts"
|
|
10
|
+
},
|
|
6
11
|
"type": "module",
|
|
12
|
+
"files": [
|
|
13
|
+
"bin"
|
|
14
|
+
],
|
|
7
15
|
"bin": {
|
|
8
16
|
"clean-node-modules": "bin/clean-node-modules.sh",
|
|
9
17
|
"clean-build-artifacts": "bin/clean-build-artifacts.sh",
|
|
10
|
-
"clean-cache-artifacts": "bin/clean-cache-artifacts.sh"
|
|
18
|
+
"clean-cache-artifacts": "bin/clean-cache-artifacts.sh",
|
|
19
|
+
"clean-docker-images": "bin/clean-docker-images.sh"
|
|
11
20
|
},
|
|
12
21
|
"devDependencies": {
|
|
13
|
-
"@slango.configs/lint-staged": "1.1.
|
|
22
|
+
"@slango.configs/lint-staged": "1.1.30"
|
|
14
23
|
},
|
|
15
24
|
"scripts": {}
|
|
16
25
|
}
|
package/CHANGELOG.md
DELETED
package/lint-staged.config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { default } from '@slango.configs/lint-staged/default.js';
|