require 'rake/packagetask' require 'octokit' GIT_REPO = "MattesGroeger/vim-bookmarks" VIM_SCRIPT_URL = "http://www.vim.org/scripts/add_script_version.php?script_id=4893" LABELS = ["feature", "enhancement", "bug"] task :default => [:release] task :ci => [:dump, :test] desc "Dump version numbers" task :dump do sh 'vim --version' end desc "Run tests" task :test do sh "bundle exec vim-flavor test" end desc "Create release archive" task :release do version = request_user_input("Which version do you want to release (0.1.0)?") file_path = create_zip(version) if request_user_input("Create git release now? (y/n)") == 'y' upload_release(version, file_path) end end desc "See the changelog for a specific version" task :changelog do version = request_user_input("For which version (0.1.0)?") show_changelog(version) end def create_zip(version) file_path = "release/vim-bookmarks-#{version}.zip" `mkdir -p release` `zip -r #{file_path} . -i "doc/*" -i "plugin/*" -i "autoload/*" -i LICENSE` file_path end def upload_release(version, asset_path) asset_name = asset_path.split("/")[-1] # login to github @client = Octokit::Client.new(netrc: true) @client.login # get all milestones milestones = @client.milestones(GIT_REPO) milestone = milestones.select { |m| m.title == version }.first return puts "Unable to find milestone for version #{version}. Aborted!" if !milestone # abort if there are still open issues return puts "Found #{milestone.open_issues} open issues for milestone #{version}. Close them first!" if milestone.open_issues > 0 # get change log via issues issues = @client.issues(GIT_REPO, milestone: milestone.number, state: :closed) changes = build_changelog(issues) # get contributor sentence thanks = contributor_sentence_since_last_release() # show change log, get it confirmed by user (y/n) changelog = changes.join changelog << "\n#{thanks}" unless thanks.nil? puts "> Changelog:\n#{changelog}\n\n" return puts "Aborted!" if request_user_input("Do you want to create release #{version} with the above changelog? (y/n)", "n").downcase != "y" # create release release = @client.create_release(GIT_REPO, version, name: "vim-bookmarks-#{version}", body: changelog) puts "> Created release #{release.name} (id: #{release.id})\n\n" # if release exists already: # releases = @client.releases(GIT_REPO) # release = releases.first # upload asset release_url = "https://api.github.com/repos/#{GIT_REPO}/releases/#{release.id}" asset = @client.upload_asset(release_url, asset_path, content_type: 'application/zip', name: asset_name) puts "> Uploaded asset #{asset.name} (id: #{asset.id})\n\n" # close milestone @client.update_milestone(GIT_REPO, milestone.number, state: :closed) puts "> Closed milestone #{version}. Done!" if request_user_input("Update script on vim.org now? (y/n)", "n").downcase == "y" `open "#{VIM_SCRIPT_URL}"` end end def show_changelog(version) # login to github @client = Octokit::Client.new(netrc: true) @client.login # get all milestones milestones = @client.milestones(GIT_REPO) + @client.milestones(GIT_REPO, state: :closed) milestone = milestones.select { |m| m.title == version }.first return puts "Unable to find milestone for version #{version}. Aborted!" if !milestone # get change log via issues issues = @client.issues(GIT_REPO, milestone: milestone.number, state: :closed) # show change log puts "\nChangelog:\n\n#{build_changelog(issues).join}\n" end def build_changelog(issues) issues.map { |i| label = (LABELS & i.labels.map { |l| l.name }).first label_txt = label == "bug" ? "bugfix" : label line = " * [#{label_txt}] #{i.title} ##{i.number}\n" if label {label: label, issue: i.number, line: line} }.select { |f| f[:label] != nil }.sort { |a, b| [LABELS.find_index(a[:label]),b[:issue]] <=> [LABELS.find_index(b[:label]),a[:issue]] }.map { |e| e[:line] } end def contributor_sentence_since_last_release() releases = @client.releases(GIT_REPO) since = releases.size > 0 ? releases.first.created_at : nil contributors = contributors(since) contributor_sentence(contributors) end def contributors(from = nil, to = nil) # Get all by default from = Time.new(1).utc.iso8601 if from.nil? to = Time.now.utc.iso8601 if to.nil? # Get all commits since last release commits = @client.commits(GIT_REPO, sha: :master, since: from, until: to) # Get all collaborators collaborators = @client.collaborators(GIT_REPO).map { |c| c.login } # Find all authors that are not site_admin contributor_map = commits.inject({}) { |hash, commit| if commit.author.nil? user = "[#{commit.commit.author.name}](mailto:#{commit.commit.author.email})" hash[user] = 1 else login = commit.author.login user = "@#{login}" if collaborators.index(login).nil? # exclude repo maintainer change_count = @client.commit(GIT_REPO, commit.sha).stats.total hash[user] = hash[user].nil? ? change_count : hash[user] + change_count end end hash } # Sort them by number of changes (importance) contributor_map.keys.sort { |a, b| contributor_map[b] <=> contributor_map[a] }.map { |c| "#{c}" } end def contributor_sentence(contributors) if contributors.size == 0 return nil elsif contributors.size == 1 authors = "#{contributors.first} for the contribution" else last = contributors.pop authors = "#{contributors.join(', ')} and #{last} who contributed" end "Thanks #{authors} to this release!" end def request_user_input(message, fallback = "") STDOUT.puts message input = STDIN.gets.strip.to_s if input.empty? if fallback.empty? request_user_input(message) # try again else fallback.to_s end else input.to_s end end