0
# Repository Integration
1
2
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.
3
4
## Capabilities
5
6
### Auto-Detection and Information Extraction
7
8
Automatically detects repository type and extracts comprehensive repository information.
9
10
```python { .api }
11
def repo(root):
12
"""
13
Auto-detect repository type and extract information.
14
15
Args:
16
root (str): Path to repository root directory
17
18
Returns:
19
dict | None: Repository information dictionary or None if no VCS detected
20
21
Detection Logic:
22
1. Check for .git directory (Git repository)
23
2. Check for .hg directory (Mercurial repository)
24
3. Return None if neither found
25
26
Repository Info Structure:
27
{
28
"head": {
29
"id": str, # Commit hash/ID
30
"author_name": str, # Author name
31
"author_email": str, # Author email
32
"committer_name": str, # Committer name
33
"committer_email": str, # Committer email
34
"message": str, # Commit message
35
},
36
"branch": str, # Current branch name
37
"remotes": [ # Remote repositories
38
{
39
"name": str, # Remote name (e.g., "origin")
40
"url": str, # Remote URL
41
}
42
]
43
}
44
"""
45
```
46
47
### Git Repository Integration
48
49
Extracts comprehensive information from Git repositories including commit details, branch, and remote configuration.
50
51
```python { .api }
52
def gitrepo(root):
53
"""
54
Extract information from Git repository.
55
56
Args:
57
root (str): Path to Git repository root
58
59
Returns:
60
dict: Git repository information
61
62
Extracted Information:
63
- Latest commit details (hash, author, committer, message)
64
- Current branch (with CI environment variable fallbacks)
65
- All configured remotes with fetch URLs
66
67
Branch Detection Priority:
68
1. CIRCLE_BRANCH environment variable (Circle CI)
69
2. TRAVIS_BRANCH environment variable (Travis CI)
70
3. git rev-parse --abbrev-ref HEAD (local branch)
71
72
Commands Used:
73
- git log -1 --pretty=format:[format] (commit info)
74
- git rev-parse --abbrev-ref HEAD (branch name)
75
- git remote -v (remote URLs)
76
"""
77
```
78
79
### Mercurial Repository Integration
80
81
Extracts information from Mercurial repositories with similar structure to Git integration.
82
83
```python { .api }
84
def hgrepo(root):
85
"""
86
Extract information from Mercurial repository.
87
88
Args:
89
root (str): Path to Mercurial repository root
90
91
Returns:
92
dict: Mercurial repository information
93
94
Extracted Information:
95
- Latest changeset details (hash, author, message)
96
- Current branch (with CI environment variable fallbacks)
97
- Configured paths (remotes)
98
99
Branch Detection Priority:
100
1. CIRCLE_BRANCH environment variable (Circle CI)
101
2. TRAVIS_BRANCH environment variable (Travis CI)
102
3. hg branch (local branch)
103
104
Commands Used:
105
- hg log -l 1 --template=[template] (changeset info)
106
- hg branch (branch name)
107
- hg paths (remote URLs)
108
"""
109
```
110
111
## Data Structures and Formats
112
113
### Git Log Format
114
115
```python { .api }
116
# Internal format string for git log command
117
FORMAT = '%n'.join(['%H', '%aN', '%ae', '%cN', '%ce', '%s'])
118
# %H: Commit hash
119
# %aN: Author name
120
# %ae: Author email
121
# %cN: Committer name
122
# %ce: Committer email
123
# %s: Subject (commit message)
124
```
125
126
### Mercurial Log Template
127
128
```python { .api }
129
# Template for mercurial log command
130
HGLOG = """{node}
131
{author|person}
132
{author|email}
133
{author|person}
134
{author|email}
135
{desc}"""
136
# {node}: Changeset hash
137
# {author|person}: Author name
138
# {author|email}: Author email
139
# {desc}: Description (commit message)
140
```
141
142
## Usage Examples
143
144
### Basic Repository Detection
145
146
```python
147
from coveralls.repository import repo
148
149
# Auto-detect and extract repository info
150
repo_info = repo('/path/to/project')
151
152
if repo_info:
153
print(f"Repository detected: {repo_info['head']['id'][:8]}")
154
print(f"Branch: {repo_info['branch']}")
155
print(f"Author: {repo_info['head']['author_name']}")
156
157
for remote in repo_info['remotes']:
158
print(f"Remote {remote['name']}: {remote['url']}")
159
else:
160
print("No version control system detected")
161
```
162
163
### Git-Specific Integration
164
165
```python
166
from coveralls.repository import gitrepo
167
import os
168
169
# Direct Git repository processing
170
try:
171
git_info = gitrepo('/path/to/git/repo')
172
173
# Access commit information
174
commit = git_info['head']
175
print(f"Commit: {commit['id']}")
176
print(f"Author: {commit['author_name']} <{commit['author_email']}>")
177
print(f"Message: {commit['message']}")
178
179
# Branch information (with CI detection)
180
print(f"Branch: {git_info['branch']}")
181
182
# Remote repositories
183
for remote in git_info['remotes']:
184
print(f"{remote['name']}: {remote['url']}")
185
186
except subprocess.CalledProcessError as e:
187
print(f"Git command failed: {e}")
188
except Exception as e:
189
print(f"Repository processing error: {e}")
190
```
191
192
### Mercurial Integration
193
194
```python
195
from coveralls.repository import hgrepo
196
197
# Direct Mercurial repository processing
198
try:
199
hg_info = hgrepo('/path/to/hg/repo')
200
201
# Access changeset information
202
head = hg_info['head']
203
print(f"Changeset: {head['id']}")
204
print(f"Author: {head['author_name']} <{head['author_email']}>")
205
print(f"Description: {head['message']}")
206
207
# Branch and remotes
208
print(f"Branch: {hg_info['branch']}")
209
for remote in hg_info['remotes']:
210
print(f"{remote['name']}: {remote['url']}")
211
212
except subprocess.CalledProcessError as e:
213
print(f"Mercurial command failed: {e}")
214
except Exception as e:
215
print(f"Repository processing error: {e}")
216
```
217
218
## CI Environment Integration
219
220
### Environment Variable Detection
221
222
The module automatically detects CI environments and uses their branch information:
223
224
```python { .api }
225
# Branch detection priority (in gitrepo and hgrepo)
226
branch_sources = [
227
"CIRCLE_BRANCH", # Circle CI
228
"TRAVIS_BRANCH", # Travis CI
229
# Local VCS command as fallback
230
]
231
232
# Example CI integration
233
import os
234
235
# Circle CI
236
if 'CIRCLE_BRANCH' in os.environ:
237
branch = os.environ['CIRCLE_BRANCH']
238
239
# Travis CI
240
elif 'TRAVIS_BRANCH' in os.environ:
241
branch = os.environ['TRAVIS_BRANCH']
242
243
# Local detection
244
else:
245
branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
246
```
247
248
### CI Service Configuration
249
250
```bash
251
# Travis CI - automatic detection
252
language: python
253
script: pytest --cov=mypackage
254
after_success: coveralls
255
256
# Circle CI - manual branch setting
257
version: 2
258
jobs:
259
build:
260
environment:
261
CIRCLE_BRANCH: ${CIRCLE_BRANCH}
262
steps:
263
- run: pytest --cov=mypackage
264
- run: coveralls
265
266
# GitHub Actions - manual configuration
267
env:
268
GITHUB_BRANCH: ${GITHUB_REF#refs/heads/}
269
run: |
270
pytest --cov=mypackage
271
TRAVIS_BRANCH=$GITHUB_BRANCH coveralls
272
```
273
274
## Error Handling and Edge Cases
275
276
### Repository Detection Failures
277
278
```python
279
from coveralls.repository import repo
280
281
# Handle missing VCS
282
repo_info = repo('/path/without/vcs')
283
if repo_info is None:
284
# No git or mercurial repository found
285
# Use empty dict or skip repository info
286
repo_info = {}
287
```
288
289
### Command Execution Errors
290
291
```python
292
from coveralls.repository import gitrepo
293
import subprocess
294
295
try:
296
git_info = gitrepo('/path/to/repo')
297
except subprocess.CalledProcessError as e:
298
# Git command failed (corrupted repo, permissions, etc.)
299
print(f"Git error: {e}")
300
git_info = None
301
except FileNotFoundError:
302
# Git not installed or not in PATH
303
print("Git not found")
304
git_info = None
305
```
306
307
### Malformed Repository Data
308
309
```python
310
# Robust repository info processing
311
def safe_repo_info(repo_path):
312
try:
313
info = repo(repo_path)
314
315
# Validate required fields
316
if info and 'head' in info and 'id' in info['head']:
317
return info
318
else:
319
return None
320
321
except Exception as e:
322
print(f"Repository info extraction failed: {e}")
323
return None
324
325
# Usage with fallback
326
repo_info = safe_repo_info('/path/to/project') or {}
327
```
328
329
## Integration with Main Workflow
330
331
### Conditional Repository Integration
332
333
```python
334
# From main workflow (wear function)
335
def wear(args=None):
336
# ... other setup ...
337
338
# Extract repository info only if not disabled
339
if not args.nogit:
340
git_info = repo(args.base_dir)
341
if git_info is None:
342
git_info = {} # Empty dict for no VCS
343
else:
344
git_info = {} # Skip repository info entirely
345
346
# ... continue with API submission ...
347
```
348
349
### Directory Context Management
350
351
```python
352
# Repository functions change working directory temporarily
353
import os
354
355
original_dir = os.getcwd()
356
try:
357
repo_info = gitrepo('/path/to/repo') # Changes to repo directory internally
358
finally:
359
os.chdir(original_dir) # Always restore original directory
360
```
361
362
## Best Practices
363
364
### Working Directory Management
365
366
The repository functions change the current working directory temporarily. Ensure proper restoration:
367
368
```python
369
import os
370
from coveralls.repository import repo
371
372
# Save current directory
373
original_cwd = os.getcwd()
374
375
try:
376
# Extract repository info (may change directory)
377
repo_info = repo('/path/to/project')
378
finally:
379
# Always restore original directory
380
os.chdir(original_cwd)
381
```
382
383
### Error Resilience
384
385
```python
386
# Robust repository integration
387
def get_repo_info(project_path, skip_git=False):
388
if skip_git:
389
return {}
390
391
try:
392
return repo(project_path) or {}
393
except Exception as e:
394
logging.warning(f"Repository info extraction failed: {e}")
395
return {}
396
```