module OpsAsk::Helpers

Public Instance Methods

asks_in_current_sprint() click to toggle source
# File lib/opsask/helpers.rb, line 122
def asks_in_current_sprint
  asks_in_sprint current_sprint_num
end
asks_in_sprint(num) click to toggle source
# File lib/opsask/helpers.rb, line 126
def asks_in_sprint num
  return [] unless logged_in?
  issues = []
  query = normalized_jql("labels in (#{sprint_label_prefix}#{num})", project: nil)
  @jira_client.Issue.jql(query, max_results: 500).each do |i|
    issues << i.attrs
  end
  return issues
end
classes_for(jira) click to toggle source
# File lib/opsask/helpers.rb, line 287
def classes_for jira
  raw_classes_for(jira).join(' ')
end
components() click to toggle source
# File lib/opsask/helpers.rb, line 414
def components
  return @project.components.map(&:name).select { |c| c =~ /^Ops/ }
end
create_jira(duedate, component, summary, description, assign_to_me, epic, ops_only) click to toggle source
# File lib/opsask/helpers.rb, line 370
def create_jira duedate, component, summary, description, assign_to_me, epic, ops_only
  assignee   = assign_to_me ? @me : settings.config[:assignee]
  components = []
  components = [ { name: component } ] unless component
  labels     = [ 'OpsAsk', current_sprint_name ].compact
  labels    << 'OpsOnly' if ops_only
  labels    << settings.config[:require_label] if settings.config[:require_label]
  data       = {
    fields: {
      project: { key: settings.config[:project_key] },
      issuetype: { name: settings.config[:issue_type] },
      versions: [ { name: settings.config[:version] } ],
      duedate: duedate,
      summary: summary,
      description: description,
      components: components,
      assignee: { name: assignee },
      reporter: { name: @me },
      labels: labels,
      customfield_10002: 1, # Story Points = 1
      customfield_10040: { id: '-1' } # Release Priority = None
    }
  }

  url = "#{settings.config[:jira_url]}/rest/api/latest/issue"
  curl_request = Curl::Easy.http_post(url, data.to_json) do |curl|
    curl.headers['Accept'] = 'application/json'
    curl.headers['Content-Type'] = 'application/json'
    curl.http_auth_types = :basic
    curl.username = settings.config[:jira_user]
    curl.password = settings.config[:jira_pass]
    curl.verbose  = true
  end

  raw_response = curl_request.body_str
  begin
    response = JSON::parse raw_response
  rescue
    $stderr.puts "Failed to parse response from JIRA: #{raw_response}"
    return nil
  end
  return response
end
current_sprint(keys=[ 'sprintsData', 'sprints', 0 ]) click to toggle source
# File lib/opsask/helpers.rb, line 218
def current_sprint keys=[ 'sprintsData', 'sprints', 0 ]
  url = "#{settings.config[:jira_url]}/rest/greenhopper/1.0/xboard/work/allData.json?rapidViewId=#{settings.config[:agile_board]}"
  curl_request = Curl::Easy.http_get(url) do |curl|
    curl.headers['Accept'] = 'application/json'
    curl.headers['Content-Type'] = 'application/json'
    curl.http_auth_types = :basic
    curl.username = settings.config[:jira_user]
    curl.password = settings.config[:jira_pass]
    curl.verbose  = true
  end

  raw_response = curl_request.body_str
  begin
    data = JSON::parse(raw_response)
    keys.each { |k| data = data[k] }
    return data unless data.nil?
  rescue
    $stderr.puts "Failed to parse response from JIRA: #{raw_response}"
  end
  get_sprint(nil, sprints.last['id'])
end
current_sprint_ends(sprint=current_sprint) click to toggle source
# File lib/opsask/helpers.rb, line 199
def current_sprint_ends sprint=current_sprint
  if ends = sprint['endDate']
    ends = DateTime.strptime(ends, '%d/%b/%y %l:%M %p')
    ends.strftime('%Y/%m/%d')
  end
end
current_sprint_id(sprint=current_sprint) click to toggle source
# File lib/opsask/helpers.rb, line 214
def current_sprint_id sprint=current_sprint
  sprint.nil? ? nil : sprint['id']
end
current_sprint_name(sprint=current_sprint) click to toggle source
# File lib/opsask/helpers.rb, line 206
def current_sprint_name sprint=current_sprint
  sprint.nil? ? nil : sprint['name'].gsub(/\s+/, '')
end
current_sprint_num(sprint=current_sprint) click to toggle source
# File lib/opsask/helpers.rb, line 210
def current_sprint_num sprint=current_sprint
  sprint.nil? ? nil : sprint['name'].gsub(/\D+/, '')
