GitHub Actions: Replaces Travis CI?
Travis CI dominated open source CI for a decade. GitHub Actions arrived, and the migration began. For many projects, Actions is now the better choice.
GitHub Actions Basics
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: pytest
Push to GitHub, CI runs. That simple.
vs Travis CI
Travis CI Configuration
# .travis.yml
language: python
python:
- "3.10"
install:
- pip install -r requirements.txt
script:
- pytest
Key Differences
| Feature | GitHub Actions | Travis CI |
|---|---|---|
| Pricing (OSS) | Free | Limited free |
| Pricing (Private) | 2000 min/month free | Paid |
| Runners | GitHub-hosted or self-hosted | Travis-hosted |
| Ecosystem | 10,000+ marketplace actions | Limited |
| Matrix builds | ✅ | ✅ |
| Caching | Built-in | Built-in |
| Secrets | Encrypted, easy | Encrypted |
| YAML complexity | Higher | Lower |
Actions Advantage: Marketplace
jobs:
test:
steps:
# Official actions
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
# Community actions
- uses: codecov/codecov-action@v3
- uses: slackapi/slack-github-action@v1
Thousands of pre-built actions. Don’t reinvent the wheel.
Matrix Builds
Test across multiple versions:
jobs:
test:
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11']
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: pytest
8 jobs (4 Python × 2 OS) in parallel.
Caching Dependencies
jobs:
test:
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip' # Built-in pip caching
- run: pip install -r requirements.txt
Or manual caching:
- uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
Deployment
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to production
uses: appleboy/ssh-action@v0.1.0
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /app
git pull
docker-compose up -d --build
Docker Builds
jobs:
build:
steps:
- uses: actions/checkout@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: myapp:latest
Secrets and Environment Variables
jobs:
deploy:
environment: production # Requires approval
steps:
- name: Deploy
run: ./deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
Conditional Jobs
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: pytest
deploy:
needs: test # Wait for test to pass
if: github.ref == 'refs/heads/main' # Only on main
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Reusable Workflows
# .github/workflows/reusable.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
python-version:
required: true
type: string
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ inputs.python-version }}
- run: pytest
# .github/workflows/ci.yml
name: CI
on: push
jobs:
test-38:
uses: ./.github/workflows/reusable.yml
with:
python-version: '3.8'
test-310:
uses: ./.github/workflows/reusable.yml
with:
python-version: '3.10'
Self-Hosted Runners
For custom environments or private networks:
jobs:
build:
runs-on: self-hosted
steps:
- run: ./build.sh
Migration from Travis
Most patterns translate directly:
| Travis | GitHub Actions |
|---|---|
language: python | setup-python@v4 |
python: ["3.8", "3.9"] | matrix.python-version |
before_install | Early steps |
install | run: pip install |
script | run: pytest |
after_success | Conditional steps |
deploy | Separate job with needs |
Should You Migrate?
Migrate if:
- You’re already on GitHub
- Travis pricing increased
- You want marketplace actions
- You need self-hosted runners
Stay if:
- Travis works fine
- Heavy Travis investment
- Not on GitHub
Final Thoughts
GitHub Actions won the CI/CD war through integration. Living inside GitHub means less context switching, better security with secrets, and a massive ecosystem.
For new projects on GitHub, Actions is the default choice. For existing Travis projects, migrate when you have time—but you probably should.
CI should be invisible. Actions makes it so.