sinshutu_kibotuの日記

大体、大抵、大半、備忘録

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がアーカイブされたとき

Workflowの編集画面
Workflowの編集画面

自動で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に設定
  • アクセスの種類は「プログラムによるアクセス」にチェック、コンソールへのログインはしないと思うのでチェックしません

f:id:sinshutu_kibotu:20180714135652p:plain

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

f:id:sinshutu_kibotu:20180714135903p:plain

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:

AWS CLIのインストールから初期設定メモ

53ningen.com

rspecからpostリクエストしたときにjsonの数値が文字列になってしまう

はじめに

rails5で開発してますが、rspecでpostリクエストのテストを書いていたときにrails側で受け取ったparamsの内容がすべて文字列になってしまうという問題に突き当たりました

再現手順

以下のようなリクエストをrspecから送信すると

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段階層

原子を組み立ててページを作る

  • 依存関係
    • 大きい要素は小さい要素に依存するように作る
      • 中間層で変更が起きたとき、その階層より大きいものだけ確認すればよい
      • 原子に比べてがページはすくないので、変更にかかるコストが小さくなる
      • 不具合の減少

どのように階層構造をつくるのか

世の中の階層アーキテクチャを参考にする

  • OSI参照モデル
    • 依存の方向が一方向
    • 各層で責務を共通して持っている
  • ドメイン駆動設計
    • 依存の方向が一方向 それぞれの階層で、責務を共通化させることが大切

A D

UIデザインの責務 - ユーザー行動のデザイン - 行動プロセスを基準につくる - プロセス -> デザイン対象 -> 層 - プロダクトの存在をしる -> マーケ -> page層 - アクセスする、初見でみたところからなにかを探す -> 画面レイアウト -> レイアウト層 - コンテンツに興味をもったら次の行動が生まれる -> コンテンツのみせ方 -> オーガニズム層 - 行動を阻害しない操作性 -> 行動を阻害しない操作性 -> - 全体を通してサービスに良い印象を受ける -> デザインの統一性 -> 1

コンポーネント

ソフトウェアは軸雑な問題を解決するもの 問題の分解が必要

UIコンポーネント

変更しやすいデザイン

構造化されたデザインのアイデア デザインを変更したい意図に対して変更の範囲が予測できる つまり、変更に強い

UIデザインは複数人が関わっている、デザインフローの見直し

現状

異なる側面でUIデザインを考えている - ディレクター - デザイナー - エンジニア

ワークフロー 分業している場合はコミュニケーションが必要 - ワイヤーフレーム - デザインカンプ - カンプの役割 - 実装前に完成イメージを共有する - ユーザーに対して、必要なものを見つけられる

実装が難しいデザインだと、実装を依頼してから出戻りが発生する

デザインの構造化フロー

  1. 構造の設計
  2. 情報の設計
  3. 構造のレビュー
  4. 実装

構造化の指針があれば、難しいデザインを依頼してしまうことが少なくなる

構造化した状態を維持するために

デザインガイドライン - 作り込まない - 方向性だけ決めて徐々に細かくできればよい

命名規則を決める - みんなの頭の中で指しているものが違う - コミュニケーションコストの減少

コンポーネントリスト - 作成したコンポーネントは再利用される - 一覧化して、どんなものかが分からないといちいち見に行ったり調べたりする必要がある - storybook - コンポーネントのテスト

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)
'''

こんな感じになります

f:id:sinshutu_kibotu:20180624025251p:plain

おわりに

lightline-aleの設定手順が英語情報しかなかったので軽くまとめてみましたというのが今回の話でした

thanks!!

github.com

github.com

github.com

マイクラ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行目にブレークポイントを設置してデバック実行します。

途中まで実行してみましょう。

f:id:sinshutu_kibotu:20170821065226p:plain

そのままの状態で、4行目のprint文を変更します

-        System.out.println("Hello World");
+        System.out.println("Hello Hot Swap");

ツールバーのBuild -> Recompile を選択するとclassがリロードされます。

f:id:sinshutu_kibotu:20170821065922p:plain

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

f:id:sinshutu_kibotu:20170821070056p:plain

すると出力が変わりました!

実際にマイクラでやってみる

サンプルコード

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 が行われれば成功しているはずです。

f:id:sinshutu_kibotu:20170821092052p:plain (伝わるのかこの画像・・・)

おわりに

細かい用語とかしっかり調べられていないので、間違っている場合などはご指摘ください。

マイクラの開発ノウハウまわりのTipsどっかにまとまってないのかな?と思う今日。

参照

備考

実行環境

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に書いてありました・・・)