Merge pull request #21752 from backstage/blam/scaffolder-vendor-modules

scaffolder: Split out Actions into smaller modules
This commit is contained in:
Patrik Oldsberg
2023-12-12 16:18:38 +01:00
committed by GitHub
128 changed files with 1875 additions and 1094 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend-module-gitlab': patch
---
Extract some more actions to this library
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-scaffolder-backend': patch
'@backstage/plugin-scaffolder-node': patch
---
Refactor some methods to `-node` instead and use the new external modules
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Updating template generation for scaffolder module
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/plugin-scaffolder-backend-module-bitbucket': minor
'@backstage/plugin-scaffolder-backend-module-gerrit': minor
'@backstage/plugin-scaffolder-backend-module-github': minor
'@backstage/plugin-scaffolder-backend-module-azure': minor
---
Create new scaffolder module for external integrations
+2 -2
View File
@@ -44,8 +44,8 @@ import { version as coreComponents } from '../../../../packages/core-components/
import { version as corePluginApi } from '../../../../packages/core-plugin-api/package.json';
import { version as devUtils } from '../../../../packages/dev-utils/package.json';
import { version as testUtils } from '../../../../packages/test-utils/package.json';
import { version as scaffolderNode } from '../../../../plugins/scaffolder-node/package.json';
import { version as theme } from '../../../../packages/theme/package.json';
import { version as scaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json';
export const packageVersions: Record<string, string> = {
'@backstage/backend-common': backendCommon,
@@ -59,7 +59,7 @@ export const packageVersions: Record<string, string> = {
'@backstage/dev-utils': devUtils,
'@backstage/test-utils': testUtils,
'@backstage/theme': theme,
'@backstage/plugin-scaffolder-backend': scaffolderBackend,
'@backstage/plugin-scaffolder-node': scaffolderNode,
};
export function findVersion() {
@@ -29,7 +29,7 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/plugin-scaffolder-backend": "{{versionQuery '@backstage/plugin-scaffolder-backend'}}"
"@backstage/plugin-scaffolder-node": "{{versionQuery '@backstage/plugin-scaffolder-node'}}"
},
"devDependencies": {
"@backstage/backend-common": "{{versionQuery '@backstage/backend-common'}}",
@@ -1,4 +1,4 @@
import { createTemplateAction } from '@backstage/plugin-scaffolder-backend';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
/**
* Creates an `acme:example` Scaffolder action.
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,5 @@
# @backstage/plugin-scaffolder-backend-module-azure
The azure module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend).
_This plugin was created through the Backstage CLI_
@@ -0,0 +1,28 @@
## API Report File for "@backstage/plugin-scaffolder-backend-module-azure"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
// @public
export function createPublishAzureAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
defaultBranch?: string | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
},
JsonObject
>;
```
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-plugin-scaffolder-backend-module-azure
title: '@backstage/plugin-scaffolder-backend-module-azure'
description: The azure module for @backstage/plugin-scaffolder-backend
spec:
lifecycle: experimental
type: backstage-backend-plugin-module
owner: maintainers
@@ -0,0 +1,40 @@
{
"name": "@backstage/plugin-scaffolder-backend-module-azure",
"description": "The azure module for @backstage/plugin-scaffolder-backend",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"azure-devops-node-api": "^11.0.1",
"yaml": "^2.0.0"
},
"devDependencies": {
"@backstage/cli": "workspace:^"
},
"files": [
"dist"
]
}
@@ -21,7 +21,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { getVoidLogger } from '@backstage/backend-common';
import { WebApi } from 'azure-devops-node-api';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
import { examples } from './azure.examples';
jest.mock('azure-devops-node-api', () => ({
@@ -29,8 +29,9 @@ jest.mock('azure-devops-node-api', () => ({
getPersonalAccessTokenHandler: jest.fn().mockReturnValue(() => {}),
}));
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -19,8 +19,9 @@ jest.mock('azure-devops-node-api', () => ({
getPersonalAccessTokenHandler: jest.fn().mockReturnValue(() => {}),
}));
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -36,7 +37,7 @@ import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { WebApi } from 'azure-devops-node-api';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('publish:azure', () => {
const config = new ConfigReader({
@@ -19,15 +19,18 @@ import {
DefaultAzureDevOpsCredentialsProvider,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { initRepoAndPush } from '../helpers';
import {
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
createTemplateAction,
} from '@backstage/plugin-scaffolder-node';
import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces';
import {
getBearerHandler,
getPersonalAccessTokenHandler,
WebApi,
} from 'azure-devops-node-api';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { Config } from '@backstage/config';
import { examples } from './azure.examples';
@@ -0,0 +1,16 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './azure';
@@ -0,0 +1,23 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A module for the scaffolder backend that lets you interact with azure
*
* @packageDocumentation
*/
export * from './actions';
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,5 @@
# @backstage/plugin-scaffolder-backend-module-bitbucket
The bitbucket module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend).
_This plugin was created through the Backstage CLI_
@@ -0,0 +1,82 @@
## API Report File for "@backstage/plugin-scaffolder-backend-module-bitbucket"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
// @public @deprecated
export function createPublishBitbucketAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
defaultBranch?: string | undefined;
repoVisibility?: 'private' | 'public' | undefined;
sourcePath?: string | undefined;
enableLFS?: boolean | undefined;
token?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
},
JsonObject
>;
// @public
export function createPublishBitbucketCloudAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
defaultBranch?: string | undefined;
repoVisibility?: 'private' | 'public' | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
},
JsonObject
>;
// @public
export function createPublishBitbucketServerAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
defaultBranch?: string | undefined;
repoVisibility?: 'private' | 'public' | undefined;
sourcePath?: string | undefined;
enableLFS?: boolean | undefined;
token?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
},
JsonObject
>;
// @public
export function createPublishBitbucketServerPullRequestAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
title: string;
description?: string | undefined;
targetBranch?: string | undefined;
sourceBranch: string;
token?: string | undefined;
},
JsonObject
>;
```
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-plugin-scaffolder-backend-module-bitbucket
title: '@backstage/plugin-scaffolder-backend-module-bitbucket'
description: The bitbucket module for @backstage/plugin-scaffolder-backend
spec:
lifecycle: experimental
type: backstage-backend-plugin-module
owner: maintainers
@@ -0,0 +1,42 @@
{
"name": "@backstage/plugin-scaffolder-backend-module-bitbucket",
"description": "The bitbucket module for @backstage/plugin-scaffolder-backend",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"node-fetch": "^2.6.7",
"yaml": "^2.0.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"msw": "^1.0.0"
},
"files": [
"dist"
]
}
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
import yaml from 'yaml';
import { sep } from 'path';
import { examples } from './bitbucket.examples';
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -24,7 +25,6 @@ jest.mock('../helpers', () => {
}),
};
});
import { createPublishBitbucketAction } from './bitbucket';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
@@ -33,7 +33,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('publish:bitbucket', () => {
const config = new ConfigReader({
@@ -19,10 +19,13 @@ import {
BitbucketIntegrationConfig,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import fetch, { Response, RequestInit } from 'node-fetch';
import { initRepoAndPush } from '../helpers';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import { Config } from '@backstage/config';
import { examples } from './bitbucket.examples';
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('publish:bitbucketCloud', () => {
const config = new ConfigReader({
@@ -16,10 +16,14 @@
import { InputError } from '@backstage/errors';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import fetch, { Response, RequestInit } from 'node-fetch';
import { initRepoAndPush } from '../helpers';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import { Config } from '@backstage/config';
const createRepository = async (opts: {
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -33,7 +34,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('publish:bitbucketServer', () => {
const config = new ConfigReader({
@@ -19,10 +19,14 @@ import {
getBitbucketServerRequestOptions,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import fetch, { Response, RequestInit } from 'node-fetch';
import { initRepoAndPush } from '../helpers';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import { Config } from '@backstage/config';
const createRepository = async (opts: {
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -19,9 +19,11 @@ import {
getBitbucketServerRequestOptions,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import fetch, { RequestInit, Response } from 'node-fetch';
import { parseRepoUrl } from './util';
import { Config } from '@backstage/config';
const createPullRequest = async (opts: {
@@ -0,0 +1,19 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './bitbucket';
export * from './bitbucketCloud';
export * from './bitbucketServer';
export * from './bitbucketServerPullRequest';
@@ -0,0 +1,23 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A module for the scaffolder backend that lets you interact with bitbucket
*
* @packageDocumentation
*/
export * from './actions';
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,5 @@
# @backstage/plugin-scaffolder-backend-module-gerrit
The gerrit module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend).
_This plugin was created through the Backstage CLI_
@@ -0,0 +1,43 @@
## API Report File for "@backstage/plugin-scaffolder-backend-module-gerrit"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
// @public
export function createPublishGerritAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
description: string;
defaultBranch?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
sourcePath?: string | undefined;
},
JsonObject
>;
// @public
export function createPublishGerritReviewAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
branch?: string | undefined;
sourcePath?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
},
JsonObject
>;
```
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-plugin-scaffolder-backend-module-gerrit
title: '@backstage/plugin-scaffolder-backend-module-gerrit'
description: The gerrit module for @backstage/plugin-scaffolder-backend
spec:
lifecycle: experimental
type: backstage-backend-plugin-module
owner: maintainers
@@ -0,0 +1,42 @@
{
"name": "@backstage/plugin-scaffolder-backend-module-gerrit",
"description": "The gerrit module for @backstage/plugin-scaffolder-backend",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"node-fetch": "^2.6.7",
"yaml": "^2.0.0"
},
"devDependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"msw": "^1.0.0"
},
"files": [
"dist"
]
}
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -34,7 +35,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
describe('publish:gerrit', () => {
const config = new ConfigReader({
@@ -22,10 +22,13 @@ import {
getGerritRequestOptions,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import {
createTemplateAction,
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import fetch, { Response, RequestInit } from 'node-fetch';
import { initRepoAndPush } from '../helpers';
import { examples } from './gerrit.examples';
const createGerritProject = async (
@@ -14,14 +14,19 @@
* limitations under the License.
*/
jest.mock('../helpers');
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
commitAndPushRepo: jest.fn(),
};
});
import { createPublishGerritReviewAction } from './gerritReview';
import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { commitAndPushRepo } from '../helpers';
import { commitAndPushRepo } from '@backstage/plugin-scaffolder-node';
describe('publish:gerrit:review', () => {
const config = new ConfigReader({
@@ -18,9 +18,12 @@ import crypto from 'crypto';
import { InputError } from '@backstage/errors';
import { Config } from '@backstage/config';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import { commitAndPushRepo } from '../helpers';
import {
createTemplateAction,
commitAndPushRepo,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
const generateGerritChangeId = (): string => {
const changeId = crypto.randomBytes(20).toString('hex');
@@ -0,0 +1,17 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './gerrit';
export * from './gerritReview';
@@ -0,0 +1,23 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A module for the scaffolder backend that lets you interact with gerrit
*
* @packageDocumentation
*/
export * from './actions';
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
@@ -0,0 +1,5 @@
# @backstage/plugin-scaffolder-backend-module-github
The github module for [@backstage/plugin-scaffolder-backend](https://www.npmjs.com/package/@backstage/plugin-scaffolder-backend).
_This plugin was created through the Backstage CLI_
@@ -0,0 +1,365 @@
## API Report File for "@backstage/plugin-scaffolder-backend-module-github"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import { createPullRequest } from 'octokit-plugin-create-pull-request';
import { GithubCredentialsProvider } from '@backstage/integration';
import { JsonObject } from '@backstage/types';
import { Octokit } from 'octokit';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { ScmIntegrations } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
// @public
export function createGithubActionsDispatchAction(options: {
integrations: ScmIntegrations;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
workflowId: string;
branchOrTagName: string;
workflowInputs?:
| {
[key: string]: string;
}
| undefined;
token?: string | undefined;
},
JsonObject
>;
// @public
export function createGithubDeployKeyAction(options: {
integrations: ScmIntegrationRegistry;
}): TemplateAction<
{
repoUrl: string;
publicKey: string;
privateKey: string;
deployKeyName: string;
privateKeySecretName?: string | undefined;
token?: string | undefined;
},
JsonObject
>;
// @public
export function createGithubEnvironmentAction(options: {
integrations: ScmIntegrationRegistry;
}): TemplateAction<
{
repoUrl: string;
name: string;
deploymentBranchPolicy?:
| {
protected_branches: boolean;
custom_branch_policies: boolean;
}
| undefined;
customBranchPolicyNames?: string[] | undefined;
environmentVariables?:
| {
[key: string]: string;
}
| undefined;
secrets?:
| {
[key: string]: string;
}
| undefined;
token?: string | undefined;
},
JsonObject
>;
// @public
export function createGithubIssuesLabelAction(options: {
integrations: ScmIntegrationRegistry;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
number: number;
labels: string[];
token?: string | undefined;
},
JsonObject
>;
// @public
export interface CreateGithubPullRequestActionOptions {
clientFactory?: (input: {
integrations: ScmIntegrationRegistry;
githubCredentialsProvider?: GithubCredentialsProvider;
host: string;
owner: string;
repo: string;
token?: string;
}) => Promise<
Octokit & {
createPullRequest(options: createPullRequest.Options): Promise<{
data: {
html_url: string;
number: number;
base: {
ref: string;
};
};
} | null>;
}
>;
githubCredentialsProvider?: GithubCredentialsProvider;
integrations: ScmIntegrationRegistry;
}
// @public
export function createGithubRepoCreateAction(options: {
integrations: ScmIntegrationRegistry;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
homepage?: string | undefined;
access?: string | undefined;
deleteBranchOnMerge?: boolean | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
allowRebaseMerge?: boolean | undefined;
allowSquashMerge?: boolean | undefined;
squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined;
squashMergeCommitMessage?:
| 'PR_BODY'
| 'COMMIT_MESSAGES'
| 'BLANK'
| undefined;
allowMergeCommit?: boolean | undefined;
allowAutoMerge?: boolean | undefined;
requireCodeOwnerReviews?: boolean | undefined;
bypassPullRequestAllowances?:
| {
users?: string[] | undefined;
teams?: string[] | undefined;
apps?: string[] | undefined;
}
| undefined;
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
users: string[];
teams: string[];
apps?: string[] | undefined;
}
| undefined;
requiredStatusCheckContexts?: string[] | undefined;
requireBranchesToBeUpToDate?: boolean | undefined;
requiredConversationResolution?: boolean | undefined;
repoVisibility?: 'internal' | 'private' | 'public' | undefined;
collaborators?:
| (
| {
user: string;
access: string;
}
| {
team: string;
access: string;
}
| {
username: string;
access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage';
}
)[]
| undefined;
hasProjects?: boolean | undefined;
hasWiki?: boolean | undefined;
hasIssues?: boolean | undefined;
token?: string | undefined;
topics?: string[] | undefined;
repoVariables?:
| {
[key: string]: string;
}
| undefined;
secrets?:
| {
[key: string]: string;
}
| undefined;
requireCommitSigning?: boolean | undefined;
},
JsonObject
>;
// @public
export function createGithubRepoPushAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
defaultBranch?: string | undefined;
protectDefaultBranch?: boolean | undefined;
protectEnforceAdmins?: boolean | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
requireCodeOwnerReviews?: boolean | undefined;
dismissStaleReviews?: boolean | undefined;
bypassPullRequestAllowances?:
| {
users?: string[];
teams?: string[];
apps?: string[];
}
| undefined;
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
users: string[];
teams: string[];
apps?: string[];
}
| undefined;
requiredStatusCheckContexts?: string[] | undefined;
requireBranchesToBeUpToDate?: boolean | undefined;
requiredConversationResolution?: boolean | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
requiredCommitSigning?: boolean | undefined;
},
JsonObject
>;
// @public
export function createGithubWebhookAction(options: {
integrations: ScmIntegrationRegistry;
defaultWebhookSecret?: string;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
webhookUrl: string;
webhookSecret?: string | undefined;
events?: string[] | undefined;
active?: boolean | undefined;
contentType?: 'form' | 'json' | undefined;
insecureSsl?: boolean | undefined;
token?: string | undefined;
},
JsonObject
>;
// @public
export function createPublishGithubAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
githubCredentialsProvider?: GithubCredentialsProvider;
}): TemplateAction<
{
repoUrl: string;
description?: string | undefined;
homepage?: string | undefined;
access?: string | undefined;
defaultBranch?: string | undefined;
protectDefaultBranch?: boolean | undefined;
protectEnforceAdmins?: boolean | undefined;
deleteBranchOnMerge?: boolean | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
allowRebaseMerge?: boolean | undefined;
allowSquashMerge?: boolean | undefined;
squashMergeCommitTitle?: 'PR_TITLE' | 'COMMIT_OR_PR_TITLE' | undefined;
squashMergeCommitMessage?:
| 'PR_BODY'
| 'COMMIT_MESSAGES'
| 'BLANK'
| undefined;
allowMergeCommit?: boolean | undefined;
allowAutoMerge?: boolean | undefined;
sourcePath?: string | undefined;
bypassPullRequestAllowances?:
| {
users?: string[];
teams?: string[];
apps?: string[];
}
| undefined;
requiredApprovingReviewCount?: number | undefined;
restrictions?:
| {
users: string[];
teams: string[];
apps?: string[];
}
| undefined;
requireCodeOwnerReviews?: boolean | undefined;
dismissStaleReviews?: boolean | undefined;
requiredStatusCheckContexts?: string[] | undefined;
requireBranchesToBeUpToDate?: boolean | undefined;
requiredConversationResolution?: boolean | undefined;
repoVisibility?: 'internal' | 'private' | 'public' | undefined;
collaborators?:
| (
| {
user: string;
access: string;
}
| {
team: string;
access: string;
}
| {
username: string;
access: 'pull' | 'push' | 'admin' | 'maintain' | 'triage';
}
)[]
| undefined;
hasProjects?: boolean | undefined;
hasWiki?: boolean | undefined;
hasIssues?: boolean | undefined;
token?: string | undefined;
topics?: string[] | undefined;
repoVariables?:
| {
[key: string]: string;
}
| undefined;
secrets?:
| {
[key: string]: string;
}
| undefined;
requiredCommitSigning?: boolean | undefined;
},
JsonObject
>;
// @public
export const createPublishGithubPullRequestAction: (
options: CreateGithubPullRequestActionOptions,
) => TemplateAction<
{
title: string;
branchName: string;
targetBranchName?: string | undefined;
description: string;
repoUrl: string;
draft?: boolean | undefined;
targetPath?: string | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
reviewers?: string[] | undefined;
teamReviewers?: string[] | undefined;
commitMessage?: string | undefined;
update?: boolean | undefined;
},
JsonObject
>;
```
@@ -0,0 +1,10 @@
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: backstage-plugin-scaffolder-backend-module-github
title: '@backstage/plugin-scaffolder-backend-module-github'
description: The github module for @backstage/plugin-scaffolder-backend
spec:
lifecycle: experimental
type: backstage-backend-plugin-module
owner: maintainers
@@ -0,0 +1,49 @@
{
"name": "@backstage/plugin-scaffolder-backend-module-github",
"description": "The github module for @backstage/plugin-scaffolder-backend",
"version": "0.0.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"backstage": {
"role": "backend-plugin-module"
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"@octokit/webhooks": "^10.0.0",
"libsodium-wrappers": "^0.7.11",
"octokit": "^2.0.0",
"octokit-plugin-create-pull-request": "^3.10.0",
"winston": "^3.2.1",
"yaml": "^2.0.0"
},
"devDependencies": {
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@types/libsodium-wrappers": "^0.7.10",
"fs-extra": "10.1.0",
"jest-when": "^3.1.0",
"jsonschema": "^1.2.6"
},
"files": [
"dist"
]
}
@@ -14,121 +14,11 @@
* limitations under the License.
*/
import { Git } from '@backstage/backend-common';
import { Config } from '@backstage/config';
import { assertError } from '@backstage/errors';
import { Octokit } from 'octokit';
import { Logger } from 'winston';
export async function initRepoAndPush({
dir,
remoteUrl,
auth,
logger,
defaultBranch = 'master',
commitMessage = 'Initial commit',
gitAuthorInfo,
}: {
dir: string;
remoteUrl: string;
// For use cases where token has to be used with Basic Auth
// it has to be provided as password together with a username
// which may be a fixed value defined by the provider.
auth: { username: string; password: string } | { token: string };
logger: Logger;
defaultBranch?: string;
commitMessage?: string;
gitAuthorInfo?: { name?: string; email?: string };
}): Promise<{ commitHash: string }> {
const git = Git.fromAuth({
...auth,
logger,
});
await git.init({
dir,
defaultBranch,
});
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',
};
const commitHash = await git.commit({
dir,
message: commitMessage,
author: authorInfo,
committer: authorInfo,
});
await git.addRemote({
dir,
url: remoteUrl,
remote: 'origin',
});
await git.push({
dir,
remote: 'origin',
});
return { commitHash };
}
export async function commitAndPushRepo({
dir,
auth,
logger,
commitMessage,
gitAuthorInfo,
branch = 'master',
remoteRef,
}: {
dir: string;
// For use cases where token has to be used with Basic Auth
// it has to be provided as password together with a username
// which may be a fixed value defined by the provider.
auth: { username: string; password: string } | { token: string };
logger: Logger;
commitMessage: string;
gitAuthorInfo?: { name?: string; email?: string };
branch?: string;
remoteRef?: string;
}): Promise<{ commitHash: string }> {
const git = Git.fromAuth({
...auth,
logger,
});
await git.fetch({ dir });
await git.checkout({ dir, ref: branch });
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',
};
const commitHash = await git.commit({
dir,
message: commitMessage,
author: authorInfo,
committer: authorInfo,
});
await git.push({
dir,
remote: 'origin',
remoteRef: remoteRef ?? `refs/heads/${branch}`,
});
return { commitHash };
}
type BranchProtectionOptions = {
client: Octokit;
owner: string;
@@ -13,9 +13,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
jest.mock('../helpers');
jest.mock('./gitHelpers', () => {
return {
...jest.requireActual('./gitHelpers'),
entityRefToName: jest.fn(),
};
});
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
commitAndPushRepo: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
};
});
import {
TemplateAction,
initRepoAndPush,
} from '@backstage/plugin-scaffolder-node';
import { getVoidLogger } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
import {
@@ -24,10 +44,10 @@ import {
ScmIntegrations,
} from '@backstage/integration';
import { PassThrough } from 'stream';
import { entityRefToName, initRepoAndPush } from '../helpers';
import { createPublishGithubAction } from './github';
import { examples } from './github.examples';
import yaml from 'yaml';
import { entityRefToName } from './gitHelpers';
const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU=';
@@ -76,7 +96,7 @@ describe('publish:github', () => {
});
const { entityRefToName: realFamiliarizeEntityName } =
jest.requireActual('../helpers');
jest.requireActual('./helpers');
const integrations = ScmIntegrations.fromConfig(config);
let githubCredentialsProvider: GithubCredentialsProvider;
let action: TemplateAction<any>;
@@ -13,7 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
jest.mock('../helpers');
jest.mock('./gitHelpers', () => {
return {
...jest.requireActual('./gitHelpers'),
enableBranchProtectionOnDefaultRepoBranch: jest.fn(),
entityRefToName: jest.fn(),
};
});
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
commitAndPushRepo: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
};
});
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
import { getVoidLogger } from '@backstage/backend-common';
@@ -25,12 +43,12 @@ import {
} from '@backstage/integration';
import { when } from 'jest-when';
import { PassThrough } from 'stream';
import { createPublishGithubAction } from './github';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
import {
enableBranchProtectionOnDefaultRepoBranch,
entityRefToName,
initRepoAndPush,
} from '../helpers';
import { createPublishGithubAction } from './github';
} from './gitHelpers';
const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU=';
@@ -79,7 +97,7 @@ describe('publish:github', () => {
});
const { entityRefToName: realFamiliarizeEntityName } =
jest.requireActual('../helpers');
jest.requireActual('./gitHelpers');
const integrations = ScmIntegrations.fromConfig(config);
let githubCredentialsProvider: GithubCredentialsProvider;
let action: TemplateAction<any>;
@@ -21,15 +21,17 @@ import {
ScmIntegrationRegistry,
} from '@backstage/integration';
import { Octokit } from 'octokit';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import {
createGithubRepoWithCollaboratorsAndTopics,
getOctokitOptions,
initRepoPushAndProtect,
} from '../github/helpers';
import * as inputProps from '../github/inputProperties';
import * as outputProps from '../github/outputProperties';
import { parseRepoUrl } from './util';
} from './helpers';
import * as inputProps from './inputProperties';
import * as outputProps from './outputProperties';
import { examples } from './github.examples';
/**
@@ -19,9 +19,11 @@ import {
GithubCredentialsProvider,
ScmIntegrations,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { Octokit } from 'octokit';
import { parseRepoUrl } from '../publish/util';
import { getOctokitOptions } from './helpers';
import { examples } from './githubActionsDispatch.examples';
@@ -15,9 +15,11 @@
*/
import { InputError } from '@backstage/errors';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { parseRepoUrl } from '../publish/util';
import { getOctokitOptions } from './helpers';
import { Octokit } from 'octokit';
import Sodium from 'libsodium-wrappers';
@@ -15,9 +15,11 @@
*/
import { InputError } from '@backstage/errors';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { parseRepoUrl } from '../publish/util';
import { getOctokitOptions } from './helpers';
import { Octokit } from 'octokit';
import Sodium from 'libsodium-wrappers';
@@ -18,11 +18,13 @@ import {
GithubCredentialsProvider,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { assertError, InputError } from '@backstage/errors';
import { Octokit } from 'octokit';
import { getOctokitOptions } from './helpers';
import { parseRepoUrl } from '../publish/util';
import { examples } from './githubIssuesLabel.examples';
/**
@@ -23,10 +23,7 @@ import {
ScmIntegrations,
} from '@backstage/integration';
import { PassThrough } from 'stream';
import {
OctokitWithPullRequestPluginClient,
createPublishGithubPullRequestAction,
} from './githubPullRequest';
import { createPublishGithubPullRequestAction } from './githubPullRequest';
import yaml from 'yaml';
import { examples } from './githubPullRequest.examples';
import { createMockDirectory } from '@backstage/backend-test-utils';
@@ -103,9 +100,7 @@ describe('publish:github:pull-request examples', () => {
},
};
const clientFactory = jest.fn(
async () => fakeClient as unknown as OctokitWithPullRequestPluginClient,
);
const clientFactory = jest.fn(async () => fakeClient as any);
mockDir.setContent({
[workspacePath]: { 'file.txt': 'Hello there!' },
@@ -26,10 +26,7 @@ import {
} from '@backstage/plugin-scaffolder-node';
import fs from 'fs-extra';
import { Writable } from 'stream';
import {
createPublishGithubPullRequestAction,
OctokitWithPullRequestPluginClient,
} from './githubPullRequest';
import { createPublishGithubPullRequestAction } from './githubPullRequest';
import { createMockDirectory } from '@backstage/backend-test-utils';
// Make sure root logger is initialized ahead of FS mock
@@ -78,9 +75,7 @@ describe('createPublishGithubPullRequestAction', () => {
},
},
};
const clientFactory = jest.fn(
async () => fakeClient as unknown as OctokitWithPullRequestPluginClient,
);
const clientFactory = jest.fn(async () => fakeClient as any);
const githubCredentialsProvider: GithubCredentialsProvider = {
getCredentials: jest.fn(),
};
@@ -15,21 +15,21 @@
*/
import path from 'path';
import { parseRepoUrl } from './util';
import {
GithubCredentialsProvider,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
SerializedFile,
serializeDirectoryContents,
} from '@backstage/plugin-scaffolder-node';
import { Octokit } from 'octokit';
import { InputError, CustomErrorBase } from '@backstage/errors';
import { resolveSafeChildPath } from '@backstage/backend-common';
import { createPullRequest } from 'octokit-plugin-create-pull-request';
import { getOctokitOptions } from '../github/helpers';
import {
SerializedFile,
serializeDirectoryContents,
} from '../../../../lib/files';
import { getOctokitOptions } from './helpers';
import { Logger } from 'winston';
import { examples } from './githubPullRequest.examples';
@@ -37,57 +37,32 @@ export type Encoding = 'utf-8' | 'base64';
class GithubResponseError extends CustomErrorBase {}
/** @public */
export type OctokitWithPullRequestPluginClient = Octokit & {
createPullRequest(options: createPullRequest.Options): Promise<{
data: {
html_url: string;
number: number;
base: {
ref: string;
};
};
} | null>;
};
/**
* The options passed to the client factory function.
* @public
*/
export type CreateGithubPullRequestClientFactoryInput = {
integrations: ScmIntegrationRegistry;
githubCredentialsProvider?: GithubCredentialsProvider;
host: string;
owner: string;
repo: string;
token?: string;
};
export const defaultClientFactory = async ({
integrations,
githubCredentialsProvider,
owner,
repo,
host = 'github.com',
token: providedToken,
}: CreateGithubPullRequestClientFactoryInput): Promise<OctokitWithPullRequestPluginClient> => {
const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map(
encodeURIComponent,
);
const octokitOptions = await getOctokitOptions({
export const defaultClientFactory: CreateGithubPullRequestActionOptions['clientFactory'] =
async ({
integrations,
credentialsProvider: githubCredentialsProvider,
repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`,
githubCredentialsProvider,
owner,
repo,
host = 'github.com',
token: providedToken,
});
}) => {
const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map(
encodeURIComponent,
);
const OctokitPR = Octokit.plugin(createPullRequest);
return new OctokitPR({
...octokitOptions,
...{ throttle: { enabled: false } },
});
};
const octokitOptions = await getOctokitOptions({
integrations,
credentialsProvider: githubCredentialsProvider,
repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`,
token: providedToken,
});
const OctokitPR = Octokit.plugin(createPullRequest);
return new OctokitPR({
...octokitOptions,
...{ throttle: { enabled: false } },
});
};
/**
* The options passed to {@link createPublishGithubPullRequestAction} method
@@ -105,9 +80,26 @@ export interface CreateGithubPullRequestActionOptions {
/**
* A method to return the Octokit client with the Pull Request Plugin.
*/
clientFactory?: (
input: CreateGithubPullRequestClientFactoryInput,
) => Promise<OctokitWithPullRequestPluginClient>;
clientFactory?: (input: {
integrations: ScmIntegrationRegistry;
githubCredentialsProvider?: GithubCredentialsProvider;
host: string;
owner: string;
repo: string;
token?: string;
}) => Promise<
Octokit & {
createPullRequest(options: createPullRequest.Options): Promise<{
data: {
html_url: string;
number: number;
base: {
ref: string;
};
};
} | null>;
}
>;
}
type GithubPullRequest = {
@@ -16,7 +16,12 @@
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
jest.mock('../helpers');
jest.mock('./gitHelpers', () => {
return {
...jest.requireActual('./gitHelpers'),
entityRefToName: jest.fn(),
};
});
import { getVoidLogger } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
@@ -27,7 +32,7 @@ import {
} from '@backstage/integration';
import { PassThrough } from 'stream';
import { createGithubRepoCreateAction } from './githubRepoCreate';
import { entityRefToName } from '../helpers';
import { entityRefToName } from './gitHelpers';
import yaml from 'yaml';
import { examples } from './githubRepoCreate.examples';
@@ -16,7 +16,12 @@
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
jest.mock('../helpers');
jest.mock('./gitHelpers', () => {
return {
...jest.requireActual('./gitHelpers'),
entityRefToName: jest.fn(),
};
});
import { getVoidLogger } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
@@ -28,7 +33,7 @@ import {
import { when } from 'jest-when';
import { PassThrough } from 'stream';
import { createGithubRepoCreateAction } from './githubRepoCreate';
import { entityRefToName } from '../helpers';
import { entityRefToName } from './gitHelpers';
const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU=';
@@ -20,8 +20,10 @@ import {
ScmIntegrationRegistry,
} from '@backstage/integration';
import { Octokit } from 'octokit';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { parseRepoUrl } from '../publish/util';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import {
createGithubRepoWithCollaboratorsAndTopics,
getOctokitOptions,
@@ -13,7 +13,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
commitAndPushRepo: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
};
});
import {
TemplateAction,
initRepoAndPush,
} from '@backstage/plugin-scaffolder-node';
import { getVoidLogger } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
import {
@@ -22,7 +37,6 @@ import {
ScmIntegrations,
} from '@backstage/integration';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { createGithubRepoPushAction } from './githubRepoPush';
import { examples } from './githubRepoPush.examples';
import yaml from 'yaml';
@@ -48,7 +62,12 @@ jest.mock('@backstage/backend-common', () => ({
getVoidLogger: jest.requireActual('@backstage/backend-common').getVoidLogger,
}));
jest.mock('../helpers');
jest.mock('./helpers', () => {
return {
...jest.requireActual('./helpers'),
entityRefToName: jest.fn(),
};
});
const initRepoAndPushMocked = initRepoAndPush as jest.Mock<
Promise<{ commitHash: string }>
@@ -98,6 +117,7 @@ describe('github:repo:push examples', () => {
githubCredentialsProvider =
DefaultGithubCredentialsProvider.fromIntegrations(integrations);
action = createGithubRepoPushAction({
integrations,
config,
@@ -35,9 +35,30 @@ jest.mock('@backstage/backend-common', () => ({
getVoidLogger: jest.requireActual('@backstage/backend-common').getVoidLogger,
}));
jest.mock('../helpers');
jest.mock('./gitHelpers', () => {
return {
...jest.requireActual('./gitHelpers'),
entityRefToName: jest.fn(),
enableBranchProtectionOnDefaultRepoBranch: jest.fn(),
};
});
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
commitAndPushRepo: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
};
});
import {
TemplateAction,
initRepoAndPush,
} from '@backstage/plugin-scaffolder-node';
import { getVoidLogger } from '@backstage/backend-common';
import { ConfigReader } from '@backstage/config';
import {
@@ -46,10 +67,7 @@ import {
ScmIntegrations,
} from '@backstage/integration';
import { PassThrough } from 'stream';
import {
enableBranchProtectionOnDefaultRepoBranch,
initRepoAndPush,
} from '../helpers';
import { enableBranchProtectionOnDefaultRepoBranch } from './gitHelpers';
import { createGithubRepoPushAction } from './githubRepoPush';
const initRepoAndPushMocked = initRepoAndPush as jest.Mock<
@@ -21,8 +21,10 @@ import {
ScmIntegrationRegistry,
} from '@backstage/integration';
import { Octokit } from 'octokit';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { parseRepoUrl } from '../publish/util';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { getOctokitOptions, initRepoPushAndProtect } from './helpers';
import * as inputProps from './inputProperties';
import * as outputProps from './outputProperties';
@@ -18,12 +18,14 @@ import {
GithubCredentialsProvider,
ScmIntegrationRegistry,
} from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import {
createTemplateAction,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { emitterEventNames } from '@octokit/webhooks';
import { assertError, InputError } from '@backstage/errors';
import { Octokit } from 'octokit';
import { getOctokitOptions } from './helpers';
import { parseRepoUrl } from '../publish/util';
import { examples } from './githubWebhook.examples';
/**
@@ -24,13 +24,18 @@ import {
import { OctokitOptions } from '@octokit/core/dist-types/types';
import { Octokit } from 'octokit';
import { Logger } from 'winston';
import {
getRepoSourceDirectory,
initRepoAndPush,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import Sodium from 'libsodium-wrappers';
import {
enableBranchProtectionOnDefaultRepoBranch,
initRepoAndPush,
} from '../helpers';
import { getRepoSourceDirectory, parseRepoUrl } from '../publish/util';
import { entityRefToName } from '../../builtin/helpers';
import Sodium from 'libsodium-wrappers';
entityRefToName,
} from './gitHelpers';
const DEFAULT_TIMEOUT_MS = 60_000;
@@ -422,3 +427,12 @@ async function validateAccessTeam(client: Octokit, access: string) {
}
}
}
export function getGitCommitMessage(
gitCommitMessage: string | undefined,
config: Config,
): string | undefined {
return gitCommitMessage
? gitCommitMessage
: config.getOptionalString('scaffolder.defaultCommitMessage');
}
@@ -21,3 +21,9 @@ export { createGithubRepoPushAction } from './githubRepoPush';
export { createGithubWebhookAction } from './githubWebhook';
export { createGithubDeployKeyAction } from './githubDeployKey';
export { createGithubEnvironmentAction } from './githubEnvironment';
export {
createPublishGithubPullRequestAction,
type CreateGithubPullRequestActionOptions,
} from './githubPullRequest';
export { createPublishGithubAction } from './github';
@@ -0,0 +1,23 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* A module for the scaffolder backend that lets you interact with github
*
* @packageDocumentation
*/
export * from './actions';
@@ -3,6 +3,7 @@
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import { JsonObject } from '@backstage/types';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-node';
@@ -74,4 +75,75 @@ export const createGitlabProjectVariableAction: (options: {
},
JsonObject
>;
// @public
export function createPublishGitlabAction(options: {
integrations: ScmIntegrationRegistry;
config: Config;
}): TemplateAction<
{
repoUrl: string;
defaultBranch?: string | undefined;
repoVisibility?: 'internal' | 'private' | 'public' | undefined;
sourcePath?: string | undefined;
token?: string | undefined;
gitCommitMessage?: string | undefined;
gitAuthorName?: string | undefined;
gitAuthorEmail?: string | undefined;
setUserAsOwner?: boolean | undefined;
topics?: string[] | undefined;
settings?:
| {
path?: string | undefined;
auto_devops_enabled?: boolean | undefined;
ci_config_path?: string | undefined;
description?: string | undefined;
topics?: string[] | undefined;
visibility?: 'internal' | 'private' | 'public' | undefined;
}
| undefined;
branches?:
| {
name: string;
protect?: boolean | undefined;
create?: boolean | undefined;
ref?: string | undefined;
}[]
| undefined;
projectVariables?:
| {
key: string;
value: string;
description?: string | undefined;
variable_type?: string | undefined;
protected?: boolean | undefined;
masked?: boolean | undefined;
raw?: boolean | undefined;
environment_scope?: string | undefined;
}[]
| undefined;
},
JsonObject
>;
// @public
export const createPublishGitlabMergeRequestAction: (options: {
integrations: ScmIntegrationRegistry;
}) => TemplateAction<
{
repoUrl: string;
title: string;
description: string;
branchName: string;
targetBranchName?: string | undefined;
sourcePath?: string | undefined;
targetPath?: string | undefined;
token?: string | undefined;
commitAction?: 'update' | 'delete' | 'create' | undefined;
projectid?: string | undefined;
removeSourceBranch?: boolean | undefined;
assignee?: string | undefined;
},
JsonObject
>;
```
@@ -31,16 +31,18 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/integration": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"@gitbeaker/core": "^35.8.0",
"@gitbeaker/node": "^35.8.0",
"yaml": "^2.0.0",
"zod": "^3.21.4"
},
"devDependencies": {
"@backstage/backend-common": "workspace:^",
"@backstage/backend-test-utils": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/core-app-api": "workspace:^"
},
@@ -15,8 +15,9 @@
*/
import yaml from 'yaml';
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -27,11 +28,11 @@ jest.mock('../helpers', () => {
});
import { createPublishGitlabAction } from './gitlab';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { examples } from './gitlab.examples';
const mockGitlabClient = {
@@ -14,8 +14,9 @@
* limitations under the License.
*/
jest.mock('../helpers', () => {
jest.mock('@backstage/plugin-scaffolder-node', () => {
return {
...jest.requireActual('@backstage/plugin-scaffolder-node'),
initRepoAndPush: jest.fn().mockResolvedValue({
commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6',
}),
@@ -30,7 +31,7 @@ import { ScmIntegrations } from '@backstage/integration';
import { ConfigReader } from '@backstage/config';
import { getVoidLogger } from '@backstage/backend-common';
import { PassThrough } from 'stream';
import { initRepoAndPush } from '../helpers';
import { initRepoAndPush } from '@backstage/plugin-scaffolder-node';
const mockGitlabClient = {
Namespaces: {
@@ -18,8 +18,11 @@ import { InputError } from '@backstage/errors';
import { ScmIntegrationRegistry } from '@backstage/integration';
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
import { Gitlab } from '@gitbeaker/node';
import { initRepoAndPush } from '../helpers';
import { getRepoSourceDirectory, parseRepoUrl } from './util';
import {
initRepoAndPush,
getRepoSourceDirectory,
parseRepoUrl,
} from '@backstage/plugin-scaffolder-node';
import { Config } from '@backstage/config';
import { examples } from './gitlab.examples';

Some files were not shown because too many files have changed in this diff Show More