This is my life.

There are many like it, but this one is mine.

ペライチ300行弱のコードで簡易CIサーバーを作った

皆さんはゴールデンウィークいかがお過ごしでしょうか。
僕は暇すぎたので雑にCIサーバーのようなものを作ることにしました。

github.com

CIサーバーを運用する際の悩みとして、サーバーの環境構築が挙げられます。
色々なプロジェクトでは言語や依存するサーバー環境が異なります。これを解決するのは非常に面倒です。
そこで、 Docker を裏で利用してコンテナ内ですべて実行することにしました。

個人の意見として、ビルドやテストの実行環境はCIサーバーで担保するのではなく、プロジェクトで担保するべきだと思っています。
実行環境をプロジェクト毎に担保することによってCIサーバーのスケールや移行が楽になります。

コード内で Docker を利用する際には、

github.com

が非常に便利です。

これを利用するため、サーバーは Golang で記述することにしました。

また、ジョブ自体は Maven や Gradle、NPM、Fastlane などのタスクランナーを利用して実行することにしました。
サクッと利用方法を見たい場合は ここ から。

作る機能

CIの機能を分解すると、

  • トリガー
  • ジョブの実行
  • 結果の通知

に分けられると思います。

トリガー

ジョブを実行するタイミングです。
今回はサーバーとして起動し、GitHub の Webhooks を待ち受けることにしました。
GitHub の Webhooks は種類・情報が豊富です。

Webhooks | GitHub Developer Guide

これを利用することで任意のタイミングでジョブを実行できるようになります。

GitHub の Pull Request のコメントをトリガーフレーズとして実行できるようにしました。
Jenkins の Pull Request Builder Plugin の trigger phrases と同じような使い勝手です。

f:id:duck8823:20180506115916p:plain

ジョブの実行

前述のとおり、ジョブは Docker コンテナ内で実行します。
プロジェクト毎に Dockerfile を用意し、 ENTRYPOINT にタスクランナーのコマンドを設定しておくことで、トリガーレーズで任意のタスクを実行できるようになります。

gist.github.com

上記のような Dockerfile を用意していた場合、 ci test とコメントすると コンテナ内で mvn test が実行されます。

結果の通知

ジョブを実行したら、その結果を通知する必要があります。
リクエストに対して同期的にジョブを実行し、成功したら 200 を返すようにしました。 ※ジョブに時間がかかってしまうので、GitHub の Webhooks は Timeout となってしまいます。

また、トリガーを GitHub の Pull Request 依存にしたので、Commit Status として結果を返すことにしました。

f:id:duck8823:20180506121019p:plain

コード

前置きが長くなりましたが、 以下が300行弱で簡易CIを実現するコードです。

gist.github.com

ここからは、上から順に各ポイントを紹介したいと思います。

Webhooks のパース

net/http を利用して Webhooks を待ち受けるサーバーを実現しています。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    ...
})
http.ListenAndServe(":8080", nil)

リクエストは JSON文字列 として受け取ります。
そのままでは非常に扱いづらいので、構造体にマッピングしましょう。

ただし、 Payload の構造体を自分で記述するのは骨が折れます。
以下のプロジェクトから構造体を拝借しました。

github.com

body, _ := ioutil.ReadAll(r.Body)
...

event := &github.IssueCommentEvent{}
json.Unmarshal(body, event)

ここでは、 github.IssueCommentEvent という構造体にマッピングしています。

冒頭で記述したとおり、GitHub の Webhooks には非常に多くの種類(event type)があります。
その種類によって Payload が異なるので、正しく構造体にマッピングしなければなりません。

どの event type かは、リクエストのヘッダー X-GitHub-Event に記述されています。
Pull Request のコメントは issue_comment です。それ以外の場合は除外しましょう。

https://developer.github.com/v3/activity/events/types/#issuecommentevent

githubEvent := r.Header.Get("X-GitHub-Event")
if githubEvent != "issue_comment" {
        ...
    return
}

