fix: resolve push_files commit action per file - #643
Conversation
createCommit hardcoded `action: "create"` for every entry, and GitLab
rejects that for a path already tracked in the branch:
400 A file with this name already exists
So push_files could only ever ADD files. Any commit touching existing
code failed, and the error read like a GitLab problem rather than a
missing capability — create_or_update_file was the only working way to
change a file, one file per commit.
The action is now resolved per file with a HEAD request against the
Repository Files API: `update` when the path exists in the target
branch, `create` when it does not. HEAD keeps the probe to headers
rather than the whole blob, and a missing branch answers 404 like a
missing file — which is correct, since a commit that also creates the
branch has to use `create`.
Adds test/test-push-files.ts covering an existing path, a new path, and
a commit mixing both.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📜 Recent review details🔇 Additional comments (2)
📝 WalkthroughSummary by CodeRabbit
Walkthrough
Changespush_files update support
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant createCommit
participant repositoryFileExists
participant GitLabRepositoryFilesAPI
createCommit->>repositoryFileExists: Check each repository path
repositoryFileExists->>GitLabRepositoryFilesAPI: Send HEAD request at branch ref
GitLabRepositoryFilesAPI-->>repositoryFileExists: Return response status
repositoryFileExists-->>createCommit: Return file existence
createCommit->>GitLabRepositoryFilesAPI: Submit update or create action
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@index.ts`:
- Around line 4812-4817: Update repositoryFileExists() so the HEAD response
returns false only when response.status is 404, returns true for successful
responses, and throws for every other non-success status. Preserve the original
response/API failure details when propagating the error so callers do not
incorrectly choose the create action.
In `@test/test-push-files.ts`:
- Around line 90-98: Update the HEAD mock handlers in the existingPaths loop to
inspect the request’s ref query parameter and assert it matches the intended
target branch before returning success. Keep the existing encoded file-path
routing and successful response behavior unchanged.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 747494bc-fdea-43d1-a4a4-f5b55a560ebf
📒 Files selected for processing (8)
CHANGELOG.mdREADME.mddocs/tools/index.mddocs/tools/repositories.mdindex.tstest/test-push-files.tstest/utils/mock-gitlab-server.tstools/registry.ts
📜 Review details
🧰 Additional context used
🪛 ast-grep (0.45.0)
test/test-push-files.ts
[warning] 2-2: Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🔇 Additional comments (6)
CHANGELOG.md (1)
9-11: LGTM!README.md (1)
562-562: LGTM!docs/tools/index.md (1)
77-77: LGTM!docs/tools/repositories.md (1)
67-67: LGTM!tools/registry.ts (1)
299-299: LGTM!test/utils/mock-gitlab-server.ts (1)
78-82: LGTM!
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/test-push-files.ts`:
- Around line 94-95: Add a regression case in the push_files tests around the
existing request handler, configuring the HEAD handler to return a non-404
failure such as 403 or 500. Assert that push_files propagates the failure and
does not send the commit request, while preserving the existing behavior where
only a 404 selects create.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 49d1fa7c-543a-43ca-a739-009351f25849
📒 Files selected for processing (2)
index.tstest/test-push-files.ts
📜 Review details
🔇 Additional comments (1)
index.ts (1)
4817-4822: LGTM!
What
createCommitbuilt its payload withaction: "create"hardcoded for every entry, sopush_filescould only ever add files. GitLab's Commits API rejectscreatefor apath already tracked in the branch:
The action is now resolved per file:
updatewhen the path exists in the target branch,createwhen it does not.repositoryFileExistsissues aHEADagainst the Repository Files API — headers ratherthan the whole blob, since a commit may carry several files and their current content is
irrelevant to the decision. A branch that does not exist yet answers 404 exactly like a
missing file, which is the right answer: a commit that also creates the branch has to use
create.create_or_update_filealready does the same existence probe for a single file, so thisbrings
push_filesin line with it rather than introducing a new pattern.Why
Any commit touching existing code failed, which makes
push_filesunusable for the mostcommon editing workflow — an agent reading a file and writing it back. The error also
reads like a GitLab problem rather than a missing capability, so it is easy to
misdiagnose as a permissions or path issue.
The only working way to change a tracked file today is
create_or_update_file, whichhandles one file per commit — so a multi-file change cannot be made atomic at all.
No existing issue; happy to open one if you'd prefer to track it separately.
How tested
npm run test:mock— 565 passing, including the new suite.npm run test:consumer-smoke— passes.npx tsc --noEmit,npm run build,npm run check:runtime-deps,npm run check:skill-sync— all clean.npx tsx scripts/generate-tool-docs.ts— regenerated;docs/tools/committed with nodrift.
New file
test/test-push-files.ts(mock GitLab server, following thetest-create-repository.tspattern) covers three cases:action: "update"action: "create"The first case fails against
main, where every action iscreate.MockGitLabServer.addMockHandlergained"head"in its method union so the probe can bestubbed. The dispatcher already keyed on the real request method, so nothing changed at
runtime.
Not run locally:
npm run test:live(needs a real GitLab token) andmkdocs build --strict(no local MkDocs). The docs change is a single generateddescription line with no new links.
Breaking changes
None. No schema change, no new parameter. The only behavioural difference is that a call
which previously failed with a 400 now succeeds; callers that only ever pushed new files
are unaffected.
The tool description changes from "Push multiple files in a single commit" to "Create or
update multiple files in a single commit", and
docs/tools/is regenerated to match.