コンテンツにスキップ

機能追加PRの作成

前提知識

CDKアプリケーションの構成

CDKアプリケーションはAppをルートとして、複数のStack, Constructから構成されています。

cdk-app-structure

このうち、Constructは以下の3つのタイプに分けられます。

  • L1 Construct
    • Cloudformationのリソースと1対1に対応するConstruct
    • Cloudformationから自動生成される
  • L2 Construct
    • L1を抽象化したConstruct
    • 型情報や関数などが追加されている
    • ユーザのPull Requestで作成・更新する
  • L3 Construct
    • 複数のL1, L2を組み合わせたConstruct

L2 Constructへの引数追加

Cloudformationで新しい引数が作成された場合、L1 Constructには自動で追加されますが、L2 Constructには自動では追加されません。

L2で使うためには、引数を追加する修正を手動で行う必要があります。

aws-cdk/packages/aws-cdk-lib/aws-sns/lib/topic.ts
export interface TopicProps {
..., // 既存のプロパティ
displayName?: string;
};
export class Topic extends TopicBase {
constructor(scope: Construct, id: string, props: TopicProps) {
super(scope, id, props);
const resource = new CfnTopic(this, 'Resource', {
...,
displayName: props.displayName
});
};
};

このように、L2で未対応の引数を追加するPRをこれから作成してみましょう。

概要

SNS Topicには表示名を設定することができ、Eメール通知における件名などに利用されます。

sns-topic-display-name

Cloudformation及びCDKのL1コンストラクトでは DisplayName というプロパティが提供されており、これを利用することで表示名を設定することができます。

const topic = sns.CfnTopic(this, 'MyTopic', {
displayName: 'MyTopicDisplayName'
})

しかし、ワークショップ向けCDKのL2コンストラクト(sns.Topic)では displayName がサポートされていません。そこで、L2コンストラクトに displayName プロパティを追加してみます。

目標

PRの作成には以下の要素を含める必要があります。

  • L2コンストラクト(packages/aws-cdk-lib/aws-sns/lib/topic.ts)のコード変更
    • TopicPropsdisplayNameプロパティを追加
    • Topicクラスのconstructor関数中のCfnTopicクラスのインスタンス作成時にdisplayNameプロパティを設定
  • ユニットテスト(packages/aws-cdk-lib/aws-sns/test/sns.test.ts)の追加
    • displayNameプロパティがCloudformationテンプレートに正しく反映されるか
  • 統合テスト(packages/@aws-cdk-testing/framework-integ/test/aws-sns/test)の追加
    • displayNameを設定したSNS Topicが正しく作成されるか
  • READMEの更新
    • 機能追加に関する説明を追加

エージェントと進める手順

この課題では 演習用 Issue #1 を CDK Contribution Skill に渡します。Kiro CLI に次のメッセージを送ってください。

Use the CDK Contribution Skill for https://github.com/jaws-ug-cdk/aws-cdk-for-workshop/issues/1.
Follow AGENTS.md, use only the workshop repository, and stop at every human approval gate.
Start with analysis and planning. Do not implement anything until I approve the plan.

Skill がワークフロー全体を提示したら内容を確認して開始します。Analysis と Planning が完了した時点 (.contributions/1/01-analysis.md, 02-solution.md が作成された時点) で、次を確認してください。

  • Issue の目的を自分の言葉で説明できる
  • 変更対象が SNS の L2、unit test、integration test、README に限定されている
  • displayName を省略した既存利用者の挙動が変わらない
  • AWS へデプロイする integration test の内容が明確である

不明点があればエージェントへ質問し、計画を修正させます。納得できた場合だけ実装を承認してください。

実装後は、エージェントが提示する diff と検証結果を確認します。integration test の実行は AWS リソースを作成するため、対象と削除方法の説明を受けてから明示的に承認してください。

Pull Request の作成前には、提出先が jaws-ug-cdk/aws-cdk-for-workshop であることと、Issue #1 を参照していることを確認します。ファシリテーターの確認を受けるまで push や Pull Request 作成を承認しないでください。

手動手順(トラブルシューティング用リファレンス)

ブランチ作成

まずは、この機能追加用のブランチを作成します。

Terminal window
git switch -c add-sns-topic-display-name

L2コンストラクトのコード変更

TopicPropsdisplayNameの追加

aws-cdk/packages/aws-cdk-lib/aws-sns/lib/topic.tsを開き、TopicPropsreadonlydisplayNameプロパティを追加します。

既存のPropsに新たな引数を追加するとき、必須なものを追加すると破壊的変更になってしまうため、optionalなプロパティとして追加することに注意してください。

jsdocにはdisplayNameプロパティの説明をCloudformationのドキュメントからコピーしてきましょう。

また、上記の通りoptionalなプロパティであることを示すために?を付け、デフォルトの挙動を@defaultに記述します。

aws-cdk/packages/aws-cdk-lib/aws-sns/lib/topic.ts
export interface TopicProps {
..., // 既存のプロパティ
/**
* The display name to use for an Amazon SNS topic with SMS subscriptions.
*
* The display name must be maximum 100 characters long, including hyphens (-), underscores (_), spaces, and tabs.
*
* @default - no display name
*/
readonly displayName?: string;
};

