class Manifestly::CLI

Public Class Methods

exit_on_failure?() click to toggle source

github.com/erikhuda/thor/issues/244 stackoverflow.com/a/18490048/1664216

# File lib/manifestly/cli.rb, line 17
def self.exit_on_failure?
  true
end
file_option(description_action=nil) click to toggle source
# File lib/manifestly/cli.rb, line 51
def self.file_option(description_action=nil)
  description = "The local manifest file"
  description += " to #{description_action}" if description_action

  method_option :file,
                desc: description,
                type: :string,
                banner: '',
                required: true
end
repo_file_option(description=nil) click to toggle source
# File lib/manifestly/cli.rb, line 42
def self.repo_file_option(description=nil)
  description ||= "The name of the repository file, with path if applicable"
  method_option :repo_file,
                desc: description,
                type: :string,
                banner: '',
                required: true
end
repo_option() click to toggle source
# File lib/manifestly/cli.rb, line 34
def self.repo_option
  method_option :repo,
                desc: "The github manifest repository to use, given as 'organization/reponame'",
                type: :string,
                banner: '',
                required: true
end
search_paths_option() click to toggle source

Common command line options

# File lib/manifestly/cli.rb, line 25
def self.search_paths_option
  method_option :search_paths,
                desc: "A list of paths where git repositories can be found",
                type: :array,
                required: false,
                banner: '',
                default: '.'
end

Public Instance Methods

apply() click to toggle source
# File lib/manifestly/cli.rb, line 224
def apply
  begin
    manifest = load_manifest(file: options[:file]) || error!
    manifest.items.each{ |item| item.checkout_commit!(options[:update]) }
  rescue Manifestly::ManifestItem::MultipleSameNameRepositories => e
    say "Multiple repositories have the same name (#{e.message}) so we " +
        "can't apply the manifest. Try limiting the search_paths or " +
        "separate the duplicates."
    error!
  rescue Manifestly::Repository::CommitNotPresent => e
    say "Could not find commit #{e.sha} in repository #{e.repository.github_name_or_path}. " +
        "Try running again with the `--update` option."
    error!
  end


end
create() click to toggle source
# File lib/manifestly/cli.rb, line 187
def create
  manifest = if options[:based_on]
    load_manifest(file: options[:based_on]) || error!
  else
    Manifest.new
  end

  if options[:interactive]
    present_create_menu(manifest)
  else
    repos_to_remove = get_repos_from_options(options[:remove])
    repos_to_remove.each do |repo_to_remove|
      manifest.remove_repository(repo_to_remove)
    end

    repos_to_add = get_repos_from_options(options[:add])
    repos_to_add.each do |repo_to_add|
      manifest.add_repository(repo_to_add)
    end

    write_manifest(manifest, false)
  end
end
diff() click to toggle source
# File lib/manifestly/cli.rb, line 449
def diff
  repository = Repository.load_cached(options[:repo], update: true)
  from_manifest = load_manifest(repository: repository, sha: options[:from_sha])
  to_manifest = load_manifest(repository: repository, sha: options[:to_sha])

  if !from_manifest || !to_manifest
    say("Could not load the 'from' manifest so cannot continue with the diff.") if !from_manifest
    say("Could not load the 'to' manifest so cannot continue with the diff.") if !to_manifest
    error!
  end

  manifest_diff = ManifestDiff.new(from_manifest, to_manifest)
  manifest_diff.to_markdown
end
download() click to toggle source
# File lib/manifestly/cli.rb, line 284
def download
  repository = Repository.load_cached(options[:repo], update: true)

  commit_content = begin
    repository.get_commit_content(options[:sha])
  rescue Manifestly::Repository::CommitNotPresent
    say('That SHA is invalid')
    error!
  end

  save_as = options[:save_as]

  if save_as.nil?
    # Get the whole SHA so filenames are consistent
    sha = repository.find_commit(options[:sha]).sha
    save_as = "#{sha[0..9]}.manifest"
  end

  File.open(save_as, 'w') { |file| file.write(commit_content) }
  say "Downloaded #{save_as}.  #{commit_content.split("\n").count} line(s)."
end
find() click to toggle source
# File lib/manifestly/cli.rb, line 415
def find
  repository = Repository.load_cached(options[:repo], update: true)
  shas = repository.get_shas_with_tag(tag: options[:tag], file: options[:repo_file])
  shas = shas.take(options[:limit].to_i) if options[:limit]
  say shas.uniq.join("\n")
