require 'octokit' require 'dotenv' require 'highline'
Dotenv.load
module Dotenv
def self.add(key_value, filename = nil) filename = File.expand_path(filename || '.env') f = File.open(filename, File.exists?(filename) ? 'a' : 'w') f.puts key_value key, value = key_value.split('=') ENV[key] = value end
end
namespace :github do
namespace :releases do set :ask_release, false set :released_at, -> { Time.now } set :release_tag, -> { fetch(:released_at).strftime('%Y%m%d-%H%M%S%z') } set :username, -> { username = `git config --get user.name`.strip username = `whoami`.strip unless username username } set :release_title, -> { default_title = nil run_locally do begin pull_request = Octokit.pull(fetch(:github_repo), fetch(:pull_request_id)) default_title = pull_request.title rescue => e error e.message default_title = fetch(:release_tag) end end if fetch(:ask_release) title = HighLine.new.ask("Release Title? [default: #{default_title}]") title = default_title if title.empty? title else default_title end } set :release_body, -> { default_body = <<-MD.gsub(/^ {6}/, '').strip released at #{fetch(:released_at).strftime('%Y-%m-%d %H:%M:%S %z')} pull request: #{fetch(:github_repo)}##{fetch(:pull_request_id)} MD if fetch(:ask_release) body = HighLine.new.ask("Release Body?") do |q| q.gather = '' end "#{body.join("\n") + "\n" unless body.empty?}\n#{default_body}" else default_body end } set :pull_request_id, -> { id = nil run_locally do merge_comment = capture "git log | grep 'Merge pull request' | head -n 1" id = merge_comment.match(/#(\d+)/)[1].to_i end id } set :release_comment, -> { url = "#{fetch(:github_releases_path)}/#{fetch(:release_tag)}" <<-MD.gsub(/^ {6}/, '').strip This change was deployed to production :octocat: #{fetch(:release_title)}: [#{fetch(:release_tag)}](#{url}) MD } set :github_token, -> { if ENV['GITHUB_PERSONAL_ACCESS_TOKEN'].nil? token = HighLine.new.ask('GitHub Personal Access Token?') Dotenv.add "GITHUB_PERSONAL_ACCESS_TOKEN=#{token}" else ENV['GITHUB_PERSONAL_ACCESS_TOKEN'] end } set :github_repo, -> { repo = "#{fetch(:repo_url)}" repo.match(/([\w\-]+\/[\w\-\.]+)\.git$/)[1] } set :github_releases_path, -> { "#{Octokit.web_endpoint}#{fetch(:github_repo)}/releases/tag" } desc 'GitHub authentication' task :authentication do run_locally do begin Octokit.configure do |c| c.access_token = fetch(:github_token) end rate_limit = Octokit.rate_limit! info 'Exceeded limit of the GitHub API request' if rate_limit.remaining.zero? debug "#{rate_limit}" rescue Octokit::NotFound # No rate limit for white listed users rescue => e error e.message end end end desc 'Create new release note' task create: :authentication do run_locally do begin Octokit.create_release( fetch(:github_repo), fetch(:release_tag), name: fetch(:release_title), body: fetch(:release_body), target_commitish: fetch(:branch, 'master'), draft: false, prerelease: false ) info "Release as #{fetch(:release_tag)} to #{fetch(:github_repo)} was created" rescue => e error e.message invoke 'github:git:create_tag_and_push_origin' end end end desc 'Add comment for new release' task add_comment: :authentication do run_locally do begin Octokit.add_comment( fetch(:github_repo), fetch(:pull_request_id), fetch(:release_comment) ) info "Comment to #{fetch(:github_repo)}/pull##{fetch(:pull_request_id)} was added" rescue => e error e.message end end end desc 'Remove all labels of the pull request' task remove_labels: :authentication do run_locally do begin Octokit.remove_all_labels( fetch(:github_repo), fetch(:pull_request_id) ) info "Labels of #{fetch(:github_repo)}/pull##{fetch(:pull_request_id)} was removed" rescue => e error e.message end end end end namespace :git do desc 'Create tag for new release and push to origin' task :create_tag_and_push_origin do message = "#{fetch(:release_title)} by #{fetch(:username)}\n" message += "#{fetch(:github_repo)}##{fetch(:pull_request_id)}" run_locally do execute :git, :tag, '-am', "#{message}", "#{fetch(:release_tag)}" execute :git, :push, :origin, "#{fetch(:release_tag)}" end end end
end