diff --git a/.changeset/young-forks-grab.md b/.changeset/young-forks-grab.md new file mode 100644 index 0000000000..d48a4f1f7d --- /dev/null +++ b/.changeset/young-forks-grab.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': minor +--- + +Updated the path field in the gitlab:group:ensureExists action to accept an array of either strings or objects with name and slug fields. diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts index 202b397d19..eaeb65ae9c 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.test.ts @@ -196,4 +196,51 @@ describe('gitlab:group:ensureExists', () => { expect(mockContext.output).toHaveBeenCalledWith('groupId', 42); }); + + it(`Should ${examples[4].description}`, async () => { + mockGitlabClient.Groups.search.mockResolvedValue([ + { + id: 1, + full_path: 'group1', + }, + { + id: 2, + full_path: 'group1/group2', + }, + ]); + mockGitlabClient.Groups.create.mockResolvedValue({ + id: 3, + full_path: 'group1/group2/group3', + }); + + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'gitlab.com', + token: 'tokenlols', + apiBaseUrl: 'https://api.gitlab.com', + }, + ], + }, + }); + const integrations = ScmIntegrations.fromConfig(config); + + const action = createGitlabGroupEnsureExistsAction({ integrations }); + + await action.handler({ + ...mockContext, + input: yaml.parse(examples[4].example).steps[0].input, + }); + + expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith( + 'Group 3', + 'group3', + { + parentId: 2, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); + }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts index 41dd822e82..bbe7ad4722 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts @@ -82,4 +82,24 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: 'Create a group nested within another group using objects', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabGroup', + name: 'Group', + action: 'gitlab:group:ensureExists', + input: { + repoUrl: 'gitlab.com', + path: [ + { name: 'Group 1', slug: 'group1' }, + { name: 'Group 2', slug: 'group2' }, + { name: 'Group 3', slug: 'group3' }, + ], + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts index 1192052e6d..f9dc12eb54 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts @@ -62,7 +62,7 @@ describe('gitlab:group:ensureExists', () => { const mockContext = createMockActionContext(); - it('should create a new group if it does not exists', async () => { + it('should create a new group from string if it does not exists', async () => { mockGitlabClient.Groups.search.mockResolvedValue([ { id: 1, @@ -94,6 +94,45 @@ describe('gitlab:group:ensureExists', () => { expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); }); + it('should create a new group from object if it does not exists', async () => { + mockGitlabClient.Groups.search.mockResolvedValue([ + { + id: 1, + full_path: 'bar', + }, + { + id: 2, + full_path: 'foo', + }, + ]); + + mockGitlabClient.Groups.create.mockResolvedValue({ + id: 3, + full_path: 'foo/bar', + }); + + await action.handler({ + ...mockContext, + input: { + repoUrl: 'gitlab.com?repo=repo&owner=owner', + path: [ + { name: 'Foo', slug: 'foo' }, + { name: 'Bar is a nice name', slug: 'bar' }, + ], + }, + }); + + expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith( + 'Bar is a nice name', + 'bar', + { + parentId: 2, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); + }); + it('should return existing group if it does exists', async () => { mockGitlabClient.Groups.search.mockResolvedValue([ { diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts index 7134726e6f..50ce7a761b 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts @@ -41,9 +41,18 @@ export const createGitlabGroupEnsureExistsAction = (options: { input: commonGitlabConfig.merge( z.object({ path: z - .array(z.string(), { - description: 'A path of group names that is ensured to exist', - }) + .array( + z.string().or( + z.object({ + name: z.string(), + slug: z.string(), + }), + ), + { + description: + 'A path of group names or objects (name and slug) that is ensured to exist', + }, + ) .min(1), }), ), @@ -68,9 +77,11 @@ export const createGitlabGroupEnsureExistsAction = (options: { let currentPath: string | null = null; let parentId: number | null = null; for (const pathElement of path) { - const fullPath: string = currentPath - ? `${currentPath}/${pathElement}` - : pathElement; + const slug = + typeof pathElement === 'string' ? pathElement : pathElement.slug; + const name = + typeof pathElement === 'string' ? pathElement : pathElement.name; + const fullPath: string = currentPath ? `${currentPath}/${slug}` : slug; const result = (await api.Groups.search( fullPath, )) as unknown as Array; // recast since the return type for search is wrong in the gitbeaker typings @@ -81,8 +92,8 @@ export const createGitlabGroupEnsureExistsAction = (options: { ctx.logger.info(`creating missing group ${fullPath}`); parentId = ( await api.Groups.create( - pathElement, - pathElement, + name, + slug, parentId ? { parentId: parentId,