@backstage/plugin-scaffolder-backend 1.2.0-next.0 → 1.3.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -0
- package/dist/index.cjs.js +182 -8
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +27 -1
- package/migrations/20220129100000_created_by.js +38 -0
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,74 @@
|
|
|
1
1
|
# @backstage/plugin-scaffolder-backend
|
|
2
2
|
|
|
3
|
+
## 1.3.0-next.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 72dfcbc8bf: A new scaffolder action has been added: `gerrit:publish`
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 6901f6be4a: Adds more of an explanation when the `publish:github` scaffolder action fails to create a repository.
|
|
12
|
+
- Updated dependencies
|
|
13
|
+
- @backstage/backend-common@0.13.6-next.0
|
|
14
|
+
- @backstage/integration@1.2.1-next.0
|
|
15
|
+
- @backstage/plugin-catalog-backend@1.2.0-next.0
|
|
16
|
+
|
|
17
|
+
## 1.2.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 9818112d12: Update the `github:publish` action to allow passing required status check
|
|
22
|
+
contexts before merging to the main branch.
|
|
23
|
+
- f8baf7df44: Added the ability to reference the user in the `template.yaml` manifest
|
|
24
|
+
- 8d5a2238a9: Split `publish:bitbucket` into `publish:bitbucketCloud` and `publish:bitbucketServer`.
|
|
25
|
+
|
|
26
|
+
In order to migrate from the deprecated action, you need to replace the use of action
|
|
27
|
+
`publish:bitbucket` in your templates with the use of either `publish:bitbucketCloud`
|
|
28
|
+
or `publish:bitbucketServer` - depending on which destination SCM provider you use.
|
|
29
|
+
|
|
30
|
+
Additionally, these actions will not utilize `integrations.bitbucket` anymore,
|
|
31
|
+
but `integrations.bitbucketCloud` or `integrations.bitbucketServer` respectively.
|
|
32
|
+
You may or may not have migrated to these already.
|
|
33
|
+
|
|
34
|
+
As described in a previous changeset, using these two replacement integrations configs
|
|
35
|
+
will not compromise use cases which still rely on `integrations.bitbucket` as this was
|
|
36
|
+
set up in a backwards compatible way.
|
|
37
|
+
|
|
38
|
+
Additionally, please mind that the option `enableLFS` is only available (and always was)
|
|
39
|
+
for Bitbucket Server use cases and therefore, is not even part of the schema for
|
|
40
|
+
`publish:bitbucketCloud` anymore.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- 0fc65cbf89: Override default commit message and author details in GitHub, Azure, bitbucket
|
|
45
|
+
- cfc0f19699: Updated dependency `fs-extra` to `10.1.0`.
|
|
46
|
+
- Updated dependencies
|
|
47
|
+
- @backstage/backend-common@0.13.3
|
|
48
|
+
- @backstage/plugin-catalog-backend@1.1.2
|
|
49
|
+
- @backstage/integration@1.2.0
|
|
50
|
+
- @backstage/plugin-scaffolder-common@1.1.0
|
|
51
|
+
- @backstage/config@1.0.1
|
|
52
|
+
- @backstage/catalog-client@1.0.2
|
|
53
|
+
- @backstage/catalog-model@1.0.2
|
|
54
|
+
|
|
55
|
+
## 1.2.0-next.1
|
|
56
|
+
|
|
57
|
+
### Minor Changes
|
|
58
|
+
|
|
59
|
+
- f8baf7df44: Added the ability to reference the user in the `template.yaml` manifest
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- Updated dependencies
|
|
64
|
+
- @backstage/backend-common@0.13.3-next.2
|
|
65
|
+
- @backstage/plugin-catalog-backend@1.1.2-next.2
|
|
66
|
+
- @backstage/plugin-scaffolder-common@1.1.0-next.0
|
|
67
|
+
- @backstage/config@1.0.1-next.0
|
|
68
|
+
- @backstage/catalog-model@1.0.2-next.0
|
|
69
|
+
- @backstage/integration@1.2.0-next.1
|
|
70
|
+
- @backstage/catalog-client@1.0.2-next.0
|
|
71
|
+
|
|
3
72
|
## 1.2.0-next.0
|
|
4
73
|
|
|
5
74
|
### Minor Changes
|
package/dist/index.cjs.js
CHANGED
|
@@ -16,6 +16,7 @@ var child_process = require('child_process');
|
|
|
16
16
|
var stream = require('stream');
|
|
17
17
|
var azureDevopsNodeApi = require('azure-devops-node-api');
|
|
18
18
|
var fetch = require('node-fetch');
|
|
19
|
+
var crypto = require('crypto');
|
|
19
20
|
var octokit = require('octokit');
|
|
20
21
|
var lodash = require('lodash');
|
|
21
22
|
var octokitPluginCreatePullRequest = require('octokit-plugin-create-pull-request');
|
|
@@ -58,6 +59,7 @@ var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
|
|
|
58
59
|
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
59
60
|
var globby__default = /*#__PURE__*/_interopDefaultLegacy(globby);
|
|
60
61
|
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
|
|
62
|
+
var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
61
63
|
var ObservableImpl__default = /*#__PURE__*/_interopDefaultLegacy(ObservableImpl);
|
|
62
64
|
var winston__namespace = /*#__PURE__*/_interopNamespace(winston);
|
|
63
65
|
var nunjucks__default = /*#__PURE__*/_interopDefaultLegacy(nunjucks);
|
|
@@ -1578,6 +1580,138 @@ function createPublishFileAction() {
|
|
|
1578
1580
|
});
|
|
1579
1581
|
}
|
|
1580
1582
|
|
|
1583
|
+
const createGerritProject = async (config, options) => {
|
|
1584
|
+
const { projectName, parent, owner, description } = options;
|
|
1585
|
+
const fetchOptions = {
|
|
1586
|
+
method: "PUT",
|
|
1587
|
+
body: JSON.stringify({
|
|
1588
|
+
parent,
|
|
1589
|
+
description,
|
|
1590
|
+
owners: [owner],
|
|
1591
|
+
create_empty_commit: false
|
|
1592
|
+
}),
|
|
1593
|
+
headers: {
|
|
1594
|
+
...integration.getGerritRequestOptions(config).headers,
|
|
1595
|
+
"Content-Type": "application/json"
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
const response = await fetch__default["default"](`${config.baseUrl}/a/projects/${encodeURIComponent(projectName)}`, fetchOptions);
|
|
1599
|
+
if (response.status !== 201) {
|
|
1600
|
+
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
const generateCommitMessage = (config, commitSubject) => {
|
|
1604
|
+
const changeId = crypto__default["default"].randomBytes(20).toString("hex");
|
|
1605
|
+
const msg = `${config.getOptionalString("scaffolder.defaultCommitMessage") || commitSubject}
|
|
1606
|
+
|
|
1607
|
+
Change-Id: I${changeId}`;
|
|
1608
|
+
return msg;
|
|
1609
|
+
};
|
|
1610
|
+
function createPublishGerritAction(options) {
|
|
1611
|
+
const { integrations, config } = options;
|
|
1612
|
+
return createTemplateAction({
|
|
1613
|
+
id: "publish:gerrit",
|
|
1614
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Gerrit.",
|
|
1615
|
+
schema: {
|
|
1616
|
+
input: {
|
|
1617
|
+
type: "object",
|
|
1618
|
+
required: ["repoUrl"],
|
|
1619
|
+
properties: {
|
|
1620
|
+
repoUrl: {
|
|
1621
|
+
title: "Repository Location",
|
|
1622
|
+
type: "string"
|
|
1623
|
+
},
|
|
1624
|
+
description: {
|
|
1625
|
+
title: "Repository Description",
|
|
1626
|
+
type: "string"
|
|
1627
|
+
},
|
|
1628
|
+
defaultBranch: {
|
|
1629
|
+
title: "Default Branch",
|
|
1630
|
+
type: "string",
|
|
1631
|
+
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1632
|
+
},
|
|
1633
|
+
gitCommitMessage: {
|
|
1634
|
+
title: "Git Commit Message",
|
|
1635
|
+
type: "string",
|
|
1636
|
+
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
1637
|
+
},
|
|
1638
|
+
gitAuthorName: {
|
|
1639
|
+
title: "Default Author Name",
|
|
1640
|
+
type: "string",
|
|
1641
|
+
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
1642
|
+
},
|
|
1643
|
+
gitAuthorEmail: {
|
|
1644
|
+
title: "Default Author Email",
|
|
1645
|
+
type: "string",
|
|
1646
|
+
description: `Sets the default author email for the commit.`
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
},
|
|
1650
|
+
output: {
|
|
1651
|
+
type: "object",
|
|
1652
|
+
properties: {
|
|
1653
|
+
remoteUrl: {
|
|
1654
|
+
title: "A URL to the repository with the provider",
|
|
1655
|
+
type: "string"
|
|
1656
|
+
},
|
|
1657
|
+
repoContentsUrl: {
|
|
1658
|
+
title: "A URL to the root of the repository",
|
|
1659
|
+
type: "string"
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
},
|
|
1664
|
+
async handler(ctx) {
|
|
1665
|
+
const {
|
|
1666
|
+
repoUrl,
|
|
1667
|
+
description,
|
|
1668
|
+
defaultBranch = "master",
|
|
1669
|
+
gitAuthorName,
|
|
1670
|
+
gitAuthorEmail,
|
|
1671
|
+
gitCommitMessage = "initial commit"
|
|
1672
|
+
} = ctx.input;
|
|
1673
|
+
const { repo, host, owner, workspace } = parseRepoUrl(repoUrl, integrations);
|
|
1674
|
+
const integrationConfig = integrations.gerrit.byHost(host);
|
|
1675
|
+
if (!integrationConfig) {
|
|
1676
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1677
|
+
}
|
|
1678
|
+
if (!owner) {
|
|
1679
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing owner`);
|
|
1680
|
+
}
|
|
1681
|
+
if (!workspace) {
|
|
1682
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
|
|
1683
|
+
}
|
|
1684
|
+
await createGerritProject(integrationConfig.config, {
|
|
1685
|
+
description,
|
|
1686
|
+
owner,
|
|
1687
|
+
projectName: repo,
|
|
1688
|
+
parent: workspace
|
|
1689
|
+
});
|
|
1690
|
+
const auth = {
|
|
1691
|
+
username: integrationConfig.config.username,
|
|
1692
|
+
password: integrationConfig.config.password
|
|
1693
|
+
};
|
|
1694
|
+
const gitAuthorInfo = {
|
|
1695
|
+
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1696
|
+
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1697
|
+
};
|
|
1698
|
+
const remoteUrl = `${integrationConfig.config.cloneUrl}/a/${repo}`;
|
|
1699
|
+
await initRepoAndPush({
|
|
1700
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, void 0),
|
|
1701
|
+
remoteUrl,
|
|
1702
|
+
auth,
|
|
1703
|
+
defaultBranch,
|
|
1704
|
+
logger: ctx.logger,
|
|
1705
|
+
commitMessage: generateCommitMessage(config, gitCommitMessage),
|
|
1706
|
+
gitAuthorInfo
|
|
1707
|
+
});
|
|
1708
|
+
const repoContentsUrl = `${integrationConfig.config.gitilesBaseUrl}/${repo}/+/refs/heads/${defaultBranch}`;
|
|
1709
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
1710
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1711
|
+
}
|
|
1712
|
+
});
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1581
1715
|
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
1582
1716
|
async function getOctokitOptions(options) {
|
|
1583
1717
|
var _a;
|
|
@@ -1803,7 +1937,16 @@ function createPublishGithubAction(options) {
|
|
|
1803
1937
|
allow_squash_merge: allowSquashMerge,
|
|
1804
1938
|
allow_rebase_merge: allowRebaseMerge
|
|
1805
1939
|
});
|
|
1806
|
-
|
|
1940
|
+
let newRepo;
|
|
1941
|
+
try {
|
|
1942
|
+
newRepo = (await repoCreationPromise).data;
|
|
1943
|
+
} catch (e) {
|
|
1944
|
+
errors.assertError(e);
|
|
1945
|
+
if (e.message === "Resource not accessible by integration") {
|
|
1946
|
+
ctx.logger.warn(`The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`);
|
|
1947
|
+
}
|
|
1948
|
+
throw new Error(`Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`);
|
|
1949
|
+
}
|
|
1807
1950
|
if (access == null ? void 0 : access.startsWith(`${owner}/`)) {
|
|
1808
1951
|
const [, team] = access.split("/");
|
|
1809
1952
|
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
@@ -2566,6 +2709,10 @@ const createBuiltinActions = (options) => {
|
|
|
2566
2709
|
reader,
|
|
2567
2710
|
additionalTemplateFilters
|
|
2568
2711
|
}),
|
|
2712
|
+
createPublishGerritAction({
|
|
2713
|
+
integrations,
|
|
2714
|
+
config
|
|
2715
|
+
}),
|
|
2569
2716
|
createPublishGithubAction({
|
|
2570
2717
|
integrations,
|
|
2571
2718
|
config,
|
|
@@ -2653,6 +2800,7 @@ class DatabaseTaskStore {
|
|
|
2653
2800
|
this.db = options.database;
|
|
2654
2801
|
}
|
|
2655
2802
|
async getTask(taskId) {
|
|
2803
|
+
var _a;
|
|
2656
2804
|
const [result] = await this.db("tasks").where({ id: taskId }).select();
|
|
2657
2805
|
if (!result) {
|
|
2658
2806
|
throw new errors.NotFoundError(`No task with id '${taskId}' found`);
|
|
@@ -2666,6 +2814,7 @@ class DatabaseTaskStore {
|
|
|
2666
2814
|
status: result.status,
|
|
2667
2815
|
lastHeartbeatAt: result.last_heartbeat_at,
|
|
2668
2816
|
createdAt: result.created_at,
|
|
2817
|
+
createdBy: (_a = result.created_by) != null ? _a : void 0,
|
|
2669
2818
|
secrets
|
|
2670
2819
|
};
|
|
2671
2820
|
} catch (error) {
|
|
@@ -2673,17 +2822,20 @@ class DatabaseTaskStore {
|
|
|
2673
2822
|
}
|
|
2674
2823
|
}
|
|
2675
2824
|
async createTask(options) {
|
|
2825
|
+
var _a;
|
|
2676
2826
|
const taskId = uuid.v4();
|
|
2677
2827
|
await this.db("tasks").insert({
|
|
2678
2828
|
id: taskId,
|
|
2679
2829
|
spec: JSON.stringify(options.spec),
|
|
2680
2830
|
secrets: options.secrets ? JSON.stringify(options.secrets) : void 0,
|
|
2831
|
+
created_by: (_a = options.createdBy) != null ? _a : null,
|
|
2681
2832
|
status: "open"
|
|
2682
2833
|
});
|
|
2683
2834
|
return { taskId };
|
|
2684
2835
|
}
|
|
2685
2836
|
async claimTask() {
|
|
2686
2837
|
return this.db.transaction(async (tx) => {
|
|
2838
|
+
var _a;
|
|
2687
2839
|
const [task] = await tx("tasks").where({
|
|
2688
2840
|
status: "open"
|
|
2689
2841
|
}).limit(1).select();
|
|
@@ -2707,6 +2859,7 @@ class DatabaseTaskStore {
|
|
|
2707
2859
|
status: "processing",
|
|
2708
2860
|
lastHeartbeatAt: task.last_heartbeat_at,
|
|
2709
2861
|
createdAt: task.created_at,
|
|
2862
|
+
createdBy: (_a = task.created_by) != null ? _a : void 0,
|
|
2710
2863
|
secrets
|
|
2711
2864
|
};
|
|
2712
2865
|
} catch (error) {
|
|
@@ -2825,6 +2978,9 @@ class TaskManager {
|
|
|
2825
2978
|
get secrets() {
|
|
2826
2979
|
return this.task.secrets;
|
|
2827
2980
|
}
|
|
2981
|
+
get createdBy() {
|
|
2982
|
+
return this.task.createdBy;
|
|
2983
|
+
}
|
|
2828
2984
|
async getWorkspaceName() {
|
|
2829
2985
|
return this.task.taskId;
|
|
2830
2986
|
}
|
|
@@ -2884,7 +3040,8 @@ class StorageTaskBroker {
|
|
|
2884
3040
|
return TaskManager.create({
|
|
2885
3041
|
taskId: pendingTask.id,
|
|
2886
3042
|
spec: pendingTask.spec,
|
|
2887
|
-
secrets: pendingTask.secrets
|
|
3043
|
+
secrets: pendingTask.secrets,
|
|
3044
|
+
createdBy: pendingTask.createdBy
|
|
2888
3045
|
}, this.storage, this.logger);
|
|
2889
3046
|
}
|
|
2890
3047
|
await this.waitForDispatch();
|
|
@@ -3035,7 +3192,8 @@ class NunjucksWorkflowRunner {
|
|
|
3035
3192
|
await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);
|
|
3036
3193
|
const context = {
|
|
3037
3194
|
parameters: task.spec.parameters,
|
|
3038
|
-
steps: {}
|
|
3195
|
+
steps: {},
|
|
3196
|
+
user: task.spec.user
|
|
3039
3197
|
};
|
|
3040
3198
|
for (const step of task.spec.steps) {
|
|
3041
3199
|
try {
|
|
@@ -3253,10 +3411,11 @@ async function createRouter(options) {
|
|
|
3253
3411
|
router.get("/v2/templates/:namespace/:kind/:name/parameter-schema", async (req, res) => {
|
|
3254
3412
|
var _a, _b;
|
|
3255
3413
|
const { namespace, kind, name } = req.params;
|
|
3414
|
+
const { token } = parseBearerToken(req.headers.authorization);
|
|
3256
3415
|
const template = await findTemplate({
|
|
3257
3416
|
catalogApi: catalogClient,
|
|
3258
3417
|
entityRef: { kind, namespace, name },
|
|
3259
|
-
token
|
|
3418
|
+
token
|
|
3260
3419
|
});
|
|
3261
3420
|
if (isSupportedTemplate(template)) {
|
|
3262
3421
|
const parameters = [(_a = template.spec.parameters) != null ? _a : []].flat();
|
|
@@ -3288,12 +3447,13 @@ async function createRouter(options) {
|
|
|
3288
3447
|
const { kind, namespace, name } = catalogModel.parseEntityRef(templateRef, {
|
|
3289
3448
|
defaultKind: "template"
|
|
3290
3449
|
});
|
|
3450
|
+
const { token, entityRef: userEntityRef } = parseBearerToken(req.headers.authorization);
|
|
3451
|
+
const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) : void 0;
|
|
3291
3452
|
const values = req.body.values;
|
|
3292
|
-
const token = getBearerToken(req.headers.authorization);
|
|
3293
3453
|
const template = await findTemplate({
|
|
3294
3454
|
catalogApi: catalogClient,
|
|
3295
3455
|
entityRef: { kind, namespace, name },
|
|
3296
|
-
token
|
|
3456
|
+
token
|
|
3297
3457
|
});
|
|
3298
3458
|
if (!isSupportedTemplate(template)) {
|
|
3299
3459
|
throw new errors.InputError(`Unsupported apiVersion field in schema entity, ${template.apiVersion}`);
|
|
@@ -3318,6 +3478,10 @@ async function createRouter(options) {
|
|
|
3318
3478
|
}),
|
|
3319
3479
|
output: (_b = template.spec.output) != null ? _b : {},
|
|
3320
3480
|
parameters: values,
|
|
3481
|
+
user: {
|
|
3482
|
+
entity: userEntity,
|
|
3483
|
+
ref: userEntityRef
|
|
3484
|
+
},
|
|
3321
3485
|
templateInfo: {
|
|
3322
3486
|
entityRef: catalogModel.stringifyEntityRef({
|
|
3323
3487
|
kind,
|
|
@@ -3329,6 +3493,7 @@ async function createRouter(options) {
|
|
|
3329
3493
|
};
|
|
3330
3494
|
const result = await taskBroker.dispatch({
|
|
3331
3495
|
spec: taskSpec,
|
|
3496
|
+
createdBy: userEntityRef,
|
|
3332
3497
|
secrets: {
|
|
3333
3498
|
...req.body.secrets,
|
|
3334
3499
|
backstageToken: token
|
|
@@ -3403,9 +3568,17 @@ data: ${JSON.stringify(event)}
|
|
|
3403
3568
|
app.use("/", router);
|
|
3404
3569
|
return app;
|
|
3405
3570
|
}
|
|
3406
|
-
function
|
|
3571
|
+
function parseBearerToken(header) {
|
|
3407
3572
|
var _a;
|
|
3408
|
-
|
|
3573
|
+
const token = (_a = header == null ? void 0 : header.match(/Bearer\s+(\S+)/i)) == null ? void 0 : _a[1];
|
|
3574
|
+
if (!token)
|
|
3575
|
+
return {};
|
|
3576
|
+
const [_header, rawPayload, _signature] = token.split(".");
|
|
3577
|
+
const payload = JSON.parse(Buffer.from(rawPayload, "base64").toString());
|
|
3578
|
+
return {
|
|
3579
|
+
entityRef: payload.sub,
|
|
3580
|
+
token
|
|
3581
|
+
};
|
|
3409
3582
|
}
|
|
3410
3583
|
|
|
3411
3584
|
class ScaffolderEntitiesProcessor {
|
|
@@ -3478,6 +3651,7 @@ exports.createPublishBitbucketAction = createPublishBitbucketAction;
|
|
|
3478
3651
|
exports.createPublishBitbucketCloudAction = createPublishBitbucketCloudAction;
|
|
3479
3652
|
exports.createPublishBitbucketServerAction = createPublishBitbucketServerAction;
|
|
3480
3653
|
exports.createPublishFileAction = createPublishFileAction;
|
|
3654
|
+
exports.createPublishGerritAction = createPublishGerritAction;
|
|
3481
3655
|
exports.createPublishGithubAction = createPublishGithubAction;
|
|
3482
3656
|
exports.createPublishGithubPullRequestAction = createPublishGithubPullRequestAction;
|
|
3483
3657
|
exports.createPublishGitlabAction = createPublishGitlabAction;
|