Closed3

daggerを使ってGitHub Actionsでも使えるCIを書いてみるまでの道のり

bun913bun913

やりたいこと

  • GitHub Actions で実行できる超軽いCIを作りたい
    • 例えばRubyの場合は Brakeman などのツールで静的解析ができます
    • とはいえ、あくまで静的解析なのでチームで色々検討した上で「これは無視しよう」と決めることもあると思います
    • Brakemanには brakeman.ignore というファイルで特定の部分に対する特定のルールの適用を無視させることが可能です
    • Brakemanには note というフィールドがあり、除外した理由などをメモすることができます
    • 今回やりたいことはこのような note にあたるような項目を書いていない場合は、CIで自動的に失敗するといったことを自動化したいです
    • 最初は brakeman.ignore にだけ対応するスモールな感じで実現したいと思います

通るはずの道のり

以前以下のような記事を書いたことがあります。

https://dev.classmethod.jp/articles/dagger_nodejs_sdk_get_started/

dagger というツールでは、GitHub Actionsであろうとローカルであろうとさまざまな
環境でCIをプログラマブルに実装しようという試みがされています。

今回はこちらを使って、サクサクっと TypeScript でコードを書いていこうと思います

https://docs.dagger.io/quickstart/daggerize

bun913bun913

Dagger CLI のインストール

https://docs.dagger.io/quickstart/daggerize/

こちらに従って以下のコマンドで brew install を実施。

brew install dagger/tap/dagger

なお dagger コマンドを実行する際には docker コマンドが利用できる必要があります。

プロジェクト初期化

次にプロジェクトディレクトリを作成します。

mkdir why-dont-you-write-ignore-reason
mkdir why-dont-you-write-ignore-reason

dagger init コマンドで初期化します。

❯ dagger init --sdk=typescript --source=./dagger
✔ connect 0.2s
✔ cache request: mkfile /schema.json 0.0s
✔ load cache: mkfile /schema.json 0.0s
✔ moduleSource(refString: "."): ModuleSource! 0.0s
✔ ModuleSource.kind: ModuleSourceKind! 0.0s
✔ ModuleSource.resolveContextPathFromCaller: String! 0.0s
✔ ModuleSource.withName(name: "why-dont-you-write-ignore-reason"): ModuleSource! 0.0s
✔ ModuleSource.withSDK(sdk: "typescript"): ModuleSource! 0.0s
✔ ModuleSource.withInit: ModuleSource! 0.0s
✔ ModuleSource.withSourceSubpath(path: "dagger"): ModuleSource! 0.0s
✔ ModuleSource.resolveFromCaller: ModuleSource! 4.0s
✔ ModuleSource.asModule(engineVersion: "latest"): Module! 37.6s
✔ Module.generatedContextDiff: Directory! 0.0s
✔ Directory.export(path: "hoge/why-dont-you-write-ignore-reason"): String! 1.5s

以下のようにディレクトリなどが作成されました。

.
├── LICENSE
├── dagger
│   ├── package.json
│   ├── sdk
│   │   ├── LICENSE
│   │   ├── README.md
│   │   ├── api
│   │   ├── common
│   │   ├── connect.ts
│   │   ├── connectOpts.ts
│   │   ├── context
│   │   ├── entrypoint
│   │   ├── graphql
│   │   ├── index.ts
│   │   ├── introspector
│   │   ├── package.json
│   │   ├── provisioning
│   │   └── telemetry
│   ├── src
│   │   └── index.ts
│   ├── tsconfig.json
│   └── yarn.lock
└── dagger.json

Hello world

dagger login

オプショナルと書いてありますが、公式に従って dagger login を行って、認証・認可を行いました。

https://docs.dagger.io/quickstart/daggerize#visualizing-in-dagger-cloud-optional

ソースの初期状態

以下のようにファイルにコードが作成されています。

/**
 * A generated module for WhyDontYouWriteIgnoreReason functions
 *
 * This module has been generated via dagger init and serves as a reference to
 * basic module structure as you get started with Dagger.
 *
 * Two functions have been pre-created. You can modify, delete, or add to them,
 * as needed. They demonstrate usage of arguments and return types using simple
 * echo and grep commands. The functions can be called from the dagger CLI or
 * from one of the SDKs.
 *
 * The first line in this comment block is a short description line and the
 * rest is a long description with more detail on the module's purpose or usage,
 * if appropriate. All modules should have a short description.
 */
import { dag, Container, Directory, object, func } from "@dagger.io/dagger"

@object()
class WhyDontYouWriteIgnoreReason {
  /**
   * Returns a container that echoes whatever string argument is provided
   */
  @func()
  containerEcho(stringArg: string): Container {
    return dag.container().from("alpine:latest").withExec(["echo", stringArg])
  }

  /**
   * Returns lines that match a pattern in the files of the provided Directory
   */
  @func()
  async grepDir(directoryArg: Directory, pattern: string): Promise<string> {
    return dag
      .container()
      .from("alpine:latest")
      .withMountedDirectory("/mnt", directoryArg)
      .withWorkdir("/mnt")
      .withExec(["grep", "-R", pattern, "."])
      .stdout()
  }
}

そこでローカルで早速ハローワールド的に関数を呼び出してみましょう。

dagger call container-echo --string-arg="hey"

dagger cloud で以下のように結果を確認できました!

ローカルで実行できていい感じですね。

bun913bun913

やりたいことに対して、daggerで学ぶ必要のあることが結構あり、公開した後のことを考えて断念。

普通に GitHub Actions で公開して、CircleCIでも公開できるようにした方が早そう。(このくらいの規模だと特に)

このスクラップは2ヶ月前にクローズされました