Updated the path field in the gitlab:group:ensureExists action to accept an array of objects (with name and slug) besides the existing array of strings

Fixes #28392

Signed-off-by: Jente Sondervorst <jentesondervorst@gmail.com>
This commit is contained in:
Jente Sondervorst
2025-01-10 22:20:09 +01:00
parent 9f04ad87e0
commit 7b6298706b
5 changed files with 131 additions and 9 deletions
+5
View File
@@ -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.
@@ -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);
});
});
@@ -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' },
],
},
},
],
}),
},
];
@@ -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([
{
@@ -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<GroupSchema>; // 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,