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