class Courseware::Repository

Public Class Methods

new(config) click to toggle source
# File lib/courseware/repository.rb, line 5
def initialize(config)
  @config = config
  return if @config[:nocache]

  raise 'This is not a courseware repository' unless Courseware::Repository.repository?
  configure_courseware
end

Private Class Methods

repository?() click to toggle source
# File lib/courseware/repository.rb, line 205
def self.repository?
  system('git status >/dev/null 2>&1')
end

Public Instance Methods

branch_exists?(branch) click to toggle source
# File lib/courseware/repository.rb, line 88
def branch_exists?(branch)
  `git branch --list '#{branch}'` != ''
end
checkout(branch, pull=false) click to toggle source
# File lib/courseware/repository.rb, line 36
def checkout(branch, pull=false)
  system("git checkout #{branch}")
  pull(branch) if pull
end
clean?() click to toggle source
# File lib/courseware/repository.rb, line 79
def clean?
  system('git diff-index --quiet HEAD')
end
commit(*args) click to toggle source
# File lib/courseware/repository.rb, line 56
def commit(*args)
  message = args.pop
  args.each do |file|
    system('git', 'add', file)
  end
  system('git', 'commit', '-m', message)
end
courselevel?() click to toggle source
# File lib/courseware/repository.rb, line 96
def courselevel?
  File.expand_path("#{Dir.pwd}/..") == `git rev-parse --show-toplevel`.chomp
end
create(branch) click to toggle source
# File lib/courseware/repository.rb, line 31
def create(branch)
  system("git checkout -b #{branch}")
  system("git push upstream #{branch}")
