[Bps-public-commit] r16687 - in sd/branches/init-and-clone: . lib/App lib/App/SD lib/App/SD/CLI lib/App/SD/CLI/Command lib/App/SD/CLI/Command/Help lib/App/SD/CLI/Command/Ticket lib/App/SD/CLI/Model lib/App/SD/Model lib/App/SD/Replica lib/App/SD/Replica/hm t

jesse at bestpractical.com jesse at bestpractical.com
Thu Nov 6 01:48:56 EST 2008


Author: jesse
Date: Thu Nov  6 01:48:55 2008
New Revision: 16687

Added:
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Config.pm
   sd/branches/init-and-clone/lib/App/SD/Config.pm
   sd/branches/init-and-clone/t/05-config-file-loading.t
Removed:
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Server.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Ticket/Resolve.pm
Modified:
   sd/branches/init-and-clone/   (props changed)
   sd/branches/init-and-clone/lib/App/SD.pm
   sd/branches/init-and-clone/lib/App/SD/CLI.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Command.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Environment.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Command/Ticket/Update.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Dispatcher.pm
   sd/branches/init-and-clone/lib/App/SD/CLI/Model/Ticket.pm
   sd/branches/init-and-clone/lib/App/SD/Model/Ticket.pm
   sd/branches/init-and-clone/lib/App/SD/Replica/hm.pm
   sd/branches/init-and-clone/lib/App/SD/Replica/hm/PushEncoder.pm
   sd/branches/init-and-clone/lib/App/SD/Replica/rt/PullEncoder.pm
   sd/branches/init-and-clone/lib/App/SD/Test.pm
   sd/branches/init-and-clone/t/01-create.t
   sd/branches/init-and-clone/t/02-create-with-editor.t
   sd/branches/init-and-clone/t/03-update-ticket-with-editor.t
   sd/branches/init-and-clone/t/sd-comments.t
   sd/branches/init-and-clone/t/sd-hm-comments.t
   sd/branches/init-and-clone/t/sd-hm-comments1.t
   sd/branches/init-and-clone/t/sd-hm-group.t
   sd/branches/init-and-clone/t/sd-hm-tag.t
   sd/branches/init-and-clone/t/sd-hm.t
   sd/branches/init-and-clone/t/sd-rt-hm-single.t
   sd/branches/init-and-clone/t/sd-rt-permission.t
   sd/branches/init-and-clone/t/sd-rt.t

Log:
 r49325 at 31b:  jesse | 2008-11-06 10:20:09 +0900
 Mergedown and local changes for the clone/init branch


Modified: sd/branches/init-and-clone/lib/App/SD.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD.pm	Thu Nov  6 01:48:55 2008
@@ -1,9 +1,16 @@
 package App::SD;
 use Moose;
+use App::SD::Config;
 
 extends 'Prophet::App';
 our $VERSION = '0.01';
 
+has +config => (
+    default => sub {
+        my $self = shift;
+        return App::SD::Config->new(app_handle => $self);
+    }
+);
 
 sub database_settings {
 { 

Modified: sd/branches/init-and-clone/lib/App/SD/CLI.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI.pm	Thu Nov  6 01:48:55 2008
@@ -10,7 +10,7 @@
     default => 'App::SD',
 );
 
-sub dispatcher { "App::SD::CLI::Dispatcher" }
+sub dispatcher_class { "App::SD::CLI::Dispatcher" }
 
 __PACKAGE__->meta->make_immutable;
 no Moose;

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Command.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Command.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Command.pm	Thu Nov  6 01:48:55 2008
@@ -50,7 +50,8 @@
         if (my $footer = $args{footer}) {
             $text .= $footer;
         }
-        $content = $self->edit_text($text);
+    
+           $content = $self->edit_text($text);
         # user aborted their text editor without changing anything; signify
         # this to the caller by returning nothing
         $content = '' if $content eq $text;

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help.pm	Thu Nov  6 01:48:55 2008
@@ -43,6 +43,7 @@
 $cmd help attachments -  Working with ticket attachments
 $cmd help sync        -  Publishing and importing ticket databases
 $cmd help environment -  Environment variables which affect sd
+$cmd help config      -  Database configuration variables
 
 EOF
 

Added: sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Config.pm
==============================================================================
--- (empty file)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Config.pm	Thu Nov  6 01:48:55 2008
@@ -0,0 +1,30 @@
+package App::SD::CLI::Command::Help::Config;
+use Moose;
+extends 'App::SD::CLI::Command::Help';
+
+sub run {
+    my $self = shift;
+    $self->print_header('Configuration Options');
+
+print <<EOF
+  SD supports both a user-wide configuration (\$HOME/.sdrc and per-database
+  configuration (/path/to/repo/sdrc). If both configuration files are present,
+  the database-specific config file will be used.
+
+  Currently, the following configuration variables are available:
+
+  reporter_email = foo\@bar.com
+    Specifies an email address to use as the default for tickets'
+    reported_by field.
+
+  summary_format_ticket = %4s },\$luid | %-11.11s,status | %-60.60s,summary
+    Specifies how to format ticket summaries (when listing tickets, e.g.).
+EOF
+
+}
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+
+1;
+

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Environment.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Environment.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Command/Help/Environment.pm	Thu Nov  6 01:48:55 2008
@@ -9,6 +9,9 @@
 print <<EOF
   export SD_REPO=/path/to/sd/replica
     Specify where the ticket database SD is using should reside
+
+  export SD_CONFIG=/path/to/sd/config/file
+    Specify where the configuration file SD is using should reside
 EOF
 
 }

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Command/Ticket/Update.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Command/Ticket/Update.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Command/Ticket/Update.pm	Thu Nov  6 01:48:55 2008
@@ -14,7 +14,7 @@
     my $self = shift;
     $self->require_uuid;
     my $record = $self->_load_record;
-   return super() if (@{$self->prop_set} && !$self->has_arg('edit'));
+   return super() if ($self->context->prop_names && !$self->has_arg('edit'));
     my $template_to_edit = $self->create_record_template($record);
 
     my $done = 0;

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Dispatcher.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Dispatcher.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Dispatcher.pm	Thu Nov  6 01:48:55 2008
@@ -1,67 +1,102 @@
 #!/usr/bin/env perl
 package App::SD::CLI::Dispatcher;
-use strict;
-use warnings;
 use Prophet::CLI::Dispatcher -base;
+use Moose;
 
-
-on qr'^\?(.*)$' => sub {my $cmd = $1 || '';  run ('help'. $cmd,  @_); last_rule;};
+# "sd ?about" => "sd help about"
+rewrite qr/^\?(.*)/ => sub { "help $1" };
 
 # 'sd about' -> 'sd help about', 'sd copying' -> 'sd help copying'
-on qr'^(about|copying)$' => sub { run('help '.$1, @_); last_rule;};
-on qr'^help (?:push|pull|publish|server)$' => sub { run('help sync', @_); last_rule;};
-on qr'^help (?:env)$' => sub { run('help environment', @_); last_rule;};
-on qr'^help (?:ticket)$' => sub { run('help tickets', @_); last_rule;};
-on qr'^help ticket (list|search|find)$' => sub { run('help search', @_); last_rule;};
-on qr'^help (?:list|find)$' => sub { run('help search', @_); last_rule;};
-
-on qr{ticket \s+ give \s+ (.*) \s+ (.*)}xi => sub {
-    my %args = @_;
-    $args{context}->set_arg(type => 'ticket');
-    $args{context}->set_arg(id => $1);
-    $args{context}->set_arg(owner => $2);
-    run('update', %args);
+rewrite [ ['about', 'copying'] ] => sub { "help $1" };
+
+under help => sub {
+    on about   => run_command('Help::About');
+    on config  => run_command('Help::Config');
+    on copying => run_command('Help::Copying');
+
+    on [ ['author', 'authors'] ]         => run_command('Help::Authors');
+    on [ ['environment', 'env'] ]        => run_command('Help::Environment');
+    on [ ['ticket', 'tickets'] ]         => run_command('Help::Tickets');
+    on [ ['attachment', 'attachments'] ] => run_command('Help::Attachments');
+    on [ ['comment', 'comments'] ]       => run_command('Help:::Comments');
+
+    on [
+        ['ticket', 'attachment', 'comment'],
+        ['list', 'search', 'find'],
+    ] => run_command('Help::Search');
+
+    on [ ['search', 'list', 'find'] ] => run_command('Help::Search');
+
+    on [ ['sync', 'push', 'pull', 'publish', 'server'] ]
+        => run_command('Help::Sync');
+};
+
+on help => run_command('Help');
+
+under ticket => sub {
+    on create   => run_command('Ticket::Create');
+    on basics   => run_command('Ticket::Basics');
+    on comments => run_command('Ticket::Comments');
+    on comment  => run_command('Ticket::Comment');
+    on details  => run_command('Ticket::Details');
+    on search   => run_command('Ticket::Search');
+    on show     => run_command('Ticket::Show');
+    on update   => run_command('Ticket::Update');
+
+    on ['give', qr/.*/, qr/.*/] => sub {
+        my $self = shift;
+        $self->context->set_arg(id    => $2);
+        $self->context->set_arg(owner => $3);
+        run('ticket update', $self, @_);
+    };
+
+    on [ ['resolve', 'close'] ] => sub {
+        my $self = shift;
+        $self->context->set_prop(status => 'closed');
+        run('ticket update', $self, @_);
+    };
+
+    under comment => sub {
+        on create => run_command('Ticket::Comment::Create');
+        on update => run_command('Ticket::Comment::Update');
+    };
+
+    under attachment => sub {
+        on create => run_command('Ticket::Attachment::Create');
+        on search => run_command('Ticket::Attachment::Search');
+    };
+};
+
+under attachment => sub {
+    on content => run_command('Attachment::Content');
+    on create  => run_command('Attachment::Create');
 };
 
 # allow type to be specified via primary commands, e.g.
 # 'sd ticket display --id 14' -> 'sd display --type ticket --id 14'
 on qr{^(ticket|comment|attachment) \s+ (.*)}xi => sub {
-    my %args = @_;
-    $args{context}->set_arg(type => $1);
-    run($2, %args);
+    my $self = shift;
+    $self->context->set_arg(type => $1);
+    run($2, $self, @_);
 };
 
-#on qr'^about$' => sub { run('help about'); last_rule;};
+__PACKAGE__->dispatcher->add_rule(
+    Path::Dispatcher::Rule::Dispatch->new(
+        dispatcher => Prophet::CLI::Dispatcher->dispatcher,
+    ),
+);
+
+sub run_command { Prophet::CLI::Dispatcher::run_command(@_) }
+
+sub class_names {
+    my $self = shift;
+    my $name = shift;
 
+    ("App::SD::CLI::Command::$name", $self->SUPER::class_names($name, @_));
+}
 
-# Run class based commands
-on qr{.} => sub {
-    my %args = @_;
-    my $cli = $args{cli};
-
-    my @possible_classes;
-
-    # we want to dispatch on the original command "ticket attachment create"
-    # AND on the command we received "create"
-    for ([@{ $args{dispatching_on} }], [split ' ', $_]) {
-        my @pieces = __PACKAGE__->resolve_builtin_aliases(@$_);
-
-        while (@pieces) {
-            push @possible_classes, "App::SD::CLI::Command::" . join '::', @pieces;
-            shift @pieces;
-        }
-    }
-
-    for my $class (@possible_classes) {
-        if ($args{cli}->_try_to_load_cmd_class($class)) {
-            return $args{got_command}->($class) 
-        }
-    }
-
-    # found no class-based rule
-    next_rule;
-};
-
+__PACKAGE__->meta->make_immutable;
+no Moose;
 
 1;
 

Modified: sd/branches/init-and-clone/lib/App/SD/CLI/Model/Ticket.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/CLI/Model/Ticket.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/CLI/Model/Ticket.pm	Thu Nov  6 01:48:55 2008
@@ -160,7 +160,7 @@
 
     # glue all the parts together
     return join(
-        "\n\n",
+        "\n",
 
         $self->_build_template_section(
             header => metadata_separator,

Added: sd/branches/init-and-clone/lib/App/SD/Config.pm
==============================================================================
--- (empty file)
+++ sd/branches/init-and-clone/lib/App/SD/Config.pm	Thu Nov  6 01:48:55 2008
@@ -0,0 +1,34 @@
+package App::SD::Config;
+use Moose;
+use File::Spec;
+
+extends 'Prophet::Config';
+
+# We can't just frob $ENV{PROPHET_APP_CONFIG} the way the sd script does
+# with $ENV{PROPHET_REPO} because we need to instantiate App::SD::CLI to
+# get the location of the repo root, and then Prophet would load its own
+# config file before we got around to messing with the env var
+before 'app_config_file' => sub {
+    my $self = shift;
+
+    # The order of preference for config files is:
+    #   $ENV{SD_CONFIG} > fs_root/sdrc > fs_root/prophetrc (for backcompat)
+    #   $HOME/.sdrc > $ENV{PROPHET_APP_CONFIG} > $HOME/.prophetrc
+
+    $ENV{'PROPHET_APP_CONFIG'}
+            =  $self->file_if_exists($ENV{'SD_CONFIG'})
+            || $self->file_if_exists(
+                File::Spec->catfile($self->app_handle->handle->fs_root => 'sdrc'))
+            || $self->file_if_exists(
+                # backcompat
+                File::Spec->catfile($self->app_handle->handle->fs_root => 'prophetrc'))
+            || $self->file_if_exists(
+                File::Spec->catfile($ENV{'HOME'}.'/.sdrc'))
+            || $ENV{'PROPHET_APP_CONFIG'} # don't overwrite with nothing
+            || ''; # don't write undef
+};
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+
+1;

Modified: sd/branches/init-and-clone/lib/App/SD/Model/Ticket.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/Model/Ticket.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/Model/Ticket.pm	Thu Nov  6 01:48:55 2008
@@ -34,7 +34,7 @@
 =cut
 
 sub default_prop_reported_by {
-    shift->app_handle->config->{reporter_email} or $ENV{EMAIL}
+    shift->app_handle->config->get('reporter_email') or $ENV{EMAIL}
 }
 
 =head2 canonicalize_prop_status

Modified: sd/branches/init-and-clone/lib/App/SD/Replica/hm.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/Replica/hm.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/Replica/hm.pm	Thu Nov  6 01:48:55 2008
@@ -27,7 +27,6 @@
 
 sub BUILD {
     my $self = shift;
-
     require Net::Jifty;
     my ($server, $props) = $self->{url} =~ m/^hm:(.*?)(?:\|(.*))?$/
         or die "Can't parse Hiveminder server spec. Expected hm:http://hiveminder.com or hm:http://hiveminder.com|props";
@@ -39,13 +38,12 @@
         $uri->userinfo(undef);
     }
     $self->remote_url("$uri");
+    $self->hm_username($username);
     ( $username, $password ) = $self->prompt_for_login( $uri, $username ) unless $password;
-
     if ( $props ) {
         my %props = split /=|;/, $props;
         $self->props( \%props );
     }
-
     $self->hm(
         Net::Jifty->new(
             site        => $self->remote_url,
@@ -55,18 +53,17 @@
             password => $password
         )
     );
-
-    $self->hm_username($username);
 }
 
 =head2 uuid
 
-Return the replica SVN repository's UUID
+Return the replica's UUID
 
 =cut
 
 sub uuid {
     my $self = shift;
+    Carp::cluck "- can't make a uuid for this" unless ($self->remote_url && $self->hm_username);
     return $self->uuid_for_url( join( '/', $self->remote_url, $self->hm_username ) );
 }
 
@@ -96,17 +93,15 @@
 
 sub find_matching_tasks {
     my $self = shift;
-    my %args = (
-        owner        => 'me',
-        group        => 0,
-        requestor    => 'me',
-        not_complete => 1,
-    );
+    my %args;
     if ( my $props = $self->props ) {
         while ( my ($k, $v) = each %$props ) { $args{$k} = $v }
     }
-    my $tasks = $self->hm->act( 'TaskSearch', %args )->{content}->{tasks};
-    return $tasks;
+    my $status = $self->hm->act( 'TaskSearch', %args );
+    unless ( $status->{'success'} ) {
+        die "couldn't search";
+    }
+    return $status->{content}{tasks};
 }
 
 sub record_pushed_transactions {

Modified: sd/branches/init-and-clone/lib/App/SD/Replica/hm/PushEncoder.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/Replica/hm/PushEncoder.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/Replica/hm/PushEncoder.pm	Thu Nov  6 01:48:55 2008
@@ -68,6 +68,9 @@
         repeat_stacking => 0,
         %{ $self->_recode_props_for_create($change) }
     );
+    unless ( $task->{'success'} ) {
+        die "Couldn't create a task: ". $self->decode_error( $task );
+    }
 
     my $txns = $self->sync_source->hm->search( 'TaskTransaction', task_id => $task->{content}->{id} );
 
@@ -76,6 +79,19 @@
     return $task->{content}->{id};
 }
 
+sub decode_error {
+    my $self = shift;
+    my $status = shift;
+    my $msg = '';
+    $msg .= $status->{'error'} if defined $status->{'error'};
+    if ( $status->{'field_errors'} ) {
+        while ( my ($k, $v) = each %{ $status->{'field_errors'} } ) {
+            $msg .= "field '$k' - '$v'\n";
+        }
+    }
+    return $msg;
+}
+
 sub integrate_comment {
     my $self = shift;
     my ($change, $changeset) = validate_pos( @_, { isa => 'Prophet::Change' }, {isa => 'Prophet::ChangeSet'} );
@@ -93,7 +109,7 @@
     );
     return $status->{'content'}{'id'} if $status->{'success'};
 
-    die "Couldn't integrate comment: ". $status->{'error'};
+    die "Couldn't integrate comment: ". $self->decode_error( $status );
 }
 
 sub integrate_ticket_update {
@@ -113,7 +129,7 @@
     );
     return $status->{'content'}{'id'} if $status->{'success'};
 
