Skip to content

fix(github): create missing changelog file when pushing updates - #3639

Merged
IsmaelMartinez merged 3 commits into
The-PR-Agent:mainfrom
remote-controlled-man:codex/pr-agent-selfdisc-20260923
Sep 24, 2026
Merged

IsmaelMartinez merged 3 commits into
The-PR-Agent:mainfrom
remote-controlled-man:codex/pr-agent-selfdisc-20260923

Conversation

@remote-controlled-man

@remote-controlled-man remote-controlled-man commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Create CHANGELOG.md when the GitHub provider confirms the file is absent — same-repository pull requests only (fork PRs re-raise the 404 before any write).
  • Continue updating an existing file using its blob SHA.
  • Propagate other read failures without attempting a write.

Why

The /update_changelog command accepts a missing CHANGELOG.md and can generate its initial content. With pushing enabled, the GitHub provider previously called update_file with an empty SHA after a 404, so that initial content could not be committed.

Validation

  • Two regression tests failed before the provider change and pass afterward; two additional tests cover the fork and deleted-fork cases (no write calls, original 404 propagates).
  • GitHub provider, provider contract, and changelog tool tests: 454 passed.
  • Ruff check on the two changed files passed.

Related: #3524 narrows provider exception handling but does not implement missing-file creation.

Copilot AI lite review requested due to automatic review settings September 23, 2026 03:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Create missing GitHub files during changelog updates

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Create files when GitHub returns 404 instead of attempting an invalid SHA-less update.
• Preserve SHA-based updates for existing files and propagate unrelated read failures.
• Add regression coverage for missing files and non-404 errors.
Diagram

graph TD
  A["Write file request"] --> B["Read branch file"] --> C{"Read result"}
  C -->|Found| D["Update with SHA"] --> G["Return commit"]
  C -->|404| E["Create file"] --> G
  C -->|Other error| F["Propagate error"]
Loading
High-Level Assessment

The status-directed create-or-update flow is the appropriate approach because GitHub exposes separate APIs rather than an atomic upsert. It preserves required SHA-based updates while restricting creation to a confirmed 404; optimistic update retries or broad exception handling could mask authorization, transport, or service failures.

Files changed (2) +64 / -11

Bug fix (1) +19 / -11
github_provider.pyCreate absent files and preserve GitHub read failures +19/-11

Create absent files and preserve GitHub read failures

• The provider now creates a file when its branch lookup returns 404 and updates existing files using their blob SHA. Non-404 GitHub errors are reraised without attempting either write operation.

pr_agent/git_providers/github_provider.py

Tests (1) +45 / -0
test_github_provider_file_content.pyCover missing-file creation and failed-read handling +45/-0

Cover missing-file creation and failed-read handling

• Adds regression tests verifying that 404 responses call 'create_file' and return its commit. Also verifies that non-404 lookup errors propagate without creating or updating a file.

tests/unittest/test_github_provider_file_content.py

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Fork updates can alter the wrong branch ✓ Resolved 🐞 Bug ≡ Correctness
Description
create_or_update_pr_file calls create_file on _get_repo(), which resolves the base repository
from the pull request URL, while its branch argument comes from the unqualified pr.head.ref.
When a fork’s source branch name also exists in the base repository and lacks the requested file,
the new 404 path creates the changelog on that unrelated base branch; if the name does not exist
there, the intended fork update fails.
Code

pr_agent/git_providers/github_provider.py[R1702-1705]

+            response = repo.create_file(
+                path=file_path,
+                message=message,
+                content=contents,
Evidence
set_pr derives self.repo from the pull request URL, and _get_repo resolves that repository,
while get_pr_branch independently returns the head ref without its repository identity. The
changed create path then applies that head branch name to the base repository object, and the
changelog caller supplies exactly this branch value.

pr_agent/git_providers/github_provider.py[213-215]
pr_agent/git_providers/github_provider.py[1221-1222]
pr_agent/git_providers/github_provider.py[1657-1664]
pr_agent/git_providers/github_provider.py[1696-1715]
pr_agent/tools/pr_update_changelog.py[287-292]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Fork pull request writes combine the base repository selected by `_get_repo()` with the source branch name returned by `get_pr_branch()`. The new missing-file path can therefore create `CHANGELOG.md` on a same-named base branch rather than the fork branch.
## Fix Focus Areas
- pr_agent/git_providers/github_provider.py[1696-1715]
- pr_agent/git_providers/github_provider.py[1221-1222]
- tests/unittest/test_github_provider_file_content.py[77-119]
## Recommended Fix
Resolve the write repository and branch as one matched pull-request-head target, using the head repository together with `pr.head.ref` for the existence check, creation, and update. Add a fork regression test with a same-named base branch and assert that the base repository is never read or written while the head repository receives the create call; propagate an access failure when the head repository cannot be written.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. New branch notes use narrative phrasing 📘 Rule violation ⚙ Maintainability
Description
The _pr_head_in_base_repo docstring begins with True when, while the new fork-handling comments
describe behavior narratively instead of using imperative phrasing. These additions establish the
same nonconforming style across production logic and regression tests, encouraging later
explanations of this branch behavior to follow it.
Code

pr_agent/git_providers/github_provider.py[1725]

+        """True when the pull request head branch lives in the base repository itself.
Evidence
Compliance rule 2694688 requires added docstrings and behavioral comments to use imperative
phrasing. The cited additions instead begin with True when, A fork pull request resolves, `Fork
pull request, and GitHub reports`, all of which are descriptive rather than imperative.

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/git_providers/github_provider.py[1703-1706]
pr_agent/git_providers/github_provider.py[1725-1730]
tests/unittest/test_github_provider_file_content.py[112-113]
tests/unittest/test_github_provider_file_content.py[138-138]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `_pr_head_in_base_repo` docstring and fork-handling comments use descriptive or fragmentary phrasing rather than the required imperative style.
## Fix Focus Areas
- pr_agent/git_providers/github_provider.py[1703-1706]
- pr_agent/git_providers/github_provider.py[1725-1730]
- tests/unittest/test_github_provider_file_content.py[112-113]
- tests/unittest/test_github_provider_file_content.py[138-138]
## Recommended Fix
Rewrite the docstring to begin with an imperative phrase such as `Return whether`, and rewrite the behavioral comments as concise instructions while preserving their meaning.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


  • Author self-review: I have reviewed the code review findings, and addressed the relevant ones.

Grey Divider

Tip of the day
💡 Did you know, you can choose which labels appear on a finding, and whether they show icons or text

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@IsmaelMartinez IsmaelMartinez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this one, and for flagging #3524 so the overlap was easy to place. The missing-file fix holds: both new tests go red against main's provider, and the non-404 path now raises instead of writing.

One ask before approval, on Qodo's fork finding. Main already reads and updates CHANGELOG.md on the base repository's branch named after the fork's head ref; this change adds creating it there, so a fork pull request opened from its own main can now create the file on the base repository's main. Could the create path run only for same-repository pull requests, with a test for the fork case? Further security findings are best reported privately at https://github.com/The-PR-Agent/pr-agent/security/advisories/new.

@remote-controlled-man

Copy link
Copy Markdown
Contributor Author

Done — the create path is now gated to same-repository pull requests (_pr_head_in_base_repo() compares head.repo.full_name against the base repo, case-insensitively; a missing or deleted fork head is treated as a fork, so the failure direction stays safe). Fork PRs re-raise the original 404 before any write call, preserving the pre-existing fallback behavior. Added two tests for the fork and deleted-fork cases asserting zero write calls; the updated same-repo test asserts exactly one create_file call. Focused file: 10 passed; changelog pair: 60 passed.

One related observation while in here (pre-existing, out of scope for this fix): when the file already exists on the base repository's same-named branch, the update path can still write there for fork PRs — that behavior predates this PR. Happy to open a follow-up issue if you want it tracked.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit b9a2b37

# Conflicts:
#	pr_agent/git_providers/github_provider.py
@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 758285c

@IsmaelMartinez IsmaelMartinez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for gating the create path to same-repository pull requests and testing both the fork and deleted-fork cases. #3524 changed the same except today, so I merged main in and kept your version of create_or_update_pr_file. Qodo's docstring phrasing note is style only. For the update-path observation, please use the private form rather than a public issue: https://github.com/The-PR-Agent/pr-agent/security/advisories/new. Approving, and merging once CI has run.

@IsmaelMartinez
IsmaelMartinez merged commit 7c64665 into The-PR-Agent:main Sep 24, 2026
10 checks passed
@remote-controlled-man
remote-controlled-man deleted the codex/pr-agent-selfdisc-20260923 branch October 13, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants