or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-commands.mdconfiguration.mdcore-version-management.mdfile-operations.mdhooks.mdindex.mdscm-integration.md

scm-integration.mddocs/

0

# SCM Integration

1

2

Source control management integration supporting Git and Mercurial for automated commits, tagging, and repository state management. Provides comprehensive SCM operations with repository status checking, dirty state validation, and automated commit/tag workflows.

3

4

## Capabilities

5

6

### SCM Information and Status

7

8

Classes for managing source control information and repository state.

9

10

```python { .api }

11

class SCMInfo:

12

"""

13

Information about the current source code management system.

14

15

Provides comprehensive repository state including current commit,

16

branch information, tag distance, and version detection from SCM.

17

"""

18

19

def __init__(

20

self,

21

tool: Optional[str] = None,

22

commit_sha: Optional[str] = None,

23

distance_to_latest_tag: int = 0,

24

current_version: str = "0.0.0",

25

branch_name: Optional[str] = None,

26

repository_root: Optional[Path] = None,

27

short_branch_name: Optional[str] = None

28

) -> None:

29

"""

30

Initialize SCM information.

31

32

Args:

33

tool: SCM tool name ('git', 'hg', etc.)

34

commit_sha: Current commit SHA

35

distance_to_latest_tag: Number of commits since latest tag

36

current_version: Current version string

37

branch_name: Full branch name

38

repository_root: Path to repository root

39

short_branch_name: Short branch name

40

"""

41

42

@property

43

def is_dirty(self) -> bool:

44

"""Whether repository has uncommitted changes."""

45

46

@property

47

def latest_tag_info(self) -> Optional[LatestTagInfo]:

48

"""Information about the most recent tag."""

49

50

class LatestTagInfo:

51

"""

52

Information about the latest repository tag.

53

54

Contains tag name, commit SHA, and version information

55

extracted from the most recent repository tag.

56

"""

57

58

tag_name: str

59

commit_sha: str

60

version: Optional[str] = None

61

62

@property

63

def is_version_tag(self) -> bool:

64

"""Whether tag represents a version."""

65

66

class SCMConfig:

67

"""

68

Configuration for SCM operations.

69

70

Contains settings for commit behavior, tag creation,

71

message templates, and repository interaction options.

72

"""

73

74

commit: bool = False

75

tag: bool = False

76

commit_args: str = ""

77

message: str = "Bump version: {current_version} → {new_version}"

78

tag_name: str = "v{new_version}"

79

tag_message: str = "Bump version: {current_version} → {new_version}"

80

sign_tags: bool = False

81

allow_dirty: bool = False

82

```

83

84

### Git Implementation

85

86

Comprehensive Git integration with full repository management capabilities.

87

88

```python { .api }

89

class Git:

90

"""

91

Git implementation for SCM operations.

92

93

Provides complete Git integration including repository status checking,

94

commit creation, tag management, and branch operations.

95

"""

96

97

def __init__(self, repo_root: Path) -> None:

98

"""

99

Initialize Git integration.

100

101

Args:

102

repo_root: Path to Git repository root

103

"""

104

105

def is_dirty(self) -> bool:

106

"""

107

Check if repository has uncommitted changes.

108

109

Returns:

110

True if repository has staged or unstaged changes

111

"""

112

113

def commit_and_tag(

114

self,

115

message: str,

116

tag_name: Optional[str] = None,

117

tag_message: Optional[str] = None,

118

sign_tags: bool = False,

119

commit_args: str = ""

120

) -> None:

121

"""

122

Create commit and optional tag for version changes.

123

124

Stages all modified files, creates commit with specified message,

125

and optionally creates annotated tag.

126

127

Args:

128

message: Commit message

129

tag_name: Tag name to create (optional)

130

tag_message: Tag annotation message

131

sign_tags: Whether to sign tags with GPG

132

commit_args: Additional arguments for git commit

133

134

Raises:

135

subprocess.CalledProcessError: Git command failed

136

"""

137

138

def get_current_info(self) -> SCMInfo:

139

"""

140

Get comprehensive repository information.

141

142

Returns:

143

SCMInfo object with current repository state

144

"""

145

146

def get_latest_tag_info(self) -> Optional[LatestTagInfo]:

147

"""

148

Get information about the most recent tag.

149

150

Returns:

151

LatestTagInfo object or None if no tags exist

152

"""

153

154

def get_branch_name(self) -> Optional[str]:

155

"""

156

Get current branch name.

157

158

Returns:

159

Current branch name or None if detached HEAD

160

"""

161

162

def add_path(self, path: Path) -> None:

163

"""

164

Add file or directory to Git staging area.

165

166

Args:

167

path: Path to add to staging area

168

"""

169

170

def tag_exists(self, tag_name: str) -> bool:

171

"""

172

Check if tag exists in repository.

173

174

Args:

175

tag_name: Tag name to check

176

177

Returns:

178

True if tag exists

179

"""

180

181

class Mercurial:

182

"""

183

Mercurial implementation for SCM operations.

184

185

Provides Mercurial integration with repository status checking,

186

commit creation, and tag management capabilities.

187

"""

188

189

def __init__(self, repo_root: Path) -> None:

190

"""Initialize Mercurial integration."""

191

192

def is_dirty(self) -> bool:

193

"""Check if repository has uncommitted changes."""

194

195

def commit_and_tag(

196

self,

197

message: str,

198

tag_name: Optional[str] = None,

199

tag_message: Optional[str] = None

200

) -> None:

201

"""Create commit and optional tag."""

202

203

def get_current_info(self) -> SCMInfo:

204

"""Get repository information."""

205

```

