@backstage-community/plugin-copilot-backend 0.3.2 → 0.4.0
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
CHANGED
package/README.md
CHANGED
|
@@ -63,9 +63,9 @@ To install the plugin using the old method:
|
|
|
63
63
|
|
|
64
64
|
## Configuration
|
|
65
65
|
|
|
66
|
-
###
|
|
66
|
+
### App Config
|
|
67
67
|
|
|
68
|
-
To configure the GitHub Copilot plugin, you need to set the following
|
|
68
|
+
To configure the GitHub Copilot plugin, you need to set the following values in the app-config:
|
|
69
69
|
|
|
70
70
|
- **`copilot.host`**: The host URL for your GitHub Copilot instance (e.g., `github.com` or `github.enterprise.com`).
|
|
71
71
|
- **`copilot.enterprise`**: The name of your GitHub Enterprise instance (e.g., `my-enterprise`).
|
|
@@ -75,9 +75,14 @@ These variables are used to configure the plugin and ensure it communicates with
|
|
|
75
75
|
|
|
76
76
|
### GitHub Credentials
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
GitHub support different auth methods depending on which API you are using.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
- Enterprise API - [only supports "classic" PAT tokens](https://docs.github.com/en/enterprise-cloud@latest/rest/copilot/copilot-usage?apiVersion=2022-11-28#get-a-summary-of-copilot-usage-for-enterprise-members)
|
|
81
|
+
- Org Api - [Supports app tokens, "classic", and fine grained PAT tokens](https://docs.github.com/en/enterprise-cloud@latest/rest/copilot/copilot-usage?apiVersion=2022-11-28#get-a-summary-of-copilot-usage-for-organization-members)
|
|
82
|
+
|
|
83
|
+
This plugin supports both schemes and detects the best scheme based on which API(s) you have configured for use.
|
|
84
|
+
|
|
85
|
+
### GitHub Token/App Scopes
|
|
81
86
|
|
|
82
87
|
To ensure the GitHub Copilot plugin operates correctly within your organization or enterprise, your GitHub access token must include specific scopes. These scopes grant the plugin the necessary permissions to interact with your GitHub organization and manage Copilot usage.
|
|
83
88
|
|
|
@@ -95,10 +100,18 @@ To ensure the GitHub Copilot plugin operates correctly within your organization
|
|
|
95
100
|
|
|
96
101
|
#### How to Configure Token Scopes
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
103
|
+
**Generate a Personal Access Token (PAT) (Entperise only supports "classic" PAT tokens)**
|
|
104
|
+
|
|
105
|
+
- Navigate to [GitHub Personal Access Tokens](https://github.com/settings/tokens).
|
|
106
|
+
- Click on **Generate new token**.
|
|
107
|
+
- Select the scopes according to your needs
|
|
108
|
+
|
|
109
|
+
**Using a GitHub App**
|
|
110
|
+
|
|
111
|
+
- Create or reuse an existing GitHub App that you own.
|
|
112
|
+
- Navigate to the app permissions
|
|
113
|
+
- Select the permissions to read the org and manage billing for copilot and save
|
|
114
|
+
- Install and update permissions in your oeg.
|
|
102
115
|
|
|
103
116
|
### YAML Configuration Example
|
|
104
117
|
|
|
@@ -115,12 +128,28 @@ copilot:
|
|
|
115
128
|
enterprise: YOUR_ENTERPRISE_NAME_HERE
|
|
116
129
|
organization: YOUR_ORGANIZATION_NAME_HERE
|
|
117
130
|
|
|
131
|
+
# Using a PAT
|
|
118
132
|
integrations:
|
|
119
133
|
github:
|
|
120
134
|
- host: YOUR_GITHUB_HOST_HERE
|
|
121
135
|
token: YOUR_GENERATED_TOKEN
|
|
136
|
+
|
|
137
|
+
# Using a GitHub App
|
|
138
|
+
integrations:
|
|
139
|
+
github:
|
|
140
|
+
- host: github.com
|
|
141
|
+
apps:
|
|
142
|
+
- appId: YOUR_APP_ID
|
|
143
|
+
allowedInstallationOwners:
|
|
144
|
+
- YOUR_ORG_NAME
|
|
145
|
+
clientId: CLIENT_ID
|
|
146
|
+
clientSecret: CLIENT_SECRET
|
|
147
|
+
webhookSecret: WEBHOOK_SECRET
|
|
148
|
+
privateKey: PRIVATE_KEY
|
|
122
149
|
```
|
|
123
150
|
|
|
151
|
+
[You can find more about the integrations config in the official docs](https://backstage.io/docs/integrations/github/locations/)
|
|
152
|
+
|
|
124
153
|
### API Documentation
|
|
125
154
|
|
|
126
155
|
For more details on using the GitHub Copilot and Teams APIs, refer to the following documentation:
|
|
@@ -9,41 +9,47 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
9
9
|
var fetch__default = /*#__PURE__*/_interopDefaultCompat(fetch);
|
|
10
10
|
|
|
11
11
|
class GithubClient {
|
|
12
|
-
constructor(
|
|
13
|
-
this.
|
|
12
|
+
constructor(copilotConfig, config) {
|
|
13
|
+
this.copilotConfig = copilotConfig;
|
|
14
|
+
this.config = config;
|
|
14
15
|
}
|
|
15
16
|
static async fromConfig(config) {
|
|
16
|
-
const info =
|
|
17
|
-
return new GithubClient(info);
|
|
17
|
+
const info = GithubUtils.getCopilotConfig(config);
|
|
18
|
+
return new GithubClient(info, config);
|
|
19
|
+
}
|
|
20
|
+
async getCredentials() {
|
|
21
|
+
return await GithubUtils.getGithubCredentials(this.config, this.copilotConfig);
|
|
18
22
|
}
|
|
19
23
|
async fetchEnterpriseCopilotUsage() {
|
|
20
|
-
const path = `/enterprises/${this.
|
|
24
|
+
const path = `/enterprises/${this.copilotConfig.enterprise}/copilot/usage`;
|
|
21
25
|
return this.get(path);
|
|
22
26
|
}
|
|
23
27
|
async fetchEnterpriseTeamCopilotUsage(teamId) {
|
|
24
|
-
const path = `/enterprises/${this.
|
|
28
|
+
const path = `/enterprises/${this.copilotConfig.enterprise}/team/${teamId}/copilot/usage`;
|
|
25
29
|
return this.get(path);
|
|
26
30
|
}
|
|
27
31
|
async fetchEnterpriseTeams() {
|
|
28
|
-
const path = `/enterprises/${this.
|
|
32
|
+
const path = `/enterprises/${this.copilotConfig.enterprise}/teams`;
|
|
29
33
|
return this.get(path);
|
|
30
34
|
}
|
|
31
35
|
async fetchOrganizationCopilotUsage() {
|
|
32
|
-
const path = `/orgs/${this.
|
|
36
|
+
const path = `/orgs/${this.copilotConfig.organization}/copilot/usage`;
|
|
33
37
|
return this.get(path);
|
|
34
38
|
}
|
|
35
39
|
async fetchOrganizationTeamCopilotUsage(teamId) {
|
|
36
|
-
const path = `/orgs/${this.
|
|
40
|
+
const path = `/orgs/${this.copilotConfig.organization}/team/${teamId}/copilot/usage`;
|
|
37
41
|
return this.get(path);
|
|
38
42
|
}
|
|
39
43
|
async fetchOrganizationTeams() {
|
|
40
|
-
const path = `/orgs/${this.
|
|
44
|
+
const path = `/orgs/${this.copilotConfig.organization}/teams`;
|
|
41
45
|
return this.get(path);
|
|
42
46
|
}
|
|
43
47
|
async get(path) {
|
|
44
|
-
const
|
|
48
|
+
const credentials = await this.getCredentials();
|
|
49
|
+
const headers = path.startsWith("/enterprises") ? credentials.enterprise?.headers : credentials.organization?.headers;
|
|
50
|
+
const response = await fetch__default.default(`${this.copilotConfig.apiBaseUrl}${path}`, {
|
|
45
51
|
headers: {
|
|
46
|
-
...
|
|
52
|
+
...headers,
|
|
47
53
|
Accept: "application/vnd.github+json",
|
|
48
54
|
"X-GitHub-Api-Version": "2022-11-28"
|
|
49
55
|
}
|
|
@@ -1 +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, TeamInfo } from '@backstage-community/plugin-copilot-common';\nimport fetch from 'node-fetch';\nimport {
|
|
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, TeamInfo } from '@backstage-community/plugin-copilot-common';\nimport fetch from 'node-fetch';\nimport {\n CopilotConfig,\n CopilotCredentials,\n getCopilotConfig,\n getGithubCredentials,\n} from '../utils/GithubUtils';\n\ninterface GithubApi {\n fetchEnterpriseCopilotUsage: () => Promise<Metric[]>;\n fetchEnterpriseTeamCopilotUsage: (teamId: string) => Promise<Metric[]>;\n fetchEnterpriseTeams: () => Promise<TeamInfo[]>;\n fetchOrganizationCopilotUsage: () => Promise<Metric[]>;\n fetchOrganizationTeamCopilotUsage: (teamId: string) => Promise<Metric[]>;\n fetchOrganizationTeams: () => Promise<TeamInfo[]>;\n}\n\nexport class GithubClient implements GithubApi {\n constructor(\n private readonly copilotConfig: CopilotConfig,\n private readonly config: Config,\n ) {}\n\n static async fromConfig(config: Config) {\n const info = getCopilotConfig(config);\n return new GithubClient(info, config);\n }\n\n private async getCredentials(): Promise<CopilotCredentials> {\n return await getGithubCredentials(this.config, this.copilotConfig);\n }\n\n async fetchEnterpriseCopilotUsage(): Promise<Metric[]> {\n const path = `/enterprises/${this.copilotConfig.enterprise}/copilot/usage`;\n return this.get(path);\n }\n\n async fetchEnterpriseTeamCopilotUsage(teamId: string): Promise<Metric[]> {\n const path = `/enterprises/${this.copilotConfig.enterprise}/team/${teamId}/copilot/usage`;\n return this.get(path);\n }\n\n async fetchEnterpriseTeams(): Promise<TeamInfo[]> {\n const path = `/enterprises/${this.copilotConfig.enterprise}/teams`;\n return this.get(path);\n }\n\n async fetchOrganizationCopilotUsage(): Promise<Metric[]> {\n const path = `/orgs/${this.copilotConfig.organization}/copilot/usage`;\n return this.get(path);\n }\n\n async fetchOrganizationTeamCopilotUsage(teamId: string): Promise<Metric[]> {\n const path = `/orgs/${this.copilotConfig.organization}/team/${teamId}/copilot/usage`;\n return this.get(path);\n }\n\n async fetchOrganizationTeams(): Promise<TeamInfo[]> {\n const path = `/orgs/${this.copilotConfig.organization}/teams`;\n return this.get(path);\n }\n\n private async get<T>(path: string): Promise<T> {\n const credentials = await this.getCredentials();\n const headers = path.startsWith('/enterprises')\n ? credentials.enterprise?.headers\n : credentials.organization?.headers;\n\n const response = await fetch(`${this.copilotConfig.apiBaseUrl}${path}`, {\n headers: {\n ...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":["getCopilotConfig","getGithubCredentials","fetch","ResponseError"],"mappings":";;;;;;;;;;AAoCO,MAAM,YAAkC,CAAA;AAAA,EAC7C,WAAA,CACmB,eACA,MACjB,EAAA;AAFiB,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA;AAChB,EAEH,aAAa,WAAW,MAAgB,EAAA;AACtC,IAAM,MAAA,IAAA,GAAOA,6BAAiB,MAAM,CAAA;AACpC,IAAO,OAAA,IAAI,YAAa,CAAA,IAAA,EAAM,MAAM,CAAA;AAAA;AACtC,EAEA,MAAc,cAA8C,GAAA;AAC1D,IAAA,OAAO,MAAMC,gCAAA,CAAqB,IAAK,CAAA,MAAA,EAAQ,KAAK,aAAa,CAAA;AAAA;AACnE,EAEA,MAAM,2BAAiD,GAAA;AACrD,IAAA,MAAM,IAAO,GAAA,CAAA,aAAA,EAAgB,IAAK,CAAA,aAAA,CAAc,UAAU,CAAA,cAAA,CAAA;AAC1D,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAM,gCAAgC,MAAmC,EAAA;AACvE,IAAA,MAAM,OAAO,CAAgB,aAAA,EAAA,IAAA,CAAK,aAAc,CAAA,UAAU,SAAS,MAAM,CAAA,cAAA,CAAA;AACzE,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAM,oBAA4C,GAAA;AAChD,IAAA,MAAM,IAAO,GAAA,CAAA,aAAA,EAAgB,IAAK,CAAA,aAAA,CAAc,UAAU,CAAA,MAAA,CAAA;AAC1D,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAM,6BAAmD,GAAA;AACvD,IAAA,MAAM,IAAO,GAAA,CAAA,MAAA,EAAS,IAAK,CAAA,aAAA,CAAc,YAAY,CAAA,cAAA,CAAA;AACrD,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAM,kCAAkC,MAAmC,EAAA;AACzE,IAAA,MAAM,OAAO,CAAS,MAAA,EAAA,IAAA,CAAK,aAAc,CAAA,YAAY,SAAS,MAAM,CAAA,cAAA,CAAA;AACpE,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAM,sBAA8C,GAAA;AAClD,IAAA,MAAM,IAAO,GAAA,CAAA,MAAA,EAAS,IAAK,CAAA,aAAA,CAAc,YAAY,CAAA,MAAA,CAAA;AACrD,IAAO,OAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA;AACtB,EAEA,MAAc,IAAO,IAA0B,EAAA;AAC7C,IAAM,MAAA,WAAA,GAAc,MAAM,IAAA,CAAK,cAAe,EAAA;AAC9C,IAAM,MAAA,OAAA,GAAU,KAAK,UAAW,CAAA,cAAc,IAC1C,WAAY,CAAA,UAAA,EAAY,OACxB,GAAA,WAAA,CAAY,YAAc,EAAA,OAAA;AAE9B,IAAM,MAAA,QAAA,GAAW,MAAMC,sBAAM,CAAA,CAAA,EAAG,KAAK,aAAc,CAAA,UAAU,CAAG,EAAA,IAAI,CAAI,CAAA,EAAA;AAAA,MACtE,OAAS,EAAA;AAAA,QACP,GAAG,OAAA;AAAA,QACH,MAAQ,EAAA,6BAAA;AAAA,QACR,sBAAwB,EAAA;AAAA;AAC1B,KACD,CAAA;AAED,IAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AAChB,MAAM,MAAA,MAAMC,oBAAc,CAAA,YAAA,CAAa,QAAQ,CAAA;AAAA;AAGjD,IAAA,OAAO,SAAS,IAAK,EAAA;AAAA;AAEzB;;;;"}
|
|
@@ -2,33 +2,83 @@
|
|
|
2
2
|
|
|
3
3
|
var integration = require('@backstage/integration');
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
5
|
+
const getCopilotConfig = (config) => {
|
|
7
6
|
const host = config.getString("copilot.host");
|
|
8
7
|
const enterprise = config.getOptionalString("copilot.enterprise");
|
|
9
8
|
const organization = config.getOptionalString("copilot.organization");
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
10
|
+
const githubConfig = integrations.github.byHost(host)?.config;
|
|
11
|
+
if (!githubConfig) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`GitHub configuration for host "${host}" is missing or incomplete. Please check the integretions configuration section.`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
if (enterprise && !githubConfig.token) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Enterprise API for copilot only works with "classic PAT" tokens. No token is configured for "${host}" in the config.`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
if (organization && !(githubConfig.token || githubConfig.apps)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`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.`
|
|
24
|
+
);
|
|
12
25
|
}
|
|
26
|
+
return {
|
|
27
|
+
host,
|
|
28
|
+
enterprise,
|
|
29
|
+
organization,
|
|
30
|
+
apiBaseUrl: githubConfig.apiBaseUrl ?? "https://api.github.com"
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const getGithubCredentials = async (config, copilotConfig) => {
|
|
34
|
+
const integrations = integration.ScmIntegrations.fromConfig(config);
|
|
35
|
+
const { host, enterprise, organization } = copilotConfig;
|
|
13
36
|
const githubConfig = integrations.github.byHost(host)?.config;
|
|
14
37
|
if (!githubConfig) {
|
|
15
38
|
throw new Error(
|
|
16
39
|
`GitHub configuration for host "${host}" is missing or incomplete.`
|
|
17
40
|
);
|
|
18
41
|
}
|
|
19
|
-
const apiBaseUrl = githubConfig.apiBaseUrl ?? "https://api.github.com";
|
|
20
42
|
const credentials = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
token: githubConfig.token
|
|
24
|
-
};
|
|
25
|
-
return {
|
|
26
|
-
apiBaseUrl,
|
|
27
|
-
credentials,
|
|
28
|
-
enterprise,
|
|
29
|
-
organization
|
|
43
|
+
enterprise: void 0,
|
|
44
|
+
organization: void 0
|
|
30
45
|
};
|
|
46
|
+
if (enterprise) {
|
|
47
|
+
if (!githubConfig.token) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Enterprise API for copilot only works with "classic PAT" tokens. No token is configured for "${host}" in the config.`
|
|
50
|
+
);
|
|
51
|
+
} else {
|
|
52
|
+
credentials.enterprise = {
|
|
53
|
+
type: "token",
|
|
54
|
+
headers: { Authorization: `Bearer ${githubConfig.token}` },
|
|
55
|
+
token: githubConfig.token
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (organization) {
|
|
60
|
+
if (githubConfig.apps) {
|
|
61
|
+
const githubCredentialsProvider = integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
|
|
62
|
+
credentials.organization = await githubCredentialsProvider.getCredentials(
|
|
63
|
+
{
|
|
64
|
+
url: `https://${host}/${organization}`
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
} else if (githubConfig.token) {
|
|
68
|
+
credentials.organization = {
|
|
69
|
+
type: "token",
|
|
70
|
+
headers: { Authorization: `Bearer ${githubConfig.token}` },
|
|
71
|
+
token: githubConfig.token
|
|
72
|
+
};
|
|
73
|
+
} else {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`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.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return credentials;
|
|
31
80
|
};
|
|
32
81
|
|
|
33
|
-
exports.
|
|
82
|
+
exports.getCopilotConfig = getCopilotConfig;
|
|
83
|
+
exports.getGithubCredentials = getGithubCredentials;
|
|
34
84
|
//# sourceMappingURL=GithubUtils.cjs.js.map
|
|
@@ -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 {
|
|
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 integretions 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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"}
|