class Sah::CLI

Public Instance Methods

browse(arg=nil) click to toggle source
# File lib/sah/cli.rb, line 51
def browse(arg=nil)
  if arg
    if remotes.include? arg
      remote(arg).match %r%/([^/]+)/([^/]+?)(?:\.git)?$%
      project_key, repository_slug = $1, $2
    else
      repository_slug, project_key = arg.split("/").reverse
      project_key ||= "~#{config.user}"
    end
  else
    remote_url = `git config --get remote.origin.url`.chomp
    remote_url.match %r%/([^/]+)/([^/]+?)(?:\.git)?$%
    project_key, repository_slug = $1, $2
  end
  res = api.show_repository(project_key, repository_slug)
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end

  url = URI.parse(res.body["links"]["self"].first["href"])

  if [options[:branch], options[:commit], options[:'pull-request']].compact.count > 1
    abort "Multiple options (--branch, --commit, --pull-request) cannot be handled."
  end

  case options[:branch]
  when nil
    # skip
  when "branch"
    url.path = url.path.sub('/browse', '/branches')
  else
    url.path = url.path.sub('/browse', '/commits')
    url.query =
      URI.encode_www_form([["until", "refs/heads/#{options['branch']}"]])
  end

  case options[:commit]
  when nil
    # skip
  when "commit"
    abort 'You must specify commit hash.'
  else
    url.path = url.path.sub('/browse', "/commits/#{options['commit']}")
  end

  case options[:"pull-request"]
  when nil
    # skip
  when "pull-request"
    url.path = url.path.sub('/browse', "/pull-requests")
  else
    url.path = url.path.sub('/browse', "/pull-requests/#{options[:'pull-request']}/overview")
  end

  Launchy.open(url, debug: config.verbose)
end
clone(arg, dir=nil) click to toggle source
# File lib/sah/cli.rb, line 119
def clone(arg, dir=nil)
  repository_slug, project_key = arg.split("/").reverse
  project_key ||= "~#{config.user}"
  res = api.show_repository(project_key, repository_slug)
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end
  repository = res.body
  remote_url =
    repository["links"]["clone"].find{ |e| e["name"] == config.protocol }["href"]
  options = ["clone", remote_url]
  options << dir if dir
  system "git", *options
end
create(arg=nil) click to toggle source
# File lib/sah/cli.rb, line 148
def create(arg=nil)
  project_key = (arg || "~#{config.user}")
  repository_slug = (
    options[:name] || File.basename(`git rev-parse --show-toplevel`).chomp
  )
  res = api.create_repository(project_key, repository_slug)
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end
  remote_url =
    res.body["links"]["clone"].find{ |e| e["name"] == config.protocol }["href"]
  system "git", "remote", "add", "origin", remote_url
end
fork(arg=nil) click to toggle source
# File lib/sah/cli.rb, line 178
def fork(arg=nil)
  if arg
    project_key, repository_slug = arg.split("/")
  else
    remote_url = `git config --get remote.origin.url`.chomp
    remote_url.match %r%/([^/]+)/([^/]+?)(?:\.git)?$%
    project_key, repository_slug = $1, $2
  end
  res = api.fork_repository(project_key, repository_slug, options[:name])
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end
end
project(arg=nil) click to toggle source
# File lib/sah/cli.rb, line 200
def project(arg=nil)
  if arg
    res = api.show_project(arg)
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    project = res.body
    puts formatter.render(project, headers: false)
  else
    res = api.list_project
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    projects = res.body["values"].sort_by{|e| e["id"].to_i }
    puts formatter.render(projects, fields: %w(id key name description))
  end
end
pull_request() click to toggle source
# File lib/sah/cli.rb, line 236
def pull_request
  source_project, source_repository, source_branch = nil, nil, nil
  if options[:source]
    m = options[:source].match(%r{^([^/:]+)/([^/:]+):([^:]+)$})
    if m.nil?
      abort "Invalid format: --source #{options[:source]}"
    end
    source_project, source_repository, source_branch = $1, $2, $3
  else
    remote_url = `git config --get remote.origin.url`.chomp
    remote_url.match %r%/([^/]+)/([^/]+?)(?:\.git)?$%
    source_project, source_repository = $1, $2
    source_branch = current_branch
  end
  source = {project: source_project, repository: source_repository,
            branch: source_branch}

  target_project, target_repository, target_branch = nil, nil, nil
  if options[:target]
    m = options[:target].match(%r{^([^/:]+)/([^/:]+):([^:]+)$})
    if m.nil?
      abort "Invalid format: --target #{options[:target]}"
    end
    target_project, target_repository, target_branch = $1, $2, $3
  else
    upstream = upstream_repository
    target_project = upstream["origin"]["project"]["key"]
    target_repository = upstream["origin"]["slug"]
    res = api.show_branches(target_project, target_repository)
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    branches = res.body
    target_branch = branches["values"].find{|b| b["isDefault"] }["displayId"]
  end
  target = {project: target_project, repository: target_repository,
            branch: target_branch}

  puts "%s/%s:%s => %s/%s:%s" % [
    source[:project], source[:repository], source[:branch],
    target[:project], target[:repository], target[:branch],
  ]

  title = options[:title] || (
    puts "Edit title... (press enter key)"
    STDIN.gets
    open_editor.strip
  )
  description = options[:description] || (
    puts "Edit description... (press enter key)"
    STDIN.gets
    open_editor.strip
  )
  reviewers = options[:reviewer] || []

  res = api.create_pull_request source, target, title, description, reviewers
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end
  puts res.body["links"]["self"].first["href"]
