Merge pull request #26656 from tlanfer/scaffolder-gitlab-oauth-token

Scaffolder gitlab oauth token
This commit is contained in:
Johan Haals
2024-09-20 11:08:51 +02:00
committed by GitHub
4 changed files with 110 additions and 81 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
---
Updated `gitlab:group:ensureExists` action to instead use oauth client.
@@ -27,7 +27,8 @@ const mockGitlabClient = {
create: jest.fn(),
},
};
jest.mock('@gitbeaker/node', () => ({
jest.mock('@gitbeaker/rest', () => ({
Gitlab: class {
constructor() {
return mockGitlabClient;
@@ -38,8 +39,8 @@ jest.mock('@gitbeaker/node', () => ({
describe('gitlab:group:ensureExists', () => {
const mockContext = createMockActionContext();
afterEach(() => {
jest.resetAllMocks();
beforeEach(() => {
jest.clearAllMocks();
});
it(`Should ${examples[0].description}`, async () => {
@@ -55,7 +56,7 @@ describe('gitlab:group:ensureExists', () => {
{
host: 'gitlab.com',
token: 'tokenlols',
apiBaseUrl: 'https://api.gitlab.com',
apiBaseUrl: 'https://gitlab.com/api/v4',
},
],
},
@@ -114,7 +115,7 @@ describe('gitlab:group:ensureExists', () => {
'group2',
'group2',
{
parent_id: 1,
parentId: 1,
},
);
@@ -161,7 +162,7 @@ describe('gitlab:group:ensureExists', () => {
'group3',
'group3',
{
parent_id: 2,
parentId: 2,
},
);
@@ -18,6 +18,7 @@ import { ConfigReader } from '@backstage/core-app-api';
import { ScmIntegrations } from '@backstage/integration';
import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils';
import { createGitlabGroupEnsureExistsAction } from './gitlabGroupEnsureExists';
import { getClient } from '../util';
const mockGitlabClient = {
Groups: {
@@ -25,7 +26,8 @@ const mockGitlabClient = {
create: jest.fn(),
},
};
jest.mock('@gitbeaker/node', () => ({
jest.mock('@gitbeaker/rest', () => ({
Gitlab: class {
constructor() {
return mockGitlabClient;
@@ -33,13 +35,33 @@ jest.mock('@gitbeaker/node', () => ({
},
}));
describe('gitlab:group:ensureExists', () => {
const mockContext = createMockActionContext();
jest.mock('../util', () => ({
getClient: jest.fn().mockImplementation(() => mockGitlabClient),
parseRepoUrl: () => ({ host: 'gitlab.com', owner: 'owner', repo: 'repo' }),
}));
afterEach(() => {
jest.resetAllMocks();
describe('gitlab:group:ensureExists', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const config = new ConfigReader({
integrations: {
gitlab: [
{
host: 'gitlab.com',
token: 'tokenlols',
apiBaseUrl: 'https://gitlab.com/api/v4',
},
],
},
});
const integrations = ScmIntegrations.fromConfig(config);
const action = createGitlabGroupEnsureExistsAction({ integrations });
const mockContext = createMockActionContext();
it('should create a new group if it does not exists', async () => {
mockGitlabClient.Groups.search.mockResolvedValue([
{
@@ -57,31 +79,16 @@ describe('gitlab:group:ensureExists', () => {
full_path: 'foo/bar',
});
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: {
repoUrl: 'gitlab.com',
repoUrl: 'gitlab.com?repo=repo&owner=owner',
path: ['foo', 'bar'],
},
});
expect(mockGitlabClient.Groups.create).toHaveBeenCalledWith('bar', 'bar', {
parent_id: 2,
parentId: 2,
});
expect(mockContext.output).toHaveBeenCalledWith('groupId', 3);
@@ -103,25 +110,10 @@ describe('gitlab:group:ensureExists', () => {
},
]);
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: {
repoUrl: 'gitlab.com',
repoUrl: 'gitlab.com?repo=repo&owner=owner',
path: ['foo', 'bar'],
},
});
@@ -132,26 +124,11 @@ describe('gitlab:group:ensureExists', () => {
});
it('should not call API on dryRun', async () => {
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,
isDryRun: true,
input: {
repoUrl: 'gitlab.com',
repoUrl: 'gitlab.com?repo=repo&owner=owner',
path: ['foo', 'bar'],
},
});
@@ -161,4 +138,51 @@ describe('gitlab:group:ensureExists', () => {
expect(mockContext.output).toHaveBeenCalledWith('groupId', 42);
});
it('should use the token from the integration config when none is provided', async () => {
mockGitlabClient.Groups.search.mockResolvedValue([
{
id: 1,
full_path: 'foobar',
},
]);
await action.handler({
...mockContext,
input: {
repoUrl: 'gitlab.com?repo=repo&owner=owner',
path: ['foobar'],
},
});
expect(getClient).toHaveBeenCalledWith(
expect.not.objectContaining({
token: expect.anything(),
}),
);
});
it('should use a provided token as bearer authentication', async () => {
mockGitlabClient.Groups.search.mockResolvedValue([
{
id: 1,
full_path: 'foobar',
},
]);
await action.handler({
...mockContext,
input: {
repoUrl: 'gitlab.com?repo=repo&owner=owner',
path: ['foobar'],
token: 'mysecrettoken',
},
});
expect(getClient).toHaveBeenCalledWith(
expect.objectContaining({
token: 'mysecrettoken',
}),
);
});
});
@@ -17,10 +17,9 @@
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { GroupSchema } from '@gitbeaker/core/dist/types/resources/Groups';
import { Gitlab } from '@gitbeaker/node';
import { z } from 'zod';
import commonGitlabConfig from '../commonGitlabConfig';
import { getToken } from '../util';
import { getClient, parseRepoUrl } from '../util';
import { examples } from './gitlabGroupEnsureExists.examples';
/**
@@ -60,16 +59,14 @@ export const createGitlabGroupEnsureExistsAction = (options: {
return;
}
const { path } = ctx.input;
const { token, integrationConfig } = getToken(ctx.input, integrations);
const { token, repoUrl, path } = ctx.input;
const api = new Gitlab({
host: integrationConfig.config.baseUrl,
token: token,
});
const { host } = parseRepoUrl(repoUrl, integrations);
const api = getClient({ host, integrations, token });
let currentPath: string | null = null;
let parent: GroupSchema | null = null;
let parentId: number | null = null;
for (const pathElement of path) {
const fullPath: string = currentPath
? `${currentPath}/${pathElement}`
@@ -82,22 +79,24 @@ export const createGitlabGroupEnsureExistsAction = (options: {
);
if (!subGroup) {
ctx.logger.info(`creating missing group ${fullPath}`);
parent = await api.Groups.create(
pathElement,
pathElement,
parent
? {
parent_id: parent.id,
}
: {},
);
parentId = (
await api.Groups.create(
pathElement,
pathElement,
parentId
? {
parentId: parentId,
}
: {},
)
)?.id;
} else {
parent = subGroup;
parentId = subGroup.id;
}
currentPath = fullPath;
}
if (parent !== null) {
ctx.output('groupId', parent?.id);
if (parentId !== null) {
ctx.output('groupId', parentId);
}
},
});