summaryrefslogtreecommitdiffstats
path: root/extensions/TellUsMore/lib/VersionMirror.pm
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/TellUsMore/lib/VersionMirror.pm')
-rw-r--r--extensions/TellUsMore/lib/VersionMirror.pm207
1 files changed, 207 insertions, 0 deletions
diff --git a/extensions/TellUsMore/lib/VersionMirror.pm b/extensions/TellUsMore/lib/VersionMirror.pm
new file mode 100644
index 000000000..24c645d91
--- /dev/null
+++ b/extensions/TellUsMore/lib/VersionMirror.pm
@@ -0,0 +1,207 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::TellUsMore::VersionMirror;
+
+use strict;
+use base qw(Exporter);
+our @EXPORT_OK = qw(update_versions);
+
+use Bugzilla::Constants;
+use Bugzilla::Product;
+
+use Bugzilla::Extension::TellUsMore::Constants;
+
+sub new {
+ my $invocant = shift;
+ my $class = ref($invocant) || $invocant;
+ my $object = {};
+ bless($object, $class);
+ return $object;
+}
+
+sub created {
+ my ($self, $created) = @_;
+ return unless $self->_should_process($created);
+
+ my $version = $self->_get($created);
+ if ($version) {
+ # version already exists, reactivate if required
+ if (!$version->is_active) {
+ $version->set_is_active(1);
+ $version->update();
+ }
+ } else {
+ # create version
+ $self->_create_version($created->name);
+ }
+}
+
+sub updated {
+ my ($self, $old, $new) = @_;
+ return unless $self->_should_process($old);
+
+ my $version = $self->_get($old)
+ or return;
+
+ my $updated = 0;
+ if ($version->name ne $new->name) {
+ if ($version->bug_count) {
+ # version renamed, but old name has bugs
+ # create a new version to avoid touching bugs
+ $self->_create_version($new->name);
+ return;
+ } else {
+ # renaming the version is safe as it is unused
+ $version->set_name($new->name);
+ $updated = 1;
+ }
+ }
+
+ if ($version->is_active != $new->is_active) {
+ if ($new->is_active) {
+ # activating, always safe
+ $version->set_is_active(1);
+ $updated = 1;
+ } else {
+ # can only deactivate when all source products agree
+ my $active = 0;
+ foreach my $product ($self->_sources) {
+ foreach my $product_version (@{$product->versions}) {
+ next unless _version_eq($product_version, $new);
+ if ($product_version->is_active) {
+ $active = 1;
+ last;
+ }
+ }
+ last if $active;
+ }
+ if (!$active) {
+ $version->set_is_active(0);
+ $updated = 1;
+ }
+ }
+ }
+
+ if ($updated) {
+ $version->update();
+ }
+}
+
+sub deleted {
+ my ($self, $deleted) = @_;
+ return unless $self->_should_process($deleted);
+
+ my $version = $self->_get($deleted)
+ or return;
+
+ # can only delete when all source products agreee
+ foreach my $product ($self->_sources) {
+ next if $product->name eq $deleted->product->name;
+ if (grep { _version_eq($_, $version) } @{$product->versions}) {
+ return;
+ }
+ }
+
+ if ($version->bug_count) {
+ # if there's active bugs, deactivate instead of deleting
+ $version->set_is_active(0);
+ $version->update();
+ } else {
+ # no bugs, safe to delete
+ $version->remove_from_db();
+ }
+}
+
+sub check_setup {
+ my ($self, $full) = @_;
+ $self->{setup_error} = '';
+
+ if (!$self->_target) {
+ $self->{setup_error} = "TellUsMore: Error: Target product '" . VERSION_TARGET_PRODUCT . "' does not exist.\n";
+ return 0;
+ }
+ return 1 unless $full;
+
+ foreach my $name (VERSION_SOURCE_PRODUCTS) {
+ my $product = Bugzilla::Product->new({ name => $name });
+ if (!$product) {
+ $self->{setup_error} .= "TellUsMore: Warning: Source product '$name' does not exist.\n";
+ next;
+ }
+ my $component = Bugzilla::Component->new({ product => $self->_target, name => $name });
+ if (!$component) {
+ $self->{setup_error} .= "TellUsMore: Warning: Target component '$name' does not exist.\n";
+ }
+ }
+ return $self->{setup_error} ? 0 : 1;
+}
+
+sub setup_error {
+ my ($self) = @_;
+ return $self->{setup_error};
+}
+
+sub refresh {
+ my ($self) = @_;
+ foreach my $product ($self->_sources) {
+ foreach my $version (@{$product->versions}) {
+ if (!$self->_get($version)) {
+ $self->created($version);
+ }
+ }
+ }
+}
+
+sub _should_process {
+ my ($self, $version) = @_;
+ return 0 unless $self->check_setup();
+ foreach my $product ($self->_sources) {
+ return 1 if $version->product->name eq $product->name;
+ }
+ return 0;
+}
+
+sub _get {
+ my ($self, $query) = @_;
+ my $name = ref($query) ? $query->name : $query;
+ my @versions = grep { $_->name eq $name } @{$self->_target->versions};
+ return scalar @versions ? $versions[0] : undef;
+}
+
+sub _sources {
+ my ($self) = @_;
+ if (!$self->{sources} || scalar(@{$self->{sources}}) != scalar VERSION_SOURCE_PRODUCTS) {
+ my @sources;
+ foreach my $name (VERSION_SOURCE_PRODUCTS) {
+ my $product = Bugzilla::Product->new({ name => $name });
+ push @sources, $product if $product;
+ }
+ $self->{sources} = \@sources;
+ }
+ return @{$self->{sources}};
+}
+
+sub _target {
+ my ($self) = @_;
+ $self->{target} ||= Bugzilla::Product->new({ name => VERSION_TARGET_PRODUCT });
+ return $self->{target};
+}
+
+sub _version_eq {
+ my ($version_a, $version_b) = @_;
+ return lc($version_a->name) eq lc($version_b->name);
+}
+
+sub _create_version {
+ my ($self, $name) = @_;
+ Bugzilla::Version->create({ product => $self->_target, value => $name });
+ # remove bugzilla's cached list of versions
+ delete $self->_target->{versions};
+}
+
+1;