CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python-coveralls

Python interface to coveralls.io API for uploading code coverage results

Pending
Overview
Eval results
Files

repository-integration.mddocs/

Repository Integration

The repository integration module provides version control system support for extracting git and mercurial repository information. It automatically detects the VCS type and extracts commit details, branch information, and remote URLs required by the coveralls.io API.

Capabilities

Auto-Detection and Information Extraction

Automatically detects repository type and extracts comprehensive repository information.

def repo(root):
    """
    Auto-detect repository type and extract information.
    
    Args:
        root (str): Path to repository root directory
    
    Returns:
        dict | None: Repository information dictionary or None if no VCS detected
        
    Detection Logic:
        1. Check for .git directory (Git repository)
        2. Check for .hg directory (Mercurial repository)  
        3. Return None if neither found
        
    Repository Info Structure:
        {
            "head": {
                "id": str,              # Commit hash/ID
                "author_name": str,     # Author name
                "author_email": str,    # Author email
                "committer_name": str,  # Committer name  
                "committer_email": str, # Committer email
                "message": str,         # Commit message
            },
            "branch": str,              # Current branch name
            "remotes": [                # Remote repositories
                {
                    "name": str,        # Remote name (e.g., "origin")
                    "url": str,         # Remote URL
                }
            ]
        }
    """

Git Repository Integration

Extracts comprehensive information from Git repositories including commit details, branch, and remote configuration.

def gitrepo(root):
    """
    Extract information from Git repository.
    
    Args:
        root (str): Path to Git repository root
    
    Returns:
        dict: Git repository information
        
    Extracted Information:
        - Latest commit details (hash, author, committer, message)
        - Current branch (with CI environment variable fallbacks)
        - All configured remotes with fetch URLs
        
    Branch Detection Priority:
        1. CIRCLE_BRANCH environment variable (Circle CI)
        2. TRAVIS_BRANCH environment variable (Travis CI)  
        3. git rev-parse --abbrev-ref HEAD (local branch)
        
    Commands Used:
        - git log -1 --pretty=format:[format] (commit info)
        - git rev-parse --abbrev-ref HEAD (branch name)
        - git remote -v (remote URLs)
    """

Mercurial Repository Integration

Extracts information from Mercurial repositories with similar structure to Git integration.

def hgrepo(root):
    """
    Extract information from Mercurial repository.
    
    Args:
        root (str): Path to Mercurial repository root
    
    Returns:
        dict: Mercurial repository information
        
    Extracted Information:
        - Latest changeset details (hash, author, message)
        - Current branch (with CI environment variable fallbacks)
        - Configured paths (remotes)
        
    Branch Detection Priority:
        1. CIRCLE_BRANCH environment variable (Circle CI)
        2. TRAVIS_BRANCH environment variable (Travis CI)
        3. hg branch (local branch)
        
    Commands Used:
        - hg log -l 1 --template=[template] (changeset info)
        - hg branch (branch name)
        - hg paths (remote URLs)
    """

Data Structures and Formats

Git Log Format

# Internal format string for git log command
FORMAT = '%n'.join(['%H', '%aN', '%ae', '%cN', '%ce', '%s'])
    # %H: Commit hash
    # %aN: Author name  
    # %ae: Author email
    # %cN: Committer name
    # %ce: Committer email
    # %s: Subject (commit message)

Mercurial Log Template

# Template for mercurial log command
HGLOG = """{node}
{author|person}
{author|email}
{author|person}  
{author|email}
{desc}"""
    # {node}: Changeset hash
    # {author|person}: Author name
    # {author|email}: Author email  
    # {desc}: Description (commit message)

Usage Examples

Basic Repository Detection

from coveralls.repository import repo

# Auto-detect and extract repository info
repo_info = repo('/path/to/project')

if repo_info:
    print(f"Repository detected: {repo_info['head']['id'][:8]}")
    print(f"Branch: {repo_info['branch']}")
    print(f"Author: {repo_info['head']['author_name']}")
    
    for remote in repo_info['remotes']:
        print(f"Remote {remote['name']}: {remote['url']}")
else:
    print("No version control system detected")

Git-Specific Integration

from coveralls.repository import gitrepo
import os

# Direct Git repository processing
try:
    git_info = gitrepo('/path/to/git/repo')
    
    # Access commit information
    commit = git_info['head']
    print(f"Commit: {commit['id']}")
    print(f"Author: {commit['author_name']} <{commit['author_email']}>")
    print(f"Message: {commit['message']}")
    
    # Branch information (with CI detection)
    print(f"Branch: {git_info['branch']}")
    
    # Remote repositories
    for remote in git_info['remotes']:
        print(f"{remote['name']}: {remote['url']}")
        
