catalog,register-component: always register locations using a 'url' type

This commit is contained in:
Patrik Oldsberg
2020-10-28 14:37:21 +01:00
parent b89c676dbc
commit 8b9c8196f1
9 changed files with 39 additions and 55 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog': minor
'@backstage/plugin-register-component': patch
---
Locations registered through the catalog client now default to the 'url' type. The type selection dropdown in the register-component form has been removed.
+10 -2
View File
@@ -19,7 +19,12 @@ import {
Location,
LOCATION_ANNOTATION,
} from '@backstage/catalog-model';
import { CatalogApi, EntityCompoundName } from './types';
import {
AddLocationRequest,
AddLocationResponse,
CatalogApi,
EntityCompoundName,
} from './types';
import { DiscoveryApi } from '@backstage/core';
export class CatalogClient implements CatalogApi {
@@ -87,7 +92,10 @@ export class CatalogClient implements CatalogApi {
return this.getOptional(`/entities/by-name/${kind}/${namespace}/${name}`);
}
async addLocation(type: string, target: string) {
async addLocation({
type = 'url',
target,
}: AddLocationRequest): Promise<AddLocationResponse> {
const response = await fetch(
`${await this.discoveryApi.getBaseUrl('catalog')}/locations`,
{
+6 -1
View File
@@ -35,11 +35,16 @@ export interface CatalogApi {
compoundName: EntityCompoundName,
): Promise<Entity | undefined>;
getEntities(filter?: Record<string, string | string[]>): Promise<Entity[]>;
addLocation(type: string, target: string): Promise<AddLocationResponse>;
addLocation(location: AddLocationRequest): Promise<AddLocationResponse>;
getLocationByEntity(entity: Entity): Promise<Location | undefined>;
removeEntityByUid(uid: string): Promise<void>;
}
export type AddLocationRequest = {
type?: string;
target: string;
};
export type AddLocationResponse = {
location: Location;
entities: Entity[];
@@ -76,7 +76,7 @@ const CatalogPageContents = () => {
const root = configApi.getConfig('catalog.exampleEntityLocations');
for (const type of root.keys()) {
for (const target of root.getStringArray(type)) {
promises.push(catalogApi.addLocation(type, target));
promises.push(catalogApi.addLocation({ target }));
}
}
await Promise.all(promises);
@@ -30,7 +30,7 @@ describe('useEntityFilterGroup', () => {
beforeEach(() => {
catalogApi = {
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
addLocation: jest.fn((_a, _b) => new Promise(() => {})),
addLocation: jest.fn(_a => new Promise(() => {})),
getEntities: jest.fn(),
getLocationByEntity: jest.fn(),
getLocationById: jest.fn(),
@@ -19,15 +19,12 @@ import {
Button,
FormControl,
FormHelperText,
InputLabel,
LinearProgress,
MenuItem,
Select,
TextField,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { ComponentIdValidators } from '../../util/validate';
const useStyles = makeStyles<BackstageTheme>(theme => ({
@@ -50,11 +47,11 @@ export type Props = {
};
export const RegisterComponentForm = ({ onSubmit, submitting }: Props) => {
const { control, register, handleSubmit, errors, formState } = useForm({
const { register, handleSubmit, errors, formState } = useForm({
mode: 'onChange',
});
const classes = useStyles();
const hasErrors = !!errors.componentLocation;
const hasErrors = !!errors.entityLocation;
const dirty = formState?.isDirty;
return submitting ? (
@@ -71,10 +68,9 @@ export const RegisterComponentForm = ({ onSubmit, submitting }: Props) => {
id="registerComponentInput"
variant="outlined"
label="Entity file URL"
data-testid="componentLocationInput"
error={hasErrors}
placeholder="https://example.com/user/some-service/blob/master/catalog-info.yaml"
name="componentLocation"
name="entityLocation"
required
margin="normal"
helperText="Enter the full path to the catalog-info.yaml file in GitHub, GitLab, Bitbucket or Azure to start tracking your component."
@@ -84,36 +80,13 @@ export const RegisterComponentForm = ({ onSubmit, submitting }: Props) => {
})}
/>
{errors.componentLocation && (
{errors.entityLocation && (
<FormHelperText error={hasErrors} id="register-component-helper-text">
{errors.componentLocation.message}
{errors.entityLocation.message}
</FormHelperText>
)}
</FormControl>
<FormControl variant="outlined" className={classes.select}>
<InputLabel id="scmLabel">Host type</InputLabel>
<Controller
control={control}
name="scmType"
defaultValue="AUTO"
render={({ onChange, onBlur, value }) => (
<Select
labelId="scmLabel"
id="scmSelect"
label="scmLabel"
value={value}
onChange={onChange}
onBlur={onBlur}
>
<MenuItem value="AUTO">Auto-detect</MenuItem>
<MenuItem value="gitlab">GitLab</MenuItem>
<MenuItem value="bitbucket/api">Bitbucket</MenuItem>
<MenuItem value="azure/api">Azure</MenuItem>
</Select>
)}
/>
</FormControl>
<Button
variant="contained"
color="primary"
@@ -35,7 +35,7 @@ const errorApi: jest.Mocked<typeof errorApiRef.T> = {
const catalogApi: jest.Mocked<typeof catalogApiRef.T> = {
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
addLocation: jest.fn((_a, _b) => new Promise(() => {})),
addLocation: jest.fn(_a => new Promise(() => {})),
getEntities: jest.fn(),
getLocationByEntity: jest.fn(),
getLocationById: jest.fn(),
@@ -82,20 +82,9 @@ export const RegisterComponentPage = ({
const handleSubmit = async (formData: Record<string, string>) => {
setFormState(FormStates.Submitting);
const { scmType, componentLocation: target } = formData;
const { entityLocation: target } = formData;
try {
const typeMapping = [
{ url: /^https:\/\/gitlab\.com\/.*/, type: 'gitlab/api' },
{ url: /^https:\/\/bitbucket\.org\/.*/, type: 'bitbucket/api' },
{ url: /^https:\/\/dev\.azure\.com\/.*/, type: 'azure/api' },
{ url: /.*/, type: 'github' },
];
const type =
scmType === 'AUTO'
? typeMapping.filter(item => item.url.test(target))[0].type
: scmType;
const data = await catalogApi.addLocation(type, target);
const data = await catalogApi.addLocation({ target });
if (!isMounted()) return;
@@ -108,12 +108,15 @@ export const TemplatePage = () => {
);
const handleCreateComplete = async (job: Job) => {
const componentYaml = job.metadata.remoteUrl?.replace(
const target = job.metadata.remoteUrl?.replace(
/\.git$/,
// TODO(Rugvip): This is not the location we want. As part of scaffodler v2 we
// want this to be more flexible, but before that we might want
// to update all templates to use catalog-info.yaml instead.
'/blob/master/component-info.yaml',
);
if (!componentYaml) {
if (!target) {
errorApi.post(
new Error(
`Failed to find component-info.yaml file in ${job.metadata.remoteUrl}.`,
@@ -124,7 +127,7 @@ export const TemplatePage = () => {
const {
entities: [createdEntity],
} = await catalogApi.addLocation('github', componentYaml);
} = await catalogApi.addLocation({ target });
setEntity((createdEntity as any) as TemplateEntityV1alpha1);
};