scaffolder: Fix providers
Co-authored-by: Ben Lambert <ben@blam.sh> Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -138,6 +138,221 @@ spec:
|
||||
catalogInfoPath: '/catalog-info.yaml'
|
||||
|
||||
|
||||
output:
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
|
||||
entityRef: '{{ steps.register.output.entityRef }}'
|
||||
|
||||
---
|
||||
|
||||
apiVersion: backstage.io/v1beta2
|
||||
kind: Template
|
||||
metadata:
|
||||
name: test-template-v2-gitlab
|
||||
title: Test Template v2-gitlab
|
||||
description: Testing out the new template schema
|
||||
spec:
|
||||
owner: backstage/techdocs-core
|
||||
type: service
|
||||
|
||||
parameters:
|
||||
- title: Fill in some steps
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
ui:autofocus: true
|
||||
ui:options:
|
||||
rows: 5
|
||||
- title: Choose a location
|
||||
required:
|
||||
- repoUrl
|
||||
properties:
|
||||
repoUrl:
|
||||
title: Repository Location
|
||||
type: string
|
||||
ui:field: RepoUrlPicker
|
||||
ui:options:
|
||||
allowedHosts:
|
||||
- gitlab.com
|
||||
|
||||
steps:
|
||||
- id: fetch-base
|
||||
name: Fetch Base
|
||||
action: fetch:cookiecutter
|
||||
parameters:
|
||||
url: ./template
|
||||
values:
|
||||
name: '{{ parameters.name }}'
|
||||
|
||||
- id: fetch-docs
|
||||
name: Fetch Docs
|
||||
action: fetch:plain
|
||||
parameters:
|
||||
targetPath: ./community
|
||||
url: https://github.com/backstage/community/tree/main/backstage-community-sessions
|
||||
|
||||
- id: publish
|
||||
name: Publish
|
||||
action: publish:gitlab
|
||||
parameters:
|
||||
allowedHosts: ['gitlab.com']
|
||||
description: 'This is {{ parameters.name }}'
|
||||
repoUrl: '{{ parameters.repoUrl }}'
|
||||
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
parameters:
|
||||
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
|
||||
catalogInfoPath: '/catalog-info.yaml'
|
||||
|
||||
|
||||
output:
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
|
||||
entityRef: '{{ steps.register.output.entityRef }}'
|
||||
|
||||
---
|
||||
|
||||
apiVersion: backstage.io/v1beta2
|
||||
kind: Template
|
||||
metadata:
|
||||
name: test-template-v2-bitbucket
|
||||
title: Test Template v2-bitbucket
|
||||
description: Testing out the new template schema
|
||||
spec:
|
||||
owner: backstage/techdocs-core
|
||||
type: service
|
||||
|
||||
parameters:
|
||||
- title: Fill in some steps
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
ui:autofocus: true
|
||||
ui:options:
|
||||
rows: 5
|
||||
- title: Choose a location
|
||||
required:
|
||||
- repoUrl
|
||||
properties:
|
||||
repoUrl:
|
||||
title: Repository Location
|
||||
type: string
|
||||
ui:field: RepoUrlPicker
|
||||
ui:options:
|
||||
allowedHosts:
|
||||
- bitbucket.org
|
||||
|
||||
steps:
|
||||
- id: fetch-base
|
||||
name: Fetch Base
|
||||
action: fetch:cookiecutter
|
||||
parameters:
|
||||
url: ./template
|
||||
values:
|
||||
name: '{{ parameters.name }}'
|
||||
|
||||
- id: fetch-docs
|
||||
name: Fetch Docs
|
||||
action: fetch:plain
|
||||
parameters:
|
||||
targetPath: ./community
|
||||
url: https://github.com/backstage/community/tree/main/backstage-community-sessions
|
||||
|
||||
- id: publish
|
||||
name: Publish
|
||||
action: publish:bitbucket
|
||||
parameters:
|
||||
allowedHosts: ['bitbucket.org']
|
||||
description: 'This is {{ parameters.name }}'
|
||||
repoUrl: '{{ parameters.repoUrl }}'
|
||||
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
parameters:
|
||||
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
|
||||
catalogInfoPath: '/catalog-info.yaml'
|
||||
|
||||
|
||||
output:
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
|
||||
entityRef: '{{ steps.register.output.entityRef }}'
|
||||
|
||||
---
|
||||
apiVersion: backstage.io/v1beta2
|
||||
kind: Template
|
||||
metadata:
|
||||
name: test-template-v2-azure
|
||||
title: Test Template v2-azure
|
||||
description: Testing out the new template schema
|
||||
spec:
|
||||
owner: backstage/techdocs-core
|
||||
type: service
|
||||
|
||||
parameters:
|
||||
- title: Fill in some steps
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
ui:autofocus: true
|
||||
ui:options:
|
||||
rows: 5
|
||||
- title: Choose a location
|
||||
required:
|
||||
- repoUrl
|
||||
properties:
|
||||
repoUrl:
|
||||
title: Repository Location
|
||||
type: string
|
||||
ui:field: RepoUrlPicker
|
||||
ui:options:
|
||||
allowedHosts:
|
||||
- dev.azure.com
|
||||
|
||||
steps:
|
||||
- id: fetch-base
|
||||
name: Fetch Base
|
||||
action: fetch:cookiecutter
|
||||
parameters:
|
||||
url: ./template
|
||||
values:
|
||||
name: '{{ parameters.name }}'
|
||||
|
||||
- id: fetch-docs
|
||||
name: Fetch Docs
|
||||
action: fetch:plain
|
||||
parameters:
|
||||
targetPath: ./community
|
||||
url: https://github.com/backstage/community/tree/main/backstage-community-sessions
|
||||
|
||||
- id: publish
|
||||
name: Publish
|
||||
action: publish:azure
|
||||
parameters:
|
||||
allowedHosts: ['dev.azure.com']
|
||||
description: 'This is {{ parameters.name }}'
|
||||
repoUrl: '{{ parameters.repoUrl }}'
|
||||
|
||||
- id: register
|
||||
name: Register
|
||||
action: catalog:register
|
||||
parameters:
|
||||
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
|
||||
catalogInfoPath: '/catalog-info.yaml'
|
||||
|
||||
|
||||
output:
|
||||
remoteUrl: '{{ steps.publish.output.remoteUrl }}'
|
||||
entityRef: '{{ steps.register.output.entityRef }}'
|
||||
|
||||
@@ -47,7 +47,16 @@ export function createPublishAzureAction(options: {
|
||||
},
|
||||
},
|
||||
async handler(ctx) {
|
||||
const { owner, repo, host } = parseRepoUrl(ctx.parameters.repoUrl);
|
||||
const { owner, repo, host, organization } = parseRepoUrl(
|
||||
ctx.parameters.repoUrl,
|
||||
);
|
||||
|
||||
if (!organization) {
|
||||
throw new InputError(
|
||||
`No Organization was included in the repo URL to create ${ctx.parameters.repoUrl}`,
|
||||
);
|
||||
}
|
||||
|
||||
const integrationConfig = integrations.azure.byHost(host);
|
||||
|
||||
if (!integrationConfig) {
|
||||
@@ -62,10 +71,18 @@ export function createPublishAzureAction(options: {
|
||||
integrationConfig.config.token,
|
||||
);
|
||||
|
||||
const webApi = new WebApi(`https://${host}/${owner}`, authHandler);
|
||||
const webApi = new WebApi(`https://${host}/${organization}`, authHandler);
|
||||
const client = await webApi.getGitApi();
|
||||
const createOptions: GitRepositoryCreateOptions = { name: repo };
|
||||
const { remoteUrl } = await client.createRepository(createOptions, owner);
|
||||
const returnedRepo = await client.createRepository(createOptions, owner);
|
||||
|
||||
if (!returnedRepo) {
|
||||
throw new InputError(
|
||||
`Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}.
|
||||
Please make sure you that both the Org and Project are typed corrected and exist.`,
|
||||
);
|
||||
}
|
||||
const remoteUrl = returnedRepo.remoteUrl;
|
||||
|
||||
if (!remoteUrl) {
|
||||
throw new InputError(
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import { TemplateAction } from '../../types';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { parseRepoUrl } from './util';
|
||||
import fetch from 'cross-fetch';
|
||||
|
||||
const createBitbucketCloudRepository = async (opts: {
|
||||
owner: string;
|
||||
|
||||
@@ -87,7 +87,7 @@ export function createPublishGitlabAction(options: {
|
||||
|
||||
await initRepoAndPush({
|
||||
dir: ctx.workspacePath,
|
||||
remoteUrl,
|
||||
remoteUrl: http_url_to_repo as string,
|
||||
auth: {
|
||||
username: 'oauth2',
|
||||
password: integrationConfig.config.token,
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* 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 { InputError } from '@backstage/backend-common';
|
||||
|
||||
export const parseRepoUrl = (repoUrl: string) => {
|
||||
@@ -24,5 +40,7 @@ export const parseRepoUrl = (repoUrl: string) => {
|
||||
);
|
||||
}
|
||||
|
||||
return { host, owner, repo };
|
||||
const organization = parsed.searchParams.get('organization');
|
||||
|
||||
return { host, owner, repo, organization };
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@ function splitFormData(url: string | undefined) {
|
||||
let host = undefined;
|
||||
let owner = undefined;
|
||||
let repo = undefined;
|
||||
let organization = undefined;
|
||||
|
||||
try {
|
||||
if (url) {
|
||||
@@ -35,18 +36,21 @@ function splitFormData(url: string | undefined) {
|
||||
host = parsed.host;
|
||||
owner = parsed.searchParams.get('owner') || undefined;
|
||||
repo = parsed.searchParams.get('repo') || undefined;
|
||||
// This is azure dev ops specific. not used for any other provider.
|
||||
organization = parsed.searchParams.get('organization') || undefined;
|
||||
}
|
||||
} catch {
|
||||
/* ok */
|
||||
}
|
||||
|
||||
return { host, owner, repo };
|
||||
return { host, owner, repo, organization };
|
||||
}
|
||||
|
||||
function serializeFormData(data: {
|
||||
host?: string;
|
||||
owner?: string;
|
||||
repo?: string;
|
||||
organization?: string;
|
||||
}) {
|
||||
if (!data.host) {
|
||||
return undefined;
|
||||
@@ -58,6 +62,9 @@ function serializeFormData(data: {
|
||||
if (data.repo) {
|
||||
params.set('repo', data.repo);
|
||||
}
|
||||
if (data.organization) {
|
||||
params.set('organization', data.organization);
|
||||
}
|
||||
|
||||
return `${data.host}?${params.toString()}`;
|
||||
}
|
||||
@@ -75,36 +82,71 @@ export const RepoUrlPicker: Field = ({
|
||||
return await api.getIntegrationsList({ allowedHosts });
|
||||
});
|
||||
|
||||
const { host, owner, repo } = splitFormData(formData);
|
||||
const { host, owner, repo, organization } = splitFormData(formData);
|
||||
const updateHost = useCallback(
|
||||
(evt: React.ChangeEvent<{ name?: string; value: unknown }>) =>
|
||||
onChange(
|
||||
serializeFormData({ host: evt.target.value as string, owner, repo }),
|
||||
serializeFormData({
|
||||
host: evt.target.value as string,
|
||||
owner,
|
||||
repo,
|
||||
organization,
|
||||
}),
|
||||
),
|
||||
[onChange, owner, repo],
|
||||
[onChange, owner, repo, organization],
|
||||
);
|
||||
|
||||
const updateOwner = useCallback(
|
||||
(evt: React.ChangeEvent<{ name?: string; value: unknown }>) =>
|
||||
onChange(
|
||||
serializeFormData({ host, owner: evt.target.value as string, repo }),
|
||||
serializeFormData({
|
||||
host,
|
||||
owner: evt.target.value as string,
|
||||
repo,
|
||||
organization,
|
||||
}),
|
||||
),
|
||||
[onChange, host, repo],
|
||||
[onChange, host, repo, organization],
|
||||
);
|
||||
|
||||
const updateRepo = useCallback(
|
||||
(evt: React.ChangeEvent<{ name?: string; value: unknown }>) =>
|
||||
onChange(
|
||||
serializeFormData({ host, owner, repo: evt.target.value as string }),
|
||||
serializeFormData({
|
||||
host,
|
||||
owner,
|
||||
repo: evt.target.value as string,
|
||||
organization,
|
||||
}),
|
||||
),
|
||||
[onChange, host, owner],
|
||||
[onChange, host, owner, organization],
|
||||
);
|
||||
|
||||
const updateOrganization = useCallback(
|
||||
(evt: React.ChangeEvent<{ name?: string; value: unknown }>) =>
|
||||
onChange(
|
||||
serializeFormData({
|
||||
host,
|
||||
owner,
|
||||
repo,
|
||||
organization: evt.target.value as string,
|
||||
}),
|
||||
),
|
||||
[onChange, host, owner, repo],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (host === undefined && integrations?.length) {
|
||||
onChange(serializeFormData({ host: integrations[0].host, owner, repo }));
|
||||
onChange(
|
||||
serializeFormData({
|
||||
host: integrations[0].host,
|
||||
owner,
|
||||
repo,
|
||||
organization,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}, [onChange, integrations, host, owner, repo]);
|
||||
}, [onChange, integrations, host, owner, repo, organization]);
|
||||
|
||||
if (loading) {
|
||||
return <Progress />;
|
||||
@@ -119,18 +161,37 @@ export const RepoUrlPicker: Field = ({
|
||||
>
|
||||
<InputLabel htmlFor="hostInput">Host</InputLabel>
|
||||
<Select native id="hostInput" onChange={updateHost} value={host}>
|
||||
{integrations!
|
||||
.filter(i => allowedHosts?.includes(i.host))
|
||||
.map(i => (
|
||||
<option key={i.host} value={i.host}>
|
||||
{i.title}
|
||||
</option>
|
||||
))}
|
||||
{integrations ? (
|
||||
integrations
|
||||
.filter(i => allowedHosts?.includes(i.host))
|
||||
.map(i => (
|
||||
<option key={i.host} value={i.host}>
|
||||
{i.title}
|
||||
</option>
|
||||
))
|
||||
) : (
|
||||
<p>loading</p>
|
||||
)}
|
||||
</Select>
|
||||
<FormHelperText>
|
||||
The host where the repository will be created
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
{host === 'dev.azure.com' && (
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
error={rawErrors?.length > 0 && !organization}
|
||||
>
|
||||
<InputLabel htmlFor="repoInput">Organization</InputLabel>
|
||||
<Input
|
||||
id="repoInput"
|
||||
onChange={updateOrganization}
|
||||
value={organization}
|
||||
/>
|
||||
<FormHelperText>The name of the organization</FormHelperText>
|
||||
</FormControl>
|
||||
)}
|
||||
<FormControl
|
||||
margin="normal"
|
||||
required
|
||||
|
||||
Reference in New Issue
Block a user