[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#753733: tracker.debian.org: Learn about auto-removals



Hi,

Here is an updated patch, it fixes the issues you mentioned and adds
basic testing.

Raphael Hertzog wrote:
> I was thinking of having a generic task (i.e. a new class that we can
> inherit from in UpdateAutoRemovalsStatsTask) so that we
> don't duplicate the logic in __init__(), set_parameters, get_*_stats, etc
> and having a set of tests ready to run on any task built on top of the new
> generic task.

Yes we could have a GenericActionItemsTask.

Cheers,
Christophe
>From 1a98d4493b2e7a384fee6d18f9eb8d8784b7ff27 Mon Sep 17 00:00:00 2001
From: Christophe Siraut <d@tobald.eu.org>
Date: Sun, 24 Aug 2014 13:38:46 +0200
Subject: [PATCH] vendor/debian: generate action items for auto-removals

---
 .../templates/debian/autoremoval-action-item.html  | 23 ++++++
 distro_tracker/vendor/debian/tests.py              | 72 ++++++++++++++++++
 distro_tracker/vendor/debian/tracker_tasks.py      | 85 ++++++++++++++++++++++
 3 files changed, 180 insertions(+)
 create mode 100644 distro_tracker/vendor/debian/templates/debian/autoremoval-action-item.html

diff --git a/distro_tracker/vendor/debian/templates/debian/autoremoval-action-item.html b/distro_tracker/vendor/debian/templates/debian/autoremoval-action-item.html
new file mode 100644
index 0000000..e0d8752
--- /dev/null
+++ b/distro_tracker/vendor/debian/templates/debian/autoremoval-action-item.html
@@ -0,0 +1,23 @@
+{% spaceless %}
+{% with bugs=item.extra_data.bugs %}
+{% with bugs_dependencies=item.extra_data.bugs_dependencies %}
+{% with buggy_dependencies=item.extra_data.buggy_dependencies %}
+
+<div>
+    <span>Version {{ item.extra_data.version }} of {{ item.package.name }} is marked for autoremoval from testing on {{ item.extra_data.removal_date }}. </span>
+
+    {% if bugs %}
+    <span>It is affected by {{ bugs|safe }}. </span>
+    {% endif %}  
+
+    {% if bugs_dependencies %}
+    <span>It depends (transitively) on {{ buggy_dependencies|safe }}, affected by {{ bugs_dependencies|safe }}. </span>
+    {% endif %}  
+
+    </span>You should try to prevent the removal by fixing these RC bugs.</span>
+</div>
+
+{% endwith %}
+{% endwith %}
+{% endwith %}
+{% endspaceless %}
diff --git a/distro_tracker/vendor/debian/tests.py b/distro_tracker/vendor/debian/tests.py
index 19e0586..646867e 100644
--- a/distro_tracker/vendor/debian/tests.py
+++ b/distro_tracker/vendor/debian/tests.py
@@ -62,6 +62,7 @@ from distro_tracker.vendor.debian.tracker_tasks import DebianWatchFileScannerUpd
 from distro_tracker.vendor.debian.tracker_tasks import UpdateExcusesTask
 from distro_tracker.vendor.debian.tracker_tasks import UpdateDebciStatusTask
 from distro_tracker.vendor.debian.tracker_tasks import UpdateDebianDuckTask
+from distro_tracker.vendor.debian.tracker_tasks import UpdateAutoRemovalsStatsTask
 from distro_tracker.vendor.debian.models import DebianContributor
 from distro_tracker.vendor.debian.models import UbuntuPackage
 from distro_tracker.vendor.debian.tracker_tasks import UpdateLintianStatsTask
@@ -4707,3 +4708,74 @@ class UpdateDebciStatusTaskTest(TestCase):
         self.run_task()
 
         self.assertEqual(ActionItem.objects.count(), 0)
+
+
+@mock.patch('distro_tracker.core.utils.http.requests')
+class UpdateAutoRemovalsStatsTaskTest(TestCase):
+    """
+    Tests for the :class:`distro_tracker.vendor.debian.tracker_tasks
+    .UpdateAutoRemovalsStatsTask` task.
+    """
+    def setUp(self):
+        self.dummy_package = SourcePackageName.objects.create(
+            name='dummy-package')
+        self.other_package = SourcePackageName.objects.create(
+            name='other-package')
+        self.autoremovals_data = """
+        dummy-package:
+            bugs:
+            - '12345'
+            removal_date: 2014-08-24 10:20:00
+        dummy-package2:
+            bugs:
+            - '123456'
+            removal_date: 2014-08-25 12:00:00
+        """
+
+    def run_task(self):
+        """
+        Runs the autoremovals status update task.
+        """
+        task = UpdateAutoRemovalsStatsTask()
+        task.execute()
+
+    def test_action_item_when_in_list(self, mock_requests):
+        """
+        Tests that an ActionItem is created for a package reported by
+        autoremovals.
+        """
+        set_mock_response(mock_requests, text=self.autoremovals_data)
+
+        self.run_task()
+        self.assertEqual(1, self.dummy_package.action_items.count())
+
+    def test_no_action_item_when_not_in_list(self, mock_requests):
+        """
+        Tests that no ActionItem is created for a package not reported by
+        autoremovals.
+        """
+        set_mock_response(mock_requests, text=self.autoremovals_data)
+
+        self.run_task()
+        self.assertEqual(0, self.other_package.action_items.count())
+
+    def test_action_item_is_dropped_when_autoremovals_reports_nothing_again(
+            self, mock_requests):
+        """
+        Tests that ActionItems are dropped when a package was previousy
+        reported but is now not reported anymore.
+        """
+        set_mock_response(mock_requests, text=self.autoremovals_data)
+        self.run_task()
+        self.assertEqual(1, self.dummy_package.action_items.count())
+
+        autoremovals_data = """
+        dummy-package3:
+            bugs:
+            - '1234567'
+            removal_date: 2014-08-22 12:21:00
+        """
+        set_mock_response(mock_requests, text=autoremovals_data)
+
+        self.run_task()
+        self.assertEqual(0, self.dummy_package.action_items.count())
diff --git a/distro_tracker/vendor/debian/tracker_tasks.py b/distro_tracker/vendor/debian/tracker_tasks.py
index 98b63d2..fc8de64 100644
--- a/distro_tracker/vendor/debian/tracker_tasks.py
+++ b/distro_tracker/vendor/debian/tracker_tasks.py
@@ -2122,3 +2122,88 @@ class UpdateDebciStatusTask(BaseTask):
             # Remove action items for packages without failing tests.
             ActionItem.objects.delete_obsolete_items(
                 [self.debci_action_item_type], packages)
+
+
+class UpdateAutoRemovalsStatsTask(BaseTask):
+    """
+    A task for updating autoremovals information on all packages.
+    """
+    ACTION_ITEM_TYPE_NAME = 'debian-autoremoval'
+    ACTION_ITEM_TEMPLATE = 'debian/autoremoval-action-item.html'
+    ITEM_DESCRIPTION = 'Marked for autoremoval on {removal_date}: {bugs}'
+
+    def __init__(self, force_update=False, *args, **kwargs):
+        super(UpdateAutoRemovalsStatsTask, self).__init__(*args, **kwargs)
+        self.force_update = force_update
+        self.action_item_type = ActionItemType.objects.create_or_update(
+            type_name=self.ACTION_ITEM_TYPE_NAME,
+            full_description_template=self.ACTION_ITEM_TEMPLATE)
+
+    def set_parameters(self, parameters):
+        if 'force_update' in parameters:
+            self.force_update = parameters['force_update']
+
+    def get_autoremovals_stats(self):
+        """
+        Retrieves and parses the autoremoval stats for all packages.
+        Autoremoval stats include the BTS bugs id.
+
+        :returns: A dict mapping package names to autoremoval stats.
+        """
+        content = get_resource_content(
+            'https://udd.debian.org/cgi-bin/autoremovals.yaml.cgi')
+        if content:
+            return yaml.safe_load(six.BytesIO(content))
+
+    def update_action_item(self, package, stats):
+        """
+        Creates an :class:`ActionItem <distro_tracker.core.models.ActionItem>`
+        instance for the given type indicating that the package has an
+        autoremoval issue.
+        """
+        action_item = package.get_action_item_for_type(self.action_item_type)
+        if not action_item:
+            action_item = ActionItem(
+                package=package,
+                item_type=self.action_item_type,
+                severity=ActionItem.SEVERITY_HIGH)
+
+        bugs_dependencies = stats.get('bugs_dependencies', [])
+        buggy_dependencies = stats.get('buggy_dependencies', [])
+        all_bugs = stats['bugs'] + bugs_dependencies
+        link = '<a href="https://bugs.debian.org/{}";>{}</a>'
+
+        action_item.short_description = self.ITEM_DESCRIPTION.format(
+            removal_date=stats['removal_date'].strftime('%d %B'),
+            bugs=', '.join(link.format(bug, bug) for bug in all_bugs))
+
+        action_item.extra_data = {
+            'stats': stats,
+            'removal_date': stats['removal_date'].strftime('%a %d %b %Y'),
+            'bugs': ', '.join(link.format(bug, bug) for bug in stats['bugs']),
+            'bugs_dependencies': ', '.join(
+                link.format(bug, bug) for bug in bugs_dependencies),
+            'buggy_dependencies': ' and '.join(
+                ['<a href="/pkg/{}">{}</a>'.format(
+                    reverse(
+                        'dtracker-package-page',
+                        kwargs={'package_name': p}),
+                    p) for p in buggy_dependencies])}
+        action_item.save()
+
+    def execute(self):
+        autoremovals_stats = self.get_autoremovals_stats()
+        if autoremovals_stats is None:
+            # Nothing to do: cached content up to date
+            return
+
+        ActionItem.objects.delete_obsolete_items(
+            item_types=[self.action_item_type],
+            non_obsolete_packages=autoremovals_stats.keys())
+
+        packages = SourcePackageName.objects.filter(
+            name__in=autoremovals_stats.keys())
+        packages = packages.prefetch_related('action_items')
+
+        for package in packages:
+            self.update_action_item(package, autoremovals_stats[package.name])
-- 
2.1.0.rc1


Reply to: