Skip to content

fix: correct on-call filter params and add name-based filtering#34

Open
jeffreytolar wants to merge 2 commits into
rootlyhq:masterfrom
jeffreytolar:fix/oncall-filter-params
Open

fix: correct on-call filter params and add name-based filtering#34
jeffreytolar wants to merge 2 commits into
rootlyhq:masterfrom
jeffreytolar:fix/oncall-filter-params

Conversation

@jeffreytolar
Copy link
Copy Markdown

Summary

  • Fix plural filter params: The /v1/oncalls endpoint requires plural
    query param names (e.g. filter[user_ids][], filter[team_ids][]). The
    previous singular forms were silently ignored by the API. See
    https://docs.rootly.com/api-reference/oncalls/list-on-calls for the
    expected parameter names.
  • Add name-based filtering: oncall shifts and oncall who now accept
    --user-name and --team-name flags. These do a local resolve (list all,
    match by name) when an ID isn't known, making the CLI more ergonomic for
    interactive use.

Changes

  • internal/api/client.go — fix param pluralization; add name-resolution
    helpers for users and teams
  • internal/cmd/oncall/oncall.go — shared filter-flag wiring
  • internal/cmd/oncall/shifts.go / who.go — expose new --user-name /
    --team-name flags
  • internal/cmd/oncall/cmd_test.go — expanded test coverage for both fixes

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 4, 2026

Greptile Summary

Fixes the /v1/oncalls query parameter names from singular to plural (schedule_idschedule_ids, etc.) to match the Rootly API spec, and adds ergonomic --schedule, --service, --user, and --team name-resolution flags to oncall shifts and oncall who. The PR also backfills neturl.QueryEscape for filter values across several other list endpoints.

  • Param pluralization fix: filter[schedule_ids], filter[service_ids], filter[escalation_policy_ids], filter[user_ids], and the new filter[group_ids] are now correctly named; the API-confirmed term for team filtering is group_ids (per the Rootly OpenAPI spec).
  • Name-resolution helpers: Four new Resolve*ByName / ResolveUserID functions perform a server-side lookup and return the resolved ID, with mutual-exclusion guards preventing --x-id and --x from being used together.
  • URL encoding: neturl.QueryEscape is applied to filter values in ListIncidentsCLI, ListAlertsCLI, ListServicesCLI, ListTeamsCLI, and ListSchedulesCLI, though the parallel filter concatenation inside ListOnCallsCLI does not receive the same treatment.

Confidence Score: 4/5

Safe to merge; the core bug fixes are correct and the new name-resolution paths are well-tested.

The pluralization fix and resolver helpers are solid. The one rough edge is that the URL-encoding hardening applied to five other list functions in this PR was not extended to the ListOnCallsCLI filter values — if an ID flag ever contains a special character, those filters would be silently dropped. That gap is unlikely to bite in practice given Rootly's ID format, but it is inconsistent with the rest of the change.

internal/api/client.go — specifically the ListOnCallsCLI filter-value concatenation block (lines 2965–2979) and the multi-result guard in ResolveUserID (around line 202).

Important Files Changed

Filename Overview
internal/api/client.go Fixes plural filter param names for /v1/oncalls, adds GroupIDs field, adds URL encoding for filter values across other list functions, and adds four name-resolution helpers. The oncalls filter values themselves are not URL-encoded unlike the newly-fixed other list functions.
internal/cmd/oncall/oncall.go Adds shared resolver helpers (resolveScheduleID, resolveServiceID, resolveUserID, resolveTeamID) with correct mutual-exclusion guards between --x-id and --x name flags.
internal/cmd/oncall/shifts.go Exposes new --schedule, --service, --user, --team-id, --team flags and wires them through the resolver helpers; GroupIDs correctly populated in OnCallsParams.
internal/cmd/oncall/who.go Mirror of shifts.go changes for the who subcommand; new name-based filter flags added and resolver helpers invoked correctly.
internal/cmd/oncall/cmd_test.go Adds helper flag-registration functions and tests for name-based resolution, mutual exclusion, and not-found errors. Email filter assertion in TestRunShiftsWithUserEmailFilter uses a substring match rather than verifying the full encoded value.

Comments Outside Diff (1)

  1. internal/api/client.go, line 199-205 (link)

    P2 Email filter allows silent first-result selection on multiple matches

    When filterKey == "email", the function only errors on multiple matches when the filter is search. If the API's email filter ever returns more than one result (e.g., due to a partial-match behaviour), response.Data[0].ID is silently returned without any warning. For consistency with the search branch, consider checking len(response.Data) > 1 unconditionally.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: internal/api/client.go
    Line: 199-205
    
    Comment:
    **Email filter allows silent first-result selection on multiple matches**
    
    When `filterKey == "email"`, the function only errors on multiple matches when the filter is `search`. If the API's email filter ever returns more than one result (e.g., due to a partial-match behaviour), `response.Data[0].ID` is silently returned without any warning. For consistency with the `search` branch, consider checking `len(response.Data) > 1` unconditionally.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
internal/api/client.go:2965-2979
**OnCalls filter values not URL-encoded**

The `ListIncidentsCLI`, `ListAlertsCLI`, `ListServicesCLI`, `ListTeamsCLI`, and `ListSchedulesCLI` filter values are all updated in this PR to use `neturl.QueryEscape`, but the equivalent filter values appended in `ListOnCallsCLI` are left as raw string concatenation. If a user passes a `--schedule-id` or `--user-id` value that contains characters like `+` or `&`, the resulting query string would be silently malformed and the filter ignored.

### Issue 2 of 2
internal/api/client.go:199-205
**Email filter allows silent first-result selection on multiple matches**

When `filterKey == "email"`, the function only errors on multiple matches when the filter is `search`. If the API's email filter ever returns more than one result (e.g., due to a partial-match behaviour), `response.Data[0].ID` is silently returned without any warning. For consistency with the `search` branch, consider checking `len(response.Data) > 1` unconditionally.

Reviews (1): Last reviewed commit: "feat: add name-based filtering for oncal..." | Re-trigger Greptile

Comment thread internal/api/client.go
Comment on lines 2965 to 2979
if params.ScheduleIDs != "" {
qp = append(qp, "filter[schedule_id]="+params.ScheduleIDs)
qp = append(qp, "filter[schedule_ids]="+params.ScheduleIDs)
}
if params.ServiceIDs != "" {
qp = append(qp, "filter[service_id]="+params.ServiceIDs)
qp = append(qp, "filter[service_ids]="+params.ServiceIDs)
}
if params.EscalationPolicyIDs != "" {
qp = append(qp, "filter[escalation_policy_id]="+params.EscalationPolicyIDs)
qp = append(qp, "filter[escalation_policy_ids]="+params.EscalationPolicyIDs)
}
if params.UserIDs != "" {
qp = append(qp, "filter[user_id]="+params.UserIDs)
qp = append(qp, "filter[user_ids]="+params.UserIDs)
}
if params.GroupIDs != "" {
qp = append(qp, "filter[group_ids]="+params.GroupIDs)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 OnCalls filter values not URL-encoded

The ListIncidentsCLI, ListAlertsCLI, ListServicesCLI, ListTeamsCLI, and ListSchedulesCLI filter values are all updated in this PR to use neturl.QueryEscape, but the equivalent filter values appended in ListOnCallsCLI are left as raw string concatenation. If a user passes a --schedule-id or --user-id value that contains characters like + or &, the resulting query string would be silently malformed and the filter ignored.

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/api/client.go
Line: 2965-2979

Comment:
**OnCalls filter values not URL-encoded**

The `ListIncidentsCLI`, `ListAlertsCLI`, `ListServicesCLI`, `ListTeamsCLI`, and `ListSchedulesCLI` filter values are all updated in this PR to use `neturl.QueryEscape`, but the equivalent filter values appended in `ListOnCallsCLI` are left as raw string concatenation. If a user passes a `--schedule-id` or `--user-id` value that contains characters like `+` or `&`, the resulting query string would be silently malformed and the filter ignored.

How can I resolve this? If you propose a fix, please make it concise.

jeffreytolar and others added 2 commits June 5, 2026 00:52
The API expects filter[schedule_ids], filter[service_ids], etc. but
the CLI was sending singular forms (filter[schedule_id]) which the
server silently ignores.

Co-authored-by: Cursor <cursoragent@cursor.com>
Allow filtering by human-readable names instead of opaque IDs:
  --schedule="Primary On-Call"  (resolves via /v1/schedules)
  --service="API Gateway"       (resolves via /v1/services)
  --team="Platform Engineering" (resolves via /v1/teams)
  --user="alice@example.com"    (resolves via /v1/users)

Each name flag is mutually exclusive with its ID counterpart.
User lookup uses filter[email] for addresses containing @,
filter[search] otherwise.

Also adds --team-id/--team flags (maps to filter[group_ids]),
URL-encodes filter values to handle spaces and special chars,
and refactors tests with addShiftsFlags/addWhoFlags helpers.

Co-authored-by: Cursor <cursoragent@cursor.com>
@jeffreytolar jeffreytolar force-pushed the fix/oncall-filter-params branch from bee3d7d to c096974 Compare June 5, 2026 05:53
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.

1 participant