-    die "Couldn't integrate comment: ". $status->{'error'};
+    die "Couldn't integrate comment: ". $self->decode_error( $status );
 }
 
 sub _recode_props_for_create {

Modified: sd/branches/init-and-clone/lib/App/SD/Replica/rt/PullEncoder.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/Replica/rt/PullEncoder.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/Replica/rt/PullEncoder.pm	Thu Nov  6 01:48:55 2008
@@ -144,39 +144,41 @@
 sub transcode_one_txn {
     my ($self, $txn, $ticket) = (@_);
     
-        if ( my $sub = $self->can( '_recode_txn_' . $txn->{'Type'} ) ) {
-            my $changeset = Prophet::ChangeSet->new(
-                {   original_source_uuid => $self->sync_source->uuid,
-                    original_sequence_no => $txn->{'id'},
-                    creator => $self->resolve_user_id_to( email_address => $txn->{'Creator'} ),
-                }
-            );
-
-            if ( ( $txn->{'Ticket'} ne $ticket->{$self->sync_source->uuid . '-id'} ) && $txn->{'Type'} !~ /^(?:Comment|Correspond)$/ ) {
-                warn "Skipping a data change from a merged ticket" . $txn->{'Ticket'} . ' vs ' . $ticket->{$self->sync_source->uuid . '-id'};
-                next;
-            }
-
+    my $sub = $self->can( '_recode_txn_' . $txn->{'Type'} );
+    unless ( $sub ) {
+        die "Transaction type $txn->{Type} (for transaction $txn->{id}) not implemented yet";
+    }
 
+    my $changeset = Prophet::ChangeSet->new(
+        {   original_source_uuid => $self->sync_source->uuid,
+            original_sequence_no => $txn->{'id'},
+            creator => $self->resolve_user_id_to( email_address => $txn->{'Creator'} ),
+        }
+    );
 
-            delete $txn->{'OldValue'} if ( $txn->{'OldValue'} eq '');
-            delete $txn->{'NewValue'} if ( $txn->{'NewValue'} eq '');
+    if ( $txn->{'Ticket'} ne $ticket->{$self->sync_source->uuid . '-id'}
+        && $txn->{'Type'} !~ /^(?:Comment|Correspond)$/
+    ) {
+        warn "Skipping a data change from a merged ticket" . $txn->{'Ticket'}
+            .' vs '. $ticket->{$self->sync_source->uuid . '-id'};
+        next;
+    }
 
-            $sub->( $self, ticket => $ticket, txn          => $txn, changeset    => $changeset);
-            $self->translate_prop_names($changeset);
+    delete $txn->{'OldValue'} if ( $txn->{'OldValue'} eq '');
+    delete $txn->{'NewValue'} if ( $txn->{'NewValue'} eq '');
 
-            if (my $attachments = delete $txn->{'_attachments'}) {
-               for my $attach (@$attachments) { 
-                    $self->_recode_attachment_create( ticket => $ticket, txn => $txn, changeset =>$changeset, attachment => $attach); 
-               }
-            }
+    $sub->( $self, ticket => $ticket, txn          => $txn, changeset    => $changeset);
+    $self->translate_prop_names($changeset);
 
-            return $changeset;
-        } else {
-            die "Transaction type $txn->{Type} (for transaction $txn->{id}) not implemented yet";
-        }
+    if (my $attachments = delete $txn->{'_attachments'}) {
+       for my $attach (@$attachments) { 
+            $self->_recode_attachment_create( ticket => $ticket, txn => $txn, changeset =>$changeset, attachment => $attach); 
+       }
     }
 
+    return $changeset;
+}
+
 
 sub _recode_attachment_create {
     my $self   = shift;
@@ -227,39 +229,34 @@
     my %args = validate( @_, { txn => 1, ticket => 1, changeset => 1 } );
 
     my $change = Prophet::Change->new(
-        {   record_type   => 'ticket',
-            record_uuid   => $self->sync_source->uuid_for_remote_id( $args{'ticket'}->{$self->sync_source->uuid . '-id'} ),
+        {   record_type => 'ticket',
+            record_uuid => $self->sync_source->uuid_for_remote_id( $args{'ticket'}->{$self->sync_source->uuid . '-id'} ),
             change_type => 'update_file'
         }
     );
 
-    if ( $args{txn}->{Field} eq 'Queue' ) {
+    my ($field, $old, $new) = @{ $args{txn} }{qw(Field OldValue NewValue)};
+
+    if ( $field eq 'Queue' ) {
         my $current_queue = $args{'ticket'}->{$self->sync_source->uuid .'-queue'};
         my $user          = $args{txn}->{Creator};
         if ( $args{txn}->{Description} =~ /Queue changed from (.*) to $current_queue by $user/ ) {
-            $args{txn}->{OldValue} = $1;
-            $args{txn}->{NewValue} = $current_queue;
+            $old = $1;
+            $new = $current_queue;
         }
 
-    } elsif ( $args{txn}->{Field} eq 'Owner' ) {
-        $args{'txn'}->{NewValue} = $self->resolve_user_id_to( name => $args{'txn'}->{'NewValue'} );
-        $args{'txn'}->{OldValue} = $self->resolve_user_id_to( name => $args{'txn'}->{'OldValue'} );
+    } elsif ( $field eq 'Owner' ) {
+        $new = $self->resolve_user_id_to( email_address => $new );
+        $old = $self->resolve_user_id_to( email_address => $old );
     }
 
     $args{'changeset'}->add_change( { change => $change } );
-    if ( $args{'ticket'}->{ $args{txn}->{Field} } eq $args{txn}->{'NewValue'} ) {
-        $args{'ticket'}->{ $args{txn}->{Field} } = $args{txn}->{'OldValue'};
-    } else {
-        $args{'ticket'}->{ $args{txn}->{Field} } = $args{txn}->{'OldValue'};
-        warn "Update consistency problem: " . $args{'ticket'}->{ $args{txn}->{Field} } . " != " . $args{txn}->{'NewValue'};
-    }
-    $change->add_prop_change(
-        name => $args{txn}->{'Field'},
-        old  => $args{txn}->{'OldValue'},
-        new  => $args{txn}->{'NewValue'}
-
-    );
+    
+    # XXX: This line is kind of magic
+    # TODO: check if it's sill needed
+    $args{'ticket'}->{ $field } = $old;
 
+    $change->add_prop_change( name => $field, old => $old, new => $new );
 }
 
 *_recode_txn_Steal = \&_recode_txn_Set;
@@ -418,15 +415,23 @@
     my $self = shift;
     my $attr = shift;
     my $id   = shift;
-    return undef unless ($id);
+    return undef unless $id;
 
+    local $@;
     my $user = eval { RT::Client::REST::User->new( rt => $self->sync_source->rt, id => $id )->retrieve};
-    if (my $err = $@) {
-            warn $err;
-           return $attr eq 'name' ? 'Unknown user' : 'nobody at localhost';
-        }
-    return $user->$attr();
-
+    if ( my $err = $@ ) {
+        warn $err;
+        return $attr eq 'name' ? 'Unknown user' : 'unknown at localhost';
+    }
+    my $name = $user->name;
+    if ( lc $name eq 'nobody' ) {
+        return $attr eq 'name' ? 'nobody' : undef;
+    }
+    elsif ( lc $name eq 'RT_System' ) {
+        return $attr eq 'name' ? 'system' : undef;
+    } else {
+        return $user->$attr();
+    }
 }
 
 memoize 'resolve_user_id_to';

Modified: sd/branches/init-and-clone/lib/App/SD/Test.pm
==============================================================================
--- sd/branches/init-and-clone/lib/App/SD/Test.pm	(original)
+++ sd/branches/init-and-clone/lib/App/SD/Test.pm	Thu Nov  6 01:48:55 2008
@@ -8,9 +8,10 @@
 use File::Spec;
 use Cwd qw/getcwd/;
 use base qw/Exporter/;
-our @EXPORT = qw(create_ticket_ok create_ticket_comment_ok get_uuid_for_luid get_luid_for_uuid);
-$ENV{'EMAIL'} = "someone\@example.com";
-$ENV{'PROPHET_APP_CONFIG'} = "t/prophet_testing.conf";
+our @EXPORT = qw(create_ticket_ok create_ticket_with_editor_ok create_ticket_comment_ok get_uuid_for_luid get_luid_for_uuid);
+$ENV{'SD_CONFIG'} = 't/prophet_testing.conf';
+delete $ENV{'PROPHET_APP_CONFIG'};
+$ENV{'EDITOR'} = '/bin/true';
 
 =head2 create_ticket_ok ARGS
 
@@ -101,7 +102,8 @@
     my ( $ticket_uuid, $ticket_luid, $comment_uuid, $comment_luid );
     local $Test::Builder::Level = $Test::Builder::Level + 1;
     Prophet::Test::run_output_matches( 'sd', [ 'ticket', 'create' ],
-        [qr/Created ticket (.*?)(?{ $ticket_luid = $1})\s+\((.*)(?{ $ticket_uuid = $2 })\)/, qr/Created comment (.*?)(?{ $comment_luid = $1})\s+\((.*)(?{ $comment_uuid = $2 })\)/]
+        [qr/Created ticket (.*?)(?{ $ticket_luid = $1})\s+\((.*)(?{ $ticket_uuid = $2 })\)/,
+        qr/Created comment (.*?)(?{ $comment_luid = $1})\s+\((.*)(?{ $comment_uuid = $2 })\)/]
     );
 
     return ( $ticket_luid, $ticket_uuid, $comment_luid, $comment_uuid );
@@ -168,3 +170,20 @@
     $ENV{'EDITOR'} = File::Spec->catfile(getcwd(), 't', 'scripts', $script);
     diag 'export EDITOR=' . $ENV{'EDITOR'} . "\n";
 }
+
+=head2 write_to_file FILENAME DATA
+
+Takes the string given in DATA and writes it to the file whose name is given
+by FILENAME.
+
+=cut
+
+sub write_to_file {
+    my ($self, $filename, $data) = @_;
+
+    open FH, '>', $filename;
+    print FH $data;
+    close FH;
+}
+
+1;

Modified: sd/branches/init-and-clone/t/01-create.t
==============================================================================
--- sd/branches/init-and-clone/t/01-create.t	(original)
+++ sd/branches/init-and-clone/t/01-create.t	Thu Nov  6 01:48:55 2008
@@ -34,7 +34,6 @@
         'status: new',
         qr/^created: \d{4}-\d{2}-\d{2}.+$/,
         qr/^creator: /,
-        qr/^reported_by: /,
         'milestone: alpha',
         "original_replica: " . replica_uuid,
     ]

Modified: sd/branches/init-and-clone/t/02-create-with-editor.t
==============================================================================
--- sd/branches/init-and-clone/t/02-create-with-editor.t	(original)
+++ sd/branches/init-and-clone/t/02-create-with-editor.t	Thu Nov  6 01:48:55 2008
@@ -13,7 +13,7 @@
 run_script( 'sd', [ 'init']);
 
 my $replica_uuid = replica_uuid;
-my ($ticket_id, $ticket_uuid, $comment_id, $comment_uuid) = App::SD::Test::create_ticket_with_editor_ok();
+my ($ticket_id, $ticket_uuid, $comment_id, $comment_uuid) = create_ticket_with_editor_ok();
 
 run_output_matches( 'sd', [ 'ticket',
     'list', '--regex', '.' ],
@@ -27,7 +27,6 @@
         'status: new',
         qr/^created: \d{4}-\d{2}-\d{2}.+$/,
         qr/^creator: /,
-        qr/^reported_by: /,
         'milestone: alpha',
         "original_replica: $replica_uuid",
     ]

Modified: sd/branches/init-and-clone/t/03-update-ticket-with-editor.t
==============================================================================
--- sd/branches/init-and-clone/t/03-update-ticket-with-editor.t	(original)
+++ sd/branches/init-and-clone/t/03-update-ticket-with-editor.t	Thu Nov  6 01:48:55 2008
@@ -27,7 +27,6 @@
         'owner: foo at bar.com',
         qr/^created: \d{4}-\d{2}-\d{2}.+$/,
         qr/^creator: /,