end
current_sprint_starts(sprint=current_sprint) click to toggle source
# File lib/opsask/helpers.rb, line 192
def current_sprint_starts sprint=current_sprint
  if starts = sprint['startDate']
    starts = DateTime.strptime(starts, '%d/%b/%y %l:%M %p')
    starts.strftime('%Y/%m/%d')
  end
end
date_for_new_jiras(really=false, depth=0) click to toggle source
# File lib/opsask/helpers.rb, line 339
def date_for_new_jiras really=false, depth=0
  logger.debug 'date_for_new_jiras really=%s' % really.inspect
  if now.hour < settings.config[:cutoff_hour] || its_the_weekend?
    return today if room_for_new_jiras_for? today, really
  end

  # Remove the two-day limit [OPS-1862]
  n = 0 # days from now
  loop do
    n += 1 # first call n=1, tomorrow
    next_day = today n * one_day
    logger.debug 'date_for_new_jiras next_day=%s' % next_day.inspect
    return next_day if room_for_new_jiras_for? next_day, really
  end
end
epics() click to toggle source
# File lib/opsask/helpers.rb, line 443
def epics
  data = {
    jql: normalized_jql("type = Epic"),
    startAt: 0,
    maxResults: 1000
  }

  url = "#{settings.config[:jira_url]}/rest/api/latest/search"
  curl_request = Curl::Easy.http_post(url, data.to_json) do |curl|
    curl.headers['Accept'] = 'application/json'
    curl.headers['Content-Type'] = 'application/json'
    curl.http_auth_types = :basic
    curl.username = settings.config[:jira_user]
    curl.password = settings.config[:jira_pass]
    curl.verbose  = true
  end

  raw_response = curl_request.body_str
  begin
    response = JSON::parse raw_response
  rescue
    $stderr.puts "Failed to parse response from JIRA: #{raw_response}"
    return nil
  end
  return response['issues'].map do |epic|
    {
      'key' => epic['key'],
      'name' => epic['fields']['customfield_10351'] || epic['fields']['summary']
    }
  end
end
get_sprint(num, id=nil) click to toggle source
# File lib/opsask/helpers.rb, line 165
def get_sprint num, id=nil
  unless sprint_id = id
    sprint = sprints.select { |s| s['name'] == "#{sprint_prefix} #{num}" }
    sprint_id = sprint.first['id']
  end
  url = "#{settings.config[:jira_url]}/rest/greenhopper/1.0/rapid/charts/sprintreport?rapidViewId=#{settings.config[:agile_board]}&sprintId=#{sprint_id}"
  curl_request = Curl::Easy.http_get(url) do |curl|
    curl.headers['Accept'] = 'application/json'
    curl.headers['Content-Type'] = 'application/json'
    curl.http_auth_types = :basic
    curl.username = settings.config[:jira_user]
    curl.password = settings.config[:jira_pass]
    curl.verbose  = true
  end

  raw_response = curl_request.body_str
  begin
    data = JSON::parse(raw_response)
    contents = data.delete('contents')
    data = data.delete('sprint')
    return data.merge(contents)
  rescue
    $stderr.puts "Failed to parse response from JIRA: #{raw_response}"
  end
  return {}
end
holiday?(date) click to toggle source
# File lib/opsask/helpers.rb, line 325
def holiday? date
  date = date.split('-',3).map(&:to_i)
  date = Date.civil *date
  Holidays.on(date, :us).any?
end
issues_for(date) click to toggle source
# File lib/opsask/helpers.rb, line 315
def issues_for date
  jiras_for(date).sort_by do |jira|
    sorting_key_for(jira)
  end.reverse
end
issues_for_days(n, start=0) click to toggle source
# File lib/opsask/helpers.rb, line 303
def issues_for_days n, start=0
  now = Time.new.to_date
  last = start + n
  start.upto(last-1).inject({}) do |h,i|
    date = (now + i).strftime('%Y-%m-%d')
    h[date] = jiras_for(date).sort_by do |jira|
      sorting_key_for(jira)
    end.reverse
    h
  end
end
items_in_current_sprint() click to toggle source
# File lib/opsask/helpers.rb, line 107
def items_in_current_sprint
  items_in_sprint current_sprint_num
end
items_in_sprint(num) click to toggle source
# File lib/opsask/helpers.rb, line 111
def items_in_sprint num
  return [] unless logged_in?
  issues = []
  id = get_sprint(num)['id']
  query = normalized_jql("sprint = #{id}", project: nil)
  @jira_client.Issue.jql(query, max_results: 500).each do |i|
    issues << i.attrs
  end
  return issues
end
its_the_weekend?() click to toggle source
# File lib/opsask/helpers.rb, line 321
def its_the_weekend?
  now.saturday? || now.sunday?
