LoginSignup
8

More than 1 year has passed since last update.

Dartで書くタスクランナー Grinderのススメ

Posted at

概要

Grinder とはDart で実装されたタスクランナーです。
あまり聞かないかもしれませんが、Flutterの公式サンプルでも導入されていたりします。

今回は導入方法からビルドタスクの書き方を紹介したいと思います。

Flutterの公式サンプルを確認したい方は下のリンクからどうぞ
https://github.com/flutter/samples/blob/master/web/samples_index/tool/grind.dart

Version

  • Flutter
    • version: 1.22.4
    • channel: stable
  • Grinder
    • version: 0.8.6

Grinder のインストール

Grider のinstallを参考に進めていきます。
プロジェクトに対してビルドタスクを追加するので、1つFlutterプロジェクトを開いてください。

Grinder を有効にする

$ flutter pub global activate grinder

Grinderが有効になっているかを確認します。
grind と打って実際に動くか確認しましょう。
Grinderという名前ですがコマンドはgrindです。

$ grind

まだビルドタスクの設定ファイルを作成していないので、下記のようなエラーが出ると思います。
Error: expected to find 'tool/grind.dart' relative to the current directory.
あとで設定ファイルを作成するので、今は無視してください。

基本的な使い方

プロジェクトルートに tool/grind.dartというファイルを作成します

ビルドタスクを追加する

以下はdart analyzeを実行するビルドタスクです。

grind.dart
import 'package:grinder/grinder.dart';

main(List<String> args) => grind(args);

/// 静的解析
@Task('analyze')
void analyze() {
  Analyzer.analyze(['./lib']);
}

追加した静的解析のタスクを実行する

grind analyze で実行できます。
今回はわざと警告が出るようにしているので、以下のメッセージが表示されています。

$ grind analyze
grinder running analyze

analyze
  /Users/0maru/development/flutter/bin/cache/dart-sdk/bin/dartanalyzer ./lib/main.dart
  Analyzing lib/main.dart...
    lint • Prefer using lowerCamelCase for constant names. • lib/main.dart:9:16 • constant_identifier_names
  1 lint found.

finished in 7.9 seconds

追加したビルドタスク一覧を確認する

grind -h で登録しているタスク一覧を確認できます。

$ grind -h
Dart workflows, automated.

Usage: grinder [options] [<tasks>...]

Global options:
  --no-color           Whether to use terminal colors.
  --version            Reports the version of this tool.
  -h, --help           Print this usage information.

Available tasks:
  test                 unit test
                       (depends on: analyze)
  build                build
                       (depends on: test)
  analyze              analyze
  pub                  pub get
  runner               run build_runner

色々なビルドタスクを追加してみる

以下は、アプリのビルドやユニットテストを実行できるビルドタスク

grind.dat
import 'dart:io';
import 'dart:async';
import 'dart:convert';

import 'package:async/async.dart' show StreamGroup;
import 'package:grinder/grinder.dart';

main(List<String> args) => grind(args);

/// flutter pub get
@Task('pub get')
void pub() {
  _processLog(Process.start('flutter', ['pub', 'get']));
}


/// build_runner でファイルを生成
@Task('run build_runner')
void runner() {
  _runProcess(
      'flutter',
      ['pub', 'run', 'build_runner', 'build', '--delete-conflicting-outputs'],
  );
}

/// 静的解析
@Task('analyze')
void analyze() {
  Analyzer.analyze(['./lib']);
}

/// ユニットテスト
@Task('unit test')
@Depends(analyze) // 先にanalyzeを実行する
void test() {
  TestRunner().test(files: 'test/unit');
}

/// 静的解析・ユニットテストを行ったのちビルドする
@Task('build')
@Depends(test) // 先にtestを実行する
void build() {
  TaskArgs args = context.invocation.arguments;

  final mode = args.getOption('mode');
  log(mode);
  if (mode?.isEmpty ?? true) {
    throw Exception('mode option is required.');
  }

  // APサーバ、データベースの接続先などを指定する環境変数
  final isRelease = args.getFlag('release');
  final env = isRelease ? 'release' : 'staging';

  _processLog(Process.start(
    'flutter',
    ['build', mode, '--dart-define=ENV=${env}']
  ));
}


// ビルド中にログを出力する方法1
Future<void> _processLog(Future<Process> process) async {
  final _process = await process;
  final output = StreamGroup.merge([_process.stdout, _process.stderr]);
  await for (final message in output) {
    log(utf8.decode(message));
  }
}

// ビルド中にログを出力する方法2
Future<void> _runProcess(String executable, List<String> arguments) async {
  final result = await Process.run(executable, arguments);
  stdout.write(result.stdout);
  stderr.write(result.stderr);
}

Github Actions でGrinderを利用する

Grinder で作成したビルドタスクはGithub Actions やTravis CI で使用することができます
以下Github Actions のサンプル

build.yaml
name: Dart

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 2
    steps:
      - uses: actions/checkout@v2
      - uses: subosito/flutter-action@v1
        with:
          flutter-version: '1.22.x'
          channel: 'stable'
      - run: flutter pub get
      - name: test
        run: dart tool/grind.dart analyze

まとめ

いかがでしたか?
Dart で書かれているので型を書くことができたり、CIサービスと同じ流れでローカルでもビルドができたりなどGrinderを使用するメリットはあるかと思います。
Makefileが早いだのシェルスクリプトで良いだのと言われるとそこまでなのですが、一度使ってみて快適なDartライフをお送りください。

今回作成したプロジェクトです
コード全体を見たい方は以下からどうぞ
https://github.com/0maru/grinder_sample

Twitterもやってます。
良ければフォローしてください。
https://twitter.com/0maru_dev

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
8