206

207

### SCM Utility Functions

208

209

Helper functions for SCM detection and management.

210

211

```python { .api }

212

def get_scm_info(repo_path: Optional[Path] = None) -> Optional[SCMInfo]:

213

"""

214

Detect and get SCM information for repository.

215

216

Automatically detects Git or Mercurial repositories and returns

217

comprehensive information about repository state.

218

219

Args:

220

repo_path: Path to repository (defaults to current directory)

221

222

Returns:

223

SCMInfo object or None if no SCM detected

224

"""

225

226

def detect_scm_type(repo_path: Path) -> Optional[str]:

227

"""

228

Detect SCM type for repository.

229

230

Args:

231

repo_path: Path to check for SCM

232

233

Returns:

234

SCM type ('git', 'hg') or None

235

"""

236

```

237

238

## SCM Configuration Examples

239

240

### Basic SCM Settings

241

242

```toml

243

[tool.bumpversion]

244

current_version = "1.0.0"

245

commit = true

246

tag = true

247

allow_dirty = false

248

message = "Bump version: {current_version} → {new_version}"

249

tag_name = "v{new_version}"

250

tag_message = "Release {new_version}"

251

commit_args = "--no-verify"

252

sign_tags = false

253

```

254

255

### Advanced SCM Configuration

256

257

```toml

258

[tool.bumpversion]

259

# Commit settings

260

commit = true

261

commit_args = "--no-verify --gpg-sign"

262

message = """

263

Release version {new_version}

264

265

Changes:

266

- Updated version from {current_version} to {new_version}

267

- Automated by bump-my-version on {now:%Y-%m-%d}

268

"""

269

270

# Tag settings

271

tag = true

272

tag_name = "release-{new_version}"

273

tag_message = "Release {new_version} ({now:%Y-%m-%d})"

274

sign_tags = true

275

276

# Repository settings

277

allow_dirty = false

278

```

279

280

### Conditional SCM Operations

281

282

```python

283

from bumpversion.config import get_configuration

284

285

# Load configuration

286

config = get_configuration()

287

288

# Only commit in CI environment

289

import os

290

if os.getenv("CI"):

291

config.commit = True

292

config.tag = True

293

else:

294

config.commit = False

295

config.tag = False

296

```

297

298

## Usage Examples

299

300

### Basic SCM Operations

301

302

```python

303

from bumpversion.scm.git import Git

304

from pathlib import Path

305

306

# Initialize Git integration

307

git = Git(Path.cwd())

308

309

# Check repository status

310

if git.is_dirty():

311

print("Repository has uncommitted changes")

312

313

# Get repository information

314

scm_info = git.get_current_info()

315

print(f"Current branch: {scm_info.branch_name}")

316

print(f"Current commit: {scm_info.commit_sha}")

317

print(f"Distance to latest tag: {scm_info.distance_to_latest_tag}")

318

319

# Create commit and tag

320

git.commit_and_tag(

321

message="Bump version: 1.0.0 → 1.0.1",

322

tag_name="v1.0.1",

323

tag_message="Release version 1.0.1"

324

)

325

```

326

327

### Repository State Checking

328

329

