This guide explains how to test GitHub Actions workflows locally using act
before pushing changes to GitHub.
act allows you to run GitHub Actions locally in Docker containers, enabling you to:
brew install act
# Download latest release
curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
# Using Chocolatey
choco install act-cli
# Or using Scoop
scoop install act
# Run act in Docker (if you don't want to install locally)
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd):/github/workspace \
nektos/act:latest
# Show all workflows and jobs
act --list
# Show jobs for specific event
act push --list
act pull_request --list
Example Output:
Stage Job ID Job name Workflow name
0 test Test Suite CI/CD Pipeline
0 security Security Scan CI/CD Pipeline
0 commit-lint Conventional Commits Commit Lint
1 docker Docker Build & Test CI/CD Pipeline
1 build Build Package CI/CD Pipeline
# Validate all workflows
act -n
# Validate specific workflow
act -W .github/workflows/ci.yml -n
# Validate specific job
act -W .github/workflows/ci.yml -j test -n
# Run default event (usually push)
act
# Run specific event
act push
act pull_request
# Run specific workflow file
act -W .github/workflows/ci.yml
# Run specific job
act -W .github/workflows/ci.yml -j test
# Dry run first
act -W .github/workflows/commit-lint.yml -n
# Run the workflow
act -W .github/workflows/commit-lint.yml
# Expected: Validates your commit messages follow conventional format
# Test the main CI pipeline
act -W .github/workflows/ci.yml
# Test specific jobs
act -W .github/workflows/ci.yml -j test # Run test suite
act -W .github/workflows/ci.yml -j security # Run security scans
act -W .github/workflows/ci.yml -j docker # Test Docker build
# Test documentation build
act -W .github/workflows/docs.yml
# This will build the MkDocs site locally
# Test semantic release workflow structure
act -W .github/workflows/semantic-release.yml -n
# Note: Full semantic release requires GitHub API access
# Local testing focuses on validation and basic steps
Use smaller, faster images for testing:
# Use smaller Ubuntu image
act -P ubuntu-latest=catthehacker/ubuntu:act-latest
# Use Node.js image for faster Node.js workflows
act -P ubuntu-latest=node:16-slim -W .github/workflows/commit-lint.yml
# Multi-architecture support (important for M2 Macs)
act --container-architecture linux/amd64
Create local configuration files:
# Create .secrets file (don't commit this!)
echo "GITHUB_TOKEN=your_test_token_here" > .secrets
echo "DOCKER_USERNAME=your_docker_username" >> .secrets
# Create .env file for environment variables
echo "NODE_VERSION=18" > .env
echo "PYTHON_VERSION=3.12" >> .env
# Use in act commands
act -W .github/workflows/ci.yml --secret-file .secrets --env-file .env
# Bind current directory (faster than copying)
act --bind
# Use specific Docker network
act --network host
# Increase verbosity for debugging
act -v
# Use artifact server for job artifacts
act --artifact-server-path ./artifacts
ci.yml
)# Test full pipeline (may take 10-15 minutes)
act push -W .github/workflows/ci.yml
# Test individual stages
act push -W .github/workflows/ci.yml -j test
act push -W .github/workflows/ci.yml -j security
act push -W .github/workflows/ci.yml -j docker
act push -W .github/workflows/ci.yml -j build
What gets tested locally:
docs.yml
)# Test documentation build
act push -W .github/workflows/docs.yml
# Focus on build job only
act push -W .github/workflows/docs.yml -j build-docs
What gets tested locally:
commit-lint.yml
)# Test commit message validation
act push -W .github/workflows/commit-lint.yml
# Use smaller image for faster testing
act push -W .github/workflows/commit-lint.yml -P ubuntu-latest=node:18-alpine
github.*
variables may differ# Check available disk space (act uses Docker heavily)
df -h
# Clean up Docker to free space
docker system prune -a
# Use smaller images to save space
act -P ubuntu-latest=catthehacker/ubuntu:act-latest
# Error: failed to create prepare snapshot dir: no space left on device
# Solution: Clean up Docker
docker system prune -a -f
docker volume prune -f
# Use smaller images
act -P ubuntu-latest=catthehacker/ubuntu:act-latest
# Error: permission denied while trying to connect to Docker
# Solution: Add user to docker group or use sudo
sudo usermod -aG docker $USER
# Then restart terminal
# Or run with sudo
sudo act
# Error: unable to determine reference
# Solution: Ensure you're in the repository root
cd /path/to/pybiorythm
act --list
# Error: unable to resolve action
# Solution: Check if action exists and version is correct
# Update workflow to use correct action versions
# Enable verbose logging
act -v
# Enable even more verbose logging
act -vv
# Show environment variables
act --env
# Show job summary
act --job
Always validate before executing:
# Check syntax and structure
act -W .github/workflows/ci.yml -n
# Then run if validation passes
act -W .github/workflows/ci.yml
Test jobs separately for faster iteration:
# Test just the test job
act -W .github/workflows/ci.yml -j test
# Test just Docker build
act -W .github/workflows/ci.yml -j docker
Save time and disk space:
# Create .actrc file for persistent configuration
echo "-P ubuntu-latest=catthehacker/ubuntu:act-latest" > .actrc
echo "--container-architecture linux/amd64" >> .actrc
# Now act will use these settings by default
act -W .github/workflows/ci.yml
Create mock endpoints for external services:
# In your workflow, check if running locally
- name: Upload coverage
if: env.ACT != 'true' # Skip in act
uses: codecov/codecov-action@v4
# Create .secrets with dummy values
echo "GITHUB_TOKEN=dummy_token_for_testing" > .secrets
echo "DOCKER_PASSWORD=dummy_password" >> .secrets
# Add to .gitignore
echo ".secrets" >> .gitignore
#!/bin/bash
# scripts/test-workflows.sh
echo "🧪 Testing workflows locally before push..."
# Test commit lint
echo "Testing commit lint..."
act -W .github/workflows/commit-lint.yml -q
# Test main CI
echo "Testing CI pipeline..."
act -W .github/workflows/ci.yml -j test -q
# Test documentation
echo "Testing documentation build..."
act -W .github/workflows/docs.yml -j build-docs -q
echo "✅ All workflows tested successfully!"
Make it executable and use:
chmod +x scripts/test-workflows.sh
./scripts/test-workflows.sh
Add to .vscode/tasks.json
:
{
"version": "2.0.0",
"tasks": [
{
"label": "Test GitHub Actions",
"type": "shell",
"command": "act",
"args": ["-W", ".github/workflows/ci.yml", "-j", "test"],
"group": "test",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
}
}
]
}
# Enable action caching
act --use-gitignore=false
# Use local cache directory
act --action-cache-path ~/.cache/act-cache
# Run multiple jobs concurrently
act --concurrent-jobs 2
# Limit resource usage
act --container-options "--memory=2g --cpus=2"
# Test only changed workflows
git diff --name-only HEAD~1 | grep ".github/workflows" | while read workflow; do
echo "Testing $workflow"
act -W "$workflow" -n
done
Feature | GitHub Actions | Local act |
---|---|---|
Workflow Validation | ✅ | ✅ |
Job Execution | ✅ | ✅ |
Docker Builds | ✅ | ✅ |
Secret Management | ✅ | ⚠️ Limited |
GitHub Context | ✅ | ⚠️ Simulated |
External Integrations | ✅ | ❌ |
Artifact Storage | ✅ | ⚠️ Local only |
Matrix Builds | ✅ | ⚠️ Limited |
Cost | 💰 Minutes | 🆓 Free |
Speed | Slower | Faster |
Offline | ❌ | ✅ |