diff --git a/.changeset/crazy-hands-film.md b/.changeset/crazy-hands-film.md new file mode 100644 index 0000000000..694aa7b8e7 --- /dev/null +++ b/.changeset/crazy-hands-film.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Updated the path field in the `gitlab:group:ensureExists` action to suport also strings with multiple segments (e.g. group/subgroup) 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 eaeb65ae9c..4d8e0fd0c0 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 @@ -243,4 +243,55 @@ describe('gitlab:group:ensureExists', () => { expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); }); + + it(`Should ${examples[5].description}`, async () => { + mockGitlabClient.Groups.search.mockResolvedValue([ + { + id: 1, + full_path: 'group1', + }, + { + id: 2, + full_path: 'group1/group2', + }, + { + id: 3, + full_path: 'group1/group2/group3', + }, + ]); + mockGitlabClient.Groups.create.mockResolvedValue({ + id: 4, + full_path: 'group1/group2/group3/group4', + }); + + 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[5].example).steps[0].input, + }); + + expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith( + 'Group 4', + 'group4', + { + parentId: 3, + }, + ); + + expect(mockContext.output).toHaveBeenCalledWith('groupId', 4); + }); }); 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 bbe7ad4722..f379bd38ec 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.examples.ts @@ -102,4 +102,25 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: + 'Create a group nested within another group using path and objects', + example: yaml.stringify({ + steps: [ + { + id: 'gitlabGroup', + name: 'Group', + action: 'gitlab:group:ensureExists', + input: { + repoUrl: 'gitlab.com', + path: [ + 'group1/group2', + { name: 'Group 3', slug: 'group3' }, + { name: 'Group 4', slug: 'group4' }, + ], + }, + }, + ], + }), + }, ]; 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 f9dc12eb54..3d703eb91f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.test.ts @@ -94,6 +94,38 @@ describe('gitlab:group:ensureExists', () => { expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); }); + it('should create a new group from pathstring 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: ['foo/bar', 'baz'], + }, + }); + + expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith('bar', 'bar', { + parentId: 2, + }); + + expect(mockContext.output).toHaveBeenCalledWith('groupId', 3); + }); + it('should create a new group from object if it does not 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 5be5b7c10d..7e5b03ce04 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts @@ -76,11 +76,7 @@ export const createGitlabGroupEnsureExistsAction = (options: { let currentPath: string | null = null; let parentId: number | null = null; - for (const pathElement of path) { - const slug = - typeof pathElement === 'string' ? pathElement : pathElement.slug; - const name = - typeof pathElement === 'string' ? pathElement : pathElement.name; + for (const { name, slug } of pathIterator(path)) { const fullPath: string = currentPath ? `${currentPath}/${slug}` : slug; const result = (await api.Groups.search( fullPath, @@ -119,3 +115,19 @@ export const createGitlabGroupEnsureExistsAction = (options: { }, }); }; + +type PathPart = { name: string; slug: string }; +type PathItem = string | PathPart; + +function* pathIterator(items: PathItem[]): Generator { + for (const item of items) { + if (typeof item === 'string') { + const parts = item.split('/'); + for (const part of parts) { + yield { name: part, slug: part }; + } + } else { + yield item; + } + } +}