appydave-tools 0.76.5 → 0.76.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0531bc72c6c4aeac9830f72f552a4d683775d7efc61ee483069d882cdbbbf5af
4
- data.tar.gz: 1c8e032ddc4e8dfc4c196452465abea40958107d2d68c5e4063c1ec2c36a3a9d
3
+ metadata.gz: f4172ac86ad4f32c89534b2129ffed582137abc47e21fe1fb2e1d18c5a56608e
4
+ data.tar.gz: ed067098e65634fce56abf446313a7f58657dbc7fc45499915cb34d6a9ae5afe
5
5
  SHA512:
6
- metadata.gz: 1787f781bdf758fae98c3388cce0437aca330a3161937f5c214651885c80e05598682e64afc3adea1e2ffd3b2f70d09287a9acca12c8fada89077b7d48791a39
7
- data.tar.gz: 6cadabed0aa0f0be9d993b4dbda2c304c9a34f717fcc7b86b8cc059777e7cb0a57a494ddc2c3e5432fd4d4d85990330a6d401aa75c89bb7b0be5f5207c68d12b
6
+ metadata.gz: 79f3caf203405a2cf7337da3129595433515c04e6b4f9f1203b70b5ef89e07caa07ac212d6e9bb85244185f5d5d3b8e20f175e01e7587fb1fe1920630dadf8e1
7
+ data.tar.gz: e42dfc787b1331d7fdfbd32c731f13e03f946bf5e2fa9d89f948f9cb59dc393a80e054b075b650d51d72eb7070f846f0253beef5e011cf3c632b8181b5b30f7f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [0.76.5](https://github.com/appydave/appydave-tools/compare/v0.76.4...v0.76.5) (2026-03-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * extract LocalSyncStatus module from VatCLI; add spec ([0672855](https://github.com/appydave/appydave-tools/commit/0672855a25ebcbb2df3f5eea6208f910aed74124))
7
+ * remove redundant rubocop disable directives in LocalSyncStatus ([9050795](https://github.com/appydave/appydave-tools/commit/905079573caf7555771da02b2d9c6ebfc34d1c95))
8
+ * replace format_bytes with FileHelper.format_size; remove duplicate method from VatCLI ([3cd362f](https://github.com/appydave/appydave-tools/commit/3cd362f79342578ddb7a750b9b404851cf4d1eb4))
9
+ * restore youtube_automation_config require removed by micro-cleanup; fix spec brand dir setup ([a5779a7](https://github.com/appydave/appydave-tools/commit/a5779a7b5dab1697b2a21ca3bbece9c0bff340c2))
10
+
1
11
  ## [0.76.4](https://github.com/appydave/appydave-tools/compare/v0.76.3...v0.76.4) (2026-03-19)
2
12
 
3
13
 
data/bin/dam CHANGED
@@ -1325,9 +1325,9 @@ class VatCLI
1325
1325
  brand_arg = args[0]
1326
1326
 
1327
1327
  if all_brands
1328
- scan_all_brands_s3
1328
+ Appydave::Tools::Dam::S3ScanCommand.new.scan_all
1329
1329
  elsif brand_arg
1330
- scan_single_brand_s3(brand_arg)
1330
+ Appydave::Tools::Dam::S3ScanCommand.new.scan_single(brand_arg)
1331
1331
  else
1332
1332
  puts 'Usage: dam s3-scan <brand> [--all]'
1333
1333
  puts ''
@@ -1343,188 +1343,6 @@ class VatCLI
1343
1343
  puts e.backtrace.first(5).join("\n") if ENV['DEBUG']
1344
1344
  exit 1
1345
1345
  end
1346
-
1347
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
1348
- def scan_single_brand_s3(brand_arg)
1349
- puts "🔄 Scanning S3 for #{brand_arg}..."
1350
- puts ''
1351
-
1352
- brand_key = brand_arg
1353
- scanner = Appydave::Tools::Dam::S3Scanner.new(brand_key)
1354
-
1355
- # Get brand info for S3 path
1356
- Appydave::Tools::Configuration::Config.configure
1357
- brand_info = Appydave::Tools::Configuration::Config.brands.get_brand(brand_key)
1358
- bucket = brand_info.aws.s3_bucket
1359
- prefix = brand_info.aws.s3_prefix
1360
- region = brand_info.aws.region
1361
-
1362
- # Spinner characters for progress
1363
- spinner_chars = ['⠋', '⠙', 'â š', 'â ¸', 'â ŧ', 'â ´', 'â Ļ', 'â §', '⠇', '⠏']
1364
- spinner_index = 0
1365
-
1366
- print "🔍 Scanning s3://#{bucket}/#{prefix}\n"
1367
- print ' Scanning projects... '
1368
-
1369
- # Scan all projects with progress callback
1370
- results = scanner.scan_all_projects(show_progress: false) do |current, total|
1371
- print "\r Scanning projects... #{spinner_chars[spinner_index]} (#{current}/#{total})"
1372
- spinner_index = (spinner_index + 1) % spinner_chars.length
1373
- end
1374
-
1375
- print "\r Scanning projects... ✓ (#{results.size} found)\n"
1376
- puts ''
1377
-
1378
- if results.empty?
1379
- puts "âš ī¸ No projects found in S3 for #{brand_key}"
1380
- puts ' This may indicate:'
1381
- puts ' - No files uploaded to S3 yet'
1382
- puts ' - S3 bucket or prefix misconfigured'
1383
- puts ' - AWS credentials issue'
1384
- return
1385
- end
1386
-
1387
- # Load existing manifest
1388
- brand_path = Appydave::Tools::Dam::Config.brand_path(brand_key)
1389
- manifest_path = File.join(brand_path, 'projects.json')
1390
-
1391
- unless File.exist?(manifest_path)
1392
- puts "❌ Manifest not found: #{manifest_path}"
1393
- puts " Run: dam manifest #{brand_key}"
1394
- puts " Then retry: dam s3-scan #{brand_key}"
1395
- exit 1
1396
- end
1397
-
1398
- manifest = JSON.parse(File.read(manifest_path), symbolize_names: true)
1399
-
1400
- # Identify matched and orphaned S3 projects
1401
- local_project_ids = manifest[:projects].map { |p| p[:id] }
1402
- matched_projects = results.slice(*local_project_ids)
1403
- orphaned_projects = results.reject { |project_id, _| local_project_ids.include?(project_id) }
1404
-
1405
- # Merge S3 scan data into manifest for matched projects
1406
- updated_count = 0
1407
- manifest[:projects].each do |project|
1408
- project_id = project[:id]
1409
- s3_data = results[project_id]
1410
- next unless s3_data
1411
-
1412
- project[:storage][:s3] = s3_data
1413
- updated_count += 1
1414
- end
1415
-
1416
- # Update timestamp and note
1417
- manifest[:config][:last_updated] = Time.now.utc.iso8601
1418
- manifest[:config][:note] = 'Auto-generated manifest with S3 scan data. Regenerate with: dam s3-scan'
1419
-
1420
- # Write updated manifest
1421
- File.write(manifest_path, JSON.pretty_generate(manifest))
1422
-
1423
- # Add local sync status to matched projects
1424
- Appydave::Tools::Dam::LocalSyncStatus.enrich!(matched_projects, brand_key)
1425
-
1426
- # Display table
1427
- display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
1428
-
1429
- # Summary
1430
- total_manifest_projects = manifest[:projects].size
1431
- missing_count = total_manifest_projects - matched_projects.size
1432
-
1433
- puts ''
1434
- puts 'â„šī¸ Summary:'
1435
- puts " â€ĸ Updated #{updated_count} projects in manifest"
1436
- puts " â€ĸ #{missing_count} local project(s) not yet uploaded to S3" if missing_count.positive?
1437
- puts " â€ĸ Manifest: #{manifest_path}"
1438
- puts ''
1439
- end
1440
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
1441
-
1442
- # Display S3 scan results in table format
1443
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Style/FormatStringToken
1444
- def display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
1445
- puts '✅ S3 Projects Report'
1446
- puts ''
1447
- puts 'PROJECT FILES SIZE LOCAL S3 MODIFIED'
1448
- puts '-' * 92
1449
-
1450
- # Display matched projects first (sorted alphabetically)
1451
- matched_projects.sort.each do |project_id, data|
1452
- files = data[:file_count].to_s.rjust(5)
1453
- size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
1454
- local_status = Appydave::Tools::Dam::LocalSyncStatus.format(data[:local_status], data[:local_file_count], data[:file_count])
1455
- modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
1456
-
1457
- puts format('%-36s %5s %10s %-9s %s', project_id, files, size, local_status, modified)
1458
- end
1459
-
1460
- # Display orphaned projects (sorted alphabetically)
1461
- return if orphaned_projects.empty?
1462
-
1463
- puts '-' * 92
1464
- orphaned_projects.sort.each do |project_id, data|
1465
- files = data[:file_count].to_s.rjust(5)
1466
- size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
1467
- local_status = 'N/A'
1468
- modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
1469
-
1470
- puts format('%-36s %5s %10s %-9s %s', project_id, files, size, local_status, modified)
1471
- end
1472
-
1473
- puts ''
1474
- folder_word = orphaned_projects.size > 1 ? 'folders' : 'folder'
1475
- puts "âš ī¸ #{orphaned_projects.size} orphaned #{folder_word} found (no local project)"
1476
-
1477
- orphaned_projects.sort.each do |project_id, _data|
1478
- # Build AWS Console URL
1479
- project_prefix = "#{prefix}#{project_id}/"
1480
- console_url = "https://#{region}.console.aws.amazon.com/s3/buckets/#{bucket}?prefix=#{project_prefix}&region=#{region}"
1481
- puts " → #{project_id}"
1482
- puts " #{console_url}"
1483
- end
1484
- end
1485
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Style/FormatStringToken
1486
-
1487
- # rubocop:disable Metrics/MethodLength
1488
- def scan_all_brands_s3
1489
- Appydave::Tools::Configuration::Config.configure
1490
- brands_config = Appydave::Tools::Configuration::Config.brands
1491
-
1492
- results = []
1493
- brands_config.brands.each do |brand_info|
1494
- brand_key = brand_info.key
1495
- puts ''
1496
- puts '=' * 60
1497
-
1498
- begin
1499
- scan_single_brand_s3(brand_key)
1500
- results << { brand: brand_key, success: true }
1501
- rescue StandardError => e
1502
- puts "❌ Failed to scan #{brand_key}: #{e.message}"
1503
- results << { brand: brand_key, success: false, error: e.message }
1504
- end
1505
- end
1506
-
1507
- puts ''
1508
- puts '=' * 60
1509
- puts '📋 Summary - S3 Scans:'
1510
- puts ''
1511
-
1512
- successful, failed = results.partition { |r| r[:success] }
1513
-
1514
- successful.each do |result|
1515
- brand_display = result[:brand].ljust(15)
1516
- puts "✅ #{brand_display} Scanned successfully"
1517
- end
1518
-
1519
- failed.each do |result|
1520
- brand_display = result[:brand].ljust(15)
1521
- puts "❌ #{brand_display} #{result[:error]}"
1522
- end
1523
-
1524
- puts ''
1525
- puts "Total brands scanned: #{successful.size}/#{results.size}"
1526
- end
1527
- # rubocop:enable Metrics/MethodLength
1528
1346
  end
1529
1347
 
1530
1348
  # Run CLI
@@ -9,8 +9,8 @@
9
9
 
10
10
  ## Pending
11
11
  - [x] extract-format-bytes — Replaced 4 callers (plan said 3; orphaned-projects loop in display_s3_scan_table was a 4th). format_bytes deleted. rubocop 0 offenses. Commit: 3cd362f.
12
- - [~] extract-local-sync-status — Extract `add_local_sync_status!` + `format_local_status` → new `LocalSyncStatus` module; add spec; update callers in bin/dam
13
- - [ ] extract-s3-scan-command — Extract `scan_single_brand_s3` + `scan_all_brands_s3` + `display_s3_scan_table` → new `S3ScanCommand` class; add spec; **depends on extract-local-sync-status completing first**
12
+ - [x] extract-local-sync-status — LocalSyncStatus module created, 7 specs added (838 total), both methods gone from VatCLI. Side-fix: restored youtube_automation_config require incorrectly removed in prior commit. v0.76.5.
13
+ - [~] extract-s3-scan-command — Extract `scan_single_brand_s3` + `scan_all_brands_s3` + `display_s3_scan_table` → new `S3ScanCommand` class; add spec; **depends on extract-local-sync-status completing first**
14
14
  - [ ] extract-s3-arg-parser — Extract `parse_s3_args` + `valid_brand?` + `parse_share_args` + `show_share_usage_and_exit` + `parse_discover_args` → new `S3ArgParser` class; add spec
15
15
 
16
16
  ## In Progress
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appydave
4
+ module Tools
5
+ module Dam
6
+ # Encapsulates S3 scan logic: single-brand and all-brands scanning
7
+ class S3ScanCommand
8
+ # Scan a single brand's S3 bucket and update its manifest
9
+ def scan_single(brand_key)
10
+ puts "🔄 Scanning S3 for #{brand_key}..."
11
+ puts ''
12
+
13
+ scanner = Appydave::Tools::Dam::S3Scanner.new(brand_key)
14
+
15
+ # Get brand info for S3 path
16
+ Appydave::Tools::Configuration::Config.configure
17
+ brand_info = Appydave::Tools::Configuration::Config.brands.get_brand(brand_key)
18
+ bucket = brand_info.aws.s3_bucket
19
+ prefix = brand_info.aws.s3_prefix
20
+ region = brand_info.aws.region
21
+
22
+ # Spinner characters for progress
23
+ spinner_chars = ['⠋', '⠙', 'â š', 'â ¸', 'â ŧ', 'â ´', 'â Ļ', 'â §', '⠇', '⠏']
24
+ spinner_index = 0
25
+
26
+ print "🔍 Scanning s3://#{bucket}/#{prefix}\n"
27
+ print ' Scanning projects... '
28
+
29
+ # Scan all projects with progress callback
30
+ results = scanner.scan_all_projects(show_progress: false) do |current, total|
31
+ print "\r Scanning projects... #{spinner_chars[spinner_index]} (#{current}/#{total})"
32
+ spinner_index = (spinner_index + 1) % spinner_chars.length
33
+ end
34
+
35
+ print "\r Scanning projects... ✓ (#{results.size} found)\n"
36
+ puts ''
37
+
38
+ if results.empty?
39
+ puts "âš ī¸ No projects found in S3 for #{brand_key}"
40
+ puts ' This may indicate:'
41
+ puts ' - No files uploaded to S3 yet'
42
+ puts ' - S3 bucket or prefix misconfigured'
43
+ puts ' - AWS credentials issue'
44
+ return
45
+ end
46
+
47
+ # Load existing manifest
48
+ brand_path = Appydave::Tools::Dam::Config.brand_path(brand_key)
49
+ manifest_path = File.join(brand_path, 'projects.json')
50
+
51
+ unless File.exist?(manifest_path)
52
+ puts "❌ Manifest not found: #{manifest_path}"
53
+ puts " Run: dam manifest #{brand_key}"
54
+ puts " Then retry: dam s3-scan #{brand_key}"
55
+ exit 1
56
+ end
57
+
58
+ manifest = JSON.parse(File.read(manifest_path), symbolize_names: true)
59
+
60
+ # Identify matched and orphaned S3 projects
61
+ local_project_ids = manifest[:projects].map { |p| p[:id] }
62
+ matched_projects = results.slice(*local_project_ids)
63
+ orphaned_projects = results.reject { |project_id, _| local_project_ids.include?(project_id) }
64
+
65
+ # Merge S3 scan data into manifest for matched projects
66
+ updated_count = 0
67
+ manifest[:projects].each do |project|
68
+ project_id = project[:id]
69
+ s3_data = results[project_id]
70
+ next unless s3_data
71
+
72
+ project[:storage][:s3] = s3_data
73
+ updated_count += 1
74
+ end
75
+
76
+ # Update timestamp and note
77
+ manifest[:config][:last_updated] = Time.now.utc.iso8601
78
+ manifest[:config][:note] = 'Auto-generated manifest with S3 scan data. Regenerate with: dam s3-scan'
79
+
80
+ # Write updated manifest
81
+ File.write(manifest_path, JSON.pretty_generate(manifest))
82
+
83
+ # Add local sync status to matched projects
84
+ Appydave::Tools::Dam::LocalSyncStatus.enrich!(matched_projects, brand_key)
85
+
86
+ # Display table
87
+ display_table(matched_projects, orphaned_projects, bucket, prefix, region)
88
+
89
+ # Summary
90
+ total_manifest_projects = manifest[:projects].size
91
+ missing_count = total_manifest_projects - matched_projects.size
92
+
93
+ puts ''
94
+ puts 'â„šī¸ Summary:'
95
+ puts " â€ĸ Updated #{updated_count} projects in manifest"
96
+ puts " â€ĸ #{missing_count} local project(s) not yet uploaded to S3" if missing_count.positive?
97
+ puts " â€ĸ Manifest: #{manifest_path}"
98
+ puts ''
99
+ end
100
+
101
+ # Scan all brands' S3 buckets
102
+ def scan_all
103
+ Appydave::Tools::Configuration::Config.configure
104
+ brands_config = Appydave::Tools::Configuration::Config.brands
105
+
106
+ results = []
107
+ brands_config.brands.each do |brand_info|
108
+ brand_key = brand_info.key
109
+ puts ''
110
+ puts '=' * 60
111
+
112
+ begin
113
+ scan_single(brand_key)
114
+ results << { brand: brand_key, success: true }
115
+ rescue StandardError => e
116
+ puts "❌ Failed to scan #{brand_key}: #{e.message}"
117
+ results << { brand: brand_key, success: false, error: e.message }
118
+ end
119
+ end
120
+
121
+ puts ''
122
+ puts '=' * 60
123
+ puts '📋 Summary - S3 Scans:'
124
+ puts ''
125
+
126
+ successful, failed = results.partition { |r| r[:success] }
127
+
128
+ successful.each do |result|
129
+ brand_display = result[:brand].ljust(15)
130
+ puts "✅ #{brand_display} Scanned successfully"
131
+ end
132
+
133
+ failed.each do |result|
134
+ brand_display = result[:brand].ljust(15)
135
+ puts "❌ #{brand_display} #{result[:error]}"
136
+ end
137
+
138
+ puts ''
139
+ puts "Total brands scanned: #{successful.size}/#{results.size}"
140
+ end
141
+
142
+ private
143
+
144
+ # Display S3 scan results in table format
145
+ # rubocop:disable Style/FormatStringToken
146
+ def display_table(matched_projects, orphaned_projects, bucket, prefix, region)
147
+ puts '✅ S3 Projects Report'
148
+ puts ''
149
+ puts 'PROJECT FILES SIZE LOCAL S3 MODIFIED'
150
+ puts '-' * 92
151
+
152
+ # Display matched projects first (sorted alphabetically)
153
+ matched_projects.sort.each do |project_id, data|
154
+ files = data[:file_count].to_s.rjust(5)
155
+ size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
156
+ local_status = Appydave::Tools::Dam::LocalSyncStatus.format(data[:local_status], data[:local_file_count], data[:file_count])
157
+ modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
158
+
159
+ puts format('%-36s %5s %10s %-9s %s', project_id, files, size, local_status, modified)
160
+ end
161
+
162
+ # Display orphaned projects (sorted alphabetically)
163
+ return if orphaned_projects.empty?
164
+
165
+ puts '-' * 92
166
+ orphaned_projects.sort.each do |project_id, data|
167
+ files = data[:file_count].to_s.rjust(5)
168
+ size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
169
+ local_status = 'N/A'
170
+ modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
171
+
172
+ puts format('%-36s %5s %10s %-9s %s', project_id, files, size, local_status, modified)
173
+ end
174
+
175
+ puts ''
176
+ folder_word = orphaned_projects.size > 1 ? 'folders' : 'folder'
177
+ puts "âš ī¸ #{orphaned_projects.size} orphaned #{folder_word} found (no local project)"
178
+
179
+ orphaned_projects.sort.each do |project_id, _data|
180
+ # Build AWS Console URL
181
+ project_prefix = "#{prefix}#{project_id}/"
182
+ console_url = "https://#{region}.console.aws.amazon.com/s3/buckets/#{bucket}?prefix=#{project_prefix}&region=#{region}"
183
+ puts " → #{project_id}"
184
+ puts " #{console_url}"
185
+ end
186
+ end
187
+ # rubocop:enable Style/FormatStringToken
188
+ end
189
+ end
190
+ end
191
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.76.5'
5
+ VERSION = '0.76.6'
6
6
  end
7
7
  end
@@ -79,6 +79,7 @@ require 'appydave/tools/dam/repo_status'
79
79
  require 'appydave/tools/dam/repo_sync'
80
80
  require 'appydave/tools/dam/repo_push'
81
81
  require 'appydave/tools/dam/local_sync_status'
82
+ require 'appydave/tools/dam/s3_scan_command'
82
83
 
83
84
  require 'appydave/tools/jump/path_validator'
84
85
  require 'appydave/tools/jump/location'
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.76.5",
3
+ "version": "0.76.6",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.76.5
4
+ version: 0.76.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
@@ -362,6 +362,7 @@ files:
362
362
  - lib/appydave/tools/dam/repo_status.rb
363
363
  - lib/appydave/tools/dam/repo_sync.rb
364
364
  - lib/appydave/tools/dam/s3_operations.rb
365
+ - lib/appydave/tools/dam/s3_scan_command.rb
365
366
  - lib/appydave/tools/dam/s3_scanner.rb
366
367
  - lib/appydave/tools/dam/share_operations.rb
367
368
  - lib/appydave/tools/dam/ssd_status.rb