CDKコントリビューション 初心者向けTIPS

# はじめに
最近、[aws-cdk](https://github.com/aws/aws-cdk)リポジトリへのOSSコントリビューションを始めました。その際に知っておくと便利なTIPSをいくつか紹介します。

# 取り組むIssueの探し方
OSSコントリビューションをやるにあたって自分はここが一番鬼門でした。aws-cdkリポジトリには大量のIssueが存在するため、上から順にチェックしていくのは非現実的です。探し方のポイントがいくつかあります。
### ラベルでフィルタリング
まずはラベルで絞り込んで探すとよいでしょう。
- good first issue
    - 名前の通り初心者向けのIssue
- effort/small
    - 対応量が少なめと見積もられているIssue
- p2, p3
    - 優先度が高くないIssue
    - effort/smallと一緒に付けられていることが多いかも

### VPC Interface Endpointの定数追加
aws-cdkでは[vpc-endpoint.ts](https://github.com/tttol/aws-cdk/blob/main/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts)というファイルでVPC Interface Endpointを定義しています。中身は定数の羅列になっており、各エンドポイントに対して1対1で定数が定義されています。

```typescript:例：Amazon Athenaのエンドポイントに対する定数定義
  public static readonly ATHENA = new InterfaceVpcEndpointAwsService('athena');
```

AWSのサービスアップデートで新サービスが発表されると、対応する定数を追加する必要があります。例えば2024年12月に発表されたAmazon Bedrock Data Automation（プレビュー版）に対して、以下のように定数を追加する必要があります。
https://aws.amazon.com/about-aws/whats-new/2024/12/amazon-bedrock-data-automation-available-preview/

```diff
  public static readonly BEDROCK_AGENT = new InterfaceVpcEndpointAwsService('bedrock-agent');
  public static readonly BEDROCK_AGENT_RUNTIME = new InterfaceVpcEndpointAwsService('bedrock-agent-runtime');
  public static readonly BEDROCK_RUNTIME = new InterfaceVpcEndpointAwsService('bedrock-runtime');
+  public static readonly BEDROCK_DATA_AUTOMATION = new InterfaceVpcEndpointAwsService('bedrock-data-automation');
+  public static readonly BEDROCK_DATA_AUTOMATION_FIPS = new InterfaceVpcEndpointAwsService('bedrock-data-automation-fips');
+  public static readonly BEDROCK_DATA_AUTOMATION_RUNTIME = new InterfaceVpcEndpointAwsService('bedrock-data-automation-runtime');
+  public static readonly BEDROCK_DATA_AUTOMATION_RUNTIME_FIPS = new InterfaceVpcEndpointAwsService('bedrock-data-automation-runtime-fips');
  public static readonly BILLING = new InterfaceVpcEndpointAwsService('billing');
```

この4行を追加するだけでPRを作成することが可能です。
参考PR：https://github.com/aws/aws-cdk/pull/33674

未対応のVPC Interface Endpointの一覧を自動集計するツールを @badmintoncryer さんが作成してくださっているため、ここから未対応のものを確認してPR作成するだけで簡単にコントリビューションすることが可能です！

https://github.com/badmintoncryer/cdk-missing-interface-endpoint

参考ポスト：https://x.com/nixieminton/status/1896404099148726340

### `Error`をスローしている箇所を`ValidationError`/`UnscopedValidationError`に置換する
aws-cdkでは`throw new Error`と記載している箇所を`throw new ValidationError` or `thorw new UnscopedValidationError`にリファクタリングする方針があります。`ValidationError`と`UnscopedValidationError`はCDKリポジトリ内で定義されたカスタム例外クラスです。

参考情報：
- https://github.com/aws/aws-cdk/issues/32569
- https://x.com/nixieminton/status/1899797538913595723


参考PR

https://github.com/aws/aws-cdk/pull/33885


# ビルド
aws-cdkリポジトリのビルドは以下コマンドで実行可能です。
```shell
# packages/aws-cdk-libディレクトリに範囲を絞って実行
npx lerna run build --scope=aws-cdk-lib
```
aws-cdkリポジトリは巨大なコードベースであるため、リポジトリ全体のビルドを実施すると20分近くかかってしまうようです。そのため、`--scope=aws-cdk-lib`オプションでビルド対象を区切って実行するのが一般的です。
実行時にnode.jsのメモリ不足エラーが発生する場合、`export NODE_OPTIONS="--max-old-space-size=8192"`を実行してメモリ領域をあらかじめ拡張しておくとよいです。
※参考：M2 MacBook Air メモリ8Gだと上記コマンドがないとメモリ不足になりました

また、一度ビルドした内容はキャッシュされます。キャッシュを無視して実行する場合は`--skip-nx-cache`を付与しましょう。
```
# キャッシュを無視してビルド
npx lerna run build --scope=aws-cdk-lib --skip-nx-cache
```

# 差分ビルド
`yarn watch`コマンドを実行することで、ファイルが保存されるたびに差分ビルドを実施することができます。
```shell
$ cd packages/aws-cdk-lib
$ yarn watch

5:52:22 PM - Starting compilation in watch mode...
```
中止するときはCtrl+Cで抜けます

# フォーク元の差分を自身のリポジトリに適用
フォークしたリポジトリと本家のリポジトリに差分が発生した場合、フォークしたリポジトリに差分を適用する必要があります。ブラウザのGitHubのUIからSync forkを毎度実行するのは手間なので、ローカルのCLI環境から実行するとよいです。
```shell
# フォーク元のaws-cdkリポジトリをupstreamという名前で登録
git remote add upstream https://github.com/aws/aws-cdk.git

# 本家の差分をローカルに取り込む
git switch main
git fetch upstream
git merge upstream/main

# 本家の差分をリモートリポジトリの自分のブランチへPUSH
git push
```

自分は毎回忘れるので.shファイルに書いてzshrcにaliasを登録してます。

```sh:sync-fork.sh
#!/bin/zsh

set -e  # エラーが出たら止める

echo "🔁 Switching to main branch..."
cd path/to/aws-cdk
git switch main

echo "🔄 Fetching from upstream..."
git fetch upstream

echo "🔀 Merging upstream/main into local main..."
git merge upstream/main

echo "📤 Pushing changes to origin..."
git push

echo "✅ Fork sync completed!"
```

```zsh:.zshrc
alias sync-fork="path/to/sync-fork.sh"
```

# Test
### Unit Test
U Testの実行方法は以下
```shell
cd packages/aws-cdk-lib/aws-apigateway/test
yarn test restapi.test.ts
```
### Integration Test
Integration Testの実行方法は以下
```shell
# プロダクトコードのビルドを予め実施しておくk
# @aws-cdk-testingをビルドする(at repo root)
npx lerna run build --scope=@aws-cdk-testing/framework-integ

# 自身が作成/更新したinteg.*.tsをinteg.*.jsファイルにトランスパイルする
cd packages/@aws-cdk-testing/framework-integ/
yarn tsc

# integ test 実行（integ.restapi.jsは一例）
yarn integ --update-on-failed test/aws-apigateway/test/integ.restapi.js 
```

`yarn tsc`を実行した後に実際にinteg.*.jsファイルを確認し、tsファイルに施した変更が反映されていることを確認しておくと良いです。

integ testでは実際のAWSアカウントに対してcdk deployが実行されます。AWS Organizationsでinteg test用のアカウントを払い出しておくと便利です。

https://qiita.com/tttol777/items/cfd5fa540493cd6be9f9

integ testに関す参考資料：https://jaws-ug-cdk.github.io/cdk-conf-2024-contribute-workshop/4-%E6%A9%9F%E8%83%BD%E8%BF%BD%E5%8A%A0pr%E3%81%AE%E4%BD%9C%E6%88%90/display-name/#%E7%B5%B1%E5%90%88%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%BF%BD%E5%8A%A0

# さいごに
以上です！他にも思いついたら追記します。