brainiac-fizzy 0.0.26 → 0.0.28
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/lib/brainiac/plugins/fizzy/handlers/deployments.rb +109 -0
- data/lib/brainiac/plugins/fizzy/handlers/summarize.rb +6 -1
- data/lib/brainiac/plugins/fizzy/helpers.rb +58 -13
- data/lib/brainiac/plugins/fizzy/prompts.rb +24 -7
- data/lib/brainiac/plugins/fizzy/version.rb +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: e5d55859eafd2aeccf63a2083999340a1ce4a77c01b81a8297adf136b0e553b3
|
|
4
|
+
data.tar.gz: b1dbff19165dec2cf391f4c258ae2a207457cdc53088ee44062ffda050530a48
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9438b9143636ab612da09a19be5b672ada809095317ea7ce72d9045acbebe6601d5485ba4bfd234b85edcdb54a6d676edd330a74b4241cc85c0605d590fe523d
|
|
7
|
+
data.tar.gz: 93fbe26b2a546b1b72e1025f7af334ac6539efe0c4144338bd6d2929b336e2ed21752cc8a1d4ef2949d380cc72635e945e0dad819afe043570c483ddc889d2d7
|
|
@@ -274,3 +274,112 @@ def resolve_deployment_url(env_config, card_tags)
|
|
|
274
274
|
end
|
|
275
275
|
env_config["url"]
|
|
276
276
|
end
|
|
277
|
+
|
|
278
|
+
# Resolve the live ephemeral deployment URL for a given card number.
|
|
279
|
+
# Returns { env:, url: } for the environment currently occupied by this card,
|
|
280
|
+
# or nil if the card isn't deployed anywhere (or deployments aren't configured).
|
|
281
|
+
#
|
|
282
|
+
# Resolution order (live state is the source of truth):
|
|
283
|
+
# 1. A tracked dev environment (dev01/dev02...) occupied by this card, from
|
|
284
|
+
# deployment_state.json.
|
|
285
|
+
# 2. The card's ephemeral Belt environment (fizzy-<card>), from
|
|
286
|
+
# ephemeral_envs.json, with the public URL derived from its terraform.tfvars.
|
|
287
|
+
def deployment_url_for_card(card_number)
|
|
288
|
+
return nil unless card_number
|
|
289
|
+
|
|
290
|
+
tracked_deployment_for_card(card_number) || ephemeral_deployment_for_card(card_number)
|
|
291
|
+
rescue StandardError => e
|
|
292
|
+
LOG.warn "[Fizzy:Deploy] Could not resolve deployment URL for card ##{card_number}: #{e.message}" if defined?(LOG)
|
|
293
|
+
nil
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# A tracked dev environment (dev01/dev02...) currently occupied by this card.
|
|
297
|
+
def tracked_deployment_for_card(card_number)
|
|
298
|
+
return nil unless defined?(DEPLOYMENTS_CONFIG)
|
|
299
|
+
|
|
300
|
+
config = DEPLOYMENTS_CONFIG["environments"] || {}
|
|
301
|
+
state = load_deployment_state
|
|
302
|
+
|
|
303
|
+
env_key, info = state.find do |key, v|
|
|
304
|
+
v.is_a?(Hash) && v["card_number"].to_s == card_number.to_s && v["status"] == "occupied" && config.key?(key)
|
|
305
|
+
end
|
|
306
|
+
return nil unless env_key
|
|
307
|
+
|
|
308
|
+
url = resolve_deployment_url(config[env_key], info["card_tags"])
|
|
309
|
+
return nil unless url
|
|
310
|
+
|
|
311
|
+
{ env: env_key, url: url }
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
EPHEMERAL_ENVS_FILE = File.join(BRAINIAC_DIR, "ephemeral_envs.json")
|
|
315
|
+
|
|
316
|
+
# The active ephemeral Belt environment (fizzy-<card>) for this card, if any.
|
|
317
|
+
# The public URL is derived from the env's terraform.tfvars in its worktree,
|
|
318
|
+
# following the Belt frontend_urls convention.
|
|
319
|
+
def ephemeral_deployment_for_card(card_number)
|
|
320
|
+
info = active_ephemeral_env_info(card_number)
|
|
321
|
+
return nil unless info
|
|
322
|
+
|
|
323
|
+
worktree = info["worktree"]
|
|
324
|
+
env_name = "fizzy-#{card_number}"
|
|
325
|
+
return nil unless worktree
|
|
326
|
+
|
|
327
|
+
tfvars = File.join(worktree, "infrastructure", env_name, "terraform.tfvars")
|
|
328
|
+
return nil unless File.exist?(tfvars)
|
|
329
|
+
|
|
330
|
+
url = ephemeral_url_from_tfvars(tfvars)
|
|
331
|
+
return nil unless url
|
|
332
|
+
|
|
333
|
+
{ env: env_name, url: url }
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Look up the active ephemeral env metadata for a card from ephemeral_envs.json.
|
|
337
|
+
def active_ephemeral_env_info(card_number)
|
|
338
|
+
return nil unless File.exist?(EPHEMERAL_ENVS_FILE)
|
|
339
|
+
|
|
340
|
+
state = JSON.parse(File.read(EPHEMERAL_ENVS_FILE))
|
|
341
|
+
info = state["fizzy-#{card_number}"]
|
|
342
|
+
return nil unless info.is_a?(Hash) && info["status"] == "active"
|
|
343
|
+
|
|
344
|
+
info
|
|
345
|
+
rescue JSON::ParserError
|
|
346
|
+
nil
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Derive the public URL from a Belt env's terraform.tfvars, matching the
|
|
350
|
+
# frontend_urls convention in the Belt infra module:
|
|
351
|
+
# parent set -> https://<env>.<parent>.<domain>
|
|
352
|
+
# prod -> https://<domain>
|
|
353
|
+
# otherwise -> https://<env>.<domain>
|
|
354
|
+
def ephemeral_url_from_tfvars(tfvars_path)
|
|
355
|
+
vars = parse_tfvars(File.read(tfvars_path))
|
|
356
|
+
domain = vars["domain"].to_s
|
|
357
|
+
return nil if domain.empty?
|
|
358
|
+
|
|
359
|
+
environment = vars["environment"].to_s
|
|
360
|
+
parent = vars["parent_environment"].to_s
|
|
361
|
+
|
|
362
|
+
host =
|
|
363
|
+
if !parent.empty?
|
|
364
|
+
"#{environment}.#{parent}.#{domain}"
|
|
365
|
+
elsif environment == "prod"
|
|
366
|
+
domain
|
|
367
|
+
else
|
|
368
|
+
"#{environment}.#{domain}"
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
"https://#{host}"
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Minimal HCL parser for `key = "value"` lines in terraform.tfvars.
|
|
375
|
+
def parse_tfvars(contents)
|
|
376
|
+
vars = {}
|
|
377
|
+
contents.each_line do |line|
|
|
378
|
+
stripped = line.strip
|
|
379
|
+
next if stripped.empty? || stripped.start_with?("#")
|
|
380
|
+
|
|
381
|
+
match = stripped.match(/\A(\w+)\s*=\s*"([^"]*)"/)
|
|
382
|
+
vars[match[1]] = match[2] if match
|
|
383
|
+
end
|
|
384
|
+
vars
|
|
385
|
+
end
|
|
@@ -72,9 +72,14 @@ module Brainiac
|
|
|
72
72
|
env = Helpers.fizzy_env_for(agent_name)
|
|
73
73
|
|
|
74
74
|
pr_url = Helpers.send(:detect_pr_url, branch, project_config)
|
|
75
|
+
deployment = respond_to?(:deployment_url_for_card, true) ? deployment_url_for_card(card_number) : nil
|
|
75
76
|
body = "<p>✅ Work completed on this card.</p>"
|
|
76
|
-
body += "<p><a href=\"#{pr_url}\">View PR</a></p>" if pr_url
|
|
77
77
|
body += "<p><strong>Branch:</strong> <code>#{branch}</code></p>"
|
|
78
|
+
body += "<p><strong>PR:</strong> <a href=\"#{pr_url}\">#{pr_url}</a></p>" if pr_url
|
|
79
|
+
if deployment
|
|
80
|
+
body += "<p><strong>Deployment (#{deployment[:env]}):</strong> " \
|
|
81
|
+
"<a href=\"#{deployment[:url]}\">#{deployment[:url]}</a></p>"
|
|
82
|
+
end
|
|
78
83
|
|
|
79
84
|
run_cmd("fizzy", "comment", "create", "--card", card_number.to_s, "--body", body,
|
|
80
85
|
chdir: repo_path, env: env)
|
|
@@ -171,20 +171,13 @@ module Brainiac
|
|
|
171
171
|
last_agent_comment = agent_comments.last
|
|
172
172
|
return false unless last_agent_comment
|
|
173
173
|
|
|
174
|
-
#
|
|
174
|
+
# Backup: ensure the comment surfaces branch, PR link, and live deployment link.
|
|
175
|
+
# Whatever the agent already included is left alone; we only append what's missing.
|
|
175
176
|
body = last_agent_comment.dig("body", "html") || ""
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
footer = "<p><em>Branch: <code>#{branch}</code>"
|
|
181
|
-
footer += " | <a href=\"#{pr_url}\">PR</a>" if pr_url
|
|
182
|
-
footer += "</em></p>"
|
|
183
|
-
|
|
184
|
-
updated_body = body + footer
|
|
185
|
-
run_cmd("fizzy", "comment", "update", last_agent_comment["id"], "--card", card_number.to_s,
|
|
186
|
-
"--body", updated_body, chdir: repo_path, env: env)
|
|
187
|
-
end
|
|
177
|
+
updated_body = ensure_reference_footer(body, card_number, project_config)
|
|
178
|
+
if updated_body != body
|
|
179
|
+
run_cmd("fizzy", "comment", "update", last_agent_comment["id"], "--card", card_number.to_s,
|
|
180
|
+
"--body", updated_body, chdir: repo_path, env: env)
|
|
188
181
|
end
|
|
189
182
|
|
|
190
183
|
true
|
|
@@ -193,6 +186,42 @@ module Brainiac
|
|
|
193
186
|
false
|
|
194
187
|
end
|
|
195
188
|
|
|
189
|
+
# Build the reference footer (Branch / PR / Deployment) and append any pieces
|
|
190
|
+
# that the agent's comment body doesn't already contain. Returns the (possibly
|
|
191
|
+
# unchanged) body. Detection is deliberately lenient — if the branch name, PR
|
|
192
|
+
# URL, or deployment URL already appears anywhere in the body, it's not re-added.
|
|
193
|
+
def ensure_reference_footer(body, card_number, project_config)
|
|
194
|
+
branch = detect_branch_from_comment(body, card_number)
|
|
195
|
+
return body unless branch
|
|
196
|
+
|
|
197
|
+
pr_url = detect_pr_url(branch, project_config)
|
|
198
|
+
deployment = detect_deployment(card_number)
|
|
199
|
+
|
|
200
|
+
footer_lines = []
|
|
201
|
+
footer_lines << "<strong>Branch:</strong> <code>#{branch}</code>" unless body.include?(branch)
|
|
202
|
+
if pr_url && !body.include?(pr_url) && !body.include?("github.com/#{project_config["github_repo"]}/pull")
|
|
203
|
+
footer_lines << "<strong>PR:</strong> <a href=\"#{pr_url}\">#{pr_url}</a>"
|
|
204
|
+
end
|
|
205
|
+
if deployment && !body.include?(deployment[:url])
|
|
206
|
+
footer_lines << "<strong>Deployment (#{deployment[:env]}):</strong> " \
|
|
207
|
+
"<a href=\"#{deployment[:url]}\">#{deployment[:url]}</a>"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
return body if footer_lines.empty?
|
|
211
|
+
|
|
212
|
+
"#{body}<p><em>#{footer_lines.join(" · ")}</em></p>"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Resolve the live deployment for a card as { env:, url: }, or nil.
|
|
216
|
+
# Reads live deployment state (tracked dev envs from deployment_state.json,
|
|
217
|
+
# and the card's ephemeral Belt env from ephemeral_envs.json) — the actual
|
|
218
|
+
# source of truth for which environment a card currently occupies.
|
|
219
|
+
def detect_deployment(card_number)
|
|
220
|
+
return nil unless respond_to?(:deployment_url_for_card, true)
|
|
221
|
+
|
|
222
|
+
deployment_url_for_card(card_number)
|
|
223
|
+
end
|
|
224
|
+
|
|
196
225
|
def ensure_fizzy_yaml!(chdir, project_config)
|
|
197
226
|
fizzy_yaml_dest = File.join(chdir, ".fizzy.yaml")
|
|
198
227
|
return if File.exist?(fizzy_yaml_dest)
|
|
@@ -331,8 +360,24 @@ module Brainiac
|
|
|
331
360
|
repo = project_config["github_repo"]
|
|
332
361
|
return nil unless repo
|
|
333
362
|
|
|
363
|
+
# Prefer the existing open PR for this branch. `pull/new/<branch>` only
|
|
364
|
+
# opens the "create PR" page, which is wrong once a PR already exists.
|
|
365
|
+
existing = existing_pr_url(branch, repo, project_config["repo_path"])
|
|
366
|
+
return existing if existing
|
|
367
|
+
|
|
334
368
|
"https://github.com/#{repo}/pull/new/#{branch}"
|
|
335
369
|
end
|
|
370
|
+
|
|
371
|
+
# Look up the URL of an already-open PR for `branch` via the gh CLI.
|
|
372
|
+
# Returns nil if gh fails or no PR exists (caller falls back to new-PR link).
|
|
373
|
+
def existing_pr_url(branch, repo, repo_path)
|
|
374
|
+
output = run_cmd("gh", "pr", "view", branch, "--repo", repo, "--json", "url",
|
|
375
|
+
"--jq", ".url", chdir: repo_path)
|
|
376
|
+
url = output.to_s.strip
|
|
377
|
+
url.empty? ? nil : url
|
|
378
|
+
rescue StandardError
|
|
379
|
+
nil
|
|
380
|
+
end
|
|
336
381
|
end
|
|
337
382
|
end
|
|
338
383
|
end
|
|
@@ -62,10 +62,19 @@ module Brainiac
|
|
|
62
62
|
{{PR_TARGET_INSTRUCTION}}
|
|
63
63
|
|
|
64
64
|
**Response destination: Post your response as a comment on Fizzy card #{{CARD_NUMBER}}.**
|
|
65
|
-
Your comment MUST include a concise summary of what you did
|
|
65
|
+
Your comment MUST include a concise summary of what you did.
|
|
66
66
|
|
|
67
|
-
**MANDATORY: Always
|
|
68
|
-
|
|
67
|
+
**MANDATORY: Always end your comment with a References block containing all three of the following:**
|
|
68
|
+
- The branch name
|
|
69
|
+
- A link to the PR
|
|
70
|
+
- A link to the live deployed ephemeral environment (if this card was deployed — check the card's [deploy] tag / deployment; if not deployed, state "Not deployed")
|
|
71
|
+
|
|
72
|
+
Use this exact HTML format:
|
|
73
|
+
```
|
|
74
|
+
<p><strong>Branch:</strong> <code>{{BRANCH}}</code></p>
|
|
75
|
+
<p><strong>PR:</strong> <a href="PR_URL_HERE">PR_URL_HERE</a></p>
|
|
76
|
+
<p><strong>Deployment:</strong> <a href="DEPLOY_URL_HERE">DEPLOY_URL_HERE</a></p>
|
|
77
|
+
```
|
|
69
78
|
PROMPT
|
|
70
79
|
|
|
71
80
|
FOLLOWUP_WORKTREE = <<~'PROMPT'
|
|
@@ -123,11 +132,19 @@ module Brainiac
|
|
|
123
132
|
Read your memory file for this card and write a brief summary comment.
|
|
124
133
|
|
|
125
134
|
**Response destination: Post your response as a comment on Fizzy card #{{CARD_NUMBER}}.**
|
|
126
|
-
Include what you did
|
|
127
|
-
Keep it concise — this is a summary, not a full report.
|
|
135
|
+
Include what you did. Keep it concise — this is a summary, not a full report.
|
|
128
136
|
|
|
129
|
-
**MANDATORY: Always
|
|
130
|
-
|
|
137
|
+
**MANDATORY: Always end your comment with all three of the following:**
|
|
138
|
+
- The branch name
|
|
139
|
+
- A link to the PR
|
|
140
|
+
- A link to the live deployed ephemeral environment (or "Not deployed" if the card wasn't deployed)
|
|
141
|
+
|
|
142
|
+
Use this exact HTML format:
|
|
143
|
+
```
|
|
144
|
+
<p><strong>Branch:</strong> <code>{{BRANCH}}</code></p>
|
|
145
|
+
<p><strong>PR:</strong> <a href="PR_URL_HERE">PR_URL_HERE</a></p>
|
|
146
|
+
<p><strong>Deployment:</strong> <a href="DEPLOY_URL_HERE">DEPLOY_URL_HERE</a></p>
|
|
147
|
+
```
|
|
131
148
|
PROMPT
|
|
132
149
|
|
|
133
150
|
UAT_TESTING = <<~'PROMPT'
|