[Rt-commit] rt branch, 4.2/serialize-ticket, created. rt-4.2.13-122-gce38161
Shawn Moore
shawn at bestpractical.com
Fri Feb 10 17:21:24 EST 2017
The branch, 4.2/serialize-ticket has been created
at ce381610a24c7ea1b90f95c64e74b2b0c95b85e6 (commit)
- Log -----------------------------------------------------------------
commit 946461108f16d6008a4195b8db61f52343bf9a13
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Feb 10 20:03:16 2017 +0000
Add support for exporting individual tickets
This adds a --limit-tickets=1,2 option to rt-serializer
diff --git a/lib/RT/Migrate/Serializer.pm b/lib/RT/Migrate/Serializer.pm
index 3855ee9..d4e412a 100644
--- a/lib/RT/Migrate/Serializer.pm
+++ b/lib/RT/Migrate/Serializer.pm
@@ -91,6 +91,7 @@ sub Init {
FollowACL
Queues
CustomFields
+ TicketIDs
HyperlinkUnmigrated
Clone
Incremental
@@ -302,7 +303,12 @@ sub PushBasics {
$self->PushCollections(qw(Topics Classes));
}
- if ($self->{Queues}) {
+ if ($self->{TicketIDs}) {
+ my $tickets = RT::Tickets->new(RT->SystemUser);
+ $tickets->Limit(FIELD => 'id', OPERATOR => 'IN', VALUE => $self->{TicketIDs});
+ $self->PushObj($tickets);
+ }
+ elsif ($self->{Queues}) {
my $queues = RT::Queues->new(RT->SystemUser);
$queues->Limit(FIELD => 'id', OPERATOR => 'IN', VALUE => $self->{Queues});
$self->PushObj($queues);
@@ -416,8 +422,13 @@ sub Observe {
my $from = $args{from};
if ($obj->isa("RT::Ticket")) {
return 0 if $obj->Status eq "deleted" and not $self->{FollowDeleted};
+
+ my $id = $obj->EffectiveId;
+ return 0 if $self->{TicketIDs} && none { $id == $_ } @{ $self->{TicketIDs} };
+
my $queue = $obj->Queue;
return 0 if $self->{Queues} && none { $queue == $_ } @{ $self->{Queues} };
+
return $self->{FollowTickets};
} elsif ($obj->isa("RT::Queue")) {
my $id = $obj->Id;
diff --git a/sbin/rt-serializer.in b/sbin/rt-serializer.in
index c9aa484..e4e3cba 100644
--- a/sbin/rt-serializer.in
+++ b/sbin/rt-serializer.in
@@ -106,6 +106,7 @@ GetOptions(
"acls!",
"limit-queues=s@",
"limit-cfs=s@",
+ "limit-tickets=s@",
"hyperlink-unmigrated!",
"clone",
@@ -177,6 +178,11 @@ if ($OPT{'limit-cfs'}) {
$args{CustomFields} = \@cf_ids;
}
+if ($OPT{'limit-tickets'}) {
+ $args{FollowTickets} = 1;
+ $args{TicketIDs} = [ split ',', join ',', @{ $OPT{'limit-tickets'} } ];
+}
+
if (($OPT{clone} or $OPT{incremental})
and grep { /^(users|groups|deleted|scrips|tickets|acls)$/ } keys %OPT) {
die "You cannot specify object types when cloning.\n\nPlease see $0 --help.\n";
@@ -375,6 +381,11 @@ that set of queues (and the tickets in them) will be serialized.
Takes a list of custom field IDs or names separated by commas. When provided,
only that set of custom fields will be serialized.
+=item B<--limit-tickets>
+
+Takes a list of ticket IDs separated by commas. When provided, only that
+set of tickets will be serialized.
+
=item B<--hyperlink-unmigrated>
Replace links to local records which are not being migrated with hyperlinks.
commit ca06c92a43357ef8b3e402b75039675236aa58ff
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Feb 10 20:25:26 2017 +0000
Add --attributes flag to serializer
diff --git a/lib/RT/Migrate/Serializer.pm b/lib/RT/Migrate/Serializer.pm
index d4e412a..e8212ad 100644
--- a/lib/RT/Migrate/Serializer.pm
+++ b/lib/RT/Migrate/Serializer.pm
@@ -71,6 +71,7 @@ sub Init {
FollowScrips => 0,
FollowTickets => 1,
FollowACL => 0,
+ FollowAttributes => 0,
Clone => 0,
Incremental => 0,
@@ -89,6 +90,7 @@ sub Init {
FollowScrips
FollowTickets
FollowACL
+ FollowAttributes
Queues
CustomFields
TicketIDs
@@ -264,9 +266,11 @@ sub PushBasics {
$self->PushObj( $cfs );
# Global attributes
- my $attributes = RT::Attributes->new( RT->SystemUser );
- $attributes->LimitToObject( $RT::System );
- $self->PushObj( $attributes );
+ if ($self->{FollowAttributes}) {
+ my $attributes = RT::Attributes->new( RT->SystemUser );
+ $attributes->LimitToObject( $RT::System );
+ $self->PushObj( $attributes );
+ }
# Global ACLs
if ($self->{FollowACL}) {
@@ -457,6 +461,8 @@ sub Observe {
} elsif ($grp->Domain eq "SystemInternal") {
return 0 if $grp->UID eq $from;
}
+ } elsif ($obj->isa("RT::Attribute")) {
+ return $self->{FollowAttributes};
}
return 1;
diff --git a/sbin/rt-serializer.in b/sbin/rt-serializer.in
index e4e3cba..5c1aa34 100644
--- a/sbin/rt-serializer.in
+++ b/sbin/rt-serializer.in
@@ -104,6 +104,7 @@ GetOptions(
"scrips!",
"tickets!",
"acls!",
+ "attributes!",
"limit-queues=s@",
"limit-cfs=s@",
"limit-tickets=s@",
@@ -127,9 +128,10 @@ $args{AllUsers} = $OPT{users} if defined $OPT{users};
$args{AllGroups} = $OPT{groups} if defined $OPT{groups};
$args{FollowDeleted} = $OPT{deleted} if defined $OPT{deleted};
-$args{FollowScrips} = $OPT{scrips} if defined $OPT{scrips};
-$args{FollowTickets} = $OPT{tickets} if defined $OPT{tickets};
-$args{FollowACL} = $OPT{acls} if defined $OPT{acls};
+$args{FollowScrips} = $OPT{scrips} if defined $OPT{scrips};
+$args{FollowTickets} = $OPT{tickets} if defined $OPT{tickets};
+$args{FollowACL} = $OPT{acls} if defined $OPT{acls};
+$args{FollowAttributes} = $OPT{attributes} if defined $OPT{attributes};
$args{HyperlinkUnmigrated} = $OPT{'hyperlink-unmigrated'} if defined $OPT{'hyperlink-unmigrated'};
@@ -184,7 +186,7 @@ if ($OPT{'limit-tickets'}) {
}
if (($OPT{clone} or $OPT{incremental})
- and grep { /^(users|groups|deleted|scrips|tickets|acls)$/ } keys %OPT) {
+ and grep { /^(users|groups|deleted|scrips|tickets|acls|attributes)$/ } keys %OPT) {
die "You cannot specify object types when cloning.\n\nPlease see $0 --help.\n";
}
@@ -367,6 +369,11 @@ scrips and templates to be serialized.
No ACLs are serialized by default; this option forces all ACLs to be
serialized.
+=item B<--attributes>
+
+No attributes (which include saved searches, dashboards) are serialized
+by default; this option forces all attributes to be serialized.
+
=item B<--no-tickets>
Skip serialization of all ticket data.
commit ce381610a24c7ea1b90f95c64e74b2b0c95b85e6
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Feb 10 21:49:16 2017 +0000
Add way to follow renames (and existing objects) across imports
rt-importer --follow-renames
diff --git a/lib/RT/Migrate/Importer.pm b/lib/RT/Migrate/Importer.pm
index c0faade..4fad760 100644
--- a/lib/RT/Migrate/Importer.pm
+++ b/lib/RT/Migrate/Importer.pm
@@ -71,6 +71,7 @@ sub Init {
DumpObjects => undef,
HandleError => undef,
ExcludeOrganization => undef,
+ FollowRenames => undef,
@_,
);
@@ -78,6 +79,7 @@ sub Init {
$self->{OriginalId} = $args{OriginalId};
$self->{ExcludeOrganization} = $args{ExcludeOrganization};
+ $self->{FollowRenames} = $args{FollowRenames};
$self->{Progress} = $args{Progress};
@@ -294,11 +296,15 @@ sub MergeBy {
sub Qualify {
my $self = shift;
- my ($string) = @_;
- return $string if $self->{Clone};
- return $string if not defined $self->{Organization};
- return $string if $self->{ExcludeOrganization};
- return $string if $self->{Organization} eq $RT::Organization;
+ my ($string, $force) = @_;
+
+ if (!$force) {
+ return $string if $self->{Clone};
+ return $string if not defined $self->{Organization};
+ return $string if $self->{ExcludeOrganization};
+ return $string if $self->{Organization} eq $RT::Organization;
+ }
+
return $self->{Organization}.": $string";
}
@@ -344,6 +350,42 @@ sub Create {
return $obj;
}
+sub LoadForReuse {
+ my $self = shift;
+ my ($class, $uid) = @_;
+
+ return if grep { $class eq $_ } 'RT::Transaction', 'RT::Attribute';
+
+ my $attribute = RT::Attribute->new( RT->SystemUser );
+ $attribute->LoadByCols(
+ Name => 'ImporterOrigin',
+ ObjectType => $class,
+ Content => $self->Qualify($uid, 1),
+ );
+ if (!$attribute->Id) {
+ return;
+ }
+
+ my $obj = $attribute->Object;
+ return $obj;
+}
+
+sub RegisterForReuse {
+ my $self = shift;
+ my ($obj, $uid) = @_;
+
+ return if grep { ref($obj) eq $_ } 'RT::Transaction', 'RT::Attribute';
+ return if $self->LoadForReuse(ref($obj), $uid);
+
+ my $attr = RT::Attribute->new(RT->SystemUser);
+ $attr->Create(
+ Object => $obj,
+ Name => 'ImporterOrigin',
+ Content => $self->Qualify($uid, 1),
+ ContentType => 'text/plain',
+ );
+}
+
sub ReadStream {
my $self = shift;
my ($fh) = @_;
@@ -400,31 +442,47 @@ sub ReadStream {
if $class eq "RT::Queue";
my $origid = $data->{id};
- my $obj = $self->Create( $class, $uid, $data );
- return unless $obj;
+ my $obj;
- # If it's a ticket, we might need to create a
- # TicketCustomField for the previous ID
- if ($class eq "RT::Ticket" and $self->{OriginalId}) {
- my $value = $self->{ExcludeOrganization}
- ? $origid
- : $self->Organization . ":$origid";
-
- my ($id, $msg) = $obj->AddCustomFieldValue(
- Field => $self->{OriginalId},
- Value => $value,
- RecordTransaction => 0,
- );
- warn "Failed to add custom field to $uid: $msg"
- unless $id;
+ if ($self->{FollowRenames}) {
+ $obj = $self->LoadForReuse( $class, $uid );
+ if ($obj) {
+ $self->Resolve( $uid => $class => $obj->Id );
+ #$self->MergeValues( $obj, $data );
+ }
}
- # If it's a CF, we don't know yet if it's global (the OCF
- # hasn't been created yet) to store away the CF for later
- # inspection
- push @{$self->{NewCFs}}, $uid
- if $class eq "RT::CustomField"
- and $obj->LookupType =~ /^RT::Queue/;
+ if (!$obj) {
+ $obj = $self->Create( $class, $uid, $data );
+ return unless $obj;
+
+ if ($self->{FollowRenames}) {
+ $self->RegisterForReuse( $obj, $uid );
+ }
+
+ # If it's a ticket, we might need to create a
+ # TicketCustomField for the previous ID
+ if ($class eq "RT::Ticket" and $self->{OriginalId}) {
+ my $value = $self->{ExcludeOrganization}
+ ? $origid
+ : $self->Organization . ":$origid";
+
+ my ($id, $msg) = $obj->AddCustomFieldValue(
+ Field => $self->{OriginalId},
+ Value => $value,
+ RecordTransaction => 0,
+ );
+ warn "Failed to add custom field to $uid: $msg"
+ unless $id;
+ }
+
+ # If it's a CF, we don't know yet if it's global (the OCF
+ # hasn't been created yet) to store away the CF for later
+ # inspection
+ push @{$self->{NewCFs}}, $uid
+ if $class eq "RT::CustomField"
+ and $obj->LookupType =~ /^RT::Queue/;
+ }
$self->{Progress}->($obj) if $self->{Progress};
}
diff --git a/lib/RT/Migrate/Importer/File.pm b/lib/RT/Migrate/Importer/File.pm
index cf3362b..04eed1b 100644
--- a/lib/RT/Migrate/Importer/File.pm
+++ b/lib/RT/Migrate/Importer/File.pm
@@ -192,7 +192,7 @@ sub SaveState {
NewQueues NewCFs
SkipTransactions Pending Invalid
UIDs
- OriginalId ExcludeOrganization Clone
+ OriginalId ExcludeOrganization FollowRenames Clone
/;
Storable::nstore(\%data, $self->{Statefile});
diff --git a/sbin/rt-importer.in b/sbin/rt-importer.in
index 7c957ec..86338c8 100644
--- a/sbin/rt-importer.in
+++ b/sbin/rt-importer.in
@@ -96,6 +96,7 @@ GetOptions(
"resume!",
"originalid|i=s",
"exclude-organization",
+ "follow-renames",
"ask",
"ignore-errors",
@@ -146,6 +147,7 @@ my $import = RT::Migrate::Importer::File->new(
Directory => $dir,
OriginalId => $OPT{originalid},
ExcludeOrganization => $OPT{'exclude-organization'},
+ FollowRenames => $OPT{'follow-renames'},
DumpObjects => $OPT{dump},
Resume => $OPT{resume},
HandleError => $error_handler,
@@ -252,6 +254,16 @@ Ordinarily certain records (groups, queues, the B<--originalid> custom field)
include the organization name of the original RT instance. Use this option to
suppress that behavior and use the original name directly.
+=item B<--follow-renames>
+
+This advises rt-importer to try harder to reuse previously-imported
+records, such as custom fields, instead of creating new ones. This
+requires the importer to do more work for each record and so has
+performance penalty. This is intended for sites that frequently import
+small collections.
+
+This is not meant to be used with C<--clone> or C<--incremental>.
+
=item B<--ask>
Prompt for action when an error occurs inserting a record into the
-----------------------------------------------------------------------
More information about the rt-commit
mailing list