diff --git a/ci-scripts/Jenkinsfile-git-dashboard b/ci-scripts/Jenkinsfile-git-dashboard deleted file mode 100644 index 87e781fe8a..0000000000 --- a/ci-scripts/Jenkinsfile-git-dashboard +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/groovy -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -// Template Jenkins Declarative Pipeline script to run Test w/ RF HW - -// Location of the python executor node shall be in the same subnet as the others servers -def pythonExecutor = params.pythonExecutor - - -pipeline { - agent { - label pythonExecutor - } - stages { - stage ("gDashboard") { - steps { - script { - dir ("ci-scripts/ran_dashboard") { - //retrieve MR data from gitlab / mySQL db, build HTML pages and load them to AWS S3 bucket (configured as static web page hosting) - //deprecated method : sh returnStdout: true, script: 'python3 ran_dashboard.py' - sh returnStdout: true, script: 'python3 Hdashboard.py' - } - } - } - } - } -} - - diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa index 1d977f00d3..43d6372a33 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa @@ -376,19 +376,6 @@ pipeline { } } } - stage ("Result Update"){ - when { - expression { params.DataBaseHost != "none" } - } - agent {label DataBaseHost} - steps { - script { - dir ('ci-scripts/ran_dashboard') { - sh "python3 Hdashboard.py testevent ${params.eNB_MR} " - } - } - } - } } } } diff --git a/ci-scripts/ran_dashboard/Hdashboard.py b/ci-scripts/ran_dashboard/Hdashboard.py index bfa07557bd..625baa8f46 100644 --- a/ci-scripts/ran_dashboard/Hdashboard.py +++ b/ci-scripts/ran_dashboard/Hdashboard.py @@ -32,488 +32,34 @@ #Author Remi -import boto3 import shlex import subprocess import json #json structures -import datetime #now() and date formating -from datetime import datetime -import re import gitlab -import yaml -import os -import time import sys -from sqlconnect import SQLConnect - #----------------------------------------------------------- # Class Declaration #----------------------------------------------------------- class Dashboard: def __init__(self): - - - #init with data sources : git, yaml config file, test results databases + #init with data sources : git, test results databases print("Collecting Data") cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """ self.git = self.__getGitData(cmd) #git data from Gitlab - self.tests = self.__loadCfg('ran_dashboard_cfg.yaml') #tests table setup from yaml - self.db = self.__loadFromDB() #test results from database self.mr_list=[] #mr list in string format for x in range(len(self.git)): self.mr_list.append(str(self.git[x]['iid'])) - def __loadCfg(self,yaml_file): - with open(yaml_file,'r') as f: - tests = yaml.load(f) - return tests - def __getGitData(self,cmd): - #cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """ process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) output = process.stdout.readline() tmp=output.decode("utf-8") d = json.loads(tmp) return d - def __loadFromDB(self): - mr_list=[] - for x in range(len(self.git)): - mr_list.append(str(self.git[x]['iid'])) - mydb=SQLConnect() - for MR in mr_list: - mydb.get(MR) - mydb.close_connection() - return mydb.data - - def singleMR_initHTML(self, date): - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('Test Dashboard\n') - self.f_html.write('\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('
OAI RAN TEST Status Dashboard
Update : '+date+'
\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - - - def Test_initHTML(self, date): - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('Test Dashboard\n') - self.f_html.write('\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('
OAI RAN TEST Status Dashboard
Update : '+date+'
\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - - def Test_terminateHTML(self): - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.close() - - - def MR_initHTML(self,date): - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('MR Dashboard\n') - self.f_html.write('\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('
OAI RAN MR Status Dashboard
Update : '+date+'
\n') - self.f_html.write('
\n') - self.f_html.write('
\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - - def MR_terminateHTML(self): - self.f_html.write('
MRCreated_AtAuthorTitleAssigneeReviewerCAN STARTIN PROGRESSCOMPLETEDReview FormOK MergeMerge Conflicts
\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.close() - - - def MR_rowHTML(self,row): - self.f_html.write('\n') - self.f_html.write(''+row[1]+'\n') - self.f_html.write(''+row[2]+'\n') - self.f_html.write(''+row[3]+'\n') - self.f_html.write(''+row[4]+'\n') - self.f_html.write(''+row[5]+'\n') - self.f_html.write(''+row[6]+'\n') - if row[7]=='X': - self.f_html.write(''+row[7]+'\n') - else: - self.f_html.write('\n') - if row[8]=='X': - self.f_html.write(''+row[8]+'\n') - else: - self.f_html.write('\n') - if row[9]=='X': - self.f_html.write(''+row[9]+'\n') - else: - self.f_html.write('\n') - if row[10]=='X': - self.f_html.write(''+row[10]+'\n') - else: - self.f_html.write('\n') - if row[11]=='X': - self.f_html.write(''+row[11]+'\n') - else: - self.f_html.write('\n') - if row[12]=='YES': - self.f_html.write(''+row[12]+'\n') - else: - self.f_html.write('\n') - self.f_html.write('\n') - - - def Build(self, type, mr, htmlfilename): - if type=='MR': - self.Build_MR_Table(htmlfilename) - elif type=='Tests': - self.Build_Test_Table(htmlfilename) - elif type=='singleMR': - self.Build_singleMR_Table(mr,htmlfilename) - else : - print("Undefined Dashboard Type, options : MR or Tests") - - - def Build_Test_Table(self,htmlfilename): - print("Building Tests Dashboard...") - - self.f_html=open(htmlfilename,'w') - - ###update date/time, format dd/mm/YY H:M:S - now = datetime.now() - dt_string = now.strftime("%d/%m/%Y %H:%M") - #HTML table header - self.Test_initHTML(dt_string) - - - #1 table per MR if test results exist - for x in range(len(self.git)): - mr=str(self.git[x]['iid']) - if 'PASS' not in self.db[mr]: - self.f_html.write('

'+mr+''+' '+self.git[x]['title'] + '

\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write(' \n') - self.f_html.write(' \n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - - #parsing the tests - for t in self.tests: - - row=[] - short_name= t - hyperlink= self.tests[t]['link'] - job=self.tests[t]['job'] - - - if job in self.db[mr]: - if 'PASS' in self.db[mr][job]: - row.append(self.db[mr][job]['PASS']) - else: - row.append('') - if 'FAIL' in self.db[mr][job]: - row.append(self.db[mr][job]['FAIL']) - else: - row.append('') - #2 columns for last_pass and last_fail links - if 'last_pass' in self.db[mr][job]: - lastpasshyperlink= self.db[mr][job]['last_pass'][1] - lastpasstext= self.db[mr][job]['last_pass'][0] - else: - lastpasshyperlink='' - lastpasstext='' - - if 'last_fail' in self.db[mr][job]: - lastfailhyperlink= self.db[mr][job]['last_fail'][1] - lastfailtext= self.db[mr][job]['last_fail'][0] - else: - lastfailhyperlink='' - lastfailtext='' - - - - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - if row[0]!='': - self.f_html.write('\n') - else: - self.f_html.write('\n') - if row[1]!='': - self.f_html.write('\n') - else: - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - - self.f_html.write('
Test NameBenchTest# Pass# FailLast PassLast Fail
'+short_name+''+self.tests[t]['bench']+''+self.tests[t]['test']+''+str(row[0])+''+str(row[1])+''+lastpasstext+''+lastfailtext+'
\n') - - #terminate HTML table and close file - self.Test_terminateHTML() - - - def Build_singleMR_Table(self,singlemr,htmlfilename): - print("Building single MR Tests Results...") - - self.f_html=open(htmlfilename,'w') - - ###update date/time, format dd/mm/YY H:M:S - now = datetime.now() - dt_string = now.strftime("%d/%m/%Y %H:%M") - #HTML table header - self.singleMR_initHTML(dt_string) - - - #1 table per MR if test results exist => 1 table for matching mr - for x in range(len(self.git)): - mr=str(self.git[x]['iid']) - if mr==singlemr: - #if 'PASS' not in self.db[mr]: - self.f_html.write('

'+mr+''+' '+self.git[x]['title'] + '

\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write(' \n') - self.f_html.write(' \n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - - #parsing the tests - for t in self.tests: - - row=[] - short_name= t - hyperlink= self.tests[t]['link'] - job=self.tests[t]['job'] - - - if job in self.db[mr]: - if 'PASS' in self.db[mr][job]: - row.append(self.db[mr][job]['PASS']) - else: - row.append('') - if 'FAIL' in self.db[mr][job]: - row.append(self.db[mr][job]['FAIL']) - else: - row.append('') - #2 columns for last_pass and last_fail links - if 'last_pass' in self.db[mr][job]: - lastpasshyperlink= self.db[mr][job]['last_pass'][1] - lastpasstext= self.db[mr][job]['last_pass'][0] - else: - lastpasshyperlink='' - lastpasstext='' - - if 'last_fail' in self.db[mr][job]: - lastfailhyperlink= self.db[mr][job]['last_fail'][1] - lastfailtext= self.db[mr][job]['last_fail'][0] - else: - lastfailhyperlink='' - lastfailtext='' - - - - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - if row[0]!='': - self.f_html.write('\n') - else: - self.f_html.write('\n') - if row[1]!='': - self.f_html.write('\n') - else: - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - self.f_html.write('\n') - - self.f_html.write('
Test NameBenchTest# Pass# FailLast PassLast Fail
'+short_name+''+self.tests[t]['bench']+''+self.tests[t]['test']+''+str(row[0])+''+str(row[1])+''+lastpasstext+''+lastfailtext+'
\n') - - #terminate HTML table and close file - self.Test_terminateHTML() - - - - def Build_MR_Table(self,htmlfilename): - - print("Building Merge Requests Dashboard...") - - self.f_html=open(htmlfilename,'w') - - ###update date/time, format dd/mm/YY H:M:S - now = datetime.now() - dt_string = now.strftime("%d/%m/%Y %H:%M") - - #HTML table header - self.MR_initHTML(dt_string) - - - ###MR data lines - for x in range(len(self.git)): - - - hyperlink= 'https://gitlab.eurecom.fr/oai/openairinterface5g/-/merge_requests/'+ str(self.git[x]['iid']) - text= str(self.git[x]['iid']) - - - date_time_str = self.git[x]['created_at'] - date_time_obj = datetime.strptime(date_time_str, '%Y-%m-%dT%H:%M:%S.%fZ') - - milestone1=milestone2=milestone3=milestone4="" - if self.git[x]['milestone']!=None: - if self.git[x]['milestone']['title']=="REVIEW_CAN_START": - milestone1="X" - elif self.git[x]['milestone']['title']=="REVIEW_IN_PROGRESS": - milestone2="X" - elif self.git[x]['milestone']['title']=="REVIEW_COMPLETED_AND_APPROVED": - milestone3="X" - elif self.git[x]['milestone']['title']=="OK_TO_BE_MERGED": - milestone4="X" - else: - pass - else: - pass - - #check if empty or not - if self.git[x]['assignee']!=None: - assignee = str(self.git[x]['assignee']['name']) - else: - assignee = "" - - #check if empty or not - if len(self.git[x]['reviewers'])!=0: - reviewer = str(self.git[x]['reviewers'][0]['name']) - else: - reviewer = "" - - if self.git[x]['has_conflicts']==True: - conflicts = "YES" - else: - conflicts = "" - - - #add a column flagging that the review form is present - #we use gitlab API to parse the MR notes - gl = gitlab.Gitlab.from_config('OAI') - project_id = 223 - project = gl.projects.get(project_id) - #get the opened MR in the project - mrs = project.mergerequests.list(state='opened',per_page=100) - review_form='' - for m in range (0,len(mrs)): - if mrs[m].iid==self.git[x]['iid']:#check the iid is the one we are on - mr_notes = mrs[m].notes.list(all=True) - n=0 - found=False - while found==False and n1: + if len(sys.argv) > 1: #individual MR test results + test dashboard, event based (end of slave jenkins pipeline) - if sys.argv[1]=="testevent" : - mr=sys.argv[2] - htmlDash=Dashboard() - if mr in htmlDash.mr_list: - #single MR test results - htmlDash.Build('singleMR',mr,'/tmp/MR'+mr+'_index.html') - htmlDash.CopyToS3('/tmp/MR'+mr+'_index.html','oaitestdashboard','MR'+mr+'/index.html') - #all MR test results - htmlDash.Build('Tests','0000','/tmp/Tests_index.html') - htmlDash.CopyToS3('/tmp/Tests_index.html','oaitestdashboard','index.html') + if sys.argv[1] != "gitpost": + print("error: only gitpost subcommand is supported") + exit(1) - #git post with MR test results, event based (end of master jenkins pipeline) elif sys.argv[1]=="gitpost": mr=sys.argv[2] commit=sys.argv[3] @@ -603,25 +111,15 @@ def main(): htmlDash.PostGitNote(mr,commit, args) else: print("Not a Merge Request => this build is for testing/debug purpose, no report to git") - elif sys.argv[1]=="awsclean": - mode=sys.argv[2]#report or delete - htmlDash=Dashboard() - htmlDash.AWSCleanup(mode) else: print("Wrong argument at position 1") + exit(1) #test and MR status dashboards, cron based else: - htmlDash=Dashboard() - #all MR status dashboard - htmlDash.Build('MR','0000','/tmp/MR_index.html') - htmlDash.CopyToS3('/tmp/MR_index.html','oairandashboard','index.html') - #all MR test results - htmlDash.Build('Tests','0000','/tmp/Tests_index.html') - htmlDash.CopyToS3('/tmp/Tests_index.html','oaitestdashboard','index.html') - - + print("error: only gitpost subcommand is supported") + exit(1) if __name__ == "__main__": # execute only if run as a script diff --git a/ci-scripts/ran_dashboard/mr_styles.css b/ci-scripts/ran_dashboard/mr_styles.css deleted file mode 100755 index 5d938669cb..0000000000 --- a/ci-scripts/ran_dashboard/mr_styles.css +++ /dev/null @@ -1,136 +0,0 @@ -body { - font-family: 'lato', sans-serif; - } - - -.Main { - text-align:left; - font-size: 30px; - font-weight: bold; -} - -.DashLink { - text-align:left; - font-size: 16px; -} - -.DashLink:hover { - font-weight: bold; -} - -.Date { - text-align:left; - font-size: 16px; - font-weight: bold; -} - - -a { text-decoration: none; } -a:visited { text-decoration: none; color:blue} -a:hover { text-decoration: none; font-weight: bold; color:blue} - - -.MR_Table { - border-collapse: collapse; -} - -.MR_Table tr { - font-size: 12px; - text-align:center; -} - - -.MR_Table tr:hover { - background-color:lightgray; -} - -.MR_Table td { - border: 1px solid black; - padding : 5px; -} -.MR_Table td:hover { -font-weight : bold; -} - -.MR_Table th { - font-size: 14px; - text-align:center; - padding : 5px; -} - - -.title_cell { - text-align:left; -} - - -.MR { - table-layout: fixed; - width: 50px; - background-color: rgb(143, 154, 216); -} - -.CREATED_AT { - table-layout: fixed; - width: 100px; - background-color: rgb(143, 154, 216); -} - -.AUTHOR { - table-layout: fixed; - width: 150px; - background-color: rgb(143, 154, 216); -} - -.TITLE { - table-layout: fixed; - width: 500px; - background-color: rgb(143, 154, 216); -} - -.ASSIGNEE { - table-layout: fixed; - width: 150px; - background-color: rgb(143, 154, 216); -} - -.REVIEWER { - table-layout: fixed; - width: 150px; - background-color: rgb(143, 154, 216); -} - -.CAN_START { - background-color: orange; - table-layout: fixed; - width: 150px; -} -.IN_PROGRESS { - background-color: yellow; - table-layout: fixed; - width: 150px; -} -.COMPLETED { - background-color: rgb(144, 221, 231); - table-layout: fixed; - width: 150px; -} - -.REVIEW_FORM { - table-layout: fixed; - width: 100px; - background-color: rgb(143, 154, 216); -} - -.OK_MERGE { - background-color: rgb(58, 236, 58); - table-layout: fixed; - width: 150px; -} - -.MERGE_CONFLICTS { - table-layout: fixed; - width: 100px; - background-color: rgb(143, 154, 216); -} - diff --git a/ci-scripts/ran_dashboard/ran_dashboard.py b/ci-scripts/ran_dashboard/ran_dashboard.py deleted file mode 100644 index 54a98ec878..0000000000 --- a/ci-scripts/ran_dashboard/ran_dashboard.py +++ /dev/null @@ -1,405 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (the "License"); you may not use this file -# * except in compliance with the License. -# * You may obtain a copy of the License at -# * -# * http://www.openairinterface.org/?page_id=698 -# * -# * Unless required by applicable law or agreed to in writing, software -# * distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# Merge Requests Dashboard for RAN on googleSheet -# -# Required Python Version -# Python 3.x -# -#--------------------------------------------------------------------- - -#----------------------------------------------------------- -# Import -#----------------------------------------------------------- - -#author Remi - -#import google spreadsheet API -import gspread -from oauth2client.service_account import ServiceAccountCredentials - - -import subprocess -import shlex #lexical analysis -import json #json structures -import datetime #now() and date formating -from datetime import datetime -import re -import gitlab -import yaml -import os -import pickle -import time - - -from sqlconnect import SQLConnect - -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- - -class gDashboard: - def __init__(self, creds_file, spreadsheet, worksheet): #"creds.json", 'OAI RAN Dashboard', 'MR Status' - self.scope = ["https://spreadsheets.google.com/feeds",'https://www.googleapis.com/auth/spreadsheets',"https://www.googleapis.com/auth/drive.file","https://www.googleapis.com/auth/drive"] - self.creds = ServiceAccountCredentials.from_json_keyfile_name(creds_file, self.scope) - self.client = gspread.authorize(self.creds) - #spreadsheet - self.ss = self.client.open(spreadsheet) - #worksheet - self.sheet = self.ss.worksheet(worksheet) - self.ss.del_worksheet(self.sheet) #start by deleting the old sheet - self.sheet = self.ss.add_worksheet(title=worksheet, rows="100", cols="30") #create a new one - - #init with data sources : git, yaml config file, test results databases - cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """ - self.git = self.__getGitData(cmd) #git data from Gitlab - self.tests = self.__loadCfg('ran_dashboard_cfg.yaml') #tests table setup from yaml - self.db = self.__loadFromDB() #test results from database - - - def __loadCfg(self,yaml_file): - with open(yaml_file,'r') as f: - tests = yaml.load(f) - return tests - - def __getGitData(self,cmd): - #cmd="""curl --silent "https://gitlab.eurecom.fr/api/v4/projects/oai%2Fopenairinterface5g/merge_requests?state=opened&per_page=100" """ - process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE) - output = process.stdout.readline() - tmp=output.decode("utf-8") - d = json.loads(tmp) - return d - - def __loadFromDB(self): - mr_list=[] - for x in range(len(self.git)): - mr_list.append(str(self.git[x]['iid'])) - mydb=SQLConnect() - for MR in mr_list: - mydb.get(MR) - mydb.close_connection() - return mydb.data - - - - def gBuild(self, destinationSheetName): - - ###line 1 : update date/time, format dd/mm/YY H:M:S - now = datetime.now() - dt_string = "Update : " + now.strftime("%d/%m/%Y %H:%M") - row =[dt_string] - self.sheet.insert_row(row, index=1, value_input_option='RAW') - - ###line 2 is for the test short names (links to jenkins pipeline), updated at the end - - ###line 3 is for the column names - i=3 - row =["MR","Created_at","Author","Title","Assignee", "Reviewer", "CAN START","IN PROGRESS","COMPLETED","Review Form","OK MERGE","Merge conflicts",""] - - #tests - for t in range(0,len(self.tests)): - row.append("# PASS") - row.append("# FAIL") - row.append("Last Pass") - row.append("Last Fail") - - self.sheet.insert_row(row, index=i, value_input_option='RAW') - - ###line 4 onward, MR data lines - for x in range(len(self.git)): - i=i+1 - date_time_str = self.git[x]['created_at'] - date_time_obj = datetime.strptime(date_time_str, '%Y-%m-%dT%H:%M:%S.%fZ') - - milestone1=milestone2=milestone3=milestone4="" - if self.git[x]['milestone']!=None: - if self.git[x]['milestone']['title']=="REVIEW_CAN_START": - milestone1="X" - elif self.git[x]['milestone']['title']=="REVIEW_IN_PROGRESS": - milestone2="X" - elif self.git[x]['milestone']['title']=="REVIEW_COMPLETED_AND_APPROVED": - milestone3="X" - elif self.git[x]['milestone']['title']=="OK_TO_BE_MERGED": - milestone4="X" - else: - pass - else: - pass - - #check if empty or not - if self.git[x]['assignee']!=None: - assignee = str(self.git[x]['assignee']['name']) - else: - assignee = "" - - #check if empty or not - if len(self.git[x]['reviewers'])!=0: - reviewer = str(self.git[x]['reviewers'][0]['name']) - else: - reviewer = "" - - if self.git[x]['has_conflicts']==True: - conflicts = "YES" - else: - conflicts = "" - - - #add a column flagging that the review form is present - #we use gitlab API to parse the MR notes - gl = gitlab.Gitlab.from_config('OAI') - project_id = 223 - project = gl.projects.get(project_id) - #get the opened MR in the project - mrs = project.mergerequests.list(state='opened',per_page=100) - review_form='' - for m in range (0,len(mrs)): - if mrs[m].iid==self.git[x]['iid']:#check the iid is the one we are on - mr_notes = mrs[m].notes.list(all=True) - n=0 - found=False - while found==False and n