はじめに
インストールしたい OSS ツールのバージョンを GitHub API などを使って動的に取得したいことがありました。コードスニペットにしておくと便利そうだったので、bash と PowerShell でスクリプトを書いてみました。
シェルスクリプト
bash だとこんな感じになります。
repover() { check_rate_limit() { if [[ $1 == *"rate limit"* ]]; then echo "ERROR: Rate limit has been exceeded." return 1 fi return 0 } if [[ $# != 2 ]]; then echo "ERROR: Need two parameters. repo-author and repo-name." return 1 fi if ! command -v jq &>/dev/null; then echo "ERROR: 'jq' is not installed but is required." return 1 fi if ! response=$(curl -s "https://api.github.com/repos/$1/$2/releases/latest" 2>/dev/null); then echo "ERROR: Failed to get the latest release of $2 via the GitHub API." return 1 fi check_rate_limit "$response" || return 1 if ! ver=$(echo "$response" | jq -r .tag_name 2>/dev/null); then echo "ERROR: 'tag_name' does not exist in the response." return 1 fi if [[ ! $ver == 'null' ]]; then echo "$ver" return 0 fi if ! response=$(curl -s "https://api.github.com/repos/$1/$2/tags" 2>/dev/null); then echo "ERROR: Failed to get the latest tag of $2 via the GitHub API." return 1 fi check_rate_limit "$response" || return 1 if ! tags=$(echo "$response" | jq ".[].name" 2>/dev/null); then echo "ERROR: 'name' does not exist in the response." return 1 fi if ! echo "$tags" | jq -r 'sort_by(.) | reverse | .[0]'; then echo "ERROR: Failed to parse the latest tag of $2 via the GitHub API." return 1 fi }
内容ですが、まず Rate Limit に引っかかったかを確認する関数を用意します。
check_rate_limit() { if [[ $1 == *"rate limit"* ]]; then echo "ERROR: Rate limit has been exceeded." return 1 fi return 0 }
GitHub API を使って、引数で author/repo を渡して最新リリースを取得します。戻り値で Rate Limit を検出した場合はそのまま終了します。
if ! response=$(curl -s "https://api.github.com/repos/$1/$2/releases/latest" 2>/dev/null); then echo "ERROR: Failed to get the latest release of $2 via the GitHub API." return 1 fi check_rate_limit "$response" || return 1
戻り値に tag_name
キーが含まれているか確認します。なかったら終了します。
if ! ver=$(echo "$response" | jq -r .tag_name 2>/dev/null); then echo "ERROR: 'tag_name' does not exist in the response." return 1 fi
上記でバージョンが取れたらそれを返して正常終了します。
if [[ ! $ver == 'null' ]]; then echo "$ver" return 0 fi
バージョンが取得できなかった場合、タグを見にいきます。この場合も Rate Limit を確認します。
if ! response=$(curl -s "https://api.github.com/repos/$1/$2/tags" 2>/dev/null); then echo "ERROR: Failed to get the latest tag of $2 via the GitHub API." return 1 fi check_rate_limit "$response" || return 1
戻り値に name
キーが含まれているか確認します。なかったら終了します。
if ! tags=$(echo "$response" | jq ".[].name" 2>/dev/null); then echo "ERROR: 'name' does not exist in the response." return 1 fi
取得したタグを降順でソートし、最初の要素を返します。
if ! echo "$tags" | jq -r 'sort_by(.) | reverse | .[0]'; then echo "ERROR: Failed to parse the latest tag of $2 via the GitHub API." return 1 fi
使用例 (リリースがあるリポジトリ)
$ repover aws aws-cdk v2.94.0
使用例 (リリースがなくタグで管理されているリポジトリ)
$ repover awslabs git-secrets 1.3.0
PowerShell スクリプト
かなり簡略化していますが、PowerShell で書く場合の例です。
#Requires -Version 6.0 function repover { param ( [Alias('u')] [string]$author, [Alias('r')] [string]$repo ) $content = (Invoke-WebRequest -Uri $('https://api.github.com/repos/{0}/{1}/releases/latest' -f $author, $repo) -UseBasicParsing -SkipHttpErrorCheck).Content | ConvertFrom-Json if ($content.PSObject.Properties.Name -contains 'tag_name') { return $content.tag_name } $content = (Invoke-WebRequest -Uri $('https://api.github.com/repos/{0}/{1}/tags' -f $author, $repo) -UseBasicParsing -SkipHttpErrorCheck).Content | ConvertFrom-Json if ($content.PSObject.Properties.Value -contains 'name') { return $content.name | Sort-Object -Descending -Unique | Select-Object -First 1 } }
やっていることは以下の通りです。
Invoke-WebRequest
で API を叩いて最新リリースを取得- 戻り値に含まれる
Content
を JSON から PowerShell のオブジェクトに変換 - プロパティに
tag_name
があるか確認し、あれば返す tag_name
からバージョンが取れなかった場合、Invoke-WebRequest
でタグ取得の API を叩く- 戻り値に含まれる
Content
を JSON から PowerShell のオブジェクトに変換 - プロパティに
name
があるか確認し、あれば降順ソートした先頭の要素を返す
使用例
PS> repover -author aws -repo aws-cdk v2.94.0 PS> repover -author awslabs -repo git-secrets 1.3.0
おわりに
そこそこ便利に使っています。ターミナルは毎日のように開くものですし、よく使う API はひととおり関数化しておくと捗ります。