diff --git a/lib/config/presets/local/index.ts b/lib/config/presets/local/index.ts
index 4703b51c5e00dbaf6a717401ec08662eda91ab19..81a4b97694235738da776b55de467f3cb349a552 100644
--- a/lib/config/presets/local/index.ts
+++ b/lib/config/presets/local/index.ts
@@ -7,11 +7,13 @@ import * as gitea from '../gitea';
 import * as github from '../github';
 import * as gitlab from '../gitlab';
 import type { Preset, PresetConfig } from '../types';
+import * as local from './common';
 
 const resolvers = {
   [PlatformId.Azure]: azure,
   [PlatformId.Bitbucket]: bitbucket,
   [PlatformId.BitbucketServer]: bitbucketServer,
+  [PlatformId.CodeCommit]: local,
   [PlatformId.Gitea]: gitea,
   [PlatformId.Github]: github,
   [PlatformId.Gitlab]: gitlab,
diff --git a/lib/constants/platforms.ts b/lib/constants/platforms.ts
index fd2e3ebd1dcb0a146de8ff0d708b62bc133df2f5..af2d3c8ec41de427eeea91373601b45d8122ba64 100644
--- a/lib/constants/platforms.ts
+++ b/lib/constants/platforms.ts
@@ -3,6 +3,7 @@ export const enum PlatformId {
   Azure = 'azure',
   Bitbucket = 'bitbucket',
   BitbucketServer = 'bitbucket-server',
+  CodeCommit = 'codecommit',
   Gitea = 'gitea',
   Github = 'github',
   Gitlab = 'gitlab',
diff --git a/lib/modules/manager/gomod/artifacts.ts b/lib/modules/manager/gomod/artifacts.ts
index 4a856c2831f70fc659a1c392e05882020a4565f6..30cf703dc2feadd8db78e9121f20bb514c8aa9ad 100644
--- a/lib/modules/manager/gomod/artifacts.ts
+++ b/lib/modules/manager/gomod/artifacts.ts
@@ -59,6 +59,7 @@ function getGitEnvironmentVariables(): NodeJS.ProcessEnv {
     PlatformId.Azure,
     PlatformId.Bitbucket,
     PlatformId.BitbucketServer,
+    PlatformId.CodeCommit,
     PlatformId.Gitea,
     PlatformId.Github,
     PlatformId.Gitlab,
diff --git a/lib/modules/platform/api.ts b/lib/modules/platform/api.ts
index 44df268c3d321994ffe577ad0b3da9925ecff5f0..3a0a16e3da3528c0dd03d7913776b5fd1eda0ac5 100644
--- a/lib/modules/platform/api.ts
+++ b/lib/modules/platform/api.ts
@@ -1,6 +1,7 @@
 import * as azure from './azure';
 import * as bitbucket from './bitbucket';
 import * as bitbucketServer from './bitbucket-server';
+import * as codecommit from './codecommit';
 import * as gitea from './gitea';
 import * as github from './github';
 import * as gitlab from './gitlab';
@@ -12,6 +13,7 @@ export default api;
 api.set('azure', azure);
 api.set('bitbucket', bitbucket);
 api.set('bitbucket-server', bitbucketServer);
+api.set('codecommit', codecommit);
 api.set('gitea', gitea);
 api.set('github', github);
 api.set('gitlab', gitlab);
diff --git a/lib/modules/platform/codecommit/codecommit-client.ts b/lib/modules/platform/codecommit/codecommit-client.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc427ba0854b5cdc3ae12a9d2cc2ac1b2107825d
--- /dev/null
+++ b/lib/modules/platform/codecommit/codecommit-client.ts
@@ -0,0 +1,342 @@
+import {
+  CodeCommitClient,
+  CreatePullRequestApprovalRuleCommand,
+  CreatePullRequestApprovalRuleInput,
+  CreatePullRequestApprovalRuleOutput,
+  CreatePullRequestCommand,
+  CreatePullRequestInput,
+  CreatePullRequestOutput,
+  DeleteCommentContentCommand,
+  DeleteCommentContentInput,
+  DeleteCommentContentOutput,
+  DescribePullRequestEventsCommand,
+  DescribePullRequestEventsInput,
+  DescribePullRequestEventsOutput,
+  GetCommentsForPullRequestCommand,
+  GetCommentsForPullRequestInput,
+  GetCommentsForPullRequestOutput,
+  GetFileCommand,
+  GetFileInput,
+  GetFileOutput,
+  GetPullRequestCommand,
+  GetPullRequestInput,
+  GetPullRequestOutput,
+  GetRepositoryCommand,
+  GetRepositoryInput,
+  GetRepositoryOutput,
+  ListPullRequestsCommand,
+  ListPullRequestsInput,
+  ListPullRequestsOutput,
+  ListRepositoriesCommand,
+  ListRepositoriesInput,
+  ListRepositoriesOutput,
+  // MergeBranchesByFastForwardCommand,
+  // MergeBranchesByFastForwardInput,
+  // MergeBranchesByFastForwardOutput,
+  // MergeBranchesBySquashCommand,
+  // MergeBranchesBySquashInput,
+  // MergeBranchesBySquashOutput,
+  PostCommentForPullRequestCommand,
+  PostCommentForPullRequestInput,
+  PostCommentForPullRequestOutput,
+  PullRequestEventType,
+  PullRequestStatusEnum,
+  UpdateCommentCommand,
+  UpdateCommentInput,
+  UpdateCommentOutput,
+  UpdatePullRequestDescriptionCommand,
+  UpdatePullRequestDescriptionInput,
+  UpdatePullRequestDescriptionOutput,
+  UpdatePullRequestStatusCommand,
+  UpdatePullRequestStatusInput,
+  UpdatePullRequestStatusOutput,
+  UpdatePullRequestTitleCommand,
+  UpdatePullRequestTitleInput,
+  UpdatePullRequestTitleOutput,
+} from '@aws-sdk/client-codecommit';
+import type { Credentials } from '@aws-sdk/types';
+import is from '@sindresorhus/is';
+import * as aws4 from 'aws4';
+import { REPOSITORY_UNINITIATED } from '../../../constants/error-messages';
+import { logger } from '../../../logger';
+
+let codeCommitClient: CodeCommitClient;
+
+export function buildCodeCommitClient(
+  region: string,
+  credentials: Credentials
+): void {
+  if (!codeCommitClient) {
+    codeCommitClient = new CodeCommitClient({
+      region,
+      credentials,
+    });
+  }
+
+  // istanbul ignore if
+  if (!codeCommitClient) {
+    throw new Error('Failed to initialize codecommit client');
+  }
+}
+
+export async function deleteComment(
+  commentId: string
+): Promise<DeleteCommentContentOutput> {
+  const input: DeleteCommentContentInput = {
+    commentId,
+  };
+  const cmd = new DeleteCommentContentCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function getPrComments(
+  repositoryName: string,
+  pullRequestId: string
+): Promise<GetCommentsForPullRequestOutput> {
+  const input: GetCommentsForPullRequestInput = {
+    repositoryName,
+    pullRequestId,
+  };
+  const cmd = new GetCommentsForPullRequestCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function updateComment(
+  commentId: string,
+  content: string
+): Promise<UpdateCommentOutput> {
+  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<PostCommentForPullRequestOutput> {
+  const input: PostCommentForPullRequestInput = {
+    pullRequestId,
+    repositoryName,
+    content,
+    afterCommitId,
+    beforeCommitId,
+  };
+  const cmd = new PostCommentForPullRequestCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function getPrEvents(
+  pullRequestId: string
+): Promise<DescribePullRequestEventsOutput> {
+  const input: DescribePullRequestEventsInput = {
+    pullRequestId,
+    pullRequestEventType:
+      PullRequestEventType.PULL_REQUEST_SOURCE_REFERENCE_UPDATED,
+  };
+  const cmd = new DescribePullRequestEventsCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+// export async function fastForwardMerge(
+//   repositoryName: string,
+//   sourceCommitSpecifier: string,
+//   destinationReference: string
+// ): Promise<MergeBranchesByFastForwardOutput> {
+//   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<MergeBranchesBySquashOutput> {
+//   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.CLOSED | PullRequestStatusEnum.OPEN
+): Promise<UpdatePullRequestStatusOutput> {
+  const input: UpdatePullRequestStatusInput = {
+    pullRequestId,
+    pullRequestStatus,
+  };
+  const cmd = new UpdatePullRequestStatusCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function updatePrTitle(
+  prNo: string,
+  title: string
+): Promise<UpdatePullRequestTitleOutput> {
+  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<UpdatePullRequestDescriptionOutput> {
+  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<CreatePullRequestOutput> {
+  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<GetFileOutput> {
+  const input: GetFileInput = {
+    repositoryName,
+    filePath,
+    commitSpecifier,
+  };
+  const cmd: GetFileCommand = new GetFileCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function listPullRequests(
+  repositoryName: string,
+  authorArn: string
+): Promise<ListPullRequestsOutput> {
+  const input: ListPullRequestsInput = {
+    repositoryName,
+    authorArn,
+    pullRequestStatus: PullRequestStatusEnum.OPEN,
+  };
+  const cmd = new ListPullRequestsCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function getRepositoryInfo(
+  repository: string
+): Promise<GetRepositoryOutput> {
+  const input: GetRepositoryInput = {
+    repositoryName: `${repository}`,
+  };
+  const cmd = new GetRepositoryCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function getPr(
+  pullRequestId: string
+): Promise<GetPullRequestOutput | undefined> {
+  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<ListRepositoriesOutput> {
+  const input: ListRepositoriesInput = {};
+  const cmd = new ListRepositoriesCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export async function createPrApprovalRule(
+  pullRequestId: string,
+  approvalRuleContent: string
+): Promise<CreatePullRequestApprovalRuleOutput> {
+  const input: CreatePullRequestApprovalRuleInput = {
+    approvalRuleContent,
+    approvalRuleName: 'Reviewers By Renovate',
+    pullRequestId,
+  };
+  const cmd = new CreatePullRequestApprovalRuleCommand(input);
+  return await codeCommitClient.send(cmd);
+}
+
+export function getCodeCommitUrl(
+  region: string,
+  repoName: string,
+  credentials: Credentials
+): string {
+  const signer = new aws4.RequestSigner(
+    {
+      service: 'codecommit',
+      host: `git-codecommit.${region}.amazonaws.com`,
+      method: 'GIT',
+      path: `v1/repos/${repoName}`,
+    },
+    credentials
+  );
+  const dateTime = signer.getDateTime();
+
+  /* istanbul ignore if */
+  if (!is.string(dateTime)) {
+    throw new Error(REPOSITORY_UNINITIATED);
+  }
+
+  const accessKeyId = credentials.accessKeyId;
+  const token = `${dateTime}Z${signer.signature()}`;
+
+  let username = `${accessKeyId}${
+    credentials.sessionToken ? `%${credentials.sessionToken}` : ''
+  }`;
+
+  // massaging username with the session token,
+  // istanbul ignore if
+  if (username.includes('/')) {
+    username = username.replace(/\//g, '%2F');
+  }
+  return `https://${username}:${token}@git-codecommit.${region}.amazonaws.com/v1/repos/${repoName}`;
+}
diff --git a/lib/modules/platform/codecommit/iam-client.spec.ts b/lib/modules/platform/codecommit/iam-client.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b4782852fc97e5c8a23c3c18521579098eea4765
--- /dev/null
+++ b/lib/modules/platform/codecommit/iam-client.spec.ts
@@ -0,0 +1,43 @@
+import { GetUserCommand, IAMClient } from '@aws-sdk/client-iam';
+import { mockClient } from 'aws-sdk-client-mock';
+import { PLATFORM_BAD_CREDENTIALS } from '../../../constants/error-messages';
+import * as iam from './iam-client';
+
+describe('modules/platform/codecommit/iam-client', () => {
+  const iamClient = mockClient(IAMClient);
+  iam.initIamClient('eu-east', {
+    accessKeyId: 'aaa',
+    secretAccessKey: 'bbb',
+  });
+
+  it('should return empty', async () => {
+    iamClient.on(GetUserCommand).resolves({});
+    await expect(iam.getUserArn()).resolves.toMatch('');
+  });
+
+  it('should return the user normally', async () => {
+    iamClient.on(GetUserCommand).resolves({
+      User: {
+        Arn: 'aws:arn:example:123456',
+        UserName: 'someone',
+        UserId: 'something',
+        Path: 'somewhere',
+        CreateDate: new Date(),
+      },
+    });
+    await expect(iam.getUserArn()).resolves.toMatch('aws:arn:example:123456');
+  });
+
+  it('should throw in case of bad authentication', async () => {
+    const err = new Error(PLATFORM_BAD_CREDENTIALS);
+    iamClient.on(GetUserCommand).rejects(err);
+    await expect(iam.getUserArn()).rejects.toThrow(err);
+  });
+
+  it('should return the user arn, even though user has no permission', async () => {
+    iamClient
+      .on(GetUserCommand)
+      .rejects(new Error('User: aws:arn:example:123456 has no permissions'));
+    await expect(iam.getUserArn()).resolves.toMatch('aws:arn:example:123456');
+  });
+});
diff --git a/lib/modules/platform/codecommit/iam-client.ts b/lib/modules/platform/codecommit/iam-client.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f52811006c13ab96eae579c79205d39a56a11173
--- /dev/null
+++ b/lib/modules/platform/codecommit/iam-client.ts
@@ -0,0 +1,52 @@
+import {
+  GetUserCommand,
+  GetUserCommandOutput,
+  IAMClient,
+} from '@aws-sdk/client-iam';
+import type { Credentials } from '@aws-sdk/types';
+import { logger } from '../../../logger';
+import { regEx } from '../../../util/regex';
+
+let iam: IAMClient;
+
+export function initIamClient(region: string, credentials: Credentials): void {
+  if (!iam) {
+    iam = new IAMClient({
+      region,
+      credentials,
+    });
+  }
+}
+
+const userRe = regEx(/User:\s*(?<arn>[^ ]+).*/);
+
+/**
+ * This method will throw an exception only in case we have no connection
+ * 1) there is a connection and we return user.arn.
+ * 2) there is a connection but no permission for the current user, we still get his user arn in the error message
+ * 3) there is a problem in the connection to the aws api, then throw an error with the err
+ */
+export async function getUserArn(): Promise<string> {
+  const cmd = new GetUserCommand({});
+  let res;
+  try {
+    const userRes: GetUserCommandOutput = await iam.send(cmd);
+    res = userRes?.User?.Arn;
+  } catch (err) {
+    const match = userRe.exec(err.message);
+    if (match) {
+      logger.warn(
+        'It is recommended to add "IAMReadOnlyAccess" policy to this IAM user'
+      );
+      res = match.groups?.arn;
+    }
+    if (!res) {
+      logger.warn(
+        'Failed to get IAM user info, Make sure your user has "IAMReadOnlyAccess" policy'
+      );
+      throw err;
+    }
+  }
+
+  return res ?? '';
+}
diff --git a/lib/modules/platform/codecommit/index.md b/lib/modules/platform/codecommit/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..8df6f9d61151f04842432b498996a9b196a79cbd
--- /dev/null
+++ b/lib/modules/platform/codecommit/index.md
@@ -0,0 +1,65 @@
+# AWS CodeCommit
+
+<!-- prettier-ignore -->
+!!! warning "This feature is flagged as experimental"
+    Experimental features might be changed or even removed at any time, To track this feature visit the following GitHub issue [#2868](https://github.com/renovatebot/renovate/issues/2868)
+
+## Authentication
+
+First, you need to obtain an AWS [IAM Access Key id and a Secret access key id](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)
+
+Let Renovate use AWS CodeCommit access keys by doing one of the following:
+
+1. Set a Renovate configuration file - config.js and set:
+
+   - `endpoint:` the url endpoint e.g `https://git-codecommit.us-east-1.amazonaws.com/`
+   - `username:` AWS IAM access key id
+   - `password:` AWS Secret access key
+
+2. Set environment variables:
+   - `AWS_REGION:` the region e.g `us-east-1`
+   - `AWS_ACCESS_KEY_ID:` your IAM Access key id
+   - `AWS_SECRET_ACCESS_KEY:` your IAM Secret access key id
+
+---
+
+- `AWS_SESSION_TOKEN`: your AWS Session token if you have one
+
+## AWS IAM security policies
+
+- Make sure to attach the [AWSCodeCommitFullAccess](https://docs.aws.amazon.com/codecommit/latest/userguide/security-iam-awsmanpol.html#managed-policies-full) policy to your IAM User.
+- It is recommended to also attach the [IAMReadOnlyAccess](https://docs.aws.amazon.com/IAM/latest/UserGuide/security-iam-awsmanpol.html) policy to your IAM User
+
+## Running Renovate
+
+Set up a global configuration file (config.js) for running Renovate on CodeCommit:
+
+- Set `platform: 'codecommit'`
+- Set `repositories: ['{repository names separated by comma}']`, or alternatively use Renovate’s [autodiscover](https://docs.renovatebot.com/self-hosted-configuration/#autodiscover)
+
+Run Renovate with the configuration file, and it will create an onboarding Pull Request in your set repositories.
+
+## Unsupported platform features/concepts
+
+- adding assignees to PRs not supported
+- auto-merge not supported
+- rebaseLabel isn't supported (request a rebase for Renovate)
+
+## recommendations
+
+- We recommend limiting Open Renovate PRs using `prConcurrentLimit`
+- Due to current platform limitations, if you close a PR and don’t wish for Renovate to recreate if, use [package rules](https://docs.renovatebot.com/configuration-options/#packagerules) with the `"enabled": false` key.
+
+Here's an example config.js:
+
+```js
+module.exports = {
+  endpoint: 'https://git-codecommit.us-east-1.amazonaws.com/',
+  platform: 'codecommit',
+  repositories: ['abc/def', 'abc/ghi'],
+  username: 'ACCESS_KEY_ID_GOES_HERE',
+  password: 'SECRET_ACCESS_KEY_GOES_HERE',
+  gitAuthor: 'your_email@domain',
+  prConcurrentLimit: 10,
+};
+```
diff --git a/lib/modules/platform/codecommit/index.spec.ts b/lib/modules/platform/codecommit/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2eb1aa31cb74f84dac825a68696241c36786ad3a
--- /dev/null
+++ b/lib/modules/platform/codecommit/index.spec.ts
@@ -0,0 +1,1301 @@
+import {
+  CodeCommitClient,
+  CreatePullRequestApprovalRuleCommand,
+  CreatePullRequestCommand,
+  DeleteCommentContentCommand,
+  DescribePullRequestEventsCommand,
+  GetCommentsForPullRequestCommand,
+  GetFileCommand,
+  GetPullRequestCommand,
+  GetRepositoryCommand,
+  ListPullRequestsCommand,
+  ListRepositoriesCommand,
+  // MergeBranchesBySquashCommand,
+  PostCommentForPullRequestCommand,
+  UpdatePullRequestDescriptionCommand,
+  UpdatePullRequestStatusCommand,
+  UpdatePullRequestTitleCommand,
+} from '@aws-sdk/client-codecommit';
+import { GetUserCommand, IAMClient } from '@aws-sdk/client-iam';
+import { mockClient } from 'aws-sdk-client-mock';
+import { logger } from '../../../../test/util';
+import {
+  PLATFORM_BAD_CREDENTIALS,
+  REPOSITORY_EMPTY,
+  REPOSITORY_NOT_FOUND,
+} from '../../../constants/error-messages';
+import { PrState } from '../../../types';
+import * as git from '../../../util/git';
+import type { Platform } from '../types';
+import { CodeCommitPr, config } from './index';
+
+const codeCommitClient = mockClient(CodeCommitClient);
+const iamClient = mockClient(IAMClient);
+
+describe('modules/platform/codecommit/index', () => {
+  let codeCommit: Platform;
+
+  beforeAll(async () => {
+    codeCommit = await import('.');
+    iamClient.on(GetUserCommand).resolves({
+      User: {
+        Arn: 'aws:arn:example:123456',
+        UserName: 'someone',
+        UserId: 'something',
+        Path: 'somewhere',
+        CreateDate: new Date(),
+      },
+    });
+    await codeCommit.initPlatform({
+      endpoint: 'https://git-codecommit.eu-central-1.amazonaws.com/',
+      username: 'accessKeyId',
+      password: 'SecretAccessKey',
+    });
+  });
+
+  beforeEach(() => {
+    codeCommitClient.reset();
+    config.prList = undefined;
+    config.repository = undefined;
+  });
+
+  it('validates massageMarkdown functionality', () => {
+    const newStr = codeCommit.massageMarkdown(
+      '<details><summary>foo</summary>bar</details>text<details>\n<!--renovate-debug:hiddenmessage123-->'
+    );
+    expect(newStr).toBe(
+      '**foo**bartext\n[//]: # (<!--renovate-debug:hiddenmessage123-->)'
+    );
+  });
+
+  describe('initPlatform()', () => {
+    it('should throw if no username/password', async () => {
+      const err = new Error(
+        'Init: You must configure a AWS user(accessKeyId), password(secretAccessKey) and endpoint/AWS_REGION'
+      );
+      await expect(codeCommit.initPlatform({})).rejects.toThrow(err);
+    });
+
+    it('should show warning message if custom endpoint', async () => {
+      const err = new Error(
+        'Init: You must configure a AWS user(accessKeyId), password(secretAccessKey) and endpoint/AWS_REGION'
+      );
+      await expect(
+        codeCommit.initPlatform({
+          endpoint: 'endpoint',
+          username: 'abc',
+          password: '123',
+        })
+      ).rejects.toThrow(err);
+
+      expect(logger.logger.warn).toHaveBeenCalledWith(
+        "Can't parse region, make sure your endpoint is correct"
+      );
+    });
+
+    it('should init', async () => {
+      expect(
+        await codeCommit.initPlatform({
+          endpoint: 'https://git-codecommit.REGION.amazonaws.com/',
+          username: 'abc',
+          password: '123',
+        })
+      ).toEqual({
+        endpoint: 'https://git-codecommit.REGION.amazonaws.com/',
+      });
+    });
+
+    it('should init with env vars', async () => {
+      const temp = process.env.AWS_REGION;
+      process.env.AWS_REGION = 'REGION';
+      await expect(
+        codeCommit.initPlatform({
+          username: 'abc',
+          password: '123',
+        })
+      ).resolves.toEqual({
+        endpoint: 'https://git-codecommit.REGION.amazonaws.com/',
+      });
+      process.env.AWS_REGION = temp;
+    });
+  });
+
+  describe('initRepos()', () => {
+    it('fails to git.initRepo', async () => {
+      jest.spyOn(git, 'initRepo').mockImplementationOnce(() => {
+        throw new Error('any error');
+      });
+      codeCommitClient.on(GetRepositoryCommand).resolvesOnce({});
+
+      await expect(
+        codeCommit.initRepo({ repository: 'repositoryName' })
+      ).rejects.toThrow(new Error(PLATFORM_BAD_CREDENTIALS));
+    });
+
+    it('fails on getRepositoryInfo', async () => {
+      jest.spyOn(git, 'initRepo').mockReturnValueOnce(Promise.resolve());
+      codeCommitClient
+        .on(GetRepositoryCommand)
+        .rejectsOnce(new Error('Could not find repository'));
+      await expect(
+        codeCommit.initRepo({ repository: 'repositoryName' })
+      ).rejects.toThrow(new Error(REPOSITORY_NOT_FOUND));
+    });
+
+    it('getRepositoryInfo returns bad results', async () => {
+      jest.spyOn(git, 'initRepo').mockReturnValueOnce(Promise.resolve());
+      codeCommitClient.on(GetRepositoryCommand).resolvesOnce({});
+      await expect(
+        codeCommit.initRepo({ repository: 'repositoryName' })
+      ).rejects.toThrow(new Error(REPOSITORY_NOT_FOUND));
+    });
+
+    it('getRepositoryInfo returns bad results 2', async () => {
+      jest.spyOn(git, 'initRepo').mockReturnValueOnce(Promise.resolve());
+      codeCommitClient
+        .on(GetRepositoryCommand)
+        .resolvesOnce({ repositoryMetadata: {} });
+      await expect(
+        codeCommit.initRepo({ repository: 'repositoryName' })
+      ).rejects.toThrow(new Error(REPOSITORY_EMPTY));
+    });
+
+    it('initiates repo successfully', async () => {
+      jest.spyOn(git, 'initRepo').mockReturnValueOnce(Promise.resolve());
+      codeCommitClient.on(GetRepositoryCommand).resolvesOnce({
+        repositoryMetadata: {
+          defaultBranch: 'main',
+          repositoryId: 'id',
+        },
+      });
+      await expect(
+        codeCommit.initRepo({ repository: 'repositoryName' })
+      ).resolves.toEqual({
+        repoFingerprint:
+          'f0bcfd81abefcdf9ae5e5de58d1a868317503ea76422309bc212d1ef25a1e67789d0bfa752a7e2abd4510f4f3e4f60cdaf6202a42883fb97bb7110ab3600785e',
+        defaultBranch: 'main',
+        isFork: false,
+      });
+    });
+  });
+
+  describe('getRepos()', () => {
+    it('returns repos', async () => {
+      const result = {
+        repositories: [
+          {
+            repositoryId: 'id',
+            repositoryName: 'repoName',
+          },
+        ],
+      };
+      codeCommitClient.on(ListRepositoriesCommand).resolvesOnce(result);
+
+      const res = await codeCommit.getRepos();
+      expect(res).toEqual(['repoName']);
+    });
+
+    it('returns empty if error', async () => {
+      codeCommitClient
+        .on(ListRepositoriesCommand)
+        .rejectsOnce(new Error('something'));
+      const res = await codeCommit.getRepos();
+      expect(res).toEqual([]);
+    });
+  });
+
+  describe('getRepoForceRebase()', () => {
+    it('Always return false, since CodeCommit does not support force rebase', async () => {
+      const actual = await codeCommit.getRepoForceRebase();
+      expect(actual).toBeFalse();
+    });
+  });
+
+  describe('getPrList()', () => {
+    it('gets PR list by author', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1', '2'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce({});
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.getPrList();
+      expect(res).toMatchObject([
+        {
+          sourceBranch: 'refs/heads/sourceBranch',
+          targetBranch: 'refs/heads/targetBranch',
+          state: 'open',
+          number: 1,
+          title: 'someTitle',
+        },
+      ]);
+      codeCommitClient
+        .on(GetPullRequestCommand)
+        .rejectsOnce(new Error('failed connection'));
+      // test cache
+      const res2 = await codeCommit.getPrList();
+      expect(res2).toMatchObject([
+        {
+          sourceBranch: 'refs/heads/sourceBranch',
+          targetBranch: 'refs/heads/targetBranch',
+          state: 'open',
+          number: 1,
+          title: 'someTitle',
+        },
+      ]);
+    });
+
+    it('checks if nullcheck works for list prs', async () => {
+      codeCommitClient.on(ListPullRequestsCommand).resolvesOnce({});
+      const res = await codeCommit.getPrList();
+      expect(res).toEqual([]);
+    });
+  });
+
+  describe('findPr()', () => {
+    it('throws error on findPr', async () => {
+      const err = new Error('failed');
+      codeCommitClient.on(ListPullRequestsCommand).rejectsOnce(err);
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+        state: PrState.Open,
+      });
+      expect(res).toBeNull();
+      expect(logger.logger.error).toHaveBeenCalledWith({ err }, 'findPr error');
+    });
+
+    it('finds pr', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+        state: PrState.Open,
+      });
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'open',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('finds any pr with that title in regardless of state', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+        state: PrState.All,
+      });
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'open',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('finds closed/merged pr', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: PrState.NotOpen,
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+        state: PrState.NotOpen,
+      });
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'closed',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('finds any pr', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: PrState.Closed,
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+      });
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'closed',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('returns empty list in case prs dont exist yet', async () => {
+      const res = await codeCommit.findPr({
+        branchName: 'sourceBranch',
+        prTitle: 'someTitle',
+        state: PrState.Open,
+      });
+      expect(res).toBeNull();
+    });
+  });
+
+  describe('getBranchPr()', () => {
+    it('codecommit find PR for branch', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolves(prRes);
+      const res = await codeCommit.getBranchPr('sourceBranch');
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'open',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('returns null if no PR for branch', async () => {
+      codeCommitClient
+        .on(ListPullRequestsCommand)
+        .resolvesOnce({ pullRequestIds: ['1'] });
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+      const res = await codeCommit.getBranchPr('branch_without_pr');
+      expect(res).toBeNull();
+    });
+  });
+
+  describe('getPr()', () => {
+    it('gets pr', async () => {
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          description: 'body',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+
+      const res = await codeCommit.getPr(1);
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'open',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('gets closed pr', async () => {
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'CLOSED',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+            },
+          ],
+        },
+      };
+
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+
+      const res = await codeCommit.getPr(1);
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'closed',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('gets merged pr', async () => {
+      const prRes = {
+        pullRequest: {
+          title: 'someTitle',
+          pullRequestStatus: 'OPEN',
+          pullRequestTargets: [
+            {
+              sourceReference: 'refs/heads/sourceBranch',
+              destinationReference: 'refs/heads/targetBranch',
+              mergeMetadata: {
+                isMerged: true,
+              },
+            },
+          ],
+        },
+      };
+
+      codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+
+      const res = await codeCommit.getPr(1);
+      expect(res).toMatchObject({
+        sourceBranch: 'refs/heads/sourceBranch',
+        targetBranch: 'refs/heads/targetBranch',
+        state: 'merged',
+        number: 1,
+        title: 'someTitle',
+      });
+    });
+
+    it('returns null in case input is null', async () => {
+      codeCommitClient
+        .on(GetPullRequestCommand)
+        .rejectsOnce(new Error('bad creds'));
+      const res = await codeCommit.getPr(1);
+      expect(res).toBeNull();
+    });
+  });
+
+  describe('getJsonFile()', () => {
+    it('returns file content', async () => {
+      const data = { foo: 'bar' };
+      const uint8arrData = new Uint8Array(Buffer.from(JSON.stringify(data)));
+      codeCommitClient
+        .on(GetFileCommand)
+        .resolvesOnce({ fileContent: uint8arrData });
+      const res = await codeCommit.getJsonFile('file.json');
+      expect(res).toEqual(data);
+    });
+
+    it('returns file content in json5 format', async () => {
+      const json5Data = `
+        {
+          // json5 comment
+          foo: 'bar'
+        }
+      `;
+      const uint8arrData = new Uint8Array(Buffer.from(json5Data));
+      codeCommitClient
+        .on(GetFileCommand)
+        .resolvesOnce({ fileContent: uint8arrData });
+      const res = await codeCommit.getJsonFile('file.json');
+      expect(res).toEqual({ foo: 'bar' });
+    });
+  });
+
+  describe('getRawFile()', () => {
+    it('returns file content', async () => {
+      const data = { foo: 'bar' };
+      const uint8arrData = new Uint8Array(Buffer.from(JSON.stringify(data)));
+      codeCommitClient
+        .on(GetFileCommand)
+        .resolvesOnce({ fileContent: uint8arrData });
+      const res = await codeCommit.getRawFile('file.json');
+      expect(res).toBe('{"foo":"bar"}');
+    });
+
+    it('returns null', async () => {
+      codeCommitClient
+        .on(GetFileCommand)
+        .resolvesOnce({ fileContent: undefined });
+      const res = await codeCommit.getRawFile('file.json');
+      expect(res).toBeNull();
+    });
+
+    it('returns file content in json5 format', async () => {
+      const json5Data = `
+        {
+          // json5 comment
+          foo: 'bar'
+        }
+      `;
+      const uint8arrData = new Uint8Array(Buffer.from(json5Data));
+      codeCommitClient
+        .on(GetFileCommand)
+        .resolvesOnce({ fileContent: uint8arrData });
+      const res = await codeCommit.getRawFile('file.json');
+      expect(res).toBe(`
+        {
+          // json5 comment
+          foo: 'bar'
+        }
+      `);
+    });
+  });
+
+  describe('createPr()', () => {
+    it('posts PR', async () => {
+      const prRes = {
+        pullRequest: {
+          pullRequestId: '1',
+          pullRequestStatus: 'OPEN',
+          title: 'someTitle',
+          description: 'mybody',
+        },
+      };
+
+      codeCommitClient.on(CreatePullRequestCommand).resolvesOnce(prRes);
+      const pr = await codeCommit.createPr({
+        sourceBranch: 'sourceBranch',
+        targetBranch: 'targetBranch',
+        prTitle: 'mytitle',
+        prBody: 'mybody',
+      });
+
+      expect(pr).toMatchObject({
+        number: 1,
+        state: 'open',
+        title: 'someTitle',
+        sourceBranch: 'sourceBranch',
+        targetBranch: 'targetBranch',
+        sourceRepo: undefined,
+        body: 'mybody',
+      });
+    });
+
+    it('doesnt return a title', async () => {
+      const prRes = {
+        pullRequest: {
+          pullRequestId: '1',
+          pullRequestStatus: 'OPEN',
+        },
+      };
+
+      codeCommitClient.on(CreatePullRequestCommand).resolvesOnce(prRes);
+
+      await expect(
+        codeCommit.createPr({
+          sourceBranch: 'sourceBranch',
+          targetBranch: 'targetBranch',
+          prTitle: 'mytitle',
+          prBody: 'mybody',
+        })
+      ).rejects.toThrow(new Error('Could not create pr, missing PR info'));
+    });
+  });
+
+  describe('updatePr()', () => {
+    it('updates PR', async () => {
+      codeCommitClient.on(UpdatePullRequestDescriptionCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestTitleCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestStatusCommand).resolvesOnce({});
+      await expect(
+        codeCommit.updatePr({
+          number: 1,
+          prTitle: 'title',
+          prBody: 'body',
+          state: PrState.Open,
+        })
+      ).toResolve();
+    });
+
+    it('updates PR body if cache is not the same', async () => {
+      config.prList = [];
+      const pr: CodeCommitPr = {
+        number: 1,
+        state: 'open',
+        title: 'someTitle',
+        sourceBranch: 'sourceBranch',
+        targetBranch: 'targetBranch',
+        sourceRepo: undefined,
+        body: 'some old description',
+      };
+      config.prList.push(pr);
+      codeCommitClient.on(UpdatePullRequestDescriptionCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestTitleCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestStatusCommand).resolvesOnce({});
+      await expect(
+        codeCommit.updatePr({
+          number: 1,
+          prTitle: 'title',
+          prBody: 'new description',
+          state: PrState.Open,
+        })
+      ).toResolve();
+    });
+
+    it('updates PR body does not update if cache is the same', async () => {
+      config.prList = [];
+      const pr: CodeCommitPr = {
+        number: 1,
+        state: 'open',
+        title: 'someTitle',
+        sourceBranch: 'sourceBranch',
+        targetBranch: 'targetBranch',
+        sourceRepo: undefined,
+        body: 'new description',
+      };
+      config.prList.push(pr);
+      codeCommitClient.on(UpdatePullRequestTitleCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestStatusCommand).resolvesOnce({});
+      await expect(
+        codeCommit.updatePr({
+          number: 1,
+          prTitle: 'title',
+          prBody: 'new description',
+          state: PrState.Open,
+        })
+      ).toResolve();
+    });
+
+    it('updates PR regardless of status failure', async () => {
+      codeCommitClient.on(UpdatePullRequestDescriptionCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestTitleCommand).resolvesOnce({});
+      codeCommitClient
+        .on(UpdatePullRequestStatusCommand)
+        .rejectsOnce(new Error('update status failure'));
+      await expect(
+        codeCommit.updatePr({
+          number: 1,
+          prTitle: 'title',
+          prBody: 'body',
+          state: PrState.Open,
+        })
+      ).toResolve();
+    });
+
+    it('updates PR with status closed', async () => {
+      codeCommitClient.on(UpdatePullRequestDescriptionCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestTitleCommand).resolvesOnce({});
+      codeCommitClient.on(UpdatePullRequestStatusCommand).resolvesOnce({});
+      await expect(
+        codeCommit.updatePr({
+          number: 1,
+          prTitle: 'title',
+          prBody: 'body',
+          state: PrState.Closed,
+        })
+      ).toResolve();
+    });
+  });
+
+  // eslint-disable-next-line jest/no-commented-out-tests
+  // describe('mergePr()', () => {
+  // eslint-disable-next-line jest/no-commented-out-tests
+  //   it('checks that rebase is not supported', async () => {
+  //     expect(
+  //       await codeCommit.mergePr({
+  //         branchName: 'branch',
+  //         id: 1,
+  //         strategy: 'rebase',
+  //       })
+  //     ).toBeFalse();
+  //   });
+
+  // eslint-disable-next-line jest/no-commented-out-tests
+  //   it('posts Merge with auto', async () => {
+  //     const prRes = {
+  //       pullRequest: {
+  //         title: 'someTitle',
+  //         pullRequestStatus: 'OPEN',
+  //         pullRequestTargets: [
+  //           {
+  //             sourceReference: 'refs/heads/sourceBranch',
+  //             destinationReference: 'refs/heads/targetBranch',
+  //           },
+  //         ],
+  //       },
+  //     };
+  //     codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+  //     codeCommitClient.on(MergeBranchesBySquashCommand).resolvesOnce({});
+  //
+  //     const updateStatusRes = {
+  //       pullRequest: {
+  //         pullRequestStatus: 'OPEN',
+  //       },
+  //     };
+  //     codeCommitClient
+  //       .on(UpdatePullRequestStatusCommand)
+  //       .resolvesOnce(updateStatusRes);
+  //     expect(
+  //       await codeCommit.mergePr({
+  //         branchName: 'branch',
+  //         id: 1,
+  //         strategy: 'auto',
+  //       })
+  //     ).toBeTrue();
+  //   });
+  //
+  // eslint-disable-next-line jest/no-commented-out-tests
+  //   it('posts Merge with squash', async () => {
+  //     const prRes = {
+  //       pullRequest: {
+  //         title: 'someTitle',
+  //         pullRequestStatus: 'OPEN',
+  //         pullRequestTargets: [
+  //           {
+  //             sourceReference: 'refs/heads/sourceBranch',
+  //             destinationReference: 'refs/heads/targetBranch',
+  //           },
+  //         ],
+  //       },
+  //     };
+  //     codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+  //     codeCommitClient.on(MergeBranchesBySquashCommand).resolvesOnce({});
+  //     const updateStatusRes = {
+  //       pullRequest: {
+  //         pullRequestStatus: 'OPEN',
+  //       },
+  //     };
+  //     codeCommitClient
+  //       .on(UpdatePullRequestStatusCommand)
+  //       .resolvesOnce(updateStatusRes);
+  //     expect(
+  //       await codeCommit.mergePr({
+  //         branchName: 'branch',
+  //         id: 5,
+  //         strategy: 'squash',
+  //       })
+  //     ).toBeTrue();
+  //   });
+
+  // eslint-disable-next-line jest/no-commented-out-tests
+  //   it('posts Merge with fast-forward', async () => {
+  //     const prRes = {
+  //       pullRequest: {
+  //         title: 'someTitle',
+  //         pullRequestStatus: 'OPEN',
+  //         pullRequestTargets: [
+  //           {
+  //             sourceReference: 'refs/heads/sourceBranch',
+  //             destinationReference: 'refs/heads/targetBranch',
+  //           },
+  //         ],
+  //       },
+  //     };
+  //     codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+  //     codeCommitClient.on(MergeBranchesBySquashCommand).resolvesOnce({});
+  //     const updateStatusRes = {
+  //       pullRequest: {
+  //         pullRequestStatus: 'OPEN',
+  //       },
+  //     };
+  //     codeCommitClient
+  //       .on(UpdatePullRequestStatusCommand)
+  //       .resolvesOnce(updateStatusRes);
+  //     expect(
+  //       await codeCommit.mergePr({
+  //         branchName: 'branch',
+  //         id: 1,
+  //         strategy: 'fast-forward',
+  //       })
+  //     ).toBe(true);
+  //   });
+
+  // eslint-disable-next-line jest/no-commented-out-tests
+  //   it('checks that merge-commit is not supported', async () => {
+  //     const prRes = {
+  //       pullRequest: {
+  //         title: 'someTitle',
+  //         pullRequestStatus: 'OPEN',
+  //         pullRequestTargets: [
+  //           {
+  //             sourceReference: 'refs/heads/sourceBranch',
+  //             destinationReference: 'refs/heads/targetBranch',
+  //           },
+  //         ],
+  //       },
+  //     };
+  //     codeCommitClient.on(GetPullRequestCommand).resolvesOnce(prRes);
+  //     expect(
+  //       await codeCommit.mergePr({
+  //         branchName: 'branch',
+  //         id: 1,
+  //         strategy: 'merge-commit',
+  //       })
+  //     ).toBeFalse();
+  //   });
+  // });
+
+  describe('ensureComment', () => {
+    it('adds comment if missing', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: 'my comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+
+      const eventsRes = {
+        pullRequestEvents: [
+          {
+            pullRequestSourceReferenceUpdatedEventMetadata: {
+              beforeCommitId: 'beforeCid',
+              afterCommitId: 'afterCid',
+            },
+          },
+        ],
+      };
+      codeCommitClient
+        .on(DescribePullRequestEventsCommand)
+        .resolvesOnce(eventsRes);
+      codeCommitClient.on(PostCommentForPullRequestCommand).resolvesOnce({});
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: 'some-subject',
+        content: 'some\ncontent',
+      });
+      expect(res).toBeTrue();
+      expect(logger.logger.info).toHaveBeenCalledWith(
+        { repository: undefined, prNo: 42, topic: 'some-subject' },
+        'Comment added'
+      );
+    });
+
+    it('updates comment if different content', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: '### some-subject\n\n - my comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      codeCommitClient.on(PostCommentForPullRequestCommand).resolvesOnce({});
+
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: 'some-subject',
+        content: 'some\ncontent',
+      });
+      expect(res).toBeTrue();
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        { repository: undefined, prNo: 42, topic: 'some-subject' },
+        'Comment updated'
+      );
+    });
+
+    it('does nothing if comment exists and is the same', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: '### some-subject\n\nmy comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: 'some-subject',
+        content: 'my comment content',
+      });
+      expect(res).toBeTrue();
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        { repository: undefined, prNo: 42, topic: 'some-subject' },
+        'Comment is already update-to-date'
+      );
+    });
+
+    it('does nothing if comment exists and is the same when there is no topic', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: 'my comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+      expect(res).toBeTrue();
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        { repository: undefined, prNo: 42, topic: null },
+        'Comment is already update-to-date'
+      );
+    });
+
+    it('throws an exception in case of api failed connection ', async () => {
+      const err = new Error('some error');
+      codeCommitClient.on(GetCommentsForPullRequestCommand).rejectsOnce(err);
+
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+      expect(res).toBeFalse();
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        { err },
+        'Unable to retrieve pr comments'
+      );
+    });
+
+    it('fails at null check for response', async () => {
+      codeCommitClient.on(GetCommentsForPullRequestCommand).resolvesOnce({});
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+      expect(res).toBeFalse();
+    });
+
+    it('doesnt find comments obj', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+      expect(res).toBeFalse();
+    });
+
+    it('doesnt find events data', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      codeCommitClient.on(DescribePullRequestEventsCommand).resolvesOnce({});
+      codeCommitClient.on(PostCommentForPullRequestCommand).resolvesOnce({});
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+
+      expect(res).toBeFalse();
+    });
+
+    it('doesnt find event before/after', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      const eventsRes = {
+        pullRequestEvents: [
+          {
+            pullRequestSourceReferenceUpdatedEventMetadata: {},
+          },
+        ],
+      };
+      codeCommitClient
+        .on(DescribePullRequestEventsCommand)
+        .resolvesOnce(eventsRes);
+      codeCommitClient.on(PostCommentForPullRequestCommand).resolvesOnce({});
+      const res = await codeCommit.ensureComment({
+        number: 42,
+        topic: null,
+        content: 'my comment content',
+      });
+
+      expect(res).toBeFalse();
+    });
+  });
+
+  describe('ensureCommentRemoval', () => {
+    it('deletes comment by topic if found', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: '### some-subject\n\nmy comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      codeCommitClient.on(DeleteCommentContentCommand).resolvesOnce({});
+      await codeCommit.ensureCommentRemoval({
+        type: 'by-topic',
+        number: 42,
+        topic: 'some-subject',
+      });
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'comment "some-subject" in PR #42 was removed'
+      );
+    });
+
+    it('doesnt find commentsForPullRequestData', async () => {
+      codeCommitClient.on(GetCommentsForPullRequestCommand).resolvesOnce({});
+      codeCommitClient.on(DeleteCommentContentCommand).resolvesOnce({});
+      await codeCommit.ensureCommentRemoval({
+        type: 'by-topic',
+        number: 42,
+        topic: 'some-subject',
+      });
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'commentsForPullRequestData not found'
+      );
+    });
+
+    it('doesnt find comment obj', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      codeCommitClient.on(DeleteCommentContentCommand).resolvesOnce({});
+      await codeCommit.ensureCommentRemoval({
+        type: 'by-topic',
+        number: 42,
+        topic: 'some-subject',
+      });
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'comments object not found under commentsForPullRequestData'
+      );
+    });
+
+    it('deletes comment by content if found', async () => {
+      const commentsRes = {
+        commentsForPullRequestData: [
+          {
+            pullRequestId: '1',
+            repositoryName: 'someRepo',
+            beforeCommitId: 'beforeCommitId',
+            afterCommitId: 'afterCommitId',
+            comments: [
+              {
+                commentId: '1',
+                content: 'my comment content',
+              },
+            ],
+          },
+        ],
+      };
+      codeCommitClient
+        .on(GetCommentsForPullRequestCommand)
+        .resolvesOnce(commentsRes);
+      codeCommitClient.on(DeleteCommentContentCommand).resolvesOnce({});
+      await codeCommit.ensureCommentRemoval({
+        type: 'by-content',
+        number: 42,
+        content: 'my comment content',
+      });
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        'comment "my comment content" in PR #42 was removed'
+      );
+    });
+
+    it('throws exception in case failed api connection', async () => {
+      const err = new Error('some error');
+      codeCommitClient.on(GetCommentsForPullRequestCommand).rejectsOnce(err);
+      await codeCommit.ensureCommentRemoval({
+        type: 'by-content',
+        number: 42,
+        content: 'my comment content',
+      });
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        { err },
+        'Unable to retrieve pr comments'
+      );
+    });
+  });
+
+  describe('addReviewers', () => {
+    it('checks that the function resolves', async () => {
+      const res = {
+        approvalRule: {
+          approvalRuleName: 'Assignees By Renovate',
+          lastModifiedDate: new Date(),
+          ruleContentSha256: '7c44e6ebEXAMPLE',
+          creationDate: new Date(),
+          approvalRuleId: 'aac33506-EXAMPLE',
+          approvalRuleContent:
+            '{"Version": "2018-11-08","Statements": [{"Type": "Approvers","NumberOfApprovalsNeeded": 1,"ApprovalPoolMembers": ["arn:aws:iam::someUser:user/ReviewerUser"]}]}',
+          lastModifiedUser: 'arn:aws:iam::someUser:user/ReviewerUser',
+        },
+      };
+      codeCommitClient
+        .on(CreatePullRequestApprovalRuleCommand)
+        .resolvesOnce(res);
+      await expect(
+        codeCommit.addReviewers(13, ['arn:aws:iam::someUser:user/ReviewerUser'])
+      ).toResolve();
+      expect(logger.logger.debug).toHaveBeenCalledWith(
+        res,
+        'Approval Rule Added to PR #13:'
+      );
+    });
+  });
+});
diff --git a/lib/modules/platform/codecommit/index.ts b/lib/modules/platform/codecommit/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..82a82c14c0cff7e8e8090b7be2143b379699fa0e
--- /dev/null
+++ b/lib/modules/platform/codecommit/index.ts
@@ -0,0 +1,745 @@
+import { Buffer } from 'buffer';
+import {
+  GetCommentsForPullRequestOutput,
+  ListRepositoriesOutput,
+  PullRequestStatusEnum,
+} from '@aws-sdk/client-codecommit';
+import type { Credentials } from '@aws-sdk/types';
+import JSON5 from 'json5';
+
+import {
+  PLATFORM_BAD_CREDENTIALS,
+  REPOSITORY_EMPTY,
+  REPOSITORY_NOT_FOUND,
+} from '../../../constants/error-messages';
+import { logger } from '../../../logger';
+import { BranchStatus, PrState, VulnerabilityAlert } from '../../../types';
+import * as git from '../../../util/git';
+import { regEx } from '../../../util/regex';
+import { sanitize } from '../../../util/sanitize';
+import type {
+  BranchStatusConfig,
+  CreatePRConfig,
+  EnsureCommentConfig,
+  EnsureCommentRemovalConfig,
+  EnsureIssueConfig,
+  EnsureIssueResult,
+  FindPRConfig,
+  Issue,
+  MergePRConfig,
+  PlatformParams,
+  PlatformResult,
+  Pr,
+  RepoParams,
+  RepoResult,
+  UpdatePrConfig,
+} from '../types';
+import { getNewBranchName, repoFingerprint } from '../util';
+import { smartTruncate } from '../utils/pr-body';
+import { getCodeCommitUrl } from './codecommit-client';
+import * as client from './codecommit-client';
+import { getUserArn, initIamClient } from './iam-client';
+
+export interface CodeCommitPr extends Pr {
+  body: string;
+}
+
+interface Config {
+  repository?: string;
+  defaultBranch?: string;
+  region?: string;
+  prList?: CodeCommitPr[];
+  credentials?: Credentials;
+  userArn?: string;
+}
+
+export const config: Config = {};
+
+export async function initPlatform({
+  endpoint,
+  username,
+  password,
+}: PlatformParams): Promise<PlatformResult> {
+  let accessKeyId = username;
+  let secretAccessKey = password;
+  let region;
+
+  if (!accessKeyId) {
+    accessKeyId = process.env.AWS_ACCESS_KEY_ID;
+  }
+  if (!secretAccessKey) {
+    secretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
+  }
+  if (endpoint) {
+    const regionReg = regEx(/.*codecommit\.(?<region>.+)\.amazonaws\.com/);
+    const codeCommitMatch = regionReg.exec(endpoint);
+    region = codeCommitMatch?.groups?.region;
+    if (!region) {
+      logger.warn("Can't parse region, make sure your endpoint is correct");
+    }
+  } else {
+    region = process.env.AWS_REGION;
+  }
+
+  if (!accessKeyId || !secretAccessKey || !region) {
+    throw new Error(
+      'Init: You must configure a AWS user(accessKeyId), password(secretAccessKey) and endpoint/AWS_REGION'
+    );
+  }
+
+  config.region = region;
+  const credentials: Credentials = {
+    accessKeyId,
+    secretAccessKey,
+    sessionToken: process.env.AWS_SESSION_TOKEN,
+  };
+  config.credentials = credentials;
+
+  // If any of the below fails, it will throw an exception stopping the program.
+  client.buildCodeCommitClient(region, credentials);
+  // To check if we have permission to codecommit
+  await client.listRepositories();
+
+  initIamClient(region, credentials);
+  config.userArn = await getUserArn();
+
+  const platformConfig: PlatformResult = {
+    endpoint: endpoint ?? `https://git-codecommit.${region}.amazonaws.com/`,
+  };
+  return Promise.resolve(platformConfig);
+}
+
+export async function initRepo({
+  repository,
+  endpoint,
+}: RepoParams): Promise<RepoResult> {
+  logger.debug(`initRepo("${repository}")`);
+
+  config.repository = repository;
+
+  let repo;
+  try {
+    repo = await client.getRepositoryInfo(repository);
+  } catch (err) {
+    logger.error({ err }, 'Could not find repository');
+    throw new Error(REPOSITORY_NOT_FOUND);
+  }
+
+  const url = getCodeCommitUrl(config.region!, repository, config.credentials!);
+  try {
+    await git.initRepo({
+      url,
+    });
+  } catch (err) {
+    logger.debug({ err }, 'Failed to git init');
+    throw new Error(PLATFORM_BAD_CREDENTIALS);
+  }
+
+  if (!repo?.repositoryMetadata) {
+    logger.error({ repository }, 'Could not find repository');
+    throw new Error(REPOSITORY_NOT_FOUND);
+  }
+
+  logger.debug({ repositoryDetails: repo }, 'Repository details');
+  const metadata = repo.repositoryMetadata;
+
+  if (!metadata.defaultBranch || !metadata.repositoryId) {
+    logger.debug('Repo is empty');
+    throw new Error(REPOSITORY_EMPTY);
+  }
+
+  const defaultBranch = metadata.defaultBranch;
+  config.defaultBranch = defaultBranch;
+  logger.debug(`${repository} default branch = ${defaultBranch}`);
+
+  return {
+    repoFingerprint: repoFingerprint(metadata.repositoryId, endpoint),
+    defaultBranch,
+    isFork: false,
+  };
+}
+
+export async function getPrList(): Promise<CodeCommitPr[]> {
+  logger.debug('getPrList()');
+
+  if (config.prList) {
+    return config.prList;
+  }
+
+  const listPrsResponse = await client.listPullRequests(
+    config.repository!,
+    config.userArn!
+  );
+  const fetchedPrs: CodeCommitPr[] = [];
+
+  if (listPrsResponse && !listPrsResponse.pullRequestIds) {
+    return fetchedPrs;
+  }
+
+  const prIds = listPrsResponse.pullRequestIds ?? [];
+
+  for (const prId of prIds) {
+    const prRes = await client.getPr(prId);
+
+    if (!prRes?.pullRequest) {
+      continue;
+    }
+    const prInfo = prRes.pullRequest;
+    const pr: CodeCommitPr = {
+      targetBranch: prInfo.pullRequestTargets![0].destinationReference!,
+      sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,
+      state:
+        prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN
+          ? PrState.Open
+          : PrState.Closed,
+      number: Number.parseInt(prId),
+      title: prInfo.title!,
+      body: prInfo.description!,
+    };
+    fetchedPrs.push(pr);
+  }
+
+  config.prList = fetchedPrs;
+
+  logger.debug({ length: fetchedPrs.length }, 'Retrieved Pull Requests');
+  return fetchedPrs;
+}
+
+export async function findPr({
+  branchName,
+  prTitle,
+  state = PrState.All,
+}: FindPRConfig): Promise<CodeCommitPr | null> {
+  let prsFiltered: CodeCommitPr[] = [];
+  try {
+    const prs = await getPrList();
+    const refsHeadBranchName = getNewBranchName(branchName);
+    prsFiltered = prs.filter(
+      (item) => item.sourceBranch === refsHeadBranchName
+    );
+
+    if (prTitle) {
+      prsFiltered = prsFiltered.filter((item) => item.title === prTitle);
+    }
+
+    switch (state) {
+      case PrState.All:
+        break;
+      case PrState.NotOpen:
+        prsFiltered = prsFiltered.filter((item) => item.state !== PrState.Open);
+        break;
+      default:
+        prsFiltered = prsFiltered.filter((item) => item.state === PrState.Open);
+        break;
+    }
+  } catch (err) {
+    logger.error({ err }, 'findPr error');
+  }
+  if (prsFiltered.length === 0) {
+    return null;
+  }
+  return prsFiltered[0];
+}
+
+export async function getBranchPr(
+  branchName: string
+): Promise<CodeCommitPr | null> {
+  logger.debug(`getBranchPr(${branchName})`);
+  const existingPr = await findPr({
+    branchName,
+    state: PrState.Open,
+  });
+  return existingPr ? getPr(existingPr.number) : null;
+}
+
+export async function getPr(
+  pullRequestId: number
+): Promise<CodeCommitPr | null> {
+  logger.debug(`getPr(${pullRequestId})`);
+  const prRes = await client.getPr(`${pullRequestId}`);
+
+  if (!prRes?.pullRequest) {
+    return null;
+  }
+
+  const prInfo = prRes.pullRequest;
+  let prState: PrState;
+  if (prInfo.pullRequestTargets![0].mergeMetadata?.isMerged) {
+    prState = PrState.Merged;
+  } else {
+    prState =
+      prInfo.pullRequestStatus === PullRequestStatusEnum.OPEN
+        ? PrState.Open
+        : PrState.Closed;
+  }
+
+  return {
+    sourceBranch: prInfo.pullRequestTargets![0].sourceReference!,
+    state: prState,
+    number: pullRequestId,
+    title: prInfo.title!,
+    targetBranch: prInfo.pullRequestTargets![0].destinationReference!,
+    sha: prInfo.revisionId,
+    body: prInfo.description!,
+  };
+}
+
+export async function getRepos(): Promise<string[]> {
+  logger.debug('Autodiscovering AWS CodeCommit repositories');
+
+  let reposRes: ListRepositoriesOutput;
+  try {
+    reposRes = await client.listRepositories();
+    //todo do we need pagination? maximum number of repos is 1000 without pagination, also the same for free account
+  } catch (error) {
+    logger.error({ error }, 'Could not retrieve repositories');
+    return [];
+  }
+
+  const res: string[] = [];
+
+  const repoNames = reposRes?.repositories ?? [];
+
+  for (const repo of repoNames) {
+    if (repo.repositoryName) {
+      res.push(repo.repositoryName);
+    }
+  }
+
+  return res;
+}
+
+export function massageMarkdown(input: string): string {
+  // Remove any HTML we use
+  return input
+    .replace(
+      'you tick the rebase/retry checkbox',
+      'rename PR to start with "rebase!"'
+    )
+    .replace(regEx(/<\/?summary>/g), '**')
+    .replace(regEx(/<\/?details>/g), '')
+    .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), '')
+    .replace(regEx(/\]\(\.\.\/pull\//g), '](../../pull-requests/')
+    .replace(
+      regEx(/(?<hiddenComment><!--renovate-(?:debug|config-hash):.*?-->)/g),
+      '[//]: # ($<hiddenComment>)'
+    );
+}
+
+export async function getJsonFile(
+  fileName: string,
+  repoName?: string,
+  branchOrTag?: string
+): Promise<any | null> {
+  const raw = await getRawFile(fileName, repoName, branchOrTag);
+  return raw ? JSON5.parse(raw) : null;
+}
+
+export async function getRawFile(
+  fileName: string,
+  repoName?: string,
+  branchOrTag?: string
+): Promise<string | null> {
+  const fileRes = await client.getFile(
+    repoName ?? config.repository,
+    fileName,
+    branchOrTag
+  );
+  if (!fileRes?.fileContent) {
+    return null;
+  }
+  const buf = Buffer.from(fileRes.fileContent);
+  return buf.toString();
+}
+
+/* istanbul ignore next */
+export function getRepoForceRebase(): Promise<boolean> {
+  return Promise.resolve(false);
+}
+
+const AMAZON_MAX_BODY_LENGTH = 10239;
+
+export async function createPr({
+  sourceBranch,
+  targetBranch,
+  prTitle: title,
+  prBody: body,
+}: CreatePRConfig): Promise<CodeCommitPr> {
+  const description = smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH);
+
+  const prCreateRes = await client.createPr(
+    title,
+    sanitize(description),
+    sourceBranch,
+    targetBranch,
+    config.repository
+  );
+
+  if (
+    !prCreateRes.pullRequest?.title ||
+    !prCreateRes.pullRequest?.pullRequestId ||
+    !prCreateRes.pullRequest?.description
+  ) {
+    throw new Error('Could not create pr, missing PR info');
+  }
+
+  return {
+    number: Number.parseInt(prCreateRes.pullRequest.pullRequestId),
+    state: PrState.Open,
+    title: prCreateRes.pullRequest.title,
+    sourceBranch,
+    targetBranch,
+    sourceRepo: config.repository,
+    body: prCreateRes.pullRequest.description,
+  };
+}
+
+export async function updatePr({
+  number: prNo,
+  prTitle: title,
+  prBody: body,
+  state,
+}: UpdatePrConfig): Promise<void> {
+  logger.debug(`updatePr(${prNo}, ${title}, body)`);
+
+  let cachedPr: CodeCommitPr | undefined = undefined;
+  const cachedPrs = config.prList ?? [];
+  for (const p of cachedPrs) {
+    if (p.number === prNo) {
+      cachedPr = p;
+    }
+  }
+
+  if (body && cachedPr?.body !== body) {
+    await client.updatePrDescription(
+      `${prNo}`,
+      smartTruncate(sanitize(body), AMAZON_MAX_BODY_LENGTH)
+    );
+  }
+
+  if (title && cachedPr?.title !== title) {
+    await client.updatePrTitle(`${prNo}`, title);
+  }
+
+  const prStatusInput =
+    state === PrState.Closed
+      ? PullRequestStatusEnum.CLOSED
+      : PullRequestStatusEnum.OPEN;
+  if (cachedPr?.state !== prStatusInput) {
+    try {
+      await client.updatePrStatus(`${prNo}`, prStatusInput);
+    } catch (err) {
+      // safety check
+      // do nothing, it's ok to fail sometimes when trying to update from open to open or from closed to closed.
+    }
+  }
+}
+
+// Auto-Merge not supported currently.
+/* istanbul ignore next */
+export async function mergePr({
+  branchName,
+  id: prNo,
+  strategy,
+}: MergePRConfig): Promise<boolean> {
+  logger.debug(`mergePr(${prNo}, ${branchName!})`);
+  await client.getPr(`${prNo}`);
+  return Promise.resolve(false);
+  //
+  // // istanbul ignore if
+  // if (!prOut) {
+  //   return false;
+  // }
+  // const pReq = prOut.pullRequest;
+  // const targets = pReq?.pullRequestTargets;
+  //
+  // // istanbul ignore if
+  // if (!targets) {
+  //   return false;
+  // }
+  //
+  // if (strategy === 'rebase') {
+  //   logger.warn('CodeCommit does not support a "rebase" strategy.');
+  //   return false;
+  // }
+  //
+  // try {
+  //   if (strategy === 'auto' || strategy === 'squash') {
+  //     await client.squashMerge(
+  //       targets[0].repositoryName!,
+  //       targets[0].sourceReference!,
+  //       targets[0].destinationReference!,
+  //       pReq?.title
+  //     );
+  //   } else if (strategy === 'fast-forward') {
+  //     await client.fastForwardMerge(
+  //       targets[0].repositoryName!,
+  //       targets[0].sourceReference!,
+  //       targets[0].destinationReference!
+  //     );
+  //   } else {
+  //     logger.debug(`unsupported strategy`);
+  //     return false;
+  //   }
+  // } catch (err) {
+  //   logger.debug({ err }, `PR merge error`);
+  //   logger.info({ pr: prNo }, 'PR automerge failed');
+  //   return false;
+  // }
+  //
+  // logger.trace(`Updating PR ${prNo} to status ${PullRequestStatusEnum.CLOSED}`);
+  //
+  // try {
+  //   const response = await client.updatePrStatus(
+  //     `${prNo}`,
+  //     PullRequestStatusEnum.CLOSED
+  //   );
+  //   const isClosed =
+  //     response.pullRequest?.pullRequestStatus === PullRequestStatusEnum.CLOSED;
+  //
+  //   if (!isClosed) {
+  //     logger.warn(
+  //       {
+  //         pullRequestId: prNo,
+  //         status: response.pullRequest?.pullRequestStatus,
+  //       },
+  //       `Expected PR to have status`
+  //     );
+  //   }
+  //   return true;
+  // } catch (err) {
+  //   logger.debug({ err }, 'Failed to set the PR as Closed.');
+  //   return false;
+  // }
+}
+
+export async function addReviewers(
+  prNo: number,
+  reviewers: string[]
+): Promise<void> {
+  const numberOfApprovers = reviewers.length;
+  const approvalRuleContents = `{"Version":"2018-11-08","Statements": [{"Type": "Approvers","NumberOfApprovalsNeeded":${numberOfApprovers},"ApprovalPoolMembers": ${JSON.stringify(
+    reviewers
+  )}}]}`;
+  const res = await client.createPrApprovalRule(
+    `${prNo}`,
+    approvalRuleContents
+  );
+  if (res) {
+    const approvalRule = res.approvalRule;
+    logger.debug({ approvalRule }, `Approval Rule Added to PR #${prNo}:`);
+  }
+}
+
+/* istanbul ignore next */
+export function addAssignees(iid: number, assignees: string[]): Promise<void> {
+  // CodeCommit does not support adding reviewers
+  return Promise.resolve();
+}
+
+/* istanbul ignore next */
+export function findIssue(title: string): Promise<Issue | null> {
+  // CodeCommit does not have issues
+  return Promise.resolve(null);
+}
+
+/* istanbul ignore next */
+export function ensureIssue({
+  title,
+}: EnsureIssueConfig): Promise<EnsureIssueResult | null> {
+  // CodeCommit does not have issues
+  return Promise.resolve(null);
+}
+
+/* istanbul ignore next */
+export function getIssueList(): Promise<Issue[]> {
+  // CodeCommit does not have issues
+  return Promise.resolve([]);
+}
+
+/* istanbul ignore next */
+export function ensureIssueClosing(title: string): Promise<void> {
+  // CodeCommit does not have issues
+  return Promise.resolve();
+}
+
+/* istanbul ignore next */
+export function deleteLabel(prNumber: number, label: string): Promise<void> {
+  return Promise.resolve();
+}
+
+/* istanbul ignore next */
+export function getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]> {
+  return Promise.resolve([]);
+}
+
+// Returns the combined status for a branch.
+/* istanbul ignore next */
+export function getBranchStatus(branchName: string): Promise<BranchStatus> {
+  logger.debug(`getBranchStatus(${branchName})`);
+  logger.debug(
+    'returning branch status yellow, because getBranchStatus isnt supported on aws yet'
+  );
+  return Promise.resolve(BranchStatus.yellow);
+}
+
+/* istanbul ignore next */
+export function getBranchStatusCheck(
+  branchName: string,
+  context: string
+): Promise<BranchStatus | null> {
+  logger.debug(`getBranchStatusCheck(${branchName}, context=${context})`);
+  logger.debug(
+    'returning null, because getBranchStatusCheck is not supported on aws yet'
+  );
+  return Promise.resolve(null);
+}
+
+/* istanbul ignore next */
+export function setBranchStatus({
+  branchName,
+  context,
+  description,
+  state,
+  url: targetUrl,
+}: BranchStatusConfig): Promise<void> {
+  return Promise.resolve();
+}
+
+export async function ensureComment({
+  number,
+  topic,
+  content,
+}: EnsureCommentConfig): Promise<boolean> {
+  logger.debug(`ensureComment(${number}, ${topic!}, content)`);
+  const header = topic ? `### ${topic}\n\n` : '';
+  const body = `${header}${sanitize(content)}`;
+  let prCommentsResponse: GetCommentsForPullRequestOutput;
+  try {
+    prCommentsResponse = await client.getPrComments(
+      config.repository!,
+      `${number}`
+    );
+  } catch (err) {
+    logger.debug({ err }, 'Unable to retrieve pr comments');
+    return false;
+  }
+
+  let commentId: string | undefined = undefined;
+  let commentNeedsUpdating = false;
+
+  if (!prCommentsResponse?.commentsForPullRequestData) {
+    return false;
+  }
+
+  for (const commentObj of prCommentsResponse.commentsForPullRequestData) {
+    if (!commentObj?.comments) {
+      continue;
+    }
+    const firstCommentContent = commentObj.comments[0].content;
+    if (
+      (topic && firstCommentContent?.startsWith(header)) ||
+      (!topic && firstCommentContent === body)
+    ) {
+      commentId = commentObj.comments[0].commentId;
+      commentNeedsUpdating = firstCommentContent !== body;
+      break;
+    }
+  }
+
+  if (!commentId) {
+    const prEvent = await client.getPrEvents(`${number}`);
+
+    if (!prEvent?.pullRequestEvents) {
+      return false;
+    }
+
+    const event =
+      prEvent.pullRequestEvents[0]
+        .pullRequestSourceReferenceUpdatedEventMetadata;
+
+    if (!event?.beforeCommitId || !event?.afterCommitId) {
+      return false;
+    }
+
+    await client.createPrComment(
+      `${number}`,
+      config.repository,
+      body,
+      event.beforeCommitId,
+      event.afterCommitId
+    );
+    logger.info(
+      { repository: config.repository, prNo: number, topic },
+      'Comment added'
+    );
+  } else if (commentNeedsUpdating && commentId) {
+    await client.updateComment(commentId, body);
+
+    logger.debug(
+      { repository: config.repository, prNo: number, topic },
+      'Comment updated'
+    );
+  } else {
+    logger.debug(
+      { repository: config.repository, prNo: number, topic },
+      'Comment is already update-to-date'
+    );
+  }
+
+  return true;
+}
+
+export async function ensureCommentRemoval(
+  removeConfig: EnsureCommentRemovalConfig
+): Promise<void> {
+  const { number: prNo } = removeConfig;
+  const key =
+    removeConfig.type === 'by-topic'
+      ? removeConfig.topic
+      : removeConfig.content;
+  logger.debug(`Ensuring comment "${key}" in #${prNo} is removed`);
+
+  let prCommentsResponse: GetCommentsForPullRequestOutput;
+  try {
+    prCommentsResponse = await client.getPrComments(
+      config.repository!,
+      `${prNo}`
+    );
+  } catch (err) {
+    logger.debug({ err }, 'Unable to retrieve pr comments');
+    return;
+  }
+
+  if (!prCommentsResponse?.commentsForPullRequestData) {
+    logger.debug('commentsForPullRequestData not found');
+    return;
+  }
+
+  let commentIdToRemove: string | undefined;
+  for (const commentObj of prCommentsResponse.commentsForPullRequestData) {
+    if (!commentObj?.comments) {
+      logger.debug(
+        'comments object not found under commentsForPullRequestData'
+      );
+      continue;
+    }
+
+    for (const comment of commentObj.comments) {
+      if (
+        (removeConfig.type === 'by-topic' &&
+          comment.content?.startsWith(`### ${removeConfig.topic}\n\n`)) ||
+        (removeConfig.type === 'by-content' &&
+          removeConfig.content === comment.content?.trim())
+      ) {
+        commentIdToRemove = comment.commentId;
+        break;
+      }
+    }
+    if (commentIdToRemove) {
+      await client.deleteComment(commentIdToRemove);
+      logger.debug(`comment "${key}" in PR #${prNo} was removed`);
+      break;
+    }
+  }
+}
diff --git a/package.json b/package.json
index fe0f0a69198e31394d06512a4f2f7339e2f28703..0b93ce3c4bbc5b0600b99a877a00276a26bddb4e 100644
--- a/package.json
+++ b/package.json
@@ -135,8 +135,10 @@
     "node": ">=16.13.0"
   },
   "dependencies": {
+    "@aws-sdk/client-codecommit": "3.154.0",
     "@aws-sdk/client-ec2": "3.155.0",
     "@aws-sdk/client-ecr": "3.154.0",
+    "@aws-sdk/client-iam": "3.154.0",
     "@aws-sdk/client-rds": "3.154.0",
     "@aws-sdk/client-s3": "3.154.0",
     "@breejs/later": "4.1.0",
@@ -152,6 +154,7 @@
     "agentkeepalive": "4.2.1",
     "aggregate-error": "3.1.0",
     "auth-header": "1.0.0",
+    "aws4": "1.11.0",
     "azure-devops-node-api": "11.2.0",
     "bunyan": "1.8.15",
     "cacache": "17.0.0",
@@ -234,6 +237,7 @@
     "@renovate/eslint-plugin": "https://github.com/renovatebot/eslint-plugin#v0.0.4",
     "@semantic-release/exec": "6.0.3",
     "@types/auth-header": "1.0.2",
+    "@types/aws4": "1.11.2",
     "@types/bunyan": "1.8.8",
     "@types/cacache": "15.0.1",
     "@types/callsite": "1.0.31",
diff --git a/yarn.lock b/yarn.lock
index fe1acef7c8d569fff0a2c2d2af46960466301984..e3f08ff25974355faf89b48de04310f3421b5ba9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -140,6 +140,47 @@
   dependencies:
     tslib "^2.3.1"
 
+"@aws-sdk/client-codecommit@3.154.0":
+  version "3.154.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-codecommit/-/client-codecommit-3.154.0.tgz#4b78f57b4da47f36a817f42c8df19ce62bae8464"
+  integrity sha512-7rm5+OcZ08nAfPRAB2ru8ZvRObFRpipdcOMzRSYOrJmg3CpvK2zf4E2As14q1yBmrnPnExG5x0bSSkfBsVewyQ==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.154.0"
+    "@aws-sdk/config-resolver" "3.130.0"
+    "@aws-sdk/credential-provider-node" "3.154.0"
+    "@aws-sdk/fetch-http-handler" "3.131.0"
+    "@aws-sdk/hash-node" "3.127.0"
+    "@aws-sdk/invalid-dependency" "3.127.0"
+    "@aws-sdk/middleware-content-length" "3.127.0"
+    "@aws-sdk/middleware-host-header" "3.127.0"
+    "@aws-sdk/middleware-logger" "3.127.0"
+    "@aws-sdk/middleware-recursion-detection" "3.127.0"
+    "@aws-sdk/middleware-retry" "3.127.0"
+    "@aws-sdk/middleware-serde" "3.127.0"
+    "@aws-sdk/middleware-signing" "3.130.0"
+    "@aws-sdk/middleware-stack" "3.127.0"
+    "@aws-sdk/middleware-user-agent" "3.127.0"
+    "@aws-sdk/node-config-provider" "3.127.0"
+    "@aws-sdk/node-http-handler" "3.127.0"
+    "@aws-sdk/protocol-http" "3.127.0"
+    "@aws-sdk/smithy-client" "3.142.0"
+    "@aws-sdk/types" "3.127.0"
+    "@aws-sdk/url-parser" "3.127.0"
+    "@aws-sdk/util-base64-browser" "3.109.0"
+    "@aws-sdk/util-base64-node" "3.55.0"
+    "@aws-sdk/util-body-length-browser" "3.154.0"
+    "@aws-sdk/util-body-length-node" "3.55.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.142.0"
+    "@aws-sdk/util-defaults-mode-node" "3.142.0"
+    "@aws-sdk/util-user-agent-browser" "3.127.0"
+    "@aws-sdk/util-user-agent-node" "3.127.0"
+    "@aws-sdk/util-utf8-browser" "3.109.0"
+    "@aws-sdk/util-utf8-node" "3.109.0"
+    tslib "^2.3.1"
+    uuid "^8.3.2"
+
 "@aws-sdk/client-ec2@3.155.0":
   version "3.155.0"
   resolved "https://registry.yarnpkg.com/@aws-sdk/client-ec2/-/client-ec2-3.155.0.tgz#1b10868bb603dda2071c2baac0c5eb57d80af7c8"
@@ -226,6 +267,49 @@
     "@aws-sdk/util-waiter" "3.127.0"
     tslib "^2.3.1"
 
+"@aws-sdk/client-iam@3.154.0":
+  version "3.154.0"
+  resolved "https://registry.yarnpkg.com/@aws-sdk/client-iam/-/client-iam-3.154.0.tgz#0a6f11ee729e9d21e6357b9f075f9bac3f3c8fe2"
+  integrity sha512-+lZCo4NkICCjho+D0Tajaowukd5hHYAFX5nzjJm/Yvmnc/rS1HGuKw7+3OXMiu2NebEjl3k23JVcvbaZMdFJ0w==
+  dependencies:
+    "@aws-crypto/sha256-browser" "2.0.0"
+    "@aws-crypto/sha256-js" "2.0.0"
+    "@aws-sdk/client-sts" "3.154.0"
+    "@aws-sdk/config-resolver" "3.130.0"
+    "@aws-sdk/credential-provider-node" "3.154.0"
+    "@aws-sdk/fetch-http-handler" "3.131.0"
+    "@aws-sdk/hash-node" "3.127.0"
+    "@aws-sdk/invalid-dependency" "3.127.0"
+    "@aws-sdk/middleware-content-length" "3.127.0"
+    "@aws-sdk/middleware-host-header" "3.127.0"
+    "@aws-sdk/middleware-logger" "3.127.0"
+    "@aws-sdk/middleware-recursion-detection" "3.127.0"
+    "@aws-sdk/middleware-retry" "3.127.0"
+    "@aws-sdk/middleware-serde" "3.127.0"
+    "@aws-sdk/middleware-signing" "3.130.0"
+    "@aws-sdk/middleware-stack" "3.127.0"
+    "@aws-sdk/middleware-user-agent" "3.127.0"
+    "@aws-sdk/node-config-provider" "3.127.0"
+    "@aws-sdk/node-http-handler" "3.127.0"
+    "@aws-sdk/protocol-http" "3.127.0"
+    "@aws-sdk/smithy-client" "3.142.0"
+    "@aws-sdk/types" "3.127.0"
+    "@aws-sdk/url-parser" "3.127.0"
+    "@aws-sdk/util-base64-browser" "3.109.0"
+    "@aws-sdk/util-base64-node" "3.55.0"
+    "@aws-sdk/util-body-length-browser" "3.154.0"
+    "@aws-sdk/util-body-length-node" "3.55.0"
+    "@aws-sdk/util-defaults-mode-browser" "3.142.0"
+    "@aws-sdk/util-defaults-mode-node" "3.142.0"
+    "@aws-sdk/util-user-agent-browser" "3.127.0"
+    "@aws-sdk/util-user-agent-node" "3.127.0"
+    "@aws-sdk/util-utf8-browser" "3.109.0"
+    "@aws-sdk/util-utf8-node" "3.109.0"
+    "@aws-sdk/util-waiter" "3.127.0"
+    entities "2.2.0"
+    fast-xml-parser "3.19.0"
+    tslib "^2.3.1"
+
 "@aws-sdk/client-rds@3.154.0":
   version "3.154.0"
   resolved "https://registry.yarnpkg.com/@aws-sdk/client-rds/-/client-rds-3.154.0.tgz#032fe8e4fd94f1e0bd55523f4c631fbac9ccb0cf"
@@ -2609,6 +2693,13 @@
   resolved "https://registry.yarnpkg.com/@types/auth-header/-/auth-header-1.0.2.tgz#45879542c5c754debbb753b1491bbf690888b4ef"
   integrity sha512-KWpTfyz+F5GtURfp7W9c4ubFSXaPAvb1dUN5MlU3xSvlNIYhFrmrTNE7vd6SUOfSOO7FI/ePe03Y/KCPM/YOoA==
 
+"@types/aws4@1.11.2":
+  version "1.11.2"
+  resolved "https://registry.yarnpkg.com/@types/aws4/-/aws4-1.11.2.tgz#7700aabe4646f8868b5d2b20820d9583225e7b78"
+  integrity sha512-x0f96eBPrCCJzJxdPbUvDFRva4yPpINJzTuXXpmS2j9qLUpF2nyGzvXPlRziuGbCsPukwY4JfuO+8xwsoZLzGw==
+  dependencies:
+    "@types/node" "*"
+
 "@types/babel__core@^7.1.14":
   version "7.1.19"
   resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460"
@@ -3446,6 +3537,11 @@ aws-sdk-client-mock@2.0.0:
     sinon "^11.1.1"
     tslib "^2.1.0"
 
+aws4@1.11.0:
+  version "1.11.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+  integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+
 azure-devops-node-api@11.2.0:
   version "11.2.0"
   resolved "https://registry.yarnpkg.com/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz#bf04edbef60313117a0507415eed4790a420ad6b"
@@ -9862,9 +9958,9 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
 util@^0.12.4:
-  version "0.12.5"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
-  integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
+  version "0.12.4"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253"
+  integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==
   dependencies:
     inherits "^2.0.3"
     is-arguments "^1.0.4"