```python

330

from bumpversion.scm.models import SCMInfo

331

from bumpversion.scm.git import Git

332

333

# Get comprehensive repository information

334

git = Git(Path.cwd())

335

scm_info = git.get_current_info()

336

337

print(f"SCM Tool: {scm_info.tool}")

338

print(f"Repository Root: {scm_info.repository_root}")

339

print(f"Current Branch: {scm_info.branch_name}")

340

print(f"Is Dirty: {scm_info.is_dirty}")

341

342

# Check latest tag information

343

latest_tag = git.get_latest_tag_info()

344

if latest_tag:

345

print(f"Latest Tag: {latest_tag.tag_name}")

346

print(f"Tag Commit: {latest_tag.commit_sha}")

347

print(f"Is Version Tag: {latest_tag.is_version_tag}")

348

```

349

350

### Automated Commit and Tag Creation

351

352

```python

353

from bumpversion.scm.git import Git

354

from bumpversion.context import get_context

355

from bumpversion.config import get_configuration

356

357

# Load configuration and create context

358

config = get_configuration()

359

context = get_context(config)

360

361

# Initialize Git

362

git = Git(Path.cwd())

363

364

# Check if repository is clean (if required)

365

if not config.allow_dirty and git.is_dirty():

366

raise DirtyWorkingDirectoryError("Repository has uncommitted changes")

367

368

# Format commit and tag messages

369

commit_message = config.message.format(**context)

370

tag_name = config.tag_name.format(**context) if config.tag else None

371

tag_message = config.tag_message.format(**context) if config.tag else None

372

373

# Create commit and tag

374

git.commit_and_tag(

375

message=commit_message,

376

tag_name=tag_name,

377

tag_message=tag_message,

378

sign_tags=config.sign_tags,

379

commit_args=config.commit_args

380

)

381

```

382

383

### Branch and Tag Management

384

385

```python

386

from bumpversion.scm.git import Git

387

388

git = Git(Path.cwd())

389

390

# Get current branch

391

branch = git.get_branch_name()

392

print(f"Current branch: {branch}")

393

394

# Check if tag exists

395

tag_name = "v1.0.1"

396

if git.tag_exists(tag_name):

397

print(f"Tag {tag_name} already exists")

398

else:

399

print(f"Tag {tag_name} is available")

400

401

# Add specific files to staging

402

from pathlib import Path

403

git.add_path(Path("setup.py"))

404

git.add_path(Path("src/mypackage/__init__.py"))

405

```

406

407

### SCM Integration with Configuration

408

409

```python

410

from bumpversion.config import get_configuration

411

from bumpversion.scm.git import Git

412

from bumpversion.context import get_context

413

414

# Load configuration with SCM settings

415

config = get_configuration(

416

commit=True,

417

tag=True,

418

message="Release {new_version}",

419

tag_name="v{new_version}",

420

allow_dirty=False

421

)

422

423

# Get SCM instance

424

git = Git(Path.cwd())

425

426

# Validate repository state

427

if not config.allow_dirty and git.is_dirty():

428

print("Repository must be clean for version bump")

429

exit(1)

430

431

# Get context for templating

432

context = get_context(config)

433

context.update({

434

"current_version": "1.0.0",

435

"new_version": "1.0.1"

436

})

437

438

# Execute SCM operations if configured

439

if config.commit or config.tag:

440

git.commit_and_tag(

441

message=config.message.format(**context),

442

tag_name=config.tag_name.format(**context) if config.tag else None,

443

tag_message=config.tag_message.format(**context) if config.tag else None,

444

sign_tags=config.sign_tags,

445

commit_args=config.commit_args

446

)

447

```

448

449

### Error Handling

450

451

```python

452

from bumpversion.scm.git import Git

453

from bumpversion.exceptions import DirtyWorkingDirectoryError

454

import subprocess

455

456

try:

457

git = Git(Path.cwd())

458

459

# Check repository state

460

if git.is_dirty() and not allow_dirty:

461

raise DirtyWorkingDirectoryError(

462

"Repository has uncommitted changes. "

463

"Use --allow-dirty to override."

464

)

465

466

# Attempt SCM operations

467

git.commit_and_tag(

468

message="Bump version",

469

tag_name="v1.0.1",

470

tag_message="Release 1.0.1"

471

)

472

473

except subprocess.CalledProcessError as e:

474

print(f"Git command failed: {e}")

475

print(f"Command: {e.cmd}")

476

print(f"Output: {e.output}")

477

478

except DirtyWorkingDirectoryError as e:

479

print(f"Repository state error: {e}")

480

```