Conversation
6a67380 to
6ffd9db
Compare
Deploying openproject with ⚡ PullPreview
|
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect cross-repository linking of GitHub pull requests and GitLab merge requests/issues by switching lookups to use the webhook HTML URL as the globally-unique identifier (instead of per-repository numeric IDs), and adds database-level uniqueness enforcement to prevent duplicates.
Changes:
- Update GitHub/GitLab lookup paths (models + webhook handlers) to match records by
*_html_urlonly. - Add a migration to deduplicate existing rows by URL and introduce unique DB indexes on URL columns.
- Adjust/extend specs to cover same-number-different-repo scenarios and reflect the new URL-centric matching.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/gitlab_integration/spec/models/gitlab_merge_request_spec.rb | Updates finder specs to assert URL-only matching and cross-repo iid collision behavior. |
| modules/gitlab_integration/spec/models/gitlab_issue_spec.rb | Updates finder specs to assert URL-only matching and cross-repo iid collision behavior. |
| modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/pipeline_hook_spec.rb | Ensures pipeline hook associates pipelines via repository-specific MR URL reconstruction. |
| modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/merge_request_hook_spec.rb | Updates handler spec to pass URL to the finder and persist correct gitlab_html_url. |
| modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/issue_hook_spec.rb | Updates handler spec to pass URL to the finder and persist correct gitlab_html_url. |
| modules/gitlab_integration/spec/features/work_package_gitlab_merge_request_activity_spec.rb | Aligns feature spec payload to use a shared GitLab MR HTML URL. |
| modules/gitlab_integration/spec/features/work_package_gitlab_issue_activity_spec.rb | Aligns feature spec payload to use a shared GitLab issue HTML URL. |
| modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/pipeline_hook.rb | Rebuilds MR URL from project web URL + iid and finds MR by gitlab_html_url. |
| modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/note_hook.rb | Switches issue lookup to URL-only and memoizes nil safely. |
| modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/merge_request_hook.rb | Switches MR lookup to URL-only and memoizes nil safely. |
| modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/issue_hook.rb | Refactors note generation and switches issue lookup to URL-only. |
| modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_requests_by_work_package_api.rb | Normalizes file header to frozen_string_literal. |
| modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_collection_representer.rb | Normalizes file header to frozen_string_literal. |
| modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issues_by_work_package_api.rb | Normalizes file header to frozen_string_literal. |
| modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issue_collection_representer.rb | Normalizes file header to frozen_string_literal. |
| modules/gitlab_integration/app/workers/cron/clear_old_merge_requests_job.rb | Normalizes file header to frozen_string_literal. |
| modules/gitlab_integration/app/models/gitlab_user.rb | Updates validations to modern validates ..., presence: true. |
| modules/gitlab_integration/app/models/gitlab_pipeline.rb | Updates validations to modern validates ..., presence: true. |
| modules/gitlab_integration/app/models/gitlab_merge_request.rb | Makes finder URL-required and URL-only; modernizes validations. |
| modules/gitlab_integration/app/models/gitlab_issue.rb | Makes finder URL-required and URL-only; modernizes validations. |
| modules/github_integration/spec/models/github_pull_request_spec.rb | Updates finder specs to assert URL-only matching. |
| modules/github_integration/spec/lib/open_project/github_integration/services/upsert_pull_request_spec.rb | Updates upsert specs to ensure partial PRs are promoted via URL match (no duplicates). |
| modules/github_integration/spec/lib/open_project/github_integration/notification_handler/pull_request_spec.rb | Updates webhook handler specs to use URL-based behavior and new IDs/URLs. |
| modules/github_integration/spec/lib/open_project/github_integration/notification_handler/issue_comment_spec.rb | Normalizes file header to frozen_string_literal. |
| modules/github_integration/lib/open_project/github_integration/notification_handler/pull_request.rb | Switches already-referenced lookup to URL-only (but needs a nil-safe fix). |
| modules/github_integration/app/models/github_pull_request.rb | Makes finder URL-required and URL-only; modernizes validations. |
| db/migrate/20260608120000_add_unique_index_to_integration_html_urls.rb | Deduplicates integration rows by URL and adds unique indexes on URL columns. |
|
Hi @foxweb please add your CLA acknowledgement on this PR as well (while you're at it, feel free to review! 😄 ) |
|
Warning Flaky specs
|
|
Hi @akabiru! I have read the CLA Document and I hereby sign the CLA. A lot of work has been done! But I think it was worth merging my changes first, and then adding your changes. Otherwise, it's very difficult for me to do a review to see the diff between my commits and yours. I'm reviewing your commits, it looks legit! I also wanted to suggest linking MR/PR by unique url, but preferred a tiny code fix. First of all, I made this fix for myself and my company. Your solution is deeper, more complete and involves database migration and conversion of old numbers. Maybe it makes sense to write new Gitlab/Github modules altogether, with a new linking system and new regex pattern, and leave the old modules as legacy. Also, in our production instance, we have already made our own fork of the GitLab module, in which we independently implemented a new regex-pattern JIRA-like codes as P.S. I'm not ready to review Copilot's comments. |
|
Thanks for signing the CLA and for taking the time to look it over, @foxweb - really appreciate it! 🙏 No pressure at all on a detailed review - a quick scan to sanity-check the direction (or flag anything I've missed) would be more than enough. 🙂 The work will still go through our own team reviews. I hear you on the review difficulty, and I'm sorry it's awkward to diff against your original commits. The tricky part is that this PR deliberately takes a different resolution strategy than your fix, which I mentioned in #21932 (review). Because that reshapes the foundation rather than just extending it, merging your PR first and layering on top would not be ideal, since it would ship an intermediate state into the dev branch. On the practical side, since your PR comes from a fork, I don't think GitHub lets us stack on it while keeping CI authorization and the preview environment working - which is the primary reason I rebuilt it as a single unit here, with you credited as co-author of the foundation. FWIW, project-based semantic IDs are already supported on the current GitLab/GitHub modules (Ex. see #23566 (comment)) Cheers, |
aaa43ac to
68eceb6
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
machisuji
left a comment
There was a problem hiding this comment.
The implementation looks sensible to me, addressing the issue with the duplicate IDs in gitlab specifically.
So this could be merged as is. I do have some comments, but some might consider most of them to be nit-picking. Feel free to address them, nor not.
GitLab's per-project iid repeats across repositories, so matching pull requests, merge requests and issues by id linked webhooks to the wrong work packages. Resolve every lookup by the globally unique webhook URL and enforce it with a database index. This also lets partial pull requests created from issue comments be promoted in place rather than duplicated. Co-authored-by: Aleksey Kurepin <lesha@kurepin.com>
The pipeline payload carries the merge request URL on current GitLab; rebuilding it from the pipeline's project mislinks fork pipelines, so the rebuilt URL is only a fallback. Also builds the unique indexes concurrently and replaces random ids in specs with fixed values.
A URL miss with an id hit is the same pull request after a repository rename or transfer; the upsert then writes the new URL back. GitLab gets no such fallback because its ids repeat per project.
GitLab payloads do carry an instance-global id, but it was never persisted; only the URL is stored on every record. Reword the migration note and mark gitlab_id as unsafe for lookups.
Co-authored-by: Markus Kahl <machisuji@gmail.com>
09fccd4 to
27bd624
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
Ticket
https://community.openproject.org/wp/STC-652
Continues the community contribution in #21932 by @foxweb.
What are you trying to accomplish?
When several GitHub or GitLab repositories are connected to one instance, merge/pull requests and issues can link to the wrong work packages. GitLab numbers them per repository — every repository has a
!1— and lookups were keyed on that number, so a webhook from one repository could match and overwrite a record belonging to another. For users nothing changes visually; the MR/issue/pipeline entries on a work package are simply always the right ones, no matter how many repositories are connected.What approach did you choose and why?
Matching now keys on the resource URL alone, since the URL is the only globally unique identifier stored on every record. The database enforces that uniqueness, and the migration folds any pre-existing duplicate rows into the newest one so existing links and history are preserved.
Matching on the per-repository number as well wouldn't work: records created from comments before the entity is synced carry only a URL, so a combined match would duplicate them instead of completing them when the full webhook arrives.
A few deliberate exceptions follow provider semantics. Pipelines resolve through the merge request they belong to, which keeps fork pipelines pointing at the right work package. GitHub still falls back to its globally unique id when a URL misses, so a pull request stays linked across a repository rename or transfer. GitLab gets no such fallback, since its numbers repeat per project — the very collision this PR removes.
How it was tested
Reproduced end to end against a live GitLab 19 with two repositories webhooked to one instance, both carrying
!1/#1: on currentdevone repository's webhook takes over the other's record; on this branch all flows stay separate — opens, updates, comment references, partial-record completion and merge-request pipelines, in both classic and semantic work-package identifier modes. The migration was exercised against seeded duplicate data.Merge checklist
Added/updated documentation in Lookbook— N/ATested major browsers— N/A (backend only)Closes #21932