or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

commands.mdconfiguration.mdgit-operations.mdindex.mdplugins.mdversion-management.md

plugins.mddocs/

0

# Plugin Development

1

2

Extensible plugin system for creating custom commit message rules, version providers, changelog formats, and version schemes. Commitizen's plugin architecture enables teams to define their own commit conventions and integrate with various project types and workflows.

3

4

## Capabilities

5

6

### Plugin Discovery

7

8

Automatic discovery and registration of commitizen plugins installed via entry points.

9

10

```python { .api }

11

def discover_plugins() -> None:

12

"""

13

Discover and register all available commitizen plugins.

14

15

Searches for plugins in the 'commitizen.plugin' entry point group

16

and registers them in the global plugin registry.

17

"""

18

19

registry: dict[str, type[BaseCommitizen]]

20

"""Global plugin registry mapping plugin names to plugin classes."""

21

```

22

23

### Plugin Factory

24

25

Factory function for creating commitizen plugin instances based on configuration.

26

27

```python { .api }

28

def commiter_factory(config: BaseConfig) -> BaseCommitizen:

29

"""

30

Create commitizen plugin instance based on configuration.

31

32

Parameters:

33

- config: Configuration object containing plugin name

34

35

Returns:

36

BaseCommitizen instance for the configured plugin

37

38

Raises:

39

NoCommitizenFoundException: If plugin is not found

40

"""

41

```

42

43

### Base Plugin Class

44

45

Abstract base class that all commitizen plugins must inherit from.

46

47

```python { .api }

48

class BaseCommitizen:

49

"""

50

Abstract base class for all commitizen plugins.

51

52

Defines the interface that plugins must implement for commit message

53

generation, validation, and version bump logic.

54

"""

55

def __init__(self, config: BaseConfig):

56

"""

57

Initialize plugin with configuration.

58

59

Parameters:

60

- config: Configuration object

61

"""

62

63

def questions(self) -> Questions:

64

"""

65

Return interactive questions for commit creation.

66

67

Returns:

68

List of question dictionaries for questionary prompts

69

"""

70

71

def message(self, answers: dict[str, Any]) -> str:

72

"""

73

Generate commit message from user answers.

74

75

Parameters:

76

- answers: Dictionary of answers from interactive questions

77

78

Returns:

79

Formatted commit message string

80

"""

81

82

def example(self) -> str:

83

"""

84

Return example commit message.

85

86

Returns:

87

Example commit message following plugin rules

88

"""

89

90

def schema(self) -> str:

91

"""

92

Return commit message schema description.

93

94

Returns:

95

Human-readable schema description

96

"""

97

98

def schema_pattern(self) -> str:

99

"""

100

Return regex pattern for commit message validation.

101

102

Returns:

103

Regex pattern string for validation

104

"""

105

106

def info(self) -> str:

107

"""

108

Return plugin information.

109

110

Returns:

111

Plugin description and usage information

112

"""

113

114

def process_commit(self, commit: str) -> str:

115

"""

116

Process commit message for changelog generation.

117

118

Parameters:

119

- commit: Raw commit message

120

121

Returns:

122

Processed commit message for changelog

123

"""

124

125

def changelog_pattern(self) -> str:

126

"""

127

Return regex pattern for changelog parsing.

128

129

Returns:

130

Regex pattern for extracting changelog information

131

"""

132

133

def change_type_map(self) -> dict[str, str]:

134

"""

135

Return mapping of change types to display names.

136

137

Returns:

138

Dictionary mapping change types to changelog section names

139

"""

140

141

def change_type_order(self) -> list[str]:

142

"""

143

Return ordered list of change types for changelog.

144

145

Returns:

146

List of change types in display order

147

"""

148

149

def bump_pattern(self) -> str:

150

"""

151

Return regex pattern for version bump detection.

152

153

Returns:

154

Regex pattern for determining version increments

155

"""

156

157

def bump_map(self) -> dict[str, str]:

158

"""

159

Return mapping of patterns to version increments.

160

161

Returns:

162

Dictionary mapping regex groups to increment types (MAJOR, MINOR, PATCH)

163

"""

164

```

165

166

### Built-in Plugins

167

168

#### Conventional Commits Plugin

169

170

Standard plugin implementing the Conventional Commits specification.

171

172