end
repository(arg) click to toggle source
# File lib/sah/cli.rb, line 306
def repository(arg)
  project_key, repository_slug = arg.split("/")
  if repository_slug
    res = api.show_repository(project_key, repository_slug)
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    repository = res.body
    puts formatter.render(repository, headers: false)
  else
    res = api.list_repository(project_key)
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    repositories = (res.body["values"] || []).sort_by{|e| e["id"].to_i }
    puts formatter.render(repositories, fields: %w(id slug name))
  end
end
upstream() click to toggle source
# File lib/sah/cli.rb, line 338
def upstream
  upstream_url =
    upstream_repository["origin"]["links"]["clone"].find{ |e| e["name"] == config.protocol }["href"]

  if options[:"add-remote"]
    remote_name = options["remote-name"]
    remote_name = config.upstream_remote_name if remote_name.nil? || remote_name.empty?
    system "git", "remote", "add", remote_name, upstream_url
    if config.upstream_fetch_pull_request || options[:"fetch-pull-request"]
        %x(git config --add remote.#{remote_name}.fetch \
             '+refs/pull-requests/*:refs/remotes/#{remote_name}/pull-requests/*')
    end
    if config.upstream_prevent_push || options[:"prevent-push"]
      %x(git remote set-url --push #{remote_name} "")
    end
  else
    puts upstream_url
  end
end
user(arg=nil) click to toggle source
# File lib/sah/cli.rb, line 366
def user(arg=nil)
  if arg
    res = api.show_user(arg)
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    user = res.body
    puts formatter.render(user, headers: false)
  else
    res = api.list_user
    if res.body.key? "errors"
      abort res.body["errors"].first["message"]
    end
    users = (res.body["values"] || []).sort_by{|e| e["id"].to_i }
    puts formatter.render(users, fields: %w(id slug name displayName))
  end
end
version() click to toggle source
# File lib/sah/cli.rb, line 385
def version
  puts VERSION
end

Private Instance Methods

api() click to toggle source
# File lib/sah/cli.rb, line 397
def api
  @api ||= API.new(config)
end
config() click to toggle source
# File lib/sah/cli.rb, line 391
def config
  @config ||= Config.new(options[:profile],
                         verbose: options[:verbose],
                         format: options[:format])
end
current_branch() click to toggle source
# File lib/sah/cli.rb, line 412
def current_branch
  %x(git rev-parse --abbrev-ref HEAD).chomp
end
formatter() click to toggle source
# File lib/sah/cli.rb, line 401
def formatter
  @formatter ||= Formatter.new(format: options[:format])
end
open_editor() click to toggle source
# File lib/sah/cli.rb, line 405
def open_editor
  tmp = Tempfile.new('sah')
  editor = ENV['GIT_EDITOR'] || ENV['EDITOR'] || 'vi'
  system(editor, tmp.path)
  File.open(tmp.path).read
end
remote(name) click to toggle source
# File lib/sah/cli.rb, line 420
def remote(name)
  %x(git remote show "#{name}").scan(/(?<=Fetch URL: ).*?\.git/).first
end
remotes() click to toggle source
# File lib/sah/cli.rb, line 416
def remotes
  Open3.capture3('git remote').first.split
end
upstream_repository() click to toggle source
# File lib/sah/cli.rb, line 424
def upstream_repository
  remote_url = `git config --get remote.origin.url`.chomp
  remote_url.match %r%/([^/]+)/([^/]+?)(?:\.git)?$%
  project, repository = $1, $2

  res = api.show_repository(project, repository)
  if res.body.key? "errors"
    abort res.body["errors"].first["message"]
  end

  repository = res.body
  unless repository.key? "origin"
    abort "Upstream repos does not exist."
  end

  repository
end