Skip to content

Adapt Devstar/Gitea action integration#2308

Open
mengning wants to merge 3 commits intoThe-PR-Agent:mainfrom
devstar-actions:devstar
Open

Adapt Devstar/Gitea action integration#2308
mengning wants to merge 3 commits intoThe-PR-Agent:mainfrom
devstar-actions:devstar

Conversation

@mengning
Copy link
Copy Markdown

@mengning mengning commented Apr 6, 2026

Adapt Devstar/Gitea action integration

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Add Gitea Actions runner and ticket context integration

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add Gitea Actions runner integration for automated PR workflows
• Implement issue context fetching and ticket compliance checking for Gitea
• Refactor repository settings handling with hardcoded .pr_agent.toml path
• Add Docker build workflow and update documentation for Devstar/Gitea support
Diagram
flowchart LR
  A["Gitea Actions Event"] -->|"EVENT_NAME, TOKEN"| B["gitea_action_runner.py"]
  B -->|"Configure Provider"| C["GiteaProvider"]
  C -->|"Fetch Issue Context"| D["get_issue_main_description"]
  C -->|"Extract Tickets"| E["ticket_pr_compliance_check.py"]
  B -->|"Execute Tools"| F["PRDescription/Reviewer/Suggestions"]
  G["entrypoint.sh"] -->|"Route Event"| B
  H["Docker Workflow"] -->|"Build & Push"| I["Docker Image"]
Loading

Grey Divider

File Changes

1. pr_agent/servers/gitea_actions_runner.py ✨ Enhancement +224/-0

New Gitea Actions runner implementation

• New file implementing Gitea Actions runner for automated PR workflows
• Handles event routing for pull_request and issue_comment events
• Configures Gitea provider with environment variables (DEVSTAR_URL, GITEA_URL, TOKEN)
• Implements PR filtering logic based on authors, titles, and branches
• Supports multilingual response injection and repository settings loading
• Executes PR description, review, and code suggestion tools based on configuration

pr_agent/servers/gitea_actions_runner.py


2. pr_agent/git_providers/gitea_provider.py ✨ Enhancement +32/-18

Add issue context and improve settings handling

• Hardcode repo_settings to .pr_agent.toml instead of reading from configuration
• Add get_issue_main_description() method to fetch issue body for acceptance criteria
• Add get_issue() wrapper method in repo API for fetching issue details
• Refactor get_repo_settings() with exception handling and return bytes instead of string
• Improve error handling with specific 404 detection for missing configuration files

pr_agent/git_providers/gitea_provider.py


3. pr_agent/tools/ticket_pr_compliance_check.py ✨ Enhancement +32/-0

Add Gitea ticket extraction support

• Add GiteaProvider import and support for Gitea ticket extraction
• Implement ticket extraction logic for Gitea using regex pattern matching on PR description
• Fetch issue details including body, title, labels, and URL from Gitea API
• Handle character limit truncation for issue bodies (MAX_TICKET_CHARACTERS)
• Add error handling with warning logs for failed Gitea issue fetches

pr_agent/tools/ticket_pr_compliance_check.py


View more (3)
4. github_action/entrypoint.sh ✨ Enhancement +8/-1

Add Gitea Actions routing logic

• Add environment variable check for Gitea Actions (GITEA_EVENT_NAME or GITEA_ACTIONS)
• Route to gitea_action_runner.py for Gitea events, fallback to GitHub runner
• Set PYTHONUNBUFFERED=1 for unbuffered Python output

github_action/entrypoint.sh


5. .github/workflows/build-and-push.yaml ⚙️ Configuration changes +34/-0

Add Docker build and push workflow

• New workflow file for building and pushing Docker images on devstar branch pushes
• Uses Docker Buildx for multi-platform builds
• Authenticates with Docker Hub using secrets
• Builds image from Dockerfile.github_action with caching
• Tags image with latest version

.github/workflows/build-and-push.yaml


6. README.md 📝 Documentation +4/-4

Update documentation for Devstar/Gitea support

• Update Gitea column header to "Devstar/Gitea" for clarity
• Mark Actions support as enabled (✅) for Devstar/Gitea
• Mark Fetching ticket context as enabled (✅) for Devstar/Gitea
• Mark Self reflection as enabled (✅) for Devstar/Gitea

README.md


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 6, 2026

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown
Contributor

qodo-free-for-open-source-projects bot commented Apr 6, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (9) 📎 Requirement gaps (0) 🎨 UX Issues (0)

