Context
Several modules independently implement the same "create or update a file on a branch via the GitHub Contents API, handling the existing sha" pattern:
R/blog-add.R — PUT /repos/{owner}/{repo}/contents/{path} (no sha check)
R/contributors.R — GET existing, compare content, PUT with sha
R/chapter-onboard.R — base64-encode + PUT
R/airtable-sync.R — PUT with sha
R/copilot-sync.R — copilot_put_file() (GET, skip-if-unchanged, PUT with sha)
Flagged by the reuse pass of a /simplify review on #80. copilot_put_file() is effectively the 4th–5th copy. The variants differ subtly (some skip the GET, some compare content before encoding), so bug fixes and behaviour (e.g. no-op skipping) don't propagate.
Proposal
Extract one gh_put_file(owner, repo, path, content, branch, message) into R/gh.R that:
- GETs the existing file on
branch (tolerating 404),
- returns early (no commit) when the decoded existing content is identical,
- base64-encodes and PUTs, passing
sha when the file exists,
- returns whether a commit was pushed.
Then migrate the call sites to it. Each migration must preserve that module's current behaviour (e.g. blog-add's create-only semantics) and keep its tests green.
Notes
Context
Several modules independently implement the same "create or update a file on a branch via the GitHub Contents API, handling the existing
sha" pattern:R/blog-add.R—PUT /repos/{owner}/{repo}/contents/{path}(no sha check)R/contributors.R— GET existing, compare content, PUT withshaR/chapter-onboard.R— base64-encode + PUTR/airtable-sync.R— PUT withshaR/copilot-sync.R—copilot_put_file()(GET, skip-if-unchanged, PUT withsha)Flagged by the reuse pass of a
/simplifyreview on #80.copilot_put_file()is effectively the 4th–5th copy. The variants differ subtly (some skip the GET, some compare content before encoding), so bug fixes and behaviour (e.g. no-op skipping) don't propagate.Proposal
Extract one
gh_put_file(owner, repo, path, content, branch, message)intoR/gh.Rthat:branch(tolerating 404),shawhen the file exists,Then migrate the call sites to it. Each migration must preserve that module's current behaviour (e.g. blog-add's create-only semantics) and keep its tests green.
Notes
base64_decode()(R/i18n.R) for the unchanged-check.