トリガーフレーズの取得

Pull Requestのコメント内容は Payload の comment.body から取得することができます。
正規表現/^ci\s+(?<phrase>.+)/ にマッチした場合にジョブを実行します。

if !regexp.MustCompile("^ci\\s+[^\\s]+").Match([]byte(event.Comment.GetBody())) {
    ...
    return
}
phrase := regexp.MustCompile("^ci\\s+").ReplaceAllString(event.Comment.GetBody(), "")

Pull Requestかどうかの判定

event type issue_comment は名前から分かる通り Issue のコメントでも発火してしまいます。
Payload の issue.number から得られた番号から、 Pull Request 情報を取得することができます。

pr, _, err := githubClient.PullRequests.Get(
    context.Background(),
    event.Repo.Owner.GetLogin(),
    event.Repo.GetName(),
    event.Issue.GetNumber(),
)

特定のブランチを Clone する

Gitリポジトリの Clone には、

github.com

を利用しました。
特定のブランチをクローンする場合は CloneOptions.ReferenceName を指定します。
refs/heads/<ブランチ名> で指定する必要があります。
Pull Request の Head ブランチは上記で取得した Pull Request 情報から取得することができます。

base := fmt.Sprintf("%v", time.Now().Unix())
root := fmt.Sprintf("/tmp/%s", base)
repo, err := git.PlainClone(root, false, &git.CloneOptions{
    URL:           event.Repo.GetCloneURL(),
    Progress:      os.Stdout,
    ReferenceName: plumbing.ReferenceName(fmt.Sprintf("refs/heads/%s", pr.Head.GetRef())),
})

GitHub に Pending の commit status をつける

Commit Status は進行によって更新するので、共通の処理は CommitStatusService としてまとめておきました。

https://gist.github.com/duck8823/261fafdcea18b655ce6a49381499d9b5#file-main-go-L262-L294

git.PlainClone した際の戻り値として得られる git.Repository から、 HEAD の Hash を得ることができます。
Commit Status は特定の Commit Hash に対して設定することができます。
また、 Context はトリガーフレーズごとに異なるようにしました。これにより build は成功したけど test に失敗したなどの情報がわかるようになります。

ref, err := repo.Head()
...
statusService := &CommitStatusService{
    Context:      fmt.Sprintf("minimal_ci-%s", phrase),
    GithubClient: githubClient,
    Repo:         event.Repo,
    Hash:         ref.Hash(),
}
statusService.Create(PENDING)

Dockerイメージをビルドするための tarアーカイブ を作成する

Moby では Dockerfile を含むディレクトリを tar形式 でアーカイブする必要があります。
filepath.Walk を利用して、クローンしてきたディレクトリに対して再帰的に tarアーカイブに含めるようにしています。

filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }
    if info.IsDir() {
        return nil
    }
    file, _ := os.Open(path)
    defer file.Close()

    data, _ := ioutil.ReadAll(file)

    header := &tar.Header{
        Name: strings.Replace(file.Name(), root, "", -1),
        Mode: 0666,
        Size: info.Size(),
    }
    writer.WriteHeader(header)
    writer.Write(data)

    return nil
})

イメージのビルド

client.NewEnvClient()DOCKER_HOST などの環境変数を利用した Dockerクライアント を作成することができます。
Client.ImageBuild では非同期にDocker Imageのビルドが実行されます。
戻り値である types.ImageBuildResponseBodyEOF まで読むことでビルドの終了を同期的に待つことができます。

また、types.ImageBuildOptionsTags で タグを指定することができます( -t オプション相当 )。 タグにはコンテナの作成時と同じものを利用しましょう。今回は 実行ごとに UNIX時間 をつけているのですが、 リポジトリ名などでキャッシュを利用するようにすれば、ジョブの実行が高速化されるかもしれません。

cli, _ := client.NewEnvClient()
resp, _ := cli.ImageBuild(context.Background(), file, types.ImageBuildOptions{
    Tags: []string{base},
})
defer resp.Body.Close()

ioutil.ReadAll(resp.Body)
logger.Info("Image Build succeeded.")

コンテナの作成

コンテナを作成します。
Cmd に トリガーフレーズ 指定することで、任意のタスクの実行を実現できます。

con, _ := cli.ContainerCreate(context.Background(), &container.Config{
    Image: base,
    Cmd:   []string{phrase},
}, nil, nil, "")

コンテナの実行

いよいよコンテナの実行です。 コンテナ作成時に取得した コンテナID をスタートさせます。
コンテナの実行は同期的に行われます。
Client.ContainerWait で待つことができます。戻り値には コンテナ内で実行したコマンドの return code が含まれます。
return code0 以外のときはジョブに失敗したとみなし、 Commit Status を failure にしました。

また、ログは Client.ContainerLogs で取得できます。

cli.ContainerStart(context.Background(), con.ID, types.ContainerStartOptions{})
if code, err := cli.ContainerWait(context.Background(), con.ID); err != nil {
    ...
    return
} else if code != 0 {
    statusService.Create(FAILURE)

    http.Error(w, fmt.Sprintf("return code: %v", code), http.StatusInternalServerError)
    return
}

out, _ := cli.ContainerLogs(context.Background(), con.ID, types.ContainerLogsOptions{
    ShowStdout: true,
    ShowStderr: true,
})

成功の通知

最後までエラーが無ければ、 Commit Status を success にしましょう。
また、レスポンスにログを渡しています。

statusService.Create(SUCCESS)

buf := new(bytes.Buffer)
buf.ReadFrom(out)

respBody, err := json.Marshal(struct {
    Console string `json:"console"`
}{
    Console: buf.String(),
})

w.WriteHeader(http.StatusOK)
w.Write(respBody)

使い方

準備

Commit Status を作成するために、 GITHUB_API_TOKEN を設定する必要があります。
トークンは https://github.com/settings/tokens から取得することができます。

export GITHUB_API_TOKEN=<your api token>

サーバーを起動する

Go の環境がある場合

$GOPATH が設定されていて、 $GOPATH/bin に $PATH が通っている場合、は go get で取得できます。

go get -u github.com/duck8823/minimal-ci
minimal-ci

Docker Compose で起動する (コンテナからホストのDockerデーモンを利用する)

サーバー自体を Docker コンテナで起動する場合も、ホストの Docker デーモンを利用して実行するようにしましょう。
OS によって若干異なるのでそれぞれの compose ファイルを用意しました。

Windows の場合

Docker for Windows を利用します。

www.docker.com

あらかじめ Docker for Windows の Settings から、 Expose daemon on tcp://localhost:2375 without TLS を設定しておきましょう。

f:id:duck8823:20180506165017p:plain

DOCKER_HOST として tcp://docker.for.win.host.internal:2375 を設定することでコンテナ内からホストの Dockerデーモン を利用することができます。

docker-compose -f docker-compose.win.yml

Mac の場合

Docker for Mac を利用します。

www.docker.com

Docker for Mac には Expose daemon... の設定はありません。

bobrik/socat のイメージを利用することで実現できました。
https://hub.docker.com/r/bobrik/socat/

また、 DOCKER_HOSTtcp://docker.for.mac.host.internal:2375 です。

docker-compose -f docker-compose.mac.yml

Optional.of( ngrok の利用 )

Webhooks を受け取るために、GitHubからサーバーにアクセスできる必要があります。
ngrok でローカルのポートを外部に公開することができます。
試しにポートを公開したい場合は利用するといいかもしれません。
リポジトリの composeファイル では ngrok コンテナはコメントアウトしています。

ngrok.com

ngrok を起動したら http://localhost:4040/status にアクセスしてみましょう。

f:id:duck8823:20180506172407p:plain

ここで表示される URL にアクセスすることによって、 フォワーディングされます。

Webhooks の設定

GitHubでは、リポジトリ毎に Webhooks を設定します。
https://github.com/<owner>/<repo>/settings/hooks/new

