goreleaser と Travis CI で Golang のバイナリ配布を自動化する

Golang で作ったツールを配布したいとき、ビルドして zip なりにまとめて GitHub の Release ページなり Homebrew で公開する必要がありますが、毎回手作業でやるのは面倒です。 そこで goreleaser と Travis CI を使って自動化してみました。

goreleaser の README にサンプルが載っていることと、GitHub と連携できて楽という理由で Travis CI を使っています。

goreleaser とは

Golang のバイナリを速く、簡単にデリバリーできるツールです(リポジトリ見てください) github.com

手順

Travis CI で GITHUB_TOKEN を設定

f:id:rnitame:20170719013612p:plain

権限を repo だけつけた Personal access token を生成して設定します。

yml を書く

.goreleaser.yml はこんな感じ。

# Build customization
builds:
  - binary: daily
    goos:
      - windows
      - darwin
      - linux
    goarch:
      - amd64

# Archive customization
archive:
  format: zip
  format_overrides:
    - goos: windows
      format: zip

# Release customization
release:
  github:
    owner: rnitame
    name: daily

brew:
  github:
    owner: rnitame
    name: homebrew-daily

  homepage: "https://github.com/rnitame/daily"

  install: |
    bin.install "daily"

builds でクロスビルド、archive で zip に固める、release で固めた zip をリリースするための設定をしています。 brew では homebrew-tap でも使えるようにするための設定をしてます。 設定自体はちょっとわかりづらいんですが、goreleaser のリポジトリにある yml を見ると参考になるかと思います。

.travis.yml はこんな感じ。

language: go

before_install:
  - go get -u github.com/Masterminds/glide

script:
  - glide install
  - go test -v

after_success:
  - test -n "$TRAVIS_TAG" && curl -sL https://git.io/goreleaser | bash

今回バイナリ配布した daily というツールがあるんですが、そこで glide を使っているので先にそれをインストールします。 そして、script でライブラリをインストールするなり、テストまわすなり、カバレッジ取るなりいろいろして、成功したあとに goreleaser を起動する。といった具合です。

before_install の go get のところは、curl https://glide.sh/get | sh でやってみたんですが linux amd64 に対応しておらずビルドがこけるのでこのようにしています。 参考 ↓

github.com

タグを打つ

上記の $TRAVIS_TAG はタグを打ったときに値が入る Travis CI の定数です。なのでタグを打ったときだけ自動でバイナリを生成してリリースします。

結果

タグを打つとビルドが走って、goreleaserbot がリリース作ってくれたり homebrew-tap のリポジトリにコミットしてくれます。

リリース↓

f:id:rnitame:20170719013923p:plain

homebrew-tap ↓

f:id:rnitame:20170719011724p:plain

便利!!

さいごに

自動化ってすばらしい 🙌

サイバーエージェントに入社します

近況です。

f:id:rnitame:20170627182618p:plain

前職であるアイスタイルを 6/30 付けで退職しました。 アイスタイルは新卒入社した会社で、内定者アルバイトを含めると1年4ヶ月、その前のインターンも含めると2年弱お世話になりました。

やっていたこと

元々 Web サービスがメインの会社なので、アルバイトの時から php (Laravel とか CakePHP とか) をずっと書いてました。 主に社内ツールを作っていて、Laravel で基本作っていたところを Angular と TypeScript 使ってフロント実装する経験もさせていただきました。(確か Angular を使ったプロジェクトは社内初) 社内ツールが終わったあとはアプリのプロジェクトへ。ごくまれに Android もやりつつ、iOS アプリを主に担当しました。

Android は経験あったんですが、Web と iOS の経験がほとんどなく。にもかかわらず優しく教えて頂いた&あれやりたいこれやりたいっていう我が儘を聞いてくださった部署の皆さんに感謝です。

本当にありがとうございました。

辞める理由

うまく言葉にできなかったのでオフラインで聞いてください (:3 」∠) 簡潔に言うと前の会社に不満はなかったのですが、オファーいただいてお話を聞いたときによりレベルアップできそうと思ったのと、よりサービスと密接に関われそうだなと思ったのが理由です。

次は?

次は7/3からサイバーエージェントで働きます。新規事業で Android エンジニアをやる予定です。 フル Kotlin の機運が高まってきていて Kotlin 漬けになりそうでめちゃくちゃ楽しみです。

ほしいものリスト

置いておきます。 amzn.asia

