Skip to content

Commit 56fcb1f

Browse files
Fix Copilot seat organization attribution causing wrong DORA adoption denominator
1 parent 739771b commit 56fcb1f

4 files changed

Lines changed: 16 additions & 5 deletions

File tree

backend/plugins/gh-copilot/tasks/metrics_extractor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type copilotSeatResponse struct {
3939
LastActivityEditor string `json:"last_activity_editor"`
4040
Assignee copilotAssignee `json:"assignee"`
4141
AssigningTeam *copilotTeam `json:"assigning_team"`
42+
Organization *copilotOrgRef `json:"organization"`
4243
}
4344

4445
type copilotAssignee struct {
@@ -49,6 +50,11 @@ type copilotAssignee struct {
4950
Email string `json:"email"`
5051
}
5152

53+
type copilotOrgRef struct {
54+
Login string `json:"login"`
55+
Id int64 `json:"id"`
56+
}
57+
5258
type copilotTeam struct {
5359
Id int64 `json:"id"`
5460
Name string `json:"name"`

backend/plugins/gh-copilot/tasks/seat_extractor.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,14 @@ func ExtractSeats(taskCtx plugin.SubTaskContext) errors.Error {
9191
return nil, err
9292
}
9393

94+
seatOrganization := connection.Organization
95+
if seat.Organization != nil && seat.Organization.Login != "" {
96+
seatOrganization = seat.Organization.Login
97+
}
98+
9499
toolSeat := &models.GhCopilotSeat{
95100
ConnectionId: data.Options.ConnectionId,
96-
Organization: connection.Organization,
101+
Organization: seatOrganization,
97102
UserLogin: seat.Assignee.Login,
98103
UserId: seat.Assignee.Id,
99104
UserName: seat.Assignee.Name,

grafana/dashboards/mysql/github-copilot-dora-correlation.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

grafana/dashboards/postgresql/github-copilot-dora-correlation.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@
460460
"datasource": {"type": "grafana-postgresql-datasource", "uid": "devlake-postgres-api"},
461461
"format": "table",
462462
"rawQuery": true,
463-
"rawSql": "WITH _copilot_adoption AS (SELECT metric_date, ROUND(CAST(active_users * 100.0 AS NUMERIC) / NULLIF(NULLIF(total_seats, 0), 0), 1) AS adoption_pct FROM (SELECT day AS metric_date, SUM(daily_active_users) AS active_users, (SELECT COUNT(*) FROM _tool_copilot_seats AS s WHERE ('${connection_id}' = '' OR s.connection_id::text = '${connection_id}') AND COALESCE(s.organization, '') = COALESCE((SELECT sc.organization FROM _tool_copilot_scopes AS sc WHERE ('${connection_id}' = '' OR sc.connection_id::text = '${connection_id}') AND sc.id = '${scope_id}' LIMIT 1), '')) AS total_seats FROM _tool_copilot_enterprise_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(day) GROUP BY day UNION ALL SELECT date AS metric_date, total_active_users AS active_users, seat_total AS total_seats FROM _tool_copilot_org_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(date)) AS _unified), _adoption_weekly AS (SELECT metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day' AS week_start, AVG(adoption_pct) AS adoption_pct FROM _copilot_adoption GROUP BY metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day'), _pr_metrics_weekly AS (SELECT CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day' AS week_start, CAST(AVG(pr_cycle_time) AS NUMERIC) / NULLIF(60.0, 0) AS avg_cycle_time_hours FROM project_pr_metrics WHERE ('${project:sqlstring}' = '' OR project_name::text = '${project:sqlstring}') AND $__timeFilter(pr_merged_date) GROUP BY CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day'), _adoption_pr_joined AS (SELECT aw.week_start, aw.adoption_pct, pm.avg_cycle_time_hours, CASE WHEN aw.adoption_pct >= 50 THEN 'high' ELSE 'low' END AS adoption_tier FROM _adoption_weekly AS aw INNER JOIN _pr_metrics_weekly AS pm ON aw.week_start = pm.week_start), _tier_averages AS (SELECT adoption_tier, AVG(avg_cycle_time_hours) AS avg_cycle_time FROM _adoption_pr_joined GROUP BY adoption_tier) SELECT ROUND(CAST(((SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'high') - (SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'low')) AS NUMERIC) / NULLIF(NULLIF((SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'low'), 0), 0) * 100, 1) AS value",
463+
"rawSql": "WITH _copilot_adoption AS (SELECT metric_date, ROUND(CAST(active_users * 100.0 AS NUMERIC) / NULLIF(NULLIF(total_seats, 0), 0), 1) AS adoption_pct FROM (SELECT day AS metric_date, SUM(daily_active_users) AS active_users, (SELECT COUNT(*) FROM _tool_copilot_seats AS s WHERE ('${connection_id}' = '' OR s.connection_id::text = '${connection_id}') AND COALESCE(s.organization, '') = COALESCE((SELECT sc.organization FROM _tool_copilot_scopes AS sc WHERE ('${connection_id}' = '' OR sc.connection_id::text = '${connection_id}') AND sc.id = '${scope_id}' LIMIT 1), '')) AS total_seats FROM _tool_copilot_enterprise_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(day) GROUP BY day UNION ALL SELECT date AS metric_date, total_active_users AS active_users, seat_total AS total_seats FROM _tool_copilot_org_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(date)) AS _unified), _adoption_weekly AS (SELECT metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day' AS week_start, AVG(adoption_pct) AS adoption_pct FROM _copilot_adoption GROUP BY metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day'), _pr_metrics_weekly AS (SELECT CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day' AS week_start, CAST(AVG(pr_cycle_time) AS NUMERIC) / NULLIF(60.0, 0) AS avg_cycle_time_hours FROM project_pr_metrics WHERE ('${project:sqlstring}' = '' OR project_name::text = '${project:sqlstring}') AND $__timeFilter(pr_merged_date) GROUP BY CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day'), _adoption_pr_joined AS (SELECT aw.week_start, aw.adoption_pct, pm.avg_cycle_time_hours, CASE WHEN aw.adoption_pct >= 50 THEN 'high' WHEN aw.adoption_pct < 50 THEN 'low' END AS adoption_tier FROM _adoption_weekly AS aw INNER JOIN _pr_metrics_weekly AS pm ON aw.week_start = pm.week_start WHERE aw.adoption_pct IS NOT NULL), _tier_averages AS (SELECT adoption_tier, AVG(avg_cycle_time_hours) AS avg_cycle_time FROM _adoption_pr_joined GROUP BY adoption_tier) SELECT ROUND(CAST(((SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'high') - (SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'low')) AS NUMERIC) / NULLIF(NULLIF((SELECT avg_cycle_time FROM _tier_averages WHERE adoption_tier = 'low'), 0), 0) * 100, 1) AS value",
464464
"refId": "A"
465465
}
466466
],
@@ -686,7 +686,7 @@
686686
"datasource": {"type": "grafana-postgresql-datasource", "uid": "devlake-postgres-api"},
687687
"format": "table",
688688
"rawQuery": true,
689-
"rawSql": "WITH _copilot_adoption AS (SELECT metric_date, ROUND(CAST(active_users * 100.0 AS NUMERIC) / NULLIF(NULLIF(total_seats, 0), 0), 1) AS adoption_pct FROM (SELECT day AS metric_date, SUM(daily_active_users) AS active_users, (SELECT COUNT(*) FROM _tool_copilot_seats AS s WHERE ('${connection_id}' = '' OR s.connection_id::text = '${connection_id}') AND COALESCE(s.organization, '') = COALESCE((SELECT sc.organization FROM _tool_copilot_scopes AS sc WHERE ('${connection_id}' = '' OR sc.connection_id::text = '${connection_id}') AND sc.id = '${scope_id}' LIMIT 1), '')) AS total_seats FROM _tool_copilot_enterprise_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(day) GROUP BY day UNION ALL SELECT date AS metric_date, total_active_users AS active_users, seat_total AS total_seats FROM _tool_copilot_org_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(date)) AS _unified), _adoption_weekly AS (SELECT metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day' AS week_start, AVG(adoption_pct) AS adoption_pct FROM _copilot_adoption GROUP BY metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day'), _pr_metrics_weekly AS (SELECT CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day' AS week_start, CAST(AVG(pr_cycle_time) AS NUMERIC) / NULLIF(60.0, 0) AS avg_cycle_time_hours FROM project_pr_metrics WHERE ('${project:sqlstring}' = '' OR project_name::text = '${project:sqlstring}') AND $__timeFilter(pr_merged_date) GROUP BY CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day'), _adoption_pr_joined AS (SELECT aw.adoption_pct, pm.avg_cycle_time_hours, CASE WHEN aw.adoption_pct < 25 THEN '1. <25%' WHEN aw.adoption_pct < 50 THEN '2. 25-50%' WHEN aw.adoption_pct < 75 THEN '3. 50-75%' ELSE '4. >75%' END AS adoption_tier FROM _adoption_weekly AS aw INNER JOIN _pr_metrics_weekly AS pm ON aw.week_start = pm.week_start) SELECT adoption_tier AS metric, ROUND(CAST(AVG(avg_cycle_time_hours) AS DECIMAL), 1) AS value FROM _adoption_pr_joined GROUP BY adoption_tier ORDER BY adoption_tier NULLS FIRST",
689+
"rawSql": "WITH _copilot_adoption AS (SELECT metric_date, ROUND(CAST(active_users * 100.0 AS NUMERIC) / NULLIF(NULLIF(total_seats, 0), 0), 1) AS adoption_pct FROM (SELECT day AS metric_date, SUM(daily_active_users) AS active_users, (SELECT COUNT(*) FROM _tool_copilot_seats AS s WHERE ('${connection_id}' = '' OR s.connection_id::text = '${connection_id}') AND COALESCE(s.organization, '') = COALESCE((SELECT sc.organization FROM _tool_copilot_scopes AS sc WHERE ('${connection_id}' = '' OR sc.connection_id::text = '${connection_id}') AND sc.id = '${scope_id}' LIMIT 1), '')) AS total_seats FROM _tool_copilot_enterprise_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(day) GROUP BY day UNION ALL SELECT date AS metric_date, total_active_users AS active_users, seat_total AS total_seats FROM _tool_copilot_org_daily_metrics WHERE ('${connection_id}' = '' OR connection_id::text = '${connection_id}') AND scope_id = '${scope_id}' AND $__timeFilter(date)) AS _unified), _adoption_weekly AS (SELECT metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day' AS week_start, AVG(adoption_pct) AS adoption_pct FROM _copilot_adoption GROUP BY metric_date - (EXTRACT(ISODOW FROM metric_date) - 1) * INTERVAL '1 day'), _pr_metrics_weekly AS (SELECT CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day' AS week_start, CAST(AVG(pr_cycle_time) AS NUMERIC) / NULLIF(60.0, 0) AS avg_cycle_time_hours FROM project_pr_metrics WHERE ('${project:sqlstring}' = '' OR project_name::text = '${project:sqlstring}') AND $__timeFilter(pr_merged_date) GROUP BY CAST(pr_merged_date AS DATE) - (EXTRACT(ISODOW FROM CAST(pr_merged_date AS DATE)) - 1) * INTERVAL '1 day'), _adoption_pr_joined AS (SELECT aw.adoption_pct, pm.avg_cycle_time_hours, CASE WHEN aw.adoption_pct < 25 THEN '1. <25%' WHEN aw.adoption_pct < 50 THEN '2. 25-50%' WHEN aw.adoption_pct < 75 THEN '3. 50-75%' WHEN aw.adoption_pct >= 75 THEN '4. >75%' END AS adoption_tier FROM _adoption_weekly AS aw INNER JOIN _pr_metrics_weekly AS pm ON aw.week_start = pm.week_start WHERE aw.adoption_pct IS NOT NULL) SELECT adoption_tier AS metric, ROUND(CAST(AVG(avg_cycle_time_hours) AS DECIMAL), 1) AS value FROM _adoption_pr_joined GROUP BY adoption_tier ORDER BY adoption_tier NULLS FIRST",
690690
"refId": "A"
691691
}
692692
],
@@ -695,7 +695,7 @@
695695
},
696696
{
697697
"datasource": {
698-
"type": "datasource",
698+
"type": "datasource"INNER JOIN _pr_metrics_weekly AS pm ON aw.week_start = pm.week_start WHERE aw.adoption_pct IS NOT NULL) SELECT adoption_tier AS metric
699699
"uid": "grafana"
700700
},
701701
"gridPos": {

0 commit comments

Comments
 (0)