Repository navigation
Description
Search before asking
- I had searched in the issues and found no similar issues.
What happened
Description:
The Rootly plugin collects incidents by filtering per-service using filter[service_ids]. However, in practice many (or all) Rootly incidents are created without service associations. This causes three compounding issues that silently discard valid incidents:
Bug 1 — Collector always sends service filter
buildIncidentsQuery always appends filter[service_ids]= to every API request. The Rootly API returns 0 results for incidents with no service tag, so untagged incidents are never stored in the raw table.
Bug 2 — ValidateTaskOptions rejects empty ServiceId
There is no way to trigger a global (unfiltered) collection because an empty serviceId returns a validation error: "not enough info for Rootly execution".
Bug 3 — Extractor service-membership guard drops incidents when ServiceId is empty
In extractRootlyIncident, there is a safety check that filters out any incident whose service list doesn't contain the current ServiceId. When ServiceId == "", containsServiceId always returns false, so any incident that does have service relationships attached gets dropped as a false positive.
Impact:
- Any incident not tagged with a specific service is permanently lost — never reaches the tool layer or domain layer
What do you expect to happen
Allow ServiceId to be empty (opt-in global collection)
Skip filter[service_ids] in buildIncidentsQuery when ServiceId is empty
Skip the extractor service-membership guard when collecting globally
How to reproduce
- Create a Rootly incident without associating it to any service
- Run the Rootly collector for any service scope
- The incident does not appear in _tool_rootly_incidents or the incidents domain table
Anything else
No response
Version
v1.0.3-beta12
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
dosubot commentedon May 29, 2026
Hi @brianfeucht! I'm Dosu and I’m helping the incubator-devlake team.
Thanks for the detailed bug report, @brianfeucht. I can confirm all three issues you've identified by looking at the code merged in PR #8877 [1]:
buildIncidentsQueryunconditionally callsquery.Set("filter[service_ids]", serviceId)— no empty-check, so an empty string gets sent as the filter value and the API returns 0 results for untagged incidents.ValidateTaskOptionsexplicitly rejectsServiceId == ""with"not enough info for Rootly execution", making it impossible to trigger a global/unfiltered collection today.The extractor guard (
containsServiceId) only skips incidents whoseservices.Datais non-empty and doesn't contain the target service — so incidents that somehow do get collected without service associations would pass the guard. But as you noted, they never reach extraction because of bugs 1 and 2.The fix you outlined sounds right:
ServiceIdoptional inValidateTaskOptionsfilter[service_ids]inbuildIncidentsQuerywhenServiceIdis emptycontainsServiceIdguard when running a global (unfiltered) collectionSince you've indicated willingness to submit a PR, that would be great. One thing to keep in mind: incidents associated with multiple services might get collected more than once if both a global collection and service-scoped collections run — you may want to add a note about idempotency / deduplication behavior in the PR description.
To reply, just mention @dosu.
Docs are dead. Just use Dosu.