@backstage-community/plugin-copilot-backend 0.1.3 → 0.1.4
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 +8 -0
- package/dist/client/GithubClient.cjs.js +39 -0
- package/dist/client/GithubClient.cjs.js.map +1 -0
- package/dist/db/DatabaseHandler.cjs.js +50 -0
- package/dist/db/DatabaseHandler.cjs.js.map +1 -0
- package/dist/index.cjs.js +4 -258
- package/dist/index.cjs.js.map +1 -1
- package/dist/plugin.cjs.js +36 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/service/router.cjs.js +80 -0
- package/dist/service/router.cjs.js.map +1 -0
- package/dist/task/Scheduler.cjs.js +59 -0
- package/dist/task/Scheduler.cjs.js.map +1 -0
- package/dist/utils/GithubUtils.cjs.js +37 -0
- package/dist/utils/GithubUtils.cjs.js.map +1 -0
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @backstage-community/plugin-copilot-backend
|
|
2
2
|
|
|
3
|
+
## 0.1.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 399dc3b: Backstage version bump to v1.32.2
|
|
8
|
+
- Updated dependencies [399dc3b]
|
|
9
|
+
- @backstage-community/plugin-copilot-common@0.2.2
|
|
10
|
+
|
|
3
11
|
## 0.1.3
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
var fetch = require('node-fetch');
|
|
5
|
+
var GithubUtils = require('../utils/GithubUtils.cjs.js');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
|
|
10
|
+
|
|
11
|
+
class GithubClient {
|
|
12
|
+
constructor(props) {
|
|
13
|
+
this.props = props;
|
|
14
|
+
}
|
|
15
|
+
static async fromConfig(config) {
|
|
16
|
+
const info = await GithubUtils.getGithubInfo(config);
|
|
17
|
+
return new GithubClient(info);
|
|
18
|
+
}
|
|
19
|
+
async getCopilotUsageDataForEnterprise() {
|
|
20
|
+
const path = `/enterprises/${this.props.enterprise}/copilot/usage`;
|
|
21
|
+
return this.get(path);
|
|
22
|
+
}
|
|
23
|
+
async get(path) {
|
|
24
|
+
const response = await fetch__default.default(`${this.props.apiBaseUrl}${path}`, {
|
|
25
|
+
headers: {
|
|
26
|
+
...this.props.credentials.headers,
|
|
27
|
+
Accept: "application/vnd.github+json",
|
|
28
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw await errors.ResponseError.fromResponse(response);
|
|
33
|
+
}
|
|
34
|
+
return response.json();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.GithubClient = GithubClient;
|
|
39
|
+
//# sourceMappingURL=GithubClient.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GithubClient.cjs.js","sources":["../../src/client/GithubClient.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 { ResponseError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { Metric } from '@backstage-community/plugin-copilot-common';\nimport fetch from 'node-fetch';\nimport { getGithubInfo, GithubInfo } from '../utils/GithubUtils';\n\ninterface GithubApi {\n getCopilotUsageDataForEnterprise: () => Promise<Metric[]>;\n}\n\nexport class GithubClient implements GithubApi {\n constructor(private readonly props: GithubInfo) {}\n\n static async fromConfig(config: Config) {\n const info = await getGithubInfo(config);\n return new GithubClient(info);\n }\n\n async getCopilotUsageDataForEnterprise(): Promise<Metric[]> {\n const path = `/enterprises/${this.props.enterprise}/copilot/usage`;\n return this.get(path);\n }\n\n private async get<T>(path: string): Promise<T> {\n const response = await fetch(`${this.props.apiBaseUrl}${path}`, {\n headers: {\n ...this.props.credentials.headers,\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n },\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n}\n"],"names":["getGithubInfo","fetch","ResponseError"],"mappings":";;;;;;;;;;AA0BO,MAAM,YAAkC,CAAA;AAAA,EAC7C,YAA6B,KAAmB,EAAA;AAAnB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA,CAAA;AAAA,GAAoB;AAAA,EAEjD,aAAa,WAAW,MAAgB,EAAA;AACtC,IAAM,MAAA,IAAA,GAAO,MAAMA,yBAAA,CAAc,MAAM,CAAA,CAAA;AACvC,IAAO,OAAA,IAAI,aAAa,IAAI,CAAA,CAAA;AAAA,GAC9B;AAAA,EAEA,MAAM,gCAAsD,GAAA;AAC1D,IAAA,MAAM,IAAO,GAAA,CAAA,aAAA,EAAgB,IAAK,CAAA,KAAA,CAAM,UAAU,CAAA,cAAA,CAAA,CAAA;AAClD,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA,CAAA;AAAA,GACtB;AAAA,EAEA,MAAc,IAAO,IAA0B,EAAA;AAC7C,IAAM,MAAA,QAAA,GAAW,MAAMC,sBAAM,CAAA,CAAA,EAAG,KAAK,KAAM,CAAA,UAAU,CAAG,EAAA,IAAI,CAAI,CAAA,EAAA;AAAA,MAC9D,OAAS,EAAA;AAAA,QACP,GAAG,IAAK,CAAA,KAAA,CAAM,WAAY,CAAA,OAAA;AAAA,QAC1B,MAAQ,EAAA,6BAAA;AAAA,QACR,sBAAwB,EAAA,YAAA;AAAA,OAC1B;AAAA,KACD,CAAA,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,MAAMC,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA,CAAA;AAAA,KACjD;AAEA,IAAA,OAAO,SAAS,IAAK,EAAA,CAAA;AAAA,GACvB;AACF;;;;"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
|
|
5
|
+
const migrationsDir = backendPluginApi.resolvePackagePath(
|
|
6
|
+
"@backstage-community/plugin-copilot-backend",
|
|
7
|
+
"migrations"
|
|
8
|
+
);
|
|
9
|
+
class DatabaseHandler {
|
|
10
|
+
constructor(db) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
}
|
|
13
|
+
static async create(options) {
|
|
14
|
+
const { database } = options;
|
|
15
|
+
const client = await database.getClient();
|
|
16
|
+
if (!database.migrations?.skip) {
|
|
17
|
+
await client.migrate.latest({
|
|
18
|
+
directory: migrationsDir
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return new DatabaseHandler(client);
|
|
22
|
+
}
|
|
23
|
+
async getMetricsByPeriod(startDate, endDate) {
|
|
24
|
+
const records = await this.db("metrics").whereBetween("day", [
|
|
25
|
+
startDate,
|
|
26
|
+
endDate
|
|
27
|
+
]);
|
|
28
|
+
return records ?? [];
|
|
29
|
+
}
|
|
30
|
+
async getPeriodRange() {
|
|
31
|
+
const minDate = await this.db("metrics").orderBy("day", "asc").first("day");
|
|
32
|
+
const maxDate = await this.db("metrics").orderBy("day", "desc").first("day");
|
|
33
|
+
if (!minDate?.day || !maxDate?.day) return void 0;
|
|
34
|
+
return { minDate: minDate.day, maxDate: maxDate.day };
|
|
35
|
+
}
|
|
36
|
+
async batchInsert(metrics) {
|
|
37
|
+
await this.db("metrics").insert(metrics).onConflict("day").ignore();
|
|
38
|
+
}
|
|
39
|
+
async getMostRecentDayFromMetrics() {
|
|
40
|
+
try {
|
|
41
|
+
const mostRecent = await this.db("metrics").orderBy("day", "desc").first("day");
|
|
42
|
+
return mostRecent ? mostRecent.day : void 0;
|
|
43
|
+
} catch (e) {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exports.DatabaseHandler = DatabaseHandler;
|
|
50
|
+
//# sourceMappingURL=DatabaseHandler.cjs.js.map
|
|
@@ -0,0 +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 PeriodRange,\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 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 getMetricsByPeriod(\n startDate: string,\n endDate: string,\n ): Promise<MetricDbRow[]> {\n const records = await this.db<MetricDbRow>('metrics').whereBetween('day', [\n startDate,\n endDate,\n ]);\n return records ?? [];\n }\n\n async getPeriodRange(): Promise<PeriodRange | undefined> {\n const minDate = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'asc')\n .first('day');\n const maxDate = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'desc')\n .first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async batchInsert(metrics: MetricDbRow[]): Promise<void> {\n await this.db<MetricDbRow[]>('metrics')\n .insert(metrics)\n .onConflict('day')\n .ignore();\n }\n\n async getMostRecentDayFromMetrics(): Promise<string | undefined> {\n try {\n const mostRecent = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'desc')\n .first('day');\n\n return mostRecent ? mostRecent.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n}\n"],"names":["resolvePackagePath"],"mappings":";;;;AA0BA,MAAM,aAAgB,GAAAA,mCAAA;AAAA,EACpB,6CAAA;AAAA,EACA,YAAA;AACF,CAAA,CAAA;AAUO,MAAM,eAAgB,CAAA;AAAA,EAcnB,YAA6B,EAAU,EAAA;AAAV,IAAA,IAAA,CAAA,EAAA,GAAA,EAAA,CAAA;AAAA,GAAW;AAAA,EAbhD,aAAa,OAAO,OAA4C,EAAA;AAC9D,IAAM,MAAA,EAAE,UAAa,GAAA,OAAA,CAAA;AACrB,IAAM,MAAA,MAAA,GAAS,MAAM,QAAA,CAAS,SAAU,EAAA,CAAA;AAExC,IAAI,IAAA,CAAC,QAAS,CAAA,UAAA,EAAY,IAAM,EAAA;AAC9B,MAAM,MAAA,MAAA,CAAO,QAAQ,MAAO,CAAA;AAAA,QAC1B,SAAW,EAAA,aAAA;AAAA,OACZ,CAAA,CAAA;AAAA,KACH;AAEA,IAAO,OAAA,IAAI,gBAAgB,MAAM,CAAA,CAAA;AAAA,GACnC;AAAA,EAIA,MAAM,kBACJ,CAAA,SAAA,EACA,OACwB,EAAA;AACxB,IAAA,MAAM,UAAU,MAAM,IAAA,CAAK,GAAgB,SAAS,CAAA,CAAE,aAAa,KAAO,EAAA;AAAA,MACxE,SAAA;AAAA,MACA,OAAA;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAO,WAAW,EAAC,CAAA;AAAA,GACrB;AAAA,EAEA,MAAM,cAAmD,GAAA;AACvD,IAAM,MAAA,OAAA,GAAU,MAAM,IAAA,CAAK,EAAgB,CAAA,SAAS,CACjD,CAAA,OAAA,CAAQ,KAAO,EAAA,KAAK,CACpB,CAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AACd,IAAM,MAAA,OAAA,GAAU,MAAM,IAAA,CAAK,EAAgB,CAAA,SAAS,CACjD,CAAA,OAAA,CAAQ,KAAO,EAAA,MAAM,CACrB,CAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAEd,IAAA,IAAI,CAAC,OAAS,EAAA,GAAA,IAAO,CAAC,OAAA,EAAS,KAAY,OAAA,KAAA,CAAA,CAAA;AAE3C,IAAA,OAAO,EAAE,OAAS,EAAA,OAAA,CAAQ,GAAK,EAAA,OAAA,EAAS,QAAQ,GAAI,EAAA,CAAA;AAAA,GACtD;AAAA,EAEA,MAAM,YAAY,OAAuC,EAAA;AACvD,IAAM,MAAA,IAAA,CAAK,EAAkB,CAAA,SAAS,CACnC,CAAA,MAAA,CAAO,OAAO,CACd,CAAA,UAAA,CAAW,KAAK,CAAA,CAChB,MAAO,EAAA,CAAA;AAAA,GACZ;AAAA,EAEA,MAAM,2BAA2D,GAAA;AAC/D,IAAI,IAAA;AACF,MAAM,MAAA,UAAA,GAAa,MAAM,IAAA,CAAK,EAAgB,CAAA,SAAS,CACpD,CAAA,OAAA,CAAQ,KAAO,EAAA,MAAM,CACrB,CAAA,KAAA,CAAM,KAAK,CAAA,CAAA;AAEd,MAAO,OAAA,UAAA,GAAa,WAAW,GAAM,GAAA,KAAA,CAAA,CAAA;AAAA,aAC9B,CAAG,EAAA;AACV,MAAO,OAAA,KAAA,CAAA,CAAA;AAAA,KACT;AAAA,GACF;AACF;;;;"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -2,265 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
8
|
-
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
9
|
-
var luxon = require('luxon');
|
|
10
|
-
var errors = require('@backstage/errors');
|
|
11
|
-
var fetch = require('node-fetch');
|
|
12
|
-
var integration = require('@backstage/integration');
|
|
5
|
+
var router = require('./service/router.cjs.js');
|
|
6
|
+
var plugin = require('./plugin.cjs.js');
|
|
13
7
|
|
|
14
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
15
8
|
|
|
16
|
-
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
17
|
-
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
18
|
-
var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
|
|
19
9
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"migrations"
|
|
23
|
-
);
|
|
24
|
-
class DatabaseHandler {
|
|
25
|
-
constructor(db) {
|
|
26
|
-
this.db = db;
|
|
27
|
-
}
|
|
28
|
-
static async create(options) {
|
|
29
|
-
const { database } = options;
|
|
30
|
-
const client = await database.getClient();
|
|
31
|
-
if (!database.migrations?.skip) {
|
|
32
|
-
await client.migrate.latest({
|
|
33
|
-
directory: migrationsDir
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
return new DatabaseHandler(client);
|
|
37
|
-
}
|
|
38
|
-
async getMetricsByPeriod(startDate, endDate) {
|
|
39
|
-
const records = await this.db("metrics").whereBetween("day", [
|
|
40
|
-
startDate,
|
|
41
|
-
endDate
|
|
42
|
-
]);
|
|
43
|
-
return records ?? [];
|
|
44
|
-
}
|
|
45
|
-
async getPeriodRange() {
|
|
46
|
-
const minDate = await this.db("metrics").orderBy("day", "asc").first("day");
|
|
47
|
-
const maxDate = await this.db("metrics").orderBy("day", "desc").first("day");
|
|
48
|
-
if (!minDate?.day || !maxDate?.day) return void 0;
|
|
49
|
-
return { minDate: minDate.day, maxDate: maxDate.day };
|
|
50
|
-
}
|
|
51
|
-
async batchInsert(metrics) {
|
|
52
|
-
await this.db("metrics").insert(metrics).onConflict("day").ignore();
|
|
53
|
-
}
|
|
54
|
-
async getMostRecentDayFromMetrics() {
|
|
55
|
-
try {
|
|
56
|
-
const mostRecent = await this.db("metrics").orderBy("day", "desc").first("day");
|
|
57
|
-
return mostRecent ? mostRecent.day : void 0;
|
|
58
|
-
} catch (e) {
|
|
59
|
-
return void 0;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
class Scheduler {
|
|
65
|
-
constructor(options) {
|
|
66
|
-
this.options = options;
|
|
67
|
-
}
|
|
68
|
-
static create(options) {
|
|
69
|
-
return new Scheduler(options);
|
|
70
|
-
}
|
|
71
|
-
async run() {
|
|
72
|
-
try {
|
|
73
|
-
this.options.logger.info("Starting Github Copilot Processor");
|
|
74
|
-
const copilotMetrics = await this.options.api.getCopilotUsageDataForEnterprise();
|
|
75
|
-
this.options.logger.info(`Fetched ${copilotMetrics.length} metrics`);
|
|
76
|
-
const lastDay = await this.options.db.getMostRecentDayFromMetrics();
|
|
77
|
-
this.options.logger.info(`Found last day: ${lastDay}`);
|
|
78
|
-
const diff = copilotMetrics.sort(
|
|
79
|
-
(a, b) => luxon.DateTime.fromISO(a.day).toMillis() - luxon.DateTime.fromISO(b.day).toMillis()
|
|
80
|
-
).filter((metric) => {
|
|
81
|
-
const metricDate = luxon.DateTime.fromISO(metric.day);
|
|
82
|
-
const lastDayDate = lastDay ? luxon.DateTime.fromISO(lastDay) : null;
|
|
83
|
-
return !lastDayDate || metricDate > lastDayDate;
|
|
84
|
-
}).map(({ breakdown, ...rest }) => ({
|
|
85
|
-
...rest,
|
|
86
|
-
breakdown: JSON.stringify(breakdown)
|
|
87
|
-
}));
|
|
88
|
-
this.options.logger.info(`Found ${diff.length} new metrics to insert`);
|
|
89
|
-
if (diff.length > 0) {
|
|
90
|
-
await batchInsertInChunks(
|
|
91
|
-
diff,
|
|
92
|
-
30,
|
|
93
|
-
async (chunk) => {
|
|
94
|
-
await this.options.db.batchInsert(chunk);
|
|
95
|
-
}
|
|
96
|
-
);
|
|
97
|
-
this.options.logger.info("Inserted new metrics into the database");
|
|
98
|
-
} else {
|
|
99
|
-
this.options.logger.info("No new metrics found to insert");
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
this.options.logger.error(
|
|
103
|
-
`An error occurred while processing Github Copilot metrics: ${error}`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
async function batchInsertInChunks(data, chunkSize, batchInsertFunc) {
|
|
109
|
-
for (let i = 0; i < data.length; i += chunkSize) {
|
|
110
|
-
const chunk = data.slice(i, i + chunkSize);
|
|
111
|
-
await batchInsertFunc(chunk);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const getGithubInfo = async (config) => {
|
|
116
|
-
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
117
|
-
const credentialsProvider = integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
|
|
118
|
-
const host = config.getString("copilot.host");
|
|
119
|
-
const enterprise = config.getString("copilot.enterprise");
|
|
120
|
-
if (!host) {
|
|
121
|
-
throw new Error("The host configuration is missing from the config.");
|
|
122
|
-
}
|
|
123
|
-
if (!enterprise) {
|
|
124
|
-
throw new Error("The enterprise configuration is missing from the config.");
|
|
125
|
-
}
|
|
126
|
-
const githubConfig = integrations.github.byHost(host)?.config;
|
|
127
|
-
if (!githubConfig) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`GitHub configuration for host "${host}" is missing or incomplete.`
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
const apiBaseUrl = githubConfig.apiBaseUrl ?? "https://api.github.com";
|
|
133
|
-
const credentials = await credentialsProvider.getCredentials({
|
|
134
|
-
url: apiBaseUrl
|
|
135
|
-
});
|
|
136
|
-
if (!credentials.headers) {
|
|
137
|
-
throw new Error("Failed to retrieve credentials headers.");
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
apiBaseUrl,
|
|
141
|
-
credentials,
|
|
142
|
-
enterprise
|
|
143
|
-
};
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
class GithubClient {
|
|
147
|
-
constructor(props) {
|
|
148
|
-
this.props = props;
|
|
149
|
-
}
|
|
150
|
-
static async fromConfig(config) {
|
|
151
|
-
const info = await getGithubInfo(config);
|
|
152
|
-
return new GithubClient(info);
|
|
153
|
-
}
|
|
154
|
-
async getCopilotUsageDataForEnterprise() {
|
|
155
|
-
const path = `/enterprises/${this.props.enterprise}/copilot/usage`;
|
|
156
|
-
return this.get(path);
|
|
157
|
-
}
|
|
158
|
-
async get(path) {
|
|
159
|
-
const response = await fetch__default.default(`${this.props.apiBaseUrl}${path}`, {
|
|
160
|
-
headers: {
|
|
161
|
-
...this.props.credentials.headers,
|
|
162
|
-
Accept: "application/vnd.github+json",
|
|
163
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
if (!response.ok) {
|
|
167
|
-
throw await errors.ResponseError.fromResponse(response);
|
|
168
|
-
}
|
|
169
|
-
return response.json();
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const defaultSchedule = {
|
|
174
|
-
frequency: { cron: "0 2 * * *" },
|
|
175
|
-
timeout: { minutes: 15 },
|
|
176
|
-
initialDelay: { minutes: 1 },
|
|
177
|
-
scope: "local"
|
|
178
|
-
};
|
|
179
|
-
async function createRouterFromConfig(routerOptions) {
|
|
180
|
-
const { config } = routerOptions;
|
|
181
|
-
const pluginOptions = {
|
|
182
|
-
schedule: defaultSchedule
|
|
183
|
-
};
|
|
184
|
-
if (config && config.has("copilot.schedule")) {
|
|
185
|
-
pluginOptions.schedule = backendPluginApi.readSchedulerServiceTaskScheduleDefinitionFromConfig(
|
|
186
|
-
config.getConfig("copilot.schedule")
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
return createRouter(routerOptions, pluginOptions);
|
|
190
|
-
}
|
|
191
|
-
async function createRouter(routerOptions, pluginOptions) {
|
|
192
|
-
const { logger, database, scheduler, config } = routerOptions;
|
|
193
|
-
const { schedule } = pluginOptions;
|
|
194
|
-
const db = await DatabaseHandler.create({ database });
|
|
195
|
-
const api = await GithubClient.fromConfig(config);
|
|
196
|
-
await scheduler.scheduleTask({
|
|
197
|
-
id: "copilot-metrics",
|
|
198
|
-
...schedule ?? defaultSchedule,
|
|
199
|
-
fn: async () => await Scheduler.create({ db, logger, api, config }).run()
|
|
200
|
-
});
|
|
201
|
-
const router = Router__default.default();
|
|
202
|
-
router.use(express__default.default.json());
|
|
203
|
-
router.get("/health", (_, response) => {
|
|
204
|
-
logger.info("PONG!");
|
|
205
|
-
response.json({ status: "ok" });
|
|
206
|
-
});
|
|
207
|
-
router.get("/metrics", async (request, response) => {
|
|
208
|
-
const { startDate, endDate } = request.query;
|
|
209
|
-
if (typeof startDate !== "string" || typeof endDate !== "string") {
|
|
210
|
-
return response.status(400).json("Invalid query parameters");
|
|
211
|
-
}
|
|
212
|
-
const parsedStartDate = luxon.DateTime.fromISO(startDate);
|
|
213
|
-
const parsedEndDate = luxon.DateTime.fromISO(endDate);
|
|
214
|
-
if (!parsedStartDate.isValid || !parsedEndDate.isValid) {
|
|
215
|
-
return response.status(400).json("Invalid date format");
|
|
216
|
-
}
|
|
217
|
-
const result = await db.getMetricsByPeriod(startDate, endDate);
|
|
218
|
-
const metrics = result.map((metric) => ({
|
|
219
|
-
...metric,
|
|
220
|
-
breakdown: JSON.parse(metric.breakdown)
|
|
221
|
-
}));
|
|
222
|
-
return response.json(metrics);
|
|
223
|
-
});
|
|
224
|
-
router.get("/metrics/period-range", async (_, response) => {
|
|
225
|
-
const result = await db.getPeriodRange();
|
|
226
|
-
if (!result) {
|
|
227
|
-
return response.status(400).json("No available data");
|
|
228
|
-
}
|
|
229
|
-
return response.json(result);
|
|
230
|
-
});
|
|
231
|
-
router.use(rootHttpRouter.MiddlewareFactory.create({ config, logger }).error);
|
|
232
|
-
return router;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const copilotPlugin = backendPluginApi.createBackendPlugin({
|
|
236
|
-
pluginId: "copilot",
|
|
237
|
-
register(env) {
|
|
238
|
-
env.registerInit({
|
|
239
|
-
deps: {
|
|
240
|
-
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
241
|
-
logger: backendPluginApi.coreServices.logger,
|
|
242
|
-
database: backendPluginApi.coreServices.database,
|
|
243
|
-
scheduler: backendPluginApi.coreServices.scheduler,
|
|
244
|
-
config: backendPluginApi.coreServices.rootConfig
|
|
245
|
-
},
|
|
246
|
-
async init({ httpRouter, logger, database, scheduler, config }) {
|
|
247
|
-
httpRouter.use(
|
|
248
|
-
await createRouterFromConfig({
|
|
249
|
-
logger,
|
|
250
|
-
database,
|
|
251
|
-
scheduler,
|
|
252
|
-
config
|
|
253
|
-
})
|
|
254
|
-
);
|
|
255
|
-
httpRouter.addAuthPolicy({
|
|
256
|
-
path: "/health",
|
|
257
|
-
allow: "unauthenticated"
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
exports.createRouterFromConfig = createRouterFromConfig;
|
|
265
|
-
exports.default = copilotPlugin;
|
|
10
|
+
exports.createRouterFromConfig = router.createRouterFromConfig;
|
|
11
|
+
exports.default = plugin.copilotPlugin;
|
|
266
12
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/db/DatabaseHandler.ts","../src/task/Scheduler.ts","../src/utils/GithubUtils.ts","../src/client/GithubClient.ts","../src/service/router.ts","../src/plugin.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 PeriodRange,\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 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 getMetricsByPeriod(\n startDate: string,\n endDate: string,\n ): Promise<MetricDbRow[]> {\n const records = await this.db<MetricDbRow>('metrics').whereBetween('day', [\n startDate,\n endDate,\n ]);\n return records ?? [];\n }\n\n async getPeriodRange(): Promise<PeriodRange | undefined> {\n const minDate = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'asc')\n .first('day');\n const maxDate = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'desc')\n .first('day');\n\n if (!minDate?.day || !maxDate?.day) return undefined;\n\n return { minDate: minDate.day, maxDate: maxDate.day };\n }\n\n async batchInsert(metrics: MetricDbRow[]): Promise<void> {\n await this.db<MetricDbRow[]>('metrics')\n .insert(metrics)\n .onConflict('day')\n .ignore();\n }\n\n async getMostRecentDayFromMetrics(): Promise<string | undefined> {\n try {\n const mostRecent = await this.db<MetricDbRow>('metrics')\n .orderBy('day', 'desc')\n .first('day');\n\n return mostRecent ? mostRecent.day : undefined;\n } catch (e) {\n return undefined;\n }\n }\n}\n","/*\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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { GithubClient } from '../client/GithubClient';\nimport { DatabaseHandler, MetricDbRow } from '../db/DatabaseHandler';\nimport { Config } from '@backstage/config';\nimport { DateTime } from 'luxon';\n\ntype Options = {\n api: GithubClient;\n config: Config;\n logger: LoggerService;\n db: DatabaseHandler;\n};\n\nexport default class Scheduler {\n constructor(private readonly options: Options) {}\n\n static create(options: Options) {\n return new Scheduler(options);\n }\n\n async run() {\n try {\n this.options.logger.info('Starting Github Copilot Processor');\n\n const copilotMetrics =\n await this.options.api.getCopilotUsageDataForEnterprise();\n this.options.logger.info(`Fetched ${copilotMetrics.length} metrics`);\n\n const lastDay = await this.options.db.getMostRecentDayFromMetrics();\n this.options.logger.info(`Found last day: ${lastDay}`);\n\n const diff = copilotMetrics\n .sort(\n (a, b) =>\n DateTime.fromISO(a.day).toMillis() -\n DateTime.fromISO(b.day).toMillis(),\n )\n .filter(metric => {\n const metricDate = DateTime.fromISO(metric.day);\n const lastDayDate = lastDay ? DateTime.fromISO(lastDay) : null;\n return !lastDayDate || metricDate > lastDayDate;\n })\n .map(({ breakdown, ...rest }) => ({\n ...rest,\n breakdown: JSON.stringify(breakdown),\n }));\n\n this.options.logger.info(`Found ${diff.length} new metrics to insert`);\n\n if (diff.length > 0) {\n await batchInsertInChunks<MetricDbRow>(\n diff,\n 30,\n async (chunk: MetricDbRow[]) => {\n await this.options.db.batchInsert(chunk);\n },\n );\n this.options.logger.info('Inserted new metrics into the database');\n } else {\n this.options.logger.info('No new metrics found to insert');\n }\n } catch (error) {\n this.options.logger.error(\n `An error occurred while processing Github Copilot metrics: ${error}`,\n );\n }\n }\n}\n\nasync function batchInsertInChunks<T>(\n data: T[],\n chunkSize: number,\n batchInsertFunc: (chunk: T[]) => Promise<void>,\n): Promise<void> {\n for (let i = 0; i < data.length; i += chunkSize) {\n const chunk = data.slice(i, i + chunkSize);\n await batchInsertFunc(chunk);\n }\n}\n","/*\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 GithubInfo = {\n credentials: GithubCredentials;\n apiBaseUrl: string;\n enterprise: string;\n};\n\nexport const getGithubInfo = async (config: Config): Promise<GithubInfo> => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credentialsProvider =\n DefaultGithubCredentialsProvider.fromIntegrations(integrations);\n\n const host = config.getString('copilot.host');\n const enterprise = config.getString('copilot.enterprise');\n\n if (!host) {\n throw new Error('The host configuration is missing from the config.');\n }\n\n if (!enterprise) {\n throw new Error('The enterprise configuration is missing from the config.');\n }\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 apiBaseUrl = githubConfig.apiBaseUrl ?? 'https://api.github.com';\n\n const credentials = await credentialsProvider.getCredentials({\n url: apiBaseUrl,\n });\n\n if (!credentials.headers) {\n throw new Error('Failed to retrieve credentials headers.');\n }\n\n return {\n apiBaseUrl,\n credentials,\n enterprise,\n };\n};\n","/*\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 { ResponseError } from '@backstage/errors';\nimport { Config } from '@backstage/config';\nimport { Metric } from '@backstage-community/plugin-copilot-common';\nimport fetch from 'node-fetch';\nimport { getGithubInfo, GithubInfo } from '../utils/GithubUtils';\n\ninterface GithubApi {\n getCopilotUsageDataForEnterprise: () => Promise<Metric[]>;\n}\n\nexport class GithubClient implements GithubApi {\n constructor(private readonly props: GithubInfo) {}\n\n static async fromConfig(config: Config) {\n const info = await getGithubInfo(config);\n return new GithubClient(info);\n }\n\n async getCopilotUsageDataForEnterprise(): Promise<Metric[]> {\n const path = `/enterprises/${this.props.enterprise}/copilot/usage`;\n return this.get(path);\n }\n\n private async get<T>(path: string): Promise<T> {\n const response = await fetch(`${this.props.apiBaseUrl}${path}`, {\n headers: {\n ...this.props.credentials.headers,\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n },\n });\n\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return response.json() as Promise<T>;\n }\n}\n","/*\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 express from 'express';\nimport Router from 'express-promise-router';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n DatabaseService,\n LoggerService,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n SchedulerService,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { Metric } from '@backstage-community/plugin-copilot-common';\nimport { DatabaseHandler } from '../db/DatabaseHandler';\nimport Scheduler from '../task/Scheduler';\nimport { GithubClient } from '../client/GithubClient';\nimport { DateTime } from 'luxon';\n\n/**\n * Options for configuring the Copilot plugin.\n *\n * @public\n */\nexport interface PluginOptions {\n /**\n * Schedule configuration for the plugin.\n */\n schedule?: SchedulerServiceTaskScheduleDefinition;\n}\n\n/**\n * Options for configuring the router used by the Copilot plugin.\n *\n * @public\n */\nexport interface RouterOptions {\n /**\n * Logger service for the router.\n */\n logger: LoggerService;\n\n /**\n * Database service for the router.\n */\n database: DatabaseService;\n\n /**\n * Scheduler service for the router.\n */\n scheduler: SchedulerService;\n\n /**\n * Configuration for the router.\n */\n config: Config;\n}\n\nconst defaultSchedule: SchedulerServiceTaskScheduleDefinition = {\n frequency: { cron: '0 2 * * *' },\n timeout: { minutes: 15 },\n initialDelay: { minutes: 1 },\n scope: 'local',\n};\n\n/**\n * Creates an Express router configured based on the provided router options and plugin options.\n *\n * This function initializes the router with the appropriate middleware and routes based on the\n * configuration and options provided. It also schedules tasks if scheduling options are provided.\n *\n * @param routerOptions - Options for configuring the router, including services and configuration.\n * @returns A promise that resolves to an Express router instance.\n *\n * @public\n */\nexport async function createRouterFromConfig(routerOptions: RouterOptions) {\n const { config } = routerOptions;\n const pluginOptions: PluginOptions = {\n schedule: defaultSchedule,\n };\n if (config && config.has('copilot.schedule')) {\n pluginOptions.schedule =\n readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('copilot.schedule'),\n );\n }\n return createRouter(routerOptions, pluginOptions);\n}\n\n/** @private */\nasync function createRouter(\n routerOptions: RouterOptions,\n pluginOptions: PluginOptions,\n): Promise<express.Router> {\n const { logger, database, scheduler, config } = routerOptions;\n const { schedule } = pluginOptions;\n\n const db = await DatabaseHandler.create({ database });\n const api = await GithubClient.fromConfig(config);\n\n await scheduler.scheduleTask({\n id: 'copilot-metrics',\n ...(schedule ?? defaultSchedule),\n fn: async () => await Scheduler.create({ db, logger, api, config }).run(),\n });\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/metrics', async (request, response) => {\n const { startDate, endDate } = request.query;\n\n if (typeof startDate !== 'string' || typeof endDate !== 'string') {\n return response.status(400).json('Invalid query parameters');\n }\n\n const parsedStartDate = DateTime.fromISO(startDate);\n const parsedEndDate = DateTime.fromISO(endDate);\n\n if (!parsedStartDate.isValid || !parsedEndDate.isValid) {\n return response.status(400).json('Invalid date format');\n }\n\n const result = await db.getMetricsByPeriod(startDate, endDate);\n\n const metrics: Metric[] = result.map(metric => ({\n ...metric,\n breakdown: JSON.parse(metric.breakdown),\n }));\n\n return response.json(metrics);\n });\n\n router.get('/metrics/period-range', async (_, response) => {\n const result = await db.getPeriodRange();\n\n if (!result) {\n return response.status(400).json('No available data');\n }\n\n return response.json(result);\n });\n\n router.use(MiddlewareFactory.create({ config, logger }).error);\n return router;\n}\n","/*\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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouterFromConfig } from './service/router';\n\n/**\n * Backend plugin for Copilot.\n *\n * @public\n */\nexport const copilotPlugin = createBackendPlugin({\n pluginId: 'copilot',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n scheduler: coreServices.scheduler,\n config: coreServices.rootConfig,\n },\n async init({ httpRouter, logger, database, scheduler, config }) {\n httpRouter.use(\n await createRouterFromConfig({\n logger,\n database,\n scheduler,\n config,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["resolvePackagePath","DateTime","ScmIntegrations","DefaultGithubCredentialsProvider","fetch","ResponseError","readSchedulerServiceTaskScheduleDefinitionFromConfig","Router","express","MiddlewareFactory","createBackendPlugin","coreServices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var router = require('./service/router.cjs.js');
|
|
5
|
+
|
|
6
|
+
const copilotPlugin = backendPluginApi.createBackendPlugin({
|
|
7
|
+
pluginId: "copilot",
|
|
8
|
+
register(env) {
|
|
9
|
+
env.registerInit({
|
|
10
|
+
deps: {
|
|
11
|
+
httpRouter: backendPluginApi.coreServices.httpRouter,
|
|
12
|
+
logger: backendPluginApi.coreServices.logger,
|
|
13
|
+
database: backendPluginApi.coreServices.database,
|
|
14
|
+
scheduler: backendPluginApi.coreServices.scheduler,
|
|
15
|
+
config: backendPluginApi.coreServices.rootConfig
|
|
16
|
+
},
|
|
17
|
+
async init({ httpRouter, logger, database, scheduler, config }) {
|
|
18
|
+
httpRouter.use(
|
|
19
|
+
await router.createRouterFromConfig({
|
|
20
|
+
logger,
|
|
21
|
+
database,
|
|
22
|
+
scheduler,
|
|
23
|
+
config
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
httpRouter.addAuthPolicy({
|
|
27
|
+
path: "/health",
|
|
28
|
+
allow: "unauthenticated"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
exports.copilotPlugin = copilotPlugin;
|
|
36
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["../src/plugin.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 {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouterFromConfig } from './service/router';\n\n/**\n * Backend plugin for Copilot.\n *\n * @public\n */\nexport const copilotPlugin = createBackendPlugin({\n pluginId: 'copilot',\n register(env) {\n env.registerInit({\n deps: {\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n database: coreServices.database,\n scheduler: coreServices.scheduler,\n config: coreServices.rootConfig,\n },\n async init({ httpRouter, logger, database, scheduler, config }) {\n httpRouter.use(\n await createRouterFromConfig({\n logger,\n database,\n scheduler,\n config,\n }),\n );\n httpRouter.addAuthPolicy({\n path: '/health',\n allow: 'unauthenticated',\n });\n },\n });\n },\n});\n"],"names":["createBackendPlugin","coreServices","createRouterFromConfig"],"mappings":";;;;;AA0BO,MAAM,gBAAgBA,oCAAoB,CAAA;AAAA,EAC/C,QAAU,EAAA,SAAA;AAAA,EACV,SAAS,GAAK,EAAA;AACZ,IAAA,GAAA,CAAI,YAAa,CAAA;AAAA,MACf,IAAM,EAAA;AAAA,QACJ,YAAYC,6BAAa,CAAA,UAAA;AAAA,QACzB,QAAQA,6BAAa,CAAA,MAAA;AAAA,QACrB,UAAUA,6BAAa,CAAA,QAAA;AAAA,QACvB,WAAWA,6BAAa,CAAA,SAAA;AAAA,QACxB,QAAQA,6BAAa,CAAA,UAAA;AAAA,OACvB;AAAA,MACA,MAAM,KAAK,EAAE,UAAA,EAAY,QAAQ,QAAU,EAAA,SAAA,EAAW,QAAU,EAAA;AAC9D,QAAW,UAAA,CAAA,GAAA;AAAA,UACT,MAAMC,6BAAuB,CAAA;AAAA,YAC3B,MAAA;AAAA,YACA,QAAA;AAAA,YACA,SAAA;AAAA,YACA,MAAA;AAAA,WACD,CAAA;AAAA,SACH,CAAA;AACA,QAAA,UAAA,CAAW,aAAc,CAAA;AAAA,UACvB,IAAM,EAAA,SAAA;AAAA,UACN,KAAO,EAAA,iBAAA;AAAA,SACR,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var express = require('express');
|
|
4
|
+
var Router = require('express-promise-router');
|
|
5
|
+
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
6
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
7
|
+
var DatabaseHandler = require('../db/DatabaseHandler.cjs.js');
|
|
8
|
+
var Scheduler = require('../task/Scheduler.cjs.js');
|
|
9
|
+
var GithubClient = require('../client/GithubClient.cjs.js');
|
|
10
|
+
var luxon = require('luxon');
|
|
11
|
+
|
|
12
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
var express__default = /*#__PURE__*/_interopDefaultCompat(express);
|
|
15
|
+
var Router__default = /*#__PURE__*/_interopDefaultCompat(Router);
|
|
16
|
+
|
|
17
|
+
const defaultSchedule = {
|
|
18
|
+
frequency: { cron: "0 2 * * *" },
|
|
19
|
+
timeout: { minutes: 15 },
|
|
20
|
+
initialDelay: { minutes: 1 },
|
|
21
|
+
scope: "local"
|
|
22
|
+
};
|
|
23
|
+
async function createRouterFromConfig(routerOptions) {
|
|
24
|
+
const { config } = routerOptions;
|
|
25
|
+
const pluginOptions = {
|
|
26
|
+
schedule: defaultSchedule
|
|
27
|
+
};
|
|
28
|
+
if (config && config.has("copilot.schedule")) {
|
|
29
|
+
pluginOptions.schedule = backendPluginApi.readSchedulerServiceTaskScheduleDefinitionFromConfig(
|
|
30
|
+
config.getConfig("copilot.schedule")
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return createRouter(routerOptions, pluginOptions);
|
|
34
|
+
}
|
|
35
|
+
async function createRouter(routerOptions, pluginOptions) {
|
|
36
|
+
const { logger, database, scheduler, config } = routerOptions;
|
|
37
|
+
const { schedule } = pluginOptions;
|
|
38
|
+
const db = await DatabaseHandler.DatabaseHandler.create({ database });
|
|
39
|
+
const api = await GithubClient.GithubClient.fromConfig(config);
|
|
40
|
+
await scheduler.scheduleTask({
|
|
41
|
+
id: "copilot-metrics",
|
|
42
|
+
...schedule ?? defaultSchedule,
|
|
43
|
+
fn: async () => await Scheduler.default.create({ db, logger, api, config }).run()
|
|
44
|
+
});
|
|
45
|
+
const router = Router__default.default();
|
|
46
|
+
router.use(express__default.default.json());
|
|
47
|
+
router.get("/health", (_, response) => {
|
|
48
|
+
logger.info("PONG!");
|
|
49
|
+
response.json({ status: "ok" });
|
|
50
|
+
});
|
|
51
|
+
router.get("/metrics", async (request, response) => {
|
|
52
|
+
const { startDate, endDate } = request.query;
|
|
53
|
+
if (typeof startDate !== "string" || typeof endDate !== "string") {
|
|
54
|
+
return response.status(400).json("Invalid query parameters");
|
|
55
|
+
}
|
|
56
|
+
const parsedStartDate = luxon.DateTime.fromISO(startDate);
|
|
57
|
+
const parsedEndDate = luxon.DateTime.fromISO(endDate);
|
|
58
|
+
if (!parsedStartDate.isValid || !parsedEndDate.isValid) {
|
|
59
|
+
return response.status(400).json("Invalid date format");
|
|
60
|
+
}
|
|
61
|
+
const result = await db.getMetricsByPeriod(startDate, endDate);
|
|
62
|
+
const metrics = result.map((metric) => ({
|
|
63
|
+
...metric,
|
|
64
|
+
breakdown: JSON.parse(metric.breakdown)
|
|
65
|
+
}));
|
|
66
|
+
return response.json(metrics);
|
|
67
|
+
});
|
|
68
|
+
router.get("/metrics/period-range", async (_, response) => {
|
|
69
|
+
const result = await db.getPeriodRange();
|
|
70
|
+
if (!result) {
|
|
71
|
+
return response.status(400).json("No available data");
|
|
72
|
+
}
|
|
73
|
+
return response.json(result);
|
|
74
|
+
});
|
|
75
|
+
router.use(rootHttpRouter.MiddlewareFactory.create({ config, logger }).error);
|
|
76
|
+
return router;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
exports.createRouterFromConfig = createRouterFromConfig;
|
|
80
|
+
//# sourceMappingURL=router.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 express from 'express';\nimport Router from 'express-promise-router';\nimport { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport {\n DatabaseService,\n LoggerService,\n readSchedulerServiceTaskScheduleDefinitionFromConfig,\n SchedulerService,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { Metric } from '@backstage-community/plugin-copilot-common';\nimport { DatabaseHandler } from '../db/DatabaseHandler';\nimport Scheduler from '../task/Scheduler';\nimport { GithubClient } from '../client/GithubClient';\nimport { DateTime } from 'luxon';\n\n/**\n * Options for configuring the Copilot plugin.\n *\n * @public\n */\nexport interface PluginOptions {\n /**\n * Schedule configuration for the plugin.\n */\n schedule?: SchedulerServiceTaskScheduleDefinition;\n}\n\n/**\n * Options for configuring the router used by the Copilot plugin.\n *\n * @public\n */\nexport interface RouterOptions {\n /**\n * Logger service for the router.\n */\n logger: LoggerService;\n\n /**\n * Database service for the router.\n */\n database: DatabaseService;\n\n /**\n * Scheduler service for the router.\n */\n scheduler: SchedulerService;\n\n /**\n * Configuration for the router.\n */\n config: Config;\n}\n\nconst defaultSchedule: SchedulerServiceTaskScheduleDefinition = {\n frequency: { cron: '0 2 * * *' },\n timeout: { minutes: 15 },\n initialDelay: { minutes: 1 },\n scope: 'local',\n};\n\n/**\n * Creates an Express router configured based on the provided router options and plugin options.\n *\n * This function initializes the router with the appropriate middleware and routes based on the\n * configuration and options provided. It also schedules tasks if scheduling options are provided.\n *\n * @param routerOptions - Options for configuring the router, including services and configuration.\n * @returns A promise that resolves to an Express router instance.\n *\n * @public\n */\nexport async function createRouterFromConfig(routerOptions: RouterOptions) {\n const { config } = routerOptions;\n const pluginOptions: PluginOptions = {\n schedule: defaultSchedule,\n };\n if (config && config.has('copilot.schedule')) {\n pluginOptions.schedule =\n readSchedulerServiceTaskScheduleDefinitionFromConfig(\n config.getConfig('copilot.schedule'),\n );\n }\n return createRouter(routerOptions, pluginOptions);\n}\n\n/** @private */\nasync function createRouter(\n routerOptions: RouterOptions,\n pluginOptions: PluginOptions,\n): Promise<express.Router> {\n const { logger, database, scheduler, config } = routerOptions;\n const { schedule } = pluginOptions;\n\n const db = await DatabaseHandler.create({ database });\n const api = await GithubClient.fromConfig(config);\n\n await scheduler.scheduleTask({\n id: 'copilot-metrics',\n ...(schedule ?? defaultSchedule),\n fn: async () => await Scheduler.create({ db, logger, api, config }).run(),\n });\n\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n logger.info('PONG!');\n response.json({ status: 'ok' });\n });\n\n router.get('/metrics', async (request, response) => {\n const { startDate, endDate } = request.query;\n\n if (typeof startDate !== 'string' || typeof endDate !== 'string') {\n return response.status(400).json('Invalid query parameters');\n }\n\n const parsedStartDate = DateTime.fromISO(startDate);\n const parsedEndDate = DateTime.fromISO(endDate);\n\n if (!parsedStartDate.isValid || !parsedEndDate.isValid) {\n return response.status(400).json('Invalid date format');\n }\n\n const result = await db.getMetricsByPeriod(startDate, endDate);\n\n const metrics: Metric[] = result.map(metric => ({\n ...metric,\n breakdown: JSON.parse(metric.breakdown),\n }));\n\n return response.json(metrics);\n });\n\n router.get('/metrics/period-range', async (_, response) => {\n const result = await db.getPeriodRange();\n\n if (!result) {\n return response.status(400).json('No available data');\n }\n\n return response.json(result);\n });\n\n router.use(MiddlewareFactory.create({ config, logger }).error);\n return router;\n}\n"],"names":["readSchedulerServiceTaskScheduleDefinitionFromConfig","DatabaseHandler","GithubClient","Scheduler","Router","express","DateTime","MiddlewareFactory"],"mappings":";;;;;;;;;;;;;;;;AAuEA,MAAM,eAA0D,GAAA;AAAA,EAC9D,SAAA,EAAW,EAAE,IAAA,EAAM,WAAY,EAAA;AAAA,EAC/B,OAAA,EAAS,EAAE,OAAA,EAAS,EAAG,EAAA;AAAA,EACvB,YAAA,EAAc,EAAE,OAAA,EAAS,CAAE,EAAA;AAAA,EAC3B,KAAO,EAAA,OAAA;AACT,CAAA,CAAA;AAaA,eAAsB,uBAAuB,aAA8B,EAAA;AACzE,EAAM,MAAA,EAAE,QAAW,GAAA,aAAA,CAAA;AACnB,EAAA,MAAM,aAA+B,GAAA;AAAA,IACnC,QAAU,EAAA,eAAA;AAAA,GACZ,CAAA;AACA,EAAA,IAAI,MAAU,IAAA,MAAA,CAAO,GAAI,CAAA,kBAAkB,CAAG,EAAA;AAC5C,IAAA,aAAA,CAAc,QACZ,GAAAA,qEAAA;AAAA,MACE,MAAA,CAAO,UAAU,kBAAkB,CAAA;AAAA,KACrC,CAAA;AAAA,GACJ;AACA,EAAO,OAAA,YAAA,CAAa,eAAe,aAAa,CAAA,CAAA;AAClD,CAAA;AAGA,eAAe,YAAA,CACb,eACA,aACyB,EAAA;AACzB,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAU,EAAA,SAAA,EAAW,QAAW,GAAA,aAAA,CAAA;AAChD,EAAM,MAAA,EAAE,UAAa,GAAA,aAAA,CAAA;AAErB,EAAA,MAAM,KAAK,MAAMC,+BAAA,CAAgB,MAAO,CAAA,EAAE,UAAU,CAAA,CAAA;AACpD,EAAA,MAAM,GAAM,GAAA,MAAMC,yBAAa,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AAEhD,EAAA,MAAM,UAAU,YAAa,CAAA;AAAA,IAC3B,EAAI,EAAA,iBAAA;AAAA,IACJ,GAAI,QAAY,IAAA,eAAA;AAAA,IAChB,EAAI,EAAA,YAAY,MAAMC,iBAAA,CAAU,MAAO,CAAA,EAAE,EAAI,EAAA,MAAA,EAAQ,GAAK,EAAA,MAAA,EAAQ,CAAA,CAAE,GAAI,EAAA;AAAA,GACzE,CAAA,CAAA;AAED,EAAA,MAAM,SAASC,uBAAO,EAAA,CAAA;AACtB,EAAO,MAAA,CAAA,GAAA,CAAIC,wBAAQ,CAAA,IAAA,EAAM,CAAA,CAAA;AAEzB,EAAA,MAAA,CAAO,GAAI,CAAA,SAAA,EAAW,CAAC,CAAA,EAAG,QAAa,KAAA;AACrC,IAAA,MAAA,CAAO,KAAK,OAAO,CAAA,CAAA;AACnB,IAAA,QAAA,CAAS,IAAK,CAAA,EAAE,MAAQ,EAAA,IAAA,EAAM,CAAA,CAAA;AAAA,GAC/B,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,GAAI,CAAA,UAAA,EAAY,OAAO,OAAA,EAAS,QAAa,KAAA;AAClD,IAAA,MAAM,EAAE,SAAA,EAAW,OAAQ,EAAA,GAAI,OAAQ,CAAA,KAAA,CAAA;AAEvC,IAAA,IAAI,OAAO,SAAA,KAAc,QAAY,IAAA,OAAO,YAAY,QAAU,EAAA;AAChE,MAAA,OAAO,QAAS,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,0BAA0B,CAAA,CAAA;AAAA,KAC7D;AAEA,IAAM,MAAA,eAAA,GAAkBC,cAAS,CAAA,OAAA,CAAQ,SAAS,CAAA,CAAA;AAClD,IAAM,MAAA,aAAA,GAAgBA,cAAS,CAAA,OAAA,CAAQ,OAAO,CAAA,CAAA;AAE9C,IAAA,IAAI,CAAC,eAAA,CAAgB,OAAW,IAAA,CAAC,cAAc,OAAS,EAAA;AACtD,MAAA,OAAO,QAAS,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,qBAAqB,CAAA,CAAA;AAAA,KACxD;AAEA,IAAA,MAAM,MAAS,GAAA,MAAM,EAAG,CAAA,kBAAA,CAAmB,WAAW,OAAO,CAAA,CAAA;AAE7D,IAAM,MAAA,OAAA,GAAoB,MAAO,CAAA,GAAA,CAAI,CAAW,MAAA,MAAA;AAAA,MAC9C,GAAG,MAAA;AAAA,MACH,SAAW,EAAA,IAAA,CAAK,KAAM,CAAA,MAAA,CAAO,SAAS,CAAA;AAAA,KACtC,CAAA,CAAA,CAAA;AAEF,IAAO,OAAA,QAAA,CAAS,KAAK,OAAO,CAAA,CAAA;AAAA,GAC7B,CAAA,CAAA;AAED,EAAA,MAAA,CAAO,GAAI,CAAA,uBAAA,EAAyB,OAAO,CAAA,EAAG,QAAa,KAAA;AACzD,IAAM,MAAA,MAAA,GAAS,MAAM,EAAA,CAAG,cAAe,EAAA,CAAA;AAEvC,IAAA,IAAI,CAAC,MAAQ,EAAA;AACX,MAAA,OAAO,QAAS,CAAA,MAAA,CAAO,GAAG,CAAA,CAAE,KAAK,mBAAmB,CAAA,CAAA;AAAA,KACtD;AAEA,IAAO,OAAA,QAAA,CAAS,KAAK,MAAM,CAAA,CAAA;AAAA,GAC5B,CAAA,CAAA;AAED,EAAO,MAAA,CAAA,GAAA,CAAIC,iCAAkB,MAAO,CAAA,EAAE,QAAQ,MAAO,EAAC,EAAE,KAAK,CAAA,CAAA;AAC7D,EAAO,OAAA,MAAA,CAAA;AACT;;;;"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var luxon = require('luxon');
|
|
6
|
+
|
|
7
|
+
class Scheduler {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
static create(options) {
|
|
12
|
+
return new Scheduler(options);
|
|
13
|
+
}
|
|
14
|
+
async run() {
|
|
15
|
+
try {
|
|
16
|
+
this.options.logger.info("Starting Github Copilot Processor");
|
|
17
|
+
const copilotMetrics = await this.options.api.getCopilotUsageDataForEnterprise();
|
|
18
|
+
this.options.logger.info(`Fetched ${copilotMetrics.length} metrics`);
|
|
19
|
+
const lastDay = await this.options.db.getMostRecentDayFromMetrics();
|
|
20
|
+
this.options.logger.info(`Found last day: ${lastDay}`);
|
|
21
|
+
const diff = copilotMetrics.sort(
|
|
22
|
+
(a, b) => luxon.DateTime.fromISO(a.day).toMillis() - luxon.DateTime.fromISO(b.day).toMillis()
|
|
23
|
+
).filter((metric) => {
|
|
24
|
+
const metricDate = luxon.DateTime.fromISO(metric.day);
|
|
25
|
+
const lastDayDate = lastDay ? luxon.DateTime.fromISO(lastDay) : null;
|
|
26
|
+
return !lastDayDate || metricDate > lastDayDate;
|
|
27
|
+
}).map(({ breakdown, ...rest }) => ({
|
|
28
|
+
...rest,
|
|
29
|
+
breakdown: JSON.stringify(breakdown)
|
|
30
|
+
}));
|
|
31
|
+
this.options.logger.info(`Found ${diff.length} new metrics to insert`);
|
|
32
|
+
if (diff.length > 0) {
|
|
33
|
+
await batchInsertInChunks(
|
|
34
|
+
diff,
|
|
35
|
+
30,
|
|
36
|
+
async (chunk) => {
|
|
37
|
+
await this.options.db.batchInsert(chunk);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
this.options.logger.info("Inserted new metrics into the database");
|
|
41
|
+
} else {
|
|
42
|
+
this.options.logger.info("No new metrics found to insert");
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
this.options.logger.error(
|
|
46
|
+
`An error occurred while processing Github Copilot metrics: ${error}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function batchInsertInChunks(data, chunkSize, batchInsertFunc) {
|
|
52
|
+
for (let i = 0; i < data.length; i += chunkSize) {
|
|
53
|
+
const chunk = data.slice(i, i + chunkSize);
|
|
54
|
+
await batchInsertFunc(chunk);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.default = Scheduler;
|
|
59
|
+
//# sourceMappingURL=Scheduler.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Scheduler.cjs.js","sources":["../../src/task/Scheduler.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 { LoggerService } from '@backstage/backend-plugin-api';\nimport { GithubClient } from '../client/GithubClient';\nimport { DatabaseHandler, MetricDbRow } from '../db/DatabaseHandler';\nimport { Config } from '@backstage/config';\nimport { DateTime } from 'luxon';\n\ntype Options = {\n api: GithubClient;\n config: Config;\n logger: LoggerService;\n db: DatabaseHandler;\n};\n\nexport default class Scheduler {\n constructor(private readonly options: Options) {}\n\n static create(options: Options) {\n return new Scheduler(options);\n }\n\n async run() {\n try {\n this.options.logger.info('Starting Github Copilot Processor');\n\n const copilotMetrics =\n await this.options.api.getCopilotUsageDataForEnterprise();\n this.options.logger.info(`Fetched ${copilotMetrics.length} metrics`);\n\n const lastDay = await this.options.db.getMostRecentDayFromMetrics();\n this.options.logger.info(`Found last day: ${lastDay}`);\n\n const diff = copilotMetrics\n .sort(\n (a, b) =>\n DateTime.fromISO(a.day).toMillis() -\n DateTime.fromISO(b.day).toMillis(),\n )\n .filter(metric => {\n const metricDate = DateTime.fromISO(metric.day);\n const lastDayDate = lastDay ? DateTime.fromISO(lastDay) : null;\n return !lastDayDate || metricDate > lastDayDate;\n })\n .map(({ breakdown, ...rest }) => ({\n ...rest,\n breakdown: JSON.stringify(breakdown),\n }));\n\n this.options.logger.info(`Found ${diff.length} new metrics to insert`);\n\n if (diff.length > 0) {\n await batchInsertInChunks<MetricDbRow>(\n diff,\n 30,\n async (chunk: MetricDbRow[]) => {\n await this.options.db.batchInsert(chunk);\n },\n );\n this.options.logger.info('Inserted new metrics into the database');\n } else {\n this.options.logger.info('No new metrics found to insert');\n }\n } catch (error) {\n this.options.logger.error(\n `An error occurred while processing Github Copilot metrics: ${error}`,\n );\n }\n }\n}\n\nasync function batchInsertInChunks<T>(\n data: T[],\n chunkSize: number,\n batchInsertFunc: (chunk: T[]) => Promise<void>,\n): Promise<void> {\n for (let i = 0; i < data.length; i += chunkSize) {\n const chunk = data.slice(i, i + chunkSize);\n await batchInsertFunc(chunk);\n }\n}\n"],"names":["DateTime"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var integration = require('@backstage/integration');
|
|
4
|
+
|
|
5
|
+
const getGithubInfo = async (config) => {
|
|
6
|
+
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
7
|
+
const credentialsProvider = integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
|
|
8
|
+
const host = config.getString("copilot.host");
|
|
9
|
+
const enterprise = config.getString("copilot.enterprise");
|
|
10
|
+
if (!host) {
|
|
11
|
+
throw new Error("The host configuration is missing from the config.");
|
|
12
|
+
}
|
|
13
|
+
if (!enterprise) {
|
|
14
|
+
throw new Error("The enterprise configuration is missing from the config.");
|
|
15
|
+
}
|
|
16
|
+
const githubConfig = integrations.github.byHost(host)?.config;
|
|
17
|
+
if (!githubConfig) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`GitHub configuration for host "${host}" is missing or incomplete.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const apiBaseUrl = githubConfig.apiBaseUrl ?? "https://api.github.com";
|
|
23
|
+
const credentials = await credentialsProvider.getCredentials({
|
|
24
|
+
url: apiBaseUrl
|
|
25
|
+
});
|
|
26
|
+
if (!credentials.headers) {
|
|
27
|
+
throw new Error("Failed to retrieve credentials headers.");
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
apiBaseUrl,
|
|
31
|
+
credentials,
|
|
32
|
+
enterprise
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
exports.getGithubInfo = getGithubInfo;
|
|
37
|
+
//# sourceMappingURL=GithubUtils.cjs.js.map
|
|
@@ -0,0 +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 GithubInfo = {\n credentials: GithubCredentials;\n apiBaseUrl: string;\n enterprise: string;\n};\n\nexport const getGithubInfo = async (config: Config): Promise<GithubInfo> => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credentialsProvider =\n DefaultGithubCredentialsProvider.fromIntegrations(integrations);\n\n const host = config.getString('copilot.host');\n const enterprise = config.getString('copilot.enterprise');\n\n if (!host) {\n throw new Error('The host configuration is missing from the config.');\n }\n\n if (!enterprise) {\n throw new Error('The enterprise configuration is missing from the config.');\n }\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 apiBaseUrl = githubConfig.apiBaseUrl ?? 'https://api.github.com';\n\n const credentials = await credentialsProvider.getCredentials({\n url: apiBaseUrl,\n });\n\n if (!credentials.headers) {\n throw new Error('Failed to retrieve credentials headers.');\n }\n\n return {\n apiBaseUrl,\n credentials,\n enterprise,\n };\n};\n"],"names":["ScmIntegrations","DefaultGithubCredentialsProvider"],"mappings":";;;;AA6Ba,MAAA,aAAA,GAAgB,OAAO,MAAwC,KAAA;AAC1E,EAAM,MAAA,YAAA,GAAeA,2BAAgB,CAAA,UAAA,CAAW,MAAM,CAAA,CAAA;AACtD,EAAM,MAAA,mBAAA,GACJC,4CAAiC,CAAA,gBAAA,CAAiB,YAAY,CAAA,CAAA;AAEhE,EAAM,MAAA,IAAA,GAAO,MAAO,CAAA,SAAA,CAAU,cAAc,CAAA,CAAA;AAC5C,EAAM,MAAA,UAAA,GAAa,MAAO,CAAA,SAAA,CAAU,oBAAoB,CAAA,CAAA;AAExD,EAAA,IAAI,CAAC,IAAM,EAAA;AACT,IAAM,MAAA,IAAI,MAAM,oDAAoD,CAAA,CAAA;AAAA,GACtE;AAEA,EAAA,IAAI,CAAC,UAAY,EAAA;AACf,IAAM,MAAA,IAAI,MAAM,0DAA0D,CAAA,CAAA;AAAA,GAC5E;AAEA,EAAA,MAAM,YAAe,GAAA,YAAA,CAAa,MAAO,CAAA,MAAA,CAAO,IAAI,CAAG,EAAA,MAAA,CAAA;AAEvD,EAAA,IAAI,CAAC,YAAc,EAAA;AACjB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,kCAAkC,IAAI,CAAA,2BAAA,CAAA;AAAA,KACxC,CAAA;AAAA,GACF;AAEA,EAAM,MAAA,UAAA,GAAa,aAAa,UAAc,IAAA,wBAAA,CAAA;AAE9C,EAAM,MAAA,WAAA,GAAc,MAAM,mBAAA,CAAoB,cAAe,CAAA;AAAA,IAC3D,GAAK,EAAA,UAAA;AAAA,GACN,CAAA,CAAA;AAED,EAAI,IAAA,CAAC,YAAY,OAAS,EAAA;AACxB,IAAM,MAAA,IAAI,MAAM,yCAAyC,CAAA,CAAA;AAAA,GAC3D;AAEA,EAAO,OAAA;AAAA,IACL,UAAA;AAAA,IACA,WAAA;AAAA,IACA,UAAA;AAAA,GACF,CAAA;AACF;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage-community/plugin-copilot-backend",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"homepage": "https://backstage.io",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/index.cjs.js",
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
"postpack": "backstage-cli package postpack"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@backstage-community/plugin-copilot-common": "^0.2.
|
|
43
|
-
"@backstage/backend-app-api": "^1.0.
|
|
42
|
+
"@backstage-community/plugin-copilot-common": "^0.2.2",
|
|
43
|
+
"@backstage/backend-app-api": "^1.0.1",
|
|
44
44
|
"@backstage/backend-common": "^0.25.0",
|
|
45
|
-
"@backstage/backend-defaults": "^0.5.
|
|
46
|
-
"@backstage/backend-plugin-api": "^1.0.
|
|
45
|
+
"@backstage/backend-defaults": "^0.5.2",
|
|
46
|
+
"@backstage/backend-plugin-api": "^1.0.1",
|
|
47
47
|
"@backstage/backend-tasks": "^0.6.1",
|
|
48
48
|
"@backstage/config": "^1.2.0",
|
|
49
49
|
"@backstage/errors": "^1.2.4",
|
|
50
|
-
"@backstage/integration": "^1.15.
|
|
50
|
+
"@backstage/integration": "^1.15.1",
|
|
51
51
|
"@types/express": "*",
|
|
52
52
|
"express": "^4.17.1",
|
|
53
53
|
"express-promise-router": "^4.1.0",
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"yn": "^4.0.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@backstage/backend-test-utils": "^1.0.
|
|
62
|
-
"@backstage/cli": "^0.
|
|
63
|
-
"@backstage/plugin-auth-backend": "^0.23.
|
|
64
|
-
"@backstage/plugin-auth-backend-module-guest-provider": "^0.2.
|
|
65
|
-
"@backstage/test-utils": "^1.
|
|
61
|
+
"@backstage/backend-test-utils": "^1.0.2",
|
|
62
|
+
"@backstage/cli": "^0.28.0",
|
|
63
|
+
"@backstage/plugin-auth-backend": "^0.23.1",
|
|
64
|
+
"@backstage/plugin-auth-backend-module-guest-provider": "^0.2.1",
|
|
65
|
+
"@backstage/test-utils": "^1.7.0",
|
|
66
66
|
"@types/node-fetch": "^2.6.11",
|
|
67
67
|
"@types/supertest": "^2.0.8",
|
|
68
68
|
"msw": "^1.0.0",
|