Gradleプラグインを使用して、AWS CodeArtifactを使いやすくする


[KINTO Technologies Advent Calendar 2021 - Qiita](https://qiita.com/advent-calendar/2021/kinto-technologies) の23日目の記事です。

## なぜCodeArtifactを使用するのか？

弊社のように、多くの企業は毎日内部使用のためにアーティファクトを生成しているため、インハウスのMavenレポジトリを用意する必要があります。いくつかの代替ソリューションを検討し、最終的にCodeArtifactを選択しました。これは主に、ほとんどのシステムがすでにAWSでホストされており、追加のメンテナンスが必要ないためです。

## 日常の使用上の問題は？

CodeArtifactでは、ユーザーはAWSクレデンシャルを使用して認証トークンを作成する必要があります。トークンの有効期間はわずか12時間であるため、ローカル環境とCI環境で手動で頻繁にトークンを取得することはプログラマーにとって厄介なことです。ほとんどのプロジェクトはGradleを使用しているため、CodeArtifactに対して自動的に認証され、必要なトークンを使用してリポジトリにアクセスできるプラグインを探しました。

## プラグインの使い方は？
- プラグインを使用する前に、[AWS CLI](https://aws.amazon.com/cn/cli/
)がローカルにインストールされていることを確認してください。そして、次のコマンドを使用して、AWSクレデンシャルをローカルプロファイルに設定します。
`aws config --profile your-profile-name`

- 次に、上記の`your-profile-name`を環境変数`CODEARTIFACT_PROFILE`に設定します。

- 次に、build.gradleに次のコンテンツを追加するだけです。
 
```groovy
plugins {
  //Latest version on https://plugins.gradle.org/plugin/ai.clarity.codeartifact
  id 'ai.clarity.codeartifact' version '0.0.12' 
}

repositories {
  maven {
    //Your CodeArtifact repository's endpoint  
    url 'https://domain-id.d.codeartifact.eu-central-1.amazonaws.com/maven/repository/' 
  }
}

publishing {
  repositories {
    maven {
      //Your CodeArtifact repository's endpoint
      url 'https://domain-id.d.codeartifact.eu-central-1.amazonaws.com/maven/repository/' 
    }
  }
}
```


プラグインのソースコードは次から参照できます。
https://github.com/clarityai-eng/codeartifact-gradle-plugin


## CodeArtifactからGradleカスタムプラグインを取るにはどうすればいいの？

AWS CodeArtifactリポジトリでホストされているGradleカスタムプラグインを使用する場合は、個別対応が必要です。 カスタムプラグインのMavenライブラリは通常、`setting.gradle`の`pluginManagement`で設定されます。 Gradleによるプラグインの分析は他の依存関係よりもはるかに早く行われるため、上記の`ai.clarity.codeartifact`プラグインを`build.gradle`に適用しても、`pluginManagement`でカスタムプラグインのMavenリポジトリ（CodeArtifact）を利用することはできません。

したがって、`setting.gradle`を解析する前に、トークンを取得して設定する必要があります。 次のコードを`init.gradle`に追加したら、CodeArtifactのトークンを取得し、`pluginManagement`に設定することできます。
~/.gradle/init.gradle

```groovy
initscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.amazonaws:aws-java-sdk-codeartifact:1.12.108'
    }
}


import com.amazonaws.services.codeartifact.AWSCodeArtifactClient;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.codeartifact.model.GetAuthorizationTokenRequest;
def setAuthorizationToken = {mavenArtifactRepository ->
    def profile = System.getenv("CODEARTIFACT_PROFILE")
    println "aws profile for codeartifact: [$profile]"
	def domainLevels = mavenArtifactRepository.url.getHost().split('\\.')
	def artifactDomain = domainLevels[0].substring(0,domainLevels[0].lastIndexOf("-"))
	def artifactOwner = domainLevels[0].substring(domainLevels[0].lastIndexOf("-")+1)
	def region = domainLevels[domainLevels.length -3]

	def client = AWSCodeArtifactClient.builder()
		.withCredentials(new ProfileCredentialsProvider(profile))
		.withRegion(region)
	.build();

	def result = client.getAuthorizationToken(new GetAuthorizationTokenRequest()
		.withDomain(artifactDomain)
		.withDomainOwner(artifactOwner)
	);

	mavenArtifactRepository.credentials {
		username "aws"
		password result.authorizationToken
	}
}

settingsEvaluated { settings ->
    settings.pluginManagement {
        repositories {
            maven {
                url = "https://domain-id.d.codeartifact.eu-central-1.amazonaws.com/maven/repository/"
                setAuthorizationToken(owner)
            }
        }
    }
}
```

## プラグインを使用しなくてもいいの？

Gradleプラグインをまったく使用せずに、リポジトリが定義されているところに、AWSCLIの呼び出しを追加することもできます。 コードは次のとおりです。事前に環境変数にAWSプロファイルを設定しておく必要があります。

```groovy
repositories {
  maven {
    //Your CodeArtifact repository's endpoint  
    url 'https://domain-id.d.codeartifact.eu-central-1.amazonaws.com/maven/repository/'
    credentials {
        def AWSCLI = "aws codeartifact get-authorization-token --domain domain-id --domain-owner owner-account-id --query authorizationToken --output text"
        def CODEARTIFACT_PROFILE = System.env.CODEARTIFACT_PROFILE
        username "aws"
        password CODEARTIFACT_PROFILE == null ?
                AWSCLI.execute().text :
                "$AWSCLI --profile $CODEARTIFACT_PROFILE".execute().text
    }
  }
}
```

当社では、トヨタ車のサブスク「KINTO」等の企画/開発を行っており、エンジニアを募集中です。
[KINTO Technologies コーポレートサイト](https://www.kinto-technologies.com)

## 参考

- [*Clarity CodeArtifact Gradle plugin*](https://plugins.gradle.org/plugin/ai.clarity.codeartifact)
- [*GitHub repository*](https://github.com/clarityai-eng/codeartifact-gradle-plugin)
- [*AWS CodeArtifact authentication and tokens*](https://docs.aws.amazon.com/codeartifact/latest/ug/tokens-authentication.html)
- [*Use CodeArtifact with Gradle*](https://docs.aws.amazon.com/codeartifact/latest/ug/maven-gradle.html)
- [*Developing Custom Gradle Plugins*](https://docs.gradle.org/current/userguide/custom_plugins.html)