Pretty most files

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>
This commit is contained in:
Jonathan Mezach
2023-02-15 14:05:13 +01:00
parent 318e1fa26b
commit 3a4e7fbb16
9 changed files with 279 additions and 116 deletions
+86 -61
View File
@@ -1,88 +1,113 @@
import { createApiRef, DiscoveryApi, IdentityApi } from "@backstage/core-plugin-api";
/*
* Copyright 2023 The Backstage Authors
*
* 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 {
createApiRef,
DiscoveryApi,
IdentityApi,
} from '@backstage/core-plugin-api';
export type OctopusProgression = {
Environments: OctopusEnvironment[];
Releases: OctopusReleaseProgression[];
}
Environments: OctopusEnvironment[];
Releases: OctopusReleaseProgression[];
};
export type OctopusEnvironment = {
Id: string,
Name: string
}
Id: string;
Name: string;
};
export type OctopusReleaseProgression = {
Release: OctopusRelease
Deployments: { [key: string]: OctopusDeployment[] }
}
Release: OctopusRelease;
Deployments: { [key: string]: OctopusDeployment[] };
};
export type OctopusRelease = {
Id: string
Version: string
}
Id: string;
Version: string;
};
export type OctopusDeployment = {
State: string
}
State: string;
};
export const octopusDeployApiRef = createApiRef<OctopusDeployApi>({
id: 'plugin.octopusdeploy.service'
id: 'plugin.octopusdeploy.service',
});
const DEFAULT_PROXY_PATH_BASE = '/octopus-deploy';
type Options = {
discoveryApi: DiscoveryApi;
identityApi: IdentityApi
/**
* Path to use for requests via the proxy, defaults to /octopus-deploy
*/
proxyPathBase?: string
}
discoveryApi: DiscoveryApi;
identityApi: IdentityApi;
/**
* Path to use for requests via the proxy, defaults to /octopus-deploy
*/
proxyPathBase?: string;
};
export interface OctopusDeployApi {
getReleaseProgression(projectId: string, releaseHistoryCount: number): Promise<OctopusProgression>;
getReleaseProgression(
projectId: string,
releaseHistoryCount: number,
): Promise<OctopusProgression>;
}
export class OctopusDeployClient implements OctopusDeployApi {
private readonly discoveryApi: DiscoveryApi;
private readonly identityApi: IdentityApi;
private readonly proxyPathBase: string;
private readonly discoveryApi: DiscoveryApi;
private readonly identityApi: IdentityApi;
private readonly proxyPathBase: string;
constructor(options: Options) {
this.discoveryApi = options.discoveryApi;
this.identityApi = options.identityApi;
this.proxyPathBase = options.proxyPathBase ?? DEFAULT_PROXY_PATH_BASE;
constructor(options: Options) {
this.discoveryApi = options.discoveryApi;
this.identityApi = options.identityApi;
this.proxyPathBase = options.proxyPathBase ?? DEFAULT_PROXY_PATH_BASE;
}
async getReleaseProgression(
projectId: string,
releaseHistoryCount: number,
): Promise<OctopusProgression> {
const url = await this.getApiUrl(projectId, releaseHistoryCount);
const { token: idToken } = await this.identityApi.getCredentials();
const response = await fetch(url, {
headers: idToken ? { Authorization: `Bearer ${idToken}` } : {},
});
let responseJson;
try {
responseJson = await response.json();
} catch (e) {
responseJson = { releases: [] };
}
async getReleaseProgression(projectId: string, releaseHistoryCount: number): Promise<OctopusProgression> {
const url = await this.getApiUrl(projectId, releaseHistoryCount);
const { token: idToken } = await this.identityApi.getCredentials();
const response = await fetch(url, {
headers: idToken ? { Authorization: `Bearer ${idToken}` } : {},
});
let responseJson;
try {
responseJson = await response.json();
} catch (e) {
responseJson = { releases: [] };
}
if (response.status !== 200) {
throw new Error(
`Error communicating with Octopus Deploy: ${
responseJson?.error?.title || response.statusText
}`,
);
}
return responseJson;
if (response.status !== 200) {
throw new Error(
`Error communicating with Octopus Deploy: ${
responseJson?.error?.title || response.statusText
}`,
);
}
private async getApiUrl(projectId: string, releaseHistoryCount: number) {
const proxyUrl = await this.discoveryApi.getBaseUrl('proxy');
return `${proxyUrl}${this.proxyPathBase}/projects/${projectId}/progression?releaseHistoryCount=${releaseHistoryCount}`;
}
}
return responseJson;
}
private async getApiUrl(projectId: string, releaseHistoryCount: number) {
const proxyUrl = await this.discoveryApi.getBaseUrl('proxy');
return `${proxyUrl}${this.proxyPathBase}/projects/${projectId}/progression?releaseHistoryCount=${releaseHistoryCount}`;
}
}
@@ -1,3 +1,18 @@
/*
* Copyright 2023 The Backstage Authors
*
* 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 { useEntity } from '@backstage/plugin-catalog-react';
import { useReleases } from '../../hooks/useReleases';
import { getAnnotationFromEntity } from '../../utils/getAnnotationFromEntity';
@@ -5,11 +20,21 @@ import React from 'react';
import { ReleaseTable } from '../ReleaseTable';
export const EntityPageOctopusDeploy = (props: { defaultLimit?: number }) => {
const { entity } = useEntity();
const { entity } = useEntity();
const projectId = getAnnotationFromEntity(entity);
const projectId = getAnnotationFromEntity(entity);
const { environments, releases, loading, error } = useReleases(projectId, props.defaultLimit ?? 3);
const { environments, releases, loading, error } = useReleases(
projectId,
props.defaultLimit ?? 3,
);
return <ReleaseTable environments={environments} releases={releases} loading={loading} error={error} />;
}
return (
<ReleaseTable
environments={environments}
releases={releases}
loading={loading}
error={error}
/>
);
};
@@ -1 +1,16 @@
export { EntityPageOctopusDeploy } from './EntityPageOctopusDeploy';
/*
* Copyright 2023 The Backstage Authors
*
* 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 { EntityPageOctopusDeploy } from './EntityPageOctopusDeploy';
@@ -1 +1,16 @@
export { ReleaseTable } from './ReleaseTable';
/*
* Copyright 2023 The Backstage Authors
*
* 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 { ReleaseTable } from './ReleaseTable';
+16 -1
View File
@@ -1 +1,16 @@
export const OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION = 'octopus.com/project-id';
/*
* Copyright 2023 The Backstage Authors
*
* 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 const OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION = 'octopus.com/project-id';
+40 -21
View File
@@ -1,26 +1,45 @@
import { useApi } from "@backstage/core-plugin-api";
import useAsync from "react-use/lib/useAsync";
import { octopusDeployApiRef, OctopusEnvironment, OctopusReleaseProgression } from "../api";
/*
* Copyright 2023 The Backstage Authors
*
* 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 { useApi } from '@backstage/core-plugin-api';
import useAsync from 'react-use/lib/useAsync';
import {
octopusDeployApiRef,
OctopusEnvironment,
OctopusReleaseProgression,
} from '../api';
export function useReleases(
projectId: string,
releaseHistoryCount: number
projectId: string,
releaseHistoryCount: number,
): {
environments?: OctopusEnvironment[],
releases?: OctopusReleaseProgression[]
loading: boolean;
error?: Error;
environments?: OctopusEnvironment[];
releases?: OctopusReleaseProgression[];
loading: boolean;
error?: Error;
} {
const api = useApi(octopusDeployApiRef);
const { value, loading, error } = useAsync(() => {
return api.getReleaseProgression(projectId, releaseHistoryCount);
}, [ api, projectId, releaseHistoryCount ]);
const api = useApi(octopusDeployApiRef);
return {
environments: value?.Environments,
releases: value?.Releases,
loading,
error
};
}
const { value, loading, error } = useAsync(() => {
return api.getReleaseProgression(projectId, releaseHistoryCount);
}, [api, projectId, releaseHistoryCount]);
return {
environments: value?.Environments,
releases: value?.Releases,
loading,
error,
};
}
+32 -14
View File
@@ -1,13 +1,30 @@
import {
OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION
} from './constants';
import {
octopusDeployEntityContentRouteRef
} from './routes';
/*
* Copyright 2023 The Backstage Authors
*
* 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 { OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION } from './constants';
import { octopusDeployEntityContentRouteRef } from './routes';
import { OctopusDeployClient, octopusDeployApiRef } from './api';
import { createApiFactory, createPlugin, createRoutableExtension, discoveryApiRef, identityApiRef } from '@backstage/core-plugin-api';
import {
createApiFactory,
createPlugin,
createRoutableExtension,
discoveryApiRef,
identityApiRef,
} from '@backstage/core-plugin-api';
import { Entity } from '@backstage/catalog-model';
@@ -21,9 +38,10 @@ export const octopusDeployPlugin = createPlugin({
createApiFactory({
api: octopusDeployApiRef,
deps: { discoveryApi: discoveryApiRef, identityApi: identityApiRef },
factory: ({ discoveryApi, identityApi }) => new OctopusDeployClient({ discoveryApi, identityApi })
})
]
factory: ({ discoveryApi, identityApi }) =>
new OctopusDeployClient({ discoveryApi, identityApi }),
}),
],
});
/*
@@ -42,8 +60,8 @@ export const EntityOctopusDeployContent = octopusDeployPlugin.provide(
name: 'EntityOctopusDeployContent',
component: () =>
import('./components/EntityPageOctopusDeploy').then(
m => m.EntityPageOctopusDeploy
m => m.EntityPageOctopusDeploy,
),
mountPoint: octopusDeployEntityContentRouteRef
})
)
mountPoint: octopusDeployEntityContentRouteRef,
}),
);
+17 -2
View File
@@ -1,5 +1,20 @@
/*
* Copyright 2023 The Backstage Authors
*
* 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 { createRouteRef } from '@backstage/core-plugin-api';
export const octopusDeployEntityContentRouteRef = createRouteRef({
id: 'octopus-deploy-entity-content'
})
id: 'octopus-deploy-entity-content',
});
@@ -1,14 +1,30 @@
import {
OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION
} from '../constants';
/*
* Copyright 2023 The Backstage Authors
*
* 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 { OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION } from '../constants';
import { Entity } from '@backstage/catalog-model';
export function getAnnotationFromEntity(entity: Entity): string {
const annotation = entity.metadata.annotations?.[OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION];
if (!annotation) {
throw new Error('Value for annotation octopus.com/project-id was not found');
}
return annotation;
}
const annotation =
entity.metadata.annotations?.[OCTOPUS_DEPLOY_PROJECT_ID_ANNOTATION];
if (!annotation) {
throw new Error(
'Value for annotation octopus.com/project-id was not found',
);
}
return annotation;
}