import type { CreatePullRequestApprovalRuleInput, CreatePullRequestApprovalRuleOutput, CreatePullRequestInput, CreatePullRequestOutput, DeleteCommentContentInput, DeleteCommentContentOutput, GetCommentsForPullRequestInput, GetCommentsForPullRequestOutput, GetFileInput, GetFileOutput, GetPullRequestInput, GetPullRequestOutput, GetRepositoryInput, GetRepositoryOutput, ListPullRequestsInput, ListPullRequestsOutput, ListRepositoriesInput, ListRepositoriesOutput, PostCommentForPullRequestInput, PostCommentForPullRequestOutput, RepositoryMetadata, UpdateCommentInput, UpdateCommentOutput, UpdatePullRequestDescriptionInput, UpdatePullRequestDescriptionOutput, UpdatePullRequestStatusInput, UpdatePullRequestStatusOutput, UpdatePullRequestTitleInput, UpdatePullRequestTitleOutput, } from '@aws-sdk/client-codecommit'; import { CodeCommitClient, CreatePullRequestApprovalRuleCommand, CreatePullRequestCommand, DeleteCommentContentCommand, GetCommentsForPullRequestCommand, GetFileCommand, GetPullRequestCommand, GetRepositoryCommand, ListPullRequestsCommand, ListRepositoriesCommand, PostCommentForPullRequestCommand, PullRequestStatusEnum, UpdateCommentCommand, UpdatePullRequestDescriptionCommand, UpdatePullRequestStatusCommand, UpdatePullRequestTitleCommand, } from '@aws-sdk/client-codecommit'; import { isString } from '@sindresorhus/is'; import * as aws4 from 'aws4'; import { REPOSITORY_UNINITIATED } from '../../../constants/error-messages.ts'; import { logger } from '../../../logger/index.ts'; import { getEnv } from '../../../util/env.ts'; import { regEx } from '../../../util/regex.ts'; let codeCommitClient: CodeCommitClient; export function buildCodeCommitClient(): void { if (!codeCommitClient) { codeCommitClient = new CodeCommitClient({}); } /* v8 ignore next -- unreachable: the client was just constructed above */ if (!codeCommitClient) { throw new Error('Failed to initialize codecommit client'); } } export async function deleteComment( commentId: string, ): Promise { const input: DeleteCommentContentInput = { commentId, }; const cmd = new DeleteCommentContentCommand(input); return await codeCommitClient.send(cmd); } export async function getPrComments( pullRequestId: string, ): Promise { const input: GetCommentsForPullRequestInput = { pullRequestId, }; const cmd = new GetCommentsForPullRequestCommand(input); return await codeCommitClient.send(cmd); } export async function updateComment( commentId: string, content: string, ): Promise { const input: UpdateCommentInput = { commentId, content, }; const cmd = new UpdateCommentCommand(input); return await codeCommitClient.send(cmd); } export async function createPrComment( pullRequestId: string, repositoryName: string | undefined, content: string, beforeCommitId: string, afterCommitId: string, ): Promise { const input: PostCommentForPullRequestInput = { pullRequestId, repositoryName, content, afterCommitId, beforeCommitId, }; const cmd = new PostCommentForPullRequestCommand(input); return await codeCommitClient.send(cmd); } // export async function fastForwardMerge( // repositoryName: string, // sourceCommitSpecifier: string, // destinationReference: string // ): Promise { // const input: MergeBranchesByFastForwardInput = { // repositoryName, // sourceCommitSpecifier, // destinationCommitSpecifier: destinationReference, // targetBranch: destinationReference, // }; // const cmd = new MergeBranchesByFastForwardCommand(input); // return await codeCommitClient.send(cmd); // } // export async function squashMerge( // repositoryName: string, // sourceCommitSpecifier: string, // destinationReference: string, // commitMessage: string | undefined // ): Promise { // const input: MergeBranchesBySquashInput = { // repositoryName, // sourceCommitSpecifier, // destinationCommitSpecifier: destinationReference, // targetBranch: destinationReference, // commitMessage, // }; // const cmd = new MergeBranchesBySquashCommand(input); // return await codeCommitClient.send(cmd); // } export async function updatePrStatus( pullRequestId: string, pullRequestStatus: PullRequestStatusEnum, ): Promise { const input: UpdatePullRequestStatusInput = { pullRequestId, pullRequestStatus, }; const cmd = new UpdatePullRequestStatusCommand(input); return await codeCommitClient.send(cmd); } export async function updatePrTitle( prNo: string, title: string, ): Promise { const input: UpdatePullRequestTitleInput = { pullRequestId: `${prNo}`, title, }; const cmd = new UpdatePullRequestTitleCommand(input); return await codeCommitClient.send(cmd); } export async function updatePrDescription( pullRequestId: string, description: string, ): Promise { const input: UpdatePullRequestDescriptionInput = { pullRequestId, description, }; const cmd = new UpdatePullRequestDescriptionCommand(input); return await codeCommitClient.send(cmd); } export async function createPr( title: string, description: string, sourceReference: string, destinationReference: string, repositoryName: string | undefined, ): Promise { const input: CreatePullRequestInput = { title, description, targets: [ { sourceReference, destinationReference, repositoryName, }, ], }; const cmd = new CreatePullRequestCommand(input); return await codeCommitClient.send(cmd); } export async function getFile( repositoryName: string | undefined, filePath: string, commitSpecifier: string | undefined, ): Promise { const input: GetFileInput = { repositoryName, filePath, commitSpecifier, }; const cmd: GetFileCommand = new GetFileCommand(input); return await codeCommitClient.send(cmd); } export async function listPullRequests( repositoryName: string, ): Promise { const input: ListPullRequestsInput = { repositoryName, pullRequestStatus: PullRequestStatusEnum.OPEN, }; const cmd = new ListPullRequestsCommand(input); return await codeCommitClient.send(cmd); } export async function getRepositoryInfo( repository: string, ): Promise { const input: GetRepositoryInput = { repositoryName: `${repository}`, }; const cmd = new GetRepositoryCommand(input); return await codeCommitClient.send(cmd); } export async function getPr( pullRequestId: string, ): Promise { const input: GetPullRequestInput = { pullRequestId, }; const cmd = new GetPullRequestCommand(input); let res; try { res = await codeCommitClient.send(cmd); } catch (err) { logger.debug({ err }, 'failed to get PR using prId'); } return res; } export async function listRepositories(): Promise { const input: ListRepositoriesInput = {}; const cmd = new ListRepositoriesCommand(input); return await codeCommitClient.send(cmd); } export async function createPrApprovalRule( pullRequestId: string, approvalRuleContent: string, ): Promise { const input: CreatePullRequestApprovalRuleInput = { approvalRuleContent, approvalRuleName: 'Reviewers By Renovate', pullRequestId, }; const cmd = new CreatePullRequestApprovalRuleCommand(input); return await codeCommitClient.send(cmd); } export function getCodeCommitUrl( repoMetadata: RepositoryMetadata, repoName: string, ): string { logger.debug('get code commit url'); const env = getEnv(); if (!env.AWS_ACCESS_KEY_ID || !env.AWS_SECRET_ACCESS_KEY) { if (repoMetadata.cloneUrlHttp) { return repoMetadata.cloneUrlHttp; } // shouldn't reach here, but just in case return `https://git-codecommit.${ env.AWS_REGION ?? 'us-east-1' }.amazonaws.com/v1/repos/${repoName}`; } const signer = new aws4.RequestSigner({ service: 'codecommit', host: `git-codecommit.${env.AWS_REGION ?? 'us-east-1'}.amazonaws.com`, method: 'GIT', path: `v1/repos/${repoName}`, }); const dateTime = signer.getDateTime(); /* v8 ignore next -- defensive: the SigV4 signer always returns a datetime string */ if (!isString(dateTime)) { throw new Error(REPOSITORY_UNINITIATED); } const token = `${dateTime}Z${signer.signature()}`; let username = `${env.AWS_ACCESS_KEY_ID}${ env.AWS_SESSION_TOKEN ? `%${env.AWS_SESSION_TOKEN}` : '' }`; // massaging username with the session token, /* v8 ignore next -- only hit when an AWS session token contains '/', not present in spec env */ if (username.includes('/')) { username = username.replace(regEx(/\//g), '%2F'); } return `https://${username}:${token}@git-codecommit.${ env.AWS_REGION ?? 'us-east-1' }.amazonaws.com/v1/repos/${repoName}`; }