Skip to content

Commit

Permalink
Merge pull request #1204 from tier4/ci/check-message-update
Browse files Browse the repository at this point in the history
Check message definition updates automatically
  • Loading branch information
HansRobo authored Feb 29, 2024
2 parents 314f1ec + 50c202b commit f5e0bc0
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 2 deletions.
150 changes: 150 additions & 0 deletions .github/msgs_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/python3

from glob import glob
import re
from dataclasses import dataclass
from typing import Set, Dict
from catkin_pkg.packages import find_packages
from catkin_pkg.package import Package
from subprocess import check_output
from pathlib import Path
from itertools import chain
from json import dumps
import requests
import os


# cspell: ignore srvs
@dataclass
class UsedPackage:
msgs: Set[str]
srvs: Set[str]


# u_int8 -> UInt8
def to_camel_case(snake_str: str):
return "".join(x.capitalize() for x in snake_str.lower().split("_"))


def either_glob(str: str):
return "".join([f"[{c.lower()}{c.upper()}]" if c.isalpha() else c for c in str])


def main():
# Glob all *.cpp / *.hpp files
files = glob("**/*.cpp", recursive=True) + glob("**/*.hpp", recursive=True)

# Message include regex
msg_include_regex = re.compile(r"#include\s*[<\"](.+_msgs)/msg/(.+)\.hpp[>\"]")
srv_include_regex = re.compile(r"#include\s*[<\"](.+_srv)/srv/(.+)\.hpp[>\"]")

# Check for `#include` statements
used_packages: Dict[str, UsedPackage] = {}
for file in files:
with open(file, "r") as f:
lines = f.readlines()
for line in lines:
msg_match = msg_include_regex.match(line)
srv_match = srv_include_regex.match(line)
if msg_match:
package = msg_match.group(1)
msg = to_camel_case(msg_match.group(2))

if package not in used_packages:
used_packages[package] = UsedPackage(set(), set())
used_packages[package].msgs.add(msg)

if srv_match:
package = srv_match.group(1)
srv = to_camel_case(srv_match.group(2))

if package not in used_packages:
used_packages[package] = UsedPackage(set(), set())
used_packages[package].srvs.add(srv)

# Expect external packages to be in the workspace...
pkgs: Dict[str, Package] = find_packages(".")
known_packages = [pkg.name for pkg in pkgs.values()]
unknown_packages = set(used_packages.keys()) - set(known_packages)
if len(unknown_packages) > 0:
print(f"Unknown packages: {unknown_packages}")

updated_patches = []

for path, pkg in pkgs.items():
if pkg.name not in used_packages:
continue

used_msgs = used_packages[pkg.name].msgs
used_srvs = used_packages[pkg.name].srvs
used_names = used_msgs | used_srvs

base_path = Path(path)
check_paths = chain(
*(
[base_path.rglob(f"**/{either_glob(msg)}.msg") for msg in used_names]
+ [base_path.rglob(f"**/{either_glob(msg)}.srv") for msg in used_names]
+ [base_path.rglob(f"**/{either_glob(msg)}.idl") for msg in used_names]
)
)
existing_files = [path for path in check_paths if path.exists()]
existing_files = [str(path.relative_to(base_path)) for path in existing_files]

if len(existing_files) == 0:
print(
f"Package {pkg.name} has no messages or services {used_msgs} {used_srvs}"
)
continue

# Call `git log` for 7 days history
# cspell: ignore oneline
log = (
check_output(
[
"git",
"log",
"--since",
"7.days",
"-p",
"--minimal",
"--pretty=oneline",
"--",
*existing_files,
],
cwd=base_path,
)
.strip()
.decode("utf-8")
)

if len(log) == 0:
print(f"Package {pkg.name} has no recent changes")
continue

updated_patches.append(log)

if len(updated_patches) == 0:
print("No patches to notify")
return

patches = "\n".join(updated_patches)

# Post to GitHub issues comment

body = dumps(
{
"body": f"```diff\n{patches}\n```",
}
)
requests.post(
f"https://api.github.com/repos/{os.environ['GITHUB_REPOSITORY']}/issues/{os.environ['ISSUE_NUMBER']}/comments",
headers={
"Authorization": f"token {os.environ['GITHUB_TOKEN']}",
"Content-Type": "application/json",
},
data=body,
)


if __name__ == "__main__":
main()
45 changes: 45 additions & 0 deletions .github/workflows/CheckMessageDepsUpdate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Check msgs / srvs update
on:
schedule:
- cron: "0 0 * * 1"
workflow_dispatch:

jobs:
check_message_updates:
name: Check message updates
runs-on: ubuntu-22.04
container: ros:humble
steps:
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
path: scenario_simulator_v2

- name: Install dependencies
run: |
vcs import scenario_simulator_v2/external < scenario_simulator_v2/dependency_humble.repos
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"

- uses: abatilo/actions-poetry@v2
with:
poetry-version: "1.5.1"

- name: Install Python dependencies
run: |
cd scenario_simulator_v2
poetry install --no-interaction
- name: Check updates
shell: bash
run: |
cd scenario_simulator_v2
poetry run python3 .github/msgs_checker.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
ISSUE_NUMBER: 1203
52 changes: 50 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ mkdocs-codeinclude-plugin = "^0.2.1"
mkdocs-git-revision-date-localized-plugin = "^1.2.0"
plantuml = "^0.3.0"
mkdocs-redirects = "^1.2.1"
requests = "^2.31.0"
catkin-pkg = "^1.0.0"


[build-system]
Expand Down

0 comments on commit f5e0bc0

Please sign in to comment.