end
list() click to toggle source
# File lib/manifestly/cli.rb, line 315
def list
  repository = Repository.load_cached(options[:repo], update: true)
  commits = repository.file_commits(options[:repo_file])
  present_list_menu(commits, show_author: true)
end
tag() click to toggle source
# File lib/manifestly/cli.rb, line 365
def tag
  repository = Repository.load_cached(options[:repo], update: true)

  begin
    repository.tag_scoped_to_file(
      tag: options[:tag], sha: options[:sha], message: options[:message], push: true
    )
  rescue Manifestly::Repository::ShaAlreadyTagged
  end
end
upload() click to toggle source
# File lib/manifestly/cli.rb, line 256
def upload
  repository = Repository.load_cached(options[:repo], update: true)

  begin
    repository.push_file!(options[:file], options[:repo_file], options[:message])
  rescue Manifestly::Repository::ManifestUnchanged
  ensure
    say repository.current_commit
  end
end
version() click to toggle source
# File lib/manifestly/cli.rb, line 465
def version
  say "Manifestly #{Manifestly::VERSION} - https://github.com/openstax/manifestly"
end

Protected Instance Methods

add_repositories(manifest) click to toggle source
# File lib/manifestly/cli.rb, line 627
def add_repositories(manifest)
  puts "\n"

  selected_repositories = select(
    repository_choices(manifest),
    hide_shortcuts: true,
    choice_name: "repository",
    question: "\nChoose which repositories you want in the manifest (e.g. '0 2 5') or (r)eturn:",
    no_selection: 'r'
  )

  return if selected_repositories.nil?

  selected_repositories.each do |repository|
    begin
      manifest.add_repository(repository)
    rescue Manifestly::Repository::NoCommitsError => e
      say "Cannot add #{repository.display_name} because it doesn't have any commits."
    end
  end
end
ask_and_split(message) click to toggle source
# File lib/manifestly/cli.rb, line 579
def ask_and_split(message)
  answer = ask(message).downcase.split

  if answer.empty?
    say('No response provided, please try again.')
    return false
  end

  [answer.shift, answer]
end
available_repositories() click to toggle source
# File lib/manifestly/cli.rb, line 744
def available_repositories
  @available_repositories ||= (repository_search_paths.flat_map do |path|
    directories_under(path).collect{|dir| Manifestly::Repository.load(dir)}
  end).compact
end
convert_args_to_indices(args, select_one=false) click to toggle source
# File lib/manifestly/cli.rb, line 590
def convert_args_to_indices(args, select_one=false)
  if args.empty?
    say('You must specify index(es) of manifest items after the action, e.g. "r 2 7".')
    false
  elsif select_one && args.size > 1
    say('You can only specify one manifest index for this action.')
    false
  elsif args.any? {|si| !si.is_i?}
    say('All specified indices must be integers.')
    false
  else
    args.collect{|index| index.to_i}
  end
end
directories_under(path) click to toggle source
# File lib/manifestly/cli.rb, line 750
def directories_under(path)
  entries = Dir.entries(path)
  entries.reject!{ |dir| dir =='.' || dir == '..' }

  full_entry_paths = entries.collect{|entry| File.join(path, entry)}
  full_entry_paths.reject{ |path| !File.directory?(path) }
end
dynamic_height() click to toggle source
# File lib/manifestly/cli.rb, line 775
def dynamic_height
  %x{stty size 2>/dev/null}.split[0].to_i
end
error!() click to toggle source
# File lib/manifestly/cli.rb, line 801
def error!
  exit 1
end
find_dir(path) click to toggle source

Finds the provided directory looking first to see if it is an absolute directory, and then looking for it on the search paths

# File lib/manifestly/cli.rb, line 790
def find_dir(path)
  return path if path.starts_with?('/') && Dir.exist?(path)

  repository_search_paths.each do |search_path|
    combined_path = File.join(search_path, path)
    return combined_path if Dir.exist?(combined_path)
  end

  nil
end
get_repos_from_options(options) click to toggle source
# File lib/manifestly/cli.rb, line 779
def get_repos_from_options(options)
  if options.include?("all")
    available_repositories
  else
    dirs = options.collect{|option| find_dir(option)}.compact
    dirs.collect{|dir| Repository.load(dir)}
  end
end
load_manifest(options={}) click to toggle source
# File lib/manifestly/cli.rb, line 605
def load_manifest(options={})
  begin
    if options[:file]
      Manifest.read_file(options[:file], available_repositories)
    elsif options[:repository] && options[:sha]
      content = options[:repository].get_commit_content(options[:sha])
      Manifest.read_string(content, available_repositories).tap do |manifest|
        manifest.manifest_repository = options[:repository]
        manifest.manifest_sha = options[:sha]
        manifest.manifest_file = options[:repository].get_commit_filename(options[:sha])
      end
    else
      say "Missing arguments when trying to load manifest"
      nil
    end
  rescue Manifestly::ManifestItem::RepositoryNotFound => e
    say "Couldn't find the #{e.message} repository listed in the manifest.  " +
        "Might need to specify --search-paths."
    nil
  end
end
present_commit_menu(manifest_item, options={}) click to toggle source
# File lib/manifestly/cli.rb, line 519
def present_commit_menu(manifest_item, options={})
  page = 0

  while true
    options[:page] = page
    print_commits(manifest_item.repository.commits, options)

    action, args = ask_and_split(
      '(n)ext or (p)revious page; (c)hoose index; (m)anual SHA entry; (t)oggle PRs only; (r)eturn:'
    ) || next

    case action
    when 'n'
      page += 1
    when 'p'
      page -= 1
    when 'c'
      indices = convert_args_to_indices(args, true) || next
      manifest_item.set_commit_by_index(indices.first)
      break
    when 'm'
      sha = args.first
      begin
        manifest_item.set_commit_by_sha(sha)
        break
      rescue CommitNotPresent
        say('That SHA is invalid')
        next
      end
    when 't'
      manifest_item.repository.toggle_prs_only
      page = 0
    when 'r'
      break
    end
  end
end
present_create_menu(manifest) click to toggle source
# File lib/manifestly/cli.rb, line 471
def present_create_menu(manifest)
  while true
    print_manifest(manifest)

    action, args = ask_and_split(
      '(a)dd or (r)emove repository; (f)etch; (c)hoose commit; (w)rite manifest; (q)uit:'
    ) || next

    case action
    when 'a'
      add_repositories(manifest)
    when 'r'
      indices = convert_args_to_indices(args) || next
      manifest.remove_repositories_by_index(indices)
    when 'f'
      progress = ProgressBar.create(title: "Fetching", total: manifest.items.count)
      manifest.items.each do |item|
        item.fetch
        progress.increment
      end
    when 'c'
      indices = convert_args_to_indices(args, true) || next
      present_commit_menu(manifest[indices.first])
    when 'w'
      write_manifest(manifest, true)
      break
    when 'q!'
      break
    when 'q'
      break if yes?('Are you sure you want to quit? (y or yes):')
    end
  end
end
present_list_menu(commits, options={}) click to toggle source
# File lib/manifestly/cli.rb, line 557
def present_list_menu(commits, options={})
  page = 0

  while true
    options[:page] = page
    print_commits(commits, options)

    action, args = ask_and_split(
      '(n)ext or (p)revious page; (q)uit:'
    ) || next

    case action
    when 'n'
      page += 1
    when 'p'
      page -= 1
    when 'q'
      break
    end
  end
end
print_commits(commits, options={}) click to toggle source
print_manifest(manifest) click to toggle source
repository_choices(except_in_manifest=nil) click to toggle source
# File lib/manifestly/cli.rb, line 737
def repository_choices(except_in_manifest=nil)
  choices = available_repositories.collect{|repo| {display: repo.display_name, value: repo}}
  except_in_manifest.nil? ?
    choices :
    choices.reject{|choice| except_in_manifest.includes?(choice[:value])}
end
repository_search_paths() click to toggle source
# File lib/manifestly/cli.rb, line 758
def repository_search_paths
  [options[:search_paths]].flatten
end
terminal_height() click to toggle source
# File lib/manifestly/cli.rb, line 762
def terminal_height
  # This code was derived from Thor and from Rake, the latter of which is
  # available under MIT-LICENSE Copyright 2003, 2004 Jim Weirich
  if ENV["THOR_ROWS"]
    result = ENV["THOR_ROWS"].to_i
  else
    result = unix? ? dynamic_width : 40
  end
  result < 10 ? 40 : result
rescue
  40
end
write_manifest(manifest, prompt_for_filename=false, filename="") click to toggle source
# File lib/manifestly/cli.rb, line 505
def write_manifest(manifest, prompt_for_filename=false, filename="")
  default_filename = options[:save_as].blank? ?
                       Time.now.strftime("%Y%m%d-%H%M%S") + "-#{::SecureRandom.hex(2)}.manifest" :
                       options[:save_as]

  if prompt_for_filename
    filename = ask("Enter desired manifest filename (ENTER for '#{default_filename}'):")
  end

  filename = default_filename if filename.blank?

  manifest.write(filename, options.slice("full_shas"))
end