その日の GitHub の Activity を拾って表示する Daily を Golang で作った

daily とは?

golang 製の CLI で、コマンドを叩いた日の GitHub の Activity を出力します。

会社で日報を書いている
↓
その日やったこととして、〜の機能を実装した、〜は途中、レビューした、などなどを書く
↓
量が多いと何をどこまでやったか思い出せない、書くのも面倒になる
↓
GitHub の履歴から自動生成すればいいんじゃないか?

といった感じで思いついたのが実装を始めるきっかけ。

インストール方法

go get か Homebrew で。

# go get
$ go get github.com/rnitame/daily

# Homebrew
$ brew tap rnitame/homebrew-daily
$ brew install daily

f:id:rnitame:20170627163203p:plain

↑ Homebrew でインストールするとこんな感じになる

使い方

GitHubトークンをセット

$ git config --global "github.token" xxxxx

セットした状態で daily を叩くと結果が出力される
出力例はこんな感じ。

f:id:rnitame:20170627163208p:plain

特定の organization のイベントだけほしいとき

-org オプションをつけることで可能。

$ daily -org xxxxx

golang っぽい書き方を目指す

1つのファイルに全ての処理を勢いで書き殴っていたが、テストを書こうとした瞬間にものすごい面倒くささが押し寄せてきた。(何か処理を追加するときもだいぶ面倒。。) そのため、この記事を見ながらファイルを分割してテストを書く。

もっと使いやすいツールに

PR や issue がどういうものなのかわからなかったので、表示するようにした。

最後に

まだヘルプページがないので充実させたい。issue もちょっと残ってるのでなくしたい。

PR などなどお待ちしてます! https://github.com/rnitame/daily

Laravel プロジェクトに Angular を導入してみた

はじめに

Laravel のプロジェクトに Angular を導入してみたのでご紹介。 Angular (TypeScript) を Webpack でトランスパイルして、blade で表示する流れ。

環境

  • Laravel 5.2
  • Angular 4.0
  • TypeScript 2.1
  • Webpack 1

すでに Laravel をインストールして、new project した前提で話を進める。

Laravel からいらないライブラリやファイルを削除する

Laravel の JS や CSS のビルドは、gulp で行われているのでそれに関係するライブラリやファイル群を削除。

 gulpfile.js
 gulp
 gulp-environments
 gulp-if
 gulp-load-plugins
 gulp-notify
 gulp-plumber
 gulp-postcss
 gulp-rev
 gulp-sass
 gulp-sourcemaps
 gulp-typescript
 gulp-uglify
 gulp-watch
 gulp-webpack
 lite-server

Angular / TypeScript などなどインストー

Angular を TypeScript で書くのでインストール。他、ビルド等で必要なものも。

@angular/common
@angular/compiler
@angular/core
@angular/forms
@angular/http
@angular/platform-browser
@angular/platform-browser-dynamic
@types/core-js
@types/jasmine
@types/karma
@types/lodash
@types/node
@types/webpack
@types/webpack-env
core-js
es6-promise
es6-shim
hammerjs
jasmine-core
karma-typescript
rxjs
systemjs
zone.js
tslint
tslint-loader
css-loader
karma
karma-jasmine
karma-phantomjs-launcher
karma-sourcemap-loader
karma-webpack
phantomjs-prebuilt
style-loader
ts-helpers
ts-loader
typescript
webpack

Angular 用のディレクトリを掘ってコンポーネント配置

public/ の中に入れてしまうか、resources/ の下に入れてしまうか迷った結果、ルートに angular というディレクトリを掘ってそこに集約。これはどこでも良いと思うが、わかりやすさを重視した。 コンポーネントの配置は、基本的に Angular の Style Guide に乗っ取った。components/ の中はどのコンポーネントが何を内包しているかわかりやすくするため、階層型にしている。

├── components
│   ├── footer
│   │   ├── footer.component.html
│   │   ├── footer.component.scss
│   │   ├── footer.component.spec.ts
│   │   └── footer.component.ts
│   ├── header
│   │   ├── header.component.html
│   │   ├── header.component.scss
│   │   ├── header.component.spec.ts
│   │   └── header.component.ts
│   ├── main-area
│   │   ├── xxx/ (子コンポーネント)
│   │   ├── main-area.component.html
│   │   ├── main-area.component.scss
│   │   ├── main-area.component.spec.ts
│   │   └── main-area.component.ts
├── config
│   ├── config.ts
│   ├── development.ts
│   ├── production.ts
│   └── staging.ts
├── environments
│   ├── environment.prod.ts
│   └── environment.ts
├── main.ts
├── polyfills.ts
└── services

