@backstage-community/plugin-copilot-backend 0.15.0 → 0.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/config.d.ts +1 -1
- package/dist/db/DatabaseHandler.cjs.js +23 -56
- package/dist/db/DatabaseHandler.cjs.js.map +1 -1
- package/dist/utils/GithubUtils.cjs.js +1 -1
- package/dist/utils/GithubUtils.cjs.js.map +1 -1
- package/dist/utils/metricHelpers.cjs.js +9 -9
- package/dist/utils/metricHelpers.cjs.js.map +1 -1
- package/migrations/202503211252_change_tables_to_not_nullable.js +296 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @backstage-community/plugin-copilot-backend
|
|
2
2
|
|
|
3
|
+
## 0.15.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1b7adc8: Fixed a mismatch between the backend requiring copilot.host and the config declaration stating it was optional.
|
|
8
|
+
|
|
9
|
+
## 0.15.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 3fd5298: Fixed an issue causing incorrect metrics to be displayed due to duplicate database entries for the same day.
|
|
14
|
+
|
|
3
15
|
## 0.15.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/config.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ class DatabaseHandler {
|
|
|
35
35
|
return { minDate: minDate.day, maxDate: maxDate.day };
|
|
36
36
|
}
|
|
37
37
|
async getTeams(type, startDate, endDate) {
|
|
38
|
-
const result = await this.db("copilot_metrics").where("type", type).whereBetween("day", [startDate, endDate]).
|
|
38
|
+
const result = await this.db("copilot_metrics").where("type", type).whereBetween("day", [startDate, endDate]).whereNot("team_name", "").distinct("team_name").orderBy("team_name", "asc").select("team_name");
|
|
39
39
|
return result.map((x) => x.team_name);
|
|
40
40
|
}
|
|
41
41
|
async batchInsert(metrics) {
|
|
@@ -81,7 +81,7 @@ class DatabaseHandler {
|
|
|
81
81
|
}
|
|
82
82
|
async getMostRecentDayFromMetrics(type, teamName) {
|
|
83
83
|
try {
|
|
84
|
-
const query = await this.db("metrics").where("type", type).where("team_name", teamName ??
|
|
84
|
+
const query = await this.db("metrics").where("type", type).where("team_name", teamName ?? "").orderBy("day", "desc").first("day");
|
|
85
85
|
return query ? query.day : void 0;
|
|
86
86
|
} catch (e) {
|
|
87
87
|
return void 0;
|
|
@@ -89,7 +89,7 @@ class DatabaseHandler {
|
|
|
89
89
|
}
|
|
90
90
|
async getMostRecentDayFromMetricsV2(type, teamName) {
|
|
91
91
|
try {
|
|
92
|
-
const query = this.db("copilot_metrics").where("type", type).where("team_name", teamName ??
|
|
92
|
+
const query = this.db("copilot_metrics").where("type", type).where("team_name", teamName ?? "").orderBy("day", "desc").first("day");
|
|
93
93
|
const res = await query;
|
|
94
94
|
return res ? res.day : void 0;
|
|
95
95
|
} catch (e) {
|
|
@@ -98,7 +98,7 @@ class DatabaseHandler {
|
|
|
98
98
|
}
|
|
99
99
|
async getEarliestDayFromMetricsV2(type, teamName) {
|
|
100
100
|
try {
|
|
101
|
-
const query = this.db("copilot_metrics").where("type", type).where("team_name", teamName ??
|
|
101
|
+
const query = this.db("copilot_metrics").where("type", type).where("team_name", teamName ?? "").orderBy("day", "asc").first("day");
|
|
102
102
|
const res = await query;
|
|
103
103
|
return res ? res.day : void 0;
|
|
104
104
|
} catch (e) {
|
|
@@ -106,10 +106,7 @@ class DatabaseHandler {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
async getMetrics(startDate, endDate, type, teamName) {
|
|
109
|
-
|
|
110
|
-
return await this.db("metrics").where("type", type).where("team_name", teamName).whereBetween("day", [startDate, endDate]);
|
|
111
|
-
}
|
|
112
|
-
return this.db("metrics").where("type", type).whereNull("team_name").whereBetween("day", [startDate, endDate]);
|
|
109
|
+
return await this.db("metrics").where("type", type).where("team_name", teamName ?? "").whereBetween("day", [startDate, endDate]);
|
|
113
110
|
}
|
|
114
111
|
async getSeatMetrics(startDate, endDate, type, teamName) {
|
|
115
112
|
return await this.db("seats").where("type", type).where("team_name", teamName ?? "").whereBetween("day", [startDate, endDate]).orderBy("day", "asc");
|
|
@@ -182,7 +179,7 @@ class DatabaseHandler {
|
|
|
182
179
|
return await query;
|
|
183
180
|
}
|
|
184
181
|
async getMetricsV2(startDate, endDate, type, teamName) {
|
|
185
|
-
|
|
182
|
+
const query = this.db("copilot_metrics as cm").select(
|
|
186
183
|
"cm.day",
|
|
187
184
|
"cm.type",
|
|
188
185
|
"cm.team_name",
|
|
@@ -212,23 +209,17 @@ class DatabaseHandler {
|
|
|
212
209
|
),
|
|
213
210
|
this.db.raw("'' as breakdown")
|
|
214
211
|
).join("ide_completions", (join) => {
|
|
215
|
-
join.on("ide_completions.day", "=", "cm.day").andOn("ide_completions.type", "=", "cm.type")
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
this.db.raw("?", [teamName])
|
|
221
|
-
);
|
|
222
|
-
} else {
|
|
223
|
-
join.andOnNull("ide_completions.team_name");
|
|
224
|
-
}
|
|
212
|
+
join.on("ide_completions.day", "=", "cm.day").andOn("ide_completions.type", "=", "cm.type").andOn(
|
|
213
|
+
"ide_completions.team_name",
|
|
214
|
+
"=",
|
|
215
|
+
this.db.raw("?", [teamName ?? ""])
|
|
216
|
+
);
|
|
225
217
|
}).join("ide_chats", (join) => {
|
|
226
|
-
join.on("ide_chats.day", "=", "cm.day").andOn("ide_chats.type", "=", "cm.type")
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
218
|
+
join.on("ide_chats.day", "=", "cm.day").andOn("ide_chats.type", "=", "cm.type").andOn(
|
|
219
|
+
"ide_chats.team_name",
|
|
220
|
+
"=",
|
|
221
|
+
this.db.raw("?", [teamName ?? ""])
|
|
222
|
+
);
|
|
232
223
|
}).join(
|
|
233
224
|
this.db.raw(
|
|
234
225
|
`(SELECT day, type, team_name,
|
|
@@ -240,12 +231,7 @@ class DatabaseHandler {
|
|
|
240
231
|
as icelm`
|
|
241
232
|
),
|
|
242
233
|
(join) => {
|
|
243
|
-
join.on("icelm.day", "=", "cm.day").andOn("icelm.type", "=", "cm.type");
|
|
244
|
-
if (teamName) {
|
|
245
|
-
join.andOn("icelm.team_name", "=", this.db.raw("?", [teamName]));
|
|
246
|
-
} else {
|
|
247
|
-
join.andOnNull("icelm.team_name");
|
|
248
|
-
}
|
|
234
|
+
join.on("icelm.day", "=", "cm.day").andOn("icelm.type", "=", "cm.type").andOn("icelm.team_name", "=", this.db.raw("?", [teamName ?? ""]));
|
|
249
235
|
}
|
|
250
236
|
).join(
|
|
251
237
|
this.db.raw(
|
|
@@ -254,23 +240,13 @@ class DatabaseHandler {
|
|
|
254
240
|
FROM ide_chat_editors_model GROUP BY day, type, team_name) as icem`
|
|
255
241
|
),
|
|
256
242
|
(join) => {
|
|
257
|
-
join.on("icem.day", "=", "cm.day").andOn("icem.type", "=", "cm.type");
|
|
258
|
-
if (teamName) {
|
|
259
|
-
join.andOn("icem.team_name", "=", this.db.raw("?", [teamName]));
|
|
260
|
-
} else {
|
|
261
|
-
join.andOnNull("icem.team_name");
|
|
262
|
-
}
|
|
243
|
+
join.on("icem.day", "=", "cm.day").andOn("icem.type", "=", "cm.type").andOn("icem.team_name", "=", this.db.raw("?", [teamName ?? ""]));
|
|
263
244
|
}
|
|
264
|
-
).where("cm.type", type).whereBetween("cm.day", [startDate, endDate]).groupBy("cm.day", "cm.type", "cm.team_name").orderBy("cm.day", "asc");
|
|
265
|
-
if (teamName) {
|
|
266
|
-
query = query.where("cm.team_name", teamName);
|
|
267
|
-
} else {
|
|
268
|
-
query = query.whereNull("cm.team_name");
|
|
269
|
-
}
|
|
245
|
+
).where("cm.type", type).where("cm.team_name", teamName ?? "").whereBetween("cm.day", [startDate, endDate]).groupBy("cm.day", "cm.type", "cm.team_name").orderBy("cm.day", "asc");
|
|
270
246
|
return await query;
|
|
271
247
|
}
|
|
272
248
|
async getBreakdown(startDate, endDate, type, teamName) {
|
|
273
|
-
|
|
249
|
+
const query = this.db("copilot_metrics as cm").select(
|
|
274
250
|
"cm.day",
|
|
275
251
|
"icleml.editor as editor",
|
|
276
252
|
"icleml.language as language",
|
|
@@ -292,22 +268,13 @@ class DatabaseHandler {
|
|
|
292
268
|
).join(
|
|
293
269
|
"ide_completions_language_editors_model_language as icleml",
|
|
294
270
|
(join) => {
|
|
295
|
-
join.on("icleml.day", "=", "cm.day").andOn("icleml.type", "=", "cm.type");
|
|
296
|
-
if (teamName) {
|
|
297
|
-
join.andOn("icleml.team_name", "=", this.db.raw("?", [teamName]));
|
|
298
|
-
} else {
|
|
299
|
-
join.andOnNull("icleml.team_name");
|
|
300
|
-
}
|
|
271
|
+
join.on("icleml.day", "=", "cm.day").andOn("icleml.type", "=", "cm.type").andOn("icleml.team_name", "=", this.db.raw("?", [teamName ?? ""]));
|
|
301
272
|
}
|
|
302
|
-
).whereBetween("cm.day", [startDate, endDate]).where("icleml.model", "default").where("cm.type", type).groupBy("cm.day", "icleml.editor", "icleml.language").orderBy("cm.day", "asc");
|
|
303
|
-
if (teamName) {
|
|
304
|
-
query = query.where("cm.team_name", teamName);
|
|
305
|
-
} else {
|
|
306
|
-
query = query.whereNull("cm.team_name");
|
|
307
|
-
}
|
|
273
|
+
).whereBetween("cm.day", [startDate, endDate]).where("icleml.model", "default").where("cm.type", type).where("cm.team_name", teamName ?? "").groupBy("cm.day", "icleml.editor", "icleml.language").orderBy("cm.day", "asc");
|
|
308
274
|
return await query;
|
|
309
275
|
}
|
|
310
276
|
}
|
|
311
277
|
|
|
312
278
|
exports.DatabaseHandler = DatabaseHandler;
|
|
279
|
+
exports.migrationsDir = migrationsDir;
|
|
313
280
|
//# sourceMappingURL=DatabaseHandler.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatabaseHandler.cjs.js","sources":["../../src/db/DatabaseHandler.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n resolvePackagePath,\n DatabaseService,\n} from '@backstage/backend-plugin-api';\nimport {\n Metric,\n MetricsType,\n PeriodRange,\n CopilotIdeCodeCompletions,\n CopilotIdeLanguages,\n CopilotMetrics,\n CopilotEditors,\n CopilotModels,\n CopilotLanguages,\n CopilotChats,\n CopilotChatEditors,\n CopilotChatModels,\n EngagementMetrics,\n SeatAnalysis,\n} from '@backstage-community/plugin-copilot-common';\nimport { Knex } from 'knex';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-copilot-backend',\n 'migrations',\n);\n\ntype Options = {\n database: DatabaseService;\n};\n\nexport type Breakdown = {\n day: string;\n editor: string;\n language: string;\n lines_accepted: number;\n lines_suggested: number;\n suggestions_count: number;\n acceptances_count: number;\n active_users: number;\n};\n\nexport type CopilotMetricsDb = Omit<\n CopilotMetrics,\n | 'date'\n | 'copilot_ide_code_completions'\n | 'copilot_ide_chat'\n | 'copilot_dotcom_chat'\n | 'copilot_dotcom_pull_requests'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n};\n\nexport type CopilotIdeCodeCompletionsDb = Omit<\n CopilotIdeCodeCompletions,\n 'editors' | 'languages'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n};\n\nexport type CopilotIdeCodeCompletionsLanguageDb = Omit<\n CopilotIdeLanguages,\n 'day' | 'name' | 'language'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n language: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorsDb = Omit<\n CopilotEditors,\n 'day' | 'name' | 'models'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n};\n\nexport type CopilotIdeChatsDb = Omit<CopilotChats, 'day' | 'editors'> & {\n day: string;\n};\n\nexport type CopilotIdeChatsEditorsDb = Omit<\n CopilotChatEditors,\n 'day' | 'name' | 'models' | 'editor'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n};\n\nexport type CopilotIdeChatsEditorModelDb = Omit<\n CopilotChatModels,\n 'name' | 'day' | 'model' | 'editor'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorModelsDb = Omit<\n CopilotModels,\n 'day' | 'editor' | 'model' | 'name' | 'languages'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorModelLanguagesDb = Omit<\n CopilotLanguages,\n 'day' | 'editor' | 'model' | 'name' | 'language'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n language: string;\n};\n\nexport type MetricDbRow = Omit<Metric, 'breakdown'> & {\n breakdown: string;\n};\n\nexport class DatabaseHandler {\n static async create(options: Options): Promise<DatabaseHandler> {\n const { database } = options;\n const client = await database.getClient();\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseHandler(client);\n }\n\n private constructor(private readonly db: Knex) {}\n\n async getPeriodRange(type: MetricsType): Promise<PeriodRange | undefined> {\n const query = this.db<MetricDbRow>('metrics').where('type', type);\n\n const minDate = await query.orderBy('day', 'asc').first('day');\n const maxDate = await query.orderBy('day', 'desc').first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async getPeriodRangeV2(type: MetricsType): Promise<PeriodRange | undefined> {\n const query = this.db('copilot_metrics').where('type', type);\n\n const minDate = await query.orderBy('day', 'asc').first('day');\n const maxDate = await query.orderBy('day', 'desc').first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async getTeams(\n type: MetricsType,\n startDate: string,\n endDate: string,\n ): Promise<Array<string | undefined>> {\n const result = await this.db<MetricDbRow>('copilot_metrics')\n .where('type', type)\n .whereBetween('day', [startDate, endDate])\n .whereNotNull('team_name')\n .distinct('team_name')\n .orderBy('team_name', 'asc')\n .select('team_name');\n\n return result.map(x => x.team_name);\n }\n\n async batchInsert(metrics: MetricDbRow[]): Promise<void> {\n await this.db<MetricDbRow[]>('metrics')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertMetrics(metrics: CopilotMetricsDb[]): Promise<void> {\n await this.db<CopilotMetricsDb[]>('copilot_metrics')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeCompletions(\n metrics: CopilotIdeCodeCompletionsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsDb[]>('ide_completions')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsLanguages(\n metrics: CopilotIdeCodeCompletionsLanguageDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsLanguageDb[]>(\n 'ide_completions_language_users',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'language'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditors(\n metrics: CopilotIdeCodeCompletionsEditorsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorsDb[]>(\n 'ide_completions_language_editors',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditorModels(\n metrics: CopilotIdeCodeCompletionsEditorModelsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorModelsDb[]>(\n 'ide_completions_language_editors_model',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditorModelLanguages(\n metrics: CopilotIdeCodeCompletionsEditorModelLanguagesDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorModelLanguagesDb[]>(\n 'ide_completions_language_editors_model_language',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model', 'language'])\n .ignore();\n }\n\n async batchInsertIdeChats(metrics: CopilotIdeChatsDb[]): Promise<void> {\n await this.db<CopilotIdeChatsDb[]>('ide_chats')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeChatEditors(\n metrics: CopilotIdeChatsEditorsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeChatsEditorsDb[]>('ide_chat_editors')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor'])\n .ignore();\n }\n\n async batchInsertIdeChatEditorModels(\n metrics: CopilotIdeChatsEditorModelDb[],\n ): Promise<void> {\n await this.db<CopilotIdeChatsEditorModelDb[]>('ide_chat_editors_model')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model'])\n .ignore();\n }\n\n async insertSeatAnalysys(metric: SeatAnalysis): Promise<void> {\n await this.db<SeatAnalysis>('seats')\n .insert(metric)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async getMostRecentDayFromMetrics(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = await this.db<MetricDbRow>('metrics')\n .where('type', type)\n .where('team_name', teamName ?? null)\n .orderBy('day', 'desc')\n .first('day');\n return query ? query.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getMostRecentDayFromMetricsV2(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = this.db('copilot_metrics')\n .where('type', type)\n .where('team_name', teamName ?? null)\n .orderBy('day', 'desc')\n .first('day');\n const res = await query;\n return res ? res.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getEarliestDayFromMetricsV2(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = this.db('copilot_metrics')\n .where('type', type)\n .where('team_name', teamName ?? null)\n .orderBy('day', 'asc')\n .first('day');\n const res = await query;\n return res ? res.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<MetricDbRow[]> {\n if (teamName) {\n return await this.db<MetricDbRow>('metrics')\n .where('type', type)\n .where('team_name', teamName)\n .whereBetween('day', [startDate, endDate]);\n }\n return this.db<MetricDbRow>('metrics')\n .where('type', type)\n .whereNull('team_name')\n .whereBetween('day', [startDate, endDate]);\n }\n\n async getSeatMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<SeatAnalysis[]> {\n return await this.db<SeatAnalysis>('seats')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .whereBetween('day', [startDate, endDate])\n .orderBy('day', 'asc');\n }\n\n async getEngagementMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<EngagementMetrics[]> {\n let query = this.db('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'cm.type',\n 'cm.team_name',\n this.db.raw(\n 'CAST(MIN(cm.total_active_users) AS INTEGER) as total_active_users',\n ),\n this.db.raw(\n 'CAST(MIN(cm.total_engaged_users) AS INTEGER) as total_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_completions.total_engaged_users) AS INTEGER) as ide_completions_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_chats.total_engaged_users) AS INTEGER) as ide_chats_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(dotcom_chats.total_engaged_users) AS INTEGER) as dotcom_chats_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(dotcom_prs.total_engaged_users) AS INTEGER) as dotcom_prs_engaged_users',\n ),\n )\n .leftJoin('ide_completions', join => {\n join\n .on('ide_completions.day', '=', 'cm.day')\n .andOn('ide_completions.type', '=', 'cm.type');\n if (teamName) {\n join.andOn(\n 'ide_completions.team_name',\n '=',\n this.db.raw('?', [teamName]),\n );\n } else {\n join.andOnNull('ide_completions.team_name');\n }\n })\n .leftJoin('ide_chats', join => {\n join\n .on('ide_chats.day', '=', 'cm.day')\n .andOn('ide_chats.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('ide_chats.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('ide_chats.team_name');\n }\n })\n .leftJoin('dotcom_chats', join => {\n join\n .on('dotcom_chats.day', '=', 'cm.day')\n .andOn('dotcom_chats.type', '=', 'cm.type');\n if (teamName) {\n join.andOn(\n 'dotcom_chats.team_name',\n '=',\n this.db.raw('?', [teamName]),\n );\n } else {\n join.andOnNull('dotcom_chats.team_name');\n }\n })\n .leftJoin('dotcom_prs', join => {\n join\n .on('dotcom_prs.day', '=', 'cm.day')\n .andOn('dotcom_prs.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('dotcom_prs.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('dotcom_prs.team_name');\n }\n })\n .where('cm.type', type)\n .whereBetween('cm.day', [startDate, endDate])\n .groupBy('cm.day', 'cm.type', 'cm.team_name')\n .orderBy('cm.day', 'asc');\n\n if (teamName) {\n query = query.where('cm.team_name', teamName);\n } else {\n query = query.whereNull('cm.team_name');\n }\n\n return await query;\n }\n\n async getMetricsV2(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<MetricDbRow[]> {\n let query = this.db('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'cm.type',\n 'cm.team_name',\n this.db.raw(\n 'CAST(MIN(cm.total_active_users) AS INTEGER) as total_active_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_chats.total_engaged_users) AS INTEGER) as total_active_chat_users',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_suggestions) AS INTEGER) as total_suggestions_count',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_acceptances) AS INTEGER) as total_acceptances_count',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_lines_suggested) AS INTEGER) as total_lines_suggested',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_lines_accepted) AS INTEGER) as total_lines_accepted',\n ),\n this.db.raw(\n 'CAST(SUM(icem.total_chats) AS INTEGER) as total_chat_turns',\n ),\n this.db.raw(\n 'CAST(SUM(icem.total_chat_copy_events) AS INTEGER) as total_chat_acceptances',\n ),\n this.db.raw(\"'' as breakdown\"),\n )\n .join('ide_completions', join => {\n join\n .on('ide_completions.day', '=', 'cm.day')\n .andOn('ide_completions.type', '=', 'cm.type');\n if (teamName) {\n join.andOn(\n 'ide_completions.team_name',\n '=',\n this.db.raw('?', [teamName]),\n );\n } else {\n join.andOnNull('ide_completions.team_name');\n }\n })\n .join('ide_chats', join => {\n join\n .on('ide_chats.day', '=', 'cm.day')\n .andOn('ide_chats.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('ide_chats.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('ide_chats.team_name');\n }\n })\n .join(\n this.db.raw(\n `(SELECT day, type, team_name,\n SUM(total_code_suggestions) as total_code_suggestions, \n SUM(total_code_acceptances) as total_code_acceptances, \n SUM(total_code_lines_suggested) as total_code_lines_suggested, \n SUM(total_code_lines_accepted) as total_code_lines_accepted \n FROM ide_completions_language_editors_model_language GROUP BY day, type, team_name) \n as icelm`,\n ),\n join => {\n join\n .on('icelm.day', '=', 'cm.day')\n .andOn('icelm.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('icelm.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('icelm.team_name');\n }\n },\n )\n .join(\n this.db.raw(\n `(SELECT day, type, team_name, SUM(total_chats) as total_chats, \n SUM(total_chat_copy_events) as total_chat_copy_events \n FROM ide_chat_editors_model GROUP BY day, type, team_name) as icem`,\n ),\n join => {\n join.on('icem.day', '=', 'cm.day').andOn('icem.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('icem.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('icem.team_name');\n }\n },\n )\n .where('cm.type', type)\n .whereBetween('cm.day', [startDate, endDate])\n .groupBy('cm.day', 'cm.type', 'cm.team_name')\n .orderBy('cm.day', 'asc');\n\n if (teamName) {\n query = query.where('cm.team_name', teamName);\n } else {\n query = query.whereNull('cm.team_name');\n }\n\n return await query;\n }\n\n async getBreakdown(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<Breakdown[]> {\n let query = this.db<Breakdown>('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'icleml.editor as editor',\n 'icleml.language as language',\n this.db.raw(\n 'CAST(SUM(icleml.total_engaged_users) AS INTEGER) as active_users',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_lines_suggested) AS INTEGER) as lines_suggested',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_lines_accepted) AS INTEGER) as lines_accepted',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_suggestions) AS INTEGER) as suggestions_count',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_acceptances) AS INTEGER) as acceptances_count',\n ),\n )\n .join(\n 'ide_completions_language_editors_model_language as icleml',\n join => {\n join\n .on('icleml.day', '=', 'cm.day')\n .andOn('icleml.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('icleml.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('icleml.team_name');\n }\n },\n )\n .whereBetween('cm.day', [startDate, endDate])\n .where('icleml.model', 'default')\n .where('cm.type', type)\n .groupBy('cm.day', 'icleml.editor', 'icleml.language')\n .orderBy('cm.day', 'asc');\n\n if (teamName) {\n query = query.where('cm.team_name', teamName);\n } else {\n query = query.whereNull('cm.team_name');\n }\n\n return await query;\n }\n}\n"],"names":["resolvePackagePath"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatabaseHandler.cjs.js","sources":["../../src/db/DatabaseHandler.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n resolvePackagePath,\n DatabaseService,\n} from '@backstage/backend-plugin-api';\nimport {\n Metric,\n MetricsType,\n PeriodRange,\n CopilotIdeCodeCompletions,\n CopilotIdeLanguages,\n CopilotMetrics,\n CopilotEditors,\n CopilotModels,\n CopilotLanguages,\n CopilotChats,\n CopilotChatEditors,\n CopilotChatModels,\n EngagementMetrics,\n SeatAnalysis,\n} from '@backstage-community/plugin-copilot-common';\nimport { Knex } from 'knex';\n\nexport const migrationsDir = resolvePackagePath(\n '@backstage-community/plugin-copilot-backend',\n 'migrations',\n);\n\ntype Options = {\n database: DatabaseService;\n};\n\nexport type Breakdown = {\n day: string;\n editor: string;\n language: string;\n lines_accepted: number;\n lines_suggested: number;\n suggestions_count: number;\n acceptances_count: number;\n active_users: number;\n};\n\nexport type CopilotMetricsDb = Omit<\n CopilotMetrics,\n | 'date'\n | 'copilot_ide_code_completions'\n | 'copilot_ide_chat'\n | 'copilot_dotcom_chat'\n | 'copilot_dotcom_pull_requests'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n};\n\nexport type CopilotIdeCodeCompletionsDb = Omit<\n CopilotIdeCodeCompletions,\n 'editors' | 'languages'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n};\n\nexport type CopilotIdeCodeCompletionsLanguageDb = Omit<\n CopilotIdeLanguages,\n 'day' | 'name' | 'language'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n language: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorsDb = Omit<\n CopilotEditors,\n 'day' | 'name' | 'models'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n};\n\nexport type CopilotIdeChatsDb = Omit<CopilotChats, 'day' | 'editors'> & {\n day: string;\n};\n\nexport type CopilotIdeChatsEditorsDb = Omit<\n CopilotChatEditors,\n 'day' | 'name' | 'models' | 'editor'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n};\n\nexport type CopilotIdeChatsEditorModelDb = Omit<\n CopilotChatModels,\n 'name' | 'day' | 'model' | 'editor'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorModelsDb = Omit<\n CopilotModels,\n 'day' | 'editor' | 'model' | 'name' | 'languages'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n};\n\nexport type CopilotIdeCodeCompletionsEditorModelLanguagesDb = Omit<\n CopilotLanguages,\n 'day' | 'editor' | 'model' | 'name' | 'language'\n> & {\n day: string;\n /**\n * The type of the metrics data.\n * Can be 'enterprise', 'organization'.\n */\n type: MetricsType;\n\n /**\n * The name of the team, applicable when the metric is for a specific team.\n * When null, it indicates metrics for all teams, aggregated at the 'enterprise' or 'organization' level.\n */\n team_name?: string;\n editor: string;\n model: string;\n language: string;\n};\n\nexport type MetricDbRow = Omit<Metric, 'breakdown'> & {\n breakdown: string;\n};\n\nexport class DatabaseHandler {\n static async create(options: Options): Promise<DatabaseHandler> {\n const { database } = options;\n const client = await database.getClient();\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n\n return new DatabaseHandler(client);\n }\n\n private constructor(private readonly db: Knex) {}\n\n async getPeriodRange(type: MetricsType): Promise<PeriodRange | undefined> {\n const query = this.db<MetricDbRow>('metrics').where('type', type);\n\n const minDate = await query.orderBy('day', 'asc').first('day');\n const maxDate = await query.orderBy('day', 'desc').first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async getPeriodRangeV2(type: MetricsType): Promise<PeriodRange | undefined> {\n const query = this.db('copilot_metrics').where('type', type);\n\n const minDate = await query.orderBy('day', 'asc').first('day');\n const maxDate = await query.orderBy('day', 'desc').first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async getTeams(\n type: MetricsType,\n startDate: string,\n endDate: string,\n ): Promise<Array<string | undefined>> {\n const result = await this.db<MetricDbRow>('copilot_metrics')\n .where('type', type)\n .whereBetween('day', [startDate, endDate])\n .whereNot('team_name', '')\n .distinct('team_name')\n .orderBy('team_name', 'asc')\n .select('team_name');\n\n return result.map(x => x.team_name);\n }\n\n async batchInsert(metrics: MetricDbRow[]): Promise<void> {\n await this.db<MetricDbRow[]>('metrics')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertMetrics(metrics: CopilotMetricsDb[]): Promise<void> {\n await this.db<CopilotMetricsDb[]>('copilot_metrics')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeCompletions(\n metrics: CopilotIdeCodeCompletionsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsDb[]>('ide_completions')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsLanguages(\n metrics: CopilotIdeCodeCompletionsLanguageDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsLanguageDb[]>(\n 'ide_completions_language_users',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'language'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditors(\n metrics: CopilotIdeCodeCompletionsEditorsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorsDb[]>(\n 'ide_completions_language_editors',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditorModels(\n metrics: CopilotIdeCodeCompletionsEditorModelsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorModelsDb[]>(\n 'ide_completions_language_editors_model',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model'])\n .ignore();\n }\n\n async batchInsertIdeCompletionsEditorModelLanguages(\n metrics: CopilotIdeCodeCompletionsEditorModelLanguagesDb[],\n ): Promise<void> {\n await this.db<CopilotIdeCodeCompletionsEditorModelLanguagesDb[]>(\n 'ide_completions_language_editors_model_language',\n )\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model', 'language'])\n .ignore();\n }\n\n async batchInsertIdeChats(metrics: CopilotIdeChatsDb[]): Promise<void> {\n await this.db<CopilotIdeChatsDb[]>('ide_chats')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async batchInsertIdeChatEditors(\n metrics: CopilotIdeChatsEditorsDb[],\n ): Promise<void> {\n await this.db<CopilotIdeChatsEditorsDb[]>('ide_chat_editors')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor'])\n .ignore();\n }\n\n async batchInsertIdeChatEditorModels(\n metrics: CopilotIdeChatsEditorModelDb[],\n ): Promise<void> {\n await this.db<CopilotIdeChatsEditorModelDb[]>('ide_chat_editors_model')\n .insert(metrics)\n .onConflict(['day', 'type', 'team_name', 'editor', 'model'])\n .ignore();\n }\n\n async insertSeatAnalysys(metric: SeatAnalysis): Promise<void> {\n await this.db<SeatAnalysis>('seats')\n .insert(metric)\n .onConflict(['day', 'type', 'team_name'])\n .ignore();\n }\n\n async getMostRecentDayFromMetrics(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = await this.db<MetricDbRow>('metrics')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .orderBy('day', 'desc')\n .first('day');\n return query ? query.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getMostRecentDayFromMetricsV2(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = this.db('copilot_metrics')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .orderBy('day', 'desc')\n .first('day');\n const res = await query;\n return res ? res.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getEarliestDayFromMetricsV2(\n type: MetricsType,\n teamName?: string,\n ): Promise<string | undefined> {\n try {\n const query = this.db('copilot_metrics')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .orderBy('day', 'asc')\n .first('day');\n const res = await query;\n return res ? res.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n\n async getMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<MetricDbRow[]> {\n return await this.db<MetricDbRow>('metrics')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .whereBetween('day', [startDate, endDate]);\n }\n\n async getSeatMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<SeatAnalysis[]> {\n return await this.db<SeatAnalysis>('seats')\n .where('type', type)\n .where('team_name', teamName ?? '')\n .whereBetween('day', [startDate, endDate])\n .orderBy('day', 'asc');\n }\n\n async getEngagementMetrics(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<EngagementMetrics[]> {\n let query = this.db('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'cm.type',\n 'cm.team_name',\n this.db.raw(\n 'CAST(MIN(cm.total_active_users) AS INTEGER) as total_active_users',\n ),\n this.db.raw(\n 'CAST(MIN(cm.total_engaged_users) AS INTEGER) as total_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_completions.total_engaged_users) AS INTEGER) as ide_completions_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_chats.total_engaged_users) AS INTEGER) as ide_chats_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(dotcom_chats.total_engaged_users) AS INTEGER) as dotcom_chats_engaged_users',\n ),\n this.db.raw(\n 'CAST(MIN(dotcom_prs.total_engaged_users) AS INTEGER) as dotcom_prs_engaged_users',\n ),\n )\n .leftJoin('ide_completions', join => {\n join\n .on('ide_completions.day', '=', 'cm.day')\n .andOn('ide_completions.type', '=', 'cm.type');\n if (teamName) {\n join.andOn(\n 'ide_completions.team_name',\n '=',\n this.db.raw('?', [teamName]),\n );\n } else {\n join.andOnNull('ide_completions.team_name');\n }\n })\n .leftJoin('ide_chats', join => {\n join\n .on('ide_chats.day', '=', 'cm.day')\n .andOn('ide_chats.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('ide_chats.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('ide_chats.team_name');\n }\n })\n .leftJoin('dotcom_chats', join => {\n join\n .on('dotcom_chats.day', '=', 'cm.day')\n .andOn('dotcom_chats.type', '=', 'cm.type');\n if (teamName) {\n join.andOn(\n 'dotcom_chats.team_name',\n '=',\n this.db.raw('?', [teamName]),\n );\n } else {\n join.andOnNull('dotcom_chats.team_name');\n }\n })\n .leftJoin('dotcom_prs', join => {\n join\n .on('dotcom_prs.day', '=', 'cm.day')\n .andOn('dotcom_prs.type', '=', 'cm.type');\n if (teamName) {\n join.andOn('dotcom_prs.team_name', '=', this.db.raw('?', [teamName]));\n } else {\n join.andOnNull('dotcom_prs.team_name');\n }\n })\n .where('cm.type', type)\n .whereBetween('cm.day', [startDate, endDate])\n .groupBy('cm.day', 'cm.type', 'cm.team_name')\n .orderBy('cm.day', 'asc');\n\n if (teamName) {\n query = query.where('cm.team_name', teamName);\n } else {\n query = query.whereNull('cm.team_name');\n }\n\n return await query;\n }\n\n async getMetricsV2(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<MetricDbRow[]> {\n const query = this.db('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'cm.type',\n 'cm.team_name',\n this.db.raw(\n 'CAST(MIN(cm.total_active_users) AS INTEGER) as total_active_users',\n ),\n this.db.raw(\n 'CAST(MIN(ide_chats.total_engaged_users) AS INTEGER) as total_active_chat_users',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_suggestions) AS INTEGER) as total_suggestions_count',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_acceptances) AS INTEGER) as total_acceptances_count',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_lines_suggested) AS INTEGER) as total_lines_suggested',\n ),\n this.db.raw(\n 'CAST(SUM(icelm.total_code_lines_accepted) AS INTEGER) as total_lines_accepted',\n ),\n this.db.raw(\n 'CAST(SUM(icem.total_chats) AS INTEGER) as total_chat_turns',\n ),\n this.db.raw(\n 'CAST(SUM(icem.total_chat_copy_events) AS INTEGER) as total_chat_acceptances',\n ),\n this.db.raw(\"'' as breakdown\"),\n )\n .join('ide_completions', join => {\n join\n .on('ide_completions.day', '=', 'cm.day')\n .andOn('ide_completions.type', '=', 'cm.type')\n .andOn(\n 'ide_completions.team_name',\n '=',\n this.db.raw('?', [teamName ?? '']),\n );\n })\n .join('ide_chats', join => {\n join\n .on('ide_chats.day', '=', 'cm.day')\n .andOn('ide_chats.type', '=', 'cm.type')\n .andOn(\n 'ide_chats.team_name',\n '=',\n this.db.raw('?', [teamName ?? '']),\n );\n })\n .join(\n this.db.raw(\n `(SELECT day, type, team_name,\n SUM(total_code_suggestions) as total_code_suggestions, \n SUM(total_code_acceptances) as total_code_acceptances, \n SUM(total_code_lines_suggested) as total_code_lines_suggested, \n SUM(total_code_lines_accepted) as total_code_lines_accepted \n FROM ide_completions_language_editors_model_language GROUP BY day, type, team_name) \n as icelm`,\n ),\n join => {\n join\n .on('icelm.day', '=', 'cm.day')\n .andOn('icelm.type', '=', 'cm.type')\n .andOn('icelm.team_name', '=', this.db.raw('?', [teamName ?? '']));\n },\n )\n .join(\n this.db.raw(\n `(SELECT day, type, team_name, SUM(total_chats) as total_chats, \n SUM(total_chat_copy_events) as total_chat_copy_events \n FROM ide_chat_editors_model GROUP BY day, type, team_name) as icem`,\n ),\n join => {\n join\n .on('icem.day', '=', 'cm.day')\n .andOn('icem.type', '=', 'cm.type')\n .andOn('icem.team_name', '=', this.db.raw('?', [teamName ?? '']));\n },\n )\n .where('cm.type', type)\n .where('cm.team_name', teamName ?? '')\n .whereBetween('cm.day', [startDate, endDate])\n .groupBy('cm.day', 'cm.type', 'cm.team_name')\n .orderBy('cm.day', 'asc');\n\n return await query;\n }\n\n async getBreakdown(\n startDate: string,\n endDate: string,\n type: MetricsType,\n teamName?: string,\n ): Promise<Breakdown[]> {\n const query = this.db<Breakdown>('copilot_metrics as cm')\n .select(\n 'cm.day',\n 'icleml.editor as editor',\n 'icleml.language as language',\n this.db.raw(\n 'CAST(SUM(icleml.total_engaged_users) AS INTEGER) as active_users',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_lines_suggested) AS INTEGER) as lines_suggested',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_lines_accepted) AS INTEGER) as lines_accepted',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_suggestions) AS INTEGER) as suggestions_count',\n ),\n this.db.raw(\n 'CAST(SUM(icleml.total_code_acceptances) AS INTEGER) as acceptances_count',\n ),\n )\n .join(\n 'ide_completions_language_editors_model_language as icleml',\n join => {\n join\n .on('icleml.day', '=', 'cm.day')\n .andOn('icleml.type', '=', 'cm.type')\n .andOn('icleml.team_name', '=', this.db.raw('?', [teamName ?? '']));\n },\n )\n .whereBetween('cm.day', [startDate, endDate])\n .where('icleml.model', 'default')\n .where('cm.type', type)\n .where('cm.team_name', teamName ?? '')\n .groupBy('cm.day', 'icleml.editor', 'icleml.language')\n .orderBy('cm.day', 'asc');\n\n return await query;\n }\n}\n"],"names":["resolvePackagePath"],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ const getCopilotConfig = (config) => {
|
|
|
10
10
|
const githubConfig = integrations.github.byHost(host)?.config;
|
|
11
11
|
if (!githubConfig) {
|
|
12
12
|
throw new Error(
|
|
13
|
-
`GitHub configuration for host "${host}" is missing or incomplete. Please check the
|
|
13
|
+
`GitHub configuration for host "${host}" is missing or incomplete. Please check the integrations configuration section.`
|
|
14
14
|
);
|
|
15
15
|
}
|
|
16
16
|
if (enterprise && !githubConfig.token) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GithubUtils.cjs.js","sources":["../../src/utils/GithubUtils.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n DefaultGithubCredentialsProvider,\n GithubCredentials,\n ScmIntegrations,\n} from '@backstage/integration';\n\nexport type CopilotCredentials = {\n enterprise?: GithubCredentials;\n organization?: GithubCredentials;\n};\n\nexport type CopilotConfig = {\n host: string;\n enterprise?: string;\n organization?: string;\n apiBaseUrl: string;\n};\n\nexport const getCopilotConfig = (config: Config): CopilotConfig => {\n const host = config.getString('copilot.host');\n const enterprise = config.getOptionalString('copilot.enterprise');\n const organization = config.getOptionalString('copilot.organization');\n\n const integrations = ScmIntegrations.fromConfig(config);\n\n const githubConfig = integrations.github.byHost(host)?.config;\n\n if (!githubConfig) {\n throw new Error(\n `GitHub configuration for host \"${host}\" is missing or incomplete. Please check the
|
|
1
|
+
{"version":3,"file":"GithubUtils.cjs.js","sources":["../../src/utils/GithubUtils.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Config } from '@backstage/config';\nimport {\n DefaultGithubCredentialsProvider,\n GithubCredentials,\n ScmIntegrations,\n} from '@backstage/integration';\n\nexport type CopilotCredentials = {\n enterprise?: GithubCredentials;\n organization?: GithubCredentials;\n};\n\nexport type CopilotConfig = {\n host: string;\n enterprise?: string;\n organization?: string;\n apiBaseUrl: string;\n};\n\nexport const getCopilotConfig = (config: Config): CopilotConfig => {\n const host = config.getString('copilot.host');\n const enterprise = config.getOptionalString('copilot.enterprise');\n const organization = config.getOptionalString('copilot.organization');\n\n const integrations = ScmIntegrations.fromConfig(config);\n\n const githubConfig = integrations.github.byHost(host)?.config;\n\n if (!githubConfig) {\n throw new Error(\n `GitHub configuration for host \"${host}\" is missing or incomplete. Please check the integrations configuration section.`,\n );\n }\n\n if (enterprise && !githubConfig.token) {\n throw new Error(\n `Enterprise API for copilot only works with \"classic PAT\" tokens. No token is configured for \"${host}\" in the config.`,\n );\n }\n\n if (organization && !(githubConfig.token || githubConfig.apps)) {\n throw new Error(\n `Organization API for copilot works with both classic and fine grained PAT tokens or GitHub apps. No token or app is configured for \"${host}\" in the config.`,\n );\n }\n\n return {\n host,\n enterprise,\n organization,\n apiBaseUrl: githubConfig.apiBaseUrl ?? 'https://api.github.com',\n };\n};\n\nexport const getGithubCredentials = async (\n config: Config,\n copilotConfig: CopilotConfig,\n): Promise<CopilotCredentials> => {\n const integrations = ScmIntegrations.fromConfig(config);\n const { host, enterprise, organization } = copilotConfig;\n\n const githubConfig = integrations.github.byHost(host)?.config;\n\n if (!githubConfig) {\n throw new Error(\n `GitHub configuration for host \"${host}\" is missing or incomplete.`,\n );\n }\n\n const credentials: CopilotCredentials = {\n enterprise: undefined,\n organization: undefined,\n };\n\n if (enterprise) {\n if (!githubConfig.token) {\n throw new Error(\n `Enterprise API for copilot only works with \"classic PAT\" tokens. No token is configured for \"${host}\" in the config.`,\n );\n } else {\n credentials.enterprise = {\n type: 'token',\n headers: { Authorization: `Bearer ${githubConfig.token}` },\n token: githubConfig.token,\n };\n }\n }\n\n if (organization) {\n if (githubConfig.apps) {\n const githubCredentialsProvider =\n DefaultGithubCredentialsProvider.fromIntegrations(integrations);\n\n credentials.organization = await githubCredentialsProvider.getCredentials(\n {\n url: `https://${host}/${organization}`,\n },\n );\n } else if (githubConfig.token) {\n credentials.organization = {\n type: 'token',\n headers: { Authorization: `Bearer ${githubConfig.token}` },\n token: githubConfig.token,\n };\n } else {\n throw new Error(\n `Organization API for copilot works with both classic and fine grained PAT tokens or GitHub apps. No token or app is configured for \"${host}\" in the config.`,\n );\n }\n }\n\n return credentials;\n};\n"],"names":["ScmIntegrations","DefaultGithubCredentialsProvider"],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ function filterBaseMetrics(metrics, type, team) {
|
|
|
15
15
|
return metrics.map((metric) => ({
|
|
16
16
|
day: metric.date,
|
|
17
17
|
type,
|
|
18
|
-
team_name: team,
|
|
18
|
+
team_name: team ?? "",
|
|
19
19
|
total_engaged_users: metric.total_engaged_users,
|
|
20
20
|
total_active_users: metric.total_active_users
|
|
21
21
|
})).filter((metric) => metric.total_engaged_users > 0);
|
|
@@ -24,7 +24,7 @@ function filterIdeCompletionMetrics(metrics, type, team) {
|
|
|
24
24
|
return metrics.map((metric) => ({
|
|
25
25
|
day: metric.date,
|
|
26
26
|
type,
|
|
27
|
-
team_name: team,
|
|
27
|
+
team_name: team ?? "",
|
|
28
28
|
total_engaged_users: metric.copilot_ide_code_completions.total_engaged_users
|
|
29
29
|
})).filter((completion) => completion.total_engaged_users > 0);
|
|
30
30
|
}
|
|
@@ -33,7 +33,7 @@ function filterIdeCompletionLanguageMetrics(metrics, type, team) {
|
|
|
33
33
|
(metric) => metric.copilot_ide_code_completions.languages?.map((language) => ({
|
|
34
34
|
day: metric.date,
|
|
35
35
|
type,
|
|
36
|
-
team_name: team,
|
|
36
|
+
team_name: team ?? "",
|
|
37
37
|
language: language.name,
|
|
38
38
|
total_engaged_users: language.total_engaged_users
|
|
39
39
|
})) || []
|
|
@@ -44,7 +44,7 @@ function filterIdeCompletionEditorMetrics(metrics, type, team) {
|
|
|
44
44
|
(metric) => metric.copilot_ide_code_completions.editors?.map((editor) => ({
|
|
45
45
|
day: metric.date,
|
|
46
46
|
type,
|
|
47
|
-
team_name: team,
|
|
47
|
+
team_name: team ?? "",
|
|
48
48
|
editor: editor.name,
|
|
49
49
|
total_engaged_users: editor.total_engaged_users
|
|
50
50
|
})) || []
|
|
@@ -56,7 +56,7 @@ function filterIdeCompletionEditorModelMetrics(metrics, type, team) {
|
|
|
56
56
|
(editor) => editor.models.map((model) => ({
|
|
57
57
|
day: metric.date,
|
|
58
58
|
type,
|
|
59
|
-
team_name: team,
|
|
59
|
+
team_name: team ?? "",
|
|
60
60
|
editor: editor.name,
|
|
61
61
|
model: model.name,
|
|
62
62
|
total_engaged_users: model.total_engaged_users
|
|
@@ -71,7 +71,7 @@ function filterIdeCompletionEditorModelLanguageMetrics(metrics, type, team) {
|
|
|
71
71
|
(model) => model.languages.map((language) => ({
|
|
72
72
|
day: metric.date,
|
|
73
73
|
type,
|
|
74
|
-
team_name: team,
|
|
74
|
+
team_name: team ?? "",
|
|
75
75
|
editor: editor.name,
|
|
76
76
|
model: model.name,
|
|
77
77
|
language: language.name,
|
|
@@ -89,7 +89,7 @@ function filterIdeChatMetrics(metrics, type, team) {
|
|
|
89
89
|
return metrics.map((metric) => ({
|
|
90
90
|
day: metric.date,
|
|
91
91
|
type,
|
|
92
|
-
team_name: team,
|
|
92
|
+
team_name: team ?? "",
|
|
93
93
|
total_engaged_users: metric.copilot_ide_chat.total_engaged_users
|
|
94
94
|
})).filter((chat) => chat.total_engaged_users > 0);
|
|
95
95
|
}
|
|
@@ -98,7 +98,7 @@ function filterIdeEditorMetrics(metrics, type, team) {
|
|
|
98
98
|
(metric) => metric.copilot_ide_chat.editors?.map((editor) => ({
|
|
99
99
|
day: metric.date,
|
|
100
100
|
type,
|
|
101
|
-
team_name: team,
|
|
101
|
+
team_name: team ?? "",
|
|
102
102
|
editor: editor.name,
|
|
103
103
|
total_engaged_users: editor.total_engaged_users
|
|
104
104
|
})) || []
|
|
@@ -110,7 +110,7 @@ function filterIdeChatEditorModelMetrics(metrics, type, team) {
|
|
|
110
110
|
(editor) => editor.models.map((model) => ({
|
|
111
111
|
day: metric.date,
|
|
112
112
|
type,
|
|
113
|
-
team_name: team,
|
|
113
|
+
team_name: team ?? "",
|
|
114
114
|
editor: editor.name,
|
|
115
115
|
model: model.name,
|
|
116
116
|
total_engaged_users: model.total_engaged_users,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricHelpers.cjs.js","sources":["../../src/utils/metricHelpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DateTime } from 'luxon';\nimport {\n CopilotIdeChatsDb,\n CopilotIdeChatsEditorModelDb,\n CopilotIdeChatsEditorsDb,\n CopilotIdeCodeCompletionsDb,\n CopilotIdeCodeCompletionsEditorModelLanguagesDb,\n CopilotIdeCodeCompletionsEditorModelsDb,\n CopilotIdeCodeCompletionsEditorsDb,\n CopilotIdeCodeCompletionsLanguageDb,\n CopilotMetricsDb,\n MetricDbRow,\n} from '../db/DatabaseHandler';\nimport {\n Metric,\n MetricsType,\n CopilotMetrics,\n CopilotSeats,\n SeatAnalysis,\n} from '@backstage-community/plugin-copilot-common';\n\nexport function filterNewMetricsV2(\n metrics: CopilotMetrics[],\n lastDay?: string,\n): CopilotMetrics[] {\n return metrics\n .sort(\n (a, b) =>\n DateTime.fromISO(a.date).toMillis() -\n DateTime.fromISO(b.date).toMillis(),\n )\n .filter(metric => {\n const metricDate = DateTime.fromISO(metric.date);\n\n const lastDayDate = lastDay\n ? DateTime.fromJSDate(new Date(lastDay))\n : null;\n\n return !lastDay || (lastDayDate?.isValid && metricDate > lastDayDate);\n });\n}\n\nexport function filterBaseMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotMetricsDb[] {\n return metrics\n .map(metric => ({\n day: metric.date,\n type: type,\n team_name: team,\n total_engaged_users: metric.total_engaged_users,\n total_active_users: metric.total_active_users,\n }))\n .filter(metric => metric.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsDb[] {\n return metrics\n .map(metric => ({\n day: metric.date,\n type: type,\n team_name: team,\n total_engaged_users:\n metric.copilot_ide_code_completions.total_engaged_users,\n }))\n .filter(completion => completion.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionLanguageMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsLanguageDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.languages?.map(language => ({\n day: metric.date,\n type: type,\n team_name: team,\n language: language.name,\n total_engaged_users: language.total_engaged_users,\n })) || [],\n )\n .filter(language => language.total_engaged_users > 0);\n}\nexport function filterIdeCompletionEditorMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.map(editor => ({\n day: metric.date,\n type: type,\n team_name: team,\n editor: editor.name,\n total_engaged_users: editor.total_engaged_users,\n })) || [],\n )\n .filter(editor => editor.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionEditorModelMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorModelsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.flatMap(editor =>\n editor.models.map(model => ({\n day: metric.date,\n type: type,\n team_name: team,\n editor: editor.name,\n model: model.name,\n total_engaged_users: model.total_engaged_users,\n })),\n ) || [],\n )\n .filter(model => model.total_engaged_users > 0);\n}\nexport function filterIdeCompletionEditorModelLanguageMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorModelLanguagesDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.flatMap(editor =>\n editor.models.flatMap(model =>\n model.languages.map(language => ({\n day: metric.date,\n type: type,\n team_name: team,\n editor: editor.name,\n model: model.name,\n language: language.name,\n total_engaged_users: language.total_engaged_users,\n total_code_acceptances: language.total_code_acceptances,\n total_code_suggestions: language.total_code_suggestions,\n total_code_lines_accepted: language.total_code_lines_accepted,\n total_code_lines_suggested: language.total_code_lines_suggested,\n })),\n ),\n ) || [],\n )\n .filter(language => language.total_engaged_users > 0);\n}\n\nexport function filterIdeChatMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsDb[] {\n return metrics\n .map((metric: CopilotMetrics) => ({\n day: metric.date,\n type: type,\n team_name: team,\n total_engaged_users: metric.copilot_ide_chat.total_engaged_users,\n }))\n .filter(chat => chat.total_engaged_users > 0);\n}\n\nexport function filterIdeEditorMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsEditorsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_chat.editors?.map(editor => ({\n day: metric.date,\n type: type,\n team_name: team,\n editor: editor.name,\n total_engaged_users: editor.total_engaged_users,\n })) || [],\n )\n .filter(editor => editor.total_engaged_users > 0);\n}\n\nexport function filterIdeChatEditorModelMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsEditorModelDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_chat.editors?.flatMap(editor =>\n editor.models.map(model => ({\n day: metric.date,\n type: type,\n team_name: team,\n editor: editor.name,\n model: model.name,\n total_engaged_users: model.total_engaged_users,\n total_chat_copy_events: model.total_chat_copy_events,\n total_chats: model.total_chats,\n total_chat_insertion_events: model.total_chat_insertion_events,\n })),\n ) || [],\n )\n .filter(model => model.total_engaged_users > 0);\n}\n\nexport function prepareMetricsForInsert(\n metrics: Metric[],\n type: MetricsType,\n team_name?: string,\n): MetricDbRow[] {\n return metrics.map(({ breakdown, ...rest }) => ({\n ...rest,\n type,\n team_name,\n breakdown: JSON.stringify(breakdown),\n })) as MetricDbRow[];\n}\n\nexport function convertToSeatAnalysis(\n metrics: CopilotSeats,\n type: MetricsType,\n team?: string,\n): SeatAnalysis {\n const totalSeats = metrics.total_seats;\n const today = DateTime.now().startOf('day');\n\n // Count seats with no activity\n const seatsNeverUsed = metrics.seats.filter(\n seat => !seat.last_activity_at,\n ).length;\n\n // Count seats with no activity in the last 7, 14, and 28 days\n const seatsInactive7Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 7;\n }).length;\n\n const seatsInactive14Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 14;\n }).length;\n\n const seatsInactive28Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 28;\n }).length;\n\n return {\n day: today.toISODate(),\n type,\n team_name: team ?? '',\n total_seats: totalSeats,\n seats_never_used: seatsNeverUsed,\n seats_inactive_7_days: seatsInactive7Days,\n seats_inactive_14_days: seatsInactive14Days,\n seats_inactive_28_days: seatsInactive28Days,\n };\n}\n\nexport function convertToTeamSeatAnalysis(\n metrics: CopilotSeats,\n type: MetricsType,\n team: string,\n): SeatAnalysis {\n const teamSeatMetrics = metrics.seats.filter(\n seat => seat.assigning_team?.slug === team,\n );\n const teamMetrics = {\n total_seats: teamSeatMetrics.length,\n seats: teamSeatMetrics,\n };\n\n return convertToSeatAnalysis(teamMetrics, type, team);\n}\n"],"names":["DateTime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"metricHelpers.cjs.js","sources":["../../src/utils/metricHelpers.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DateTime } from 'luxon';\nimport {\n CopilotIdeChatsDb,\n CopilotIdeChatsEditorModelDb,\n CopilotIdeChatsEditorsDb,\n CopilotIdeCodeCompletionsDb,\n CopilotIdeCodeCompletionsEditorModelLanguagesDb,\n CopilotIdeCodeCompletionsEditorModelsDb,\n CopilotIdeCodeCompletionsEditorsDb,\n CopilotIdeCodeCompletionsLanguageDb,\n CopilotMetricsDb,\n} from '../db/DatabaseHandler';\nimport {\n MetricsType,\n CopilotMetrics,\n CopilotSeats,\n SeatAnalysis,\n} from '@backstage-community/plugin-copilot-common';\n\nexport function filterNewMetricsV2(\n metrics: CopilotMetrics[],\n lastDay?: string,\n): CopilotMetrics[] {\n return metrics\n .sort(\n (a, b) =>\n DateTime.fromISO(a.date).toMillis() -\n DateTime.fromISO(b.date).toMillis(),\n )\n .filter(metric => {\n const metricDate = DateTime.fromISO(metric.date);\n\n const lastDayDate = lastDay\n ? DateTime.fromJSDate(new Date(lastDay))\n : null;\n\n return !lastDay || (lastDayDate?.isValid && metricDate > lastDayDate);\n });\n}\n\nexport function filterBaseMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotMetricsDb[] {\n return metrics\n .map(metric => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n total_engaged_users: metric.total_engaged_users,\n total_active_users: metric.total_active_users,\n }))\n .filter(metric => metric.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsDb[] {\n return metrics\n .map(metric => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n total_engaged_users:\n metric.copilot_ide_code_completions.total_engaged_users,\n }))\n .filter(completion => completion.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionLanguageMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsLanguageDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.languages?.map(language => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n language: language.name,\n total_engaged_users: language.total_engaged_users,\n })) || [],\n )\n .filter(language => language.total_engaged_users > 0);\n}\nexport function filterIdeCompletionEditorMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.map(editor => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n editor: editor.name,\n total_engaged_users: editor.total_engaged_users,\n })) || [],\n )\n .filter(editor => editor.total_engaged_users > 0);\n}\n\nexport function filterIdeCompletionEditorModelMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorModelsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.flatMap(editor =>\n editor.models.map(model => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n editor: editor.name,\n model: model.name,\n total_engaged_users: model.total_engaged_users,\n })),\n ) || [],\n )\n .filter(model => model.total_engaged_users > 0);\n}\nexport function filterIdeCompletionEditorModelLanguageMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeCodeCompletionsEditorModelLanguagesDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_code_completions.editors?.flatMap(editor =>\n editor.models.flatMap(model =>\n model.languages.map(language => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n editor: editor.name,\n model: model.name,\n language: language.name,\n total_engaged_users: language.total_engaged_users,\n total_code_acceptances: language.total_code_acceptances,\n total_code_suggestions: language.total_code_suggestions,\n total_code_lines_accepted: language.total_code_lines_accepted,\n total_code_lines_suggested: language.total_code_lines_suggested,\n })),\n ),\n ) || [],\n )\n .filter(language => language.total_engaged_users > 0);\n}\n\nexport function filterIdeChatMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsDb[] {\n return metrics\n .map((metric: CopilotMetrics) => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n total_engaged_users: metric.copilot_ide_chat.total_engaged_users,\n }))\n .filter(chat => chat.total_engaged_users > 0);\n}\n\nexport function filterIdeEditorMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsEditorsDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_chat.editors?.map(editor => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n editor: editor.name,\n total_engaged_users: editor.total_engaged_users,\n })) || [],\n )\n .filter(editor => editor.total_engaged_users > 0);\n}\n\nexport function filterIdeChatEditorModelMetrics(\n metrics: CopilotMetrics[],\n type: MetricsType,\n team?: string,\n): CopilotIdeChatsEditorModelDb[] {\n return metrics\n .flatMap(\n (metric: CopilotMetrics) =>\n metric.copilot_ide_chat.editors?.flatMap(editor =>\n editor.models.map(model => ({\n day: metric.date,\n type: type,\n team_name: team ?? '',\n editor: editor.name,\n model: model.name,\n total_engaged_users: model.total_engaged_users,\n total_chat_copy_events: model.total_chat_copy_events,\n total_chats: model.total_chats,\n total_chat_insertion_events: model.total_chat_insertion_events,\n })),\n ) || [],\n )\n .filter(model => model.total_engaged_users > 0);\n}\n\nexport function convertToSeatAnalysis(\n metrics: CopilotSeats,\n type: MetricsType,\n team?: string,\n): SeatAnalysis {\n const totalSeats = metrics.total_seats;\n const today = DateTime.now().startOf('day');\n\n // Count seats with no activity\n const seatsNeverUsed = metrics.seats.filter(\n seat => !seat.last_activity_at,\n ).length;\n\n // Count seats with no activity in the last 7, 14, and 28 days\n const seatsInactive7Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 7;\n }).length;\n\n const seatsInactive14Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 14;\n }).length;\n\n const seatsInactive28Days = metrics.seats.filter(seat => {\n if (!seat.last_activity_at) return false;\n const lastActivityDate = DateTime.fromISO(seat.last_activity_at);\n return today.diff(lastActivityDate, 'days').days >= 28;\n }).length;\n\n return {\n day: today.toISODate(),\n type,\n team_name: team ?? '',\n total_seats: totalSeats,\n seats_never_used: seatsNeverUsed,\n seats_inactive_7_days: seatsInactive7Days,\n seats_inactive_14_days: seatsInactive14Days,\n seats_inactive_28_days: seatsInactive28Days,\n };\n}\n\nexport function convertToTeamSeatAnalysis(\n metrics: CopilotSeats,\n type: MetricsType,\n team: string,\n): SeatAnalysis {\n const teamSeatMetrics = metrics.seats.filter(\n seat => seat.assigning_team?.slug === team,\n );\n const teamMetrics = {\n total_seats: teamSeatMetrics.length,\n seats: teamSeatMetrics,\n };\n\n return convertToSeatAnalysis(teamMetrics, type, team);\n}\n"],"names":["DateTime"],"mappings":"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"}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 The Backstage Authors
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* @param {import('knex').Knex} knex
|
|
18
|
+
*/
|
|
19
|
+
exports.up = async function up(knex) {
|
|
20
|
+
await deleteDuplicates('copilot_metrics', ['day', 'type']);
|
|
21
|
+
|
|
22
|
+
await deleteDuplicates('ide_completions', ['day', 'type']);
|
|
23
|
+
|
|
24
|
+
await deleteDuplicates('ide_completions_language_users', [
|
|
25
|
+
'day',
|
|
26
|
+
'language',
|
|
27
|
+
'type',
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
await deleteDuplicates('ide_completions_language_editors', [
|
|
31
|
+
'day',
|
|
32
|
+
'editor',
|
|
33
|
+
'type',
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
await deleteDuplicates('ide_completions_language_editors_model', [
|
|
37
|
+
'day',
|
|
38
|
+
'editor',
|
|
39
|
+
'model',
|
|
40
|
+
'type',
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
await deleteDuplicates('ide_completions_language_editors_model_language', [
|
|
44
|
+
'day',
|
|
45
|
+
'editor',
|
|
46
|
+
'model',
|
|
47
|
+
'language',
|
|
48
|
+
'type',
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
await deleteDuplicates('ide_chats', ['day', 'type']);
|
|
52
|
+
|
|
53
|
+
await deleteDuplicates('ide_chat_editors', ['day', 'editor', 'type']);
|
|
54
|
+
|
|
55
|
+
await deleteDuplicates('ide_chat_editors_model', [
|
|
56
|
+
'day',
|
|
57
|
+
'editor',
|
|
58
|
+
'model',
|
|
59
|
+
'type',
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
await deleteDuplicates('dotcom_chats', ['day', 'type']);
|
|
63
|
+
|
|
64
|
+
await deleteDuplicates('dotcom_chat_models', ['day', 'model', 'type']);
|
|
65
|
+
|
|
66
|
+
await deleteDuplicates('dotcom_prs', ['day', 'type']);
|
|
67
|
+
|
|
68
|
+
await deleteDuplicates('dotcom_pr_repositories', [
|
|
69
|
+
'day',
|
|
70
|
+
'repository',
|
|
71
|
+
'type',
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
await deleteDuplicates('dotcom_pr_repositories_models', [
|
|
75
|
+
'day',
|
|
76
|
+
'repository',
|
|
77
|
+
'model',
|
|
78
|
+
'type',
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
// Update all remaining null team_name values to empty strings
|
|
82
|
+
await knex('copilot_metrics')
|
|
83
|
+
.where('team_name', null)
|
|
84
|
+
.update({ team_name: '' });
|
|
85
|
+
|
|
86
|
+
await knex('ide_completions')
|
|
87
|
+
.where('team_name', null)
|
|
88
|
+
.update({ team_name: '' });
|
|
89
|
+
|
|
90
|
+
await knex('ide_completions_language_users')
|
|
91
|
+
.where('team_name', null)
|
|
92
|
+
.update({ team_name: '' });
|
|
93
|
+
|
|
94
|
+
await knex('ide_completions_language_editors')
|
|
95
|
+
.where('team_name', null)
|
|
96
|
+
.update({ team_name: '' });
|
|
97
|
+
|
|
98
|
+
await knex('ide_completions_language_editors_model')
|
|
99
|
+
.where('team_name', null)
|
|
100
|
+
.update({ team_name: '' });
|
|
101
|
+
|
|
102
|
+
await knex('ide_completions_language_editors_model_language')
|
|
103
|
+
.where('team_name', null)
|
|
104
|
+
.update({ team_name: '' });
|
|
105
|
+
|
|
106
|
+
await knex('ide_chats').where('team_name', null).update({ team_name: '' });
|
|
107
|
+
|
|
108
|
+
await knex('ide_chat_editors')
|
|
109
|
+
.where('team_name', null)
|
|
110
|
+
.update({ team_name: '' });
|
|
111
|
+
|
|
112
|
+
await knex('ide_chat_editors_model')
|
|
113
|
+
.where('team_name', null)
|
|
114
|
+
.update({ team_name: '' });
|
|
115
|
+
|
|
116
|
+
await knex('dotcom_chats').where('team_name', null).update({ team_name: '' });
|
|
117
|
+
|
|
118
|
+
await knex('dotcom_chat_models')
|
|
119
|
+
.where('team_name', null)
|
|
120
|
+
.update({ team_name: '' });
|
|
121
|
+
|
|
122
|
+
await knex('dotcom_prs').where('team_name', null).update({ team_name: '' });
|
|
123
|
+
|
|
124
|
+
await knex('dotcom_pr_repositories')
|
|
125
|
+
.where('team_name', null)
|
|
126
|
+
.update({ team_name: '' });
|
|
127
|
+
|
|
128
|
+
await knex('dotcom_pr_repositories_models')
|
|
129
|
+
.where('team_name', null)
|
|
130
|
+
.update({ team_name: '' });
|
|
131
|
+
|
|
132
|
+
// Finally, update all the team_name columns to not null
|
|
133
|
+
await knex.schema.table('copilot_metrics', table => {
|
|
134
|
+
table.string('team_name').notNullable().alter();
|
|
135
|
+
});
|
|
136
|
+
await knex.schema.table('ide_completions', table => {
|
|
137
|
+
table.string('team_name').notNullable().alter();
|
|
138
|
+
});
|
|
139
|
+
await knex.schema.table('ide_completions_language_users', table => {
|
|
140
|
+
table.string('team_name').notNullable().alter();
|
|
141
|
+
});
|
|
142
|
+
await knex.schema.table('ide_completions_language_editors', table => {
|
|
143
|
+
table.string('team_name').notNullable().alter();
|
|
144
|
+
});
|
|
145
|
+
await knex.schema.table('ide_completions_language_editors_model', table => {
|
|
146
|
+
table.string('team_name').notNullable().alter();
|
|
147
|
+
});
|
|
148
|
+
await knex.schema.table(
|
|
149
|
+
'ide_completions_language_editors_model_language',
|
|
150
|
+
table => {
|
|
151
|
+
table.string('team_name').notNullable().alter();
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
await knex.schema.table('ide_chats', table => {
|
|
155
|
+
table.string('team_name').notNullable().alter();
|
|
156
|
+
});
|
|
157
|
+
await knex.schema.table('ide_chat_editors', table => {
|
|
158
|
+
table.string('team_name').notNullable().alter();
|
|
159
|
+
});
|
|
160
|
+
await knex.schema.table('ide_chat_editors_model', table => {
|
|
161
|
+
table.string('team_name').notNullable().alter();
|
|
162
|
+
});
|
|
163
|
+
await knex.schema.table('dotcom_chats', table => {
|
|
164
|
+
table.string('team_name').notNullable().alter();
|
|
165
|
+
});
|
|
166
|
+
await knex.schema.table('dotcom_chat_models', table => {
|
|
167
|
+
table.string('team_name').notNullable().alter();
|
|
168
|
+
});
|
|
169
|
+
await knex.schema.table('dotcom_prs', table => {
|
|
170
|
+
table.string('team_name').notNullable().alter();
|
|
171
|
+
});
|
|
172
|
+
await knex.schema.table('dotcom_pr_repositories', table => {
|
|
173
|
+
table.string('team_name').notNullable().alter();
|
|
174
|
+
});
|
|
175
|
+
await knex.schema.table('dotcom_pr_repositories_models', table => {
|
|
176
|
+
table.string('team_name').notNullable().alter();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Delete duplicate rows keeping the one with highest total_engaged_users
|
|
180
|
+
// When there are ties (same total_engaged_users), keep only one row
|
|
181
|
+
async function deleteDuplicates(tableName, partitionColumns) {
|
|
182
|
+
const isSqlite = knex.client.config.client.includes('sqlite3');
|
|
183
|
+
const rowIdColumn = isSqlite ? 'rowid' : 'ctid';
|
|
184
|
+
|
|
185
|
+
const partitionBy = partitionColumns.join(', ');
|
|
186
|
+
|
|
187
|
+
await knex.raw(`
|
|
188
|
+
DELETE FROM ${tableName}
|
|
189
|
+
WHERE ${rowIdColumn} IN (
|
|
190
|
+
SELECT ${rowIdColumn}
|
|
191
|
+
FROM (
|
|
192
|
+
SELECT ${rowIdColumn},
|
|
193
|
+
ROW_NUMBER() OVER (
|
|
194
|
+
PARTITION BY ${partitionBy}
|
|
195
|
+
ORDER BY total_engaged_users DESC, ${rowIdColumn}
|
|
196
|
+
) as row_num
|
|
197
|
+
FROM ${tableName}
|
|
198
|
+
WHERE team_name IS NULL
|
|
199
|
+
) ranked
|
|
200
|
+
WHERE row_num > 1
|
|
201
|
+
)
|
|
202
|
+
`);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @param {import('knex').Knex} knex
|
|
208
|
+
*/
|
|
209
|
+
exports.down = async function down(knex) {
|
|
210
|
+
// a reverse migration is to update all the team_name columns to nullable
|
|
211
|
+
await knex.schema.table('copilot_metrics', table => {
|
|
212
|
+
table.string('team_name').nullable().alter();
|
|
213
|
+
});
|
|
214
|
+
await knex.schema.table('ide_completions', table => {
|
|
215
|
+
table.string('team_name').nullable().alter();
|
|
216
|
+
});
|
|
217
|
+
await knex.schema.table('ide_completions_language_users', table => {
|
|
218
|
+
table.string('team_name').nullable().alter();
|
|
219
|
+
});
|
|
220
|
+
await knex.schema.table('ide_completions_language_editors', table => {
|
|
221
|
+
table.string('team_name').nullable().alter();
|
|
222
|
+
});
|
|
223
|
+
await knex.schema.table('ide_completions_language_editors_model', table => {
|
|
224
|
+
table.string('team_name').nullable().alter();
|
|
225
|
+
});
|
|
226
|
+
await knex.schema.table(
|
|
227
|
+
'ide_completions_language_editors_model_language',
|
|
228
|
+
table => {
|
|
229
|
+
table.string('team_name').nullable().alter();
|
|
230
|
+
},
|
|
231
|
+
);
|
|
232
|
+
await knex.schema.table('ide_chats', table => {
|
|
233
|
+
table.string('team_name').nullable().alter();
|
|
234
|
+
});
|
|
235
|
+
await knex.schema.table('ide_chat_editors', table => {
|
|
236
|
+
table.string('team_name').nullable().alter();
|
|
237
|
+
});
|
|
238
|
+
await knex.schema.table('ide_chat_editors_model', table => {
|
|
239
|
+
table.string('team_name').nullable().alter();
|
|
240
|
+
});
|
|
241
|
+
await knex.schema.table('dotcom_chats', table => {
|
|
242
|
+
table.string('team_name').nullable().alter();
|
|
243
|
+
});
|
|
244
|
+
await knex.schema.table('dotcom_chat_models', table => {
|
|
245
|
+
table.string('team_name').nullable().alter();
|
|
246
|
+
});
|
|
247
|
+
await knex.schema.table('dotcom_prs', table => {
|
|
248
|
+
table.string('team_name').nullable().alter();
|
|
249
|
+
});
|
|
250
|
+
await knex.schema.table('dotcom_pr_repositories', table => {
|
|
251
|
+
table.string('team_name').nullable().alter();
|
|
252
|
+
});
|
|
253
|
+
await knex.schema.table('dotcom_pr_repositories_models', table => {
|
|
254
|
+
table.string('team_name').nullable().alter();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Then update all the rows with team_name = '' to null
|
|
258
|
+
// This makes all duplicates gone, but the possibillity of having
|
|
259
|
+
// more duplicates until the next migration
|
|
260
|
+
await knex('copilot_metrics')
|
|
261
|
+
.where('team_name', '')
|
|
262
|
+
.update({ team_name: null });
|
|
263
|
+
await knex('ide_completions')
|
|
264
|
+
.where('team_name', '')
|
|
265
|
+
.update({ team_name: null });
|
|
266
|
+
await knex('ide_completions_language_users')
|
|
267
|
+
.where('team_name', '')
|
|
268
|
+
.update({ team_name: null });
|
|
269
|
+
await knex('ide_completions_language_editors')
|
|
270
|
+
.where('team_name', '')
|
|
271
|
+
.update({ team_name: null });
|
|
272
|
+
await knex('ide_completions_language_editors_model')
|
|
273
|
+
.where('team_name', '')
|
|
274
|
+
.update({ team_name: null });
|
|
275
|
+
await knex('ide_completions_language_editors_model_language')
|
|
276
|
+
.where('team_name', '')
|
|
277
|
+
.update({ team_name: null });
|
|
278
|
+
await knex('ide_chats').where('team_name', '').update({ team_name: null });
|
|
279
|
+
await knex('ide_chat_editors')
|
|
280
|
+
.where('team_name', '')
|
|
281
|
+
.update({ team_name: null });
|
|
282
|
+
await knex('ide_chat_editors_model')
|
|
283
|
+
.where('team_name', '')
|
|
284
|
+
.update({ team_name: null });
|
|
285
|
+
await knex('dotcom_chats').where('team_name', '').update({ team_name: null });
|
|
286
|
+
await knex('dotcom_chat_models')
|
|
287
|
+
.where('team_name', '')
|
|
288
|
+
.update({ team_name: null });
|
|
289
|
+
await knex('dotcom_prs').where('team_name', '').update({ team_name: null });
|
|
290
|
+
await knex('dotcom_pr_repositories')
|
|
291
|
+
.where('team_name', '')
|
|
292
|
+
.update({ team_name: null });
|
|
293
|
+
await knex('dotcom_pr_repositories_models')
|
|
294
|
+
.where('team_name', '')
|
|
295
|
+
.update({ team_name: null });
|
|
296
|
+
};
|