minor improvements to the coverage backend
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-code-coverage-backend': patch
|
||||
---
|
||||
|
||||
`RouterOptions` now accepts an optional `catalogApi` argument, allowing custom catalog clients to be used. This is leveraged in the local standalone development runner to pass in a catalog client that returns fake data.
|
||||
@@ -209,7 +209,7 @@ describe('CodeCoverageUtils', () => {
|
||||
} catch (error: any) {
|
||||
err = error;
|
||||
}
|
||||
expect(err?.message).toEqual('Content-Type missing');
|
||||
expect(err?.message).toEqual('Content-Type header missing');
|
||||
});
|
||||
|
||||
it('rejects unsupported content type', () => {
|
||||
@@ -223,7 +223,9 @@ describe('CodeCoverageUtils', () => {
|
||||
} catch (error: any) {
|
||||
err = error;
|
||||
}
|
||||
expect(err?.message).toEqual('Illegal Content-Type');
|
||||
expect(err?.message).toEqual(
|
||||
'Content-Type header "application/json" not supported, expected "text/xml" possibly followed by a charset',
|
||||
);
|
||||
});
|
||||
|
||||
it('parses the body', () => {
|
||||
|
||||
@@ -162,9 +162,11 @@ export class CoverageUtils {
|
||||
validateRequestBody(req: Request) {
|
||||
const contentType = req.headers['content-type'];
|
||||
if (!contentType) {
|
||||
throw new InputError('Content-Type missing');
|
||||
throw new InputError('Content-Type header missing');
|
||||
} else if (!contentType.match(/^text\/xml($|;)/)) {
|
||||
throw new InputError('Illegal Content-Type');
|
||||
throw new InputError(
|
||||
`Content-Type header "${contentType}" not supported, expected "text/xml" possibly followed by a charset`,
|
||||
);
|
||||
}
|
||||
const body = req.body;
|
||||
if (!body) {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BranchHit, FileEntry } from '../types';
|
||||
import { JacocoSourceFile, JacocoXML } from './types';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface RouterOptions {
|
||||
database: PluginDatabaseManager;
|
||||
urlReader: UrlReader;
|
||||
logger: Logger;
|
||||
catalogApi?: CatalogApi;
|
||||
}
|
||||
|
||||
export interface CodeCoverageApi {
|
||||
@@ -59,7 +60,8 @@ export const makeRouter = async (
|
||||
|
||||
const codeCoverageDatabase = await CodeCoverageDatabase.create(database);
|
||||
const codecovUrl = await discovery.getExternalBaseUrl('code-coverage');
|
||||
const catalogApi: CatalogApi = new CatalogClient({ discoveryApi: discovery });
|
||||
const catalogApi =
|
||||
options.catalogApi ?? new CatalogClient({ discoveryApi: discovery });
|
||||
const scm = ScmIntegrations.fromConfig(config);
|
||||
|
||||
const router = Router();
|
||||
@@ -167,10 +169,10 @@ export const makeRouter = async (
|
||||
* /report?entity=component:default/mycomponent&coverageType=cobertura
|
||||
*/
|
||||
router.post('/report', async (req, res) => {
|
||||
const { entity, coverageType } = req.query;
|
||||
const entityLookup = await catalogApi.getEntityByRef(entity as string);
|
||||
if (!entityLookup) {
|
||||
throw new NotFoundError(`No entity found matching ${entity}`);
|
||||
const { entity: entityRef, coverageType } = req.query;
|
||||
const entity = await catalogApi.getEntityByRef(entityRef as string);
|
||||
if (!entity) {
|
||||
throw new NotFoundError(`No entity found matching ${entityRef}`);
|
||||
}
|
||||
|
||||
let converter: Converter;
|
||||
@@ -185,7 +187,7 @@ export const makeRouter = async (
|
||||
}
|
||||
|
||||
const { sourceLocation, vcs, scmFiles, body } =
|
||||
await utils.processCoveragePayload(entityLookup, req);
|
||||
await utils.processCoveragePayload(entity, req);
|
||||
|
||||
const files = converter.convert(body, scmFiles);
|
||||
if (!files || files.length === 0) {
|
||||
@@ -193,7 +195,7 @@ export const makeRouter = async (
|
||||
}
|
||||
|
||||
const coverage = await utils.buildCoverage(
|
||||
entityLookup,
|
||||
entity,
|
||||
sourceLocation,
|
||||
vcs,
|
||||
files,
|
||||
@@ -204,7 +206,7 @@ export const makeRouter = async (
|
||||
links: [
|
||||
{
|
||||
rel: 'coverage',
|
||||
href: `${codecovUrl}/report?entity=${entity}`,
|
||||
href: `${codecovUrl}/report?entity=${entityRef}`,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -21,6 +21,8 @@ import {
|
||||
UrlReaders,
|
||||
useHotMemoize,
|
||||
} from '@backstage/backend-common';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { CompoundEntityRef, parseEntityRef } from '@backstage/catalog-model';
|
||||
import { Server } from 'http';
|
||||
import knexFactory from 'knex';
|
||||
import { Logger } from 'winston';
|
||||
@@ -52,13 +54,27 @@ export async function startStandaloneServer(
|
||||
return knex;
|
||||
});
|
||||
|
||||
const catalogApi = {
|
||||
async getEntityByRef(entityRef: string | CompoundEntityRef) {
|
||||
const { kind, namespace, name } = parseEntityRef(entityRef);
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind,
|
||||
metadata: { name, namespace },
|
||||
spec: {},
|
||||
};
|
||||
},
|
||||
} as Partial<CatalogApi> as CatalogApi;
|
||||
|
||||
logger.debug('Starting application server...');
|
||||
|
||||
const router = await createRouter({
|
||||
database: { getClient: async () => db },
|
||||
config,
|
||||
discovery: SingleHostDiscovery.fromConfig(config),
|
||||
urlReader: UrlReaders.default({ logger, config }),
|
||||
logger,
|
||||
catalogApi,
|
||||
});
|
||||
|
||||
let service = createServiceBuilder(module)
|
||||
|
||||
Reference in New Issue
Block a user