Python interface to coveralls.io API for uploading code coverage results
—
The API communication module handles HTTP interaction with the coveralls.io API, including request formatting, authentication, payload construction, and response processing. It provides functions for building JSON payloads and submitting coverage data via HTTP POST requests.
Sends coverage data to the coveralls.io API endpoint with proper authentication and formatting.
def post(url, repo_token, service_job_id, service_name, git, source_files, parallel, skip_ssl_verify=False):
"""
Submit coverage data to coveralls.io API via HTTP POST.
Args:
url (str): coveralls.io API endpoint URL (typically 'https://coveralls.io/api/v1/jobs')
repo_token (str): Repository authentication token from coveralls.io
service_job_id (str): CI service job identifier (e.g., Travis job ID)
service_name (str): CI service name (e.g., 'travis-ci', 'circle-ci')
git (dict): Git repository information (commit, branch, remotes)
source_files (list[dict]): Coverage data for source files
parallel (bool): True if this is a parallel build
skip_ssl_verify (bool): If True, skip SSL certificate verification
Returns:
requests.Response: HTTP response object from coveralls.io API
Response Structure:
- status_code: HTTP status (200 for success)
- json(): Response data including success/error messages
- text: Raw response content
"""Builds the JSON payload structure required by the coveralls.io API format.
def build_file(repo_token, service_job_id, service_name, git, source_files, parallel):
"""
Build JSON payload for coveralls.io API request.
Args:
repo_token (str): Repository authentication token
service_job_id (str): CI service job identifier
service_name (str): CI service name
git (dict): Git repository information
source_files (list[dict]): Source files with coverage data
parallel (bool): Parallel build flag
Returns:
StringIO: JSON data formatted as file-like object for HTTP upload
Payload Structure:
{
"service_job_id": str,
"service_name": str,
"git": {...},
"source_files": [...],
"repo_token": str (optional - only if provided),
"parallel": true (optional - only if true)
}
"""# Core required fields
payload_structure = {
"service_job_id": str, # CI job identifier
"service_name": str, # CI service name
"git": dict, # Repository information
"source_files": list, # Coverage data
}
# Optional fields
optional_fields = {
"repo_token": str, # Authentication token (required for private repos)
"parallel": bool, # Parallel build indicator
}git_info_structure = {
"head": {
"id": str, # Commit SHA
"author_name": str, # Commit author name
"author_email": str, # Commit author email
"committer_name": str, # Committer name
"committer_email": str, # Committer email
"message": str, # Commit message
},
"branch": str, # Current branch name
"remotes": [
{
"name": str, # Remote name (e.g., "origin")
"url": str, # Remote URL
}
]
}source_file_structure = {
"name": str, # Relative file path
"source": str, # Complete file content
"coverage": list[int | None], # Line-by-line coverage array
}
# Coverage array values:
# None: Non-executable line (comments, blank lines)
# 0: Executable line that was not hit (missed)
# 1: Executable line that was hit (covered)from coveralls.api import post, build_file
# Prepare data
repo_token = "your_repo_token"
service_job_id = "12345"
service_name = "travis-ci"
git_info = {...} # From repository module
source_files = [...] # From coverage processing
# Submit to coveralls.io
response = post(
url="https://coveralls.io/api/v1/jobs",
repo_token=repo_token,
service_job_id=service_job_id,
service_name=service_name,
git=git_info,
source_files=source_files,
parallel=False,
skip_ssl_verify=False
)
# Check response
if response.status_code == 200:
result = response.json()
if 'error' in result:
print(f"API Error: {result}")
else:
print("Coverage uploaded successfully")
else:
print(f"HTTP Error: {response.status_code}")from coveralls.api import build_file
import json
# Build payload file object
json_file = build_file(
repo_token="repo_token_here",
service_job_id="travis_job_123",
service_name="travis-ci",
git={
"head": {
"id": "abc123",
"author_name": "Developer",
"author_email": "dev@example.com",
"committer_name": "Developer",
"committer_email": "dev@example.com",
"message": "Add new feature"
},
"branch": "main",
"remotes": [{"name": "origin", "url": "https://github.com/user/repo.git"}]
},
source_files=[
{
"name": "src/module.py",
"source": "def hello():\n return 'world'",
"coverage": [1, 1]
}
],
parallel=True
)
# Access JSON content
json_content = json_file.getvalue()
data = json.loads(json_content)from coveralls.api import post
import logging
# Enable request logging for debugging
logging.basicConfig(level=logging.DEBUG)
try:
response = post(
url="https://coveralls.io/api/v1/jobs",
repo_token=repo_token,
service_job_id=service_job_id,
service_name=service_name,
git=git_info,
source_files=source_files,
parallel=parallel,
skip_ssl_verify=skip_ssl_verify
)
# Log response details
print(f"Status Code: {response.status_code}")
print(f"Response Headers: {response.headers}")
print(f"Response Content: {response.text}")
# Parse JSON response
if response.headers.get('content-type', '').startswith('application/json'):
result = response.json()
if 'error' in result:
print(f"Coveralls API Error: {result['error']}")
if 'message' in result:
print(f"Error Message: {result['message']}")
else:
print("Upload successful!")
if 'url' in result:
print(f"Coverage Report URL: {result['url']}")
except requests.exceptions.RequestException as e:
print(f"HTTP Request Error: {e}")
except json.JSONDecodeError as e:
print(f"JSON Parse Error: {e}")
except Exception as e:
print(f"Unexpected Error: {e}")# Skip SSL verification for corporate environments
response = post(
url="https://coveralls.io/api/v1/jobs",
repo_token=repo_token,
service_job_id=service_job_id,
service_name=service_name,
git=git_info,
source_files=source_files,
parallel=False,
skip_ssl_verify=True # Skip SSL verification
)
# Custom API endpoint (for enterprise installations)
response = post(
url="https://coveralls.company.com/api/v1/jobs",
repo_token=repo_token,
service_job_id=service_job_id,
service_name=service_name,
git=git_info,
source_files=source_files,
parallel=False
)# For private repositories or when not using supported CI services
repo_token = "your_coveralls_repo_token"
# Token is included in payload automatically
response = post(
url="https://coveralls.io/api/v1/jobs",
repo_token=repo_token, # Included in JSON payload
service_job_id=service_job_id,
service_name=service_name,
git=git_info,
source_files=source_files,
parallel=False
)# For supported CI services (Travis, Circle, etc.)
# No repo_token needed if properly configured
response = post(
url="https://coveralls.io/api/v1/jobs",
repo_token="", # Empty for public repos with CI integration
service_job_id=os.environ.get('TRAVIS_JOB_ID'),
service_name="travis-ci",
git=git_info,
source_files=source_files,
parallel=False
)# Successful upload response
success_response = {
"message": "Job #123.1",
"url": "https://coveralls.io/jobs/12345"
}# Error response examples
error_responses = [
{"error": "Couldn't find a repository matching this job."},
{"error": "Build processing error.", "message": "Details about the error"},
{"error": "Invalid repo token."}
]Install with Tessl CLI
npx tessl i tessl/pypi-python-coveralls