@backstage-community/plugin-azure-devops 0.4.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/README.md ADDED
@@ -0,0 +1,399 @@
1
+ # Azure DevOps Plugin
2
+
3
+ Website: [https://dev.azure.com/](https://dev.azure.com/)
4
+
5
+ ## Features
6
+
7
+ ### Azure Pipelines
8
+
9
+ Lists the top _n_ builds for a given Azure Repo where _n_ is a configurable value
10
+
11
+ ![Azure Pipelines Builds Example](./docs/azure-devops-builds.png)
12
+
13
+ ### Azure Repos
14
+
15
+ Lists the top _n_ Active, Completed, or Abandoned Pull Requests for a given repository where _n_ is a configurable value
16
+
17
+ ![Azure Repos Pull Requests Example](./docs/azure-devops-pull-requests.png)
18
+
19
+ ### Azure Repos Git Tags
20
+
21
+ Lists all Git Tags for a given repository
22
+
23
+ ![Azure Repos Git Tags Example](./docs/azure-devops-git-tags.png)
24
+
25
+ ### Azure Readme
26
+
27
+ Readme for a given repository
28
+
29
+ ![Azure Readme Example](./docs/azure-devops-readme.png)
30
+
31
+ ## Setup
32
+
33
+ The following sections will help you get the Azure DevOps plugin setup and running
34
+
35
+ ### Azure DevOps Backend
36
+
37
+ You need to setup the [Azure DevOps backend plugin](https://github.com/backstage/backstage/tree/master/plugins/azure-devops-backend) before you move forward with any of these steps if you haven't already
38
+
39
+ ### Entity Annotation
40
+
41
+ To be able to use the Azure DevOps plugin you need to add the following annotation to any entities you want to use it with:
42
+
43
+ ```yaml
44
+ dev.azure.com/project-repo: <project-name>/<repo-name>
45
+ ```
46
+
47
+ Let's break this down a little: `<project-name>` will be the name of your Team Project and `<repo-name>` will be the name of your repository which needs to be part of the Team Project you entered for `<project-name>`.
48
+
49
+ Here's what that will look like in action:
50
+
51
+ ```yaml
52
+ # Example catalog-info.yaml entity definition file
53
+ apiVersion: backstage.io/v1alpha1
54
+ kind: Component
55
+ metadata:
56
+ # ...
57
+ annotations:
58
+ dev.azure.com/project-repo: my-project/my-repo
59
+ spec:
60
+ type: service
61
+ # ...
62
+ ```
63
+
64
+ #### Mono repos
65
+
66
+ If you have multiple entities within a single repo, you will need to specify which pipelines belong to each entity, like this:
67
+
68
+ ```yaml
69
+ dev.azure.com/project-repo: <my-project>/<my-repo>
70
+ dev.azure.com/build-definition: <build-definition-name>
71
+ ```
72
+
73
+ Then to display the `README` file that belongs to each entity you would do this:
74
+
75
+ ```yaml
76
+ dev.azure.com/readme-path: /<path-to>/<my-readme-file>.md
77
+ ```
78
+
79
+ #### Pipeline in different project to repo
80
+
81
+ If your pipeline is in a different project to the source code, you will need to specify this in the project annotation.
82
+
83
+ ```yaml
84
+ dev.azure.com/project-repo: <project-with-source-code>/<my-repo>
85
+ dev.azure.com/build-definition: <build-definition-name>
86
+ dev.azure.com/project: <project-with-build-code>
87
+ ```
88
+
89
+ #### Azure Pipelines Only
90
+
91
+ If you are only using Azure Pipelines along with a different SCM tool then you can use the following two annotations to see Builds:
92
+
93
+ ```yaml
94
+ dev.azure.com/project: <project-name>
95
+ dev.azure.com/build-definition: <build-definition-name>
96
+ ```
97
+
98
+ In this case `<project-name>` will be the name of your Team Project and `<build-definition-name>` will be the name of the Build Definition you would like to see Builds for, and it's possible to add more Builds separated by a comma. If the Build Definition name has spaces in it make sure to put quotes around it.
99
+
100
+ #### Multiple Organizations
101
+
102
+ If you have multiple organizations you'll need to also add this annotation:
103
+
104
+ ```yaml
105
+ dev.azure.com/host-org: <host>/<organization>
106
+ ```
107
+
108
+ For this annotation `<host>` will match the `host` value in the `integrations.azure` section in your `app-config.yaml` and `<organization>` will be the name of the Organization that is part of the `host`. Let's break this down with an example:
109
+
110
+ Say we have the following `integrations.azure` section:
111
+
112
+ ```yaml
113
+ integrations:
114
+ azure:
115
+ - host: dev.azure.com
116
+ credentials:
117
+ - organizations:
118
+ - my-org
119
+ - my-other-org
120
+ clientId: ${AZURE_CLIENT_ID}
121
+ clientSecret: ${AZURE_CLIENT_SECRET}
122
+ tenantId: ${AZURE_TENANT_ID}
123
+ - organizations:
124
+ - another-org
125
+ clientId: ${AZURE_CLIENT_ID}
126
+ - host: server.company.com
127
+ credentials:
128
+ - organizations:
129
+ - yet-another-org
130
+ personalAccessToken: ${PERSONAL_ACCESS_TOKEN}
131
+ ```
132
+
133
+ If the entity we are viewing lives in the `my-other-org` organization then the `dev.azure.com/host-org` annotation would look like this:
134
+
135
+ ```yaml
136
+ dev.azure.com/host-org: dev.azure.com/my-other-org
137
+ ```
138
+
139
+ And if the entity was from `yet-another-org` it would look like this:
140
+
141
+ ```yaml
142
+ dev.azure.com/host-org: server.company.com/yet-another-org
143
+ ```
144
+
145
+ **Note:** To save you time, effort, and confusion setting up these annotations manually you can use the `AzureDevOpsAnnotatorProcessor` processor which will add the `dev.azure.com/host-org` and `dev.azure.com/project-repo` annotations for you with the correct values. The Azure DevOps backend plugin has details on how to [add this processor](https://github.com/backstage/backstage/tree/master/plugins/azure-devops-backend#processor).
146
+
147
+ ### Azure Pipelines Component
148
+
149
+ To get the Azure Pipelines component working you'll need to do the following two steps:
150
+
151
+ 1. First we need to add the `@backstage-community/plugin-azure-devops` package to your frontend app:
152
+
153
+ ```bash
154
+ # From your Backstage root directory
155
+ yarn --cwd packages/app add @backstage-community/plugin-azure-devops
156
+ ```
157
+
158
+ 2. Second we need to add the `EntityAzurePipelinesContent` extension to the entity page in your app. How to do this will depend on which annotation you are using in your entities:
159
+
160
+ 1. If you are using the `dev.azure.com/project-repo` annotation then you'll want to do the following:
161
+
162
+ ```tsx
163
+ // In packages/app/src/components/catalog/EntityPage.tsx
164
+ import {
165
+ EntityAzurePipelinesContent,
166
+ isAzureDevOpsAvailable,
167
+ } from '@backstage-community/plugin-azure-devops';
168
+
169
+ // For example in the CI/CD section
170
+ const cicdContent = (
171
+ <EntitySwitch>
172
+ // ...
173
+ <EntitySwitch.Case if={isAzureDevOpsAvailable}>
174
+ <EntityAzurePipelinesContent defaultLimit={25} />
175
+ </EntitySwitch.Case>
176
+ // ...
177
+ </EntitySwitch>
178
+ ```
179
+
180
+ 2. If you are using the `dev.azure.com/project` and `dev.azure.com/build-definition` annotations then you'll want to do this:
181
+
182
+ ```tsx
183
+ // In packages/app/src/components/catalog/EntityPage.tsx
184
+ import {
185
+ EntityAzurePipelinesContent,
186
+ isAzurePipelinesAvailable,
187
+ } from '@backstage-community/plugin-azure-devops';
188
+
189
+ // For example in the CI/CD section
190
+ const cicdContent = (
191
+ <EntitySwitch>
192
+ // ...
193
+ <EntitySwitch.Case if={isAzurePipelinesAvailable}>
194
+ <EntityAzurePipelinesContent defaultLimit={25} />
195
+ </EntitySwitch.Case>
196
+ // ...
197
+ </EntitySwitch>
198
+ ```
199
+
200
+ **Notes:**
201
+
202
+ - The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
203
+ - The `defaultLimit` property on the `EntityAzurePipelinesContent` will set the max number of Builds you would like to see, if not set this will default to 10
204
+
205
+ ### Azure Repos Component
206
+
207
+ To get the Azure Repos component working you'll need to do the following two steps:
208
+
209
+ 1. First we need to add the @backstage-community/plugin-azure-devops package to your frontend app:
210
+
211
+ ```bash
212
+ # From your Backstage root directory
213
+ yarn --cwd packages/app add @backstage-community/plugin-azure-devops
214
+ ```
215
+
216
+ 2. Second we need to add the `EntityAzurePullRequestsContent` extension to the entity page in your app:
217
+
218
+ ```tsx
219
+ // In packages/app/src/components/catalog/EntityPage.tsx
220
+ import {
221
+ EntityAzurePullRequestsContent,
222
+ isAzureDevOpsAvailable,
223
+ } from '@backstage-community/plugin-azure-devops';
224
+
225
+ // For example in the Service section
226
+ const serviceEntityPage = (
227
+ <EntityLayout>
228
+ // ...
229
+ <EntityLayout.Route if={isAzureDevOpsAvailable} path="/pull-requests" title="Pull Requests">
230
+ <EntityAzurePullRequestsContent defaultLimit={25} />
231
+ </EntityLayout.Route>
232
+ // ...
233
+ </EntityLayout>
234
+ ```
235
+
236
+ **Notes:**
237
+
238
+ - You'll need to add the `EntityLayout.Route` above from step 2 to all the entity sections you want to see Pull Requests in. For example if you wanted to see Pull Requests when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
239
+ - The `if` prop is optional on the `EntityLayout.Route`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
240
+ - The `defaultLimit` property on the `EntityAzurePullRequestsContent` will set the max number of Pull Requests you would like to see, if not set this will default to 10
241
+
242
+ ### Git Tags Component
243
+
244
+ To get the Git Tags component working you'll need to do the following two steps:
245
+
246
+ 1. First we need to add the @backstage-community/plugin-azure-devops package to your frontend app:
247
+
248
+ ```bash
249
+ # From your Backstage root directory
250
+ yarn --cwd packages/app add @backstage-community/plugin-azure-devops
251
+ ```
252
+
253
+ 2. Second we need to add the `EntityAzureGitTagsContent` extension to the entity page in your app:
254
+
255
+ ```tsx
256
+ // In packages/app/src/components/catalog/EntityPage.tsx
257
+ import {
258
+ EntityAzureGitTagsContent,
259
+ isAzureDevOpsAvailable,
260
+ } from '@backstage-community/plugin-azure-devops';
261
+
262
+ // For example in the Service section
263
+ const serviceEntityPage = (
264
+ <EntityLayout>
265
+ // ...
266
+ <EntityLayout.Route if={isAzureDevOpsAvailable} path="/git-tags" title="Git Tags">
267
+ <EntityAzureGitTagsContent />
268
+ </EntityLayout.Route>
269
+ // ...
270
+ </EntityLayout>
271
+ ```
272
+
273
+ **Notes:**
274
+
275
+ - You'll need to add the `EntityLayout.Route` above from step 2 to all the entity sections you want to see Git Tags in. For example if you wanted to see Git Tags when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
276
+ - The `if` prop is optional on the `EntityLayout.Route`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
277
+
278
+ ### Git README
279
+
280
+ To get the README component working you'll need to do the following two steps:
281
+
282
+ 1. First we need to add the @backstage-community/plugin-azure-devops package to your frontend app:
283
+
284
+ ```bash
285
+ # From your Backstage root directory
286
+ yarn --cwd packages/app add @backstage-community/plugin-azure-devops
287
+ ```
288
+
289
+ 2. Second we need to add the `EntityAzureReadmeCard` extension to the entity page in your app:
290
+
291
+ ```tsx
292
+ // In packages/app/src/components/catalog/EntityPage.tsx
293
+ import {
294
+ EntityAzureReadmeCard,
295
+ isAzureDevOpsAvailable,
296
+ } from '@backstage-community/plugin-azure-devops';
297
+
298
+ // As it is a card, you can customize it the way you prefer
299
+ // For example in the Service section
300
+
301
+ const overviewContent = (
302
+ <Grid container spacing={3} alignItems="stretch">
303
+ <EntitySwitch>
304
+ <EntitySwitch.Case if={isAzureDevOpsAvailable}>
305
+ <Grid item md={6}>
306
+ ...
307
+ </Grid>
308
+ <Grid item md={6}>
309
+ <EntityAzureReadmeCard maxHeight={350} />
310
+ </Grid>
311
+ </EntitySwitch.Case>
312
+ </EntitySwitch>
313
+ </Grid>
314
+ );
315
+ ```
316
+
317
+ **Notes:**
318
+
319
+ - You'll need to add the `EntitySwitch.Case` above from step 2 to all the entity sections you want to see Readme in. For example if you wanted to see Readme when looking at Website entities then you would need to add this to the `websiteEntityPage` section.
320
+ - The `if` prop is optional on the `EntitySwitch.Case`, you can remove it if you always want to see the tab even if the entity being viewed does not have the needed annotation
321
+ - The `maxHeight` property on the `EntityAzureReadmeCard` will set the maximum screen size you would like to see, if not set it will default to 100%
322
+
323
+ ## Permission Framework
324
+
325
+ Azure DevOps plugin supports the permission framework for PRs, GitTags, Pipelines and Readme features.
326
+
327
+ ```bash
328
+ # From your Backstage root directory
329
+ yarn --cwd packages/backend add @backstage-community/plugin-azure-devops-common
330
+ ```
331
+
332
+ New Backend you can skip the below and proceed with [permission configuration](#configure-permission)
333
+
334
+ To enable permissions for the legacy backend system in `packages/backend/src/plugins/azure-devops.ts` add the following.
335
+
336
+ ```diff
337
+ export default async function createPlugin(
338
+ env: PluginEnvironment,
339
+ ): Promise<Router> {
340
+ return createRouter({
341
+ logger: env.logger,
342
+ config: env.config,
343
+ reader: env.reader,
344
+ + permissions: env.permissions,
345
+ });
346
+ }
347
+ ```
348
+
349
+ ### Configure Permission
350
+
351
+ To apply the permission rules add the following in `packages/backend/src/plugins/permissions.ts`.
352
+
353
+ > Note: the following is just an example of how you might want to setup permissions, as an Adopter you can configure this to fit your needs. Also all the permissions are Resource Permissions as they work with an Entity with the exception of `azureDevOpsPullRequestDashboardReadPermission`.
354
+
355
+ ```diff
356
+
357
+ + import {
358
+ + azureDevOpsPullRequestReadPermission,
359
+ + azureDevOpsPipelineReadPermission,
360
+ + azureDevOpsGitTagReadPermission,
361
+ + azureDevOpsReadmeReadPermission,
362
+ + azureDevOpsPullRequestDashboardReadPermission } from '@backstage-community/plugin-azure-devops-common';
363
+ + import {
364
+ + AuthorizeResult,
365
+ + PolicyDecision,
366
+ + isPermission,
367
+ + } from '@backstage/plugin-permission-common';
368
+ + import {
369
+ + catalogConditions,
370
+ + createCatalogConditionalDecision,
371
+ + } from '@backstage/plugin-catalog-backend/alpha';
372
+ ...
373
+ async handle(
374
+ request: PolicyQuery,
375
+ user?: BackstageIdentityResponse,
376
+ ): Promise<PolicyDecision> {
377
+ + if ( isPermission(request.permission, azureDevOpsPullRequestReadPermission) ||
378
+ + isPermission(request.permission, azureDevOpsPipelineReadPermission) ||
379
+ + isPermission(request.permission, azureDevOpsGitTagReadPermission) ||
380
+ + isPermission(request.permission, azureDevOpsReadmeReadPermission)) {
381
+ + return createCatalogConditionalDecision(
382
+ + request.permission,
383
+ + catalogConditions.isEntityOwner({
384
+ + claims: user?.identity.ownershipEntityRefs ?? [],
385
+ + }),
386
+ + );
387
+ + }
388
+
389
+ + if ( isPermission(request.permission, azureDevOpsPullRequestDashboardReadPermission) {
390
+ + return {
391
+ + result: AuthorizeResult.ALLOW,
392
+ + };
393
+ + }
394
+
395
+ return {
396
+ result: AuthorizeResult.ALLOW,
397
+ };
398
+ }
399
+ ```
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@backstage-community/plugin-azure-devops",
3
+ "version": "0.4.4",
4
+ "main": "../dist/alpha.esm.js",
5
+ "module": "../dist/alpha.esm.js",
6
+ "types": "../dist/alpha.d.ts"
7
+ }
@@ -0,0 +1,6 @@
1
+ import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
2
+
3
+ /** @alpha */
4
+ declare const _default: _backstage_frontend_plugin_api.BackstagePlugin<{}, {}>;
5
+
6
+ export { _default as default };
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import { createApiExtension, createApiFactory, discoveryApiRef, fetchApiRef, createPageExtension, createPlugin } from '@backstage/frontend-plugin-api';
3
+ import { a as azureDevOpsApiRef, A as AzureDevOpsClient, b as azurePullRequestDashboardRouteRef } from './esm/AzureDevOpsApi-GBxs-uQ7.esm.js';
4
+ import { convertLegacyRouteRef, compatWrapper } from '@backstage/core-compat-api';
5
+ import { createEntityContentExtension, createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha';
6
+ import '@backstage/core-plugin-api';
7
+ import '@backstage/errors';
8
+
9
+ const azureDevOpsApi = createApiExtension({
10
+ factory: createApiFactory({
11
+ api: azureDevOpsApiRef,
12
+ deps: {
13
+ discoveryApi: discoveryApiRef,
14
+ fetchApi: fetchApiRef
15
+ },
16
+ factory: ({ discoveryApi, fetchApi }) => new AzureDevOpsClient({ discoveryApi, fetchApi })
17
+ })
18
+ });
19
+ const azureDevOpsPullRequestPage = createPageExtension({
20
+ defaultPath: "/azure-pull-requests",
21
+ routeRef: convertLegacyRouteRef(azurePullRequestDashboardRouteRef),
22
+ loader: () => import('./esm/index-W1pvc5vi.esm.js').then(
23
+ (m) => compatWrapper(/* @__PURE__ */ React.createElement(m.PullRequestsPage, null))
24
+ )
25
+ });
26
+ const azureDevOpsPipelinesEntityContent = createEntityContentExtension({
27
+ name: "pipelines",
28
+ defaultPath: "/pipelines",
29
+ defaultTitle: "Pipelines",
30
+ loader: () => import('./esm/index-Bwu2-Sgs.esm.js').then(
31
+ (m) => compatWrapper(/* @__PURE__ */ React.createElement(m.EntityPageAzurePipelines, null))
32
+ )
33
+ });
34
+ const azureDevOpsGitTagsEntityContent = createEntityContentExtension({
35
+ name: "git-tags",
36
+ defaultPath: "/git-tags",
37
+ defaultTitle: "Git Tags",
38
+ loader: () => import('./esm/index-1Rl7C23d.esm.js').then(
39
+ (m) => compatWrapper(/* @__PURE__ */ React.createElement(m.EntityPageAzureGitTags, null))
40
+ )
41
+ });
42
+ const azureDevOpsPullRequestsEntityContent = createEntityContentExtension({
43
+ name: "pull-requests",
44
+ defaultPath: "/pull-requests",
45
+ defaultTitle: "Pull Requests",
46
+ loader: () => import('./esm/index-Bo-6jkQA.esm.js').then(
47
+ (m) => compatWrapper(/* @__PURE__ */ React.createElement(m.EntityPageAzurePullRequests, null))
48
+ )
49
+ });
50
+ const azureDevOpsReadmeEntityCard = createEntityCardExtension({
51
+ name: "readme",
52
+ loader: async () => import('./esm/index-BJ_pWnMh.esm.js').then(
53
+ (m) => compatWrapper(/* @__PURE__ */ React.createElement(m.ReadmeCard, null))
54
+ )
55
+ });
56
+ var plugin = createPlugin({
57
+ id: "azure-devops",
58
+ extensions: [
59
+ azureDevOpsApi,
60
+ azureDevOpsReadmeEntityCard,
61
+ azureDevOpsPipelinesEntityContent,
62
+ azureDevOpsGitTagsEntityContent,
63
+ azureDevOpsPullRequestsEntityContent,
64
+ azureDevOpsPullRequestPage
65
+ ]
66
+ });
67
+
68
+ export { plugin as default };
69
+ //# sourceMappingURL=alpha.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alpha.esm.js","sources":["../src/alpha/plugin.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 React from 'react';\nimport {\n createApiExtension,\n createApiFactory,\n createPageExtension,\n createPlugin,\n discoveryApiRef,\n fetchApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { azureDevOpsApiRef, AzureDevOpsClient } from '../api';\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport {\n createEntityCardExtension,\n createEntityContentExtension,\n} from '@backstage/plugin-catalog-react/alpha';\nimport { azurePullRequestDashboardRouteRef } from '../routes';\n\n/** @alpha */\nexport const azureDevOpsApi = createApiExtension({\n factory: createApiFactory({\n api: azureDevOpsApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new AzureDevOpsClient({ discoveryApi, fetchApi }),\n }),\n});\n\n/** @alpha */\nexport const azureDevOpsPullRequestPage = createPageExtension({\n defaultPath: '/azure-pull-requests',\n routeRef: convertLegacyRouteRef(azurePullRequestDashboardRouteRef),\n loader: () =>\n import('../components/PullRequestsPage').then(m =>\n compatWrapper(<m.PullRequestsPage />),\n ),\n});\n\n/** @alpha */\nexport const azureDevOpsPipelinesEntityContent = createEntityContentExtension({\n name: 'pipelines',\n defaultPath: '/pipelines',\n defaultTitle: 'Pipelines',\n loader: () =>\n import('../components/EntityPageAzurePipelines').then(m =>\n compatWrapper(<m.EntityPageAzurePipelines />),\n ),\n});\n\n/** @alpha */\nexport const azureDevOpsGitTagsEntityContent = createEntityContentExtension({\n name: 'git-tags',\n defaultPath: '/git-tags',\n defaultTitle: 'Git Tags',\n loader: () =>\n import('../components/EntityPageAzureGitTags').then(m =>\n compatWrapper(<m.EntityPageAzureGitTags />),\n ),\n});\n\n/** @alpha */\nexport const azureDevOpsPullRequestsEntityContent =\n createEntityContentExtension({\n name: 'pull-requests',\n defaultPath: '/pull-requests',\n defaultTitle: 'Pull Requests',\n loader: () =>\n import('../components/EntityPageAzurePullRequests').then(m =>\n compatWrapper(<m.EntityPageAzurePullRequests />),\n ),\n });\n\n/** @alpha */\nexport const azureDevOpsReadmeEntityCard = createEntityCardExtension({\n name: 'readme',\n loader: async () =>\n import('../components/ReadmeCard').then(m =>\n compatWrapper(<m.ReadmeCard />),\n ),\n});\n\n/** @alpha */\nexport default createPlugin({\n id: 'azure-devops',\n extensions: [\n azureDevOpsApi,\n azureDevOpsReadmeEntityCard,\n azureDevOpsPipelinesEntityContent,\n azureDevOpsGitTagsEntityContent,\n azureDevOpsPullRequestsEntityContent,\n azureDevOpsPullRequestPage,\n ],\n});\n"],"names":[],"mappings":";;;;;;;;AAqCO,MAAM,iBAAiB,kBAAmB,CAAA;AAAA,EAC/C,SAAS,gBAAiB,CAAA;AAAA,IACxB,GAAK,EAAA,iBAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,YAAc,EAAA,eAAA;AAAA,MACd,QAAU,EAAA,WAAA;AAAA,KACZ;AAAA,IACA,OAAA,EAAS,CAAC,EAAE,YAAc,EAAA,QAAA,EACxB,KAAA,IAAI,iBAAkB,CAAA,EAAE,YAAc,EAAA,QAAA,EAAU,CAAA;AAAA,GACnD,CAAA;AACH,CAAC,CAAA,CAAA;AAGM,MAAM,6BAA6B,mBAAoB,CAAA;AAAA,EAC5D,WAAa,EAAA,sBAAA;AAAA,EACb,QAAA,EAAU,sBAAsB,iCAAiC,CAAA;AAAA,EACjE,MAAQ,EAAA,MACN,OAAO,6BAAgC,CAAE,CAAA,IAAA;AAAA,IAAK,OAC5C,aAAc,iBAAA,KAAA,CAAA,aAAA,CAAC,CAAE,CAAA,gBAAA,EAAF,IAAmB,CAAE,CAAA;AAAA,GACtC;AACJ,CAAC,CAAA,CAAA;AAGM,MAAM,oCAAoC,4BAA6B,CAAA;AAAA,EAC5E,IAAM,EAAA,WAAA;AAAA,EACN,WAAa,EAAA,YAAA;AAAA,EACb,YAAc,EAAA,WAAA;AAAA,EACd,MAAQ,EAAA,MACN,OAAO,6BAAwC,CAAE,CAAA,IAAA;AAAA,IAAK,OACpD,aAAc,iBAAA,KAAA,CAAA,aAAA,CAAC,CAAE,CAAA,wBAAA,EAAF,IAA2B,CAAE,CAAA;AAAA,GAC9C;AACJ,CAAC,CAAA,CAAA;AAGM,MAAM,kCAAkC,4BAA6B,CAAA;AAAA,EAC1E,IAAM,EAAA,UAAA;AAAA,EACN,WAAa,EAAA,WAAA;AAAA,EACb,YAAc,EAAA,UAAA;AAAA,EACd,MAAQ,EAAA,MACN,OAAO,6BAAsC,CAAE,CAAA,IAAA;AAAA,IAAK,OAClD,aAAc,iBAAA,KAAA,CAAA,aAAA,CAAC,CAAE,CAAA,sBAAA,EAAF,IAAyB,CAAE,CAAA;AAAA,GAC5C;AACJ,CAAC,CAAA,CAAA;AAGM,MAAM,uCACX,4BAA6B,CAAA;AAAA,EAC3B,IAAM,EAAA,eAAA;AAAA,EACN,WAAa,EAAA,gBAAA;AAAA,EACb,YAAc,EAAA,eAAA;AAAA,EACd,MAAQ,EAAA,MACN,OAAO,6BAA2C,CAAE,CAAA,IAAA;AAAA,IAAK,OACvD,aAAc,iBAAA,KAAA,CAAA,aAAA,CAAC,CAAE,CAAA,2BAAA,EAAF,IAA8B,CAAE,CAAA;AAAA,GACjD;AACJ,CAAC,CAAA,CAAA;AAGI,MAAM,8BAA8B,yBAA0B,CAAA;AAAA,EACnE,IAAM,EAAA,QAAA;AAAA,EACN,MAAQ,EAAA,YACN,OAAO,6BAA0B,CAAE,CAAA,IAAA;AAAA,IAAK,OACtC,aAAc,iBAAA,KAAA,CAAA,aAAA,CAAC,CAAE,CAAA,UAAA,EAAF,IAAa,CAAE,CAAA;AAAA,GAChC;AACJ,CAAC,CAAA,CAAA;AAGD,aAAe,YAAa,CAAA;AAAA,EAC1B,EAAI,EAAA,cAAA;AAAA,EACJ,UAAY,EAAA;AAAA,IACV,cAAA;AAAA,IACA,2BAAA;AAAA,IACA,iCAAA;AAAA,IACA,+BAAA;AAAA,IACA,oCAAA;AAAA,IACA,0BAAA;AAAA,GACF;AACF,CAAC,CAAA;;;;"}
@@ -0,0 +1,184 @@
1
+ import { createRouteRef, createApiRef } from '@backstage/core-plugin-api';
2
+ import { ResponseError } from '@backstage/errors';
3
+
4
+ const azurePullRequestDashboardRouteRef = createRouteRef({
5
+ id: "azure-pull-request-dashboard"
6
+ });
7
+ const azurePipelinesEntityContentRouteRef = createRouteRef({
8
+ id: "azure-pipelines-entity-content"
9
+ });
10
+ const azureGitTagsEntityContentRouteRef = createRouteRef({
11
+ id: "azure-git-tags-entity-content"
12
+ });
13
+ const azurePullRequestsEntityContentRouteRef = createRouteRef({
14
+ id: "azure-pull-requests-entity-content"
15
+ });
16
+
17
+ var __defProp = Object.defineProperty;
18
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
19
+ var __publicField = (obj, key, value) => {
20
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+ return value;
22
+ };
23
+ class AzureDevOpsClient {
24
+ constructor(options) {
25
+ __publicField(this, "discoveryApi");
26
+ __publicField(this, "fetchApi");
27
+ this.discoveryApi = options.discoveryApi;
28
+ this.fetchApi = options.fetchApi;
29
+ }
30
+ async getRepoBuilds(projectName, repoName, host, org, options) {
31
+ const queryString = new URLSearchParams();
32
+ if (options == null ? void 0 : options.top) {
33
+ queryString.append("top", options.top.toString());
34
+ }
35
+ if (host) {
36
+ queryString.append("host", host);
37
+ }
38
+ if (org) {
39
+ queryString.append("org", org);
40
+ }
41
+ const urlSegment = `repo-builds/${encodeURIComponent(
42
+ projectName
43
+ )}/${encodeURIComponent(repoName)}?${queryString}`;
44
+ const items = await this.get(urlSegment);
45
+ return { items };
46
+ }
47
+ async getGitTags(projectName, repoName, entityRef, host, org) {
48
+ const queryString = new URLSearchParams();
49
+ if (host) {
50
+ queryString.append("host", host);
51
+ }
52
+ if (org) {
53
+ queryString.append("org", org);
54
+ }
55
+ queryString.append("entityRef", entityRef);
56
+ const urlSegment = `git-tags/${encodeURIComponent(
57
+ projectName
58
+ )}/${encodeURIComponent(repoName)}?${queryString}`;
59
+ const items = await this.get(urlSegment);
60
+ return { items };
61
+ }
62
+ async getPullRequests(projectName, repoName, entityRef, host, org, options) {
63
+ const queryString = new URLSearchParams();
64
+ if (options == null ? void 0 : options.top) {
65
+ queryString.append("top", options.top.toString());
66
+ }
67
+ if (options == null ? void 0 : options.status) {
68
+ queryString.append("status", options.status.toString());
69
+ }
70
+ if (options == null ? void 0 : options.teamsLimit) {
71
+ queryString.append("teamsLimit", options.teamsLimit.toString());
72
+ }
73
+ if (host) {
74
+ queryString.append("host", host);
75
+ }
76
+ if (org) {
77
+ queryString.append("org", org);
78
+ }
79
+ queryString.append("entityRef", entityRef);
80
+ const urlSegment = `pull-requests/${encodeURIComponent(
81
+ projectName
82
+ )}/${encodeURIComponent(repoName)}?${queryString}`;
83
+ const items = await this.get(urlSegment);
84
+ return { items };
85
+ }
86
+ getDashboardPullRequests(projectName, teamsLimit) {
87
+ const queryString = new URLSearchParams();
88
+ queryString.append("top", "100");
89
+ if (teamsLimit) {
90
+ queryString.append("teamsLimit", teamsLimit.toString());
91
+ }
92
+ const urlSegment = `dashboard-pull-requests/${projectName}?${queryString}`;
93
+ return this.get(urlSegment);
94
+ }
95
+ getAllTeams(limit) {
96
+ const queryString = new URLSearchParams();
97
+ if (limit) {
98
+ queryString.append("limit", limit.toString());
99
+ }
100
+ let urlSegment = "all-teams";
101
+ if (queryString.toString()) {
102
+ urlSegment += `?${queryString}`;
103
+ }
104
+ return this.get(urlSegment);
105
+ }
106
+ getUserTeamIds(userId) {
107
+ return this.get(`users/${userId}/team-ids`);
108
+ }
109
+ async getBuildRuns(projectName, entityRef, repoName, definitionName, host, org, options) {
110
+ const queryString = new URLSearchParams();
111
+ if (repoName) {
112
+ queryString.append("repoName", repoName);
113
+ }
114
+ if (host) {
115
+ queryString.append("host", host);
116
+ }
117
+ if (org) {
118
+ queryString.append("org", org);
119
+ }
120
+ if (definitionName) {
121
+ const definitionNames = definitionName.split(",");
122
+ if (definitionNames.length > 1) {
123
+ const buildRuns = [];
124
+ for (const name of definitionNames) {
125
+ queryString.set("definitionName", name.trim());
126
+ if (options == null ? void 0 : options.top) {
127
+ queryString.set("top", options.top.toString());
128
+ }
129
+ queryString.append("entityRef", entityRef);
130
+ const urlSegment2 = `builds/${encodeURIComponent(
131
+ projectName
132
+ )}?${queryString}`;
133
+ const items2 = await this.get(urlSegment2);
134
+ buildRuns.push(...items2);
135
+ }
136
+ return { items: buildRuns };
137
+ }
138
+ queryString.append("definitionName", definitionName.trim());
139
+ }
140
+ if (options == null ? void 0 : options.top) {
141
+ queryString.append("top", options.top.toString());
142
+ }
143
+ queryString.append("entityRef", entityRef);
144
+ const urlSegment = `builds/${encodeURIComponent(
145
+ projectName
146
+ )}?${queryString}`;
147
+ const items = await this.get(urlSegment);
148
+ return { items };
149
+ }
150
+ async getReadme(opts) {
151
+ const queryString = new URLSearchParams();
152
+ if (opts.host) {
153
+ queryString.append("host", opts.host);
154
+ }
155
+ if (opts.org) {
156
+ queryString.append("org", opts.org);
157
+ }
158
+ if (opts.path) {
159
+ queryString.append("path", opts.path);
160
+ }
161
+ queryString.append("entityRef", opts.entityRef);
162
+ return await this.get(
163
+ `readme/${encodeURIComponent(opts.project)}/${encodeURIComponent(
164
+ opts.repo
165
+ )}?${queryString}`
166
+ );
167
+ }
168
+ async get(path) {
169
+ const baseUrl = `${await this.discoveryApi.getBaseUrl("azure-devops")}/`;
170
+ const url = new URL(path, baseUrl);
171
+ const response = await this.fetchApi.fetch(url.toString());
172
+ if (!response.ok) {
173
+ throw await ResponseError.fromResponse(response);
174
+ }
175
+ return response.json();
176
+ }
177
+ }
178
+
179
+ const azureDevOpsApiRef = createApiRef({
180
+ id: "plugin.azure-devops.service"
181
+ });
182
+
183
+ export { AzureDevOpsClient as A, azureDevOpsApiRef as a, azurePullRequestDashboardRouteRef as b, azurePipelinesEntityContentRouteRef as c, azureGitTagsEntityContentRouteRef as d, azurePullRequestsEntityContentRouteRef as e };
184
+ //# sourceMappingURL=AzureDevOpsApi-GBxs-uQ7.esm.js.map