-        qr/^reported_by: /,
         'milestone: alpha',
         "original_replica: $replica_uuid",
     ]
@@ -44,7 +43,6 @@
         'status: new',
         qr/^created: \d{4}-\d{2}-\d{2}.+$/,
         qr/^creator: /,
-        qr/^reported_by: /,
         'milestone: alpha',
         "original_replica: $replica_uuid",
     ]

Added: sd/branches/init-and-clone/t/05-config-file-loading.t
==============================================================================
--- (empty file)
+++ sd/branches/init-and-clone/t/05-config-file-loading.t	Thu Nov  6 01:48:55 2008
@@ -0,0 +1,113 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use Prophet::Test tests => 10;
+use App::SD::Test;
+use File::Temp qw/tempdir/;
+use Path::Class;
+
+
+no warnings 'once';
+
+BEGIN {
+    require File::Temp;
+    $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = $ENV{'HOME'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
+    diag "export SD_REPO=".$ENV{'PROPHET_REPO'} ."\n";
+    diag "export HOME=".$ENV{'PROPHET_REPO'} ."\n";
+    $ENV{'PROPHET_APP_CONFIG'} = undef; # clear this because Prophet::Test sets it
+}
+
+# Tests the config file order of preference laid out in App::SD::Config
+run_script( 'sd', [ 'init']);
+
+
+
+# create from sd
+my ($yatta_id, $yatta_uuid) = create_ticket_ok( '--summary', 'YATTA');
+
+# default config file
+diag("Testing default config file\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/(\d+) YATTA new/]
+);
+
+$ENV{'SD_CONFIG'} = $ENV{'PROPHET_APP_CONFIG'} = undef;  # override App::SD::Test
+ok( ! $ENV{'SD_CONFIG'}, "SD_CONFIG env var has been cleared" );
+ok( ! $ENV{'PROPHET_APP_CONFIG'}, "PROPHET_APP_CONFIG env var has been cleared" );
+
+# Test from least-preferred to most preferred, leaving the least-preferred
+# files in place to make sure the next-most-preferred file is preferred
+# over all the files beneath it.
+
+diag("Testing \$HOME/.prophetrc\n");
+
+my $config_filename = $ENV{'HOME'} . '/.prophetrc';
+
+App::SD::Test->write_to_file($config_filename,
+    "summary_format_ticket = %4s },\$luid | %-11.11s,status | %-60.60s,summary\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/\s+(\d+) } new         YATTA/]
+);
+
+diag("Testing PROPHET_APP_CONFIG\n");
+
+$config_filename = $ENV{'HOME'} . '/config-test';
+$ENV{'PROPHET_APP_CONFIG'} = $config_filename;
+
+App::SD::Test->write_to_file($config_filename,
+    "summary_format_ticket = %-9.9s,status | %-60.60s,summary\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/new       YATTA/]
+);
+
+diag("Testing \$HOME/.sdrc\n");
+
+$config_filename = $ENV{'HOME'} . '/.sdrc';
+
+App::SD::Test->write_to_file($config_filename,
+    "summary_format_ticket = %4s },\$luid | %-7.7s,status | %-60.60s,summary\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/\s+(\d+) } new     YATTA/]
+);
+
+diag("Testing fs_root/prophetrc\n");
+
+$config_filename = $ENV{'SD_REPO'} . '/prophetrc';
+
+App::SD::Test->write_to_file($config_filename,
+    "summary_format_ticket = %4s },\$luid | %-10.10s,status | %-60.60s,summary\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/\s+(\d+) } new        YATTA/]
+);
+
+diag("Testing fs_root/sdrc\n");
+
+$config_filename = $ENV{'SD_REPO'} . '/sdrc';
+
+App::SD::Test->write_to_file($config_filename,
+    "summary_format_ticket = %4s },\$luid | %-6.6s,status | %-60.60s,summary\n");
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/\s+(\d+) } new    YATTA/]
+);
+
+diag("Testing SD_CONFIG\n");
+
+$ENV{'SD_CONFIG'} = 't/prophet_testing.conf';
+
+run_output_matches( 'sd', [ 'ticket',
+    'list', '--regex', '.' ],
+    [ qr/(\d+) YATTA new/]
+);

