PIT CLI options -e, -E, --title, --text.
PIT CLI ------- * Added an option, `-e`, to filter by extended properties and its complement, `-E`, to set extended properties. Format of the option argument is `<propName>=<propValue>`. * Added the `--title` and `--text` options to specify the title and text of an issue on the command line. * When a new issue is created or an issue is set to rejected or resolved status a timestamp is added as an extended property: `created`, `rejected`, and `resolved` are the property names respectively.
This commit is contained in:
parent
846d1edc74
commit
ae0d782a5b
@ -1,9 +1,9 @@
|
|||||||
#Wed, 07 Dec 2011 17:57:54 -0600
|
#Thu, 08 Dec 2011 14:59:30 -0600
|
||||||
build.dir=build
|
build.dir=build
|
||||||
src.dir=src
|
src.dir=src
|
||||||
build.jar=pit-cli-${application.version}.${build.number}.jar
|
build.jar=pit-cli-${application.version}.${build.number}.jar
|
||||||
build.number=13
|
build.number=12
|
||||||
version=3.1.0
|
version=3.2.0
|
||||||
name=pit-cli
|
name=pit-cli
|
||||||
lib.dir=lib
|
lib.dir=lib
|
||||||
lib.local=true
|
lib.local=true
|
||||||
|
@ -3,6 +3,7 @@ package com.jdbernard.pit
|
|||||||
import com.jdbernard.pit.file.*
|
import com.jdbernard.pit.file.*
|
||||||
|
|
||||||
import org.joda.time.DateMidnight
|
import org.joda.time.DateMidnight
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
import static java.lang.Math.max
|
import static java.lang.Math.max
|
||||||
import static java.lang.Math.min
|
import static java.lang.Math.min
|
||||||
@ -28,16 +29,26 @@ cli.p(argName: 'priority', longOpt: 'priority', args: 1,
|
|||||||
cli.r(argName: 'project', longOpt: 'project', args: 1,
|
cli.r(argName: 'project', longOpt: 'project', args: 1,
|
||||||
'Filter issues by project (relative to the current directory). Accepts a '
|
'Filter issues by project (relative to the current directory). Accepts a '
|
||||||
+ 'comma-delimited list.')
|
+ 'comma-delimited list.')
|
||||||
|
cli.e(argName: 'extended-property', args: 1, 'Filter for issues by extended ' +
|
||||||
|
'property. Format is "-e <propname>=<propvalue>".')
|
||||||
/*cli.s(longOpt: 'show-subprojects',
|
/*cli.s(longOpt: 'show-subprojects',
|
||||||
'Include sup projects in listing (default behaviour)')
|
'Include sup projects in listing (default behaviour)')
|
||||||
cli.S(longOpt: 'no-subprojects', 'Do not list subprojects.')*/ // TODO: figure out better flags for these options.
|
cli.S(longOpt: 'no-subprojects', 'Do not list subprojects.')*/ // TODO: figure out better flags for these options.
|
||||||
cli.P(argName: 'new-priority', longOpt: 'set-priority', args: 1,
|
cli.P(argName: 'new-priority', longOpt: 'set-priority', args: 1,
|
||||||
required: false, 'Modify the priority of the selected issues.')
|
'Modify the priority of the selected issues.')
|
||||||
cli.C(argName: 'new-category', longOpt: 'set-category', args: 1,
|
cli.C(argName: 'new-category', longOpt: 'set-category', args: 1,
|
||||||
required: false, 'Modify the category of the selected issues.')
|
'Modify the category of the selected issues.')
|
||||||
cli.S(argName: 'new-status', longOpt: 'set-status', args: 1,
|
cli.S(argName: 'new-status', longOpt: 'set-status', args: 1,
|
||||||
required: false, 'Modify the status of the selected issues.')
|
'Modify the status of the selected issues.')
|
||||||
|
cli.E(argName: 'new-extended-property', args: 1, 'Modify the extended ' +
|
||||||
|
'property of the selected issues. Format is "-E <propname>=<propvalue>"')
|
||||||
cli.n(longOpt: 'new-issue', 'Create a new issue.')
|
cli.n(longOpt: 'new-issue', 'Create a new issue.')
|
||||||
|
cli._(longOpt: 'title', args: 1, argName: 'title', 'Give the title for a new' +
|
||||||
|
' issue or modify the title for an existing issue. By default the title' +
|
||||||
|
' for a new issue is expected on stanard input.')
|
||||||
|
cli._(longOpt: 'text', args: 1, argName: 'text', 'Give the text for a new' +
|
||||||
|
' issue or modify the text for an exising issue. By default the text for' +
|
||||||
|
' a new issue is expected on standard input.')
|
||||||
cli.o(longOpt: 'order', argName: 'order', args: 1, required: false,
|
cli.o(longOpt: 'order', argName: 'order', args: 1, required: false,
|
||||||
'Order (sort) the results by the given properties. Provide a comma-' +
|
'Order (sort) the results by the given properties. Provide a comma-' +
|
||||||
'seperated list of property names to sort by in order of importance. The' +
|
'seperated list of property names to sort by in order of importance. The' +
|
||||||
@ -72,7 +83,7 @@ cli._(longOpt: 'version', 'Display PIT version information.')
|
|||||||
// ======== Parse CLI Options ======== //
|
// ======== Parse CLI Options ======== //
|
||||||
// =================================== //
|
// =================================== //
|
||||||
|
|
||||||
def VERSION = "3.1.0"
|
def VERSION = "3.2.0"
|
||||||
def opts = cli.parse(args)
|
def opts = cli.parse(args)
|
||||||
def issuedb = [:]
|
def issuedb = [:]
|
||||||
def workingDir = new File('.')
|
def workingDir = new File('.')
|
||||||
@ -85,14 +96,11 @@ def selectOpts = [
|
|||||||
priority: 9,
|
priority: 9,
|
||||||
projects: [],
|
projects: [],
|
||||||
ids: [],
|
ids: [],
|
||||||
|
extendedProperties: [:],
|
||||||
acceptProjects: true]
|
acceptProjects: true]
|
||||||
|
|
||||||
// defaults for changing properties of issue(s)
|
// options for changing properties of issue(s)
|
||||||
def assignOpts = [
|
def assignOpts = [:]
|
||||||
category: Category.TASK,
|
|
||||||
status: Status.NEW,
|
|
||||||
priority: 5,
|
|
||||||
text: "New issue."]
|
|
||||||
|
|
||||||
if (!opts) opts.l = true; // default to 'list'
|
if (!opts) opts.l = true; // default to 'list'
|
||||||
|
|
||||||
@ -157,6 +165,13 @@ if (opts.o) {
|
|||||||
case ~/^c$/: return { issue -> issue.category }
|
case ~/^c$/: return { issue -> issue.category }
|
||||||
default: return { issue -> issue[prop] } }}}
|
default: return { issue -> issue[prop] } }}}
|
||||||
|
|
||||||
|
// read and parse extended property selection criteria
|
||||||
|
if (opts.e) {
|
||||||
|
opts.es.each { option ->
|
||||||
|
def parts = option.split("=")
|
||||||
|
selectOpts.extendedProperties[parts[0]] =
|
||||||
|
ExtendedPropertyHelp.parse(parts[1]) }}
|
||||||
|
|
||||||
// TODO: accept projects value from input
|
// TODO: accept projects value from input
|
||||||
|
|
||||||
// read and parse the category to assign
|
// read and parse the category to assign
|
||||||
@ -182,9 +197,16 @@ catch (NumberFormatException nfe) {
|
|||||||
println "Valid values are: 0-9"
|
println "Valid values are: 0-9"
|
||||||
System.exit(1) }
|
System.exit(1) }
|
||||||
|
|
||||||
// look for assignment text
|
if (opts.E) {
|
||||||
if (opts.getArgs().length > 0) {
|
opts.Es.each { option ->
|
||||||
assignOpts.text = opts.getArgs()[0] }
|
def parts = option.split("=")
|
||||||
|
assignOpts[parts[0]] = ExtendedPropertyHelp.parse(parts[1]) }}
|
||||||
|
|
||||||
|
// Read the title if given.
|
||||||
|
if (opts.title) { assignOpts.title = opts.title }
|
||||||
|
|
||||||
|
// Read the text if given
|
||||||
|
if (opts.text) { assignOpts.text = opts.text }
|
||||||
|
|
||||||
// set the project working directory
|
// set the project working directory
|
||||||
if (opts.d) {
|
if (opts.d) {
|
||||||
@ -192,6 +214,7 @@ if (opts.d) {
|
|||||||
if (!workingDir.exists()) {
|
if (!workingDir.exists()) {
|
||||||
println "Directory '${workingDir}' does not exist."
|
println "Directory '${workingDir}' does not exist."
|
||||||
return -1 } }
|
return -1 } }
|
||||||
|
|
||||||
def EOL = System.getProperty('line.separator')
|
def EOL = System.getProperty('line.separator')
|
||||||
|
|
||||||
|
|
||||||
@ -222,7 +245,10 @@ if (opts.l) {
|
|||||||
if (opts.v) {
|
if (opts.v) {
|
||||||
println ""
|
println ""
|
||||||
issue.text.eachLine { println "${offset} ${it}" }
|
issue.text.eachLine { println "${offset} ${it}" }
|
||||||
println "" } }
|
issue.extendedProperties.each { name, value ->
|
||||||
|
def formattedValue = ExtendedPropertyHelp.format(value)
|
||||||
|
println "${offset} * ${name}: ${formattedValue}"}
|
||||||
|
println ""}}
|
||||||
|
|
||||||
// local function (closure) to print a project and all visible subprojects
|
// local function (closure) to print a project and all visible subprojects
|
||||||
def printProject
|
def printProject
|
||||||
@ -336,62 +362,78 @@ else if (opts.D) {
|
|||||||
|
|
||||||
// new issues fourth
|
// new issues fourth
|
||||||
else if (opts.n) {
|
else if (opts.n) {
|
||||||
def cat, priority
|
|
||||||
String text = ""
|
|
||||||
Issue issue
|
Issue issue
|
||||||
def sin = System.in.newReader()
|
def sin = System.in.newReader()
|
||||||
|
|
||||||
if (opts.C) { cat = assignOpts.category }
|
// Set the created extended property
|
||||||
else while(true) {
|
assignOpts.created = new DateTime()
|
||||||
try {
|
|
||||||
print "Category (bug, feature, task): "
|
|
||||||
cat = Category.toCategory(sin.readLine())
|
|
||||||
break }
|
|
||||||
catch (e) {
|
|
||||||
println "Invalid category: " + e.getLocalizedMessage()
|
|
||||||
println "Valid options are: \n${Category.values().join(', ')}"
|
|
||||||
println " (abbreviations are accepted)." } }
|
|
||||||
|
|
||||||
if (opts.P) { priority = assignOpts.priority }
|
// Prompt for the different options if they were not given on the command
|
||||||
else while (true) {
|
// line. We will loop until they have entered a valid value. How it works:
|
||||||
|
// In the body of the loop we will try to read the input, parse it and
|
||||||
|
// assign it to a variable. If the input is invalid it will throw as
|
||||||
|
// exception before the assignment happens, the variable will still be
|
||||||
|
// null, and we will prompt the user again.
|
||||||
|
|
||||||
|
// Prompt for category.
|
||||||
|
while(!assignOpts.category) {
|
||||||
|
try {
|
||||||
|
print "Category (bug, feature, task): "
|
||||||
|
assignOpts.category = Category.toCategory(sin.readLine())
|
||||||
|
break }
|
||||||
|
catch (e) {
|
||||||
|
println "Invalid category: " + e.getLocalizedMessage()
|
||||||
|
println "Valid options are: \n${Category.values().join(', ')}"
|
||||||
|
println " (abbreviations are accepted)." } }
|
||||||
|
|
||||||
|
// Prompt for the priority.
|
||||||
|
while (!assignOpts.priority) {
|
||||||
try {
|
try {
|
||||||
print "Priority (0-9): "
|
print "Priority (0-9): "
|
||||||
priority = max(0, min(9, sin.readLine().toInteger()))
|
assignOpts.priority = max(0, min(9, sin.readLine().toInteger()))
|
||||||
break }
|
break }
|
||||||
catch (e) { println "Not a valid value." } }
|
catch (e) { println "Not a valid value." } }
|
||||||
|
|
||||||
if (opts.getArgs().length > 0) { text = assignOpts.text }
|
// Prompt for the issue title. No need to loop as the input does not need
|
||||||
else {
|
// to be validated.
|
||||||
println "Enter issue (use EOF): "
|
if (!assignOpts.title) {
|
||||||
|
println "Issue title: "
|
||||||
|
assignOpts.title = sin.readLine().trim() }
|
||||||
|
|
||||||
|
// Prompt for the issue text.
|
||||||
|
if (!assignOpts.text) {
|
||||||
|
assignOpts.text = ""
|
||||||
|
println "Enter issue text (use EOF to stop): "
|
||||||
try {
|
try {
|
||||||
def line = ""
|
def line = ""
|
||||||
while(true) {
|
while(true) {
|
||||||
line = sin.readLine()
|
line = sin.readLine()
|
||||||
|
|
||||||
if (line =~ /EOF/) break
|
// Stop when they enter EOF
|
||||||
|
if (line ==~ /^EOF$/) break
|
||||||
|
|
||||||
text += line + EOL
|
assignOpts.text += line + EOL } }
|
||||||
} }
|
|
||||||
catch (e) {} }
|
catch (e) {} }
|
||||||
|
|
||||||
issue = issuedb.createNewIssue(category: cat, priority: priority, text: text)
|
issue = issuedb.createNewIssue(assignOpts)
|
||||||
|
|
||||||
println "New issue created: "
|
println "New issue created: "
|
||||||
println issue }
|
println issue }
|
||||||
|
|
||||||
// last, changes to existing issues
|
// last, changes to existing issues
|
||||||
else {
|
else if (assignOpts.size() > 0) {
|
||||||
// change priority
|
|
||||||
if (opts.P) issuedb.walkProject(filter) {
|
|
||||||
it.priority = assignOpts.priority
|
|
||||||
println "[${it}] -- set priority to ${assignOpts.priority}"}
|
|
||||||
|
|
||||||
// change category
|
// We are going to add some extra properties if the status is being changed,
|
||||||
else if (opts.C) issuedb.walkProject(filter) {
|
// because we are nice like that.
|
||||||
it.category = assignOpts.cat
|
if (assignOpts.status) { switch (assignOpts.status) {
|
||||||
println "[${it}] -- set category to ${assignOpts.category}"}
|
case Status.RESOLVED: assignOpts.resolved = new DateTime(); break
|
||||||
|
case Status.REJECTED: assignOpts.rejected = new DateTime(); break
|
||||||
|
default: break }}
|
||||||
|
|
||||||
// change status
|
issuedb.walkProject(filter) { issue ->
|
||||||
else if (opts.S) issuedb.walkProject(filter) {
|
println issue
|
||||||
it.status = assignOpts.status
|
assignOpts.each { propName, value ->
|
||||||
println "[${it}] -- set status to ${assignOpts.status}"} }}
|
issue[propName] = value
|
||||||
|
println " set ${propName} to ${value}" } }}
|
||||||
|
|
||||||
|
else { cli.usage(); return -1 }}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user