導入

対象 : すでに "magiques" または予期しないビルドの挙動に遭遇した Gradle 開発者

私たちのプラグイン作成の冒険で`site-baker`, 我々は TDD を厳格に実践しました。各機能はテストされ、検証され、そして我々は確信を持って進んでいきました。そしてある日、予期せぬことが起こりました。ビルドは予測不能な動作を始めました。プラグインのロジックや設定ファイルの変更が無視されているかのように見え、かつて信頼できた機能テストも理由もなく失敗し始めました。

この種の問題は信じがたいほどイライラさせることがあります。これはツールの信頼性と私たちのコードの妥当性を疑問視します。激しいデバッグセッションの後、犯人が特定されました:そのGradleの設定キャッシュ。

症状:幽霊ビルド

問題は様々な形で現れていた:

  1. タスク内の文字列を編集していた`println`, しかし古い文字列は実行時に表示され続けた。

  2. ファイルの中で値を変更していた。`managed-jbake-context.yml`しかし、プラグインはファイルが変更されていないかのように振る舞った。

  3. 機能テストは、その場でテストプロジェクトを作成するものですが、プラグインが新しく作成された設定ファイルを検出しているようには見えず、失敗していました。

まるで Gradle が私たちのビルドの「幽霊バージョン」を実行しているかのように、すべてが進行していました。最新の変更を無視して。

調査:構成キャッシュとは何ですか?

構成キャッシュは、比較的新しい機能であり、Gradleの非常に強力な機能です。新しいバージョンではデフォルトで有効になっています。その目的は、ビルドをより速くすることです。

原理は単純です:
  1. 最初の実行時に、Gradle は フェーズ を実行します設定(の読み取り`build.gradle.kts`, タスクの作成, 依存関係の解決) と タスクグラフを構築します。

  2. このフェーズの終わりに、Gradleこのタスクグラフをシリアライズしてそしてそれをキャッシュに保存します。

  3. 次の実行時に何も変更されていない場合(ビルドスクリプトが,gradle.properties, など), Gradle設定フェーズを完全にスキップするそしてキャッシュされたタスクグラフを再利用します。

大規模なプロジェクトでは時間の節約が驚くほど顕著です。ただし、このパフォーマンスにはコストが伴います:プラグインの記述方法に厳格なルールを課します。

構成キャッシュのライフサイクル
@startuml
start
:Première exécution;
:Phase de Configuration;
:Création du graphe de tâches;
:Mise en cache du graphe;
:Phase d'Exécution;
end

start
:Exécution suivante;
if (Cache valide ?) then (oui)
  :Restauration du graphe depuis le cache;
  note right
    La phase de configuration
    est sautée !
  end note
else (non)
  :Phase de Configuration;
  :Mise à jour du cache;
endif
:Phase d'Exécution;
stop
@enduml

問題の原因: 適合していないプラグイン

私たちのプラグイン`site-baker`無意識のうちに、設定キャッシュのいくつかのルールを違反していた。タスクグラフがシリアライズ可能であるためには、タスクはオブジェクトなどの複雑なオブジェクトへの参照を含んではならない。`Project`または、実行フェーズ中に任意のファイルを読み込むことができます。

私たちの主な間違いは、タスクの実行ロジック内でYAMLファイルの内容を直接読み込んでいたことです。これは、拡張機能に保存されているパスへの参照を使用して行われました。このアプローチは、この読み込みがモデル化されていないような場合、Gradleがファイルの内容が変更されたかどうかを知ることができないため、キャッシュと互換性がありません。タスクエントリ (Task Input).

一時的なソリューション:キャッシュを無効にする

私たちのブロックを解除し、予測可能なビルド動作を取り戻すために、最も速い方法は設定キャッシュを無効にすることでした。ファイルに以下の行を追加するだけです`gradle.properties`プラグインを使用しているプロジェクト(または私たちの場合、テストプロジェクト)の`site-baker`).

# site-baker/gradle.properties
org.gradle.configuration-cache=false

瞬時に、ビルドは通常の動作を取り戻しました。各実行が構成フェーズを再起動し、私たちの変更が考慮されました。

ただし、これは回避策であり、持続可能な解決策ではありません。パフォーマンスを犠牲にし、プラグインの根本的な問題を解決しません。

真の解決策:プラグインを互換性を持たせる

プラグインが現代のGradleエコシステムの良い市民であるためには、設定キャッシュと互換性がある必要があります。これは、データがタスクに流れる方法を見直すことを意味します。

キーはそれらを使うことですプロバイダーのAPIGradleの。 直接の値を渡す代わりに(例えば`String` ou un File) 私たちのタスクに対して、私たちは何かを通過しなければならない`Property<T>`または`Provider<T>`.

以下はリファクタリング計画です:
  1. タスクエントリを宣言する :YAMLファイルをパースするタスクは、このファイルを入力として宣言しなければなりません。そのためにアノテーションを使用します。@InputFile。

[source,kotlin] python


関連記事