Topicクラスのconstructor関数の変更

Topicクラスのconstructor関数内で、CfnTopicクラスのインスタンス作成時にdisplayName引数を設定します。

aws-cdk/packages/aws-cdk-lib/aws-sns/lib/topic.ts
export class Topic extends TopicBase {
constructor(scope: Construct, id: string, props: TopicProps) {
super(scope, id, props);
const resource = new CfnTopic(this, 'Resource', {
..., // 既存のプロパティ
displayName: props.displayName
});
};
};

以上で機能修正は完了です。一連の内容をcommitしておきましょう。

ユニットテストの追加

テストファイルの修正

続いてユニットテストを追加します。テストファイルはaws-cdk/packages/aws-cdk-lib/aws-sns/test/sns.test.tsです。

ユニットテストでは、displayNameプロパティがCloudformationテンプレートに正しく反映されるかを確認します。

aws-cdk/packages/aws-cdk-lib/aws-sns/test/sns.test.ts
test('specify displayName', () => {
const stack = new cdk.Stack();
new sns.Topic(stack, 'MyTopic', {
displayName: 'MyDisplayName',
});
Template.fromStack(stack).hasResourceProperties('AWS::SNS::Topic', {
DisplayName: 'MyDisplayName',
});
});

テストの実行

ユニットテストを実行して、テストが正常に通ることを確認します。

Terminal window
cd packages/aws-cdk-lib
yarn test aws-sns/test/sns.test.ts

これでユニットテストの追加は完了です。一連の内容をcommitしておきましょう。

統合テストの追加

テストファイルの作成

続いて統合テストを追加します。統合テストでは、displayNameを設定したSNS Topicが正しく作成されるかを確認します。

テストファイルはpackages/@aws-cdk-testing/framework-integ/test/aws-sns/testに作成します。 今回は新規の統合テストファイル(integ.sns-display-name.ts)を作成します。

// packages/@aws-cdk-testing/framework-integ/test/aws-sns/test/integ.sns-display-name.ts
import { App, Stack, StackProps } from 'aws-cdk-lib';
import { Topic } from 'aws-cdk-lib/aws-sns';
import * as integ from '@aws-cdk/integ-tests-alpha';
// テスト用のStackを定義
class TestStack extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);
new Topic(this, 'MyTopic', {
topicName: 'MyTopicName',
// displayNameを設定
displayName: 'MyDisplayName',
});
}
}
const app = new App();
const stack = new TestStack(app, 'DisplayNameTopicTestStack');
// 統合テストの実行
new integ.IntegTest(app, 'SnsTest', {
testCases: [stack],
});

統合テストの実行

下準備

本ワークショップでの統合テストでは us-east-1 リージョンに対してデプロイが行われます。内部的に cdk deploy が実行されるため、事前に bootstrap が必要になります。 もし、今までに一度もus-east-1にcdk deployを実行していない場合は、以下のコマンドを実行してください。

Terminal window
cdk bootstrap aws://{ACCOUNT_ID}/us-east-1
ビルド及び実行

統合テストを実行して、テストが正常に通ることを確認します。 各ビルドコマンドは1分程度かかるため、別ターミナルで並列実行してもOKです。

Terminal window
# Topicクラスを含めたSNSのコンストラクトを再ビルド
cd packages/aws-cdk-lib
yarn tsc
# integ テスト側 (framework-integ) をビルドして javascript ファイルを生成
cd ../..
npx lerna run build --scope=@aws-cdk-testing/framework-integ
# 実際に integration テストを実行する
cd packages/@aws-cdk-testing/framework-integ
yarn integ test/aws-sns/test/integ.sns-display-name.js --update-on-failed

自動でCloudformationテンプレートの作成, スタックのデプロイ及び削除が行われます。エラーなく完了すれば統合テストも完了です。

作成したテストファイル及び生成されたスナップショットファイルをコミットしておきましょう。

READMEの更新

最後に、この機能追加に関する説明をREADMEに追加します。

aws-cdk/packages/aws-cdk-lib/aws-sns/README.md
## Display Name
You can set a display name for the topic.
To set a display name, use the `displayName` property:
```ts
const topic = new sns.Topic(this, 'Topic', {
displayName: 'MyDisplayName',
});
\```

以上で必要な変更はすべて完了しました。

PRの提出

最後にPRを提出します。

PRルールに則り、以下のようなPRを作成しましょう。

項目内容記入例
PRタイトルPRの目的feat(sns): add displayName property to a Topic
Issue # (if applicable)関連するIssue番号Closes #1
Reason for this change変更理由We can set a display name for an SNS topic from cloudformation, but this was not supported in the AWS CDK L2 construct.
Description of changes変更内容の詳細Add displayName property to TopicProps and set it in the CfnTopic constructor.
Description of how you validated changes変更の検証方法Added both unit and integration tests.

以上でPRの作成は完了です。おつかれさまでした!