Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def main():
# skip branches with the pattern _*
if args.head_branch.startswith("_"):
return
repo = Repository(args.token, "legendu-net", "github_rest_api")
repo = Repository(args.token, "legendu-net/github_rest_api")
repo.create_pull_request(
{
"base": args.base_branch,
Expand Down
14 changes: 9 additions & 5 deletions github_rest_api/actions/cargo/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
from pathlib import Path
import datetime
import shutil
import subprocess as sp
from dulwich import porcelain
from ..utils import (
config_git,
create_branch,
switch_branch,
push_branch,
gen_temp_branch,
commit_benchmarks,
)
from ...utils import run_cmd


def _copy_last_dev_bench(bench_dir: Path) -> None:
branch = gen_temp_branch()
create_branch(branch)
porcelain.checkout(repo=".", new_branch=branch)
switch_branch(branch="gh-pages", fetch=True)
src = bench_dir / "dev/criterion"
tmpdir = tempfile.mkdtemp()
Expand All @@ -37,7 +37,11 @@ def _cargo_criterion(bench_dir: Path, env: str = "") -> None:
:param branch: The branch to benchmark.
"""
_copy_last_dev_bench(bench_dir=bench_dir)
run_cmd(f"{env} cargo criterion --all-features --message-format=json")
sp.run(
f"{env} cargo criterion --all-features --message-format=json",
shell=True,
check=True,
)


def _copy_bench_results(bench_dir: Path, storage: str) -> None:
Expand All @@ -63,7 +67,7 @@ def _git_push_gh_pages(bench_dir: Path, pr_number: str) -> str:
commit_benchmarks(bench_dir=bench_dir)
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
branch = f"gh-pages_{pr_number}_{timestamp}"
create_branch(branch=branch)
porcelain.checkout(repo=".", new_branch=branch)
push_branch(branch=branch)
return branch

Expand Down
6 changes: 3 additions & 3 deletions github_rest_api/actions/cargo/profiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import psutil
from .utils import build_project
from ..utils import config_git, switch_branch, push_branch, commit_profiling
from ...utils import partition, run_cmd
from ...utils import partition


def launch_application(cmd: list[str]) -> int:
Expand Down Expand Up @@ -64,13 +64,13 @@ def nperf(pid: int, prof_name: str, prof_dir: str | Path = ".") -> Path:
yymmdd = time.strftime("%Y%m%d")
prof_dir.mkdir(exist_ok=True, parents=True)
data_file = prof_dir / f"{yymmdd}_{prof_name}"
run_cmd(f"nperf record -p {pid} -o '{data_file}'")
sp.run(f"nperf record -p {pid} -o '{data_file}'", shell=True, check=True)
return _gen_flamegraph(data_file)


def _gen_flamegraph(data_file: Path) -> Path:
flamegraph = data_file.with_name(data_file.name + ".svg")
run_cmd(f"nperf flamegraph '{data_file}' > '{flamegraph}'")
sp.run(f"nperf flamegraph '{data_file}' > '{flamegraph}'", shell=True, check=True)
return flamegraph


Expand Down
6 changes: 4 additions & 2 deletions github_rest_api/actions/cargo/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Util functions for building GitHub Actions for Rust projects."""

from ...utils import run_cmd
import subprocess as sp


def build_project(profile: str = "release") -> None:
"""Build the Rust project.
:param profile: The profile for building.
"""
run_cmd(f"RUSTFLAGS=-Awarnings cargo build --profile {profile}")
sp.run(
f"RUSTFLAGS=-Awarnings cargo build --profile {profile}", shell=True, check=True
)
51 changes: 17 additions & 34 deletions github_rest_api/actions/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,8 @@
from typing import Iterable
from pathlib import Path
import random
from ..utils import run_cmd


class FailToPushToGitHubException(Exception):
"""Exception for failure to push a branch to GitHub."""

def __init__(self, branch: str, branch_alt: str):
msg = f"Failed to push the branch {branch} to GitHub!"
if branch_alt:
msg += f" Pushed to {branch_alt} instead."
super().__init__(msg)
from dulwich import porcelain
from dulwich.repo import Repo


def config_git(local_repo_dir: str | Path, user_email: str, user_name: str):
Expand All @@ -22,18 +13,9 @@ def config_git(local_repo_dir: str | Path, user_email: str, user_name: str):
:param user_email: The email of the user (no need to be a valid one).
:param user_name: The name of the user.
"""
cmd = f"""git config --global --add safe.directory {local_repo_dir} \
&& git config --global user.email "{user_email}" \
&& git config --global user.name "{user_name}"
"""
run_cmd(cmd)


def create_branch(branch: str) -> None:
"""Create a new local branch.
:param branch: The new local branch to create.
"""
run_cmd(f"git checkout -b {branch}")
config = Repo(local_repo_dir).get_config()
config.set(b"user", b"email", user_email.encode())
config.set(b"user", b"name", user_name.encode())


def switch_branch(branch: str, fetch: bool) -> None:
Expand All @@ -42,8 +24,8 @@ def switch_branch(branch: str, fetch: bool) -> None:
:param fetch: If true, fetch the branch from remote first.
"""
if fetch:
run_cmd(f"git fetch origin {branch}")
run_cmd(f"git checkout {branch}")
porcelain.fetch(repo=".")
porcelain.checkout(repo=".", target=branch)


def gen_temp_branch(
Expand All @@ -67,26 +49,27 @@ def push_branch(branch: str, branch_alt: str = ""):
:param branch_alt: An alternative branch name to push to GitHub.
"""
try:
run_cmd(f"git push origin {branch}")
porcelain.push(repo=".", refspecs=branch)
except Exception as err:
if branch_alt:
cmd = f"""git checkout {branch} \
&& git checkout -b {branch_alt} \
&& git push origin {branch_alt}
"""
run_cmd(cmd)
raise FailToPushToGitHubException(branch, branch_alt) from err
porcelain.checkout(repo=".", target=branch)
porcelain.checkout(repo=".", new_branch=branch_alt)
porcelain.push(repo=".", refspecs=branch_alt)
else:
raise err


def commit_benchmarks(bench_dir: str | Path):
"""Commit changes in the benchmark directory.
:param bench_dir: The benchmark directory.
"""
run_cmd(f"git add {bench_dir} && git commit -m 'add benchmarks'")
porcelain.add(paths=bench_dir)
porcelain.commit(message="Add benchmarks.")


def commit_profiling(prof_dir: str | Path):
"""Commit changes in the profiling directory.
:param prof_dir: The profiling directory.
"""
run_cmd(f"git add {prof_dir} && git commit -m 'update profiling results'")
porcelain.add(paths=prof_dir)
porcelain.commit(message="Updating profiling results.")
18 changes: 8 additions & 10 deletions github_rest_api/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,18 @@ def put(self, url, raise_for_status: bool = True) -> requests.Response:
class Repository(GitHub):
"""Abstraction of a GitHub repository."""

def __init__(self, token: str, owner: str, repo: str):
def __init__(self, token: str, repo: str):
"""Initialize Repository.
:param token: An authorization token for GitHub REST APIs.
:param owner: The owner of the repository.
:param repo: The name of the repository.
:param repo: A GitHub repository (in the format of owner/repo).
"""
super().__init__(token)
self._owner = owner
self._repo = repo
self._url_pull = f"https://api.github.com/repos/{owner}/{repo}/pulls"
self._url_branches = f"https://api.github.com/repos/{owner}/{repo}/branches"
self._url_refs = f"https://api.github.com/repos/{owner}/{repo}/git/refs"
self._url_issues = f"https://api.github.com/repos/{owner}/{repo}/issues"
self._url_releases = f"https://api.github.com/repos/{owner}/{repo}/releases"
self._url_pull = f"https://api.github.com/repos/{repo}/pulls"
self._url_branches = f"https://api.github.com/repos/{repo}/branches"
self._url_refs = f"https://api.github.com/repos/{repo}/git/refs"
self._url_issues = f"https://api.github.com/repos/{repo}/issues"
self._url_releases = f"https://api.github.com/repos/{repo}/releases"

def get_releases(self) -> list[dict[str, Any]]:
"""List releases in this repository."""
Expand Down Expand Up @@ -315,4 +313,4 @@ def get_repositories(
return repos

def instantiate_repository(self, repo: str) -> Repository:
return Repository(token=self._token, owner=self._owner, repo=repo)
return Repository(token=self._token, repo=f"{self._owner}/{repo}")
14 changes: 0 additions & 14 deletions github_rest_api/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Some generally useful util functions."""

from itertools import tee, filterfalse
import logging
import subprocess as sp


def partition(pred, iterable):
Expand All @@ -12,15 +10,3 @@ def partition(pred, iterable):
"""
it1, it2 = tee(iterable)
return filter(pred, it1), filterfalse(pred, it2)


def run_cmd(cmd: list | str, capture_output: bool = False) -> None:
"""Run a shell command.

:param cmd: The command to run.
:param capture_output: Whether to capture stdout and stderr of the command.
"""
proc = sp.run(
cmd, shell=isinstance(cmd, str), check=True, capture_output=capture_output
)
logging.debug(proc.args)
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[project]
name = "github_rest_api"
version = "0.26.0"
version = "0.27.0"
description = "Simple wrapper of GitHub REST APIs."
authors = [{ name = "Ben Du", email = "longendu@yahoo.com" }]
requires-python = ">=3.11,<4"
readme = "README.md"
dependencies = [
"requests>=2.28.2",
"psutil>=5.9.4",
"dulwich>=0.25.1",
]

[dependency-groups]
Expand Down
34 changes: 34 additions & 0 deletions uv.lock

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

Loading