feat(scaffolder): add auto_init option for repository creation and examples

Signed-off-by: Adam Östör <adam.ostor@fundingcircle.com>
This commit is contained in:
Adam Östör
2025-09-10 17:38:03 +01:00
parent a59be35d43
commit aee107ba37
8 changed files with 278 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
---
'@backstage/plugin-scaffolder-backend-module-github': patch
---
Add `auto_init` option to 'github:repo:create' action to create repository with an initial commit containing a README.md file
This initial commit is created by GitHub itself and the commit is signed, so the repository will not be empty after creation.
```diff
- action: github:repo:create
id: init-new-repo
input:
repoUrl: 'github.com?repo=repo&owner=owner'
description: This is the description
visibility: private
+ autoInit: true
```
@@ -291,6 +291,7 @@ export function createGithubRepoCreateAction(options: {
requiredLinearHistory?: boolean | undefined;
customProperties?: Record<string, string | string[]> | undefined;
subscribe?: boolean | undefined;
autoInit?: boolean | undefined;
},
{
remoteUrl: string;
@@ -136,6 +136,7 @@ describe('github:repo:create examples', () => {
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: undefined,
});
});
@@ -169,6 +170,7 @@ describe('github:repo:create examples', () => {
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: undefined,
});
});
@@ -203,6 +205,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: false, // disable wiki
homepage: undefined,
auto_init: undefined,
});
});
@@ -246,6 +249,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
});
@@ -289,6 +293,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -332,6 +337,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -375,6 +381,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -418,6 +425,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -461,6 +469,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -504,6 +513,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -547,6 +557,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -590,6 +601,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -633,6 +645,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -676,6 +689,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -719,6 +733,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -762,6 +777,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -805,6 +821,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -848,6 +865,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -891,6 +909,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -934,6 +953,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -977,6 +997,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://project-xyz.com',
auto_init: undefined,
});
});
@@ -1020,6 +1041,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1063,6 +1085,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1106,6 +1129,7 @@ describe('github:repo:create examples', () => {
has_projects: true,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1149,6 +1173,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1192,6 +1217,7 @@ describe('github:repo:create examples', () => {
has_projects: false,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1235,6 +1261,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1278,6 +1305,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1321,6 +1349,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1364,6 +1393,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1407,6 +1437,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1450,6 +1481,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1493,6 +1525,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1536,6 +1569,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1579,6 +1613,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://internal.example.com',
auto_init: undefined,
});
});
@@ -1622,6 +1657,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1665,6 +1701,7 @@ describe('github:repo:create examples', () => {
has_projects: true,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1708,6 +1745,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1751,6 +1789,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1794,6 +1833,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1837,6 +1877,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://webapp.example.com',
auto_init: undefined,
});
});
@@ -1880,6 +1921,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1923,6 +1965,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -1966,6 +2009,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2009,6 +2053,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2052,6 +2097,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2095,6 +2141,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: false,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2138,6 +2185,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2181,6 +2229,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2224,6 +2273,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2267,6 +2317,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2310,6 +2361,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
});
@@ -2353,6 +2405,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2396,6 +2449,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2439,6 +2493,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2482,6 +2537,7 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
@@ -2525,6 +2581,51 @@ describe('github:repo:create examples', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
});
it(`Should ${examples[58].description}`, async () => {
mockOctokit.rest.users.getByUsername.mockResolvedValue({
data: { type: 'Organization' },
});
mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} });
let input;
try {
input = yaml.parse(examples[58].example).steps[0].input;
} catch (error) {
console.error('Failed to parse YAML:', error);
}
await action.handler({
...mockContext,
input: {
...mockContext.input,
...input,
},
});
expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({
name: 'repo',
org: 'owner',
private: true,
delete_branch_on_merge: false,
allow_squash_merge: true,
allow_update_branch: false,
custom_properties: undefined,
squash_merge_commit_title: 'COMMIT_OR_PR_TITLE',
squash_merge_commit_message: 'COMMIT_MESSAGES',
allow_merge_commit: true,
allow_rebase_merge: true,
allow_auto_merge: false,
visibility: 'private',
has_issues: undefined,
description: undefined,
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: true,
});
});
});
@@ -1006,4 +1006,19 @@ export const examples: TemplateExample[] = [
],
}),
},
{
description: 'Create a repository with an initial commit.',
example: yaml.stringify({
steps: [
{
action: 'github:repo:create',
name: 'Create a new GitHub repository with an initial (signed) commit containing a README',
input: {
repoUrl: 'github.com?repo=repo&owner=owner',
autoInit: true,
},
},
],
}),
},
];
@@ -157,6 +157,7 @@ describe('github:repo:create', () => {
has_wiki: undefined,
homepage: undefined,
visibility: 'private',
auto_init: undefined,
});
await action.handler({
@@ -185,6 +186,7 @@ describe('github:repo:create', () => {
has_wiki: undefined,
homepage: undefined,
visibility: 'public',
auto_init: undefined,
});
await action.handler({
@@ -212,6 +214,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_wiki: undefined,
visibility: 'private',
auto_init: undefined,
});
await action.handler({
@@ -242,6 +245,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
@@ -271,6 +275,7 @@ describe('github:repo:create', () => {
has_wiki: undefined,
has_projects: undefined,
has_issues: undefined,
auto_init: undefined,
});
await action.handler({
@@ -303,6 +308,67 @@ describe('github:repo:create', () => {
has_wiki: undefined,
homepage: 'https://example.com',
visibility: 'private',
auto_init: undefined,
});
await action.handler({
...mockContext,
input: {
...mockContext.input,
autoInit: true,
},
});
expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({
description: 'description',
name: 'repo',
org: 'owner',
private: true,
delete_branch_on_merge: false,
allow_squash_merge: true,
squash_merge_commit_title: 'COMMIT_OR_PR_TITLE',
squash_merge_commit_message: 'COMMIT_MESSAGES',
allow_merge_commit: true,
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,
});
await action.handler({
...mockContext,
input: {
...mockContext.input,
autoInit: false,
},
});
expect(mockOctokit.rest.repos.createInOrg).toHaveBeenCalledWith({
description: 'description',
name: 'repo',
org: 'owner',
private: true,
delete_branch_on_merge: false,
allow_squash_merge: true,
squash_merge_commit_title: 'COMMIT_OR_PR_TITLE',
squash_merge_commit_message: 'COMMIT_MESSAGES',
allow_merge_commit: true,
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,
});
});
@@ -334,6 +400,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
await action.handler({
@@ -361,6 +428,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: undefined,
auto_init: undefined,
});
await action.handler({
@@ -388,6 +456,7 @@ describe('github:repo:create', () => {
has_issues: undefined,
has_projects: undefined,
has_wiki: undefined,
auto_init: undefined,
});
await action.handler({
@@ -417,6 +486,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
@@ -446,6 +516,7 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_issues: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
// Custom properties on user repos should be ignored
@@ -478,6 +549,63 @@ describe('github:repo:create', () => {
has_projects: undefined,
has_wiki: undefined,
homepage: 'https://example.com',
auto_init: undefined,
});
await action.handler({
...mockContext,
input: {
...mockContext.input,
autoInit: true,
},
});
expect(
mockOctokit.rest.repos.createForAuthenticatedUser,
).toHaveBeenCalledWith({
description: 'description',
name: 'repo',
private: true,
delete_branch_on_merge: false,
allow_squash_merge: true,
squash_merge_commit_message: 'COMMIT_MESSAGES',
squash_merge_commit_title: 'COMMIT_OR_PR_TITLE',
allow_merge_commit: true,
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,
});
await action.handler({
...mockContext,
input: {
...mockContext.input,
autoInit: false,
},
});
expect(
mockOctokit.rest.repos.createForAuthenticatedUser,
).toHaveBeenCalledWith({
description: 'description',
name: 'repo',
private: true,
delete_branch_on_merge: false,
allow_squash_merge: true,
squash_merge_commit_message: 'COMMIT_MESSAGES',
squash_merge_commit_title: 'COMMIT_OR_PR_TITLE',
allow_merge_commit: true,
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,
});
});
@@ -81,6 +81,7 @@ export function createGithubRepoCreateAction(options: {
requiredLinearHistory: inputProps.requiredLinearHistory,
customProperties: inputProps.customProperties,
subscribe: inputProps.subscribe,
autoInit: inputProps.autoInit,
},
output: {
remoteUrl: outputProps.remoteUrl,
@@ -113,6 +114,7 @@ export function createGithubRepoCreateAction(options: {
customProperties,
subscribe,
token: providedToken,
autoInit = undefined,
} = ctx.input;
const { host, owner, repo } = parseRepoUrl(repoUrl, integrations);
@@ -164,6 +166,7 @@ export function createGithubRepoCreateAction(options: {
customProperties,
subscribe,
ctx.logger,
autoInit,
);
return newRepo.clone_url;
},
@@ -78,6 +78,7 @@ export async function createGithubRepoWithCollaboratorsAndTopics(
customProperties: { [key: string]: string | string[] } | undefined,
subscribe: boolean | undefined,
logger: LoggerService,
autoInit?: boolean | undefined,
) {
// eslint-disable-next-line testing-library/no-await-sync-queries
const user = await client.rest.users.getByUsername({
@@ -109,6 +110,7 @@ export async function createGithubRepoWithCollaboratorsAndTopics(
has_projects: hasProjects,
has_wiki: hasWiki,
has_issues: hasIssues,
auto_init: autoInit,
// Custom properties only available on org repos
custom_properties: customProperties,
})
@@ -128,6 +130,7 @@ export async function createGithubRepoWithCollaboratorsAndTopics(
has_projects: hasProjects,
has_wiki: hasWiki,
has_issues: hasIssues,
auto_init: autoInit,
});
let newRepo;
@@ -413,6 +413,14 @@ const branch = (z: typeof zod) =>
})
.optional();
const autoInit = (z: typeof zod) =>
z
.boolean({
description: `Create an initial commit with empty README. Default is 'false'`,
})
.default(false)
.optional();
export {
repoUrl,
description,
@@ -458,4 +466,5 @@ export {
bypassPullRequestAllowances,
branch,
blockCreations,
autoInit,
};