@backstage/plugin-scaffolder-backend 1.4.0-next.0 → 1.4.0-next.3
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 +64 -2
- package/alpha/package.json +6 -0
- package/dist/index.alpha.d.ts +959 -0
- package/dist/index.beta.d.ts +955 -0
- package/dist/index.cjs.js +1629 -1425
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +657 -553
- package/package.json +24 -20
package/dist/index.cjs.js
CHANGED
|
@@ -12,16 +12,16 @@ var path = require('path');
|
|
|
12
12
|
var globby = require('globby');
|
|
13
13
|
var isbinaryfile = require('isbinaryfile');
|
|
14
14
|
var vm2 = require('vm2');
|
|
15
|
+
var octokit = require('octokit');
|
|
15
16
|
var child_process = require('child_process');
|
|
16
17
|
var stream = require('stream');
|
|
18
|
+
var webhooks = require('@octokit/webhooks');
|
|
17
19
|
var azureDevopsNodeApi = require('azure-devops-node-api');
|
|
18
20
|
var fetch = require('node-fetch');
|
|
19
21
|
var crypto = require('crypto');
|
|
20
|
-
var octokit = require('octokit');
|
|
21
22
|
var octokitPluginCreatePullRequest = require('octokit-plugin-create-pull-request');
|
|
22
23
|
var limiterFactory = require('p-limit');
|
|
23
24
|
var node = require('@gitbeaker/node');
|
|
24
|
-
var webhooks = require('@octokit/webhooks');
|
|
25
25
|
var uuid = require('uuid');
|
|
26
26
|
var luxon = require('luxon');
|
|
27
27
|
var ObservableImpl = require('zen-observable');
|
|
@@ -36,6 +36,8 @@ var zod = require('zod');
|
|
|
36
36
|
var url = require('url');
|
|
37
37
|
var os = require('os');
|
|
38
38
|
var pluginCatalogBackend = require('@backstage/plugin-catalog-backend');
|
|
39
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
40
|
+
var pluginCatalogNode = require('@backstage/plugin-catalog-node');
|
|
39
41
|
|
|
40
42
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
41
43
|
|
|
@@ -571,8 +573,9 @@ function createFetchTemplateAction(options) {
|
|
|
571
573
|
await fs__default["default"].ensureDir(outputPath);
|
|
572
574
|
} else {
|
|
573
575
|
const inputFilePath = backendCommon.resolveSafeChildPath(templateDir, location);
|
|
574
|
-
|
|
575
|
-
|
|
576
|
+
const stats = await fs__default["default"].promises.lstat(inputFilePath);
|
|
577
|
+
if (stats.isSymbolicLink() || await isbinaryfile.isBinaryFile(inputFilePath)) {
|
|
578
|
+
ctx.logger.info(`Copying file binary or symbolic link at ${location}, to template output path.`);
|
|
576
579
|
await fs__default["default"].copy(inputFilePath, outputPath);
|
|
577
580
|
} else {
|
|
578
581
|
const statsObj = await fs__default["default"].stat(inputFilePath);
|
|
@@ -688,6 +691,55 @@ const createFilesystemRenameAction = () => {
|
|
|
688
691
|
});
|
|
689
692
|
};
|
|
690
693
|
|
|
694
|
+
const getRepoSourceDirectory = (workspacePath, sourcePath) => {
|
|
695
|
+
if (sourcePath) {
|
|
696
|
+
const safeSuffix = path.normalize(sourcePath).replace(/^(\.\.(\/|\\|$))+/, "");
|
|
697
|
+
const path$1 = path.join(workspacePath, safeSuffix);
|
|
698
|
+
if (!backendCommon.isChildPath(workspacePath, path$1)) {
|
|
699
|
+
throw new Error("Invalid source path");
|
|
700
|
+
}
|
|
701
|
+
return path$1;
|
|
702
|
+
}
|
|
703
|
+
return workspacePath;
|
|
704
|
+
};
|
|
705
|
+
const parseRepoUrl = (repoUrl, integrations) => {
|
|
706
|
+
var _a, _b, _c, _d, _e;
|
|
707
|
+
let parsed;
|
|
708
|
+
try {
|
|
709
|
+
parsed = new URL(`https://${repoUrl}`);
|
|
710
|
+
} catch (error) {
|
|
711
|
+
throw new errors.InputError(`Invalid repo URL passed to publisher, got ${repoUrl}, ${error}`);
|
|
712
|
+
}
|
|
713
|
+
const host = parsed.host;
|
|
714
|
+
const owner = (_a = parsed.searchParams.get("owner")) != null ? _a : void 0;
|
|
715
|
+
const organization = (_b = parsed.searchParams.get("organization")) != null ? _b : void 0;
|
|
716
|
+
const workspace = (_c = parsed.searchParams.get("workspace")) != null ? _c : void 0;
|
|
717
|
+
const project = (_d = parsed.searchParams.get("project")) != null ? _d : void 0;
|
|
718
|
+
const type = (_e = integrations.byHost(host)) == null ? void 0 : _e.type;
|
|
719
|
+
if (!type) {
|
|
720
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
721
|
+
}
|
|
722
|
+
if (type === "bitbucket") {
|
|
723
|
+
if (host === "bitbucket.org") {
|
|
724
|
+
if (!workspace) {
|
|
725
|
+
throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing workspace`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (!project) {
|
|
729
|
+
throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing project`);
|
|
730
|
+
}
|
|
731
|
+
} else {
|
|
732
|
+
if (!owner) {
|
|
733
|
+
throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing owner`);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
const repo = parsed.searchParams.get("repo");
|
|
737
|
+
if (!repo) {
|
|
738
|
+
throw new errors.InputError(`Invalid repo URL passed to publisher: ${repoUrl}, missing repo`);
|
|
739
|
+
}
|
|
740
|
+
return { host, owner, repo, organization, workspace, project };
|
|
741
|
+
};
|
|
742
|
+
|
|
691
743
|
const executeShellCommand = async (options) => {
|
|
692
744
|
const {
|
|
693
745
|
command,
|
|
@@ -803,663 +855,684 @@ const enableBranchProtectionOnDefaultRepoBranch = async ({
|
|
|
803
855
|
}
|
|
804
856
|
};
|
|
805
857
|
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
858
|
+
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
859
|
+
async function getOctokitOptions(options) {
|
|
860
|
+
var _a;
|
|
861
|
+
const { integrations, credentialsProvider, repoUrl, token } = options;
|
|
862
|
+
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
863
|
+
const requestOptions = {
|
|
864
|
+
timeout: DEFAULT_TIMEOUT_MS
|
|
865
|
+
};
|
|
866
|
+
if (!owner) {
|
|
867
|
+
throw new errors.InputError(`No owner provided for repo ${repoUrl}`);
|
|
814
868
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
869
|
+
const integrationConfig = (_a = integrations.github.byHost(host)) == null ? void 0 : _a.config;
|
|
870
|
+
if (!integrationConfig) {
|
|
871
|
+
throw new errors.InputError(`No integration for host ${host}`);
|
|
872
|
+
}
|
|
873
|
+
if (token) {
|
|
874
|
+
return {
|
|
875
|
+
auth: token,
|
|
876
|
+
baseUrl: integrationConfig.apiBaseUrl,
|
|
877
|
+
previews: ["nebula-preview"],
|
|
878
|
+
request: requestOptions
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
const githubCredentialsProvider = credentialsProvider != null ? credentialsProvider : integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations);
|
|
882
|
+
const { token: credentialProviderToken } = await githubCredentialsProvider.getCredentials({
|
|
883
|
+
url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
|
|
884
|
+
});
|
|
885
|
+
if (!credentialProviderToken) {
|
|
886
|
+
throw new errors.InputError(`No token available for host: ${host}, with owner ${owner}, and repo ${repo}`);
|
|
887
|
+
}
|
|
888
|
+
return {
|
|
889
|
+
auth: credentialProviderToken,
|
|
890
|
+
baseUrl: integrationConfig.apiBaseUrl,
|
|
891
|
+
previews: ["nebula-preview"]
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
async function createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, logger) {
|
|
895
|
+
const user = await client.rest.users.getByUsername({
|
|
896
|
+
username: owner
|
|
897
|
+
});
|
|
898
|
+
const repoCreationPromise = user.data.type === "Organization" ? client.rest.repos.createInOrg({
|
|
899
|
+
name: repo,
|
|
900
|
+
org: owner,
|
|
901
|
+
private: repoVisibility === "private",
|
|
902
|
+
visibility: repoVisibility,
|
|
903
|
+
description,
|
|
904
|
+
delete_branch_on_merge: deleteBranchOnMerge,
|
|
905
|
+
allow_merge_commit: allowMergeCommit,
|
|
906
|
+
allow_squash_merge: allowSquashMerge,
|
|
907
|
+
allow_rebase_merge: allowRebaseMerge
|
|
908
|
+
}) : client.rest.repos.createForAuthenticatedUser({
|
|
909
|
+
name: repo,
|
|
910
|
+
private: repoVisibility === "private",
|
|
911
|
+
description,
|
|
912
|
+
delete_branch_on_merge: deleteBranchOnMerge,
|
|
913
|
+
allow_merge_commit: allowMergeCommit,
|
|
914
|
+
allow_squash_merge: allowSquashMerge,
|
|
915
|
+
allow_rebase_merge: allowRebaseMerge
|
|
916
|
+
});
|
|
917
|
+
let newRepo;
|
|
820
918
|
try {
|
|
821
|
-
|
|
822
|
-
} catch (
|
|
823
|
-
|
|
919
|
+
newRepo = (await repoCreationPromise).data;
|
|
920
|
+
} catch (e) {
|
|
921
|
+
errors.assertError(e);
|
|
922
|
+
if (e.message === "Resource not accessible by integration") {
|
|
923
|
+
logger.warn(`The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`);
|
|
924
|
+
}
|
|
925
|
+
throw new Error(`Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`);
|
|
824
926
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
927
|
+
if (access == null ? void 0 : access.startsWith(`${owner}/`)) {
|
|
928
|
+
const [, team] = access.split("/");
|
|
929
|
+
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
930
|
+
org: owner,
|
|
931
|
+
team_slug: team,
|
|
932
|
+
owner,
|
|
933
|
+
repo,
|
|
934
|
+
permission: "admin"
|
|
935
|
+
});
|
|
936
|
+
} else if (access && access !== owner) {
|
|
937
|
+
await client.rest.repos.addCollaborator({
|
|
938
|
+
owner,
|
|
939
|
+
repo,
|
|
940
|
+
username: access,
|
|
941
|
+
permission: "admin"
|
|
942
|
+
});
|
|
833
943
|
}
|
|
834
|
-
if (
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
944
|
+
if (collaborators) {
|
|
945
|
+
for (const collaborator of collaborators) {
|
|
946
|
+
try {
|
|
947
|
+
if ("user" in collaborator) {
|
|
948
|
+
await client.rest.repos.addCollaborator({
|
|
949
|
+
owner,
|
|
950
|
+
repo,
|
|
951
|
+
username: collaborator.user,
|
|
952
|
+
permission: collaborator.access
|
|
953
|
+
});
|
|
954
|
+
} else if ("team" in collaborator) {
|
|
955
|
+
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
956
|
+
org: owner,
|
|
957
|
+
team_slug: collaborator.team,
|
|
958
|
+
owner,
|
|
959
|
+
repo,
|
|
960
|
+
permission: collaborator.access
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
} catch (e) {
|
|
964
|
+
errors.assertError(e);
|
|
965
|
+
const name = extractCollaboratorName(collaborator);
|
|
966
|
+
logger.warn(`Skipping ${collaborator.access} access for ${name}, ${e.message}`);
|
|
838
967
|
}
|
|
839
968
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
969
|
+
}
|
|
970
|
+
if (topics) {
|
|
971
|
+
try {
|
|
972
|
+
await client.rest.repos.replaceAllTopics({
|
|
973
|
+
owner,
|
|
974
|
+
repo,
|
|
975
|
+
names: topics.map((t) => t.toLowerCase())
|
|
976
|
+
});
|
|
977
|
+
} catch (e) {
|
|
978
|
+
errors.assertError(e);
|
|
979
|
+
logger.warn(`Skipping topics ${topics.join(" ")}, ${e.message}`);
|
|
846
980
|
}
|
|
847
981
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
982
|
+
return newRepo;
|
|
983
|
+
}
|
|
984
|
+
async function initRepoPushAndProtect(remoteUrl, password, workspacePath, sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, logger, gitCommitMessage, gitAuthorName, gitAuthorEmail) {
|
|
985
|
+
const gitAuthorInfo = {
|
|
986
|
+
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
987
|
+
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
988
|
+
};
|
|
989
|
+
const commitMessage = gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage");
|
|
990
|
+
await initRepoAndPush({
|
|
991
|
+
dir: getRepoSourceDirectory(workspacePath, sourcePath),
|
|
992
|
+
remoteUrl,
|
|
993
|
+
defaultBranch,
|
|
994
|
+
auth: {
|
|
995
|
+
username: "x-access-token",
|
|
996
|
+
password
|
|
997
|
+
},
|
|
998
|
+
logger,
|
|
999
|
+
commitMessage,
|
|
1000
|
+
gitAuthorInfo
|
|
1001
|
+
});
|
|
1002
|
+
if (protectDefaultBranch) {
|
|
1003
|
+
try {
|
|
1004
|
+
await enableBranchProtectionOnDefaultRepoBranch({
|
|
1005
|
+
owner,
|
|
1006
|
+
client,
|
|
1007
|
+
repoName: repo,
|
|
1008
|
+
logger,
|
|
1009
|
+
defaultBranch,
|
|
1010
|
+
requireCodeOwnerReviews,
|
|
1011
|
+
requiredStatusCheckContexts
|
|
1012
|
+
});
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
errors.assertError(e);
|
|
1015
|
+
logger.warn(`Skipping: default branch protection on '${repo}', ${e.message}`);
|
|
1016
|
+
}
|
|
851
1017
|
}
|
|
852
|
-
|
|
853
|
-
|
|
1018
|
+
}
|
|
1019
|
+
function extractCollaboratorName(collaborator) {
|
|
1020
|
+
if ("username" in collaborator)
|
|
1021
|
+
return collaborator.username;
|
|
1022
|
+
if ("user" in collaborator)
|
|
1023
|
+
return collaborator.user;
|
|
1024
|
+
return collaborator.team;
|
|
1025
|
+
}
|
|
854
1026
|
|
|
855
|
-
function
|
|
856
|
-
const { integrations,
|
|
1027
|
+
function createGithubActionsDispatchAction(options) {
|
|
1028
|
+
const { integrations, githubCredentialsProvider } = options;
|
|
857
1029
|
return createTemplateAction({
|
|
858
|
-
id: "
|
|
859
|
-
description: "
|
|
1030
|
+
id: "github:actions:dispatch",
|
|
1031
|
+
description: "Dispatches a GitHub Action workflow for a given branch or tag",
|
|
860
1032
|
schema: {
|
|
861
1033
|
input: {
|
|
862
1034
|
type: "object",
|
|
863
|
-
required: ["repoUrl"],
|
|
1035
|
+
required: ["repoUrl", "workflowId", "branchOrTagName"],
|
|
864
1036
|
properties: {
|
|
865
1037
|
repoUrl: {
|
|
866
1038
|
title: "Repository Location",
|
|
1039
|
+
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`,
|
|
867
1040
|
type: "string"
|
|
868
1041
|
},
|
|
869
|
-
|
|
870
|
-
title: "
|
|
1042
|
+
workflowId: {
|
|
1043
|
+
title: "Workflow ID",
|
|
1044
|
+
description: "The GitHub Action Workflow filename",
|
|
871
1045
|
type: "string"
|
|
872
1046
|
},
|
|
873
|
-
|
|
874
|
-
title: "
|
|
875
|
-
|
|
876
|
-
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
877
|
-
},
|
|
878
|
-
gitCommitMessage: {
|
|
879
|
-
title: "Git Commit Message",
|
|
880
|
-
type: "string",
|
|
881
|
-
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
882
|
-
},
|
|
883
|
-
gitAuthorName: {
|
|
884
|
-
title: "Default Author Name",
|
|
885
|
-
type: "string",
|
|
886
|
-
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
887
|
-
},
|
|
888
|
-
gitAuthorEmail: {
|
|
889
|
-
title: "Default Author Email",
|
|
890
|
-
type: "string",
|
|
891
|
-
description: `Sets the default author email for the commit.`
|
|
892
|
-
},
|
|
893
|
-
sourcePath: {
|
|
894
|
-
title: "Source Path",
|
|
895
|
-
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1047
|
+
branchOrTagName: {
|
|
1048
|
+
title: "Branch or Tag name",
|
|
1049
|
+
description: "The git branch or tag name used to dispatch the workflow",
|
|
896
1050
|
type: "string"
|
|
897
1051
|
},
|
|
1052
|
+
workflowInputs: {
|
|
1053
|
+
title: "Workflow Inputs",
|
|
1054
|
+
description: "Inputs keys and values to send to GitHub Action configured on the workflow file. The maximum number of properties is 10. ",
|
|
1055
|
+
type: "object"
|
|
1056
|
+
},
|
|
898
1057
|
token: {
|
|
899
1058
|
title: "Authentication Token",
|
|
900
1059
|
type: "string",
|
|
901
|
-
description: "The
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
},
|
|
905
|
-
output: {
|
|
906
|
-
type: "object",
|
|
907
|
-
properties: {
|
|
908
|
-
remoteUrl: {
|
|
909
|
-
title: "A URL to the repository with the provider",
|
|
910
|
-
type: "string"
|
|
911
|
-
},
|
|
912
|
-
repoContentsUrl: {
|
|
913
|
-
title: "A URL to the root of the repository",
|
|
914
|
-
type: "string"
|
|
1060
|
+
description: "The GITHUB_TOKEN to use for authorization to GitHub"
|
|
915
1061
|
}
|
|
916
1062
|
}
|
|
917
1063
|
}
|
|
918
1064
|
},
|
|
919
1065
|
async handler(ctx) {
|
|
920
|
-
var _a;
|
|
921
1066
|
const {
|
|
922
1067
|
repoUrl,
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1068
|
+
workflowId,
|
|
1069
|
+
branchOrTagName,
|
|
1070
|
+
workflowInputs,
|
|
1071
|
+
token: providedToken
|
|
927
1072
|
} = ctx.input;
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const integrationConfig = integrations.azure.byHost(host);
|
|
933
|
-
if (!integrationConfig) {
|
|
934
|
-
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1073
|
+
ctx.logger.info(`Dispatching workflow ${workflowId} for repo ${repoUrl} on ${branchOrTagName}`);
|
|
1074
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
1075
|
+
if (!owner) {
|
|
1076
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
935
1077
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
}
|
|
949
|
-
const remoteUrl = returnedRepo.remoteUrl;
|
|
950
|
-
if (!remoteUrl) {
|
|
951
|
-
throw new errors.InputError("No remote URL returned from create repository for Azure");
|
|
952
|
-
}
|
|
953
|
-
const repoContentsUrl = remoteUrl;
|
|
954
|
-
const gitAuthorInfo = {
|
|
955
|
-
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
956
|
-
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
957
|
-
};
|
|
958
|
-
await initRepoAndPush({
|
|
959
|
-
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
960
|
-
remoteUrl,
|
|
961
|
-
defaultBranch,
|
|
962
|
-
auth: {
|
|
963
|
-
username: "notempty",
|
|
964
|
-
password: token
|
|
965
|
-
},
|
|
966
|
-
logger: ctx.logger,
|
|
967
|
-
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
968
|
-
gitAuthorInfo
|
|
1078
|
+
const client = new octokit.Octokit(await getOctokitOptions({
|
|
1079
|
+
integrations,
|
|
1080
|
+
repoUrl,
|
|
1081
|
+
credentialsProvider: githubCredentialsProvider,
|
|
1082
|
+
token: providedToken
|
|
1083
|
+
}));
|
|
1084
|
+
await client.rest.actions.createWorkflowDispatch({
|
|
1085
|
+
owner,
|
|
1086
|
+
repo,
|
|
1087
|
+
workflow_id: workflowId,
|
|
1088
|
+
ref: branchOrTagName,
|
|
1089
|
+
inputs: workflowInputs
|
|
969
1090
|
});
|
|
970
|
-
ctx.
|
|
971
|
-
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1091
|
+
ctx.logger.info(`Workflow ${workflowId} dispatched successfully`);
|
|
972
1092
|
}
|
|
973
1093
|
});
|
|
974
1094
|
}
|
|
975
1095
|
|
|
976
|
-
|
|
977
|
-
const {
|
|
978
|
-
workspace,
|
|
979
|
-
project,
|
|
980
|
-
repo,
|
|
981
|
-
description,
|
|
982
|
-
repoVisibility,
|
|
983
|
-
mainBranch,
|
|
984
|
-
authorization,
|
|
985
|
-
apiBaseUrl
|
|
986
|
-
} = opts;
|
|
987
|
-
const options = {
|
|
988
|
-
method: "POST",
|
|
989
|
-
body: JSON.stringify({
|
|
990
|
-
scm: "git",
|
|
991
|
-
description,
|
|
992
|
-
is_private: repoVisibility === "private",
|
|
993
|
-
project: { key: project }
|
|
994
|
-
}),
|
|
995
|
-
headers: {
|
|
996
|
-
Authorization: authorization,
|
|
997
|
-
"Content-Type": "application/json"
|
|
998
|
-
}
|
|
999
|
-
};
|
|
1000
|
-
let response;
|
|
1001
|
-
try {
|
|
1002
|
-
response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
|
|
1003
|
-
} catch (e) {
|
|
1004
|
-
throw new Error(`Unable to create repository, ${e}`);
|
|
1005
|
-
}
|
|
1006
|
-
if (response.status !== 200) {
|
|
1007
|
-
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1008
|
-
}
|
|
1009
|
-
const r = await response.json();
|
|
1010
|
-
let remoteUrl = "";
|
|
1011
|
-
for (const link of r.links.clone) {
|
|
1012
|
-
if (link.name === "https") {
|
|
1013
|
-
remoteUrl = link.href;
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
|
|
1017
|
-
return { remoteUrl, repoContentsUrl };
|
|
1018
|
-
};
|
|
1019
|
-
const createBitbucketServerRepository = async (opts) => {
|
|
1020
|
-
const {
|
|
1021
|
-
project,
|
|
1022
|
-
repo,
|
|
1023
|
-
description,
|
|
1024
|
-
authorization,
|
|
1025
|
-
repoVisibility,
|
|
1026
|
-
apiBaseUrl
|
|
1027
|
-
} = opts;
|
|
1028
|
-
let response;
|
|
1029
|
-
const options = {
|
|
1030
|
-
method: "POST",
|
|
1031
|
-
body: JSON.stringify({
|
|
1032
|
-
name: repo,
|
|
1033
|
-
description,
|
|
1034
|
-
public: repoVisibility === "public"
|
|
1035
|
-
}),
|
|
1036
|
-
headers: {
|
|
1037
|
-
Authorization: authorization,
|
|
1038
|
-
"Content-Type": "application/json"
|
|
1039
|
-
}
|
|
1040
|
-
};
|
|
1041
|
-
try {
|
|
1042
|
-
response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
|
|
1043
|
-
} catch (e) {
|
|
1044
|
-
throw new Error(`Unable to create repository, ${e}`);
|
|
1045
|
-
}
|
|
1046
|
-
if (response.status !== 201) {
|
|
1047
|
-
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1048
|
-
}
|
|
1049
|
-
const r = await response.json();
|
|
1050
|
-
let remoteUrl = "";
|
|
1051
|
-
for (const link of r.links.clone) {
|
|
1052
|
-
if (link.name === "http") {
|
|
1053
|
-
remoteUrl = link.href;
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
const repoContentsUrl = `${r.links.self[0].href}`;
|
|
1057
|
-
return { remoteUrl, repoContentsUrl };
|
|
1058
|
-
};
|
|
1059
|
-
const getAuthorizationHeader$2 = (config) => {
|
|
1060
|
-
if (config.username && config.appPassword) {
|
|
1061
|
-
const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
|
|
1062
|
-
return `Basic ${buffer.toString("base64")}`;
|
|
1063
|
-
}
|
|
1064
|
-
if (config.token) {
|
|
1065
|
-
return `Bearer ${config.token}`;
|
|
1066
|
-
}
|
|
1067
|
-
throw new Error(`Authorization has not been provided for Bitbucket. Please add either username + appPassword or token to the Integrations config`);
|
|
1068
|
-
};
|
|
1069
|
-
const performEnableLFS$1 = async (opts) => {
|
|
1070
|
-
const { authorization, host, project, repo } = opts;
|
|
1071
|
-
const options = {
|
|
1072
|
-
method: "PUT",
|
|
1073
|
-
headers: {
|
|
1074
|
-
Authorization: authorization
|
|
1075
|
-
}
|
|
1076
|
-
};
|
|
1077
|
-
const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
|
|
1078
|
-
if (!ok)
|
|
1079
|
-
throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
|
|
1080
|
-
};
|
|
1081
|
-
function createPublishBitbucketAction(options) {
|
|
1082
|
-
const { integrations, config } = options;
|
|
1096
|
+
function createGithubIssuesLabelAction(options) {
|
|
1097
|
+
const { integrations, githubCredentialsProvider } = options;
|
|
1083
1098
|
return createTemplateAction({
|
|
1084
|
-
id: "
|
|
1085
|
-
description: "
|
|
1099
|
+
id: "github:issues:label",
|
|
1100
|
+
description: "Adds labels to a pull request or issue on GitHub.",
|
|
1086
1101
|
schema: {
|
|
1087
1102
|
input: {
|
|
1088
1103
|
type: "object",
|
|
1089
|
-
required: ["repoUrl"],
|
|
1104
|
+
required: ["repoUrl", "number", "labels"],
|
|
1090
1105
|
properties: {
|
|
1091
1106
|
repoUrl: {
|
|
1092
1107
|
title: "Repository Location",
|
|
1108
|
+
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the repository name and 'owner' is an organization or username`,
|
|
1093
1109
|
type: "string"
|
|
1094
1110
|
},
|
|
1095
|
-
|
|
1096
|
-
title: "
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
repoVisibility: {
|
|
1100
|
-
title: "Repository Visibility",
|
|
1101
|
-
type: "string",
|
|
1102
|
-
enum: ["private", "public"]
|
|
1103
|
-
},
|
|
1104
|
-
defaultBranch: {
|
|
1105
|
-
title: "Default Branch",
|
|
1106
|
-
type: "string",
|
|
1107
|
-
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1108
|
-
},
|
|
1109
|
-
sourcePath: {
|
|
1110
|
-
title: "Source Path",
|
|
1111
|
-
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1112
|
-
type: "string"
|
|
1111
|
+
number: {
|
|
1112
|
+
title: "Pull Request or issue number",
|
|
1113
|
+
description: "The pull request or issue number to add labels to",
|
|
1114
|
+
type: "number"
|
|
1113
1115
|
},
|
|
1114
|
-
|
|
1115
|
-
title: "
|
|
1116
|
-
description: "
|
|
1117
|
-
type: "
|
|
1116
|
+
labels: {
|
|
1117
|
+
title: "Labels",
|
|
1118
|
+
description: "The labels to add to the pull request or issue",
|
|
1119
|
+
type: "array",
|
|
1120
|
+
items: {
|
|
1121
|
+
type: "string"
|
|
1122
|
+
}
|
|
1118
1123
|
},
|
|
1119
1124
|
token: {
|
|
1120
1125
|
title: "Authentication Token",
|
|
1121
1126
|
type: "string",
|
|
1122
|
-
description: "The
|
|
1123
|
-
},
|
|
1124
|
-
gitCommitMessage: {
|
|
1125
|
-
title: "Git Commit Message",
|
|
1126
|
-
type: "string",
|
|
1127
|
-
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
1128
|
-
},
|
|
1129
|
-
gitAuthorName: {
|
|
1130
|
-
title: "Default Author Name",
|
|
1131
|
-
type: "string",
|
|
1132
|
-
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
1133
|
-
},
|
|
1134
|
-
gitAuthorEmail: {
|
|
1135
|
-
title: "Default Author Email",
|
|
1136
|
-
type: "string",
|
|
1137
|
-
description: `Sets the default author email for the commit.`
|
|
1127
|
+
description: "The GITHUB_TOKEN to use for authorization to GitHub"
|
|
1138
1128
|
}
|
|
1139
1129
|
}
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
async handler(ctx) {
|
|
1133
|
+
const { repoUrl, number, labels, token: providedToken } = ctx.input;
|
|
1134
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
1135
|
+
ctx.logger.info(`Adding labels to ${number} issue on repo ${repo}`);
|
|
1136
|
+
if (!owner) {
|
|
1137
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
1138
|
+
}
|
|
1139
|
+
const client = new octokit.Octokit(await getOctokitOptions({
|
|
1140
|
+
integrations,
|
|
1141
|
+
credentialsProvider: githubCredentialsProvider,
|
|
1142
|
+
repoUrl,
|
|
1143
|
+
token: providedToken
|
|
1144
|
+
}));
|
|
1145
|
+
try {
|
|
1146
|
+
await client.rest.issues.addLabels({
|
|
1147
|
+
owner,
|
|
1148
|
+
repo,
|
|
1149
|
+
issue_number: number,
|
|
1150
|
+
labels
|
|
1151
|
+
});
|
|
1152
|
+
} catch (e) {
|
|
1153
|
+
errors.assertError(e);
|
|
1154
|
+
ctx.logger.warn(`Failed: adding labels to issue: '${number}' on repo: '${repo}', ${e.message}`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const repoUrl = {
|
|
1161
|
+
title: "Repository Location",
|
|
1162
|
+
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`,
|
|
1163
|
+
type: "string"
|
|
1164
|
+
};
|
|
1165
|
+
const description = {
|
|
1166
|
+
title: "Repository Description",
|
|
1167
|
+
type: "string"
|
|
1168
|
+
};
|
|
1169
|
+
const access = {
|
|
1170
|
+
title: "Repository Access",
|
|
1171
|
+
description: `Sets an admin collaborator on the repository. Can either be a user reference different from 'owner' in 'repoUrl' or team reference, eg. 'org/team-name'`,
|
|
1172
|
+
type: "string"
|
|
1173
|
+
};
|
|
1174
|
+
const requireCodeOwnerReviews = {
|
|
1175
|
+
title: "Require CODEOWNER Reviews?",
|
|
1176
|
+
description: "Require an approved review in PR including files with a designated Code Owner",
|
|
1177
|
+
type: "boolean"
|
|
1178
|
+
};
|
|
1179
|
+
const requiredStatusCheckContexts = {
|
|
1180
|
+
title: "Required Status Check Contexts",
|
|
1181
|
+
description: "The list of status checks to require in order to merge into this branch",
|
|
1182
|
+
type: "array",
|
|
1183
|
+
items: {
|
|
1184
|
+
type: "string"
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
const repoVisibility = {
|
|
1188
|
+
title: "Repository Visibility",
|
|
1189
|
+
type: "string",
|
|
1190
|
+
enum: ["private", "public", "internal"]
|
|
1191
|
+
};
|
|
1192
|
+
const deleteBranchOnMerge = {
|
|
1193
|
+
title: "Delete Branch On Merge",
|
|
1194
|
+
type: "boolean",
|
|
1195
|
+
description: `Delete the branch after merging the PR. The default value is 'false'`
|
|
1196
|
+
};
|
|
1197
|
+
const gitAuthorName = {
|
|
1198
|
+
title: "Default Author Name",
|
|
1199
|
+
type: "string",
|
|
1200
|
+
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
1201
|
+
};
|
|
1202
|
+
const gitAuthorEmail = {
|
|
1203
|
+
title: "Default Author Email",
|
|
1204
|
+
type: "string",
|
|
1205
|
+
description: `Sets the default author email for the commit.`
|
|
1206
|
+
};
|
|
1207
|
+
const allowMergeCommit = {
|
|
1208
|
+
title: "Allow Merge Commits",
|
|
1209
|
+
type: "boolean",
|
|
1210
|
+
description: `Allow merge commits. The default value is 'true'`
|
|
1211
|
+
};
|
|
1212
|
+
const allowSquashMerge = {
|
|
1213
|
+
title: "Allow Squash Merges",
|
|
1214
|
+
type: "boolean",
|
|
1215
|
+
description: `Allow squash merges. The default value is 'true'`
|
|
1216
|
+
};
|
|
1217
|
+
const allowRebaseMerge = {
|
|
1218
|
+
title: "Allow Rebase Merges",
|
|
1219
|
+
type: "boolean",
|
|
1220
|
+
description: `Allow rebase merges. The default value is 'true'`
|
|
1221
|
+
};
|
|
1222
|
+
const collaborators = {
|
|
1223
|
+
title: "Collaborators",
|
|
1224
|
+
description: "Provide additional users or teams with permissions",
|
|
1225
|
+
type: "array",
|
|
1226
|
+
items: {
|
|
1227
|
+
type: "object",
|
|
1228
|
+
additionalProperties: false,
|
|
1229
|
+
required: ["access"],
|
|
1230
|
+
properties: {
|
|
1231
|
+
access: {
|
|
1232
|
+
type: "string",
|
|
1233
|
+
description: "The type of access for the user",
|
|
1234
|
+
enum: ["push", "pull", "admin", "maintain", "triage"]
|
|
1235
|
+
},
|
|
1236
|
+
user: {
|
|
1237
|
+
type: "string",
|
|
1238
|
+
description: "The name of the user that will be added as a collaborator"
|
|
1239
|
+
},
|
|
1240
|
+
team: {
|
|
1241
|
+
type: "string",
|
|
1242
|
+
description: "The name of the team that will be added as a collaborator"
|
|
1243
|
+
}
|
|
1244
|
+
},
|
|
1245
|
+
oneOf: [{ required: ["user"] }, { required: ["team"] }]
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
const token = {
|
|
1249
|
+
title: "Authentication Token",
|
|
1250
|
+
type: "string",
|
|
1251
|
+
description: "The token to use for authorization to GitHub"
|
|
1252
|
+
};
|
|
1253
|
+
const topics = {
|
|
1254
|
+
title: "Topics",
|
|
1255
|
+
type: "array",
|
|
1256
|
+
items: {
|
|
1257
|
+
type: "string"
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
const defaultBranch = {
|
|
1261
|
+
title: "Default Branch",
|
|
1262
|
+
type: "string",
|
|
1263
|
+
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1264
|
+
};
|
|
1265
|
+
const protectDefaultBranch = {
|
|
1266
|
+
title: "Protect Default Branch",
|
|
1267
|
+
type: "boolean",
|
|
1268
|
+
description: `Protect the default branch after creating the repository. The default value is 'true'`
|
|
1269
|
+
};
|
|
1270
|
+
const gitCommitMessage = {
|
|
1271
|
+
title: "Git Commit Message",
|
|
1272
|
+
type: "string",
|
|
1273
|
+
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
1274
|
+
};
|
|
1275
|
+
const sourcePath = {
|
|
1276
|
+
title: "Source Path",
|
|
1277
|
+
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1278
|
+
type: "string"
|
|
1279
|
+
};
|
|
1280
|
+
|
|
1281
|
+
const remoteUrl = {
|
|
1282
|
+
title: "A URL to the repository with the provider",
|
|
1283
|
+
type: "string"
|
|
1284
|
+
};
|
|
1285
|
+
const repoContentsUrl = {
|
|
1286
|
+
title: "A URL to the root of the repository",
|
|
1287
|
+
type: "string"
|
|
1288
|
+
};
|
|
1289
|
+
|
|
1290
|
+
function createGithubRepoCreateAction(options) {
|
|
1291
|
+
const { integrations, githubCredentialsProvider } = options;
|
|
1292
|
+
return createTemplateAction({
|
|
1293
|
+
id: "github:repo:create",
|
|
1294
|
+
description: "Creates a GitHub repository.",
|
|
1295
|
+
schema: {
|
|
1296
|
+
input: {
|
|
1297
|
+
type: "object",
|
|
1298
|
+
required: ["repoUrl"],
|
|
1299
|
+
properties: {
|
|
1300
|
+
repoUrl: repoUrl,
|
|
1301
|
+
description: description,
|
|
1302
|
+
access: access,
|
|
1303
|
+
requireCodeOwnerReviews: requireCodeOwnerReviews,
|
|
1304
|
+
requiredStatusCheckContexts: requiredStatusCheckContexts,
|
|
1305
|
+
repoVisibility: repoVisibility,
|
|
1306
|
+
deleteBranchOnMerge: deleteBranchOnMerge,
|
|
1307
|
+
allowMergeCommit: allowMergeCommit,
|
|
1308
|
+
allowSquashMerge: allowSquashMerge,
|
|
1309
|
+
allowRebaseMerge: allowRebaseMerge,
|
|
1310
|
+
collaborators: collaborators,
|
|
1311
|
+
token: token,
|
|
1312
|
+
topics: topics
|
|
1313
|
+
}
|
|
1314
|
+
},
|
|
1315
|
+
output: {
|
|
1316
|
+
type: "object",
|
|
1317
|
+
properties: {
|
|
1318
|
+
remoteUrl: remoteUrl,
|
|
1319
|
+
repoContentsUrl: repoContentsUrl
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
},
|
|
1323
|
+
async handler(ctx) {
|
|
1324
|
+
const {
|
|
1325
|
+
repoUrl,
|
|
1326
|
+
description,
|
|
1327
|
+
access,
|
|
1328
|
+
repoVisibility = "private",
|
|
1329
|
+
deleteBranchOnMerge = false,
|
|
1330
|
+
allowMergeCommit = true,
|
|
1331
|
+
allowSquashMerge = true,
|
|
1332
|
+
allowRebaseMerge = true,
|
|
1333
|
+
collaborators,
|
|
1334
|
+
topics,
|
|
1335
|
+
token: providedToken
|
|
1336
|
+
} = ctx.input;
|
|
1337
|
+
const octokitOptions = await getOctokitOptions({
|
|
1338
|
+
integrations,
|
|
1339
|
+
credentialsProvider: githubCredentialsProvider,
|
|
1340
|
+
token: providedToken,
|
|
1341
|
+
repoUrl
|
|
1342
|
+
});
|
|
1343
|
+
const client = new octokit.Octokit(octokitOptions);
|
|
1344
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
1345
|
+
if (!owner) {
|
|
1346
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
1347
|
+
}
|
|
1348
|
+
const newRepo = await createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, ctx.logger);
|
|
1349
|
+
ctx.output("remoteUrl", newRepo.clone_url);
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
function createGithubRepoPushAction(options) {
|
|
1355
|
+
const { integrations, config, githubCredentialsProvider } = options;
|
|
1356
|
+
return createTemplateAction({
|
|
1357
|
+
id: "github:repo:push",
|
|
1358
|
+
description: "Initializes a git repository of contents in workspace and publishes it to GitHub.",
|
|
1359
|
+
schema: {
|
|
1360
|
+
input: {
|
|
1361
|
+
type: "object",
|
|
1362
|
+
required: ["repoUrl"],
|
|
1363
|
+
properties: {
|
|
1364
|
+
repoUrl: repoUrl,
|
|
1365
|
+
requireCodeOwnerReviews: requireCodeOwnerReviews,
|
|
1366
|
+
requiredStatusCheckContexts: requiredStatusCheckContexts,
|
|
1367
|
+
defaultBranch: defaultBranch,
|
|
1368
|
+
protectDefaultBranch: protectDefaultBranch,
|
|
1369
|
+
gitCommitMessage: gitCommitMessage,
|
|
1370
|
+
gitAuthorName: gitAuthorName,
|
|
1371
|
+
gitAuthorEmail: gitAuthorEmail,
|
|
1372
|
+
sourcePath: sourcePath,
|
|
1373
|
+
token: token
|
|
1374
|
+
}
|
|
1140
1375
|
},
|
|
1141
1376
|
output: {
|
|
1142
1377
|
type: "object",
|
|
1143
1378
|
properties: {
|
|
1144
|
-
remoteUrl:
|
|
1145
|
-
|
|
1146
|
-
type: "string"
|
|
1147
|
-
},
|
|
1148
|
-
repoContentsUrl: {
|
|
1149
|
-
title: "A URL to the root of the repository",
|
|
1150
|
-
type: "string"
|
|
1151
|
-
}
|
|
1379
|
+
remoteUrl: remoteUrl,
|
|
1380
|
+
repoContentsUrl: repoContentsUrl
|
|
1152
1381
|
}
|
|
1153
1382
|
}
|
|
1154
1383
|
},
|
|
1155
1384
|
async handler(ctx) {
|
|
1156
|
-
var _a;
|
|
1157
|
-
ctx.logger.warn(`[Deprecated] Please migrate the use of action "publish:bitbucket" to "publish:bitbucketCloud" or "publish:bitbucketServer".`);
|
|
1158
1385
|
const {
|
|
1159
1386
|
repoUrl,
|
|
1160
|
-
description,
|
|
1161
1387
|
defaultBranch = "master",
|
|
1162
|
-
|
|
1163
|
-
enableLFS = false,
|
|
1388
|
+
protectDefaultBranch = true,
|
|
1164
1389
|
gitCommitMessage = "initial commit",
|
|
1165
1390
|
gitAuthorName,
|
|
1166
|
-
gitAuthorEmail
|
|
1391
|
+
gitAuthorEmail,
|
|
1392
|
+
requireCodeOwnerReviews = false,
|
|
1393
|
+
requiredStatusCheckContexts = [],
|
|
1394
|
+
token: providedToken
|
|
1167
1395
|
} = ctx.input;
|
|
1168
|
-
const {
|
|
1169
|
-
if (
|
|
1170
|
-
|
|
1171
|
-
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
1174
|
-
if (!project) {
|
|
1175
|
-
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
|
|
1176
|
-
}
|
|
1177
|
-
const integrationConfig = integrations.bitbucket.byHost(host);
|
|
1178
|
-
if (!integrationConfig) {
|
|
1179
|
-
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1180
|
-
}
|
|
1181
|
-
const authorization = getAuthorizationHeader$2(ctx.input.token ? {
|
|
1182
|
-
host: integrationConfig.config.host,
|
|
1183
|
-
apiBaseUrl: integrationConfig.config.apiBaseUrl,
|
|
1184
|
-
token: ctx.input.token
|
|
1185
|
-
} : integrationConfig.config);
|
|
1186
|
-
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
1187
|
-
const createMethod = host === "bitbucket.org" ? createBitbucketCloudRepository : createBitbucketServerRepository;
|
|
1188
|
-
const { remoteUrl, repoContentsUrl } = await createMethod({
|
|
1189
|
-
authorization,
|
|
1190
|
-
workspace: workspace || "",
|
|
1191
|
-
project,
|
|
1192
|
-
repo,
|
|
1193
|
-
repoVisibility,
|
|
1194
|
-
mainBranch: defaultBranch,
|
|
1195
|
-
description,
|
|
1196
|
-
apiBaseUrl
|
|
1197
|
-
});
|
|
1198
|
-
const gitAuthorInfo = {
|
|
1199
|
-
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1200
|
-
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1201
|
-
};
|
|
1202
|
-
let auth;
|
|
1203
|
-
if (ctx.input.token) {
|
|
1204
|
-
auth = {
|
|
1205
|
-
username: "x-token-auth",
|
|
1206
|
-
password: ctx.input.token
|
|
1207
|
-
};
|
|
1208
|
-
} else {
|
|
1209
|
-
auth = {
|
|
1210
|
-
username: integrationConfig.config.username ? integrationConfig.config.username : "x-token-auth",
|
|
1211
|
-
password: integrationConfig.config.appPassword ? integrationConfig.config.appPassword : (_a = integrationConfig.config.token) != null ? _a : ""
|
|
1212
|
-
};
|
|
1396
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
1397
|
+
if (!owner) {
|
|
1398
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
1213
1399
|
}
|
|
1214
|
-
await
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
logger: ctx.logger,
|
|
1220
|
-
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
1221
|
-
gitAuthorInfo
|
|
1400
|
+
const octokitOptions = await getOctokitOptions({
|
|
1401
|
+
integrations,
|
|
1402
|
+
credentialsProvider: githubCredentialsProvider,
|
|
1403
|
+
token: providedToken,
|
|
1404
|
+
repoUrl
|
|
1222
1405
|
});
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1406
|
+
const client = new octokit.Octokit(octokitOptions);
|
|
1407
|
+
const targetRepo = await client.rest.repos.get({ owner, repo });
|
|
1408
|
+
const remoteUrl = targetRepo.data.clone_url;
|
|
1409
|
+
const repoContentsUrl = `${targetRepo.data.html_url}/blob/${defaultBranch}`;
|
|
1410
|
+
await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
|
|
1226
1411
|
ctx.output("remoteUrl", remoteUrl);
|
|
1227
1412
|
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1228
1413
|
}
|
|
1229
1414
|
});
|
|
1230
1415
|
}
|
|
1231
1416
|
|
|
1232
|
-
|
|
1233
|
-
const {
|
|
1234
|
-
|
|
1235
|
-
project,
|
|
1236
|
-
repo,
|
|
1237
|
-
description,
|
|
1238
|
-
repoVisibility,
|
|
1239
|
-
mainBranch,
|
|
1240
|
-
authorization,
|
|
1241
|
-
apiBaseUrl
|
|
1242
|
-
} = opts;
|
|
1243
|
-
const options = {
|
|
1244
|
-
method: "POST",
|
|
1245
|
-
body: JSON.stringify({
|
|
1246
|
-
scm: "git",
|
|
1247
|
-
description,
|
|
1248
|
-
is_private: repoVisibility === "private",
|
|
1249
|
-
project: { key: project }
|
|
1250
|
-
}),
|
|
1251
|
-
headers: {
|
|
1252
|
-
Authorization: authorization,
|
|
1253
|
-
"Content-Type": "application/json"
|
|
1254
|
-
}
|
|
1255
|
-
};
|
|
1256
|
-
let response;
|
|
1257
|
-
try {
|
|
1258
|
-
response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
|
|
1259
|
-
} catch (e) {
|
|
1260
|
-
throw new Error(`Unable to create repository, ${e}`);
|
|
1261
|
-
}
|
|
1262
|
-
if (response.status !== 200) {
|
|
1263
|
-
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1264
|
-
}
|
|
1265
|
-
const r = await response.json();
|
|
1266
|
-
let remoteUrl = "";
|
|
1267
|
-
for (const link of r.links.clone) {
|
|
1268
|
-
if (link.name === "https") {
|
|
1269
|
-
remoteUrl = link.href;
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
|
|
1273
|
-
return { remoteUrl, repoContentsUrl };
|
|
1274
|
-
};
|
|
1275
|
-
const getAuthorizationHeader$1 = (config) => {
|
|
1276
|
-
if (config.username && config.appPassword) {
|
|
1277
|
-
const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
|
|
1278
|
-
return `Basic ${buffer.toString("base64")}`;
|
|
1279
|
-
}
|
|
1280
|
-
if (config.token) {
|
|
1281
|
-
return `Bearer ${config.token}`;
|
|
1282
|
-
}
|
|
1283
|
-
throw new Error(`Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`);
|
|
1284
|
-
};
|
|
1285
|
-
function createPublishBitbucketCloudAction(options) {
|
|
1286
|
-
const { integrations, config } = options;
|
|
1417
|
+
function createGithubWebhookAction(options) {
|
|
1418
|
+
const { integrations, defaultWebhookSecret, githubCredentialsProvider } = options;
|
|
1419
|
+
const eventNames = webhooks.emitterEventNames.filter((event) => !event.includes("."));
|
|
1287
1420
|
return createTemplateAction({
|
|
1288
|
-
id: "
|
|
1289
|
-
description: "
|
|
1421
|
+
id: "github:webhook",
|
|
1422
|
+
description: "Creates webhook for a repository on GitHub.",
|
|
1290
1423
|
schema: {
|
|
1291
1424
|
input: {
|
|
1292
1425
|
type: "object",
|
|
1293
|
-
required: ["repoUrl"],
|
|
1426
|
+
required: ["repoUrl", "webhookUrl"],
|
|
1294
1427
|
properties: {
|
|
1295
1428
|
repoUrl: {
|
|
1296
1429
|
title: "Repository Location",
|
|
1430
|
+
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`,
|
|
1297
1431
|
type: "string"
|
|
1298
1432
|
},
|
|
1299
|
-
|
|
1300
|
-
title: "
|
|
1433
|
+
webhookUrl: {
|
|
1434
|
+
title: "Webhook URL",
|
|
1435
|
+
description: "The URL to which the payloads will be delivered",
|
|
1301
1436
|
type: "string"
|
|
1302
1437
|
},
|
|
1303
|
-
|
|
1304
|
-
title: "
|
|
1305
|
-
|
|
1306
|
-
enum: ["private", "public"]
|
|
1307
|
-
},
|
|
1308
|
-
defaultBranch: {
|
|
1309
|
-
title: "Default Branch",
|
|
1310
|
-
type: "string",
|
|
1311
|
-
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1312
|
-
},
|
|
1313
|
-
sourcePath: {
|
|
1314
|
-
title: "Source Path",
|
|
1315
|
-
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1438
|
+
webhookSecret: {
|
|
1439
|
+
title: "Webhook Secret",
|
|
1440
|
+
description: "Webhook secret value. The default can be provided internally in action creation",
|
|
1316
1441
|
type: "string"
|
|
1317
1442
|
},
|
|
1318
|
-
|
|
1319
|
-
title: "
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1443
|
+
events: {
|
|
1444
|
+
title: "Triggering Events",
|
|
1445
|
+
description: "Determines what events the hook is triggered for. Default: push",
|
|
1446
|
+
type: "array",
|
|
1447
|
+
oneOf: [
|
|
1448
|
+
{
|
|
1449
|
+
items: {
|
|
1450
|
+
type: "string",
|
|
1451
|
+
enum: eventNames
|
|
1452
|
+
}
|
|
1453
|
+
},
|
|
1454
|
+
{
|
|
1455
|
+
items: {
|
|
1456
|
+
type: "string",
|
|
1457
|
+
const: "*"
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
]
|
|
1331
1461
|
},
|
|
1332
|
-
|
|
1333
|
-
title: "
|
|
1334
|
-
type: "
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
const integrationConfig = integrations.bitbucketCloud.byHost(host);
|
|
1354
|
-
if (!integrationConfig) {
|
|
1355
|
-
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1356
|
-
}
|
|
1357
|
-
const authorization = getAuthorizationHeader$1(ctx.input.token ? { token: ctx.input.token } : integrationConfig.config);
|
|
1358
|
-
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
1359
|
-
const { remoteUrl, repoContentsUrl } = await createRepository$1({
|
|
1360
|
-
authorization,
|
|
1361
|
-
workspace: workspace || "",
|
|
1362
|
-
project,
|
|
1363
|
-
repo,
|
|
1364
|
-
repoVisibility,
|
|
1365
|
-
mainBranch: defaultBranch,
|
|
1366
|
-
description,
|
|
1367
|
-
apiBaseUrl
|
|
1368
|
-
});
|
|
1369
|
-
const gitAuthorInfo = {
|
|
1370
|
-
name: config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1371
|
-
email: config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1372
|
-
};
|
|
1373
|
-
let auth;
|
|
1374
|
-
if (ctx.input.token) {
|
|
1375
|
-
auth = {
|
|
1376
|
-
username: "x-token-auth",
|
|
1377
|
-
password: ctx.input.token
|
|
1378
|
-
};
|
|
1379
|
-
} else {
|
|
1380
|
-
if (!integrationConfig.config.username || !integrationConfig.config.appPassword) {
|
|
1381
|
-
throw new Error("Credentials for Bitbucket Cloud integration required for this action.");
|
|
1462
|
+
active: {
|
|
1463
|
+
title: "Active",
|
|
1464
|
+
type: "boolean",
|
|
1465
|
+
description: `Determines if notifications are sent when the webhook is triggered. Default: true`
|
|
1466
|
+
},
|
|
1467
|
+
contentType: {
|
|
1468
|
+
title: "Content Type",
|
|
1469
|
+
type: "string",
|
|
1470
|
+
enum: ["form", "json"],
|
|
1471
|
+
description: `The media type used to serialize the payloads. The default is 'form'`
|
|
1472
|
+
},
|
|
1473
|
+
insecureSsl: {
|
|
1474
|
+
title: "Insecure SSL",
|
|
1475
|
+
type: "boolean",
|
|
1476
|
+
description: `Determines whether the SSL certificate of the host for url will be verified when delivering payloads. Default 'false'`
|
|
1477
|
+
},
|
|
1478
|
+
token: {
|
|
1479
|
+
title: "Authentication Token",
|
|
1480
|
+
type: "string",
|
|
1481
|
+
description: "The GITHUB_TOKEN to use for authorization to GitHub"
|
|
1482
|
+
}
|
|
1382
1483
|
}
|
|
1383
|
-
auth = {
|
|
1384
|
-
username: integrationConfig.config.username,
|
|
1385
|
-
password: integrationConfig.config.appPassword
|
|
1386
|
-
};
|
|
1387
1484
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1485
|
+
},
|
|
1486
|
+
async handler(ctx) {
|
|
1487
|
+
const {
|
|
1488
|
+
repoUrl,
|
|
1489
|
+
webhookUrl,
|
|
1490
|
+
webhookSecret = defaultWebhookSecret,
|
|
1491
|
+
events = ["push"],
|
|
1492
|
+
active = true,
|
|
1493
|
+
contentType = "form",
|
|
1494
|
+
insecureSsl = false,
|
|
1495
|
+
token: providedToken
|
|
1496
|
+
} = ctx.input;
|
|
1497
|
+
ctx.logger.info(`Creating webhook ${webhookUrl} for repo ${repoUrl}`);
|
|
1498
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
1499
|
+
if (!owner) {
|
|
1500
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
1501
|
+
}
|
|
1502
|
+
const client = new octokit.Octokit(await getOctokitOptions({
|
|
1503
|
+
integrations,
|
|
1504
|
+
credentialsProvider: githubCredentialsProvider,
|
|
1505
|
+
repoUrl,
|
|
1506
|
+
token: providedToken
|
|
1507
|
+
}));
|
|
1508
|
+
try {
|
|
1509
|
+
const insecure_ssl = insecureSsl ? "1" : "0";
|
|
1510
|
+
await client.rest.repos.createWebhook({
|
|
1511
|
+
owner,
|
|
1512
|
+
repo,
|
|
1513
|
+
config: {
|
|
1514
|
+
url: webhookUrl,
|
|
1515
|
+
content_type: contentType,
|
|
1516
|
+
secret: webhookSecret,
|
|
1517
|
+
insecure_ssl
|
|
1518
|
+
},
|
|
1519
|
+
events,
|
|
1520
|
+
active
|
|
1521
|
+
});
|
|
1522
|
+
ctx.logger.info(`Webhook '${webhookUrl}' created successfully`);
|
|
1523
|
+
} catch (e) {
|
|
1524
|
+
errors.assertError(e);
|
|
1525
|
+
ctx.logger.warn(`Failed: create webhook '${webhookUrl}' on repo: '${repo}', ${e.message}`);
|
|
1526
|
+
}
|
|
1399
1527
|
}
|
|
1400
1528
|
});
|
|
1401
1529
|
}
|
|
1402
1530
|
|
|
1403
|
-
|
|
1404
|
-
const {
|
|
1405
|
-
project,
|
|
1406
|
-
repo,
|
|
1407
|
-
description,
|
|
1408
|
-
authorization,
|
|
1409
|
-
repoVisibility,
|
|
1410
|
-
apiBaseUrl
|
|
1411
|
-
} = opts;
|
|
1412
|
-
let response;
|
|
1413
|
-
const options = {
|
|
1414
|
-
method: "POST",
|
|
1415
|
-
body: JSON.stringify({
|
|
1416
|
-
name: repo,
|
|
1417
|
-
description,
|
|
1418
|
-
public: repoVisibility === "public"
|
|
1419
|
-
}),
|
|
1420
|
-
headers: {
|
|
1421
|
-
Authorization: authorization,
|
|
1422
|
-
"Content-Type": "application/json"
|
|
1423
|
-
}
|
|
1424
|
-
};
|
|
1425
|
-
try {
|
|
1426
|
-
response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
|
|
1427
|
-
} catch (e) {
|
|
1428
|
-
throw new Error(`Unable to create repository, ${e}`);
|
|
1429
|
-
}
|
|
1430
|
-
if (response.status !== 201) {
|
|
1431
|
-
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1432
|
-
}
|
|
1433
|
-
const r = await response.json();
|
|
1434
|
-
let remoteUrl = "";
|
|
1435
|
-
for (const link of r.links.clone) {
|
|
1436
|
-
if (link.name === "http") {
|
|
1437
|
-
remoteUrl = link.href;
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
const repoContentsUrl = `${r.links.self[0].href}`;
|
|
1441
|
-
return { remoteUrl, repoContentsUrl };
|
|
1442
|
-
};
|
|
1443
|
-
const getAuthorizationHeader = (config) => {
|
|
1444
|
-
return `Bearer ${config.token}`;
|
|
1445
|
-
};
|
|
1446
|
-
const performEnableLFS = async (opts) => {
|
|
1447
|
-
const { authorization, host, project, repo } = opts;
|
|
1448
|
-
const options = {
|
|
1449
|
-
method: "PUT",
|
|
1450
|
-
headers: {
|
|
1451
|
-
Authorization: authorization
|
|
1452
|
-
}
|
|
1453
|
-
};
|
|
1454
|
-
const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
|
|
1455
|
-
if (!ok)
|
|
1456
|
-
throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
|
|
1457
|
-
};
|
|
1458
|
-
function createPublishBitbucketServerAction(options) {
|
|
1531
|
+
function createPublishAzureAction(options) {
|
|
1459
1532
|
const { integrations, config } = options;
|
|
1460
1533
|
return createTemplateAction({
|
|
1461
|
-
id: "publish:
|
|
1462
|
-
description: "Initializes a git repository of the content in the workspace, and publishes it to
|
|
1534
|
+
id: "publish:azure",
|
|
1535
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Azure.",
|
|
1463
1536
|
schema: {
|
|
1464
1537
|
input: {
|
|
1465
1538
|
type: "object",
|
|
@@ -1473,30 +1546,35 @@ function createPublishBitbucketServerAction(options) {
|
|
|
1473
1546
|
title: "Repository Description",
|
|
1474
1547
|
type: "string"
|
|
1475
1548
|
},
|
|
1476
|
-
repoVisibility: {
|
|
1477
|
-
title: "Repository Visibility",
|
|
1478
|
-
type: "string",
|
|
1479
|
-
enum: ["private", "public"]
|
|
1480
|
-
},
|
|
1481
1549
|
defaultBranch: {
|
|
1482
1550
|
title: "Default Branch",
|
|
1483
1551
|
type: "string",
|
|
1484
1552
|
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1485
1553
|
},
|
|
1554
|
+
gitCommitMessage: {
|
|
1555
|
+
title: "Git Commit Message",
|
|
1556
|
+
type: "string",
|
|
1557
|
+
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
1558
|
+
},
|
|
1559
|
+
gitAuthorName: {
|
|
1560
|
+
title: "Default Author Name",
|
|
1561
|
+
type: "string",
|
|
1562
|
+
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
1563
|
+
},
|
|
1564
|
+
gitAuthorEmail: {
|
|
1565
|
+
title: "Default Author Email",
|
|
1566
|
+
type: "string",
|
|
1567
|
+
description: `Sets the default author email for the commit.`
|
|
1568
|
+
},
|
|
1486
1569
|
sourcePath: {
|
|
1487
1570
|
title: "Source Path",
|
|
1488
1571
|
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1489
1572
|
type: "string"
|
|
1490
1573
|
},
|
|
1491
|
-
enableLFS: {
|
|
1492
|
-
title: "Enable LFS?",
|
|
1493
|
-
description: "Enable LFS for the repository.",
|
|
1494
|
-
type: "boolean"
|
|
1495
|
-
},
|
|
1496
1574
|
token: {
|
|
1497
1575
|
title: "Authentication Token",
|
|
1498
1576
|
type: "string",
|
|
1499
|
-
description: "The token to use for authorization to
|
|
1577
|
+
description: "The token to use for authorization to Azure"
|
|
1500
1578
|
}
|
|
1501
1579
|
}
|
|
1502
1580
|
},
|
|
@@ -1518,119 +1596,169 @@ function createPublishBitbucketServerAction(options) {
|
|
|
1518
1596
|
var _a;
|
|
1519
1597
|
const {
|
|
1520
1598
|
repoUrl,
|
|
1521
|
-
description,
|
|
1522
1599
|
defaultBranch = "master",
|
|
1523
|
-
|
|
1524
|
-
|
|
1600
|
+
gitCommitMessage = "initial commit",
|
|
1601
|
+
gitAuthorName,
|
|
1602
|
+
gitAuthorEmail
|
|
1525
1603
|
} = ctx.input;
|
|
1526
|
-
const {
|
|
1527
|
-
if (!
|
|
1528
|
-
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing
|
|
1604
|
+
const { owner, repo, host, organization } = parseRepoUrl(repoUrl, integrations);
|
|
1605
|
+
if (!organization) {
|
|
1606
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing organization`);
|
|
1529
1607
|
}
|
|
1530
|
-
const integrationConfig = integrations.
|
|
1608
|
+
const integrationConfig = integrations.azure.byHost(host);
|
|
1531
1609
|
if (!integrationConfig) {
|
|
1532
1610
|
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1533
1611
|
}
|
|
1612
|
+
if (!integrationConfig.config.token && !ctx.input.token) {
|
|
1613
|
+
throw new errors.InputError(`No token provided for Azure Integration ${host}`);
|
|
1614
|
+
}
|
|
1534
1615
|
const token = (_a = ctx.input.token) != null ? _a : integrationConfig.config.token;
|
|
1535
|
-
|
|
1536
|
-
|
|
1616
|
+
const authHandler = azureDevopsNodeApi.getPersonalAccessTokenHandler(token);
|
|
1617
|
+
const webApi = new azureDevopsNodeApi.WebApi(`https://${host}/${organization}`, authHandler);
|
|
1618
|
+
const client = await webApi.getGitApi();
|
|
1619
|
+
const createOptions = { name: repo };
|
|
1620
|
+
const returnedRepo = await client.createRepository(createOptions, owner);
|
|
1621
|
+
if (!returnedRepo) {
|
|
1622
|
+
throw new errors.InputError(`Unable to create the repository with Organization ${organization}, Project ${owner} and Repo ${repo}.
|
|
1623
|
+
Please make sure that both the Org and Project are typed corrected and exist.`);
|
|
1537
1624
|
}
|
|
1538
|
-
const
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
repo,
|
|
1544
|
-
repoVisibility,
|
|
1545
|
-
description,
|
|
1546
|
-
apiBaseUrl
|
|
1547
|
-
});
|
|
1625
|
+
const remoteUrl = returnedRepo.remoteUrl;
|
|
1626
|
+
if (!remoteUrl) {
|
|
1627
|
+
throw new errors.InputError("No remote URL returned from create repository for Azure");
|
|
1628
|
+
}
|
|
1629
|
+
const repoContentsUrl = remoteUrl;
|
|
1548
1630
|
const gitAuthorInfo = {
|
|
1549
|
-
name: config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1550
|
-
email: config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1551
|
-
};
|
|
1552
|
-
const auth = {
|
|
1553
|
-
username: "x-token-auth",
|
|
1554
|
-
password: token
|
|
1631
|
+
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1632
|
+
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1555
1633
|
};
|
|
1556
1634
|
await initRepoAndPush({
|
|
1557
|
-
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
1558
|
-
remoteUrl,
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
}
|
|
1568
|
-
ctx.output("remoteUrl", remoteUrl);
|
|
1569
|
-
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1570
|
-
}
|
|
1571
|
-
});
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
function createPublishFileAction() {
|
|
1575
|
-
return createTemplateAction({
|
|
1576
|
-
id: "publish:file",
|
|
1577
|
-
description: "Writes contents of the workspace to a local directory",
|
|
1578
|
-
schema: {
|
|
1579
|
-
input: {
|
|
1580
|
-
type: "object",
|
|
1581
|
-
required: ["path"],
|
|
1582
|
-
properties: {
|
|
1583
|
-
path: {
|
|
1584
|
-
title: "Path to a directory where the output will be written",
|
|
1585
|
-
type: "string"
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
},
|
|
1590
|
-
async handler(ctx) {
|
|
1591
|
-
const { path: path$1 } = ctx.input;
|
|
1592
|
-
const exists = await fs__default["default"].pathExists(path$1);
|
|
1593
|
-
if (exists) {
|
|
1594
|
-
throw new errors.InputError("Output path already exists");
|
|
1595
|
-
}
|
|
1596
|
-
await fs__default["default"].ensureDir(path.dirname(path$1));
|
|
1597
|
-
await fs__default["default"].copy(ctx.workspacePath, path$1);
|
|
1635
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
1636
|
+
remoteUrl,
|
|
1637
|
+
defaultBranch,
|
|
1638
|
+
auth: {
|
|
1639
|
+
username: "notempty",
|
|
1640
|
+
password: token
|
|
1641
|
+
},
|
|
1642
|
+
logger: ctx.logger,
|
|
1643
|
+
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
1644
|
+
gitAuthorInfo
|
|
1645
|
+
});
|
|
1646
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
1647
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1598
1648
|
}
|
|
1599
1649
|
});
|
|
1600
1650
|
}
|
|
1601
1651
|
|
|
1602
|
-
const
|
|
1603
|
-
const {
|
|
1604
|
-
|
|
1605
|
-
|
|
1652
|
+
const createBitbucketCloudRepository = async (opts) => {
|
|
1653
|
+
const {
|
|
1654
|
+
workspace,
|
|
1655
|
+
project,
|
|
1656
|
+
repo,
|
|
1657
|
+
description,
|
|
1658
|
+
repoVisibility,
|
|
1659
|
+
mainBranch,
|
|
1660
|
+
authorization,
|
|
1661
|
+
apiBaseUrl
|
|
1662
|
+
} = opts;
|
|
1663
|
+
const options = {
|
|
1664
|
+
method: "POST",
|
|
1606
1665
|
body: JSON.stringify({
|
|
1607
|
-
|
|
1666
|
+
scm: "git",
|
|
1608
1667
|
description,
|
|
1609
|
-
|
|
1610
|
-
|
|
1668
|
+
is_private: repoVisibility === "private",
|
|
1669
|
+
project: { key: project }
|
|
1611
1670
|
}),
|
|
1612
1671
|
headers: {
|
|
1613
|
-
|
|
1672
|
+
Authorization: authorization,
|
|
1614
1673
|
"Content-Type": "application/json"
|
|
1615
1674
|
}
|
|
1616
1675
|
};
|
|
1617
|
-
|
|
1676
|
+
let response;
|
|
1677
|
+
try {
|
|
1678
|
+
response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
|
|
1679
|
+
} catch (e) {
|
|
1680
|
+
throw new Error(`Unable to create repository, ${e}`);
|
|
1681
|
+
}
|
|
1682
|
+
if (response.status !== 200) {
|
|
1683
|
+
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1684
|
+
}
|
|
1685
|
+
const r = await response.json();
|
|
1686
|
+
let remoteUrl = "";
|
|
1687
|
+
for (const link of r.links.clone) {
|
|
1688
|
+
if (link.name === "https") {
|
|
1689
|
+
remoteUrl = link.href;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
|
|
1693
|
+
return { remoteUrl, repoContentsUrl };
|
|
1694
|
+
};
|
|
1695
|
+
const createBitbucketServerRepository = async (opts) => {
|
|
1696
|
+
const {
|
|
1697
|
+
project,
|
|
1698
|
+
repo,
|
|
1699
|
+
description,
|
|
1700
|
+
authorization,
|
|
1701
|
+
repoVisibility,
|
|
1702
|
+
apiBaseUrl
|
|
1703
|
+
} = opts;
|
|
1704
|
+
let response;
|
|
1705
|
+
const options = {
|
|
1706
|
+
method: "POST",
|
|
1707
|
+
body: JSON.stringify({
|
|
1708
|
+
name: repo,
|
|
1709
|
+
description,
|
|
1710
|
+
public: repoVisibility === "public"
|
|
1711
|
+
}),
|
|
1712
|
+
headers: {
|
|
1713
|
+
Authorization: authorization,
|
|
1714
|
+
"Content-Type": "application/json"
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
try {
|
|
1718
|
+
response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
|
|
1719
|
+
} catch (e) {
|
|
1720
|
+
throw new Error(`Unable to create repository, ${e}`);
|
|
1721
|
+
}
|
|
1618
1722
|
if (response.status !== 201) {
|
|
1619
1723
|
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1620
1724
|
}
|
|
1725
|
+
const r = await response.json();
|
|
1726
|
+
let remoteUrl = "";
|
|
1727
|
+
for (const link of r.links.clone) {
|
|
1728
|
+
if (link.name === "http") {
|
|
1729
|
+
remoteUrl = link.href;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
const repoContentsUrl = `${r.links.self[0].href}`;
|
|
1733
|
+
return { remoteUrl, repoContentsUrl };
|
|
1621
1734
|
};
|
|
1622
|
-
const
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1735
|
+
const getAuthorizationHeader$2 = (config) => {
|
|
1736
|
+
if (config.username && config.appPassword) {
|
|
1737
|
+
const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
|
|
1738
|
+
return `Basic ${buffer.toString("base64")}`;
|
|
1739
|
+
}
|
|
1740
|
+
if (config.token) {
|
|
1741
|
+
return `Bearer ${config.token}`;
|
|
1742
|
+
}
|
|
1743
|
+
throw new Error(`Authorization has not been provided for Bitbucket. Please add either username + appPassword or token to the Integrations config`);
|
|
1628
1744
|
};
|
|
1629
|
-
|
|
1745
|
+
const performEnableLFS$1 = async (opts) => {
|
|
1746
|
+
const { authorization, host, project, repo } = opts;
|
|
1747
|
+
const options = {
|
|
1748
|
+
method: "PUT",
|
|
1749
|
+
headers: {
|
|
1750
|
+
Authorization: authorization
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
|
|
1754
|
+
if (!ok)
|
|
1755
|
+
throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
|
|
1756
|
+
};
|
|
1757
|
+
function createPublishBitbucketAction(options) {
|
|
1630
1758
|
const { integrations, config } = options;
|
|
1631
1759
|
return createTemplateAction({
|
|
1632
|
-
id: "publish:
|
|
1633
|
-
description: "Initializes a git repository of the content in the workspace, and publishes it to
|
|
1760
|
+
id: "publish:bitbucket",
|
|
1761
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Bitbucket.",
|
|
1634
1762
|
schema: {
|
|
1635
1763
|
input: {
|
|
1636
1764
|
type: "object",
|
|
@@ -1644,11 +1772,31 @@ function createPublishGerritAction(options) {
|
|
|
1644
1772
|
title: "Repository Description",
|
|
1645
1773
|
type: "string"
|
|
1646
1774
|
},
|
|
1775
|
+
repoVisibility: {
|
|
1776
|
+
title: "Repository Visibility",
|
|
1777
|
+
type: "string",
|
|
1778
|
+
enum: ["private", "public"]
|
|
1779
|
+
},
|
|
1647
1780
|
defaultBranch: {
|
|
1648
1781
|
title: "Default Branch",
|
|
1649
1782
|
type: "string",
|
|
1650
1783
|
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1651
1784
|
},
|
|
1785
|
+
sourcePath: {
|
|
1786
|
+
title: "Source Path",
|
|
1787
|
+
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1788
|
+
type: "string"
|
|
1789
|
+
},
|
|
1790
|
+
enableLFS: {
|
|
1791
|
+
title: "Enable LFS?",
|
|
1792
|
+
description: "Enable LFS for the repository. Only available for hosted Bitbucket.",
|
|
1793
|
+
type: "boolean"
|
|
1794
|
+
},
|
|
1795
|
+
token: {
|
|
1796
|
+
title: "Authentication Token",
|
|
1797
|
+
type: "string",
|
|
1798
|
+
description: "The token to use for authorization to BitBucket"
|
|
1799
|
+
},
|
|
1652
1800
|
gitCommitMessage: {
|
|
1653
1801
|
title: "Git Commit Message",
|
|
1654
1802
|
type: "string",
|
|
@@ -1681,98 +1829,140 @@ function createPublishGerritAction(options) {
|
|
|
1681
1829
|
}
|
|
1682
1830
|
},
|
|
1683
1831
|
async handler(ctx) {
|
|
1832
|
+
var _a;
|
|
1833
|
+
ctx.logger.warn(`[Deprecated] Please migrate the use of action "publish:bitbucket" to "publish:bitbucketCloud" or "publish:bitbucketServer".`);
|
|
1684
1834
|
const {
|
|
1685
1835
|
repoUrl,
|
|
1686
1836
|
description,
|
|
1687
1837
|
defaultBranch = "master",
|
|
1838
|
+
repoVisibility = "private",
|
|
1839
|
+
enableLFS = false,
|
|
1840
|
+
gitCommitMessage = "initial commit",
|
|
1688
1841
|
gitAuthorName,
|
|
1689
|
-
gitAuthorEmail
|
|
1690
|
-
gitCommitMessage = "initial commit"
|
|
1842
|
+
gitAuthorEmail
|
|
1691
1843
|
} = ctx.input;
|
|
1692
|
-
const {
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1844
|
+
const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
1845
|
+
if (host === "bitbucket.org") {
|
|
1846
|
+
if (!workspace) {
|
|
1847
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
|
|
1848
|
+
}
|
|
1696
1849
|
}
|
|
1697
|
-
if (!
|
|
1698
|
-
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing
|
|
1850
|
+
if (!project) {
|
|
1851
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
|
|
1699
1852
|
}
|
|
1700
|
-
|
|
1701
|
-
|
|
1853
|
+
const integrationConfig = integrations.bitbucket.byHost(host);
|
|
1854
|
+
if (!integrationConfig) {
|
|
1855
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
1702
1856
|
}
|
|
1703
|
-
|
|
1857
|
+
const authorization = getAuthorizationHeader$2(ctx.input.token ? {
|
|
1858
|
+
host: integrationConfig.config.host,
|
|
1859
|
+
apiBaseUrl: integrationConfig.config.apiBaseUrl,
|
|
1860
|
+
token: ctx.input.token
|
|
1861
|
+
} : integrationConfig.config);
|
|
1862
|
+
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
1863
|
+
const createMethod = host === "bitbucket.org" ? createBitbucketCloudRepository : createBitbucketServerRepository;
|
|
1864
|
+
const { remoteUrl, repoContentsUrl } = await createMethod({
|
|
1865
|
+
authorization,
|
|
1866
|
+
workspace: workspace || "",
|
|
1867
|
+
project,
|
|
1868
|
+
repo,
|
|
1869
|
+
repoVisibility,
|
|
1870
|
+
mainBranch: defaultBranch,
|
|
1704
1871
|
description,
|
|
1705
|
-
|
|
1706
|
-
projectName: repo,
|
|
1707
|
-
parent: workspace
|
|
1872
|
+
apiBaseUrl
|
|
1708
1873
|
});
|
|
1709
|
-
const auth = {
|
|
1710
|
-
username: integrationConfig.config.username,
|
|
1711
|
-
password: integrationConfig.config.password
|
|
1712
|
-
};
|
|
1713
1874
|
const gitAuthorInfo = {
|
|
1714
1875
|
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
1715
1876
|
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
1716
1877
|
};
|
|
1717
|
-
|
|
1878
|
+
let auth;
|
|
1879
|
+
if (ctx.input.token) {
|
|
1880
|
+
auth = {
|
|
1881
|
+
username: "x-token-auth",
|
|
1882
|
+
password: ctx.input.token
|
|
1883
|
+
};
|
|
1884
|
+
} else {
|
|
1885
|
+
auth = {
|
|
1886
|
+
username: integrationConfig.config.username ? integrationConfig.config.username : "x-token-auth",
|
|
1887
|
+
password: integrationConfig.config.appPassword ? integrationConfig.config.appPassword : (_a = integrationConfig.config.token) != null ? _a : ""
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1718
1890
|
await initRepoAndPush({
|
|
1719
|
-
dir: getRepoSourceDirectory(ctx.workspacePath,
|
|
1891
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
1720
1892
|
remoteUrl,
|
|
1721
1893
|
auth,
|
|
1722
1894
|
defaultBranch,
|
|
1723
1895
|
logger: ctx.logger,
|
|
1724
|
-
commitMessage:
|
|
1896
|
+
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
1725
1897
|
gitAuthorInfo
|
|
1726
1898
|
});
|
|
1727
|
-
|
|
1899
|
+
if (enableLFS && host !== "bitbucket.org") {
|
|
1900
|
+
await performEnableLFS$1({ authorization, host, project, repo });
|
|
1901
|
+
}
|
|
1728
1902
|
ctx.output("remoteUrl", remoteUrl);
|
|
1729
1903
|
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
1730
1904
|
}
|
|
1731
1905
|
});
|
|
1732
1906
|
}
|
|
1733
1907
|
|
|
1734
|
-
const
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1908
|
+
const createRepository$1 = async (opts) => {
|
|
1909
|
+
const {
|
|
1910
|
+
workspace,
|
|
1911
|
+
project,
|
|
1912
|
+
repo,
|
|
1913
|
+
description,
|
|
1914
|
+
repoVisibility,
|
|
1915
|
+
mainBranch,
|
|
1916
|
+
authorization,
|
|
1917
|
+
apiBaseUrl
|
|
1918
|
+
} = opts;
|
|
1919
|
+
const options = {
|
|
1920
|
+
method: "POST",
|
|
1921
|
+
body: JSON.stringify({
|
|
1922
|
+
scm: "git",
|
|
1923
|
+
description,
|
|
1924
|
+
is_private: repoVisibility === "private",
|
|
1925
|
+
project: { key: project }
|
|
1926
|
+
}),
|
|
1927
|
+
headers: {
|
|
1928
|
+
Authorization: authorization,
|
|
1929
|
+
"Content-Type": "application/json"
|
|
1930
|
+
}
|
|
1741
1931
|
};
|
|
1742
|
-
|
|
1743
|
-
|
|
1932
|
+
let response;
|
|
1933
|
+
try {
|
|
1934
|
+
response = await fetch__default["default"](`${apiBaseUrl}/repositories/${workspace}/${repo}`, options);
|
|
1935
|
+
} catch (e) {
|
|
1936
|
+
throw new Error(`Unable to create repository, ${e}`);
|
|
1937
|
+
}
|
|
1938
|
+
if (response.status !== 200) {
|
|
1939
|
+
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
1744
1940
|
}
|
|
1745
|
-
const
|
|
1746
|
-
|
|
1747
|
-
|
|
1941
|
+
const r = await response.json();
|
|
1942
|
+
let remoteUrl = "";
|
|
1943
|
+
for (const link of r.links.clone) {
|
|
1944
|
+
if (link.name === "https") {
|
|
1945
|
+
remoteUrl = link.href;
|
|
1946
|
+
}
|
|
1748
1947
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
}
|
|
1948
|
+
const repoContentsUrl = `${r.links.html.href}/src/${mainBranch}`;
|
|
1949
|
+
return { remoteUrl, repoContentsUrl };
|
|
1950
|
+
};
|
|
1951
|
+
const getAuthorizationHeader$1 = (config) => {
|
|
1952
|
+
if (config.username && config.appPassword) {
|
|
1953
|
+
const buffer = Buffer.from(`${config.username}:${config.appPassword}`, "utf8");
|
|
1954
|
+
return `Basic ${buffer.toString("base64")}`;
|
|
1756
1955
|
}
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`
|
|
1760
|
-
});
|
|
1761
|
-
if (!credentialProviderToken) {
|
|
1762
|
-
throw new errors.InputError(`No token available for host: ${host}, with owner ${owner}, and repo ${repo}`);
|
|
1956
|
+
if (config.token) {
|
|
1957
|
+
return `Bearer ${config.token}`;
|
|
1763
1958
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
function createPublishGithubAction(options) {
|
|
1772
|
-
const { integrations, config, githubCredentialsProvider } = options;
|
|
1959
|
+
throw new Error(`Authorization has not been provided for Bitbucket Cloud. Please add either username + appPassword to the Integrations config or a user login auth token`);
|
|
1960
|
+
};
|
|
1961
|
+
function createPublishBitbucketCloudAction(options) {
|
|
1962
|
+
const { integrations, config } = options;
|
|
1773
1963
|
return createTemplateAction({
|
|
1774
|
-
id: "publish:
|
|
1775
|
-
description: "Initializes a git repository of
|
|
1964
|
+
id: "publish:bitbucketCloud",
|
|
1965
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Bitbucket Cloud.",
|
|
1776
1966
|
schema: {
|
|
1777
1967
|
input: {
|
|
1778
1968
|
type: "object",
|
|
@@ -1780,131 +1970,31 @@ function createPublishGithubAction(options) {
|
|
|
1780
1970
|
properties: {
|
|
1781
1971
|
repoUrl: {
|
|
1782
1972
|
title: "Repository Location",
|
|
1783
|
-
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`,
|
|
1784
1973
|
type: "string"
|
|
1785
1974
|
},
|
|
1786
1975
|
description: {
|
|
1787
1976
|
title: "Repository Description",
|
|
1788
1977
|
type: "string"
|
|
1789
1978
|
},
|
|
1790
|
-
access: {
|
|
1791
|
-
title: "Repository Access",
|
|
1792
|
-
description: `Sets an admin collaborator on the repository. Can either be a user reference different from 'owner' in 'repoUrl' or team reference, eg. 'org/team-name'`,
|
|
1793
|
-
type: "string"
|
|
1794
|
-
},
|
|
1795
|
-
requireCodeOwnerReviews: {
|
|
1796
|
-
title: "Require CODEOWNER Reviews?",
|
|
1797
|
-
description: "Require an approved review in PR including files with a designated Code Owner",
|
|
1798
|
-
type: "boolean"
|
|
1799
|
-
},
|
|
1800
|
-
requiredStatusCheckContexts: {
|
|
1801
|
-
title: "Required Status Check Contexts",
|
|
1802
|
-
description: "The list of status checks to require in order to merge into this branch",
|
|
1803
|
-
type: "array",
|
|
1804
|
-
items: {
|
|
1805
|
-
type: "string"
|
|
1806
|
-
}
|
|
1807
|
-
},
|
|
1808
1979
|
repoVisibility: {
|
|
1809
1980
|
title: "Repository Visibility",
|
|
1810
1981
|
type: "string",
|
|
1811
|
-
enum: ["private", "public"
|
|
1982
|
+
enum: ["private", "public"]
|
|
1812
1983
|
},
|
|
1813
1984
|
defaultBranch: {
|
|
1814
1985
|
title: "Default Branch",
|
|
1815
1986
|
type: "string",
|
|
1816
1987
|
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
1817
1988
|
},
|
|
1818
|
-
protectDefaultBranch: {
|
|
1819
|
-
title: "Protect Default Branch",
|
|
1820
|
-
type: "boolean",
|
|
1821
|
-
description: `Protect the default branch after creating the repository. The default value is 'true'`
|
|
1822
|
-
},
|
|
1823
|
-
deleteBranchOnMerge: {
|
|
1824
|
-
title: "Delete Branch On Merge",
|
|
1825
|
-
type: "boolean",
|
|
1826
|
-
description: `Delete the branch after merging the PR. The default value is 'false'`
|
|
1827
|
-
},
|
|
1828
|
-
gitCommitMessage: {
|
|
1829
|
-
title: "Git Commit Message",
|
|
1830
|
-
type: "string",
|
|
1831
|
-
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
1832
|
-
},
|
|
1833
|
-
gitAuthorName: {
|
|
1834
|
-
title: "Default Author Name",
|
|
1835
|
-
type: "string",
|
|
1836
|
-
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
1837
|
-
},
|
|
1838
|
-
gitAuthorEmail: {
|
|
1839
|
-
title: "Default Author Email",
|
|
1840
|
-
type: "string",
|
|
1841
|
-
description: `Sets the default author email for the commit.`
|
|
1842
|
-
},
|
|
1843
|
-
allowMergeCommit: {
|
|
1844
|
-
title: "Allow Merge Commits",
|
|
1845
|
-
type: "boolean",
|
|
1846
|
-
description: `Allow merge commits. The default value is 'true'`
|
|
1847
|
-
},
|
|
1848
|
-
allowSquashMerge: {
|
|
1849
|
-
title: "Allow Squash Merges",
|
|
1850
|
-
type: "boolean",
|
|
1851
|
-
description: `Allow squash merges. The default value is 'true'`
|
|
1852
|
-
},
|
|
1853
|
-
allowRebaseMerge: {
|
|
1854
|
-
title: "Allow Rebase Merges",
|
|
1855
|
-
type: "boolean",
|
|
1856
|
-
description: `Allow rebase merges. The default value is 'true'`
|
|
1857
|
-
},
|
|
1858
1989
|
sourcePath: {
|
|
1859
1990
|
title: "Source Path",
|
|
1860
1991
|
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
1861
1992
|
type: "string"
|
|
1862
1993
|
},
|
|
1863
|
-
collaborators: {
|
|
1864
|
-
title: "Collaborators",
|
|
1865
|
-
description: "Provide additional users or teams with permissions",
|
|
1866
|
-
type: "array",
|
|
1867
|
-
items: {
|
|
1868
|
-
type: "object",
|
|
1869
|
-
additionalProperties: false,
|
|
1870
|
-
required: ["access"],
|
|
1871
|
-
properties: {
|
|
1872
|
-
access: {
|
|
1873
|
-
type: "string",
|
|
1874
|
-
description: "The type of access for the user",
|
|
1875
|
-
enum: ["push", "pull", "admin", "maintain", "triage"]
|
|
1876
|
-
},
|
|
1877
|
-
user: {
|
|
1878
|
-
type: "string",
|
|
1879
|
-
description: "The name of the user that will be added as a collaborator"
|
|
1880
|
-
},
|
|
1881
|
-
username: {
|
|
1882
|
-
type: "string",
|
|
1883
|
-
description: "Deprecated. Use the `team` or `user` field instead."
|
|
1884
|
-
},
|
|
1885
|
-
team: {
|
|
1886
|
-
type: "string",
|
|
1887
|
-
description: "The name of the team that will be added as a collaborator"
|
|
1888
|
-
}
|
|
1889
|
-
},
|
|
1890
|
-
oneOf: [
|
|
1891
|
-
{ required: ["user"] },
|
|
1892
|
-
{ required: ["username"] },
|
|
1893
|
-
{ required: ["team"] }
|
|
1894
|
-
]
|
|
1895
|
-
}
|
|
1896
|
-
},
|
|
1897
1994
|
token: {
|
|
1898
1995
|
title: "Authentication Token",
|
|
1899
1996
|
type: "string",
|
|
1900
|
-
description: "The token to use for authorization to
|
|
1901
|
-
},
|
|
1902
|
-
topics: {
|
|
1903
|
-
title: "Topics",
|
|
1904
|
-
type: "array",
|
|
1905
|
-
items: {
|
|
1906
|
-
type: "string"
|
|
1907
|
-
}
|
|
1997
|
+
description: "The token to use for authorization to BitBucket Cloud"
|
|
1908
1998
|
}
|
|
1909
1999
|
}
|
|
1910
2000
|
},
|
|
@@ -1926,370 +2016,297 @@ function createPublishGithubAction(options) {
|
|
|
1926
2016
|
const {
|
|
1927
2017
|
repoUrl,
|
|
1928
2018
|
description,
|
|
1929
|
-
access,
|
|
1930
|
-
requireCodeOwnerReviews = false,
|
|
1931
|
-
requiredStatusCheckContexts = [],
|
|
1932
|
-
repoVisibility = "private",
|
|
1933
2019
|
defaultBranch = "master",
|
|
1934
|
-
|
|
1935
|
-
deleteBranchOnMerge = false,
|
|
1936
|
-
gitCommitMessage = "initial commit",
|
|
1937
|
-
gitAuthorName,
|
|
1938
|
-
gitAuthorEmail,
|
|
1939
|
-
allowMergeCommit = true,
|
|
1940
|
-
allowSquashMerge = true,
|
|
1941
|
-
allowRebaseMerge = true,
|
|
1942
|
-
collaborators,
|
|
1943
|
-
topics,
|
|
1944
|
-
token: providedToken
|
|
2020
|
+
repoVisibility = "private"
|
|
1945
2021
|
} = ctx.input;
|
|
1946
|
-
const {
|
|
1947
|
-
if (!
|
|
1948
|
-
throw new errors.InputError(
|
|
1949
|
-
}
|
|
1950
|
-
const octokitOptions = await getOctokitOptions({
|
|
1951
|
-
integrations,
|
|
1952
|
-
credentialsProvider: githubCredentialsProvider,
|
|
1953
|
-
token: providedToken,
|
|
1954
|
-
repoUrl
|
|
1955
|
-
});
|
|
1956
|
-
const client = new octokit.Octokit(octokitOptions);
|
|
1957
|
-
const user = await client.rest.users.getByUsername({
|
|
1958
|
-
username: owner
|
|
1959
|
-
});
|
|
1960
|
-
const repoCreationPromise = user.data.type === "Organization" ? client.rest.repos.createInOrg({
|
|
1961
|
-
name: repo,
|
|
1962
|
-
org: owner,
|
|
1963
|
-
private: repoVisibility === "private",
|
|
1964
|
-
visibility: repoVisibility,
|
|
1965
|
-
description,
|
|
1966
|
-
delete_branch_on_merge: deleteBranchOnMerge,
|
|
1967
|
-
allow_merge_commit: allowMergeCommit,
|
|
1968
|
-
allow_squash_merge: allowSquashMerge,
|
|
1969
|
-
allow_rebase_merge: allowRebaseMerge
|
|
1970
|
-
}) : client.rest.repos.createForAuthenticatedUser({
|
|
1971
|
-
name: repo,
|
|
1972
|
-
private: repoVisibility === "private",
|
|
1973
|
-
description,
|
|
1974
|
-
delete_branch_on_merge: deleteBranchOnMerge,
|
|
1975
|
-
allow_merge_commit: allowMergeCommit,
|
|
1976
|
-
allow_squash_merge: allowSquashMerge,
|
|
1977
|
-
allow_rebase_merge: allowRebaseMerge
|
|
1978
|
-
});
|
|
1979
|
-
let newRepo;
|
|
1980
|
-
try {
|
|
1981
|
-
newRepo = (await repoCreationPromise).data;
|
|
1982
|
-
} catch (e) {
|
|
1983
|
-
errors.assertError(e);
|
|
1984
|
-
if (e.message === "Resource not accessible by integration") {
|
|
1985
|
-
ctx.logger.warn(`The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.`);
|
|
1986
|
-
}
|
|
1987
|
-
throw new Error(`Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}`);
|
|
1988
|
-
}
|
|
1989
|
-
if (access == null ? void 0 : access.startsWith(`${owner}/`)) {
|
|
1990
|
-
const [, team] = access.split("/");
|
|
1991
|
-
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
1992
|
-
org: owner,
|
|
1993
|
-
team_slug: team,
|
|
1994
|
-
owner,
|
|
1995
|
-
repo,
|
|
1996
|
-
permission: "admin"
|
|
1997
|
-
});
|
|
1998
|
-
} else if (access && access !== owner) {
|
|
1999
|
-
await client.rest.repos.addCollaborator({
|
|
2000
|
-
owner,
|
|
2001
|
-
repo,
|
|
2002
|
-
username: access,
|
|
2003
|
-
permission: "admin"
|
|
2004
|
-
});
|
|
2022
|
+
const { workspace, project, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
2023
|
+
if (!workspace) {
|
|
2024
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
|
|
2005
2025
|
}
|
|
2006
|
-
if (
|
|
2007
|
-
|
|
2008
|
-
try {
|
|
2009
|
-
if ("user" in collaborator) {
|
|
2010
|
-
await client.rest.repos.addCollaborator({
|
|
2011
|
-
owner,
|
|
2012
|
-
repo,
|
|
2013
|
-
username: collaborator.user,
|
|
2014
|
-
permission: collaborator.access
|
|
2015
|
-
});
|
|
2016
|
-
} else if ("username" in collaborator) {
|
|
2017
|
-
ctx.logger.warn("The field `username` is deprecated in favor of `team` and will be removed in the future.");
|
|
2018
|
-
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
2019
|
-
org: owner,
|
|
2020
|
-
team_slug: collaborator.username,
|
|
2021
|
-
owner,
|
|
2022
|
-
repo,
|
|
2023
|
-
permission: collaborator.access
|
|
2024
|
-
});
|
|
2025
|
-
} else if ("team" in collaborator) {
|
|
2026
|
-
await client.rest.teams.addOrUpdateRepoPermissionsInOrg({
|
|
2027
|
-
org: owner,
|
|
2028
|
-
team_slug: collaborator.team,
|
|
2029
|
-
owner,
|
|
2030
|
-
repo,
|
|
2031
|
-
permission: collaborator.access
|
|
2032
|
-
});
|
|
2033
|
-
}
|
|
2034
|
-
} catch (e) {
|
|
2035
|
-
errors.assertError(e);
|
|
2036
|
-
const name = extractCollaboratorName(collaborator);
|
|
2037
|
-
ctx.logger.warn(`Skipping ${collaborator.access} access for ${name}, ${e.message}`);
|
|
2038
|
-
}
|
|
2039
|
-
}
|
|
2026
|
+
if (!project) {
|
|
2027
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
|
|
2040
2028
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
owner,
|
|
2045
|
-
repo,
|
|
2046
|
-
names: topics.map((t) => t.toLowerCase())
|
|
2047
|
-
});
|
|
2048
|
-
} catch (e) {
|
|
2049
|
-
errors.assertError(e);
|
|
2050
|
-
ctx.logger.warn(`Skipping topics ${topics.join(" ")}, ${e.message}`);
|
|
2051
|
-
}
|
|
2029
|
+
const integrationConfig = integrations.bitbucketCloud.byHost(host);
|
|
2030
|
+
if (!integrationConfig) {
|
|
2031
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
2052
2032
|
}
|
|
2053
|
-
const
|
|
2054
|
-
const
|
|
2033
|
+
const authorization = getAuthorizationHeader$1(ctx.input.token ? { token: ctx.input.token } : integrationConfig.config);
|
|
2034
|
+
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
2035
|
+
const { remoteUrl, repoContentsUrl } = await createRepository$1({
|
|
2036
|
+
authorization,
|
|
2037
|
+
workspace: workspace || "",
|
|
2038
|
+
project,
|
|
2039
|
+
repo,
|
|
2040
|
+
repoVisibility,
|
|
2041
|
+
mainBranch: defaultBranch,
|
|
2042
|
+
description,
|
|
2043
|
+
apiBaseUrl
|
|
2044
|
+
});
|
|
2055
2045
|
const gitAuthorInfo = {
|
|
2056
|
-
name:
|
|
2057
|
-
email:
|
|
2046
|
+
name: config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
2047
|
+
email: config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
2058
2048
|
};
|
|
2049
|
+
let auth;
|
|
2050
|
+
if (ctx.input.token) {
|
|
2051
|
+
auth = {
|
|
2052
|
+
username: "x-token-auth",
|
|
2053
|
+
password: ctx.input.token
|
|
2054
|
+
};
|
|
2055
|
+
} else {
|
|
2056
|
+
if (!integrationConfig.config.username || !integrationConfig.config.appPassword) {
|
|
2057
|
+
throw new Error("Credentials for Bitbucket Cloud integration required for this action.");
|
|
2058
|
+
}
|
|
2059
|
+
auth = {
|
|
2060
|
+
username: integrationConfig.config.username,
|
|
2061
|
+
password: integrationConfig.config.appPassword
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2059
2064
|
await initRepoAndPush({
|
|
2060
2065
|
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
2061
2066
|
remoteUrl,
|
|
2067
|
+
auth,
|
|
2062
2068
|
defaultBranch,
|
|
2063
|
-
auth: {
|
|
2064
|
-
username: "x-access-token",
|
|
2065
|
-
password: octokitOptions.auth
|
|
2066
|
-
},
|
|
2067
2069
|
logger: ctx.logger,
|
|
2068
|
-
commitMessage:
|
|
2070
|
+
commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
2069
2071
|
gitAuthorInfo
|
|
2070
2072
|
});
|
|
2071
|
-
if (protectDefaultBranch) {
|
|
2072
|
-
try {
|
|
2073
|
-
await enableBranchProtectionOnDefaultRepoBranch({
|
|
2074
|
-
owner,
|
|
2075
|
-
client,
|
|
2076
|
-
repoName: newRepo.name,
|
|
2077
|
-
logger: ctx.logger,
|
|
2078
|
-
defaultBranch,
|
|
2079
|
-
requireCodeOwnerReviews,
|
|
2080
|
-
requiredStatusCheckContexts
|
|
2081
|
-
});
|
|
2082
|
-
} catch (e) {
|
|
2083
|
-
errors.assertError(e);
|
|
2084
|
-
ctx.logger.warn(`Skipping: default branch protection on '${newRepo.name}', ${e.message}`);
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
2073
|
ctx.output("remoteUrl", remoteUrl);
|
|
2088
2074
|
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
2089
|
-
}
|
|
2090
|
-
});
|
|
2091
|
-
}
|
|
2092
|
-
function extractCollaboratorName(collaborator) {
|
|
2093
|
-
if ("username" in collaborator)
|
|
2094
|
-
return collaborator.username;
|
|
2095
|
-
if ("user" in collaborator)
|
|
2096
|
-
return collaborator.user;
|
|
2097
|
-
return collaborator.team;
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
const DEFAULT_GLOB_PATTERNS = ["./**", "!.git"];
|
|
2101
|
-
const isExecutable = (fileMode) => {
|
|
2102
|
-
if (!fileMode) {
|
|
2103
|
-
return false;
|
|
2104
|
-
}
|
|
2105
|
-
const executeBitMask = 73;
|
|
2106
|
-
const res = fileMode & executeBitMask;
|
|
2107
|
-
return res > 0;
|
|
2108
|
-
};
|
|
2109
|
-
async function serializeDirectoryContents(sourcePath, options) {
|
|
2110
|
-
var _a;
|
|
2111
|
-
const paths = await globby__default["default"]((_a = options == null ? void 0 : options.globPatterns) != null ? _a : DEFAULT_GLOB_PATTERNS, {
|
|
2112
|
-
cwd: sourcePath,
|
|
2113
|
-
dot: true,
|
|
2114
|
-
gitignore: options == null ? void 0 : options.gitignore,
|
|
2115
|
-
followSymbolicLinks: false,
|
|
2116
|
-
objectMode: true,
|
|
2117
|
-
stats: true
|
|
2118
|
-
});
|
|
2119
|
-
const limiter = limiterFactory__default["default"](10);
|
|
2120
|
-
return Promise.all(paths.map(async ({ path: path$1, stats }) => ({
|
|
2121
|
-
path: path$1,
|
|
2122
|
-
content: await limiter(async () => fs__default["default"].readFile(path.join(sourcePath, path$1))),
|
|
2123
|
-
executable: isExecutable(stats == null ? void 0 : stats.mode)
|
|
2124
|
-
})));
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
async function deserializeDirectoryContents(targetPath, files) {
|
|
2128
|
-
for (const file of files) {
|
|
2129
|
-
const filePath = backendCommon.resolveSafeChildPath(targetPath, file.path);
|
|
2130
|
-
await fs__default["default"].ensureDir(path.dirname(filePath));
|
|
2131
|
-
await fs__default["default"].writeFile(filePath, file.content);
|
|
2132
|
-
}
|
|
2075
|
+
}
|
|
2076
|
+
});
|
|
2133
2077
|
}
|
|
2134
2078
|
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2079
|
+
const createRepository = async (opts) => {
|
|
2080
|
+
const {
|
|
2081
|
+
project,
|
|
2082
|
+
repo,
|
|
2083
|
+
description,
|
|
2084
|
+
authorization,
|
|
2085
|
+
repoVisibility,
|
|
2086
|
+
apiBaseUrl
|
|
2087
|
+
} = opts;
|
|
2088
|
+
let response;
|
|
2089
|
+
const options = {
|
|
2090
|
+
method: "POST",
|
|
2091
|
+
body: JSON.stringify({
|
|
2092
|
+
name: repo,
|
|
2093
|
+
description,
|
|
2094
|
+
public: repoVisibility === "public"
|
|
2095
|
+
}),
|
|
2096
|
+
headers: {
|
|
2097
|
+
Authorization: authorization,
|
|
2098
|
+
"Content-Type": "application/json"
|
|
2099
|
+
}
|
|
2100
|
+
};
|
|
2101
|
+
try {
|
|
2102
|
+
response = await fetch__default["default"](`${apiBaseUrl}/projects/${project}/repos`, options);
|
|
2103
|
+
} catch (e) {
|
|
2104
|
+
throw new Error(`Unable to create repository, ${e}`);
|
|
2105
|
+
}
|
|
2106
|
+
if (response.status !== 201) {
|
|
2107
|
+
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
2108
|
+
}
|
|
2109
|
+
const r = await response.json();
|
|
2110
|
+
let remoteUrl = "";
|
|
2111
|
+
for (const link of r.links.clone) {
|
|
2112
|
+
if (link.name === "http") {
|
|
2113
|
+
remoteUrl = link.href;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
const repoContentsUrl = `${r.links.self[0].href}`;
|
|
2117
|
+
return { remoteUrl, repoContentsUrl };
|
|
2154
2118
|
};
|
|
2155
|
-
const
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
}
|
|
2119
|
+
const getAuthorizationHeader = (config) => {
|
|
2120
|
+
return `Bearer ${config.token}`;
|
|
2121
|
+
};
|
|
2122
|
+
const performEnableLFS = async (opts) => {
|
|
2123
|
+
const { authorization, host, project, repo } = opts;
|
|
2124
|
+
const options = {
|
|
2125
|
+
method: "PUT",
|
|
2126
|
+
headers: {
|
|
2127
|
+
Authorization: authorization
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
const { ok, status, statusText } = await fetch__default["default"](`https://${host}/rest/git-lfs/admin/projects/${project}/repos/${repo}/enabled`, options);
|
|
2131
|
+
if (!ok)
|
|
2132
|
+
throw new Error(`Failed to enable LFS in the repository, ${status}: ${statusText}`);
|
|
2133
|
+
};
|
|
2134
|
+
function createPublishBitbucketServerAction(options) {
|
|
2135
|
+
const { integrations, config } = options;
|
|
2160
2136
|
return createTemplateAction({
|
|
2161
|
-
id: "publish:
|
|
2137
|
+
id: "publish:bitbucketServer",
|
|
2138
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Bitbucket Server.",
|
|
2162
2139
|
schema: {
|
|
2163
2140
|
input: {
|
|
2164
|
-
required: ["repoUrl", "title", "description", "branchName"],
|
|
2165
2141
|
type: "object",
|
|
2142
|
+
required: ["repoUrl"],
|
|
2166
2143
|
properties: {
|
|
2167
2144
|
repoUrl: {
|
|
2168
2145
|
title: "Repository Location",
|
|
2169
|
-
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the repository name and 'owner' is an organization or username`,
|
|
2170
2146
|
type: "string"
|
|
2171
2147
|
},
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
description: "The name for the branch"
|
|
2148
|
+
description: {
|
|
2149
|
+
title: "Repository Description",
|
|
2150
|
+
type: "string"
|
|
2176
2151
|
},
|
|
2177
|
-
|
|
2152
|
+
repoVisibility: {
|
|
2153
|
+
title: "Repository Visibility",
|
|
2178
2154
|
type: "string",
|
|
2179
|
-
|
|
2180
|
-
description: "The name for the pull request"
|
|
2155
|
+
enum: ["private", "public"]
|
|
2181
2156
|
},
|
|
2182
|
-
|
|
2157
|
+
defaultBranch: {
|
|
2158
|
+
title: "Default Branch",
|
|
2183
2159
|
type: "string",
|
|
2184
|
-
|
|
2185
|
-
description: "The description of the pull request"
|
|
2186
|
-
},
|
|
2187
|
-
draft: {
|
|
2188
|
-
type: "boolean",
|
|
2189
|
-
title: "Create as Draft",
|
|
2190
|
-
description: "Create a draft pull request"
|
|
2160
|
+
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
2191
2161
|
},
|
|
2192
2162
|
sourcePath: {
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2163
|
+
title: "Source Path",
|
|
2164
|
+
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
2165
|
+
type: "string"
|
|
2196
2166
|
},
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2167
|
+
enableLFS: {
|
|
2168
|
+
title: "Enable LFS?",
|
|
2169
|
+
description: "Enable LFS for the repository.",
|
|
2170
|
+
type: "boolean"
|
|
2201
2171
|
},
|
|
2202
2172
|
token: {
|
|
2203
2173
|
title: "Authentication Token",
|
|
2204
2174
|
type: "string",
|
|
2205
|
-
description: "The token to use for authorization to
|
|
2175
|
+
description: "The token to use for authorization to BitBucket Server"
|
|
2206
2176
|
}
|
|
2207
2177
|
}
|
|
2208
2178
|
},
|
|
2209
2179
|
output: {
|
|
2210
|
-
required: ["remoteUrl"],
|
|
2211
2180
|
type: "object",
|
|
2212
2181
|
properties: {
|
|
2213
2182
|
remoteUrl: {
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
description: "Link to the pull request in Github"
|
|
2183
|
+
title: "A URL to the repository with the provider",
|
|
2184
|
+
type: "string"
|
|
2217
2185
|
},
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
description: "The pull request number"
|
|
2186
|
+
repoContentsUrl: {
|
|
2187
|
+
title: "A URL to the root of the repository",
|
|
2188
|
+
type: "string"
|
|
2222
2189
|
}
|
|
2223
2190
|
}
|
|
2224
2191
|
}
|
|
2225
2192
|
},
|
|
2226
2193
|
async handler(ctx) {
|
|
2194
|
+
var _a;
|
|
2227
2195
|
const {
|
|
2228
2196
|
repoUrl,
|
|
2229
|
-
branchName,
|
|
2230
|
-
title,
|
|
2231
2197
|
description,
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
token: providedToken
|
|
2198
|
+
defaultBranch = "master",
|
|
2199
|
+
repoVisibility = "private",
|
|
2200
|
+
enableLFS = false
|
|
2236
2201
|
} = ctx.input;
|
|
2237
|
-
const {
|
|
2238
|
-
if (!
|
|
2239
|
-
throw new errors.InputError(`
|
|
2202
|
+
const { project, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
2203
|
+
if (!project) {
|
|
2204
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing project`);
|
|
2240
2205
|
}
|
|
2241
|
-
const
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2206
|
+
const integrationConfig = integrations.bitbucketServer.byHost(host);
|
|
2207
|
+
if (!integrationConfig) {
|
|
2208
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
2209
|
+
}
|
|
2210
|
+
const token = (_a = ctx.input.token) != null ? _a : integrationConfig.config.token;
|
|
2211
|
+
if (!token) {
|
|
2212
|
+
throw new Error(`Authorization has not been provided for ${integrationConfig.config.host}. Please add either token to the Integrations config or a user login auth token`);
|
|
2213
|
+
}
|
|
2214
|
+
const authorization = getAuthorizationHeader({ token });
|
|
2215
|
+
const apiBaseUrl = integrationConfig.config.apiBaseUrl;
|
|
2216
|
+
const { remoteUrl, repoContentsUrl } = await createRepository({
|
|
2217
|
+
authorization,
|
|
2218
|
+
project,
|
|
2246
2219
|
repo,
|
|
2247
|
-
|
|
2220
|
+
repoVisibility,
|
|
2221
|
+
description,
|
|
2222
|
+
apiBaseUrl
|
|
2248
2223
|
});
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2251
|
-
|
|
2224
|
+
const gitAuthorInfo = {
|
|
2225
|
+
name: config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
2226
|
+
email: config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
2227
|
+
};
|
|
2228
|
+
const auth = {
|
|
2229
|
+
username: "x-token-auth",
|
|
2230
|
+
password: token
|
|
2231
|
+
};
|
|
2232
|
+
await initRepoAndPush({
|
|
2233
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
2234
|
+
remoteUrl,
|
|
2235
|
+
auth,
|
|
2236
|
+
defaultBranch,
|
|
2237
|
+
logger: ctx.logger,
|
|
2238
|
+
commitMessage: config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
2239
|
+
gitAuthorInfo
|
|
2252
2240
|
});
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
});
|
|
2276
|
-
if (!response) {
|
|
2277
|
-
throw new GithubResponseError("null response from Github");
|
|
2241
|
+
if (enableLFS) {
|
|
2242
|
+
await performEnableLFS({ authorization, host, project, repo });
|
|
2243
|
+
}
|
|
2244
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
2245
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
function createPublishFileAction() {
|
|
2251
|
+
return createTemplateAction({
|
|
2252
|
+
id: "publish:file",
|
|
2253
|
+
description: "Writes contents of the workspace to a local directory",
|
|
2254
|
+
schema: {
|
|
2255
|
+
input: {
|
|
2256
|
+
type: "object",
|
|
2257
|
+
required: ["path"],
|
|
2258
|
+
properties: {
|
|
2259
|
+
path: {
|
|
2260
|
+
title: "Path to a directory where the output will be written",
|
|
2261
|
+
type: "string"
|
|
2262
|
+
}
|
|
2278
2263
|
}
|
|
2279
|
-
ctx.output("remoteUrl", response.data.html_url);
|
|
2280
|
-
ctx.output("pullRequestNumber", response.data.number);
|
|
2281
|
-
} catch (e) {
|
|
2282
|
-
throw new GithubResponseError("Pull request creation failed", e);
|
|
2283
2264
|
}
|
|
2265
|
+
},
|
|
2266
|
+
async handler(ctx) {
|
|
2267
|
+
const { path: path$1 } = ctx.input;
|
|
2268
|
+
const exists = await fs__default["default"].pathExists(path$1);
|
|
2269
|
+
if (exists) {
|
|
2270
|
+
throw new errors.InputError("Output path already exists");
|
|
2271
|
+
}
|
|
2272
|
+
await fs__default["default"].ensureDir(path.dirname(path$1));
|
|
2273
|
+
await fs__default["default"].copy(ctx.workspacePath, path$1);
|
|
2284
2274
|
}
|
|
2285
2275
|
});
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
const createGerritProject = async (config, options) => {
|
|
2279
|
+
const { projectName, parent, owner, description } = options;
|
|
2280
|
+
const fetchOptions = {
|
|
2281
|
+
method: "PUT",
|
|
2282
|
+
body: JSON.stringify({
|
|
2283
|
+
parent,
|
|
2284
|
+
description,
|
|
2285
|
+
owners: [owner],
|
|
2286
|
+
create_empty_commit: false
|
|
2287
|
+
}),
|
|
2288
|
+
headers: {
|
|
2289
|
+
...integration.getGerritRequestOptions(config).headers,
|
|
2290
|
+
"Content-Type": "application/json"
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
const response = await fetch__default["default"](`${config.baseUrl}/a/projects/${encodeURIComponent(projectName)}`, fetchOptions);
|
|
2294
|
+
if (response.status !== 201) {
|
|
2295
|
+
throw new Error(`Unable to create repository, ${response.status} ${response.statusText}, ${await response.text()}`);
|
|
2296
|
+
}
|
|
2286
2297
|
};
|
|
2298
|
+
const generateCommitMessage = (config, commitSubject) => {
|
|
2299
|
+
const changeId = crypto__default["default"].randomBytes(20).toString("hex");
|
|
2300
|
+
const msg = `${config.getOptionalString("scaffolder.defaultCommitMessage") || commitSubject}
|
|
2287
2301
|
|
|
2288
|
-
|
|
2302
|
+
Change-Id: I${changeId}`;
|
|
2303
|
+
return msg;
|
|
2304
|
+
};
|
|
2305
|
+
function createPublishGerritAction(options) {
|
|
2289
2306
|
const { integrations, config } = options;
|
|
2290
2307
|
return createTemplateAction({
|
|
2291
|
-
id: "publish:
|
|
2292
|
-
description: "Initializes a git repository of the content in the workspace, and publishes it to
|
|
2308
|
+
id: "publish:gerrit",
|
|
2309
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to Gerrit.",
|
|
2293
2310
|
schema: {
|
|
2294
2311
|
input: {
|
|
2295
2312
|
type: "object",
|
|
@@ -2299,10 +2316,9 @@ function createPublishGitlabAction(options) {
|
|
|
2299
2316
|
title: "Repository Location",
|
|
2300
2317
|
type: "string"
|
|
2301
2318
|
},
|
|
2302
|
-
|
|
2303
|
-
title: "Repository
|
|
2304
|
-
type: "string"
|
|
2305
|
-
enum: ["private", "public", "internal"]
|
|
2319
|
+
description: {
|
|
2320
|
+
title: "Repository Description",
|
|
2321
|
+
type: "string"
|
|
2306
2322
|
},
|
|
2307
2323
|
defaultBranch: {
|
|
2308
2324
|
title: "Default Branch",
|
|
@@ -2323,16 +2339,6 @@ function createPublishGitlabAction(options) {
|
|
|
2323
2339
|
title: "Default Author Email",
|
|
2324
2340
|
type: "string",
|
|
2325
2341
|
description: `Sets the default author email for the commit.`
|
|
2326
|
-
},
|
|
2327
|
-
sourcePath: {
|
|
2328
|
-
title: "Source Path",
|
|
2329
|
-
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
2330
|
-
type: "string"
|
|
2331
|
-
},
|
|
2332
|
-
token: {
|
|
2333
|
-
title: "Authentication Token",
|
|
2334
|
-
type: "string",
|
|
2335
|
-
description: "The token to use for authorization to GitLab"
|
|
2336
2342
|
}
|
|
2337
2343
|
}
|
|
2338
2344
|
},
|
|
@@ -2353,223 +2359,257 @@ function createPublishGitlabAction(options) {
|
|
|
2353
2359
|
async handler(ctx) {
|
|
2354
2360
|
const {
|
|
2355
2361
|
repoUrl,
|
|
2356
|
-
|
|
2362
|
+
description,
|
|
2357
2363
|
defaultBranch = "master",
|
|
2358
|
-
gitCommitMessage = "initial commit",
|
|
2359
2364
|
gitAuthorName,
|
|
2360
|
-
gitAuthorEmail
|
|
2365
|
+
gitAuthorEmail,
|
|
2366
|
+
gitCommitMessage = "initial commit"
|
|
2361
2367
|
} = ctx.input;
|
|
2362
|
-
const {
|
|
2363
|
-
|
|
2364
|
-
throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
|
|
2365
|
-
}
|
|
2366
|
-
const integrationConfig = integrations.gitlab.byHost(host);
|
|
2368
|
+
const { repo, host, owner, workspace } = parseRepoUrl(repoUrl, integrations);
|
|
2369
|
+
const integrationConfig = integrations.gerrit.byHost(host);
|
|
2367
2370
|
if (!integrationConfig) {
|
|
2368
2371
|
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
2369
2372
|
}
|
|
2370
|
-
if (!
|
|
2371
|
-
throw new errors.InputError(`
|
|
2373
|
+
if (!owner) {
|
|
2374
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing owner`);
|
|
2372
2375
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
const client = new node.Gitlab({
|
|
2376
|
-
host: integrationConfig.config.baseUrl,
|
|
2377
|
-
[tokenType]: token
|
|
2378
|
-
});
|
|
2379
|
-
let { id: targetNamespace } = await client.Namespaces.show(owner);
|
|
2380
|
-
if (!targetNamespace) {
|
|
2381
|
-
const { id } = await client.Users.current();
|
|
2382
|
-
targetNamespace = id;
|
|
2376
|
+
if (!workspace) {
|
|
2377
|
+
throw new errors.InputError(`Invalid URL provider was included in the repo URL to create ${ctx.input.repoUrl}, missing workspace`);
|
|
2383
2378
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2379
|
+
await createGerritProject(integrationConfig.config, {
|
|
2380
|
+
description,
|
|
2381
|
+
owner,
|
|
2382
|
+
projectName: repo,
|
|
2383
|
+
parent: workspace
|
|
2388
2384
|
});
|
|
2389
|
-
const
|
|
2390
|
-
|
|
2385
|
+
const auth = {
|
|
2386
|
+
username: integrationConfig.config.username,
|
|
2387
|
+
password: integrationConfig.config.password
|
|
2388
|
+
};
|
|
2391
2389
|
const gitAuthorInfo = {
|
|
2392
2390
|
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
2393
2391
|
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
2394
2392
|
};
|
|
2393
|
+
const remoteUrl = `${integrationConfig.config.cloneUrl}/a/${repo}`;
|
|
2395
2394
|
await initRepoAndPush({
|
|
2396
|
-
dir: getRepoSourceDirectory(ctx.workspacePath,
|
|
2397
|
-
remoteUrl
|
|
2395
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, void 0),
|
|
2396
|
+
remoteUrl,
|
|
2397
|
+
auth,
|
|
2398
2398
|
defaultBranch,
|
|
2399
|
-
auth: {
|
|
2400
|
-
username: "oauth2",
|
|
2401
|
-
password: token
|
|
2402
|
-
},
|
|
2403
2399
|
logger: ctx.logger,
|
|
2404
|
-
commitMessage:
|
|
2400
|
+
commitMessage: generateCommitMessage(config, gitCommitMessage),
|
|
2405
2401
|
gitAuthorInfo
|
|
2406
2402
|
});
|
|
2403
|
+
const repoContentsUrl = `${integrationConfig.config.gitilesBaseUrl}/${repo}/+/refs/heads/${defaultBranch}`;
|
|
2407
2404
|
ctx.output("remoteUrl", remoteUrl);
|
|
2408
2405
|
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
2409
2406
|
}
|
|
2410
2407
|
});
|
|
2411
2408
|
}
|
|
2412
2409
|
|
|
2413
|
-
|
|
2414
|
-
const { integrations } = options;
|
|
2410
|
+
function createPublishGithubAction(options) {
|
|
2411
|
+
const { integrations, config, githubCredentialsProvider } = options;
|
|
2415
2412
|
return createTemplateAction({
|
|
2416
|
-
id: "publish:
|
|
2413
|
+
id: "publish:github",
|
|
2414
|
+
description: "Initializes a git repository of contents in workspace and publishes it to GitHub.",
|
|
2417
2415
|
schema: {
|
|
2418
2416
|
input: {
|
|
2419
|
-
required: ["repoUrl", "targetPath", "branchName"],
|
|
2420
2417
|
type: "object",
|
|
2418
|
+
required: ["repoUrl"],
|
|
2421
2419
|
properties: {
|
|
2422
|
-
repoUrl:
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
},
|
|
2442
|
-
branchName: {
|
|
2443
|
-
type: "string",
|
|
2444
|
-
title: "Destination Branch name",
|
|
2445
|
-
description: "The description of the merge request"
|
|
2446
|
-
},
|
|
2447
|
-
targetPath: {
|
|
2448
|
-
type: "string",
|
|
2449
|
-
title: "Repository Subdirectory",
|
|
2450
|
-
description: "Subdirectory of repository to apply changes to"
|
|
2451
|
-
},
|
|
2452
|
-
token: {
|
|
2453
|
-
title: "Authentication Token",
|
|
2454
|
-
type: "string",
|
|
2455
|
-
description: "The token to use for authorization to GitLab"
|
|
2456
|
-
}
|
|
2420
|
+
repoUrl: repoUrl,
|
|
2421
|
+
description: description,
|
|
2422
|
+
access: access,
|
|
2423
|
+
requireCodeOwnerReviews: requireCodeOwnerReviews,
|
|
2424
|
+
requiredStatusCheckContexts: requiredStatusCheckContexts,
|
|
2425
|
+
repoVisibility: repoVisibility,
|
|
2426
|
+
defaultBranch: defaultBranch,
|
|
2427
|
+
protectDefaultBranch: protectDefaultBranch,
|
|
2428
|
+
deleteBranchOnMerge: deleteBranchOnMerge,
|
|
2429
|
+
gitCommitMessage: gitCommitMessage,
|
|
2430
|
+
gitAuthorName: gitAuthorName,
|
|
2431
|
+
gitAuthorEmail: gitAuthorEmail,
|
|
2432
|
+
allowMergeCommit: allowMergeCommit,
|
|
2433
|
+
allowSquashMerge: allowSquashMerge,
|
|
2434
|
+
allowRebaseMerge: allowRebaseMerge,
|
|
2435
|
+
sourcePath: sourcePath,
|
|
2436
|
+
collaborators: collaborators,
|
|
2437
|
+
token: token,
|
|
2438
|
+
topics: topics
|
|
2457
2439
|
}
|
|
2458
2440
|
},
|
|
2459
2441
|
output: {
|
|
2460
2442
|
type: "object",
|
|
2461
2443
|
properties: {
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
type: "string"
|
|
2465
|
-
},
|
|
2466
|
-
projectPath: {
|
|
2467
|
-
title: "Gitlab Project path",
|
|
2468
|
-
type: "string"
|
|
2469
|
-
},
|
|
2470
|
-
mergeRequestURL: {
|
|
2471
|
-
title: "MergeRequest(MR) URL",
|
|
2472
|
-
type: "string",
|
|
2473
|
-
description: "Link to the merge request in GitLab"
|
|
2474
|
-
}
|
|
2444
|
+
remoteUrl: remoteUrl,
|
|
2445
|
+
repoContentsUrl: repoContentsUrl
|
|
2475
2446
|
}
|
|
2476
2447
|
}
|
|
2477
2448
|
},
|
|
2478
2449
|
async handler(ctx) {
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
gitignore: true
|
|
2450
|
+
const {
|
|
2451
|
+
repoUrl,
|
|
2452
|
+
description,
|
|
2453
|
+
access,
|
|
2454
|
+
requireCodeOwnerReviews = false,
|
|
2455
|
+
requiredStatusCheckContexts = [],
|
|
2456
|
+
repoVisibility = "private",
|
|
2457
|
+
defaultBranch = "master",
|
|
2458
|
+
protectDefaultBranch = true,
|
|
2459
|
+
deleteBranchOnMerge = false,
|
|
2460
|
+
gitCommitMessage = "initial commit",
|
|
2461
|
+
gitAuthorName,
|
|
2462
|
+
gitAuthorEmail,
|
|
2463
|
+
allowMergeCommit = true,
|
|
2464
|
+
allowSquashMerge = true,
|
|
2465
|
+
allowRebaseMerge = true,
|
|
2466
|
+
collaborators,
|
|
2467
|
+
topics,
|
|
2468
|
+
token: providedToken
|
|
2469
|
+
} = ctx.input;
|
|
2470
|
+
const octokitOptions = await getOctokitOptions({
|
|
2471
|
+
integrations,
|
|
2472
|
+
credentialsProvider: githubCredentialsProvider,
|
|
2473
|
+
token: providedToken,
|
|
2474
|
+
repoUrl
|
|
2505
2475
|
});
|
|
2506
|
-
const
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
content: file.content.toString("base64"),
|
|
2511
|
-
execute_filemode: file.executable
|
|
2512
|
-
}));
|
|
2513
|
-
const projects = await api.Projects.show(projectPath);
|
|
2514
|
-
const { default_branch: defaultBranch } = projects;
|
|
2515
|
-
try {
|
|
2516
|
-
await api.Branches.create(projectPath, destinationBranch, String(defaultBranch));
|
|
2517
|
-
} catch (e) {
|
|
2518
|
-
throw new errors.InputError(`The branch creation failed ${e}`);
|
|
2519
|
-
}
|
|
2520
|
-
try {
|
|
2521
|
-
await api.Commits.create(projectPath, destinationBranch, ctx.input.title, actions);
|
|
2522
|
-
} catch (e) {
|
|
2523
|
-
throw new errors.InputError(`Committing the changes to ${destinationBranch} failed ${e}`);
|
|
2524
|
-
}
|
|
2525
|
-
try {
|
|
2526
|
-
const mergeRequestUrl = await api.MergeRequests.create(projectPath, destinationBranch, String(defaultBranch), ctx.input.title, { description: ctx.input.description }).then((mergeRequest) => {
|
|
2527
|
-
return mergeRequest.web_url;
|
|
2528
|
-
});
|
|
2529
|
-
ctx.output("projectid", projectPath);
|
|
2530
|
-
ctx.output("projectPath", projectPath);
|
|
2531
|
-
ctx.output("mergeRequestUrl", mergeRequestUrl);
|
|
2532
|
-
} catch (e) {
|
|
2533
|
-
throw new errors.InputError(`Merge request creation failed${e}`);
|
|
2476
|
+
const client = new octokit.Octokit(octokitOptions);
|
|
2477
|
+
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
2478
|
+
if (!owner) {
|
|
2479
|
+
throw new errors.InputError("Invalid repository owner provided in repoUrl");
|
|
2534
2480
|
}
|
|
2481
|
+
const newRepo = await createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, allowRebaseMerge, access, collaborators, topics, ctx.logger);
|
|
2482
|
+
const remoteUrl = newRepo.clone_url;
|
|
2483
|
+
const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`;
|
|
2484
|
+
await initRepoPushAndProtect(remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, owner, client, repo, requireCodeOwnerReviews, requiredStatusCheckContexts, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail);
|
|
2485
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
2486
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
2535
2487
|
}
|
|
2536
2488
|
});
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
const DEFAULT_GLOB_PATTERNS = ["./**", "!.git"];
|
|
2492
|
+
const isExecutable = (fileMode) => {
|
|
2493
|
+
if (!fileMode) {
|
|
2494
|
+
return false;
|
|
2495
|
+
}
|
|
2496
|
+
const executeBitMask = 73;
|
|
2497
|
+
const res = fileMode & executeBitMask;
|
|
2498
|
+
return res > 0;
|
|
2537
2499
|
};
|
|
2500
|
+
async function serializeDirectoryContents(sourcePath, options) {
|
|
2501
|
+
var _a;
|
|
2502
|
+
const paths = await globby__default["default"]((_a = options == null ? void 0 : options.globPatterns) != null ? _a : DEFAULT_GLOB_PATTERNS, {
|
|
2503
|
+
cwd: sourcePath,
|
|
2504
|
+
dot: true,
|
|
2505
|
+
gitignore: options == null ? void 0 : options.gitignore,
|
|
2506
|
+
followSymbolicLinks: false,
|
|
2507
|
+
objectMode: true,
|
|
2508
|
+
stats: true
|
|
2509
|
+
});
|
|
2510
|
+
const limiter = limiterFactory__default["default"](10);
|
|
2511
|
+
return Promise.all(paths.map(async ({ path: path$1, stats }) => ({
|
|
2512
|
+
path: path$1,
|
|
2513
|
+
content: await limiter(async () => fs__default["default"].readFile(path.join(sourcePath, path$1))),
|
|
2514
|
+
executable: isExecutable(stats == null ? void 0 : stats.mode)
|
|
2515
|
+
})));
|
|
2516
|
+
}
|
|
2538
2517
|
|
|
2539
|
-
function
|
|
2540
|
-
const
|
|
2518
|
+
async function deserializeDirectoryContents(targetPath, files) {
|
|
2519
|
+
for (const file of files) {
|
|
2520
|
+
const filePath = backendCommon.resolveSafeChildPath(targetPath, file.path);
|
|
2521
|
+
await fs__default["default"].ensureDir(path.dirname(filePath));
|
|
2522
|
+
await fs__default["default"].writeFile(filePath, file.content);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
class GithubResponseError extends errors.CustomErrorBase {
|
|
2527
|
+
}
|
|
2528
|
+
const defaultClientFactory = async ({
|
|
2529
|
+
integrations,
|
|
2530
|
+
githubCredentialsProvider,
|
|
2531
|
+
owner,
|
|
2532
|
+
repo,
|
|
2533
|
+
host = "github.com",
|
|
2534
|
+
token: providedToken
|
|
2535
|
+
}) => {
|
|
2536
|
+
const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map(encodeURIComponent);
|
|
2537
|
+
const octokitOptions = await getOctokitOptions({
|
|
2538
|
+
integrations,
|
|
2539
|
+
credentialsProvider: githubCredentialsProvider,
|
|
2540
|
+
repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`,
|
|
2541
|
+
token: providedToken
|
|
2542
|
+
});
|
|
2543
|
+
const OctokitPR = octokit.Octokit.plugin(octokitPluginCreatePullRequest.createPullRequest);
|
|
2544
|
+
return new OctokitPR(octokitOptions);
|
|
2545
|
+
};
|
|
2546
|
+
const createPublishGithubPullRequestAction = ({
|
|
2547
|
+
integrations,
|
|
2548
|
+
githubCredentialsProvider,
|
|
2549
|
+
clientFactory = defaultClientFactory
|
|
2550
|
+
}) => {
|
|
2541
2551
|
return createTemplateAction({
|
|
2542
|
-
id: "github:
|
|
2543
|
-
description: "Dispatches a GitHub Action workflow for a given branch or tag",
|
|
2552
|
+
id: "publish:github:pull-request",
|
|
2544
2553
|
schema: {
|
|
2545
2554
|
input: {
|
|
2555
|
+
required: ["repoUrl", "title", "description", "branchName"],
|
|
2546
2556
|
type: "object",
|
|
2547
|
-
required: ["repoUrl", "workflowId", "branchOrTagName"],
|
|
2548
2557
|
properties: {
|
|
2549
2558
|
repoUrl: {
|
|
2550
2559
|
title: "Repository Location",
|
|
2551
|
-
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the
|
|
2560
|
+
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the repository name and 'owner' is an organization or username`,
|
|
2552
2561
|
type: "string"
|
|
2553
2562
|
},
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2563
|
+
branchName: {
|
|
2564
|
+
type: "string",
|
|
2565
|
+
title: "Branch Name",
|
|
2566
|
+
description: "The name for the branch"
|
|
2558
2567
|
},
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2568
|
+
title: {
|
|
2569
|
+
type: "string",
|
|
2570
|
+
title: "Pull Request Name",
|
|
2571
|
+
description: "The name for the pull request"
|
|
2563
2572
|
},
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2573
|
+
description: {
|
|
2574
|
+
type: "string",
|
|
2575
|
+
title: "Pull Request Description",
|
|
2576
|
+
description: "The description of the pull request"
|
|
2577
|
+
},
|
|
2578
|
+
draft: {
|
|
2579
|
+
type: "boolean",
|
|
2580
|
+
title: "Create as Draft",
|
|
2581
|
+
description: "Create a draft pull request"
|
|
2582
|
+
},
|
|
2583
|
+
sourcePath: {
|
|
2584
|
+
type: "string",
|
|
2585
|
+
title: "Working Subdirectory",
|
|
2586
|
+
description: "Subdirectory of working directory to copy changes from"
|
|
2587
|
+
},
|
|
2588
|
+
targetPath: {
|
|
2589
|
+
type: "string",
|
|
2590
|
+
title: "Repository Subdirectory",
|
|
2591
|
+
description: "Subdirectory of repository to apply changes to"
|
|
2568
2592
|
},
|
|
2569
2593
|
token: {
|
|
2570
2594
|
title: "Authentication Token",
|
|
2571
2595
|
type: "string",
|
|
2572
|
-
description: "The
|
|
2596
|
+
description: "The token to use for authorization to GitHub"
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
},
|
|
2600
|
+
output: {
|
|
2601
|
+
required: ["remoteUrl"],
|
|
2602
|
+
type: "object",
|
|
2603
|
+
properties: {
|
|
2604
|
+
remoteUrl: {
|
|
2605
|
+
type: "string",
|
|
2606
|
+
title: "Pull Request URL",
|
|
2607
|
+
description: "Link to the pull request in Github"
|
|
2608
|
+
},
|
|
2609
|
+
pullRequestNumber: {
|
|
2610
|
+
type: "number",
|
|
2611
|
+
title: "Pull Request Number",
|
|
2612
|
+
description: "The pull request number"
|
|
2573
2613
|
}
|
|
2574
2614
|
}
|
|
2575
2615
|
}
|
|
@@ -2577,99 +2617,131 @@ function createGithubActionsDispatchAction(options) {
|
|
|
2577
2617
|
async handler(ctx) {
|
|
2578
2618
|
const {
|
|
2579
2619
|
repoUrl,
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2620
|
+
branchName,
|
|
2621
|
+
title,
|
|
2622
|
+
description,
|
|
2623
|
+
draft,
|
|
2624
|
+
targetPath,
|
|
2625
|
+
sourcePath,
|
|
2583
2626
|
token: providedToken
|
|
2584
2627
|
} = ctx.input;
|
|
2585
|
-
|
|
2586
|
-
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
2628
|
+
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
2587
2629
|
if (!owner) {
|
|
2588
|
-
throw new errors.InputError(
|
|
2630
|
+
throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
|
|
2589
2631
|
}
|
|
2590
|
-
const client =
|
|
2632
|
+
const client = await clientFactory({
|
|
2591
2633
|
integrations,
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
token: providedToken
|
|
2595
|
-
}));
|
|
2596
|
-
await client.rest.actions.createWorkflowDispatch({
|
|
2634
|
+
githubCredentialsProvider,
|
|
2635
|
+
host,
|
|
2597
2636
|
owner,
|
|
2598
2637
|
repo,
|
|
2599
|
-
|
|
2600
|
-
ref: branchOrTagName,
|
|
2601
|
-
inputs: workflowInputs
|
|
2638
|
+
token: providedToken
|
|
2602
2639
|
});
|
|
2603
|
-
ctx.
|
|
2640
|
+
const fileRoot = sourcePath ? backendCommon.resolveSafeChildPath(ctx.workspacePath, sourcePath) : ctx.workspacePath;
|
|
2641
|
+
const directoryContents = await serializeDirectoryContents(fileRoot, {
|
|
2642
|
+
gitignore: true
|
|
2643
|
+
});
|
|
2644
|
+
const files = Object.fromEntries(directoryContents.map((file) => [
|
|
2645
|
+
targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path,
|
|
2646
|
+
{
|
|
2647
|
+
mode: file.executable ? "100755" : "100644",
|
|
2648
|
+
encoding: "base64",
|
|
2649
|
+
content: file.content.toString("base64")
|
|
2650
|
+
}
|
|
2651
|
+
]));
|
|
2652
|
+
try {
|
|
2653
|
+
const response = await client.createPullRequest({
|
|
2654
|
+
owner,
|
|
2655
|
+
repo,
|
|
2656
|
+
title,
|
|
2657
|
+
changes: [
|
|
2658
|
+
{
|
|
2659
|
+
files,
|
|
2660
|
+
commit: title
|
|
2661
|
+
}
|
|
2662
|
+
],
|
|
2663
|
+
body: description,
|
|
2664
|
+
head: branchName,
|
|
2665
|
+
draft
|
|
2666
|
+
});
|
|
2667
|
+
if (!response) {
|
|
2668
|
+
throw new GithubResponseError("null response from Github");
|
|
2669
|
+
}
|
|
2670
|
+
ctx.output("remoteUrl", response.data.html_url);
|
|
2671
|
+
ctx.output("pullRequestNumber", response.data.number);
|
|
2672
|
+
} catch (e) {
|
|
2673
|
+
throw new GithubResponseError("Pull request creation failed", e);
|
|
2674
|
+
}
|
|
2604
2675
|
}
|
|
2605
2676
|
});
|
|
2606
|
-
}
|
|
2677
|
+
};
|
|
2607
2678
|
|
|
2608
|
-
function
|
|
2609
|
-
const { integrations,
|
|
2610
|
-
const eventNames = webhooks.emitterEventNames.filter((event) => !event.includes("."));
|
|
2679
|
+
function createPublishGitlabAction(options) {
|
|
2680
|
+
const { integrations, config } = options;
|
|
2611
2681
|
return createTemplateAction({
|
|
2612
|
-
id: "
|
|
2613
|
-
description: "
|
|
2682
|
+
id: "publish:gitlab",
|
|
2683
|
+
description: "Initializes a git repository of the content in the workspace, and publishes it to GitLab.",
|
|
2614
2684
|
schema: {
|
|
2615
2685
|
input: {
|
|
2616
2686
|
type: "object",
|
|
2617
|
-
required: ["repoUrl"
|
|
2687
|
+
required: ["repoUrl"],
|
|
2618
2688
|
properties: {
|
|
2619
2689
|
repoUrl: {
|
|
2620
2690
|
title: "Repository Location",
|
|
2621
|
-
description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`,
|
|
2622
2691
|
type: "string"
|
|
2623
2692
|
},
|
|
2624
|
-
|
|
2625
|
-
title: "
|
|
2626
|
-
|
|
2627
|
-
|
|
2693
|
+
repoVisibility: {
|
|
2694
|
+
title: "Repository Visibility",
|
|
2695
|
+
type: "string",
|
|
2696
|
+
enum: ["private", "public", "internal"]
|
|
2628
2697
|
},
|
|
2629
|
-
|
|
2630
|
-
title: "
|
|
2631
|
-
|
|
2632
|
-
|
|
2698
|
+
defaultBranch: {
|
|
2699
|
+
title: "Default Branch",
|
|
2700
|
+
type: "string",
|
|
2701
|
+
description: `Sets the default branch on the repository. The default value is 'master'`
|
|
2633
2702
|
},
|
|
2634
|
-
|
|
2635
|
-
title: "
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
oneOf: [
|
|
2639
|
-
{
|
|
2640
|
-
items: {
|
|
2641
|
-
type: "string",
|
|
2642
|
-
enum: eventNames
|
|
2643
|
-
}
|
|
2644
|
-
},
|
|
2645
|
-
{
|
|
2646
|
-
items: {
|
|
2647
|
-
type: "string",
|
|
2648
|
-
const: "*"
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
]
|
|
2703
|
+
gitCommitMessage: {
|
|
2704
|
+
title: "Git Commit Message",
|
|
2705
|
+
type: "string",
|
|
2706
|
+
description: `Sets the commit message on the repository. The default value is 'initial commit'`
|
|
2652
2707
|
},
|
|
2653
|
-
|
|
2654
|
-
title: "
|
|
2655
|
-
type: "
|
|
2656
|
-
description: `
|
|
2708
|
+
gitAuthorName: {
|
|
2709
|
+
title: "Default Author Name",
|
|
2710
|
+
type: "string",
|
|
2711
|
+
description: `Sets the default author name for the commit. The default value is 'Scaffolder'`
|
|
2657
2712
|
},
|
|
2658
|
-
|
|
2659
|
-
title: "
|
|
2713
|
+
gitAuthorEmail: {
|
|
2714
|
+
title: "Default Author Email",
|
|
2660
2715
|
type: "string",
|
|
2661
|
-
|
|
2662
|
-
description: `The media type used to serialize the payloads. The default is 'form'`
|
|
2716
|
+
description: `Sets the default author email for the commit.`
|
|
2663
2717
|
},
|
|
2664
|
-
|
|
2665
|
-
title: "
|
|
2666
|
-
|
|
2667
|
-
|
|
2718
|
+
sourcePath: {
|
|
2719
|
+
title: "Source Path",
|
|
2720
|
+
description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.",
|
|
2721
|
+
type: "string"
|
|
2668
2722
|
},
|
|
2669
2723
|
token: {
|
|
2670
2724
|
title: "Authentication Token",
|
|
2671
2725
|
type: "string",
|
|
2672
|
-
description: "The
|
|
2726
|
+
description: "The token to use for authorization to GitLab"
|
|
2727
|
+
},
|
|
2728
|
+
setUserAsOwner: {
|
|
2729
|
+
title: "Set User As Owner",
|
|
2730
|
+
type: "boolean",
|
|
2731
|
+
description: "Set the token user as owner of the newly created repository. Requires a token authorized to do the edit in the integration configuration for the matching host"
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
},
|
|
2735
|
+
output: {
|
|
2736
|
+
type: "object",
|
|
2737
|
+
properties: {
|
|
2738
|
+
remoteUrl: {
|
|
2739
|
+
title: "A URL to the repository with the provider",
|
|
2740
|
+
type: "string"
|
|
2741
|
+
},
|
|
2742
|
+
repoContentsUrl: {
|
|
2743
|
+
title: "A URL to the root of the repository",
|
|
2744
|
+
type: "string"
|
|
2673
2745
|
}
|
|
2674
2746
|
}
|
|
2675
2747
|
}
|
|
@@ -2677,111 +2749,204 @@ function createGithubWebhookAction(options) {
|
|
|
2677
2749
|
async handler(ctx) {
|
|
2678
2750
|
const {
|
|
2679
2751
|
repoUrl,
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
token: providedToken
|
|
2752
|
+
repoVisibility = "private",
|
|
2753
|
+
defaultBranch = "master",
|
|
2754
|
+
gitCommitMessage = "initial commit",
|
|
2755
|
+
gitAuthorName,
|
|
2756
|
+
gitAuthorEmail,
|
|
2757
|
+
setUserAsOwner = false
|
|
2687
2758
|
} = ctx.input;
|
|
2688
|
-
|
|
2689
|
-
const { owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
2759
|
+
const { owner, repo, host } = parseRepoUrl(repoUrl, integrations);
|
|
2690
2760
|
if (!owner) {
|
|
2691
|
-
throw new errors.InputError(
|
|
2761
|
+
throw new errors.InputError(`No owner provided for host: ${host}, and repo ${repo}`);
|
|
2692
2762
|
}
|
|
2693
|
-
const
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2763
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
2764
|
+
if (!integrationConfig) {
|
|
2765
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
2766
|
+
}
|
|
2767
|
+
if (!integrationConfig.config.token && !ctx.input.token) {
|
|
2768
|
+
throw new errors.InputError(`No token available for host ${host}`);
|
|
2769
|
+
}
|
|
2770
|
+
const token = ctx.input.token || integrationConfig.config.token;
|
|
2771
|
+
const tokenType = ctx.input.token ? "oauthToken" : "token";
|
|
2772
|
+
const client = new node.Gitlab({
|
|
2773
|
+
host: integrationConfig.config.baseUrl,
|
|
2774
|
+
[tokenType]: token
|
|
2775
|
+
});
|
|
2776
|
+
let { id: targetNamespace } = await client.Namespaces.show(owner);
|
|
2777
|
+
const { id: userId } = await client.Users.current();
|
|
2778
|
+
if (!targetNamespace) {
|
|
2779
|
+
targetNamespace = userId;
|
|
2780
|
+
}
|
|
2781
|
+
const { id: projectId, http_url_to_repo } = await client.Projects.create({
|
|
2782
|
+
namespace_id: targetNamespace,
|
|
2783
|
+
name: repo,
|
|
2784
|
+
visibility: repoVisibility
|
|
2785
|
+
});
|
|
2786
|
+
if (setUserAsOwner && integrationConfig.config.token) {
|
|
2787
|
+
const adminClient = new node.Gitlab({
|
|
2788
|
+
host: integrationConfig.config.baseUrl,
|
|
2789
|
+
token: integrationConfig.config.token
|
|
2712
2790
|
});
|
|
2713
|
-
|
|
2714
|
-
} catch (e) {
|
|
2715
|
-
errors.assertError(e);
|
|
2716
|
-
ctx.logger.warn(`Failed: create webhook '${webhookUrl}' on repo: '${repo}', ${e.message}`);
|
|
2791
|
+
await adminClient.ProjectMembers.add(projectId, userId, 50);
|
|
2717
2792
|
}
|
|
2793
|
+
const remoteUrl = http_url_to_repo.replace(/\.git$/, "");
|
|
2794
|
+
const repoContentsUrl = `${remoteUrl}/-/blob/${defaultBranch}`;
|
|
2795
|
+
const gitAuthorInfo = {
|
|
2796
|
+
name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"),
|
|
2797
|
+
email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email")
|
|
2798
|
+
};
|
|
2799
|
+
await initRepoAndPush({
|
|
2800
|
+
dir: getRepoSourceDirectory(ctx.workspacePath, ctx.input.sourcePath),
|
|
2801
|
+
remoteUrl: http_url_to_repo,
|
|
2802
|
+
defaultBranch,
|
|
2803
|
+
auth: {
|
|
2804
|
+
username: "oauth2",
|
|
2805
|
+
password: token
|
|
2806
|
+
},
|
|
2807
|
+
logger: ctx.logger,
|
|
2808
|
+
commitMessage: gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"),
|
|
2809
|
+
gitAuthorInfo
|
|
2810
|
+
});
|
|
2811
|
+
ctx.output("remoteUrl", remoteUrl);
|
|
2812
|
+
ctx.output("repoContentsUrl", repoContentsUrl);
|
|
2718
2813
|
}
|
|
2719
2814
|
});
|
|
2720
2815
|
}
|
|
2721
2816
|
|
|
2722
|
-
|
|
2723
|
-
const { integrations
|
|
2817
|
+
const createPublishGitlabMergeRequestAction = (options) => {
|
|
2818
|
+
const { integrations } = options;
|
|
2724
2819
|
return createTemplateAction({
|
|
2725
|
-
id: "
|
|
2726
|
-
description: "Adds labels to a pull request or issue on GitHub.",
|
|
2820
|
+
id: "publish:gitlab:merge-request",
|
|
2727
2821
|
schema: {
|
|
2728
2822
|
input: {
|
|
2823
|
+
required: ["repoUrl", "targetPath", "branchName"],
|
|
2729
2824
|
type: "object",
|
|
2730
|
-
required: ["repoUrl", "number", "labels"],
|
|
2731
2825
|
properties: {
|
|
2732
2826
|
repoUrl: {
|
|
2827
|
+
type: "string",
|
|
2733
2828
|
title: "Repository Location",
|
|
2734
|
-
description: `Accepts the format '
|
|
2735
|
-
type: "string"
|
|
2829
|
+
description: `Accepts the format 'gitlab.com/group_name/project_name' where 'project_name' is the repository name and 'group_name' is a group or username`
|
|
2736
2830
|
},
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2831
|
+
projectid: {
|
|
2832
|
+
type: "string",
|
|
2833
|
+
title: "projectid",
|
|
2834
|
+
description: "Project ID/Name(slug) of the Gitlab Project"
|
|
2741
2835
|
},
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2836
|
+
title: {
|
|
2837
|
+
type: "string",
|
|
2838
|
+
title: "Merge Request Name",
|
|
2839
|
+
description: "The name for the merge request"
|
|
2840
|
+
},
|
|
2841
|
+
description: {
|
|
2842
|
+
type: "string",
|
|
2843
|
+
title: "Merge Request Description",
|
|
2844
|
+
description: "The description of the merge request"
|
|
2845
|
+
},
|
|
2846
|
+
branchName: {
|
|
2847
|
+
type: "string",
|
|
2848
|
+
title: "Destination Branch name",
|
|
2849
|
+
description: "The description of the merge request"
|
|
2850
|
+
},
|
|
2851
|
+
targetPath: {
|
|
2852
|
+
type: "string",
|
|
2853
|
+
title: "Repository Subdirectory",
|
|
2854
|
+
description: "Subdirectory of repository to apply changes to"
|
|
2749
2855
|
},
|
|
2750
2856
|
token: {
|
|
2751
2857
|
title: "Authentication Token",
|
|
2752
2858
|
type: "string",
|
|
2753
|
-
description: "The
|
|
2859
|
+
description: "The token to use for authorization to GitLab"
|
|
2860
|
+
},
|
|
2861
|
+
removeSourceBranch: {
|
|
2862
|
+
title: "Delete source branch",
|
|
2863
|
+
type: "boolean",
|
|
2864
|
+
description: "Option to delete source branch once the MR has been merged. Default: false"
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
},
|
|
2868
|
+
output: {
|
|
2869
|
+
type: "object",
|
|
2870
|
+
properties: {
|
|
2871
|
+
projectid: {
|
|
2872
|
+
title: "Gitlab Project id/Name(slug)",
|
|
2873
|
+
type: "string"
|
|
2874
|
+
},
|
|
2875
|
+
projectPath: {
|
|
2876
|
+
title: "Gitlab Project path",
|
|
2877
|
+
type: "string"
|
|
2878
|
+
},
|
|
2879
|
+
mergeRequestURL: {
|
|
2880
|
+
title: "MergeRequest(MR) URL",
|
|
2881
|
+
type: "string",
|
|
2882
|
+
description: "Link to the merge request in GitLab"
|
|
2754
2883
|
}
|
|
2755
2884
|
}
|
|
2756
2885
|
}
|
|
2757
2886
|
},
|
|
2758
2887
|
async handler(ctx) {
|
|
2759
|
-
|
|
2760
|
-
const
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2888
|
+
var _a;
|
|
2889
|
+
const repoUrl = ctx.input.repoUrl;
|
|
2890
|
+
const { host, owner, repo } = parseRepoUrl(repoUrl, integrations);
|
|
2891
|
+
const projectPath = `${owner}/${repo}`;
|
|
2892
|
+
if (ctx.input.projectid) {
|
|
2893
|
+
const deprecationWarning = `Property "projectid" is deprecated and no longer to needed to create a MR`;
|
|
2894
|
+
ctx.logger.warn(deprecationWarning);
|
|
2895
|
+
console.warn(deprecationWarning);
|
|
2764
2896
|
}
|
|
2765
|
-
const
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2897
|
+
const integrationConfig = integrations.gitlab.byHost(host);
|
|
2898
|
+
const destinationBranch = ctx.input.branchName;
|
|
2899
|
+
if (!integrationConfig) {
|
|
2900
|
+
throw new errors.InputError(`No matching integration configuration for host ${host}, please check your integrations config`);
|
|
2901
|
+
}
|
|
2902
|
+
if (!integrationConfig.config.token && !ctx.input.token) {
|
|
2903
|
+
throw new errors.InputError(`No token available for host ${host}`);
|
|
2904
|
+
}
|
|
2905
|
+
const token = (_a = ctx.input.token) != null ? _a : integrationConfig.config.token;
|
|
2906
|
+
const tokenType = ctx.input.token ? "oauthToken" : "token";
|
|
2907
|
+
const api = new node.Gitlab({
|
|
2908
|
+
host: integrationConfig.config.baseUrl,
|
|
2909
|
+
[tokenType]: token
|
|
2910
|
+
});
|
|
2911
|
+
const targetPath = backendCommon.resolveSafeChildPath(ctx.workspacePath, ctx.input.targetPath);
|
|
2912
|
+
const fileContents = await serializeDirectoryContents(targetPath, {
|
|
2913
|
+
gitignore: true
|
|
2914
|
+
});
|
|
2915
|
+
const actions = fileContents.map((file) => ({
|
|
2916
|
+
action: "create",
|
|
2917
|
+
filePath: path__default["default"].posix.join(ctx.input.targetPath, file.path),
|
|
2918
|
+
encoding: "base64",
|
|
2919
|
+
content: file.content.toString("base64"),
|
|
2920
|
+
execute_filemode: file.executable
|
|
2770
2921
|
}));
|
|
2922
|
+
const projects = await api.Projects.show(projectPath);
|
|
2923
|
+
const { default_branch: defaultBranch } = projects;
|
|
2771
2924
|
try {
|
|
2772
|
-
await
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2925
|
+
await api.Branches.create(projectPath, destinationBranch, String(defaultBranch));
|
|
2926
|
+
} catch (e) {
|
|
2927
|
+
throw new errors.InputError(`The branch creation failed ${e}`);
|
|
2928
|
+
}
|
|
2929
|
+
try {
|
|
2930
|
+
await api.Commits.create(projectPath, destinationBranch, ctx.input.title, actions);
|
|
2931
|
+
} catch (e) {
|
|
2932
|
+
throw new errors.InputError(`Committing the changes to ${destinationBranch} failed ${e}`);
|
|
2933
|
+
}
|
|
2934
|
+
try {
|
|
2935
|
+
const mergeRequestUrl = await api.MergeRequests.create(projectPath, destinationBranch, String(defaultBranch), ctx.input.title, {
|
|
2936
|
+
description: ctx.input.description,
|
|
2937
|
+
removeSourceBranch: ctx.input.removeSourceBranch ? ctx.input.removeSourceBranch : false
|
|
2938
|
+
}).then((mergeRequest) => {
|
|
2939
|
+
return mergeRequest.web_url;
|
|
2777
2940
|
});
|
|
2941
|
+
ctx.output("projectid", projectPath);
|
|
2942
|
+
ctx.output("projectPath", projectPath);
|
|
2943
|
+
ctx.output("mergeRequestUrl", mergeRequestUrl);
|
|
2778
2944
|
} catch (e) {
|
|
2779
|
-
errors.
|
|
2780
|
-
ctx.logger.warn(`Failed: adding labels to issue: '${number}' on repo: '${repo}', ${e.message}`);
|
|
2945
|
+
throw new errors.InputError(`Merge request creation failed${e}`);
|
|
2781
2946
|
}
|
|
2782
2947
|
}
|
|
2783
2948
|
});
|
|
2784
|
-
}
|
|
2949
|
+
};
|
|
2785
2950
|
|
|
2786
2951
|
const createBuiltinActions = (options) => {
|
|
2787
2952
|
const {
|
|
@@ -2854,6 +3019,15 @@ const createBuiltinActions = (options) => {
|
|
|
2854
3019
|
createGithubIssuesLabelAction({
|
|
2855
3020
|
integrations,
|
|
2856
3021
|
githubCredentialsProvider
|
|
3022
|
+
}),
|
|
3023
|
+
createGithubRepoCreateAction({
|
|
3024
|
+
integrations,
|
|
3025
|
+
githubCredentialsProvider
|
|
3026
|
+
}),
|
|
3027
|
+
createGithubRepoPushAction({
|
|
3028
|
+
integrations,
|
|
3029
|
+
config,
|
|
3030
|
+
githubCredentialsProvider
|
|
2857
3031
|
})
|
|
2858
3032
|
];
|
|
2859
3033
|
return actions;
|
|
@@ -3898,15 +4072,27 @@ data: ${JSON.stringify(event)}
|
|
|
3898
4072
|
}
|
|
3899
4073
|
function parseBearerToken(header) {
|
|
3900
4074
|
var _a;
|
|
3901
|
-
|
|
3902
|
-
if (!token)
|
|
4075
|
+
if (!header) {
|
|
3903
4076
|
return {};
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
4077
|
+
}
|
|
4078
|
+
try {
|
|
4079
|
+
const token = (_a = header.match(/^Bearer\s(\S+\.\S+\.\S+)$/i)) == null ? void 0 : _a[1];
|
|
4080
|
+
if (!token) {
|
|
4081
|
+
throw new TypeError("Expected Bearer with JWT");
|
|
4082
|
+
}
|
|
4083
|
+
const [_header, rawPayload, _signature] = token.split(".");
|
|
4084
|
+
const payload = JSON.parse(Buffer.from(rawPayload, "base64").toString());
|
|
4085
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
|
|
4086
|
+
throw new TypeError("Malformed JWT payload");
|
|
4087
|
+
}
|
|
4088
|
+
const sub = payload.sub;
|
|
4089
|
+
if (typeof sub !== "string") {
|
|
4090
|
+
throw new TypeError("Expected string sub claim");
|
|
4091
|
+
}
|
|
4092
|
+
return { entityRef: sub, token };
|
|
4093
|
+
} catch (e) {
|
|
4094
|
+
throw new errors.InputError(`Invalid authorization header: ${errors.stringifyError(e)}`);
|
|
4095
|
+
}
|
|
3910
4096
|
}
|
|
3911
4097
|
|
|
3912
4098
|
class ScaffolderEntitiesProcessor {
|
|
@@ -3958,6 +4144,21 @@ class ScaffolderEntitiesProcessor {
|
|
|
3958
4144
|
}
|
|
3959
4145
|
}
|
|
3960
4146
|
|
|
4147
|
+
const scaffolderCatalogModule = backendPluginApi.createBackendModule({
|
|
4148
|
+
moduleId: "scaffolder.module",
|
|
4149
|
+
pluginId: "catalog",
|
|
4150
|
+
register(env) {
|
|
4151
|
+
env.registerInit({
|
|
4152
|
+
deps: {
|
|
4153
|
+
catalogProcessingExtensionPoint: pluginCatalogNode.catalogProcessingExtentionPoint
|
|
4154
|
+
},
|
|
4155
|
+
async init({ catalogProcessingExtensionPoint }) {
|
|
4156
|
+
catalogProcessingExtensionPoint.addProcessor(new ScaffolderEntitiesProcessor());
|
|
4157
|
+
}
|
|
4158
|
+
});
|
|
4159
|
+
}
|
|
4160
|
+
});
|
|
4161
|
+
|
|
3961
4162
|
exports.DatabaseTaskStore = DatabaseTaskStore;
|
|
3962
4163
|
exports.ScaffolderEntitiesProcessor = ScaffolderEntitiesProcessor;
|
|
3963
4164
|
exports.TaskManager = TaskManager;
|
|
@@ -3973,6 +4174,8 @@ exports.createFilesystemDeleteAction = createFilesystemDeleteAction;
|
|
|
3973
4174
|
exports.createFilesystemRenameAction = createFilesystemRenameAction;
|
|
3974
4175
|
exports.createGithubActionsDispatchAction = createGithubActionsDispatchAction;
|
|
3975
4176
|
exports.createGithubIssuesLabelAction = createGithubIssuesLabelAction;
|
|
4177
|
+
exports.createGithubRepoCreateAction = createGithubRepoCreateAction;
|
|
4178
|
+
exports.createGithubRepoPushAction = createGithubRepoPushAction;
|
|
3976
4179
|
exports.createGithubWebhookAction = createGithubWebhookAction;
|
|
3977
4180
|
exports.createPublishAzureAction = createPublishAzureAction;
|
|
3978
4181
|
exports.createPublishBitbucketAction = createPublishBitbucketAction;
|
|
@@ -3988,4 +4191,5 @@ exports.createRouter = createRouter;
|
|
|
3988
4191
|
exports.createTemplateAction = createTemplateAction;
|
|
3989
4192
|
exports.executeShellCommand = executeShellCommand;
|
|
3990
4193
|
exports.fetchContents = fetchContents;
|
|
4194
|
+
exports.scaffolderCatalogModule = scaffolderCatalogModule;
|
|
3991
4195
|
//# sourceMappingURL=index.cjs.js.map
|