Merge pull request #6275 from backstage/mob/scaffolder-git-identity
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend': minor
|
||||
---
|
||||
|
||||
Adding `config: Config` as a required argument to `createBuiltinActions` and downstream methods in order to support configuration of the default git author used for Scaffolder commits.
|
||||
|
||||
The affected methods are:
|
||||
|
||||
- `createBuiltinActions`
|
||||
- `createPublishGithubAction`
|
||||
- `createPublishGitlabAction`
|
||||
- `createPublishBitbucketAction`
|
||||
- `createPublishAzureAction`
|
||||
|
||||
Call sites to these methods will need to be migrated to include the new `config` argument. See `createRouter` in `plugins/scaffolder-backend/src/service/router.ts` for an example of adding this new argument.
|
||||
|
||||
To configure the default git author, use the `defaultAuthor` key under `scaffolder` in `app-config.yaml`:
|
||||
|
||||
```yaml
|
||||
scaffolder:
|
||||
defaultAuthor:
|
||||
name: Example
|
||||
email: example@example.com
|
||||
```
|
||||
@@ -250,6 +250,10 @@ catalog:
|
||||
target: ../catalog-model/examples/acme-corp.yaml
|
||||
|
||||
scaffolder:
|
||||
# Use to customize default commit author info used when new components are created
|
||||
# defaultAuthor:
|
||||
# name: Scaffolder
|
||||
# email: scaffolder@backstage.io
|
||||
github:
|
||||
token: ${GITHUB_TOKEN}
|
||||
visibility: public # or 'internal' or 'private'
|
||||
|
||||
@@ -116,6 +116,7 @@ export const createBuiltinActions: (options: {
|
||||
integrations: ScmIntegrations;
|
||||
catalogClient: CatalogApi;
|
||||
templaters: TemplaterBuilder;
|
||||
config: Config;
|
||||
}) => TemplateAction<any>[];
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -155,11 +156,13 @@ export function createLegacyActions(options: Options): TemplateAction<any>[];
|
||||
// @public (undocumented)
|
||||
export function createPublishAzureAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}): TemplateAction<any>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function createPublishBitbucketAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}): TemplateAction<any>;
|
||||
|
||||
// @public
|
||||
@@ -168,6 +171,7 @@ export function createPublishFileAction(): TemplateAction<any>;
|
||||
// @public (undocumented)
|
||||
export function createPublishGithubAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}): TemplateAction<any>;
|
||||
|
||||
// @public (undocumented)
|
||||
@@ -176,6 +180,7 @@ export const createPublishGithubPullRequestAction: ({ integrations, clientFactor
|
||||
// @public (undocumented)
|
||||
export function createPublishGitlabAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}): TemplateAction<any>;
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
+7
@@ -17,6 +17,13 @@
|
||||
export interface Config {
|
||||
/** Configuration options for the scaffolder plugin */
|
||||
scaffolder?: {
|
||||
/**
|
||||
* The commit author info used when new components are created.
|
||||
*/
|
||||
defaultAuthor?: {
|
||||
name?: string;
|
||||
email?: string;
|
||||
};
|
||||
github?: {
|
||||
[key: string]: string;
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { UrlReader } from '@backstage/backend-common';
|
||||
import { CatalogApi } from '@backstage/catalog-client';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { Config } from '@backstage/config';
|
||||
import { TemplaterBuilder } from '../../stages';
|
||||
import {
|
||||
createCatalogRegisterAction,
|
||||
@@ -41,8 +42,9 @@ export const createBuiltinActions = (options: {
|
||||
integrations: ScmIntegrations;
|
||||
catalogClient: CatalogApi;
|
||||
templaters: TemplaterBuilder;
|
||||
config: Config;
|
||||
}) => {
|
||||
const { reader, integrations, templaters, catalogClient } = options;
|
||||
const { reader, integrations, templaters, catalogClient, config } = options;
|
||||
|
||||
return [
|
||||
createFetchPlainAction({
|
||||
@@ -56,18 +58,22 @@ export const createBuiltinActions = (options: {
|
||||
}),
|
||||
createPublishGithubAction({
|
||||
integrations,
|
||||
config,
|
||||
}),
|
||||
createPublishGithubPullRequestAction({
|
||||
integrations,
|
||||
}),
|
||||
createPublishGitlabAction({
|
||||
integrations,
|
||||
config,
|
||||
}),
|
||||
createPublishBitbucketAction({
|
||||
integrations,
|
||||
config,
|
||||
}),
|
||||
createPublishAzureAction({
|
||||
integrations,
|
||||
config,
|
||||
}),
|
||||
createDebugLogAction(),
|
||||
createCatalogRegisterAction({ catalogClient, integrations }),
|
||||
|
||||
@@ -28,17 +28,17 @@ import { PassThrough } from 'stream';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
|
||||
describe('publish:azure', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
azure: [
|
||||
{ host: 'dev.azure.com', token: 'tokenlols' },
|
||||
{ host: 'myazurehostnotoken.com' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const action = createPublishAzureAction({ integrations });
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
azure: [
|
||||
{ host: 'dev.azure.com', token: 'tokenlols' },
|
||||
{ host: 'myazurehostnotoken.com' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const action = createPublishAzureAction({ integrations, config });
|
||||
const mockContext = {
|
||||
input: {
|
||||
repoUrl: 'dev.azure.com?repo=repo&owner=owner&organization=org',
|
||||
@@ -165,6 +165,7 @@ describe('publish:azure', () => {
|
||||
defaultBranch: 'master',
|
||||
auth: { username: 'notempty', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -187,6 +188,47 @@ describe('publish:azure', () => {
|
||||
defaultBranch: 'master',
|
||||
auth: { username: 'notempty', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call initRepoAndPush with the configured defaultAuthor', async () => {
|
||||
const customAuthorConfig = new ConfigReader({
|
||||
integrations: {
|
||||
azure: [
|
||||
{ host: 'dev.azure.com', token: 'tokenlols' },
|
||||
{ host: 'myazurehostnotoken.com' },
|
||||
],
|
||||
},
|
||||
scaffolder: {
|
||||
defaultAuthor: {
|
||||
name: 'Test',
|
||||
email: 'example@example.com',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const customAuthorIntegrations = ScmIntegrations.fromConfig(
|
||||
customAuthorConfig,
|
||||
);
|
||||
const customAuthorAction = createPublishAzureAction({
|
||||
integrations: customAuthorIntegrations,
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGitClient.createRepository.mockImplementation(() => ({
|
||||
remoteUrl: 'https://dev.azure.com/organization/project/_git/repo',
|
||||
}));
|
||||
|
||||
await customAuthorAction.handler(mockContext);
|
||||
|
||||
expect(initRepoAndPush).toHaveBeenCalledWith({
|
||||
dir: mockContext.workspacePath,
|
||||
remoteUrl: 'https://dev.azure.com/organization/project/_git/repo',
|
||||
auth: { username: 'notempty', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
defaultBranch: 'master',
|
||||
gitAuthorInfo: { name: 'Test', email: 'example@example.com' },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/Git
|
||||
import { getPersonalAccessTokenHandler, WebApi } from 'azure-devops-node-api';
|
||||
import { getRepoSourceDirectory, parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
export function createPublishAzureAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
const { integrations, config } = options;
|
||||
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
@@ -123,6 +125,11 @@ export function createPublishAzureAction(options: {
|
||||
// so it's just the base path I think
|
||||
const repoContentsUrl = remoteUrl;
|
||||
|
||||
const gitAuthorInfo = {
|
||||
name: config.getOptionalString('scaffolder.defaultAuthor.name'),
|
||||
email: config.getOptionalString('scaffolder.defaultAuthor.email'),
|
||||
};
|
||||
|
||||
await initRepoAndPush({
|
||||
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
||||
remoteUrl,
|
||||
@@ -132,6 +139,7 @@ export function createPublishAzureAction(options: {
|
||||
password: integrationConfig.config.token,
|
||||
},
|
||||
logger: ctx.logger,
|
||||
gitAuthorInfo,
|
||||
});
|
||||
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
|
||||
+93
-21
@@ -26,27 +26,27 @@ import { PassThrough } from 'stream';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
|
||||
describe('publish:bitbucket', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
bitbucket: [
|
||||
{
|
||||
host: 'bitbucket.org',
|
||||
token: 'tokenlols',
|
||||
},
|
||||
{
|
||||
host: 'hosted.bitbucket.com',
|
||||
token: 'thing',
|
||||
apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0',
|
||||
},
|
||||
{
|
||||
host: 'notoken.bitbucket.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const action = createPublishBitbucketAction({ integrations });
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
bitbucket: [
|
||||
{
|
||||
host: 'bitbucket.org',
|
||||
token: 'tokenlols',
|
||||
},
|
||||
{
|
||||
host: 'hosted.bitbucket.com',
|
||||
token: 'thing',
|
||||
apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0',
|
||||
},
|
||||
{
|
||||
host: 'notoken.bitbucket.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const action = createPublishBitbucketAction({ integrations, config });
|
||||
const mockContext = {
|
||||
input: {
|
||||
repoUrl: 'bitbucket.org?repo=repo&owner=owner',
|
||||
@@ -289,6 +289,7 @@ describe('publish:bitbucket', () => {
|
||||
defaultBranch: 'master',
|
||||
auth: { username: 'x-token-auth', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -331,6 +332,77 @@ describe('publish:bitbucket', () => {
|
||||
defaultBranch: 'main',
|
||||
auth: { username: 'x-token-auth', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call initAndPush with the configured defaultAuthor', async () => {
|
||||
const customAuthorConfig = new ConfigReader({
|
||||
integrations: {
|
||||
bitbucket: [
|
||||
{
|
||||
host: 'bitbucket.org',
|
||||
token: 'tokenlols',
|
||||
},
|
||||
{
|
||||
host: 'hosted.bitbucket.com',
|
||||
token: 'thing',
|
||||
apiBaseUrl: 'https://hosted.bitbucket.com/rest/api/1.0',
|
||||
},
|
||||
{
|
||||
host: 'notoken.bitbucket.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
scaffolder: {
|
||||
defaultAuthor: {
|
||||
name: 'Test',
|
||||
email: 'example@example.com',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const customAuthorIntegrations = ScmIntegrations.fromConfig(
|
||||
customAuthorConfig,
|
||||
);
|
||||
const customAuthorAction = createPublishBitbucketAction({
|
||||
integrations: customAuthorIntegrations,
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
server.use(
|
||||
rest.post(
|
||||
'https://api.bitbucket.org/2.0/repositories/owner/repo',
|
||||
(_, res, ctx) =>
|
||||
res(
|
||||
ctx.status(200),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({
|
||||
links: {
|
||||
html: {
|
||||
href: 'https://bitbucket.org/owner/repo',
|
||||
},
|
||||
clone: [
|
||||
{
|
||||
name: 'https',
|
||||
href: 'https://bitbucket.org/owner/cloneurl',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await customAuthorAction.handler(mockContext);
|
||||
|
||||
expect(initRepoAndPush).toHaveBeenCalledWith({
|
||||
dir: mockContext.workspacePath,
|
||||
remoteUrl: 'https://bitbucket.org/owner/cloneurl',
|
||||
auth: { username: 'x-token-auth', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
defaultBranch: 'master',
|
||||
gitAuthorInfo: { name: 'Test', email: 'example@example.com' },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import fetch from 'cross-fetch';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
import { getRepoSourceDirectory, parseRepoUrl } from './util';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
const createBitbucketCloudRepository = async (opts: {
|
||||
owner: string;
|
||||
@@ -184,8 +185,9 @@ const performEnableLFS = async (opts: {
|
||||
|
||||
export function createPublishBitbucketAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
const { integrations, config } = options;
|
||||
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
@@ -284,6 +286,11 @@ export function createPublishBitbucketAction(options: {
|
||||
apiBaseUrl,
|
||||
});
|
||||
|
||||
const gitAuthorInfo = {
|
||||
name: config.getOptionalString('scaffolder.defaultAuthor.name'),
|
||||
email: config.getOptionalString('scaffolder.defaultAuthor.email'),
|
||||
};
|
||||
|
||||
await initRepoAndPush({
|
||||
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
||||
remoteUrl,
|
||||
@@ -297,6 +304,7 @@ export function createPublishBitbucketAction(options: {
|
||||
},
|
||||
defaultBranch,
|
||||
logger: ctx.logger,
|
||||
gitAuthorInfo,
|
||||
});
|
||||
|
||||
if (enableLFS && host !== 'bitbucket.org') {
|
||||
|
||||
@@ -25,17 +25,17 @@ import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { when } from 'jest-when';
|
||||
|
||||
describe('publish:github', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
github: [
|
||||
{ host: 'github.com', token: 'tokenlols' },
|
||||
{ host: 'ghe.github.com' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const action = createPublishGithubAction({ integrations });
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
github: [
|
||||
{ host: 'github.com', token: 'tokenlols' },
|
||||
{ host: 'ghe.github.com' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const action = createPublishGithubAction({ integrations, config });
|
||||
const mockContext = {
|
||||
input: {
|
||||
repoUrl: 'github.com?repo=repo&owner=owner',
|
||||
@@ -178,6 +178,7 @@ describe('publish:github', () => {
|
||||
defaultBranch: 'master',
|
||||
auth: { username: 'x-access-token', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -207,6 +208,54 @@ describe('publish:github', () => {
|
||||
defaultBranch: 'main',
|
||||
auth: { username: 'x-access-token', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call initRepoAndPush with the configured defaultAuthor', async () => {
|
||||
const customAuthorConfig = new ConfigReader({
|
||||
integrations: {
|
||||
github: [
|
||||
{ host: 'github.com', token: 'tokenlols' },
|
||||
{ host: 'ghe.github.com' },
|
||||
],
|
||||
},
|
||||
scaffolder: {
|
||||
defaultAuthor: {
|
||||
name: 'Test',
|
||||
email: 'example@example.com',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const customAuthorIntegrations = ScmIntegrations.fromConfig(
|
||||
customAuthorConfig,
|
||||
);
|
||||
const customAuthorAction = createPublishGithubAction({
|
||||
integrations: customAuthorIntegrations,
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGithubClient.users.getByUsername.mockResolvedValue({
|
||||
data: { type: 'User' },
|
||||
});
|
||||
|
||||
mockGithubClient.repos.createForAuthenticatedUser.mockResolvedValue({
|
||||
data: {
|
||||
clone_url: 'https://github.com/clone/url.git',
|
||||
html_url: 'https://github.com/html/url',
|
||||
},
|
||||
});
|
||||
|
||||
await customAuthorAction.handler(mockContext);
|
||||
|
||||
expect(initRepoAndPush).toHaveBeenCalledWith({
|
||||
dir: mockContext.workspacePath,
|
||||
remoteUrl: 'https://github.com/clone/url.git',
|
||||
defaultBranch: 'master',
|
||||
auth: { username: 'x-access-token', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: { name: 'Test', email: 'example@example.com' },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -25,14 +25,16 @@ import {
|
||||
} from '../../../stages/publish/helpers';
|
||||
import { getRepoSourceDirectory, parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
type Permission = 'pull' | 'push' | 'admin' | 'maintain' | 'triage';
|
||||
type Collaborator = { access: Permission; username: string };
|
||||
|
||||
export function createPublishGithubAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
const { integrations, config } = options;
|
||||
|
||||
const credentialsProviders = new Map(
|
||||
integrations.github.list().map(integration => {
|
||||
@@ -248,6 +250,11 @@ export function createPublishGithubAction(options: {
|
||||
const remoteUrl = newRepo.clone_url;
|
||||
const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
|
||||
|
||||
const gitAuthorInfo = {
|
||||
name: config.getOptionalString('scaffolder.defaultAuthor.name'),
|
||||
email: config.getOptionalString('scaffolder.defaultAuthor.email'),
|
||||
};
|
||||
|
||||
await initRepoAndPush({
|
||||
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
||||
remoteUrl,
|
||||
@@ -257,6 +264,7 @@ export function createPublishGithubAction(options: {
|
||||
password: token,
|
||||
},
|
||||
logger: ctx.logger,
|
||||
gitAuthorInfo,
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -24,24 +24,24 @@ import { PassThrough } from 'stream';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
|
||||
describe('publish:gitlab', () => {
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
{
|
||||
host: 'hosted.gitlab.com',
|
||||
apiBaseUrl: 'https://api.hosted.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
const action = createPublishGitlabAction({ integrations });
|
||||
const config = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
{
|
||||
host: 'hosted.gitlab.com',
|
||||
apiBaseUrl: 'https://api.hosted.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const integrations = ScmIntegrations.fromConfig(config);
|
||||
const action = createPublishGitlabAction({ integrations, config });
|
||||
const mockContext = {
|
||||
input: {
|
||||
repoUrl: 'gitlab.com?repo=repo&owner=owner',
|
||||
@@ -143,6 +143,7 @@ describe('publish:gitlab', () => {
|
||||
remoteUrl: 'http://mockurl.git',
|
||||
auth: { username: 'oauth2', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -166,6 +167,55 @@ describe('publish:gitlab', () => {
|
||||
remoteUrl: 'http://mockurl.git',
|
||||
auth: { username: 'oauth2', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
gitAuthorInfo: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('should call initRepoAndPush with the configured defaultAuthor', async () => {
|
||||
const customAuthorConfig = new ConfigReader({
|
||||
integrations: {
|
||||
gitlab: [
|
||||
{
|
||||
host: 'gitlab.com',
|
||||
token: 'tokenlols',
|
||||
apiBaseUrl: 'https://api.gitlab.com',
|
||||
},
|
||||
{
|
||||
host: 'hosted.gitlab.com',
|
||||
apiBaseUrl: 'https://api.hosted.gitlab.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
scaffolder: {
|
||||
defaultAuthor: {
|
||||
name: 'Test',
|
||||
email: 'example@example.com',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const customAuthorIntegrations = ScmIntegrations.fromConfig(
|
||||
customAuthorConfig,
|
||||
);
|
||||
const customAuthorAction = createPublishGitlabAction({
|
||||
integrations: customAuthorIntegrations,
|
||||
config: customAuthorConfig,
|
||||
});
|
||||
|
||||
mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 });
|
||||
mockGitlabClient.Projects.create.mockResolvedValue({
|
||||
http_url_to_repo: 'http://mockurl.git',
|
||||
});
|
||||
|
||||
await customAuthorAction.handler(mockContext);
|
||||
|
||||
expect(initRepoAndPush).toHaveBeenCalledWith({
|
||||
dir: mockContext.workspacePath,
|
||||
remoteUrl: 'http://mockurl.git',
|
||||
auth: { username: 'oauth2', password: 'tokenlols' },
|
||||
logger: mockContext.logger,
|
||||
defaultBranch: 'master',
|
||||
gitAuthorInfo: { name: 'Test', email: 'example@example.com' },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -20,11 +20,13 @@ import { Gitlab } from '@gitbeaker/node';
|
||||
import { initRepoAndPush } from '../../../stages/publish/helpers';
|
||||
import { getRepoSourceDirectory, parseRepoUrl } from './util';
|
||||
import { createTemplateAction } from '../../createTemplateAction';
|
||||
import { Config } from '@backstage/config';
|
||||
|
||||
export function createPublishGitlabAction(options: {
|
||||
integrations: ScmIntegrationRegistry;
|
||||
config: Config;
|
||||
}) {
|
||||
const { integrations } = options;
|
||||
const { integrations, config } = options;
|
||||
|
||||
return createTemplateAction<{
|
||||
repoUrl: string;
|
||||
@@ -121,6 +123,11 @@ export function createPublishGitlabAction(options: {
|
||||
const remoteUrl = (http_url_to_repo as string).replace(/\.git$/, '');
|
||||
const repoContentsUrl = `${remoteUrl}/-/blob/master`;
|
||||
|
||||
const gitAuthorInfo = {
|
||||
name: config.getOptionalString('scaffolder.defaultAuthor.name'),
|
||||
email: config.getOptionalString('scaffolder.defaultAuthor.email'),
|
||||
};
|
||||
|
||||
await initRepoAndPush({
|
||||
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
||||
remoteUrl: http_url_to_repo as string,
|
||||
@@ -130,6 +137,7 @@ export function createPublishGitlabAction(options: {
|
||||
password: integrationConfig.config.token,
|
||||
},
|
||||
logger: ctx.logger,
|
||||
gitAuthorInfo,
|
||||
});
|
||||
|
||||
ctx.output('remoteUrl', remoteUrl);
|
||||
|
||||
@@ -25,12 +25,14 @@ export async function initRepoAndPush({
|
||||
auth,
|
||||
logger,
|
||||
defaultBranch = 'master',
|
||||
gitAuthorInfo,
|
||||
}: {
|
||||
dir: string;
|
||||
remoteUrl: string;
|
||||
auth: { username: string; password: string };
|
||||
logger: Logger;
|
||||
defaultBranch?: string;
|
||||
gitAuthorInfo?: { name?: string; email?: string };
|
||||
}): Promise<void> {
|
||||
const git = Git.fromAuth({
|
||||
username: auth.username,
|
||||
@@ -53,11 +55,17 @@ export async function initRepoAndPush({
|
||||
await git.add({ dir, filepath });
|
||||
}
|
||||
|
||||
// use provided info if possible, otherwise use fallbacks
|
||||
const authorInfo = {
|
||||
name: gitAuthorInfo?.name ?? 'Scaffolder',
|
||||
email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io',
|
||||
};
|
||||
|
||||
await git.commit({
|
||||
dir,
|
||||
message: 'Initial commit',
|
||||
author: { name: 'Scaffolder', email: 'scaffolder@backstage.io' },
|
||||
committer: { name: 'Scaffolder', email: 'scaffolder@backstage.io' },
|
||||
author: authorInfo,
|
||||
committer: authorInfo,
|
||||
});
|
||||
|
||||
await git.addRemote({
|
||||
|
||||
@@ -129,6 +129,7 @@ export async function createRouter(
|
||||
catalogClient,
|
||||
templaters,
|
||||
reader,
|
||||
config,
|
||||
}),
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user