diff --git a/bin/commit-info b/bin/commit-info new file mode 100755 index 0000000..c70e9c5 --- /dev/null +++ b/bin/commit-info @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'optparse' + +require_relative '../lib/commit_info' +require_relative '../lib/errors' +require_relative '../lib/log' + +options = { + repo: 'emacs-mirror/emacs', + output: File.expand_path('../tarballs', __dir__), + log_level: :info +} + +OptionParser.new do |opts| + opts.banner = <<~TXT + Usage: ./commit-info [options] + + Fetch commit info of given GitHub repository branch, tag, or SHA. + + Options: + TXT + + opts.on('-r', '--repo STRING', + "GitHub repository (default: #{options[:repo]})") do |v| + options[:repo] = v + end + + opts.on('-o', '--output DIR', 'Directory to save tarball in ' \ + "(default: #{options[:output]})") do |v| + options[:output] = v + end + + opts.on('-l', '--log-level LEVEL', 'Log level ' \ + "(default: #{options[:log_level]})") do |v| + options[:log_level] = v.to_sym + end +end.parse! + +begin + logger = Log.new('commit-info', options[:log_level]) + commit = CommitInfo.new( + ref: ARGV[0], + repo: options[:repo], + logger: logger + ).perform + + puts commit.to_yaml +rescue Error => e + handle_error(e) +end diff --git a/bin/download-tarball b/bin/download-tarball index c61ac97..f067c2a 100755 --- a/bin/download-tarball +++ b/bin/download-tarball @@ -5,6 +5,7 @@ require 'optparse' require_relative '../lib/download_tarball' require_relative '../lib/errors' +require_relative '../lib/log' options = { repo: 'emacs-mirror/emacs', @@ -38,7 +39,13 @@ OptionParser.new do |opts| end.parse! begin - tarball = DownloadTarball.new(ref: ARGV[0], **options).perform + logger = Log.new('download-tarball', options[:log_level]) + tarball = DownloadTarball.new( + ref: ARGV[0], + repo: options[:repo], + output: options[:output], + logger: logger + ).perform puts tarball.to_yaml rescue Error => e diff --git a/lib/base_action.rb b/lib/base_action.rb new file mode 100644 index 0000000..909e151 --- /dev/null +++ b/lib/base_action.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require_relative './common' +require_relative './output' + +class BaseAction + include Common + include Output +end diff --git a/lib/commit.rb b/lib/commit.rb index ac608e3..adf9ce2 100644 --- a/lib/commit.rb +++ b/lib/commit.rb @@ -1,14 +1,27 @@ # frozen_string_literal: true +require 'json' +require 'time' require 'yaml' +require_relative './errors' +require_relative './common' + class Commit + include Common + + attr_reader :repo + attr_reader :ref + attr_reader :message attr_reader :sha attr_reader :time - def initialize(sha:, time:) + def initialize(sha:, time:, repo: nil, ref: nil, message: nil) @sha = sha @time = time + @repo = repo + @ref = ref + @message = message end def sha_short @@ -17,9 +30,13 @@ class Commit def to_hash { + 'repo' => repo, + 'ref' => ref, 'sha' => sha, 'sha_short' => sha_short, - 'time' => time + 'time' => time.utc, + 'timestamp' => time.utc.to_i, + 'message' => message } end diff --git a/lib/commit_info.rb b/lib/commit_info.rb new file mode 100644 index 0000000..464dcf0 --- /dev/null +++ b/lib/commit_info.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require_relative './base_action' +require_relative './commit' + +class CommitInfo < BaseAction + COMMIT_URL = 'https://api.github.com/repos/%s/commits/%s' + + attr_reader :ref + attr_reader :repo + attr_reader :logger + + def initialize(ref:, repo:, logger:) + @ref = ref + @repo = repo + @logger = logger + + err 'branch/tag/sha argument cannot be empty' if ref.nil? || ref.empty? + end + + def perform + info "Fetching info for git ref: #{ref}" + + url = format(COMMIT_URL, repo, ref) + commit_json = http_get(url) + + err "Failed to get commit info about: #{ref}" if commit_json.nil? + + parsed = JSON.parse(commit_json) + commit = Commit.new( + repo: repo, + ref: ref, + sha: parsed&.dig('sha'), + message: parsed&.dig('commit', 'message'), + time: Time.parse(parsed&.dig('commit', 'committer', 'date')).utc + ) + + err 'Failed to get commit SHA' if commit.sha.nil? || commit.sha.empty? + err 'Failed to get commit time' if commit.time.nil? + + commit + end +end diff --git a/lib/common.rb b/lib/common.rb index e25b463..bf17160 100644 --- a/lib/common.rb +++ b/lib/common.rb @@ -5,6 +5,10 @@ require 'net/http' module Common private + def self.included(base) + base.extend(self) + end + def run_cmd(*args) info "executing: #{args.join(' ')}" system(*args) || err("Exit code: #{$CHILD_STATUS.exitstatus}") diff --git a/lib/download_tarball.rb b/lib/download_tarball.rb index ae37824..1bae8fb 100644 --- a/lib/download_tarball.rb +++ b/lib/download_tarball.rb @@ -4,30 +4,24 @@ require 'fileutils' require 'json' require 'time' -require_relative './common' -require_relative './commit' -require_relative './output' +require_relative './base_action' + +require_relative './commit_info' require_relative './tarball' -class DownloadTarball - include Common - include Output - - logger_name 'download-tarball' - +class DownloadTarball < BaseAction TARBALL_URL = 'https://github.com/%s/tarball/%s' - COMMIT_URL = 'https://api.github.com/repos/%s/commits/%s' attr_reader :ref attr_reader :repo attr_reader :output - attr_reader :log_level + attr_reader :logger - def initialize(ref:, repo:, output:, log_level:) + def initialize(ref:, repo:, output:, logger:) @ref = ref @repo = repo @output = output - @log_level = log_level + @logger = logger err 'branch/tag/sha argument cannot be empty' if ref.nil? || ref.empty? end @@ -62,22 +56,6 @@ class DownloadTarball end def commit - return @commit if @commit - - info "Fetching info for git ref: #{ref}" - url = format(COMMIT_URL, repo, ref) - commit_json = http_get(url) - err "Failed to get commit info about: #{ref}" if commit_json.nil? - - parsed = JSON.parse(commit_json) - commit = Commit.new( - sha: parsed&.dig('sha'), - time: Time.parse(parsed&.dig('commit', 'committer', 'date')) - ) - - err 'Failed to get commit SHA' if commit.sha.nil? || commit.sha.empty? - err 'Failed to get commit time' if commit.time.nil? - - @commit = commit + @commit ||= CommitInfo.new(ref: ref, repo: repo, logger: logger).perform end end diff --git a/lib/errors.rb b/lib/errors.rb index 5af62fd..02410a6 100644 --- a/lib/errors.rb +++ b/lib/errors.rb @@ -6,3 +6,7 @@ def handle_error(err) end class Error < StandardError; end + +class CommitNotFound < Error; end +class NoCommitSHA < Error; end +class NoCommitTime < Error; end diff --git a/lib/log.rb b/lib/log.rb new file mode 100644 index 0000000..31d1e97 --- /dev/null +++ b/lib/log.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Log + extend Forwardable + + attr_reader :name + attr_reader :level + + def initialize(name, level = :info) + @name = name + @level = level + end + + def_delegators :logger, :debug, :info, :warn, :error, :fatal, :unkonwn + + private + + def logger + @logger ||= Logger.new($stderr).tap do |l| + l.progname = name + l.level = level + l.formatter = formatter + end + end + + def formatter + proc do |severity, _datetime, progname, msg| + "==> [#{progname}] #{severity}: #{msg}\n" + end + end +end diff --git a/lib/output.rb b/lib/output.rb index 04f227c..571f478 100644 --- a/lib/output.rb +++ b/lib/output.rb @@ -25,25 +25,4 @@ module Output def err(msg = nil) raise Error, msg end - - private - - # override to set custom log level - def log_level - :info - end - - def logger - @logger ||= Logger.new($stderr).tap do |l| - l.progname = self.class.logger_name - l.level = log_level - l.formatter = log_formatter - end - end - - def log_formatter - proc do |severity, _datetime, progname, msg| - "==> [#{progname}] #{severity}: #{msg}\n" - end - end end