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

Fix logging reamd #13

Merged
merged 8 commits into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
name: Tox test
strategy:
matrix:
tox_env: [py38, py39, py310, py311, py312]
tox_env: [py311, py312]
phracek marked this conversation as resolved.
Show resolved Hide resolved
# Use GitHub's Linux Docker host
runs-on: ubuntu-latest
steps:
Expand Down
25 changes: 7 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,36 +82,25 @@ the email service is configured, then the results are send to corresponding emai

# Automatic pull request merger

This option is used for analysation pull request in the specific namespace and repositories mentioned
This option is used for analyation pull request in the specific namespace and repositories mentioned
phracek marked this conversation as resolved.
Show resolved Hide resolved
in configuration file. At the end `auto-merger` provides the output into command line.

```bash
$ auto-merger pr-checker --help
Usage: auto-merger pr-checker [OPTIONS]
$ auto-merger merger --help
Usage: auto-merger merger [OPTIONS]

Options:
--send-email TEXT Specify email addresses to which the mail will be sent.
--help Show this message and exit.

```

The real output from `auto-merger pr-checker` could be:
The real output from `auto-merger merger` could be:
```bash
s2i-ruby-container
------

https://github.com/sclorg/s2i-ruby-container/pull/570 pr/missing-review pr/failing-ci
https://github.com/sclorg/s2i-ruby-container/pull/569 dependencies ruby pr/missing-review
SUMMARY
https://github.com/sclorg/mariadb-container/pull/262 -> CAN BE MERGED
Let's try to merge 262....

s2i-nodejs-container
------

https://github.com/sclorg/s2i-nodejs-container/pull/463 pr/missing-review pr/failing-ci
https://github.com/sclorg/s2i-nodejs-container/pull/236 pr/missing-review


Pull requests that can be merged or missing 2 approvals
https://github.com/sclorg/s2i-python-container/pull/574 - Missing 2 APPROVAL
```

In case user specifies `--send-email`, multipletimes, and the system where is auto-merger running
Expand Down
3 changes: 3 additions & 0 deletions auto-merger
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ from auto_merger.exceptions import AutoMergerConfigException

logger = logging.getLogger("auto-merger")


@click.group("auto-merger")
@click.option("-d", "--debug", is_flag=True, default=False, help="Enable debug logs")
@click.pass_context
Expand All @@ -56,12 +57,14 @@ def auto_merger(ctx, debug):
sys.exit(10)
ctx.obj = c
logger.debug(f"auto_merger Debug: {ctx.obj.debug}")
ctx.obj.debug = debug
if ctx.obj.debug:
setup_logger(level=logging.DEBUG)
else:
setup_logger(level=logging.INFO)
logger.debug("Let's get analyses")


auto_merger.add_command(pr_checker)
auto_merger.add_command(merger)

Expand Down
8 changes: 5 additions & 3 deletions auto_merger/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
from auto_merger.config import Config
from auto_merger.merger import AutoMerger

logger = logging.getLogger("auto-merger")
logger = logging.getLogger(__name__)


def pull_request_checker(config: Config, send_email: List[str]) -> int:
"""
Checks NVR from brew build against pulp
"""
logger.debug(f"Configuration: {config.__str__()}")
pr_status_checker = PRStatusChecker(config=config)
ret_value = pr_status_checker.check_all_containers()
if ret_value != 0:
Expand All @@ -47,7 +49,7 @@ def pull_request_checker(config: Config, send_email: List[str]) -> int:


def merger(config: Config, send_email: List[str]) -> int:
logger.debug(f"merger: {config.__str__()}")
logger.debug(f"Configuration: {config.__str__()}")
auto_merger = AutoMerger(config=config)
ret_value = auto_merger.check_all_containers()
if ret_value != 0:
Expand All @@ -57,4 +59,4 @@ def merger(config: Config, send_email: List[str]) -> int:
if send_email:
if not auto_merger.send_results(send_email):
return 1
return ret_value
return ret_value
3 changes: 2 additions & 1 deletion auto_merger/cli/merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
from auto_merger.config import pass_config
from auto_merger import api

logger = logging.getLogger("auto-merger")

logger = logging.getLogger(__name__)

@click.command("merger")
@click.option("--send-email", multiple=True, help="Specify email addresses to which the mail will be sent.")
Expand Down
7 changes: 3 additions & 4 deletions auto_merger/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,20 @@
import smtplib
import logging

from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from typing import List

logger = logging.getLogger(__name__)


class EmailSender:

def __init__(self, recipient_email: List[str] = None):
self.recipient_email = recipient_email
self.mime_msg = MIMEMultipart()
self.send_from = ""
self.send_to = ""
self.send_to = [""]

def create_email_msg(self, subject_msg: str):
if not self.recipient_email:
Expand All @@ -59,5 +59,4 @@ def send_email(self, subject_msg, body: List[str] = None):
smtp = smtplib.SMTP("127.0.0.1")
smtp.sendmail(self.send_from, self.send_to, self.mime_msg.as_string())
smtp.close()
print("Sending email finished")

logger.info("Sending email finished")
73 changes: 37 additions & 36 deletions auto_merger/merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@
import logging

from datetime import datetime, timedelta
from typing import List
from pathlib import Path

from typing import Dict, List
phracek marked this conversation as resolved.
Show resolved Hide resolved

from auto_merger import utils
from auto_merger.config import Config
from auto_merger.utils import cwd
from auto_merger.email import EmailSender

logger = logging.getLogger("auto-merger")

logger = logging.getLogger(__name__)


