はじめに
インストールしたい 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 はひととおり関数化しておくと捗ります。