[Bps-public-commit] r15218 - in sd/trunk: . lib/App/SD lib/App/SD/CLI lib/App/SD/CLI/Command/Ticket lib/App/SD/CLI/Command/Ticket/Comment lib/App/SD/CLI/Model lib/App/SD/Model t/scripts

spang at bestpractical.com spang at bestpractical.com
Mon Aug 18 10:18:07 EDT 2008


Author: spang
Date: Mon Aug 18 10:18:05 2008
New Revision: 15218

Added:
   sd/trunk/lib/App/SD/CLI/Command/Ticket/Comment/Update.pm
   sd/trunk/lib/App/SD/CLI/Command/Ticket/Update.pm
   sd/trunk/t/03-update-ticket-with-editor.t
   sd/trunk/t/04-update-ticket-comment-with-editor.t
   sd/trunk/t/scripts/
   sd/trunk/t/scripts/ticket-comment-update-editor.pl   (contents, props changed)
   sd/trunk/t/scripts/ticket-create-editor.pl   (contents, props changed)
   sd/trunk/t/scripts/ticket-update-editor.pl   (contents, props changed)
Removed:
   sd/trunk/t/ticket-create-editor.pl
Modified:
   sd/trunk/   (props changed)
   sd/trunk/lib/App/SD/CLI/Command.pm
   sd/trunk/lib/App/SD/CLI/Command/Ticket/Create.pm
   sd/trunk/lib/App/SD/CLI/Model/Ticket.pm
   sd/trunk/lib/App/SD/Model/Ticket.pm
   sd/trunk/lib/App/SD/Test.pm
   sd/trunk/t/02-create-with-editor.t

Log:
 r48270 at loki:  spang | 2008-08-14 17:25:24 +0100
 re-add strangely missing test code, making a fix in the process
 r48272 at loki:  spang | 2008-08-14 22:15:22 +0100
 use props_not_to_edit to determine which props not to present for editing
 r48273 at loki:  spang | 2008-08-14 22:47:08 +0100
 patch Help.pm to Jesse's new version, which seems to have gotten mis-merged somewhere along the line
 r48277 at loki:  spang | 2008-08-15 15:56:08 +0100
 add creator to props_not_to_edit
 r48278 at loki:  spang | 2008-08-15 15:57:28 +0100
 add new create_new_comment method to consolidate code from ticket update / create
 r48279 at loki:  spang | 2008-08-15 15:58:25 +0100
 bugfix the ticket comment parsing regex and a minor change to the comment separator
 r48280 at loki:  spang | 2008-08-15 15:59:20 +0100
 use new create_new_comment method in ticket create command
 r48281 at loki:  spang | 2008-08-15 16:12:06 +0100
 customize comment and ticket update commands for sd
 r48419 at loki:  spang | 2008-08-18 10:26:12 +0100
 prophet doesn't like commands with incorrect package names
 r48420 at loki:  spang | 2008-08-18 11:48:14 +0100
 tests for new update functionality
 r48421 at loki:  spang | 2008-08-18 11:49:09 +0100
 support functions for new tests
 r48422 at loki:  spang | 2008-08-18 11:49:37 +0100
 print success message after comment updated


Modified: sd/trunk/lib/App/SD/CLI/Command.pm
==============================================================================
--- sd/trunk/lib/App/SD/CLI/Command.pm	(original)
+++ sd/trunk/lib/App/SD/CLI/Command.pm	Mon Aug 18 10:18:05 2008
@@ -1,6 +1,7 @@
 package App::SD::CLI::Command;
 use Moose::Role;
 use Path::Class;
+use Params::Validate qw(validate);
 
 =head2 get_content %args
 
@@ -61,6 +62,30 @@
     return $content;
 }
 
+=head2 create_new_comment content => str, uuid => str
+
+A convenience method that takes a content string and a ticket uuid and creates
+a new comment record, for use in other commands (such as ticket create
+and ticket update).
+
+=cut
+
+sub create_new_comment {
+    my $self = shift;
+    validate(@_, { content => 1, uuid => 1 } );
+    my %args = @_;
+
+    use App::SD::CLI::Command::Ticket::Comment::Create;
+
+    $self->cli->change_attributes( args => \%args );
+    my $command = App::SD::CLI::Command::Ticket::Comment::Create->new(
+        uuid => $args{uuid},
+        cli => $self->cli,
+        type => 'comment',
+    );
+    $command->run();
+}
+
 no Moose::Role;
 
 1;

