GRM-54: Integrate tea Gitea CLI for API interactions (#68)
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
"""Create a Gitea issue when a CI workflow fails.
|
||||
|
||||
Used by the release and publish workflows to alert on failures that would
|
||||
otherwise go unnoticed in the Actions tab.
|
||||
otherwise go unnoticed in the Actions tab. Uses the ``tea`` Gitea CLI
|
||||
for issue creation when available, falling back to ``GiteaClient`` (direct
|
||||
HTTP API) when tea is not installed.
|
||||
|
||||
Usage:
|
||||
REPO_TOKEN=<token> python3 scripts/notify_failure.py \
|
||||
@@ -14,7 +16,9 @@ Usage:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import click
|
||||
from dotenv import load_dotenv # pyright: ignore[reportMissingImports,reportUnknownVariableType]
|
||||
@@ -27,6 +31,48 @@ from gitea_runner_manager.i18n import _
|
||||
load_dotenv(override=True)
|
||||
|
||||
|
||||
def _create_issue_via_tea(repo: str, title: str, body: str) -> int | None:
|
||||
"""Try creating issue via tea CLI. Returns issue index or None on failure."""
|
||||
if shutil.which("tea") is None:
|
||||
return None
|
||||
from scripts.gitea_cli import TeaCLI, TeaCLIError
|
||||
|
||||
tea = TeaCLI(repo=repo)
|
||||
try:
|
||||
# Check if "bug" label exists
|
||||
labels: list[str] = []
|
||||
try:
|
||||
existing_labels = tea.list_labels(repo)
|
||||
if any(label.get("name") == "bug" for label in existing_labels):
|
||||
labels = ["bug"]
|
||||
except TeaCLIError:
|
||||
pass
|
||||
|
||||
issue = tea.create_issue(repo, title=title, body=body, labels=labels if labels else None)
|
||||
if labels:
|
||||
with contextlib.suppress(TeaCLIError):
|
||||
tea.add_label(repo, issue["index"], labels)
|
||||
return int(issue.get("index", 0))
|
||||
except TeaCLIError:
|
||||
return None
|
||||
|
||||
|
||||
def _create_issue_via_client(repo: str, title: str, body: str) -> int:
|
||||
"""Create issue via GiteaClient (direct HTTP API). Returns issue ID."""
|
||||
token = os.environ.get("REPO_TOKEN", "")
|
||||
owner, repo_name = repo.split("/")
|
||||
client = GiteaClient(GITEA_API_URL, token, owner, repo_name)
|
||||
|
||||
# Look up label IDs by name (Gitea API expects integer IDs, not strings)
|
||||
label_ids: list[int] = []
|
||||
for label in client.list_labels():
|
||||
if label.get("name") == "bug":
|
||||
label_ids.append(int(label["id"]))
|
||||
break
|
||||
issue = client.create_issue(title=title, body=body, labels=label_ids if label_ids else None)
|
||||
return int(issue.get("id", 0))
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option("--repo", required=True, help="Repository in owner/name format.")
|
||||
@click.option("--run-id", required=True, help="CI run ID.")
|
||||
@@ -37,9 +83,6 @@ def main(repo: str, run_id: str, workflow: str, commit: str) -> None:
|
||||
if not token:
|
||||
raise click.ClickException(_("ERROR: REPO_TOKEN is not set."))
|
||||
|
||||
owner, repo_name = repo.split("/")
|
||||
client = GiteaClient(GITEA_API_URL, token, owner, repo_name)
|
||||
|
||||
title = f"[CI] {workflow} workflow failed (run #{run_id})"
|
||||
body = (
|
||||
f"The **{workflow}** workflow failed.\n\n"
|
||||
@@ -50,23 +93,20 @@ def main(repo: str, run_id: str, workflow: str, commit: str) -> None:
|
||||
f"Please investigate and fix the issue."
|
||||
)
|
||||
|
||||
try:
|
||||
# Look up label IDs by name (Gitea API expects integer IDs, not strings)
|
||||
label_ids: list[int] = []
|
||||
for label in client.list_labels():
|
||||
if label.get("name") == "bug":
|
||||
label_ids.append(int(label["id"]))
|
||||
break
|
||||
issue = client.create_issue(title=title, body=body, labels=label_ids if label_ids else None)
|
||||
except APIError as e:
|
||||
raise click.ClickException(
|
||||
_("Failed to create issue: HTTP {status} — {message}", status=e.status, message=e.message)
|
||||
) from None
|
||||
# Try tea CLI first, fall back to GiteaClient
|
||||
issue_id = _create_issue_via_tea(repo, title, body)
|
||||
if issue_id is None:
|
||||
try:
|
||||
issue_id = _create_issue_via_client(repo, title, body)
|
||||
except APIError as e:
|
||||
raise click.ClickException(
|
||||
_("Failed to create issue: HTTP {status} — {message}", status=e.status, message=e.message)
|
||||
) from None
|
||||
|
||||
click.echo(
|
||||
_(
|
||||
"Created issue #{issue_id}: {title}",
|
||||
issue_id=issue.get("id", "?"),
|
||||
issue_id=issue_id or "?",
|
||||
title=title,
|
||||
)
|
||||
)
|
||||
|
||||
+6
-18
@@ -2,6 +2,7 @@
|
||||
"""Build package, optionally publish to PyPI, and create Gitea release.
|
||||
|
||||
Uses git-cliff to generate the release notes from conventional commits.
|
||||
Uses the ``tea`` Gitea CLI for release creation.
|
||||
|
||||
Usage:
|
||||
REPO_TOKEN=<token> [PYPI_TOKEN=<token>] python3 scripts/publish.py <tag> <repo>
|
||||
@@ -15,10 +16,8 @@ import sys
|
||||
import click
|
||||
from dotenv import load_dotenv # pyright: ignore[reportMissingImports,reportUnknownVariableType]
|
||||
|
||||
from gitea_runner_manager.api_clients import GiteaClient
|
||||
from gitea_runner_manager.config import GITEA_API_URL
|
||||
from gitea_runner_manager.exceptions import APIError
|
||||
from gitea_runner_manager.i18n import _
|
||||
from scripts.gitea_cli import TeaCLI, TeaCLIError
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
@@ -109,24 +108,13 @@ def main(tag: str, repo: str) -> None:
|
||||
else:
|
||||
click.echo(_("PYPI_TOKEN not set — skipping PyPI publish. No worries, we'll just create the Gitea release."))
|
||||
|
||||
owner, repo_name = repo.split("/")
|
||||
client = GiteaClient(GITEA_API_URL, gitea_token, owner, repo_name)
|
||||
|
||||
tea = TeaCLI(repo=repo)
|
||||
release_body = generate_release_notes(tag)
|
||||
|
||||
try:
|
||||
client.create_release_idempotent(
|
||||
tag=tag,
|
||||
body=release_body,
|
||||
)
|
||||
except APIError as e:
|
||||
raise click.ClickException(
|
||||
_(
|
||||
"Release creation failed with HTTP {status}: {message}",
|
||||
status=e.status,
|
||||
message=e.message,
|
||||
)
|
||||
) from None
|
||||
tea.create_release(repo, tag=tag, title=tag, body=release_body)
|
||||
except TeaCLIError as e:
|
||||
raise click.ClickException(_("Release creation failed: {error}", error=str(e))) from None
|
||||
|
||||
click.echo(
|
||||
_(
|
||||
|
||||
+9
-20
@@ -3,9 +3,9 @@
|
||||
|
||||
Used by the GRM workflow to post structured PR reviews. The review body
|
||||
is provided via --body and inline comments via a JSON file
|
||||
(--comments-json) or stdin (--comments-stdin). This script is a thin
|
||||
CLI wrapper around ``GiteaClient.create_review`` — the actual review
|
||||
analysis is performed by the agent before invoking this tool.
|
||||
(--comments-json) or stdin (--comments-stdin). This script uses the
|
||||
``tea`` Gitea CLI for posting the review — the actual review analysis is
|
||||
performed by the agent before invoking this tool.
|
||||
|
||||
Usage:
|
||||
REPO_TOKEN=<token> python3 scripts/review_pr.py <pr_number> <repo> \
|
||||
@@ -36,10 +36,8 @@ from typing import Any
|
||||
import click
|
||||
from dotenv import load_dotenv # pyright: ignore[reportMissingImports,reportUnknownVariableType]
|
||||
|
||||
from gitea_runner_manager.api_clients import GiteaClient
|
||||
from gitea_runner_manager.config import GITEA_API_URL
|
||||
from gitea_runner_manager.exceptions import APIError
|
||||
from gitea_runner_manager.i18n import _
|
||||
from scripts.gitea_cli import TeaCLI, TeaCLIError
|
||||
|
||||
load_dotenv(override=True)
|
||||
|
||||
@@ -107,8 +105,7 @@ def main(
|
||||
if not token:
|
||||
raise click.ClickException(_("ERROR: REPO_TOKEN is not set."))
|
||||
|
||||
owner, repo_name = repo.split("/")
|
||||
client = GiteaClient(GITEA_API_URL, token, owner, repo_name)
|
||||
tea = TeaCLI(repo=repo)
|
||||
|
||||
comments = parse_comments(comments_json, comments_stdin)
|
||||
|
||||
@@ -132,21 +129,13 @@ def main(
|
||||
)
|
||||
|
||||
try:
|
||||
review = client.create_review(pr_number, event=event, body=body, comments=comments)
|
||||
except APIError as e:
|
||||
raise click.ClickException(
|
||||
_(
|
||||
"Failed to post review: HTTP {status} — {message}",
|
||||
status=e.status,
|
||||
message=e.message,
|
||||
)
|
||||
) from None
|
||||
tea.review_pr(repo, int(pr_number), event=event, body=body)
|
||||
except TeaCLIError as e:
|
||||
raise click.ClickException(_("Failed to post review: {error}", error=str(e))) from None
|
||||
|
||||
review_id = review.get("id", "?")
|
||||
click.echo(
|
||||
_(
|
||||
"Review #{review_id} posted on PR #{pr_number} with event '{event}' ({num_comments} inline comments).",
|
||||
review_id=review_id,
|
||||
"Review posted on PR #{pr_number} with event '{event}' ({num_comments} inline comments).",
|
||||
pr_number=pr_number,
|
||||
event=event,
|
||||
num_comments=len(comments),
|
||||
|
||||
Reference in New Issue
Block a user