スプレッドシートのデータを取得する
slack botでスプレッドシートからデータ取得する場面があったので調査して検証がてらgolangで実装してみた。
気をつける所とかメモ的に書いておく。
作ったのはスプレッドシートで重み付け抽選を行うアプリ。
認証
認証方法はAPIキー、OAuth、サービスアカウントの3つがある。
APIキー
公開されたスプレッドシートしか読み込めないようだったので今回はパス。
OAuthクライアントID
一度ユーザがブラウザを開いて認証する必要がある。
bot用には使えないなーと思ったのでパス。
サービスアカウント
新しくGoogleアカウントを発行するイメージ。
スプレッドシートに招待して使う。
招待してしまえばずっと使えるためbotには合っていると思い、今回はサービスアカウントを使用することにした。
使用方法
発行したjsonキーファイルの中から client_email
を取り出す。
$ cat /path/to/key.json | jq -r .client_email test@quickstart-1551059800000.iam.gserviceaccount.com
データを取得したいスプレッドシートに移動して右上の共有ボタンをクリック。
『他のユーザと共有』ダイアログを開き、先程取得した client_email
を追加する。
実装
実装側の認証には google.JWTConfigFromJSON
を使う。
キーjsonファイルの中身とスコープ(今回は取得なのでreadonly)を渡す。
conf, err := google.JWTConfigFromJSON( jsonKeyBytes, "https://www.googleapis.com/auth/spreadsheets.readonly" )
返ってきた conf
からhttpクライアントを取得し、 sheets.New
に渡して Service
を取得する。
srv, err := sheets.New(conf.Client(ctx))
あとは取得したサービスを使ってGetすればいい。
スプレッドシートIDと取得するデータのレンジ(下記の例では A2:B
)を指定する。
( A2:B
はA2セルからB列の最後のセルまでという意味)
resp, err := srv.Spreadsheets.Values.Get(spreadsheetID, "A2:B").Context(ctx).Do() var items []lotteryItem for _, row := range resp.Values { name := row[0].(string) weight, err := strconv.Atoi(row[1].(string)) items = append(items, lotteryItem{name: name, weight: weight}) }
※エラーハンドリングは省略してあります。
列方向への取得
デフォルトでは行方向の取得になるが、列方向に取得したい場合は MajorDimension
に COLUMNS
を指定すればよい。
resp, err := srv.Spreadsheets.Values.Get(spreadsheetID, "A2:B").Context(ctx).MajorDimension("COLUMNS").Do()
参考
Nuxt.js×Express使用時のhost指定でハマった
Nuxt.js×ExpressのDockerfileを書いている時に、コンテナ外からアクセスを受け付けようと思って server/index.js
の host
の値を 127.0.0.1
を 0.0.0.0
に書き換えた。
host = process.env.HOST || '0.0.0.0',
しかしコンテナ外からアクセスできなかった。
よく見ると nuxt.options.server
で上書きされているようだった。
const { host = process.env.HOST || '0.0.0.0', port = process.env.PORT || 3000 } = nuxt.options.server
(最近のjsに慣れてなくて、この記法の意味調べるのに手間取った...)
nuxt.options.server
のデフォルト値
環境変数 HOST
に 0.0.0.0
を指定するとコンテナ外からのアクセスは通った。
まとめ
ENV HOST 0.0.0.0
追記
結局上書きされるなら server/index.js
で代入してる所無駄じゃない?と思ってPR出してみた。
追記2
PRマージされてた😊
AlexaアプリケーションをServerlessで作成するコマンド
$ serverless create -t aws-alexa-typescript -p <app_name>
LinuxにNode.js入れる時はPermissionのためにnvm使ったほうがいい
前回の記事ではyumでNode.jsをインストールしたが、それはServerlessをインストールしようと思ったためであった。
しかし、Node.jsのインストール後、Serverless公式に書いてあったコマンド
npm install serverless -g
を実行したらPermissionで怒られた。
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules' npm ERR! { Error: EACCES: permission denied, access '/usr/local/lib/node_modules' npm ERR! errno: -13, npm ERR! code: 'EACCES', npm ERR! syscall: 'access', npm ERR! path: '/usr/local/lib/node_modules' } npm ERR! npm ERR! Please try running this command again as root/Administrator.
Permissionで怒られたのでsudoつけて実行したら以下のようなエラーが出た。
┌───────────────────────────────────────────────────┐ │ serverless update check failed │ │ Try running with sudo or get access │ │ to the local update config store via │ │ sudo chown -R $USER:$(id -gn $USER) /root/.config │ └───────────────────────────────────────────────────┘
インストールはできていてコマンドは使えるようだったが、このようなエラーを放置するのはちょっと気持ち悪いのでnpmのPermission周りについて色々調べた。
すると以下のページを発見。
Resolving EACCES permissions errors when installing packages globally
ここの『Reinstall npm with a node version manager』に以下の記述がある。
This is the best way to avoid permissions issues.
node version managerでnpmをインストールする事がPermission問題を回避する最善の方法らしい。
そのままリンクを辿っていくとversion managerの紹介がされていた。
Using a Node version manager to install Node.js and npm
ここでnとnvmが紹介されていたのだが、nvmの方がスター数が多かったため今回はnvmを選択した。
nvmのインストール方法は割愛する。
以下nvmレポジトリの Installation を参照してください。
nvmのインストール後、 nvm install node
で最新のNode.jsがインストールされる。
その後Serverlessをインストールするとエラーは出なかった🎉
まとめ
LinuxにNode.js入れる時はPermissionのためにnvm使ったほうがいい!
Amazon Linuxで古いNode.jsがインストールされる時の解決方法
Amazon Linuxで何度Node.js v11をインストールしようとしてもv6が入ってしまう現象が起こったのでその解決策をメモ。
現象
v11用RPMのセットアップをする。
$ curl -sL https://rpm.nodesource.com/setup_11.x | sudo bash -
その後、yum installしても 2:6.14.4-1nodesource
がインストールされる。
$ sudo yum install -y nodejs ... Installed: nodejs.x86_64 2:6.14.4-1nodesource
解決策
以下のコマンドでRPMのキャッシュを消す。
$ sudo yum remove -y nodesource-release* nodejs $ yum clean all $ sudo rm -rf /var/cache/yum/* $ sudo rm /etc/yum.repos.d/nodesource-el.repo
その後、再度RPMセットアップコマンドを流してyum installすればよい。
$ curl -sL https://rpm.nodesource.com/setup_11.x | sudo bash - ... $ sudo yum install -y nodejs ... Installed: nodejs.x86_64 2:11.1.0-1nodesource
v11が入りました。
参考
削除済みリモートブランチを追跡しているローカルブランチを1発で全削除するコマンド
リモートブランチはマージ後GitHubが削除するか聞いてくれるのでその時点で削除するようにしている。
だが、そのリモートブランチを追跡しているローカルブランチの削除を忘れて溜まっていることがよくある。
$ git branch -v * develop fef1cdd Merge pull request #30 from abcdef/fix/bazbarfoo feature/foo e57408f [gone] Fix deploy feature/bar a9b73ad [gone] Upload image feature/baz b833113 [gone] Fix test feature/foobar 703e2ad [gone] Add foobar.c feature/foobaz 1587581 [gone] Fix foobaz.rb feature/barfoo 37265cb [gone] Add barfoo.php feature/barbaz 3c121ca [gone] Fix barbaz.py feature/bazfoo cb69767 [gone] Add bazfoo.go feature/bazbar bb8575f [gone] Fix bazbar.pl feature/foobarbaz 66d2807 [gone] Fix README.md fix/foobazbar 84a781e [gone] Add gitignore fix/bazfoobar cd36a6b [gone] Fix ci master 0a41ce8 Merge pull request #20 from abcdef/develop
[gone]
が付いているのがリモートブランチへの追跡が切れているローカルブランチ。
いつも git branch -d
の後ろに1つずつブランチ名をコピペして削除していた。
$ git branch -d feature/foo feature/bar feature/baz feature/foobar feature/foobaz feature/barfoo feature/barbaz feature/bazfoo feature/bazbar feature/foobarbaz fix/foobazbar fix/bazfoobar Deleted branch feature/foo (was e57408f). Deleted branch feature/bar (was a9b73ad). Deleted branch feature/baz (was b833113). Deleted branch feature/foobar (was 703e2ad). Deleted branch feature/foobaz (was 1587581). Deleted branch feature/barfoo (was 37265cb). Deleted branch feature/barbaz (was 3c121ca). Deleted branch feature/bazfoo (was cb69767). Deleted branch feature/bazbar (was bb8575f). Deleted branch feature/foobarbaz (was 66d2807). Deleted branch fix/foobazbar (was 84a781e). Deleted branch fix/bazfoobar (was cd36a6b).
面倒なので1発コマンド打つだけで全部消えるコマンドを組もうと思い調べた。
コマンド
git for-each-ref --format '%(if)%(upstream:track)%(then)%(refname:short)%(end)' | xargs git branch -d
解説
最初は git branch
コマンドを使って作ろうとしていた。
だが、先の記事にも書いた通り、 git branch
を使ってスクリプトを書かないほうがいいらしい。
なので git for-each-ref
を使って書いた。
これはGitレポジトリの各refの情報を条件に従って出力していくコマンド。
Git - git-for-each-ref Documentation
何点か解説を書いてみる。
ブランチ名
ブランチ名は %(refname:short)
で取得。
short
をつけないと refs/heads
がついてしまい、ブランチ名として認識されないので注意が必要。
# `refs/heads` がついてしまう。 $ git for-each-ref --format '%(refname)' refs/heads/develop refs/heads/feature/foo refs/heads/feature/bar refs/heads/feature/baz refs/heads/feature/foobar refs/heads/feature/foobaz refs/heads/feature/barfoo refs/heads/feature/barbaz refs/heads/feature/bazfoo refs/heads/feature/bazbar refs/heads/feature/foobarbaz refs/heads/fix/foobazbar refs/heads/fix/bazfoobar refs/heads/master refs/remotes/origin/HEAD refs/remotes/origin/develop refs/remotes/origin/feature/aaa refs/remotes/origin/feature/bbb refs/remotes/origin/ccc refs/remotes/origin/master refs/remotes/origin/try/ddd refs/remotes/origin/try/eee # shortをつければ正しいブランチ名が取得できる。 $ git for-each-ref --format '%(refname:short)' develop feature/foo feature/bar feature/baz feature/foobar feature/foobaz feature/barfoo feature/barbaz feature/bazfoo feature/bazbar feature/foobarbaz fix/foobazbar fix/bazfoobar master origin/HEAD origin/develop origin/feature/aaa origin/feature/bbb origin/ccc origin/master origin/try/ddd origin/try/eee
gone
削除対象は [gone]
が付いたブランチなのでこれを取得する。
upstream の項で以下のように説明されている。
:track
also prints "[gone]" whenever unknown upstream ref is encountered.
試すと
$ git for-each-ref --format '%(upstream:track)' [gone] [gone] [gone] [gone] [gone] [gone] [gone] [gone] [gone] [gone] [gone] [gone]
[gone]
のみでは分かりづらいと思うのでブランチ名をつけてみる。
$ git for-each-ref --format '%(upstream:track) %(refname:short)' develop [gone] feature/foo [gone] feature/bar [gone] feature/baz [gone] feature/foobar [gone] feature/foobaz [gone] feature/barfoo [gone] feature/barbaz [gone] feature/bazfoo [gone] feature/bazbar [gone] feature/foobarbaz [gone] fix/foobazbar [gone] fix/bazfoobar master origin/HEAD origin/develop origin/feature/aaa origin/feature/bbb origin/ccc origin/master origin/try/ddd origin/try/eee
リモートへの追跡が切れていない develop
, master
やリモートにのみ存在しているブランチには [gone]
がついておらず、リモートへの追跡が切れたローカルブランチにのみ [gone]
がついている事がわかる。
if
git for-each-ref
ではif文( %(if)…%(then)…%(end)
)が使える。
if文を使い、 [gone]
があるときだけブランチ名を表示するようにする。
$ git for-each-ref --format '%(if)%(upstream:track)%(then)%(refname:short)%(end)' feature/foo feature/bar feature/baz feature/foobar feature/foobaz feature/barfoo feature/barbaz feature/bazfoo feature/bazbar feature/foobarbaz fix/foobazbar fix/bazfoobar
xargs
取得できたブランチ名をxargsを使って git branch -d
に流す。
ちなみにxargsだけ実行すると git branch -d
にどんな値が渡っているのかわかる。
$ git for-each-ref --format '%(if)%(upstream:track)%(then)%(refname:short)%(end)' | xargs feature/foo feature/bar feature/baz feature/foobar feature/foobaz feature/barfoo feature/barbaz feature/bazfoo feature/bazbar feature/foobarbaz fix/foobazbar fix/bazfoobar
こんな感じ。
別解
サブコマンドとして実行してもよい。
git branch -d $(git for-each-ref --format '%(if)%(upstream:track)%(then)%(refname:short)%(end)')