Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve background garbage prs and branches collection in unit tests when concurrent tests are run #23

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 66 additions & 23 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
import shlex
import sys
import textwrap
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from importlib.machinery import SourceFileLoader
from importlib.util import spec_from_loader, module_from_spec
from itertools import groupby
from os import chdir, getcwd, mkdir, environ
from os.path import basename, dirname, realpath
from platform import python_version
from shutil import rmtree
from subprocess import Popen, check_output, CalledProcessError, STDOUT, PIPE
from typing import Literal
from typing import Any, Literal, cast
from unittest import TestCase

GIT_GROK_PATH = dirname(dirname(realpath(__file__))) + "/git-grok"
Expand All @@ -20,6 +22,19 @@
MAX_BRANCH_AGE = timedelta(minutes=10)


@dataclass
class GarbageItem:
kind: Literal["sync", "async"]
name: str
ts: str


@dataclass
class GarbageTask:
kind: Literal["sync", "async"]
task: Any


def import_path(path: str):
module_name = basename(path).replace("-", "_")
spec = spec_from_loader(module_name, SourceFileLoader(module_name, path))
Expand Down Expand Up @@ -91,8 +106,13 @@ def git_init_and_cd_to_test_dir(
)

check_output_x("git", "fetch")
old_branches = [
{"name": name.replace(f"{TEST_REMOTE}/", ""), "date": date}

branches = [
GarbageItem(
kind=kind,
name=name.replace(f"{TEST_REMOTE}/", ""),
ts=date,
)
for b in check_output_x(
"git",
"for-each-ref",
Expand All @@ -101,15 +121,23 @@ def git_init_and_cd_to_test_dir(
).splitlines()
for name, date in [b.split()]
if (
name != f"{TEST_REMOTE}/main"
and datetime.now(timezone.utc)
- datetime.fromisoformat(date.replace("Z", "+00:00"))
> MAX_BRANCH_AGE
kind := (
("grok/" in name and initial_branch in name and "sync")
or (
name != f"{TEST_REMOTE}/main"
and from_now(date) > MAX_BRANCH_AGE
and "async"
)
or None
)
)
or ("grok/" in name and initial_branch in name)
]
old_prs = [
pr
prs = [
GarbageItem(
kind=kind,
name=str(pr["number"]),
ts=str(pr["updatedAt"]),
)
for pr in json.loads(
check_output_x(
"gh",
Expand All @@ -122,28 +150,37 @@ def git_init_and_cd_to_test_dir(
)
)
if (
datetime.now(timezone.utc)
- datetime.fromisoformat(pr["updatedAt"].replace("Z", "+00:00"))
> MAX_BRANCH_AGE
kind := (
(initial_branch in pr["headRefName"] and "sync")
or (from_now(pr["updatedAt"]) > MAX_BRANCH_AGE and "async")
or None
)
)
or initial_branch in pr["headRefName"]
]

tasks = [
git_grok.Task(check_output_x, "gh", "pr", "close", str(pr["number"]))
for pr in old_prs
]
if old_branches:
tasks.append(
git_grok.Task(
GarbageTask(
kind=pr.kind,
task=git_grok.Task(check_output_x, "gh", "pr", "close", pr.name),
)
for pr in prs
] + [
GarbageTask(
kind=cast(Any, kind),
task=git_grok.Task(
check_output_x,
"git",
"push",
TEST_REMOTE,
"--delete",
*[branch["name"] for branch in old_branches],
)
*[branch.name for branch in group],
),
)
[task.wait() for task in tasks if task]
for kind, group in groupby(branches, key=lambda branch: branch.kind)
]
[task.task.wait() for task in tasks if task.kind == "sync"]
# Leave async tasks work in background and swallow errors (e.g. in case a
# branch has already been deleted by a parallel test run or so).


def git_touch(file: str):
Expand Down Expand Up @@ -234,4 +271,10 @@ def git_init_and_cd_to_test_dir(
)


def from_now(ts: str) -> timedelta:
return datetime.now(timezone.utc) - datetime.fromisoformat(
ts.replace("Z", "+00:00")
)


git_grok = import_path(GIT_GROK_PATH)
Loading