end
jira_count_for(date, really=false) click to toggle source
# File lib/opsask/helpers.rb, line 269
def jira_count_for date, really=false
  jiras_for(date, really).length
end
jira_count_for_today(really=false ;) click to toggle source
# File lib/opsask/helpers.rb, line 273
def jira_count_for_today really=false ; jira_count_for(today, really) end
jira_count_for_tomorrow(really=false ;) click to toggle source
# File lib/opsask/helpers.rb, line 275
def jira_count_for_tomorrow really=false ; jira_count_for(tomorrow, really) end
jiras_for(date, really=false) click to toggle source
# File lib/opsask/helpers.rb, line 260
def jiras_for date, really=false
  return [] unless logged_in?
  if !ops? || really
    @jira_client.Issue.jql normalized_jql("due = #{date} and labels in (OpsAsk) and labels not in (OpsOnly)"), max_results: 100
  else
    @jira_client.Issue.jql normalized_jql("due = #{date} and labels in (OpsAsk)"), max_results: 100
  end
end
logged_in?() click to toggle source
# File lib/opsask/helpers.rb, line 7
def logged_in?
  !!session[:jira_auth]
end
name_for_coming_week() click to toggle source
# File lib/opsask/helpers.rb, line 256
def name_for_coming_week
  todays_date.strftime 'Week of %-d %b'
end
name_for_today(offset=0) click to toggle source
# File lib/opsask/helpers.rb, line 248
def name_for_today offset=0
  todays_date(offset).strftime '%A %-d %b'
end
name_for_tomorrow() click to toggle source
# File lib/opsask/helpers.rb, line 252
def name_for_tomorrow
  name_for_today(one_day)
end
no_ops(jiras) click to toggle source
# File lib/opsask/helpers.rb, line 11
def no_ops jiras
  jiras.reject do |jira|
    jira.fields['labels'].include? 'OpsOnly'
  end
end
normalized_jql(query, \ project: settings.config[:project_name], \ require_label: settings.config[:require_label], ignore_label: settings.config[:ignore_label]) click to toggle source
# File lib/opsask/helpers.rb, line 475
def normalized_jql query, \
  project: settings.config[:project_name], \
  require_label: settings.config[:require_label],
  ignore_label: settings.config[:ignore_label]
