Use AbstractAction to implement common execute() method

Each action had common code in the execute()-method, which checked,
whether the code is executed and to log the error, which might happen
during execution.

This change moves this code to a method in the abstract class, thereby
reducing code duplication.

Change-Id: I9020c3f3c10a6dc7029895fa9ce3766f8eaad480
diff --git a/container/tools/actions/abstract.py b/container/tools/actions/abstract.py
index 5ad4f45..820908a 100644
--- a/container/tools/actions/abstract.py
+++ b/container/tools/actions/abstract.py
@@ -14,10 +14,11 @@
 
 import abc
 import logging
+import traceback
 
 import numpy as np
 
-
+# pylint: disable=W0703
 class AbstractAction(abc.ABC):
     def __init__(self, url, user, pwd, probability=1.0):
         self.url = url
@@ -29,8 +30,18 @@
 
         self.log = logging.getLogger("ActionLogger")
 
-    @abc.abstractmethod
     def execute(self):
+        if self._is_executed():
+            try:
+                return self._execute_action()
+            except Exception:
+                self.failed = True
+                self._log_result(traceback.format_exc().replace("\n", " "))
+
+        return None
+
+    @abc.abstractmethod
+    def _execute_action(self):
         pass
 
     def _log_result(self, message=""):
diff --git a/container/tools/actions/abstract_push.py b/container/tools/actions/abstract_push.py
index 3f36ce0..b03520c 100644
--- a/container/tools/actions/abstract_push.py
+++ b/container/tools/actions/abstract_push.py
@@ -16,13 +16,12 @@
 import os
 import random
 import string
-import traceback
 
 import git
 
 from . import abstract
 
-# pylint: disable=W0703
+
 class AbstractPushAction(abstract.AbstractAction):
     def __init__(self, refspec, project_name, probability=0.2):
         super().__init__(url=None, user=None, pwd=None, probability=probability)
@@ -33,25 +32,22 @@
         self.refspec = refspec
 
     @abc.abstractmethod
-    def execute(self):
+    def _prepare(self):
         pass
 
-    def _push(self):
+    def _execute_action(self):
         self.repo.git.checkout("origin/master")
-        if os.path.exists(self.local_repo_path) and self._is_executed():
-            try:
-                num_commits = random.randint(1, 5)
-                for _ in range(num_commits):
-                    self._create_commit()
-                self.repo.remotes.origin.push(refspec=self.refspec)
-                self.was_executed = True
-                self._log_result(
-                    "Pushed %d commits to project %s using refspec %s"
-                    % (num_commits, self.project_name, self.refspec)
-                )
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
+        self._prepare()
+        if os.path.exists(self.local_repo_path):
+            num_commits = random.randint(1, 5)
+            for _ in range(num_commits):
+                self._create_commit()
+            self.repo.remotes.origin.push(refspec=self.refspec)
+            self.was_executed = True
+            self._log_result(
+                "Pushed %d commits to project %s using refspec %s"
+                % (num_commits, self.project_name, self.refspec)
+            )
 
     def _create_commit(self):
         change_type_choice = random.choice(self.change_types)
diff --git a/container/tools/actions/clone_project.py b/container/tools/actions/clone_project.py
index 2a0cfd9..cdbb714 100644
--- a/container/tools/actions/clone_project.py
+++ b/container/tools/actions/clone_project.py
@@ -15,32 +15,26 @@
 import os
 import shutil
 import stat
-import traceback
 
 import git
 import requests
 
 from . import abstract
 
-# pylint: disable=W0703
+
 class CloneProjectAction(abstract.AbstractAction):
     def __init__(self, url, user, pwd, project_name, probability=0.02):
         super().__init__(url, user, pwd, probability)
         self.project_name = project_name
 
-    def execute(self):
-        if self._is_executed():
-            try:
-                local_repo_path = os.path.join("/tmp", self.project_name)
-                if os.path.exists(local_repo_path):
-                    shutil.rmtree(local_repo_path)
-                git.Repo.clone_from(self._assemble_url(), local_repo_path)
-                self._install_commit_hook()
-                self.was_executed = True
-                self._log_result(self.project_name)
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
+    def _execute_action(self):
+        local_repo_path = os.path.join("/tmp", self.project_name)
+        if os.path.exists(local_repo_path):
+            shutil.rmtree(local_repo_path)
+        git.Repo.clone_from(self._assemble_url(), local_repo_path)
+        self._install_commit_hook()
+        self.was_executed = True
+        self._log_result(self.project_name)
 
     def _install_commit_hook(self):
         hook_path = os.path.join("/tmp", self.project_name, ".git/hooks/commit-msg")
diff --git a/container/tools/actions/create_project.py b/container/tools/actions/create_project.py
index 57cc4b3..91fd8dc 100644
--- a/container/tools/actions/create_project.py
+++ b/container/tools/actions/create_project.py
@@ -14,7 +14,6 @@
 
 import random
 import string
-import traceback
 
 import requests
 
@@ -22,29 +21,20 @@
 
 PROJECT_NAME_LENGTH = 16
 
-# pylint: disable=W0703
+
 class CreateProjectAction(abstract.AbstractAction):
     def __init__(self, url, user, pwd, probability=0.00002):
         super().__init__(url, user, pwd, probability)
         self.project_name = self._get_random_project_name()
 
-    def execute(self):
-        if self._is_executed():
-            try:
-                rest_url = self._assemble_url()
-                requests.put(
-                    rest_url,
-                    auth=(self.user, self.pwd),
-                    json={"create_empty_commit": "true"},
-                )
-                self.was_executed = True
-                self._log_result(self.project_name)
-                return self.project_name
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
-
-        return None
+    def _execute_action(self):
+        rest_url = self._assemble_url()
+        requests.put(
+            rest_url, auth=(self.user, self.pwd), json={"create_empty_commit": "true"}
+        )
+        self.was_executed = True
+        self._log_result(self.project_name)
+        return self.project_name
 
     def _assemble_url(self):
         return "%s/a/projects/%s" % (self.url, self.project_name)
diff --git a/container/tools/actions/fetch_project.py b/container/tools/actions/fetch_project.py
index 83ba36f..3030293 100644
--- a/container/tools/actions/fetch_project.py
+++ b/container/tools/actions/fetch_project.py
@@ -13,27 +13,24 @@
 # limitations under the License.
 
 import os.path
-import traceback
 
 import git
 
 from . import abstract
 
 # pylint: disable=W0703
+
+
 class FetchProjectAction(abstract.AbstractAction):
     def __init__(self, project_name, probability=0.1):
         super().__init__(url=None, user=None, pwd=None, probability=probability)
         self.project_name = project_name
 
-    def execute(self):
+    def _execute_action(self):
         local_repo_path = os.path.join("/tmp", self.project_name)
-        if os.path.exists(local_repo_path) and self._is_executed():
-            try:
-                repo = git.Repo(local_repo_path)
-                for remote in repo.remotes:
-                    remote.fetch()
-                self.was_executed = True
-                self._log_result(self.project_name)
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
+        if os.path.exists(local_repo_path):
+            repo = git.Repo(local_repo_path)
+            for remote in repo.remotes:
+                remote.fetch()
+            self.was_executed = True
+            self._log_result(self.project_name)
diff --git a/container/tools/actions/push_change.py b/container/tools/actions/push_change.py
index cf90ee6..ba268ff 100644
--- a/container/tools/actions/push_change.py
+++ b/container/tools/actions/push_change.py
@@ -19,5 +19,5 @@
     def __init__(self, project_name, probability=0.2):
         super().__init__("HEAD:refs/for/master", project_name, probability=probability)
 
-    def execute(self):
-        self._push()
+    def _prepare(self):
+        pass
diff --git a/container/tools/actions/push_commit.py b/container/tools/actions/push_commit.py
index 2e876d0..7f88a6c 100644
--- a/container/tools/actions/push_commit.py
+++ b/container/tools/actions/push_commit.py
@@ -20,7 +20,6 @@
     def __init__(self, project_name, probability=0.2):
         super().__init__("HEAD:master", project_name, probability=probability)
 
-    def execute(self):
+    def _prepare(self):
         action = FetchProjectAction(self.project_name, 1.0)
         action.execute()
-        self._push()
diff --git a/container/tools/actions/query_change_files.py b/container/tools/actions/query_change_files.py
index e5ea8bb..c011401 100644
--- a/container/tools/actions/query_change_files.py
+++ b/container/tools/actions/query_change_files.py
@@ -13,33 +13,23 @@
 # limitations under the License.
 
 import json
-import traceback
 
 import requests
 
 from . import abstract
 
-# pylint: disable=W0703
+
 class QueryChangeFilesAction(abstract.AbstractAction):
     def __init__(self, change_id, url, user, pwd, probability=0.2):
         super().__init__(url, user, pwd, probability)
         self.change_id = change_id
         self.revision_id = 1
 
-    def execute(self):
-        if self._is_executed():
-            try:
-                response = requests.get(
-                    self._assemble_url(), auth=(self.user, self.pwd)
-                )
-                files = list(json.loads(response.text.split("\n", 1)[1]).keys())
-                self._log_result(files)
-                return files
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
-
-        return None
+    def _execute_action(self):
+        response = requests.get(self._assemble_url(), auth=(self.user, self.pwd))
+        files = list(json.loads(response.text.split("\n", 1)[1]).keys())
+        self._log_result(files)
+        return files
 
     def _assemble_url(self):
         return "%s/a/changes/%s/revisions/%s/files" % (
diff --git a/container/tools/actions/query_changes.py b/container/tools/actions/query_changes.py
index ceb83a2..a465021 100644
--- a/container/tools/actions/query_changes.py
+++ b/container/tools/actions/query_changes.py
@@ -14,36 +14,23 @@
 
 import json
 import random
-import traceback
 
 import requests
 
 from . import abstract
 
-# pylint: disable=W0703
+
 class QueryChangesAction(abstract.AbstractAction):
     def __init__(self, url, user, pwd, probability=0.2):
         super().__init__(url, user, pwd, probability)
 
-    def execute(self):
-        if self._is_executed():
-            try:
-                rest_url = self._assemble_url()
-                response = requests.get(rest_url, auth=(self.user, self.pwd))
-                self.was_executed = True
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
-                return None
-
-            try:
-                change = random.choice(json.loads(response.text.split("\n", 1)[1]))
-                self._log_result(change["change_id"])
-                return change
-            except Exception:
-                return None
-
-        return None
+    def _execute_action(self):
+        rest_url = self._assemble_url()
+        response = requests.get(rest_url, auth=(self.user, self.pwd))
+        self.was_executed = True
+        change = random.choice(json.loads(response.text.split("\n", 1)[1]))
+        self._log_result(change["change_id"])
+        return change
 
     def _assemble_url(self):
         return "%s/a/changes/?q=status:open&n=100" % (self.url)
diff --git a/container/tools/actions/query_projects.py b/container/tools/actions/query_projects.py
index 11b5990..989f18d 100644
--- a/container/tools/actions/query_projects.py
+++ b/container/tools/actions/query_projects.py
@@ -14,7 +14,6 @@
 
 import json
 import random
-import traceback
 
 import requests
 
@@ -22,30 +21,22 @@
 
 DISALLOWED_PROJECTS = ["All-Projects", "All-Users"]
 
-# pylint: disable=W0703
+
 class QueryProjectsAction(abstract.AbstractAction):
     def __init__(self, url, user, pwd, probability=0.05):
         super().__init__(url, user, pwd, probability)
 
-    def execute(self):
-        if self._is_executed():
-            selected_project = None
-            try:
-                rest_url = self._assemble_url()
-                response = requests.get(rest_url, auth=(self.user, self.pwd))
-                self.was_executed = True
-                projects = list(json.loads(response.text.split("\n", 1)[1]).keys())
-                for project in DISALLOWED_PROJECTS:
-                    projects.remove(project)
-                selected_project = random.choice(projects)
-                self._log_result(selected_project)
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
-
-            return selected_project
-
-        return None
+    def _execute_action(self):
+        selected_project = None
+        rest_url = self._assemble_url()
+        response = requests.get(rest_url, auth=(self.user, self.pwd))
+        self.was_executed = True
+        projects = list(json.loads(response.text.split("\n", 1)[1]).keys())
+        for project in DISALLOWED_PROJECTS:
+            projects.remove(project)
+        selected_project = random.choice(projects)
+        self._log_result(selected_project)
+        return selected_project
 
     def _assemble_url(self):
         return "%s/a/projects/?d" % (self.url)
diff --git a/container/tools/actions/review_change.py b/container/tools/actions/review_change.py
index ba9dac3..20db3bd 100644
--- a/container/tools/actions/review_change.py
+++ b/container/tools/actions/review_change.py
@@ -13,7 +13,6 @@
 # limitations under the License.
 
 import random
-import traceback
 
 import requests
 
@@ -28,18 +27,11 @@
         self.change_id = self._get_change_id()
         self.revision_id = 1
 
-    def execute(self):
-        if self._is_executed() and self.change_id:
-            try:
-                rest_url = self._assemble_review_url()
-                requests.post(
-                    rest_url, auth=(self.user, self.pwd), json=self._assemble_body()
-                )
-                self.was_executed = True
-                self._log_result()
-            except Exception:
-                self.failed = True
-                self._log_result(traceback.format_exc().replace("\n", " "))
+    def _execute_action(self):
+        rest_url = self._assemble_review_url()
+        requests.post(rest_url, auth=(self.user, self.pwd), json=self._assemble_body())
+        self.was_executed = True
+        self._log_result()
 
     def _get_change_id(self):
         try: