システム開発で思うところ

JavaEEを主にシステム開発をしながら思うところをツラツラを綴る

GitHubにMavenリポジトリをつくる

Mavenプロジェクトを細かく分割することを前提にしたら、私が作成しているものは公開リポジトリが無いと利用者側*1にとって凄く不便だなと思って調べてみました。

はじめに

さくっとは出来ないだろうなぁとは思いましたが案の定かなり苦戦しました。自分なりに 初めから やり直したので大丈夫な手順だとは思います*2

環境

Windows10、Java8、NetBeans8.2

なぜGitHub

コードの管理は今のところ基本的にBitBucketを使っています。その中でMavenリポジトリGitHubにしました。理由は知見量が多かったことと、当初、BitBucketでやろうとしたのですが良く分からなかったというのが一番の理由です。あと後付け的なところはありますが、公開する資産についてはGitHubの方が多くの人にとって馴染みがあるかな?というところもあってGitHubMavenリポジトリの置き場にすることにしました。

構築の流れ

格納先となるリポジトリを作成する

f:id:vermeer-1977:20170901131727p:plain

  • ブランチを作成

ブランチ名は「mvn-repo」

f:id:vermeer-1977:20170901132124p:plain

f:id:vermeer-1977:20170901132311p:plain

f:id:vermeer-1977:20170901132808p:plain

「save」ボタンを押すのを忘れずに

認証キーを作成する

Webで調べるとユーザー名とパスワードを設定するやり方が多かったように思いますが、OAuthによる認証の方がセキュリティー的にみて良いと思います。

f:id:vermeer-1977:20170901133320p:plain


f:id:vermeer-1977:20170901133524p:plain


Token description は「maven-pass」。ただのラベルなので何でも大丈夫です。

チェックボックスpublic_repo user:email だけ。必要最低限は この2つをチェックすれば良いようです*5

f:id:vermeer-1977:20170901133846p:plain


認証キーが生成されます。

後から確認は出来ませんので ここでメモしておくのを忘れずに。忘れたときは再生成することになるので気を付けましょう。

f:id:vermeer-1977:20170901134123p:plain

pom.xmlを編集する

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vermeerlab</groupId>
    <artifactId>maven-git-sample</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <github.global.server>github</github.global.server>
        <git.branchName>mvn-repo</git.branchName>
        <git.repositoryOwner>vermeer-1977</git.repositoryOwner>
        <git.repositoryName>maven</git.repositoryName>
        <git.isMerge>true</git.isMerge>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
                <configuration>
                    <altDeploymentRepository>internal.repo::default::file://${project.build.directory}/${git.branchName}</altDeploymentRepository>
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.github.github</groupId>
                <artifactId>site-maven-plugin</artifactId>
                <version>0.12</version>
                <configuration>
                    <!-- git commit message -->
                    <message>Maven artifacts for ${project.version}</message>
                    <noJekyll>true</noJekyll>
                    <outputDirectory>${project.build.directory}/${git.branchName}</outputDirectory>
                    <branch>refs/heads/${git.branchName}</branch>
                    <includes>
                        <include>**/*</include>
                    </includes>

                    <repositoryName>${git.repositoryName}</repositoryName>
                    <repositoryOwner>${git.repositoryOwner}</repositoryOwner>

                    <!-- true:履歴を残す false:直近バージョンのみ repositoryに残る -->
                    <merge>${git.isMerge}</merge>

                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>site</goal>
                        </goals>
                        <phase>deploy</phase>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.source}</target>
                    <compilerArgs>
                        <arg>-Xlint</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
        </plugins>

    </build>

    <distributionManagement>
        <repository>
            <id>internal.repo</id>
            <name>Temporary Staging Repository</name>
            <url>file://${project.build.directory}/${git.branchName}</url>
        </repository>
    </distributionManagement>
</project>
  • ローカル保存先の distributionManagementurl の指定でリポジトリ名と同じフォルダを指定しています。任意のフォルダ名で良く、特に意味を持たせる必然は無いけれど pom内に複数個所指定するので 記述誤りを防ぐために同名にしました。

  • git.isMergetrueであればアップロードした資産の履歴を残します。SNAPSHOTの場合は履歴を残すけど、そうじゃなくなったら履歴は不要というような指定をしたい場合に使用する想定かな?と思っています。

settings.xmlを編集する

...\.m2\settings.xmlに格納されています。

NetBeansMavenプロジェクトだったら、以下のものを編集。見た感じだとプロジェクト毎に存在するように見えますが 全てのプロジェクトで共通の資産です。どのプロジェクトのものを編集してもちゃんと反映されます*6

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    <servers>
        <server>
            <id>github</id>
            <password>hogehogehogehogehogehogehogehogehogehoge</password>
        </server>
    </servers>
</settings>

hogehoge… は先に取得した認証キーを設定してください。

Maven資産をアップロード

mvn deploy コマンドを実行します。


f:id:vermeer-1977:20170901154750p:plain


f:id:vermeer-1977:20170901154823p:plain


f:id:vermeer-1977:20170901161244p:plain


アップロードされたリポジトリのアドレスは

GitHub - vermeer-1977/maven at mvn-repo

ちなみに通常のビルドではアップロードはされません。

簡易クラスを作成

次の工程で参照するためのクラスを追加します。

public class Sample {

    public void testPrint() {
        System.out.println("maven-test-sample");
    }
}

改めて deploy します。

リポジトリ資産を取り込む

public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new org.vermeerlab.maven.git.sample.Sample().testPrint();
    }

}

アップロードをした資産の取り込むための設定。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vermeerlab</groupId>
    <artifactId>maven-git-client</artifactId>
    <version>0.1.0</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <github.global.server>github</github.global.server>
        <git.branchName>mvn-repo</git.branchName>
        <git.repositoryOwner>vermeer-1977</git.repositoryOwner>
        <git.repositoryName>maven</git.repositoryName>
        <git.isMerge>true</git.isMerge>
    </properties>

    <repositories>
        <repository>
            <id>github-maven</id>
            <url>https://raw.github.com/${git.repositoryOwner}/${git.repositoryName}/${git.branchName}/</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>maven-git-sample</artifactId>
            <version>0.1.0</version>
        </dependency>
    </dependencies>

</project>

この流れだとローカルリポジトリを参照してしまいます。念のためローカルリポジトリの資産を削除して確認をすると良いと思います。ログをみたら、きちんとダウンロードをしていることが確認できます。

f:id:vermeer-1977:20170901165044p:plain

基本は以上です。

Git(コード)

vermeer_etc / maven-git-sample — Bitbucket

vermeer_etc / maven-git-client — Bitbucket


応用編(親子pomで共通化)

親pomを持つことで重厚なpom記述を全てのプロジェクトに記載しなくて良くなります。

同一ユーザーの別リポジトリにアップしたい

artifact単位でフォルダは作成されますが、意味のある単位としてリポジトリを分けておきたいケースがあります。その場合は、子pomの git.repositoryName を指定します。

子pomで指定

    <properties>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

同一ユーザーの別組織のリポジトリにアップしたい

リポジトリ名だけでなく、ライブラリ管理用のOrganizationを作成すると、製品毎に配布資産をグループ化することができます。

子pomで指定

    <properties>
        <git.repositoryOwner>(変更したい組織名)</git.repositoryOwner>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

別ユーザーのリポジトリにアップしたい

別ユーザー=認証キーが異なるアカウント管理配下のリポジトリを意図しています。例えばオーナーは別の人だけど配布資産のアップロード権限を持っている状態です。このケースはタグによる上書きだけでなく、対象権限の認証キーも併せて指定する必要があります。

★★あくまで理論上の話です*7。★★

別ユーザーや別組織のリポジトリにアップするためには、アップロード権限のある認証キーが必要です。

認証キーは別途入手できている前提として、いちいちsettings.xmlを書き換えるのは面倒です。ということで切り替えるというのが良いと思います。

  • settings.xmlidと認証キーを追記
<server>
    <id>github</id>
    <password>hogehogehogehogehogehogehogehogehogehoge</password>
</server>

<!-- 追記 -->
<server>
    <id>github-blog</id>
    <password>fugafugafugafugafugafugafugafugafugafuga</password>
</server>

  • 子pom
    <properties>
        <github.global.server>github-blog</github.global.server>
        <git.repositoryOwner>(変更したい組織名)</git.repositoryOwner>
        <git.repositoryName>(変更したいリポジトリ名)</git.repositoryName>
    </properties>

もし基本構造が全く同じであれば指定は不要ですが リポジトリ名など明示的に変更が必要なところがあれば それも指定してください。

間違ってリモートリポジトリにアップしない工夫

とりあえず現時点で私が思いつく懸念事項と対策案です。

  • 履歴を残す

上述していますがgit.isMergeは基本的にtrueにして子pom側で上書きをしないようにすることを推奨します。履歴を持つ分、リポジトリの容量が増えてしまいますが 間違ってアップロードしたときに履歴があれば戻すことが可能です*8

  • github.global.serverの指定は子pomで明示的にする

親pomで宛先を指定しておくと子pomの記述量は減るのですが、上述の事例にあるような切り替えを検討した場合、いくつかの偶然が重なると(各種名称が重複していた&ユーザーとしても更新権限を持っていた、など)、間違った宛先のリポジトリを更新してしまうことが懸念されます。親pomには無効な値を記述しておけば、未指定の場合はアップロードが出来ないのでリスクは減るかと思います。また子pomに本記述があることが先頭で分かるので「これは公開リポジトリにアップロードする対象の資産だな」ということが明示的に分かりやすいように思います。

ただ、切り替えは基本的にしないというのであれば、親pomに記述した方が良いと思います。仕事が増えるとミスの原因も増えます。

子pom

<plugins>
    <plugin>
        <groupId>com.github.github</groupId>
        <artifactId>site-maven-plugin</artifactId>
    </plugin>
</plugins>

のところを基本的にコメントアウトしておけば 間違ってdeploy を実行してもアップロードはされません。リポジトリに資産をアップする頻度にもよりますが、頻繁でないのであれば、こういう運用もありだと思います。

注意事項

親pomのビルドを忘れずに

子pomからローカルリポジトリを参照させたいので、子pomによるビルドの前に親pomのローカルリポジトリの作成またはコードを`git clone'してビルドをするのを忘れないようにしましょう。

ローカルリポジトリの指定を忘れずに

ローカルリポジトリの相対位置をrelativePathで指定しています。こうしておかないと子pomから親pomの参照ができないためエラーになります。今回は同一グループなので、このくらいの記述ですが別グループだと、こうはいかない可能性があります*9。基本的に親pomプロジェクトは同一グループにつくると思いますので、ご自身のグループを適当に作って親と子の資産を1つのグループとして扱うと良いでしょう。

    <parent>
        <groupId>org.vermeerlab</groupId>
        <artifactId>maven-git-parent</artifactId>
        <version>0.1.0</version>
        <relativePath>../</relativePath> <!-- この指定 -->
    </parent>

Git(コード)

  • 親pom

vermeer_etc / maven-git-parent — Bitbucket

  • 子pom

vermeer_etc / maven-git-child — Bitbucket


参考

Github を Maven リポジトリとして使う -

Github上に私設Mavenリポジトリをつくる - M12i.

GitHub の Pages を maven リポジトリとして使用するときのアカウント情報をセキュアにする(OAuth2Token) | KK.Kon の徒然メモ書き

http://synergian.github.io/wagon-git/usage.html

さいごに

これでオレオレリポジトリが気軽に作れるようになりました。
目的としていた「細かいMavenプロジェクトを作っても、利用したいときにコードのダウンロードで地獄を見ない」ということが実現できそうです。

本題とは関係ないですが、目次を初めて使ってみました。これは良いですね。

*1:自分自身も含めて

*2:やり直して思うところとしてはGitHub側の認証キーのところが原因だったかも。もしくはGitPageの作成かな?

*3:作ってから思いましたが紛らわしいので違う名前にした方が分かりやすかったかも

*4:あぁ、いきなり分かりにくい

*5:上手くいかなかったのは、user:email にチェックしていなかったからダメだったかも

*6:反映というか「同じ」なんですけどね

*7:GitHub上で別ユーザーの作成も考えましたが、今回のためだけに作成するのは ちょっと違うかな と思ってやめました

*8:ミスをしない工夫も大事ですが、ミスはするもの という前提を仕組みに入れておくと心理的に安心です

*9:試してはいませんが理屈上はそのはずです