Skip to content

Instantly share code, notes, and snippets.

@GregPK
Created May 22, 2024 12:23
Show Gist options
  • Save GregPK/b59be02977b16ec4c4073065f870b6a0 to your computer and use it in GitHub Desktop.
Save GregPK/b59be02977b16ec4c4073065f870b6a0 to your computer and use it in GitHub Desktop.
JIRA script for everyday use
#!/usr/bin/env /home/gregpk/.rbenv/shims/ruby
# This script handles personal check for JIRA tickets.
# Currently it supports the following commands:
# - daily - output and open HTML report about the current tickets
# - breaching - check for breaching issues and notify if there are any
require 'bundler/inline'
require 'json'
require 'optparse'
require 'date'
require 'csv'
gemfile do
source 'https://rubygems.org'
gem 'jira-ruby'
gem 'pry'
end
# Basic objects
Issue = Struct.new(:key, :assignee, :status, :title, :points)
class MyJiraStuff
COMMANDS = %w[daily assess breaching].freeze
attr_accessor :command, :options
def initialize(args)
parse_options(args)
end
def run
case command
when 'daily'
daily
when 'breaching'
breaching
else
raise "Command [#{command}] not implemented yet"
end
end
def breaching
breach_days = 3
resolution_timestamp = (Date.today + breach_days).to_s
q = <<~Q
(project = "BILL" OR project = "ER")
AND assignee IN (currentUser()) AND statusCategory in ("To Do", "In Progress")
AND issuetype != "Epic" AND "Resolution Target[Time stamp]" <= "#{resolution_timestamp}"
ORDER BY created DESC
Q
issues = JiraQuery.new(q, 'Breaching issues').issues
if issues.empty?
puts "No breaching issues found <= [#{resolution_timestamp}]"
return
end
issue_keys = issues.map(&:key).join(', ')
title = 'There are Jira issues assigned to you that are breaching soon'
body = "Issues: \n#{issue_keys}\n"
`notify-send '#{title}' "#{body}"`
puts title
puts messages
end
def daily
stories_query = '(project = "BILL" OR project = "ER") AND assignee IN (currentUser()) AND statusCategory in ("To Do", "In Progress") AND issuetype != "Epic"'
epics_query = '(project = "BILL" OR project = "ER") AND assignee IN (currentUser()) AND statusCategory in ("To Do", "In Progress") AND issuetype = "Epic"'
query_and_report([
JiraQuery.new(stories_query, 'Issues'),
JiraQuery.new(epics_query, 'Epics'),
])
end
Result = Struct.new(:who, :total_points, :bill_points, :er_points, :bill_issues, :er_issues)
private
def parse_options(args)
options = {}
self.command = args.first
opt_parser = OptionParser.new do |opts|
opts.banner = 'Usage: ,j [command] [options]'
opts.on('-sDATE', '--date-start=DATE', 'Start date for comparison') do |n|
options[:date_start] = Date.parse(n)
end
opts.on('-eDATE', '--date-end=DATE', 'End date for comparison') do |n|
options[:date_end] = Date.parse(n)
end
end
opt_parser.parse!(args)
unless options[:date_start]
options[:date_start] = Date.today - (Date.today.day - 1) # first_day_of_month
end
unless options[:date_end]
options[:date_end] = Date.today - (Date.today.day - 1) - 1 >> 1 # last day of month
end
unless COMMANDS.include?(command)
puts <<~HLP
Invalid command:
Available commands: #{COMMANDS.join(', ')}
HLP
end
self.options = options
end
def query_and_report(title_queries)
issue_lists = []
Array(title_queries).each do |tq|
data_stories = `jira list -q '#{tq.query}'`
issue_lists << JiraQuery.new(tq.query, tq.title)
end
report = HTMLReport.new(issue_lists)
report.write_report
report.open_report
report.print_txt_version
end
end
# Responsible for generating HTML reports
class HTMLReport
attr_accessor :str, :file, :story_lists
def initialize(story_lists)
self.story_lists = story_lists
self.str = ''
end
def write_report
str = ''
story_lists.each do |story_list|
str += "<h2>#{story_list.title}</h2>\n"
str += "<ul>\n"
story_list.issues.each do |issue|
verb = case issue.status
when 'To Do' then 'Left'
when 'In Progress' then 'Started on'
when 'In Review' then 'Finished'
else 'Also working on'
end
str += %|<li>#{verb} <a href="https://toptal-core.atlassian.net/browse/#{issue.key}">#{issue.key} (#{issue.title})</a></li>|
end
str += "</ul>\n"
end
self.str = str
write_to_tmp_file
end
def open_report
`google-chrome-stable #{file}`
end
def print_txt_version
story_lists.each do |story_list|
puts "# #{story_list.title}:"
story_list.issues.each do |issue|
puts "[#{issue.key}] #{issue.title}"
end
end
end
private
def write_to_tmp_file
f = File.new('/tmp/jdaily'+Random.new.rand.to_s+'.html', 'w+')
f.write(str)
f.rewind
f.close
self.file = f.path
end
end
class JiraQuery
attr_accessor :query, :title, :client
def initialize(query, title=nil)
@title = title
@query = query
@client = JIRA::Client.new(jira_options)
end
def jira_options
{
site: 'https://toptal-core.atlassian.net/',
context_path: '',
username: '[email protected]',
password: ENV.fetch('JIRA_GEM_AUTH_TOKEN'),
auth_type: :basic
}
end
def issues
hashes = client.Issue.jql(query, max_results: 500)
@issues ||= hashes.map{ |h| data_hash_to_issue(h) }.compact
end
def data_hash_to_issue(issue)
return unless issue.fields['assignee']
Issue.new(
key: issue.key,
title: issue.fields['summary'],
assignee: issue.fields['assignee']['displayName'],
points: issue.fields['customfield_10024'].to_f,
status: issue.fields['status']['name']
)
rescue => e
raise StandardError.new("Problem with parsing #{issue.key}: error: #{e.inspect}")
end
end
MyJiraStuff.new(ARGV).run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment