Skip to content

feat(native): sync owning team for services/functionalities and resolve kind: group fields - #25

Merged
devin-ai-integration[bot] merged 6 commits into
masterfrom
devin/1791494941-service-owner-team
Oct 9, 2026
Merged

devin-ai-integration[bot] merged 6 commits into
masterfrom
devin/1791494941-service-owner-team

Conversation

@kwent

@kwent kwent commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

This PR is the CLI half of PRF-3452. Backstage users can now map spec.owner straight to the owning team of a service or functionality:

to: service            # or: functionality
map:
  owner_team: "{{ .spec.owner }}"      # e.g. group:default/sre
  responder:  { value: "{{ .team }}", kind: group }
  • owner_team built-in (client.AttrOwnerTeam, gated by client.HasOwnerTeam), for services and functionalities.
    • It's sent as owner_group_ids: [id] on /v1/{services,functionalities}/bulk_upsert.
    • The live value is the record's owner_group_ids, comma-joined (setOwnerTeam), so plan/diff only shows a change when the owner actually differs.
    • rootly-go's bulk upsert types don't model owner_group_ids yet. withOwners injects it into the encoded body, and the request goes through Bulk*WithBodyWithResponse. Batches with no owners send the same bytes as before.
    • Backward compatible: if the resource type already has a custom property with slug owner_team, that property keeps syncing as a property. That case gets no team lookup, no owner_group_ids, and live owners aren't reported under owner_team. The check is in Client.OwnerTeamIsBuiltin / KnownAttrsWithProps.
  • Team resolution (resolveTeamFields). It's called from resolveReferenceFields, so plan, sync and explain all get it.
    • The built-in owner_team and any kind: group field are resolved to a team ID by matching the team's ID, then external_id, then backstage_id, then name.
    • Teams are listed once per output, and only when one of these fields is configured.
    • An unknown team fails the plan with a clear error.
    • An empty owner_team is dropped, so the current owners stay unchanged.
    • An empty kind: group value is kept, so it tries to clear the live value. Today the API rejects blank values for every single-value custom property type with a 422.

Depends on rootlyhq/rootly#24148 (merged; in train-prod-2373), which makes the API accept owner_group_ids on services and functionalities bulk upsert.

Tests:

  • Unit tests:
    • TestBulkUpsertNative_{Service,Functionality}OwnerTeam and TestBulkUpsertNative_OwnerTeamCustomProperty
    • Test{Service,Functionality}ToLive_OwnerTeam and TestServiceToLive_OwnerTeamCustomProperty
    • TestKnownAttrsWithProps
    • TestResolveReferenceFields_{Teams,UnknownTeam,FunctionalityOwnerTeam,OwnerTeamCustomProperty,OwnerTeamIgnoredOutsideServices}
  • New integration step, Integration — native owner_team, in .github/workflows/integration.yaml. It runs on push to master and on workflow_dispatch, and fails if any of its status checks fail.
    • Uses two teams with Backstage-style external_ids.
    • Checks owner create, idempotent re-sync, a move from team A to team B (the plan must show 2 owner_team diffs), and that leaving owner_team unmapped keeps the owners.
    • It needs a working INTEGRATION_API_KEY.
  • Local runtime validation against a Rootly API that includes #24148 passed; results are in the PR comment.

Link to Devin session: https://rootly.devinenterprise.com/sessions/ba7eaa797c98438bb7166d6f8a275fbd
Open in Devin Desktop: https://rootly.devinenterprise.com/desktop/session/ba7eaa797c98438bb7166d6f8a275fbd?variant=devin
Requested by: @kwent

…elds

Adds an owner_team built-in for services, sent as owner_group_ids, and
resolves owner_team and kind: group values to team IDs by id,
external_id, backstage_id or name.

Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat(native): sync a service's owning team and resolve kind: group fields feat(native): sync owning team for services/functionalities and resolve kind: group fields Oct 8, 2026
…ties

Co-Authored-By: Quentin Rousseau <quentin@rootly.com>

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👀 1 finding needs your review

Devin fixed 1 of 2 findings on 6cf486c. Click a finding below to jump to its comment.

For your review (1)

Fixed by Devin (1)

  • Empty group mapping leaves stale membership

View all findings in Devin Review

Devin Review

Co-Authored-By: Quentin Rousseau <quentin@rootly.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

Devin Review

Comment thread client/native.go
devin-ai-integration Bot and others added 2 commits October 9, 2026 04:03
… property

Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
Co-Authored-By: Quentin Rousseau <quentin@rootly.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

Local runtime validation: PASS for the owner_team scope at fab1a75, run against a local Rootly API at 3a3f37b (rootly#24148). The only commit since then, f219b66, makes the owner_team integration step fail when a status check fails.

  • The Integration — native owner_team script printed all six ✓ lines. Separate GETs confirmed the owners of both the service and the functionality went A → B, then stayed B when owner_team was omitted.
  • Custom owner_team property collision: a functionality TEXT property with slug owner_team kept the value "Platform notes" as a property. No team lookup ran and no owner_group_ids was sent, owners stayed B, and a re-sync showed no drift.
  • Checked on 230791f and not re-run on this revision:
    • unknown-team plans fail with no writes;
    • name and UUID resolution work;
    • an empty owner keeps the current owners;
    • [] clears owners;
    • a group from another org returns a 422.
Native ownership Property collision
Native CLI/API evidence Collision CLI/API evidence
Limitations

Written by Devin

@devin-ai-integration
devin-ai-integration Bot merged commit 7a50f69 into master Oct 9, 2026
4 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.

1 participant