diff --git a/libpit/project.properties b/libpit/project.properties index 4db4631..6daa108 100755 --- a/libpit/project.properties +++ b/libpit/project.properties @@ -3,8 +3,8 @@ build.dir=build src.dir=src lib.shared.dir=../shared-libs test.dir=test -build.number=4 -expected.application.version=2.5.1 +build.number=1 +expected.application.version=2.6.0 lib.dir=lib release.dir=release release.jar=pit-${application.version}.jar diff --git a/libpit/release/pit-2.6.0.jar b/libpit/release/pit-2.6.0.jar new file mode 100644 index 0000000..d2736d1 Binary files /dev/null and b/libpit/release/pit-2.6.0.jar differ diff --git a/pit-cli/lib/pit-2.6.0.jar b/pit-cli/lib/pit-2.6.0.jar new file mode 100644 index 0000000..d2736d1 Binary files /dev/null and b/pit-cli/lib/pit-2.6.0.jar differ diff --git a/pit-cli/project.properties b/pit-cli/project.properties index 80a3582..249562d 100755 --- a/pit-cli/project.properties +++ b/pit-cli/project.properties @@ -1,9 +1,9 @@ -#Sat Feb 27 03:01:15 CST 2010 +#Tue, 09 Aug 2011 17:21:28 -0500 build.dir=build src.dir=src build.jar=pit-cli-${application.version}.${build.number}.jar -build.number=5 -expected.application.version=2.5.1 +build.number=7 +expected.application.version=2.6.0 lib.dir=lib release.dir=release release.jar=pit-cli-${application.version}.jar diff --git a/pit-cli/release/pit-cli-2.1.0.jar b/pit-cli/release/pit-cli-2.1.0.jar deleted file mode 100755 index 3fcfcaf..0000000 Binary files a/pit-cli/release/pit-cli-2.1.0.jar and /dev/null differ diff --git a/pit-cli/release/pit-cli-2.6.0.jar b/pit-cli/release/pit-cli-2.6.0.jar new file mode 100644 index 0000000..887c437 Binary files /dev/null and b/pit-cli/release/pit-cli-2.6.0.jar differ diff --git a/pit-cli/src/com/jdbernard/pit/PersonalIssueTrackerCLI.groovy b/pit-cli/src/com/jdbernard/pit/PersonalIssueTrackerCLI.groovy index 5e62168..86929b7 100644 --- a/pit-cli/src/com/jdbernard/pit/PersonalIssueTrackerCLI.groovy +++ b/pit-cli/src/com/jdbernard/pit/PersonalIssueTrackerCLI.groovy @@ -5,6 +5,8 @@ import com.jdbernard.pit.file.* import static java.lang.Math.max import static java.lang.Math.min +// -------- command-line interface specification -------- // + def cli = new CliBuilder(usage: 'pit-cli [options]') cli.h(longOpt: 'help', 'Show help information.') cli.v(longOpt: 'verbose', 'Show verbose task information') @@ -14,8 +16,8 @@ cli.i(argName: 'id', longOpt: 'id', args: 1, 'Filter issues by id. Accepts a comma-delimited list.') cli.c(argName: 'category', longOpt: 'category', args: 1, 'Filter issues by category (bug, feature, task). Accepts a ' - + 'comma-delimited list.') -cli.t(argName: 'status', longOpt: 'status', args: 1, + + 'comma-delimited list. By default all categories are selected.') +cli.s(argName: 'status', longOpt: 'status', args: 1, 'Filter issues by status (new, reassigned, rejected, resolved, ' + 'validation_required)') cli.p(argName: 'priority', longOpt: 'priority', args: 1, @@ -24,152 +26,225 @@ cli.p(argName: 'priority', longOpt: 'priority', args: 1, cli.r(argName: 'project', longOpt: 'project', args: 1, 'Filter issues by project (relative to the current directory). Accepts a ' + 'comma-delimited list.') -cli.s(longOpt: 'show-subprojects', +/*cli.s(longOpt: 'show-subprojects', 'Include sup projects in listing (default behaviour)') -cli.S(longOpt: 'no-subprojects', 'Do not list subprojects.') +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, required: false, 'Modify the priority of the selected issues.') cli.C(argName: 'new-category', longOpt: 'set-category', args: 1, required: false, 'Modify the category of the selected issues.') -cli.T(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.') cli.n(longOpt: 'new-issue', 'Create a new issue.') cli.d(longOpt: 'dir', argName: 'dir', args: 1, required: false, 'Use as the base directory (defaults to current directory).') +// -------- parse CLI options -------- // def opts = cli.parse(args) def issuedb = [:] def workingDir = new File('.') -if (!opts) System.exit(1) // better solution? +// defaults for the issue filter/selector +def selectOpts = [ + categories: ['bug', 'feature', 'task'], + status: ['new', 'validation_required'], + priority: 9, + projects: [], + ids: [], + acceptProjects: true] -if (opts.h) cli.usage() +// defaults for changing properties of issue(s) +def assignOpts = [ + category: Category.TASK, + status: Status.NEW, + priority: 5, + text: "New issue."] -def categories = ['bug','feature','task'] -if (opts.c) categories = opts.c.split(/[,\s]/) -categories = categories.collect { Category.toCategory(it) } +if (!opts) opts.l = true; // default to 'list' -def statusList = ['new', 'validation_required'] -if (opts.t) statusList = opts.t.split(/[,\s]/) -statusList = statusList.collect { Status.toStatus(it) } +if (opts.h) { + cli.usage() + System.exit(0) } +// read the category filter designation(s) +if (opts.c) { + if (opts.c =~ /all/) {} // no-op, same as defaults + else { selectOpts.categories = opts.c.split(/[,\s]/) } } + +// parse the categories names into Category objects +try { selectOpts.categories = + selectOpts.categories.collect { Category.toCategory(it) } } +catch (Exception e) { + println "Invalid category option: '-c ${e.localizedMessage}'." + println "Valid options are: \n${Category.values().join(', ')}" + println " (abbreviations are accepted)." + System.exit(1) } + +// read the status filter designation(s) +if (opts.s) { + // -s all + if (opts.s =~ /all/) selectOpts.status = ['new', 'reassigned', 'rejected', + 'resolved', 'validation_required'] + // is + else selectOpts.status = opts.s.split(/[,\s]/) } + +// parse the statuses into Status objects +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(', ')}" + println " (abbreviations are accepted.)" + System.exit(1) } + +// read and parse the priority filter +if (opts.p) try { + selectOpts.priority = opts.p.toInteger() } +catch (NumberFormatException nfe) { + println "Not a valid priority value: '-p ${opts.p}'." + println "Valid values are: 0-9" + System.exit(1) } + +// read and parse the projects filter +if (opts.r) { selectOpts.projects = + opts.r.toLowerCase().split(/[,\s]/).asType(List.class) } + +// read and parse the ids filter +if (opts.i) { selectOpts.ids = opts.i.split(/[,\s]/).asType(List.class) } + +// TODO: accept projects value from input + +// read and parse the category to assign +if (opts.C) try { assignOpts.category = Category.toCategory(opts.C) } +catch (Exception e) { + println "Invalid category option: '-C ${e.localizedMessage}'." + println "Valid categories are: \n${Category.values().join(', ')}" + println " (abbreviations are accepted)." + System.exit(1) } + +// read and parse the status to assign +if (opts.S) try { assignOpts.status = Status.toStatus(opts.S) } +catch (Exception e) { + println "Invalid status option: '-S ${e.localizedMessage}'." + println "Valid stasus options are: \n{Status.values().join(', ')}" + println " (abbreviations are accepted)." + System.exit(1) } + +// read and parse the priority to assign +if (opts.P) try {assignOpts.priority = opts.P.toInteger() } +catch (NumberFormatException nfe) { + println "Not a valid priority value: '-P ${opts.P}'." + println "Valid values are: 0-9" + System.exit(1) } + +// look for assignment text +if (opts.getArgs().length > 0) { + assignOpts.text = opts.getArgs()[0] } + +// set the project working directory if (opts.d) { workingDir = new File(opts.d.trim()) if (!workingDir.exists()) { println "Directory '${workingDir}' does not exist." - return -1 - } -} - + return -1 } } def EOL = System.getProperty('line.separator') // build issue list issuedb = new FileProject(workingDir) // build filter from options -def filter = new Filter('categories': categories, - 'status': statusList, - 'priority': (opts.p ? opts.p.toInteger() : 9), - 'projects': (opts.r ? opts.r.toLowerCase().split(/[,\s]/).asType(List.class) : []), - 'ids': (opts.i ? opts.i.split(/[,\s]/).asType(List.class) : []), - 'acceptProjects': (opts.s || !opts.S)) +def filter = new Filter(selectOpts) // list first if (opts.l) { + // local function (closure) to print a single issue def printIssue = { issue, offset -> println "${offset}${issue}" if (opts.v) { println "" issue.text.eachLine { println "${offset} ${it}" } - println "" - } - } + println "" } } + // local function (closure) to print a project and all visible subprojects def printProject printProject = { project, offset -> println "\n${offset}${project.name}" println "${offset}${'-'.multiply(project.name.length())}" project.eachIssue(filter) { printIssue(it, offset) } - project.eachProject(filter) { printProject(it, offset + " ") } - } + project.eachProject(filter) { printProject(it, offset + " ") } } + + // print all the issues in the root of this db issuedb.eachIssue(filter) { printIssue(it, "") } - issuedb.eachProject(filter) { printProject(it, "") } -} + // print all projects + issuedb.eachProject(filter) { printProject(it, "") } } -// change priority second -else if (opts.P) { - def priority - try { priority = max(0, min(9, opts.P.toInteger())) } - catch (e) { println "Invalid priority: ${opts.P}"; return 1 } - - walkProject(issuedb, filter) { it.priority = priority } -} -// change category third -else if (opts.C) { - def cat - try { cat = Category.toCategory(opts.C) } - catch (e) { println "Invalid category: ${opts.C}"; return 1 } - - walkProject(issuedb, filter) { it.category = cat } -} -// change status fourth -else if (opts.T) { - def status - try { status = Status.toStatus(opts.T) } - catch (e) { println "Invalid status: ${opts.T}"; return 1 } - - walkProject(issuedb, filter) { it.status = status } -} -// new entry last +// new issues second else if (opts.n) { def cat, priority String text = "" Issue issue def sin = System.in.newReader() - while(true) { - try { - print "Category (bug, feature, task, closed): " - cat = Category.toCategory(sin.readLine()) - break - } catch (e) { - println "Invalid category: " + e.getLocalizedMessage() - println "Valid options are: \n${Category.values().join(', ')}\n " + - "(abbreviations are accepted.)" - } - } + if (opts.C) { cat = assignOpts.category } + else while(true) { + try { + print "Category (bug, feature, task, closed): " + 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)." } } - while (true) { + if (opts.P) { priority = assignOpts.priority } + else while (true) { try { print "Priority (0-9): " priority = max(0, min(9, sin.readLine().toInteger())) - break - } catch (e) { println "Not a valid value." } - } + break } + catch (e) { println "Not a valid value." } } - println "Enter issue (use EOF or ^D to end): " - try { - sin.eachLine { line -> - def m = line =~ /(.*)EOF.*/ - if (m) { - text += m[0][1] + EOL - sin.close() - } else text += line + EOL - } - } catch (e) {} + if (opts.getArgs().length > 0) { text = assignOpts.text } + else { + println "Enter issue (use EOF): " + try { + def line = "" + while(true) { + line = sin.readLine() + if (line =~ /EOF/) break + + text += line + EOL + } } + catch (e) {} } issue = issuedb.createNewIssue(category: cat, priority: priority, text: text) println "New issue created: " - println issue + println issue } + +// last, changes to existing issues +else { + // change priority + if (opts.P) walkProject(issuedb, filter) { + it.priority = assignOpts.priority + println "[${it}] -- set priority to ${assignOpts.priority}"} + + // change third + else if (opts.C) walkProject(issuedb, filter) { + it.category = assignOpts.cat + println "[${it}] -- set category to ${assignOpts.category}"} + + // change status + else if (opts.S) walkProject(issuedb, filter) { + it.status = assignOpts.status + println "[${it}] -- set status to ${assignOpts.status}"} } +// walk every issue and project in this project recursively and execute the +// given closure on each issue that meets the filter criteria def walkProject(Project p, Filter filter, Closure c) { p.eachIssue(filter, c) p.eachProject(filter) { walkProject(it, filter, c) } } - -def printProject(Project project, String offset, Filter filter, boolean verbose = false) { -} diff --git a/version.properties b/version.properties index 9d9db1b..5d78337 100755 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -application.version=2.5.1 +application.version=2.6.0