class AutoMerger:
Expand All @@ -54,8 +54,8 @@ def __init__(self, config: Config):
self.approvals = self.config.github["approvals"]
self.namespace = self.config.github["namespace"]
self.pr_lifetime = self.config.github["pr_lifetime"]
self.pr_to_merge = {}
self.approval_body = []
self.pr_to_merge: Dict = {}
self.approval_body: List = []
phracek marked this conversation as resolved.
Show resolved Hide resolved
self.repo_data: List = []
self.temp_dir = ""

Expand All @@ -82,32 +82,21 @@ def get_gh_pr_list(self):
continue
self.repo_data.append(pr)

def is_authenticated(self):
def is_authenticated(self) -> bool:
token = os.getenv("GH_TOKEN")
if token == "":
logger.error(f"Environment variable GH_TOKEN is not specified.")
logger.error("Environment variable GH_TOKEN is not specified.")
return False
cmd = [f"gh status"]
cmd = ["gh status"]
logger.debug(f"Authentication command: {cmd}")
try:
return_output = utils.run_command(cmd=cmd, return_output=True)
utils.run_command(cmd=cmd, return_output=True)
except subprocess.CalledProcessError as cpe:
logger.error(f"Authentication to GitHub failed. {cpe}")
return False
return True

def add_approved_pr(self, pr: {}):
self.pr_to_merge[self.container_name].append({
"number": pr["number"],
"pr_dict": {
"title": pr["title"],
"labels": pr["labels"],
"createdAt": pr["createdAt"],
}
})
logger.debug(f"PR {pr['number']} added to approved")

def check_labels_to_merge(self, pr):
def check_labels_to_merge(self, pr) -> bool:
if "labels" not in pr:
return False
logger.debug(f"check_labels_to_merge for {self.container_name}: {pr['labels']} and {self.approval_labels}")
Expand Down Expand Up @@ -149,7 +138,9 @@ def is_draft(pull_request):
return True
return False

def check_pr_lifetime(self, pr: dict) -> bool:
def check_pr_lifetime(self, pr=None) -> bool:
if pr is None:
return False
if self.pr_lifetime == 0:
return True
if "createdAt" not in pr:
Expand All @@ -165,7 +156,10 @@ def check_pr_to_merge(self) -> bool:
return False
for pr in self.repo_data:
if not self.check_labels_to_merge(pr):
logger.debug(f"check_pr_to_merge for {self.container_name}: pull request {pr['number']} did not met labels.")
logger.debug(
f"check_pr_to_merge for {self.container_name}: "
f"pull request {pr['number']} did not met labels."
)
continue
if "reviews" not in pr:
logger.debug(
Expand All @@ -182,10 +176,12 @@ def check_pr_to_merge(self) -> bool:
"title": pr["title"],
}
})
return True

def clone_repo(self):
utils.run_command(
f"gh repo clone https://github.com/{self.namespace}/{self.container_name} {self.temp_dir}/{self.container_name}"
f"gh repo clone https://github.com/{self.namespace}/{self.container_name} "
f"{self.temp_dir}/{self.container_name}"
)
self.container_dir = Path(self.temp_dir) / f"{self.container_name}"

Expand All @@ -198,7 +194,6 @@ def merge_pull_requests(self):
os.chdir(self.current_dir)
self.clean_dirs()


def clean_dirs(self):
os.chdir(self.current_dir)
if self.container_dir.exists():
Expand All @@ -217,9 +212,9 @@ def merge_pr(self):
logger.error(f"Merging pr {pr} failed with reason {cpe.output}")
continue

def check_all_containers(self) -> int:
def check_all_containers(self) -> bool:
if not self.is_authenticated():
return 1
return False
self.temp_dir = utils.temporary_dir()
for container in self.config.github["repos"]:
self.container_name = container
Expand All @@ -240,15 +235,16 @@ def check_all_containers(self) -> int:
logger.error(f"Something went wrong {self.container_name}.")
continue
os.chdir(self.current_dir)
return 0
return True

def print_pull_request_to_merge(self):
# Do not print anything in case we do not have PR.
if not [x for x in self.pr_to_merge if self.pr_to_merge[x]]:
return 0
logger.info(f"Nothing to be merged in repos {self.config.github['repos']} "
f"in organization {self.namespace}")
return
to_approval: bool = False
pr_body: List = []
is_empty: bool = False
pr_body: list[str] = []
logger.info("SUMMARY")
for container, pr_list in self.pr_to_merge.items():
for pr in pr_list:
Expand All @@ -257,23 +253,28 @@ def print_pull_request_to_merge(self):
if int(pr["approvals"]) < self.approvals:
continue
to_approval = True
result_pr = f"CAN BE MERGED"
result_pr = "CAN BE MERGED"
logger.info(f"https://github.com/{self.namespace}/{container}/pull/{pr['number']} -> {result_pr}")
pr_body.append(
f"<tr><td>https://github.com/{self.namespace}/{container}/pull/{pr['number']}</td>"
f"<td>{pr['pr_dict']['title']}</td><td><p style='color:red;'>{result_pr}</p></td></tr>"
)
if to_approval:
self.approval_body.append(f"Pull requests that can be merged.")
self.approval_body.append("<table><tr><th>Pull request URL</th><th>Title</th><th>Approval status</th></tr>")
self.approval_body.append("Pull requests that can be merged.")
self.approval_body.append(
"<table><tr><th>Pull request URL</th><th>Title</th><th>Approval status</th></tr>"
)
self.approval_body.extend(pr_body)
self.approval_body.append("</table><br>")
is_empty = True
if not to_approval:
logger.info(
f"Nothing to be merged in repos {self.config.github['repos']} in organization {self.namespace}"
)

def send_results(self, recipients):
logger.debug(f"Recipients are: {recipients}")
if not recipients:
return 1
return False
sender_class = EmailSender(recipient_email=list(recipients))
subject_msg = f"Pull request statuses for organization https://github.com/{self.namespace}"
if self.approval_body:
Expand Down
Loading
Loading