except subprocess.CalledProcessError as e:
    print(f"Git command failed: {e}")
except Exception as e:
    print(f"Repository processing error: {e}")

Mercurial Integration

from coveralls.repository import hgrepo

# Direct Mercurial repository processing
try:
    hg_info = hgrepo('/path/to/hg/repo')
    
    # Access changeset information
    head = hg_info['head']
    print(f"Changeset: {head['id']}")
    print(f"Author: {head['author_name']} <{head['author_email']}>")
    print(f"Description: {head['message']}")
    
    # Branch and remotes
    print(f"Branch: {hg_info['branch']}")
    for remote in hg_info['remotes']:
        print(f"{remote['name']}: {remote['url']}")
        
except subprocess.CalledProcessError as e:
    print(f"Mercurial command failed: {e}")
except Exception as e:
    print(f"Repository processing error: {e}")

CI Environment Integration

Environment Variable Detection

The module automatically detects CI environments and uses their branch information:

# Branch detection priority (in gitrepo and hgrepo)
branch_sources = [
    "CIRCLE_BRANCH",    # Circle CI
    "TRAVIS_BRANCH",    # Travis CI  
    # Local VCS command as fallback
]

# Example CI integration
import os

# Circle CI
if 'CIRCLE_BRANCH' in os.environ:
    branch = os.environ['CIRCLE_BRANCH']
    
# Travis CI  
elif 'TRAVIS_BRANCH' in os.environ:
    branch = os.environ['TRAVIS_BRANCH']
    
# Local detection
else:
    branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])

CI Service Configuration

# Travis CI - automatic detection
language: python
script: pytest --cov=mypackage
after_success: coveralls

# Circle CI - manual branch setting
version: 2
jobs:
  build:
    environment:
      CIRCLE_BRANCH: ${CIRCLE_BRANCH}
    steps:
      - run: pytest --cov=mypackage
      - run: coveralls

# GitHub Actions - manual configuration
env:
  GITHUB_BRANCH: ${GITHUB_REF#refs/heads/}
run: |
  pytest --cov=mypackage
  TRAVIS_BRANCH=$GITHUB_BRANCH coveralls

Error Handling and Edge Cases

Repository Detection Failures

from coveralls.repository import repo

# Handle missing VCS
repo_info = repo('/path/without/vcs')
if repo_info is None:
    # No git or mercurial repository found
    # Use empty dict or skip repository info
    repo_info = {}

Command Execution Errors

from coveralls.repository import gitrepo
import subprocess

try:
    git_info = gitrepo('/path/to/repo')
except subprocess.CalledProcessError as e:
    # Git command failed (corrupted repo, permissions, etc.)
    print(f"Git error: {e}")
    git_info = None
except FileNotFoundError:
    # Git not installed or not in PATH
    print("Git not found")
    git_info = None

Malformed Repository Data

# Robust repository info processing
def safe_repo_info(repo_path):
    try:
        info = repo(repo_path)
        
        # Validate required fields
        if info and 'head' in info and 'id' in info['head']:
            return info
        else:
            return None
            
    except Exception as e:
        print(f"Repository info extraction failed: {e}")
        return None

# Usage with fallback
repo_info = safe_repo_info('/path/to/project') or {}

Integration with Main Workflow

Conditional Repository Integration

# From main workflow (wear function)
def wear(args=None):
    # ... other setup ...
    
    # Extract repository info only if not disabled
    if not args.nogit:
        git_info = repo(args.base_dir)
        if git_info is None:
            git_info = {}  # Empty dict for no VCS
    else:
        git_info = {}  # Skip repository info entirely
    
    # ... continue with API submission ...

Directory Context Management

# Repository functions change working directory temporarily
import os

original_dir = os.getcwd()
try:
    repo_info = gitrepo('/path/to/repo')  # Changes to repo directory internally
finally:
    os.chdir(original_dir)  # Always restore original directory

Best Practices

Working Directory Management

The repository functions change the current working directory temporarily. Ensure proper restoration:

import os
from coveralls.repository import repo

# Save current directory
original_cwd = os.getcwd()

try:
    # Extract repository info (may change directory)
    repo_info = repo('/path/to/project')
finally:
    # Always restore original directory
    os.chdir(original_cwd)

Error Resilience

# Robust repository integration
def get_repo_info(project_path, skip_git=False):
    if skip_git:
        return {}
    
    try:
        return repo(project_path) or {}
    except Exception as e:
        logging.warning(f"Repository info extraction failed: {e}")
        return {}

Install with Tessl CLI

npx tessl i tessl/pypi-python-coveralls

docs

api-communication.md

coverage-processing.md

index.md

main-workflow.md

repository-integration.md

tile.json