Added: sd/trunk/lib/App/SD/CLI/Command/Ticket/Comment/Update.pm
==============================================================================
--- (empty file)
+++ sd/trunk/lib/App/SD/CLI/Command/Ticket/Comment/Update.pm	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,27 @@
+package App::SD::CLI::Command::Ticket::Comment::Update;
+use Moose;
+
+extends 'Prophet::CLI::Command::Update';
+
+override run => sub {
+    my $self = shift;
+    $self->require_uuid;
+
+    my $record = $self->_load_record;
+    my @prop_set = $self->prop_set;
+
+    # we don't want to do prop: value editing by default for comments since
+    # it's just a blob of text
+    if (!@prop_set || $self->has_arg('edit')) {
+        my $updated_comment = $self->edit_text($record->prop('content'));
+        $record->set_prop(name => 'content', value => $updated_comment);
+        print "Updated comment " . $record->luid . " (" . $record->uuid . ")\n";
+    } else {
+        super();
+    }
+};
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+
+1;

Modified: sd/trunk/lib/App/SD/CLI/Command/Ticket/Create.pm
==============================================================================
--- sd/trunk/lib/App/SD/CLI/Command/Ticket/Create.pm	(original)
+++ sd/trunk/lib/App/SD/CLI/Command/Ticket/Create.pm	Mon Aug 18 10:18:05 2008
@@ -1,8 +1,6 @@
 package App::SD::CLI::Command::Ticket::Create;
 use Moose;
 
-use App::SD::CLI::Command::Ticket::Comment::Create;
-
 extends 'Prophet::CLI::Command::Create';
 with 'App::SD::CLI::Model::Ticket';
 with 'App::SD::CLI::Command';
@@ -17,7 +15,8 @@
     # only invoke editor if no props specified on the commandline or edit arg
     # specified
     if (!@prop_set || $self->has_arg('edit')) {
-        my @props = grep {!/^id$/} $record->props_to_show;
+        my $do_not_edit = $record->props_not_to_edit;
+        my @props = grep {!/$do_not_edit/} $record->props_to_show;
 
         my %prefill_props;
         # these props must exist in the hash, even if they have no value
@@ -47,7 +46,7 @@
 
         foreach my $prop (keys %$props_ref) {
             $self->set_prop($prop => $props_ref->{$prop})
-                unless $prop eq 'id'; # don't let users create ids
+                unless $prop =~ /$do_not_edit/; # don't let users create ids
         }
 
         super();
@@ -55,16 +54,9 @@
         # retrieve the created record from the superclass
         $record = $self->record();
 
-        if ($comment) {
-            my $args = { content => $comment };
-            $self->cli->change_attributes( args => $args );
-            my $command = App::SD::CLI::Command::Ticket::Comment::Create->new(
-                uuid => $record->uuid,
-                cli => $self->cli,
-                type => 'comment',
-            );
-            $command->run();
-        }
+        $self->create_new_comment( content => $comment, uuid => $record->uuid )
+            if $comment;
+
     } else {
         super();
     }

Added: sd/trunk/lib/App/SD/CLI/Command/Ticket/Update.pm
==============================================================================
--- (empty file)
+++ sd/trunk/lib/App/SD/CLI/Command/Ticket/Update.pm	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,77 @@
+package App::SD::CLI::Command::Ticket::Update;
+use Moose;
+
+extends 'Prophet::CLI::Command::Update';
+with 'App::SD::CLI::Model::Ticket';
+with 'App::SD::CLI::Command';
+
+# use an editor to edit if no props are specified on the commandline,
+# allowing the creation of a new comment in the process
+override run => sub {
+    my $self = shift;
+    $self->require_uuid;
+
+    my $record = $self->_load_record;
+    my $props = $record->get_props;
+
+    if (!@{$self->prop_set} || $self->has_arg('edit')) {
+        my $do_not_edit = $record->props_not_to_edit;
+
+        my @show_props;
+        if ($record->can('props_to_show')) {
+            @show_props = $record->props_to_show;
+        } else {
+            @show_props = sort keys %$props;
+        }
+
+        # props we want to show for editing
+        my %prefill_props = %{$record->get_props};
+        map { $prefill_props{$_} = '' if !exists $prefill_props{$_} } @show_props;
+
+        # add any other defined props onto the end of the ordering and remove
+        # unwanted props
+        my %tmp;
+        map { $tmp{$_} = 1 } @show_props;
+        map { push @show_props, $_ unless exists $tmp{$_} } keys %prefill_props;
+        @show_props = grep !/$do_not_edit/, @show_props;
+
+        my $updated = $self->get_content( type => 'ticket', default_edit => 1,
+                                          prefill_props => \%prefill_props,
+                                          props_order => \@show_props,
+                                          footer => comment_separator(),
+                                      );
+
+        die "Aborted.\n"
+            if length($updated) == 0;
+
+        my ($props_ref, $comment) = $self->parse_record($updated);
+
+        no warnings 'uninitialized';
+
+        foreach my $prop (keys %$props_ref) {
+            my $val = $props_ref->{$prop};
+            $record->set_prop(name => $prop, value => $val) unless
+                ($prop =~ /$do_not_edit/ or $val eq $prefill_props{$prop});
+        }
+
+        # if a formerly existing prop was removed from the output, delete it
+        foreach my $prop (keys %{$record->get_props}) {
+            unless ($prop =~ /$do_not_edit/) {
+                $record->delete_prop(name => $prop) if !exists $props_ref->{$prop};
+            }
+        }
+
+        print 'Updated ticket ' . $record->luid . ' (' . $record->uuid . ")\n";
+
+        $self->create_new_comment( content => $comment, uuid => $record->uuid )
+            if $comment;
+
+    } else {
+        super();
+    }
+};
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+
+1;

Modified: sd/trunk/lib/App/SD/CLI/Model/Ticket.pm
==============================================================================
--- sd/trunk/lib/App/SD/CLI/Model/Ticket.pm	(original)
+++ sd/trunk/lib/App/SD/CLI/Model/Ticket.pm	Mon Aug 18 10:18:05 2008
@@ -11,7 +11,7 @@
 
 =cut
 
-sub comment_separator { "\n\n=== add ticket comment below ===\n"; }
+sub comment_separator { "\n\n=== add new ticket comment below ===\n"; }
 
 =head2 parse_record $str
 
@@ -32,7 +32,7 @@
     my @lines = split "\n", $new_props;
     foreach my $line (@lines) {
         # match prop: value pairs. whitespace in between is ignored.
-        if ($line =~ m/^(.+):\s*(.*)$/) {
+        if ($line =~ m/^([^:]+):\s*(.*)$/) {
             my $prop = $1;
             my $val = $2;
             $props{$prop} = $val unless !($val);

Modified: sd/trunk/lib/App/SD/Model/Ticket.pm
==============================================================================
--- sd/trunk/lib/App/SD/Model/Ticket.pm	(original)
+++ sd/trunk/lib/App/SD/Model/Ticket.pm	Mon Aug 18 10:18:05 2008
@@ -93,6 +93,16 @@
     ('id', 'summary', 'status', 'owner', 'created', 'due', 'creator', 'reported_by')
 }
 
+=head2 props_not_to_edit
+
+A pattern of props not to show in an editor (when creating or updating a
+ticket, for example). Could also be used to determine which props shouldn't be
+user-modifiable.
+
+=cut
+
+sub props_not_to_edit { qr/^(id|created|creator)$/ }
+
 =head2 is_overdue [$date]
 
 Takes an ISO date (or uses the C<date> prop value if no date is given).

Modified: sd/trunk/lib/App/SD/Test.pm
==============================================================================
--- sd/trunk/lib/App/SD/Test.pm	(original)
+++ sd/trunk/lib/App/SD/Test.pm	Mon Aug 18 10:18:05 2008
@@ -103,3 +103,48 @@
 
     return ( $ticket_luid, $ticket_uuid, $comment_luid, $comment_uuid );
 }
+
+=head2 update_ticket_with_editor_ok TICKET_LUID, TICKET_UUID
+
+Updates the ticket given by TICKET_UUID using a spawned editor. It's
+expected that C<$ENV{VISUAL}> has been frobbed into something non-interactive,
+or this test will just hang forever.
+
+Returns the luid and uuid of the comment created during the update (both will
+be undef if none is created).
+
+=cut
+
+sub update_ticket_with_editor_ok {
+    my $self = shift;
+    my $ticket_luid = shift;
+    my $ticket_uuid = shift;
+    my ($comment_luid, $comment_uuid);
+
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    Prophet::Test::run_output_matches( 'sd', [ 'ticket', 'update', $ticket_uuid ],
+        [ qr/Updated ticket (.*?)(?{ $ticket_luid })\s+\((.*)(?{ $ticket_uuid })\)/,
+          qr/Created comment (.*?)(?{ $comment_luid = $1 })\s+\((.*)(?{ $comment_uuid = $2 })\)/ ]
+    );
+
+    return ( $comment_luid, $comment_uuid );
+}
+
+=head2 update_ticket_comment_with_editor_ok COMMENT_LUID, COMMENT_UUID
+
+Updates the ticket comment given by COMMENT_UUID using a spawned editor. It's
+expected that C<$ENV{VISUAL}> has been frobbed into something non-interactive,
+or this test will just hang forever.
+
+=cut
+
+sub update_ticket_comment_with_editor_ok {
+    my $self = shift;
+    my ($comment_luid, $comment_uuid) = @_;
+
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+    Prophet::Test::run_output_matches( 'sd',
+        [ 'ticket', 'comment', 'update', $comment_uuid ],
+        [ qr/Updated comment (.*?)(?{ $comment_luid })\s+\((.*)(?{ $comment_uuid })\)/]
+    );
+}

Modified: sd/trunk/t/02-create-with-editor.t
==============================================================================
--- sd/trunk/t/02-create-with-editor.t	(original)
+++ sd/trunk/t/02-create-with-editor.t	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Prophet::Test tests => 4;
+use App::SD::Test;
+use Cwd;
+
+BEGIN {
+    require File::Temp;
+    $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
+    diag 'export SD_REPO=' . $ENV{'PROPHET_REPO'} . "\n";
+    # frob the editor to use a perl script instead of spawning vi/emacs/etc.
+    $ENV{'VISUAL'} = File::Spec->catfile(getcwd(), 't', 'scripts', 'ticket-create-editor.pl');
+    diag 'export VISUAL=' . $ENV{'VISUAL'} . "\n";
+}
+
+my ($ticket_id, $ticket_uuid, $comment_id, $comment_uuid) = App::SD::Test::create_ticket_with_editor_ok();
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/(\d+) creating tickets with an editor is totally awesome new/]
+);
+
+run_output_matches( 'sd', [ 'ticket', 'show', '--batch', '--id', $ticket_id ],
+    [
+        "id: $ticket_id ($ticket_uuid)",
+        'summary: creating tickets with an editor is totally awesome',
+        'status: new',
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+    ]
+);
+
+run_output_matches( 'sd', [ 'ticket', 'comment', 'show', '--batch', '--id', $comment_id ],
+    [
+        "id: $comment_id ($comment_uuid)",
+        'content: We can create a comment at the same time.',
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+        qr/^ticket: $ticket_uuid$/,
+    ]
+);

Added: sd/trunk/t/03-update-ticket-with-editor.t
==============================================================================
--- (empty file)
+++ sd/trunk/t/03-update-ticket-with-editor.t	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,55 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Prophet::Test tests => 5;
+use App::SD::Test;
+use Cwd;
+
+BEGIN {
+    require File::Temp;
+    $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
+    diag 'export SD_REPO=' . $ENV{'PROPHET_REPO'} . "\n";
+    # frob the editor to use a perl script instead of spawning vi/emacs/etc.
+    $ENV{'VISUAL'} = File::Spec->catfile(getcwd(), 't', 'scripts', 'ticket-update-editor.pl');
+    diag 'export VISUAL=' . $ENV{'VISUAL'} . "\n";
+}
+
+# create ticket
+my ($ticket_id, $ticket_uuid) = create_ticket_ok( '--summary', 'zomg!',
+    '--owner', 'foo at bar.com');
+
+# verify that it's correct (test prop won't be shown)
+run_output_matches( 'sd', [ 'ticket', 'show', '--batch', '--id', $ticket_id ],
+    [
+        "id: $ticket_id ($ticket_uuid)",
+        'summary: zomg!',
+        'status: new',
+        'owner: foo at bar.com',
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+    ]
+);
+
+# update it
+my ($comment_id, $comment_uuid) = App::SD::Test->update_ticket_with_editor_ok($ticket_id, $ticket_uuid);
+
+# check output
+run_output_matches( 'sd', [ 'ticket', 'show', '--batch', '--id', $ticket_id ],
+    [
+        "id: $ticket_id ($ticket_uuid)",
+        'summary: summary changed',
+        'status: new',
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+    ]
+);
+
+run_output_matches( 'sd', [ 'ticket', 'comment', 'show', '--batch', '--id', $comment_id ],
+    [
+        "id: $comment_id ($comment_uuid)",
+        'content: We can create a comment at the same time.',
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+        qr/^ticket: $ticket_uuid$/,
+    ]
+);