Modified: sd/branches/init-and-clone/t/sd-comments.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-comments.t	(original)
+++ sd/branches/init-and-clone/t/sd-comments.t	Thu Nov  6 01:48:55 2008
@@ -2,7 +2,7 @@
 
 use strict;
 
-use Prophet::Test tests => 8;
+use Prophet::Test tests => 10;
 use App::SD::Test;
 no warnings 'once';
 
@@ -48,6 +48,7 @@
     [],
     "Found the comment"
 );
+
 run_output_matches(
     'sd',
     [   qw/ticket comment update --uuid/, $comment_uuid,
@@ -58,6 +59,7 @@
     [],
     "updated the comment"
 );
+
 run_output_matches(
     'sd',
     [ qw/ticket comment show --batch --uuid/, $comment_uuid ],
@@ -79,3 +81,30 @@
     [],
     "Found the comment when we tried to search for all comments on a ticket by the ticket's uuid"
 );
+
+run_output_matches(
+    'sd',
+    [   qw/ticket comment update --uuid/, $comment_uuid,
+        '--',
+        qw/--content/,                    "A\nmultiline\ncomment"
+    ],
+    [qr/comment \d+ \($comment_uuid\) updated/],
+    [],
+    "updated the comment to a multiline content"
+);
+
+run_output_matches(
+    'sd',
+    [ qw/ticket comment show --batch --uuid/, $comment_uuid ],
+    [ qr/id: (\d+) \($comment_uuid\)/, 
+        qr/^content: A/,
+        qr/^multiline$/,
+        qr/^comment$/,
+        qr/created: /i,
+        qr/creator: /i,
+        "original_replica: $replica_uuid",
+        "ticket: $yatta_uuid"
+    ],
+    [],
+    "Found the comment new version"
+);

Modified: sd/branches/init-and-clone/t/sd-hm-comments.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-hm-comments.t	(original)
+++ sd/branches/init-and-clone/t/sd-hm-comments.t	Thu Nov  6 01:48:55 2008
@@ -41,7 +41,6 @@
 my ($yatta_uuid, $yatta_id);
 {
     my ($ret, $out, $err) = run_script( 'sd', [ 'clone', '--from', $sd_hm_url ] );
-
     run_output_matches( 'sd', [qw(ticket list --regex .)], [qr/(.*?)(?{ $yatta_uuid = $1 }) YATTA (.*)/] );
     ( $ret, $out, $err ) = run_script( 'sd', [ qw(ticket show --batch --id), $yatta_uuid ] );
     $yatta_id = $1 if $out =~ /^id: (\d+) /m;

Modified: sd/branches/init-and-clone/t/sd-hm-comments1.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-hm-comments1.t	(original)
+++ sd/branches/init-and-clone/t/sd-hm-comments1.t	Thu Nov  6 01:48:55 2008
@@ -35,6 +35,8 @@
 
 my $sd_hm_url = "hm:$URL";
 
+run_script('sd', [qw(init)]);
+
 my ($yatta_id, $yatta_uuid) = create_ticket_ok( qw(--summary YATTA --status new) );
 {
     my ( $ret, $out, $err ) = run_script( 'sd', [ 'push','--to', $sd_hm_url ] );

Modified: sd/branches/init-and-clone/t/sd-hm-group.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-hm-group.t	(original)
+++ sd/branches/init-and-clone/t/sd-hm-group.t	Thu Nov  6 01:48:55 2008
@@ -66,8 +66,10 @@
 
 # pull
 {
-    eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_hm_url ] ) };
+    eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'clone', '--from', $sd_hm_url ] ) };
     like($out, qr/one changeset/, "only one change");
