99 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import os
 | 
						|
import json
 | 
						|
import time
 | 
						|
import logging
 | 
						|
 | 
						|
try:
 | 
						|
    import urllib.request as urllib2
 | 
						|
except ImportError:
 | 
						|
    import urllib2
 | 
						|
 | 
						|
log = logging.getLogger("travis.leader")
 | 
						|
log.addHandler(logging.StreamHandler())
 | 
						|
log.setLevel(logging.INFO)
 | 
						|
 | 
						|
TRAVIS_JOB_NUMBER = 'TRAVIS_JOB_NUMBER'
 | 
						|
TRAVIS_BUILD_ID = 'TRAVIS_BUILD_ID'
 | 
						|
POLLING_INTERVAL = 'LEADER_POLLING_INTERVAL'
 | 
						|
 | 
						|
build_id = os.getenv(TRAVIS_BUILD_ID)
 | 
						|
polling_interval = int(os.getenv(POLLING_INTERVAL, '5'))
 | 
						|
 | 
						|
#assume, first job is the leader
 | 
						|
is_leader = lambda job_number: job_number.endswith('.1')
 | 
						|
 | 
						|
if not os.getenv(TRAVIS_JOB_NUMBER):
 | 
						|
    # seems even for builds with only one job, this won't get here
 | 
						|
    log.fatal("Don't use defining leader for build without matrix")
 | 
						|
    exit(1)
 | 
						|
elif is_leader(os.getenv(TRAVIS_JOB_NUMBER)):
 | 
						|
    log.info("This is a leader")
 | 
						|
else:
 | 
						|
    #since python is subprocess, env variables are exported back via file
 | 
						|
    with open(".to_export_back", "w") as export_var:
 | 
						|
        export_var.write("BUILD_MINION=YES")
 | 
						|
    log.info("This is a minion")
 | 
						|
    exit(0)
 | 
						|
 | 
						|
 | 
						|
class MatrixElement(object):
 | 
						|
    def __init__(self, json_raw):
 | 
						|
        self.allow_failure = json_raw['allow_failure']
 | 
						|
        self.is_finished = json_raw['finished_at'] is not None
 | 
						|
        self.is_succeeded = json_raw['result'] == 0
 | 
						|
        self.number = json_raw['number']
 | 
						|
        self.is_leader = is_leader(self.number)
 | 
						|
 | 
						|
 | 
						|
def matrix_snapshot():
 | 
						|
    """
 | 
						|
    :return: Matrix List
 | 
						|
    """
 | 
						|
    response = urllib2.build_opener().open("https://api.travis-ci.org/builds/{0}".format(build_id)).read()
 | 
						|
    raw_json = json.loads(response)
 | 
						|
    matrix_without_leader = [MatrixElement(element) for element in raw_json["matrix"]]
 | 
						|
    return matrix_without_leader
 | 
						|
 | 
						|
 | 
						|
def wait_others_to_finish():
 | 
						|
    def others_finished():
 | 
						|
        """
 | 
						|
        Dumps others to finish
 | 
						|
        Leader cannot finish, it is working now
 | 
						|
        :return: tuple(True or False, List of not finished jobs)
 | 
						|
        """
 | 
						|
        snapshot = matrix_snapshot()
 | 
						|
        finished = [el.is_finished for el in snapshot if not (el.is_leader or el.allow_failure)]
 | 
						|
        return reduce(lambda a, b: a and b, finished), [el.number for el in snapshot if
 | 
						|
                                                        not el.is_leader and not el.is_finished]
 | 
						|
 | 
						|
    while True:
 | 
						|
        finished, waiting_list = others_finished()
 | 
						|
        if finished: break
 | 
						|
        log.info("Leader waits for minions {0}...".format(waiting_list))  # just in case do not get "silence timeout"
 | 
						|
        time.sleep(polling_interval)
 | 
						|
 | 
						|
 | 
						|
try:
 | 
						|
    wait_others_to_finish()
 | 
						|
 | 
						|
    final_snapshot = matrix_snapshot()
 | 
						|
    log.info("Final Results: {0}".format([(e.number, e.is_succeeded, e.allow_failure) for e in final_snapshot]))
 | 
						|
 | 
						|
    BUILD_AGGREGATE_STATUS = 'BUILD_AGGREGATE_STATUS'
 | 
						|
    others_snapshot = [el for el in final_snapshot if not (el.is_leader or el.allow_failure)]
 | 
						|
    if reduce(lambda a, b: a and b, [e.is_succeeded for e in others_snapshot]):
 | 
						|
        os.environ[BUILD_AGGREGATE_STATUS] = "others_succeeded"
 | 
						|
    elif reduce(lambda a, b: a and b, [not e.is_succeeded for e in others_snapshot]):
 | 
						|
        log.error("Others Failed")
 | 
						|
        os.environ[BUILD_AGGREGATE_STATUS] = "others_failed"
 | 
						|
    else:
 | 
						|
        log.warn("Others Unknown")
 | 
						|
        os.environ[BUILD_AGGREGATE_STATUS] = "unknown"
 | 
						|
    #since python is subprocess, env variables are exported back via file
 | 
						|
    with open(".to_export_back", "w") as export_var:
 | 
						|
        export_var.write("BUILD_LEADER=YES {0}={1}".format(BUILD_AGGREGATE_STATUS, os.environ[BUILD_AGGREGATE_STATUS]))
 | 
						|
 | 
						|
except Exception as e:
 | 
						|
    log.fatal(e)
 |