2017年8月8日火曜日

[CI] Scrutinizer 始めました



今回紹介する CI サービスは Scrutinizer です。
Pricing をみるとフリープランはないように見えますが、OSS であればフリーで使えるようです

今回、使い始めてから紹介できるようになるまでにかなーりの年月を費やしてしまいましたので、Sign up まわりは省略させていただきます。
(C++非サポート&Python のテスト周りで手間取った)

Scruntinizer の魅力
Scruntinizer の魅力は登録するだけですぐに静的解析の結果が得られるところです。
Scruntinizer は静的解析などの検証に特化した CI サービスで、めんどうな設定や YAML を書かずにすぐに始められます。テストもリポジトリを探索して自動で実行してくれます。

あと、レポートもグラフィカルでいい感じです。


使用例
いつもであれば、iutest の使用例で紹介するのですが、C++ は非サポートなので、
今回は「ブログズミ: ソースコード中の単語からの略語/スペルミス検出に挑戦」で作成した
taggertool リポジトリで紹介します。

リポジトリ登録
まずは、リポジトリの登録から始めます。
「Add Repository」ボタンを押すと、以下のような画面になるので、CI したいリポジトリを入力、言語を選択して、登録します。


リポジトリは、Github/Bitbucket/GitLab/PlainGit から選択できます。
Plain Git が可能なので、独自リポジトリが使えるのは良いところだと思います。

登録は以上です。
完了すると最初のテストが実行されます。

taggertool の結果
taggertool の結果はこんな感じです。

サマリー


Issues に、各静的解析で出た結果が出ます。


Code にはクラスおよび関数のサイズと複雑度がリストアップされます。


Inspections はキックされたジョブが並びます。


Reports には最後に実行されたジョブの結果が表示されます。


最後に、Statistics には Quality Rating や issue などの推移がグラフで確認できます。
Quality Rating は上の図で 9 となっているやつで、コードの複雑度、結合度など複数の要素から1つのスコアにしたもので、10点満点で評価されます。


チェック項目を増やす
さて、Scrutinizer には様々なツールで様々な解析ができる準備がされていますが、デフォルトでは多くのチェックは無効になっています。
チェックを有効にするには、Settings の Configuration に Checks ボタンがあるので、そこを開きます。


開くと Not Enabled なチェック項目がリストアップされているので、
必要なものにチェックを入れてください。


チェックの有効化は Congiguration の Repogitry Config や yml に直接書くこともできます。
チェックしたい項目が多い場合は、(UI でチェックするのが面倒なので)こちらの方がよいでしょう。

また、グローバルな設定も作成できるので、
複数プロジェクトで同じチェックをさせたい場合は、そちらを使うと良さそうです。
checks:
    python:
        code_rating: true
        duplicate_code: true
        variables_used_before_assignment: true
        variables_unused_wildcard_import: true
        variables_unused_variable: true
        variables_unused_import: true
        variables_unused_argument: true
        variables_unpacking_non_sequence: true
        variables_undefined_variable: true
        variables_undefined_loop_variable: true
        variables_undefined_all_variable: true
        variables_unbalanced_tuple_unpacking: true
        variables_redefined_outer_name: true
        variables_redefined_builtin: true
        variables_redefine_in_handler: true
        variables_no_name_in_module: true
        variables_invalid_all_object: true
        variables_global_variable_undefined: true
        variables_global_variable_not_assigned: true
        variables_global_statement: true
        variables_global_at_module_level: true
        typecheck_unexpected_keyword_arg: true
        typecheck_too_many_function_args: true
        typecheck_redundant_keyword_arg: true
        typecheck_not_callable: true
        typecheck_no_value_for_parameter: true
        typecheck_no_member: true
        typecheck_missing_kwoa: true
        typecheck_maybe_no_member: true
        typecheck_duplicate_keyword_arg: true
        typecheck_assignment_from_none: true
        typecheck_assignment_from_no_return: true
        string_truncated_format_string: true
        string_unused_format_string_key: true
        string_too_many_format_args: true
        string_too_few_format_args: true
        string_mixed_format_string: true
        string_missing_format_string_key: true
        string_format_needs_mapping: true
        string_constant_anomalous_unicode_escape_in_string: true
        string_bad_str_strip_call: true
        string_constant_anomalous_backslash_in_string: true
        string_bad_format_string_key: true
        string_bad_format_character: true
        open_mode_bad_open_mode: true
        miscellaneous_fixme: true
        newstyle_bad_super_call: true
        logging_unsupported_format: true
        logging_too_many_args: true
        logging_too_few_args: true
        logging_not_lazy: true
        logging_format_truncated: true
        imports_wildcard_import: true
        imports_relative_import: true
        imports_reimported: true
        imports_import_self: true
        imports_import_error: true
        imports_deprecated_module: true
        imports_cyclic_import: true
        format_unnecessary_semicolon: true
        format_trailing_whitespace: true
        format_superfluous_parens: true
        format_old_ne_operator: true
        format_multiple_statements: true
        format_mixed_indentation: true
        format_missing_final_newline: true
        format_lowercase_l_suffix: true
        format_line_too_long:
            max_length: '100'
        format_bad_whitespace: true
        format_bad_indentation:
            indentation: '4 spaces'
        format_backtick: true
        exceptions_raising_non_exception: true
        exceptions_raising_string: true
        exceptions_raising_bad_type: true
        exceptions_pointless_except: true
        exceptions_notimplemented_raised: true
        exceptions_catching_non_exception: true
        exceptions_broad_except: true
        exceptions_binary_op_exception: true
        exceptions_bare_except: true
        exceptions_bad_except_order: true
        design_interface_not_implemented: true
        design_abstract_class_not_used: true
        design_abstract_class_little_used: true
        classes_valid_slots: true
        classes_super_init_not_called: true
        classes_signature_differs: true
        classes_protected_access: true
        classes_non_parent_init_called: true
        classes_non_iterator_returned: true
        classes_no_self_use: true
        classes_no_self_argument: true
        classes_no_method_argument: true
        classes_no_init: true
        classes_missing_interface_method: true
        classes_method_hidden: true
        classes_interface_is_not_class: true
        classes_bad_staticmethod_argument: true
        classes_bad_mcs_method_argument: true
        classes_bad_mcs_classmethod_argument: true
        classes_bad_context_manager: true
        classes_bad_classmethod_argument: true
        classes_attribute_defined_outside_init: true
        classes_arguments_differ: true
        classes_access_member_before_definition: true
        classes_abstract_method: true
        basic_yield_outside_function: true
        basic_useless_else_on_loop: true
        basic_unreachable: true
        basic_unnecessary_pass: true
        basic_unnecessary_lambda: true
        basic_star_args: true
        basic_return_outside_function: true
        basic_return_in_init: true
        basic_return_arg_in_generator: true
        basic_pointless_string_statement: true
        basic_pointless_statement: true
        basic_old_raise_syntax: true
        basic_not_in_loop: true
        basic_nonexistent_operator: true
        basic_missing_reversed_argument: true
        basic_missing_module_attribute: true
        basic_missing_docstring: true
        basic_lost_exception: true
        basic_init_is_generator: true
        basic_function_redefined: true
        basic_expression_not_assigned: true
        basic_exec_used: true
        basic_eval_used: true
        basic_empty_docstring: true
        basic_duplicate_key: true
        basic_duplicate_argument_name: true
        basic_dangerous_default_value: true
        basic_bad_reversed_sequence: true
        basic_assert_on_tuple: true
        basic_abstract_class_instantiated: true

