Maven リポジトリを S3 上に構築して Leiningen から使う


外部に公開したくないライブラリをインハウスリポジトリに置いておきたいなーと思ったので知らべました。
それと自分が次に同じことをやらないといけないときに、毎回 Leiningen のドキュメントを読むのがしんどいので…。

## 必要なもの

- Leiningen 2.x
- AWS S3
- gpg

## デプロイ

まず簡単に適当なプロジェクトを作成します。

```
$ lein new cstap/my-private-lib
$ cd my-private-lib
```

そしたら `project.clj` を開き、次の記述を追加します。

```clj
  :profiles {:deploy {:deploy-repositories [["your-repo" {:url        "s3p://your-repo/"
                                                           :username   [:gpg :env/aws_access_key_id]
                                                           :passphrase [:gpg :env/aws_secret_access_key]}]
                                            ["releases" :your-repo]
                                            ["snapshots" :your-repo]]
                      :plugins             [[s3-wagon-private "1.2.0"]]}}
```

`"s3p://your-repo/"` のところは S3 のバケツ名を入力してください。

次に認証情報に関してですが、これは gpg を使うか、環境変数を利用するかで手順が違うので下に別途記載します。
認証情報を記述した後は `lein with-profile +deploy deploy` と実行します。これでデプロイができました。

- [s3-wagon-private](https://github.com/technomancy/s3-wagon-private)

## 認証について

### gpg を利用する場合

`~/.lein/credentials.clj` を作成し以下のように記述します。

```clj
{"s3p://your-repo/"
 {:username   "your-aws-access-key"
  :passphrase "your-aws-secret-access-key"}}
```

これを `gpg --default-recipient-self -e ~/.lein/credentials.clj` として `~/.lein/credentials.clj.gpg` を作成します( `~/.lein/credentials.clj` は忘れずに削除しましょう )。

これで OK です。

また複数の鍵を使っている場合は下ようなの記述を `project.clj` へと追加しておくと便利です。

```clj
:signing {:gpg-key "your-gpg-key"}
```

### 環境変数を利用する場合

`:env/aws_access_key_id` と設定している場合、環境変数 `AWS_ACCESS_KEY_ID` を探しに行くのでそのように設定しておけば OK です。

## リリース

Leiningen にはリリース時に行なう作業をまとめてくれる機能があるので、それを利用する場合の話についても簡単に記述しておきます。

通常であれば、単に `lein release` とするところですが、 S3 にデプロイしたいので少し修正しましょう。

`project.clj` に次のように記述します(ちなみに `deploy` profile を設定しているからこのようにしないといけないのであって、 `deploy` profile ではなく、直接リポジトリの情報など記述してしまえばこのようなことをする必要はありません)。

```clj
  :release-tasks
  [["vcs" "assert-committed"]
   ["change" "version" "leiningen.release/bump-version" "release"]
   ["vcs" "commit"]
   ["vcs" "tag"]
   ["with-profile" "+deploy" "deploy"] ;; この行が通常と違う
   ["change" "version" "leiningen.release/bump-version"]
   ["vcs" "commit"]
   ["vcs" "push"]]
```

git などに tag を打つときに gpg での認証が必要になるので、設定しておきます。

```
git config --global gpg.program gpg2
git config --global user.signingkey your-gpg-key
```

( gpg を回避する場合は [こちら](https://github.com/technomancy/leiningen/blob/master/doc/DEPLOY.md#tagging) を参照してください )

## S3 からデプロイしたライブラリを取得する

[Making Artifacts Public - spring-projects/aws-maven](https://github.com/spring-projects/aws-maven#making-artifacts-public) に従って S3 側の設定を行います。

そして、利用する側のプロジェクトの `project.clj` に次のようにリポジトリの情報を追加します。

```clj
:repositories [["your-repo" "https://your-repo.s3.amazonaws.com/"]]
```

設定によって URI とか微妙に変わるかもしれないですが、こんな感じで大丈夫だと思います。

## gpg に関するハマりどころ

### gpg 特有の問題

gpg 特有というか環境によって違うと思うんですが、 Ubuntu の場合デフォルトで gpg v1 がインストールされています。
ですが、 gpg-agent は v2 がインストールされていて、しかも gpg v2 もインストールされているからパッと見は綺麗に動いているように見えます。

なので、 Leiningen のドキュメントとかに書いてある

```
Could not decrypt credentials from /home/xxx/.lein/credentials.clj.gpg
gpg: can't query passphrase in batch mode
gpg: decryption failed: secret key not available
```

みたいなエラーに遭遇したら、 `use-agent` を `~/.gnupg/gpg.conf` に書きこんで以下のコマンドを試してみろ

```
gpg --quiet --batch --decrypt ~/.lein/credentials.clj.gpg
```

というのは上手くうごかないことがあります。このとき gpg2 がインストールされていることを確認して、 gpg を gpg2 と置き換えると上手く動作することが確認できます。

なので実際に鍵をつくったりするのも gpg コマンドではなく gpg2 コマンドを使ったほうがいいでしょう(一応 gpg で作ったあとに gpg2 を使うとマイグレーションしてくれるぽいけど良く分からない)。

あるいは使い分ける必要も特にないはずなので、 gpg2 に gpg と alias を貼って上書きしてしまってもいいかもしれません。

### Leiningen が絡む場合の問題

前述の話と絡みます。

Leiningen が使う gpg はデフォルトで gpg です。これを gpg2 に変更したい場合は環境変数 `LEIN_GPG` を設定する必要があります。

```
export LEIN_GPG=gpg2
```

## あとがき

色々と端折りましたが Leiningen のドキュメントを隅から隅まで読めば綺麗に説明されています。
`lein help gpg`, `lein help deploy`, `lein help deploying` あたりを読み込めば理解できるとおもいます。

## 参考

- [MavenリポジトリをS3上に構築してMaven/Gradle/sbtから使う - nulab](https://nulab-inc.com/ja/blog/nulab/building-maven-repository-on-s3/)