# ...
  query += %Q| and project = #{project}| if project
  query += %Q| and labels = #{require_label}| if require_label
  query += %Q| and (labels != #{ignore_label} OR labels is empty)| if ignore_label
  return query
end
now() click to toggle source
# File lib/opsask/helpers.rb, line 29
def now
  Time.now # + 3 * one_day # DEBUG
end
one_day() click to toggle source
# File lib/opsask/helpers.rb, line 25
def one_day
  1 * 24 * 60 * 60 # Day * Hour * Minute * Second = Seconds / Day
end
ops?() click to toggle source
# File lib/opsask/helpers.rb, line 17
def ops?
  return false unless logged_in?
  @myself['groups']['items'].each do |i|
    return true if i['name'] == settings.config[:ops_group]
  end
  return false
end
outlier_issues(sprint, num) click to toggle source
# File lib/opsask/helpers.rb, line 98
def outlier_issues sprint, num
  return [] unless logged_in?
  issues = []
  @jira_client.Issue.jql(outlier_query(sprint, num), max_results: 500).each do |i|
    issues << i.attrs
  end
  return issues
end
outlier_query(sprint, num) click to toggle source
# File lib/opsask/helpers.rb, line 88
def outlier_query sprint, num
  starts = current_sprint_starts sprint
  ends   = current_sprint_ends sprint
  normalized_jql("(sprint != #{sprint['id']} or sprint is empty) and (labels != \"#{sprint_label_prefix}#{num}\" OR labels is empty) and resolved >= \"#{starts}\" and resolved <= \"#{ends}\"")
end
raw_classes_for(jira) click to toggle source
# File lib/opsask/helpers.rb, line 277
def raw_classes_for jira
  classes = [ jira.fields['resolution'].nil? ? 'open' : 'closed' ]
  if assignee = jira.fields['assignee']
    if name = assignee['name']
      classes << name.downcase.gsub(/\W+/, '')
    end
  end
  return classes
end
room_for_new_jiras_for?(date, really=false) click to toggle source
# File lib/opsask/helpers.rb, line 331
def room_for_new_jiras_for? date, really=false
  return true  if params[:force]
  return false if params[:full]
  return false if holiday? date
  return true  if ops? && !really
  jira_count_for(date, really) < settings.config[:queue_size]
end
sorting_key_for(jira) click to toggle source
# File lib/opsask/helpers.rb, line 291
def sorting_key_for jira
  rcs = raw_classes_for(jira)
  idx = 1
  idx = 2 if rcs.include? 'denimcores'
  idx = 0 if rcs.include? 'closed'
  return "#{idx}-#{jira.key}"
end
sprint_label_prefix() click to toggle source
# File lib/opsask/helpers.rb, line 161
def sprint_label_prefix
  sprint_prefix.gsub(/\s+/, '')
end
sprint_prefix() click to toggle source
# File lib/opsask/helpers.rb, line 157
def sprint_prefix
  settings.config[:sprint_prefix] ||= 'Sprint'
end
sprints() click to toggle source
# File lib/opsask/helpers.rb, line 136
def sprints
  url = "#{settings.config[:jira_url]}/rest/greenhopper/1.0/sprintquery/#{settings.config[:agile_board]}"
  curl_request = Curl::Easy.http_get(url) do |curl|
    curl.headers['Accept'] = 'application/json'
    curl.headers['Content-Type'] = 'application/json'
    curl.http_auth_types = :basic
    curl.username = settings.config[:jira_user]
    curl.password = settings.config[:jira_pass]
    curl.verbose  = true
  end

  raw_response = curl_request.body_str
  begin
    data = JSON::parse(raw_response)
    return data['sprints']
  rescue
    $stderr.puts "Failed to parse response from JIRA: #{raw_response}"
  end
  return nil
end
stats_for(issues, resolved_link, unresolved_link, unsized_link) click to toggle source
# File lib/opsask/helpers.rb, line 40
def stats_for issues, resolved_link, unresolved_link, unsized_link
  return {} unless logged_in?
  return {} unless issues

  unsized_issues, resolved_issues, unresolved_issues = [], [], []

  issues.map! do |i|
    key = i['key']
    status = i['fields']['status']['name']
    resolution = i['fields']['resolution']['name'] rescue nil
    points = i['fields']['customfield_10002'].to_i

    issue = {
      key: key,
      status: status,
      resolution: resolution,
      points: points
    }

    if i['fields']['customfield_10002'].nil?
      unsized_issues << issue
    end

    if resolution.nil?
      unresolved_issues << issue
    else
      resolved_issues << issue
    end
  end

  {
    resolved: {
      number: resolved_issues.size,
      points: resolved_issues.map { |i| i[:points] }.reduce(0, :+),
      link: resolved_link
    },
    unresolved: {
      number: unresolved_issues.size,
      points: unresolved_issues.map { |i| i[:points] }.reduce(0, :+),
      link: unresolved_link
    },
    unsized: {
      number: unsized_issues.size,
      link: unsized_link
    }
  }
end
straggling_issues() click to toggle source
# File lib/opsask/helpers.rb, line 430
def straggling_issues
  return [] unless logged_in?
  constraints = [
    "due < #{today}",
    "labels in (OpsAsk)",
    "resolution = unresolved",
    "assignee != denimcores"
  ].join(' and ')
  @jira_client.Issue.jql(normalized_jql(constraints), max_results: 100).sort_by do |jira|
    sorting_key_for(jira)
  end.reverse
end
today(offset=0) click to toggle source
# File lib/opsask/helpers.rb, line 240
def today offset=0
  todays_date(offset).strftime '%Y-%m-%d'
end
today?(date) click to toggle source
# File lib/opsask/helpers.rb, line 299
def today? date
  Time.new.to_date.strftime('%Y-%m-%d') == date
end
todays_date(offset=0) click to toggle source
# File lib/opsask/helpers.rb, line 33
def todays_date offset=0
  date  = now + offset
  date += one_day if date.saturday?
  date += one_day if date.sunday?
  return date
end
tomorrow() click to toggle source
# File lib/opsask/helpers.rb, line 244
def tomorrow
  today(one_day)
end
untracked_issues() click to toggle source
# File lib/opsask/helpers.rb, line 418
def untracked_issues
  return [] unless logged_in?
  constraints = [
    "due < #{today}",
    "resolution = unresolved",
    "assignee = denimcores"
  ].join(' and ')
  @jira_client.Issue.jql(normalized_jql(constraints), max_results: 100).sort_by do |jira|
    sorting_key_for(jira)
  end.reverse
end
validate_jira_params() click to toggle source
# File lib/opsask/helpers.rb, line 355
def validate_jira_params
  flash[:error] = []
  flash[:error] << 'Summary is required' if params['jira-summary'].empty?
  redirect '/' unless flash[:error].empty?
  return [
    params['jira-component'],
    params['jira-summary'],
    params['jira-description'],
    !!params['jira-assign_to_me'],
    nil,
    !!params['jira-ops_only'],
    params['jira-datepicker']
  ]
end