Grey Divider


Action required

1. entrypoint.sh calls missing runner 📘 Rule violation ☼ Reliability
Description
github_action/entrypoint.sh runs python /app/pr_agent/servers/gitea_action_runner.py, but this
PR adds pr_agent/servers/gitea_actions_runner.py (different filename). This will fail at runtime
when Gitea actions are detected, preventing the action from starting.
Code

github_action/entrypoint.sh[R4-5]

+if [ -n "$GITEA_EVENT_NAME" ] || [ "$GITEA_ACTIONS" == "true" ]; then
+    python /app/pr_agent/servers/gitea_action_runner.py
Evidence
The entrypoint invokes a runner filename that does not exist in the repository after this PR,
causing an unhandled startup error when the condition is met (violating robust handling for action
startup).

Rule 3: Robust Error Handling
github_action/entrypoint.sh[4-5]
pr_agent/servers/gitea_actions_runner.py[1-1]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The action entrypoint runs `gitea_action_runner.py`, but the repo contains `gitea_actions_runner.py`. This causes the container to crash when Gitea actions are detected.

## Issue Context
The mismatch is in the startup path for Devstar/Gitea actions.

## Fix Focus Areas
- github_action/entrypoint.sh[4-5]
- pr_agent/servers/gitea_actions_runner.py[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Hardcoded .pr_agent.toml path 📘 Rule violation ⚙ Maintainability
Description
The Gitea provider now hardcodes the repository settings path to .pr_agent.toml instead of reading
it from configuration. This makes behavior non-configurable and breaks the intended configuration
override mechanism.
Code

pr_agent/git_providers/gitea_provider.py[38]

+        self.repo_settings = ".pr_agent.toml"
Evidence
The compliance checklist requires behavior to be controlled via Dynaconf/TOML overrides rather than
hard-coded values. The PR sets self.repo_settings and filepath to .pr_agent.toml directly in
code.

AGENTS.md
pr_agent/git_providers/gitea_provider.py[38-38]
pr_agent/git_providers/gitea_provider.py[617-624]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Repository settings path is hard-coded to `.pr_agent.toml` in the Gitea provider, preventing configuration overrides.

## Issue Context
Previously this value was configurable; hard-coding reduces deployability and breaks expected configuration patterns.

## Fix Focus Areas
- pr_agent/git_providers/gitea_provider.py[38-38]
- pr_agent/git_providers/gitea_provider.py[617-624]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Broad except Exception in provider 📘 Rule violation ☼ Reliability
Description
New Gitea provider methods catch Exception broadly and then return empty values, which can mask
unexpected failures and make debugging harder. This violates the requirement to use targeted
exception handling and preserve error context.
Code

pr_agent/git_providers/gitea_provider.py[R551-553]

+        except Exception as e:
+            self.logger.error(f"Failed to fetch Gitea issue body: {e}")
+            return ""
Evidence
The checklist prohibits broad except Exception; the added code catches all exceptions while
fetching issue bodies/settings and degrades to empty results without exception chaining.

pr_agent/git_providers/gitea_provider.py[546-553]
pr_agent/git_providers/gitea_provider.py[630-635]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Gitea provider uses broad `except Exception` and returns empty values, masking unexpected failures.

## Issue Context
Fetching issue bodies and repo settings should catch expected API/HTTP errors (e.g., 404) separately, and preserve context when re-raising/wrapping.

## Fix Focus Areas
- pr_agent/git_providers/gitea_provider.py[546-553]
- pr_agent/git_providers/gitea_provider.py[630-635]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (4)
4. Broad except Exception in runner 📘 Rule violation ☼ Reliability
Description
pr_agent/servers/gitea_actions_runner.py uses broad except Exception in multiple places, which
can hide real bugs and removes error specificity. This violates the requirement to catch expected
exception types and preserve context.
Code

pr_agent/servers/gitea_actions_runner.py[R132-137]

+    try:
+        with open(EVENT_PATH, "r") as f:
+            event_payload = json.load(f)
+    except Exception as e:
+        get_logger().error(f"Failed to parse payload JSON: {e}")
+        return
Evidence
The runner wraps JSON parsing, settings application, and filtering logic in except Exception,
rather than handling expected error types (e.g., OSError, json.JSONDecodeError) with targeted
handling.

pr_agent/servers/gitea_actions_runner.py[84-86]
pr_agent/servers/gitea_actions_runner.py[132-137]
pr_agent/servers/gitea_actions_runner.py[153-156]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Gitea actions runner catches `Exception` broadly in multiple blocks.

## Issue Context
Replace broad catches with specific exceptions (e.g., `json.JSONDecodeError`, `FileNotFoundError`, provider API exceptions) and use exception chaining when appropriate.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[84-86]
- pr_agent/servers/gitea_actions_runner.py[132-137]
- pr_agent/servers/gitea_actions_runner.py[153-156]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. set() dedupes ticket_numbers 📘 Rule violation ☼ Reliability
Description
Ticket numbers are deduplicated via set(...), which does not preserve ordering and can produce
non-deterministic ticket processing order. This can lead to unstable outputs, especially when
truncation/limits are applied later.
Code

pr_agent/tools/ticket_pr_compliance_check.py[223]

+            ticket_numbers = list(set(re.findall(r'#(\d+)', user_description)))
Evidence
The checklist requires deterministic ordering when merging/deduplicating. The new Gitea ticket
extraction uses list(set(...)), which is unordered.

pr_agent/tools/ticket_pr_compliance_check.py[221-224]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ticket_numbers = list(set(...))` is non-deterministic and can reorder extracted tickets.

## Issue Context
Stable ordering matters for consistent reviews and reproducible outputs.

## Fix Focus Areas
- pr_agent/tools/ticket_pr_compliance_check.py[221-224]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Runner whitespace/newline issues 📘 Rule violation ⚙ Maintainability
Description
pr_agent/servers/gitea_actions_runner.py includes trailing whitespace and is missing a final
newline, which can cause pre-commit hooks to fail. This violates repository whitespace and newline
requirements.
Code

pr_agent/servers/gitea_actions_runner.py[124]

+        get_logger().info(f"Resolved Gitea URL from GITEA_URL: {FINAL_GITEA_URL}")  
Evidence
Pre-commit checks commonly enforce no trailing whitespace and require a final newline; the diff
explicitly shows trailing spaces and \ No newline at end of file.

AGENTS.md
pr_agent/servers/gitea_actions_runner.py[124-124]
pr_agent/servers/gitea_actions_runner.py[223-224]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new runner file has trailing whitespace and no final newline, which can fail pre-commit hooks.

## Issue Context
The diff shows trailing spaces and indicates a missing newline at EOF.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[124-124]
- pr_agent/servers/gitea_actions_runner.py[223-224]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. PR URL field mismatch 🐞 Bug ≡ Correctness
Description
pr_agent/servers/gitea_actions_runner.py reads PR URL from pull_request.html_url, but the existing
Gitea handler uses pull_request.url. If the Actions payload matches the webhook payload shape,
pr_url will be empty and the runner exits without processing PR events.
Code

pr_agent/servers/gitea_actions_runner.py[R139-150]

+    # 4. Extract the PR URL
+    pr_url = None
+    if EVENT_NAME in ["pull_request", "pull_request_target"]:
+        pr_url = event_payload.get("pull_request", {}).get("html_url")
+    elif EVENT_NAME == "issue_comment":
+        issue_data = event_payload.get("issue", {})
+        if "pull_request" in issue_data:
+            pr_url = issue_data.get("pull_request", {}).get("html_url") or issue_data.get("html_url")
+
+    if not pr_url:
+        get_logger().warning("No valid PR URL found in the payload. Exiting.")
+        return
Evidence
The new Actions runner only looks for pull_request.html_url, while the existing Gitea webhook
server extracts the PR URL from pull_request.url. This inconsistency means PR URL extraction can
fail, leading to an early exit (No valid PR URL found).

pr_agent/servers/gitea_actions_runner.py[139-150]
pr_agent/servers/gitea_app.py[86-101]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Gitea Actions runner extracts the PR URL from `pull_request.html_url` only. Existing Gitea code paths use `pull_request.url`, so the runner can fail to find a PR URL and exit.

### Issue Context
Gitea webhook handling uses `pull_request.url` as the canonical URL passed into `apply_repo_settings()` / `handle_request()`.

### Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[139-150]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

8. Mixed get_settings access 📘 Rule violation ⚙ Maintainability
Description
The runner mixes key-based settings access (get_settings().set(...)) with attribute-based access
(get_settings().config.get(...) / get_settings().config.is_auto_command = True) in the same
flow. This increases the risk of inconsistent behavior and unvalidated configuration values.
Code

pr_agent/servers/gitea_actions_runner.py[R106-200]

+    # 2. Configure Git provider identity and self-hosted address
+    get_settings().set("config.git_provider", "gitea")
+    get_settings().set("gitea.personal_access_token", TOKEN)
+
+    if OPENAI_KEY:
+        get_settings().set("OPENAI.KEY", OPENAI_KEY)
+    else:
+        print("OPENAI_KEY not set")
+
+    if OPENAI_ORG:
+        get_settings().set("OPENAI.ORG", OPENAI_ORG)
+
+    get_settings().set("gitea.url", FINAL_GITEA_URL)
+    get_settings().set("gitea.api_url", f"{FINAL_GITEA_URL}/api/v1")
+
+    if DEVSTAR_URL:
+        get_logger().info(f"Resolved Gitea URL from DEVSTAR_URL: {FINAL_GITEA_URL}")
+    elif GITEA_URL:
+        get_logger().info(f"Resolved Gitea URL from GITEA_URL: {FINAL_GITEA_URL}")  
+    else:
+        get_logger().info(f"No URL configuration detected, using default:{FINAL_GITEA_URL}")
+
+    get_settings().set("GITHUB.USER_TOKEN", TOKEN)
+    get_settings().set("GITHUB.DEPLOYMENT_TYPE", "user")
+
+    # 3. Read the local payload JSON
+    try:
+        with open(EVENT_PATH, "r") as f:
+            event_payload = json.load(f)
+    except Exception as e:
+        get_logger().error(f"Failed to parse payload JSON: {e}")
+        return
+
+    # 4. Extract the PR URL
+    pr_url = None
+    if EVENT_NAME in ["pull_request", "pull_request_target"]:
+        pr_url = event_payload.get("pull_request", {}).get("html_url")
+    elif EVENT_NAME == "issue_comment":
+        issue_data = event_payload.get("issue", {})
+        if "pull_request" in issue_data:
+            pr_url = issue_data.get("pull_request", {}).get("html_url") or issue_data.get("html_url")
+
+    if not pr_url:
+        get_logger().warning("No valid PR URL found in the payload. Exiting.")
+        return
+
+    # 5. Apply repository-level configuration (.pr_agent.toml)
+    try:
+        apply_repo_settings(pr_url)
+    except Exception as e:
+        get_logger().warning(f"Failed to apply repository settings: {e}")
+
+    if os.path.exists(".pr_agent.toml"):
+        get_logger().info("Loaded local .pr_agent.toml")
+        get_settings().load_file(".pr_agent.toml")
+    elif os.path.exists("/workspace/.pr_agent.toml"):
+        get_settings().load_file("/workspace/.pr_agent.toml")
+        get_logger().info("Loaded local .pr_agent.toml")
+
+    # 6. Inject multilingual instruction prompts
+    try:
+        response_language = get_settings().config.get("response_language", "en-us")
+        if response_language.lower() != "en-us":
+            get_logger().info(f"Custom response language detected: {response_language}")
+            lang_instruction_text = (
+                f"Your response MUST be written in the language corresponding to locale code: "
+                f"'{response_language}'. This is crucial."
+            )
+            separator_text = "\n======\n\nIn addition, "
+
+            for key in get_settings():
+                setting = get_settings().get(key)
+                if str(type(setting)) == "<class 'dynaconf.utils.boxing.DynaBox'>":
+                    if key.lower() in ["pr_description", "pr_code_suggestions", "pr_reviewer"]:
+                        if hasattr(setting, "extra_instructions"):
+                            extra_instructions = setting.extra_instructions
+                            if lang_instruction_text not in str(extra_instructions):
+                                updated_instructions = (
+                                    str(extra_instructions) + separator_text + lang_instruction_text
+                                    if extra_instructions
+                                    else lang_instruction_text
+                                )
+                                setting.extra_instructions = updated_instructions
+    except Exception as e:
+        get_logger().warning(f"Instruction injection failed: {e}")
+
+    # 7. Core event routing and execution
+    if EVENT_NAME in ["pull_request", "pull_request_target"]:
+        if not should_process_pr_logic(event_payload):
+            return
+
+        action = event_payload.get("action")
+        if action in ["opened", "reopened", "ready_for_review", "synchronize", "synchronized"]:
+            get_settings().config.is_auto_command = True
+            get_logger().info(f"Triggered automated review action: {action}")
Evidence
The checklist requires a single consistent settings access pattern and validation/normalization. The
new code mixes .set(...) with .config.get(...) and direct .config mutation.

pr_agent/servers/gitea_actions_runner.py[106-120]
pr_agent/servers/gitea_actions_runner.py[166-168]
pr_agent/servers/gitea_actions_runner.py[197-204]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The runner mixes Dynaconf access styles (`.set`, `.config.get`, and direct `.config` mutation) in one code path.

## Issue Context
Standardizing access reduces bugs caused by differing key casing/paths and improves predictability.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[106-120]
- pr_agent/servers/gitea_actions_runner.py[166-168]
- pr_agent/servers/gitea_actions_runner.py[197-204]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Hardcoded https://gitea.com default 📘 Rule violation ⚙ Maintainability
Description
The runner hardcodes a default base URL (https://gitea.com) when no environment variable is
present. This runtime behavior should be controlled via the configuration/override system rather
than embedded in code.
Code

pr_agent/servers/gitea_actions_runner.py[R96-99]

+    DEVSTAR_URL = os.environ.get("DEVSTAR_URL")
+    GITEA_URL = os.environ.get("GITEA_URL")
+    FINAL_GITEA_URL = normalize_url(DEVSTAR_URL or GITEA_URL or "https://gitea.com")
+
Evidence
The checklist requires configuration overrides (Dynaconf/TOML) for behavior changes instead of
hard-coded values. The PR introduces a hard-coded default URL in the runner logic.

AGENTS.md
pr_agent/servers/gitea_actions_runner.py[96-99]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The runner falls back to a hard-coded `https://gitea.com` URL.

## Issue Context
This should come from Dynaconf defaults / TOML settings so deployments can override behavior without code changes.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[96-99]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Redundant inner import re 📘 Rule violation ⚙ Maintainability
Description
The new Gitea ticket extraction branch adds import re inside the function even though re is
already imported at module scope. This is unnecessary and may be flagged by linting rules.
Code

pr_agent/tools/ticket_pr_compliance_check.py[R219-223]

+        elif isinstance(git_provider, GiteaProvider):
+            import re
+            user_description = git_provider.get_pr_description_full()
+            
+            ticket_numbers = list(set(re.findall(r'#(\d+)', user_description)))
Evidence
The repository enforces lint/format tooling; redundant imports and avoidable style issues can fail
Ruff/pre-commit checks. The module already imports re, yet the new code re-imports it in the
function branch.

pr_agent/tools/ticket_pr_compliance_check.py[1-1]
pr_agent/tools/ticket_pr_compliance_check.py[219-223]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Gitea branch re-imports `re` inside the function even though it is already imported at the top of the module.

## Issue Context
This is unnecessary and may trigger lint failures.

## Fix Focus Areas
- pr_agent/tools/ticket_pr_compliance_check.py[1-1]
- pr_agent/tools/ticket_pr_compliance_check.py[219-223]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
11. Unbounded ticket fetch 🐞 Bug ➹ Performance
Description
extract_tickets() for Gitea fetches every “#<num>” occurrence in the PR description with no cap,
unlike the GitHub branch that limits to 3 tickets. This can trigger many API calls and slow the
compliance check significantly.
Code

pr_agent/tools/ticket_pr_compliance_check.py[R219-250]

+        elif isinstance(git_provider, GiteaProvider):
+            import re
+            user_description = git_provider.get_pr_description_full()
+            
+            ticket_numbers = list(set(re.findall(r'#(\d+)', user_description)))
+            tickets_content = []

+            for ticket_num_str in ticket_numbers:
+                try:
+                    ticket_num = int(ticket_num_str)
+                    issue = git_provider.repo_api.get_issue(git_provider.owner, git_provider.repo, ticket_num)
+
+                    if issue:
+                        issue_body_str = issue.body or ""
+                        if len(issue_body_str) > MAX_TICKET_CHARACTERS:
+                            issue_body_str = issue_body_str[:MAX_TICKET_CHARACTERS] + "..."
+
+                        labels = []
+                        if hasattr(issue, 'labels') and issue.labels:
+                            labels = [label.name for label in issue.labels]
+
+                        tickets_content.append({
+                            'ticket_id': ticket_num,
+                            'ticket_url': f"{git_provider.base_url}/{git_provider.owner}/{git_provider.repo}/issues/{ticket_num}",
+                            'title': issue.title if hasattr(issue, 'title') else "",
+                            'body': issue_body_str, 
+                            'labels': ", ".join(labels)
+                        })
+                except Exception as e:
+                    get_logger().warning(f"Failed to fetch Gitea issue {ticket_num_str}: {e}")
+                    
+            return tickets_content
Evidence
The GitHub path explicitly caps the number of tickets processed, but the new Gitea path iterates
over all matches from the PR description and calls the provider API for each.

pr_agent/tools/ticket_pr_compliance_check.py[121-132]
pr_agent/tools/ticket_pr_compliance_check.py[219-250]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The Gitea ticket extractor makes one API call per matched ticket number in the PR description, without bounding the count.

### Issue Context
The GitHub implementation in the same function limits tickets to 3 to avoid excessive calls.

### Fix Focus Areas
- pr_agent/tools/ticket_pr_compliance_check.py[219-250]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

12. Repo settings type hint wrong 🐞 Bug ⚙ Maintainability
Description
GiteaProvider.get_repo_settings is annotated as returning str but actually returns bytes (and b"" on
error). This contradicts the actual contract used by apply_repo_settings and can cause type-checking
or caller confusion.
Code

pr_agent/git_providers/gitea_provider.py[R617-635]

+    def get_repo_settings(self) -> str:  
+        try:
+            response = self.repo_api.get_file_content(
+                owner=self.owner,
+                repo=self.repo,
+                commit_sha=self.sha,
+                filepath=".pr_agent.toml"
+            )
+            
+            
+            if isinstance(response, str):
+                return response.encode('utf-8')
+            return response
+        except Exception as e:
+            if "404" in str(e):
+                self.logger.info("No .pr_agent.toml found, using defaults")
+            else:
+                self.logger.error(f"Error fetching settings: {e}")
+            return b""  # Return an empty bytes object.
Evidence
apply_repo_settings writes the returned value using os.write (bytes required), and
GiteaProvider.get_repo_settings encodes the content to bytes, so the annotation should match the
bytes-based contract.

pr_agent/git_providers/gitea_provider.py[617-635]
pr_agent/git_providers/utils.py[32-40]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`GiteaProvider.get_repo_settings()` returns `bytes` but is annotated as `str`.

### Issue Context
`apply_repo_settings()` uses `os.write(fd, repo_settings)` so providers effectively must return bytes.

### Fix Focus Areas
- pr_agent/git_providers/gitea_provider.py[617-635]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +4 to +5
if [ -n "$GITEA_EVENT_NAME" ] || [ "$GITEA_ACTIONS" == "true" ]; then
python /app/pr_agent/servers/gitea_action_runner.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. entrypoint.sh calls missing runner 📘 Rule violation ☼ Reliability

github_action/entrypoint.sh runs python /app/pr_agent/servers/gitea_action_runner.py, but this
PR adds pr_agent/servers/gitea_actions_runner.py (different filename). This will fail at runtime
when Gitea actions are detected, preventing the action from starting.
Agent Prompt
## Issue description
The action entrypoint runs `gitea_action_runner.py`, but the repo contains `gitea_actions_runner.py`. This causes the container to crash when Gitea actions are detected.

## Issue Context
The mismatch is in the startup path for Devstar/Gitea actions.

## Fix Focus Areas
- github_action/entrypoint.sh[4-5]
- pr_agent/servers/gitea_actions_runner.py[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

raise ValueError("Gitea access token not found in settings.")

self.repo_settings = get_settings().get("GITEA.REPO_SETTING", None)
self.repo_settings = ".pr_agent.toml"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Hardcoded .pr_agent.toml path 📘 Rule violation ⚙ Maintainability

The Gitea provider now hardcodes the repository settings path to .pr_agent.toml instead of reading
it from configuration. This makes behavior non-configurable and breaks the intended configuration
override mechanism.
Agent Prompt
## Issue description
Repository settings path is hard-coded to `.pr_agent.toml` in the Gitea provider, preventing configuration overrides.

## Issue Context
Previously this value was configurable; hard-coding reduces deployability and breaks expected configuration patterns.

## Fix Focus Areas
- pr_agent/git_providers/gitea_provider.py[38-38]
- pr_agent/git_providers/gitea_provider.py[617-624]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +551 to +553
except Exception as e:
self.logger.error(f"Failed to fetch Gitea issue body: {e}")
return ""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Broad except exception in provider 📘 Rule violation ☼ Reliability

New Gitea provider methods catch Exception broadly and then return empty values, which can mask
unexpected failures and make debugging harder. This violates the requirement to use targeted
exception handling and preserve error context.
Agent Prompt
## Issue description
The Gitea provider uses broad `except Exception` and returns empty values, masking unexpected failures.

## Issue Context
Fetching issue bodies and repo settings should catch expected API/HTTP errors (e.g., 404) separately, and preserve context when re-raising/wrapping.

## Fix Focus Areas
- pr_agent/git_providers/gitea_provider.py[546-553]
- pr_agent/git_providers/gitea_provider.py[630-635]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +132 to +137
try:
with open(EVENT_PATH, "r") as f:
event_payload = json.load(f)
except Exception as e:
get_logger().error(f"Failed to parse payload JSON: {e}")
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Broad except exception in runner 📘 Rule violation ☼ Reliability

pr_agent/servers/gitea_actions_runner.py uses broad except Exception in multiple places, which
can hide real bugs and removes error specificity. This violates the requirement to catch expected
exception types and preserve context.
Agent Prompt
## Issue description
The new Gitea actions runner catches `Exception` broadly in multiple blocks.

## Issue Context
Replace broad catches with specific exceptions (e.g., `json.JSONDecodeError`, `FileNotFoundError`, provider API exceptions) and use exception chaining when appropriate.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[84-86]
- pr_agent/servers/gitea_actions_runner.py[132-137]
- pr_agent/servers/gitea_actions_runner.py[153-156]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

import re
user_description = git_provider.get_pr_description_full()

ticket_numbers = list(set(re.findall(r'#(\d+)', user_description)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. set() dedupes ticket_numbers 📘 Rule violation ☼ Reliability

Ticket numbers are deduplicated via set(...), which does not preserve ordering and can produce
non-deterministic ticket processing order. This can lead to unstable outputs, especially when
truncation/limits are applied later.
Agent Prompt
## Issue description
`ticket_numbers = list(set(...))` is non-deterministic and can reorder extracted tickets.

## Issue Context
Stable ordering matters for consistent reviews and reproducible outputs.

## Fix Focus Areas
- pr_agent/tools/ticket_pr_compliance_check.py[221-224]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

if DEVSTAR_URL:
get_logger().info(f"Resolved Gitea URL from DEVSTAR_URL: {FINAL_GITEA_URL}")
elif GITEA_URL:
get_logger().info(f"Resolved Gitea URL from GITEA_URL: {FINAL_GITEA_URL}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Runner whitespace/newline issues 📘 Rule violation ⚙ Maintainability

pr_agent/servers/gitea_actions_runner.py includes trailing whitespace and is missing a final
newline, which can cause pre-commit hooks to fail. This violates repository whitespace and newline
requirements.
Agent Prompt
## Issue description
The new runner file has trailing whitespace and no final newline, which can fail pre-commit hooks.

## Issue Context
The diff shows trailing spaces and indicates a missing newline at EOF.

## Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[124-124]
- pr_agent/servers/gitea_actions_runner.py[223-224]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +139 to +150
# 4. Extract the PR URL
pr_url = None
if EVENT_NAME in ["pull_request", "pull_request_target"]:
pr_url = event_payload.get("pull_request", {}).get("html_url")
elif EVENT_NAME == "issue_comment":
issue_data = event_payload.get("issue", {})
if "pull_request" in issue_data:
pr_url = issue_data.get("pull_request", {}).get("html_url") or issue_data.get("html_url")

if not pr_url:
get_logger().warning("No valid PR URL found in the payload. Exiting.")
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Pr url field mismatch 🐞 Bug ≡ Correctness

pr_agent/servers/gitea_actions_runner.py reads PR URL from pull_request.html_url, but the existing
Gitea handler uses pull_request.url. If the Actions payload matches the webhook payload shape,
pr_url will be empty and the runner exits without processing PR events.
Agent Prompt
### Issue description
The Gitea Actions runner extracts the PR URL from `pull_request.html_url` only. Existing Gitea code paths use `pull_request.url`, so the runner can fail to find a PR URL and exit.

### Issue Context
Gitea webhook handling uses `pull_request.url` as the canonical URL passed into `apply_repo_settings()` / `handle_request()`.

### Fix Focus Areas
- pr_agent/servers/gitea_actions_runner.py[139-150]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants