Merge branch 'master' into add-support-for-plugin-specific-db

This commit is contained in:
Patrik Oldsberg
2021-06-15 17:49:50 +02:00
committed by GitHub
253 changed files with 2621 additions and 2492 deletions
+50
View File
@@ -1,5 +1,55 @@
# @backstage/plugin-scaffolder-backend
## 0.12.0
### Minor Changes
- 66c6bfebd: Scaffolding a repository in Bitbucket will now use the apiBaseUrl if it is provided instead of only the host parameter
### Patch Changes
- 27a9b503a: Introduce conditional steps in scaffolder templates.
A step can now include an `if` property that only executes a step if the
condition is truthy. The condition can include handlebar templates.
```yaml
- id: register
if: '{{ not parameters.dryRun }}'
name: Register
action: catalog:register
input:
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
catalogInfoPath: '/catalog-info.yaml'
```
Also introduces a `not` helper in handlebar templates that allows to negate
boolean expressions.
- 55a253de2: Migrating old `backstage.io/v1alpha1` templates to `backstage.io/v1beta2`
Deprecating the `create-react-app` Template. We're planning on removing the `create-react-app` templater, as it's been a little tricky to support and takes 15mins to run in a container. We've currently cached a copy of the output for `create-react-app` and ship that under our sample templates folder. If you want to continue using it, we suggest copying the template out of there and putting it in your own repository as it will be removed in upcoming releases.
We also recommend removing this entry from your `app-config.yaml` if it exists:
```diff
- - type: url
- target: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml
- rules:
- - allow: [Template]
```
- f26e6008f: Add `debug:log` action for debugging.
- 4f8cf50fe: Update gitbeaker past the broken version without a dist folder
- Updated dependencies [92963779b]
- Updated dependencies [27a9b503a]
- Updated dependencies [70bc30c5b]
- Updated dependencies [eda9dbd5f]
- @backstage/backend-common@0.8.2
- @backstage/catalog-model@0.8.2
- @backstage/catalog-client@0.3.13
- @backstage/integration@0.5.6
## 0.11.5
### Patch Changes
+8 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-scaffolder-backend",
"version": "0.11.5",
"version": "0.12.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -29,19 +29,19 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.8.1",
"@backstage/catalog-client": "^0.3.12",
"@backstage/catalog-model": "^0.8.1",
"@backstage/backend-common": "^0.8.2",
"@backstage/catalog-client": "^0.3.13",
"@backstage/catalog-model": "^0.8.2",
"@backstage/config": "^0.1.5",
"@backstage/errors": "^0.1.1",
"@backstage/integration": "^0.5.5",
"@backstage/integration": "^0.5.6",
"@gitbeaker/core": "^30.2.0",
"@gitbeaker/node": "^30.2.0",
"@octokit/rest": "^18.5.3",
"@types/express": "^4.17.6",
"@types/git-url-parse": "^9.0.0",
"azure-devops-node-api": "^10.1.1",
"command-exists-promise": "^2.0.2",
"command-exists": "^1.2.9",
"compression": "^1.7.4",
"cors": "^2.8.5",
"cross-fetch": "^3.0.6",
@@ -64,8 +64,9 @@
"yaml": "^1.10.0"
},
"devDependencies": {
"@backstage/cli": "^0.6.14",
"@backstage/cli": "^0.7.0",
"@backstage/test-utils": "^0.1.13",
"@types/command-exists": "^1.2.0",
"@types/fs-extra": "^9.0.1",
"@types/mock-fs": "^4.13.0",
"@types/supertest": "^2.0.8",
@@ -140,7 +140,7 @@ describe('publish:bitbucket', () => {
'https://hosted.bitbucket.com/rest/api/1.0/projects/owner/repos',
(req, res, ctx) => {
expect(req.headers.get('Authorization')).toBe('Bearer thing');
expect(req.body).toEqual({ is_private: true, name: 'repo' });
expect(req.body).toEqual({ public: false, name: 'repo' });
return res(
ctx.status(201),
ctx.set('Content-Type', 'application/json'),
@@ -174,6 +174,88 @@ describe('publish:bitbucket', () => {
});
});
describe('LFS for hosted bitbucket', () => {
const repoCreationResponse = {
links: {
self: [
{
href: 'https://bitbucket.mycompany.com/projects/project/repos/repo',
},
],
clone: [
{
name: 'http',
href: 'https://bitbucket.mycompany.com/scm/project/repo',
},
],
},
};
it('should call the correct APIs to enable LFS if requested and the host is hosted bitbucket', async () => {
expect.assertions(1);
server.use(
rest.post(
'https://hosted.bitbucket.com/rest/api/1.0/projects/owner/repos',
(_, res, ctx) => {
return res(
ctx.status(201),
ctx.set('Content-Type', 'application/json'),
ctx.json(repoCreationResponse),
);
},
),
rest.put(
'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/owner/repos/repo/enabled',
(req, res, ctx) => {
expect(req.headers.get('Authorization')).toBe('Bearer thing');
return res(ctx.status(204));
},
),
);
await action.handler({
...mockContext,
input: {
...mockContext.input,
repoUrl: 'hosted.bitbucket.com?owner=owner&repo=repo',
enableLFS: true,
},
});
});
it('should report an error if enabling LFS fails', async () => {
server.use(
rest.post(
'https://hosted.bitbucket.com/rest/api/1.0/projects/owner/repos',
(_, res, ctx) => {
return res(
ctx.status(201),
ctx.set('Content-Type', 'application/json'),
ctx.json(repoCreationResponse),
);
},
),
rest.put(
'https://hosted.bitbucket.com/rest/git-lfs/admin/projects/owner/repos/repo/enabled',
(_, res, ctx) => {
return res(ctx.status(500));
},
),
);
await expect(
action.handler({
...mockContext,
input: {
...mockContext.input,
repoUrl: 'hosted.bitbucket.com?owner=owner&repo=repo',
enableLFS: true,
},
}),
).rejects.toThrow(/Failed to enable LFS/);
});
});
it('should call initAndPush with the correct values', async () => {
server.use(
rest.post(
@@ -19,10 +19,10 @@ import {
BitbucketIntegrationConfig,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { initRepoAndPush } from '../../../stages/publish/helpers';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import fetch from 'cross-fetch';
import { initRepoAndPush } from '../../../stages/publish/helpers';
import { createTemplateAction } from '../../createTemplateAction';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
const createBitbucketCloudRepository = async (opts: {
owner: string;
@@ -102,7 +102,7 @@ const createBitbucketServerRepository = async (opts: {
body: JSON.stringify({
name: repo,
description: description,
is_private: repoVisibility === 'private',
public: repoVisibility === 'public',
}),
headers: {
Authorization: authorization,
@@ -156,6 +156,32 @@ const getAuthorizationHeader = (config: BitbucketIntegrationConfig) => {
);
};
const performEnableLFS = async (opts: {
authorization: string;
host: string;
owner: string;
repo: string;
}) => {
const { authorization, host, owner, repo } = opts;
const options: RequestInit = {
method: 'PUT',
headers: {
Authorization: authorization,
},
};
const { ok, status, statusText } = await fetch(
`https://${host}/rest/git-lfs/admin/projects/${owner}/repos/${repo}/enabled`,
options,
);
if (!ok)
throw new Error(
`Failed to enable LFS in the repository, ${status}: ${statusText}`,
);
};
export function createPublishBitbucketAction(options: {
integrations: ScmIntegrationRegistry;
}) {
@@ -166,6 +192,7 @@ export function createPublishBitbucketAction(options: {
description: string;
repoVisibility: 'private' | 'public';
sourcePath?: string;
enableLFS: boolean;
}>({
id: 'publish:bitbucket',
description:
@@ -193,6 +220,11 @@ export function createPublishBitbucketAction(options: {
'Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.',
type: 'string',
},
enableLFS: {
title:
'Enable LFS for the repository. Only available for hosted Bitbucket.',
type: 'boolean',
},
},
},
output: {
@@ -210,7 +242,12 @@ export function createPublishBitbucketAction(options: {
},
},
async handler(ctx) {
const { repoUrl, description, repoVisibility = 'private' } = ctx.input;
const {
repoUrl,
description,
repoVisibility = 'private',
enableLFS = false,
} = ctx.input;
const { owner, repo, host } = parseRepoUrl(repoUrl);
@@ -254,6 +291,10 @@ export function createPublishBitbucketAction(options: {
logger: ctx.logger,
});
if (enableLFS && host !== 'bitbucket.org') {
await performEnableLFS({ authorization, host, owner, repo });
}
ctx.output('remoteUrl', remoteUrl);
ctx.output('repoContentsUrl', repoContentsUrl);
},
@@ -174,7 +174,7 @@ export class BitbucketPublisher implements PublisherBase {
body: JSON.stringify({
name: name,
description: description,
is_private: this.config.repoVisibility === 'private',
public: this.config.repoVisibility === 'public',
}),
headers: {
Authorization: this.getAuthorizationHeader(),
@@ -18,7 +18,7 @@ const runCommand = jest.fn();
const commandExists = jest.fn();
jest.mock('./helpers', () => ({ runCommand }));
jest.mock('command-exists-promise', () => commandExists);
jest.mock('command-exists', () => commandExists);
jest.mock('fs-extra');
import { ContainerRunner } from '@backstage/backend-common';
@@ -16,13 +16,12 @@
import { ContainerRunner } from '@backstage/backend-common';
import { JsonValue } from '@backstage/config';
import commandExists from 'command-exists';
import fs from 'fs-extra';
import path from 'path';
import { runCommand } from './helpers';
import { TemplaterBase, TemplaterRunOptions } from './types';
const commandExists = require('command-exists-promise');
export class CookieCutter implements TemplaterBase {
private readonly containerRunner: ContainerRunner;