おでーぶでおでーぶ

いろいろ書く。いろいろ。

internal app sharing と DeployGate の機能差早見表

この記事は DeployGate 社員としてではなく、アプリ開発者の見解として書いています(おわりに、を除く)。また Beta などの他のサービスとの比較は入っていないので、internal app sharing または DeployGate の2択として記述しています。

TL;DR

  • 完全無料がいい && いっぱい固定リンク発行したい -> internal app sharing
  • dynamic delivery をテストしたい -> internal app sharing
  • アップデートを配布したい -> DeployGate
  • テスターに一般人が含まれる -> DeployGate
  • こだわりはない -> なんでもいいと思います

というか、完全無料というポリシーがない限りは併用でいいと思いますし、あとは QA で何をチェックしたいかだと思います。

参考:

便宜上、internal app sharing の固定リンクとDeployGate の配布ページを同時に表現する場合、「配布リンク」としています。

○ : 対応済み
△ : 対応予定または一部対応
× : 対応していない(対応予定なし、不明)
機能等 internal app sharing DeployGate
無料利用が可能か *1
配布リンクの上限 ありません グループプラン以上では制限はありません
debuggable app の配布
無署名 app の配布 ×*2
aab upload
dynamic delivery ×
dynamic feature module を利用した app の配布 *3
Upload API
任意の署名キーの利用 ×
任意のpackage名の利用 *4 *5
FireOS などでの利用 ×
Production と完全に同じ app を配布できるか ×*6 ×*7
同一バージョンコードの配信
リビジョン情報の埋め込み *8
ダウンロード数の制限機能 *9 *10
Uploader の制限
配布リンクの削除 ×
配布リンクに対する配信 app version の更新 ×
配布リンクへのパスワード設定 ×
自然流入のテスターへのインストール許可 *11
特定のテスターへのインストール許可
↑に認証をつける *12
異なる app 間でのテスターの流用 *13
異なる app ごとにテスターを設定する ×
参加テスターの確認 *14
テスターへの連絡 × ×*15
in-app updates の利用 × ×

また internal app sharing では機能を利用するために Play Store app の Developer モードを有効にするなどの操作が必要で、ガイドがなく、テスターに一定の説明やリテラシー要求を行う必要があります。DeployGateではアプリ内部からの導線で前設定が完結するようになっています。*16

おわりに

現段階で、internal app sharing にのみ「技術的に」可能であることは dynamic feature module のダウンロード程度です。他の機能についてはすでに DeployGate で実装している、上位互換なものも多く、またやろうと思えば技術的に実装可能なものが殆どです。

ということで、△について、一緒に実装してくれる人を募集しています。

*1:最初課金しないと配布ページが〜と書いてたんですが、個数制限有りで利用できました・・・

*2:無署名 app はインストール不可のため、署名し直す必要があります。aab対応後に実現可能になりますが、特に話に上がっていないので△ではありません

*3:DeployGate ではuniversal apkでの配信になります

*4:PlayStore に存在するもののみ配信可能です

*5:異なるパッケージ名の app をグルーピングして同一視する機能などはありません

*6:署名が選べません

*7:dynamic deliveryが使えません

*8:配信名を設定できますが、リリースノートと併記するといった用途には耐えきれません

*9:変更できません

*10:変更が可能です

*11:internal app sharing では自然流入を許可する/しないを一括管理するため、全てのリンクに対して設定が継承される。したがって一部のリンクでは認証有り、といった使い分けができない。

*12:プランごとに異なります。また配布ページにはパスワード機能がありますが、別途認証機能を実装することを検討しています。

*13:グループプラン以上が必要です

*14:ドキュメントによると出来るらしいんですが、UIがありません

*15:特に話に上がっていないので、実現可能性はあれど△としませんでした

*16:ただしリテラシー要求はいらないとは言ってません

CircleCI (Workflow) の tags filter でドキュメントを誤読してハマった

CircleCI (Workflow) の tags filter で document を読み違えてハマったのでメモ。

Configuring CircleCI - CircleCI

CircleCI では filters 機構を用いて、tag/branch ごとに job の実行を制御することが可能。*1

例えば master branch のみで実行したい場合は

filters:
  branches:
    only: master

とすればよく、反対に master branch では実行したくない場合、

filters:
  branches:
    ignore: master

と記述すればよい。これは filters 指定がなければ デフォルトで全ての branch がjob実行対象 であることを意味している。

