Composerの更新 -> PRを作る、をCI上で自動的に実行するプラグインを作った(作っている)

業務で利用しているAWFの更新を、チームメンバーでローテで回しているのだがレポジトリの数が増えてくると大変だ。
私も先日、1つのレポジトリの更新作業担当になったことがあった。「手が空いたらやっておいてね」もしくは「スプリントの狭間くらいでやっておいてね」である。
恥ずかしながら機会を逃しているうちに数日が経ってしまい、むきーーー!というところでした。どちらかというと、普段は「更新しようぜ!!」と煽ち立てる役回りだったので立つ瀬がないという事はこの事。

転んだのにタダで立ち上がるのは癪なので、どうにか「CIで自動的にPR作るところまでやってくれ〜〜」という事をするようにした。

github.com

前提として、「こまめにupdateしていけると、修正対応とのコストは劇的に下がる(ほとんどのものは、互換性を保ったまま動いてくれることのほうが多い)」という立場です。
AWF本体の更新というのは大掛かりな部類と考えるが、それですら「ビルドバージョンごとに最新に追従していく」戦略をとることで、これまで大きな問題の発生を避けられているという体感がある*1。また、テストカバレッジも高めに保ててている〜という背景があるのに支えられていると感じる。

てな訳で、「更新しておいたわ!サマリーつけておくから、軽く確認しておいて!!」というPRをCIが自動的に出してくれ・・・という夢を、形にした次第です。

これは結局のところComposer Pluginという形に落ち着いたのだけど、当初はスタンドアロンに「Composerを使役する側」の何かを書こうとしていた。

  • そもそもはyarnにはそういうのあるらしいよという話を聞いて、「composerでもできるっしょ!!」と思ったのがとっかかり
  • お、gemにもあるじゃん
  • どうやるかな〜composerコマンドをスクリプトで叩く感じかな〜
  • まぁshでもgoでもいいよね〜
  • updateしたあとにdiffをとって、内容をPRに書くのは必須だなー。
  • diffを取るのはcomposer使うとすぐできたりするかな・・?
  • あー、じゃあPHPで書くかー
  • どうやって差分取るんだ?composerソースコード読んでみるか・・
  • Command クラス作ってinvokeしたりするのか〜
  • 結構大変そう・・・どうしたものか・・
  • 今回のスコープはあくまで「CI上で動くようなもの」、なら「更新する」って仕事自体はCIに任せちゃっていいな。composer cli
  • そういえば、composer-diff-pluginがプラグインになっているってことは、「更新があったときに結果を受け取ってゴニョ」ができるってことだな
  • なるほどcomposer-plugin、アリだな・・・!

という思考プロセス。
結果としてcomposer-pluginとか、普段からあんなにお世話になっているcomposer本体への興味が向いたのが凄く収穫に感じた。

何度も読んだスライド ↓↓

speakerdeck.com

「いちおう動く」なところまでは行ったので、ひとまず(私が更新を忘れてしまって、かわいそうな・・)会社のレポジトリで試してみる。
テストとか静的解析を入れられていないので、書いた本人ですら「開発途中っていってもテストゼロってやばくない?糞ダサエンジニアじゃん・・・」ていう敗北感が強いのだけど。どうやってテスト入れたら良いのかなーーーーという感じ。*2
やれるところからやっちゃおう、という感じも勿論ありつつ。

そのあたりを形式だけでも整えてしまって、そしたらv1.0.0タグを打ってQiitaとかに使い方紹介記事みたいなの書こうかなーという算段

業務前とか業務後に時間を取ってやったので、それも毎日ではなかったということで、あまりまとまった時間を集中的に取る!!ということはできていなかったのだけど。
2週間前に思い立ち、2日めくらいに「そうか〜composer pluginなら行けそう!」と方針が変わり、最初の1週間で7割位のとこまで行って、実際にtravisのdaily cronで叩いたりして様子を見つつ、いまちょうど2週間目終わりかなって感じ。
1,2週間くらいでひとまず形になる〜〜〜ていう規模のペットプロジェクトは良いのでないかな、と思ったしリフレッシュになりそう

*1:CakePHPが、そのあたりに寛容でドラスティックな変更が入りづらい〜という事情はあると思います。ので、使っているソフトや属している文化次第かなぁ・・といった

*2:実際問題としては、テスト書けるようなモノの方が「やりたいこと」「この実装でやれていること」といった問題点を浮彫にできるので、開発効率は上がる・・ので今回のような形は割と苦しさを感じた