```python { .api }

173

class ConventionalCommitsCz(BaseCommitizen):

174

"""

175

Plugin implementing the Conventional Commits specification.

176

177

Supports standard commit types: feat, fix, docs, style, refactor, test, chore.

178

Includes BREAKING CHANGE detection for major version bumps.

179

"""

180

def questions(self) -> Questions:

181

"""

182

Interactive questions for conventional commits.

183

184

Prompts for commit type, scope, description, body, and breaking changes.

185

"""

186

187

def message(self, answers: dict[str, Any]) -> str:

188

"""

189

Generate conventional commit message.

190

191

Format: <type>[optional scope]: <description>

192

193

[optional body]

194

195

[optional footer(s)]

196

"""

197

```

198

199

#### Jira Smart Plugin

200

201

Plugin for integrating with Jira issue tracking.

202

203

```python { .api }

204

class JiraSmartCz(BaseCommitizen):

205

"""

206

Plugin for Jira integration with smart branch detection.

207

208

Automatically detects Jira issue keys from branch names and includes

209

them in commit messages.

210

"""

211

def questions(self) -> Questions:

212

"""

213

Interactive questions with Jira issue integration.

214

215

Includes Jira issue key detection and linking.

216

"""

217

```

218

219

#### Customizable Plugin

220

221

Highly configurable plugin for teams with specific commit conventions.

222

223

```python { .api }

224

class CustomizeCommitsCz(BaseCommitizen):

225

"""

226

Customizable plugin supporting user-defined commit conventions.

227

228

Allows complete customization of questions, message format, and validation

229

through configuration file settings.

230

"""

231

def questions(self) -> Questions:

232

"""

233

Questions defined in configuration [tool.commitizen.customize.questions].

234

235

Supports all questionary question types with full customization.

236

"""

237

```

238

239

## Plugin Development Guide

240

241

### Creating a Custom Plugin

242

243

```python

244

from commitizen.cz.base import BaseCommitizen

245

from commitizen.defaults import Questions

246

247

class MyCustomCz(BaseCommitizen):

248

"""Custom commitizen plugin for my team's conventions."""

249

250

def questions(self) -> Questions:

251

return [

252

{

253

"type": "list",

254

"name": "type",

255

"message": "Select the type of change:",

256

"choices": [

257

{"value": "feature", "name": "feature: New feature"},

258

{"value": "bugfix", "name": "bugfix: Bug fix"},

259

{"value": "docs", "name": "docs: Documentation"},

260

{"value": "refactor", "name": "refactor: Code refactoring"}

261

]

262

},

263

{

264

"type": "input",

265

"name": "scope",

266

"message": "Scope (optional):"

267

},

268

{

269

"type": "input",

270

"name": "subject",

271

"message": "Short description:",

272

"validate": lambda x: len(x) > 0 and len(x) <= 50

273

},

274

{

275

"type": "input",

276

"name": "body",

277

"message": "Longer description (optional):"

278

}

279

]

280

281

def message(self, answers: dict[str, Any]) -> str:

282

scope = f"({answers['scope']})" if answers.get('scope') else ""

283

message = f"{answers['type']}{scope}: {answers['subject']}"

284

285

if answers.get('body'):

286

message += f"\n\n{answers['body']}"

287

288

return message

289

290

def example(self) -> str:

291

return "feature(auth): add OAuth2 integration"

292

293

def schema(self) -> str:

294

return "<type>[(scope)]: <subject>\n\n[body]"

295

296

def schema_pattern(self) -> str:

297

return r"^(feature|bugfix|docs|refactor)(\(.+\))?: .{1,50}$"

298

299

def info(self) -> str:

300

return "Custom plugin for MyTeam commit conventions"

301

302

def bump_pattern(self) -> str:

303

return r"^(feature|BREAKING)"

304

305

def bump_map(self) -> dict[str, str]:

306

return {

307

"BREAKING": "MAJOR",

308

"feature": "MINOR",

309

"bugfix": "PATCH"

310

}

311

312

def change_type_map(self) -> dict[str, str]:

313

return {

314

"feature": "Features",

315

"bugfix": "Bug Fixes",

316

"docs": "Documentation",

317

"refactor": "Refactoring"

318

}

319

```

320

321

### Plugin Entry Points

322

323

#### setup.py Entry Points

324

325

```python

326

from setuptools import setup, find_packages

327

328

setup(

329

name="my-commitizen-plugin",

330

version="1.0.0",

331

packages=find_packages(),

332

install_requires=["commitizen>=3.0.0"],

333

entry_points={

334

"commitizen.plugin": [

335

"my_custom_cz = my_plugin:MyCustomCz"

336

]

337

}

338

)

339

```

340

341

#### pyproject.toml Entry Points

342

343

```toml

344

[build-system]

345

requires = ["poetry-core"]

346

build-backend = "poetry.core.masonry.api"

347

348

[tool.poetry]

349

name = "my-commitizen-plugin"

350

version = "1.0.0"

351

description = "Custom commitizen plugin"

352

353

[tool.poetry.dependencies]

354

python = "^3.8"

355

commitizen = "^3.0.0"

356

357

[tool.poetry.plugins."commitizen.plugin"]

358

my_custom_cz = "my_plugin:MyCustomCz"

359

```

360

361

### Version Provider Plugins

362

363

Custom version providers for different project types.

364

365

```python { .api }

366

class VersionProvider:

367

"""Abstract base class for version providers."""

368

369

def get_version(self) -> str:

370

"""

371

Get current version from provider source.

372

373

Returns:

374

Current version string

375

"""

376

377

def set_version(self, version: str) -> None:

378

"""

379

Set version in provider source.

380

381

Parameters:

382

- version: New version string

383

"""

384

385

@property

386

def keyword(self) -> str:

387

"""

388

Provider keyword for entry point registration.

389

390

Returns:

391

String identifier for the provider

392

"""

393

394

class CustomProvider(VersionProvider):

395

"""Example custom version provider."""

396

397

@property

398

def keyword(self) -> str:

399

return "custom"

400

401

def get_version(self) -> str:

402

# Read version from custom source

403

with open("VERSION.txt") as f:

404

return f.read().strip()

405

406

def set_version(self, version: str) -> None:

407

# Write version to custom source

408

with open("VERSION.txt", "w") as f:

409

f.write(version)

410

```

411

412

### Changelog Format Plugins

413

414

Custom changelog formats for different documentation styles.

415

416

```python { .api }

417

class ChangelogFormat(Protocol):

418

"""Protocol for changelog format implementations."""

419

420

def get_changelog(

421

self,

422

tree: dict[str, Any],

423

header_format: str = "",

424

**kwargs: Any

425

) -> str:

426

"""

427

Generate changelog content from commit tree.

428

429

Parameters:

430

- tree: Parsed commit tree structure

431

- header_format: Header format template

432

- kwargs: Additional format-specific options

433

434

Returns:

435

Formatted changelog content

436

"""

437

438

class CustomChangelogFormat:

439

"""Example custom changelog format."""

440

441

def get_changelog(

442

self,

443

tree: dict[str, Any],

444

header_format: str = "",

445

**kwargs: Any

446

) -> str:

447

# Generate custom format changelog

448

content = []

449

450

for version, changes in tree.items():

451

content.append(f"## Version {version}")

452

453

for change_type, items in changes.items():

454

content.append(f"### {change_type.title()}")

455

for item in items:

456

content.append(f"- {item}")

457

content.append("")

458

459

return "\n".join(content)

460

```

461

462

## Plugin Configuration

463

464

### Using Custom Plugins

465

466

```toml

467

[tool.commitizen]

468

name = "my_custom_cz" # Plugin entry point name

469

version = "1.0.0"

470

471

# Plugin-specific configuration

472

[tool.commitizen.customize]

473

# Custom plugin settings go here

474

```

475

476

### Plugin Testing

477

478

```python

479

import pytest

480

from commitizen.config import BaseConfig

481

from my_plugin import MyCustomCz

482

483

def test_plugin_questions():

484

config = BaseConfig({"name": "my_custom_cz"})

485

plugin = MyCustomCz(config)

486

487

questions = plugin.questions()

488

assert len(questions) > 0

489

assert questions[0]["name"] == "type"

490

491

def test_plugin_message():

492

config = BaseConfig({"name": "my_custom_cz"})

493

plugin = MyCustomCz(config)

494

495

answers = {

496

"type": "feature",

497

"subject": "add new feature"

498

}

499

500

message = plugin.message(answers)

501

assert message == "feature: add new feature"

502

503

def test_plugin_validation():

504

config = BaseConfig({"name": "my_custom_cz"})

505

plugin = MyCustomCz(config)

506

507

pattern = plugin.schema_pattern()

508

import re

509

510

assert re.match(pattern, "feature: valid message")

511

assert not re.match(pattern, "invalid message format")

512

```