tags についてはどうなっているかというと

CircleCI does not run workflows for tags unless you explicitly specify tag filters. Additionally, if a job requires any other jobs (directly or indirectly), you must specify tag filters for those jobs.

Tags can have the keys only and ignore keys. You may also use regular expressions to match against tags by enclosing them with ‘/s’, or map to a list of such strings. Regular expressions must match the entire string. Both lightweight and annotated tags are supported.

- Any tags that match only will run the job.
- Any tags that match ignore will not run the job.
- If neither only nor ignore are specified then the job is skipped for all tags.
- If both only and ignore are specified the only is considered before ignore.

明示的に tags の設定をしないとタグは job 実行対象にならないと言っている。ここで v1.0.0 タグでのみ実行させる場合を考える。意味を深く考えずに branches の例を取るなら

filters:
  tags:
    only: v1.0.0

のようになるが、この表記の意味は 任意の branch 及び v1.0.0 タグのとき job 実行対象とする となってしまう。

したがって、v1.0.0 タグでのみ実行させる場合は以下のように 全ての branch を実行対象としないように記述する 必要がある。

filters:
  tags:
    only: v1.0.0
  branches:
    ignore: /.*/

ちなみに以下でも any branch で job が実行されてしまう。

filters:
  tags:
    only: v1.0.0
  branches:
    only: []

久々に tags を使おうとしてハマりまくってしまった・・・ちゃんと読むとたしかにそう書いてあるんだけど。なんとなく「指定する == 絞り込み」みたいな感覚だった。

filters:
  tags:
    run: true
  branches:
    run: false

みたいな書き方ができると嬉しいなぁ!

そういえば tags を必要とする workflow の実行したい jobs には全てこの filters をつけないといけないのがつらいけど、placeholder job を作って、そいつに filters を設定し、その job を始点とするような job tree を書けばいいんじゃないんですかね(動くかは知らない)

*1:余談ではあるが、workflow-level filtering が欲しい

KotlinFest 2019 CfP に応募した

Deep Dive into Kotlin DSL

DSL の話から Kotlin DSL (Gradle Kotlin DSL じゃないよ)について触れ、自分たちでも DSL を構築する方法を知る・構築できるようになることを目的とした発表です。

日本語で出したんですが、英語発表でもいいよと書いておきました。(英語発表がどの程度欲しい・採択するつもりなのか分からなかったので)

この発表では DSL の基礎から Kotlin DSL における拡張表現や開発方法まで踏み込んで発表します。

また Kotlin DSL の実例として

- Gradle Kotlin DSL
- Ktor or DOM (like React)
- Android Jetpack Compose

あたりを取り上げて、どのように Kotlin DSL が作用し、Java/Groovy ではなぜ出来ないのかについても触れたいと思います。

Topics (予定)

- What's domain-specific language and Kotlin DSL?
- Let you know real examples of Kotlin DSL
- Getting started understanding and developing DSL
    - What's the *primitive* DSL
    - The power of *Lambda* in DSL world
    - Typesafe builder and Kotlin DSL
- Syntactic extension
    - Extension method e.g. Gradle Kotlin DSL
    - Operator overloading e.g. Ktor
    - Infix operator based Fluent style e.g. Assertion libraries
    - DSLMarker and implicit receiver resolution e.g. Jetpack Compose
- For DSL users
    - Adapt Kotlin DSL to existing libraries
- For DSL developers
    - How to keep both usabilities of Kotlin DSL and other JVM languages
    - Examples in Gradle Kotlin DSL

英語なら以下みたいな感じ。

In this presentation, I will talk about the basis and practical application of Kotlin DSL in achieving attendees will be able to develop Kotlin DSL.

I will pick up the following examples to explain how Kotlin DSL work and why Java/Groovy are not enough or not good at doing so.

- Gradle Kotlin DSL
- Ktor or DOM (like React)
- Android Jetpack Compose

Topics (just a plan)

- What's domain-specific language and Kotlin DSL?
- Let you know real examples of Kotlin DSL
- Getting started understanding and developing DSL
    - What's the *primitive* DSL
    - The power of *Lambda* in DSL world
    - Typesafe builder and Kotlin DSL
- Syntactic extension
    - Extension method e.g. Gradle Kotlin DSL
    - Operator overloading e.g. Ktor
    - Infix operator based Fluent style e.g. Assertion libraries
    - DSLMarker and implicit receiver resolution e.g. Jetpack Compose
