2019-11-14 02:24
GitHub Actionsを遅まきながら使ってみて、自分のアクティブなGitHub上のGoのOSSプロジェクトで知見がたまったので、共有するものである。
GitHub Actionsについて
非常に良い。VCSとCI/CDの統合は体験が良い。各種イベントをハンドリングできるが、そのイベントが元々Webhookで提供されていたものなので、Webhookを弄っていた身からすると非常に親しみやすかった。コードpush以外のイベントもハンドリングしてプログラマブルに扱えるので夢が広がる。
使い勝手とか具体的に良くなった点
リポジトリ直下の.github/workflows
配下に既定のYAMLをpushすると、その設定にしたがって自動でアクションが動いてくれる。ブラウザ操作必要ないのは快適。
GitHub上でいろいろ完結できる
Windowsのテストもできる!
GITHUB_TOKEN
管理もうまいことやってくれるのでreleaseのアップロードもやりやすくなった
各種イベントドリブンでジョブを起動でき、それぞれのワークフローごとにファイル分割できる
定型作業はアクションという形で誰でも利用可能な形で公開可能
Goで扱う場合
オレオレGoオーサリングツールである、godzil に導入している。ちなみに、godzilで作られる雛形も、GitHub Actions前提となりました。詳しくはリポジトリをみて貰えばと思いますが、以下に解説を書きます。
テストの実施
.github/workflows/test.yaml
の中身が以下。
name: test
on:
push:
branches:
- "**"
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macOS-latest
- windows-latest
steps:
- name: setup go
uses: actions/setup-go@v1
with:
go-version: 1.x
- name: checkout
uses: actions/checkout@v1
with:
fetch-depth: 1
- name: lint
run: |
GO111MODULE=off GOBIN=$(pwd)/bin go get golang.org/x/lint/golint
bin/golint -set_exit_status ./...
if: "matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest'"
- name: test
run: go test -coverprofile coverage.out -covermode atomic ./...
- name: Convert coverage to lcov
uses: jandelgado/gcov2lcov-action@v1.0.0
with:
infile: coverage.out
outfile: coverage.lcov
if: "matrix.os == 'ubuntu-latest'"
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
path-to-lcov: coverage.lcov
if: "matrix.os == 'ubuntu-latest'"
ポイントは以下。
構文はヘルプによく纏まっている
pushイベントをトリガーにしている
branch指定を**
にしている
これは全てのブランチを対象にしつつtagのpushは対象外とするため
ubuntu/maxOS/windowsを対象にしている
windows環境ではautocrlfがtrueになっているようなので、改行がCRLFに変換されてしまうことは注意が必要
golintをかける時に、GOBINを明示的に指定している
if構文を使って動作可否の判定ができる
go test
を実施時に、カバレッジ用のファイルも出力している
それを、coverallsに連携させている
coveralls公式のアクションcoverallsapp/github-aciton を利用してカバレッジを投稿している
coverallsのアカウント登録さえ済んでいれば、coveralls上でのrepo登録操作も不要
coveralls公式のアクションはlcov形式しか介してくれないので、事前の変換のためにjandelgado/gcov2lcov-action を利用している
これで、mattn/goverallsが不要になった。お世話になりました。(まだお世話になっているところもある)
リリース
release.yaml
が以下。
name: release
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: setup go
uses: actions/setup-go@v1
with:
go-version: 1.x
- name: checkout
uses: actions/checkout@v1
with:
fetch-depth: 1
- name: release
env:
GITHUB_TOKEN: ${{ secrets.github_token }}
run: |
export GOBIN=$(pwd)/bin
PATH=$GOBIN:$PATH make crossbuild upload
pushイベントをsemverにマッチするtag限定でフックして、リリースイベントをキックしている。実プロセスとしては最後の行のmake crossbuild upload
が全てですが、内部的にはgoxz でcrossbuildして、ghr でアップロードしています。GITHUB_TOKEN
環境変数をsecrets.github_token
で受け渡せるのが嬉しいポイント。
これまで個人的にはtoken管理の煩雑さを嫌って、手元でビルドしてGitHub Releasesにあげるパターンが多かったのだけど、これで、GitHub Actions上でリリースするようにできたので嬉しい。今はアップロードにghrを使っているが、公式のアクションactions/upload-artifact の機能が充実してきたらそっちに乗り換えも考えたいと思っている。
ちなみに、on: create
でcreateイベントを方法も検討したが、createイベントだとtagsで絞り込むことができないのでやめた。イベントごとに指定できるattributeが異なるのでドキュメントをよく読む必要があります。
バッジ
README.md等に貼り付ける用のバッジも当然あり、URL体系は以下の具合です。
https://github.com/<OWNER>/<REPOSITORY>/workflows/<WORKFLOW_NAME>/badge.svg?branch=master
godzilだと以下の通りです。
https://github.com/Songmu/godzil/workflows/test/badge.svg?branch=master
今後
actions/cache の活用や、独自acitonの公開などをして知見を貯めて、社内環境への導入も伺いたい。
2019-10-22 20:02
プロジェクトルートで以下を実行するだけです。ghq import -P
で高速に並列cloneしているのがお洒落ポイントです。
go list -f '{{join .Deps "\n"}}' | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' | ghq import -P
以下のようにシェル関数を定義しても良いでしょう。
gomod-ghq() {
go list -f '{{join .Deps "\n"}}' | xargs go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' | ghq import -P
}
Go 1.13もリリースされ、Go Modulesに対応したプロジェクトも増えてきました。GOPATH時代は $GOPATH/src
に依存が自然とcloneされていたのに、そうではなくなったので、このようにghqで一括取得してやると便利です。
ghqは元々Goのパッケージ取得のルールを参考にして作られたツールなのに、逆にこのようにGoのライブラリを取得するためにghqが必要になったというのも面白い話ですね。
そういえば、みんなのGo言語の改訂2版出ていたので皆さん是非ご購入ください。改訂にあたっては、Goの依存管理周りをglideからGo Modulesにゴリっと書き換えました。改訂作業中にもGo Modulesの仕様調整がたびたび入るので結構大変でした。結局Go 1.13でGo Modulesは完全に正式化はされませんでしたしね。
2019-10-21 19:24
RDBのレコードに、作成日時や更新日時を自動で入れ込むコードを書いたりすることあると思いますが、それに対する個人的な設計指針です。ここでは、作成日時カラム名をcreated_at
、更新日時をupdated_at
として説明します。
tl;dr
レコード作成日時や更新日時をRDBのトリガーで埋めるのは便利なのでやると良い
ただ、アプリケーションからそれらのカラムを参照することはせず別に定義した方が良い
MySQLにおける時刻自動挿入
MySQL5.6.5以降であれば、以下のようにトリガーを設定すれば、レコード挿入時に作成日時と更新日時を、更新時に更新日時を、DATETIME型にも自動で埋めてくれます。いい時代になりました。(MySQLが遅すぎたという話もある)
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
便利なので積極的に使っていくと良いでしょう。アプリケーションがバグっていても確実に埋めてくれます。アプリケーションフレームワークでこれらの値を自動で埋めてくれるものもありますが、今の時代はトリガーを使うのが良いのではないでしょうか。
ただし、これらはログ的な調査記録用の扱いで、アプリケーションから参照することはしないようにするのが良いと考えます。
なぜアプリケーションから参照しない方が良いのか
以下のような理由です。
トリガーにアプリケーションロジックが依存しすぎて密結合になってしまう
アプリケーションから使うのであれば、汎用的な名前ではなく意味のある名前にすべき
トリガーにアプリケーションロジックが依存しすぎて密結合になってしまう
例えば、テストコードを書く際にRDBも一緒に動かすことが必須になってしまう。現在時刻のモックも難しい。テストの時だけINSERT文に明示的に時刻を指定するのは本末転倒です。
ちなみに矛盾するようなことを言いますが、僕は、アプリケーションのテストコードはなるべく実際のDBを起動してバンバンデータを入れながらテストするのがいいとは考えています。変に頑張りすぎてインターフェースレイヤー切っちゃうとそこがバグったりするので。
アプリケーションから使うのであれば、汎用的な名前ではなく意味のある名前にすべき
created_at
や updated_at
のような汎用的な名前ではなく、例えば、blog_entries
テーブルであれば、published_at
, edited_at
などの命名にすべきです。
これらのカラムは、created_at
や updated_at
とは別に設け 、値もトリガーではなくアプリケーションから埋めるべき でしょう。
想定問答など
記録用のためであればログをしっかり残して無駄なデータを入れる必要はないんじゃないの?
これはその通りです。ログ保存の確実性と検索性が高いのであれば、別にここにいちいち記録する必要はないでしょう。ただ、多くの場合そこまでログ整備はしっかりしておらず、とりあえずRDBにクエリを打った方が手っ取り早いということも多いでしょう。ログを取り漏れている可能性もあります。多少冗長な情報はいざという時にあなたの身を助けてくれます
イミュータブルデータモデルを採用している場合更新時刻は不要ではないか?
参考: イミュータブルデータモデル(入門編)
これもその通りです。思考停止して created_at
と updated_at
を追加するのではなく、そのカラムが本当に必要なのかを考えてテーブル設計しましょう。ただ、考えすぎても案外脳のリソースを取られるので、迷ったらとりあえず入れておく、でも良いとも思います。残念ながら設計力が足りず「やっぱり更新が必要になってしまった」となることもあるでしょう(データ量が許すのであればそうなってからカラムを追加してもいいとは思いますが)。
イミュターブルデータモデルの他にも、例えば、ユーザが操作しないマスタ系のテーブルでdeploy時にそのデータを埋めるフローなのであれば、作成時刻や更新時刻は不要でしょう。
ちなみに、レコードをイミュータブルに扱うというのは、近年の安全な設計論からしても理に叶っています。なるべくイベントとして扱うというのはわかりやすい指針です。ただ、現実問題として、難しい局面もあります。データ量も多くなりがちです。データ量はパーティションなどを活用すれば解決できますが、他にも例えば「10人のユーザーの最新のイベントだけを取って一覧する」といったことが案外難しかったりします。
データが重複してデータ量が増えるのが嫌なんですが
もちろん余計なデータが増えることは避けたいですし、そのカラムが本当に必要かどうか都度検討するのが望ましいと前項で述べました。
また、上記の例ですと、created_at
とpublished_at
に同じ値が入ってしまうことが気持ち悪いかもしれません。しかし、この場合は良くないDRYの落とし穴にはまっています。
本当に、created_at
とpublished_at
は本当に同じデータで良いのでしょうか?例えば下書き機能で「下書き追加時点では公開日時は記録しない」などの仕様が発生したら大変です。そしてこの仕様は妥当です。updated_at
とedited_at
も同じで良いのでしょうか。例えばコメントが追加されたり、トラックバックが送信された場合にはどうすれば良いのか困ってしまいます。
(この辺りの設計も、実はイミュータブルデータモデル的に時刻を更新するそれぞれのイベントごとにテーブルを分ければ綺麗に設計できたりするのですが、それは別の話)
つまり、created_at
とupdated_at
はRDBのドメインの上で「レコードが作成された時刻・更新された時刻」以上の意味を持たないことに価値があるのです。RDBドメイン上の情報であるので、RDBの機能(トリガー)でデータを埋めた方が良いとも考えます。
そして、繰り返しとなりますが、アプリケーションから参照するカラム名は、より意味のある命名を心がけましょう。
2019-10-09 01:24
https://github.com/Songmu/replaceablewriter
表題の通りですが、io.Writer
をラップして io.WriteCloser
として振る舞い、その内部に保持した io.Writer
を差し替え可能にするライブラリを書いた。
例えば、Goの標準logをログローテートしたい場合には以下のようにします。
f, _ := os.OpenFile("20191001.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
w := replaceablewriter.New(f)
log.SetOutput(w)
// 翌日になったら差し替える
f2, _ := os.OpenFile("20191002.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
w.Replace(f2) // 以降、20191002.logにログが書き込まれる
io.Writer
の差し替えはシグナル受けたときにやっても良いし、タイマーを回しても良いでしょう。ファイル名を同じにしたい場合は、事前にファイルを os.Rename
してからファイルを開き直して、Replace
を呼べばOKです。例えば以下のような形。
logname := "log.log"
f, _ := os.OpenFile(logname, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
w := replaceablewriter.New(f)
log.SetOutput(w)
// 翌日になったら差し替える
os.Rename(logname, "log-20191001.log")
f2, _ := os.OpenFile(logname, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
w.Replace(f2)
単なる io.WriteCloser
なので、io.Writer
を指定できるloggerであればなんでも対応可能です。ざっと書いたので、まだ適当クオリティですが、フィードバックあると嬉しいです。
作った動機とか
個人的に多機能なロガーが好きじゃない。ロガーは呼び出しも多く、IOを伴う処理でもあるため、地味にパフォーマンスのボトルネックになりやすい。なので、ロガーはシンプルにストリームに書くことに集中して欲しい。プラガブルな機能とかログローテート機能は別に必要ない。実際、多機能で知られるlogrusとかもパフォーマンスが悪いことで有名です。
ログローテートも、アプリケーション自体はシンプルに標準エラー出力や標準出力に吐いておいて、後続のlograotate, clonolog, multilog等に任せるのが好みです。kazuhoさんもこう言っています。
そもそもファイルに書くという発想が時代遅れになりつつあるわけです。それでもログローテートしたい場合、ファットなロガーがオールインワンでそれを提供するのではなくて、Goにはio.Writer
という素晴らしい抽象があるので、このレイヤーで書き出し先を差し替えれば良いんじゃないかと思ったのが、このreplaceablewriterを作った動機です。
ログローテートについて熱く語ってしまいましたが、別にログローテートに限らず、書き出し先を切り替えられるのは便利だと思うので、よろしければご活用ください。
2019-09-16 21:02
開催から少し経ったが、今年もbuildersconに行ってきた。一般参加。転職のタイミングとCfP締め切りが近く、無理やり現職ネタでCfP出そうとも思ったのだが間に合わなかった。無念。来年はCfP通してトークしたい。
今年はフルで参加できなさそうで実際そうだったんだけど、コンプリートパック買っておいたので、行きたいところにふらっと行くことができたので体験良かったです。
印象に残ったトークをいくつか。
スーパーカミオカンデ!
今年はとにかく、スーパーカミオカンデのトークが圧巻だった。
http://www-sk.icrr.u-tokyo.ac.jp/~hayato_s/20190831_Super-Kamiokande.pdf
あまりにも規模や桁が違いすぎて、わからない事だらけなのにトークはとにかく面白く引き込まれた。規模は違えど、CentOSとかCiscoのスイッチとか、FPGAでTCPスタック実装(!)とか、僕らでも知っている技術も活用している点が興味深かった。
「何言ってるか全然わからないけどとにかく面白い」という、Shibuya.pm等の技術カンファレンスに行き始めた頃の感覚、「ああ、技術カンファレンスっていうのはこういうのが快感なんだよ」ってのを思い出すことができた。初心に戻れるようなすごく良い発表だった。まさしく「知らなかった、を聞く」
アフターパーティーにスピーカーの早戸さんがいらっしゃっていたので、めっちゃ話を聞きに行った。
アプリ国際化の舞台裏
国際化の技術について前提含めて丁寧に話していてそこだけでもわかりやすくてよかったんだけど、最後に意外にもチームや多様性の話がでてきて、その話が思いの外良かった。
多様性のあるチームは働きにくさを感じるがより良い成果が出るという研究結果
というのが印象に残っている。出典としてでている以下のエントリも必読。
https://hbr.org/2016/09/diverse-teams-feel-less-comfortable-and-thats-why-they-perform-better
20年後のソフトウェアテストの話をしよう
ハードウェアを含めたテストが今後どうなっていくかには現在の業務的にも興味があるので見に行った。20年前と現在を比較して、どれくらいの飛躍があったのかから考察が始まったのが面白かった。
ハードウェアや機械学習など色々な技術要素が取り上げられていた。結局リアルワールドをどれくらい再現可能にするのかという話なので、今後技術トピック的にもめちゃくちゃアツい領域なんだなーというのを改めて感じた。
立ち見だったのだけど、僕より後に入ってきた @t_wada さんが、会場に入るやいなやツカツカツカと脇目もふらず会場の前の方に突き進んで行ったのが面白かった。獲物に突き進むライオンのごとしであった。
ということで
なんだかんだで色々交流もできて、非常に楽しませてもらいました。運営の皆様本当にありがとうございました。お疲れさまでした。
来年も期待しています。トークしたい。
2019-07-29 02:56
tl;dr
CI/CD環境から複数のGitHubのprivate repositoryにアクセスさせたい場合にはmachine account(machine user)を使うと良い
SSH KeyでもAPI tokenでもどちらでも良いけどSSH方式がGo公式repoでも紹介されている
CircleCIだとSSH Keyの設定(User Key)が簡単でその他の設定がほとんど不要
本題
Goに限った話ではありませんが、プロジェクトで使っているprivate repositoryからまた別のprivate repositoryを参照している場合、CI/CDなどの外部環境からどのようにそれらにアクセスさせるか困ることがあります。
例えば、git submoduleを使っている場合や、Goの場合ですとGo Modulesで指定しているパッケージがprivate repositoryである場合などがあるでしょう。
なぜ困るのかと言うと、GitHubの場合、CI/CD環境からprivate repositoryのリソースにアクセスさせる場合、repositoryにRead-only deploy key を設定して使う方法が個人にも依存せず、アクセス権限を絞る上でも望ましく、一般的に利用されますが、このDeploy Keyを複数のrepositoryで共有することができないという仕様上の制約 があるため、複数のprivate repositoryをcloneしようとすると途端に困ってしまうからです。
どうするか
Deploy Keyが使えない以上、個人ユーザーのSSH Keyか、API tokenを利用するしかありません。しかし、個人のものを使ってしまうと、個人に依存してしまいますし、自分の全てのprivate repositoryにアクセス可能になってしまいます。これでは困る。
ここでも、前回の記事 でも取り上げた、"machine account"を活用します。
そういった用途に関して、GitHubのDeveloper Guideにも"Machine users"という項でドンピシャで説明されています。ここでは、accountではなくusersになっています。
ref. https://developer.github.com/v3/guides/managing-deploy-keys/#machine-users
Machine userを作成し、最小限必要なrepositoryのみにREAD権限を与えることで権限を絞ることができます。そのアカウントを複数人で管理すれば個人に依存することもありません。
Goの場合
GoのModulesの場合、対象のpackage repositoryをhttpsスキームのURLで取得しようとするため、取得時にそれを insteadOf で書き換えてやるのが基本戦略になります。
SSHを利用する場合
% git config --global url."ssh://git@github.com/<myorg>/".insteadOf "https://github.com/<myorg>/"
personal access tokenを使う場合
% git config --global url."https://${user}:${token}@github.com/<myorg>/".insteadOf "https://github.com/<myorg>/"
SSHかaccess tokenか
CI/CD上で利用する時、tokenの設定をする方法だと、うっかり画面の実行ログ上でtokenが見えてしまうリスクがあるかも知れません。またSSHを使う方法のほうが、GitHub固有の設定にもならないため、SSH KeyをCI/CD環境上に安全に設定する方法があるのであれば、そちらのほうが良さそうです。
Go公式の以下のissueでも特定のソースホスティングサービス用の設定を持たせられるようにできないか議論されていますが、やはり、sshでinsteadOfを使う方法が現状の対応案として紹介されています。Russ Cox氏もコメントしていますね。
https://github.com/golang/go/issues/26134
CircleCIだとSSH方式がより簡単
CiecleCIは標準でprivate repositoryにDeploy Keyを自動登録することで、repositoryのリソースアクセスを実現しています。
これでは冒頭に述べたように、単一private repositoryのリソースしか取得できないため、CircleCIにはそれを回避するために"User Key"を簡単に設定する機能が備えられています。公式ドキュメントの "Controlling Access Via a Machine User" という項にそれが書かれています。
ref. https://circleci.com/docs/2.0/gh-bb-integration/#controlling-access-via-a-machine-user
これはCircleCIがOAuth経由でGitHubユーザーにSSH Keyを自動的に登録する方法で、CircleCIはそのSSH Keyを使って、repositoryのリソースにアクセスするようになります。
これは少し怖いので、やはり、個人ではなくMachine userでやるべきでしょう。 一度、SSH Keyが登録されたあとは、その認可は念の為revokeしておいた方が良いでしょう。GitHubの個人設定のApplications -> Authorized OAuth Apps からrevokeできます。 revokeするとSSHキーも根こそぎ消えるみたいで駄目でした。セキュリティ的には正しい挙動…。
Go Modulesの依存取得
ここまでくればあとは簡単です。checkout ディレクティブを使えば、repositoryを取得できますが、この時、前項のSSH Keyを自動的に使い、insteadOfの設定も以下のように暗黙的にやってくれています。
% git config --global url."ssh://git@github.com".insteadOf "https://github.com"
あとは、private repositoryはmachine userの権限の範囲で取得できますし、Go Modulesの依存取得もinsteadOfの設定がされているため、go mod download
とかでうまいことやってくれます。
まとめ
ということで、GitHubのMachine userとCircleCIのSSHのUser Keyを利用すれば、複数のprivate repositoryの取得が容易になり、privateなGoパッケージの取得も同様に簡単になります。
2019-07-28 22:50
git-pr-release そのものの説明に関してはninjinkunの以下のエントリを参照ください。
git-pr-releaseのすすめ
さて、現職に入社したら、git-pr-releaseが使われていたのですが、リリース担当者が手元で実行するフローになっていました。しかし、git-pr-releaseの本場であり発祥の地でもある、はてな社では、git-pr-releaseはCIに作らせるものであったので、それに倣って、こちらも現職で利用しているCircleCIに作らせるようにしてみた。
手順
.git-pr-release
をrepositoryに配置する
GIT_PR_RELEASE_TOKEN
をCircleCIに登録する
.circleci/config.yml
にjobを設定する
おまけ
machine accountを作るといいよ
Triage(トリアージ)権限が便利
1. .git-pr-releaseをrepositoryに配置する
すでにgit-pr-releaseをお使いの場合は、既に配置されているかも知れませんが、repository rootに以下のような.git-pr-release
ファイルを配置してコミットもしておく。
[pr-release "branch"]
production = master
staging = develop
[pr-release]
labels = pr-release
pr-release.labels
でラベルの設定もできるのでこれも後でリリース履歴のリストアップするときなどに便利です。設定を~/.gitconfig
や.git/config
に登録しておく手もありますが、ちゃんとrepositoryに置いておくとプロジェクト共通の設定になるので何にせよ良いです。
2. GIT_PR_RELEASE_TOKEN
をCircleCIに登録する
GitHub上でpersonal access tokenを発行する。その際、scopeの選択のときにrepoにチェックを入れておく。
そこで作られたtokenをCircleCIのプロジェクトの環境変数設定で GIT_PR_RELEASE_TOKEN
という名前で登録しておく。
ここで個人のpersonal access tokenを使うのが嫌な場合は、後述のmachine accountを活用すると良い。
3. .circleci/config.yml
にjobを設定する
CircleCIの設定に例えば以下のようにjobを設定する。ここでは"pr-release"という名前で、jobを設定している。たった3ステップの簡単なjobである。
version: 2.1
jobs:
build:
...(略)...
pr-release:
docker:
- image: circleci/ruby
steps:
- checkout
- run: gem install -N git-pr-release
- run: git-pr-release --no-fetch
workflows:
version: 2.1
works:
jobs:
- build
- pr-release:
filters:
branches:
only: develop
workflowのfilters設定で、developでしか動かないように設定しているのもポイントで、これで、developが進んだときだけgit-pr-releaseが再実行されることになる。そして、git-pr-releaseは再実行してもいい感じに既存のpull requestをアップデートしてくれるのです。
ということでこれだけで、developにfeatureブランチをマージしていけばCircleCIが自動的にpr-releaseを生やしてくれるようになりました。開発者の手元にgit-pr-releaseをインストールする必要もなくなりました。めでたしめでたし。
おまけ: machine accountとTriage権限の話
個人のtokenを使うの怖いし、退職リスク等もあるので、アクセスできるrepositoryや権限を絞ったユーザーを自動化のためにオーガニゼーションに一つ作るとよいでしょう。
これは、GitHubの利用規約 に、machine accountという名前で定義されています。自動化のためのアカウントを1フリーユーザー辺り1つ作ってもよく、これを複数人でメンテしても良いとされています。
A machine account is an Account set up by an individual human who accepts the Terms on behalf of the Account, provides a valid email address, and is responsible for its actions. A machine account is used exclusively for performing automated tasks. Multiple users may direct the actions of a machine account, but the owner of the Account is ultimately responsible for the machine's actions. You may maintain no more than one free machine account in addition to your free User Account.
Triage(トリアージ)権限
machine accountには必要以上の権限を与えるべきではなく、一般的にはrepositoryのRead権限のみを与えることになるでしょう。
しかし今回の、git-pr-releaseを実行させる場合、pull requestを作成しそれにラベルを付与します。しかし、ラベルの付与はRead権限のみではできません。
ここで、最近ベータで追加 されたTriage権限が有用です。これはRead権限に加えて、issueやpull requestの操作が可能になっているものです。
ref. https://help.github.com/en/articles/repository-permission-levels-for-an-organization
とう言うことで、今回の場合、machineアカウントに対象repositoryへのTriage権限を付与すれば万事解決です。
ニッチな権限でありますが、このようにうまく嵌るところが見つかると面白いですね。
ちなみに、machine accountは複数のprivate repositoryにアクセスが必要なCI/CDを構築する際にも効果を発揮するのでその辺りはまた今度。
2019-07-22 03:13
これは、ITエンジニアが真っ先に想起するアプリケーションコンテナではなくて「物理コンテナ」の物語です。以前、コンテナに関するイベントに登壇させていただいた 際に読んでいたのですが、やっとこさエントリを書きます。
この本について
この本には、コンテナが「20世紀最大の発明」と言われるくらい、如何に革新的であったか、どのように普及していったかが書かれている。これは是非ITエンジニアに読んで欲しい。今のアプリケーションコンテナとの類似点が非常に多いからだ。原題は「The Box」であるが、日本語訳の「コンテナ物語」は僕らにとってはナイス訳だと言わざるを得ない。
コンテナが発明され、世界の船やトラック、鉄道のコンテナ運送が共通化される中で、どのような変化が起こったかについて、具体的には以下のようなことが書かれている。
そもそもどうしてそのようなアイデアが出てきたのか
どのように規格化が進行したのか
現場の反発に対してどのように対応したのか
パラダイムシフトによる隆盛と衰退
その後の世界の変化
マルコム・マクリーンというビジョナリー
まず、この本は裸一貫で運送会社を立ち上げたマルコム・マクリーンというビジョナリーがコンテナ輸送を提唱し、その行動力を持って普及させたことについて書かれている。
早く新事業に乗り出したくてうずうずしているマルコム・マクリーンは、なんとかアイデアを実現する方法をみつけるよう部下をせかす。
冲仲士という専門職能団
当時の技術職である沖仲士(港湾労働者)の描写も面白い。当時の沖仲士が会社へのエンゲージメントよりも横のつながりが強かったことは、2000年代のWebエンジニアを彷彿とさせる。
港湾労働の特殊性から、波止場には独特の文化が生まれた。一つの会社のために働く仲仕はまずいないから、彼らの忠誠心は仲間とともにあり、会社に義理立てする者はいなかった。自分の仕事ぶりを知っているのも、気にかけているのも、仲間だけだと男たちは考えていた。労働は苛酷で危険である。そのつらさは他人にはわからない。だから、労働者同士の団結は強かった。
大都市の他の産業と比べ、港湾荷役業では労働者階級特有のコミュニティが発達した
そんな彼らが、コンテナという破壊的イノベーションに対してどのような抵抗を示し、どのように受け入れていったかといったこともこの本には書かれている。
コンテナという「システム」
コンテナは単なる箱ではなくてシステムとなって本領を発揮した。
輸送コストの圧縮に必要なのは単に金属製の箱ではなく、貨物を扱う新しいシステムなのだ
単なる箱だけではなく、港や船、クレーン、制御ソフト、それらがあってこそ、コンテナの本領が発揮される。そこには標準化の物語があり、その中でどのような思惑の交錯があったのか、アメリカとヨーロッパでの思惑の違いについてもこの本には書かれている。
このあたりはKubernetes周りのエコシステムの発展を思い描きながら読んだ。ここでちょっと面白かったのは「コンテナ化して盗難が減った」という話。「隔離性」の重要性が物理コンテナでも在ったのだ。
隆盛と衰退
船会社はコンテナに移行するための巨額の費用を負担して青息吐息になり、ほんの一握りしか生き残れなかった
コンテナリゼーションは世界の港のパワーバランスを一変させた。コンテナ対応が早かった港が一気に成長することとなり、逆にニューヨーク港など隆盛を誇った港が衰退した。
例えば、湾の奥の港はコンテナ以前は工場の近くまで物資を運ぶために大いにメリットがあったが、コンテナ時代になると、無理して湾の奥まで行かなくても、手前の付けやすい港に停泊して、ハイウェイでコンテナを運んでしまえば良くなった。わざわざ湾の奥の港を使う必要がなくなったし、コンテナ化により、船が巨大化し、喫水の関係上、浅い港には停泊できなくなったというのもあった。
パラダイムシフトで情勢が一変したことが書かれていて、インパクトが強い。
アジャイルの萌芽
このような可能性が最初に注目されたのは、一九八〇年代初めのことだった。日本のトヨタ自動車が開発したジャストインタイム方式である
この本はアジャイルについては書かれていないが「コンテナの未来」という章でトヨタについて書かれている。
コンテナにより、輸送コストが下がり、リードタイムも短くなった。これにより、部品などの中間財の在庫を抱えずに、リアルタイムに不足を補うようになっていた。これにより、世界の物流の半分以上を中間財が占めるようになった。
これが「ジャストインタイム」方式である。コンテナによりリードタイムのボトルネックが解消されたからこそ、ジャストインタイムが生まれ、トヨタが躍進したのである。
八七年には、フォーチュン五〇〇にランクされる米企業の五分の二がジャストインタイムを採り入れている。そして採り入れた企業の大多数が、これまでとは全然ちがう輸送方式に切り替えなければだめだと気づいた
「トヨタ生産方式」は僕らアジャイル開発者にとっては必読の一冊である。口酸っぱく「作り過ぎの無駄」について書かれている。そうしないようにジャストインタイム方式が生まれ、それを生み出したものがリアルコンテナなのである。それがまたアジャイルの種になり、クラウドそしてアプリケーションコンテナに至り、インフラ調達のリードタイムを解消する革新的イノベーションにつながっていることは胸熱だと言わざるを得ない。
このエントリでだいぶ書いてしまったが、それでもこの「コンテナ物語」の面白さを損なうものではないので、ぜひ読んで欲しい。
2019-07-17 22:42
https://github.com/Songmu/kibelasync
Nature では、Kibela をナレッジベースとして利用していますが、文章は書き慣れたエディタで書きたいという気持ちがあり、クライアントを作った。GraphQLの勉強にもなると思ったというのもある。
名前やコンセプトはblogsync のオマージュです。手元にMarkdownをごそっと落としてきて、編集して更新するものです。
Install
% brew install Songmu/tap/homebrew
# or
% go get github.com/Songmu/kibelasync/cmd/kibelasync
https://github.com/Songmu/kibelasync/releases からバイナリ取得も可能です
Setup
KIBELA_TOKEN
とKIBELA_TEAM
環境変数を適宜設定してください。
Usage
記事を取得する
デフォルトでは ./notes
以下にごそっとMarkdownを取得します。これは KIBELA_DIR
環境変数や、-dir
オプションで変更可能です。
また、取得時にMarkdownファイルのmtimeがその記事の最終更新日時にセットされます。
# 全件一括取得(ローカルファイルのほうが新しい場合は更新されない)
% kibelasync pull
# 全件一括取得(問答無用で全てのファイルを上書き・高速)
% kibelasync pull -full
# limit指定(更新日時が新しいものから指定件数取得)
% kibelasync pull -limit 10
# folder指定
% kibelasync pull -folder=議事録
記事を更新する
落としてきたMarkdownを編集後、そのファイルを引数に指定して、push
サブコマンドを叩きます。
% kibelasync push notes/333.md
記事を作成する
サブコマンドpublish
に標準入力、もしくはMarkdownファイルを引数に指定することで新規記事を作成できます。
% kibelasync publish --title=こんにちは /path/to/draft.md
% kibelasync publish --title=kibelasync
さてかきはじめるか…
^D
% echo "# こんにちは\nさようなら" | kibelasync publish
この時、何らかの形でのタイトル指定が必須です。Markdownの冒頭にMarkdownのh1要素がある場合、それがタイトルだとみなされます。
# 共同編集を有効にする
% kibelasync publish -co-edit /path/to/draft.md
# 記事投稿後、当該記事のMarkdownをサーバーから取得して保存する
% kibelasync publish -save /path/to/draft.md
-save
オプションを利用した場合、元のMarkdownファイルは削除されます。
ということで
だいぶ便利だと思うのでご利用ください。開発にあたってはAPIの挙動に関してKibelaにいくつかフィードバックを送らせてもらい、爆速で対応してもらいました。ありがとうございました。
開発言語はGoですが、実装的に面白い点として、APIリミットに引っかからないように、http.Client.Transport
をカスタムして過剰なリクエストを送らないように工夫しています。このあたりは、先日のOpen Go Friday in Fukuokaでお話させてもらいましたが、別記事にまとめるかも知れません。興味がある方は、client/ratelimit.go
辺りの実装を見てみてください。
2019-07-16 02:48
https://junkyard.song.mu/slides/gocon2019-fukuoka/#0
色々あってお声がけ頂き、登壇させてもらえることになったので、福岡に行ってきました。出張扱いで、出張費用も所属のNature Japan株式会社に出してもらいました。
話した内容は、Go Conference 2019 Springで20分で話した内容を、単なる再演にならないように内容を膨らませて40分で話した感じです。割と好評のようで良かったです。資料は口頭で説明した部分も多いので、トピックに分けて改めてブログ記事にしたいと思っています。
イベント全体を通して
スタッフの皆さまが少人数ながら的確に動いていて、何もストレスなく快適にイベントを過ごすことができました。すごく楽しかった。ビールや生ハム、スピーカーディナーも楽しませてもらいました。スポンサーの各社に感謝。
会場のFukuoka Growth Nextも小学校をリノベしたスタートアップ支援施設ということで、趣があって良かった。高島市長がいらっしゃった のはびっくりしました。市長のスピーチすごかった…。
交流とか
@k1LoW さんと初めてお話できたのが良かった。ツールを量産していることになんとなく一方的に共感を持っていて、実際、彼の発表 でお話されていた「技芸のコードによるボトムアップ」という言葉には共感を感じることができた。
@pyama86 さんには毎回福岡行くたびに勝手にお世話になっています。ありがとうございます。
@budougumi0617 さんと話が盛り上がった。普段、東京でも交流がありますが、地方のカンファレンスで話すとなんか盛り上がったりして、そういう合宿的な非日常感は地方開催ならではというところ。
あとは、前夜に、メルカリさんの福岡オフィスにお邪魔してOpen Go Friday #5 に参加させてもらったのですが、そこで期せずして@dragon3 さんに二年ぶり(YAPC::Fukuoka以来!)にお会いできたのが嬉しかった。
その他福岡の皆様と色々交流させてもらいました。なんだかんだで福岡には年に一回くらい行っていて、今後も行きそうなのでまた機会でもよろしくお願いします。