Skip to content

Commit c5f2e27

Browse files
committed
travis after all
1 parent abfde2b commit c5f2e27

File tree

2 files changed

+113
-4
lines changed

2 files changed

+113
-4
lines changed

.travis.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ notifications:
1515
slack:
1616
secure: G7fzaXoPI1cyyW7dlpQ8oG/ot73n4kE83HgbyK1iEN1YBfodsytVgh0jS+zB3DhhRAotS/VfGVz9Wj2Oo109U5w/FyxdMGuKvFan/0B/aAws1sPxLGWA5230u1wTKQCHAu17+yppFOODUu1ILDXaD2A//Wj5iru9M4NnKc1bO6VHkfBHPTLQLbdPHmorwuSH02Ocbh7K4XOWzXRxM6VrwamEn1KnyXGu2w3QdJUT31OjGEEdf6FUzvjwzFgXPhngCw5+enpwm71ljHDNu8YHhXvHtS4328O5pYQO8np7j653HNEqi+ZUiYEOWpwC8be1xHdvi/s32tPFZiCx28ZmDoCUrY744tpPtE6tzuncmSKB0Y3EjutdXBpxllNr5l5hpX5092G2MlpokFbv85J+E2ALcZYNYeFOqTYTKwTYkxK6B1x4amBNpM+FXgUhloK4BK9OT0Qh5SiQOsM8cZT0h6QP91n+REljtpugW3VbuIxq5OJAi42FYbHBC27pohhq6ohU1euZfobk9a7ZawnjoEUk1EZHXiJzYKY/QqzyB6dwk0ersBl3l3OX/wnjwKTkqc9aTmDWo2L+lHaUCXuCY1+KQXsRicfnH395szTJXQbvcbN0zz188gdz6sawzi5BxndWo0NRwZyOG2YcyUHFQR4bK1rL7Lo6t6rijQ/XMeQ=
1717

18+
before_script:
19+
- npm config set spin false --global
20+
21+
after_failure:
22+
- python scripts/travis_after_all.py
23+
24+
after_success:
25+
- python scripts/travis_after_all.py
26+
- export $(cat scripts/.to_export_back)
27+
- if [ "$BUILD_LEADER" = "YES" ]; then npm run coveralls; fi
28+
1829
deploy:
1930
provider: npm
2031
@@ -23,7 +34,4 @@ deploy:
2334
on:
2435
tags: true
2536
branch: master
26-
node: "iojs"
27-
28-
after_success:
29-
- npm run coveralls
37+
condition: "$BUILD_LEADER$BUILD_AGGREGATE_STATUS = YESothers_succeeded"

scripts/travis_after_all.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""
2+
https://github.com/dmakhno/travis_after_all/blob/master/travis_after_all.py
3+
"""
4+
5+
import os
6+
import json
7+
import time
8+
import logging
9+
10+
try:
11+
import urllib.request as urllib2
12+
except ImportError:
13+
import urllib2
14+
15+
log = logging.getLogger("travis.leader")
16+
log.addHandler(logging.StreamHandler())
17+
log.setLevel(logging.INFO)
18+
19+
TRAVIS_JOB_NUMBER = 'TRAVIS_JOB_NUMBER'
20+
TRAVIS_BUILD_ID = 'TRAVIS_BUILD_ID'
21+
POLLING_INTERVAL = 'LEADER_POLLING_INTERVAL'
22+
23+
build_id = os.getenv(TRAVIS_BUILD_ID)
24+
polling_interval = int(os.getenv(POLLING_INTERVAL, '5'))
25+
26+
#assume, first job is the leader
27+
is_leader = lambda job_number: job_number.endswith('.1')
28+
29+
if not os.getenv(TRAVIS_JOB_NUMBER):
30+
# seems even for builds with only one job, this won't get here
31+
log.fatal("Don't use defining leader for build without matrix")
32+
exit(1)
33+
elif is_leader(os.getenv(TRAVIS_JOB_NUMBER)):
34+
log.info("This is a leader")
35+
else:
36+
#since python is subprocess, env variables are exported back via file
37+
with open(".to_export_back", "w") as export_var:
38+
export_var.write("BUILD_MINION=YES")
39+
log.info("This is a minion")
40+
exit(0)
41+
42+
43+
class MatrixElement(object):
44+
def __init__(self, json_raw):
45+
self.is_finished = json_raw['finished_at'] is not None
46+
self.is_succeeded = json_raw['result'] == 0
47+
self.number = json_raw['number']
48+
self.is_leader = is_leader(self.number)
49+
50+
51+
def matrix_snapshot():
52+
"""
53+
:return: Matrix List
54+
"""
55+
response = urllib2.build_opener().open("https://api.travis-ci.org/builds/{0}".format(build_id)).read()
56+
raw_json = json.loads(response)
57+
matrix_without_leader = [MatrixElement(element) for element in raw_json["matrix"]]
58+
return matrix_without_leader
59+
60+
61+
def wait_others_to_finish():
62+
def others_finished():
63+
"""
64+
Dumps others to finish
65+
Leader cannot finish, it is working now
66+
:return: tuple(True or False, List of not finished jobs)
67+
"""
68+
snapshot = matrix_snapshot()
69+
finished = [el.is_finished for el in snapshot if not el.is_leader]
70+
return reduce(lambda a, b: a and b, finished), [el.number for el in snapshot if
71+
not el.is_leader and not el.is_finished]
72+
73+
while True:
74+
finished, waiting_list = others_finished()
75+
if finished: break
76+
log.info("Leader waits for minions {0}...".format(waiting_list)) # just in case do not get "silence timeout"
77+
time.sleep(polling_interval)
78+
79+
80+
try:
81+
wait_others_to_finish()
82+
83+
final_snapshot = matrix_snapshot()
84+
log.info("Final Results: {0}".format([(e.number, e.is_succeeded) for e in final_snapshot]))
85+
86+
BUILD_AGGREGATE_STATUS = 'BUILD_AGGREGATE_STATUS'
87+
others_snapshot = [el for el in final_snapshot if not el.is_leader]
88+
if reduce(lambda a, b: a and b, [e.is_succeeded for e in others_snapshot]):
89+
os.environ[BUILD_AGGREGATE_STATUS] = "others_succeeded"
90+
elif reduce(lambda a, b: a and b, [not e.is_succeeded for e in others_snapshot]):
91+
log.error("Others Failed")
92+
os.environ[BUILD_AGGREGATE_STATUS] = "others_failed"
93+
else:
94+
log.warn("Others Unknown")
95+
os.environ[BUILD_AGGREGATE_STATUS] = "unknown"
96+
#since python is subprocess, env variables are exported back via file
97+
with open(".to_export_back", "w") as export_var:
98+
export_var.write("BUILD_LEADER=YES {0}={1}".format(BUILD_AGGREGATE_STATUS, os.environ[BUILD_AGGREGATE_STATUS]))
99+
100+
except Exception as e:
101+
log.fatal(e)

0 commit comments

Comments
 (0)