- For DSL users
    - Adapt Kotlin DSL to existing libraries
- For DSL developers
    - How to keep both usabilities of Kotlin DSL and other JVM languages
    - Examples in Gradle Kotlin DSL

おまけ

昨日の勉強会で Nkzn さんに「Gradle Kotlin DSLの話聞きたい」と言われたけど、45分やれる気がしないのでサクッと5分LTに送るか悩む。

GitHubなどで Issue/PR ごとに情報を読み書きする

GitHub などを使っていると PR Review だのなんだのを自動化したくなりますよね。

ただ GitHub Issue などには Issue ごとの metadata attachment みたいなものがなく、何かしらの方法で情報を保存する必要があります。

CI のキャッシュを用いて、キーを PR URL などにすれば1対1のデータリレーションが作成できますが、ここにも CI ごとの特性や複数の情報保持などで少々面倒くさいことになります。

例えば CircleCI だと同じキャッシュキーへのデータ上書きはできない *1 ため、PR URL をキーにしてデータを保存するということが困難です。

そこで Issue/PR/comment Body が markdown (もとい HTML rendering) であることを利用して、Issue/PR ごとにデータを保存する方法を紹介します。

<!-- <metadata name>/<ここに json を埋め込む> -->

↑のように HTML コメントを利用するだけです。HTML コメントは見かけ上 rendering されないため、見た目を損ねることなくデータの保持が可能です。 *2

あとは以下の流れで json を取り出し、よしなにしましょう。

  • Issue/PR/comment body を DOM Tree に変換
  • Comment Node だけ filter
  • metadata name で filter
  • 該当 node の text content から <metadata name>/ を削除し、JSON にパースする
  • よしなにする

これの使い方は本当に多様で、利用方法の一例は別の記事で紹介します。

*1:expire した場合は新規書き込みと見なしており、上書きのときに限ります

*2:これは danger などで実際に利用されているテクニックです。

フィルターコマンドと組み合わせると幸せになれるコマンド集 その1

fzy, fzf, peco などなど様々なフィルターコマンドがこの世にはあるけれど、結局それで何をすれば DX があがるのか・・・と言われたので、よく使うやつを羅列しました。とりあえずその1ということで。

GitHub - jhawthorn/fzy: A better fuzzy finder

GitHub - junegunn/fzf: A command-line fuzzy finder

GitHub - peco/peco: Simplistic interactive filtering tool

動かしてる環境は zsh 、フィルターは fzf です。適宜変えてください。*1

コマンド履歴を見る

$ alias hist="fzf < ~/.zsh_history"

ghqディレクトリに移動する

$ alias cg='cd $(ghq root)/$(ghq list|fzf)'

git checkout <local> を簡単に

$ git config --global alias.co '!git checkout $(git branch | fzf)'
$ git co

git checkout -b <branch_name> <remote> を簡単に

$ git config --global alias.cor '!f() { local -r ref=$(git branch -r | fzf); git checkout -b "${1:-${ref#*/}}" $ref; }; f'
$ git cor
$ git cor <any_branch_name>

git <command> <file>... を簡単に

$ git config --global alias.staged 'diff --name-only --staged'
$ git config --global alias.modified 'diff --name-only'
$ git config --global alias.untracked 'ls-files --others --exclude-standard'
$ 
$ git config --global alias.add-m '!git add -- $(git modified | fzf -m)'
$ git config --global alias.add-u '!git add -- $(git untracked | fzf -m)'
$ git config --global alias.reset-s '!git reset -- $(git staged | fzf -m)'

特定の拡張子のファイルを探索したい

# ~/.zshrc

find_xxx_seed() {
  local -r ext="$1"
  echo "alias find_${ext}='find . -name \"*.${ext}\"|fzf -m'"
}

eval $(find_xxx_seed "apk")
eval $(find_xxx_seed "ipa")

# find_apk, find_ipa が有効になる

現在のワーキングディレクトリ化にある特定のディレクトリにいきたい

$ alias dive='cd $(find . -type d | fzf)'

他の用途には enhancd を使っています。また上の alias で「あ、この下にないんだった」と思ってキャンセルがてらCtrl+Cを押すと cd 無引数扱いになって履歴に移れるので重宝してます。(enhancd を使ってる場合に限る)

$ alias dive='f() { local -r go_to="$(find . -type d | fzf)"; if [[ -n "$go_to" ]]; then cd "$go_to"; fi; }; f'

