Merge pull request #2442 from timja/add-access-support
scaffolder: Add support for granting access on create
This commit is contained in:
@@ -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.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user