Skip to content

feat: --gif follow-up polish (#32)#34

Merged
Hinne1 merged 5 commits into
mainfrom
claude/gif-followups-32
Jul 5, 2026
Merged

feat: --gif follow-up polish (#32)#34
Hinne1 merged 5 commits into
mainfrom
claude/gif-followups-32

Conversation

@Hinne1

@Hinne1 Hinne1 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Closes #32 (4 of 5 items; item 5 intentionally declined — see below).

Non-blocking polish from the --gif whole-branch review, plus fixes adopted from this PR's own council review.

Changes

  • JSON-mode warning surfacinguploadResult gains a warning field (omitempty). In --json mode stderr is suppressed, so this is the only channel a consumer has to learn the GIF was capped / oversized / renamed.
  • Re-encode-failure fallback — when only the size-ceiling reduction encode errors, keep the valid oversized first encode and warn, rather than failing and discarding it. The reduction encoder is injected via a nil-defaulting gifAssembleOptions field (per-call seam, no racy package global).
  • --name forced to .gif — the payload is always a GIF and GitHub derives content-type from the name extension, so a non-.gif name (even .png) can render as a static still instead of animating. .gif is appended (case-insensitively; .GIF untouched) rather than substituted, so a dotted base name like release-1.0 keeps its .0.
  • Tests — combined guards; re-encode-failure fallback and successful reduction (both via the injected encoder); .gif/.GIF unchanged, non-.gif appended, dotted-name preserved; no---name defaults to clip.gif with no spurious warning; JSON vs stderr warning branches through runWithDeps.

Item 5 (shared name-sanitization helper) — declined

The issue notes the two checks are "kept separate deliberately as defense-in-depth." assembleGIF sanitizes-with-fallback (filepath.Base + reject ./../separator); validateName validates-and-errors. Different contracts — a shared helper would couple two deliberately independent defenses for marginal gain.

Verification

  • go build ./..., go vet ./... — clean.
  • go test ./... — all pass.
  • golangci-lint run ./... — 0 issues.
  • CI (go.yml, dispatched on the branch): Go Test, Go Lint, License Check all green.

https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B

…ext nudge)

Addresses the non-blocking follow-ups from the --gif whole-branch review:

- JSON-mode warning surfacing: uploadResult gains a `warning` field, so a
  --json consumer (stderr suppressed) still learns a GIF was capped,
  oversized, or renamed. Populated from the assembleGIF warning.
- Re-encode-failure fallback: when only the size-ceiling reduction encode
  errors, keep the valid oversized first encode and warn, instead of
  failing and discarding it.
- --name without an inline-image extension now gets `.gif` appended (with a
  warning) so the clip renders inline rather than as a click-through link;
  gh.IsImage exported for the check.
- Tests: both-guards-in-one-call, re-encode-failure fallback (via an
  injectable reduction-encode seam), name-ext append + unchanged-when-valid,
  and the JSON vs stderr warning-surfacing branches through runWithDeps.

The shared name-sanitization helper item is intentionally not taken: the
assembleGIF sanitize-with-fallback contract and validateName's
validate-and-error contract differ, so a shared helper would couple two
deliberately independent defenses for marginal gain.

Claude-Session: https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B
Hinne1 added 4 commits July 5, 2026 12:34
Remove 7 test doc/inline comments that restated the test name or its
body; keep the two that explain non-obvious fixture values (why the
frame/ceiling constants are chosen, why the kept-frame assertion is 4).

Claude-Session: https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B
Council review adopted:

- --name now normalizes to a .gif extension (case-insensitive) rather than
  accepting any inline-image extension. The payload is always a GIF and
  GitHub derives the content-type from the name extension, so a GIF shipped
  under a .png/.jpg name can render as a static still instead of animating —
  the exact case --gif exists to prevent. Drops the gh.IsImage export (only
  this guard used it).
- The size-ceiling reduction encoder is injected via a nil-defaulting
  gifAssembleOptions field instead of a mutable package var, scoping the
  test override per call so it can't race a future t.Parallel test.

Tests updated: .gif (incl. uppercase .GIF) left unchanged; non-.gif image
name normalized to .gif; re-encode-failure seam driven through the option.

Claude-Session: https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B
Substituting filepath.Ext dropped legitimate dotted base-name segments —
"release-1.0" became "release-1.gif". Append ".gif" instead so every
segment is preserved while the payload still ships under a .gif name that
animates inline. Still case-insensitive, so an existing .GIF is untouched.

Test renamed and extended to cover the dotted-name case.

Claude-Session: https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B
- No --name resolves to "clip.gif" (not a frame basename), so the .gif
  normalization is a no-op and emits no --name warning on the common path.
- The size-ceiling reduction success path emits its "reduced to …" warning
  (driven via the injected re-encode returning a small payload).

Claude-Session: https://claude.ai/code/session_01XGKirUaMS7kttgBwCzcJ3B
@Hinne1 Hinne1 marked this pull request as ready for review July 5, 2026 10:56
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/enthus-appdev/gh-attach/internal/cli 97.20% (+0.62%) 👍

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/enthus-appdev/gh-attach/internal/cli/gif.go 91.18% (+4.29%) 68 (+7) 62 (+9) 6 (-2) 👍
github.com/enthus-appdev/gh-attach/internal/cli/run.go 97.69% (+0.61%) 173 (+2) 169 (+3) 4 (-1) 👍

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/enthus-appdev/gh-attach/internal/cli/gif_followups_test.go

@Hinne1 Hinne1 merged commit be5a345 into main Jul 5, 2026
15 checks passed
@Hinne1 Hinne1 deleted the claude/gif-followups-32 branch July 5, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gif mode: follow-up polish (JSON warning, re-encode fallback, guard test, name-ext UX)

1 participant