API Reference
Complete API reference for Review Bot Automator.
Core Classes
ConflictResolver
Main class for conflict resolution operations.
from pr_conflict_resolver import ConflictResolver
from pr_conflict_resolver.config import PresetConfig
resolver = ConflictResolver(config=PresetConfig.BALANCED)
Methods
__init__(config: dict[str, Any] | None = None) -> None
Initialize the conflict resolver with optional configuration.
Parameters:
config(dict, optional): Configuration dictionary for customizing resolver behavior
Example:
resolver = ConflictResolver(config={
"semantic_merging": True,
"priority_system": True,
})
detect_file_type(path: str) -> FileType
Determine file type from path extension.
Parameters:
path(str): File path
Returns:
FileType: Detected file type enum
Example:
file_type = resolver.detect_file_type("config.json")
# Returns: FileType.JSON
generate_fingerprint(path: str, start: int, end: int, content: str) -> str
Create unique fingerprint for a change.
Parameters:
path(str): File pathstart(int): Start line numberend(int): End line numbercontent(str): Change content
Returns:
str: 16-character hex fingerprint
Example:
fingerprint = resolver.generate_fingerprint(
"file.py", 10, 15, "def new_function():"
)
extract_changes_from_comments(comments: list[dict[str, Any]]) -> list[Change]
Extract Change objects from GitHub comment data.
Parameters:
comments(list[dict]): GitHub comment objects
Returns:
list[Change]: List of extracted Change objects
analyze_conflicts(owner: str, repo: str, pr_number: int) -> list[Conflict]
Analyze conflicts in a pull request without applying changes.
Parameters:
owner(str): Repository ownerrepo(str): Repository namepr_number(int): Pull request number
Returns:
list[Conflict]: List of detected conflicts
Example:
conflicts = resolver.analyze_conflicts("myorg", "myrepo", 123)
for conflict in conflicts:
print(f"Conflict in {conflict.file_path}: {conflict.conflict_type}")
resolve_pr_conflicts(owner: str, repo: str, pr_number: int, mode: ApplicationMode = ApplicationMode.ALL, validate: bool = True, parallel: bool = False, max_workers: int = 4, enable_rollback: bool = True) -> ResolutionResult
Resolve all conflicts in a pull request and return results.
Parameters:
owner(str): Repository ownerrepo(str): Repository namepr_number(int): Pull request numbermode(ApplicationMode, optional): Application mode (default: ALL)ApplicationMode.ALL: Apply both conflicting and non-conflicting changesApplicationMode.CONFLICTS_ONLY: Apply only conflicting changesApplicationMode.NON_CONFLICTS_ONLY: Apply only non-conflicting changesApplicationMode.DRY_RUN: Analyze without applying
validate(bool, optional): Enable pre-application validation (default: True)parallel(bool, optional): Enable parallel processing (default: False)max_workers(int, optional): Number of parallel workers (default: 4)enable_rollback(bool, optional): Enable automatic rollback on failure (default: True)
Returns:
ResolutionResult: Complete resolution results with counts and details
Example:
from pr_conflict_resolver.config.runtime_config import ApplicationMode
# Apply only conflicting changes with rollback
results = resolver.resolve_pr_conflicts(
"myorg", "myrepo", 123,
mode=ApplicationMode.CONFLICTS_ONLY,
enable_rollback=True
)
# Parallel processing for large PRs
results = resolver.resolve_pr_conflicts(
"myorg", "myrepo", 456,
parallel=True,
max_workers=8
)
print(f"Applied: {results.applied_count}")
print(f"Conflicts: {results.conflict_count}")
print(f"Success rate: {results.success_rate}%")
apply_changes(changes: list[Change], validate: bool = True, parallel: bool = False, max_workers: int = 4) -> tuple[list[Change], list[Change], list[tuple[Change, str]]]
Apply changes to files with optional validation and parallel processing.
Parameters:
changes(list[Change]): List of changes to applyvalidate(bool, optional): Validate changes before applying (default: True)parallel(bool, optional): Process files in parallel (default: False)max_workers(int, optional): Number of parallel workers (default: 4)
Returns:
tuple: (applied_changes, skipped_changes, failed_changes_with_errors)
Example:
applied, skipped, failed = resolver.apply_changes(
changes,
validate=True,
parallel=True,
max_workers=8
)
for change in applied:
print(f"Applied: {change.path}:{change.start_line}")
for change, error in failed:
print(f"Failed {change.path}: {error}")
apply_changes_with_rollback(changes: list[Change], enable_rollback: bool = True, parallel: bool = False, max_workers: int = 4) -> tuple[int, int, int]
Apply changes with automatic rollback on failure.
Parameters:
changes(list[Change]): List of changes to applyenable_rollback(bool, optional): Enable rollback (default: True)parallel(bool, optional): Process files in parallel (default: False)max_workers(int, optional): Number of parallel workers (default: 4)
Returns:
tuple[int, int, int]: (applied_count, skipped_count, failed_count)
Example:
applied_count, skipped_count, failed_count = resolver.apply_changes_with_rollback(
changes,
enable_rollback=True,
parallel=True,
max_workers=8
)
print(f"Applied: {applied_count}, Skipped: {skipped_count}, Failed: {failed_count}")
separate_changes_by_conflict_status(changes: list[Change]) -> tuple[list[Change], list[Change]]
Separate changes into conflicting and non-conflicting groups.
Parameters:
changes(list[Change]): List of changes to separate
Returns:
tuple[list[Change], list[Change]]: (conflicting_changes, non_conflicting_changes)
Example:
conflicting, non_conflicting = resolver.separate_changes_by_conflict_status(changes)
print(f"Conflicting: {len(conflicting)}")
print(f"Non-conflicting: {len(non_conflicting)}")
RollbackManager
Manages git-based rollback checkpoints for safe change application.
from pr_conflict_resolver.core.rollback import RollbackManager
rollback_manager = RollbackManager(workspace_root="/path/to/repo")
Methods
__init__(workspace_root: Path | str) -> None
Initialize the rollback manager.
Parameters:
workspace_root(Path | str): Path to git repository root
create_checkpoint() -> str
Create a rollback checkpoint using git stash.
Returns:
str: Checkpoint identifier
Example:
checkpoint_id = rollback_manager.create_checkpoint()
print(f"Created checkpoint: {checkpoint_id}")
rollback(checkpoint_id: str) -> bool
Restore from a checkpoint.
Parameters:
checkpoint_id(str): Checkpoint identifier to restore
Returns:
bool: True if rollback successful, False otherwise
Example:
success = rollback_manager.rollback(checkpoint_id)
if success:
print("Rollback successful")
else:
print("Rollback failed")
Context Manager Usage
Use as a context manager for automatic rollback on exception:
with RollbackManager(workspace_root="/path/to/repo") as rollback:
# Apply changes here
# Automatically rolls back if exception occurs
apply_changes(changes)
# Cleanup happens automatically
RuntimeConfig
Runtime configuration with multiple source support (defaults, file, env, CLI).
from pr_conflict_resolver.config.runtime_config import RuntimeConfig, ApplicationMode
# Load from defaults
config = RuntimeConfig.from_defaults()
# Load from file
config = RuntimeConfig.from_file("config.yaml")
# Load from environment variables
config = RuntimeConfig.from_env()
# Use preset configurations
config = RuntimeConfig.from_conservative()
config = RuntimeConfig.from_balanced()
config = RuntimeConfig.from_aggressive()
config = RuntimeConfig.from_semantic()
Attributes
mode(ApplicationMode): Application modeenable_rollback(bool): Enable automatic rollbackvalidate_before_apply(bool): Enable pre-application validationparallel_processing(bool): Enable parallel processingmax_workers(int): Number of parallel workerslog_level(str): Logging levellog_file(str | None): Log file path
Class Methods
from_defaults() -> RuntimeConfig
Create configuration with default values.
Returns:
RuntimeConfig: Configuration with defaults
from_file(file_path: Path | str) -> RuntimeConfig
Load configuration from YAML or TOML file.
Parameters:
file_path(Path | str): Path to configuration file
Returns:
RuntimeConfig: Loaded configuration
Example:
config = RuntimeConfig.from_file("config.yaml")
from_env() -> RuntimeConfig
Load configuration from environment variables (CR_* prefix).
Returns:
RuntimeConfig: Configuration from environment
Example:
# Set environment: CR_MODE=conflicts-only, CR_PARALLEL=true
config = RuntimeConfig.from_env()
from_conservative() -> RuntimeConfig
Create conservative preset configuration.
Returns:
RuntimeConfig: Conservative configuration
from_balanced() -> RuntimeConfig
Create balanced preset configuration (default).
Returns:
RuntimeConfig: Balanced configuration
from_aggressive() -> RuntimeConfig
Create aggressive preset configuration.
Returns:
RuntimeConfig: Aggressive configuration
from_semantic() -> RuntimeConfig
Create semantic preset configuration.
Returns:
RuntimeConfig: Semantic configuration
Instance Methods
merge_with_cli(**cli_overrides) -> RuntimeConfig
Merge configuration with CLI overrides.
Parameters:
**cli_overrides: CLI flag overrides (mode, enable_rollback, etc.)
Returns:
RuntimeConfig: New configuration with CLI overrides applied
Example:
config = RuntimeConfig.from_file("config.yaml")
config = config.merge_with_cli(
mode="conflicts-only",
parallel_processing=True,
max_workers=8
)
ApplicationMode
Enumeration of application modes.
from pr_conflict_resolver.config.runtime_config import ApplicationMode
ApplicationMode.ALL # Apply both conflicting and non-conflicting changes (default)
ApplicationMode.CONFLICTS_ONLY # Apply only conflicting changes
ApplicationMode.NON_CONFLICTS_ONLY # Apply only non-conflicting changes
ApplicationMode.DRY_RUN # Analyze without applying changes
Usage:
from pr_conflict_resolver import ConflictResolver
from pr_conflict_resolver.config.runtime_config import ApplicationMode
resolver = ConflictResolver()
results = resolver.resolve_pr_conflicts(
"myorg", "myrepo", 123,
mode=ApplicationMode.CONFLICTS_ONLY
)
Data Models
FileType
Enumeration of supported file types.
from pr_conflict_resolver.core.models import FileType
FileType.JSON # JSON files
FileType.YAML # YAML files
FileType.TOML # TOML files
FileType.PYTHON # Python files
FileType.TYPESCRIPT # TypeScript/JavaScript files
FileType.PLAINTEXT # Plain text files
Change
Represents a single change suggestion.
@dataclass
class Change:
path: str # File path
start_line: int # Start line (1-indexed)
end_line: int # End line (1-indexed)
content: str # Replacement content
metadata: dict[str, Any] # Additional metadata
fingerprint: str # Unique identifier
file_type: FileType # Detected file type
Example:
from pr_conflict_resolver.core.models import Change, FileType
change = Change(
path="config.json",
start_line=10,
end_line=12,
content='{"key": "value"}',
metadata={"author": "user", "url": "https://..."},
fingerprint="abc123def456",
file_type=FileType.JSON
)
Conflict
Represents a conflict between multiple changes.
@dataclass
class Conflict:
file_path: str # Path to conflicted file
line_range: tuple[int, int] # (start, end) lines
changes: list[Change] # Conflicting changes
conflict_type: str # Type of conflict
severity: str # Severity level
overlap_percentage: float # Overlap percentage
Example:
conflict = Conflict(
file_path="config.json",
line_range=(10, 20),
changes=[change1, change2],
conflict_type="exact",
severity="high",
overlap_percentage=100.0
)
Resolution
Represents a resolution for a conflict.
@dataclass
class Resolution:
strategy: str # Strategy used
applied_changes: list[Change] # Applied changes
skipped_changes: list[Change] # Skipped changes
success: bool # Success status
message: str # Result message
ResolutionResult
Complete results of conflict resolution.
@dataclass
class ResolutionResult:
applied_count: int # Number of changes applied
conflict_count: int # Total conflicts found
success_rate: float # Success rate percentage
resolutions: list[Resolution] # All resolutions
conflicts: list[Conflict] # All conflicts
Handlers
BaseHandler
Abstract base class for all file handlers.
from pr_conflict_resolver.handlers.base import BaseHandler
Abstract Methods
can_handle(file_path: str) -> bool
Check if handler can process a file type.
apply_change(path: str, content: str, start_line: int, end_line: int) -> bool
Apply a change to a file.
validate_change(path: str, content: str, start_line: int, end_line: int) -> tuple[bool, str]
Validate a change without applying it.
detect_conflicts(path: str, changes: list[Change]) -> list[Conflict]
Detect conflicts in file changes.
Utility Methods
backup_file(path: str) -> str
Create backup of a file.
restore_file(backup_path: str, original_path: str) -> bool
Restore a file from backup.
JsonHandler
Handler for JSON files.
from pr_conflict_resolver.handlers.json_handler import JsonHandler
handler = JsonHandler()
Extends BaseHandler with JSON-specific logic:
Duplicate key detection
Key-level merging
Structure validation
YamlHandler
Handler for YAML files.
from pr_conflict_resolver.handlers.yaml_handler import YamlHandler
handler = YamlHandler()
Extends BaseHandler with YAML-specific logic:
Comment preservation
Anchor/alias handling
Structure-aware merging
TomlHandler
Handler for TOML files.
from pr_conflict_resolver.handlers.toml_handler import TomlHandler
handler = TomlHandler()
Extends BaseHandler with TOML-specific logic:
Section merging
Comment preservation
Table array handling
Strategies
PriorityStrategy
Priority-based resolution strategy.
from pr_conflict_resolver.strategies.priority_strategy import PriorityStrategy
strategy = PriorityStrategy(config={
"priority_rules": {
"user_selections": 100,
"security_fixes": 90,
}
})
Methods
__init__(config: dict[str, Any] | None = None) -> None
Initialize strategy with configuration.
resolve(conflict: Conflict) -> Resolution
Resolve a conflict using priority rules.
Returns:
Resolution: Resolution with applied and skipped changes
Integration
GitHubCommentExtractor
Extract comments from GitHub PRs.
from pr_conflict_resolver.integrations.github import GitHubCommentExtractor
extractor = GitHubCommentExtractor(token="your_token")
Methods
__init__(token: str | None = None, base_url: str = "https://api.github.com") -> None
Initialize with optional token.
Parameters:
token(str, optional): GitHub personal access tokenbase_url(str): GitHub API base URL
fetch_pr_comments(owner: str, repo: str, pr_number: int) -> list[dict[str, Any]]
Fetch all comments for a PR.
Parameters:
owner(str): Repository ownerrepo(str): Repository namepr_number(int): PR number
Returns:
list[dict]: List of comment objects from GitHub API
Example:
comments = extractor.fetch_pr_comments("myorg", "myrepo", 123)
for comment in comments:
print(comment["body"])
Configuration
PresetConfig
Predefined configuration presets.
from pr_conflict_resolver.config import PresetConfig
# Available presets
PresetConfig.CONSERVATIVE
PresetConfig.BALANCED
PresetConfig.AGGRESSIVE
PresetConfig.SEMANTIC
Utilities
Text Utilities
from pr_conflict_resolver.utils.text import normalize_content
normalized = normalize_content("some content\n\nwith spaces")
normalize_content(content: str) -> str
Normalize whitespace in content for comparison.
CLI Command Reference
Analyze Command
pr-resolve analyze --pr <number> --owner <owner> --repo <repo> [--config <preset>]
Analyze conflicts in a PR without applying changes.
Apply Command
pr-resolve apply --pr <number> --owner <owner> --repo <repo> [--strategy <strategy>] [--dry-run]
Apply conflict resolutions to a PR.
Simulate Command
pr-resolve simulate --pr <number> --owner <owner> --repo <repo> [--config <preset>]
Simulate conflict resolution without applying changes.
Examples
Basic Usage
from pr_conflict_resolver import ConflictResolver
from pr_conflict_resolver.config import PresetConfig
# Initialize resolver
resolver = ConflictResolver(config=PresetConfig.BALANCED)
# Analyze conflicts
conflicts = resolver.analyze_conflicts("myorg", "myrepo", 123)
print(f"Found {len(conflicts)} conflicts")
# Resolve conflicts
results = resolver.resolve_pr_conflicts("myorg", "myrepo", 123)
print(f"Applied {results.applied_count} changes")
Custom Configuration
custom_config = {
"semantic_merging": True,
"priority_system": True,
"priority_rules": {
"user_selections": 100,
"security_fixes": 95,
}
}
resolver = ConflictResolver(config=custom_config)
Custom Handler
from pr_conflict_resolver.handlers.base import BaseHandler
from pr_conflict_resolver.core.models import Change, Conflict
class CustomHandler(BaseHandler):
def can_handle(self, file_path: str) -> bool:
return file_path.endswith(".custom")
def apply_change(self, path: str, content: str, start_line: int, end_line: int) -> bool:
# Implementation
return True
def validate_change(self, path: str, content: str, start_line: int, end_line: int) -> tuple[bool, str]:
# Implementation
return True, "Valid"
def detect_conflicts(self, path: str, changes: list[Change]) -> list[Conflict]:
# Implementation
return []
Custom Strategy
from pr_conflict_resolver.core.models import Conflict, Resolution
class CustomStrategy:
def resolve(self, conflict: Conflict) -> Resolution:
# Custom resolution logic
return Resolution(
strategy="custom",
applied_changes=[conflict.changes[0]],
skipped_changes=conflict.changes[1:],
success=True,
message="Custom resolution applied"
)
Error Handling
All operations may raise standard Python exceptions:
IOError: File operations failValueError: Invalid parameters or datarequests.RequestException: GitHub API errors
Type Hints
All functions are fully type-hinted for IDE support and type checking.
from typing import Any, List, Dict, Tuple
def example_function(data: Dict[str, Any]) -> List[str]:
"""Fully typed function."""
return []
See Also
Getting Started - Installation and basic usage
Configuration - Configuration options
Conflict Types - Understanding conflicts
Resolution Strategies - Strategy details