Webpack や TypeScript の設定

tsconfig.json はいろんな設定をパクった結果、今のものに行き着いた。tsconfig.json の設定如何では、コンパイル通らなくなったりコード書きづらくなる(any 周りなど)のでドキュメント見ながら設定することをおすすめする。 また、webpack.config.js は、development と production で分岐。 development では sourcemap を出してデバッグしやすく、production ではなるべくバンドルを圧縮させるプラグインを使用。 webpack-dev-server を使ってみたのですが、ルートディレクトリに index.html がないと起動しないらしく、webpack –watch で代用。

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "allowJs": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "declaration": false,
    "removeComments": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "compileOnSave": false,
    "types": [
      "node",
      "jasmine"
    ],
    "lib": [
      "es2015", "dom"
    ]
  },
  "typeRoots": [
    "node_modules/@types"
  ],
  "exclude": [
    "node_modules",
    "vendor"
  ]

webpack.config.js

'use strict';

var webpack = require('webpack');
var path = require('path');
var isProd = process.env.NODE_ENV === 'production';

var config = {
  devtool: isProd ? 'eval' : 'inline-source-map',
  entry: {
    'app': './angular/main.ts'
  },
  output: {
    path: path.resolve(__dirname, 'public/js'),
    filename: 'app.js',
    chunkFilename: (+new Date) + '.app.js'
  },
  resolve: {
    modules: [
      path.join(__dirname + 'angular/'),
      "node_modules"
    ],
    extensions: ['.ts', '.js']
  },
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: ['light-ts-loader', 'angular2-template-loader'],
        exclude: /node_modules/
      },
      {
        test: /\.css$/,
        use: ['to-string-loader', 'style-loader', 'css-loader']
      },
      {
        test: /\.scss$/,
        use: ['to-string-loader', 'css-loader', 'sass-loader']
      },
      {
        test: /\.html$/,
        use: ['html-loader?-minimize']
      },
      {
        test: /\.(png|woff|woff2|eot|ttf|svg)$/,
        use: ['url-loader']
      }
    ]
  },
  plugins: isProd ? [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: true,
        screw_ie8: true
      }
    }),
    new webpack.optimize.AggressiveMergingPlugin()
  ] : [],
  watchOptions: {
    poll: true
  }
};

module.exports = config;

ユニットテスト設定

こちらもいろんなライブラリを使ってみた結果、Angular のドキュメントでも紹介されていた karma + jasmine に行き着いた。 karma の設定は簡単だったが、disconnected になったときのエラーを探るときが大変。(karma start しないとでてこない)

karma.conf.js

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      {pattern: './karma-shims.js', watched: false}
    ],
    exclude: [
    ],
    preprocessors: {
      './karma-shims.js': ['webpack', 'sourcemap'],
      'angular/**/*.spec.ts': ['coverage']
    },
    webpack: require('./webpack.config.js'),
    webpackMiddleware: {
      watchOptions: {
        poll: true
      }
    },
    reporters: ['progress', 'coverage'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['PhantomJS'],
    singleRun: false,
    concurrency: Infinity,

    coverageReporter: {
      dir: 'public/coverage',
      reporters: [
        {
          type: 'json',
          subdir: './',
          file: 'result.json',
        },
        {
          type: 'lcov',
        }
      ]
    }
  })
}

Angular のバージョン上げてみた

Angular 2 -> 4

これ以上早くならないと思っていたビルド時間が早くなり、バンドルのサイズも1〜2割ほどちっちゃくなったので感動。笑

比較結果

Angular 2
<dev>
Time: 15.06s
bundle size: 10.9MB
<prod>
Time: 14.05s
bundle size: 4.72MB
Angular 4
<dev>
Time: 20.40s
bundle size: 9.39MB
<prod>
Time: 11.96s
bundle size: 3.8MB

まとめ

Angular はドキュメントがかなり充実してるので、ドキュメントを見よう!
https://angular.io

※ もう少し細かいところで詰まった気がしているが、だいたい tsconfig.json か webpack.config.js の内容や設定を理解してなかったのが原因だったので設定ファイルのドキュメントを見るのが大事

Ansible local を使ってオリジナルの Vagrantfile を作った