Ctrl-C をしたら何もしてほしくないときは多分こう。

*1:ファイル数が多すぎるとパフォーマンスに支障が出ます。

git git status がつらいと聞いて

最近某社の人と、「そういうコマンドあったんだ」みたいな話ってあんまり外に出てこないし、無駄なことしてる可能性あるよね(意訳)みたいな話をした。

ということでそういうコマンドをどんどん書いていきたい。

1個目は git git 問題。

git まで打って、少し考えて git git status と走らせたことはないだろうか。僕はある。あれは悲しい。

drop-git() {
  if let "$# > 0"; then
    while [[ "$1" == "git" ]]; do
        shift 1
    done

    if type command >/dev/null 2>&1; then
      command git "$@"
    else
      git "$@"
    fi
  else
    if type command >/dev/null 2>&1; then
      command git
    else
      git
    fi
  fi
}

alias git="drop-git"

ということでこういう alias を張って凌いでいる。

コマンドのマニュアル・サンプルで使う記法について

よくコマンドの実行例で以下のような記法を見ることがあると思う。

$ git add <file>...

これは man で使ってる記法を元にしてることが多い。ただ「コマンドのサンプル(マニュアル)はこう書け」という厳密な構文が存在するわけではなく、MicrosoftIBM始め、ある程度の共通項持った様々な亜種を定義している。

表現記法

ぱっと目に着くものを試しに書き下してみると、

用途 記法 その他備考
foo は変数 foo or <foo> or foo or FOO 斜体にならず、_foo_ と表示される端末もある(ミスなのかは知らない)
foo は literal foo これは太字
foo または bar foo|bar
foo が optional [foo]
-f foo-b をグルーピング(1つも選ばなくてもよい) [-f foo|-b] 任意用の角括弧はグルーピングにも使える
-f foo-b をグルーピング(最低でも1つ選ぶ必要がある) (-f foo|-b) or {-f foo|-b}
foo を繰り返し指定できる foo...
最低でも1つの foo が必要 foo foo...
複数の変数を指定する foo bar baz 上記繰り返しでは表現できない場合のみ
空白を含めた foo bar を1つの引数とする "foo bar" シェルのオプションパース仕様に依存しているところが強い

これらの表現は合成・入れ子が可能とはいえ、1行で書くには限界がある。そういう場合は複数行に分けることが多い。例えば下記のコマンドのような表記の場合、

$ foo bar ([-a] <baz> | -b)

2行に分解し、排他であることを明確に示す。

$ foo bar [-a] <baz>
$ foo bar -b

共通表現

厳密な構文が存在しないとは言っても、広く用いられている共通の表現がある。

用途 記法
foo は変数 foo or <foo> or foo or FOO
foo または bar foo|bar
foo が optional [foo]
-f foo-b をグルーピング(1つも選ばなくてもよい) [-f foo|-b]
-f foo-b をグルーピング(最低でも1つ選ぶ必要がある) (-f foo|-b) or {-f foo|-b}
foo を繰り返し指定できる foo...

<foo> を optional の意味で使ったり、[foo] を変数の意味でとして使ったり、そういうことをしている明記されたルールは見たことがない。*1

正直ここらへんの規則すら破ってるサンプル表記は本当にやめて欲しいな、と思ったりする。*2

$ foo [bar]

で、実は bar が必須とか。それでいて bar は実は変数だとか。普通に実行出来る気がしない。*3

語弊が少なそうだなって思う記法の組み合わせ

僕の思う最強の(ry みたいな。

用途 記法
foo は変数 FOO or <foo>
foo は literal foo
foo または bar foo|bar
foo が optional [foo]
-f foo-b をグルーピング(1つも選ばなくてもよい) [-f foo|-b]
-f foo-b をグルーピング(最低でも1つ選ぶ必要がある) (-f foo|-b)
foo を繰り返し指定できる foo...
  • 斜体や太字 -> 見づらい*4
  • {} -> 正規表現のせいか () の方がグルーピングっぽく、{} にグルーピング感を感じない*5

RFCとかで制定されて欲しい今日この頃。

参考

*1:個人の感想です

*2:個人の感想です

*3:というか出来なかった。この記事を書いてる理由はまさにこれで、サンプルを見ても全く分からずソースコードを読むことになった。

*4:個人の感想です

*5:個人の感想です