Hugo + CircleCIでブログを作った

前の記事の続き。
最終的にHugoにすることになった。

  • やりたいのは「記事集」みたいなやつ
    • 静的ページとフィードアイテム?みたいな区別はそこまで必要ではない
    • まして立派なトップページとかはいらないんだよなぁ〜
  • Docusaurusは寧ろstaticな「サイト」を主眼としている印象。実際、「トップにfeed並べたいなあ・・」というところで手が止まってしまった
  • 「静的サイトジェネレータ」ってスコープでいくと、(ちょっと古い記事だけど)すげーたくさんあるw
  • その中で、hugo良さそうかな〜と思っていたら会社の人にも「hugoはいいぞ〜」って聞いたので選択

という流れで。

整備にあたって、主にここら辺の記事を参考にさせていただきました。

circleci.com hori-ryota.com chroju.github.io

で、実際に書いたcircleciの設定はこんな感じ。*1

version: 2
jobs:
  build:
    docker:
      - image: felicianotech/docker-hugo:latest
    steps:
      - checkout
      - run: git config --global user.email (ここにemail)
      - run: git config --global user.name (ここに名前)
      - run: echo "machine github.com login (ここにgithub id) password $GITHUB_TOKEN" > ~/.netrc
      - run: git submodule sync
      - run: git submodule update --init --recursive
      - run: git worktree add -B gh-pages public origin/gh-pages
      - run: rm -rf public/*
      - run: hugo
      # ユーザページサイトにPushする
      - deploy:
          command: cd public && git add . && git diff --cached --exit-code --quiet || git commit -m "Rebuilding site" && git push origin gh-pages

workflows:
  version: 2
  build:
    jobs:
      - build:
          filters:
            branches:
              only: master

ちょっと無駄がありそうな気もするんだけど・・・ machine github.com login とかは要らないのかもな?ひとまず調べても試してもいないです。

  1. hugo作れる〜なdocker imageがあるのでそのまま使わせてもらう
  2. themeをsubmoduleで入れているので、checkoutしたらsyncして
  3. 今回は gh-pagesブランチを使ってるので publicディレクトリをsubtreeで gh-pagesブランチ化して*2
  4. hugo コマンドで public ディレクトリ(= gh-pagee ブランチのroot)にサイトを生成して
  5. publicディレクトリに移動して、add & commit & push
  6. workflowsで「マスターの更新があった時だけ実行」というfilterを掛けて
    • master merge時にサイトが更新されるようにする

という流れ。
もうちょいスッキリさせられる気はするけど、とりあえずこれで動く。

しかしながら感動したのは、「hugoって何やってるの?」みたいなところを理解しなくてもそのまま動いた!!という点。
多少コマンドや設定周りでドキュメントを読みはしたものの、ソースコード読んだり〜とかは全くしていない。
よいツールだなぁ〜という印象。。golangだとこんな感じでポータビリティの高いソフトを作りやすいのかな?とか思ったり。

*1:鍵の設定とか環境変数の設定は、以前に済んでいたので。

*2:公開用ディレクトリの中身を一旦rmってるのは、当初のブランチの状態が面倒くさそうだったから。

アウトプットの量にも拘ってみたい〜

大体いつも、自分が「ちゃんとできること増えてるかな〜」とか「強くなっているかな〜」みたいなのを振り返ると絶望的な気持ちになるのだけど、「いやいや・・もっと色々とやってません・・でしたっけ・・・」みたいな。
そのため、「こういうコトしました!」みたいなのを纏めておきたいな〜と思った。

daisuki.nichiyoubi.land

ずっとやろうやろうと思っていて、えいっ!ってやった次第。
そうか、もっとcakeにはPR送っていると思ったぜ・・・と感じる。
昨年中、ふとしたタイミングで「外部から見たときに自分がどんなことしているかって、可視化する気概が無いと何も語られないものだなぁ〜」と気づいた事があり。それからずっと、「やったほうが良いな」と思っていたこと。
もっと強いエンジニアなら、「github.comを見てみな!全部おいてあるぜ!!」だと思うのだけど。そこまで行っていないので・・

自分の owned なものは、さほど言及しなくてもいいと思い、

  • 他者のOSSへのPRやらContribution
  • 会社のブログやOSS

あたりかな?という感じ。
逆に、前のエントリーで触れているpet project系の話だったり、qiitaへの投稿だったりは、それはそれで良いか〜、と思う。

もっと社会貢献できると良いですね。

個人的なお勉強プロジェクトを作ってサイトを公開!してみる

サイトを作る

daisuki.nichiyoubi.land

「色々といんたーねっとに発信していきたいな〜」と思っている流れがずっとあるので、 pet project を作るぞ!!という流れで、
とりあえず「CakePHPについては、仕事で色々とググっているので、思ったこととかメモっておく場があるとスッキリしそう〜」という流れです。

ところで #phpgenba の「自分のサービスを作る」は良かった。

php-genba.shin1x1.com

とりあえず作ってみ!!って自分に言い聞かせる事は必要に思う・・・

作ってみるぞ

手軽にサイトを、ってことで。
github pages使ったことなかったからそれで〜〜っていうとこまでは思った、というよりも
github pages使ったことないから何かしたいな」「Cakeなら定常的にインプットあるからそれ絡めるか」です。

作るぞ〜、作らねぇとな〜って思っていた矢先にmoongiftからこんな記事が流れてきて

www.moongift.jp

よっしゃ使ってみよ!という流れ。

こうなるといいな

  • 見た目的なところは、最低限整っていればOK
  • 「気軽に更新できること」に重きを置きたい
    • ページ(リンク)の追加は勝手にできたら嬉しい
    • ディレクトリ構造がそのままサイト上のページ構造になって、ディレクトリ配下のページが勝手に一覧される〜とかなれば最高に素敵なんだけど
  • サイトの更新も自動でやってほしい
    • CI回してmaster にマージされたら自動でデプロイされてほしい

ここまで出来ると最高。

作業メモ

調べたら qiita.com を見つけたので、元々「お勉強サイト」用に作ってあったレポジトリをクローンしてきて

f:id:o0h:20180210215042p:plain

私のローカルホストが2分でこんな姿に・・・ まだ「Docusaurusuってどんなことができるの?」て話しすら、してないのに・・・いわば自己紹介すらまだ住んでない状態なのに・・・

めっちゃすごいですね。良い時代だ。
ヘッダー 出来上がったディレクトリとかファイルとか見てみると、ページが入ってるのが docs blogの2箇所かな。 でsiteConfig.js` を見てみると、

headerLinks: [
  {doc: 'doc1', label: 'Docs'},
  {doc: 'doc4', label: 'API'},
  {page: 'help', label: 'Help'},
  {blog: true, label: 'Blog'},
],

となっていて、 docs ディレクトリと website/blog ディレクトリがあるので、この辺りが関係してそう

$ ls -l blog
total 40
-rwxr-xr-x  1 hkinjyo  staff  3293  2 10 21:40 2016-03-11-blog-post.md
-rw-r--r--  1 hkinjyo  staff  3296  2 10 21:40 2017-04-10-blog-post-two.md
-rw-r--r--  1 hkinjyo  staff   475  2 10 21:40 2017-09-25-testing-rss.md
-rw-r--r--  1 hkinjyo  staff   180  2 10 21:40 2017-09-26-adding-rss.md
-rw-r--r--  1 hkinjyo  staff   197  2 10 21:40 2017-10-24-new-version-1.0.0.md

とのことで、

f:id:o0h:20180210223724p:plain

とのことなので、 blog:true になっていると、そのディレクトリの下に追加されたページがサイドバーに出るのかな。 良さそう〜。
これを使えば「ページの自動追加」もできるかな。
ディレクトリ構造もそのまま反映してくれないだろうか、と思って website/blog/hoge/test.md みたいなの作ったらエラー出たw

そろそろリファレンス見てみる

「どういう機能があるの」をまともに見ていなかったので、そろそろ見てみる。
「siteConfigの内容を掘れば良さそうかな〜」と思ったので。

docusaurus.io

f:id:o0h:20180210225243p:plain

  • doc: .md ファイルの表示
  • page: (jsで)任意のページ
  • blog: /blog 以下に置かれた .md ファイルでの「ブログ」機能

みたいな感じかなぁ。

customDocsPath っていう設定項目もあるから、 /docs の位置については変更できるみたい。
ん〜、「カテゴリごとに自動追加」は難しいのかもなぁ。

Create Your Basic Site を見ると、各docに id という概念を持たせられるみたい。
docs ディレクトリも、そのままだと複階層にするのは無理かな?

実ファイルの配置ってよりもリンクの見え方どうなるかなーていう方が関心事として大きく、サイドバーがだいぶ大事になってくると思うので見てみる。

docusaurus.io

ホワイトリスト式でdoc-idを列挙して、「自分が属するサイドバーがあればそれを表示する」ってか感じかー。

{
     "category-name": {
        "sub-category-name": ["doc-id1", "doc-id2"]
    }
     "category2-name": {
        "sub-category-name": ["other-doc-id1", "other-doc-id2"],
        "sub-category-2-name": ["other-doc-id3"],
    }
}

そうすると、 doc/doc-id1.html を開いたときにはサイドバーには doc-id1 doc-id2 が表示されるし、 other-doc-id3 の時は other-doc-id1 other-doc-id2 other-doc-id3 が表示されるし・・みたいな塩梅っぽい。

  • 命名規則を持たせたファイル名/doc-idを配置する
  • sidebarからのリンクを更新していく
    • カテゴリのdocへのリンク一覧を表示

っていう感じになるかな。

- hoge_index.md
- hoge_1.md
- hoge_sub_1.md
- fuga_index.md
- fuga_1.md
- fuga_2.md

とかしていけば、一覧性もそんな悪くないでしょっていう気がする。

sidebars.json

公開の自動化を・・

Publishing your site · Docusaurus です。

  1. Circle CIのアカウントを作ってPJを作成
  2. https://github.com/settings/tokens/newrepo スコープのトークンを作成
  3. CI側、レポジトリのeditを開いてサイドバーからEnvironment variablesを探して
    • GITHUB_TOKEN を追加
  4. circle.yml のセット
    • あとでversionかえよう・・
  5. github-pagesに対応するようにsiteConfigをいじる必要がある
    • clone元のレポジトリを編集
    • /test-site/ ではなくルートディレクトリになると思うので、baseUrlの編集
circleci.yml

https://github.com/o0h/cakephp3-with-me/commit/6525b47b72fc92bb51ecf6067a98a43ad001cc84

machine:
  node:
    version: 6.11.2
    npm:
      version: 3.10.10
deployment:
  website:
    branch: master
    commands:
      - git config --global user.email "o0h@users.noreply.github.com"
      - git config --global user.name "Hideki Kinjyo"
      - echo "machine github.com login o0h password $GITHUB_TOKEN" > ~/.netrc
      - cd website && npm install && GIT_USER=o0h npm run publish-gh-pages
website/siteConfig.js

https://github.com/o0h/cakephp3-with-me/commit/e1421fd85ec9ae9113e8c61cbe5786dc2d6fb543

diff --git a/website/siteConfig.js b/website/siteConfig.js
index 5c29ab9..76262d8 100644
--- a/website/siteConfig.js
+++ b/website/siteConfig.js
@@ -9,7 +9,7 @@
 const users = [
   {
     caption: 'User1',
-    image: '/test-site/img/docusaurus.svg',
+    image: '/img/docusaurus.svg',
     infoLink: 'https://www.facebook.com',
     pinned: true,
   },
@@ -18,9 +18,9 @@ const users = [
 const siteConfig = {
   title: 'Test Site' /* title for your website */,
   tagline: 'A website for testing',