なぜ作ったのか

ホスト OS にいろいろ環境をつっこんでぐちゃぐちゃになるのが嫌だったので、vagrant で作った仮想マシンに全部つっこむようにしていました。ただ、ほぼほぼ vagrantfile いじってなかったので vagrant destroy したりするといろいろインストールやらやり直さないといけません。vagrant の良いところの 1 つとして環境破壊 -> 再構築が簡単であることがあげられると思いますが、再構築の部分をもっと簡単にするためにオリジナルの vagrantfile を作りました。

Vagrantfile

https://github.com/rnitame/Vagrantfile

初めて vagrant up したときか、vagrant provision をしたとき、ゲスト OS にインストールされた ansible が動いて諸々ソフトウェアをインストールします。

f:id:rnitame:20170627164655g:plain

各ソフトウェアのインストールされるバージョンはこの通り。 https://github.com/rnitame/Vagrantfile#software-version

中身について

f:id:rnitame:20170627164826p:plain

hosts の ip に対して playbook.yml にある内容を実行します。内容は roles にある tasks たちになります。 基本やっていることは、apt-get で最新版のものをインストールしてるだけです。他は nginx をスタートさせたりちょっとしたシェルを実行させたり。シェルを実行させるあたりについては、冪等性に気を付けつつ作りました。

はまった

vagrant up したときに ssh のコネクションをするところでタイムアウトしました。いろいろぐぐるタイムアウトになるまでの時間を増やせとかでてきますが解決せず。

解決策

公式の issue にあがってますが、NAT のインターフェースが接続されていなかったのが原因でした。(VirtualBox の Network のところを見て確認) https://github.com/mitchellh/vagrant/issues/7648

なので issue にもあるとおり、以下を vagrantfile へ。

config.vm.provider 'virtualbox' do |vb|
    vb.customize ['modifyvm', :id, '--cableconnected1', 'on']
end

https://github.com/rnitame/Vagrantfile/blob/master/Vagrantfile#L21

まとめ

ansible local を使ってオリジナルの vagrantfile を作りました。ホスト OS に ansible を入れる必要がないので、vagrant up するだけで良いのはとても助かりますね! それと、task 名を記述できるのでどこでなにをしているのかがわかりやすくて良いです。 Docker と組み合わせもしてみたい!

エンジニアとして働きはじめて8ヵ月経った

はじめに

この記事は 岩手県立大学 Advent Calendar の 7 日目の記事になるはずだった 20 日目の記事です。

f:id:rnitame:20170627165839p:plain

(isseium さんありがとうございました…)

後輩氏からこう言われたのでポエムになっております。それでは本題です。

自分はソフトウェア情報学研究科 博士前期課程(長い)を今年3月に卒業して、4月からアイスタイルでWebエンジニアとして働いています。

17卒の後輩たちの勢いを感じる最近ですが、この8ヶ月で学んだ良いことをお伝えできたらと思います。

※下記内容は自分個人の意見で、所属企業を代表するものではありません。念のため。

自分なりのしっかりした行動指針ができた

自分なりの1つのルールを作ることができました。 会社に入ると、大学では経験し得なかったことをたくさん経験することになります。数百人規模が参加するイベントの運営、などなど。 なんにもわからないのでひたすら手探りです。試行錯誤の連続。 その試行錯誤の連続で、思い切り頭使って考えることで「こういうときはこれからこうしよう!」と思うようになりました。 その端々で思ったことをまとめたものが行動指針になっています。 詳しくは自分の行動指針 - 本当にそれは気にするべきことなのか?: /storage/tummy.log にかきましたのでぜひ。

ただこの行動指針も、今後の社会人生活でどんどん変わっていくはずなので考えることはやめないようにしたいですね。

質問することへの抵抗がなくなった

よくある悩みで初心者の質問だからしちゃいけない、といったものがあると思いますがどんどんした方がいいということに気づきました。 自分がいま所属している部では、分報というちょっとしたTwitterのような感覚で悩みや興味があったことを投稿する場所が Slack にあります。

f:id:rnitame:20170627165842p:plain

(隣に座っている先輩に温かいお言葉をいただいている図)