+    diag($out);
+    diag($err);
 }
 
 my ($flyman_uuid, $flyman_id );
@@ -122,7 +124,7 @@
 rmtree( $ENV{'SD_REPO'}, {keep_root => 1} );
 
 
-my $sd_hm_url = "hm:$URL|group=$gname";
+$sd_hm_url = "hm:$URL|group=$gname";
 # pull
 {
     eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_hm_url ] ) };

Modified: sd/branches/init-and-clone/t/sd-hm-tag.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-hm-tag.t	(original)
+++ sd/branches/init-and-clone/t/sd-hm-tag.t	Thu Nov  6 01:48:55 2008
@@ -54,7 +54,7 @@
 my ( $ret, $out, $err );
 
 my $sd_hm_url = "hm:$URL|tag=mytag";
-eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_hm_url ] ) };
+eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'clone', '--from', $sd_hm_url ] ) };
 like($out, qr/one changeset/, "only one change");
 
 my ($flyman_uuid, $flyman_id );

Modified: sd/branches/init-and-clone/t/sd-hm.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-hm.t	(original)
+++ sd/branches/init-and-clone/t/sd-hm.t	Thu Nov  6 01:48:55 2008
@@ -42,7 +42,7 @@
 my ( $ret, $out, $err );
 
 my $sd_hm_url = "hm:$URL";
-eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_hm_url ] ) };
+eval { ( $ret, $out, $err ) = run_script( 'sd', [ 'clone', '--from', $sd_hm_url ] ) };
 diag $err;
 
 my ($flyman_uuid, $flyman_id );

Modified: sd/branches/init-and-clone/t/sd-rt-hm-single.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-rt-hm-single.t	(original)
+++ sd/branches/init-and-clone/t/sd-rt-hm-single.t	Thu Nov  6 01:48:55 2008
@@ -82,7 +82,7 @@
 
 as_bob {
     local $ENV{SD_REPO} = $ENV{'PROPHET_REPO'};
-    ( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from', $sd_hm_url ] );
+    ( $ret, $out, $err ) = run_script( 'sd', [ 'clone', '--from', $sd_hm_url ] );
     diag($err) if ($err);
     run_output_matches( 'sd', [ 'ticket', 'list', '--regex', '.' ], [qr/^(.*?)(?{ $yatta_id = $1 }) YATTA .*/] );
     $yatta_uuid = get_uuid_for_luid($yatta_id);

Modified: sd/branches/init-and-clone/t/sd-rt-permission.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-rt-permission.t	(original)
+++ sd/branches/init-and-clone/t/sd-rt-permission.t	Thu Nov  6 01:48:55 2008
@@ -19,6 +19,7 @@
     require File::Temp;
     $ENV{'PROPHET_REPO'} = $ENV{'SD_REPO'} = File::Temp::tempdir( CLEANUP => 0 ) . '/_svb';
     diag "export SD_REPO=".$ENV{'PROPHET_REPO'} ."\n";
+
 }
 
 use Prophet::Test tests => 22;
@@ -64,7 +65,7 @@
 
 as_alice {
     run_script( 'sd', [ 'init']);
-    ($ret, $out, $err) = run_script('sd', ['pull', '--from',  $sd_alice_url]);
+    ($ret, $out, $err) = run_script('sd', ['pull', '--from',  $sd_alice_url, '--force']);
     ok($ret);
     like($out, qr/No new changesets/);
 

Modified: sd/branches/init-and-clone/t/sd-rt.t
==============================================================================
--- sd/branches/init-and-clone/t/sd-rt.t	(original)
+++ sd/branches/init-and-clone/t/sd-rt.t	Thu Nov  6 01:48:55 2008
@@ -51,7 +51,7 @@
 )->store( text => "Ticket Comment" );
 
 my ( $ret, $out, $err );
-( $ret, $out, $err ) = run_script( 'sd', [ 'pull', '--from',  $sd_rt_url ] );
+( $ret, $out, $err ) = run_script( 'sd', [ 'clone', '--from',  $sd_rt_url ] );
 my ( $yatta_id, $flyman_id );
 run_output_matches( 'sd', [ 'ticket', 'list', '--regex', '.' ], 
     [qr/(.*?)(?{ $flyman_id = $1 }) Fly Man new/] );
@@ -77,6 +77,8 @@
 run_output_matches_unordered( 'sd', [ 'ticket',                     'list', '--regex', '.' ], [sort  "$yatta_id YATTA new", "$flyman_id Fly Man open" ]);
 
 ( $ret, $out, $err ) = run_script( 'sd', [ 'push', '--to', $sd_rt_url ] );
+diag ($out);
+diag ($err);
 my @tix = $rt->search(
     type  => 'ticket',
     query => "Subject='YATTA'"



More information about the Bps-public-commit mailing list