From 1cd274040228736628de52b07b19611a0c704486 Mon Sep 17 00:00:00 2001 From: ThomasTroschke Date: Thu, 18 Jan 2024 19:36:27 +0100 Subject: [PATCH 1/6] Added some patches to the plugin-scaffolder-backend-module-gitlab Part2 Signed-off-by: thomastroschke --- .changeset/hungry-lions-sit.md | 5 + packages/backend/package.json | 1 + ...bProjectAccessTokenAction.examples.test.ts | 240 +++++------------- ...GitlabProjectAccessTokenAction.examples.ts | 3 +- .../createGitlabProjectAccessTokenAction.ts | 106 +++++--- yarn.lock | 4 +- 6 files changed, 156 insertions(+), 203 deletions(-) create mode 100644 .changeset/hungry-lions-sit.md diff --git a/.changeset/hungry-lions-sit.md b/.changeset/hungry-lions-sit.md new file mode 100644 index 0000000000..76a46aacde --- /dev/null +++ b/.changeset/hungry-lions-sit.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': patch +--- + +Establishing compatibility of scaffolder action gitlab:projectAccessToken:create with GitLab version ^16 by introducing the expired at parameter. diff --git a/packages/backend/package.json b/packages/backend/package.json index 2386d799a9..b8b2961870 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -63,6 +63,7 @@ "@backstage/plugin-rollbar-backend": "workspace:^", "@backstage/plugin-scaffolder-backend": "workspace:^", "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^", + "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^", "@backstage/plugin-scaffolder-backend-module-rails": "workspace:^", "@backstage/plugin-search-backend": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.test.ts index 6a809fc386..ab4fe0e637 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.test.ts @@ -13,23 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { getVoidLogger } from '@backstage/backend-common'; +import { ConfigReader } from '@backstage/config'; +import { ScmIntegrations } from '@backstage/integration'; +import { PassThrough } from 'stream'; import yaml from 'yaml'; import { createGitlabProjectAccessTokenAction } from './createGitlabProjectAccessTokenAction'; // Adjust the import based on your project structure -import { ScmIntegrations } from '@backstage/integration'; -import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; -import { PassThrough } from 'stream'; import { examples } from './createGitlabProjectAccessTokenAction.examples'; +import { DateTime } from 'luxon'; + jest.mock('node-fetch'); const mockGitlabClient = { - ProjectDeployTokens: { + ProjectAccessTokens: { create: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -73,231 +75,127 @@ describe('gitlab:projectAccessToken:create examples', () => { }); it('Create a GitLab project access token with minimal options.', async () => { - const fetchMock = jest.spyOn(global, 'fetch'); - const mockResponse = { - token: 'mock-access-token', - }; - - fetchMock.mockResolvedValue({ - json: async () => mockResponse, - } as Response); - - jest.mock('../util', () => ({ - getToken: jest.fn().mockReturnValue({ - token: 'mock-api-token', - integrationConfig: { config: { baseUrl: 'https://api.gitlab.com' } }, - }), - })); + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); const input = yaml.parse(examples[0].example).steps[0].input; - await action.handler({ ...mockContext, input, }); - expect(fetchMock).toHaveBeenCalledWith( - 'https://gitlab.com/api/v4/projects/456/access_tokens', + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '456', + 'tokenname', + ['read_repository'], { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': 'tokenlols', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: undefined, - scopes: undefined, - access_level: undefined, - }), + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); - expect(mockContext.output).toHaveBeenCalledWith( - 'access_token', - 'mock-access-token', - ); + + expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); it('Create a GitLab project access token with custom scopes.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); + const input = yaml.parse(examples[1].example).steps[0].input; - - const mockResponse = { - token: 'mock-access-token', - }; - - const fetchMock = jest.spyOn(global, 'fetch'); - fetchMock.mockResolvedValue({ - json: async () => mockResponse, - } as Response); - - jest.mock('../util', () => ({ - getToken: jest.fn().mockReturnValue({ - token: 'mock-api-token', - integrationConfig: { config: { baseUrl: 'https://api.gitlab.com' } }, - }), - })); - await action.handler({ ...mockContext, input, }); - expect(fetchMock).toHaveBeenCalledWith( - 'https://gitlab.com/api/v4/projects/789/access_tokens', + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '789', + 'tokenname', + ['read_registry', 'write_repository'], { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': 'tokenlols', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: undefined, - scopes: ['read_registry', 'write_repository'], - access_level: undefined, - }), + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); - expect(mockContext.output).toHaveBeenCalledWith( - 'access_token', - 'mock-access-token', - ); + expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); it('Create a GitLab project access token with a specified name.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); + const input = yaml.parse(examples[2].example).steps[0].input; - - const mockResponse = { - token: 'mock-access-token', - }; - - const fetchMock = jest.spyOn(global, 'fetch'); - fetchMock.mockResolvedValue({ - json: async () => mockResponse, - } as Response); - - jest.mock('../util', () => ({ - getToken: jest.fn().mockReturnValue({ - token: 'mock-api-token', - integrationConfig: { config: { baseUrl: 'https://api.gitlab.com' } }, - }), - })); - await action.handler({ ...mockContext, input, }); - expect(fetchMock).toHaveBeenCalledWith( - 'https://gitlab.com/api/v4/projects/101112/access_tokens', + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '101112', + 'my-custom-token', + ['read_repository'], { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': 'tokenlols', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: 'my-custom-token', - scopes: undefined, - access_level: undefined, - }), + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); - expect(mockContext.output).toHaveBeenCalledWith( - 'access_token', - 'mock-access-token', - ); + expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); it('Create a GitLab project access token with a numeric project ID.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); + const input = yaml.parse(examples[3].example).steps[0].input; - - const mockResponse = { - token: 'mock-access-token', - }; - - const fetchMock = jest.spyOn(global, 'fetch'); - fetchMock.mockResolvedValue({ - json: async () => mockResponse, - } as Response); - - jest.mock('../util', () => ({ - getToken: jest.fn().mockReturnValue({ - token: 'mock-api-token', - integrationConfig: { config: { baseUrl: 'https://api.gitlab.com' } }, - }), - })); - await action.handler({ ...mockContext, input, }); - expect(fetchMock).toHaveBeenCalledWith( - 'https://gitlab.com/api/v4/projects/42/access_tokens', + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + 42, + 'tokenname', + ['read_repository'], { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': 'tokenlols', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: undefined, - scopes: undefined, - access_level: undefined, - }), + accessLevel: 40, + expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); - expect(mockContext.output).toHaveBeenCalledWith( - 'access_token', - 'mock-access-token', - ); + expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); - it('Create a GitLab project access token using specific GitLab integrations.', async () => { + it('Create a GitLab project access token with a specified expired Date.', async () => { + mockGitlabClient.ProjectAccessTokens.create.mockResolvedValue({ + token: 'TOKEN', + username: 'User', + }); + const input = yaml.parse(examples[4].example).steps[0].input; - - const mockResponse = { - token: 'mock-access-token', - }; - - const fetchMock = jest.spyOn(global, 'fetch'); - fetchMock.mockResolvedValue({ - json: async () => mockResponse, - } as Response); - - jest.mock('../util', () => ({ - getToken: jest.fn().mockReturnValue({ - token: 'mock-api-token', - integrationConfig: { config: { baseUrl: 'https://api.gitlab.com' } }, - }), - })); - await action.handler({ ...mockContext, input, }); - expect(fetchMock).toHaveBeenCalledWith( - 'https://gitlab.com/api/v4/projects/123/access_tokens', + expect(mockGitlabClient.ProjectAccessTokens.create).toHaveBeenCalledWith( + '123', + 'tokenname', + ['read_repository'], { - method: 'POST', - headers: { - 'PRIVATE-TOKEN': 'tokenlols', - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: undefined, - scopes: undefined, - access_level: undefined, - }), + accessLevel: 40, + expiresAt: '2024-06-25', }, ); - expect(mockContext.output).toHaveBeenCalledWith( - 'access_token', - 'mock-access-token', - ); + expect(mockContext.output).toHaveBeenCalledWith('access_token', 'TOKEN'); }); }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.ts index 5fe157badf..8d4f335a46 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.examples.ts @@ -86,7 +86,7 @@ export const examples: TemplateExample[] = [ }, { description: - 'Create a GitLab project access token using specific GitLab integrations.', + 'Create a GitLab project access token with a specified expired Date.', example: yaml.stringify({ steps: [ { @@ -96,6 +96,7 @@ export const examples: TemplateExample[] = [ input: { repoUrl: 'gitlab.com?repo=repo&owner=owner', projectId: '123', + expiresAt: '2024-06-25', }, }, ], diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts index a050b3c1b4..4ee9375064 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts @@ -14,11 +14,14 @@ * limitations under the License. */ -import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import commonGitlabConfig from '../commonGitlabConfig'; -import { getToken } from '../util'; +import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; +import { AccessTokenScopes } from '@gitbeaker/core'; +import { Gitlab } from '@gitbeaker/rest'; +import { DateTime } from 'luxon'; import { z } from 'zod'; +import { getToken } from '../util'; import { examples } from './createGitlabProjectAccessTokenAction.examples'; /** @@ -27,6 +30,9 @@ import { examples } from './createGitlabProjectAccessTokenAction.examples'; * @param options - Templating configuration. * @public */ + +const gitbeakerAccessTokenScopesType: z.ZodType = z.any(); + export const createGitlabProjectAccessTokenAction = (options: { integrations: ScmIntegrationRegistry; }) => { @@ -35,46 +41,86 @@ export const createGitlabProjectAccessTokenAction = (options: { id: 'gitlab:projectAccessToken:create', examples, schema: { - input: commonGitlabConfig.merge( - z.object({ - projectId: z.union([z.number(), z.string()], { - description: 'Project ID', - }), - name: z.string({ description: 'Deploy Token Name' }).optional(), - accessLevel: z - .number({ description: 'Access Level of the Token' }) - .optional(), - scopes: z.array(z.string(), { description: 'Scopes' }).optional(), + input: z.object({ + projectId: z.number({ + description: 'Project ID/Name(slug) of the Gitlab Project', }), - ), + name: z.string({ description: 'Name of Access Key' }).optional(), + repoUrl: z.string({ description: 'URL to gitlab instance' }), + accessLevel: z + .number({ + description: + 'Access Level of the Token, 10 (Guest), 20 (Reporter), 30 (Developer), 40 (Maintainer), and 50 (Owner)', + }) + .optional(), + scopes: gitbeakerAccessTokenScopesType, + expiresAt: z + .string({ + description: + 'Expiration date of the access token in ISO format (YYYY-MM-DD). If Empty, it will set to the maximum of 365 days.', + }) + .optional(), + token: z + .string({ + description: 'The token to use for authorization to GitLab', + }) + .optional(), + }), output: z.object({ access_token: z.string({ description: 'Access Token' }), }), }, async handler(ctx) { ctx.logger.info(`Creating Token for Project "${ctx.input.projectId}"`); - const { projectId, name, accessLevel, scopes } = ctx.input; + const { + projectId, + name = 'tokenname', + accessLevel = 40, + scopes = ['read_repository'], + expiresAt, + } = ctx.input; + const { token, integrationConfig } = getToken(ctx.input, integrations); - const response = await fetch( - `${integrationConfig.config.baseUrl}/api/v4/projects/${projectId}/access_tokens`, + if (!integrationConfig.config.token && token) { + throw new InputError( + `No token available for host ${integrationConfig.config.baseUrl}`, + ); + } + + let api; + + if (!ctx.input.token) { + api = new Gitlab({ + host: integrationConfig.config.baseUrl, + token: token, + }); + } else { + api = new Gitlab({ + host: integrationConfig.config.baseUrl, + oauthToken: token, + }); + } + + const mappedAccessLevel = Number(accessLevel.valueOf()) as AccessLevel; + + const response = await api.ProjectAccessTokens.create( + projectId, + name, + scopes, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. - headers: { - 'PRIVATE-TOKEN': token, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: name, - scopes: scopes, - access_level: accessLevel, - }), + expiresAt: + expiresAt || DateTime.now().plus({ days: 365 }).toISODate()!, + accessLevel: mappedAccessLevel, }, ); + if (!response.token) { + throw new Error('Could not create project access token'); + } - const result = await response.json(); - - ctx.output('access_token', result.token); + ctx.output('access_token', response.token); }, }); }; + +declare type AccessLevel = 0 | 5 | 10 | 20 | 30 | 40 | 50; diff --git a/yarn.lock b/yarn.lock index 8c0ddcabc2..703e7debab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8385,6 +8385,7 @@ __metadata: "@gitbeaker/node": ^35.8.0 "@gitbeaker/rest": ^39.25.0 jest-date-mock: ^1.0.8 + luxon: ^3.4.4 yaml: ^2.0.0 zod: ^3.22.4 languageName: unknown @@ -26885,6 +26886,7 @@ __metadata: "@backstage/plugin-rollbar-backend": "workspace:^" "@backstage/plugin-scaffolder-backend": "workspace:^" "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "workspace:^" + "@backstage/plugin-scaffolder-backend-module-gitlab": "workspace:^" "@backstage/plugin-scaffolder-backend-module-rails": "workspace:^" "@backstage/plugin-search-backend": "workspace:^" "@backstage/plugin-search-backend-module-catalog": "workspace:^" @@ -33297,7 +33299,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3": +"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3, luxon@npm:^3.4.4": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c From 8727e7ada4119f1a11333c072915fd40c5b1cff1 Mon Sep 17 00:00:00 2001 From: thomastroschke Date: Wed, 24 Jan 2024 13:34:39 +0100 Subject: [PATCH 2/6] run new yarn install + DCO commit Signed-off-by: thomastroschke --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 703e7debab..92cba60d60 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8381,7 +8381,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" - "@gitbeaker/core": ^35.8.0 + "@gitbeaker/core": ^39.25.0 "@gitbeaker/node": ^35.8.0 "@gitbeaker/rest": ^39.25.0 jest-date-mock: ^1.0.8 @@ -11260,7 +11260,7 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.0, @gitbeaker/core@npm:^35.8.1": +"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.1": version: 35.8.1 resolution: "@gitbeaker/core@npm:35.8.1" dependencies: From a14c084cad1c132087180e26d7843a84c7a7a687 Mon Sep 17 00:00:00 2001 From: Thomas Troschke Date: Thu, 8 Feb 2024 13:18:28 +0100 Subject: [PATCH 3/6] changed to older Gitbeaker version Signed-off-by: Thomas Troschke --- .../api-report.md | 1 + .../createGitlabProjectAccessTokenAction.ts | 24 ++++++++++--------- .../src/util.ts | 7 +----- yarn.lock | 4 ++-- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/api-report.md b/plugins/scaffolder-backend-module-gitlab/api-report.md index 94aabe9b72..f7ec2edac8 100644 --- a/plugins/scaffolder-backend-module-gitlab/api-report.md +++ b/plugins/scaffolder-backend-module-gitlab/api-report.md @@ -62,6 +62,7 @@ export const createGitlabProjectAccessTokenAction: (options: { name?: string | undefined; accessLevel?: number | undefined; scopes?: string[] | undefined; + expiresAt?: string | undefined; }, { access_token: string; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts index 4ee9375064..7de2dca011 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts @@ -17,7 +17,6 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { AccessTokenScopes } from '@gitbeaker/core'; import { Gitlab } from '@gitbeaker/rest'; import { DateTime } from 'luxon'; import { z } from 'zod'; @@ -31,8 +30,6 @@ import { examples } from './createGitlabProjectAccessTokenAction.examples'; * @public */ -const gitbeakerAccessTokenScopesType: z.ZodType = z.any(); - export const createGitlabProjectAccessTokenAction = (options: { integrations: ScmIntegrationRegistry; }) => { @@ -42,9 +39,14 @@ export const createGitlabProjectAccessTokenAction = (options: { examples, schema: { input: z.object({ - projectId: z.number({ + projectId: z.union([z.number(), z.string()], { description: 'Project ID/Name(slug) of the Gitlab Project', }), + token: z + .string({ + description: 'The token to use for authorization to GitLab', + }) + .optional(), name: z.string({ description: 'Name of Access Key' }).optional(), repoUrl: z.string({ description: 'URL to gitlab instance' }), accessLevel: z @@ -53,18 +55,18 @@ export const createGitlabProjectAccessTokenAction = (options: { 'Access Level of the Token, 10 (Guest), 20 (Reporter), 30 (Developer), 40 (Maintainer), and 50 (Owner)', }) .optional(), - scopes: gitbeakerAccessTokenScopesType, + scopes: z + .string({ + description: 'Scopes for a project access token', + }) + .array() + .optional(), expiresAt: z .string({ description: 'Expiration date of the access token in ISO format (YYYY-MM-DD). If Empty, it will set to the maximum of 365 days.', }) .optional(), - token: z - .string({ - description: 'The token to use for authorization to GitLab', - }) - .optional(), }), output: z.object({ access_token: z.string({ description: 'Access Token' }), @@ -107,7 +109,7 @@ export const createGitlabProjectAccessTokenAction = (options: { const response = await api.ProjectAccessTokens.create( projectId, name, - scopes, + scopes as any, { expiresAt: expiresAt || DateTime.now().plus({ days: 365 }).toISODate()!, diff --git a/plugins/scaffolder-backend-module-gitlab/src/util.ts b/plugins/scaffolder-backend-module-gitlab/src/util.ts index a4d819d490..d897604956 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/util.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/util.ts @@ -19,9 +19,9 @@ import { GitLabIntegration, ScmIntegrationRegistry, } from '@backstage/integration'; +import { Gitlab, GroupSchema } from '@gitbeaker/rest'; import { z } from 'zod'; import commonGitlabConfig from './commonGitlabConfig'; -import { Gitlab, GroupSchema } from '@gitbeaker/rest'; import * as util from './util'; export const parseRepoHost = (repoUrl: string): string => { @@ -50,11 +50,6 @@ export const getToken = ( } const token = config.token || integrationConfig.config.token!; - const tokenType = config.token ? 'oauthToken' : 'token'; - - if (tokenType === 'oauthToken') { - throw new InputError(`OAuth Token is currently not supported`); - } return { token: token, integrationConfig: integrationConfig }; }; diff --git a/yarn.lock b/yarn.lock index 92cba60d60..703e7debab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8381,7 +8381,7 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" - "@gitbeaker/core": ^39.25.0 + "@gitbeaker/core": ^35.8.0 "@gitbeaker/node": ^35.8.0 "@gitbeaker/rest": ^39.25.0 jest-date-mock: ^1.0.8 @@ -11260,7 +11260,7 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.1": +"@gitbeaker/core@npm:^35.6.0, @gitbeaker/core@npm:^35.8.0, @gitbeaker/core@npm:^35.8.1": version: 35.8.1 resolution: "@gitbeaker/core@npm:35.8.1" dependencies: From 3e1f8e95e1862350d4c545511d01ec58802875e6 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 8 Feb 2024 14:04:15 +0100 Subject: [PATCH 4/6] chore: fix deps Signed-off-by: blam --- yarn.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 703e7debab..d374912af0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8385,7 +8385,6 @@ __metadata: "@gitbeaker/node": ^35.8.0 "@gitbeaker/rest": ^39.25.0 jest-date-mock: ^1.0.8 - luxon: ^3.4.4 yaml: ^2.0.0 zod: ^3.22.4 languageName: unknown @@ -33299,7 +33298,7 @@ __metadata: languageName: node linkType: hard -"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3, luxon@npm:^3.4.4": +"luxon@npm:^3.0.0, luxon@npm:^3.3.0, luxon@npm:^3.4.3": version: 3.4.4 resolution: "luxon@npm:3.4.4" checksum: 36c1f99c4796ee4bfddf7dc94fa87815add43ebc44c8934c924946260a58512f0fd2743a629302885df7f35ccbd2d13f178c15df046d0e3b6eb71db178f1c60c From a9027dd983bb07e4d443cfb8c2e1dcec52b0ec4c Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 13 Feb 2024 13:18:28 +0100 Subject: [PATCH 5/6] chore: fixing typescript warnings Signed-off-by: blam --- .../src/actions/createGitlabProjectAccessTokenAction.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts index 7de2dca011..c6e1dfaa8a 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts @@ -104,7 +104,7 @@ export const createGitlabProjectAccessTokenAction = (options: { }); } - const mappedAccessLevel = Number(accessLevel.valueOf()) as AccessLevel; + const mappedAccessLevel = Number(accessLevel.valueOf()); const response = await api.ProjectAccessTokens.create( projectId, @@ -124,5 +124,3 @@ export const createGitlabProjectAccessTokenAction = (options: { }, }); }; - -declare type AccessLevel = 0 | 5 | 10 | 20 | 30 | 40 | 50; From ff3057c5af26cf5624299cb5815393abcbf716df Mon Sep 17 00:00:00 2001 From: blam Date: Tue, 13 Feb 2024 13:26:21 +0100 Subject: [PATCH 6/6] chore: tweak the action a little bit Signed-off-by: blam --- .changeset/hungry-lions-sit.md | 2 +- plugins/scaffolder-backend-module-gitlab/package.json | 1 + .../src/actions/createGitlabProjectAccessTokenAction.ts | 9 ++++----- yarn.lock | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.changeset/hungry-lions-sit.md b/.changeset/hungry-lions-sit.md index 76a46aacde..b283cc976f 100644 --- a/.changeset/hungry-lions-sit.md +++ b/.changeset/hungry-lions-sit.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend-module-gitlab': patch --- -Establishing compatibility of scaffolder action gitlab:projectAccessToken:create with GitLab version ^16 by introducing the expired at parameter. +Use the Gitbeaker library for `gitlab:projectAccessToken:create` action, enabling the `expiresAt` option diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index d0b2fd7dd0..90466025bf 100644 --- a/plugins/scaffolder-backend-module-gitlab/package.json +++ b/plugins/scaffolder-backend-module-gitlab/package.json @@ -49,6 +49,7 @@ "@gitbeaker/core": "^35.8.0", "@gitbeaker/node": "^35.8.0", "@gitbeaker/rest": "^39.25.0", + "luxon": "^3.0.0", "yaml": "^2.0.0", "zod": "^3.22.4" }, diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts index c6e1dfaa8a..2193dbb02f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/createGitlabProjectAccessTokenAction.ts @@ -17,7 +17,7 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { Gitlab } from '@gitbeaker/rest'; +import { AccessTokenScopes, Gitlab } from '@gitbeaker/rest'; import { DateTime } from 'luxon'; import { z } from 'zod'; import { getToken } from '../util'; @@ -104,18 +104,17 @@ export const createGitlabProjectAccessTokenAction = (options: { }); } - const mappedAccessLevel = Number(accessLevel.valueOf()); - const response = await api.ProjectAccessTokens.create( projectId, name, - scopes as any, + scopes as AccessTokenScopes[], { expiresAt: expiresAt || DateTime.now().plus({ days: 365 }).toISODate()!, - accessLevel: mappedAccessLevel, + accessLevel, }, ); + if (!response.token) { throw new Error('Could not create project access token'); } diff --git a/yarn.lock b/yarn.lock index d374912af0..93b4601763 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8385,6 +8385,7 @@ __metadata: "@gitbeaker/node": ^35.8.0 "@gitbeaker/rest": ^39.25.0 jest-date-mock: ^1.0.8 + luxon: ^3.0.0 yaml: ^2.0.0 zod: ^3.22.4 languageName: unknown