·ci

CircleCI設定の痛みをTypeScriptで解消するアイディア

CircleCI設定ファイルの編集やメンテナンスの悩みを解決するため、TypeScriptを活用する方法を紹介。

18 min read
Writing style

tl;dr

  • circleciのyamlを書く/メンテンするのは辛い
  • javascirpt objectをjs-yamlでdumpするようにすればtypescirptの補完が受けられる
  • typescirptの型生成の方法はいくつかありそうだが、現状仕様変更に追従するのが厳しそう

CircleCI設定の痛みをTypeScriptで解消するアイディア

CircleCIの設定ファイルcircle.ymlをメンテナンスすることは、往々にして難しいです。YAMLの書式に苦戦したり、JSON Schemaによる補完が十分ではない場合があります。この記事では、TypeScriptを使ってCircleCI設定の問題を解決する方法を紹介します。

YAMLの悩み

YAMLを直接書くことは煩雑で、アンカーを使って回避する方法も癖があります。また、JSON Schemaによる補完はある程度効果があるものの、十分強力ではないため、困難な状況がしばしば発生します。

circleci-config-sdk-tsの限界

circleci-config-sdk-tsは、CircleCIの設定を扱うための公式のライブラリですが、宣言的ではないため、思ったように書くことができません。

TypeScriptで解決

TypeScriptを使って以下の手順で問題を解決できそうです。

  1. TypeScript用の型を作成する
  2. 型に合致するJavaScriptオブジェクトを作成する
  3. js-yamlでJavaScriptオブジェクトをYAMLに変換する
  4. TypeScript用の型を作成する方法
  5. 型を作成するには、以下の方法が考えられます。

以下で実際に型を生成するアイディアをまとめます

JSON Schemaから生成する方法

JSON Schemaからtypescirptの型を生成するパッケージがあるため、それもとに生成することができます。

Chat GPTにconfig referenceから生成させる方法

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));

さらなる改善

今後の展望として、以下の改善が考えられます。

  • npm packageとして公開
  • Zodスキーマによる検証を追加
    • TypeScriptでは、min/max/regex/defaultなどの検証ができないため、Zodスキーマに変換したい(現状では適切な変換ができていない)
  • デフォルトの設定を自動生成させるようにしたい
  • GitHub Workflow/GitHub Actionsでも同様のことができるはず
    • actionlintのように、GitHub Actionsの独自構文内の諸々にも対応できると良いでしょう
    • 以上で、CircleCI設定ファイルの書き方やメンテナンスが、TypeScriptを利用することでより容易になります。

今回紹介した手法を活用することで、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の独自構文内の諸々にも対応できると良さそう