Merge branch 'master' of github.com:backstage/backstage into RoadieHQ-5identity-api-client-interface

This commit is contained in:
Brian Fletcher
2022-08-31 10:39:48 +01:00
627 changed files with 10721 additions and 3559 deletions
+19
View File
@@ -1,5 +1,18 @@
# @backstage/plugin-scaffolder-backend
## 1.6.0-next.1
### Minor Changes
- 7db9613671: Added `projectId` for gitlab projects to be displayed in the `gitlab:publish` output
### Patch Changes
- 0d8d650e32: Applied the fix from version 1.5.1 of this package, which is part of the v1.5.1 release of Backstage.
- Updated dependencies
- @backstage/backend-common@0.15.1-next.1
- @backstage/plugin-catalog-backend@1.4.0-next.1
## 1.6.0-next.0
### Minor Changes
@@ -34,6 +47,12 @@
- @backstage/plugin-scaffolder-common@1.2.0-next.0
- @backstage/plugin-catalog-node@1.0.2-next.0
## 1.5.1
### Patch Changes
- Fix minimum required version for `vm2`
## 1.5.0
### Minor Changes
+6 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@backstage/plugin-scaffolder-backend",
"description": "The Backstage backend plugin that helps you create new things",
"version": "1.6.0-next.0",
"version": "1.6.0-next.1",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -35,14 +35,14 @@
"build:assets": "node scripts/build-nunjucks.js"
},
"dependencies": {
"@backstage/backend-common": "^0.15.1-next.0",
"@backstage/backend-common": "^0.15.1-next.1",
"@backstage/catalog-client": "^1.0.5-next.0",
"@backstage/catalog-model": "^1.1.0",
"@backstage/config": "^1.0.1",
"@backstage/errors": "^1.1.0",
"@backstage/integration": "^1.3.1-next.0",
"@backstage/plugin-auth-node": "^0.2.5-next.0",
"@backstage/plugin-catalog-backend": "^1.3.2-next.0",
"@backstage/plugin-catalog-backend": "^1.4.0-next.1",
"@backstage/plugin-scaffolder-common": "^1.2.0-next.0",
"@backstage/backend-plugin-api": "^0.1.2-next.0",
"@backstage/plugin-catalog-node": "^1.0.2-next.0",
@@ -75,13 +75,13 @@
"uuid": "^8.2.0",
"winston": "^3.2.1",
"yaml": "^2.0.0",
"vm2": "^3.9.6",
"vm2": "^3.9.11",
"zen-observable": "^0.8.15",
"zod": "^3.11.6"
},
"devDependencies": {
"@backstage/backend-test-utils": "^0.1.28-next.0",
"@backstage/cli": "^0.18.2-next.0",
"@backstage/backend-test-utils": "^0.1.28-next.1",
"@backstage/cli": "^0.19.0-next.1",
"@types/command-exists": "^1.2.0",
"@types/fs-extra": "^9.0.1",
"@types/git-url-parse": "^9.0.0",
@@ -58,8 +58,8 @@ describe('ScaffolderEntitiesProcessor', () => {
await processor.postProcessEntity(mockEntity, mockLocation, emit);
expect(emit).toBeCalledTimes(2);
expect(emit).toBeCalledWith({
expect(emit).toHaveBeenCalledTimes(2);
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: { kind: 'Group', namespace: 'default', name: 'o' },
@@ -67,7 +67,7 @@ describe('ScaffolderEntitiesProcessor', () => {
target: { kind: 'Template', namespace: 'default', name: 'n' },
},
});
expect(emit).toBeCalledWith({
expect(emit).toHaveBeenCalledWith({
type: 'relation',
relation: {
source: { kind: 'Template', namespace: 'default', name: 'n' },
@@ -107,11 +107,11 @@ describe('catalog:register', () => {
{},
);
expect(mockContext.output).toBeCalledWith(
expect(mockContext.output).toHaveBeenCalledWith(
'entityRef',
'component:default/test',
);
expect(mockContext.output).toBeCalledWith(
expect(mockContext.output).toHaveBeenCalledWith(
'catalogInfoUrl',
'http://foo/var',
);
@@ -160,7 +160,7 @@ describe('catalog:register', () => {
catalogInfoUrl: 'http://foo/var',
},
});
expect(mockContext.output).toBeCalledWith(
expect(mockContext.output).toHaveBeenCalledWith(
'entityRef',
'component:default/test',
);
@@ -202,7 +202,10 @@ describe('catalog:register', () => {
catalogInfoUrl: 'http://foo/var',
},
});
expect(mockContext.output).toBeCalledWith('entityRef', 'api:default/test');
expect(mockContext.output).toHaveBeenCalledWith(
'entityRef',
'api:default/test',
);
});
it('should return entityRef with the first entity if no non-generated entities can be found', async () => {
@@ -234,7 +237,7 @@ describe('catalog:register', () => {
catalogInfoUrl: 'http://foo/var',
},
});
expect(mockContext.output).toBeCalledWith(
expect(mockContext.output).toHaveBeenCalledWith(
'entityRef',
'location:default/generated-1238',
);
@@ -254,7 +257,7 @@ describe('catalog:register', () => {
catalogInfoUrl: 'http://foo/var',
},
});
expect(mockContext.output).not.toBeCalledWith(
expect(mockContext.output).not.toHaveBeenCalledWith(
'entityRef',
expect.any(String),
);
@@ -292,7 +295,7 @@ describe('catalog:register', () => {
{},
);
expect(mockContext.output).toBeCalledWith(
expect(mockContext.output).toHaveBeenCalledWith(
'catalogInfoUrl',
'http://foo/var',
);
@@ -54,7 +54,7 @@ describe('debug:log', () => {
it('should do nothing', async () => {
await action.handler(mockContext);
expect(logStream.write).toBeCalledTimes(0);
expect(logStream.write).toHaveBeenCalledTimes(0);
});
it('should log the workspace content, if active', async () => {
@@ -67,11 +67,11 @@ describe('debug:log', () => {
await action.handler(context);
expect(logStream.write).toBeCalledTimes(1);
expect(logStream.write).toBeCalledWith(
expect(logStream.write).toHaveBeenCalledTimes(1);
expect(logStream.write).toHaveBeenCalledWith(
expect.stringContaining('README.md'),
);
expect(logStream.write).toBeCalledWith(
expect(logStream.write).toHaveBeenCalledWith(
expect.stringContaining(join('a-directory', 'index.md')),
);
});
@@ -86,8 +86,8 @@ describe('debug:log', () => {
await action.handler(context);
expect(logStream.write).toBeCalledTimes(1);
expect(logStream.write).toBeCalledWith(
expect(logStream.write).toHaveBeenCalledTimes(1);
expect(logStream.write).toHaveBeenCalledWith(
expect.stringContaining('Hello Backstage!'),
);
});
@@ -81,7 +81,7 @@ describe('fetchContent helper', () => {
fetchUrl: 'foo',
outputPath: 'somepath',
});
expect(fs.copy).toBeCalledWith(resolvePath('/some/foo'), 'somepath');
expect(fs.copy).toHaveBeenCalledWith(resolvePath('/some/foo'), 'somepath');
});
it('should reject if no integration matches location', async () => {
@@ -116,7 +116,7 @@ describe('fetchContent helper', () => {
outputPath: 'foo',
fetchUrl: 'https://github.com/backstage/foo',
});
expect(fs.ensureDir).toBeCalled();
expect(dirFunction).toBeCalledWith({ targetDir: 'foo' });
expect(fs.ensureDir).toHaveBeenCalled();
expect(dirFunction).toHaveBeenCalledWith({ targetDir: 'foo' });
});
});
@@ -73,7 +73,7 @@ describe('fetch:plain', () => {
targetPath: 'lol',
},
});
expect(fetchContents).toBeCalledWith(
expect(fetchContents).toHaveBeenCalledWith(
expect.objectContaining({
outputPath: resolvePath(mockContext.workspacePath, 'lol'),
fetchUrl:
@@ -117,7 +117,7 @@ describe('fetch:template', () => {
it('throws if output directory is outside the workspace', async () => {
await expect(() =>
action.handler(mockContext({ targetPath: '../' })),
).rejects.toThrowError(
).rejects.toThrow(
/relative path is not allowed to refer to a directory outside its parent/i,
);
});
@@ -127,7 +127,7 @@ describe('fetch:template', () => {
action.handler(
mockContext({ copyWithoutRender: 'abc' as unknown as string[] }),
),
).rejects.toThrowError(
).rejects.toThrow(
/copyWithoutRender\/copyWithoutTemplating must be an array/i,
);
});
@@ -140,7 +140,7 @@ describe('fetch:template', () => {
copyWithoutTemplating: 'def' as unknown as string[],
}),
),
).rejects.toThrowError(
).rejects.toThrow(
/copyWithoutRender and copyWithoutTemplating can not be used at the same time/i,
);
});
@@ -153,7 +153,7 @@ describe('fetch:template', () => {
templateFileExtension: true,
}),
),
).rejects.toThrowError(
).rejects.toThrow(
/input extension incompatible with copyWithoutRender\/copyWithoutTemplating and cookiecutterCompat/,
);
});
@@ -166,7 +166,7 @@ describe('fetch:template', () => {
templateFileExtension: true,
}),
),
).rejects.toThrowError(
).rejects.toThrow(
/input extension incompatible with copyWithoutRender\/copyWithoutTemplating and cookiecutterCompat/,
);
});
@@ -302,8 +302,8 @@ describe('createPublishGithubPullRequestAction', () => {
it('creates a pull request and requests a review from the given reviewers', async () => {
await instance.handler(ctx);
expect(fakeClient.createPullRequest).toBeCalled();
expect(fakeClient.rest.pulls.requestReviewers).toBeCalledWith({
expect(fakeClient.createPullRequest).toHaveBeenCalled();
expect(fakeClient.rest.pulls.requestReviewers).toHaveBeenCalledWith({
owner: 'myorg',
repo: 'myrepo',
pull_number: 123,
@@ -354,8 +354,8 @@ describe('createPublishGithubPullRequestAction', () => {
it('does not call the API endpoint for requesting reviewers', async () => {
await instance.handler(ctx);
expect(fakeClient.createPullRequest).toBeCalled();
expect(fakeClient.rest.pulls.requestReviewers).not.toBeCalled();
expect(fakeClient.createPullRequest).toHaveBeenCalled();
expect(fakeClient.rest.pulls.requestReviewers).not.toHaveBeenCalled();
});
});
@@ -313,11 +313,12 @@ describe('publish:gitlab', () => {
});
});
it('should call output with the remoteUrl and repoContentsUrl', async () => {
it('should call output with the remoteUrl and repoContentsUrl and projectId', async () => {
mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 });
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
mockGitlabClient.Projects.create.mockResolvedValue({
http_url_to_repo: 'http://mockurl.git',
id: 1234,
});
await action.handler(mockContext);
@@ -330,6 +331,7 @@ describe('publish:gitlab', () => {
'repoContentsUrl',
'http://mockurl/-/blob/master',
);
expect(mockContext.output).toHaveBeenCalledWith('projectId', 1234);
});
it('should call the correct Gitlab APIs when setUserAsOwner option is true and integration config has a token', async () => {
@@ -112,6 +112,10 @@ export function createPublishGitlabAction(options: {
title: 'A URL to the root of the repository',
type: 'string',
},
projectId: {
title: 'The ID of the project',
type: 'string',
},
},
},
},
@@ -214,6 +218,7 @@ export function createPublishGitlabAction(options: {
ctx.output('remoteUrl', remoteUrl);
ctx.output('repoContentsUrl', repoContentsUrl);
ctx.output('projectId', projectId);
},
});
}
@@ -128,7 +128,7 @@ describe('DefaultWorkflowRunner', () => {
steps: [{ id: 'test', name: 'name', action: 'does-not-exist' }],
});
await expect(runner.execute(task)).rejects.toThrowError(
await expect(runner.execute(task)).rejects.toThrow(
"Template action with ID 'does-not-exist' is not registered.",
);
});
@@ -142,7 +142,7 @@ describe('DefaultWorkflowRunner', () => {
steps: [{ id: 'test', name: 'name', action: 'jest-validated-action' }],
});
await expect(runner.execute(task)).rejects.toThrowError(
await expect(runner.execute(task)).rejects.toThrow(
/Invalid input passed to action jest-validated-action, instance requires property \"foo\"/,
);
});
@@ -421,7 +421,7 @@ describe('createRouter', () => {
});
const response = await request(app).get(`/v2/tasks`);
expect(taskBroker.list).toBeCalledWith({
expect(taskBroker.list).toHaveBeenCalledWith({
createdBy: undefined,
});
expect(response.status).toEqual(200);
@@ -456,7 +456,7 @@ describe('createRouter', () => {
const response = await request(app).get(
`/v2/tasks?createdBy=user:default/foo`,
);
expect(taskBroker.list).toBeCalledWith({
expect(taskBroker.list).toHaveBeenCalledWith({
createdBy: 'user:default/foo',
});
@@ -556,18 +556,20 @@ describe('createRouter', () => {
expect(statusCode).toBe(200);
expect(headers['content-type']).toBe('text/event-stream');
expect(responseDataFn).toBeCalledTimes(2);
expect(responseDataFn).toBeCalledWith(`event: log
expect(responseDataFn).toHaveBeenCalledTimes(2);
expect(responseDataFn).toHaveBeenCalledWith(`event: log
data: {"id":0,"taskId":"a-random-id","type":"log","createdAt":"","body":{"message":"My log message"}}
`);
expect(responseDataFn).toBeCalledWith(`event: completion
expect(responseDataFn).toHaveBeenCalledWith(`event: completion
data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{"message":"Finished!"}}
`);
expect(taskBroker.event$).toBeCalledTimes(1);
expect(taskBroker.event$).toBeCalledWith({ taskId: 'a-random-id' });
expect(taskBroker.event$).toHaveBeenCalledTimes(1);
expect(taskBroker.event$).toHaveBeenCalledWith({
taskId: 'a-random-id',
});
expect(subscriber!.closed).toBe(true);
});
@@ -618,8 +620,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{
expect(statusCode).toBe(200);
expect(headers['content-type']).toBe('text/event-stream');
expect(taskBroker.event$).toBeCalledTimes(1);
expect(taskBroker.event$).toBeCalledWith({
expect(taskBroker.event$).toHaveBeenCalledTimes(1);
expect(taskBroker.event$).toHaveBeenCalledWith({
taskId: 'a-random-id',
after: 10,
});
@@ -677,8 +679,10 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{
},
]);
expect(taskBroker.event$).toBeCalledTimes(1);
expect(taskBroker.event$).toBeCalledWith({ taskId: 'a-random-id' });
expect(taskBroker.event$).toHaveBeenCalledTimes(1);
expect(taskBroker.event$).toHaveBeenCalledWith({
taskId: 'a-random-id',
});
expect(subscriber!.closed).toBe(true);
});
@@ -700,8 +704,8 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{
expect(response.status).toEqual(200);
expect(response.body).toEqual([]);
expect(taskBroker.event$).toBeCalledTimes(1);
expect(taskBroker.event$).toBeCalledWith({
expect(taskBroker.event$).toHaveBeenCalledTimes(1);
expect(taskBroker.event$).toHaveBeenCalledWith({
taskId: 'a-random-id',
after: 10,
});
@@ -709,7 +713,6 @@ data: {"id":1,"taskId":"a-random-id","type":"completion","createdAt":"","body":{
});
});
});
describe('providing an identity api', () => {
beforeEach(async () => {
const logger = getVoidLogger();