281 lines
10 KiB
Python
281 lines
10 KiB
Python
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'<img[^>]*?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'<img src="{download_url}"/>', updated_sHtml)
|
|
else:
|
|
updated_sHtml += f'\n<img src="{download_url}"/>'
|
|
|
|
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() |