【Gradle】プロキシ環境下でプラグインを利用する

# はじめに

最小構成のテンプレートで`gradle build`コマンドを打ったのに、なぜかエラーで通らない人のための記事です。
主にプロキシ環境だったりファイアウォールなどが原因で発生するものを挙げています。

具体的なエラーは以下。

* plugin not found
* The server may not support the client's requested TLS protocol versions

# 環境
| ツール       | バージョン   |
|:-------------|:------------|
| Gradle       | 7.3.3       ​|
| OS           | Windows 10  ​|

コマンドはGit Bashで叩いています。

# plugin not found

```sh
user@DESKTOP-HOGE MINGW64 /programPath/demo
$ gradle build

FAILURE: Build failed with an exception.

* Where:
Build file 'C:\programPath\demo\build.gradle' line: 3

* What went wrong:
Plugin [id: 'io.spring.dependency-management', version: '1.0.11.RELEASE'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (could not resolve plugin artifact 'io.spring.dependency-management:io.spring.dependency-management.gradle.plugin:1.0.11.RELEASE')
  Searched in the following repositories:
    MavenRepo

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
```

プロキシ環境下では、主にGradle Core Pluginsに接続できない場合に発生するエラー。
または、指定したプラグインがGradle Core Pluginsにない場合。

Gradleでは、Gradle Core Plugins以外から取得したモジュールをプラグインとして利用する場合は
外部プラグインとして、明示的に使用するモジュールを定義する必要があります。

### 1.Gradle Core Plugins以外から取得する

社内アーティファクトリが存在するなど、Gradle Core Pluginsに繋げないが接続できるレポジトリ自体はあるという場合は、`settings.gradle`ファイルの頭に以下の記載を追記するだけで完了します。

```settings.gradle
pluginManagement {
	repositories {
		maven {
			url 'http://hoge.repository'
			allowInsecureProtocol true
		}
		mavenCentral()
		gradlePluginPortal()
	}
	resolutionStrategy {
		eachPlugin {
			switch (requested.id.id) {
				case 'io.spring.dependency-management':
					useModule "io.spring.gradle:dependency-management-plugin:${requested.version}"
					break
			}
		}
	}
}
```

利用プラグインが増えた際には`case`配下を追加して対応してください。

`${requested.version}`の部分は明示的にバージョンを指定しても問題ありませんし、`gradle.properties`でも設定できるようです。
参考：[Using Gradle Plugins#plugin_version_management](https://docs.gradle.org/current/userguide/plugins.html#sec:plugin_version_management)

繋げるレポジトリが無い？
→ 2.ローカルでレポジトリを構成する へ

### 2.ローカルでレポジトリを構成する
Gradle Core Pluginsに接続できず、その他利用できるレポジトリも存在しないとき、
ブラウザでパブリックレポジトリが開ける、または別環境では接続できるなど、何かしらの方法でモジュールだけであれば取得できる場合。
ローカル環境にモジュールを置いて使いましょう！

まずは以下を追記。

```settings.gradle
pluginManagement {
	repositories {
		maven {
			url "${rootProject.projectDir}/libs" // プラグインを格納予定のフォルダ
		}
```
プロジェクトルートに作成した`libs`フォルダをローカルレポジトリとします。
今回の例では、`io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE`を配置してみます。

モジュールを手に入れます。私はMaven Central Repositoryから取得しました。
https://repo1.maven.org/maven2/io/spring/gradle/dependency-management-plugin/1.0.11.RELEASE/

これを、mavenのレポジトリ構成に従って`${rootProject.projectDir}/libs/`（ローカルレポジトリとして利用するフォルダ）に格納します。
以下のようになりました。
![dilectory](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522187/0f3e1f38-bf4d-0162-26a4-92a960ebe6da.png)
モジュール：`io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE`
フォルダ構成：`【レポジトリルート】/io/spring/gradle/dependency-management-plugin/1.0.1.RELEASE/`

これでプラグインとして利用できます！

このローカルレポジトリを作成する方法は`build.gradle`の`dependency`ブロックにも有効です。
その際は`build.gradle`にも別途レポジトリの定義をしてください。

#The server may not support the client's requested TLS protocol versions

```sh
The server may not support the client's requested TLS protocol versions: (TLSv1.2). You may need to configure the client to allow other protocols to be used.
See: https://docs.gradle.org/6.8.3/userguide/build_environment.html#gradle_system_properties
  > sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
```

※自宅の環境で再現できなかったため、上記メッセージは同様のエラーが発生した質問よりお借りしています
[→引用元](https://stackoverflow.com/questions/69180079/how-to-resolve-gradle-tls-connection-after-upgrading-from-5-4-to-6-8-3)

直訳するとサーバーがTLS1.2に対応してないよ！という文言ですが、プロキシ環境であればおそらく証明書エラーです。
`build gradle`を叩いているツール（BashまたはEclipse、STSなど）が見ているJDKに対して証明書のインストールを行うことで解消することができます。

### 証明書のインストールをする
証明書を取得して以下のコマンドを打ちます。
`keytool -import -alias 【証明書のエイリアス】 -keystore 【JDKのPATH】/lib/security/cacerts -file 【証明書のファイル名】.cer`
キーストアのパスワードを求められたら`changeit`を入力してください。

以下で登録を確認することができます。
`keytool -list -keystore 【JDKのPATH】/lib/security/cacerts -alias 【証明書のエイリアス】`

もしビルド結果に変更が無ければ、本当に証明書のインストールをしたJDKを見ているのか確認してみてください。
解決！

ちなみに本当にTLSエラーである場合、特にJDK7以下バージョンを利用している方は此方を参照してみてください。
[Why am I getting "Received fatal alert: protocol_version" or "peer not authenticated" from Maven Central? - Stack Overflow](https://stackoverflow.com/questions/50824789/why-am-i-getting-received-fatal-alert-protocol-version-or-peer-not-authentic)

# 参考
[Gradleでプラグインを利用する方法 - mike-neckのブログ](https://mike-neck.hatenadiary.com/entry/2017/10/12/083000)
[Using Gradle Plugins](https://docs.gradle.org/current/userguide/plugins.html)
[GradleでローカルのMavenアーティファクトを参照する - Qiita](https://qiita.com/seijikohara/items/8bf05b0208e7f2661570)
[java - How to resolve gradle tls connection after upgrading from 5.4 to 6.8.3? - Stack Overflow](https://stackoverflow.com/questions/69180079/how-to-resolve-gradle-tls-connection-after-upgrading-from-5-4-to-6-8-3)
[Java環境に手動でグローバルサインのルート証明書をインストールする方法 | GMOグローバルサイン サポート](https://jp.globalsign.com/support/ssl/confinfo/rootcert-import-java.html)