Merge branch 'master' into samiram/pagerduty-plugin
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
# example-app
|
||||
|
||||
## 0.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7b37d65fd]
|
||||
- Updated dependencies [4aca74e08]
|
||||
- Updated dependencies [a41730c6e]
|
||||
- Updated dependencies [9a294574c]
|
||||
- Updated dependencies [0703edee0]
|
||||
- Updated dependencies [e8f69ba93]
|
||||
- Updated dependencies [0c0798f08]
|
||||
- Updated dependencies [5a2705de2]
|
||||
- Updated dependencies [0c0798f08]
|
||||
- Updated dependencies [84b654d5d]
|
||||
- Updated dependencies [0c0798f08]
|
||||
- Updated dependencies [199237d2f]
|
||||
- Updated dependencies [6627b626f]
|
||||
- Updated dependencies [3f05616bf]
|
||||
- Updated dependencies [803527bd3]
|
||||
- Updated dependencies [4577e377b]
|
||||
- Updated dependencies [2d0bd1be7]
|
||||
- Updated dependencies [59166e5ec]
|
||||
- Updated dependencies [a906f20e7]
|
||||
- @backstage/core@0.3.0
|
||||
- @backstage/plugin-jenkins@0.3.0
|
||||
- @backstage/plugin-cost-insights@0.3.0
|
||||
- @backstage/plugin-user-settings@0.2.1
|
||||
- @backstage/plugin-api-docs@0.2.1
|
||||
- @backstage/plugin-tech-radar@0.3.0
|
||||
- @backstage/theme@0.2.1
|
||||
- @backstage/plugin-catalog@0.2.1
|
||||
- @backstage/plugin-scaffolder@0.3.0
|
||||
- @backstage/plugin-circleci@0.2.1
|
||||
- @backstage/plugin-cloudbuild@0.2.1
|
||||
- @backstage/plugin-explore@0.2.1
|
||||
- @backstage/plugin-gcp-projects@0.2.1
|
||||
- @backstage/plugin-github-actions@0.2.1
|
||||
- @backstage/plugin-gitops-profiles@0.2.1
|
||||
- @backstage/plugin-graphiql@0.2.1
|
||||
- @backstage/plugin-kubernetes@0.2.1
|
||||
- @backstage/plugin-lighthouse@0.2.1
|
||||
- @backstage/plugin-newrelic@0.2.1
|
||||
- @backstage/plugin-register-component@0.2.1
|
||||
- @backstage/plugin-rollbar@0.2.1
|
||||
- @backstage/plugin-sentry@0.2.1
|
||||
- @backstage/plugin-techdocs@0.2.1
|
||||
- @backstage/plugin-welcome@0.2.1
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 6d97d2d6f: The InfoCard variant `'height100'` is deprecated. Use variant `'gridItem'` instead.
|
||||
|
||||
When the InfoCard is displayed as a grid item within a grid, you may want items to have the same height for all items.
|
||||
Set to the `'gridItem'` variant to display the InfoCard with full height suitable for Grid:
|
||||
`<InfoCard variant="gridItem">...</InfoCard>`
|
||||
|
||||
Changed the InfoCards in '@backstage/plugin-github-actions', '@backstage/plugin-jenkins', '@backstage/plugin-lighthouse'
|
||||
to pass an optional variant to the corresponding card of the plugin.
|
||||
|
||||
As a result the overview content of the EntityPage shows cards with full height suitable for Grid.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 65d722455: Add Pull Request tab to components view.
|
||||
- 26e69ab1a: Remove cost insights example client from demo app and export from plugin
|
||||
Create cost insights dev plugin using example client
|
||||
Make PluginConfig and dependent types public
|
||||
- e7f5471fd: cleaning up because external plugins have already implemented new api for creating
|
||||
- Updated dependencies [28edd7d29]
|
||||
- Updated dependencies [819a70229]
|
||||
- Updated dependencies [2846ef95c]
|
||||
- Updated dependencies [3a4236570]
|
||||
- Updated dependencies [ae5983387]
|
||||
- Updated dependencies [0d4459c08]
|
||||
- Updated dependencies [d67c529ab]
|
||||
- Updated dependencies [482b6313d]
|
||||
- Updated dependencies [e0be86b6f]
|
||||
- Updated dependencies [f70a52868]
|
||||
- Updated dependencies [12b5fe940]
|
||||
- Updated dependencies [8351ad79b]
|
||||
- Updated dependencies [30dd11122]
|
||||
- Updated dependencies [1297dcb3a]
|
||||
- Updated dependencies [368fd8243]
|
||||
- Updated dependencies [fb74f1db6]
|
||||
- Updated dependencies [3472c8be7]
|
||||
- Updated dependencies [cab473771]
|
||||
- Updated dependencies [1d0aec70f]
|
||||
- Updated dependencies [1c60f716e]
|
||||
- Updated dependencies [a73979d45]
|
||||
- Updated dependencies [144c66d50]
|
||||
- Updated dependencies [a768a07fb]
|
||||
- Updated dependencies [a3840bed2]
|
||||
- Updated dependencies [339668995]
|
||||
- Updated dependencies [b79017fd3]
|
||||
- Updated dependencies [6d97d2d6f]
|
||||
- Updated dependencies [5adfc005e]
|
||||
- Updated dependencies [f0aa01bcc]
|
||||
- Updated dependencies [8d1360aa9]
|
||||
- Updated dependencies [72f6cda35]
|
||||
- Updated dependencies [0ee9e9f66]
|
||||
- Updated dependencies [5c70f3d35]
|
||||
- Updated dependencies [bb48b9833]
|
||||
- Updated dependencies [fd8384d7e]
|
||||
- Updated dependencies [8c2b76e45]
|
||||
- Updated dependencies [0aecfded0]
|
||||
- Updated dependencies [93a3fa3ae]
|
||||
- Updated dependencies [782f3b354]
|
||||
- Updated dependencies [c5ef12926]
|
||||
- Updated dependencies [8b9c8196f]
|
||||
- Updated dependencies [2713f28f4]
|
||||
- Updated dependencies [6a84cb072]
|
||||
- Updated dependencies [406015b0d]
|
||||
- Updated dependencies [82759d3e4]
|
||||
- Updated dependencies [60d40892c]
|
||||
- Updated dependencies [cba4e4d97]
|
||||
- Updated dependencies [ac8d5d5c7]
|
||||
- Updated dependencies [2ebcfac8d]
|
||||
- Updated dependencies [4fc1d440e]
|
||||
- Updated dependencies [fa56f4615]
|
||||
- Updated dependencies [8afce088a]
|
||||
- Updated dependencies [4512b9967]
|
||||
- Updated dependencies [ebca83d48]
|
||||
- Updated dependencies [aca79334f]
|
||||
- Updated dependencies [c0d5242a0]
|
||||
- Updated dependencies [b3d57961c]
|
||||
- Updated dependencies [9a3b3dbf1]
|
||||
- Updated dependencies [e7d4ac7ce]
|
||||
- Updated dependencies [0b956f21b]
|
||||
- Updated dependencies [1c8c43756]
|
||||
- Updated dependencies [0e67c6b40]
|
||||
- Updated dependencies [26e69ab1a]
|
||||
- Updated dependencies [97c2cb19b]
|
||||
- Updated dependencies [02c60b5f8]
|
||||
- Updated dependencies [3beb5c9fc]
|
||||
- Updated dependencies [754e31db5]
|
||||
- Updated dependencies [57b54c8ed]
|
||||
- Updated dependencies [1611c6dbc]
|
||||
- Updated dependencies [7bbeb049f]
|
||||
- @backstage/cli@0.2.0
|
||||
- @backstage/plugin-api-docs@0.2.0
|
||||
- @backstage/plugin-catalog@0.2.0
|
||||
- @backstage/plugin-circleci@0.2.0
|
||||
- @backstage/plugin-explore@0.2.0
|
||||
- @backstage/plugin-gcp-projects@0.2.0
|
||||
- @backstage/plugin-github-actions@0.2.0
|
||||
- @backstage/plugin-gitops-profiles@0.2.0
|
||||
- @backstage/plugin-graphiql@0.2.0
|
||||
- @backstage/plugin-jenkins@0.2.0
|
||||
- @backstage/plugin-kubernetes@0.2.0
|
||||
- @backstage/plugin-lighthouse@0.2.0
|
||||
- @backstage/plugin-newrelic@0.2.0
|
||||
- @backstage/plugin-register-component@0.2.0
|
||||
- @backstage/plugin-rollbar@0.2.0
|
||||
- @backstage/plugin-scaffolder@0.2.0
|
||||
- @backstage/plugin-sentry@0.2.0
|
||||
- @backstage/plugin-tech-radar@0.2.0
|
||||
- @backstage/plugin-techdocs@0.2.0
|
||||
- @backstage/plugin-welcome@0.2.0
|
||||
- @backstage/core@0.2.0
|
||||
- @backstage/plugin-cloudbuild@0.2.0
|
||||
- @backstage/catalog-model@0.2.0
|
||||
- @backstage/theme@0.2.0
|
||||
- @backstage/plugin-cost-insights@0.2.0
|
||||
- @backstage/plugin-user-settings@0.2.0
|
||||
- @backstage/test-utils@0.1.2
|
||||
+33
-35
@@ -1,44 +1,44 @@
|
||||
{
|
||||
"name": "example-app",
|
||||
"version": "0.1.1-alpha.25",
|
||||
"version": "0.2.1",
|
||||
"private": true,
|
||||
"bundled": true,
|
||||
"dependencies": {
|
||||
"@backstage/catalog-model": "^0.1.1-alpha.25",
|
||||
"@backstage/cli": "^0.1.1-alpha.25",
|
||||
"@backstage/core": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-api-docs": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-catalog": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-circleci": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-cloudbuild": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-cost-insights": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-explore": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-gcp-projects": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-github-actions": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-gitops-profiles": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-graphiql": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-jenkins": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-kubernetes": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-lighthouse": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-newrelic": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-pagerduty": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-register-component": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-rollbar": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-scaffolder": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-sentry": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-tech-radar": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-techdocs": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-user-settings": "^0.1.1-alpha.25",
|
||||
"@backstage/plugin-welcome": "^0.1.1-alpha.25",
|
||||
"@backstage/test-utils": "^0.1.1-alpha.25",
|
||||
"@backstage/theme": "^0.1.1-alpha.25",
|
||||
"@backstage/catalog-model": "^0.2.0",
|
||||
"@backstage/cli": "^0.2.0",
|
||||
"@backstage/core": "^0.3.0",
|
||||
"@backstage/plugin-api-docs": "^0.2.1",
|
||||
"@backstage/plugin-catalog": "^0.2.1",
|
||||
"@backstage/plugin-circleci": "^0.2.1",
|
||||
"@backstage/plugin-cloudbuild": "^0.2.1",
|
||||
"@backstage/plugin-cost-insights": "^0.3.0",
|
||||
"@backstage/plugin-explore": "^0.2.1",
|
||||
"@backstage/plugin-gcp-projects": "^0.2.1",
|
||||
"@backstage/plugin-github-actions": "^0.2.1",
|
||||
"@backstage/plugin-gitops-profiles": "^0.2.1",
|
||||
"@backstage/plugin-graphiql": "^0.2.1",
|
||||
"@backstage/plugin-jenkins": "^0.3.0",
|
||||
"@backstage/plugin-kubernetes": "^0.2.1",
|
||||
"@backstage/plugin-lighthouse": "^0.2.1",
|
||||
"@backstage/plugin-newrelic": "^0.2.1",
|
||||
"@backstage/plugin-register-component": "^0.2.1",
|
||||
"@backstage/plugin-rollbar": "^0.2.1",
|
||||
"@backstage/plugin-scaffolder": "^0.3.0",
|
||||
"@backstage/plugin-sentry": "^0.2.1",
|
||||
"@backstage/plugin-tech-radar": "^0.3.0",
|
||||
"@backstage/plugin-techdocs": "^0.2.1",
|
||||
"@backstage/plugin-user-settings": "^0.2.1",
|
||||
"@backstage/plugin-welcome": "^0.2.1",
|
||||
"@backstage/test-utils": "^0.1.2",
|
||||
"@backstage/plugin-pagerduty": "^0.2.1",
|
||||
"@backstage/theme": "^0.2.1",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@octokit/rest": "^18.0.0",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^0.2.6",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^0.5.1",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^0.2.3",
|
||||
"dayjs": "^1.9.1",
|
||||
"@roadiehq/backstage-plugin-github-insights": "^0.2.12",
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "^0.6.2",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^0.2.7",
|
||||
"@roadiehq/backstage-plugin-buildkite": "^0.1.2",
|
||||
"history": "^5.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
@@ -47,7 +47,6 @@
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
"react-use": "^15.3.3",
|
||||
"regression": "^2.0.1",
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -59,7 +58,6 @@
|
||||
"@types/jquery": "^3.3.34",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/regression": "^2.0.0",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^4.2.0",
|
||||
|
||||
@@ -26,17 +26,9 @@ import {
|
||||
} from '@backstage/plugin-graphiql';
|
||||
|
||||
import {
|
||||
TravisCIApi,
|
||||
travisCIApiRef,
|
||||
} from '@roadiehq/backstage-plugin-travis-ci';
|
||||
|
||||
import {
|
||||
GithubPullRequestsClient,
|
||||
githubPullRequestsApiRef,
|
||||
} from '@roadiehq/backstage-plugin-github-pull-requests';
|
||||
|
||||
import { costInsightsApiRef } from '@backstage/plugin-cost-insights';
|
||||
import { ExampleCostInsightsClient } from './plugins/cost-insights';
|
||||
costInsightsApiRef,
|
||||
ExampleCostInsightsClient,
|
||||
} from '@backstage/plugin-cost-insights';
|
||||
|
||||
export const apis = [
|
||||
createApiFactory({
|
||||
@@ -59,8 +51,4 @@ export const apis = [
|
||||
}),
|
||||
|
||||
createApiFactory(costInsightsApiRef, new ExampleCostInsightsClient()),
|
||||
|
||||
// TODO: move to plugins
|
||||
createApiFactory(travisCIApiRef, new TravisCIApi()),
|
||||
createApiFactory(githubPullRequestsApiRef, new GithubPullRequestsClient()),
|
||||
];
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { CICDSwitcher } from './EntityPage';
|
||||
import { UrlPatternDiscovery, ApiProvider, ApiRegistry } from '@backstage/core';
|
||||
import {
|
||||
buildKiteApiRef,
|
||||
BuildKiteApi,
|
||||
} from '@roadiehq/backstage-plugin-buildkite';
|
||||
import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
|
||||
|
||||
describe('EntityPage Test', () => {
|
||||
const entity = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'ExampleComponent',
|
||||
annotations: {
|
||||
'buildkite.com/project-slug': 'exampleProject/examplePipeline',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
owner: 'guest',
|
||||
type: 'service',
|
||||
lifecycle: 'production',
|
||||
},
|
||||
};
|
||||
|
||||
const discoveryApi = UrlPatternDiscovery.compile('http://exampleapi.com');
|
||||
|
||||
const apis = ApiRegistry.from([
|
||||
[buildKiteApiRef, new BuildKiteApi({ discoveryApi })],
|
||||
]);
|
||||
|
||||
describe('CICDSwitcher Test', () => {
|
||||
it('Should render BuildKite View', async () => {
|
||||
const renderedComponent = await renderWithEffects(
|
||||
wrapInTestApp(
|
||||
<ApiProvider apis={apis}>
|
||||
<CICDSwitcher entity={entity} />
|
||||
</ApiProvider>,
|
||||
),
|
||||
);
|
||||
expect(
|
||||
renderedComponent.getByText(/exampleProject\/examplePipeline/),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -70,13 +70,18 @@ import {
|
||||
isPluginApplicableToEntity as isPagerDutyAvailable,
|
||||
PagerDutyCard,
|
||||
} from '@backstage/plugin-pagerduty';
|
||||
import { Router as BuildKiteRouter,
|
||||
isPluginApplicableToEntity as isBuildKiteAvailable,
|
||||
} from '@roadiehq/backstage-plugin-buildkite';
|
||||
|
||||
const CICDSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
export const CICDSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
// This component is just an example of how you can implement your company's logic in entity page.
|
||||
// You can for example enforce that all components of type 'service' should use GitHubActions
|
||||
switch (true) {
|
||||
case isJenkinsAvailable(entity):
|
||||
return <JenkinsRouter entity={entity} />;
|
||||
case isBuildKiteAvailable(entity):
|
||||
return <BuildKiteRouter entity={entity} />;
|
||||
case isGitHubActionsAvailable(entity):
|
||||
return <GitHubActionsRouter entity={entity} />;
|
||||
case isCircleCIAvailable(entity):
|
||||
@@ -109,10 +114,12 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
let content: ReactNode;
|
||||
switch (true) {
|
||||
case isJenkinsAvailable(entity):
|
||||
content = <JenkinsLatestRunCard branch="master" />;
|
||||
content = <JenkinsLatestRunCard branch="master" variant="gridItem" />;
|
||||
break;
|
||||
case isGitHubActionsAvailable(entity):
|
||||
content = <RecentWorkflowRunsCard entity={entity} />;
|
||||
content = (
|
||||
<RecentWorkflowRunsCard entity={entity} limit={4} variant="gridItem" />
|
||||
);
|
||||
break;
|
||||
case isTravisCIAvailable(entity):
|
||||
content = <RecentTravisCIBuildsWidget entity={entity} />;
|
||||
@@ -131,9 +138,9 @@ const RecentCICDRunsSwitcher = ({ entity }: { entity: Entity }) => {
|
||||
};
|
||||
|
||||
const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
<Grid container spacing={3}>
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
<AboutCard entity={entity} />
|
||||
<AboutCard entity={entity} variant="gridItem" />
|
||||
</Grid>
|
||||
{isPagerDutyAvailable(entity) && (
|
||||
<Grid item md={6}>
|
||||
@@ -154,7 +161,7 @@ const OverviewContent = ({ entity }: { entity: Entity }) => (
|
||||
)}
|
||||
{isLighthouseAvailable(entity) && (
|
||||
<Grid item sm={4}>
|
||||
<LastLighthouseAuditCard />
|
||||
<LastLighthouseAuditCard variant="gridItem" />
|
||||
</Grid>
|
||||
)}
|
||||
{isPullRequestsAvailable(entity) && (
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
githubAuthApiRef,
|
||||
samlAuthApiRef,
|
||||
microsoftAuthApiRef,
|
||||
oneloginAuthApiRef,
|
||||
} from '@backstage/core';
|
||||
|
||||
export const providers = [
|
||||
@@ -60,4 +61,10 @@ export const providers = [
|
||||
message: 'Sign In using SAML',
|
||||
apiRef: samlAuthApiRef,
|
||||
},
|
||||
{
|
||||
id: 'onelogin-auth-provider',
|
||||
title: 'OneLogin',
|
||||
message: 'Sign In using OneLogin',
|
||||
apiRef: oneloginAuthApiRef,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -39,3 +39,4 @@ export { plugin as CostInsights } from '@backstage/plugin-cost-insights';
|
||||
export { plugin as GitHubInsights } from '@roadiehq/backstage-plugin-github-insights';
|
||||
export { plugin as UserSettings } from '@backstage/plugin-user-settings';
|
||||
export { plugin as Pagerduty } from '@backstage/plugin-pagerduty';
|
||||
export { plugin as BuildKite } from '@roadiehq/backstage-plugin-buildkite';
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* eslint-disable no-restricted-imports */
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import regression, { DataPoint } from 'regression';
|
||||
import {
|
||||
Alert,
|
||||
ChangeStatistic,
|
||||
Cost,
|
||||
CostInsightsApi,
|
||||
DateAggregation,
|
||||
Duration,
|
||||
exclusiveEndDateOf,
|
||||
Group,
|
||||
inclusiveStartDateOf,
|
||||
Maybe,
|
||||
MetricData,
|
||||
ProductCost,
|
||||
Project,
|
||||
ProjectGrowthAlert,
|
||||
ProjectGrowthData,
|
||||
Trendline,
|
||||
UnlabeledDataflowAlert,
|
||||
UnlabeledDataflowData,
|
||||
} from '@backstage/plugin-cost-insights';
|
||||
|
||||
function durationOf(intervals: string): Duration {
|
||||
const match = intervals.match(/\/(?<duration>P\d+[DM])\//);
|
||||
const { duration } = match!.groups!;
|
||||
return duration as Duration;
|
||||
}
|
||||
|
||||
function aggregationFor(
|
||||
duration: Duration,
|
||||
baseline: number,
|
||||
): DateAggregation[] {
|
||||
const days = dayjs(exclusiveEndDateOf(duration)).diff(
|
||||
inclusiveStartDateOf(duration),
|
||||
'day',
|
||||
);
|
||||
|
||||
return [...Array(days).keys()].reduce(
|
||||
(values: DateAggregation[], i: number): DateAggregation[] => {
|
||||
const last = values.length ? values[values.length - 1].amount : baseline;
|
||||
values.push({
|
||||
date: dayjs(inclusiveStartDateOf(duration))
|
||||
.add(i, 'day')
|
||||
.format('YYYY-MM-DD'),
|
||||
amount: last + (baseline / 20) * (Math.random() * 2 - 1),
|
||||
});
|
||||
return values;
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
function trendlineOf(aggregation: DateAggregation[]): Trendline {
|
||||
const data: ReadonlyArray<DataPoint> = aggregation.map(a => [
|
||||
Date.parse(a.date) / 1000,
|
||||
a.amount,
|
||||
]);
|
||||
const result = regression.linear(data, { precision: 5 });
|
||||
return {
|
||||
slope: result.equation[0],
|
||||
intercept: result.equation[1],
|
||||
};
|
||||
}
|
||||
|
||||
function changeOf(aggregation: DateAggregation[]): ChangeStatistic {
|
||||
const half = Math.ceil(aggregation.length / 2);
|
||||
const before = aggregation
|
||||
.slice(0, half)
|
||||
.reduce((sum, a) => sum + a.amount, 0);
|
||||
const after = aggregation
|
||||
.slice(half, aggregation.length)
|
||||
.reduce((sum, a) => sum + a.amount, 0);
|
||||
return {
|
||||
ratio: (after - before) / before,
|
||||
amount: after - before,
|
||||
};
|
||||
}
|
||||
|
||||
export class ExampleCostInsightsClient implements CostInsightsApi {
|
||||
private request(_: any, res: any): Promise<any> {
|
||||
return new Promise(resolve => setTimeout(resolve, 0, res));
|
||||
}
|
||||
|
||||
async getUserGroups(userId: string): Promise<Group[]> {
|
||||
const groups: Group[] = await this.request({ userId }, [
|
||||
{ id: 'pied-piper' },
|
||||
]);
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
async getGroupProjects(group: string): Promise<Project[]> {
|
||||
const projects: Project[] = await this.request({ group }, [
|
||||
{ id: 'project-a' },
|
||||
{ id: 'project-b' },
|
||||
{ id: 'project-c' },
|
||||
]);
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
async getDailyMetricData(
|
||||
metric: string,
|
||||
intervals: string,
|
||||
): Promise<MetricData> {
|
||||
const aggregation = aggregationFor(
|
||||
durationOf(intervals),
|
||||
100_000,
|
||||
).map(entry => ({ ...entry, amount: Math.round(entry.amount) }));
|
||||
|
||||
const cost: MetricData = await this.request(
|
||||
{ metric, intervals },
|
||||
{
|
||||
format: 'number',
|
||||
aggregation: aggregation,
|
||||
change: changeOf(aggregation),
|
||||
trendline: trendlineOf(aggregation),
|
||||
},
|
||||
);
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
async getGroupDailyCost(group: string, intervals: string): Promise<Cost> {
|
||||
const aggregation = aggregationFor(durationOf(intervals), 8_000);
|
||||
const groupDailyCost: Cost = await this.request(
|
||||
{ group, intervals },
|
||||
{
|
||||
aggregation: aggregation,
|
||||
change: changeOf(aggregation),
|
||||
trendline: trendlineOf(aggregation),
|
||||
},
|
||||
);
|
||||
|
||||
return groupDailyCost;
|
||||
}
|
||||
|
||||
async getProjectDailyCost(project: string, intervals: string): Promise<Cost> {
|
||||
const aggregation = aggregationFor(durationOf(intervals), 1_500);
|
||||
const projectDailyCost: Cost = await this.request(
|
||||
{ project, intervals },
|
||||
{
|
||||
id: 'project-a',
|
||||
aggregation: aggregation,
|
||||
change: changeOf(aggregation),
|
||||
trendline: trendlineOf(aggregation),
|
||||
},
|
||||
);
|
||||
|
||||
return projectDailyCost;
|
||||
}
|
||||
|
||||
async getProductInsights(
|
||||
product: string,
|
||||
group: string,
|
||||
duration: Duration,
|
||||
project: Maybe<string>,
|
||||
): Promise<ProductCost> {
|
||||
const projectProductInsights = await this.request(
|
||||
{ product, group, duration, project },
|
||||
{
|
||||
aggregation: [80_000, 110_000],
|
||||
change: {
|
||||
ratio: 0.375,
|
||||
amount: 30_000,
|
||||
},
|
||||
entities: [
|
||||
{
|
||||
id: null, // entities with null ids will be appear as "Unlabeled" in product panels
|
||||
aggregation: [45_000, 50_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-a',
|
||||
aggregation: [15_000, 20_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-b',
|
||||
aggregation: [20_000, 30_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-e',
|
||||
aggregation: [0, 10_000],
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
const productInsights: ProductCost = await this.request(
|
||||
{ product, group, duration, project },
|
||||
{
|
||||
aggregation: [200_000, 250_000],
|
||||
change: {
|
||||
ratio: 0.2,
|
||||
amount: 50_000,
|
||||
},
|
||||
entities: [
|
||||
{
|
||||
id: null, // entities with null ids will be appear as "Unlabeled" in product panels
|
||||
aggregation: [15_000, 30_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-a',
|
||||
aggregation: [15_000, 20_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-b',
|
||||
aggregation: [20_000, 30_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-c',
|
||||
aggregation: [18_000, 25_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-d',
|
||||
aggregation: [36_000, 42_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-e',
|
||||
aggregation: [0, 10_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-f',
|
||||
aggregation: [17_000, 19_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-g',
|
||||
aggregation: [49_000, 30_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-h',
|
||||
aggregation: [0, 34_000],
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
return project ? projectProductInsights : productInsights;
|
||||
}
|
||||
|
||||
async getAlerts(group: string): Promise<Alert[]> {
|
||||
const projectGrowthData: ProjectGrowthData = {
|
||||
project: 'example-project',
|
||||
periodStart: 'Q2 2020',
|
||||
periodEnd: 'Q3 2020',
|
||||
aggregation: [60_000, 120_000],
|
||||
change: {
|
||||
ratio: 1,
|
||||
amount: 60000,
|
||||
},
|
||||
products: [
|
||||
{ id: 'Compute Engine', aggregation: [58_000, 118_000] },
|
||||
{ id: 'Cloud Dataflow', aggregation: [1200, 1500] },
|
||||
{ id: 'Cloud Storage', aggregation: [800, 500] },
|
||||
],
|
||||
};
|
||||
|
||||
const unlabeledDataflowData: UnlabeledDataflowData = {
|
||||
periodStart: '2020-09-01',
|
||||
periodEnd: '2020-09-30',
|
||||
labeledCost: 6_200,
|
||||
unlabeledCost: 7_000,
|
||||
projects: [
|
||||
{
|
||||
id: 'example-project-1',
|
||||
unlabeledCost: 5_000,
|
||||
labeledCost: 3_000,
|
||||
},
|
||||
{
|
||||
id: 'example-project-2',
|
||||
unlabeledCost: 2_000,
|
||||
labeledCost: 3_200,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const alerts: Alert[] = await this.request({ group }, [
|
||||
new ProjectGrowthAlert(projectGrowthData),
|
||||
new UnlabeledDataflowAlert(unlabeledDataflowData),
|
||||
]);
|
||||
|
||||
return alerts;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ExampleCostInsightsClient } from './ExampleCostInsightsClient';
|
||||
Reference in New Issue
Block a user