Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 235 additions & 0 deletions LOCAL_CLI_USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# Running GitHub Actions Locally

This guide shows you how to run your GitHub Actions CI workflow locally using the `local_cli.py` module.

## What It Does

The local CI runner:
- ✅ Runs your `.github/workflows/ci.yml` locally using [act](https://github.com/nektos/act)
- ✅ Spins up isolated Docker containers that mimic GitHub's runners
- ✅ Executes each CI step exactly as defined in your workflow
- ✅ Cleans up containers on success, preserves them on failure for debugging
- ✅ Provides clear feedback on what's happening

## Quick Start

### 1. Check Dependencies

```bash
python -m isee.local_cli --check-deps
```

This checks if `act` and Docker are installed and running. If not, you'll get installation instructions.

### 2. Run Your CI

```bash
# Run the entire CI workflow
python -m isee.local_cli

# Run just the validation job
python -m isee.local_cli -j validation

# Run with specific Python version
python -m isee.local_cli -j validation -m python-version:3.10

# See what would run (dry run)
python -m isee.local_cli --dry-run
```

## Installation

### Install act

**macOS:**
```bash
brew install act
```

**Linux:**
```bash
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
```

**Windows:**
```bash
choco install act-cli
```

### Install Docker

Follow instructions at https://docs.docker.com/get-docker/

Make sure Docker is running before using the local CI runner.

## Usage Examples

### Run Entire Workflow

```bash
python -m isee.local_cli
```

This runs all jobs in your `.github/workflows/ci.yml`.

### Run Specific Job

```bash
# Run just validation
python -m isee.local_cli -j validation

# Run just publish
python -m isee.local_cli -j publish
```

### Run Specific Matrix Combination

```bash
# Run validation with Python 3.10
python -m isee.local_cli -j validation -m python-version:3.10
```

### Dry Run (List Jobs)

```bash
python -m isee.local_cli --dry-run
```

Shows what jobs and steps would run without actually executing them.

### Use Custom Workflow File

```bash
python -m isee.local_cli -w .github/workflows/test.yml
```

### Quiet Mode

```bash
python -m isee.local_cli -q
```

Suppresses progress messages.

## Command-Line Options

```
usage: local_cli.py [-h] [-j JOB] [-m MATRIX] [-n] [-w WORKFLOW] [-q] [--check-deps]

Run GitHub Actions CI locally using act

options:
-h, --help show this help message and exit
-j JOB, --job JOB Specific job to run (e.g., validation)
-m MATRIX, --matrix MATRIX
Matrix combination (e.g., python-version:3.12)
-n, --dry-run List what would run without executing
-w WORKFLOW, --workflow WORKFLOW
Path to workflow file (default: .github/workflows/ci.yml)
-q, --quiet Suppress progress messages
--check-deps Only check dependencies and exit
```

## Debugging Failures

When CI fails locally, containers are preserved for debugging:

```bash
# List containers
docker ps -a

# View logs
docker logs <container-id>

# Inspect container
docker exec -it <container-id> /bin/bash

# Remove container when done
docker rm <container-id>
```

## How It Works

1. **Dependency Check**: Verifies `act` and Docker are available
2. **Workflow Parse**: Reads your `.github/workflows/ci.yml`
3. **Container Spin-up**: Creates Docker containers mimicking GitHub runners
4. **Job Execution**: Runs each step in your workflow
5. **Cleanup**: Removes containers on success, keeps them on failure

## Single Source of Truth

Your `.github/workflows/ci.yml` is the **only** definition of your CI process. The local runner uses the exact same workflow, ensuring what passes locally will pass on GitHub.

## Differences from GitHub Actions

A few things work differently locally:

- **Secrets**: Not available by default (use `.secrets` file with act)
- **GitHub Context**: Limited (can mock with `-s GITHUB_TOKEN=...`)
- **Caching**: Works differently than GitHub's cache
- **Performance**: May be slower or faster depending on your machine

## Troubleshooting

### "act not found"

Install act:
- macOS: `brew install act`
- Linux: `curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash`

### "Docker not running"

Start Docker Desktop or the Docker daemon.

### "Cannot connect to Docker daemon"

On Linux, you may need to add your user to the docker group:
```bash
sudo usermod -aG docker $USER
newgrp docker
```

### "Workflow file not found"

Make sure you're running from the repository root, or specify the workflow path with `-w`.

## Testing

The local CI runner has comprehensive tests. To run them:

```bash
# Install test dependencies
pip install pytest pytest-cov

# Run tests
pytest tests/ -v

# Run with coverage
pytest tests/ --cov=isee.local_cli --cov-report=html

# Or use the test runner script
bash run_tests.sh
```

See `tests/README.md` for more details on testing.

## CI Integration

You can also use this in your CI to test workflows:

```yaml
- name: Test workflow locally
run: |
pip install -e .
python -m isee.local_cli --dry-run
```

## More Information

- [act documentation](https://github.com/nektos/act)
- [GitHub Actions documentation](https://docs.github.com/en/actions)
- [Docker documentation](https://docs.docker.com/)

## Questions?

File an issue at https://github.com/i2mint/isee/issues
16 changes: 16 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--tb=short
--strict-markers
--disable-warnings

markers =
unit: Unit tests that test individual functions
integration: Integration tests that test full workflows
requires_docker: Tests that require Docker to be running
requires_act: Tests that require act to be installed
91 changes: 91 additions & 0 deletions run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/bin/bash
# Test runner script for local_cli tests

set -e # Exit on error

# Fix for setuptools/distutils compatibility issue
export SETUPTOOLS_USE_DISTUTILS=stdlib

echo "🧪 Running Local CI Tests"
echo "========================"
echo

# Check if pytest is installed
if ! command -v pytest &> /dev/null; then
echo "❌ pytest is not installed"
echo " Install with: pip install pytest pytest-cov"
exit 1
fi

# Parse command line arguments
COVERAGE=false
VERBOSE=false
PATTERN=""

while [[ $# -gt 0 ]]; do
case $1 in
--coverage|-c)
COVERAGE=true
shift
;;
--verbose|-v)
VERBOSE=true
shift
;;
--pattern|-k)
PATTERN="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo
echo "Options:"
echo " -c, --coverage Generate coverage report"
echo " -v, --verbose Verbose output"
echo " -k, --pattern Run tests matching pattern"
echo " -h, --help Show this help message"
echo
echo "Examples:"
echo " $0 # Run all tests"
echo " $0 --coverage # Run with coverage report"
echo " $0 -k TestCheckDeps # Run tests matching pattern"
echo " $0 --coverage --verbose # Both coverage and verbose"
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done

# Build pytest command
CMD="pytest tests/"

if [ "$VERBOSE" = true ]; then
CMD="$CMD -v"
fi

if [ "$COVERAGE" = true ]; then
CMD="$CMD --cov=isee.local_cli --cov-report=term --cov-report=html"
fi

if [ -n "$PATTERN" ]; then
CMD="$CMD -k $PATTERN"
fi

# Run tests
echo "Running: $CMD"
echo
$CMD

# Show coverage location if generated
if [ "$COVERAGE" = true ]; then
echo
echo "📊 Coverage report generated: htmlcov/index.html"
echo " Open with: xdg-open htmlcov/index.html (Linux) or open htmlcov/index.html (Mac)"
fi

echo
echo "✅ Tests completed successfully!"
Loading