JetBrains系IDEのためのエラーインライン表示プラグイン
まとめ
- VScodeでよく使われるエラーをインラインに表示されるプラグインにErrorLensというものがあり、大変便利
- JetBrains系IDE向けに同様の機能を提供するプラグインとしてInspectionLensがある。おすすめ
cmd + shift + [
と cmd + shift + ]
が振られているselect previous tab
と select next tab
が該当のコマンドCircleCIの設定ファイルcircle.ymlをメンテナンスすることは、往々にして難しいです。YAMLの書式に苦戦したり、JSON Schemaによる補完が十分ではない場合があります。この記事では、TypeScriptを使ってCircleCI設定の問題を解決する方法を紹介します。
YAMLを直接書くことは煩雑で、アンカーを使って回避する方法も癖があります。また、JSON Schemaによる補完はある程度効果があるものの、十分強力ではないため、困難な状況がしばしば発生します。
circleci-config-sdk-tsは、CircleCIの設定を扱うための公式のライブラリですが、宣言的ではないため、思ったように書くことができません。
TypeScriptを使って以下の手順で問題を解決できそうです。
以下で実際に型を生成するアイディアをまとめます
JSON Schemaからtypescirptの型を生成するパッケージがあるため、それもとに生成することができます。
config referenceを読ませて型を生成させる事もできます。
実際に生成させてみましたが、ある程度使えそうなものを出すことができました
実際にconfig.ymlを作る場合は以下のように型を使えばいい感じに型チェックができます
import { type JSONSchemaForCircleCIConfigurationFiles } from "./types/circleci-config-types";
import { dump } from "js-yaml";
import fs from "fs";
const config: JSONSchemaForCircleCIConfigurationFiles = {
version: 2.1,
jobs: {
build: {
docker: [
{
image: "circleci/<language>:<version TAG>",
auth: {
username: "mydockerhub-user",
password: "$DOCKERHUB_PASSWORD",
},
},
],
steps: [
"checkout",
"setup_remote_docker",
{
setup_remote_docker: {
version: "20.10.18",
},
},
{
run: 'echo "this is the build job"',
},
],
},
test: {
docker: [
{
image: "circleci/<language>:<version TAG>",
auth: {
username: "mydockerhub-user",
password: "$DOCKERHUB_PASSWORD",
},
},
],
steps: [
"add_ssh_keys",
{
run: 'echo "this is the test job"',
},
],
},
},
workflows: {
version: 2,
build_and_test: {
jobs: ["build", "test"],
},
},
};
fs.writeFileSync("output.yaml", dump(config));
今後の展望として、以下の改善が考えられます。
今回紹介した手法を活用することで、CircleCIの設定ファイルの管理がスムーズになり、エラーや誤りを減らすことが期待できます。
以上の文章は適当にtl;drを作った上でchat GPTにだいたい書いてもらいました。いい感じの文章が出てきたので、ソレに適切にリファレンスを追加するだけで完了したので楽でした。
だいたいのプロンプト
https://mkusaka.com/ の文調を参考に、以下の概要を満たすようなブログを書きなさい
# tl;dr
## circleciのyamlを書く/メンテンするのは辛い
- yamlを生で書くのは辛い
- 回避するためのアンカーも癖がある
- json schemaによる補完もある程度効くが、そこまで強くないので困る事が多い
## [circleci-config-sdk-ts](https://github.com/CircleCI-Public/circleci-config-sdk-ts)があるが、宣言的ではないので思ったようにはかけない
## これらはtypescriptで補完させながら対応することで解消できそう
1. 何らかの方法でtypescript用の型を作成
2. 型に合致するようにjs objectを作る
3. js-yamlでjs objectをyamlに変換
### typescript用の型を作成する方法
- json schemaから生成する方法
- json schemaから型を生成し、それにマッチするようにjavascriptのobjectを書く
- chat gptにconfig referenceから生成させる方法
- config referenceを読ませることで型を生成させる
だいたい生成できた結果を載せる
- https://github.com/mkusaka/ciconfig
- https://www.typescriptlang.org/
## 次の1手
- zod schemaによる検証を加えたい
- typescriptだとmin/max/regex/defaultなどの検証ができないので、zod schemaに翻訳させたい(現状は適切な変換ができていない)
- デフォルトのものは自動で生成させるようにしたい
- 同じことをgithub workflow/github actionsでもできるはず
- actionlintのようにgithub actionsの独自構文内の諸々にも対応できると良さそう
OpenAPI Specification は web api のリクエスト・レスポンスの言語によらないインターフェイスを提供するための仕様で openapi-generator はそこから自動的にクライアントのコードを生成するツールです。
同様にクライアントコードを生成するツールはたくさんありますが、openapi-generator は多くの言語/FW をサポートしており、またダウンロード数などを見てもデファクトに近いような形で使われているようです。
typescript 向けのものに関しては fetch をクライアントとして利用する typescript-fetch や axios をクライアントとして利用する typescript-axios などがあります。
OpenAPI Specification は enum をサポートしており、OpenAPI Generator はこれを各言語で対応する表現にしてコードを生成します。
typescript-fetch 向けの生成においては、今までこれを typescript の enum に変換していました。
# original.yaml
openapi: 3.0.0
# ...
paths:
# ...
/pet/findByStatus:
get:
# ...
parameters:
- name: status
in: query
# ...
schema:
type: array
items:
type: string
enum:
- available
- pending
- sold
export enum FindPetsByStatusStatusEnum {
Available = "available",
Pending = "pending",
Sold = "sold",
}
ここで利用されている typescript の enum はtree shaking との相性やtypescript 独自のものになってしまっていたり、型安全ではないような事があったりなどの懸念が指摘されているのもあり、利用を控えたい人も少なからず存在する状況です。実際こちらの記事などでは OpenAPI Generator によって enum が生成されてしまうという箇所が懸念として指摘されています。
個人的のもこの点はどうにかしたいと思っていたため、OpenAPI Generator 本体に Union として出力できるオプションを追加するPull Requestをマージしてもらいました。
オプション実装後、この動作はデフォルトで有効になり、以下のようなコードを生成するようになります。
export const FindPetsByStatusStatusEnum = {
Available: "available",
Pending: "pending",
Sold: "sold",
} as const;
export type FindPetsByStatusStatusEnum =
typeof FindPetsByStatusStatusEnum[keyof typeof FindPetsByStatusStatusEnum];
元の enum を生成する挙動のままとしたい場合 は stringEnums オプションを true にすると元の挙動のままになります。(ex: )
※この実装は typescript-axios に対して実装されたもの をそのまま借用している形で実装されいています。個人的には const で宣言した変数と同一の名前で宣言した type がうまく動くのが割と面白いなと思って実装していました。
stringEnums オプションが実装されたバージョンはまだリリースがされていません(2022 年の 5 月以降になる予定ですが、現状は決まっていません)。今すぐ利用をしたい場合はdockerの latest であれば利用ができます。
# enumのままとしたい場合
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/spec.yaml -g typescript-fetch -o local/generated/ -p stringEnums=true
# union型を生成したい場合(デフォルトでunionを生成するので、オプションの指定は不要)
docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i /local/spec.yaml -g typescript-fetch -o local/generated/
現在 OpenAPI Generator は次のメジャーバージョン向けての準備中であるため、いくつかの fallback なしの breaking changes が含まれている場合があることには注意が必要です。