Gradle SSH Plugin 2.4.0をリリースした
Gradle SSH Plugin 2.4.0、Groovy SSH 2.4.0をリリースしました。
2.4.0の変更点
New features:
- Host key checking for gateway access
- Put files filtered by given closure
- Get files filtered by given closure
- Add ssh.runtime object in CLI
Bug fixes:
- Skip lecture message from sudo result
- Specify null as UserInfo to prevent changing known_hosts
Host key checking for gateway access
ゲートウェイサーバを経由して多段接続する場合でも known_hosts
が使えるようになりました。例えば、localhost→A→Bのように踏み台Aを経由してBに接続する場合、Bは実際にはポートフォワードの接続先(localhost:xxxxx)に見えるため、ホスト鍵の検証に失敗する問題がありました。2.4.0からは known_hosts
に含まれるBをポートフォワードの接続先に読み替える実装を追加しました。
Get/Put files filtered by given closure
これまで get
put
メソッドはすべてのファイルを再帰的に転送する機能しか提供していませんでしたが、2.4.0からはクロージャでフィルタする機能も提供するようになりました。
get from: '/remote/folder', into: buildDir, filter: { it.name =~ /\.xml$/ } put from: buildDir, into: '/remote/folder', filter: { it.name =~ /\.xml$/ }
SFTP/SCP×GET/PUTのすべての組み合わせに手を入れる必要があったため、実装は随分と骨の折れる作業になりました。
Add ssh.runtime object in CLI
Groovy SSHのスタンドアロンJARを利用する場合に ssh.runtime.jar
でJAR自身を参照できるようになりました。これにより、リモートホストにJARを転送してスクリプトを実行する処理を簡単に記述できます。まあ、スタンドアロンJARのテストでうれしいだけかもしれませんが。
ssh.run { session(ssh.remotes.tester) { put from: ssh.runtime.jar, into: '.' execute 'java -jar gssh.jar --version' execute 'java -jar gssh.jar --help' } }
Skip lecture message from sudo result
sudoコマンドを実行して最初にlecture messageが表示された場合に、コマンドの実行結果にlecture messageが含まれてしまう問題を修正しました。
振り返り
ここに書いている以外にもOS Integration TestをすべてEC2に追い出すとか、Circle CIへの移行に取り掛かるといった改善をやっていました。ビルドやCIの改善に手を付け始めるとあっという間に時間を使ってしまい、気が付けば2.4.0のリリースが月末になってしまいました。
現状ではCIに7〜8分を要しているので、以下の改善に手を付けたいです。
- DockerのSSHコンテナを利用してOS Integration Testを実行する(EC2は廃止)
- Plugin Integration Testの対象バージョンを1系に限定する
- 効率的なキャッシュ
ITのビジネス価値を最大化するには
2016年になってもアジャイルはテストをしないとか、計画を立てないとか、1日10回デプロイするための技法といった誤解が広まっているのは残念すぎる。
まず、ITのビジネス価値を最大化するという視点が必要なはず。事業の売上や費用を改善するためにシステムを活用するのであって、システムを作ること自体は目的にならない。
事業を取り巻く環境は変化が速いので、ITもそれに合わせて変えていく必要がある。1年後にシステムが完成したら事業環境が変化していて役に立たないかもしれない。投資が無駄になるリスクを抑えるために、数週間で軌道修正を繰り返す。
だから、事業環境の変化にITを対応させるためにアジャイルが必要、という話の流れになるはず。システムを作るためにアジャイルが必要とはならない。事業上の必要性からアジャイルを選択する。
ここまできて初めて、ITのビジネス価値を最大化するためにスプリントや自動デプロイといったやり方が出てくる。やり方だけでは不十分で、事業と開発が一体になるための組織構造や開発スキルを評価するための人事制度も必要になる。そもそも、事業環境の変化に対応できる事業計画の立て方が必要なはず。
なので、適度に偉い人が「事業上の必要性」を言い出して「事業環境の変化が速い領域」で試行錯誤するのが王道なんじゃないかなぁ。これはEnterpriseでもServicerでも同じはず。クラウドもこんな感じで広まったはず。
もうアジャイルという言葉をやめた方が誤解が生じなくてよいのでは。マックスバリューデベロップメントあたりでいいと思う*1。
*1:誰か突っ込んでくれるかな
TestKitによるGradleプロジェクトのテスト
最近のGradleで導入されているTestKitを使ってみたのでメモします。
TestKitでできること
TestKitを利用すると、Gradleプロジェクトに対するテストを実行できます。例えば、何かの設定ファイルを自動生成するタスクをGradleで定義している場合に、そのタスクに対するテストコードを記述できます。TestKitはSpockと併用できるので、BDDスタイルでテストコードを書くこともできます。
この仕組みを応用すると、Gradleプラグインを適用したプロジェクトに対するテストを実行できます。Gradleプラグインの受け入れテストとも言えますね。詳細は The Gradle TestKit - Gradle User Guide Version 2.14 を参照してください。
使い方
ここでは、テスト対象のプロジェクトがGradle 2.13と1.12の両方でちゃんと動作するかテストする例を考えます。
build.gradle
- テストを実行するプロジェクトsrc/test/groovy/ExampleSpec.groovy
- テストコードfixture/build.gradle
- テスト対象のプロジェクト
まず、テスト対象のプロジェクトを作ります。単にGradleバージョンを表示する雑なビルドスクリプトにしておきます。
// fixture/build.gradle task show << { println gradle.gradleVersion }
それから、TestKitを利用してテストを実行するプロジェクトを作ります。
// build.gradle plugins { id 'groovy' id 'java-gradle-plugin' } repositories { jcenter() } dependencies { testCompile('org.spockframework:spock-core:1.0-groovy-2.4') { exclude module: 'groovy-all' } }
// src/test/groovy/ExampleSpec.groovy import org.gradle.testkit.runner.GradleRunner import spock.lang.Specification import spock.lang.Unroll class ExampleSpec extends Specification { @Unroll def "test should be success on Gradle #version"() { when: GradleRunner.create() .withProjectDir(new File('fixture')) .withArguments('show') .withGradleVersion(version) .forwardOutput() .build() then: noExceptionThrown() where: version << ['2.13', '1.12'] } }
テストを実行してみます。
./gradlew check
テストレポートを確認すると、テストケースが2つ実行されて、それぞれ2.13と1.12が表示されていることがわかると思います。
Gradle SSH Pluginへの適用
Gradle SSH PluginはGradle 1系も動作対象に含めているため、受け入れテストを2.13と1.12で実施しています。これまではGradle Wrapperのプロパティファイルを無理やり書き換えて複数のバージョンでテストを実行しましたが、TestKitを利用することで独立した環境でテストを実行できるようになりました。
以下の流れでビルドを実行しています。
- プラグインプロジェクトをビルドする(
test
) - プラグインプロジェクトの成果物をMaven Localにリリースする(
publishToMavenLocal
) - 受け入れテストプロジェクトではMaven Localに存在するプラグインを適用する(
buildScript
のrepositories
でmavenLocal()
を指定し、apply plugin
を実行) - 受け入れテストプロジェクトを実行する
プラグインの受け渡しはGradle 2.8以降であれば withPluginClasspath()
が使えるのですが、今回はGradle 1系でテストする必要があるのでMaven Localを採用しました。
TestKitはプラグイン開発者には便利かもですね。