diff --git a/server.py b/server.py index b0366d4..653ddbd 100644 --- a/server.py +++ b/server.py @@ -1,4 +1,5 @@ import argparse +import collections import dataclasses import json import logging @@ -15,13 +16,13 @@ import time from metrics import MetricsHandler - from prometheus_client import generate_latest load_dotenv() app = FastAPI() +pending_commits = collections.defaultdict(set) app.add_middleware( @@ -49,6 +50,7 @@ class RepoToWatch: name: str branch: str path: str + actions_need_to_pass: bool = False @dataclasses.dataclass @@ -173,35 +175,45 @@ def update_repo(repo_config: RepoToWatch) -> RepoUpdateResult: except Exception: logger.exception("update_repo had a bad time") +def handle_workflow_run(payload, repo_name): + workflow_run = payload.get("workflow_run", {}) + status = workflow_run.get("status") + conclusion = workflow_run.get("conclusion") + head_commit = workflow_run.get("head_commit", {}).get("id") + branch = workflow_run.get("head_branch") -@app.post("/webhook") -async def github_webhook(request: Request): - MetricsHandler.last_smee_request_timestamp.set(time.time()) - payload_body = await request.body() - payload = json.loads(payload_body) - - event_header = request.headers.get("X-GitHub-Event") - # check if this is a push event - if event_header != "push": + if head_commit not in pending_commits.get(repo_name, set()): + return { + "status": f"Not in pending_commits" + } + + if status != "completed" or conclusion != "success": return { - "status": f"X-GitHub-Event header was not set to push, got value {event_header}" + "status": f"Committed changes did not pass requirements. Status: {status}" } - + + actions_need_to_pass = True + commits = pending_commits.get(repo_name) + if commits: + pending_commits[repo_name].discard(head_commit) + + # check for any empty repos + if not commits: + pending_commits.pop(repo_name) + ref = payload.get("ref", "") branch = ref.split("/")[-1] - repo_name = payload.get("repository", {}).get("name") - key = (repo_name, branch) if args.development and key not in config: # if we are in development mode, pretend that # we wanted to watch this repo no matter what - config[key] = RepoToWatch(name=repo_name, branch=branch, path="/dev/null") + config[key] = RepoToWatch(name=repo_name, branch=branch, path="/dev/null", actions_need_to_pass=actions_need_to_pass) if key not in config: logging.warning(f"not acting on repo and branch name of {key}") return {"status": f"not acting on repo and branch name of {key}"} - + logger.info(f"Push to {branch} detected for {repo_name}") # update the repo thread = threading.Thread(target=update_repo, args=(config[key],)) @@ -210,6 +222,38 @@ async def github_webhook(request: Request): return {"status": "webhook received"} + +@app.post("/webhook") +async def github_webhook(request: Request): + MetricsHandler.last_smee_request_timestamp.set(time.time()) + payload_body = await request.body() + payload = json.loads(payload_body) + event_header = request.headers.get("X-GitHub-Event") + repo_name = payload.get("repository", {}).get("name") + actions_need_to_pass = False + + if (not repo_name): + return {"status": "missing repo name"} + + if event_header == "push": + head_commit = payload.get("head_commit", {}).get("id") + if not head_commit: + return {"status": "missing head_commit"} + pending_commits[repo_name].add(head_commit) + logger.info(f"Stored {head_commit} for {repo_name}") + + return { + "status": f"commit recorded" + } + + elif event_header == "workflow_run": + handle_workflow_run(payload, repo_name) + + else: + return { + "status": f"X-GitHub-Event header was not set to a valid event, got value {event_header}" + } + @app.get("/metrics") def get_metrics(): return Response( @@ -222,12 +266,11 @@ def get_metrics(): def read_root(): return {"message": "SCE CICD Server"} - def start_smee(): try: # sends the smee command to the tmux session named smee + # "npx", smee_cmd = [ - "npx", "smee", "--url", os.getenv("SMEE_URL"), @@ -237,6 +280,7 @@ def start_smee(): process = subprocess.Popen( smee_cmd, + shell=True ) logger.info(f"smee started with PID {process.pid}") except Exception: