GitHub Project(classicじゃない方)をactionsで自動整理する
100年ぶりにブログを更新します。最近は花粉がすごくてすごいですね。
わけあってGitHub ProjectのカードのStatusを特定の条件で自動更新するということをしました。 GitHub Projectまわりのアップデートが多かったのでそのあたりの紹介とやったことの備忘録になります。
要約
- GitHub Projectのワークフロー すごい、大体これで行ける
- できない操作もActionsから操作可能。しかし、MarketplaceからActionsを探すときは、Project(classic)とProject(現行)のやつが混ざっているので注意
- Project(現行)は project-beta-automations を使えばActionsで操作できる
やりたかったこと
- PRが作られたら自動的にProjectに紐づける
- PRがクローズされたらラベルに応じてStatusを更新する
Projectのワークフローの紹介
これの話 docs.github.com
Workflowでは以下の条件に応じてItemのStatusを更新することができます
- Itemがプロジェクトに追加されたとき
- Itemがreopenしたとき
- Itemがcloseしたとき
- PRに変更を要求するレビューが発生したとき
- PRが承認されたとき
- PRがマージされたとき
- Itemがアーカイブされたとき

自動でIssue/PRをプロジェクトに紐づけるには、「Auto-add to project」の項目から設定ができます。
Issue/PRの検索で利用できる is:pr is:open などのクエリが指定可能です。

workflowを利用することで「PRが作られたら自動的にProjectに紐づける」は実現できました。
PRがマージされたらラベルに応じてStatusを更新する
これはworkflowの機能だけでは実現できずActionsを利用する形になりました。
Marketplaceから既存のactionsを探しましたが、Project(classic)が混ざっており、更新されていないactionだとProjectとしか書かれていないため、ぱっとはわからない状態でつらいです。 実装を読んで見分ける方法としては、以下になりそうです。
- Project(Classic)にはrest apiとgraphqlの両方のAPIが実装されているが、Project(現行)はgraphqlの実装しかないのでrest apiだけで実装されているのは対応していない可能性が高い
- Project(現行)のgrahpqlのオブジェクト名はProjectV2なのでProjectV2の記述がある
結果として、 project-beta-automations が使えることが分かったのでこれを利用した実装が以下になります。
name: Sample on: pull_request: types: [ closed ] env: GITHUB_PROJECT_ID: 1 jobs: move-to-project-column: if: > github.event.pull_request.merged == true && ( contains(github.event.pull_request.labels.*.name, 'Case-A') || contains(github.event.pull_request.labels.*.name, 'Case-B') ) runs-on: ubuntu-latest steps: - name: Select Column id: select_column run: | if [ ${{ contains(github.event.pull_request.labels.*.name, 'Case-A') }} == true ]; then echo "column_name=Case-A" >> $GITHUB_OUTPUT else echo "column_name=Case-B" >> $GITHUB_OUTPUT fi - name: Move to Project Column uses: leonsteinhaeuser/project-beta-automations@v2.2.1 with: gh_token: ${{ secrets.GITHUB_PAT }} user: sinshutu # organization: sample-org project_id: ${{ env.GITHUB_PROJECT_ID }} resource_node_id: ${{ github.event.pull_request.node_id }} status_value: ${{ steps.select_column.outputs.column_name }}
おわりに
久しぶりにactions書くと特有の記法とか、github.eventにはどんなデータが入ってくるんだとかわからなくなりますね。 とはいえ、今までGASとかをがっつり書かないとできなかったことがgithubに閉じる形で実装できるのはすごいなぁ
terraformのbackendをs3にしてinitするまでの最低限の手順
概要
terraformのtfstateをs3で管理したいときの手順書です
terrformで使用するのユーザーの作成からterraform init するまでの手順をまとめました
手順
awsユーザーの追加
まず、はじめに、aws cliを使えるようにするためにユーザーを追加しましょう
AWSのコンソールからIAMを選択します、ユーザーを追加をクリック
- 名前は適当にterraformerに設定
- アクセスの種類は「プログラムによるアクセス」にチェック、コンソールへのログインはしないと思うのでチェックしません

次に、必要な権限をアタッチします。 s3へアクセスする権限が必要なので AmazonS3FullAccess権限 をアタッチします

FullAccessでは権限範囲が大きいので、制限を強めにしたい場合は以下の公式URLを参考に権限を割り当ててください
Backend Type: s3 - Terraform by HashiCorp
アクセスキーの取得
ユーザーの作成に成功すると、アクセスキー ID、シークレットアクセスキー の2つが表示されるのでそれを .aws/credentials へ書き込みます
また、[terraform] と表記している部分がprofile名になり、aws --profile profile名 で呼び出すことで複数のアカウントを使うことができます
[terraformer] region = ap-northeast-1 aws_access_key_id = XXXXXXXXXXXXXXXXXX aws_secret_access_key = XXXXXXXXXXXXXXXXX
次に、credentials が正常に追加されたことを確認します
$ aws s3 ls --profile terraformer
とくにエラーにならなければ大丈夫です
main.tfの作成
次に実際に実行するtfファイルを作成します
providerの設定
- awsを設定
- regionはアジアプシフィック(東京)
- provider-awsのモジュールのバージョンも指定できるので1.25.0に固定します
- profileは先ほど設定したterrformerを指定します、これでmain.tfファイル内にアクセストークンを書き込まずに済みます
terraformの設定
- versonを0.11.7を指定
- backendにs3を設定、このときのkeyにしてしたファイル名でバケットにアップロードされます
resourceにs3バケットを追加
完成したmain.tfが以下になります
# main.tfファイル
provider "aws" {
region = "ap-northeast-1"
profile = "terraformer"
version = "1.25.0"
}
terraform {
required_version = "0.11.7"
backend "s3" {
bucket = "hoge-tfstate"
region = "ap-northeast-1"
profile = "terrformer"
key = "terraform.tfstate"
encrypt = true
}
}
resource "aws_s3_bucket" "tfstate" {
bucket = "hoge-tfstate"
versioning {
enabled = true
}
}
terraformの初期化処理
$ terraform init
「Terraform has been successfully initialized!」と表示されていれば成功です、上記のコマンドでs3のバケットの作成から保存までやってくれます
最後にawsコンソールへログインして、s3バケットにtfstateが保存されていることを確認しましょう
以上の手順でtfstateをs3に保存する手順は終わりになります
参考URL:
rspecからpostリクエストしたときにjsonの数値が文字列になってしまう
はじめに
rails5で開発してますが、rspecでpostリクエストのテストを書いていたときにrails側で受け取ったparamsの内容がすべて文字列になってしまうという問題に突き当たりました
再現手順
subject(:response) {
post :update, params: {
ids: [1, 2],
names: ["hoge", "fuga"]
}
}
it {
binding.pry
expect(response.status).to eq(200)
}
binding.pryの部分でparamsを表示してみると、idsが文字列になってしまう
> params
{
ids: ["1", "2"],
names: ["hoge", "fuga"]
}
2つの解決策
CONTENT_TYPEを指定する
rspecのデフォルトのCONTENT_TYPEはapplication/x-www-form-urlencoded
なので、適切に文字列に変換してくれてます、jsonを送信する場合はapplication/jsonに書き換えるのが最良だと思います
subject(:response) {
request.env["CONTENT_TYPE"] = 'application/json'
post :update, params: {
ids: [1, 2],
names: ["hoge", "fuga"],
}
}
paramsではなくbodyを使う
postするときに paramsではなくbodyに書き込みます、また asというパラメータに :jsonを指定してあげると request.body.read でリクエストしたパラメータを取得することができます
subject(:response) {
post :update, body: {
ids: [1, 2],
names: ["hoge", "fuga"],
}.to_json,
as: :json
}
pry > request.body.read
=> {
"ids":[1,2],
"names": ["hoge", "fuga"]
}
Atomic Designの勉強会に参加してきた
DevLove主催の https://devlove.doorkeeper.jp/events/75944 へ行ってきました
登壇者は「Atomic Design ~堅牢で使いやすいUIを効率良く設計する〜」の著者の 五藤 佑典さん ( @ygoto3_ ) でした
内容
アジャイルしてますか? * スプリント * UI変更をどんどん適応する
変更に強くないデザインとは?
- 実装が原因
- プログラムのバグ
- レイアウトのバグ
- デザインが原因
- コンテンツのバグ
- ナビゲーションのバグ(ページからページへの遷移)
構造はなぜ大切か?
- アジャイルには変更に強い構造が必須
- ソフトウェアの構造
- 構造を意識になくても動作するものは作れる
- しかし
- スパゲッティーコードとか
- その時は理解できるけど、あとから変更しにくいことになる
- コードの負債
- リファクタリング
- 動作はそのままに、構造を変えること
- デザインの構造
- フォトショとかで
- 構造わけしていないレイヤー
- 見つけるのが辛い
- フォトショとかで
デザインデータだけの問題ではない
デザインデータの外で問題が発生してる デザインはデータではない、アイデアである アイデアの構造化が必要
構造のデザインパターン
UIデザインは多くのパターンで構成されている デザインパターン -> 整理術 - 本: 人生がときめく片付けの魔法
atomic design
パーツの組み合わせ方法に少々の制限やルールを与える 人間が予測しやすい状態に整理する 5つのカテゴリ - 原子 - 分子 ...
5段階層
原子を組み立ててページを作る
- 依存関係
- 大きい要素は小さい要素に依存するように作る
- 中間層で変更が起きたとき、その階層より大きいものだけ確認すればよい
- 原子に比べてがページはすくないので、変更にかかるコストが小さくなる
- 不具合の減少
- 大きい要素は小さい要素に依存するように作る
どのように階層構造をつくるのか
世の中の階層アーキテクチャを参考にする
A D
UIデザインの責務 - ユーザー行動のデザイン - 行動プロセスを基準につくる - プロセス -> デザイン対象 -> 層 - プロダクトの存在をしる -> マーケ -> page層 - アクセスする、初見でみたところからなにかを探す -> 画面レイアウト -> レイアウト層 - コンテンツに興味をもったら次の行動が生まれる -> コンテンツのみせ方 -> オーガニズム層 - 行動を阻害しない操作性 -> 行動を阻害しない操作性 -> - 全体を通してサービスに良い印象を受ける -> デザインの統一性 -> 1
コンポーネント
ソフトウェアは軸雑な問題を解決するもの 問題の分解が必要
UIコンポーネント
変更しやすいデザイン
構造化されたデザインのアイデア デザインを変更したい意図に対して変更の範囲が予測できる つまり、変更に強い
UIデザインは複数人が関わっている、デザインフローの見直し
現状
異なる側面でUIデザインを考えている - ディレクター - デザイナー - エンジニア
ワークフロー 分業している場合はコミュニケーションが必要 - ワイヤーフレーム - デザインカンプ - カンプの役割 - 実装前に完成イメージを共有する - ユーザーに対して、必要なものを見つけられる
実装が難しいデザインだと、実装を依頼してから出戻りが発生する
デザインの構造化フロー
- 構造の設計
- 情報の設計
- 構造のレビュー
- 実装
構造化の指針があれば、難しいデザインを依頼してしまうことが少なくなる
構造化した状態を維持するために
デザインガイドライン - 作り込まない - 方向性だけ決めて徐々に細かくできればよい
命名規則を決める - みんなの頭の中で指しているものが違う - コミュニケーションコストの減少
コンポーネントリスト - 作成したコンポーネントは再利用される - 一覧化して、どんなものかが分からないといちいち見に行ったり調べたりする必要がある - storybook - コンポーネントのテスト
UIテストの効率化もはかどる
チームのコラボレーション
- コードレビュー
- UIコンポーネントごとにレビュー
- スコープが狭いレビューになるように
- 文言レビュー
- 影響範囲が明確であること
- 文言の長さによるデザインの崩れとか
tips
interface inventory ワークショップ デザインの意味に応じて、部品を種類分けする それによって、統一性が図られているかどうか、小さい違いやその意味を再認識できる http://bradfrost.com/blog/post/interface-inventory/ http://makotottn.hatenablog.com/entry/2017/12/04/010923
オープン・デザイニング( モブ・デザイニング) - モブ・プログラミングと同様に難しい課題に向き合うとき、レビューコストがなくなる - 全員で頭を使うので解決が早い - 仕様レベルの話、実装レベルの話を同時にできる
感想
デザインの階層アーキテクチャで重要な部分で、層ごとに役割と責任を明確にしておくことが大切だと感じた
自分もVueJSを使って開発しているのでコンポーネントベースの開発はしていたのですが、デザインまわりはあまり巻き込んでいない開発をしています アイデアの構造化という視点はおもしろいなと感じたのと、デザインには意味や情報があるのでそれをアトミックに整理することで、ユーザーにも提供できる情報の質もあげられるのではないかなとか思いました
tipsでも上がっている interface inventoryで既存のサービスを分解して実装してみるのは勉強によさそうですね
また、書籍のご購入はこちらからどうぞ
vimプラグインのlightline-aleを使ってみた
はじめに
aleを使っていますが、エラー文を出力しているALEGetStatusLineがdeprecatedになっていた
ステータスを表示する機能自体がなくなるっぽいです
で、ale#statusline#Countを呼び出してligthlineに渡す必要がありますが、、、面倒、それをやってくれるlightline-aleというプラグインがあるのでそれを使います
lightline-aleの設定方法
deinでの設定方法
[[plugins]]
repo = 'itchyny/lightline.vim'
hook_add = '''
let g:lightline = {
\ 'colorscheme': 'wombat',
\ 'active': {
\ 'left': [ [ 'mode', 'paste' ],
\ [ 'readonly', 'filename', 'modified' ],
\ [ 'linter_checking', 'linter_errors', 'linter_warnings', 'linter_ok' ] ],
\ },
\ }
'''
[[plugins]]
repo = 'maximbaz/lightline-ale'
depends = ['lightline.vim', 'ale']
hook_add = '''
let g:lightline.component_expand = {
\ 'linter_checking': 'lightline#ale#checking',
\ 'linter_warnings': 'lightline#ale#warnings',
\ 'linter_errors': 'lightline#ale#errors',
\ 'linter_ok': 'lightline#ale#ok',
\ }
let g:lightline.component_type = {
\ 'linter_checking': 'left',
\ 'linter_warnings': 'warning',
\ 'linter_errors': 'error',
\ 'linter_ok': 'left',
\ }
'''
[[plugins]]
repo = 'w0rp/ale'
hook_add = '''
let b:ale_linters = {
\ 'javascript': ['eslint', 'eslint-plugin-vue'],
\ 'python': ['pyflakes', 'pep8'],
\ 'ruby': ['rubocop'],
\ 'tex': ['textlint'],
\ 'markdown': ['textlint'],
\ 'css': ['stylelint'],
\}
let g:ale_statusline_format = ['E%d', 'W%d', 'ok']
let g:ale_set_loclist = 0
let g:ale_set_quickfix = 1
nmap <silent> <C-n> <Plug>(ale_next_wrap)
'''
こんな感じになります

おわりに
lightline-aleの設定手順が英語情報しかなかったので軽くまとめてみましたというのが今回の話でした
thanks!!
マイクラMOD開発でマイクラを再起動させなくても変更を反映させる方法
はじめに
マイクラのMOD開発してて、ビルド重い、再起動だるいとか思ったことはありませんか? そんな人が対象の記事です。
どうにかする方法はあります!! jvmの機能?にClass Reloadingを行うためのHot Swapという機能があるのでこちらを使うことでいちいちマイクラを再起動せずに済みます。
intellijIDEAでやっていきます。
内容の要約
デバックモードで実行して、コードを変更したらRecompileを実行するだけ
Hot Swapについて
ClassファイルをJVM実行状態で更新する方法です。
まずは簡単にただのHelloWorldでHot Swapしてみます。
// Main.java public class Main { public void hello() { System.out.println("Hello World"); } public static void main(String[] args) { System.out.println("First print here"); Main main = new Main(); for(int i=0;i<5;i++){ System.out.print(i + ": "); main.hello(); } System.out.println("Line that I do not modify"); } }
普通に実行すると
First print here 0: Hello World 1: Hello World 2: Hello World 3: Hello World 4: Hello World Line that I do not modify
次に11行目にブレークポイントを設置してデバック実行します。
途中まで実行してみましょう。

