appydave-tools 0.18.5 → 0.20.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 +14 -0
- data/bin/dam +110 -0
- data/docs/dam/prd-git-integration.md +871 -0
- data/docs/dam/usage.md +138 -1
- data/lib/appydave/tools/configuration/models/brands_config.rb +4 -1
- data/lib/appydave/tools/dam/config.rb +38 -0
- data/lib/appydave/tools/dam/manifest_generator.rb +13 -0
- data/lib/appydave/tools/dam/repo_push.rb +131 -0
- data/lib/appydave/tools/dam/repo_status.rb +140 -0
- data/lib/appydave/tools/dam/repo_sync.rb +122 -0
- data/lib/appydave/tools/dam/status.rb +278 -0
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools.rb +4 -0
- data/package.json +1 -1
- metadata +6 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module Appydave
|
|
6
|
+
module Tools
|
|
7
|
+
module Dam
|
|
8
|
+
# Show unified status for video project (local, S3, SSD, git)
|
|
9
|
+
class Status
|
|
10
|
+
attr_reader :brand, :project_id, :brand_info, :brand_path, :project_path
|
|
11
|
+
|
|
12
|
+
def initialize(brand, project_id = nil)
|
|
13
|
+
@brand_info = load_brand_info(brand)
|
|
14
|
+
@brand = @brand_info.key
|
|
15
|
+
@brand_path = Config.brand_path(@brand)
|
|
16
|
+
@project_id = project_id
|
|
17
|
+
@project_path = project_id ? resolve_project_path(project_id) : nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Show status for project or brand
|
|
21
|
+
def show
|
|
22
|
+
if project_id
|
|
23
|
+
show_project_status
|
|
24
|
+
else
|
|
25
|
+
show_brand_status
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def load_brand_info(brand)
|
|
32
|
+
Appydave::Tools::Configuration::Config.configure
|
|
33
|
+
Appydave::Tools::Configuration::Config.brands.get_brand(brand)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def resolve_project_path(project_id)
|
|
37
|
+
# Resolve short name if needed (b65 -> b65-full-name)
|
|
38
|
+
resolved = ProjectResolver.new.resolve(brand, project_id)
|
|
39
|
+
File.join(brand_path, resolved)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def show_project_status
|
|
43
|
+
puts "📊 Status: v-#{brand}/#{File.basename(project_path)}"
|
|
44
|
+
puts ''
|
|
45
|
+
|
|
46
|
+
manifest = load_manifest
|
|
47
|
+
project_entry = find_project_in_manifest(manifest)
|
|
48
|
+
|
|
49
|
+
unless project_entry
|
|
50
|
+
puts '❌ Project not found in manifest'
|
|
51
|
+
puts " Run: dam manifest #{brand}"
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
show_storage_status(project_entry)
|
|
56
|
+
show_git_status if git_repo?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def show_brand_status
|
|
60
|
+
puts "📊 Brand Status: v-#{brand}"
|
|
61
|
+
puts ''
|
|
62
|
+
|
|
63
|
+
# Show git remote (with self-healing)
|
|
64
|
+
remote = Config.git_remote(brand)
|
|
65
|
+
if remote
|
|
66
|
+
puts "📡 Git Remote: #{remote}"
|
|
67
|
+
else
|
|
68
|
+
puts '📡 Git Remote: Not configured (not a git repository)'
|
|
69
|
+
end
|
|
70
|
+
puts ''
|
|
71
|
+
|
|
72
|
+
# Show git status
|
|
73
|
+
if git_repo?
|
|
74
|
+
show_brand_git_status
|
|
75
|
+
else
|
|
76
|
+
puts 'Git: Not a git repository'
|
|
77
|
+
end
|
|
78
|
+
puts ''
|
|
79
|
+
|
|
80
|
+
# Show manifest summary
|
|
81
|
+
manifest = load_manifest
|
|
82
|
+
if manifest
|
|
83
|
+
show_manifest_summary(manifest)
|
|
84
|
+
else
|
|
85
|
+
puts '❌ Manifest not found'
|
|
86
|
+
puts " Run: dam manifest #{brand}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def show_storage_status(project_entry)
|
|
91
|
+
puts 'Storage:'
|
|
92
|
+
|
|
93
|
+
# Local storage
|
|
94
|
+
show_local_status(project_entry)
|
|
95
|
+
|
|
96
|
+
# S3 staging (inferred - only show if exists)
|
|
97
|
+
show_s3_status(project_entry) if project_entry[:storage][:s3][:exists]
|
|
98
|
+
|
|
99
|
+
# SSD backup (inferred - only show if configured and exists)
|
|
100
|
+
show_ssd_status(project_entry) if brand_info.locations.ssd_backup &&
|
|
101
|
+
brand_info.locations.ssd_backup != 'NOT-SET' &&
|
|
102
|
+
project_entry[:storage][:ssd][:exists]
|
|
103
|
+
|
|
104
|
+
puts ''
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def show_local_status(project_entry)
|
|
108
|
+
local = project_entry[:storage][:local]
|
|
109
|
+
|
|
110
|
+
if local[:exists]
|
|
111
|
+
puts " 📁 Local: ✓ exists (#{local[:structure]} structure)"
|
|
112
|
+
puts " Heavy files: #{local[:has_heavy_files] ? 'yes' : 'no'}"
|
|
113
|
+
puts " Light files: #{local[:has_light_files] ? 'yes' : 'no'}"
|
|
114
|
+
else
|
|
115
|
+
puts ' 📁 Local: ✗ does not exist'
|
|
116
|
+
end
|
|
117
|
+
puts ''
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def show_s3_status(_project_entry)
|
|
121
|
+
puts ' ☁️ S3 Staging: ✓ exists'
|
|
122
|
+
|
|
123
|
+
# TODO: Query S3 for detailed status (files needing sync)
|
|
124
|
+
# For now, just show that s3-staging folder exists locally
|
|
125
|
+
s3_staging_path = File.join(project_path, 's3-staging')
|
|
126
|
+
if Dir.exist?(s3_staging_path)
|
|
127
|
+
file_count = Dir.glob(File.join(s3_staging_path, '*')).count
|
|
128
|
+
puts " Local staging files: #{file_count}"
|
|
129
|
+
end
|
|
130
|
+
puts ''
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def show_ssd_status(project_entry)
|
|
134
|
+
puts ' 💾 SSD Backup: ✓ exists'
|
|
135
|
+
puts " Path: #{project_entry[:storage][:ssd][:path]}"
|
|
136
|
+
puts ''
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def show_git_status
|
|
140
|
+
puts 'Git:'
|
|
141
|
+
|
|
142
|
+
status = git_status_info
|
|
143
|
+
|
|
144
|
+
puts " 🌿 Branch: #{status[:branch]}"
|
|
145
|
+
puts " 📡 Remote: #{status[:remote]}" if status[:remote]
|
|
146
|
+
|
|
147
|
+
if status[:modified_count].positive? || status[:untracked_count].positive?
|
|
148
|
+
puts " ↕️ Status: #{status[:modified_count]} modified, #{status[:untracked_count]} untracked"
|
|
149
|
+
else
|
|
150
|
+
puts ' ↕️ Status: Clean working directory'
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
if status[:ahead].positive? || status[:behind].positive?
|
|
154
|
+
puts " 🔄 Sync: #{sync_status_text(status[:ahead], status[:behind])}"
|
|
155
|
+
else
|
|
156
|
+
puts ' 🔄 Sync: Up to date'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
puts ''
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def show_brand_git_status
|
|
163
|
+
status = git_status_info
|
|
164
|
+
|
|
165
|
+
puts "🌿 Branch: #{status[:branch]}"
|
|
166
|
+
puts "📡 Remote: #{status[:remote]}" if status[:remote]
|
|
167
|
+
|
|
168
|
+
if status[:modified_count].positive? || status[:untracked_count].positive?
|
|
169
|
+
puts "↕️ Changes: #{status[:modified_count]} modified, #{status[:untracked_count]} untracked"
|
|
170
|
+
else
|
|
171
|
+
puts '✓ Working directory clean'
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
if status[:ahead].positive? || status[:behind].positive?
|
|
175
|
+
puts "🔄 Sync: #{sync_status_text(status[:ahead], status[:behind])}"
|
|
176
|
+
else
|
|
177
|
+
puts '✓ Up to date with remote'
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def show_manifest_summary(manifest)
|
|
182
|
+
puts '📋 Manifest Summary:'
|
|
183
|
+
puts " Total projects: #{manifest[:projects].size}"
|
|
184
|
+
|
|
185
|
+
local_count = manifest[:projects].count { |p| p[:storage][:local][:exists] }
|
|
186
|
+
s3_count = manifest[:projects].count { |p| p[:storage][:s3][:exists] }
|
|
187
|
+
ssd_count = manifest[:projects].count { |p| p[:storage][:ssd][:exists] }
|
|
188
|
+
|
|
189
|
+
puts " Local: #{local_count}"
|
|
190
|
+
puts " S3 staging: #{s3_count}"
|
|
191
|
+
puts " SSD backup: #{ssd_count}"
|
|
192
|
+
|
|
193
|
+
# Project types
|
|
194
|
+
storyline_count = manifest[:projects].count { |p| p[:hasStorylineJson] }
|
|
195
|
+
puts ''
|
|
196
|
+
puts " Storyline projects: #{storyline_count}"
|
|
197
|
+
puts " FliVideo projects: #{manifest[:projects].size - storyline_count}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def sync_status_text(ahead, behind)
|
|
201
|
+
parts = []
|
|
202
|
+
parts << "#{ahead} ahead" if ahead.positive?
|
|
203
|
+
parts << "#{behind} behind" if behind.positive?
|
|
204
|
+
parts.join(', ')
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def load_manifest
|
|
208
|
+
manifest_path = File.join(brand_path, 'projects.json')
|
|
209
|
+
return nil unless File.exist?(manifest_path)
|
|
210
|
+
|
|
211
|
+
JSON.parse(File.read(manifest_path), symbolize_names: true)
|
|
212
|
+
rescue JSON::ParserError
|
|
213
|
+
nil
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def find_project_in_manifest(manifest)
|
|
217
|
+
return nil unless manifest
|
|
218
|
+
|
|
219
|
+
project_name = File.basename(project_path)
|
|
220
|
+
manifest[:projects].find { |p| p[:id] == project_name }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def git_repo?
|
|
224
|
+
git_dir = File.join(brand_path, '.git')
|
|
225
|
+
Dir.exist?(git_dir)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def git_status_info
|
|
229
|
+
{
|
|
230
|
+
branch: current_branch,
|
|
231
|
+
remote: remote_url,
|
|
232
|
+
modified_count: modified_files_count,
|
|
233
|
+
untracked_count: untracked_files_count,
|
|
234
|
+
ahead: commits_ahead,
|
|
235
|
+
behind: commits_behind
|
|
236
|
+
}
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def current_branch
|
|
240
|
+
`git -C "#{brand_path}" rev-parse --abbrev-ref HEAD 2>/dev/null`.strip
|
|
241
|
+
rescue StandardError
|
|
242
|
+
'unknown'
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def remote_url
|
|
246
|
+
result = `git -C "#{brand_path}" remote get-url origin 2>/dev/null`.strip
|
|
247
|
+
result.empty? ? nil : result
|
|
248
|
+
rescue StandardError
|
|
249
|
+
nil
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def modified_files_count
|
|
253
|
+
`git -C "#{brand_path}" status --porcelain 2>/dev/null | grep -E "^.M|^M" | wc -l`.strip.to_i
|
|
254
|
+
rescue StandardError
|
|
255
|
+
0
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def untracked_files_count
|
|
259
|
+
`git -C "#{brand_path}" status --porcelain 2>/dev/null | grep -E "^\\?\\?" | wc -l`.strip.to_i
|
|
260
|
+
rescue StandardError
|
|
261
|
+
0
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def commits_ahead
|
|
265
|
+
`git -C "#{brand_path}" rev-list --count @{upstream}..HEAD 2>/dev/null`.strip.to_i
|
|
266
|
+
rescue StandardError
|
|
267
|
+
0
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def commits_behind
|
|
271
|
+
`git -C "#{brand_path}" rev-list --count HEAD..@{upstream} 2>/dev/null`.strip.to_i
|
|
272
|
+
rescue StandardError
|
|
273
|
+
0
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
data/lib/appydave/tools.rb
CHANGED
|
@@ -59,6 +59,10 @@ require 'appydave/tools/dam/s3_operations'
|
|
|
59
59
|
require 'appydave/tools/dam/project_listing'
|
|
60
60
|
require 'appydave/tools/dam/manifest_generator'
|
|
61
61
|
require 'appydave/tools/dam/sync_from_ssd'
|
|
62
|
+
require 'appydave/tools/dam/status'
|
|
63
|
+
require 'appydave/tools/dam/repo_status'
|
|
64
|
+
require 'appydave/tools/dam/repo_sync'
|
|
65
|
+
require 'appydave/tools/dam/repo_push'
|
|
62
66
|
|
|
63
67
|
require 'appydave/tools/youtube_automation/gpt_agent'
|
|
64
68
|
|
data/package.json
CHANGED
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.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Cruwys
|
|
@@ -243,6 +243,7 @@ files:
|
|
|
243
243
|
- docs/configuration/settings.example.json
|
|
244
244
|
- docs/dam/dam-testing-plan.md
|
|
245
245
|
- docs/dam/dam-vision.md
|
|
246
|
+
- docs/dam/prd-git-integration.md
|
|
246
247
|
- docs/dam/session-summary-2025-11-09.md
|
|
247
248
|
- docs/dam/usage.md
|
|
248
249
|
- docs/dam/windows-testing-guide.md
|
|
@@ -291,7 +292,11 @@ files:
|
|
|
291
292
|
- lib/appydave/tools/dam/manifest_generator.rb
|
|
292
293
|
- lib/appydave/tools/dam/project_listing.rb
|
|
293
294
|
- lib/appydave/tools/dam/project_resolver.rb
|
|
295
|
+
- lib/appydave/tools/dam/repo_push.rb
|
|
296
|
+
- lib/appydave/tools/dam/repo_status.rb
|
|
297
|
+
- lib/appydave/tools/dam/repo_sync.rb
|
|
294
298
|
- lib/appydave/tools/dam/s3_operations.rb
|
|
299
|
+
- lib/appydave/tools/dam/status.rb
|
|
295
300
|
- lib/appydave/tools/dam/sync_from_ssd.rb
|
|
296
301
|
- lib/appydave/tools/debuggable.rb
|
|
297
302
|
- lib/appydave/tools/gpt_context/_doc.md
|