-  url: 'https://facebook.github.io' /* your website url */,
-  baseUrl: '/test-site/' /* base url for your project */,
-  projectName: 'test-site',
+  url: 'https://cake.nichiyoubi.land' /* your website url */,
+  baseUrl: '/' /* base url for your project */,
+  projectName: 'cakephp3-with-me',
   headerLinks: [
     {doc: 'doc1', label: 'Docs'},
     {doc: 'doc4', label: 'API'},
@@ -50,7 +50,7 @@ const siteConfig = {
   },
   scripts: ['https://buttons.github.io/buttons.js'],
   // You may provide arbitrary config keys to be used as needed by your template.
-  repoUrl: 'https://github.com/facebook/test-site',
+  repoUrl: 'https://github.com/o0h/cakephp3-with-me',
 };

 module.exports = siteConfig;

GitHubの設定も

  1. github pagesの有効化
  2. (defaultのまま)gh-pagesを使うようにする
  3. (サブドメインもあてました)
    • nichiyoubi.land ドメインcakeo0h.githun.io. へのCNAME

f:id:o0h:20180211014422p:plain

基盤と基礎的な構想だけはこれで出来た!

リンクの自動化・・・までは叶わなかったけど、サイドバーを最低限更新すればOKって事なので許容範囲かな〜って感じで。
すげー更新が大変だ!!ってなったら、自分でスクリプト書く〜とかでどうにかなりそうだし。
Docusaurus + Circle CI、とりあえずの選択肢としては手軽に使えそうで良いのじゃないかな〜