Added api for adr plugin
Switched to using an AdrApi and removed the fetchers for adr reading. Signed-off-by: Robert Bunning <rbunning@webstaurantstore.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2022 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 { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { AdrApi, AdrListResult, AdrReadResult } from './types';
|
||||
|
||||
/**
|
||||
* Options for creating an AdrClient.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface AdrClientOptions {
|
||||
discoveryApi: DiscoveryApi;
|
||||
}
|
||||
|
||||
const readEndpoint = 'file';
|
||||
const listEndpoint = 'list';
|
||||
|
||||
/**
|
||||
* An implementation of the AdrApi that communicates with the ADR backend plugin.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export class AdrClient implements AdrApi {
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
|
||||
constructor(options: AdrClientOptions) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
}
|
||||
|
||||
private async fetchAdrApi<T>(endpoint: string, fileUrl: string): Promise<T> {
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl('adr');
|
||||
const targetUrl = `${baseUrl}/${endpoint}?url=${encodeURIComponent(
|
||||
fileUrl,
|
||||
)}`;
|
||||
|
||||
const result = await fetch(targetUrl);
|
||||
const data = await result.json();
|
||||
|
||||
if (!result.ok) {
|
||||
throw new Error(data.error.message);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async listAdrs(url: string): Promise<AdrListResult> {
|
||||
return this.fetchAdrApi<AdrListResult>(listEndpoint, url);
|
||||
}
|
||||
|
||||
async readAdr(url: string): Promise<AdrReadResult> {
|
||||
return this.fetchAdrApi<AdrReadResult>(readEndpoint, url);
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export * from './useOctokitRequest';
|
||||
|
||||
export { AdrClient } from './AdrClient';
|
||||
export type { AdrClientOptions } from './AdrClient';
|
||||
export { adrApiRef } from './types';
|
||||
export type {
|
||||
AdrApi,
|
||||
AdrFileInfo,
|
||||
AdrListResult,
|
||||
AdrReadResult,
|
||||
} from './types';
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2022 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 } from '@backstage/core-plugin-api';
|
||||
|
||||
/**
|
||||
* Contains information about an ADR file.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AdrFileInfo = {
|
||||
/** The file type. */
|
||||
type: string;
|
||||
|
||||
/** The relative path of the ADR file. */
|
||||
path: string;
|
||||
|
||||
/** The name of the ADR file. */
|
||||
name: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The result of listing ADRs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AdrListResult = {
|
||||
data: AdrFileInfo[];
|
||||
};
|
||||
|
||||
/**
|
||||
* The result of reading an ADR.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AdrReadResult = {
|
||||
/** The contents of the read ADR file. */
|
||||
data: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The API used by the adr plugin to list and read ADRs.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface AdrApi {
|
||||
/** Lists the ADRs at the provided url. */
|
||||
listAdrs(url: string): Promise<AdrListResult>;
|
||||
|
||||
/** Reads the contents of the ADR at the provided url. */
|
||||
readAdr(url: string): Promise<AdrReadResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* ApiRef for the AdrApi.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const adrApiRef = createApiRef<AdrApi>({
|
||||
id: 'plugin.adr.api',
|
||||
});
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React from 'react';
|
||||
import { EntityLayout } from '@backstage/plugin-catalog';
|
||||
import { Entity, ANNOTATION_SOURCE_LOCATION } from '@backstage/catalog-model';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import {
|
||||
EntityProvider,
|
||||
catalogApiRef,
|
||||
starredEntitiesApiRef,
|
||||
MockStarredEntitiesApi,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import { permissionApiRef } from '@backstage/plugin-permission-react';
|
||||
import {
|
||||
renderInTestApp,
|
||||
TestApiRegistry,
|
||||
MockPermissionApi,
|
||||
} from '@backstage/test-utils';
|
||||
import { AdrReader } from './AdrReader';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { ANNOTATION_ADR_LOCATION } from '@backstage/plugin-adr-common';
|
||||
import {
|
||||
octokitAdrFileFetcher,
|
||||
urlReaderAdrFileFetcher,
|
||||
} from '../../hooks/adrFileFetcher';
|
||||
|
||||
const mockApis = TestApiRegistry.from(
|
||||
[catalogApiRef, {} as CatalogApi],
|
||||
[starredEntitiesApiRef, new MockStarredEntitiesApi()],
|
||||
[permissionApiRef, new MockPermissionApi()],
|
||||
[
|
||||
scmIntegrationsApiRef,
|
||||
{
|
||||
resolveUrl: options => `${options.url}`,
|
||||
} as ScmIntegrationRegistry,
|
||||
],
|
||||
);
|
||||
|
||||
const mockEntity: Entity = {
|
||||
kind: 'TestEntity',
|
||||
metadata: {
|
||||
name: 'Testing Entity 1',
|
||||
annotations: {
|
||||
[ANNOTATION_ADR_LOCATION]: 'testAdrFolder',
|
||||
[ANNOTATION_SOURCE_LOCATION]: 'source:location',
|
||||
},
|
||||
},
|
||||
apiVersion: '',
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('AdrReader', () => {
|
||||
it('Falls back to octokitAdrFileFetcher when adrFileFetcher is not specified', async () => {
|
||||
const spyInstance = jest
|
||||
.spyOn(octokitAdrFileFetcher, 'useReadAdrFileAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return { data: '' };
|
||||
});
|
||||
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="tabbed-test-title">
|
||||
<AdrReader adr="testadr.md" />
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
</EntityProvider>
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(spyInstance).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Uses an alternative AdrFileFetcher when provided', async () => {
|
||||
const octokitSpyInstance = jest
|
||||
.spyOn(octokitAdrFileFetcher, 'useReadAdrFileAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
data: '',
|
||||
};
|
||||
});
|
||||
|
||||
const urlReadersSpyInstance = jest
|
||||
.spyOn(urlReaderAdrFileFetcher, 'useReadAdrFileAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
data: '',
|
||||
};
|
||||
});
|
||||
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="tabbed-test-title">
|
||||
<AdrReader
|
||||
adr="testadr.md"
|
||||
adrFileFetcher={urlReaderAdrFileFetcher}
|
||||
/>
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
</EntityProvider>
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(octokitSpyInstance).not.toHaveBeenCalled();
|
||||
expect(urlReadersSpyInstance).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -28,10 +28,8 @@ import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
|
||||
import { adrDecoratorFactories } from './decorators';
|
||||
import { AdrContentDecorator } from './types';
|
||||
import {
|
||||
AdrFileFetcher,
|
||||
octokitAdrFileFetcher,
|
||||
} from '../../hooks/adrFileFetcher';
|
||||
import { adrApiRef } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
/**
|
||||
* Component to fetch and render an ADR.
|
||||
@@ -41,16 +39,17 @@ import {
|
||||
export const AdrReader = (props: {
|
||||
adr: string;
|
||||
decorators?: AdrContentDecorator[];
|
||||
adrFileFetcher?: AdrFileFetcher;
|
||||
}) => {
|
||||
const { adr, decorators, adrFileFetcher } = props;
|
||||
const { adr, decorators } = props;
|
||||
const { entity } = useEntity();
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
const adrApi = useApi(adrApiRef);
|
||||
const adrLocationUrl = getAdrLocationUrl(entity, scmIntegrations);
|
||||
|
||||
const targetAdrFileFetcher = adrFileFetcher ?? octokitAdrFileFetcher;
|
||||
const { value, loading, error } = targetAdrFileFetcher.useReadAdrFileAtUrl(
|
||||
`${adrLocationUrl.replace(/\/$/, '')}/${adr}`,
|
||||
const url = `${adrLocationUrl.replace(/\/$/, '')}/${adr}`;
|
||||
const { value, loading, error } = useAsync(
|
||||
async () => adrApi.readAdr(url),
|
||||
[url],
|
||||
);
|
||||
|
||||
const adrContent = useMemo(() => {
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 React from 'react';
|
||||
import { EntityLayout } from '@backstage/plugin-catalog';
|
||||
import { Entity, ANNOTATION_SOURCE_LOCATION } from '@backstage/catalog-model';
|
||||
import { ApiProvider } from '@backstage/core-app-api';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import {
|
||||
EntityProvider,
|
||||
catalogApiRef,
|
||||
starredEntitiesApiRef,
|
||||
MockStarredEntitiesApi,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { scmIntegrationsApiRef } from '@backstage/integration-react';
|
||||
import { permissionApiRef } from '@backstage/plugin-permission-react';
|
||||
import {
|
||||
renderInTestApp,
|
||||
TestApiRegistry,
|
||||
MockPermissionApi,
|
||||
} from '@backstage/test-utils';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { ANNOTATION_ADR_LOCATION } from '@backstage/plugin-adr-common';
|
||||
import {
|
||||
octokitAdrFileFetcher,
|
||||
urlReaderAdrFileFetcher,
|
||||
} from '../../hooks/adrFileFetcher';
|
||||
import { EntityAdrContent } from './EntityAdrContent';
|
||||
import { rootRouteRef } from '../../routes';
|
||||
|
||||
const mockApis = TestApiRegistry.from(
|
||||
[catalogApiRef, {} as CatalogApi],
|
||||
[starredEntitiesApiRef, new MockStarredEntitiesApi()],
|
||||
[permissionApiRef, new MockPermissionApi()],
|
||||
[
|
||||
scmIntegrationsApiRef,
|
||||
{
|
||||
resolveUrl: options => `${options.url}`,
|
||||
} as ScmIntegrationRegistry,
|
||||
],
|
||||
);
|
||||
|
||||
const mockEntity: Entity = {
|
||||
kind: 'TestEntity',
|
||||
metadata: {
|
||||
name: 'Testing Entity 1',
|
||||
annotations: {
|
||||
[ANNOTATION_ADR_LOCATION]: 'testAdrFolder',
|
||||
[ANNOTATION_SOURCE_LOCATION]: 'source:location',
|
||||
},
|
||||
},
|
||||
apiVersion: '',
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('EntityAdrContent', () => {
|
||||
it('Falls back to octokitAdrFileFetcher when adrFileFetcher is not specified', async () => {
|
||||
const getAdrFilesSpyInstance = jest
|
||||
.spyOn(octokitAdrFileFetcher, 'useGetAdrFilesAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="tabbed-test-title">
|
||||
<EntityAdrContent />
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
</EntityProvider>
|
||||
</ApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/adr': rootRouteRef,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(getAdrFilesSpyInstance).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Uses an alternative AdrFileFetcher when provided', async () => {
|
||||
const octokitGetAdrFilesSpyInstance = jest
|
||||
.spyOn(octokitAdrFileFetcher, 'useGetAdrFilesAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
|
||||
const urlReadersGetAdrFilesSpyInstance = jest
|
||||
.spyOn(urlReaderAdrFileFetcher, 'useGetAdrFilesAtUrl')
|
||||
.mockImplementation(() => {
|
||||
return {
|
||||
data: [],
|
||||
};
|
||||
});
|
||||
|
||||
await renderInTestApp(
|
||||
<ApiProvider apis={mockApis}>
|
||||
<EntityProvider entity={mockEntity}>
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="tabbed-test-title">
|
||||
<EntityAdrContent adrFileFetcher={urlReaderAdrFileFetcher} />
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
</EntityProvider>
|
||||
</ApiProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/adr': rootRouteRef,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(octokitGetAdrFilesSpyInstance).not.toHaveBeenCalled();
|
||||
expect(urlReadersGetAdrFilesSpyInstance).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -46,10 +46,8 @@ import {
|
||||
|
||||
import { rootRouteRef } from '../../routes';
|
||||
import { AdrContentDecorator, AdrReader } from '../AdrReader';
|
||||
import {
|
||||
AdrFileFetcher,
|
||||
octokitAdrFileFetcher,
|
||||
} from '../../hooks/adrFileFetcher';
|
||||
import { adrApiRef } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
adrMenu: {
|
||||
@@ -64,20 +62,21 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||
export const EntityAdrContent = (props: {
|
||||
contentDecorators?: AdrContentDecorator[];
|
||||
filePathFilterFn?: AdrFilePathFilterFn;
|
||||
adrFileFetcher?: AdrFileFetcher;
|
||||
}) => {
|
||||
const { contentDecorators, filePathFilterFn, adrFileFetcher } = props;
|
||||
const { contentDecorators, filePathFilterFn } = props;
|
||||
const classes = useStyles();
|
||||
const { entity } = useEntity();
|
||||
const rootLink = useRouteRef(rootRouteRef);
|
||||
const [adrList, setAdrList] = useState<string[]>([]);
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
const adrApi = useApi(adrApiRef);
|
||||
const entityHasAdrs = isAdrAvailable(entity);
|
||||
|
||||
const targetAdrFileFetcher = adrFileFetcher ?? octokitAdrFileFetcher;
|
||||
const { value, loading, error } = targetAdrFileFetcher.useGetAdrFilesAtUrl(
|
||||
getAdrLocationUrl(entity, scmIntegrations),
|
||||
const url = getAdrLocationUrl(entity, scmIntegrations);
|
||||
const { value, loading, error } = useAsync(
|
||||
async () => adrApi.listAdrs(url),
|
||||
[url],
|
||||
);
|
||||
|
||||
const selectedAdr =
|
||||
@@ -147,11 +146,7 @@ export const EntityAdrContent = (props: {
|
||||
</List>
|
||||
</Grid>
|
||||
<Grid item xs={9}>
|
||||
<AdrReader
|
||||
adr={selectedAdr}
|
||||
adrFileFetcher={targetAdrFileFetcher}
|
||||
decorators={contentDecorators}
|
||||
/>
|
||||
<AdrReader adr={selectedAdr} decorators={contentDecorators} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
) : (
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 {
|
||||
discoveryApiRef,
|
||||
useApi,
|
||||
DiscoveryApi,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { useOctokitRequest } from './useOctokitRequest';
|
||||
|
||||
const useAdrApi = (
|
||||
endpoint: string,
|
||||
fileUrl: string,
|
||||
discoveryApi: DiscoveryApi,
|
||||
) => {
|
||||
return async () => {
|
||||
const baseUrl = await discoveryApi.getBaseUrl('adr');
|
||||
const targetUrl = `${baseUrl}/${endpoint}?url=${encodeURIComponent(
|
||||
fileUrl,
|
||||
)}`;
|
||||
|
||||
const result = await fetch(targetUrl);
|
||||
const data = await result.json();
|
||||
|
||||
if (!result.ok) {
|
||||
throw data;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents something that is capable of fetching a listing of adr files at a provided url
|
||||
* and fetching the contents of an adr file at a provided url.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface AdrFileFetcher {
|
||||
/**
|
||||
* A hook to get a listing of adr files that exist at the provided url
|
||||
*
|
||||
* @param url - The url to get files from
|
||||
*/
|
||||
useGetAdrFilesAtUrl: (url: string) => any;
|
||||
|
||||
/**
|
||||
* A hook to get the contents of the adr file at the provided url
|
||||
*
|
||||
* @param url - The url of the adr file
|
||||
*/
|
||||
useReadAdrFileAtUrl: (url: string) => any;
|
||||
}
|
||||
|
||||
const getAdrFilesEndpoint = 'list';
|
||||
const readAdrFileEndpoint = 'file';
|
||||
|
||||
/**
|
||||
* An AdrFileFetcher that uses UrlReaders to fetch adr files
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const urlReaderAdrFileFetcher: AdrFileFetcher = {
|
||||
useGetAdrFilesAtUrl(url: string) {
|
||||
const discoveryApi = useApi(discoveryApiRef);
|
||||
return useAsync<any>(useAdrApi(getAdrFilesEndpoint, url, discoveryApi), [
|
||||
url,
|
||||
]);
|
||||
},
|
||||
useReadAdrFileAtUrl(url: string) {
|
||||
const discoveryApi = useApi(discoveryApiRef);
|
||||
return useAsync<any>(useAdrApi(readAdrFileEndpoint, url, discoveryApi), [
|
||||
url,
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* An AdrFileFetcher that uses the useOctokitRequest hook for fetching adr files
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const octokitAdrFileFetcher: AdrFileFetcher = {
|
||||
useGetAdrFilesAtUrl: (url: string) => useOctokitRequest(url),
|
||||
useReadAdrFileAtUrl: (url: string) => useOctokitRequest(url),
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 parseGitUrl from 'git-url-parse';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { Octokit } from 'octokit';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
scmAuthApiRef,
|
||||
scmIntegrationsApiRef,
|
||||
} from '@backstage/integration-react';
|
||||
|
||||
/**
|
||||
* Hook for triggering authenticated Octokit requests against the GitHub Content API
|
||||
* @public
|
||||
*/
|
||||
export const useOctokitRequest = (request: string): any => {
|
||||
const authApi = useApi(scmAuthApiRef);
|
||||
const scmIntegrations = useApi(scmIntegrationsApiRef);
|
||||
|
||||
const { owner, name, ref, filepath } = parseGitUrl(request);
|
||||
const path = filepath.replace(/^\//, '');
|
||||
const baseUrl = scmIntegrations.github.byUrl(request)?.config.apiBaseUrl;
|
||||
|
||||
return useAsync<any>(async () => {
|
||||
const { token } = await authApi.getCredentials({
|
||||
url: request,
|
||||
additionalScope: {
|
||||
customScopes: {
|
||||
github: ['repo'],
|
||||
},
|
||||
},
|
||||
});
|
||||
const octokit = new Octokit({
|
||||
auth: token,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
return octokit.request(
|
||||
`GET /repos/${owner}/${name}/contents/${path}?ref=${ref}`,
|
||||
{
|
||||
headers: { Accept: 'application/vnd.github.v3.raw' },
|
||||
},
|
||||
);
|
||||
}, [request]);
|
||||
};
|
||||
@@ -13,13 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ADR frontend plugin
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export { adrApiRef, AdrClient } from './api';
|
||||
export { isAdrAvailable } from '@backstage/plugin-adr-common';
|
||||
export * from './components/AdrReader';
|
||||
export { adrPlugin, EntityAdrContent } from './plugin';
|
||||
export * from './search';
|
||||
export * from './hooks/adrFileFetcher';
|
||||
|
||||
@@ -14,11 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { adrApiRef, AdrClient } from './api';
|
||||
import {
|
||||
createApiFactory,
|
||||
createPlugin,
|
||||
createRoutableExtension,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
/**
|
||||
@@ -27,6 +29,17 @@ import { rootRouteRef } from './routes';
|
||||
*/
|
||||
export const adrPlugin = createPlugin({
|
||||
id: 'adr',
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: adrApiRef,
|
||||
deps: {
|
||||
discoveryApi: discoveryApiRef,
|
||||
},
|
||||
factory({ discoveryApi }) {
|
||||
return new AdrClient({ discoveryApi });
|
||||
},
|
||||
}),
|
||||
],
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user