Payload URL には 公開しているURL を設定します。
Which events would you like to trigger this webhook? には Issue comments を設定しましょう。

f:id:duck8823:20180506172812p:plain

まとめ

GitHub / Docker( Moby ) を使って簡易CIを作ってみました。
セキュリティがガバだったり、失敗時のログを後から見られなかったりとまだまだ機能は足りないですが、 このコードをベースにオリジナルのCIを作ってみると楽しいと思います。

Nginx の Webdav でデプロイ時のみパスワードが必要な Mavenリポジトリ を立てる

前回の記事で JitPack を使えば Mavenリポジトリ を立てる必要すらないっていう話を書いたのですが、 クローズドな環境では外部サービスの利用が難しい場合があります。

そこで、今回は Nginx を使ってサクッと Mavenリポジトリ を立ててみます。
さらにリポジトリは誰でも見られるようにして、デプロイ時はパスワード認証をかけます。

CentOS 7系でやってみましょう。
ここでは、使い捨てのDockerコンテナを立ち上げて試します。

docker run --rm -it -p 80:80 centos:7 bash 

Nginxのインストール

CentOS 7 にインストールするためには、yumリポジトリを追加する必要があります。

vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1

リポジトリを追加したら yum コマンドでインストールしましょう。

yum install -y nginx

インストールをしたら起動します。 nginx  コマンドはバックグラウンドで実行されます。

nginx 

Dockerコンテナでなく実際のサーバーで実行する場合は

systemctl start nginx

で開始することができます。

起動した状態で、ブラウザで以下にアクセスしてみましょう。

http://localhost/

以下のような画面が表示されれば Nginx が起動しています。

f:id:duck8823:20171224095744p:plain

確認が済んだらプロセスを終了します。
コンテナで起動している場合は pid を取得して kill します。

ps x | grep [n]ginx | awk '{print $1}' | xargs kill

実際のサーバーの場合は以下で終了することができます。

systemctl stop nginx

Basic認証できるようにする

ライブラリの利用時は認証せず、デプロイ時にはユーザー名とパスワードで認証するようにします。
Nginx でBasic認証を利用する場合ために httpd-tools をインストールします。

yum install -y httpd-tools

Basic認証のユーザーファイルを作成しましょう。

htpasswd -c /etc/nginx/.htpasswd ユーザー名

画面の指示に従ってパスワードを入力します。

作成された /etc/nginx/.htpasswdBasic認証用のファイルとなります。

Mavenリポジトリの設定を追加する

Maven用の Webdav 設定を追加します。

vi /etc/nginx/conf.d/maven.conf
server {
  # localhost でアクセスすると default.conf が優先される。
  # 以下の設定で 127.0.0.1 にアクセスするとこちらが優先される。 
  listen 80 default;
  server_name _;

  # アクセスする際のパス 以下の場合 http://サーバー名/maven/
  location /maven/ {
    
    # この場合 /var + /mavan/ で Mavenリポジトリの root は /var/maven
    root /var;

    # デプロイ時の一時ディレクトリ
    client_body_temp_path /tmp/maven;
    # ディレクトリを作成するか
    create_full_put_path on;

    # ブラウザでディレクトリにアクセスした際に一覧が表示されるようにする
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;

    # webav を有効にする
    dav_access group:r all:r;
    dav_methods PUT DELETE MKCOL COPY MOVE;

    # GET 以外に制限(Basic認証)をかける
    limit_except GET {
      auth_basic "Maven Repo";
      auth_basic_user_file "/etc/nginx/.htpasswd";
    }
  }
}

設定を作成したら、必要なディレクトリを作成しましょう。
プロセスは nginx ユーザーで実行されるため、作成したディレクトリのオーナーを nginx に変更しておきます。

mkdir -p /var/maven /tmp/maven
chown nginx:nginx /var/maven /tmp/maven
nginx