そのままの状態で、4行目のprint文を変更します
- System.out.println("Hello World"); + System.out.println("Hello Hot Swap");
ツールバーのBuild -> Recompile を選択するとclassがリロードされます。

そのままステップ実行をすすめてみます。

すると出力が変わりました!
実際にマイクラでやってみる
サンプルコード
https://github.com/sinshutu/MC-Modding-Hot-Swap-sample
上記のリポジトリをクローンしてintellijIDEAで開いてください。
先ほどと同様にデバック実行してください
コードの詳細は省きますが以下のようなコードが実装されています。
// src/main/java/com/sinshutu/example/CommonEvent.java
import ...
public class CommonEvent {
public CommonEvent(){
MinecraftForge.EVENT_BUS.register(this);
}
@SubscribeEvent
public void onEntityItemPickupEvent(EntityItemPickupEvent event)
{
String msg = "EntityItemPickupEvent";
event.getEntityPlayer().sendMessage(new TextComponentString(msg));
}
}
アイテムを拾ったときに、メッセージを表示するようになっています。
メッセージを表示した後、msgを変更して Recompile をしてみましょう
- msg = "EntityItemPickupEvent" + msg = "Hot Swap"
上記と同様に class reload が行われれば成功しているはずです。
(伝わるのかこの画像・・・)
おわりに
細かい用語とかしっかり調べられていないので、間違っている場合などはご指摘ください。
マイクラの開発ノウハウまわりのTipsどっかにまとまってないのかな?と思う今日。
参照
- stackoverflow.com
- Reloading Classes - Help | IntelliJ IDEA
- How to Edit Minecraft Code (Full Tutorial - Running Minecraft in Debug mode) - YouTube の7:30付近
備考
実行環境
ArchLinux: 4.12.8-2-ARCH
JVM: 1.8
idea: 2017.2.2
forge: 1.12-14.21.1.2387
fehでマルチディスプレイの背景を個別に設定する
目的
feh(画像ビューワー)で複数のデスクトップの背景設定をする
コマンド
$ feh --bg-fill img01.png img02.png
–bg-[center,fill,scale,seamless,tile,] オプションに続いて画像を複数指定するとそれぞれの画面に適応される (ちゃんとman fehに書いてありました・・・)