CDKコントリビュートネタです。
CDKのREADMEのコードスニペットは jsii-rosetta (以降Rosetta) でコンパイルされ、他言語に変換されています。 このコードスニペットですが適当に書くと、Pull Request起票時のCIにおいてコンパイルに失敗しエラーになります。
私自身つい最近まで雰囲気で書いており、トライアンドエラーで修正していました。
ただいい加減仕組みを把握しておいたほうが良いかと思い、コントリビュートガイドを見て理解したことをまとめておきます。
目次
Rosettaの概要
READMEに記載のコードスニペットはRosettaにより、TypeScript -> 他言語に変換されます。
例えば上記スライドに記載のコードスニペット(TypeScript)は、以下のようにCDKのドキュメントとして掲載されています。
Pythonバージョンは上記をもとにRosettaによりコンパイル・自動変換され以下のように、掲載されています。
このコードスニペットのRosettaによる処理はCDKコントリビュートのPull Request起票時のCIにも行われます。そのため不適切な記載の場合、コンパイルに失敗してCIが落ちます。
PRのレビューを受けるためには、CIを成功させる必要がありますが、このRosettaにより阻止されることが往々にしてあります(コードスニペットで誤った記載であっても、IDEでは検知が難しくミスに気づきにくい)。
※Rosettaのチェックを一発で通すのが、CDKコントリビュートの最難関という説もあるとかないとか...(無いです)
※以下のbuildspecで動作するように設定されています。 github.com
このRosettaを通す上で肝になるのが、2ポチ目に記載しているfixtureになります。
fixtureとは
fixtureとはコードのテンプレートのようなものです。fixtureのファイルは packages/aws-cdk-lib/rosetta 配下にモジュールごとに存在しています(αモジュールは各モジュールのディレクトリ内にrosetta
が存在します)。
fixture は 上記スライドのように /// here
という箇所に、スニペットのコードを挿入する形で解決がされます。
つまりfixtureにコードスニペットを挿入したときに、問題ないコードになっていれば良いということになります。
上記の例のfixture の /// here
にコードスニペットを挿入すると以下のようになります。これは正常なコードなので問題なく、コンパイルに成功します(import文が過剰な点は問題なし)。
import { Construct } from 'constructs'; import { CfnOutput, Fn, Size, Stack } from 'aws-cdk-lib'; import * as eks from 'aws-cdk-lib/aws-eks'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as iam from 'aws-cdk-lib/aws-iam'; import * as kms from 'aws-cdk-lib/aws-kms'; import * as s3 from 'aws-cdk-lib/aws-s3'; import * as autoscaling from 'aws-cdk-lib/aws-autoscaling'; class Context extends Stack { constructor(scope: Construct, id: string) { super(scope, id); /// here にコードスニペットを挿入 new eks.Cluster(this, 'HelloEKS', { version: eks.KubernetesVersion.V1_30, }); } }
Rosetta でコンパイルに失敗する例
fixture の /// here
にコードスニペットを挿入した場合に、不適切なコードとなる場合、Rosettaのコンパイルに失敗します。
スライドの例だと以下の理由のため失敗します。
- 1つ目の例は import の形式に沿っていないためエラーになる。(
eks
をインポートしているので、Cluster
ではなくeks.Cluster
としないといけない) - 2つ目の例は import していない
ecr
を使おうとしているためエラーになる。
特に難しい話ではなく、通常のCDK実装時と同様の話ですね。fixtureとコードスニペットが分断されているという点のみ意識すれば問題ないです。
fixtureの関連付けについて
コードスニペットの中で、関連付けるfixtureを指定できます。
- 未指定の場合は
default.ts-fixture
が関連づけられます。ほとんどはこっちです。 - 一方で個別にfixtureファイルを作成し、コードスニペットで関連付けを指定することもできます。図の例で言うと
cdk8schart.ts-fixture
を作成し、コードスニペットで指定する形になります。
なお、後者の個別作成はimport文が大量に必要など、特殊な事情がない限りは避けてdefaultを使用すべきであることがコントリビュートガイド上述べられています。
Utilize the default.ts-fixture that already exists rather than writing new .ts-fixture files. This is because values stored in .ts-fixture files do not surface to the examples visible in the docs, so while they help successful compilation, they do not help users understand the example.
fixtureの内容はドキュメント上では明確にはわからないのが理由です。fixtureはあくまでコンパイルのための補助ツールであり、fixtureの内容がなくともユーザーが理解できるようなドキュメントとすべきでしょう。
その他Rosettaの推奨事項
コントリビュートガイド上で述べられているその他推奨事項についても記載しておきます。
なお、モジュールによっては守られてないものもあったりします...
Types from the documented module should be un-qualified
日本語にするのが少々難しいですが、「ドキュメント化対象のモジュールは非修飾の形で記載すべし」といったところでしょうか。
説明文がなんとなくv1の時の名残な気もしていますが、ガイドに記載の通りaws-cdk-lib/core
配下のものは直接記載すること、と理解しています。
Duration
であれば、cdk.Duration
などではなく Duration
のみとするイメージです。
// An example in the aws-cdk-lib library, which defines Duration Duration.minutes(15);
Types from other modules should be qualified:
今度は逆に「ドキュメント化対象でないモジュールは修飾の形で記載すべし」というものです。
これはaws-cdk-lib/aws-s3
など各サービスのモジュールの方は、s3.Bucket
などのようにどのモジュールの型なのかを明記すること、と理解しています。
// An example in the aws-cdk-lib library, using something from aws-cdk-lib/aws-s3 const bucket = new s3.Bucket(this, 'Bucket'); // ...rest of the example...
Make use of declare statements directly in examples for values that are necessary for compilation but unimportant to the example
「重要でないリソース宣言だがコンパイルに必要なものは declare
で宣言して省略せよ」というものです。
例えば以下の例は pipelines.CodePipeline
の addStage
メソッドを使って、Stage
を紐づけられると言う説明で使用するコードスニペットです。
この説明の時、pipelines.CodePipeline
や Stage
のプロパティは重要ではないため、declare
で省略するというようなイメージです。
// An example about adding a stage to a pipeline in the aws-cdk-lib/pipelines library declare const pipeline: pipelines.CodePipeline; declare const myStage: Stage; pipeline.addStage(myStage);
終わりに
Rosettaをよく理解しないまま雰囲気でやっていましたが、コントリビュートガイドにバッチリ書いてありました。やはりガイドはしっかり読み込んだほうが良いですね。