こんな感じで、わからないところを投稿すると先輩方が助けてくれます。 30分くらい時間をきめて、ひたすら手探りしてわからなかったら聞いてみましょう。聞かずに格闘し続けて1日潰してしまうよりよっぽどマシです。 そして、質問して答えをもらったらなるべく同じ質問をしないよう、自分の中で反芻すると良いです。 なぜわからなくなってしまったのか、原因は何か、解決策は何か。 (まだ自分もうまくできていませんが)教えて頂いた後に反芻するだけでもその後の自分への定着具合が変わってきます。

設計やテストへの意識が高まった

いやもうお恥ずかしいことに学生の時に作ってたアプリはこの辺全無視だったので、全く知識がなかったのです。 テストは、プロジェクトにアサインされてコードを書くようになってから、テストがないとレビュー通らない環境になり、テストの大事さを痛感しました。 (冗談ですが)テスト書かないと死ぬぞ!と言われるくらいです。笑 設計ですが、会社ではチームで開発するかつ実装後もいろんな人が自分たちが書いたコードを読む可能性がある環境です。 なのでわかりやすい設計、コードを心がける必要があります。

(今も絶賛勉強中ですが)いろんなアーキテクチャやパターンを知ることでよりよい設計に活かせます。より良い設計ができれば、 そのプロジェクトのコードもよりよいものになるはずです。 ※あくまでアーキテクチャやパターンは目的

とりあえず手動かして作ってみようぜ精神ができた

~に興味ある!おもしろそう!、~やらなきゃ…と言う前に手を動かそうぜ!ということです。 これまたお恥ずかしいことに、おもしろそうだなーと思いつつ全く手を動かしていなかった学生時代なので、今がつっとツケが回ってきている気ががが。 ただでさえ、社会人になると日中は仕事で時間がないので、なんでも興味を持ったらまず調べる。プログラミングであれば、Getting Started を動かす。 そこで更に興味を持ったらサービスを作ってみる段階に行きます。個人的にも何個か作っていますが、それを GitHub に push して草をモチベーションにしていてとても楽しいです。

f:id:rnitame:20170627165845p:plain

また先程の分報にもつながりますが、プライベートで手を動かした結果出てきたわからないことを、気軽に言える空間があるのも大きな点です。

まとめ

入社してから学んだことをお伝えしました。 来年4月には後輩が入ってくるので、またいろいろ変化があります。その変化を経験すると、またここに書いた以外のことが良さとして見えてくるかもなーと思っています。 以上、在学生や同じ社会人1年目の方々に参考になれば幸いです。

自分の行動指針 - 本当にそれは気にするべきことなのか?

はじめに

この記事は 行動指針 Advent Calendar 2016 の 13 日目です。社会人 1 年目がもう終わろうとしている中で整理する意味も込めて、書いてみたいと思います。

テーマ:平和が一番

いろいろ考えた結果、やっぱり平和が一番だなということに気が付きました。笑 平和に行動するために決めている指針が以下です。

本当の目的はなんなのか?を考える

例えば書類整理の業務が発生したとします。時間制限やノルマがあれば、もちろんそれを終わらせるために動くわけですが、今自分がやっている書類整理をすると何が起こるのか。依頼してくれた方は何を目的として書類整理を自分に頼んだのかを考えるようにしています。書類整理の本来の目的が探しやすくすることで時短につなげる、であるとすればそれを達成するためにより具体的に行動ができます。

今苛ついている理由を考える

例えば複数人でミーティングをしていてなかなか意見がまとまらないとき、(自分がそうなので気をつけなければいけませんが…笑)なかなかスパッと決まらないことに苛ついていきます。ただそこでイライラを外にぶつけるのではなく、一旦冷静になってイライラしている理由を考えるようにしています。例で言えば、スパッと決まらないことにイライラしているので、なぜスパッと決まらない状況になっているのかを考えます。最終的に、本当の目的を考えることにつながっていきます。

妄想で不安にならない。まずやってから

例えば社内イベントの企画をしているとき。数百人規模のイベントを回したことはまずないので、いろんな妄想が広がっていきます。(大げさですが)もしかしたらビンゴをするときに誰もビンゴカードを受け取ってくれないかもしれない…などなど。そうなった場合、誰かに相談したくなりますが、相談された方は答えようがありません。なので、その妄想は本当にありえるのか、有り得そうならばどのような対策を講じるべきか まず 考えるようにしています。この辺については、Twitter でバズっていた技術者の質問心得がわかりやすいです。

良い回答は良い質問にしかできない

最後に

行動指針アドベントカレンダー、興味深く読ませてもらってます!明日以降も楽しみです。 明日は andmorefine さんです。