Skip to content

fix(backend): treat GitHub PRs with merged_at as merged - #309

Merged
stefan-ernst merged 2 commits into
Windshiftapp:mainfrom
spatialy:fix/github-merged-pr-detection
Oct 5, 2026
Merged

stefan-ernst merged 2 commits into
Windshiftapp:mainfrom
spatialy:fix/github-merged-pr-detection

Conversation

@spatialy

@spatialy spatialy commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Fixes #304.

What

githubPullRequest.toPullRequest() now sets IsMerged from merged || merged_at != nil instead of merged alone.

Why

SCM sync lists PRs with GET /repos/{owner}/{repo}/pulls. GitHub's list response has no merged field, only merged_at, so every listed PR converted with IsMerged = false. Sync then stored merged PRs as closed, skipped emitPRMergedEvent, and never ran smart commits. The single-PR endpoint (GetPullRequest) does return merged, which is why a link later flips to "Merged" on refresh.

This matches the GitLab provider, which already uses state == "merged" || MergedAt != nil. Gitea's list endpoint returns merged, so only the GitHub provider changes.

Tests

internal/scm/github_pull_request_test.go (with a .gitignore exception, like gitlab_test.go) drives ListPullRequests through a fake transport with list-shaped JSON and checks merged, closed-unmerged and open PRs, plus the existing merged: true path.

I couldn't run the Go suite locally against Go 1.27, so please let CI and core-tests confirm.

Not in this PR

The refresh path in #304 is still open. updateLinkFromProvider writes state = merged without emitting scm_pr_merged. If a user refreshes a link between the merge and the next sync, sync then sees previousState == merged and doesn't emit the event either. This fix makes the race narrow, because sync now detects merges on its own. Closing it fully means routing the refresh through upsertPullRequestSCMLink, or emitting from the refresh path. I can follow up with whichever approach you prefer.

GitHub's list endpoint (GET /repos/{owner}/{repo}/pulls), which the SCM
sync uses, omits the `merged` field and only returns `merged_at`. Every
listed PR therefore converted with IsMerged = false, so sync stored merged
PRs as "closed", never emitted scm_pr_merged, and skipped smart commits.

Count a non-nil MergedAt as merged as well. The single-PR endpoint keeps
working as before because it sets both fields.

Fixes Windshiftapp#304
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@spatialy

spatialy commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Oct 5, 2026
@stefan-ernst
stefan-ernst merged commit 0dcb1eb into Windshiftapp:main Oct 5, 2026
15 of 19 checks passed
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.

GitHub: merged PRs sync as "closed", so scm_pr_merged automations and smart commits never fire

2 participants