Merge pull request #34265 from backstage/freben/stable-multi-org-order

github: stabilize entity order in multi-org provider
This commit is contained in:
Fredrik Adelöw
2026-05-19 10:23:43 +02:00
committed by GitHub
3 changed files with 35 additions and 13 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': patch
---
The `GithubMultiOrgEntityProvider` now emits entities in a stable order during full mutations. Entities are sorted by entity ref, with the location annotation as a tiebreaker for entities that share the same ref. This prevents entity data from flickering between different GitHub orgs across refresh cycles when `alwaysUseDefaultNamespace` is enabled and teams with identical slugs exist in multiple orgs.
@@ -212,7 +212,7 @@ describe('GithubMultiOrgEntityProvider', () => {
});
expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({
entities: [
entities: expect.arrayContaining([
{
entity: {
apiVersion: 'backstage.io/v1alpha1',
@@ -352,7 +352,7 @@ describe('GithubMultiOrgEntityProvider', () => {
},
locationKey: 'github-multi-org-provider:my-id',
},
],
]),
type: 'full',
});
});
@@ -526,7 +526,7 @@ describe('GithubMultiOrgEntityProvider', () => {
});
expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({
entities: [
entities: expect.arrayContaining([
{
entity: {
apiVersion: 'backstage.io/v1alpha1',
@@ -666,7 +666,7 @@ describe('GithubMultiOrgEntityProvider', () => {
},
locationKey: 'github-multi-org-provider:my-id',
},
],
]),
type: 'full',
});
});
@@ -804,7 +804,7 @@ describe('GithubMultiOrgEntityProvider', () => {
await entityProvider.read();
expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({
entities: [
entities: expect.arrayContaining([
{
entity: {
apiVersion: 'backstage.io/v1alpha1',
@@ -942,7 +942,7 @@ describe('GithubMultiOrgEntityProvider', () => {
},
locationKey: 'github-multi-org-provider:my-id',
},
],
]),
type: 'full',
});
});
@@ -351,15 +351,32 @@ export class GithubMultiOrgEntityProvider implements EntityProvider {
const { markCommitComplete } = markReadComplete({ allUsers, allTeams });
const allEntities = [...allUsers, ...allTeams].map(entity => ({
locationKey: `github-multi-org-provider:${this.options.id}`,
entity: withLocations(
`https://${this.options.gitHubConfig.host}`,
entity,
),
}));
allEntities.sort((a, b) => {
const am = a.entity.metadata;
const bm = b.entity.metadata;
if (am.name !== bm.name) return am.name < bm.name ? -1 : 1;
const al = am.annotations?.[ANNOTATION_LOCATION] ?? '';
const bl = bm.annotations?.[ANNOTATION_LOCATION] ?? '';
if (al !== bl) return al < bl ? -1 : 1;
if (a.entity.kind !== b.entity.kind) {
return a.entity.kind < b.entity.kind ? -1 : 1;
}
const ans = am.namespace ?? '';
const bns = bm.namespace ?? '';
if (ans !== bns) return ans < bns ? -1 : 1;
return 0;
});
await this.connection.applyMutation({
type: 'full',
entities: [...allUsers, ...allTeams].map(entity => ({
locationKey: `github-multi-org-provider:${this.options.id}`,
entity: withLocations(
`https://${this.options.gitHubConfig.host}`,
entity,
),
})),
entities: allEntities,
});
markCommitComplete();