Added: sd/trunk/t/04-update-ticket-comment-with-editor.t
==============================================================================
--- (empty file)
+++ sd/trunk/t/04-update-ticket-comment-with-editor.t	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,50 @@
+#!/usr/bin/perl -w
+use strict;
+
+use Prophet::Test tests => 5;
+use App::SD::Test;
+use Cwd;
+
+BEGIN {
+    require File::Temp;
+    $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
+    diag 'export SD_REPO=' . $ENV{'PROPHET_REPO'} . "\n";
+    # frob the editor to use a perl script instead of spawning vi/emacs/etc.
+    $ENV{'VISUAL'} = File::Spec->catfile(getcwd(), 't', 'scripts', 'ticket-comment-update-editor.pl');
+    diag 'export VISUAL=' . $ENV{'VISUAL'} . "\n";
+}
+
+# create ticket
+my ($ticket_id, $ticket_uuid) = create_ticket_ok( '--summary', 'zomg!' );
+
+# create comment
+my ($comment_id, $comment_uuid) = create_ticket_comment_ok(
+    '--content' => 'a new comment', '--id' => $ticket_id
+);
+
+# verify that it's correct (test prop won't be shown)
+run_output_matches( 'sd',
+    [ 'ticket', 'comment', 'show', '--batch', '--id', $comment_id ],
+    [
+        "id: $comment_id ($comment_uuid)",
+        qr/a new comment/,
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+        "ticket: $ticket_uuid",
+    ]
+);
+
+# update it
+App::SD::Test->update_ticket_comment_with_editor_ok($comment_id, $comment_uuid);
+
+# check output
+run_output_matches( 'sd',
+    [ 'ticket', 'comment', 'show', '--batch', '--id', $comment_id ],
+    [
+        "id: $comment_id ($comment_uuid)",
+        qr/huzzah!/,
+        qr/^created: \d{4}-\d{2}-\d{2}.+$/,
+        qr/^creator: .+ at .+$/,
+        "ticket: $ticket_uuid",
+    ]
+);

Added: sd/trunk/t/scripts/ticket-comment-update-editor.pl
==============================================================================
--- (empty file)
+++ sd/trunk/t/scripts/ticket-comment-update-editor.pl	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,8 @@
+#!/usr/bin/perl -i
+
+# perl script to trick Proc::InvokeEditor with for the ticket update command
+
+while (<>) {
+     print "huzzah!";
+}
+

Added: sd/trunk/t/scripts/ticket-create-editor.pl
==============================================================================
--- (empty file)
+++ sd/trunk/t/scripts/ticket-create-editor.pl	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,10 @@
+#!/usr/bin/perl -i
+
+# perl script to trick Proc::InvokeEditor with for the ticket create command
+
+while (<>) {
+     s/^summary:.*$/summary: creating tickets with an editor is totally awesome/;
+     print;
+     print "We can create a comment at the same time.\n" if /^===/;
+}
+

Added: sd/trunk/t/scripts/ticket-update-editor.pl
==============================================================================
--- (empty file)
+++ sd/trunk/t/scripts/ticket-update-editor.pl	Mon Aug 18 10:18:05 2008
@@ -0,0 +1,11 @@
+#!/usr/bin/perl -i
+
+# perl script to trick Proc::InvokeEditor with for the ticket update command
+
+while (<>) {
+     s/^summary:.*$/summary: summary changed/;
+     s/^owner:.*//;
+     print;
+     print "We can create a comment at the same time.\n" if /^===/;
+}
+



More information about the Bps-public-commit mailing list