feat: support setting workflow access level during repo creation

Signed-off-by: Phred <fearphage@gmail.com>
This commit is contained in:
Phred
2026-01-02 12:09:19 -06:00
parent 0fe2a23ad9
commit bb7088be42
8 changed files with 149 additions and 530 deletions
+19
View File
@@ -0,0 +1,19 @@
---
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Added options to set [workflow access level][access-level] for repositories to `github:repo:create`
This is useful when creating repositories for GitHub Actions to manage access
to the workflows during creation.
```diff
- action: github:repo:create
id: create-repo
input:
repoUrl: github.com?owner=owner&repo=repo
visibility: private
+ workflowAccess: organization
```
[access-level]: https://docs.github.com/en/rest/actions/permissions?apiVersion=2022-11-28#set-the-level-of-access-for-workflows-outside-of-the-repository
@@ -1021,4 +1021,19 @@ export const examples: TemplateExample[] = [
],
}),
},
{
description: 'Allow workflow access for organization.',
example: yaml.stringify({
steps: [
{
action: 'github:repo:create',
name: 'Create a new GitHub repository that allows org-wide access to its workflows',
input: {
repoUrl: 'github.com?owner=owner&repo=repo',
workflowAccess: 'organization',
},
},
],
}),
},
];
@@ -57,6 +57,7 @@ const mockOctokit = {
createRepoVariable: jest.fn(),
createOrUpdateRepoSecret: jest.fn(),
getRepoPublicKey: jest.fn(),
setWorkflowAccessToRepository: jest.fn(),
},
activity: {
setRepoSubscription: jest.fn(),
@@ -152,12 +153,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: undefined,
});
await action.handler({
@@ -180,13 +176,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
visibility: 'public',
auto_init: undefined,
});
await action.handler({
@@ -210,11 +200,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
visibility: 'private',
auto_init: undefined,
});
await action.handler({
@@ -239,13 +225,8 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
visibility: 'private',
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
@@ -270,12 +251,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
visibility: 'private',
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
auto_init: undefined,
});
await action.handler({
@@ -302,13 +278,8 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://example.com',
visibility: 'private',
auto_init: undefined,
});
await action.handler({
@@ -332,11 +303,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: true,
});
@@ -362,11 +328,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
custom_properties: undefined,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: false,
});
@@ -396,11 +357,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
await action.handler({
@@ -424,11 +380,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
await action.handler({
@@ -453,10 +404,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
auto_init: undefined,
});
await action.handler({
@@ -482,11 +429,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
@@ -512,11 +455,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
// Custom properties on user repos should be ignored
@@ -545,11 +484,7 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
@@ -573,10 +508,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
homepage: undefined,
auto_init: true,
});
@@ -601,10 +532,6 @@ describe('github:repo:create', () => {
allow_rebase_merge: true,
allow_auto_merge: false,
allow_update_branch: false,
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
homepage: undefined,
auto_init: false,
});
});
@@ -966,4 +893,30 @@ describe('github:repo:create', () => {
ignored: false,
});
});
it.each(['none', 'organization', 'user'])(
'should set workflow access level - %s',
async expected => {
mockOctokit.rest.users.getByUsername.mockResolvedValue({
data: { type: 'Organization' },
});
mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} });
await action.handler({
...mockContext,
input: {
...mockContext.input,
workflowAccess: expected,
},
});
expect(
mockOctokit.rest.actions.setWorkflowAccessToRepository,
).toHaveBeenCalledWith({
access_level: expected,
owner: 'owner',
repo: 'repo',
});
},
);
});
@@ -47,41 +47,7 @@ export function createGithubRepoCreateAction(options: {
examples,
schema: {
input: {
repoUrl: inputProps.repoUrl,
description: inputProps.description,
homepage: inputProps.homepage,
access: inputProps.access,
requireCodeOwnerReviews: inputProps.requireCodeOwnerReviews,
bypassPullRequestAllowances: inputProps.bypassPullRequestAllowances,
requiredApprovingReviewCount: inputProps.requiredApprovingReviewCount,
restrictions: inputProps.restrictions,
requiredStatusCheckContexts: inputProps.requiredStatusCheckContexts,
requireBranchesToBeUpToDate: inputProps.requireBranchesToBeUpToDate,
requiredConversationResolution:
inputProps.requiredConversationResolution,
repoVisibility: inputProps.repoVisibility,
deleteBranchOnMerge: inputProps.deleteBranchOnMerge,
allowMergeCommit: inputProps.allowMergeCommit,
allowSquashMerge: inputProps.allowSquashMerge,
squashMergeCommitTitle: inputProps.squashMergeCommitTitle,
squashMergeCommitMessage: inputProps.squashMergeCommitMessage,
allowRebaseMerge: inputProps.allowRebaseMerge,
allowAutoMerge: inputProps.allowAutoMerge,
allowUpdateBranch: inputProps.allowUpdateBranch,
collaborators: inputProps.collaborators,
hasProjects: inputProps.hasProjects,
hasWiki: inputProps.hasWiki,
hasIssues: inputProps.hasIssues,
token: inputProps.token,
topics: inputProps.topics,
repoVariables: inputProps.repoVariables,
secrets: inputProps.secrets,
oidcCustomization: inputProps.oidcCustomization,
requiredCommitSigning: inputProps.requiredCommitSigning,
requiredLinearHistory: inputProps.requiredLinearHistory,
customProperties: inputProps.customProperties,
subscribe: inputProps.subscribe,
autoInit: inputProps.autoInit,
...inputProps,
},
output: {
remoteUrl: outputProps.remoteUrl,
@@ -115,6 +81,7 @@ export function createGithubRepoCreateAction(options: {
subscribe,
token: providedToken,
autoInit = undefined,
workflowAccess,
} = ctx.input;
const { host, owner, repo } = parseRepoUrl(repoUrl, integrations);
@@ -167,6 +134,7 @@ export function createGithubRepoCreateAction(options: {
subscribe,
ctx.logger,
autoInit,
workflowAccess,
);
return newRepo.clone_url;
},
@@ -79,6 +79,7 @@ export async function createGithubRepoWithCollaboratorsAndTopics(
subscribe: boolean | undefined,
logger: LoggerService,
autoInit?: boolean | undefined,
workflowAccess?: 'none' | 'organization' | 'user',
) {
// eslint-disable-next-line testing-library/no-await-sync-queries
const user = await client.rest.users.getByUsername({
@@ -272,6 +273,14 @@ export async function createGithubRepoWithCollaboratorsAndTopics(
});
}
if (workflowAccess) {
await client.rest.actions.setWorkflowAccessToRepository({
access_level: workflowAccess,
owner,
repo,
});
}
return newRepo;
}
@@ -421,50 +421,59 @@ const autoInit = (z: typeof zod) =>
.default(false)
.optional();
const workflowAccess = (z: typeof zod) =>
z
.enum(['node', 'organization', 'user'], {
description:
'Level of access for workflows outside of the repository. Default is "none".',
})
.optional();
export {
repoUrl,
description,
homepage,
access,
requireCodeOwnerReviews,
dismissStaleReviews,
requiredStatusCheckContexts,
requireBranchesToBeUpToDate,
requiredConversationResolution,
requireLastPushApproval,
repoVisibility,
deleteBranchOnMerge,
gitAuthorName,
gitAuthorEmail,
allowAutoMerge,
allowMergeCommit,
allowRebaseMerge,
allowSquashMerge,
allowUpdateBranch,
squashMergeCommitTitle,
squashMergeCommitMessage,
allowRebaseMerge,
allowAutoMerge,
autoInit,
blockCreations,
branch,
bypassPullRequestAllowances,
collaborators,
customProperties,
defaultBranch,
deleteBranchOnMerge,
description,
dismissStaleReviews,
gitAuthorEmail,
gitAuthorName,
gitCommitMessage,
hasIssues,
hasProjects,
hasWiki,
hasIssues,
token,
topics,
defaultBranch,
gitCommitMessage,
sourcePath,
repoVariables,
secrets,
homepage,
oidcCustomization,
customProperties,
subscribe,
requiredApprovingReviewCount,
restrictions,
requiredCommitSigning,
requiredLinearHistory,
protectDefaultBranch,
protectEnforceAdmins,
bypassPullRequestAllowances,
branch,
blockCreations,
autoInit,
repoUrl,
repoVariables,
repoVisibility,
requireBranchesToBeUpToDate,
requireCodeOwnerReviews,
requiredApprovingReviewCount,
requiredCommitSigning,
requiredConversationResolution,
requiredLinearHistory,
requiredStatusCheckContexts,
requireLastPushApproval,
restrictions,
secrets,
sourcePath,
squashMergeCommitMessage,
squashMergeCommitTitle,
subscribe,
token,
topics,
workflowAccess,
};
@@ -31,6 +31,4 @@ const commitHash = (z: typeof zod) =>
description: 'The git commit hash of the initial commit',
});
export { remoteUrl };
export { repoContentsUrl };
export { commitHash };
export { commitHash, remoteUrl, repoContentsUrl };