import requests from fogbugz import FogBugz import os import urllib import re import base64 import mimetypes import time GITLAB_INSTANCE_URL = 'https://gitlab.com' GITLAB_API_TOKEN = 'glpat-UkUD1NfVdpvyBACgzMDZ' GITLAB_PROJECT_ID = 39832947 OWNER = 'fbenoist68' REPO = 'mobileportal' S_FOGBUGZ_URL = 'https://mobileretail.fogbugz.com/' S_EMAIL = 'frederik.benoist@gfi.fr' S_PASSWORD = '6brOc-gAr6' MAX_BUGS = 999 def delete_issue(project_id, issue_iid): url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{project_id}/issues/{issue_iid}' headers = { 'Private-Token': GITLAB_API_TOKEN } response = requests.delete(url, headers=headers) if response.status_code == 204: ##print(f'Issue with IID {issue_iid} deleted successfully.') pass else: print(f'Failed to delete issue with IID {issue_iid}:', response.text) def delete_all_issues(project_id): url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{project_id}/issues' headers = { 'Private-Token': GITLAB_API_TOKEN } remaining_issues = True while remaining_issues: response = requests.get(url, headers=headers) if response.status_code != 200: print('Failed to retrieve issues:', response.text) break issues = response.json() if len(issues) == 0: # Il n'y a plus d'issues, la suppression est terminée print('All issues deleted successfully.') break for issue in issues: delete_issue(project_id, issue['iid']) def create_gitlab_issue(title, description): headers = { 'Private-Token': GITLAB_API_TOKEN } data = { 'title': title, 'description': description } url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{OWNER}%2F{REPO}/issues' response = requests.post(url, json=data, headers=headers) if response.status_code == 201: ##print('Issue created successfully.') return response.json()['iid'] else: print('Failed to create issue:', response.text) return None def create_gitlab_comment(issue_number, comment): headers = { 'Private-Token': GITLAB_API_TOKEN } data = { 'body': comment } url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{OWNER}%2F{REPO}/issues/{issue_number}/notes' response = requests.post(url, json=data, headers=headers) if response.status_code == 201: ##print('Comment created successfully.') return response.json()['id'] else: print('Failed to create comment:', response.text) return None def upload_attachment_to_gitlab_project(filename, attachment_data): #url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{OWNER}%2F{REPO}/uploads' url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{GITLAB_PROJECT_ID}/uploads' # Encode les données binaires en base64 attachment_data_base64 = base64.b64encode(attachment_data).decode('utf-8') # Determine the content type based on the file extension mimetype, _ = mimetypes.guess_type(filename) files = { 'file': (filename, attachment_data, mimetype or 'application/octet-stream') } response = requests.post(url, files=files, headers={'Private-Token': GITLAB_API_TOKEN}) if response.status_code == 201: ##print('Attachment uploaded successfully.') # Obtenir l'URL de téléchargement depuis la réponse download_url = response.json().get('url') return download_url else: print('Failed to upload attachment:', response.text) return None def update_gitlab_comment(comment_id, body): headers = { 'Private-Token': GITLAB_API_TOKEN } data = { 'body': body } url = f'{GITLAB_INSTANCE_URL}/api/v4/projects/{OWNER}%2F{REPO}/issues/comments/{comment_id}' response = requests.put(url, json=data, headers=headers) if response.status_code == 200: # # print('Comment updated successfully.') pass else: print('Failed to update comment:', response.text) def get_issue_id(issue): return int(issue['ixBug']) def get_event_id(event): return int(event['ixBugEvent']) def main(): # Utilisation de la fonction pour supprimer toutes les issues d'un projet spécifique # delete_all_issues(GITLAB_PROJECT_ID) fb = FogBugz(S_FOGBUGZ_URL) fb.logon(S_EMAIL, S_PASSWORD) resp = fb.search(q='type:"Cases"', cols='ixBug', max=MAX_BUGS) for case in sorted(resp.cases.findAll('case'), key=get_issue_id, reverse=False): ixBug = int(case['ixBug']) if ixBug >= 590: time.sleep(1) # Pause d'une seconde print(ixBug) respBug = fb.search(q='%s' % ixBug, cols='sTitle,sPersonAssignedTo,sProject,sArea,sCategory,sPriority,events') xmlBug = respBug.cases.findAll('case')[0] BACKUP_DIR = '/Users/fbenoist68/Code/python/fogbugz/fogbackup' BACKUP_DIR += '/' + xmlBug.sProject.string if xmlBug.sProject.string else '' if not os.path.exists(BACKUP_DIR): os.makedirs(BACKUP_DIR) BACKUP_DIR += '/' + str(xmlBug['ixBug']) if not os.path.exists(BACKUP_DIR): os.makedirs(BACKUP_DIR) # Create GitLab issue issue_title = f"[FogBugz #{ixBug}] {xmlBug.sTitle.string if xmlBug.sTitle.string else ''}" issue_body = f"Assigned To: {xmlBug.sPersonAssignedTo.string}\n" issue_body += f"Project: {xmlBug.sProject.string}\n" issue_body += f"Area: {xmlBug.sArea.string}\n" issue_body += f"Category: {xmlBug.sCategory.string}\n" issue_body += f"Priority: {xmlBug.sPriority.string}\n" issue_number = create_gitlab_issue(issue_title, issue_body) if issue_number is not None: # Create Gitea comment for each event in reverse !! for event in sorted(xmlBug.events.findAll('event'), key=get_event_id, reverse=True): bugEvent = {} bugEvent['ixBugEvent'] = int(event['ixBugEvent']) bugEvent['sVerb'] = event.sVerb.string if event.sVerb.string else '' bugEvent['dt'] = event.dt.string if event.dt.string else '' bugEvent['s'] = event.s.string if event.s.string else '' bugEvent['sChanges'] = event.sChanges.string if event.sChanges.string else '' bugEvent['evtDescription'] = event.evtDescription.string if event.evtDescription.string else '' bugEvent['sPerson'] = event.sPerson.string if event.sPerson.string else '' if event.s and event.s.string: bugEvent['s'] = event.s.string.encode('ascii', 'ignore').decode('utf-8') else: bugEvent['s'] = '' if event.sHtml and event.sHtml.string: bugEvent['sHtml'] = event.sHtml.string.encode('ascii', 'ignore').decode('utf-8') else: bugEvent['sHtml'] = '' comment = f"Event ID: {bugEvent['ixBugEvent']}\n" comment += f"Date: {bugEvent['dt']}\n" comment += f"Person: {bugEvent['sPerson']}\n" comment += f"Description: {bugEvent['evtDescription']}\n\n\n" # Afficher sHtml s'il n'est pas vide, sinon afficher s content = bugEvent['sHtml'] if bugEvent['sHtml'] else bugEvent['s'] comment += f"{content}" new_links = {} for att in event.rgAttachments: # # print('Downloading attachment: ' + att.sFileName.string) str1 = att.sURL.string str2 = 'ixAttachment=' loc1 = str1.find(str2) + len(str2) loc2 = str1.find('&sFileName') str3 = ';sFileName=' loc3 = str1.find(str3) + len(str3) loc4 = str1.find('&sTicket') theURL = S_FOGBUGZ_URL # + att.sURL.string theURL += 'default.asp?' theURL += 'ixAttachment=' + str1[loc1:loc2] theURL += '&pg=pgDownload&pgType=pgFile&sFilename=' + str1[loc3:loc4] theURL += '&token=rnl0t87rp34rfg6q0u0rgbhe85v5r8' # fix the replace newFileName = att.sFileName.string.replace('/', '') newFileName = newFileName.replace(':', '') newFileName = BACKUP_DIR + '/' + newFileName # # print(newFileName) urllib.request.urlretrieve(theURL, newFileName) with open(newFileName, 'rb') as attachment_file: attachment_data = attachment_file.read() # # print('Uploading screenshot:', att.sFileName.string) download_url = upload_attachment_to_gitlab_project(att.sFileName.string, attachment_data) if download_url: # Stocker le nouveau lien avec l'ID de l'attachement comme clé new_links[str1[loc1:loc2]] = download_url if new_links: # Remplacer les liens d'attachement dans sHtml avec les nouvelles URLs updated_sHtml = comment for att_id, download_url in new_links.items(): # Utilisation d'une expression régulière pour trouver les liens img avec ixAttachment=574 pattern = fr']*?ixAttachment={att_id}[^>]*>' # Testez si le motif correspond à la chaîne de texte match = re.search(pattern, updated_sHtml) # Remplacement de tous les liens correspondant au modèle par le nouveau download_url if match: updated_sHtml = re.sub(pattern, f'', updated_sHtml) else: updated_sHtml += f'\n' comment_id = create_gitlab_comment(issue_number=issue_number, comment=updated_sHtml) else: comment_id = create_gitlab_comment(issue_number=issue_number, comment=comment) # # print('comment id',comment_id); fb.view(ixBug=ixBug) main()