GitLab 13.7でMergeRequestのReviewers*1が無料版に入ってきたので対応しました。
Assignsの他にReviewersにもメンションが飛ぶようになっています。
CHANGELOG全文 https://gitlab.com/sue445/tanuki_reminder/-/blob/master/CHANGELOG.md#anchor-060
GitLab 13.7でMergeRequestのReviewers*1が無料版に入ってきたので対応しました。
Assignsの他にReviewersにもメンションが飛ぶようになっています。
CHANGELOG全文 https://gitlab.com/sue445/tanuki_reminder/-/blob/master/CHANGELOG.md#anchor-060
正月休み中にRubyで趣味アプリを作っててSentryを導入しようとしたところ、いつもと違うセットアップ手順だったので気づきました。
v3までがsentry-ravenでv4以降がsentry-rubyらしいです。
https://rubygems.org/gems/sentry-raven/versions
https://rubygems.org/gems/sentry-ruby/versions
先月上旬にはv4が出ていたらしい。
dependabotとかで自動bundle updateしてるだけだと絶対に気づかないやつ...
https://github.com/getsentry/sentry-ruby/tree/master/sentry-raven によると
Future Support: sentry-raven has entered maintenance mode, which means it won't receive any new feature supports or aggressive bug fixes.
とのことなので移行した方がよさそうです
移行方法は https://docs.sentry.io/platforms/ruby/migration を参照。
社だとSaaS版ではなくオンプレミス版のSentryを自前でホスティングして運用してるのですが、社で使っているSentryのバージョンが古くてsentry-rubyが動かなくてハマりました。
詳しくは下記のissueを参照
https://github.com/getsentry/sentry-ruby/issues/1185#issuecomment-755441492 によると
in the new SDK we've switched the reporting endpoint from /store to /envelope, which requires 20.6.0 and above version if you use the on-premise installation.
とのこと。
同じgemでメジャーバージョンが上がったら気づくけどgemの名前が変わるとさすがに移行に気づかないので、gem install
後にdeprecation messageを出すPRを投げました。
【追記】マージされて3.1.2に入りました。
https://github.com/getsentry/sentry-ruby/blob/master/sentry-raven/CHANGELOG.md#312
あとついでに rake build
がコケる問題もついでに直してPR投げました。
上記パッチは2つともマージはされているんだけど、deprecatedなgemなのでいつリリースされるかは不明です
あとsentry-rubyの方も使ってて気になった箇所があったのでPR投げました。
こっちは4.1.5のマイルストーンに入ってるので順調に行けば次バージョンに入るかなと思ってます
マージされて4.1.5に入りました。
https://github.com/getsentry/sentry-ruby/blob/master/sentry-ruby/CHANGELOG.md#415
Cloud Functionsにデプロイする時には gcloud functions deploy を使います。
そこで bundle install
も自動で実行されるのだけど、その時に --without development test
的なことをやってくれるのか調べてみました。(調べた範囲では公式ドキュメントには記載はなかった)
個人アプリから適当に抜粋
# frozen_string_literal: true source "https://rubygems.org" ruby "~> 2.7.0" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "functions_framework" gem "google-cloud-firestore" gem "google-cloud-secret_manager" gem "moji" gem "parallel" gem "sentry-ruby" gem "slack-notifier" gem "tweet_sanitizer" gem "twitter" gem "twitter_retry", ">= 0.2.1" group :development do gem "dotenv" end group :test do gem "rspec" end
HTTPのリクエストがきた時に bundle list
の結果を標準出力に出すだけのシンプルなコード。
GCP公式の Functions Framework を使っている以外は見慣れたRubyのコードです。
require "functions_framework" begin require "dotenv/load" rescue LoadError end FunctionsFramework.http("test") do |request| puts `bundle list` "test\n" end
ログに rspec
や dotenv
がいるのを確認
$ bundle exec functions-framework-ruby --verbose --target test I, [2021-01-23T23:32:08.699683 #4427] INFO -- : FunctionsFramework v0.7.0 I, [2021-01-23T23:32:08.699761 #4427] INFO -- : FunctionsFramework: Loading functions from "./app.rb"... I, [2021-01-23T23:32:10.147408 #4427] INFO -- : FunctionsFramework: Looking for function name "test"... I, [2021-01-23T23:32:10.147486 #4427] INFO -- : FunctionsFramework: Starting server... I, [2021-01-23T23:32:10.201662 #4427] INFO -- : FunctionsFramework: Serving function "sentry_test" on port 8080... I, [2021-01-23T23:32:16.165209 #4427] INFO -- : FunctionsFramework: Handling HTTP GET request Gems included by the bundle: * addressable (2.7.0) * buftok (0.2.0) * cloud_events (0.1.2) * concurrent-ruby (1.1.8) * diff-lcs (1.4.4) * domain_name (0.5.20190701) * dotenv (2.7.6) * equalizer (0.0.11) * faraday (1.3.0) * faraday-net_http (1.0.1) * ffi (1.14.2) * ffi-compiler (1.0.1) * functions_framework (0.7.0) * gapic-common (0.3.4) * google-cloud-core (1.5.0) * google-cloud-env (1.4.0) * google-cloud-errors (1.0.1) * google-cloud-firestore (2.4.1) * google-cloud-firestore-v1 (0.2.3) * google-cloud-secret_manager (1.0.1) * google-cloud-secret_manager-v1 (0.5.1) * google-cloud-secret_manager-v1beta1 (0.6.6) * google-protobuf (3.14.0) * googleapis-common-protos (1.3.10) * googleapis-common-protos-types (1.0.5) * googleauth (0.14.0) * grpc (1.35.0) * grpc-google-iam-v1 (0.6.10) * http (4.4.1) * http-cookie (1.0.3) * http-form_data (2.3.0) * http-parser (1.2.3) * http_parser.rb (0.6.0) * jwt (2.2.2) * memoist (0.16.2) * memoizable (0.4.2) * moji (1.6) * multi_json (1.15.0) * multipart-post (2.1.1) * naught (1.1.0) * nio4r (2.5.4) * os (1.1.1) * parallel (1.20.1) * public_suffix (4.0.6) * puma (4.3.7) * rack (2.2.3) * rake (13.0.3) * rbtree (0.4.4) * rspec (3.10.0) * rspec-core (3.10.1) * rspec-expectations (3.10.1) * rspec-mocks (3.10.1) * rspec-support (3.10.1) * ruby2_keywords (0.0.4) * sentry-ruby (4.1.4) * signet (0.14.0) * simple_oauth (0.3.1) * slack-notifier (2.3.2) * thread_safe (0.3.6) * tweet_sanitizer (0.2.0) * twitter (7.0.0) * twitter_retry (0.2.1) * unf (0.1.4) * unf_ext (0.0.7.7) Use `bundle info` to print more detailed information about a gem
コンソールから関数を実行
出力されたログにはdotenvやrspecがいないので bundle install --without development test
が実行されてることが分かります。
あくまでドキュメント化されていない*1仕様なので今後この挙動は変わる可能性はあります。
*1:僕が見つけられなかったところに載ってる可能性はあります
Q: 出力されるものは?
yaml = <<YAML a: 1 YAML YAML.load(yaml) #=> ?
{"a"=>"1"}
{"a"=>1}
回答
2
YAMLの数字っぽい文字列はその言語の数字の型(Rubyだと Integer
)として解釈されます。
文字列として解釈させたい場合は "1"
(ダブルクオーテーション)や '1'
(シングルクォーテーション)のように囲んでください
Q: 出力されるものは?
yaml = <<YAML splash: ふたりはプリキュア Splash Star yes: Yes!プリキュア5 yes_gogo: Yes!プリキュア5GoGo fresh: フレッシュプリキュア! YAML data = YAML.load(yaml) "#{data['splash']},#{data['yes']},#{data['yes_gogo']},#{data['fresh']}" #=> ?
"ふたりはプリキュア Splash Star,Yes!プリキュア5,Yes!プリキュア5GoGo,フレッシュプリキュア!"
"ふたりはプリキュア Splash Star,,Yes!プリキュア5GoGo,フレッシュプリキュア!"
",Yes!プリキュア5,Yes!プリキュア5GoGo,フレッシュプリキュア!"
回答
2
true
, false
, yes
, no
, on
, off
はダブルクオーテーションなどで囲まない限りYAMLでは全て 真偽値 として扱われます
data = YAML.load(yaml) => {"splash"=>"ふたりはプリキュア Splash Star", true=>"Yes!プリキュア5GoGo!", "yes_gogo"=>"Yes!プリキュア5GoGo", "fresh"=>"フレッシュプリキュア!"}
data = YAML.load("{1: yes, 2: Yes, 3: on, 4: On, 5: true, 6: True}") #=> {1=>true, 2=>true, 3=>true, 4=>true, 5=>true, 6=>true} data = YAML.load("{1: no, 2: No, 3: off, 4: Off, 5: false, 6: False}") #=> {1=>false, 2=>false, 3=>false, 4=>false, 5=>false, 6=>false}
Q: 出力されるものは?
yaml = <<YAML default: &default slack: webhook_url: "https://example.com/" channel: "random" production: <<: *default slack: channel: "production_notify" YAML data = YAML.load(yaml) data["production"] #=> ?
{"slack"=>{"webhook_url"=>"https://example.com/", "channel"=>"random"}}
{"slack"=>{"webhook_url"=>"https://example.com/", "channel"=>"production_notify"}}
{"slack"=>{"channel"=>"production_notify"}}
回答
3
&
(アンカー)と *
(エイリアス)で定義済みの値をいい感じに共通化できるのはYAMLのよくあるリファクタリング手法ですが、<<:
(マージ)はdeep merge(要素内に別の要素があった時に再帰的にマージされる)ではなく第1要素だけを上書きするマージ(代入に近い)なので、今回の場合 default
の内容が打ち消されます。
イメージ的にはこんな感じ
data["slack"] = {"webhook_url"=>"https://example.com/", "channel"=>"random"} data["slack"] = {"channel"=>"production_notify"}
余談ですが https://github.com/railsware/global はdeep mergeしてくれるのがかなり便利で、前職のRailsアプリにはだいたい入っていました
Q: 出力されるものは?
yaml = <<YAML go: - 1.9 - 1.10 - 1.11 - 1.12 YAML data = YAML.load(yaml) data["go"] #=> ?
[1.9, 1.10, 1.11, 1.12]
[1.9, 1.1, 1.11, 1.12]
[1.90, 1.10, 1.11, 1.12]
回答
2
クオーテーションで囲んでいないので小数として解釈されるため 1.10
は 1.1
として解釈されます
厳密に 1.10
として評価するには "1.10"
のように囲む必要があります。
余談ですがGo 1.10が出た時に .travis.yml
に 1.10
を追加したらGo 1.1でCIが実行されてビルドが失敗したことがあります。
https://github.com/sue445/zatsu_monitor/commit/fc6b8ab806a3c48617cb084437d2d1c018777ee9#comments
Q: この中でシンタックスエラーになるのはどれか?
a
excludes: - *_test.rb
b
excludes: - test/**
回答
1
a
yaml = <<YAML excludes: - *_test.rb YAML YAML.load(yaml) Traceback (most recent call last): 8: from /Users/sue445/.rbenv/versions/3.0.0/bin/irb:23:in `<main>' 7: from /Users/sue445/.rbenv/versions/3.0.0/bin/irb:23:in `load' 6: from /Users/sue445/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>' 5: from (irb):62:in `<main>' 4: from /Users/sue445/.rbenv/versions/3.0.0/lib/ruby/3.0.0/psych.rb:280:in `load' 3: from /Users/sue445/.rbenv/versions/3.0.0/lib/ruby/3.0.0/psych.rb:390:in `parse' 2: from /Users/sue445/.rbenv/versions/3.0.0/lib/ruby/3.0.0/psych.rb:456:in `parse_stream' 1: from /Users/sue445/.rbenv/versions/3.0.0/lib/ruby/3.0.0/psych.rb:456:in `parse' Psych::SyntaxError ((<unknown>): did not find expected alphabetic or numeric character while scanning an alias at line 2 column 3)
b
yaml = <<YAML excludes: - test/** YAML YAML.load(yaml) #=> {"excludes"=>["test/**"]}
*_test.rb
の *
が前述のエイリアスとして評価されるのですが、対応する _test.rb
という名前のアンカーが存在しないためシンタックスエラーになります。
シンタックスエラーにしないためには "*_test.rb"
のように囲む必要があります。
タイトルが全て
GitHub Actionsで使える(事前定義済みの)環境変数 *1を列挙するだけのシンプルなワークフローです
on: - push - pull_request jobs: show_env: runs-on: ubuntu-latest steps: - run: env | grep GITHUB_ | sort
https://github.com/sue445/github_actions_sandbox_20210106/blob/master/.github/workflows/sandbox.yml
コミットグラフはこんな感じ
https://github.com/sue445/github_actions_sandbox_20210106/runs/1656991711 には
GITHUB_SHA=f308d17b80228b432d841e96624b583f632d2411
と出ているので、 master
ブランチ *2 のHEADと一致していることが分かると思います。(分かる)
検証用のPR https://github.com/sue445/github_actions_sandbox_20210106/pull/1
on
で push
と pull_request
を指定してるのでそれぞれイベントが発火します。
この時点でコミットグラフはこんな感じ
https://github.com/sue445/github_actions_sandbox_20210106/pull/1/checks?check_run_id=1657017337 には
GITHUB_SHA=8d1396316903bd747589ff2a81930e659cca1a4d
と出ているので、 tmp/pr_test
ブランチのHEADと一致しています。(分かる)
https://github.com/sue445/github_actions_sandbox_20210106/pull/1/checks?check_run_id=1657017535
GITHUB_SHA=9b0ee21ee4668fab1d29961f60108b9ef3c1946b
え!!!???
https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#push によるとpushイベントでの GITHUB_SHA
は
Commit pushed, unless deleting a branch (when it's the default branch)
とのこと。
https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#pull_request によるとpull_requestイベントでの GITHUB_SHA
は
Last merge commit on the GITHUB_REF branch
とのこと。
これしか書いていなくていまいち意味が分からなかったのですが id:r7kamura さんが RuboCop Problem Matchers で
pull_request イベントを起点に動かす場合、actions/checkout はそのPull Requestが生成しようとしているmerge commitをチェックアウトする。
と書いてるように、この GITHUB_SHA
はそのPull Requestで生成しようとしてるmerge commitのSHAだと思われます。
ちなみにこの挙動はTravis CIと同じような仕様です。
トノコト
自分が知っているものではBitriseはpull-reqトリガーで設定すると同様だったと思います。後はJenkinsもGithub Pull Request Builderプラグインを使用してpull-reqのwebhookを受けた場合は同じだったと思います
— Kenta.Kase (@Kesin11) 2021年1月7日
すみません今手元でBitriseのログを見直したところ、Bitriseはまた微妙に違う挙動でgithubのマージコミットをcheckoutしているわけではなくてgit clone後に自前でmergeしていました。その上でGIT_CLONE_COMMIT_HASHという環境変数にはブランチHEADのコミットハッシュが入っていました
— Kenta.Kase (@Kesin11) 2021年1月7日
ありがとうございます。
— sue445 (@sue445) 2021年1月7日
気になって手持ちのリポジトリ調べたのですが、WerckerはPRでもブランチのHEADをcheckoutしてたけどCircleCIはマージコミットのSHAをコミットしてました。公式ドキュメントはどっちもマージコミットに関して言及してなかったのでブランチのHEADを使ってると思ってました…
ほとんどのケースではそれほど困ることはないと思います。*3
しかしジョブの中で GITHUB_SHA
を使おうとした場合に注意が必要です。
具体的には tfnotify でTerraformの実行結果をPull Requestのコメントに出そうとした時に、pull_requestイベントを使うとPullRequestと直接紐付かない前述のマージコミットに対してコメントがつくため、初見だと謎のコミットに対してコメントが付く状態になります。(PullRequest上に登場するコミットに対してコメントがつけばPullRequest上で表示されます)
半年くらいずっと例の謎コミットにコメントがついて困ってたのですがつい先日下記で解決しました。
- name: terraform plan run: | # NOTE: tfnotify uses GITHUB_SHA, but GITHUB_SHA can't be override in env if [ -n "$PR_HEAD_SHA" ]; then export GITHUB_SHA=$PR_HEAD_SHA fi terraform plan -input=false | tfnotify plan env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
実際にPull Requestに対してtfnotifyのコメントがついた図
ちなみにコード中のコメントでも書いていますが
env: GITHUB_SHA: ${{ github.event.pull_request.head.sha }}
のように書いても GITHUB_SHA
を上書きできないので、別名として取得してジョブの中で代入して上書きするしかないです。
業務リポジトリのように開発者全員が同一リポジトリ内でPullRequestをやり取りする場合にはpushイベントだけで問題ないです。
しかしpushイベントだとforkされたリポジトリからPullRequestがきた時にイベントが発火しなくてCIのジョブが実行されないのでOSSのリポジトリで困ります。(経験済)
かといって今回のサンプルみたいに
on: - push - pull_request
で書くとPullRequestがきた時に2つジョブが実行されて無駄です。
色々検証した結果個人リポジトリだと下記に落ち着きました。
on: push: branches: - master pull_request: types: - opened - synchronize - reopened
40個以上のリポジトリで上記設定を半年以上使ってますが今の所不満はないです。
GitHub Actionsの仕様を理解した結果、何も分からなくなってしまった...
— sue445 (@sue445) 2021年1月6日
*1:公式の説明は https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables
*2:最近GitHubではmainブランチがデフォルトになってますが毎回両方併記のは大変なので本エントリでは masterブランチで統一します
*3:トピックブランチを作った時点でのmasterブランチとPullRequestを出した時のmasterブランチが大きく剥離してるとローカルではテストが通るのにCIだとテストがコケるという事象は発生するかもしれません
rubicure (2.0.0): All about Japanese battle heroine "Pretty Cure (Precure)". https://t.co/2ImrcNQ9QI
— rubygems_news (@RubygemsN) 2021年1月3日
https://github.com/sue445/rubicure/blob/master/CHANGELOG.md#v200
rubocopを最新にしようと思ったら最新のrubocopだとRuby 2.4以降必須になってたのでこの機会にRuby 2.2系と2.3系のサポートを切りました。
rubocopのバージョンを上げたのでソース上の差分が結構大きいですが機能面での変更点は無いです
今年新しく作ったものを作った順に紹介
今年の頭に作ったやつでたまにPRきてる。
最近GitHub本体のdependabotの方で go mod tidy
正式対応されたので go-mod-tidy-prはお役御免かなと思ってdeprecateにしました
下記エントリ参照
下記エントリ参照
下記エントリ参照
個人的には今年のイチオシ
今まで使ったことのないアーキテクチャで作りつつも、割と爆速で動くというのがウリ。
しかもGCPの費用が1ヶ月で1ドル切ってるのでお財布的にも嬉しい。(リリース直後にプチバズってアクセス増えたけどそれでも1ドルちょっと超えたくらい)
Cloud Functions実行時に毎回Secret Managerから機微情報を読み込んでるのでそこをGoのビルド時にいい感じに埋め込めばほぼ0円にできそうだが*1、今のままでも十分安いのでそこまでのモチベーションはないw
*1:FirestoreのQuota超えることもあるので完全に0円は無理