-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
200 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
"""Expose features related to git repositories.""" | ||
|
||
from __future__ import annotations | ||
|
||
import datetime | ||
import json | ||
import os | ||
from subprocess import run | ||
from typing import Annotated | ||
|
||
import typer | ||
from rich import box | ||
from rich.console import Console | ||
from rich.panel import Panel | ||
from typer_config.decorators import use_yaml_config | ||
|
||
|
||
class TyperApp(typer.Typer): | ||
"""Our App.""" | ||
|
||
repos: list[str] | ||
|
||
|
||
app = TyperApp() | ||
console = Console() | ||
|
||
|
||
@app.callback(invoke_without_command=True) | ||
@use_yaml_config( | ||
default_value=os.path.expanduser("~/pre.yml"), | ||
param_help="Configuration file (~/pre.yml).", | ||
) | ||
# https://github.com/tiangolo/typer/issues/533 | ||
def default(repos: Annotated[list[str], typer.Option()] = []) -> None: | ||
"""Implicit entry point.""" | ||
if repos is None: | ||
repos = [] | ||
# breakpoint() | ||
app.repos = list(filter(lambda s: not s.startswith("_"), repos)) | ||
|
||
|
||
@app.command() | ||
def releases() -> None: | ||
"""Pre helps you chain releases on github.""" | ||
for repo in app.repos: | ||
repo_link = f"[markdown.link][link=https://github.com/{repo}]{repo}[/][/]" | ||
result = run( | ||
f'gh api repos/{repo}/releases --jq "[.[] | select(.draft)"]', | ||
text=True, | ||
shell=True, # noqa: S602 | ||
capture_output=True, | ||
check=True, | ||
) | ||
drafts = json.loads(result.stdout) | ||
if not drafts or ( | ||
isinstance(drafts, dict) and drafts["message"] == "Not Found" | ||
): | ||
console.print(f"🟢 {repo_link} [dim]has no draft release.[/]") | ||
continue | ||
for draft in drafts: | ||
created = datetime.datetime.fromisoformat(draft["created_at"]).replace( | ||
tzinfo=None, | ||
) | ||
age = (datetime.datetime.now(tz=datetime.timezone.utc) - created).days | ||
if not draft["body"].strip(): | ||
console.print(f"🟢 {repo_link} [dim]has an empty draft release.[/]") | ||
continue | ||
|
||
md = Panel(draft["body"].replace("\n\n", "\n").strip("\n"), box=box.MINIMAL) | ||
msg = ( | ||
f"🟠 {repo_link} draft release " | ||
f"[link={draft['html_url']}][markdown.link]{draft['tag_name']}[/][/]" | ||
f" created [repr.number]{age}[/] days ago:\n" | ||
) | ||
console.print(msg, highlight=False, end="") | ||
console.print(md, style="dim") | ||
|
||
|
||
@app.command() | ||
def prs() -> None: | ||
"""List pending pull-request.""" | ||
# for user in TEAM: | ||
# --review-requested=@{user} | ||
# --owner=ansible --owner=ansible-community | ||
cmd = ( | ||
"GH_PAGER= gh search prs --draft=false --state=open --limit=100 --sort=updated" | ||
) | ||
cmd += "".join(f" --repo={repo}" for repo in app.repos) | ||
cmd += ( | ||
" --template '{{range .}}{{tablerow .repository.nameWithOwner (timeago .updatedAt) " | ||
'.title (hyperlink .url (printf "#%v" .number) ) }}{{end}}{{tablerender}}\' ' | ||
"--json title,url,repository,updatedAt,number" | ||
) | ||
console.print(f"[dim]{cmd}[/]", highlight=False) | ||
os.system(cmd) # noqa: S605 | ||
|
||
|
||
@app.command() | ||
def alerts() -> None: | ||
"""List open alerts.""" | ||
for repo in app.repos: | ||
cmd = "GH_PAGER= gh " | ||
cmd += f"api /repos/{repo}/dependabot/alerts" | ||
cmd += " --jq='.[] | select(.state!=\"fixed\") | .html_url'" | ||
result = run( | ||
cmd, | ||
text=True, | ||
shell=True, # noqa: S602 | ||
capture_output=True, | ||
check=False, | ||
) | ||
if result.returncode: | ||
console.print( | ||
f"[dim]{cmd}[/dim] failed with {result.returncode}\n" | ||
f"{result.stdout}\n\n{result.stderr}", | ||
) | ||
else: | ||
if result.stdout: | ||
console.print(result.stdout) | ||
if result.stderr: | ||
console.print(result.stderr) | ||
|
||
|
||
if __name__ == "__main__": | ||
# execute only if run as a script | ||
app() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
from __future__ import annotations | ||
|
||
from pathlib import Path | ||
|
||
from mk.exec import run_or_fail | ||
from mk.tools import Action, Tool | ||
|
||
|
||
class PreTool(Tool): | ||
name = "pre" | ||
|
||
def run(self, action: Action | None = None): | ||
if action: | ||
run_or_fail(["pre", action.name], tee=True) | ||
|
||
def is_present(self, path: Path) -> bool: | ||
return True | ||
|
||
def actions(self) -> list[Action]: | ||
# for command in app.registered_commands: | ||
# print(command.name, command.short_help, command.short_help, command.epilog, command.short_help) | ||
# breakpoint() | ||
return [ | ||
Action(name="prs", description="[dim]Show open PRs[/dim]", tool=self), | ||
Action( | ||
name="drafts", | ||
description="[dim]Show draft releases[/dim]", | ||
tool=self, | ||
), | ||
Action( | ||
name="alerts", | ||
description="[dim]Show dependabot security alerts[/dim]", | ||
tool=self, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--- | ||
repos: | ||
- ansible/ansible-compat | ||
- ansible/ansible-lint | ||
- ansible/ansible-navigator | ||
- ansible/ansible-creator | ||
- ansible/molecule | ||
- ansible/tox-ansible | ||
- ansible/pytest-ansible | ||
- ansible/ansible-development-environment | ||
- ansible/ansible-dev-tools | ||
- ansible/creator-ee |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""Tests""" | ||
|
||
from typer.testing import CliRunner | ||
|
||
from mk.pre import app | ||
|
||
runner = CliRunner() | ||
|
||
|
||
def test_main() -> None: | ||
"""CLI Tests""" | ||
result = runner.invoke(app, ["--help", "--config=test/pre.yml"]) | ||
assert result.exit_code == 0, result.stdout | ||
assert "Pre helps you chain releases on github." in result.stdout |