diff --git a/ghmoon b/ghmoon index 61a0df3..04b39c5 100755 --- a/ghmoon +++ b/ghmoon @@ -227,7 +227,7 @@ class GHCommit: else: status("error", "Internal error", gist) - return state == "success" + return state, gist class GHRepo: @@ -260,7 +260,10 @@ class GHRepo: if artifact.sha != sha: continue - self.process({ "sha": sha, "artifact": artifact.data }, interactive) + return self.process({ "sha": sha, "artifact": artifact.data }, interactive) + + sys.stderr.write(f"No matching artifact for {sha} in {str(self)}\n") + return "error", None def process(self, job, interactive=True): sha = job["sha"] @@ -271,7 +274,7 @@ class GHRepo: if not c.exists(): sys.stderr.write(f"Ignoring non-existing commit {sha} from {str(self)}\n") - return False + return "error", None c.checkout() @@ -289,9 +292,11 @@ class WorkQueue: "doing": os.path.join(path, "doing"), "done": os.path.join(path, "done"), } + self.pause_file = os.path.join(path, "paused") + self.result_path = os.path.join(path, "result") - for path in self.paths.values(): - os.makedirs(path, exist_ok=True) + for p in list(self.paths.values()) + [self.result_path]: + os.makedirs(p, exist_ok=True) if manage: for job in os.listdir(self.paths["doing"]): @@ -299,6 +304,21 @@ class WorkQueue: os.rename(os.path.join(self.paths["doing"], job), os.path.join(self.paths["todo"], job)) + def write_result(self, name, state, gist=None, report_log=None, error=None, heading=None): + result = { + "state": state, + "gist": gist, + "report_log": report_log, + "finished_at": time.time(), + "error": error, + "heading": heading, + } + path = os.path.join(self.result_path, f"{name}.json") + tmp = path + ".tmp" + with open(tmp, "w") as f: + f.write(json.dumps(result)) + os.replace(tmp, path) + def _job_paths(self, name): return { state: os.path.join(self.paths[state], f"{name}.json") @@ -348,6 +368,7 @@ class WorkQueue: "type": "process", "repo": str(repo), "sha": artifact.sha, + "heading": repo.api(f"commits/{artifact.sha}")["commit"]["message"].splitlines()[0], "artifact": artifact.data, }) @@ -396,10 +417,12 @@ class WorkQueue: if not ("repo" in job and "sha" in job): sys.stderr.write(f"Skipping {name}: Malformed process job\n") + self.write_result(name, "error", error="Malformed process job") os.rename(paths["todo"], paths["done"]) return if not job["repo"] in repos: sys.stderr.write(f"Skipping {name}: Unknown repo {job['repo']}\n") + self.write_result(name, "error", error=f"Unknown repo {job['repo']}") os.rename(paths["todo"], paths["done"]) return @@ -409,18 +432,35 @@ class WorkQueue: sys.stderr.write(f"Skipping {name}: Job disappeared\n") return + state, gist, error = "error", None, None try: sys.stderr.write(f"Processing {name}\n") - repos[job["repo"]].process(job, not self.publish) + state, gist = repos[job["repo"]].process(job, not self.publish) sys.stderr.write(f"Processed {name}\n") except Exception as e: sys.stderr.write(f"Aborting {name}: {str(e)}\n") traceback.print_exc() + error = str(e) + + repo_obj = repos.get(job["repo"]) + report_log = None + if repo_obj: + candidate = f"{repo_obj.path}/report-{job['sha']}.log" + if os.path.exists(candidate): + report_log = candidate + + self.write_result(name, state, gist=gist, report_log=report_log, error=error, + heading=job.get("heading")) os.rename(paths["doing"], paths["done"]) return def process_next(self): + if os.path.exists(self.pause_file): + if os.listdir(self.paths["todo"]): + sys.stderr.write("Skipping todo, work is paused\n") + return False + job = self._dequeue() if not job: return False @@ -515,4 +555,11 @@ if __name__ == "__main__": elif args.cmd == "enqueue": wq.enqueue() elif args.cmd == "process": - sys.exit(0 if repos[args.repo].process_standalone(args.sha, not args.publish) else 1) + repo_obj = repos[args.repo] + state, gist = repo_obj.process_standalone(args.sha, not args.publish) + name = f"{args.repo.replace('/', '-')}-{args.sha}" + heading = repo_obj.api(f"commits/{args.sha}")["commit"]["message"].splitlines()[0] + candidate = f"{repo_obj.path}/report-{args.sha}.log" + report_log = candidate if os.path.exists(candidate) else None + wq.write_result(name, state, gist=gist, report_log=report_log, heading=heading) + sys.exit(0 if state == "success" else 1)