Browse Source

Start teasing things into separate modules.

master
Chris Smith 5 years ago
parent
commit
e33eedbcef

+ 0
- 0
lineandsinker/__init__.py View File


+ 14
- 0
lineandsinker/common.py View File

@@ -0,0 +1,14 @@
1
+import hashlib
2
+import os
3
+
4
+BASE_URL = os.environ["LAS_BASE_URL"]
5
+SECRET = os.environ["LAS_SECRET"]
6
+
7
+
8
+def get_hook_key(service, identifier):
9
+    nonce = (service + SECRET + identifier).encode("ascii")
10
+    return hashlib.sha256(nonce).hexdigest()
11
+
12
+
13
+def get_hook_url(service, identifier):
14
+    return f"{BASE_URL}hooks/{service}/{identifier}/{get_hook_key(service, identifier)}"

+ 0
- 0
lineandsinker/services/__init__.py View File


+ 57
- 0
lineandsinker/services/gitea.py View File

@@ -0,0 +1,57 @@
1
+import os
2
+
3
+from jsonref import requests
4
+
5
+from ..common import get_hook_url
6
+from .service import Service
7
+
8
+
9
+class Gitea(Service):
10
+    def __init__(self, url, token, install_hooks=False):
11
+        self._url = url
12
+        self._token = token
13
+        self._install_hooks = install_hooks
14
+
15
+    def get_repos(self):
16
+        repos = self._request("get", f"user/repos").json()
17
+        for repo in repos:
18
+            if self._install_hooks:
19
+                self._maybe_install_gitea_hook(repo["full_name"])
20
+            yield repo["full_name"], repo["ssh_url"], repo["clone_url"]
21
+
22
+    def _maybe_install_gitea_hook(self, project):
23
+        hook_url = get_hook_url("gitea", project)
24
+        path = f"repos/{project}/hooks"
25
+        hooks = self._request("get", path).json()
26
+
27
+        if hook_url not in [hook["config"]["url"] for hook in hooks]:
28
+            body = {
29
+                "active": True,
30
+                "config": {"content_type": "json", "url": hook_url},
31
+                "events": [
32
+                    "create",
33
+                    "delete",
34
+                    "fork",
35
+                    "push",
36
+                    "issues",
37
+                    "issue_comment",
38
+                    "pull_request",
39
+                    "repository",
40
+                    "release",
41
+                ],
42
+                "type": "gitea",
43
+            }
44
+            self._request("post", path, json=body).json()
45
+
46
+    def _request(self, method, api_path, **kwargs):
47
+        if "params" not in kwargs:
48
+            kwargs["params"] = {}
49
+        kwargs["params"]["access_token"] = self._token
50
+        return requests.request(method, f"{self._url}api/v1/{api_path}", **kwargs)
51
+
52
+
53
+def gitea_factory():
54
+    return Gitea(os.environ["LAS_GITEA_URL"], os.environ["LAS_GITEA_TOKEN"])
55
+
56
+
57
+Service.add_factory(gitea_factory)

+ 35
- 0
lineandsinker/services/jenkins.py View File

@@ -0,0 +1,35 @@
1
+import os
2
+import jenkins
3
+from bs4 import BeautifulSoup
4
+
5
+from .service import Service
6
+
7
+
8
+class Jenkins(Service):
9
+
10
+    SCM_CLASS = "hudson.plugins.git.GitSCM"
11
+
12
+    def __init__(self, url, username, password):
13
+        self._server = jenkins.Jenkins(url, username=username, password=password)
14
+
15
+    def get_jobs(self):
16
+        for job in self._server.get_all_jobs():
17
+            name = job["fullname"]
18
+            config = BeautifulSoup(self._server.get_job_config(name), features="xml")
19
+            for git_config in config.find_all("scm", class_=self.SCM_CLASS):
20
+                branch_spec = git_config.find("branches").find("name").text
21
+                yield name, branch_spec, git_config.find("url").text
22
+
23
+    def build_job(self, name):
24
+        self._server.build_job(name)
25
+
26
+
27
+def jenkins_factory():
28
+    return Jenkins(
29
+        os.environ["LAS_JENKINS_URL"],
30
+        os.environ["LAS_JENKINS_USER"],
31
+        os.environ["LAS_JENKINS_PASSWORD"],
32
+    )
33
+
34
+
35
+Service.add_factory(jenkins_factory)

+ 0
- 0
lineandsinker/services/registry.py View File


+ 10
- 0
lineandsinker/services/service.py View File

@@ -0,0 +1,10 @@
1
+class Service:
2
+
3
+    factories = []
4
+
5
+    def accept_hook(self, identifier, request):
6
+        pass
7
+
8
+    @classmethod
9
+    def add_factory(cls, factory):
10
+        cls.factories.append(factory)

+ 15
- 82
main.py View File

@@ -1,49 +1,31 @@
1
-import hashlib
1
+import os
2 2
 import re
3 3
 import socket
4 4
 from functools import wraps
5 5
 
6
-import jenkins
7
-import requests
8
-import os
9
-from bs4 import BeautifulSoup
10 6
 from flask import Flask, abort, request, Response
11 7
 
12
-BASE_URL = os.environ["LAS_BASE_URL"]
13
-SECRET = os.environ["LAS_SECRET"]
14
-
15
-jenkins_server = jenkins.Jenkins(
16
-    os.environ["LAS_JENKINS_URL"],
17
-    username=os.environ["LAS_JENKINS_USER"],
18
-    password=os.environ["LAS_JENKINS_PASSWORD"],
19
-)
20
-
8
+from lineandsinker.common import get_hook_key
9
+from lineandsinker.services import gitea, jenkins
21 10
 
22
-def get_hook_key(service, identifier):
23
-    nonce = (service + SECRET + identifier).encode("ascii")
24
-    return hashlib.sha256(nonce).hexdigest()
25 11
 
26
-
27
-def get_hook_url(service, identifier):
28
-    return f"{BASE_URL}hooks/{service}/{identifier}/{get_hook_key(service, identifier)}"
12
+url_pattern = re.compile(
13
+    "^/hooks/(?P<service>[^/]+)/(?P<identifier>.*)/(?P<key>[^/]+)$"
14
+)
29 15
 
30 16
 
31 17
 def authenticate(f):
32 18
     @wraps(f)
33 19
     def wrapper(*args, **kwargs):
34
-        match = re.match(
35
-            "^/hooks/(?P<service>[^/]+)/(?P<identifier>.*)/(?P<key>[^/]+)$",
36
-            request.path,
37
-        )
20
+        path = request.path
21
+        match = url_pattern.match(path)
38 22
 
39 23
         if not match:
40 24
             return Response("Bad request", 400)
41 25
 
42 26
         expected_key = get_hook_key(match.group("service"), match.group("identifier"))
43 27
         if expected_key != match.group("key"):
44
-            app.logger.info(
45
-                f"Bad request to {request.path}: expected key {expected_key}"
46
-            )
28
+            app.logger.info(f"Bad request to {path}: expected key {expected_key}")
47 29
             return Response("Invalid key", 403)
48 30
 
49 31
         return f(*args, **kwargs)
@@ -51,57 +33,6 @@ def authenticate(f):
51 33
     return wrapper
52 34
 
53 35
 
54
-def get_jenkins_jobs():
55
-    for job in jenkins_server.get_all_jobs():
56
-        config = BeautifulSoup(
57
-            jenkins_server.get_job_config(job["fullname"]), features="xml"
58
-        )
59
-        for git_config in config.find_all("scm", class_="hudson.plugins.git.GitSCM"):
60
-            branch_spec = git_config.find("branches").find("name").text
61
-            yield job["fullname"], branch_spec, git_config.find("url").text
62
-
63
-
64
-def gitea_request(method, api_path, **kwargs):
65
-    if "params" not in kwargs:
66
-        kwargs["params"] = {}
67
-    kwargs["params"]["access_token"] = os.environ["LAS_GITEA_TOKEN"]
68
-    return requests.request(
69
-        method, f"{os.environ['LAS_GITEA_URL']}api/v1/{api_path}", **kwargs
70
-    )
71
-
72
-
73
-def maybe_install_gitea_hook(project):
74
-    hook_url = get_hook_url("gitea", project)
75
-    path = f"repos/{project}/hooks"
76
-    hooks = gitea_request("get", path).json()
77
-
78
-    if hook_url not in [hook["config"]["url"] for hook in hooks]:
79
-        body = {
80
-            "active": True,
81
-            "config": {"content_type": "json", "url": hook_url},
82
-            "events": [
83
-                "create",
84
-                "delete",
85
-                "fork",
86
-                "push",
87
-                "issues",
88
-                "issue_comment",
89
-                "pull_request",
90
-                "repository",
91
-                "release",
92
-            ],
93
-            "type": "gitea",
94
-        }
95
-        gitea_request("post", path, json=body).json()
96
-
97
-
98
-def get_gitea_repos():
99
-    repos = gitea_request("get", f"user/repos").json()
100
-    for repo in repos:
101
-        maybe_install_gitea_hook(repo["full_name"])
102
-        yield repo["full_name"], repo["ssh_url"], repo["clone_url"]
103
-
104
-
105 36
 def reportbot_announce(message):
106 37
     try:
107 38
         with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
@@ -111,12 +42,14 @@ def reportbot_announce(message):
111 42
                 f"{os.environ['LAS_REPORTBOT_PREFIX']} {message}\n".encode("utf-8")
112 43
             )
113 44
             app.logger.info(f"Report bot response: {sock.recv(512)}")
114
-    except Exception:
45
+    except:
115 46
         app.logger.exception("Unable to send report bot message")
116 47
 
117 48
 
118
-repos = dict((name, [ssh, clone]) for name, ssh, clone in get_gitea_repos())
119
-jobs = list(get_jenkins_jobs())
49
+jenkins_service = jenkins.jenkins_factory()
50
+gitea_service = gitea.gitea_factory()
51
+repos = dict((name, [ssh, clone]) for name, ssh, clone in gitea_service.get_repos())
52
+jobs = list(jenkins_service.get_jobs())
120 53
 app = Flask(__name__)
121 54
 
122 55
 
@@ -140,7 +73,7 @@ def handle_hook_gitea(repo):
140 73
             if url in urls:
141 74
                 # TODO: Check branches
142 75
                 app.logger.info(f"Found matching job: {name} with URL {url}")
143
-                jenkins_server.build_job(name)
76
+                jenkins_service.build_job(name)
144 77
 
145 78
         data = request.get_json()
146 79
         if not data["repository"]["private"]:

Loading…
Cancel
Save