Merge pull request #2442 from timja/add-access-support

scaffolder: Add support for granting access on create
This commit is contained in:
Ben Lambert
2020-09-17 09:33:08 +02:00
committed by GitHub
5 changed files with 82 additions and 3 deletions
+4 -2
View File
@@ -40,8 +40,10 @@ internally.
After filling in these variables, you'll get some more fields to fill out which
are required for backstage usage: the owner, (which is a `user` in the backstage
system), the `storePath` (which right now must be a GitHub Organisation), and a
non-existing github repository name in the format `organisation/reponame`.
system), the `storePath` (which right now must be a GitHub Organisation or
GitHub user), a non-existing github repository name in the format
`organisation/reponame`, and a GitHub team or user account which should be
granted admin access to the repository.
![Enter backstage vars](../../assets/software-templates/template-picked-2.png)
@@ -18,10 +18,14 @@ export const mockGithubClient = {
repos: {
createInOrg: jest.fn(),
createForAuthenticatedUser: jest.fn(),
addCollaborator: jest.fn(),
},
users: {
getByUsername: jest.fn(),
},
teams: {
addOrUpdateRepoPermissionsInOrg: jest.fn(),
},
};
export class Octokit {
@@ -30,6 +30,7 @@ const { mockGithubClient } = require('@octokit/rest') as {
mockGithubClient: {
repos: jest.Mocked<Octokit['repos']>;
users: jest.Mocked<Octokit['users']>;
teams: jest.Mocked<Octokit['teams']>;
};
};
@@ -76,6 +77,7 @@ describe('GitHub Publisher', () => {
values: {
storePath: 'blam/test',
owner: 'bob',
access: 'blam/team',
},
directory: '/tmp/test',
});
@@ -86,6 +88,15 @@ describe('GitHub Publisher', () => {
private: false,
visibility: 'public',
});
expect(
mockGithubClient.teams.addOrUpdateRepoPermissionsInOrg,
).toHaveBeenCalledWith({
org: 'blam',
team_slug: 'team',
owner: 'blam',
repo: 'test',
permission: 'admin',
});
});
it('should use octokit to create a repo in the authed user if the organisation property is not set', async () => {
@@ -104,6 +115,7 @@ describe('GitHub Publisher', () => {
values: {
storePath: 'blam/test',
owner: 'bob',
access: 'blam',
},
directory: '/tmp/test',
});
@@ -114,14 +126,50 @@ describe('GitHub Publisher', () => {
name: 'test',
private: false,
});
expect(mockGithubClient.repos.addCollaborator).not.toHaveBeenCalled();
});
});
it('should invite other user in the authed user', async () => {
mockGithubClient.repos.createForAuthenticatedUser.mockResolvedValue({
data: {
clone_url: 'mockclone',
},
} as OctokitResponse<ReposCreateInOrgResponseData>);
mockGithubClient.users.getByUsername.mockResolvedValue({
data: {
type: 'User',
},
} as OctokitResponse<UsersGetByUsernameResponseData>);
await publisher.publish({
values: {
storePath: 'blam/test',
owner: 'bob',
access: 'bob',
},
directory: '/tmp/test',
});
expect(
mockGithubClient.repos.createForAuthenticatedUser,
).toHaveBeenCalledWith({
name: 'test',
private: false,
});
expect(mockGithubClient.repos.addCollaborator).toHaveBeenCalledWith({
owner: 'blam',
repo: 'test',
username: 'bob',
permission: 'admin',
});
});
describe('publish: createGitDirectory', () => {
const values = {
isOrg: true,
storePath: 'blam/test',
owner: 'lols',
access: 'lols',
};
const mockDir = '/tmp/test/dir';
@@ -79,6 +79,26 @@ export class GithubPublisher implements PublisherBase {
const { data } = await repoCreationPromise;
const access = values.access as string;
if (access?.startsWith(`${owner}/`)) {
const [, team] = access.split('/');
await this.client.teams.addOrUpdateRepoPermissionsInOrg({
org: owner,
team_slug: team,
owner,
repo: name,
permission: 'admin',
});
// no need to add access if it's the person who own's the personal account
} else if (access && access !== owner) {
await this.client.repos.addCollaborator({
owner,
repo: name,
username: access,
permission: 'admin',
});
}
return data?.clone_url;
}
@@ -67,6 +67,11 @@ const OWNER_REPO_SCHEMA = {
title: 'Store path',
description: 'GitHub store path in org/repo format',
},
access: {
type: 'string' as const,
title: 'Access',
description: 'Who should have access, in org/team or user format',
},
},
};