def cancelWorkflow(slug: str, template: str): ''' Cancels a workflow run for the template supplied ''' global baseurl, runsurl log = logging.getLogger('cancelFlow') if not template or not slug: log.error('One or more required parameters got passed invalid params.') return None template = '{}.yml'.format(template) runsurl = runsurl.format(slug, template) req = sendQuery("GET", runsurl, params=None) if req is not None: runid = req.json()['workflow_runs'][0]['id'] baseurl = baseurl.format(slug, runid) req = sendQuery("POST", baseurl, json=None) if req is not None: print(G, 'Successfully requested a cancel for workflow: %s' % runid) return True else: log.fatal('Could not canel the workflow. Something went wrong!') sys.exit(1)
def deleteFlow(slug: str, template: str, path='.github/workflows/'): ''' Deletes a workflow for the authenticated user ''' global baseurl log = logging.getLogger('deleteFlow') if not slug: log.error('One or more required parameters got passed invalid params.') return None template = '%s.yml' % template wholepath = os.path.join(path, template) baseurl = baseurl.format(slug, wholepath) log.debug('Getting SHA of the file...') req = sendQuery("GET", baseurl, params=None) if req is not None: sha = req.json()['sha'] log.info('Received file SHA: %s' % sha) log.info('Trying to delete the file: %s' % wholepath) payload = {'message': 'Deleting %s' % wholepath, 'sha': sha} req = sendQuery("DELETE", baseurl, json=payload) if req is not None: print(G, 'Successfully deleted the workflow: %s' % wholepath) return True else: log.fatal('File deletion failed. Stopping all processes.') sys.exit(1)
def triggerWorkflow(slug: str, template: bool): ''' Creates a workflow run for the authenticated user ''' global baseurl log = logging.getLogger('triggerFlow') if not template or not slug: log.error('One or more required parameters got passed invalid params.') return None template = '{}.yml'.format(template) baseurl = baseurl.format(slug, template) payload = { "ref" : "master" } log.debug('Sending payload: %s' % payload) # pause for a few seconds, otheriwse github api gives out a 404 log.warning("Pausing for a few seconds to prevent race condition between API endpoints...") time.sleep(10) # github REST API is extrememly buggy about the name conventions # between the master and main, although they are the same thing # useless bullshit in my opinion. req = sendQuery("POST", baseurl, json=payload) if req is not None: print(G, 'Successfully triggered a workflow for: %s' % template) return True else: log.critical('Couldn\'t trigger a workflow! Ref seems to be messing up.') log.info('Retrying the request with different ref: master') # retry the request using ref as master instead of main # usually returns a 422 unprocessable identity payload = { "ref" : "main" } log.debug('Sending payload: %s' % payload) req = sendQuery("POST", baseurl, json=payload) if req is not None: print(G, 'Successfully triggered a workflow for: %s' % template) return True else: log.fatal('Could not trigger a workflow. Something went wrong!') sys.exit(1)
def createRepo(reponame: str, isprivate: bool): ''' Creates a repository for the authenticated user ''' log = logging.getLogger('createRepo') if not reponame or not isprivate: log.error('One or more required parameters got passed invalid params.') return None log.info('Trying to create the repository...') payload = { "name": reponame, "description": "My Custom Automation Setup", "private": isprivate, } req = sendQuery("POST", baseurl, json=payload) if req is not None: print(G, 'Successfully created: %s' % req.json()['html_url']) log.debug('Repo ID: ' + str(req.json()['id']) + ' | Repo URL: ' + req.json()['html_url']) return req.json()['full_name'] else: log.info( 'Another repository with the same name already exists on your account! Deleting it with --delete flag and trying again.' ) log.fatal('Repository creation failed. Stopping all processes.') sys.exit(1)
def getLogs(url: str, path: str): ''' Grabs the logs for a run and saves it to a directory ''' log = logging.getLogger('getLogs') if not url and not path: log.error('One or more required parameters got passed invalid params.') return None if not os.path.exists(path): log.error('Path %s doesn\'t exist on your filesystem.' % path) log.info('Creating the dir: %s' % path) os.makedirs(path) log.info('Trying to download the logs...') req = sendQuery("GET", url, redirection=True, stream=True, params=None) if req is not None: try: filename = re.search(r'(?i)filename=([^;]+)', req.headers['content-disposition']) log.info('Inflating the zipped logs: %s' % filename.group(1)) zipf = zipfile.ZipFile(io.BytesIO(req.content)) zipf.extractall(path) print(G, 'Successfully saved all logs to: %s' % path) except Exception as e: log.error('Error: %s' % e.__str__()) return None
def deleteRepo(slug: str): ''' Deletes a repository for the authenticated user ''' global baseurl log = logging.getLogger('deleteRepo') if not slug: log.error('One or more required parameters got passed invalid params.') return None log.info('Trying to delete the repository: %s' % slug) baseurl = baseurl.format(slug) req = sendQuery("DELETE", baseurl, json=None) if req is not None: print(G, 'Successfully deleted the repository: %s' % slug) return True else: log.fatal('Repository deletion failed. Stopping all processes.') sys.exit(1)
def commitFile(file: str, path: str, repo: str): ''' Commits a file to the GitHub Repository ''' global baseurl log = logging.getLogger('commitFile') if path is not None: path = '.github/workflows/{}.yml'.format(path) log.debug('Target file to create: %s' % path) else: path = '.github/workflows/{}.yml'.format('default') with open('templates/default.yml', 'r') as rf: file = rf.read() baseurl = baseurl.format(repo, path) log.debug('Encoding the file to base64.') file64 = base64.b64encode(file.encode('ascii')) file64msg = file64.decode('ascii') log.debug('Content to commit: %s' % file64msg) payload = { "content": file64msg, "message": 'Added workflow file', } log.debug('Trying to create the file...') req = sendQuery("PUT", baseurl, json=payload) if req is not None: print(G, 'File successfully committed to GitHub: %s' % path) return True return False
def checkRun(slug: str, template: str, path=None): ''' Checks workflow status of a template ''' global runsurl, jobsurl, logsurl log = logging.getLogger('checkRun') # Pause for a few seconds for the workflow to actually trigger log.info('Pausing for a few seconds for the workflow to trigger...') time.sleep(10) template = '%s.yml' % template runsurl = runsurl.format(slug, template) req = sendQuery("GET", runsurl, params=None) if req is not None: # get the last workflow run # retry for one more time if the API doesn't give a valid response while True: if len(req.json()['workflow_runs']) == 0: log.debug('Waiting for workflow to trigger...') time.sleep(10) req = sendQuery("GET", runsurl, params=None) else: break jobid = req.json()['workflow_runs'][0]['id'] print(G, 'Job ID:', jobid) jobsurl = jobsurl.format(slug, jobid) logsurl = req.json()['workflow_runs'][0]['logs_url'] log.debug('Jobs URL: %s' % jobsurl) log.debug('Logs URL: %s' % logsurl) # continuously monitor the workflow for completion while True: req = sendQuery("GET", jobsurl, params=None) if req is not None: if req.json()['jobs'][0]['status'] == "completed": print(G, 'Job seems to have successfully completed!') break else: log.debug('Workflow not completed yet.') laststep = None for step in req.json()['jobs'][0]['steps']: if step['status'] == 'completed': laststep = step['name'] print(GR, 'Last step executed: %s' % laststep) log.debug('Pausing for 7 seconds before checking again...') time.sleep(7) continue if req.json()['jobs'][0]['conclusion'] != "success": log.error('Job completed but errored out!') log.error('Visit: %s for more information' % req.json()['jobs'][0]['html_url']) if path is not None: # fetch the logs now #logsurl = logsurl.format(slug, jobid) getLogs(logsurl, path)