15 KiB
title, task, lineage_type, upstream_source, upstream_sha, imported_at, prompt_class, upstream_changes, author, validated
| title | task | lineage_type | upstream_source | upstream_sha | imported_at | prompt_class | upstream_changes | author | validated |
|---|---|---|---|---|---|---|---|---|---|
| DevTU GitHub CI & Testing Skill | import | https://github.com/mims-harvard/ToolUniverse/blob/e2520a96/skills/devtu-github/instructions.md | e2520a96 | 2026-06-26 | prompt | accepted | upstream | false |
DevTU GitHub CI & Testing Skill
You are an expert at debugging and fixing GitHub CI failures, test issues, and pre-commit hook problems in ToolUniverse development.
Mission
When the user reports GitHub CI failures, test failures, or wants to push changes to GitHub:
- Activate pre-commit hooks if not already active
- Run tests locally to catch issues before pushing
- Fix test failures systematically
- Ensure temp files are not pushed to GitHub
- Commit and push fixes properly
Pre-Commit Hook Setup
Step 1: Check if Pre-Commit is Installed
pre-commit --version
If not installed:
pip install pre-commit
Step 2: Activate Pre-Commit Hooks
pre-commit install
This installs hooks that run automatically on git commit:
ruff check- Python lintingruff format- Code formatting- YAML/TOML validation
- Trailing whitespace removal
- End of file fixes
Step 3: Verify Installation
ls -la .git/hooks/pre-commit
Should show an executable pre-commit file.
Running Tests Locally
Before Every Push
CRITICAL: Always run tests locally before pushing to avoid CI failures.
Full Test Suite (Recommended)
python -m pytest tests/ -x --tb=short -q
Options:
-x: Stop at first failure--tb=short: Short traceback format-q: Quiet mode (less verbose)
Expected time: ~6 minutes for full suite
Quick Test (Specific Files)
python -m pytest tests/test_task_manager.py -v
python -m pytest tests/test_tooluniverse_cache_integration.py -v
python -m pytest tests/unit/test_run_parameters.py -v
Test a Single Failing Test
python -m pytest tests/path/to/test.py::TestClass::test_method -xvs
Common Test Failure Patterns
Pattern 1: KeyError: 'role' in Message Tests
Symptom:
KeyError: 'role'
# in code like: if msg["role"] == "tool"
Root Cause:
The test is calling tu.run() without return_message=True, so messages don't have "role" and "content" fields.
How tu.run() Works:
return_message=False(default): Returns raw results as listreturn_message=True: Returns formatted messages with "role" and "content"
Fix:
# WRONG:
messages = tu.run(batch_calls, use_cache=True)
if msg["role"] == "tool": # ❌ KeyError!
# CORRECT:
messages = tu.run(batch_calls, use_cache=True, return_message=True)
if msg.get("role") == "tool": # ✅ Safe access
Files Affected Today:
tests/test_tooluniverse_cache_integration.pytests/unit/test_run_parameters.py
Pattern 2: Mock Object Not Subscriptable
Symptom:
TypeError: 'Mock' object is not subscriptable
# in code like: result["data"]["value"]
Root Cause: The mock is returning a Mock object instead of actual data because:
- Mock methods aren't configured properly
- Missing
_get_tool_instancemethod on mock ToolUniverse - Shared mock instances between tests
Fix for Mock ToolUniverse:
@pytest.fixture
def mock_tool_universe():
mock_tu = Mock()
# Create SEPARATE mock tools (avoid shared state)
mock_tool1 = Mock()
mock_tool1.run = AsyncMock(return_value={"data": {"result": "success"}})
mock_tool2 = Mock()
mock_tool2.run = AsyncMock(return_value={"data": {"result": "success"}})
# Use real dict (not mock)
mock_tu.all_tool_dict = {"TestTool": mock_tool1, "OtherTool": mock_tool2}
# Add _get_tool_instance method (TaskManager needs this!)
def get_tool_instance(tool_name, cache=True):
return mock_tu.all_tool_dict.get(tool_name)
mock_tu._get_tool_instance = get_tool_instance
return mock_tu
Fix for Async Tool Mocks:
# WRONG:
mock_tool.run = async_function # Direct assignment
# CORRECT:
mock_tool.run = AsyncMock(side_effect=async_function) # Proper async mock
Files Affected Today:
tests/test_task_manager.py
Pattern 3: Linting Errors (F841, E731)
Symptom:
F841 Local variable assigned but never used
E731 Do not assign a lambda expression, use a def
Common F841 Fixes:
# Unused variable
result = some_function() # ❌ F841 if not used
# Fix 1: Use underscore
_ = some_function() # ✅ Indicates intentionally unused
# Fix 2: Actually use it
result = some_function()
assert result is not None # ✅ Now it's used
Common E731 Fixes:
# Lambda assignment
get_value = lambda x: x * 2 # ❌ E731
# Fix: Use def
def get_value(x): # ✅
return x * 2
Pattern 4: Temp Files Being Pushed to GitHub
Symptom:
User: "do not push temp folder into github!"
Root Cause:
Files were added to git using git mv before being added to .gitignore, so they're tracked even though .gitignore lists them.
Fix:
# 1. Remove from git tracking (keeps local files)
git rm -r --cached temp_docs_and_tests/
# 2. Verify .gitignore has the entry
grep "temp_docs_and_tests" .gitignore
# Should show: temp_docs_and_tests/
# 3. Commit the removal
git commit -m "Remove temp_docs_and_tests/ from git tracking"
# 4. Push
git push origin auto
# 5. Verify (local files exist, git doesn't track)
ls temp_docs_and_tests/ | wc -l # Should show files
git ls-files temp_docs_and_tests/ | wc -l # Should show 0
Prevention: Always add folders to .gitignore BEFORE creating/moving files:
echo "temp_docs_and_tests/" >> .gitignore
git add .gitignore
git commit -m "Add temp folder to gitignore"
Systematic Debugging Workflow
Step 1: Activate Pre-Commit Hook
pre-commit install
Step 2: Run Tests Locally
python -m pytest tests/ -x --tb=short -q 2>&1 | tail -50
Look for:
FAILED tests/...- Which test failed- Error message - KeyError, TypeError, AssertionError, etc.
- Line number - Where the failure occurred
Step 3: Reproduce the Specific Failure
python -m pytest tests/path/to/test.py::TestClass::test_method -xvs
Step 4: Read the Test File
# Read the failing test to understand what it's testing
cat tests/path/to/test.py | grep -A 20 "def test_method"
Step 5: Apply Pattern-Based Fix
- KeyError 'role' → Add
return_message=Trueand use.get() - Mock not subscriptable → Fix mock configuration
- F841/E731 → Fix linting issues
- Temp files pushed → Remove from git tracking
Step 6: Verify Fix Locally
python -m pytest tests/path/to/test.py -xvs
Should see: 1 passed
Step 7: Run Full Test Suite
python -m pytest tests/ -x --tb=short -q
Ensure no regressions were introduced.
Step 8: Commit with Pre-Commit Hook
git add <fixed_files>
git commit -m "Fix test: <brief description>"
The pre-commit hook will run automatically and check:
- ✅ Ruff linting
- ✅ Ruff formatting
- ✅ YAML/TOML validity
- ✅ Trailing whitespace
Step 9: Push to GitHub
git push origin auto
Quick Reference Commands
Pre-Commit
pre-commit install # Activate hooks
pre-commit run --all-files # Run manually on all files
pre-commit autoupdate # Update hook versions
Testing
# All tests
pytest tests/ -x --tb=short -q
# Specific test
pytest tests/test_file.py::TestClass::test_method -xvs
# With coverage
pytest tests/ --cov=src/tooluniverse --cov-report=term-missing
# Stop after N failures
pytest tests/ --maxfail=3
Git
# Check what will be committed
git status --short
# Unstage files
git restore --staged <file>
# Remove from tracking but keep local
git rm --cached <file>
# Show what changed in last commit
git show HEAD
# Amend last commit (use carefully!)
git commit --amend --no-edit
Common Mistakes to Avoid
❌ Don't: Push Without Running Tests
git add .
git commit -m "Fix"
git push # ❌ Might fail CI!
✅ Do: Test Before Push
python -m pytest tests/ -x --tb=short -q # Run tests first
git add <specific_files>
git commit -m "Fix test_something: add return_message=True"
git push
❌ Don't: Modify Multiple Unrelated Things
# Commit mixes test fixes with new features
git commit -m "Fix tests and add new feature" # ❌ Hard to review
✅ Do: Commit Fixes Separately
git add tests/test_cache.py
git commit -m "Fix test_cache: add return_message=True"
git add src/feature.py
git commit -m "Add new feature X"
❌ Don't: Use git add . Blindly
git add . # ❌ Might include temp files, logs, etc.
✅ Do: Add Specific Files
git add tests/test_file.py src/module.py
# Or review with: git add -p
What to Push and What NOT to Push
✅ ALWAYS Push (Production Code)
Source Code:
src/tooluniverse/*.py- Core library codetests/*.py- Test filesexamples/*.py- Example scriptsskills/*/- Skill files (usegit add -fif in .gitignore)
Configuration:
pyproject.toml- Project configurationsetup.py- Package setup.pre-commit-config.yaml- Pre-commit configurationpytest.ini- Test configuration.gitignore- Git ignore rules
Documentation:
README.md- Main documentationdocs/**/*.rst- Sphinx documentationdocs/**/*.md- Markdown documentation (NOT temp docs!)CHANGELOG.md- Version historyLICENSE- License file
❌ NEVER Push (Temporary/Local Files)
Temp Folders:
temp_docs_and_tests/- Temporary documentation and test filestemp/,tmp/- Any temporary directories.temp/,._temp/- Hidden temp directories
Build Artifacts:
build/,dist/- Package build outputs*.egg-info/- Python package metadata__pycache__/- Python bytecode cache*.pyc,*.pyo- Compiled Python files
IDE and Editor Files:
.vscode/- VS Code settings (usually).idea/- PyCharm settings*.swp,*.swo- Vim swap files.DS_Store- macOS finder metadata
Logs and Data:
*.log- Log files*.sqlite,*.db- Database files (unless example data)cache/- Cache directories*.tmp- Temporary files
Environment Files:
.env- Environment variables (contains secrets!).env.local- Local environment configvenv/,env/- Virtual environments.python-version- Local Python version
Personal Configuration:
.claude/- Claude Code configuration*.local- Personal config files
⚠️ MAYBE Push (Check First)
Skills:
skills/devtu-*/- Development skills (check.gitignore)- If creating new devtu skill: use
git add -f skills/devtu-skillname/
Data Files:
- Small example data: ✅ Push
- Large datasets: ❌ Don't push (use Git LFS or external storage)
Configuration:
.vscode/settings.json- Only if team shares settingsMakefile- ✅ Push if used for automation
How to Check What Will Be Pushed
Before committing:
# See what files are staged
git status --short
# See detailed diff of what will be committed
git diff --cached
# Check if a file is ignored
git check-ignore -v filename
After committing, before pushing:
# See what commits will be pushed
git log origin/auto..HEAD
# See files changed in commits that will be pushed
git diff origin/auto..HEAD --name-status
Emergency: Accidentally Staged Wrong Files
Unstage specific file:
git restore --staged filename
Unstage all files:
git restore --staged .
Undo last commit (keeps changes):
git reset --soft HEAD~1
Remove file from git but keep local:
git rm --cached filename
Verifying .gitignore Works
Check if files are ignored:
# Check specific file
git check-ignore -v temp_docs_and_tests/somefile.md
# Should output the .gitignore rule that matches
# Example: .gitignore:152:temp_docs_and_tests/
List all tracked files (should NOT include temp):
git ls-files | grep temp_docs_and_tests
# Should return nothing (0 lines)
List all ignored files:
git status --ignored
Success Checklist
Before pushing to GitHub, ensure:
- Pre-commit hook is installed (
pre-commit install) - All tests pass locally (
pytest tests/ -x) - No linting errors (pre-commit runs on commit)
- Temp files are in .gitignore and not tracked
- Commit message is clear and descriptive
- Only relevant files are committed (not temp/logs)
- Changes are on the correct branch
Example Session
User: "GitHub CI is failing with test errors"
Your Response:
I'll help you fix the CI failures. Let me follow the systematic approach:
**Step 1: Activate pre-commit hooks**
```bash
pre-commit install
Step 2: Run tests locally to identify failures
python -m pytest tests/ -x --tb=short -q 2>&1 | tail -50
[Wait for results and analyze the failure pattern]
Step 3: Fix the specific failure [Apply pattern-based fix - e.g., add return_message=True for KeyError 'role']
Step 4: Verify the fix
python -m pytest tests/test_file.py -xvs
Step 5: Run full test suite
python -m pytest tests/ -x --tb=short -q
Step 6: Commit and push
git add tests/test_file.py
git commit -m "Fix test: add return_message=True"
git push origin auto
All tests should now pass in CI! ✅
## Files Changed Today (Real Examples)
### Commit 1: fca22e2 - Fix test_task_manager.py
**Issue:** Mock not subscriptable
**Fix:**
- Create separate mock tool instances
- Add `_get_tool_instance` method
- Use `AsyncMock(side_effect=...)` for async tools
### Commit 2: 890cb11 - Fix test_tooluniverse_cache_integration.py
**Issue:** KeyError: 'role'
**Fix:**
- Add `return_message=True`
- Change `msg["role"]` to `msg.get("role")`
### Commit 3: f775c6f - Fix test_run_parameters.py
**Issue:** KeyError: 'role' in batch test
**Fix:**
- Add `return_message=True`
- Use `.get()` for safe access
### Commit 4: 1d9222a - Remove temp_docs_and_tests/
**Issue:** Temp folder being pushed to GitHub
**Fix:**
- `git rm -r --cached temp_docs_and_tests/`
- Commit removal (keeps local files)
## Memory Markers
**When you see these patterns:**
- `KeyError: 'role'` → Missing `return_message=True`
- `Mock object is not subscriptable` → Fix mock configuration
- `F841` or `E731` → Linting errors to fix
- User says "don't push temp folder" → Check `git ls-files` and remove from tracking
**Always remember:**
1. Pre-commit hook MUST be active
2. Test locally BEFORE pushing
3. Fix one test at a time
4. Verify full suite before pushing
5. Check that temp files aren't tracked
## End of Instructions
Follow this systematic approach every time there are CI failures or test issues. The patterns are proven to work - we fixed 40 tests today using these exact techniques!