#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2007 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
# <jesse@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301 or visit their web page on the internet at
-# http://www.gnu.org/copyleft/gpl.html.
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#
# CONTRIBUTION SUBMISSION POLICY:
# those contributions and any derivatives thereof.
#
# END BPS TAGGED BLOCK }}}
+
# Designed and implemented for Best Practical Solutions, LLC by
# Abhijit Menon-Sen <ams@wiw.org>
use LWP;
use Text::ParseWords;
use HTTP::Request::Common;
-use Term::ReadLine;
# We derive configuration information from hardwired defaults, dotfiles,
# and the RT* environment variables (in increasing order of precedence).
debug => 0,
user => eval{(getpwuid($<))[0]} || $ENV{USER} || $ENV{USERNAME},
passwd => undef,
- server => 'http://localhost/',
+ server => 'http://localhost/rt/',
query => undef,
orderby => undef,
),
my $session = new Session("$HOME/.rt_sessions");
my $REST = "$config{server}/REST/1.0";
-my $prompt = 'rt> ';
-
sub whine;
sub DEBUG { warn @_ if $config{debug} >= shift }
link => ["link", "ln"],
merge => ["merge"],
grant => ["grant", "revoke"],
- take => ["take", "steal", "untake"],
- quit => ["quit", "exit"],
);
my %actions;
sub handler {
my $action;
- push @ARGV, 'shell' if (!@ARGV); # default to shell mode
- shift @ARGV if ($ARGV[0] eq 'rt'); # ignore a leading 'rt'
if (@ARGV && exists $actions{$ARGV[0]}) {
$action = shift @ARGV;
- $actions{$action}->($action);
- }
- else {
- print STDERR "rt: Unknown command '@ARGV'.\n";
- print STDERR "rt: For help, run 'rt help'.\n";
}
+ $actions{$action || "help"}->($action || ());
}
handler();
sub shell {
$|=1;
- my $term = new Term::ReadLine 'RT CLI';
- while ( defined ($_ = $term->readline($prompt)) ) {
+ print "rt> ";
+ while (<>) {
+ chomp;
next if /^#/ || /^\s*$/;
@ARGV = shellwords($_);
handler();
+ print "rt> ";
}
+ print "\n";
}
sub version {
submit("$REST/logout") if defined $session->cookie;
}
-sub quit {
- logout();
- exit;
-}
-
my %help;
sub help {
my ($action, $type) = @_;
whine "No $item specified.";
$bad = 1;
}
- #return help("list", $type) if $bad;
- return suggest_help("list", $type) if $bad;
+ return help("list", $type) if $bad;
my $r = submit("$REST/search/$type", { query => $q, %data });
print $r->content;
whine "No objects specified.";
$bad = 1;
}
- #return help("show", $type) if $bad;
- return suggest_help("show", $type) if $bad;
+ return help("show", $type) if $bad;
my $r = submit("$REST/show", { id => \@objects, %data });
- my $c = $r->content;
- # if this isn't a text reply, remove the trailing newline so we
- # don't corrupt things like tarballs when people do
- # show ticket/id/attachments/id/content > foo.tar.gz
- if ($r->content_type !~ /^text\//) {
- chomp($c);
- }
- print $c;
+ print $r->content;
}
# To create a new object, we ask the server for a form with the defaults
}
@objects = ("$type/new");
}
- #return help($action, $type) if $bad;
- return suggest_help($action, $type) if $bad;
+ return help($action, $type) if $bad;
# We need a form to make changes to. We usually ask the server for
# one, but we can avoid that if we are fed one on STDIN, or if the
# user doesn't want to edit the form by hand, and the command line
- # specifies only simple variable assignments. We *should* get a
- # form if we're creating a new ticket, so that the default values
- # get filled in properly.
-
- my @new_objects = grep /\/new$/, @objects;
+ # specifies only simple variable assignments.
if ($input) {
local $/ = undef;
$text = <STDIN>;
}
- elsif ($edit || %add || %del || !$cl || @new_objects) {
+ elsif ($edit || %add || %del || !$cl) {
my $r = submit("$REST/show", { id => \@objects, format => 'l' });
$text = $r->content;
}
whine "No object specified.";
$bad = 1;
}
- #return help($action, "ticket") if $bad;
- return suggest_help($action, "ticket") if $bad;
+ return help($action, "ticket") if $bad;
my $form = [
"",
}
$data{content} = $text;
- my $r = submit("$REST/ticket/$id/comment", \%data);
+ my $r = submit("$REST/ticket/comment/$id", \%data);
print $r->content;
}
whine "Too $evil arguments specified.";
$bad = 1;
}
- #return help("merge", "ticket") if $bad;
- return suggest_help("merge", "ticket") if $bad;
+ return help("merge", "ticket") if $bad;
- my $r = submit("$REST/ticket/$id[0]/merge/$id[1]");
+ my $r = submit("$REST/ticket/merge/$id[0]", {into => $id[1]});
print $r->content;
}
whine "Too $bad arguments specified.";
$bad = 1;
}
- #return help("link", "ticket") if $bad;
- return suggest_help("link", "ticket") if $bad;
+ return help("link", "ticket") if $bad;
my $r = submit("$REST/ticket/link", \%data);
print $r->content;
}
-# Take/steal a ticket
-sub take {
- my ($cmd) = @_;
- my ($bad, %data) = (0, ());
-
- my $id;
-
- # get the ticket id
- if (@ARGV == 1) {
- ($id) = @ARGV;
- unless ($id =~ /^\d+$/) {
- whine "Invalid ticket ID $id specified.";
- $bad = 1;
- }
- my $form = [
- "",
- [ "Ticket", "Action" ],
- {
- Ticket => $id,
- Action => $cmd,
- Status => '',
- }
- ];
-
- my $text = Form::compose([ $form ]);
- $data{content} = $text;
- }
- else {
- $bad = @ARGV < 1 ? "few" : "many";
- whine "Too $bad arguments specified.";
- $bad = 1;
- }
- return suggest_help("take", "ticket") if $bad;
-
- my $r = submit("$REST/ticket/$id/take", \%data);
- print $r->content;
-}
-
# Grant/revoke a user's rights.
sub grant {
# For anything else, we just die.
elsif ($res->code != 409) {
warn "rt: ", $res->content;
- #exit;
+ exit;
}
}
}
return \@words;
}
-# WARN: this code is duplicated in lib/RT/Interface/REST.pm
-# change both functions at once
sub expand_list {
my ($list) = @_;
+ my ($elt, @elts, %elts);
- my @elts;
- foreach (split /,/, $list) {
- push @elts, /^(\d+)-(\d+)$/? ($1..$2): $_;
+ foreach $elt (split /,/, $list) {
+ if ($elt =~ /^(\d+)-(\d+)$/) { push @elts, ($1..$2) }
+ else { push @elts, $elt }
}
- return map $_->[0], # schwartzian transform
- sort {
- defined $a->[1] && defined $b->[1]?
- # both numbers
- $a->[1] <=> $b->[1]
- :!defined $a->[1] && !defined $b->[1]?
- # both letters
- $a->[2] cmp $b->[2]
- # mix, number must be first
- :defined $a->[1]? -1: 1
- }
- map [ $_, (defined( /^(\d+)$/ )? $1: undef), lc($_) ],
- @elts;
+ @elts{@elts}=();
+ return sort {$a<=>$b} keys %elts;
}
sub get_type_argument {
return;
}
-sub suggest_help {
- my ($action, $type) = @_;
-
- print STDERR "rt: For help, run 'rt help $action'.\n" if defined $action;
- print STDERR "rt: For help, run 'rt help $type'.\n" if defined $type;
-}
-
__DATA__
Title: intro
Title: introduction
Text:
- ** THIS IS AN UNSUPPORTED PREVIEW RELEASE **
- ** PLEASE REPORT BUGS TO rt-bugs@bestpractical.com **
+ ** THIS IS AN UNSUPPORTED PREVIEW RELEASE **
+ ** PLEASE REPORT BUGS TO rt-bugs@fsck.com **
- This is a command-line interface to RT 3.0 or newer
+ This is a command-line interface to RT 3.
It allows you to interact with an RT server over HTTP, and offers an
interface to RT's functionality that is better-suited to automation
For more information:
- - rt help usage (syntax information)
- - rt help objects (how to specify objects)
- rt help actions (a list of possible actions)
- - rt help types (a list of object types)
+ - rt help objects (how to specify objects)
+ - rt help usage (syntax information)
- rt help config (configuration details)
- rt help examples (a few useful examples)
Syntax:
rt <action> [options] [arguments]
- or
- rt shell
Each invocation of this program must specify an action (e.g. "edit",
"create"), options to modify behaviour, and other arguments required
"rt help <action>". Some actions may be referred to by more than one
name ("create" is the same as "new", for example).
- You may also call "rt shell", which will give you an 'rt>' prompt at
- which you can issue commands of the form "<action> [options]
- [arguments]". See "rt help shell" for details.
-
Objects are identified by a type and an ID (which can be a name or a
number, depending on the type). For some actions, the object type is
implied (you can only comment on tickets); for others, the user must
- rt help objects (how to specify objects)
- rt help actions (a list of actions)
- rt help types (a list of object types)
- - rt help shell (how to use the shell)
--
rt ls -t tickets -i 'Priority > 5' | rt edit - set status=resolved
rt edit ticket/4 set priority=3 owner=bar@example.com \
add cc=foo@example.com bcc=quux@example.net
- rt create -t ticket set subject='new ticket' priority=10 \
+ rt create -t ticket subject='new ticket' priority=10 \
add cc=foo@example.com
--
rt merge <from-id> <to-id>
- Merges the first ticket specified into the second ticket specified.
+ Merges the two specified tickets.
--
Title: topics
Text:
- Syntax:
-
- rt help <topic>
-
- Get help on any of the following subjects:
+ Use "rt help <topic>" for help on any of the following subjects:
- tickets, users, groups, queues.
- show, edit, ls/list/search, new/create.
For the moment, please consult examples provided with each action.
--
-
-Title: shell
-Text:
-
- Syntax:
-
- rt shell
-
- Opens an interactive shell, at which you can issue commands of
- the form "<action> [options] [arguments]".
-
- To exit the shell, type "quit" or "exit".
-
- Commands can be given at the shell in the same form as they would
- be given at the command line without the leading 'rt' invocation.
-
- Example:
- $ rt shell
- rt> create -t ticket set subject='new' add cc=foo@example.com
- # Ticket 8 created.
- rt> quit
- $
-
---
-
-Title: take
-Title: untake
-Title: steal
-Text:
-
- Syntax:
-
- rt <take|untake|steal> <ticket-id>
-
- Sets the owner of the specified ticket to the current user,
- assuming said user has the bits to do so, or releases the
- ticket.
-
- 'Take' is used on tickets which are not currently owned
- (Owner: Nobody), 'steal' is used on tickets which *are*
- currently owned, and 'untake' is used to "release" a ticket
- (reset its Owner to Nobody). 'Take' cannot be used on
- tickets which are currently owned.
-
- Example:
- alice$ rt create -t ticket set subject="New ticket"
- # Ticket 7 created.
- alice$ rt take 7
- # Owner changed from Nobody to alice
- alice$ su bob
- bob$ rt steal 7
- # Owner changed from alice to bob
- bob$ rt untake 7
- # Owner changed from bob to Nobody
-
---
-
-Title: quit
-Title: exit
-Text:
-
- Use "quit" or "exit" to leave the shell. Only valid within shell
- mode.
-
- Example:
- $ rt shell
- rt> quit
- $