'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var errors = require('@backstage/errors'); var pluginScaffolderNode = require('@backstage/plugin-scaffolder-node'); var octokit = require('octokit'); var integration = require('@backstage/integration'); var Sodium = require('libsodium-wrappers'); var yaml = require('yaml'); var webhooks = require('@octokit/webhooks'); var path = require('path'); var backendCommon = require('@backstage/backend-common'); var octokitPluginCreatePullRequest = require('octokit-plugin-create-pull-request'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var Sodium__default = /*#__PURE__*/_interopDefaultLegacy(Sodium); var yaml__default = /*#__PURE__*/_interopDefaultLegacy(yaml); var path__default = /*#__PURE__*/_interopDefaultLegacy(path); const enableBranchProtectionOnDefaultRepoBranch = async ({ repoName, client, owner, logger, requireCodeOwnerReviews, bypassPullRequestAllowances, requiredApprovingReviewCount, restrictions, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, defaultBranch = "master", enforceAdmins = true, dismissStaleReviews = false, requiredCommitSigning = false }) => { const tryOnce = async () => { try { await client.rest.repos.updateBranchProtection({ mediaType: { /** * 👇 we need this preview because allowing a custom * reviewer count on branch protection is a preview * feature * * More here: https://docs.github.com/en/rest/overview/api-previews#require-multiple-approving-reviews */ previews: ["luke-cage-preview"] }, owner, repo: repoName, branch: defaultBranch, required_status_checks: { strict: requireBranchesToBeUpToDate, contexts: requiredStatusCheckContexts }, restrictions: restrictions != null ? restrictions : null, enforce_admins: enforceAdmins, required_pull_request_reviews: { required_approving_review_count: requiredApprovingReviewCount, require_code_owner_reviews: requireCodeOwnerReviews, bypass_pull_request_allowances: bypassPullRequestAllowances, dismiss_stale_reviews: dismissStaleReviews }, required_conversation_resolution: requiredConversationResolution }); if (requiredCommitSigning) { await client.rest.repos.createCommitSignatureProtection({ owner, repo: repoName, branch: defaultBranch }); } } catch (e) { errors.assertError(e); if (e.message.includes( "Upgrade to GitHub Pro or make this repository public to enable this feature" )) { logger.warn( "Branch protection was not enabled as it requires GitHub Pro for private repositories" ); } else { throw e; } } }; try { await tryOnce(); } catch (e) { if (!e.message.includes("Branch not found")) { throw e; } await new Promise((resolve) => setTimeout(resolve, 600)); await tryOnce(); } }; function entityRefToName(name) { return name.replace(/^.*[:/]/g, ""); } const DEFAULT_TIMEOUT_MS = 6e4; async function getOctokitOptions(options) { var _a; const { integrations, credentialsProvider, repoUrl, token } = options; const { owner, repo, host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); const requestOptions = { // set timeout to 60 seconds timeout: DEFAULT_TIMEOUT_MS }; if (!owner) { throw new errors.InputError(`No owner provided for repo ${repoUrl}`); } const integrationConfig = (_a = integrations.github.byHost(host)) == null ? void 0 : _a.config; if (!integrationConfig) { throw new errors.InputError(`No integration for host ${host}`); } if (token) { return { auth: token, baseUrl: integrationConfig.apiBaseUrl, previews: ["nebula-preview"], request: requestOptions }; } const githubCredentialsProvider = credentialsProvider != null ? credentialsProvider : integration.DefaultGithubCredentialsProvider.fromIntegrations(integrations); const { token: credentialProviderToken } = await githubCredentialsProvider.getCredentials({ url: `https://${host}/${encodeURIComponent(owner)}/${encodeURIComponent( repo )}` }); if (!credentialProviderToken) { throw new errors.InputError( `No token available for host: ${host}, with owner ${owner}, and repo ${repo}` ); } return { auth: credentialProviderToken, baseUrl: integrationConfig.apiBaseUrl, previews: ["nebula-preview"] }; } async function createGithubRepoWithCollaboratorsAndTopics(client, repo, owner, repoVisibility, description, homepage, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, squashMergeCommitTitle, squashMergeCommitMessage, allowRebaseMerge, allowAutoMerge, access, collaborators, hasProjects, hasWiki, hasIssues, topics, repoVariables, secrets, logger) { const user = await client.rest.users.getByUsername({ username: owner }); if (access == null ? void 0 : access.startsWith(`${owner}/`)) { await validateAccessTeam(client, access); } const repoCreationPromise = user.data.type === "Organization" ? client.rest.repos.createInOrg({ name: repo, org: owner, private: repoVisibility === "private", // @ts-ignore https://github.com/octokit/types.ts/issues/522 visibility: repoVisibility, description, delete_branch_on_merge: deleteBranchOnMerge, allow_merge_commit: allowMergeCommit, allow_squash_merge: allowSquashMerge, squash_merge_commit_title: squashMergeCommitTitle, squash_merge_commit_message: squashMergeCommitMessage, allow_rebase_merge: allowRebaseMerge, allow_auto_merge: allowAutoMerge, homepage, has_projects: hasProjects, has_wiki: hasWiki, has_issues: hasIssues }) : client.rest.repos.createForAuthenticatedUser({ name: repo, private: repoVisibility === "private", description, delete_branch_on_merge: deleteBranchOnMerge, allow_merge_commit: allowMergeCommit, allow_squash_merge: allowSquashMerge, squash_merge_commit_title: squashMergeCommitTitle, squash_merge_commit_message: squashMergeCommitMessage, allow_rebase_merge: allowRebaseMerge, allow_auto_merge: allowAutoMerge, homepage, has_projects: hasProjects, has_wiki: hasWiki, has_issues: hasIssues }); let newRepo; try { newRepo = (await repoCreationPromise).data; } catch (e) { errors.assertError(e); if (e.message === "Resource not accessible by integration") { logger.warn( `The GitHub app or token provided may not have the required permissions to create the ${user.data.type} repository ${owner}/${repo}.` ); } throw new Error( `Failed to create the ${user.data.type} repository ${owner}/${repo}, ${e.message}` ); } if (access == null ? void 0 : access.startsWith(`${owner}/`)) { const [, team] = access.split("/"); await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ org: owner, team_slug: team, owner, repo, permission: "admin" }); } else if (access && access !== owner) { await client.rest.repos.addCollaborator({ owner, repo, username: access, permission: "admin" }); } if (collaborators) { for (const collaborator of collaborators) { try { if ("user" in collaborator) { await client.rest.repos.addCollaborator({ owner, repo, username: entityRefToName(collaborator.user), permission: collaborator.access }); } else if ("team" in collaborator) { await client.rest.teams.addOrUpdateRepoPermissionsInOrg({ org: owner, team_slug: entityRefToName(collaborator.team), owner, repo, permission: collaborator.access }); } } catch (e) { errors.assertError(e); const name = extractCollaboratorName(collaborator); logger.warn( `Skipping ${collaborator.access} access for ${name}, ${e.message}` ); } } } if (topics) { try { await client.rest.repos.replaceAllTopics({ owner, repo, names: topics.map((t) => t.toLowerCase()) }); } catch (e) { errors.assertError(e); logger.warn(`Skipping topics ${topics.join(" ")}, ${e.message}`); } } for (const [key, value] of Object.entries(repoVariables != null ? repoVariables : {})) { await client.rest.actions.createRepoVariable({ owner, repo, name: key, value }); } if (secrets) { const publicKeyResponse = await client.rest.actions.getRepoPublicKey({ owner, repo }); await Sodium__default["default"].ready; const binaryKey = Sodium__default["default"].from_base64( publicKeyResponse.data.key, Sodium__default["default"].base64_variants.ORIGINAL ); for (const [key, value] of Object.entries(secrets)) { const binarySecret = Sodium__default["default"].from_string(value); const encryptedBinarySecret = Sodium__default["default"].crypto_box_seal( binarySecret, binaryKey ); const encryptedBase64Secret = Sodium__default["default"].to_base64( encryptedBinarySecret, Sodium__default["default"].base64_variants.ORIGINAL ); await client.rest.actions.createOrUpdateRepoSecret({ owner, repo, secret_name: key, encrypted_value: encryptedBase64Secret, key_id: publicKeyResponse.data.key_id }); } } return newRepo; } async function initRepoPushAndProtect(remoteUrl, password, workspacePath, sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, bypassPullRequestAllowances, requiredApprovingReviewCount, restrictions, requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, config, logger, gitCommitMessage, gitAuthorName, gitAuthorEmail, dismissStaleReviews, requiredCommitSigning) { const gitAuthorInfo = { name: gitAuthorName ? gitAuthorName : config.getOptionalString("scaffolder.defaultAuthor.name"), email: gitAuthorEmail ? gitAuthorEmail : config.getOptionalString("scaffolder.defaultAuthor.email") }; const commitMessage = getGitCommitMessage(gitCommitMessage, config) || "initial commit"; const commitResult = await pluginScaffolderNode.initRepoAndPush({ dir: pluginScaffolderNode.getRepoSourceDirectory(workspacePath, sourcePath), remoteUrl, defaultBranch, auth: { username: "x-access-token", password }, logger, commitMessage, gitAuthorInfo }); if (protectDefaultBranch) { try { await enableBranchProtectionOnDefaultRepoBranch({ owner, client, repoName: repo, logger, defaultBranch, bypassPullRequestAllowances, requiredApprovingReviewCount, restrictions, requireCodeOwnerReviews, requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, enforceAdmins: protectEnforceAdmins, dismissStaleReviews, requiredCommitSigning }); } catch (e) { errors.assertError(e); logger.warn( `Skipping: default branch protection on '${repo}', ${e.message}` ); } } return { commitHash: commitResult.commitHash }; } function extractCollaboratorName(collaborator) { if ("username" in collaborator) return collaborator.username; if ("user" in collaborator) return collaborator.user; return collaborator.team; } async function validateAccessTeam(client, access) { const [org, team_slug] = access.split("/"); try { await client.rest.teams.getByName({ org, team_slug }); } catch (e) { if (e.response.data.message === "Not Found") { const message = `Received 'Not Found' from the API; one of org: ${org} or team: ${team_slug} was not found within GitHub.`; throw new errors.NotFoundError(message); } } } function getGitCommitMessage(gitCommitMessage, config) { return gitCommitMessage ? gitCommitMessage : config.getOptionalString("scaffolder.defaultCommitMessage"); } const examples$9 = [ { description: "GitHub Action Workflow Without Inputs.", example: yaml__default["default"].stringify({ steps: [ { action: "github:actions:dispatch", name: "Dispatch Github Action Workflow", input: { repoUrl: "github.com?repo=repo&owner=owner", workflowId: "WORKFLOW_ID", branchOrTagName: "main" } } ] }) }, { description: "GitHub Action Workflow With Inputs", example: yaml__default["default"].stringify({ steps: [ { action: "github:actions:dispatch", name: "Dispatch Github Action Workflow with inputs", input: { repoUrl: "github.com?repo=repo&owner=owner", workflowId: "WORKFLOW_ID", branchOrTagName: "main", workflowInputs: { input1: "value1", input2: "value2" } } } ] }) }, { description: "GitHub Action Workflow With Custom Token", example: yaml__default["default"].stringify({ steps: [ { action: "github:actions:dispatch", name: "Dispatch GitHub Action Workflow (custom token)", input: { repoUrl: "github.com?repo=reponame&owner=owner", workflowId: "WORKFLOW_ID", branchOrTagName: "release-1.0", token: "${{ secrets.MY_CUSTOM_TOKEN }}" } } ] }) } ]; function createGithubActionsDispatchAction(options) { const { integrations, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:actions:dispatch", description: "Dispatches a GitHub Action workflow for a given branch or tag", examples: examples$9, schema: { input: { type: "object", required: ["repoUrl", "workflowId", "branchOrTagName"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }, workflowId: { title: "Workflow ID", description: "The GitHub Action Workflow filename", type: "string" }, branchOrTagName: { title: "Branch or Tag name", description: "The git branch or tag name used to dispatch the workflow", type: "string" }, workflowInputs: { title: "Workflow Inputs", description: "Inputs keys and values to send to GitHub Action configured on the workflow file. The maximum number of properties is 10. ", type: "object" }, token: { title: "Authentication Token", type: "string", description: "The GITHUB_TOKEN to use for authorization to GitHub" } } } }, async handler(ctx) { const { repoUrl, workflowId, branchOrTagName, workflowInputs, token: providedToken } = ctx.input; ctx.logger.info( `Dispatching workflow ${workflowId} for repo ${repoUrl} on ${branchOrTagName}` ); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const client = new octokit.Octokit( await getOctokitOptions({ integrations, repoUrl, credentialsProvider: githubCredentialsProvider, token: providedToken }) ); await client.rest.actions.createWorkflowDispatch({ owner, repo, workflow_id: workflowId, ref: branchOrTagName, inputs: workflowInputs }); ctx.logger.info(`Workflow ${workflowId} dispatched successfully`); } }); } const examples$8 = [ { description: "Add labels to pull request or issue", example: yaml__default["default"].stringify({ steps: [ { action: "github:issues:label", name: "Add labels to pull request or issue", input: { repoUrl: "github.com?repo=repo&owner=owner", number: "1", labels: ["bug"] } } ] }) }, { description: "Add labels to pull request or issue with specific token", example: yaml__default["default"].stringify({ steps: [ { action: "github:issues:label", name: "Add labels to pull request or issue with token", input: { repoUrl: "github.com?repo=repo&owner=owner", number: "1", labels: ["bug", "documentation"], token: "gph_YourGitHubToken" } } ] }) } ]; function createGithubIssuesLabelAction(options) { const { integrations, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:issues:label", description: "Adds labels to a pull request or issue on GitHub.", examples: examples$8, schema: { input: { type: "object", required: ["repoUrl", "number", "labels"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the repository name and 'owner' is an organization or username`, type: "string" }, number: { title: "Pull Request or issue number", description: "The pull request or issue number to add labels to", type: "number" }, labels: { title: "Labels", description: "The labels to add to the pull request or issue", type: "array", items: { type: "string" } }, token: { title: "Authentication Token", type: "string", description: "The GITHUB_TOKEN to use for authorization to GitHub" } } } }, async handler(ctx) { const { repoUrl, number, labels, token: providedToken } = ctx.input; const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); ctx.logger.info(`Adding labels to ${number} issue on repo ${repo}`); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const client = new octokit.Octokit( await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, repoUrl, token: providedToken }) ); try { await client.rest.issues.addLabels({ owner, repo, issue_number: number, labels }); } catch (e) { errors.assertError(e); ctx.logger.warn( `Failed: adding labels to issue: '${number}' on repo: '${repo}', ${e.message}` ); } } }); } const repoUrl = { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }; const description = { title: "Repository Description", type: "string" }; const homepage = { title: "Repository Homepage", type: "string" }; const access = { title: "Repository Access", 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'`, type: "string" }; const requireCodeOwnerReviews = { title: "Require CODEOWNER Reviews?", description: "Require an approved review in PR including files with a designated Code Owner", type: "boolean" }; const dismissStaleReviews = { title: "Dismiss Stale Reviews", description: "New reviewable commits pushed to a matching branch will dismiss pull request review approvals.", type: "boolean" }; const requiredStatusCheckContexts = { title: "Required Status Check Contexts", description: "The list of status checks to require in order to merge into this branch", type: "array", items: { type: "string" } }; const requireBranchesToBeUpToDate = { title: "Require Branches To Be Up To Date?", description: `Require branches to be up to date before merging. The default value is 'true'`, type: "boolean" }; const requiredConversationResolution = { title: "Required Conversation Resolution", description: "Requires all conversations on code to be resolved before a pull request can be merged into this branch", type: "boolean" }; const repoVisibility = { title: "Repository Visibility", type: "string", enum: ["private", "public", "internal"] }; const deleteBranchOnMerge = { title: "Delete Branch On Merge", type: "boolean", description: `Delete the branch after merging the PR. The default value is 'false'` }; const gitAuthorName = { title: "Default Author Name", type: "string", description: `Sets the default author name for the commit. The default value is 'Scaffolder'` }; const gitAuthorEmail = { title: "Default Author Email", type: "string", description: `Sets the default author email for the commit.` }; const allowMergeCommit = { title: "Allow Merge Commits", type: "boolean", description: `Allow merge commits. The default value is 'true'` }; const allowSquashMerge = { title: "Allow Squash Merges", type: "boolean", description: `Allow squash merges. The default value is 'true'` }; const squashMergeCommitTitle = { title: "Default squash merge commit title", enum: ["PR_TITLE", "COMMIT_OR_PR_TITLE"], description: `Sets the default value for a squash merge commit title. The default value is 'COMMIT_OR_PR_TITLE'` }; const squashMergeCommitMessage = { title: "Default squash merge commit message", enum: ["PR_BODY", "COMMIT_MESSAGES", "BLANK"], description: `Sets the default value for a squash merge commit message. The default value is 'COMMIT_MESSAGES'` }; const allowRebaseMerge = { title: "Allow Rebase Merges", type: "boolean", description: `Allow rebase merges. The default value is 'true'` }; const allowAutoMerge = { title: "Allow Auto Merges", type: "boolean", description: `Allow individual PRs to merge automatically when all merge requirements are met. The default value is 'false'` }; const collaborators = { title: "Collaborators", description: "Provide additional users or teams with permissions", type: "array", items: { type: "object", additionalProperties: false, required: ["access"], properties: { access: { type: "string", description: "The type of access for the user" }, user: { type: "string", description: "The name of the user that will be added as a collaborator" }, team: { type: "string", description: "The name of the team that will be added as a collaborator" } }, oneOf: [{ required: ["user"] }, { required: ["team"] }] } }; const hasProjects = { title: "Enable projects", type: "boolean", description: `Enable projects for the repository. The default value is 'true' unless the organization has disabled repository projects` }; const hasWiki = { title: "Enable the wiki", type: "boolean", description: `Enable the wiki for the repository. The default value is 'true'` }; const hasIssues = { title: "Enable issues", type: "boolean", description: `Enable issues for the repository. The default value is 'true'` }; const token = { title: "Authentication Token", type: "string", description: "The token to use for authorization to GitHub" }; const topics = { title: "Topics", type: "array", items: { type: "string" } }; const defaultBranch = { title: "Default Branch", type: "string", description: `Sets the default branch on the repository. The default value is 'master'` }; const protectDefaultBranch = { title: "Protect Default Branch", type: "boolean", description: `Protect the default branch after creating the repository. The default value is 'true'` }; const protectEnforceAdmins = { title: "Enforce Admins On Protected Branches", type: "boolean", description: `Enforce admins to adhere to default branch protection. The default value is 'true'` }; const bypassPullRequestAllowances = { title: "Bypass pull request requirements", description: "Allow specific users, teams, or apps to bypass pull request requirements.", type: "object", additionalProperties: false, properties: { apps: { type: "array", items: { type: "string" } }, users: { type: "array", items: { type: "string" } }, teams: { type: "array", items: { type: "string" } } } }; const gitCommitMessage = { title: "Git Commit Message", type: "string", description: `Sets the commit message on the repository. The default value is 'initial commit'` }; const sourcePath = { title: "Source Path", description: "Path within the workspace that will be used as the repository root. If omitted, the entire workspace will be published as the repository.", type: "string" }; const requiredApprovingReviewCount = { title: "Required approving review count", type: "number", description: `Specify the number of reviewers required to approve pull requests. Use a number between 1 and 6 or 0 to not require reviewers. Defaults to 1.` }; const restrictions = { title: "Restrict who can push to the protected branch", description: "Restrict who can push to the protected branch. User, app, and team restrictions are only available for organization-owned repositories.", type: "object", additionalProperties: false, properties: { apps: { type: "array", items: { type: "string" } }, users: { type: "array", items: { type: "string" } }, teams: { type: "array", items: { type: "string" } } } }; const requiredCommitSigning = { title: "Require commit signing", type: "boolean", description: `Require commit signing so that you must sign commits on this branch.` }; const repoVariables = { title: "Repository Variables", description: `Variables attached to the repository`, type: "object" }; const secrets = { title: "Repository Secrets", description: `Secrets attached to the repository`, type: "object" }; const remoteUrl = { title: "A URL to the repository with the provider", type: "string" }; const repoContentsUrl = { title: "A URL to the root of the repository", type: "string" }; const commitHash = { title: "The git commit hash of the initial commit", type: "string" }; const examples$7 = [ { description: "Creates a GitHub repository with default configuration.", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:create", name: "Create a new GitHub repository", input: { repoUrl: "github.com?repo=repo&owner=owner" } } ] }) }, { description: "Add a description.", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:create", name: "Create a new GitHub repository with a description", input: { repoUrl: "github.com?repo=repo&owner=owner", description: "My new repository" } } ] }) }, { description: "Disable wiki and issues.", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:create", name: "Create a new GitHub repository without wiki and issues", input: { repoUrl: "github.com?repo=repo&owner=owner", hasIssues: false, hasWiki: false } } ] }) } ]; function createGithubRepoCreateAction(options) { const { integrations, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:repo:create", description: "Creates a GitHub repository.", examples: examples$7, schema: { input: { type: "object", required: ["repoUrl"], properties: { repoUrl: repoUrl, description: description, homepage: homepage, access: access, requireCodeOwnerReviews: requireCodeOwnerReviews, bypassPullRequestAllowances: bypassPullRequestAllowances, requiredApprovingReviewCount: requiredApprovingReviewCount, restrictions: restrictions, requiredStatusCheckContexts: requiredStatusCheckContexts, requireBranchesToBeUpToDate: requireBranchesToBeUpToDate, requiredConversationResolution: requiredConversationResolution, repoVisibility: repoVisibility, deleteBranchOnMerge: deleteBranchOnMerge, allowMergeCommit: allowMergeCommit, allowSquashMerge: allowSquashMerge, squashMergeCommitTitle: squashMergeCommitTitle, squashMergeCommitMessage: squashMergeCommitMessage, allowRebaseMerge: allowRebaseMerge, allowAutoMerge: allowAutoMerge, collaborators: collaborators, hasProjects: hasProjects, hasWiki: hasWiki, hasIssues: hasIssues, token: token, topics: topics, repoVariables: repoVariables, secrets: secrets, requiredCommitSigning: requiredCommitSigning } }, output: { type: "object", properties: { remoteUrl: remoteUrl, repoContentsUrl: repoContentsUrl } } }, async handler(ctx) { const { repoUrl, description, homepage, access, repoVisibility = "private", deleteBranchOnMerge = false, allowMergeCommit = true, allowSquashMerge = true, squashMergeCommitTitle = "COMMIT_OR_PR_TITLE", squashMergeCommitMessage = "COMMIT_MESSAGES", allowRebaseMerge = true, allowAutoMerge = false, collaborators, hasProjects = void 0, hasWiki = void 0, hasIssues = void 0, topics, repoVariables, secrets, token: providedToken } = ctx.input; const octokitOptions = await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, token: providedToken, repoUrl }); const client = new octokit.Octokit(octokitOptions); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const newRepo = await createGithubRepoWithCollaboratorsAndTopics( client, repo, owner, repoVisibility, description, homepage, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, squashMergeCommitTitle, squashMergeCommitMessage, allowRebaseMerge, allowAutoMerge, access, collaborators, hasProjects, hasWiki, hasIssues, topics, repoVariables, secrets, ctx.logger ); ctx.output("remoteUrl", newRepo.clone_url); } }); } const examples$6 = [ { description: "Setup repo with no modifications to branch protection rules", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:push", name: "Create test repo with testuser as owner.", input: { repoUrl: "github.com?repo=test&owner=testuser" } } ] }) }, { description: "Setup repo with required codeowners check", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:push", name: "Require codeowner branch protection rule", input: { repoUrl: "github.com?repo=reponame&owner=owner", requireCodeOwnerReviews: true } } ] }) }, { description: "Change the default required number of approvals", example: yaml__default["default"].stringify({ steps: [ { action: "github:repo:push", name: "Require two approvals before merging", input: { repoUrl: "github.com?repo=reponame&owner=owner", requiredApprovingReviewCount: 2 } } ] }) } ]; function createGithubRepoPushAction(options) { const { integrations, config, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:repo:push", description: "Initializes a git repository of contents in workspace and publishes it to GitHub.", examples: examples$6, schema: { input: { type: "object", required: ["repoUrl"], properties: { repoUrl: repoUrl, requireCodeOwnerReviews: requireCodeOwnerReviews, dismissStaleReviews: dismissStaleReviews, requiredStatusCheckContexts: requiredStatusCheckContexts, bypassPullRequestAllowances: bypassPullRequestAllowances, requiredApprovingReviewCount: requiredApprovingReviewCount, restrictions: restrictions, requireBranchesToBeUpToDate: requireBranchesToBeUpToDate, requiredConversationResolution: requiredConversationResolution, defaultBranch: defaultBranch, protectDefaultBranch: protectDefaultBranch, protectEnforceAdmins: protectEnforceAdmins, gitCommitMessage: gitCommitMessage, gitAuthorName: gitAuthorName, gitAuthorEmail: gitAuthorEmail, sourcePath: sourcePath, token: token, requiredCommitSigning: requiredCommitSigning } }, output: { type: "object", properties: { remoteUrl: remoteUrl, repoContentsUrl: repoContentsUrl, commitHash: commitHash } } }, async handler(ctx) { const { repoUrl, defaultBranch = "master", protectDefaultBranch = true, protectEnforceAdmins = true, gitCommitMessage = "initial commit", gitAuthorName, gitAuthorEmail, requireCodeOwnerReviews = false, dismissStaleReviews = false, bypassPullRequestAllowances, requiredApprovingReviewCount = 1, restrictions, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, token: providedToken, requiredCommitSigning = false } = ctx.input; const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const octokitOptions = await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, token: providedToken, repoUrl }); const client = new octokit.Octokit(octokitOptions); const targetRepo = await client.rest.repos.get({ owner, repo }); const remoteUrl = targetRepo.data.clone_url; const repoContentsUrl = `${targetRepo.data.html_url}/blob/${defaultBranch}`; const { commitHash } = await initRepoPushAndProtect( remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, bypassPullRequestAllowances, requiredApprovingReviewCount, restrictions, requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail, dismissStaleReviews, requiredCommitSigning ); ctx.output("remoteUrl", remoteUrl); ctx.output("repoContentsUrl", repoContentsUrl); ctx.output("commitHash", commitHash); } }); } const examples$5 = [ { description: "Create a GitHub webhook for a repository", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook", webhookSecret: "mysecret", events: ["push"], active: true, contentType: "json", insecureSsl: false, token: "my-github-token" } } ] }) }, { description: "Create a GitHub webhook with minimal configuration", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook" } } ] }) }, { description: "Create a GitHub webhook with custom events", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook", events: ["push", "pull_request"] } } ] }) }, { description: "Create a GitHub webhook with JSON content type", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook", contentType: "json" } } ] }) }, { description: "Create a GitHub webhook with insecure SSL", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook", insecureSsl: true } } ] }) }, { description: "Create an inactive GitHub webhook", example: yaml__default["default"].stringify({ steps: [ { action: "github:webhook", name: "Create GitHub Webhook", input: { repoUrl: "github.com?repo=repo&owner=owner", webhookUrl: "https://example.com/my-webhook", active: false } } ] }) } ]; function createGithubWebhookAction(options) { const { integrations, defaultWebhookSecret, githubCredentialsProvider } = options; const eventNames = webhooks.emitterEventNames.filter((event) => !event.includes(".")); return pluginScaffolderNode.createTemplateAction({ id: "github:webhook", description: "Creates webhook for a repository on GitHub.", examples: examples$5, schema: { input: { type: "object", required: ["repoUrl", "webhookUrl"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }, webhookUrl: { title: "Webhook URL", description: "The URL to which the payloads will be delivered", type: "string" }, webhookSecret: { title: "Webhook Secret", description: "Webhook secret value. The default can be provided internally in action creation", type: "string" }, events: { title: "Triggering Events", description: "Determines what events the hook is triggered for. Default: push", type: "array", oneOf: [ { items: { type: "string", enum: eventNames } }, { items: { type: "string", const: "*" } } ] }, active: { title: "Active", type: "boolean", description: `Determines if notifications are sent when the webhook is triggered. Default: true` }, contentType: { title: "Content Type", type: "string", enum: ["form", "json"], description: `The media type used to serialize the payloads. The default is 'form'` }, insecureSsl: { title: "Insecure SSL", type: "boolean", description: `Determines whether the SSL certificate of the host for url will be verified when delivering payloads. Default 'false'` }, token: { title: "Authentication Token", type: "string", description: "The GITHUB_TOKEN to use for authorization to GitHub" } } } }, async handler(ctx) { const { repoUrl, webhookUrl, webhookSecret = defaultWebhookSecret, events = ["push"], active = true, contentType = "form", insecureSsl = false, token: providedToken } = ctx.input; ctx.logger.info(`Creating webhook ${webhookUrl} for repo ${repoUrl}`); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const client = new octokit.Octokit( await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, repoUrl, token: providedToken }) ); try { const insecure_ssl = insecureSsl ? "1" : "0"; await client.rest.repos.createWebhook({ owner, repo, config: { url: webhookUrl, content_type: contentType, secret: webhookSecret, insecure_ssl }, events, active }); ctx.logger.info(`Webhook '${webhookUrl}' created successfully`); } catch (e) { errors.assertError(e); ctx.logger.warn( `Failed: create webhook '${webhookUrl}' on repo: '${repo}', ${e.message}` ); } } }); } const examples$4 = [ { description: "Example 1: Create and store a Deploy Key", example: yaml__default["default"].stringify({ steps: [ { action: "github:deployKey:create", name: "Create and store a Deploy Key", input: { repoUrl: "github.com?repo=repository&owner=owner", publicKey: "pubkey", privateKey: "privkey", deployKeyName: "Push Tags" } } ] }) } ]; function createGithubDeployKeyAction(options) { const { integrations } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:deployKey:create", description: "Creates and stores Deploy Keys", examples: examples$4, schema: { input: { type: "object", required: ["repoUrl", "publicKey", "privateKey", "deployKeyName"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }, publicKey: { title: "SSH Public Key", description: `Generated from ssh-keygen. Begins with 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'ssh-ed25519', 'sk-ecdsa-sha2-nistp256@openssh.com', or 'sk-ssh-ed25519@openssh.com'.`, type: "string" }, privateKey: { title: "SSH Private Key", description: `SSH Private Key generated from ssh-keygen`, type: "string" }, deployKeyName: { title: "Deploy Key Name", description: `Name of the Deploy Key`, type: "string" }, privateKeySecretName: { title: "Private Key GitHub Secret Name", description: `Name of the GitHub Secret to store the private key related to the Deploy Key. Defaults to: 'KEY_NAME_PRIVATE_KEY' where 'KEY_NAME' is the name of the Deploy Key`, type: "string" }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization to GitHub" } } }, output: { type: "object", properties: { privateKeySecretName: { title: "The GitHub Action Repo Secret Name for the Private Key", type: "string" } } } }, async handler(ctx) { const { repoUrl, publicKey, privateKey, deployKeyName, privateKeySecretName = `${deployKeyName.split(" ").join("_").toLocaleUpperCase("en-US")}_PRIVATE_KEY`, token: providedToken } = ctx.input; const octokitOptions = await getOctokitOptions({ integrations, token: providedToken, repoUrl }); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError(`No owner provided for repo ${repoUrl}`); } const client = new octokit.Octokit(octokitOptions); await client.rest.repos.createDeployKey({ owner, repo, title: deployKeyName, key: publicKey }); const publicKeyResponse = await client.rest.actions.getRepoPublicKey({ owner, repo }); await Sodium__default["default"].ready; const binaryKey = Sodium__default["default"].from_base64( publicKeyResponse.data.key, Sodium__default["default"].base64_variants.ORIGINAL ); const binarySecret = Sodium__default["default"].from_string(privateKey); const encryptedBinarySecret = Sodium__default["default"].crypto_box_seal( binarySecret, binaryKey ); const encryptedBase64Secret = Sodium__default["default"].to_base64( encryptedBinarySecret, Sodium__default["default"].base64_variants.ORIGINAL ); await client.rest.actions.createOrUpdateRepoSecret({ owner, repo, secret_name: privateKeySecretName, encrypted_value: encryptedBase64Secret, key_id: publicKeyResponse.data.key_id }); ctx.output("privateKeySecretName", privateKeySecretName); } }); } const examples$3 = [ { description: "Create a GitHub Environment (No Policies, No Variables, No Secrets)", example: yaml__default["default"].stringify({ steps: [ { action: "github:environment:create", name: "Create Environment", input: { repoUrl: "github.com?repo=repository&owner=owner", name: "envname" } } ] }) }, { description: "Create a GitHub Environment with Protected Branch Policy", example: yaml__default["default"].stringify({ steps: [ { action: "github:environment:create", name: "Create Environment", input: { repoUrl: "github.com?repo=repository&owner=owner", name: "envname", deploymentBranchPolicy: { protected_branches: true, custom_branch_policies: false } } } ] }) }, { description: "Create a GitHub Environment with Custom Branch Policies", example: yaml__default["default"].stringify({ steps: [ { action: "github:environment:create", name: "Create Environment", input: { repoUrl: "github.com?repo=repository&owner=owner", name: "envname", deploymentBranchPolicy: { protected_branches: false, custom_branch_policies: true }, customBranchPolicyNames: ["main", "*.*.*"] } } ] }) }, { description: "Create a GitHub Environment with Environment Variables and Secrets", example: yaml__default["default"].stringify({ steps: [ { action: "github:environment:create", name: "Create Environment", input: { repoUrl: "github.com?repo=repository&owner=owner", name: "envname", environmentVariables: { key1: "val1", key2: "val2" }, secrets: { secret1: "supersecret1", secret2: "supersecret2" } } } ] }) } ]; function createGithubEnvironmentAction(options) { const { integrations } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:environment:create", description: "Creates Deployment Environments", examples: examples$3, schema: { input: { type: "object", required: ["repoUrl", "name"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }, name: { title: "Environment Name", description: `Name of the deployment environment to create`, type: "string" }, deploymentBranchPolicy: { title: "Deployment Branch Policy", description: `The type of deployment branch policy for this environment. To allow all branches to deploy, set to null.`, type: "object", required: ["protected_branches", "custom_branch_policies"], properties: { protected_branches: { title: "Protected Branches", description: `Whether only branches with branch protection rules can deploy to this environment. If protected_branches is true, custom_branch_policies must be false; if protected_branches is false, custom_branch_policies must be true.`, type: "boolean" }, custom_branch_policies: { title: "Custom Branch Policies", description: `Whether only branches that match the specified name patterns can deploy to this environment. If custom_branch_policies is true, protected_branches must be false; if custom_branch_policies is false, protected_branches must be true.`, type: "boolean" } } }, customBranchPolicyNames: { title: "Custom Branch Policy Name", description: `The name pattern that branches must match in order to deploy to the environment. Wildcard characters will not match /. For example, to match branches that begin with release/ and contain an additional single slash, use release/*/*. For more information about pattern matching syntax, see the Ruby File.fnmatch documentation.`, type: "array", items: { type: "string" } }, environmentVariables: { title: "Environment Variables", description: `Environment variables attached to the deployment environment`, type: "object" }, secrets: { title: "Deployment Secrets", description: `Secrets attached to the deployment environment`, type: "object" }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization to GitHub" } } } }, async handler(ctx) { const { repoUrl, name, deploymentBranchPolicy, customBranchPolicyNames, environmentVariables, secrets, token: providedToken } = ctx.input; const octokitOptions = await getOctokitOptions({ integrations, token: providedToken, repoUrl }); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError(`No owner provided for repo ${repoUrl}`); } const client = new octokit.Octokit(octokitOptions); const repository = await client.rest.repos.get({ owner, repo }); await client.rest.repos.createOrUpdateEnvironment({ owner, repo, environment_name: name, deployment_branch_policy: deploymentBranchPolicy != null ? deploymentBranchPolicy : null }); if (customBranchPolicyNames) { for (const item of customBranchPolicyNames) { await client.rest.repos.createDeploymentBranchPolicy({ owner, repo, environment_name: name, name: item }); } } for (const [key, value] of Object.entries(environmentVariables != null ? environmentVariables : {})) { await client.rest.actions.createEnvironmentVariable({ repository_id: repository.data.id, environment_name: name, name: key, value }); } if (secrets) { const publicKeyResponse = await client.rest.actions.getEnvironmentPublicKey({ repository_id: repository.data.id, environment_name: name }); await Sodium__default["default"].ready; const binaryKey = Sodium__default["default"].from_base64( publicKeyResponse.data.key, Sodium__default["default"].base64_variants.ORIGINAL ); for (const [key, value] of Object.entries(secrets)) { const binarySecret = Sodium__default["default"].from_string(value); const encryptedBinarySecret = Sodium__default["default"].crypto_box_seal( binarySecret, binaryKey ); const encryptedBase64Secret = Sodium__default["default"].to_base64( encryptedBinarySecret, Sodium__default["default"].base64_variants.ORIGINAL ); await client.rest.actions.createOrUpdateEnvironmentSecret({ repository_id: repository.data.id, environment_name: name, secret_name: key, encrypted_value: encryptedBase64Secret, key_id: publicKeyResponse.data.key_id }); } } } }); } const examples$2 = [ { description: "Create a pull request", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good" } } ] }) }, { description: "Create a pull request with target branch name", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest with target branch name", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", targetBranchName: "test" } } ] }) }, { description: "Create a pull request as draft", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest as draft", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", draft: true } } ] }) }, { description: "Create a pull request with target path", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest with target path", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", targetPath: "targetPath" } } ] }) }, { description: "Create a pull request with source path", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest with source path", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", sourcePath: "source" } } ] }) }, { description: "Create a pull request with token", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", token: "gph_YourGitHubToken" } } ] }) }, { description: "Create a pull request with reviewers", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest with reviewers", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", reviewers: ["foobar"] } } ] }) }, { description: "Create a pull request with team reviewers", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest with team reviewers", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", teamReviewers: ["team-foo"] } } ] }) }, { description: "Create a pull request with commit message", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", commitMessage: "Custom commit message" } } ] }) }, { description: "Create a pull request with all parameters", example: yaml__default["default"].stringify({ steps: [ { action: "publish:github:pull-request", name: "Create a pull reuqest", input: { repoUrl: "github.com?repo=repo&owner=owner", branchName: "new-app", title: "Create my new app", description: "This PR is really good", targetBranchName: "test", draft: true, targetPath: "targetPath", sourcePath: "source", token: "gph_YourGitHubToken", reviewers: ["foobar"], teamReviewers: ["team-foo"], commitMessage: "Commit for foo changes" } } ] }) } ]; class GithubResponseError extends errors.CustomErrorBase { } const defaultClientFactory = async ({ integrations, githubCredentialsProvider, owner, repo, host = "github.com", token: providedToken }) => { const [encodedHost, encodedOwner, encodedRepo] = [host, owner, repo].map( encodeURIComponent ); const octokitOptions = await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, repoUrl: `${encodedHost}?owner=${encodedOwner}&repo=${encodedRepo}`, token: providedToken }); const OctokitPR = octokit.Octokit.plugin(octokitPluginCreatePullRequest.createPullRequest); return new OctokitPR({ ...octokitOptions, ...{ throttle: { enabled: false } } }); }; const createPublishGithubPullRequestAction = (options) => { const { integrations, githubCredentialsProvider, clientFactory = defaultClientFactory } = options; return pluginScaffolderNode.createTemplateAction({ id: "publish:github:pull-request", examples: examples$2, schema: { input: { required: ["repoUrl", "title", "description", "branchName"], type: "object", properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the repository name and 'owner' is an organization or username`, type: "string" }, branchName: { type: "string", title: "Branch Name", description: "The name for the branch" }, targetBranchName: { type: "string", title: "Target Branch Name", description: "The target branch name of the merge request" }, title: { type: "string", title: "Pull Request Name", description: "The name for the pull request" }, description: { type: "string", title: "Pull Request Description", description: "The description of the pull request" }, draft: { type: "boolean", title: "Create as Draft", description: "Create a draft pull request" }, sourcePath: { type: "string", title: "Working Subdirectory", description: "Subdirectory of working directory to copy changes from" }, targetPath: { type: "string", title: "Repository Subdirectory", description: "Subdirectory of repository to apply changes to" }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization to GitHub" }, reviewers: { title: "Pull Request Reviewers", type: "array", items: { type: "string" }, description: "The users that will be added as reviewers to the pull request" }, teamReviewers: { title: "Pull Request Team Reviewers", type: "array", items: { type: "string" }, description: "The teams that will be added as reviewers to the pull request" }, commitMessage: { type: "string", title: "Commit Message", description: "The commit message for the pull request commit" }, update: { type: "boolean", title: "Update", description: "Update pull request if already exists" } } }, output: { required: ["remoteUrl"], type: "object", properties: { targetBranchName: { title: "Target branch name of the merge request", type: "string" }, remoteUrl: { type: "string", title: "Pull Request URL", description: "Link to the pull request in Github" }, pullRequestNumber: { type: "number", title: "Pull Request Number", description: "The pull request number" } } } }, async handler(ctx) { const { repoUrl, branchName, targetBranchName, title, description, draft, targetPath, sourcePath, token: providedToken, reviewers, teamReviewers, commitMessage, update } = ctx.input; const { owner, repo, host } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError( `No owner provided for host: ${host}, and repo ${repo}` ); } const client = await clientFactory({ integrations, githubCredentialsProvider, host, owner, repo, token: providedToken }); const fileRoot = sourcePath ? backendCommon.resolveSafeChildPath(ctx.workspacePath, sourcePath) : ctx.workspacePath; const directoryContents = await pluginScaffolderNode.serializeDirectoryContents(fileRoot, { gitignore: true }); const determineFileMode = (file) => { if (file.symlink) return "120000"; if (file.executable) return "100755"; return "100644"; }; const determineFileEncoding = (file) => file.symlink ? "utf-8" : "base64"; const files = Object.fromEntries( directoryContents.map((file) => [ targetPath ? path__default["default"].posix.join(targetPath, file.path) : file.path, { // See the properties of tree items // in https://docs.github.com/en/rest/reference/git#trees mode: determineFileMode(file), // Always use base64 encoding where possible to avoid doubling a binary file in size // due to interpreting a binary file as utf-8 and sending github // the utf-8 encoded content. Symlinks are kept as utf-8 to avoid them // being formatted as a series of scrambled characters // // For example, the original gradle-wrapper.jar is 57.8k in https://github.com/kennethzfeng/pull-request-test/pull/5/files. // Its size could be doubled to 98.3K (See https://github.com/kennethzfeng/pull-request-test/pull/4/files) encoding: determineFileEncoding(file), content: file.content.toString(determineFileEncoding(file)) } ]) ); try { const createOptions = { owner, repo, title, changes: [ { files, commit: commitMessage != null ? commitMessage : title } ], body: description, head: branchName, draft, update }; if (targetBranchName) { createOptions.base = targetBranchName; } const response = await client.createPullRequest(createOptions); if (!response) { throw new GithubResponseError("null response from Github"); } const pullRequestNumber = response.data.number; if (reviewers || teamReviewers) { const pullRequest = { owner, repo, number: pullRequestNumber }; await requestReviewersOnPullRequest( pullRequest, reviewers, teamReviewers, client, ctx.logger ); } const targetBranch = response.data.base.ref; ctx.output("targetBranchName", targetBranch); ctx.output("remoteUrl", response.data.html_url); ctx.output("pullRequestNumber", pullRequestNumber); } catch (e) { throw new GithubResponseError("Pull request creation failed", e); } } }); async function requestReviewersOnPullRequest(pr, reviewers, teamReviewers, client, logger) { var _a, _b, _c, _d; try { const result = await client.rest.pulls.requestReviewers({ owner: pr.owner, repo: pr.repo, pull_number: pr.number, reviewers, team_reviewers: teamReviewers ? [...new Set(teamReviewers)] : void 0 }); const addedUsers = (_b = (_a = result.data.requested_reviewers) == null ? void 0 : _a.join(", ")) != null ? _b : ""; const addedTeams = (_d = (_c = result.data.requested_teams) == null ? void 0 : _c.join(", ")) != null ? _d : ""; logger.info( `Added users [${addedUsers}] and teams [${addedTeams}] as reviewers to Pull request ${pr.number}` ); } catch (e) { logger.error( `Failure when adding reviewers to Pull request ${pr.number}`, e ); } } }; const examples$1 = [ { description: "Initializes a git repository of contents in workspace and publish it to GitHub with default configuration.", example: yaml__default["default"].stringify({ steps: [ { id: "publish", action: "publish:github", name: "Publish to GitHub", input: { repoUrl: "github.com?repo=repo&owner=owner" } } ] }) }, { description: "Add a description.", example: yaml__default["default"].stringify({ steps: [ { id: "publish", action: "publish:github", name: "Publish to GitHub", input: { repoUrl: "github.com?repo=repo&owner=owner", description: "Initialize a git repository" } } ] }) }, { description: "Change visibility of the repository.", example: yaml__default["default"].stringify({ steps: [ { id: "publish", action: "publish:github", name: "Publish to GitHub", input: { repoUrl: "github.com?repo=repo&owner=owner", description: "Initialize a git repository", repoVisibility: "public" } } ] }) } ]; function createPublishGithubAction(options) { const { integrations, config, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "publish:github", description: "Initializes a git repository of contents in workspace and publishes it to GitHub.", examples: examples$1, schema: { input: { type: "object", required: ["repoUrl"], properties: { repoUrl: repoUrl, description: description, homepage: homepage, access: access, bypassPullRequestAllowances: bypassPullRequestAllowances, requiredApprovingReviewCount: requiredApprovingReviewCount, restrictions: restrictions, requireCodeOwnerReviews: requireCodeOwnerReviews, dismissStaleReviews: dismissStaleReviews, requiredStatusCheckContexts: requiredStatusCheckContexts, requireBranchesToBeUpToDate: requireBranchesToBeUpToDate, requiredConversationResolution: requiredConversationResolution, repoVisibility: repoVisibility, defaultBranch: defaultBranch, protectDefaultBranch: protectDefaultBranch, protectEnforceAdmins: protectEnforceAdmins, deleteBranchOnMerge: deleteBranchOnMerge, gitCommitMessage: gitCommitMessage, gitAuthorName: gitAuthorName, gitAuthorEmail: gitAuthorEmail, allowMergeCommit: allowMergeCommit, allowSquashMerge: allowSquashMerge, squashMergeCommitTitle: squashMergeCommitTitle, squashMergeCommitMessage: squashMergeCommitMessage, allowRebaseMerge: allowRebaseMerge, allowAutoMerge: allowAutoMerge, sourcePath: sourcePath, collaborators: collaborators, hasProjects: hasProjects, hasWiki: hasWiki, hasIssues: hasIssues, token: token, topics: topics, repoVariables: repoVariables, secrets: secrets, requiredCommitSigning: requiredCommitSigning } }, output: { type: "object", properties: { remoteUrl: remoteUrl, repoContentsUrl: repoContentsUrl, commitHash: commitHash } } }, async handler(ctx) { const { repoUrl, description, homepage, access, requireCodeOwnerReviews = false, dismissStaleReviews = false, bypassPullRequestAllowances, requiredApprovingReviewCount = 1, restrictions, requiredStatusCheckContexts = [], requireBranchesToBeUpToDate = true, requiredConversationResolution = false, repoVisibility = "private", defaultBranch = "master", protectDefaultBranch = true, protectEnforceAdmins = true, deleteBranchOnMerge = false, gitCommitMessage, gitAuthorName, gitAuthorEmail, allowMergeCommit = true, allowSquashMerge = true, squashMergeCommitTitle = "COMMIT_OR_PR_TITLE", squashMergeCommitMessage = "COMMIT_MESSAGES", allowRebaseMerge = true, allowAutoMerge = false, collaborators, hasProjects = void 0, hasWiki = void 0, hasIssues = void 0, topics, repoVariables, secrets, token: providedToken, requiredCommitSigning = false } = ctx.input; const octokitOptions = await getOctokitOptions({ integrations, credentialsProvider: githubCredentialsProvider, token: providedToken, repoUrl }); const client = new octokit.Octokit(octokitOptions); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const newRepo = await createGithubRepoWithCollaboratorsAndTopics( client, repo, owner, repoVisibility, description, homepage, deleteBranchOnMerge, allowMergeCommit, allowSquashMerge, squashMergeCommitTitle, squashMergeCommitMessage, allowRebaseMerge, allowAutoMerge, access, collaborators, hasProjects, hasWiki, hasIssues, topics, repoVariables, secrets, ctx.logger ); const remoteUrl = newRepo.clone_url; const repoContentsUrl = `${newRepo.html_url}/blob/${defaultBranch}`; const commitResult = await initRepoPushAndProtect( remoteUrl, octokitOptions.auth, ctx.workspacePath, ctx.input.sourcePath, defaultBranch, protectDefaultBranch, protectEnforceAdmins, owner, client, repo, requireCodeOwnerReviews, bypassPullRequestAllowances, requiredApprovingReviewCount, restrictions, requiredStatusCheckContexts, requireBranchesToBeUpToDate, requiredConversationResolution, config, ctx.logger, gitCommitMessage, gitAuthorName, gitAuthorEmail, dismissStaleReviews, requiredCommitSigning ); ctx.output("commitHash", commitResult == null ? void 0 : commitResult.commitHash); ctx.output("remoteUrl", remoteUrl); ctx.output("repoContentsUrl", repoContentsUrl); } }); } const examples = [ { description: "GitHub alphanumric autolink reference", example: yaml__default["default"].stringify({ steps: [ { action: "github:autolinks:create", name: "Create an autolink reference", input: { repoUrl: "github.com?repo=repo&owner=owner", keyPrefix: "TICKET-", urlTemplate: "https://example.com/TICKET?query=", isAlphanumeric: false } } ] }) } ]; function createGithubAutolinksAction(options) { const { integrations, githubCredentialsProvider } = options; return pluginScaffolderNode.createTemplateAction({ id: "github:autolinks:create", description: "Create an autolink reference for a repository", examples, schema: { input: { type: "object", required: ["repoUrl", "keyPrefix", "urlTemplate"], properties: { repoUrl: { title: "Repository Location", description: `Accepts the format 'github.com?repo=reponame&owner=owner' where 'reponame' is the new repository name and 'owner' is an organization or username`, type: "string" }, keyPrefix: { title: "Key Prefix", description: "This prefix appended by certain characters will generate a link any time it is found in an issue, pull request, or commit.", type: "string" }, urlTemplate: { title: "URL Template", description: "The URL must contain for the reference number. matches different characters depending on the value of isAlphanumeric.", type: "string" }, isAlphanumeric: { title: "Alphanumeric", description: "Whether this autolink reference matches alphanumeric characters. If true, the parameter of the url_template matches alphanumeric characters A-Z (case insensitive), 0-9, and -. If false, this autolink reference only matches numeric characters. Default: true", type: "boolean" }, token: { title: "Authentication Token", type: "string", description: "The token to use for authorization to GitHub" } } } }, async handler(ctx) { const { repoUrl, keyPrefix, urlTemplate, isAlphanumeric, token } = ctx.input; ctx.logger.info(`Creating autolink reference for repo ${repoUrl}`); const { owner, repo } = pluginScaffolderNode.parseRepoUrl(repoUrl, integrations); if (!owner) { throw new errors.InputError("Invalid repository owner provided in repoUrl"); } const client = new octokit.Octokit( await getOctokitOptions({ integrations, repoUrl, credentialsProvider: githubCredentialsProvider, token }) ); await client.rest.repos.createAutolink({ owner, repo, key_prefix: keyPrefix, url_template: urlTemplate, is_alphanumeric: isAlphanumeric }); ctx.logger.info(`Autolink reference created successfully`); } }); } exports.createGithubActionsDispatchAction = createGithubActionsDispatchAction; exports.createGithubAutolinksAction = createGithubAutolinksAction; exports.createGithubDeployKeyAction = createGithubDeployKeyAction; exports.createGithubEnvironmentAction = createGithubEnvironmentAction; exports.createGithubIssuesLabelAction = createGithubIssuesLabelAction; exports.createGithubRepoCreateAction = createGithubRepoCreateAction; exports.createGithubRepoPushAction = createGithubRepoPushAction; exports.createGithubWebhookAction = createGithubWebhookAction; exports.createPublishGithubAction = createPublishGithubAction; exports.createPublishGithubPullRequestAction = createPublishGithubPullRequestAction; //# sourceMappingURL=index.cjs.js.map