From da6d4a7db313854232dd9623b8c72aff4628c7b1 Mon Sep 17 00:00:00 2001
From: Edward Hervey <bilboed@bilboed.com>
Date: Sun, 6 May 2018 13:36:40 +0100
Subject: [PATCH] Preserve author for issues, comments, attachments

Use a 'sudo' token to act as the author when posting issues, comments,
and attachments.
---
 bztogl/bztogl.py    |  16 ++++--
 bztogl/common.py    |   4 +-
 test/test_bztogl.py | 133 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+), 6 deletions(-)
 create mode 100644 test/test_bztogl.py

diff --git a/bztogl/bztogl.py b/bztogl/bztogl.py
index 3002a56..fd214bf 100644
--- a/bztogl/bztogl.py
+++ b/bztogl/bztogl.py
@@ -86,10 +86,12 @@ def processbug(bgo, target, user_cache, milestone_cache, bzbug):
             index[atid] = at
         return index
 
-    def gitlab_upload_file(target, filename, f):
+    def gitlab_upload_file(target, filename, f, sudo=None):
         url = "{}api/v3/projects/{}/uploads".format(target.gl_url,
                                                     target.get_project().id)
         target.gl.session.headers = {"PRIVATE-TOKEN": target.token}
+        if sudo:
+            target.gl.session.headers['sudo'] = '{}'.format(sudo)
         ret = target.gl.session.post(url, files={
             'file': (urllib.parse.quote(filename), f)
         })
@@ -100,10 +102,11 @@ def processbug(bgo, target, user_cache, milestone_cache, bzbug):
     def migrate_attachment(comment, metadata):
         atid = comment['attachment_id']
 
+        author = user_cache[comment['author']]
         filename = metadata[atid]['file_name']
         print("    Attachment {} found, migrating".format(filename))
         attfile = bgo.openattachment(atid)
-        ret = gitlab_upload_file(target, filename, attfile)
+        ret = gitlab_upload_file(target, filename, attfile, sudo=author.id)
 
         return template.render_attachment(atid, metadata[atid], ret)
 
@@ -228,9 +231,14 @@ def processbug(bgo, target, user_cache, milestone_cache, bzbug):
     if bz_milestone and bz_milestone != '---':
         milestone = milestone_cache[bz_milestone]
 
+    if user_cache[bzbug.creator]:
+        sudo = user_cache[bzbug.creator].id
+    else:
+        sudo = None
     issue = target.create_issue(bzbug.id, bzbug.summary, description,
                                 labels, milestone,
-                                str(bzbug.creation_time))
+                                str(bzbug.creation_time),
+                                sudo=sudo)
 
     # Assign bug to actual account if exists
     assignee = user_cache[bzbug.assigned_to]
@@ -263,7 +271,7 @@ def processbug(bgo, target, user_cache, milestone_cache, bzbug):
         issue.notes.create({
             'body': gitlab_comment,
             'created_at': str(comment['creation_time'])
-        })
+        }, sudo=author.id)
 
     # Do last, so that previous actions don't all send an email
     for cc_email in itertools.chain(bzbug.cc, [bzbug.creator]):
diff --git a/bztogl/common.py b/bztogl/common.py
index 623742e..098988f 100644
--- a/bztogl/common.py
+++ b/bztogl/common.py
@@ -32,7 +32,7 @@ class GitLab:
         return self.gl.projects.get(self.target_project)
 
     def create_issue(self, id, summary, description, labels,
-                     milestone, creation_time):
+                     milestone, creation_time, sudo=None):
         payload = {
             'title': summary,
             'description': description,
@@ -43,7 +43,7 @@ class GitLab:
         if milestone:
             payload['milestone_id'] = milestone.id
 
-        return self.get_project().issues.create(payload)
+        return self.get_project().issues.create(payload, sudo=sudo)
 
     def get_all_users(self):
         if self.all_users is None:
diff --git a/test/test_bztogl.py b/test/test_bztogl.py
new file mode 100644
index 0000000..620d56e
--- /dev/null
+++ b/test/test_bztogl.py
@@ -0,0 +1,133 @@
+import collections
+
+from bztogl import bztogl, users
+
+
+def test_create_issue():
+    bz = Bugzilla()
+    gl = Gitlab()
+    milestone_cache = collections.defaultdict(lambda: None)
+    bug = Bug(12345, bz)
+
+    # XXX: Create a mock usercache, maybe mock target too ... ?
+    issue = bztogl.create_issue(target, None, milestone_cache, bug)
+    assert issue is not None
+
+
+def test_update_content():
+    bz = Bugzilla()
+    gl = Gitlab()
+    user_cache = collections.defaultdict(lambda: None)
+    user_cache['test@example.com'] = User()
+
+    bug = Bug(12345, bz)
+    bug.assigned_to = 'test@example.com'
+    bug_dep = Bug(54321)
+    bug.depends_on = [
+        bug_dep.bug_id
+    ]
+
+    issue = Issue()
+    issue_dep = Issue()
+    issues = {
+        12345: issue,
+        54321: issue_dep,
+    }
+
+    bztogl.update_content(bz, gl, user_cache, issues, issue, bug)
+    assert 'first comment' in issue.description
+    assert '#{}'.format(issue_dep.iid) in issue.description
+
+
+def test_finalise_issue():
+    bug = Bug(12345)
+    issue = Issue()
+    user_cache = collections.defaultdict(lambda: None)
+
+    bztogl.finalise_issue(bug, issue, user_cache)
+
+
+def test_close_bug():
+    bz = Bugzilla()
+    bug = Bug(12345, bz)
+    issue = Issue()
+
+    bztogl.close_bug(bug, issue)
+
+
+class Bugzilla:
+
+    def __init__(self):
+        self._proxy = object()
+
+    def build_update(self, *args, **kwargs):
+        return None
+
+    def update_bugs(self, *args, **kwargs):
+        pass
+
+
+class Bug:
+
+    next_id = 1
+
+    def __init__(self, id, bugzilla=None):
+        self.id = Bug.next_id
+        self.bug_id = id
+        self.bugzilla = bugzilla
+        self.summary = ''
+        self.creator = 'test@example.com'
+        self.creation_time = 12345
+        self.assigned_to = None
+        self.cc = []
+        self.status = 'NEW'
+        self.component = 'General'
+        self.version = None
+        self.target_milestone = None
+        self.keywords = []
+        self.depends_on = []
+        self.blocks = []
+        self.see_also = []
+        self.attachments = []
+
+        Bug.next_id += 1
+
+    def getcomments(self):
+        return [
+            {
+                'author': self.creator,
+                'text': 'first comment'
+            }
+        ]
+
+
+class Gitlab:
+
+    def create_issue(self, *args, **kwargs):
+        issue = Issue()
+        issue.description = args[2]
+        return issue
+
+
+class Issue:
+
+    next_iid = 1
+
+    def __init__(self):
+        self.iid = Issue.next_iid
+        self.description = ''
+        self.web_url = ''
+
+        Issue.next_iid += 1
+
+    def save(self, *args, **kwargs):
+        pass
+
+
+class User:
+
+    def __init__(self):
+        self.id = None
+
+    def display_name(self):
+        return 'Test User'
-- 
GitLab