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
12 changes: 5 additions & 7 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
needs: lint
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
steps:
- name: Checkout code
uses: actions/checkout@v6
Expand All @@ -45,12 +45,10 @@ jobs:
run: pip install -e ".[dev]"

- name: Run tests with coverage
run: >-
python -m pytest tests/
--cov=timerun
--cov-branch
--cov-report=xml
--cov-report=term
run: |
coverage run --source=timerun -m behave -f progress
coverage report
coverage xml

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
Expand Down
35 changes: 25 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,39 @@ repos:
- id: check-yaml
- id: check-toml

- repo: https://github.com/HH-MWB/pyenforce
rev: v0.1.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.1
hooks:
- id: ruff-format
- id: ruff-check

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.19.1
hooks:
- id: mypy
additional_dependencies:
- ".[mypy]" # Required to re-adds mypy as a dependency
- pytest
args: ["--scripts-are-modules"]
files: ^timerun\.py$
additional_dependencies: [behave]

- repo: https://github.com/pylint-dev/pylint
rev: v4.0.4
hooks:
- id: pylint
additional_dependencies:
- ".[pylint]" # Required to re-adds Pylint as a dependency
- pytest
additional_dependencies: [behave]

- repo: https://github.com/PyCQA/bandit
rev: 1.9.3
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]

- repo: https://github.com/semgrep/pre-commit
rev: v1.151.0
hooks:
- id: semgrep
- id: vulture
args: ["--config", "p/python", "--error"]

- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
rev: v1.38.0
hooks:
- id: yamllint
214 changes: 148 additions & 66 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,201 @@
# Contributing to TimeRun

Thank you for your interest in contributing to TimeRun! This document provides guidelines for contributing to the project.
Thank you for considering contributing to TimeRun. This guide explains how to set up your environment, run tests, and submit changes.

## Getting Started
## Table of Contents

- [Code of Conduct](#code-of-conduct)
- [How You Can Help](#how-you-can-help)
- [Development Setup](#development-setup)
- [Testing](#testing)
- [Code Style and Quality](#code-style-and-quality)
- [Project Structure](#project-structure)
- [Pull Request Process](#pull-request-process)
- [Reporting Bugs](#reporting-bugs)
- [License](#license)

## Code of Conduct

Please be respectful and constructive. By participating, you agree to uphold a welcoming environment for everyone.

## How You Can Help

- **Report bugs** β€” Open an issue with clear steps to reproduce.
- **Suggest features** β€” Open an issue describing the use case and desired behavior.
- **Submit code** β€” Fix bugs or add features via pull requests (see [Pull Request Process](#pull-request-process)).
- **Improve docs** β€” Fix typos, clarify README or docstrings, or add examples.

## Development Setup

### Prerequisites

- Python 3.9 or higher
- Git
- **Python 3.10+**
- **Git**

### Development Setup
### One-time setup

1. **Fork** the repository on GitHub, then clone your fork:

1. Fork the repository on GitHub
2. Clone your fork locally:
```bash
git clone https://github.com/YOUR_USERNAME/timerun.git
cd timerun
```

3. Set up the development environment:
2. **Create and activate a virtual environment** (recommended):

```bash
make init
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
```

4. Activate the virtual environment:
3. **Install the project in editable mode with dev dependencies**:

```bash
source .venv/bin/activate
pip install -e ".[dev]"
```

## Development Workflow
4. **Install and enable pre-commit hooks** (optional but recommended):

### Running Tests
```bash
pip install pre-commit
pre-commit install
```

Or use the convenience target:

```bash
make init
```

Then activate the venv: `source .venv/bin/activate`.

### Verify setup

Run the test suite:

Run the test suite with coverage:
```bash
make test
```

### Code Style
You should see the BDD scenarios run and a coverage report.

## Testing

TimeRun uses **behavior-driven development (BDD)** with [behave](https://behave.readthedocs.io/). All tests are written in Gherkin and live under `features/`.

### Run tests

| Command | Description |
|--------------------|----------------------------------------------------------------|
| `make test` | Run BDD suite with progress + summary + coverage (default) |
| `make test-summary`| Summary and coverage only (minimal output) |
| `make test-verbose`| Full scenario/step output (use when debugging failures) |
| `behave` | Run BDD suite only (no coverage) |

### Run coverage manually

```bash
coverage run --source=timerun -m behave # full output
coverage run --source=timerun -m behave -f progress # progress + summary
coverage run --source=timerun -m behave -f null # summary only
coverage report --show-missing
```

### Adding or changing tests

This project follows these code style guidelines:
- **Black** for code formatting (line length: 79 characters)
- **isort** for import sorting
- **Feature files** β€” Add or edit `.feature` files in `features/` (e.g. `features/version.feature`). Use standard Gherkin: `Feature`, `Scenario`, `Given`, `When`, `Then`.
- **Step definitions** β€” Implement steps in Python under `features/steps/`, typically in a `*_steps.py` file. Use `@given`, `@when`, `@then` from `behave`; step functions receive a `context` argument.
- Keep scenarios focused and steps reusable. Add or extend scenarios for new behavior rather than skipping BDD.

## Code Style and Quality

Style and linting are enforced via **pre-commit** (Ruff, mypy, Pylint, and other hooks). After `pre-commit install`, these run automatically on each commit.

### Run checks manually

Pre-commit hooks are installed automatically with `make init` and will run on every commit. You can also run them manually:
```bash
pre-commit run --all-files
```

### Making Changes
### What we expect

1. Create a new branch for your feature or bugfix:
```bash
git checkout -b feature/your-feature-name
```
- **Formatting** β€” Ruff format (run via pre-commit or `ruff format`).
- **Linting** β€” Ruff check, Pylint, and other hooks must pass.
- **Types** β€” Use type hints for public APIs; mypy must pass.
- **Docstrings** β€” Public functions, classes, and modules should have docstrings.
- **Security** β€” Bandit and Semgrep run in pre-commit; address any reported issues.

2. Make your changes following the project conventions
3. Add or update tests as needed
4. Ensure all tests pass: `make test`
5. Commit your changes with a clear message
Fixing pre-commit failures before pushing keeps the history clean and CI green.

### Submitting Changes
## Project Structure

1. Push your branch to your fork:
```bash
git push origin feature/your-feature-name
```
```
timerun/
β”œβ”€β”€ timerun.py # Library (single-file by design)
β”œβ”€β”€ features/ # BDD feature files (Gherkin) β€” behave convention
β”‚ β”œβ”€β”€ __init__.py # Makes features a package for imports
β”‚ β”œβ”€β”€ *.feature
β”‚ β”œβ”€β”€ environment.py # Optional: hooks (before/after scenario, etc.)
β”‚ └── steps/ # Step definitions (flat; all .py files loaded)
β”‚ β”œβ”€β”€ __init__.py
β”‚ β”œβ”€β”€ utils.py # Shared constants and helpers (no step decorators)
β”‚ β”œβ”€β”€ common_steps.py # Shared steps used by multiple features
β”‚ └── *_steps.py # Feature-specific step files
β”œβ”€β”€ pyproject.toml # Project metadata and config
β”œβ”€β”€ Makefile # Commands: init, test, clean, help
β”œβ”€β”€ README.md
β”œβ”€β”€ CONTRIBUTING.md
└── LICENSE
```

2. Create a pull request on GitHub with:
- Clear description of the changes
- Reference to any related issues
- Test coverage for new functionality
- **`timerun.py`** β€” The only library module; keep it a single file by design.
- **`features/`** β€” All executable specs; no separate unit test directory. Layout follows [behave](https://behave.readthedocs.io/) convention: step definitions live under `features/steps/` (flat; subdirectories are not searched). Shared logic lives in `features/steps/utils.py`; shared steps (e.g. metadata, wall-time buffer, exception propagation) in `common_steps.py`. Run behave from the project root so `from features.steps.utils import ...` works.

## Project Structure
## Pull Request Process

- `timerun.py` - Main library code (single file module)
- `tests/` - Test suite
- `pyproject.toml` - Project configuration and dependencies
- `Makefile` - Development commands
1. **Create a branch** from `main`:

## Guidelines
```bash
git checkout main
git pull origin main
git checkout -b feature/short-description # or fix/short-description
```

### Code Quality
2. **Make your changes** β€” Follow [Code Style and Quality](#code-style-and-quality) and add or update BDD scenarios in `features/` for new or changed behavior.

- Maintain 100% test coverage for new code
- Follow existing code patterns and conventions
- Add docstrings for all public functions and classes
- Use type hints consistently
3. **Run the suite and pre-commit**:

### Testing
```bash
make test
pre-commit run --all-files
```

- Write tests for all new functionality
- Use descriptive test names
- Test both success and error cases
- Keep tests focused and independent
4. **Commit** with clear, concise messages. Optionally use conventional style (e.g. `feat: add X`, `fix: correct Y`).

### Documentation
5. **Push** to your fork and open a pull request against `main`:

- Update docstrings for any API changes
- Add examples for new features
- Update README.md if needed
```bash
git push origin feature/short-description
```

## Reporting Issues
6. **Fill out the PR**:
- Describe what changed and why.
- Reference any related issues (e.g. "Fixes #123").
- Confirm tests pass and, for new behavior, that BDD scenarios were added or updated.

When reporting bugs or requesting features:
Maintainers will review and may request changes. Once approved, your PR will be merged.

1. Check existing issues first
2. Use the issue templates if available
3. Provide clear reproduction steps for bugs
4. Include Python version and environment details
## Reporting Bugs

## Questions?
- **Search** existing issues to avoid duplicates.
- **Open an issue** with:
- A short, clear title.
- Steps to reproduce (code or commands).
- Expected vs actual behavior.
- Your environment: OS, Python version (`python --version`), and how you installed TimeRun (pip, editable, etc.).

Feel free to open an issue for questions about contributing or reach out to the maintainers.
For small, obvious fixes you may open a PR directly with a short explanation.

## License

By contributing to TimeRun, you agree that your contributions will be licensed under the MIT License.
Contributions are made under the [MIT License](LICENSE). By submitting a pull request, you agree that your contributions will be licensed under the same terms.
17 changes: 14 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,23 @@ init: ## Set up Python development environment with pre-commit hooks
@echo "Development environment ready! To activate it, run: source $(VENV_DIR)/bin/activate"

.PHONY: test
test: ## Run all tests and display coverage ratio
@"$(VENV_DIR)/bin/pytest" tests/ --cov=timerun --cov-report=term-missing
test: ## Run BDD tests (progress + summary + coverage)
@"$(VENV_DIR)/bin/coverage" run --source=timerun -m behave -f progress
@"$(VENV_DIR)/bin/coverage" report --show-missing

.PHONY: test-summary
test-summary: ## Run BDD tests (summary and coverage only; use 'make test' to see which feature failed)
@"$(VENV_DIR)/bin/coverage" run --source=timerun -m behave -f null
@"$(VENV_DIR)/bin/coverage" report --show-missing

.PHONY: test-verbose
test-verbose: ## Run BDD tests with full scenario/step output (for debugging failures)
@"$(VENV_DIR)/bin/coverage" run --source=timerun -m behave
@"$(VENV_DIR)/bin/coverage" report --show-missing

.PHONY: clean
clean: ## Delete all temporary files including venv
@rm -rf "$(VENV_DIR)" *.egg-info
@rm -rf .mypy_cache .pytest_cache .coverage htmlcov
@rm -rf .mypy_cache .ruff_cache .coverage htmlcov
@find . -name "*.pyc" -delete
@find . -name "__pycache__" -type d -exec rm -rf {} +
Loading