Files
gh-atournayre-claude-market…/skills/git-pr/scripts/assign_project.py
2025-11-29 17:58:54 +08:00

183 lines
5.2 KiB
Python
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Assigner PR à projet GitHub
Usage: assign_project.py <pr_number> [--project <name>]
Output: Projet assigné ou "ignored" (stdout)
"""
import argparse
import json
import subprocess
import sys
import re
from project_cache import ProjectCache
def get_repo_info():
"""Récupère owner/repo depuis git remote"""
try:
result = subprocess.run(
["git", "remote", "get-url", "origin"],
capture_output=True,
text=True,
check=True
)
url = result.stdout.strip()
match = re.search(r'github\.com[:/](.+/.+?)(?:\.git)?$', url)
if match:
repo_full = match.group(1)
owner, repo = repo_full.split('/')
return owner, repo
raise ValueError(f"Format URL invalide: {url}")
except Exception as e:
print(f"❌ Erreur récupération repo: {e}", file=sys.stderr)
sys.exit(1)
def get_projects_list(owner):
"""Récupère les projets via gh project list"""
try:
result = subprocess.run(
["gh", "project", "list", "--owner", owner, "--format", "json"],
capture_output=True,
text=True,
check=True
)
projects_data = json.loads(result.stdout)
projects = []
for project in projects_data.get('projects', []):
projects.append({
'id': project.get('id'),
'title': project.get('title'),
'number': project.get('number')
})
return projects
except subprocess.CalledProcessError as e:
print(f"⚠️ Impossible de récupérer les projets: {e.stderr}", file=sys.stderr)
return []
except json.JSONDecodeError as e:
print(f"❌ Erreur parsing JSON projets: {e}", file=sys.stderr)
return []
def get_projects_cached(owner):
"""Récupère projets avec cache"""
cache = ProjectCache()
if not cache.cache.get("projects"):
projects = get_projects_list(owner)
cache.refresh_from_api(projects)
return projects
return cache.cache["projects"]
def find_project(owner, query):
"""Cherche projet par query (exact ou alias)"""
cache = ProjectCache()
result = cache.find(query)
if result:
return result
projects = get_projects_list(owner)
cache.refresh_from_api(projects)
return cache.find(query)
def assign_pr_to_project(pr_number, project_id, owner, repo):
"""Assigne la PR au projet via GraphQL"""
# Récupérer l'ID de la PR
try:
pr_result = subprocess.run(
["gh", "pr", "view", str(pr_number), "--json", "id"],
capture_output=True,
text=True,
check=True
)
pr_data = json.loads(pr_result.stdout)
pr_id = pr_data['id']
except Exception as e:
print(f"❌ Erreur récupération ID PR: {e}", file=sys.stderr)
return False
# Ajouter la PR au projet
mutation = """
mutation($projectId: ID!, $contentId: ID!) {
addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) {
item {
id
}
}
}
"""
try:
subprocess.run(
["gh", "api", "graphql",
"-f", f"query={mutation}",
"-f", f"projectId={project_id}",
"-f", f"contentId={pr_id}"],
capture_output=True,
text=True,
check=True
)
return True
except subprocess.CalledProcessError as e:
print(f"❌ Erreur assignation projet: {e.stderr}", file=sys.stderr)
return False
def main():
parser = argparse.ArgumentParser(description="Assigne une PR à un projet GitHub")
parser.add_argument("pr_number", type=int, help="Numéro de la PR")
parser.add_argument("--project", help="Nom du projet à assigner")
args = parser.parse_args()
owner, repo = get_repo_info()
projects = get_projects_cached(owner)
if not projects:
print(" Aucun projet trouvé - ignoré")
print("ignored")
sys.exit(0)
# Si --project fourni, utiliser find_project pour recherche intelligente
if args.project:
try:
project = find_project(owner, args.project)
if not project:
print(f"❌ Projet '{args.project}' non trouvé", file=sys.stderr)
available = [p['title'] for p in projects]
print(f"Projets disponibles: {', '.join(available)}", file=sys.stderr)
sys.exit(1)
if assign_pr_to_project(args.pr_number, project['id'], owner, repo):
print(f"✅ Projet '{project['title']}' assigné")
print(project['title'])
sys.exit(0)
else:
sys.exit(1)
except Exception as e:
print(f"❌ Erreur: {e}", file=sys.stderr)
sys.exit(1)
# Sinon, retourner JSON pour AskUserQuestion
projects_list = [
{
"id": p["id"],
"title": p["title"],
"number": p.get("number")
}
for p in projects
]
output = {
"projects": projects_list,
"needs_user_input": True
}
print(json.dumps(output, indent=2))
if __name__ == "__main__":
main()