PIT CLI Options -o (order issues), -D (daily list).

* Added the order issues option (`-o`) to pit-cli. This option allows you to
  specific a sorting criteria for the issues returned. The form of the option is
  `-o <property>,<property>` where the properties can be any properties of the
  issues being sorted. The option supports short one-letter forms of the basic
  properties (id, priority, status, and category).
* Added the daily list mode (activated with the `-D` option). This mode prints
  out the tasks scheduled for today (based on the `scheduled` property, the
  tasks due today (based on he `due` property), the issues which have a reminder
  that is active (based on the `reminder` property), and the remaining open
  issues (those which do not fall in any of the other categories). This mode
  looks through all projects in the given repository and does not do any
  filtering or visual seperation by project.

  The individual sections can be suppressed or singled out by using the
  following options.

    Additive options (if none are given all sections are present).

    * `--dl-scheduled`
    * `--dl-due`
    * `--dl-reminder`
    * `--dl-open`

    Negative options (these suppress a specific section).

    * `--dl-hide-scheduled`
    * `--dl-hide-due`
    * `--dl-hide-reminder`
    * `--dl-hide-open`

  Additive options are useful if you only want one or two sections. Negative
  options are useful if you only want to exclude one or two sections.  It does
  not make sense to use both additive options and negative options, but it is
  allowed.
This commit is contained in:
Jonathan Bernard 2011-12-07 18:15:01 -06:00
parent 6f58a83ad4
commit fd94f0e41a
7 changed files with 154 additions and 14 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
release/
*.sw*
*/build/

3
pit-cli/.gitignore vendored
View File

@ -1,3 +0,0 @@
release/
build/
*.sw?

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,9 @@
#Tue, 22 Nov 2011 14:40:19 -0600
#Wed, 07 Dec 2011 17:57:54 -0600
build.dir=build
src.dir=src
build.jar=pit-cli-${application.version}.${build.number}.jar
build.number=4
version=3.0.0
build.number=13
version=3.1.0
name=pit-cli
lib.dir=lib
lib.local=true

View File

View File

@ -2,6 +2,8 @@ package com.jdbernard.pit
import com.jdbernard.pit.file.*
import org.joda.time.DateMidnight
import static java.lang.Math.max
import static java.lang.Math.min
@ -36,12 +38,41 @@ cli.C(argName: 'new-category', longOpt: 'set-category', args: 1,
cli.S(argName: 'new-status', longOpt: 'set-status', args: 1,
required: false, 'Modify the status of the selected issues.')
cli.n(longOpt: 'new-issue', 'Create a new issue.')
cli.o(longOpt: 'order', argName: 'order', args: 1, required: false,
'Order (sort) the results by the given properties. Provide a comma-' +
'seperated list of property names to sort by in order of importance. The' +
' basic properties (id, category, status, and priority) can be given' +
' using their one-letter forms (i,c,s,p) for brevity. For example:' +
' "-o Due,p,c" would sort first by the extended property "Due", then for' +
' items that have the same "Due" value it would sort by priority, then' +
' by category.')
cli.d(longOpt: 'dir', argName: 'dir', args: 1, required: false,
'Use <dir> as the base directory (defaults to current directory).')
cli.D(longOpt: 'daily-list', 'Print a Daily Task list based on issue Due and' +
' Reminder properties.')
cli._(longOpt: 'dl-scheduled', 'Show scheduled tasks in the daily list (all' +
' are shown by default).')
cli._(longOpt: 'dl-due', 'Show due tasks in the daily list (all are shown by' +
' default).')
cli._(longOpt: 'dl-reminder', 'Show upcoming tasks in the daily list (all ' +
' are shown by default).')
cli._(longOpt: 'dl-open', 'Show open tasks in the daily list (all are shown ' +
' by default).')
cli._(longOpt: 'dl-hide-scheduled', 'Hide scheduled tasks in the daily list' +
' (all are shown by default).')
cli._(longOpt: 'dl-hide-due', 'Show due tasks in the daily list (all are' +
' shown by default).')
cli._(longOpt: 'dl-hide-reminder', 'Show upcoming tasks in the daily list' +
' (all are shown by default).')
cli._(longOpt: 'dl-hide-open', 'Show open tasks in the daily list (all are' +
' shown by default).')
cli._(longOpt: 'version', 'Display PIT version information.')
// -------- parse CLI options -------- //
def VERSION = "3.0.0"
// =================================== //
// ======== Parse CLI Options ======== //
// =================================== //
def VERSION = "3.1.0"
def opts = cli.parse(args)
def issuedb = [:]
def workingDir = new File('.')
@ -96,7 +127,7 @@ try { selectOpts.status =
selectOpts.status.collect { Status.toStatus(it) } }
catch (Exception e) {
println "Invalid status option: '-s ${e.localizedMessage}'."
println "Valid options are: \b${Status.values().join(', ')}"
print "Valid options are: \n${Status.values().join(', ')}"
println " (abbreviations are accepted.)"
System.exit(1) }
@ -115,6 +146,17 @@ if (opts.r) { selectOpts.projects =
// read and parse the ids filter
if (opts.i) { selectOpts.ids = opts.i.split(/[,\s]/).asType(List.class) }
// read and parse sort criteria
if (opts.o) {
def sortProps = opts.o.split(',')
selectOpts.issueSorter = sortProps.collect { prop ->
switch (prop) {
case ~/^i$/: return { issue -> issue.id }
case ~/^p$/: return { issue -> issue.priority }
case ~/^s$/: return { issue -> issue.status }
case ~/^c$/: return { issue -> issue.category }
default: return { issue -> issue[prop] } }}}
// TODO: accept projects value from input
// read and parse the category to assign
@ -152,7 +194,11 @@ if (opts.d) {
return -1 } }
def EOL = System.getProperty('line.separator')
// -------- Actions -------- //
// ========================= //
// ======== Actions ======== //
// ========================= //
// list version information first
if (opts.version) {
@ -191,7 +237,104 @@ if (opts.l) {
// print all projects
issuedb.eachProject(filter) { printProject(it, "") } }
// new issues third
// daily list second
else if (opts.D) {
// Parse daily list specific display options
def visibleSections = []
def suppressedSections
// Parse the additive options first.
if (opts.'dl-scheduled') { visibleSections << 'scheduled' }
if (opts.'dl-due') { visibleSections << 'due' }
if (opts.'dl-reminder') { visibleSections << 'reminder' }
if (opts.'dl-open') { visibleSections << 'open' }
// If the user did not add any sections assume they want them all.
if (visibleSections.size() == 0) {
visibleSections = ['scheduled', 'due', 'reminder', 'open'] }
// Now go through the negative options.
if (opts.'dl-hide-scheduled') { visibleSections -= 'scheduled' }
if (opts.'dl-hide-due') { visibleSections -= 'due' }
if (opts.'dl-hide-reminder') { visibleSections -= 'reminder' }
if (opts.'dl-hide-open') { visibleSections -= 'open' }
// If the user did not specifically ask for a status filter, we want a
// different filter for the default when we are doing a daily list.
if (!opts.s) { filter.status = [Status.NEW, Status.VALIDATION_REQUIRED] }
// If the user did not give a specific sorting order, define our own.
if (!opts.o) { filter.issueSorter = [ {it.due}, {it.priority}, {it.id} ] }
// Get our issues
def allIssues = issuedb.getAllIssues(filter)
// Set up our time interval.
def today = new DateMidnight()
def tomorrow = today.plusDays(1)
def scheduledToday = []
def dueToday = []
def reminderToday = []
def notDueOrReminder = []
def printIssue = { issue ->
if (issue.due) println "${issue.due.toString('EEE, MM/dd')} -- ${issue}"
else println " -- ${issue}" }
// Sort the issues into seperate lists based on their due dates and
// reminders.
allIssues.each { issue ->
// Find the issues that are scheduled for today.
if (issue.scheduled && issue.scheduled < tomorrow) {
scheduledToday << issue }
// Find the issues that are due today or are past due.
else if (issue.due && issue.due < tomorrow) { dueToday << issue }
// Find the issues that are not yet due but have a reminder for today or
// days past.
else if (issue.reminder && issue.reminder < tomorrow) {
reminderToday << issue }
// All the others (not due and no reminder).
else notDueOrReminder << issue }
// Print the issues
if (visibleSections.contains('scheduled') && scheduledToday.size() > 0) {
println "Tasks Scheduled for Today"
println "-------------------------"
scheduledToday.each { printIssue(it) }
println "" }
if (visibleSections.contains('due') && dueToday.size() > 0) {
println "Tasks Due Today"
println "---------------"
dueToday.each { printIssue(it) }
println ""}
if (visibleSections.contains('reminder') && reminderToday.size() > 0) {
println "Upcoming Tasks"
println "--------------"
reminderToday.each { printIssue(it) }
println ""}
if (visibleSections.contains('open') && notDueOrReminder.size() > 0) {
println "Other Open Issues"
println "-----------------"
notDueOrReminder.each { printIssue(it) }
println "" }}
// new issues fourth
else if (opts.n) {
def cat, priority
String text = ""
@ -243,7 +386,7 @@ else {
it.priority = assignOpts.priority
println "[${it}] -- set priority to ${assignOpts.priority}"}
// change third
// change category
else if (opts.C) issuedb.walkProject(filter) {
it.category = assignOpts.cat
println "[${it}] -- set category to ${assignOpts.category}"}
@ -251,5 +394,4 @@ else {
// change status
else if (opts.S) issuedb.walkProject(filter) {
it.status = assignOpts.status
println "[${it}] -- set status to ${assignOpts.status}"}
}}
println "[${it}] -- set status to ${assignOpts.status}"} }}