WebHook broker that accepts notifications from multiple platforms and performs simple actions in response
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.py 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import hashlib
  2. import jenkins
  3. import requests
  4. import os
  5. from bs4 import BeautifulSoup
  6. from flask import Flask, abort
  7. BASE_URL = os.environ["LAS_BASE_URL"]
  8. SECRET = os.environ["LAS_SECRET"]
  9. jenkins_server = jenkins.Jenkins(
  10. os.environ["LAS_JENKINS_URL"],
  11. username=os.environ["LAS_JENKINS_USER"],
  12. password=os.environ["LAS_JENKINS_PASSWORD"],
  13. )
  14. def get_hook_key(service, identifier):
  15. nonce = (service + SECRET + identifier).encode("ascii")
  16. return hashlib.sha256(nonce).hexdigest()
  17. def get_hook_url(service, identifier):
  18. return f"{BASE_URL}hooks/{service}/{identifier}/{get_hook_key(service, identifier)}"
  19. def get_jenkins_jobs():
  20. for job in jenkins_server.get_all_jobs():
  21. config = BeautifulSoup(
  22. jenkins_server.get_job_config(job["fullname"]), features="xml"
  23. )
  24. for git_config in config.find_all("scm", class_="hudson.plugins.git.GitSCM"):
  25. branch_spec = git_config.find("branches").find("name").text
  26. yield job["fullname"], branch_spec, git_config.find("url").text
  27. def maybe_install_gitea_hook(project):
  28. gitea_url = f"{os.environ['LAS_GITEA_URL']}api/v1/repos/{project}/hooks"
  29. hook_url = get_hook_url("gitea", project)
  30. hooks = requests.get(
  31. gitea_url, params={"access_token": os.environ["LAS_GITEA_TOKEN"]}
  32. ).json()
  33. if hook_url not in [hook["config"]["url"] for hook in hooks]:
  34. body = {
  35. "active": True,
  36. "config": {"content_type": "json", "url": hook_url},
  37. "events": [
  38. "create",
  39. "delete",
  40. "fork",
  41. "push",
  42. "issues",
  43. "issue_comment",
  44. "pull_request",
  45. "repository",
  46. "release",
  47. ],
  48. "type": "gitea",
  49. }
  50. requests.post(
  51. gitea_url,
  52. json=body,
  53. params={"access_token": "5b8de94a7201bc923e99813850327caf75b85e70"},
  54. ).json()
  55. def get_gitea_repos():
  56. repos = requests.get(
  57. f"{os.environ['LAS_GITEA_URL']}api/v1/user/repos",
  58. params={"access_token": os.environ["LAS_GITEA_TOKEN"]},
  59. ).json()
  60. for repo in repos:
  61. maybe_install_gitea_hook(repo["full_name"])
  62. yield repo["full_name"], repo["ssh_url"], repo["clone_url"]
  63. repos = dict((name, [ssh, clone]) for name, ssh, clone in get_gitea_repos())
  64. jobs = list(get_jenkins_jobs())
  65. app = Flask(__name__)
  66. @app.route("/")
  67. def handle_index():
  68. return app.send_static_file("index.html")
  69. @app.route("/hooks/gitea/<path:repo>/<hash>", methods=['POST'])
  70. def handle_hook_gitea(repo, hash):
  71. print(f"Received hook for repo {repo} with has {hash}")
  72. expected_hash = get_hook_key("gitea", repo)
  73. if hash != expected_hash:
  74. print(f"Hash mismatch: expected {expected_hash}")
  75. abort(403)
  76. if repo not in repos:
  77. print(f"Repository not found. Known repos: {repos.keys()}")
  78. abort(404)
  79. urls = repos[repo]
  80. for name, spec, url in jobs:
  81. if url in urls:
  82. # TODO: Check branches
  83. print(f"Found matching job: {name} with URL {url}")
  84. jenkins_server.build_job(name)
  85. return "", 204
  86. app.run("0.0.0.0")