From 64286b138dc0678139aa9ed9ee2c2e0ef68425e5 Mon Sep 17 00:00:00 2001 From: tegwick Date: Thu, 25 Sep 2025 00:31:37 +0200 Subject: [PATCH] fix: Resolve label assignment issue using dedicated Gitea API endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update ProjectManager.set_issue_state() to use /issues/{id}/labels endpoint with PUT method - Update ProjectManager.set_issue_priority() to use dedicated labels endpoint - Update IssueWriter.update_labels() to use dedicated labels endpoint for reliability - Fix API format incompatibility where issue PATCH endpoint was ignoring label updates - Label assignment now works correctly with proper state and priority management - Issues will now properly appear in correct Kanban columns based on status labels Root cause: Gitea API issue PATCH endpoint silently ignores label updates, but the dedicated labels endpoint (/issues/{id}/labels) with PUT method works correctly. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- tddai/issue_writer.py | 46 ++++++++++++++++++++++++++++++++++++++-- tddai/project_manager.py | 17 ++++++++++----- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/tddai/issue_writer.py b/tddai/issue_writer.py index b0c8feb6..38a57b2a 100644 --- a/tddai/issue_writer.py +++ b/tddai/issue_writer.py @@ -90,8 +90,50 @@ class IssueWriter: return self.update_issue(issue_number, {'milestone': None}) def update_labels(self, issue_number: int, labels: list) -> Dict[str, Any]: - """Update issue labels completely.""" - return self.update_issue(issue_number, {'labels': labels}) + """Update issue labels completely using dedicated labels endpoint.""" + if not self.auth_token: + raise IssueError("Authentication token required for label updates") + + # Use the dedicated labels endpoint which works more reliably + url = f"{self.config.issues_api_url}/{issue_number}/labels" + + try: + # Use PUT to replace all labels + curl_cmd = [ + 'curl', '-s', '-X', 'PUT', + '-H', 'Content-Type: application/json', + '-H', f'Authorization: token {self.auth_token}', + '-d', json.dumps({'labels': labels}), + url + ] + + result = subprocess.run( + curl_cmd, + stdout=PIPE, + stderr=PIPE, + universal_newlines=True, + check=True + ) + + if result.returncode != 0: + raise IssueError(f"Failed to update labels for issue #{issue_number}: {result.stderr}") + + # Parse the response - labels endpoint returns array of labels + if result.stdout.strip(): + response_data = json.loads(result.stdout) + + # Convert labels response back to issue format for consistency + return { + 'number': issue_number, + 'labels': response_data if isinstance(response_data, list) else [] + } + else: + return {'number': issue_number, 'labels': []} + + except subprocess.CalledProcessError as e: + raise IssueError(f"Failed to update labels for issue #{issue_number}: {e}") + except json.JSONDecodeError as e: + raise IssueError(f"Failed to parse labels response: {e}") def add_labels(self, issue_number: int, new_labels: list) -> Dict[str, Any]: """Add labels to issue (preserving existing labels).""" diff --git a/tddai/project_manager.py b/tddai/project_manager.py index 370a38c5..8c199331 100644 --- a/tddai/project_manager.py +++ b/tddai/project_manager.py @@ -251,7 +251,10 @@ class ProjectManager: def set_issue_state(self, issue_number: int, state: ProjectState) -> Dict[str, Any]: """Set issue project state using labels.""" - # First remove any existing state labels + # Use the dedicated labels endpoint which works more reliably + labels_url = f"{self.config.issues_api_url}/{issue_number}/labels" + + # First get current labels issue_url = f"{self.config.issues_api_url}/{issue_number}" issue_data = self._make_api_call('GET', issue_url) @@ -266,12 +269,16 @@ class ProjectManager: # Add new state label current_labels.append(state.value) - # Update issue with new labels + # Use PUT to replace all labels on the dedicated labels endpoint data = {'labels': current_labels} - return self._make_api_call('PATCH', issue_url, data) + return self._make_api_call('PUT', labels_url, data) def set_issue_priority(self, issue_number: int, priority: Priority) -> Dict[str, Any]: """Set issue priority using labels.""" + # Use the dedicated labels endpoint which works more reliably + labels_url = f"{self.config.issues_api_url}/{issue_number}/labels" + + # First get current labels issue_url = f"{self.config.issues_api_url}/{issue_number}" issue_data = self._make_api_call('GET', issue_url) @@ -286,9 +293,9 @@ class ProjectManager: # Add new priority label current_labels.append(priority.value) - # Update issue with new labels + # Use PUT to replace all labels on the dedicated labels endpoint data = {'labels': current_labels} - return self._make_api_call('PATCH', issue_url, data) + return self._make_api_call('PUT', labels_url, data) def move_issue_to_done(self, issue_number: int) -> Dict[str, Any]: """Move issue to done state and close it."""