@backstage-community/plugin-cicd-statistics-module-buildkite 0.0.1
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 +7 -0
- package/README.md +53 -0
- package/dist/api/buildkite.esm.js +62 -0
- package/dist/api/buildkite.esm.js.map +1 -0
- package/dist/api/utils.esm.js +80 -0
- package/dist/api/utils.esm.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +66 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @backstage-community/plugin-cicd-statistics-module-buildkite
|
|
2
|
+
|
|
3
|
+
## 0.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 87d6273: An initial release implementation of a Buildkite `CicdStatisticsApi` for use in using the existing [cicd-statistics](https://github.com/backstage/community-plugins/tree/main/workspaces/cicd-statistics/plugins/cicd-statistics) plugin with [Buildkite](https://buildkite.com/).
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# cicd-statistics-module-buildkite
|
|
2
|
+
|
|
3
|
+
This is an extension module to the `cicd-statistics` plugin providing a `CicdStatisticsApiBuildkite`
|
|
4
|
+
for use extracting CI/CD statistics from Buildkite pipelines.
|
|
5
|
+
|
|
6
|
+
## Getting started
|
|
7
|
+
|
|
8
|
+
1. Install the `cicd-statistics` and `cicd-statistics-module-buildkite` plugins in the `app` package.
|
|
9
|
+
|
|
10
|
+
2. Configure your ApiFactory (Note that `CicdStatisticsApiBuildkite` accepts a [CicdStatisticsApiBuildkiteOpts](https://github.com/backstage/community-plugins/blob/master/plugins/cicd-statistics-module-buildkite/src/api/buildkite.ts#L51)):
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
// packages/app/src/apis.ts
|
|
14
|
+
import {
|
|
15
|
+
createApiFactory,
|
|
16
|
+
discoveryApiRef,
|
|
17
|
+
fetchApiRef,
|
|
18
|
+
} from '@backstage/core-plugin-api';
|
|
19
|
+
|
|
20
|
+
import { cicdStatisticsApiRef } from '@backstage-community/plugin-cicd-statistics';
|
|
21
|
+
import { CicdStatisticsApiBuildkite } from '@backstage-community/plugin-cicd-statistics-module-buildkite';
|
|
22
|
+
|
|
23
|
+
export const apis: AnyApiFactory[] = [
|
|
24
|
+
createApiFactory({
|
|
25
|
+
api: cicdStatisticsApiRef,
|
|
26
|
+
deps: {
|
|
27
|
+
discoveryApi: discoveryApiRef,
|
|
28
|
+
fetchApiApi: fetchApiRef,
|
|
29
|
+
},
|
|
30
|
+
factory({ discoveryApi, fetchApi }) {
|
|
31
|
+
return new CicdStatisticsApiBuildkite(discoveryApi, fetchApi);
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
34
|
+
];
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. Add the component to your EntityPage:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
// packages/app/src/components/catalog/EntityPage.tsx
|
|
41
|
+
import { EntityCicdStatisticsContent } from '@backstage-community/plugin-cicd-statistics';
|
|
42
|
+
|
|
43
|
+
<EntityLayout.Route path="/cicd-statistics" title="CI/CD Statistics">
|
|
44
|
+
<EntityCicdStatisticsContent />
|
|
45
|
+
</EntityLayout.Route>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
4. Configure entities to feature a `buildkite.com/pipeline-name` annotation:
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
annotations:
|
|
52
|
+
buildkite.com/pipeline-name: 'org-name/some-pipeline'
|
|
53
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { toBuilds, buildStatusMap } from './utils.esm.js';
|
|
2
|
+
import { BuildkiteApi } from '@roadiehq/backstage-plugin-buildkite';
|
|
3
|
+
|
|
4
|
+
class CicdStatisticsApiBuildkite {
|
|
5
|
+
#cicdDefaults;
|
|
6
|
+
#discoveryApi;
|
|
7
|
+
#fetchApi;
|
|
8
|
+
#proxyPath;
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this.#cicdDefaults = opts.cicdDefaults ? opts.cicdDefaults : {};
|
|
11
|
+
this.#discoveryApi = opts.discoveryApi;
|
|
12
|
+
this.#fetchApi = opts.fetchApi;
|
|
13
|
+
this.#proxyPath = opts.proxyPath;
|
|
14
|
+
}
|
|
15
|
+
async createBuildkiteApi(entity) {
|
|
16
|
+
const pipelineAnnotation = entity.metadata.annotations?.["buildkite.com/pipeline"] || "";
|
|
17
|
+
const pipelineParts = pipelineAnnotation.split("/");
|
|
18
|
+
const org = pipelineParts[0];
|
|
19
|
+
const pipeline = pipelineParts[1] ? pipelineParts[1] : "";
|
|
20
|
+
return {
|
|
21
|
+
api: new BuildkiteApi({
|
|
22
|
+
discoveryApi: this.#discoveryApi,
|
|
23
|
+
fetchApi: this.#fetchApi,
|
|
24
|
+
proxyPath: this.#proxyPath
|
|
25
|
+
}),
|
|
26
|
+
org,
|
|
27
|
+
pipeline
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async fetchBuilds(options) {
|
|
31
|
+
const {
|
|
32
|
+
entity,
|
|
33
|
+
updateProgress,
|
|
34
|
+
filterStatus = ["all"],
|
|
35
|
+
filterType = "all"
|
|
36
|
+
} = options;
|
|
37
|
+
const { api, org, pipeline } = await this.createBuildkiteApi(entity);
|
|
38
|
+
updateProgress(0, 0, 0);
|
|
39
|
+
const branch = filterType === "master" ? await this.getDefaultBranch(api, org, pipeline) : void 0;
|
|
40
|
+
const bkBuilds = await api.getBuilds(org, pipeline, 0, 25, branch);
|
|
41
|
+
const builds = toBuilds(bkBuilds);
|
|
42
|
+
const filteredBuilds = builds.filter(
|
|
43
|
+
(b) => filterStatus.includes("all") || filterStatus.includes(b.status)
|
|
44
|
+
);
|
|
45
|
+
return { builds: filteredBuilds };
|
|
46
|
+
}
|
|
47
|
+
async getConfiguration() {
|
|
48
|
+
return {
|
|
49
|
+
availableStatuses: Object.keys(
|
|
50
|
+
buildStatusMap
|
|
51
|
+
),
|
|
52
|
+
defaults: this.#cicdDefaults
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async getDefaultBranch(api, org, pipelineName) {
|
|
56
|
+
const pipeline = await api.getPipeline(org, pipelineName);
|
|
57
|
+
return pipeline.default_branch;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { CicdStatisticsApiBuildkite };
|
|
62
|
+
//# sourceMappingURL=buildkite.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildkite.esm.js","sources":["../../src/api/buildkite.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/LIAnnotationCENSE-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 { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\nimport {\n CicdStatisticsApi,\n CicdState,\n CicdConfiguration,\n CicdDefaults,\n FetchBuildsOptions,\n FilterStatusType,\n} from '@backstage-community/plugin-cicd-statistics';\nimport { Entity } from '@backstage/catalog-model';\nimport { toBuilds, buildStatusMap } from './utils';\nimport { BuildkiteApi } from '@roadiehq/backstage-plugin-buildkite';\n\n/**\n * BuildkiteClient represents an initialized Buildkite client.\n *\n * @public\n */\nexport type BuildkiteClient = {\n /* the actual API */\n api: InstanceType<typeof BuildkiteApi>;\n\n /* the Buildkite organization; retrieved from the entity */\n org: string;\n\n /* the Buildkite pipeline name; retrieved from the entity */\n pipeline: string;\n};\n\n/**\n * CicdStatisticsApiBuildkiteOpts configures a new CicdStatisticsApiBuildkite.\n *\n * @public\n */\nexport type CicdStatisticsApiBuildkiteOpts = {\n /* the DiscoveryApi to use */\n discoveryApi: DiscoveryApi;\n\n /* the FetchApi to use */\n fetchApi: FetchApi;\n\n /* the CicdDefaults to use */\n cicdDefaults?: Partial<CicdDefaults>;\n\n /* the path to the Buildkite API Backstage backend proxy endpoint */\n proxyPath?: string;\n};\n\n/**\n * Extracts the CI/CD statistics from a Buildkite pipeline.\n *\n * @public\n */\nexport class CicdStatisticsApiBuildkite implements CicdStatisticsApi {\n readonly #cicdDefaults: Partial<CicdDefaults>;\n readonly #discoveryApi: DiscoveryApi;\n readonly #fetchApi: FetchApi;\n readonly #proxyPath?: string;\n\n constructor(opts: CicdStatisticsApiBuildkiteOpts) {\n this.#cicdDefaults = opts.cicdDefaults ? opts.cicdDefaults : {};\n this.#discoveryApi = opts.discoveryApi;\n this.#fetchApi = opts.fetchApi;\n this.#proxyPath = opts.proxyPath;\n }\n\n public async createBuildkiteApi(entity: Entity): Promise<BuildkiteClient> {\n const pipelineAnnotation =\n entity.metadata.annotations?.['buildkite.com/pipeline'] || '';\n const pipelineParts = pipelineAnnotation.split('/');\n const org = pipelineParts[0];\n const pipeline = pipelineParts[1] ? pipelineParts[1] : '';\n\n return {\n api: new BuildkiteApi({\n discoveryApi: this.#discoveryApi,\n fetchApi: this.#fetchApi,\n proxyPath: this.#proxyPath,\n }),\n org,\n pipeline,\n };\n }\n\n public async fetchBuilds(options: FetchBuildsOptions): Promise<CicdState> {\n const {\n entity,\n updateProgress,\n filterStatus = ['all'],\n filterType = 'all',\n } = options;\n const { api, org, pipeline } = await this.createBuildkiteApi(entity);\n updateProgress(0, 0, 0);\n\n // Note the cicd-statistics plugin regards 'master' as a generic term\n // referring to a particular default 'trunk' branch, and not necessarily\n // the literal 'master' branch name.\n const branch =\n filterType === 'master'\n ? await this.getDefaultBranch(api, org, pipeline)\n : undefined;\n const bkBuilds = await api.getBuilds(org, pipeline, 0, 25, branch);\n const builds = toBuilds(bkBuilds);\n const filteredBuilds = builds.filter(\n b => filterStatus.includes('all') || filterStatus.includes(b.status),\n );\n\n return { builds: filteredBuilds };\n }\n\n public async getConfiguration(): Promise<Partial<CicdConfiguration>> {\n return {\n availableStatuses: Object.keys(\n buildStatusMap,\n ) as ReadonlyArray<FilterStatusType>,\n defaults: this.#cicdDefaults,\n };\n }\n\n private async getDefaultBranch(\n api: BuildkiteApi,\n org: string,\n pipelineName: string,\n ): Promise<string> {\n const pipeline = await api.getPipeline(org, pipelineName);\n\n return pipeline.default_branch;\n }\n}\n"],"names":[],"mappings":";;;AAqEO,MAAM,0BAAwD,CAAA;AAAA,EAC1D,aAAA,CAAA;AAAA,EACA,aAAA,CAAA;AAAA,EACA,SAAA,CAAA;AAAA,EACA,UAAA,CAAA;AAAA,EAET,YAAY,IAAsC,EAAA;AAChD,IAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAK,YAAe,GAAA,IAAA,CAAK,eAAe,EAAC,CAAA;AAC9D,IAAA,IAAA,CAAK,gBAAgB,IAAK,CAAA,YAAA,CAAA;AAC1B,IAAA,IAAA,CAAK,YAAY,IAAK,CAAA,QAAA,CAAA;AACtB,IAAA,IAAA,CAAK,aAAa,IAAK,CAAA,SAAA,CAAA;AAAA,GACzB;AAAA,EAEA,MAAa,mBAAmB,MAA0C,EAAA;AACxE,IAAA,MAAM,kBACJ,GAAA,MAAA,CAAO,QAAS,CAAA,WAAA,GAAc,wBAAwB,CAAK,IAAA,EAAA,CAAA;AAC7D,IAAM,MAAA,aAAA,GAAgB,kBAAmB,CAAA,KAAA,CAAM,GAAG,CAAA,CAAA;AAClD,IAAM,MAAA,GAAA,GAAM,cAAc,CAAC,CAAA,CAAA;AAC3B,IAAA,MAAM,WAAW,aAAc,CAAA,CAAC,CAAI,GAAA,aAAA,CAAc,CAAC,CAAI,GAAA,EAAA,CAAA;AAEvD,IAAO,OAAA;AAAA,MACL,GAAA,EAAK,IAAI,YAAa,CAAA;AAAA,QACpB,cAAc,IAAK,CAAA,aAAA;AAAA,QACnB,UAAU,IAAK,CAAA,SAAA;AAAA,QACf,WAAW,IAAK,CAAA,UAAA;AAAA,OACjB,CAAA;AAAA,MACD,GAAA;AAAA,MACA,QAAA;AAAA,KACF,CAAA;AAAA,GACF;AAAA,EAEA,MAAa,YAAY,OAAiD,EAAA;AACxE,IAAM,MAAA;AAAA,MACJ,MAAA;AAAA,MACA,cAAA;AAAA,MACA,YAAA,GAAe,CAAC,KAAK,CAAA;AAAA,MACrB,UAAa,GAAA,KAAA;AAAA,KACX,GAAA,OAAA,CAAA;AACJ,IAAM,MAAA,EAAE,KAAK,GAAK,EAAA,QAAA,KAAa,MAAM,IAAA,CAAK,mBAAmB,MAAM,CAAA,CAAA;AACnE,IAAe,cAAA,CAAA,CAAA,EAAG,GAAG,CAAC,CAAA,CAAA;AAKtB,IAAM,MAAA,MAAA,GACJ,eAAe,QACX,GAAA,MAAM,KAAK,gBAAiB,CAAA,GAAA,EAAK,GAAK,EAAA,QAAQ,CAC9C,GAAA,KAAA,CAAA,CAAA;AACN,IAAM,MAAA,QAAA,GAAW,MAAM,GAAI,CAAA,SAAA,CAAU,KAAK,QAAU,EAAA,CAAA,EAAG,IAAI,MAAM,CAAA,CAAA;AACjE,IAAM,MAAA,MAAA,GAAS,SAAS,QAAQ,CAAA,CAAA;AAChC,IAAA,MAAM,iBAAiB,MAAO,CAAA,MAAA;AAAA,MAC5B,CAAA,CAAA,KAAK,aAAa,QAAS,CAAA,KAAK,KAAK,YAAa,CAAA,QAAA,CAAS,EAAE,MAAM,CAAA;AAAA,KACrE,CAAA;AAEA,IAAO,OAAA,EAAE,QAAQ,cAAe,EAAA,CAAA;AAAA,GAClC;AAAA,EAEA,MAAa,gBAAwD,GAAA;AACnE,IAAO,OAAA;AAAA,MACL,mBAAmB,MAAO,CAAA,IAAA;AAAA,QACxB,cAAA;AAAA,OACF;AAAA,MACA,UAAU,IAAK,CAAA,aAAA;AAAA,KACjB,CAAA;AAAA,GACF;AAAA,EAEA,MAAc,gBAAA,CACZ,GACA,EAAA,GAAA,EACA,YACiB,EAAA;AACjB,IAAA,MAAM,QAAW,GAAA,MAAM,GAAI,CAAA,WAAA,CAAY,KAAK,YAAY,CAAA,CAAA;AAExD,IAAA,OAAO,QAAS,CAAA,cAAA,CAAA;AAAA,GAClB;AACF;;;;"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const buildStatusMap = {
|
|
2
|
+
running: "running",
|
|
3
|
+
scheduled: "scheduled",
|
|
4
|
+
passed: "succeeded",
|
|
5
|
+
failing: "failed",
|
|
6
|
+
failed: "failed",
|
|
7
|
+
blocked: "stalled",
|
|
8
|
+
canceled: "aborted",
|
|
9
|
+
canceling: "aborted",
|
|
10
|
+
skipped: "aborted",
|
|
11
|
+
not_run: "scheduled",
|
|
12
|
+
finished: "unknown"
|
|
13
|
+
};
|
|
14
|
+
const jobStatusMap = {
|
|
15
|
+
accepted: "scheduled",
|
|
16
|
+
assigned: "scheduled",
|
|
17
|
+
blocked: "stalled",
|
|
18
|
+
blocked_failed: "failed",
|
|
19
|
+
broken: "failed",
|
|
20
|
+
canceled: "aborted",
|
|
21
|
+
canceling: "aborted",
|
|
22
|
+
expired: "aborted",
|
|
23
|
+
finished: "unknown",
|
|
24
|
+
limited: "unknown",
|
|
25
|
+
limiting: "unknown",
|
|
26
|
+
pending: "stalled",
|
|
27
|
+
running: "running",
|
|
28
|
+
scheduled: "scheduled",
|
|
29
|
+
skipped: "aborted",
|
|
30
|
+
timed_out: "expired",
|
|
31
|
+
timing_out: "expired",
|
|
32
|
+
unblocked: "unknown",
|
|
33
|
+
unblocked_failed: "failed",
|
|
34
|
+
waiting: "scheduled",
|
|
35
|
+
waiting_failed: "failed"
|
|
36
|
+
};
|
|
37
|
+
function toBuilds(builds) {
|
|
38
|
+
return builds.map((build) => {
|
|
39
|
+
return {
|
|
40
|
+
id: build.id,
|
|
41
|
+
status: buildStatusMap[build.state],
|
|
42
|
+
// TODO: is this correct?
|
|
43
|
+
branchType: build.branch,
|
|
44
|
+
duration: new Date(build.finished_at).valueOf() - new Date(build.started_at).valueOf(),
|
|
45
|
+
requestedAt: new Date(build.created_at),
|
|
46
|
+
triggeredBy: triggeredBy(build.source),
|
|
47
|
+
stages: jobsToStages(build.jobs)
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function triggeredBy(source) {
|
|
52
|
+
if (source === "schedule") {
|
|
53
|
+
return "internal";
|
|
54
|
+
}
|
|
55
|
+
if (source === "ui") {
|
|
56
|
+
return "manual";
|
|
57
|
+
}
|
|
58
|
+
return "scm";
|
|
59
|
+
}
|
|
60
|
+
function jobsToStages(jobs) {
|
|
61
|
+
return jobs.map((job) => {
|
|
62
|
+
const status = jobStatusMap[job.state] ? jobStatusMap[job.state] : "unknown";
|
|
63
|
+
const duration = new Date(job.finished_at).valueOf() - new Date(job.started_at).valueOf();
|
|
64
|
+
return {
|
|
65
|
+
name: job.name,
|
|
66
|
+
status,
|
|
67
|
+
duration,
|
|
68
|
+
stages: [
|
|
69
|
+
{
|
|
70
|
+
name: job.name,
|
|
71
|
+
status,
|
|
72
|
+
duration
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export { buildStatusMap, jobsToStages, toBuilds, triggeredBy };
|
|
80
|
+
//# sourceMappingURL=utils.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../../src/api/utils.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 {\n Build,\n FilterStatusType,\n FilterBranchType,\n TriggerReason,\n Stage,\n} from '@backstage-community/plugin-cicd-statistics';\nimport { BuildkiteBuild, Job } from './types';\n\n/*\n * See https://buildkite.com/docs/pipelines/defining-steps#build-states\n */\nexport const buildStatusMap: Record<string, FilterStatusType> = {\n running: 'running',\n scheduled: 'scheduled',\n passed: 'succeeded',\n failing: 'failed',\n failed: 'failed',\n blocked: 'stalled',\n canceled: 'aborted',\n canceling: 'aborted',\n skipped: 'aborted',\n not_run: 'scheduled',\n finished: 'unknown',\n};\n\n/*\n * See https://buildkite.com/docs/pipelines/defining-steps#job-states\n */\nconst jobStatusMap: Record<string, FilterStatusType> = {\n accepted: 'scheduled',\n assigned: 'scheduled',\n blocked: 'stalled',\n blocked_failed: 'failed',\n broken: 'failed',\n canceled: 'aborted',\n canceling: 'aborted',\n expired: 'aborted',\n finished: 'unknown',\n limited: 'unknown',\n limiting: 'unknown',\n pending: 'stalled',\n running: 'running',\n scheduled: 'scheduled',\n skipped: 'aborted',\n timed_out: 'expired',\n timing_out: 'expired',\n unblocked: 'unknown',\n unblocked_failed: 'failed',\n waiting: 'scheduled',\n waiting_failed: 'failed',\n};\n\n/**\n * toBuilds transforms build objects from Buildkite to Build objects.\n *\n * @param builds - array of build objects returned from Buildkite's API.\n *\n * @public\n */\nexport function toBuilds(builds: BuildkiteBuild[]): Build[] {\n return builds.map(build => {\n return {\n id: build.id,\n status: buildStatusMap[build.state],\n // TODO: is this correct?\n branchType: build.branch as FilterBranchType,\n duration:\n new Date(build.finished_at).valueOf() -\n new Date(build.started_at).valueOf(),\n requestedAt: new Date(build.created_at),\n triggeredBy: triggeredBy(build.source),\n stages: jobsToStages(build.jobs),\n };\n });\n}\n\nexport function triggeredBy(source: string): TriggerReason {\n if (source === 'schedule') {\n return 'internal';\n }\n\n if (source === 'ui') {\n return 'manual';\n }\n\n return 'scm';\n}\n\n/**\n * jobsToStages transforms Job objects from Buildkite to Stage objects.\n *\n * @param jobs - array of job objects returned from the Buildkite API.\n *\n * @public\n */\nexport function jobsToStages(jobs: Job[]): Stage[] {\n return jobs.map(job => {\n const status = jobStatusMap[job.state]\n ? jobStatusMap[job.state]\n : 'unknown';\n const duration =\n new Date(job.finished_at).valueOf() - new Date(job.started_at).valueOf();\n\n return {\n name: job.name,\n status,\n duration,\n stages: [\n {\n name: job.name,\n status,\n duration,\n },\n ],\n };\n });\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';
|
|
2
|
+
import { CicdDefaults, CicdStatisticsApi, FetchBuildsOptions, CicdState, CicdConfiguration } from '@backstage-community/plugin-cicd-statistics';
|
|
3
|
+
import { Entity } from '@backstage/catalog-model';
|
|
4
|
+
import { BuildkiteApi } from '@roadiehq/backstage-plugin-buildkite';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* BuildkiteClient represents an initialized Buildkite client.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
type BuildkiteClient = {
|
|
12
|
+
api: InstanceType<typeof BuildkiteApi>;
|
|
13
|
+
org: string;
|
|
14
|
+
pipeline: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* CicdStatisticsApiBuildkiteOpts configures a new CicdStatisticsApiBuildkite.
|
|
18
|
+
*
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
type CicdStatisticsApiBuildkiteOpts = {
|
|
22
|
+
discoveryApi: DiscoveryApi;
|
|
23
|
+
fetchApi: FetchApi;
|
|
24
|
+
cicdDefaults?: Partial<CicdDefaults>;
|
|
25
|
+
proxyPath?: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Extracts the CI/CD statistics from a Buildkite pipeline.
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
declare class CicdStatisticsApiBuildkite implements CicdStatisticsApi {
|
|
33
|
+
#private;
|
|
34
|
+
constructor(opts: CicdStatisticsApiBuildkiteOpts);
|
|
35
|
+
createBuildkiteApi(entity: Entity): Promise<BuildkiteClient>;
|
|
36
|
+
fetchBuilds(options: FetchBuildsOptions): Promise<CicdState>;
|
|
37
|
+
getConfiguration(): Promise<Partial<CicdConfiguration>>;
|
|
38
|
+
private getDefaultBranch;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { type BuildkiteClient, CicdStatisticsApiBuildkite, type CicdStatisticsApiBuildkiteOpts };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage-community/plugin-cicd-statistics-module-buildkite",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CI/CD Statistics plugin module; Buildkite CI/CD",
|
|
5
|
+
"backstage": {
|
|
6
|
+
"role": "frontend-plugin-module",
|
|
7
|
+
"pluginId": "cicd-statistics",
|
|
8
|
+
"pluginPackage": "@backstage-community/plugin-cicd-statistics"
|
|
9
|
+
},
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public",
|
|
12
|
+
"main": "dist/index.esm.js",
|
|
13
|
+
"types": "dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"backstage",
|
|
17
|
+
"cicd statistics",
|
|
18
|
+
"gitlab"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://backstage.io",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/backstage/community-plugins",
|
|
24
|
+
"directory": "workspaces/cicd-statistics/plugins/cicd-statistics-module-buildkite"
|
|
25
|
+
},
|
|
26
|
+
"license": "Apache-2.0",
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"main": "dist/index.esm.js",
|
|
29
|
+
"types": "dist/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "backstage-cli package build",
|
|
35
|
+
"clean": "backstage-cli package clean",
|
|
36
|
+
"lint": "backstage-cli package lint",
|
|
37
|
+
"prepack": "backstage-cli package prepack",
|
|
38
|
+
"postpack": "backstage-cli package postpack",
|
|
39
|
+
"test": "backstage-cli package test"
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@backstage-community/plugin-cicd-statistics": "^0.1.39",
|
|
43
|
+
"@backstage/catalog-model": "^1.4.5",
|
|
44
|
+
"@backstage/core-plugin-api": "^1.9.2",
|
|
45
|
+
"@backstage/test-utils": "^1.5.9",
|
|
46
|
+
"@gitbeaker/browser": "^35.6.0",
|
|
47
|
+
"@gitbeaker/core": "^35.6.0",
|
|
48
|
+
"@roadiehq/backstage-plugin-buildkite": "^2.3.1",
|
|
49
|
+
"luxon": "^3.0.0",
|
|
50
|
+
"p-limit": "^3.1.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@backstage/cli": "^0.26.3",
|
|
54
|
+
"@types/react": "^16.13.1 || ^17.0.0",
|
|
55
|
+
"@types/react-dom": "^18.2.19",
|
|
56
|
+
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
57
|
+
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
58
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
62
|
+
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
63
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
64
|
+
},
|
|
65
|
+
"module": "./dist/index.esm.js"
|
|
66
|
+
}
|