diff --git a/.gitattributes b/.gitattributes
index fe033c73dbf5c34aa6e8ed4fbc747212c0b1deb7..0d5b01d2cfcfcacb69a2d5fc899ccc8f29afc217 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,2 @@
 Vagrantfile eol=lf
+*.sh text eol=lf
diff --git a/.travis.yml b/.travis.yml
index f42755e6d4c3df6cdf5b16c155f6b7a2bfd033c1..7521d0df32da5fee340817a18d35f905e2996fe1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,34 +1,49 @@
 language: python
-python:
-  - "2.7"
-  - "3.5"
-  - "3.6"
-  - "3.7"
-  - "3.8"
-  - "nightly"
-  - "pypy"
-  - "pypy3.5"
+stages:
+  - name: test
+  - name: deploy
+    if: branch = master
 cache: pip
-before_script:
-  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
-  - chmod +x ./cc-test-reporter
-  - ./cc-test-reporter before-build
-  - pip install nose2 coverage
-script:
-  - coverage run -m compile_definitions
-  - coverage run --append -m nose2 -vv
-  - COOLAMQP_FORCE_SELECT_LISTENER=1 coverage run --append -m nose2 -vv
-  - coverage run --append -m stress_tests
-install:
-  - python setup.py install
-  - pip install -r stress_tests/requirements.txt
-  - pip install yapf nose2 mock coverage nose2[coverage_plugin]
-after_success:
-  - coverage xml
-  - ./cc-test-reporter after-build -t coverage.py --exit-code $TRAVIS_TEST_RESULT
-  - bash build.sh
+jobs:
+  include:
+    - stage: test
+      python: "2.7"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "3.5"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "3.6"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "3.7"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "3.8"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "nightly"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "pypy"
+      script:
+        - bash tests/travis_test.sh
+    - stage: test
+      python: "pypy3.5"
+      script:
+        - bash tests/travis_test.sh
+    - stage: deploy
+      python: "3.8"
+      script:
+        - bash tests/travis_build.sh
 services: rabbitmq
 addons:
   apt:
     packages:
-      - rabbitmq-server
+      - rabbitmq-server
\ No newline at end of file
diff --git a/build.sh b/build.sh
deleted file mode 100644
index 413cacc14ee19bc24cd4bc369dc9092df2b49fd2..0000000000000000000000000000000000000000
--- a/build.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-set -x
-set -e
-
-pip install yapf
-python -m compile_definitions
-python setup.py bdist bdist_wheel
-
-if [ $TRAVIS_BRANCH == "master" ]; then
-
-  if [ $TRAVIS_PYTHON_VERSION == "2.7" ]; then
-    pip install wheel twine
-    twine upload -u $PYPI_USER -p $PYPI_PWD dist/*
-  fi
-fi
diff --git a/tests/travis_build.sh b/tests/travis_build.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2383bc735df62e42df803c41f5e4d5dda50348f0
--- /dev/null
+++ b/tests/travis_build.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -x
+set -e
+
+pip install wheel twine yapf
+
+python -m compile_definitions
+python setup.py bdist bdist_wheel
+
+twine upload -u $PYPI_USER -p $PYPI_PWD dist/*
diff --git a/tests/travis_test.sh b/tests/travis_test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..496ce540ed95135e566640862ace29f67dabe178
--- /dev/null
+++ b/tests/travis_test.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+set -e
+set -x
+
+curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
+chmod +x ./cc-test-reporter
+./cc-test-reporter before-build
+pip install nose2 coverage
+
+python setup.py install
+pip install -r stress_tests/requirements.txt
+pip install yapf nose2 mock coverage nose2[coverage_plugin]
+
+coverage run -m compile_definitions
+coverage run --append -m nose2 -vv
+COOLAMQP_FORCE_SELECT_LISTENER=1 coverage run --append -m nose2 -vv
+coverage run --append -m stress_tests
+
+coverage combine
+coverage report
+coverage xml
+
+./cc-test-reporter after-build -t coverage.py --exit-code $TRAVIS_TEST_RESULT
+