/etc/nginx/conf.d/default.confserver_name localhost; が設定されているため、 http://localhost/maven/ にアクセスしても default.conf が適用されます。 よって、 404 エラーが返ってきてしまいます。

http://127.0.0.1/maven/ にアクセスすることで /etc/nginx/conf.d/macen.conf が適用され、 /var/maven/ 以下を参照することができます。

ライブラリをデプロイする

Maven

デプロイしたいプロジェクトの pom.xml を編集します。

distributionManagementリポジトリ情報を追記します。
Dockerホストからデプロイする場合、 http://127.0.0.1/maven/ です。
webdav を利用してアップロードするので、 dav:http://127.0.0.1/maven/ となります。

<project>
    ...
    <distributionManagement>
        <repository>
            <id>docker.maven</id>
            <name>Maven Repo</name>
            <url>dav:http://127.0.0.1/maven/</url>
        </repository>
    </distributionManagement>
    ...
    <build>
        <extensions>
            <extension>
                <groupId>org.apache.maven.wagon</groupId>
                <artifactId>wagon-webdav-jackrabbit</artifactId>
                <version>3.0.0</version>
            </extension>
        </extensions>
        ...
    </build>
    ...
</project>

webadv で GET 以外のメソッドにはBasic認証をかけているので、 この状態では ` 401 Unauthorized デとなりプロイできません。

認証情報は $HOME/.m2/settings.xml に記述します。

<settings>
    <servers>
        <server>
            <!-- pom.xml の distributionManagement/repositoryの id と一致させる -->
            <id>docker.maven</id>
            <username>ユーザー名</username>
            <password>パスワード</password>
        </server>
    </servers>
</settings>

下記のコマンドでデプロイすることができます。

mvn deploy

Gradle

build.gradle を編集します。

apply plugin: 'maven'

configurations {
    deployerJars
}

repositories {
    mavenCentral()
}

dependencies {
    deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:3.0.0'
}

uploadArchives {
    repositories.mavenDeployer {
        configuration = configurations.deployerJars
        repository(url: "http://127.0.0.1/maven/") {
            authentication(userName: "ユーザー名", password: "パスワード")
        }
    }
}

コマンドは以下の通りです。

./gradlew uploadArchives

これによりJarファイル や pom.xml も自動的に生成され、サーバーにアップロードされます。

ライブラリの利用

デプロイ後にブラウザでアクセスしてみると、ディレクトリが増えていると思います。

f:id:duck8823:20171224100130p:plain

Mavenリポジトリは URL を指定するだけで追加できます。
リポジトリを追加したら、通常のライブラリと同じように dependency を記述します。

Maven

<project>
    <repositories>
        ...
        <repository>
            <id>maven.docker</id>
            <name>Maven Repo</name>
            <url>http://127.0.0.1/maven/</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>example-maven</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Gradle

repositories {
    maven { url 'http://127.0.0.1/maven/' }
}
dependenciea {
    implementation 'com.example:example-maven:0.0.1-SNAPSHOT'
}

おわり

Nginx で webdav を利用して Mavenリポジトリ を立てて、Basic認証でデプロイ(アップロード)を制限する方法を記述しました。
社内ネットワークでライブラリを配布したいけど、webdavでなんでもデプロイされるのはちょっと...ていう場合には使えるかもしれないです。かなりニッチ...

お試しが終わったらコンテナを終了させましょう。
最初の docker コマンドで --rm オプションを指定しているので、コンテナから抜ければ自動的に削除されます。
まっさらな環境で試す場合に Docker 非常に便利ですね。

exit

Mavenライブラリ配布の自動化をやめた話

この記事は モバイル 自動化/自動テスト Advent Calendar 2017 の19日目です。

皆さんは、JavaやKotlinで作成したライブラリ、加えてGradleプラグインの配布について悩んだことはないでしょうか。
クロスプラットフォームな開発環境も増えましたが、Android開発といえば Java や Kotlin といった JVM言語が主流です。
もちろんライブラリもこれらの言語で作成されます。 

一般的に、JavaやKotlinで作成されたライブラリの配布はMavenリポジトリを介して行われます。

Maven公式のリポジトリMaven Central です。 その他、 Bintray jcenter も有名なリポジトリです。 よってライブラリを作成して公開したい場合は上記サーバーにデプロイすることになります。 しかし、Maven Central にライブラリを登録するまでにはアカウント作成など面倒な手順を踏むことになります。

今は21世紀なのでサクッとライブラリを作成して公開したいですね。

Mavenリポジトリを立てて公開する

Mavenリポジトリは、誰でも立てることができます。 http(s) でアクセスできるサーバーを立てるだけです。

自分はこれまで、GitHubソースコードを管理し、レンタルサーバーリポジトリを立てて公開していました。 また、ソースコードの更新からリポジトリへの公開は自動化していました。

自分の場合、MavenリポジトリとJenkinsサーバーを同一にしています。 GitHubで master ブランチが更新された場合、 Jenkinsが mvn deploy を実行するだけです。 このコマンドではローカルのMavenリポジトリに配置されますが、 HTTPサーバーの静的コンテンツを配置するディレクトリ以下にMavenリポジトリを指定すると、 サーバーを介してライブラリを利用することができます。

<distributionManagement>
    <repository>
        <id>local</id>
        <name>local</name>
        <url>file://localhost/path/to/DocumentRoot</url>
    </repository>
</distributionManagement>

この方法ではライブラリを作るたびにJenkinsのジョブを追加しなければなりません。 また、公開できるサーバーとドメインを所有している必要があります。

そこで、GitHubのみを利用して公開する方法を探していました。

GitHub Pagesを利用して公開する

GitHubの ユーザー名.github.io リポジトリあるいは特定のブランチを maven リポジトリとして公開しちゃう方法です。 「GitHub Maven リポジトリ」で検索とこの方法がヒットします。

今回は ユーザー名.github.io リポジトリを利用して公開する方法をご紹介します。

  1. GitHub上に、ユーザー名.github.io リポジトリを作成する

  2. public_repo と user:email の権限を付与した Personal Access Token を作成する

  3. ローカルマシンの settings.xml でサーバーを設定する
    通常は $HOME/.m2/settings.xml にあります。

<settings ...>
  <servers>
    <server>
     <id>github.com</id>
     <password>取得した Personal Access Token</password>
    </server>
  </servers>
</settings>
  1. プロジェクトの pom.xml を設定する
    今回利用する site-maven-pluginMaven Plugin として提供されているので、pom.xml で設定しています。
  <profiles>
    ...
    <profile>
      <id>github</id>
      <properties>
        <!-- settings.xml で記述したサーバーの id -->
        <github.global.server>github.com</github.global.server>
      </properties>
      <distributionManagement>
        <repository>
          <id>internal.repos</id>
          <name>Temporary Repository</name>
          <!-- mvn deploy コマンドで ビルドディレクトリ/mvn 以下にデプロイするようにする -->
          <url>file://${project.build.directory}/mvn</url>
        </repository>
      </distributionManagement>
      <build>
        <plugins>
          <plugin>
            <groupId>com.github.github</groupId>
            <artifactId>site-maven-plugin</artifactId>
            <version>0.12</version>
            <configuration>
              <message>Maven artifacts for ${project.version}</message>
              <!-- GitHubにプッシュするディレクトリを ビルドディレクトリ に指定する -->
              <outputDirectory>${project.build.directory></outputDirectory>
              <!-- ビルドディレクトリには classファイル なども作成されるのでディレクトリを指定する -->
              <includes>
                <!-- mvn deploy コマンドで作成されるローカルリポジトリ -->
                <include>mvn/**/*</include>
              </includes>
              <repositoryOwner>GitHubのユーザー名</repositoryOwner>
              <repositoryName>GitHubのユーザー名.github.io</repositoryName>
              <branch>refs/heads/master</branch>
              <!-- デフォルトだと最新版の artifact で上書きしてしまうので、マージする -->
              <merge>true</merge>
            </configuration>
            <executions>
              <execution>
                <goals>
                  <goal>site</goal>
                </goals>
                <!-- maven deploy 後に実行されるようにする -->
                <phase>deploy</phase>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>
  1. 実行する
    実行時は上述の pom.xml で設定したプロファイルを指定します。
mvn deploy -P github
  1. 自動的に実行されるようにする
    あとはお好みの CI/CD で上述のコマンドが実行されるようにするだけです。

これによりライブラリの配布もGitHub上でできるようになりました。 ライブラリを利用する場合はリポジトリのURLとして https://ユーザー名.github.io/mvn/ を指定します。

maven-site-plugin を利用しているため、Gradleの場合は pom.xml の生成など手間が増えます。

JitPackを利用する

JitPack は少し変わったMavenリポジトリです。 Spockなどがこのリポジトリを介して配布されています。

JitPack を利用する場合、配布側でビルドする必要がありません。 JitPack上のライブラリをインポートしたタイミングで JitPack上でビルドされるのです。

GitHub上のライブラリを利用する

  1. Mavenリポジトリとして https://jitpack.io を指定する

  2. ライブラリの指定

    1. groupId を com.github.リポジトリオーナー名 にする
    2. artifactId を リポジトリ名 にする
    3. バージョンに リリースタグ または コミットハッシュ を指定する

この方法では特別ビルドを行う必要がありません。 しかし、JitPack が groupIdartifactId を書き換えてしまうので、混乱するかもしれません。 ライブラリの groupIdartifactId を それぞれ com.github.リポジトリオーナー名リポジトリ名 にしてしまうのが最も簡単でしょう。 しかし、groupId は独自のドメインを指定したい場合もあります。

JitPackでは DNS TXTレコード を利用してドメイン名を指定する方法を提供しています。 https://jitpack.io/docs/#custom-domain-name

まとめ

最近までレンタルサーバーMaven リポジトリを立てていたのですが、 できる限り管理するサーバーは減らしたいですよね。

Spockを利用する際に指定されていた Mavenリポジトリ が今まで利用したことがなかったものなので調べてみると、 とても便利だったので久しぶりにテンションがあがりました。

これまでGolangJavaScriptRubyなど比較して Javaのライブラリ配布は面倒な印象がありました。 しかし、JitPack を利用すれば配布するためのビルドする必要すらなくなりました。 また、GitHubにソースが公開されているけど配布されていないライブラリについても利用できる可能性があります。

Publicなライブラリの場合はこういったサービスを無料で利用することができて非常に便利ですね。

iOSDCで当日スタッフ & LTトークしてきました

i will blog.


こちらのiOSDCの写真をみてたんです。
…ぼくめっちゃデブやん…

鏡って2割ほど痩せて見えるんですね。気づきがありました。


さて iOSDC 2017 も終わり、日々の業務を粛々と進めております。
僕は 当日スタッフ と、 LTトーク枠で参加してきました。

LTトーク内容は 所属グループのブログ で少し紹介しているのでそちらをご覧ください。
発表前日に資料について気になって、調査したり資料を直したりしていたら朝になっていました。
発表内容に興味を持っていただいて、懇親会時に話かけていただいたりもして、やはり発表するのはいいなと思いました。
…笑いはとれなかったけど。


当日スタッフとしては、トラックDの担当でした。 トラックDはあまりセッションもなかったので、受けつけのヘルプをしていた時間の方が長かったかもしれないです。 あとは仕事ありそうなところ手伝ったり、LT前は緊張しすぎてウロウロしていました。

スタッフのみなさん本当に出来る方々ばかりで、頭があがりませんでした。 何よりみなさんが本当に楽しんでいて、それがよかった。

f:id:duck8823:20170922021214j:plain


是非来年もスタッフとして参加させていただきたいです。 トークも応募したいと思います。 それまでにダイエットします。 痩せてイケメン枠で登壇&スタッフしたいです。


普段は iOS Test Night、 Android Test Night などで運営のお手伝いをしています。こちらもどうぞ参加ください。

testnight.connpass.com

俺コンでも発表します。

orecon.connpass.com

GitHubと各種CIサービスを連携してみる

普段GitHubを使っていて、Travis CIと連携してバッヂをつけたりしています。 Pull Requestが来たときなんかも自動でビルド・テストをしてくれるので便利ですよね。

今回は、自分でサーバーを用意せず利用できるCIとGitHubを連携してみました。 今回ご紹介するのは以下のCIサービスです。


Travis CI

GitHubとの連携

https://travis-ci.org/

トップページ右上の Sign in with GitHub からログインすることができます。

f:id:duck8823:20170716225944p:plain

ログイン後、 https://travis-ci.org/profile/GitHubのアカウント名/ にアクセスすると、Publicなリポジトリ一覧が表示されます。

f:id:duck8823:20170716233025p:plain

連携したいリポジトリf:id:duck8823:20170716233225p:plain に設定すると連携できます。

リポジトリの設定

リポジトリの設定は、リポジトリ名横の歯車マークをクリックします。 f:id:duck8823:20170716234907p:plain

以下のような設定項目が表示されます。 f:id:duck8823:20170717001102p:plain

.travis.yml の記述

詳しくは https://docs.travis-ci.com/user/customizing-the-build/ を見ながら設定しましょう。

以下は ruby プロジェクト(https://github.com/duck8823/danger-slack)の例

language: ruby
cache:
  directories:
    - bundle

rvm:
  - 2.3.1

before_script:
    - bundle exec danger

script:
    - bundle exec rake spec

Travis CIはOS X のイメージも無料で利用することができます。
設定項目も必要最低限で1画面でまとまっていて、
スケジュールも設定できる。
個人のOSSなんかは Travis CI を使うと便利そうですね。



Circle CI

GitHubとの連携

Circle CI のサインアップページから Start with GitHub をクリックし、ログインします。

ログイン後に Settings > Projects に進むとリポジトリ一覧が表示されます。

f:id:duck8823:20170717015852p:plain

連携したいリポジトリの歯車マークを押し、 表示されたページで Follow Project をクリックしましょう。

f:id:duck8823:20170717020024p:plain

リポジトリの設定

follow すると、様々な設定が可能になります。 Settings > Projects > 設定したいプロジェクトの歯車マーク

f:id:duck8823:20170717020604p:plain

環境変数は BUILD SETTINGS の Environment Variables で設定できます。

circle.yml の設定

以下は ruby プロジェクト(https://github.com/duck8823/danger-slack)の例

machine:
  ruby:
    version: 2.3.1

test:
  pre:
    - bundle exec danger
  override:
    - bundle exec rake spec

circle ci では osx を利用するには有料プランを選択する必要があります。



Wercker

GitHub との連携

https://app.wercker.com にアクセスするとログインページに遷移します。
LOG IN WITH GITHUB をクリックしてログインしましょう。

ログイン後、ヘッダーに表示されている Create をクリックし、 Application を選択します。
f:id:duck8823:20170717025058p:plain

リポジトリ一覧が表示されるので、連携したいプロジェクトを選択肢し、 Use selected repo をクリックします。 f:id:duck8823:20170717025259p:plain

続いてアクセス方法を選択して Next step をクリックします。 f:id:duck8823:20170717025428p:plain

リポジトリの設定

ヘッダーメニューの Applications をクリックし、一覧から設定したいリポジトリを選択します。 Environment を選択すると環境変数を設定することができます。 TokenなどはProtectedにチェックをつけるといいでしょう。

f:id:duck8823:20170717030053p:plain

werker.yml

box: ruby
build:
    steps:
        - bundle-install
        - script:
            name: test
            code: bundle exec rake spec

Werkerは、パイプラインを作成することも可能です。
プライベートリポジトリも無料で利用できます。
残念ながら今のところ Danger は利用できません。