|
@@ -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"]:
|