Merge pull request #25373 from VeithBuergerhoff/master

Fixed validation for RepoUrlPicker
This commit is contained in:
Ben Lambert
2024-06-25 09:54:01 +02:00
committed by GitHub
7 changed files with 106 additions and 21 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-scaffolder-backend-module-azure': patch
'@backstage/plugin-scaffolder-node': patch
'@backstage/plugin-scaffolder': patch
---
Fixed a bug where the `RepoUrlPicker` would still require the `owner` field for `azure`
@@ -29,7 +29,7 @@ export const examples: TemplateExample[] = [
name: 'Publish to Azure',
input: {
repoUrl:
'dev.azure.com?organization=organization&owner=project&repo=repo',
'dev.azure.com?organization=organization&project=project&repo=repo',
},
},
],
@@ -45,7 +45,7 @@ export const examples: TemplateExample[] = [
name: 'Publish to Azure',
input: {
repoUrl:
'dev.azure.com?organization=organization&owner=project&repo=repo',
'dev.azure.com?organization=organization&project=project&repo=repo',
description: 'Initialize a git repository',
},
},
@@ -63,7 +63,7 @@ export const examples: TemplateExample[] = [
name: 'Publish to Azure',
input: {
repoUrl:
'dev.azure.com?organization=organization&owner=project&repo=repo',
'dev.azure.com?organization=organization&project=project&repo=repo',
defaultBranch: 'main',
},
},
@@ -55,7 +55,9 @@ describe('publish:azure', () => {
const action = createPublishAzureAction({ integrations, config });
const mockContext = createMockActionContext({
input: { repoUrl: 'dev.azure.com?repo=repo&owner=owner&organization=org' },
input: {
repoUrl: 'dev.azure.com?repo=repo&project=project&organization=org',
},
});
const mockGitClient = {
@@ -77,19 +79,19 @@ describe('publish:azure', () => {
...mockContext,
input: { repoUrl: 'dev.azure.com?repo=bob' },
}),
).rejects.toThrow(/missing owner/);
).rejects.toThrow(/missing project/);
await expect(
action.handler({
...mockContext,
input: { repoUrl: 'dev.azure.com?owner=owner' },
input: { repoUrl: 'dev.azure.com?project=project' },
}),
).rejects.toThrow(/missing repo/);
await expect(
action.handler({
...mockContext,
input: { repoUrl: 'dev.azure.com?owner=owner&repo=repo' },
input: { repoUrl: 'dev.azure.com?project=project&repo=repo' },
}),
).rejects.toThrow(/missing organization/);
});
@@ -98,7 +100,9 @@ describe('publish:azure', () => {
await expect(
action.handler({
...mockContext,
input: { repoUrl: 'azure.com?repo=bob&owner=owner&organization=org' },
input: {
repoUrl: 'azure.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(/No matching integration configuration/);
});
@@ -109,7 +113,7 @@ describe('publish:azure', () => {
...mockContext,
input: {
repoUrl:
'myazurehostnotoken.com?repo=bob&owner=owner&organization=org',
'myazurehostnotoken.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(
@@ -122,7 +126,7 @@ describe('publish:azure', () => {
action.handler({
...mockContext,
input: {
repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org',
repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(/Unable to create the repository/);
@@ -138,7 +142,8 @@ describe('publish:azure', () => {
await action.handler({
...mockContext,
input: {
repoUrl: 'myazurehostnotoken.com?repo=bob&owner=owner&organization=org',
repoUrl:
'myazurehostnotoken.com?repo=bob&project=project&organization=org',
token: 'lols',
},
});
@@ -152,7 +157,7 @@ describe('publish:azure', () => {
{
name: 'bob',
},
'owner',
'project',
);
});
@@ -166,7 +171,7 @@ describe('publish:azure', () => {
action.handler({
...mockContext,
input: {
repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org',
repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(/No remote URL returned/);
@@ -182,7 +187,7 @@ describe('publish:azure', () => {
action.handler({
...mockContext,
input: {
repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org',
repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(/No Id returned/);
@@ -198,7 +203,7 @@ describe('publish:azure', () => {
action.handler({
...mockContext,
input: {
repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org',
repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org',
},
}),
).rejects.toThrow(/No web URL returned/);
@@ -214,7 +219,7 @@ describe('publish:azure', () => {
await action.handler({
...mockContext,
input: {
repoUrl: 'dev.azure.com?repo=bob&owner=owner&organization=org',
repoUrl: 'dev.azure.com?repo=bob&project=project&organization=org',
},
});
@@ -227,7 +232,7 @@ describe('publish:azure', () => {
{
name: 'bob',
},
'owner',
'project',
);
});
@@ -136,7 +136,7 @@ export function createPublishAzureAction(options: {
gitAuthorEmail,
} = ctx.input;
const { owner, repo, host, organization } = parseRepoUrl(
const { project, repo, host, organization } = parseRepoUrl(
repoUrl,
integrations,
);
@@ -166,11 +166,14 @@ export function createPublishAzureAction(options: {
const webApi = new WebApi(url, authHandler);
const client = await webApi.getGitApi();
const createOptions: GitRepositoryCreateOptions = { name: repo };
const returnedRepo = await client.createRepository(createOptions, owner);
const returnedRepo = await client.createRepository(
createOptions,
project,
);
if (!returnedRepo) {
throw new InputError(
`Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}.
`Unable to create the repository with Organization ${organization}, Project ${project} and Repo ${repo}.
Please make sure that both the Org and Project are typed corrected and exist.`,
);
}
@@ -85,6 +85,10 @@ export const parseRepoUrl = (
checkRequiredParams(parsed, 'project', 'repo');
break;
}
case 'azure': {
checkRequiredParams(parsed, 'project', 'repo');
break;
}
case 'gitlab': {
// project is the projectID, and if defined, owner and repo won't be needed.
if (!project) {
@@ -36,6 +36,11 @@ describe('RepoPicker Validation', () => {
host: 'server.bitbucket.com',
},
],
azure: [
{
host: 'dev.azure.com',
},
],
github: [
{
host: 'github.com',
@@ -201,4 +206,59 @@ describe('RepoPicker Validation', () => {
'Incomplete repository location provided, repo not provided',
);
});
it('validates properly with proper input for azure', () => {
const mockFieldValidation = fieldValidator();
repoPickerValidation(
'dev.azure.com?project=a&repo=b',
mockFieldValidation,
{
apiHolder: apiHolderMock,
},
);
expect(mockFieldValidation.addError).not.toHaveBeenCalled();
});
it('validates when no project or repo provided for azure', () => {
const mockFieldValidation = fieldValidator();
repoPickerValidation('dev.azure.com', mockFieldValidation, {
apiHolder: apiHolderMock,
});
expect(mockFieldValidation.addError).toHaveBeenNthCalledWith(
1,
'Incomplete repository location provided, project not provided',
);
expect(mockFieldValidation.addError).toHaveBeenNthCalledWith(
2,
'Incomplete repository location provided, repo not provided',
);
});
it('validates when no project provided for azure', () => {
const mockFieldValidation = fieldValidator();
repoPickerValidation('dev.azure.com?repo=r', mockFieldValidation, {
apiHolder: apiHolderMock,
});
expect(mockFieldValidation.addError).toHaveBeenCalledWith(
'Incomplete repository location provided, project not provided',
);
});
it('validates when no repo provided for azure', () => {
const mockFieldValidation = fieldValidator();
repoPickerValidation('dev.azure.com?project=p', mockFieldValidation, {
apiHolder: apiHolderMock,
});
expect(mockFieldValidation.addError).toHaveBeenCalledWith(
'Incomplete repository location provided, repo not provided',
);
});
});
@@ -48,13 +48,19 @@ export const repoPickerValidation = (
);
}
if (!searchParams.get('project')) {
validation.addError(
'Incomplete repository location provided, project not provided',
);
}
} else if (integrationApi?.byHost(host)?.type === 'azure') {
if (!searchParams.get('project')) {
validation.addError(
'Incomplete repository location provided, project not provided',
);
}
}
// For anything other than bitbucket and gerrit
// For anything other than bitbucket, azure, and gerrit
else if (integrationApi?.byHost(host)?.type !== 'gerrit') {
if (!searchParams.get('owner')) {
validation.addError(