最後に
Scruntinizer は、最初から静的解析ツールが用意されており、それを目的にするのであれば、
通常の CI サービスよりも、とても簡単に恩恵が得られるのでオススメです。
(C++ がサポートされるともっとステキですが…あ、あと Scruntinizer のスペルが全然覚えられない…

今回は Python で利用しましたが、他の言語で何か作るときは、また利用したいなと思います。

以上。


2017年7月31日月曜日

続・ソースコード中の単語からの略語/スペルミス検出に挑戦

ブログズミ: ソースコード中の単語からの略語/スペルミス検出に挑戦」で紹介した略語チェッカーを大幅に更新したので、続報です。
ついでなので、Glosbe でリクエスト制限にかかってしまった場合の対処方法も紹介しておきます。

変更点
usage: abbreviation.py [-h] [-v] [-g FILE] [-w FILE] [-e EXCLUDE]
                       [-a ABBREVIATION] [--glosbe] [--dejizo] [--cache]
                       [--load-cache NAME] [--cache-dir DIR]
                       [--disable-keywords] [-x {c++,c#,objc,diff}]
                       [--list-all] [--progress] [--safe-mode]
                       [--encoding ENCODING] [--extension EXTENSION]
                       [--ignore-noexists] [--relpath] [--word WORD] [-]
                       [FILE/DIR [FILE/DIR ...]]

positional arguments:
  FILE/DIR              source code file/dir

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit
  -g FILE, --gene FILE  exlude word
  -w FILE, --whitelist FILE
                        whitelist file
  -e EXCLUDE, --exclude EXCLUDE
                        exlude word
  -a ABBREVIATION, --abbreviation ABBREVIATION
                        abbreviation word
  --glosbe              use online translation service (glosbe)
  --dejizo              use online service (dejizo)
  --cache               online translation cache enable
  --load-cache NAME     load translation cache
  --cache-dir DIR       translation cache directory
  --disable-keywords    disable general and language keywords
  -x {c++,c#,objc,diff}, --language {c++,c#,objc,diff}
                        select language
  --list-all            list up all location
  --progress            print percent progress
  --safe-mode           api request limit safe mode(glosbe)
  --encoding ENCODING   set file encoding
  --extension EXTENSION
                        file extension matcher
  --ignore-noexists     ignore option file not exists
  --relpath             print relative path
  --word WORD           dircet check words
  -                     source code from stdin

diff ファイルに対応
便利になった機能の1つがこれだと思います。
diff ファイルから差分があったところだけをチェックするので、コードレビューのときに重宝します。
対応しているフォーマットは Unified format になります。

略語判定ロジックの大幅更新
「~の略語」だけでなく、「~の過去形」「~の複数形」なども検出して、辞書判定するように改善しました。主に、boost のヘッダーファイルをチェッカーに入力して、その結果を見ながら、期待に沿わないものに対応していった感じです。

ただ、ソースコード中で出てきた場合の一般的な意味と、辞書に載っている意味で剥離している場合もあります。
例えば、「apis」とあったら、「APIs」のことだとプログラマーは思うと思うのですが、辞書的には「蜂」です。
こういったものを機械的に振り分けるのは(今の自分の力量では)難しかったので、100% プログラマーが期待する結果になるわけではありませんので、ご注意!
ディープラーニングさせたらいいのかな?

ともあれ、boost を解析して自分なりに納得のいくところまで対応できたかなーと思ってます。

Glosbe でリクエスト制限にかかってしまった場合の対処方法
('Http error:', u'429 Client Error:  for url: https://glosbe.com/gapi/translate?dest=ja&phrase=opendir&from=en&pretty=true&format=json')
('request count: ', 802)
Please access the glosbe, click the search button and check reCAPTCHA.
Glosbe でリクエスト制限にかかると上記ログが出力されます。
これが出た場合、以下の方法で回復が可能です。

まずは、https://ja.glosbe.com/ にアクセスして、普通に辞書検索します。


以下のような画面になるので、チェックをクリアすると制限が解除されます。
(何回も制限かけられましたが、今のところこの方法ですぐに解除できています。)


最後に
このツールを実際に使ってみて、当初の目的の略語検出よりも typo 検出の方が役に立ちました。
実際にヒドイ typo が見つかりました…
https://github.com/srz-zumix/iutest/commit/c063225f5abfeb157f671e3fc55b779f32e12193

ただ、typo チェックであれば、「Pull Requestに潜むタイポを自動的に検出し、修正を代行するBot - Qiita」の方がよさそうだなーと思ったのと、PyEnchant ってのがあるほを初めて知ったので機会があれば使ってみようと思いました。

最後ですが、今回のアップデートで自己満足できるところまで作れたので、これで開発を一旦終了しようと思います。
(要望いただければ対応します)
ではでは。

2017年7月24日月曜日

[CI] Bitrise で紹介プログラムが始まってた

Extra minutes on hobby plan! | Bitrise


以前の紹介したBitriseブログズミ: [CI] Bitrise 始めました)で、"Referral program(紹介プログラム)"が始まりました。
このプログラムは紹介するごとに、ビルド時間の上限が +5 分され、最大 +20 分できるものです。
条件や方法については、後述します。

無料プランではビルド時間 10分 の制限がある
Bitrise Pricing

Bitrise の Hobby plan (無料プラン)では、1ビルド10分の制限があります。

10分制限は、他の CI サービスと比べると結構短いです。
参考(少し古いですが…):「ブログズミ: 無料で使える CI サービス比較」

iutest でも、この制限回避のために iOS と Android のテストジョブを別個に用意してます。
(やりようによっては制限時間内に収められるかもしれませんし、分ける利点もあったりしますが…)

Referral program で無料プランでのビルド時間が最大 30 分になる
今回のプログラムを利用することで、ビルド時間が最大 30 分まで増やせるようになりました
1人紹介するごとに +5 分で、4人紹介で最大の 30 分になります。
さらに、紹介人数が5人になると Bitrise Tシャツがもらえるっぽいですw



条件と方法
まず、方法ですが、
Account Settings に Referrals のタブがあるのでそこを開きます。
(今なら上のバーにもリンクがありますね)
開くと、紹介用URL が右上に書いてありますので、この URL からアクセスしてもらうのが第一条件です。

筆者の場合 https://www.bitrise.io?referrer=a9c0b9baf7536067 です。(よろしくお願いしますm(__)m)

そして、アカウント登録をしてもらうこと、
さらに、ジョブ(App)を追加して、ビルドがグリーンであること、
これらの条件をすべて満たすと、紹介したことになり、+5 分されます。

筆者はまだ 0 人なので、公式ブログをキャプチャした画像になりますが、
こんな感じで状態が表示されるようです。



最後に
Bitriseは、iOS/Android のアプリ開発では定番の CI になっているようですし、それらの開発をしている方は是非使ってみてください。
また、最近どこの CI でも見るようになってきた ワークフロー も、Bitrise では使えますので、試してみたい方も是非!
そして、私に Bitrise T-shirt をください!




今回は以上です。では!


2017年7月18日火曜日

[Jenkins] Pipeline Script からプラグイン機能を呼び出す

ブログズミ: [Jenkins] Groovy で IRC Plugin を使い倒す
以前、Groovy post build プラグインから IRC Plugin の機能を呼び出して、任意のメッセージを飛ばすことをやりましたが、これを Jenkinsfile に記述します。

やり方は単純
Jenkinsfile にそのまま書くだけです。

以前、Groovy Label Assignment plugin 向けに書いた groovy がこちら。
def jenkins = hudson.model.Hudson.instance
def irc_channel="#kiwiirc-iutest"
def p = jenkins.getPlugin("ircbot")
if( p == null ) {
  println("require IRC Plugin")
  return
}
def c = p.imPlugin.provider.currentConnection()
if( c == null ) {
  println("IRC connection not found. please set to IRC configuration")
  return
}
c.send(irc_channel, "label assignment")
return

これを、すこし汎用的にして Jenkins ファイルに追加します。

def send_irc(channel, message)
{
    def jenkins = hudson.model.Hudson.instance
    def p = jenkins.getPlugin("ircbot")
    if( p == null ) {
      println("require IRC Plugin")
      return
    }
    def c = p.imPlugin.provider.currentConnection()
    if( c == null ) {
      println("IRC connection not found. please set to IRC configuration")
      return
    }
    c.send(channel, message)
    return
}

で、あとはお好きなタイミングで呼び出すだけです。
stage('irc-send') {
        send_irc('#TEST', 'ビルドに成功したよ!')
    }


簡単ですね^^

2017年7月10日月曜日

[C++] override すべき関数の名前 typo に気づける idiom

Google Test でテストのセットアップを定義する場合は、SetUp 関数をオーバーライドするのですが、これを Setup と間違えてしまう人が多いようです。
ただ、Google Test ではこの間違いにコンパイル時に気付けるようになってます。
その部分のコードがこちら

private:
  struct Setup_should_be_spelled_SetUp {};
  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }

override つけたらいいやんって話ですが、まぁ…つけない人もいるわけで…
そんな人でもすぐに間違いに気付けるのがこのイディオムです。

サンプルコード:
class A
{
public:
    virtual void SetUp() {}
private:
  struct Setup_should_be_spelled_SetUp {};
  virtual Setup_should_be_spelled_SetUp* Setup() { return 0; }
};

class Override : public A
{
public:
    void Setup() override {}
    void setup() override {}
};

class NoOverride : public A
{
public:
    void Setup() {}
    void setup() {}
};


int main()
{
    return 0;
}
[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ https://wandbox.org/permlink/jEs6OQf0t8tCkgzf



override 付けた方は当然 Setup も setup もコンパイルエラーになります。
一方、override 付けなかった方も Setup がコンパイルエラーになっています


いやー賢いですね。勉強になりました。

2017年7月3日月曜日

bat ファイルの実行時間を PowerShell で計測する

ググればいっぱい情報出てきますが、個人用備忘録として残しておく。
Windows PowerShell の機能
powershell -C "(Measure-Command { .\HogeHoge.bat | Out-Default }).TotalSeconds"

メモ:
* 秒だけ欲しいので .TotalSeconds
* ミリ秒で欲しいときは .TotalMilliseconds
* .\ をつけないと不明なコマンドになる
* 標準出力が欲しい場合は " | Out-Default" をつける
* 標準エラーはコマンドだけで出る

2017年6月19日月曜日

[Visual Studio 2017] インデント問題を解決する? .editorconfig を使ってみた

Visual Studio 2017 からプラグインインストール不要で EditorConfig が使えるようになったので、遅ればせながら使ってみました。
2017 のリリース直後に試して、ブログにしようと思ってましたが、なんだかんだでこの時期になってしまいました。
なので、特に"これ"という情報はありません(;´・ω・)。が、editorconfig 便利だなーということだけ紹介します。

EditorConfig とは?
EditorConfig はインデントのタブ派 vs スペース派などのルールを書式化し、個人のエディタ設定によらず、コーディングスタイルの統一ができるようになるものです。


チーム内のスタイル統一が容易になるのもメリットですが、個人的には1つのエディタでプロジェクトごとの設定を意識せずにコーディングできるとこが便利だなーと思いました。

Visual Studio の場合ですと、インデントの設定はグローバルに1つだけなので、タブ派なプロジェクトとスペース派なプロジェクトを跨いで作業するのは大変でした。
これが、Visual Studio 2017 から EditorConfig が使えるようになったので、とっても捗ります!
(※ 2017 以前でも拡張機能をインストールすることで使用できます)

iutest の .editorconfig
root = true
 
 [*]
 indent_style = space
 indent_size = 4
 insert_final_newline = true
 
 [Makefile]
 indent_style = tab
 
 [*.{cpp,hpp,ipp}}
 charset = utf-8-bom
 
 [*.py]
 charset = utf-8
 
 [*.{yml,html}]
 indent_size = 2

これをルートディレクトリに配置するだけで、Visual Studio が自動的に設定を読み込んで、インデントなど指定した通りに編集できるようになります。

設定できる項目
公式にまとまっているので、そちらを参照してください。

https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties




editorconfig、本当に便利なんで、会社でもリポジトリに突っ込んでいこうと思いました。
今回は以上です。ではでは。

2017年6月12日月曜日

[Docker] docker-compose で作成されるデフォルト network でハマった備忘録

こんにちは。
ブログズミ: [Docker] 始めてみたけど躓きまくってるので備忘録として残しておくよ
上記記事から、一ヶ月くらい経って、docker-compose も使うようになってきました。
Docker はもとより、ネットワークとかの知識がほとんどない素人ですが、多少覚えてきました。

それにしても、docker-compose 便利ですね!
環境変数とか設定を Dockerfile から追い出せるし、--build-arg も docker-compose.yml に書けるし、
Docker ホストが起動したときに自動起動したい場合も、"restart: always" を書いとけば OK ですし、
ブログズミ: [Windows][Docker] Host および コンテナの起動をスタートアップに登録」とか、
いらんかったわ!って感じです。

でもハマった
まぁ、でもハマりますよね。
今回ハマったのはネットワーク絡み。

Dockerfile からビルドして docker run したコンテナからは通じるのに、
それを docker-compose で run すると通じない…
そんなことがありました。

docker-compose が作成する network
docker-compose run すると、{サービス名}_default という名前で network が作成されます。

$ docker-compose up -d
Creating network "hoge_hoge_default" with the default driver

こんな感じでログが出ていると思います。

Docker 管理下のネットワークは docker network ls で確認できます。
$ docker network ls
a8c84238aaaa        bridge             bridge              local
f9b622381b6a        host               host                local
7061554ce0f1        hoge_hoge_default  bridge              local
f1c24d1dda82        none               null                local

さらに、詳細を docker network inspect {ネットワーク名} で確認できます。

$ docker network inspect hoge_hoge_default
[
    {
        "Name": "hubot2_bridge",
        "Id": "1d3906e507b39eb08cf6d7326058eb62c447772371c4d2b692765c25778a4d11",
        "Created": "2017-05-23T11:41:13.819782229Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "72917816824f2d5fe76ba854a49766787fd1bb54928fd903d251fc9dfa5a2f69": {
                "Name": "hoge_hoge_1",
                "EndpointID": "219cb4cbd809b4d3d7e5f4d1118abe87fe5e4d44222ace5e6022119366827d60",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]


で、これが目的にネットワークと衝突してて通じてなかったようです。

解決方法
docker-compose.yml にネットワークの設定を書き足します。
参考:https://github.com/docker/compose/issues/2582

services:
  hoge:
    networks:
      - bridge

networks:
  bridge:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: 172.16.238.0/24
        gateway: 172.16.238.1

これで、network の subnet/gateway を指定できるので、都合の良い設定すれば解決するはずです。



また、1つ docker のことがわかった気がします。
今回は以上です。では。

2017年6月5日月曜日

Wandbox のコンパイラー追加を通知する環境を作った

Wandbox で対応コンパイラーが増えたら、自分宛てにツイートしてくれる環境を作りました。



構成
Appveyor + Zapier

概要
https://github.com/srz-zumix/wandbox-news
ソースコードをみていただければ、どんなことやっているかはわかると思います。
特に難しいことはしてなくて、Wandbox API で取ってきたリストを成果物として保存して、前回との差分があれば Webhook を投げます。
あとは、Zapier で Webhook を受け取ってツイートするだけです。

その他
最初は、Google App Engine とか Circle CI とか使おうと思ってましたが、定期ビルド、Webhook Notification、成果物の保存・取得ができる Appveyor に落ち着きました。

あとは、Notification でカスタム json を作るのに、ちょっと手間取りました。
デフォルトで送ると Zapier で message を取るのがめんどくさかった(というか、うまくできない?)ので、カスタムで送るようにしてます。
url が secure 指定できなかったので、Web UI 設定にしてますが、appveyor.yml にコメントで書いてあるので参考にしてください。

では。


※更新なしが FAIL 更新ありが PASS になっているが、どちらも PASS にできるならしたい。
※Webhook を発行するトリガーとして、ステータスを利用しているため。
※最初は逆だったが、成果物取得で落ちてくるのが lastSuccessBuild のものだったため、更新があったときを PASS にしている。

※Zapier で tweet する際に改行がスペースに置換されてしまっている。
※改行のまま tweet したい。

2017年5月29日月曜日

[Visual Studio] 1行の文字数制限のガイドラインを表示する

cpplint とかでよく1行あたりの文字数に対してい警告が出たりしますよね?
プロジェクトによっては、"厳守" であったり、"できるだけ対応" であったり、ルールが違うと思います。

これ、lint にかける前に意識してコーディングしたいな~と思いました。
自分の場合、厳しいルールの環境ではなかったので、強制的に改行するようなものではなく、
ガイドライン引けるものがないか探して見たところ、ドンピシャなものがあったので紹介します。


Editor Guidelines
Editor Guidelines 拡張機能を使います。


これをインストールすると、エディタの右クリックメニューに「Guidelines」が追加されます。

「Add Guideline」をクリックすると、このようにガイドラインが表示されます。



短い!!


ということで、
文字数を指定する場合は、「コマンドウィンドウ」を開いて以下のコマンドを打ち込みます。
(既に Add してると失敗するので、Remove しておいてください)

Edit.AddGuideline 100




これで、任意の文字数のところにガイドラインが引けました!


ちょっとしたことですが、これでまた Visual Studio が便利になりました~
ではでは。

2017年5月22日月曜日

[Visual Studio] VS2017 のスタートページをカスタマイズする

Visual Studio 2017 になって、デフォルトのスタートページが変わりました。
が、レイアウトが変わってピン留めしたプロジェクトや履歴が見づらくなってしまいました。(個人的に)

VS2017:

VS2015:


スタートページもカスタマイズできる!
Visual Studio では拡張機能により様々な機能を追加したり、ツールと連携したり、見た目を変えたりできますが、スタートページもカスタマイズできます!
(いままで変えたい思わなかったので、VS2017 になって始めて知りました)

拡張機能を作成して、自分好みのスタートページを作ることもできますが、今回は既に Marketplace にある拡張機能を使ってみました。

BetterStartPage 拡張機能
「ツール」>「拡張機能と更新プログラム」から「BetterStartPage」をインストールしてください。


インストールしたら、「ツール」>「オプション」>「スタートアップ」を開いて、
「スタート ページのカスタマイズ」で「BetterStartPage」を選択してください。


BetterStartPage の設定
BetterStartPage にするとスタートページに、「Favorites」が追加されます。
ここで、任意のソリューション/プロジェクトを登録できます。


まずは、グレーのエリアで右クリック。「Edit Mode」をクリックします。


下のような状態になるので、「New Group」をクリックします。
(グループとプロジェクトのカラムは自由に変えてください)


グループが追加されるので、適当に名前をつけて、右上にあるプロジェクトの追加ボタンを押します。
ファイル選択ダイアログが開くので、お好きなソリューション/プロジェクトを選択してください。


追加すると、以下のようになります。


編集が終わったら、もう一度右クリックをして Edit Mode を終了します。(当たり判定が狭いかも…)


設定は以上です。


結果
設定した結果はこんな感じになります。


もっと、THE Visual Studio 2015 !! な見た目を期待してたんですが(全体的に)、それでも多少使いやすくなったような気がします。
できれば、最近使ったファイルから、Favorites に追加できればもっとよかったんですが…

ともあれ、スタートページも拡張機能でカスタマイズできることがわかりましたので、是非作ってみてください。
便利なものを待ってます。

2017年5月15日月曜日

設定 XML ファイルが壊れて SourceTree が起動しなくなった場合の対応

PC が強制終了して SourceTree が起動しなくなってしまった!!

この症状、二度目なので未来の自分のために書き残しておく。

慌てない慌てない
まずは、なんで起動しないのかイベントビューアでログを確認しましょう。

XML ファイルのオープンで落ちていた場合は、このまま読み続けてください。
それ以外の場合は、もう一度ググりなおしてください m(__)m

コンフィグファイルを確認する
SourceTree の設定ファイルが壊れている疑いがあるので、user.config ファイルを確認しましょう。

user.config は %USERPROFILE%\AppData\Local\Atlassian\SourceTree_Url_**** フォルダの中にあります。(*** はユニークID)
上記フォルダを開くと、SourceTree のバージョンごとにフォルダがあると思いますので、
現在使っているバージョンのフォルダを開いてください。

そこに、 user.config ファイルがあるので、テキストエディターなどで開きます。
すると、以下のようにノードが閉じられていないファイルになってしまってました。

そうでない場合は、Google ホームに戻ります m(__)m

コンフィグファイルを修復する
修復する、といってもファイルを消すだけです。
(※古いバージョンのフォルダがない場合は、設定消えることになるかも)

SourceTree は user.config がなかったら、古いバージョンの user.config から再作成するようなので、
壊れている user.config ファイルを消せば、古い設定から修復されます。
(1つ前のバージョンの user.config も壊れていたらそれも消す。以下繰り返し。)

ファイルを消したら、普通に SourceTree を起動してください。
問題なく起動するはずです!

起動しない!!という方、ごめんなさい m(__)m
他の情報を探してください。

最後に
未来の自分がこのブログを見ることがないことを祈ります(-人-)

2017年5月8日月曜日

[CI] Bitrise 始めました



今回も CI サービスの紹介でございます。
今回は「Bitrise」です。

http://devcenter.bitrise.io/
In short Bitrise is a Continuous Integration and Delivery (CI/CD) Platform as a Service (PaaS) with a main focus on mobile app development (iOS, Android, Xamarin, ...).

こちらに書かれているように Bitrise はモバイルをメインターゲットとした CI/CD サービスです。
今回、iutest では CMake で生成した Xcode プロジェクトをビルド(テスト)する CI サービスとして利用を開始しました。

このブログで紹介するということは、もちろんフリープランが存在します。


200ビルド/月、10分/ビルド、と少し制限厳し目ですが、iutest で使う分にはなんとかなりそうです。

Sign up
では、早速 Sign up しましょう。
「Start building for free」ボタンを押すと、まずは以下のようなアカウント登録画面が表示されます。
通常のメールアドレスの他、Github,Bitbucket,GitLab アカウントが選択できますので、お好きなものを選択してください。



続いて、簡単なアンケートが出ます。答えても答えなくても OK です。


次にパスワード設定をします。Github などのアカウントを利用した場合でも必須のようです。


これで登録完了です。


app 追加
Sign Up できたので早速ジョブ(app)を作っていきましょう。
「+Add first app」ボタンをクリックすると、リポジトリ選択画面になります。
目的のリポジトリを選択してください。


次はリポジトリアクセス設定です。
iutest では 「AUTOMATIC 」、 「No, auto-add SSH Key」としました。必要に応じて変更してください。


つづいて、セットアップの検証が行われます。
対象ブランチを選択して「Next」を押します。


検証が始まるので待ちます。


検証が終わるとビルドコンフィグが開きます。

Xamarin が選ばれてますが、おそらく Visual Studio の .sln ファイルを検出したからでしょう。
ただ、iutest は Xamarin 使ってません。ここは「MANUAL」で設定をします。

今回は、Xcode ビルド(とテスト)をしたいので、「macOS」とか「iOS」を選択したいところですが、プロジェクトファイルや Scheme を要求されるため、「OTHER/MAUNUAL」から「Xcode on macOS」な Stack を選択して次へ。



最後に Webhook 設定をします。
特に理由がなければ、「Register」で良いと思います。Push and PR が Bitrise に通知されます。


これで、作成完了です!


ワークフローを作成する
Bitrise では Workflow で処理を記述します。

Workflow タブをクリックすると Editor が開きます。




既存のステップがたくさんありますが、Script を使うと bash script ので目的にあったステップがない場合は、これを使えばなんとかなると思います。



フローが完成したら、SAVE ボタンを押して保存しましょう。
※ ちなみに、ワークフローは複数作成でき、master のときは A 、 develop のときは B のようなこともできますし、
ワークフロー同士をつなげることもできます。


特定ブランチを除外する
デフォルトの設定だとすべてのブランチを対象にワークフローが始まるようになってますが、特定のブランチは CI したくない場合(iutest の場合は gh-pages)は、「Workflow Editor」の「Triggers」から設定を変更できます。
Push / PR / Tag それぞれにトリガーの設定が可能で、ここでどのワークフローと連結するかも設定できます。

※ exclude 指定ができると良かったのですが…

バッジ
最後にお約束のバッジです。
バッジは「Dashboard」の上の方にある「バッジ」をクリックすると Markdown などのテキストが取得できます。




最後に
今回 iutest では CMake + Xocde build のために Bitrise を使いました。
これであれば正直 Bitrise じゃなくてもできます。(Travis CI や Circle CI は Mac OS ワーカーを使えたはず)

ただ、最初にも書いたように Bitrise はモバイルアプリをメインターゲットにしているので、
それらの開発をしている方は一度試してみてはいかがでしょうか?
きっと、他の CI サービスにはない旨味があるのではないでしょうか。

今回は以上です。では。