[Rt-commit] rt branch, 4.4/serialize-json-initialdata, updated. rt-4.4.1-443-g1cf47f3
Shawn Moore
shawn at bestpractical.com
Fri Mar 24 13:59:41 EDT 2017
The branch, 4.4/serialize-json-initialdata has been updated
via 1cf47f3816e864fd049a13a75f453541c2c84c7f (commit)
via 2b7e860b10c5f56f678897110ba64930345d2236 (commit)
via d93b6de21557b06bcccbfab41faff4ca2dd2dd2f (commit)
via 5ba8bef3baf8653a4bfeaec50836a603c7ac34a4 (commit)
via a2b04e3a7d85ad8b49b51e57a57e3ae39101a8ac (commit)
via d5d8803ddd6d4b751b825863c2a2891a2fa31853 (commit)
from e3621bc2c0a64b937ce94e844a87f031eeb9e4ea (commit)
Summary of changes:
lib/RT/Migrate/Serializer/JSON.pm | 10 ++-
sbin/rt-merge-initialdata.in | 180 +++++++++++++++++++++++++++++++++++---
2 files changed, 176 insertions(+), 14 deletions(-)
- Log -----------------------------------------------------------------
commit d5d8803ddd6d4b751b825863c2a2891a2fa31853
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Thu Mar 23 22:07:38 2017 +0000
Default FollowTickets and FollowTransactions to 0 for initialdata
These don't round-trip anyway
diff --git a/lib/RT/Migrate/Serializer/JSON.pm b/lib/RT/Migrate/Serializer/JSON.pm
index 1d7e524..c849ddb 100644
--- a/lib/RT/Migrate/Serializer/JSON.pm
+++ b/lib/RT/Migrate/Serializer/JSON.pm
@@ -59,8 +59,10 @@ sub Init {
my $self = shift;
my %args = (
- Directory => undef,
- Force => undef,
+ Directory => undef,
+ Force => undef,
+ FollowTickets => 0,
+ FollowTransactions => 0,
@_,
);
@@ -79,7 +81,7 @@ sub Init {
$self->{Records} = {};
- $self->SUPER::Init(@_);
+ $self->SUPER::Init(%args);
}
sub Export {
commit a2b04e3a7d85ad8b49b51e57a57e3ae39101a8ac
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 24 17:16:20 2017 +0000
Default to exporting scrips and ACLs
diff --git a/lib/RT/Migrate/Serializer/JSON.pm b/lib/RT/Migrate/Serializer/JSON.pm
index c849ddb..48ebdf8 100644
--- a/lib/RT/Migrate/Serializer/JSON.pm
+++ b/lib/RT/Migrate/Serializer/JSON.pm
@@ -63,6 +63,8 @@ sub Init {
Force => undef,
FollowTickets => 0,
FollowTransactions => 0,
+ FollowScrips => 1,
+ FollowACL => 1,
@_,
);
commit 5ba8bef3baf8653a4bfeaec50836a603c7ac34a4
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 24 17:46:47 2017 +0000
Add CLI opt parser and docs for rt-merge-initialdata
diff --git a/sbin/rt-merge-initialdata.in b/sbin/rt-merge-initialdata.in
index 463b29a..dfb3649 100644
--- a/sbin/rt-merge-initialdata.in
+++ b/sbin/rt-merge-initialdata.in
@@ -79,12 +79,27 @@ use RT;
RT::LoadConfig();
RT::Init();
+use Getopt::Long;
+use Pod::Usage qw//;
use List::MoreUtils 'uniq';
use JSON ();
my $JSON = JSON->new->canonical;
-die "usage: $0 base edited\n" unless @ARGV == 2;
-my ($base_file, $edited_file) = @ARGV;
+my %OPT;
+GetOptions(
+ \%OPT,
+ "help|h",
+
+ "base=s",
+ "edited=s",
+);
+
+exit Pod::Usage::pod2usage(-verbose => 1) if $OPT{help};
+
+my $base_file = $OPT{base};
+my $edited_file = $OPT{edited};
+
+exit Pod::Usage::pod2usage unless $base_file && $edited_file;
my $base_records = slurp_json($base_file);
my $edited_records = slurp_json($edited_file);
@@ -316,3 +331,51 @@ sub decide_merge {
}
}
+=head1 NAME
+
+rt-merge-initialdata - Merge changes from an edited initialdata
+
+=head1 SYNOPSIS
+
+ rt-merge-initialdata --base initialdata.json --edited updated.json
+
+
+This tool allows you to edit a JSON-based initialdata file and merge
+those changes into your RT instance. The intended workflow is you first
+create an initialdata from your running RT config with:
+
+ sbin/rt-serializer --sync --format JSON
+
+Then, copy the resulting C<initialdata.json> into a new file. Edit that
+C<updated.json> to create, update, and delete records (see below for
+considerations).
+
+Then run F<rt-merge-initialdata> like so:
+
+ rt-merge-initialdata --base initialdata.json --edited updated.json
+
+F<rt-merge-initialdata> will update any records that you edited, create
+any records you added, and disable (or delete) any records you removed.
+Note that the C<id> field is used to track identity across the base,
+edited, and database versions of the same record, so take care when
+dealing with it. (Any record without an C<id> is treated as a new one to
+be created, and any record in the base which does not have a
+corresponding C<id> in the edited file will be disabled/deleted).
+
+=head2 OPTIONS
+
+=over
+
+=item B<--base> I<filename>
+
+The filename of the "base" initialdata. This should be a pristine initialdata
+file exported by F<sbin/rt-serializer>.
+
+=item B<--edited> I<filename>
+
+The filename of the "edited" initialdata. This should be a copy of the
+filename provided to C<--base> with your edits made to it.
+
+=back
+
+=cut
commit d93b6de21557b06bcccbfab41faff4ca2dd2dd2f
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 24 17:47:34 2017 +0000
Add --merge-strategy flag
diff --git a/sbin/rt-merge-initialdata.in b/sbin/rt-merge-initialdata.in
index dfb3649..29c4c90 100644
--- a/sbin/rt-merge-initialdata.in
+++ b/sbin/rt-merge-initialdata.in
@@ -92,6 +92,7 @@ GetOptions(
"base=s",
"edited=s",
+ "merge-strategy=s",
);
exit Pod::Usage::pod2usage(-verbose => 1) if $OPT{help};
@@ -101,6 +102,13 @@ my $edited_file = $OPT{edited};
exit Pod::Usage::pod2usage unless $base_file && $edited_file;
+my $merge_strategy = $OPT{'merge-strategy'};
+
+die "Invalid value for --merge-strategy. Expected 'base', 'current', 'edited', or 'quit'."
+ unless !$merge_strategy || $merge_strategy =~ /^(base|current|edited|quit)$/;
+
+RT->Config->Set( LogToSTDERR => $OPT{log} ) if $OPT{log};
+
my $base_records = slurp_json($base_file);
my $edited_records = slurp_json($edited_file);
@@ -306,6 +314,13 @@ sub decide_merge {
print " Base value: $args{base_value}\n";
print " Edited value: $args{edited_value}\n";
print " Database value: $args{current_value}\n";
+
+ if ($merge_strategy) {
+ print "Using specified merge strategy '$merge_strategy'.\n" unless $OPT{quiet};
+ exit if $merge_strategy eq 'quit';
+ return $merge_strategy;
+ }
+
print "Would you like to (q)uit, (s)ee more context, or set value to (b)ase, (e)dited, or (d)atabase? ";
my $answer = (scalar <STDIN>) // "";
@@ -362,6 +377,13 @@ dealing with it. (Any record without an C<id> is treated as a new one to
be created, and any record in the base which does not have a
corresponding C<id> in the edited file will be disabled/deleted).
+Any changes made in the database after the base was exported will be
+untouched by F<rt-merge-initialdata>. If it turns out that a field was
+changed in both the edited initialdata I<and> the database, then a
+conflict will be presented to you with a prompt asking which version to
+keep. The C<--merge-strategy> flag lets you decide in advance to handle
+all such conflicts using a consistent strategy, to avoid prompting.
+
=head2 OPTIONS
=over
@@ -376,6 +398,35 @@ file exported by F<sbin/rt-serializer>.
The filename of the "edited" initialdata. This should be a copy of the
filename provided to C<--base> with your edits made to it.
+=item B<--merge-strategy> I<strategy>
+
+Automatically resolve all conflicts without prompting the user. The
+following merge strategies are available:
+
+=over 4
+
+=item C<edited>
+
+Take the edits as specified in the edited initialdata, overwriting the
+change made in the database after the base was exported.
+
+=item C<current>
+
+Keep the database's current value, ignoring the change made in the
+edited initialdata.
+
+=item C<base>
+
+Revert to the base initialdata's value, rolling back the change made in
+the database and ignoring the change made in the edited initialdata.
+
+=item C<quit>
+
+Abort processing at the first conflict. Note that this will likely
+result in a subset of the edits being applied to your database.
+
+=back
+
=back
=cut
commit 2b7e860b10c5f56f678897110ba64930345d2236
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 24 17:47:50 2017 +0000
Add --quiet and --log options
diff --git a/sbin/rt-merge-initialdata.in b/sbin/rt-merge-initialdata.in
index 29c4c90..d5fc6f0 100644
--- a/sbin/rt-merge-initialdata.in
+++ b/sbin/rt-merge-initialdata.in
@@ -89,6 +89,8 @@ my %OPT;
GetOptions(
\%OPT,
"help|h",
+ "quiet|q!",
+ "log=s",
"base=s",
"edited=s",
@@ -133,6 +135,7 @@ for my $type (@record_types) {
$edited_records->{$type},
$type,
);
+ RT->Logger->info("Merging changes from $type: " . scalar(@$new_records) . " new records, " . scalar(@$updated_records) . " updated, " . scalar(@$deleted_records) . " deleted");
my $collection_class = "RT::" . ($class_type{$type} || $type);
my $record_class = $collection_class->RecordClass;
@@ -309,11 +312,13 @@ sub decide_merge {
local $| = 1;
while (1) {
- print "\n";
- print "Conflict resolution required for $type #$id $args{column}:\n";
- print " Base value: $args{base_value}\n";
- print " Edited value: $args{edited_value}\n";
- print " Database value: $args{current_value}\n";
+ unless ($OPT{quiet} && $merge_strategy) {
+ print "\n";
+ print "Conflict resolution required for $type #$id $args{column}:\n";
+ print " Base value: $args{base_value}\n";
+ print " Edited value: $args{edited_value}\n";
+ print " Database value: $args{current_value}\n";
+ }
if ($merge_strategy) {
print "Using specified merge strategy '$merge_strategy'.\n" unless $OPT{quiet};
@@ -427,6 +432,14 @@ result in a subset of the edits being applied to your database.
=back
+=item B<--quiet>
+
+Avoid nonessential output.
+
+=item B<--log> I<level>
+
+Adjust LogToSTDERR config option.
+
=back
=cut
commit 1cf47f3816e864fd049a13a75f453541c2c84c7f
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 24 17:58:12 2017 +0000
Add --dryrun flag
diff --git a/sbin/rt-merge-initialdata.in b/sbin/rt-merge-initialdata.in
index d5fc6f0..911b718 100644
--- a/sbin/rt-merge-initialdata.in
+++ b/sbin/rt-merge-initialdata.in
@@ -77,7 +77,6 @@ BEGIN {
use RT;
RT::LoadConfig();
-RT::Init();
use Getopt::Long;
use Pod::Usage qw//;
@@ -91,6 +90,7 @@ GetOptions(
"help|h",
"quiet|q!",
"log=s",
+ "dryrun",
"base=s",
"edited=s",
@@ -111,6 +111,11 @@ die "Invalid value for --merge-strategy. Expected 'base', 'current', 'edited', o
RT->Config->Set( LogToSTDERR => $OPT{log} ) if $OPT{log};
+RT::Init();
+
+my $dryrun = $OPT{'dryrun'};
+RT->Logger->debug("dryrun enabled") if $dryrun;
+
my $base_records = slurp_json($base_file);
my $edited_records = slurp_json($edited_file);
@@ -140,7 +145,12 @@ for my $type (@record_types) {
my $collection_class = "RT::" . ($class_type{$type} || $type);
my $record_class = $collection_class->RecordClass;
- $new_for_insertdata{$type} = $new_records;
+ if ($dryrun) {
+ RT->Logger->debug("Skipping create of " . scalar(@$new_records) . "x $type because of dry run.") if @$new_records;
+ }
+ else {
+ $new_for_insertdata{$type} = $new_records;
+ }
for (@$updated_records) {
my ($base, $edited) = @$_;
@@ -193,6 +203,11 @@ for my $type (@record_types) {
}
}
+ if ($dryrun) {
+ RT->Logger->debug("Skipping update $record_class #$id $column from '$current_value' to '$new_value' because of dry run.");
+ next;
+ }
+
my ($ok, $msg) = $record->$method($new_value);
if ($ok) {
RT->Logger->debug("Updated $record_class #$id $column: $msg");
@@ -218,9 +233,17 @@ for my $type (@record_types) {
my ($ok, $msg);
if ($record->can('SetDisabled') || $record->_Accessible('Disabled', 'write')) {
+ if ($dryrun) {
+ RT->Logger->debug("Skipping disabling of $record_class #$id because of dry run.");
+ next;
+ }
($ok, $msg) = $record->SetDisabled(1);
}
elsif ($record->can('Delete')) {
+ if ($dryrun) {
+ RT->Logger->debug("Skipping delete of $record_class #$id because of dry run.");
+ next;
+ }
($ok, $msg) = $record->Delete;
}
else {
@@ -236,8 +259,10 @@ for my $type (@record_types) {
}
}
-my $new_json = $JSON->encode(\%new_for_insertdata);
-$RT::Handle->InsertData(\$new_json, undef, disconnect_after => 0);
+if (grep { scalar(@$_) } values %new_for_insertdata) {
+ my $new_json = $JSON->encode(\%new_for_insertdata);
+ $RT::Handle->InsertData(\$new_json, undef, disconnect_after => 0);
+}
sub find_differences {
my $base_records = shift;
@@ -440,6 +465,12 @@ Avoid nonessential output.
Adjust LogToSTDERR config option.
+=item B<--dryrun>
+
+Attempt to process changes but skip making any actual changes to the
+database. Changes that would have been made are logged at level C<debug>
+so you may wish to pass C<--log=debug> to see them.
+
=back
=cut
-----------------------------------------------------------------------
More information about the rt-commit
mailing list