appydave-tools 0.33.0 â 0.34.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/bin/dam +78 -30
- data/lib/appydave/tools/dam/s3_scanner.rb +11 -15
- data/lib/appydave/tools/version.rb +1 -1
- data/package.json +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0822e53f40e94e9d3c113babd747f20676c51706e0fcb8c7d4f73ab30dba1264'
|
|
4
|
+
data.tar.gz: fe3f9dc1576f199f0194e298e60330f56542ed235a65808c6edaacc6079a822e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5ec28829f3743f5fae51f54d7a387c2c2e22a79674d94c7e9af8230f0c4f0e32bbb4cfeb7e668077a68c19cad310397d81144fb78d915641636894fef8af4e24
|
|
7
|
+
data.tar.gz: cad3a37461ad7158b6e44711dd3e8b3e2b34ddc70ae95b038c9e4794c072fd7326f8a9d7ee0c19e1c0ffbc6ec2f66e2a26cd3589f8cd01a0ac7f991c60824aa3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [0.33.0](https://github.com/appydave/appydave-tools/compare/v0.32.5...v0.33.0) (2025-11-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* add orphaned S3 folder detection in s3-scan command - separates matched projects from orphaned folders with file count and size info for easier cleanup identification ([3aa03aa](https://github.com/appydave/appydave-tools/commit/3aa03aab5e57ca55015d226b39fcb4f3203d4ca4))
|
|
7
|
+
|
|
1
8
|
## [0.32.5](https://github.com/appydave/appydave-tools/compare/v0.32.4...v0.32.5) (2025-11-21)
|
|
2
9
|
|
|
3
10
|
|
data/bin/dam
CHANGED
|
@@ -1125,7 +1125,7 @@ class VatCLI
|
|
|
1125
1125
|
exit 1
|
|
1126
1126
|
end
|
|
1127
1127
|
|
|
1128
|
-
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/
|
|
1128
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
1129
1129
|
def scan_single_brand_s3(brand_arg)
|
|
1130
1130
|
puts "đ Scanning S3 for #{brand_arg}..."
|
|
1131
1131
|
puts ''
|
|
@@ -1133,11 +1133,30 @@ class VatCLI
|
|
|
1133
1133
|
brand_key = brand_arg
|
|
1134
1134
|
scanner = Appydave::Tools::Dam::S3Scanner.new(brand_key)
|
|
1135
1135
|
|
|
1136
|
-
#
|
|
1137
|
-
|
|
1136
|
+
# Get brand info for S3 path
|
|
1137
|
+
Appydave::Tools::Configuration::Config.configure
|
|
1138
|
+
brand_info = Appydave::Tools::Configuration::Config.brands.get_brand(brand_key)
|
|
1139
|
+
bucket = brand_info.aws.s3_bucket
|
|
1140
|
+
prefix = brand_info.aws.s3_prefix
|
|
1141
|
+
region = brand_info.aws.region
|
|
1142
|
+
|
|
1143
|
+
# Spinner characters for progress
|
|
1144
|
+
spinner_chars = ['â ', 'â ', 'â š', 'â ¸', 'â ŧ', 'â ´', 'â Ļ', 'â §', 'â ', 'â ']
|
|
1145
|
+
spinner_index = 0
|
|
1146
|
+
|
|
1147
|
+
print "đ Scanning s3://#{bucket}/#{prefix}\n"
|
|
1148
|
+
print ' Scanning projects... '
|
|
1149
|
+
|
|
1150
|
+
# Scan all projects with progress callback
|
|
1151
|
+
results = scanner.scan_all_projects(show_progress: false) do |current, total|
|
|
1152
|
+
print "\r Scanning projects... #{spinner_chars[spinner_index]} (#{current}/#{total})"
|
|
1153
|
+
spinner_index = (spinner_index + 1) % spinner_chars.length
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
print "\r Scanning projects... â (#{results.size} found)\n"
|
|
1157
|
+
puts ''
|
|
1138
1158
|
|
|
1139
1159
|
if results.empty?
|
|
1140
|
-
puts ''
|
|
1141
1160
|
puts "â ī¸ No projects found in S3 for #{brand_key}"
|
|
1142
1161
|
puts ' This may indicate:'
|
|
1143
1162
|
puts ' - No files uploaded to S3 yet'
|
|
@@ -1147,12 +1166,10 @@ class VatCLI
|
|
|
1147
1166
|
end
|
|
1148
1167
|
|
|
1149
1168
|
# Load existing manifest
|
|
1150
|
-
Appydave::Tools::Configuration::Config.configure
|
|
1151
1169
|
brand_path = Appydave::Tools::Dam::Config.brand_path(brand_key)
|
|
1152
1170
|
manifest_path = File.join(brand_path, 'projects.json')
|
|
1153
1171
|
|
|
1154
1172
|
unless File.exist?(manifest_path)
|
|
1155
|
-
puts ''
|
|
1156
1173
|
puts "â Manifest not found: #{manifest_path}"
|
|
1157
1174
|
puts " Run: dam manifest #{brand_key}"
|
|
1158
1175
|
puts " Then retry: dam s3-scan #{brand_key}"
|
|
@@ -1163,8 +1180,8 @@ class VatCLI
|
|
|
1163
1180
|
|
|
1164
1181
|
# Identify matched and orphaned S3 projects
|
|
1165
1182
|
local_project_ids = manifest[:projects].map { |p| p[:id] }
|
|
1166
|
-
|
|
1167
|
-
|
|
1183
|
+
matched_projects = results.slice(*local_project_ids)
|
|
1184
|
+
orphaned_projects = results.reject { |project_id, _| local_project_ids.include?(project_id) }
|
|
1168
1185
|
|
|
1169
1186
|
# Merge S3 scan data into manifest for matched projects
|
|
1170
1187
|
updated_count = 0
|
|
@@ -1184,37 +1201,68 @@ class VatCLI
|
|
|
1184
1201
|
# Write updated manifest
|
|
1185
1202
|
File.write(manifest_path, JSON.pretty_generate(manifest))
|
|
1186
1203
|
|
|
1204
|
+
# Display table
|
|
1205
|
+
display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
|
|
1206
|
+
|
|
1207
|
+
# Summary
|
|
1187
1208
|
total_manifest_projects = manifest[:projects].size
|
|
1209
|
+
missing_count = total_manifest_projects - matched_projects.size
|
|
1188
1210
|
|
|
1189
1211
|
puts ''
|
|
1190
|
-
puts
|
|
1191
|
-
puts "
|
|
1192
|
-
puts "
|
|
1193
|
-
puts "
|
|
1212
|
+
puts 'âšī¸ Summary:'
|
|
1213
|
+
puts " âĸ Updated #{updated_count} projects in manifest"
|
|
1214
|
+
puts " âĸ #{missing_count} local project(s) not yet uploaded to S3" if missing_count.positive?
|
|
1215
|
+
puts " âĸ Manifest: #{manifest_path}"
|
|
1216
|
+
puts ''
|
|
1217
|
+
end
|
|
1218
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
|
1194
1219
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1220
|
+
# Display S3 scan results in table format
|
|
1221
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Style/FormatStringToken
|
|
1222
|
+
def display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
|
|
1223
|
+
puts 'â
S3 Projects Report'
|
|
1224
|
+
puts ''
|
|
1225
|
+
puts 'PROJECT FILES SIZE STATUS LAST MODIFIED'
|
|
1226
|
+
puts '-' * 80
|
|
1227
|
+
|
|
1228
|
+
# Display matched projects first (sorted alphabetically)
|
|
1229
|
+
matched_projects.sort.each do |project_id, data|
|
|
1230
|
+
files = data[:file_count].to_s.rjust(5)
|
|
1231
|
+
size = format_bytes(data[:total_bytes]).rjust(10)
|
|
1232
|
+
status = 'â'
|
|
1233
|
+
modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
|
|
1234
|
+
|
|
1235
|
+
puts format('%-26s %5s %10s %s %s', project_id, files, size, status, modified)
|
|
1206
1236
|
end
|
|
1207
1237
|
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1238
|
+
# Display orphaned projects (sorted alphabetically)
|
|
1239
|
+
return if orphaned_projects.empty?
|
|
1240
|
+
|
|
1241
|
+
puts '-' * 80
|
|
1242
|
+
orphaned_projects.sort.each do |project_id, data|
|
|
1243
|
+
files = data[:file_count].to_s.rjust(5)
|
|
1244
|
+
size = format_bytes(data[:total_bytes]).rjust(10)
|
|
1245
|
+
status = 'â'
|
|
1246
|
+
modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
|
|
1247
|
+
|
|
1248
|
+
puts format('%-26s %5s %10s %s %s', project_id, files, size, status, modified)
|
|
1212
1249
|
end
|
|
1250
|
+
|
|
1213
1251
|
puts ''
|
|
1252
|
+
folder_word = orphaned_projects.size > 1 ? 'folders' : 'folder'
|
|
1253
|
+
puts "â ī¸ #{orphaned_projects.size} orphaned #{folder_word} found (no local project)"
|
|
1254
|
+
|
|
1255
|
+
orphaned_projects.sort.each do |project_id, _data|
|
|
1256
|
+
# Build AWS Console URL
|
|
1257
|
+
project_prefix = "#{prefix}#{project_id}/"
|
|
1258
|
+
console_url = "https://#{region}.console.aws.amazon.com/s3/buckets/#{bucket}?prefix=#{project_prefix}®ion=#{region}"
|
|
1259
|
+
puts " â #{project_id}"
|
|
1260
|
+
puts " #{console_url}"
|
|
1261
|
+
end
|
|
1214
1262
|
end
|
|
1215
|
-
# rubocop:enable Metrics/MethodLength
|
|
1263
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Style/FormatStringToken
|
|
1216
1264
|
|
|
1217
|
-
# rubocop:disable Metrics/MethodLength
|
|
1265
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
|
1218
1266
|
def scan_all_brands_s3
|
|
1219
1267
|
Appydave::Tools::Configuration::Config.configure
|
|
1220
1268
|
brands_config = Appydave::Tools::Configuration::Config.brands
|
|
@@ -1255,7 +1303,7 @@ class VatCLI
|
|
|
1255
1303
|
puts ''
|
|
1256
1304
|
puts "Total brands scanned: #{successful.size}/#{results.size}"
|
|
1257
1305
|
end
|
|
1258
|
-
# rubocop:enable Metrics/MethodLength, Metrics/
|
|
1306
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
|
1259
1307
|
|
|
1260
1308
|
# Format bytes in human-readable format
|
|
1261
1309
|
# rubocop:disable Style/FormatStringToken
|
|
@@ -17,12 +17,13 @@ module Appydave
|
|
|
17
17
|
|
|
18
18
|
# Scan S3 for a specific project
|
|
19
19
|
# @param project_id [String] Project ID (e.g., "b65-guy-monroe-marketing-plan")
|
|
20
|
+
# @param show_progress [Boolean] Whether to show progress output (default: true)
|
|
20
21
|
# @return [Hash] S3 file data with :file_count, :total_bytes, :last_modified
|
|
21
|
-
def scan_project(project_id)
|
|
22
|
+
def scan_project(project_id, show_progress: true)
|
|
22
23
|
bucket = @brand_info.aws.s3_bucket
|
|
23
24
|
prefix = File.join(@brand_info.aws.s3_prefix, project_id, '')
|
|
24
25
|
|
|
25
|
-
puts " đ Scanning #{project_id}..."
|
|
26
|
+
puts " đ Scanning #{project_id}..." if show_progress
|
|
26
27
|
|
|
27
28
|
files = list_s3_objects(bucket, prefix)
|
|
28
29
|
|
|
@@ -50,28 +51,23 @@ module Appydave
|
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
# Scan all projects in brand's S3 bucket
|
|
54
|
+
# @param show_progress [Boolean] Whether to show detailed progress (default: true)
|
|
53
55
|
# @return [Hash] Map of project_id => scan result
|
|
54
|
-
def scan_all_projects
|
|
56
|
+
def scan_all_projects(show_progress: true, &progress_callback)
|
|
55
57
|
bucket = @brand_info.aws.s3_bucket
|
|
56
58
|
prefix = @brand_info.aws.s3_prefix
|
|
57
59
|
|
|
58
|
-
puts "đ Scanning all projects in S3: s3://#{bucket}/#{prefix}"
|
|
59
|
-
puts ''
|
|
60
|
-
|
|
61
60
|
# List all "directories" (prefixes) under brand prefix
|
|
62
61
|
project_prefixes = list_s3_prefixes(bucket, prefix)
|
|
63
62
|
|
|
64
|
-
if project_prefixes.empty?
|
|
65
|
-
puts ' đ No projects found in S3'
|
|
66
|
-
return {}
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
puts " Found #{project_prefixes.size} projects in S3"
|
|
70
|
-
puts ''
|
|
63
|
+
return {} if project_prefixes.empty?
|
|
71
64
|
|
|
72
65
|
results = {}
|
|
73
|
-
project_prefixes.
|
|
74
|
-
|
|
66
|
+
project_prefixes.each_with_index do |project_id, index|
|
|
67
|
+
# Call progress callback if provided (for spinner)
|
|
68
|
+
progress_callback&.call(index + 1, project_prefixes.size)
|
|
69
|
+
|
|
70
|
+
results[project_id] = scan_project(project_id, show_progress: show_progress)
|
|
75
71
|
end
|
|
76
72
|
|
|
77
73
|
results
|
data/package.json
CHANGED