end
current(prefix) click to toggle source
# File lib/courseware/repository.rb, line 141
def current(prefix)
  tags(prefix).first.gsub(/^#{prefix}-/, '')
end
delete(branch) click to toggle source
# File lib/courseware/repository.rb, line 51
def delete(branch)
  system("git branch -d #{branch}")
  system("git push upstream --delete #{branch}")
end
discard(*args) click to toggle source
# File lib/courseware/repository.rb, line 64
def discard(*args)
  args.each do |file|
    $logger.warn "Discarding changes to #{file}"
    system('git', 'checkout', '--', file)
  end
end
last_commit() click to toggle source
# File lib/courseware/repository.rb, line 71
def last_commit
  `git show --name-status --no-color`.chomp.gsub("\t", '    ')
end
merge(branch) click to toggle source
# File lib/courseware/repository.rb, line 45
def merge(branch)
  system('git checkout master')
  system("git merge #{branch}")
  system('git push upstream master')
end
on_branch?(branch='master') click to toggle source
# File lib/courseware/repository.rb, line 75
def on_branch?(branch='master')
  `git symbolic-ref -q --short HEAD`.chomp == branch
end
outstanding_commits(prefix, verbose=false) click to toggle source
# File lib/courseware/repository.rb, line 100
def outstanding_commits(prefix, verbose=false)
  last = current(prefix)
  commits = `git log --no-merges --oneline #{prefix}-#{last}..HEAD -- .`.each_line.map {|line| line.chomp }

  verbose ? commits : commits.count
end
pristine?() click to toggle source

clean working tree and no untracked files

# File lib/courseware/repository.rb, line 84
def pristine?
  clean? and `git ls-files --other --directory --exclude-standard`.empty?
end
pull(branch) click to toggle source
# File lib/courseware/repository.rb, line 41
def pull(branch)
  system('git', 'pull', 'upstream', branch)
end
releasenotes(last, version) click to toggle source
# File lib/courseware/repository.rb, line 107
def releasenotes(last, version)
  # get used files from showoff and combine them into a single array
  used = JSON.parse(`showoff info --json`).values.reduce(:+)
  logs = `git log --name-only --no-merges --pretty="format:* (%h) %s [%aN]" #{last}..HEAD`
  curr = nil
  keep = []

  # sanitize
  used.map! {|i| i.sub('_shared', '_content') }
  used.map! {|i| i.sub('_images/shared', '_images') }

  # now iterate through and select log entries that change files this presentation uses
  logs.each_line do |line|
    if (curr.nil? or line.start_with? '*')
      curr = line
    else
      keep << curr if used.include? line.strip
    end
  end

  str = "### #{version}\n"
  str << "{{{Please summarize the release here}}}\n"
  str << "\n"
  str << keep.uniq.join
  str
end
tag(tag, message=nil) click to toggle source
# File lib/courseware/repository.rb, line 13
def tag(tag, message=nil)
  if tag
    system("git tag -a #{tag} -m '#{message}'")
  else
    system("git tag #{tag}")
  end

  system("git push upstream master")
  system("git push upstream #{tag}")
  system("git push courseware master")
  system("git push courseware #{tag}")
end
tags(prefix, count=1) click to toggle source

This gets a list of all tags matching a prefix.

# File lib/courseware/repository.rb, line 135
def tags(prefix, count=1)
  prefix ||= 'v' # even if we pass in nil, we want to default to this
  tags = `git tag -l '#{prefix}*'`.split("\n").sort_by { |tag| version(tag) }.last(count)
  tags.empty? ? ['v0.0.0'] : tags
end
toplevel?() click to toggle source
# File lib/courseware/repository.rb, line 92
def toplevel?
  Dir.pwd == `git rev-parse --show-toplevel`.chomp
end
update() click to toggle source
# File lib/courseware/repository.rb, line 26
def update
  system('git fetch upstream')
  system('git fetch upstream --tags')
end

Private Instance Methods

check_remote(remote, url) click to toggle source
# File lib/courseware/repository.rb, line 152
def check_remote(remote, url)
  existing = `git config --get remote.#{remote}.url`.chomp
  if existing =~ /^(git@|https:\/\/)github.com[:\/].*\/#{@config[:github][:repository]}(?:-.*)?(?:.git)?$/
    case $1
    when 'git@'
      ensure_remote(remote, "git@github.com:#{url}.git")
    when 'https://'
      ensure_remote(remote, "https://github.com/#{url}.git")
    end
  elsif existing.empty?
    $logger.warn 'Your origin remote is not set properly.'
    $logger.warn 'Generating PDF files and other local operations will work properly, but many repository actions will fail.'
  else
    raise "Your remote (#{existing}) does not appear to be configured correctly."
  end
end
configure_courseware() click to toggle source
# File lib/courseware/repository.rb, line 147
def configure_courseware
  check_remote('courseware', "#{@config[:github][:public]}/#{@config[:github][:repository]}")
  check_remote('upstream',   "#{@config[:github][:development]}/#{@config[:github][:repository]}")
end
ensure_remote(remote, url) click to toggle source
# File lib/courseware/repository.rb, line 169
def ensure_remote(remote, url)
  # If we *have* the remote, but it's not correct, then  let's repair it.
  if `git config --get remote.#{remote}.url`.chomp != url and $?.success?
    if Courseware.confirm("Your '#{remote}' remote should be #{url}. May I correct this?")
      raise "Error correcting remote." unless system("git remote remove #{remote}")
    else
      raise "Please configure your '#{remote}' remote before proceeding."
    end
  end

  # add the remote, either for the first time or because we removed it
  unless system("git config --get remote.#{remote}.url > /dev/null")
    # Add the remote if it doesn't already exist
    unless system("git remote add #{remote} #{url}")
      raise "Could not add the '#{remote}' remote."
    end
  end

  # for pedantry, validate the refspec too
  unless `git config --get remote.#{remote}.fetch`.chomp == "+refs/heads/*:refs/remotes/#{remote}/*"
    if Courseware.confirm("Your '#{remote}' remote has an invalid refspec. May I correct this?")
      unless system("git config remote.#{remote}.fetch '+refs/heads/*:refs/remotes/#{remote}/*'")
        raise "Could not repair the '#{remote}' refspec."
      end
    else
      raise "Please configure your '#{remote}' remote before proceeding."
    end

  end
end
version(tag) click to toggle source

Gem::Version is used simply for semantic version comparisons.

# File lib/courseware/repository.rb, line 201
def version(tag)
  Gem::Version.new(tag.gsub(/^.*-?v/, '')) rescue Gem::Version.new(0)
end