自分で持ってるリポジトリのGitHub Actionsでアクションを指定する場合、v1のようなタグ指定からコミットハッシュに変えようとしたときの備忘録。
(以下のコードのようなことをしたかった)
runs:
using: "composite"
steps:
- - uses: ruby/setup-ruby@v1.244.0
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
with:
bundler-cache: true
GitHubのページを見に行ってもいいけど、コードで取得するためにはどのようにするといいかな?となりRubyで実装してみることに。
実際に作成してみる
- githubを扱う場合の定番ということでoctokit、あとAPIトークンを使いたいので、dotenvをインストール
- faraday-retryもインストールしておくと警告が出なくて楽です
gem install octokit dotenv fataday-retry
GitHubのアクセストークンを作製する(人によってはやらなくてもよい)
- 自作のプライベートリポジトリにあるアクションのデータを取得する場合などはアクセストークンが必要です
- どの権限が必要かはケースによるので、適切なものを選択してください
- 実行回数が少ないかつ、実行対象がパブリックリポジトリの場合はなくても大丈夫です
- アクセストークンを作成したら、
.env
に保存しましょう
.env
GITHUB_TOKEN=#(取得したトークンをペースト)
実際にプログラムを作成する
- 以下のRubyプログラムを作成します
- 今回は
ruby main.rb ruby/setup-ruby@v1.244.0
のような入力をコンソールから入れることを想定します
- 今回は
- まずは最初の部分を見ます
- 以下を行っています
- ライブラリのロードと変数読み込み
- githubのclient作成
- 標準入力からリポジトリ情報を整理
- オーナー
- リポジトリ
- タグ
- clientはすべてのタグを表示するために、
auto_paginate
オプションをtrueにします
- 以下を行っています
# frozen_string_literal: true
require 'octokit'
require 'dotenv'
Dotenv.load('.env')
GITHUB_TOKEN = ENV['GITHUB_TOKEN']
def client
@client ||= Octokit::Client.new(access_token: GITHUB_TOKEN, auto_paginate: true)
end
input = ARGV[0]
owner, repo_and_tag = input.split('/', 2)
repo, input_tag = repo_and_tag.split('@', 2)
- 次にバージョンが存在するか確認します
- 完全一致するタグを探して、一致するタグがあった場合それを表示してループを終了します
- もし見つからない場合は部分一致を探して、一致するタグを表示してループを終了します
- 部分一致でも見つらない場合は見つからなかったというメッセージを出します
tags = client.tags("#{owner}/#{repo}")
found_match = false
tags.each do |tag|
next unless next unless tag.name == input_tag
puts "Found tag: #{tag.name} with commit SHA: #{tag.commit.sha}"
found_match = true
break
end
unless found_match
tags.each do |tag|
next unless array_starts_with?(tag.name.split('.'), input_tag.split('.'))
puts "Maybe found commit SHA: #{tag.commit.sha} with tag: #{tag.name}"
found_match = true
break
end
end
puts "Tag or commit #{input_tag} not found." unless found_match
- エラー処理などをまとめると以下のようになります(長いので折り畳み)
プログラム全部
# frozen_string_literal: true
require 'octokit'
require 'dotenv'
Dotenv.load('.env')
GITHUB_TOKEN = ENV['GITHUB_TOKEN']
def client
@client ||= Octokit::Client.new(access_token: GITHUB_TOKEN, auto_paginate: true)
end
# input example: ruby/setup-ruby@v1.244.0 and ruby/setup-ruby@v1
input = ARGV[0]
owner, repo_and_tag = input.split('/', 2)
repo, input_tag = repo_and_tag.split('@', 2)
def array_starts_with?(main_array, sub_array)
return false if sub_array.length > main_array.length
main_array.take(sub_array.length) == sub_array
end
begin
tags = client.tags("#{owner}/#{repo}")
if tags.empty?
puts 'No tags found.'
exit
end
found_match = false
tags.each do |tag|
next unless tag.name == input_tag
puts "Found tag: #{tag.name} with commit SHA: #{tag.commit.sha}" if tag.name == input_tag
found_match = true
break
end
unless found_match
tags.each do |tag|
next unless array_starts_with?(tag.name.split('.'), input_tag.split('.'))
puts "Maybe found commit SHA: #{tag.commit.sha} with tag: #{tag.name}"
found_match = true
break
end
end
puts "Tag or commit #{input_tag} not found." unless found_match
rescue Octokit::NotFound
puts "Repository #{owner}/#{repo} not found."
rescue Octokit::TooManyRequests
puts 'Rate limit exceeded. Please wait or use a Personal Access Token.'
rescue StandardError => e
puts "An error occurred: #{e.message}"
end
- 実際に実行すると以下のようになります
Products\hash-test> ruby main.rb ruby/setup-ruby@v1.244.0
Found tag: v1.244.0 with commit SHA: 13e7a03dc3ac6c3798f4570bfead2aed4d96abfb
Products\hash-test> ruby main.rb ruby/setup-ruby@v1
Maybe found commit SHA: 13e7a03dc3ac6c3798f4570bfead2aed4d96abfb with tag: v1.244.0
まとめ
GitHubのAPIは詳細を全部把握するのは大変ですが、octokitを使うと最小限の労力で実装することができます。
tag.name
をtag.commit.sha
に変えて若干書き換えると逆にコミットからバージョンを確認できたり、結構色んなことができるので、ぜひ何かGitHubの作業を自動化したいときはoctokitで実装してみてください。