class GitMaintain::Repo
Constants
- ACTION_HELP
- ACTION_LIST
Attributes
name[R]
path[R]
remote_stable[R]
remote_valid[R]
stable_repo[R]
valid_repo[R]
Public Class Methods
check_opts(opts)
click to toggle source
# File lib/repo.rb, line 27 def self.check_opts(opts) if opts[:action] == :submit_release then if opts[:br_suff] != "master" then raise "Action #{opts[:action]} can only be done on 'master' suffixed branches" end end end
execAction(opts, action)
click to toggle source
# File lib/repo.rb, line 35 def self.execAction(opts, action) repo = Repo::load() if action == :submit_release then repo.stableUpdate() end repo.send(action, opts) end
load(path=".")
click to toggle source
# File lib/repo.rb, line 21 def self.load(path=".") dir = Dir.pwd() repo_name = File.basename(dir) return GitMaintain::loadClass(Repo, repo_name, dir) end
new(path=nil)
click to toggle source
# File lib/repo.rb, line 44 def initialize(path=nil) GitMaintain::checkDirectConstructor(self.class) @path = path @branch_list=nil @stable_branches=nil @suffix_list=nil @config_cache={} if path == nil @path = Dir.pwd() end @name = File.basename(@path) @valid_repo = getGitConfig("maintain.valid-repo") @valid_repo = @@VALID_REPO if @valid_repo == "" @stable_repo = getGitConfig("maintain.stable-repo") @stable_repo = @@STABLE_REPO if @stable_repo == "" @remote_valid=runGit("remote -v | egrep '^#{@valid_repo}' | grep fetch | awk '{ print $2}' | sed -e 's/.*://' -e 's/\\.git//'") @remote_stable=runGit("remote -v | egrep '^#{@stable_repo}' | grep fetch | awk '{ print $2}' | sed -e 's/.*://' -e 's/\\.git//'") @auto_fetch = getGitConfig("maintain.autofetch") case @auto_fetch when "" @auto_fetch = nil when "true", "yes", "on" @auto_fetch = true when "false", "no", "off" @auto_fetch = false else raise("Invalid value '#{@auto_fetch}' in git config for maintain.autofetch") end @branch_format_raw = getGitConfig("maintain.branch-format") @branch_format = Regexp.new(/#{@branch_format_raw}/) @stable_branch_format = getGitConfig("maintain.stable-branch-format") @stable_base_format = getGitConfig("maintain.stable-base-format") @stable_base_patterns= runGit("config --get-regexp stable-base | egrep '^stable-base\.' | "+ "sed -e 's/stable-base\.//' -e 's/---/\\//g'").split("\n").inject({}){ |m, x| y=x.split(" "); m[y[0]] = y[1] m } @mail_format = getGitConfig("maintain.mail-format") if @mail_format == "" then @mail_format = :imap_send else # Check that the format is valid case @mail_format when "imap_send", "send_email" else raise("Invalid mail-format #{@mail_format}") end @mail_format = @mail_format.to_sym() end end
Public Instance Methods
api()
click to toggle source
Github API stuff
# File lib/repo.rb, line 406 def api @api ||= Octokit::Client.new(:access_token => token, :auto_paginate => true) end
createRelease(opts, tag, github_rel=true)
click to toggle source
# File lib/repo.rb, line 269 def createRelease(opts, tag, github_rel=true) log(:INFO, "Creating a release for #{tag}") runGit("push #{@stable_repo} refs/tags/#{tag}") if github_rel == true then msg = runGit("tag -l -n1000 '#{tag}'") + "\n" # Ye ghods is is a horrific format to parse name, body = msg.split("\n", 2) name = name.gsub(/^#{tag}/, '').strip body = body.split("\n").map { |l| l.sub(/^ /, '') }.join("\n") api.create_release(@remote_stable, tag, :name => name, :body => body) end end
findStableBase(branch)
click to toggle source
# File lib/repo.rb, line 293 def findStableBase(branch) base=nil if branch =~ @branch_format then base = branch.gsub(/^\*?\s*#{@branch_format_raw}\/.*$/, @stable_base_format) end @stable_base_patterns.each(){|pattern, b| if branch =~ /#{pattern}\// || branch =~ /#{pattern}$/ base = b break end } raise("Could not a find a stable base for branch #{branch}") if base == nil return base end
find_alts(commit)
click to toggle source
# File lib/repo.rb, line 385 def find_alts(commit) alts=[] subj=runGit("log -1 --pretty='%s' #{commit}") return alts if $? != 0 branches = getStableBranchList().map(){|v| @@STABLE_REPO + "/" + versionToStableBranch(v)} runGit("log -F --grep \"$#{subj}\" --format=\"%H\" #{branches.join(" ")}"). split("\n").each(){|c| next if c == commit cursubj=runGit("log -1 --pretty='%s' #{c}") alts << c if subj == cursubj } return alts end
genReleaseNotif(opts, new_tags)
click to toggle source
# File lib/repo.rb, line 211 def genReleaseNotif(opts, new_tags) return if @NOTIFY_RELEASE == false mail_path=`mktemp`.chomp() mail = File.open(mail_path, "w+") mail.puts "From " + runGit("rev-parse HEAD") + " " + `date`.chomp() mail.puts "From: " + getGitConfig("user.name") + " <" + getGitConfig("user.email") +">" mail.puts "To: " + getGitConfig("patch.target") mail.puts "Date: " + `date -R`.chomp() if new_tags.length > 4 then mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + ": new stable releases" mail.puts "" mail.puts "These version were tagged/released:\n * " + new_tags.join("\n * ") mail.puts "" else mail.puts "Subject: [ANNOUNCE] " + File.basename(@path) + " " + (new_tags.length > 1 ? (new_tags[0 .. -2].join(", ") + " and " + new_tags[-1] + " have") : (new_tags.join(" ") + " has")) + " been tagged/released" mail.puts "" end mail.puts "It's available at the normal places:" mail.puts "" mail.puts "git://github.com/#{@remote_stable}" mail.puts "https://github.com/#{@remote_stable}/releases" mail.puts "" mail.puts "---" mail.puts "" mail.puts "Here's the information from the tags:" new_tags.sort().each(){|tag| mail.puts `git show #{tag} --no-decorate -q | awk '!p;/^-----END PGP SIGNATURE-----/{p=1}'` mail.puts "" } mail.puts "It's available at the normal places:" mail.puts "" mail.puts "git://github.com/#{@remote_stable}" mail.puts "https://github.com/#{@remote_stable}/releases" mail.close() case @mail_format when :imap_send puts runGitImap("< #{mail_path}") when :send_email run("cp #{mail_path} announce-release.eml") log(:INFO, "Generated annoucement email in #{@path}/announce-release.eml") end run("rm -f #{mail_path}") end
getBranchList(br_suff)
click to toggle source
# File lib/repo.rb, line 167 def getBranchList(br_suff) return @branch_list if @branch_list != nil @branch_list=runGit("branch").split("\n").map(){|x| x=~ /#{@branch_format_raw}\/#{br_suff}$/ ? $1 : nil }.compact().uniq() return @branch_list end
getCommitHeadline(sha)
click to toggle source
# File lib/repo.rb, line 154 def getCommitHeadline(sha) return runGit("show --format=oneline --no-patch --no-decorate #{sha}") end
getCommitSubj(sha)
click to toggle source
# File lib/repo.rb, line 157 def getCommitSubj(sha) return runGit("log -1 --pretty=\"%s\" #{sha}") end
getGitConfig(entry)
click to toggle source
# File lib/repo.rb, line 140 def getGitConfig(entry) return @config_cache[entry] ||= runGit("config #{entry} 2> /dev/null").chomp() end
getStableBranchList()
click to toggle source
# File lib/repo.rb, line 178 def getStableBranchList() return @stable_branches if @stable_branches != nil @stable_branches=runGit("branch -a").split("\n").map(){|x| x=~ /remotes\/#{@@STABLE_REPO}\/#{@stable_branch_format.gsub(/\\1/, '([0-9]+)')}$/ ? $1 : nil }.compact().uniq() return @stable_branches end
getSuffixList()
click to toggle source
# File lib/repo.rb, line 189 def getSuffixList() return @suffix_list if @suffix_list != nil @suffix_list = runGit("branch").split("\n").map(){|x| x=~ @branch_format ? /^\*?\s*#{@branch_format_raw}\/([a-zA-Z0-9_-]+)\s*$/.match(x)[-1] : nil }.compact().uniq() return @suffix_list end
getUnreleasedTags(opts)
click to toggle source
# File lib/repo.rb, line 201 def getUnreleasedTags(opts) remote_tags=runGit("ls-remote --tags #{@stable_repo} | egrep 'refs/tags/v[0-9.]*$'").split("\n").map(){ |x| x.gsub(/.*refs\/tags\//, '') } local_tags =runGit("tag -l | egrep '^v[0-9.]*$'").split("\n") new_tags = local_tags - remote_tags return new_tags end
get_new_token()
click to toggle source
# File lib/repo.rb, line 418 def get_new_token puts "Requesting a new OAuth token from Github..." print "Github username: " user = $stdin.gets.chomp print "Github password: " pass = $stdin.noecho(&:gets).chomp puts api = Octokit::Client.new(:login => user, :password => pass) begin res = api.create_authorization(:scopes => [:repo], :note => "git-maintain") rescue Octokit::Unauthorized puts "Username or password incorrect. Please try again." return get_new_token rescue Octokit::OneTimePasswordRequired print "Github OTP: " otp = $stdin.noecho(&:gets).chomp res = api.create_authorization(:scopes => [:repo], :note => "git-maintain", :headers => {"X-GitHub-OTP" => otp}) end token = res[:token] runGit("config --global maintain.api-token '#{token}'") # Now reopen with the token so OTP does not bother us @api=nil token end
list_branches(opts)
click to toggle source
# File lib/repo.rb, line 309 def list_branches(opts) puts getBranchList(opts[:br_suff]) end
list_suffixes(opts)
click to toggle source
# File lib/repo.rb, line 312 def list_suffixes(opts) puts getSuffixList() end
log(lvl, str)
click to toggle source
# File lib/repo.rb, line 109 def log(lvl, str) GitMaintain::log(lvl, str) end
run(cmd)
click to toggle source
# File lib/repo.rb, line 113 def run(cmd) return `cd #{@path} && #{cmd}` end
runBash()
click to toggle source
# File lib/repo.rb, line 144 def runBash() runSystem("bash") if $? == 0 then log(:INFO, "Continuing...") else log(:ERROR, "Shell exited with code #{$?}. Exiting") raise("Cancelled by user") end end
runGit(cmd)
click to toggle source
# File lib/repo.rb, line 120 def runGit(cmd) log(:DEBUG, "Called from #{caller[1]}") log(:DEBUG, "Running git command '#{cmd}'") return `git --work-tree=#{@path} #{cmd}`.chomp() end
runGitImap(cmd)
click to toggle source
# File lib/repo.rb, line 131 def runGitImap(cmd) return `export GIT_ASKPASS=$(dirname $(dirname $(which git)))/lib/git-core/git-gui--askpass; if [ ! -f $GIT_ASKPASS ]; then export GIT_ASKPASS=$(dirname $(which git))/git-gui--askpass; fi; if [ ! -f $GIT_ASKPASS ]; then export GIT_ASKPASS=/usr/lib/ssh/ssh-askpass; fi; git --work-tree=#{@path} imap-send #{cmd}` end
runGitInteractive(cmd)
click to toggle source
# File lib/repo.rb, line 125 def runGitInteractive(cmd) log(:DEBUG, "Called from #{caller[1]}") log(:DEBUG, "Running interactive git command '#{cmd}'") return system("git --work-tree=#{@path} #{cmd}") end
runSystem(cmd)
click to toggle source
# File lib/repo.rb, line 116 def runSystem(cmd) return system("cd #{@path} && #{cmd}") end
stableUpdate(fetch=nil)
click to toggle source
# File lib/repo.rb, line 161 def stableUpdate(fetch=nil) fetch = @auto_fetch if fetch == nil return if fetch == false log(:VERBOSE, "Fetching stable updates...") runGit("fetch #{@stable_repo}") end
submitReleases(opts, new_tags)
click to toggle source
# File lib/repo.rb, line 263 def submitReleases(opts, new_tags) new_tags.each(){|tag| createRelease(opts, tag) } end
submit_release(opts)
click to toggle source
# File lib/repo.rb, line 315 def submit_release(opts) new_tags = getUnreleasedTags(opts) if new_tags.empty? then log(:INFO, "All tags are already submitted.") return end log(:WARNING, "This will officially release these tags: #{new_tags.join(", ")}") rep = GitMaintain::confirm(opts, "release them") if rep != 'y' then raise "Aborting.." end if @NOTIFY_RELEASE != false genReleaseNotif(opts, new_tags) end log(:WARNING, "Last chance to cancel before submitting") rep= GitMaintain::confirm(opts, "submit these releases") if rep != 'y' then raise "Aborting.." end submitReleases(opts, new_tags) end
summary(opts)
click to toggle source
# File lib/repo.rb, line 339 def summary(opts) log(:INFO, "Configuration summary:") log(:INFO, "Stable remote: #{@stable_repo}") log(:INFO, "Validation remote: #{@valid_repo}") log(:INFO, "") log(:INFO, "Branch config:") log(:INFO, "Local branch format: /#{@branch_format_raw}/") log(:INFO, "Remote stable branch format: #{@stable_branch_format}") log(:INFO, "Remote stable base format: #{@stable_base_format}") if @stable_base_patterns.length > 0 then log(:INFO, "") log(:INFO, "Stable base rules:") @stable_base_patterns.each(){|name, base| log(:INFO, "\t#{name} -> #{base}") } end brList = getBranchList(opts[:br_suff]) brStList = getStableBranchList() if brList.length > 0 then log(:INFO, "") log(:INFO, "Local branches:") brList.each(){|br| branch = Branch.load(self, br, nil, opts[:branch_suff]) localBr = branch.local_branch stableBr = @@STABLE_REPO + "/" + branch.remote_branch stableBase = branch.stable_base runGit("rev-parse --verify --quiet #{stableBr}") stableBr = "<MISSING>" if $? != 0 log(:INFO, "\t#{localBr} -> #{stableBr} (#{stableBase})") brStList.delete(br) } end if brStList.length > 0 then log(:INFO, "") log(:INFO, "Upstream branches:") brStList.each(){|br| branch = Branch.load(self, br, nil, opts[:branch_suff]) stableBr = @@STABLE_REPO + "/" + branch.remote_branch stableBase = branch.stable_base log(:INFO, "\t<MISSING> -> #{stableBr} (#{stableBase})") } end end
token()
click to toggle source
# File lib/repo.rb, line 410 def token @token ||= begin # We cannot use the 'defaults' functionality of git_config here, # because get_new_token would be evaluated before git_config ran tok = getGitConfig("maintain.api-token") tok.to_s() == "" ? get_new_token : tok end end
versionToLocalBranch(version, suff)
click to toggle source
# File lib/repo.rb, line 284 def versionToLocalBranch(version, suff) return @branch_format_raw.gsub(/\\\//, '/'). gsub(/\(.*\)/, version) + "/#{suff}" end
versionToStableBranch(version)
click to toggle source
# File lib/repo.rb, line 289 def versionToStableBranch(version) return version.gsub(/^(.*)$/, @stable_branch_format) end