Repository: buildbot/buildbot

Issue:
BuildMaster.addChange drops data for fields who were renamed..
See:  (From: https://github.com/buildbot/buildbot/blame/master/master/buildbot/master.py#L461)
```
        def handle_deprec(oldname, newname):
            if oldname not in kwargs:
                return 
            old = kwargs.pop(oldname)
            if old is not None:
                if kwargs.get(newname) is None:
                    log.msg("WARNING: change source is using deprecated "
                            "addChange parameter '%s'" % oldname)
                    return old
                raise TypeError("Cannot provide '%s' and '%s' to addChange"
                                % (oldname, newname))
            return kwargs.get(newname)

        kwargs['author'] = handle_deprec("who", "author")
        kwargs['when_timestamp'] = handle_deprec("when", "when_timestamp")
```

If addChange is called with when_timestamp and not when, then kwargs['when_timestamp'] = handle_deprec("when", "when_timestamp") will set it to None, and then the data in the db will just be the time the change was processed.

The fix is:
```
            if oldname not in kwargs:
                return kwargs[newname]
```

Test need to be updated for this. Don't have time at the moment to do so, but want to make sure this is not lost.

Note this affects most (if not all) webhooks.  (But not github poller's it seems)



Discussion:

Resolving patch:
diff --git a/master/buildbot/master.py b/master/buildbot/master.py
--- a/master/buildbot/master.py
+++ b/master/buildbot/master.py
@@ -459,16 +459,15 @@ def addChange(self, who=None, files=None, comments=None, **kwargs):
         kwargs['comments'] = comments
 
         def handle_deprec(oldname, newname):
-            if oldname not in kwargs:
-                return
-            old = kwargs.pop(oldname)
-            if old is not None:
-                if kwargs.get(newname) is None:
-                    log.msg("WARNING: change source is using deprecated "
-                            "addChange parameter '%s'" % oldname)
-                    return old
-                raise TypeError("Cannot provide '%s' and '%s' to addChange"
-                                % (oldname, newname))
+            if oldname in kwargs:
+                old = kwargs.pop(oldname)
+                if old is not None:
+                    if kwargs.get(newname) is None:
+                        log.msg("WARNING: change source is using deprecated "
+                                "addChange parameter '%s'" % oldname)
+                        return old
+                    raise TypeError("Cannot provide '%s' and '%s' to addChange"
+                                    % (oldname, newname))
             return kwargs.get(newname)
 
         kwargs['author'] = handle_deprec("who", "author")


Test patch:
diff --git a/master/buildbot/test/unit/test_master.py b/master/buildbot/test/unit/test_master.py
--- a/master/buildbot/test/unit/test_master.py
+++ b/master/buildbot/test/unit/test_master.py
@@ -16,6 +16,7 @@
 from __future__ import absolute_import
 from __future__ import print_function
 
+import datetime
 import os
 import signal
 
@@ -119,6 +120,20 @@ def test_addChange_args_when(self):
             kwargs=dict(when=892293875),
             exp_data_kwargs=dict(when_timestamp=892293875))
 
+    def test_addChange_args_when_timestamp(self):
+        # when_timestamp should come through as an epoch time.
+        return self.do_test_addChange_args(
+            kwargs=dict(when_timestamp=datetime.datetime(1998, 4, 11, 11, 24, 35)),
+            exp_data_kwargs=dict(when_timestamp=892293875))
+
+    def test_addChange_args_new_and_old(self):
+        func = self.do_test_addChange_args
+        kwargs = dict(who='author',
+                      author='author'),
+        exp_data_kwargs = dict(author='author')
+        self.assertRaises(TypeError, func, kwargs=kwargs,
+                          exp_data_kwargs=exp_data_kwargs)
+
     def test_addChange_args_properties(self):
         # properties should not be qualified with a source
         return self.do_test_addChange_args(