conventionalcommits

package module
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 12, 2024 License: Apache-2.0 Imports: 1 Imported by: 26

README

go-conventionalcommits

Build Coverage License Go Report

A parser for Conventional Commits v1.0 commit messages.

Fu powers to parse your commits!

This repository provides a library to parse your commit messages according to the Conventional Commits v1.0 specification.

Installation

go get github.com/leodido/go-conventionalcommits

Docs

Documentation

The parser/docs directory contains .dot and .png files representing the finite-state machines (FSMs) implementing the parser.

Usage

Parse

Your code base uses only single line commit messages like this one?

feat: awesomeness

No problem at all since the body and the footer parts are not mandatory:

m, _ := parser.NewMachine().Parse([]byte(`feat: awesomeness`))
Full conventional commit messages

Imagine you have a commit message like this:

docs: correct minor typos

see the issue for details

on docs edits.

Reviewed-by: Z
Refs #133

Go with this:

opts := []conventionalcommits.MachineOption{
    WithTypes(conventionalcommits.TypesConventional),
}
res, err := parser.NewMachine(opts...).Parse(i)

Or, more simpler:

res, err := parser.NewMachine(WithTypes(conventionalcommits.TypesConventional)).Parse(i)
Types

This library provides support for different types sets:

  • minimal: fix, feat
  • conventional: build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test
  • falco: build, ci, chore, docs, feat, fix, perf, new, revert, update, test, rule

At the moment, those types are at build time. Which means users can't configure them at runtime.

Anyway, there's also a free-form types set that accepts any combination of printable characters (before the separator after which the commit description starts) as a valid type.

You can choose the type set passing the WithTypes(conventionalcommits.TypesConventional) option as shown above.

Options

A parser behaviour is configurable by using options.

You can set them calling a function on the parser machine.

p := parser.NewMachine()
p.WithBestEffort()
res, err := p.Parse(i)

Or you can provide options to NewMachine(...) directly.

p := parser.NewMachine(WithBestEffort())
res, err := p.Parse(i)
Best effort

The best effort mode will make the parser return what it found until the point it errored out, if it found (at least) a valid type and a valid description.

Let's make an example.

Suppose this input commit message:

fix: description
a blank line is mandatory to start the body part of the commit message!

The input does not respect the Conventional Commits v1 specification because it lacks a blank line after the description (before the body).

Anyways, if the parser you're using has the best effort mode enabled, you can still obtain some structured data since at least a valid type and description have been found!

res, err := parser.NewMachine(WithBestEffort()).Parse(i)

The result will contain a ConventionalCommit struct instance with the Type and the Description fields populated and ignore the rest after the error column.

The parser will still return the error (with the position information), so that you can eventually use it.

Performances

To run the benchmark suite execute the following command.

make bench

All the parsers have the best effort mode on.

On my machine1, these are the results for the slim parser with the default - ie., minimal, commit message types.

[ok]_minimal______________________________________-12          4876018       242 ns/op     147 B/op       5 allocs/op
[ok]_minimal_with_scope___________________________-12          4258562       284 ns/op     163 B/op       6 allocs/op
[ok]_minimal_breaking_with_scope__________________-12          4176747       288 ns/op     163 B/op       6 allocs/op
[ok]_full_with_50_characters_long_description_____-12          1661618       700 ns/op     288 B/op      10 allocs/op
[no]_empty________________________________________-12          4059327       292 ns/op     112 B/op       3 allocs/op
[no]_type_but_missing_colon_______________________-12          2701904       444 ns/op     200 B/op       6 allocs/op
[no]_type_but_missing_description_________________-12          2207985       539 ns/op     288 B/op       8 allocs/op
[no]_type_and_scope_but_missing_description_______-12          1969390       605 ns/op     312 B/op      10 allocs/op
[no]_breaking_with_type_and_scope_but_missing_desc-12          1978302       606 ns/op     312 B/op      10 allocs/op
[~~]_newline_in_description_______________________-12          2115649       563 ns/op     232 B/op      11 allocs/op
[no]_missing_whitespace_in_description____________-12          1997863       595 ns/op     312 B/op      10 allocs/op

Using another set of commit message types, for example the conventional one, does not have any noticeable impact on performances, as you can see below.

[ok]_minimal______________________________________-12          5297486       228 ns/op     147 B/op       5 allocs/op
[ok]_minimal_with_scope___________________________-12          4498694       267 ns/op     163 B/op       6 allocs/op
[ok]_minimal_breaking_with_scope__________________-12          4431040       273 ns/op     163 B/op       6 allocs/op
[ok]_full_with_50_characters_long_description_____-12          1750111       692 ns/op     288 B/op      10 allocs/op
[no]_empty________________________________________-12          3996532       294 ns/op     112 B/op       3 allocs/op
[no]_type_but_missing_colon_______________________-12          2657913       451 ns/op     200 B/op       6 allocs/op
[no]_type_but_missing_description_________________-12          2172524       553 ns/op     288 B/op       8 allocs/op
[no]_type_and_scope_but_missing_description_______-12          1880526       637 ns/op     312 B/op      10 allocs/op
[no]_breaking_with_type_and_scope_but_missing_desc-12          1879779       635 ns/op     312 B/op      10 allocs/op
[~~]_newline_in_description_______________________-12          2023514       592 ns/op     232 B/op      11 allocs/op
[no]_missing_whitespace_in_description____________-12          1883124       623 ns/op     312 B/op      10 allocs/op

As you may notice, this library is very fast at what it does.

Parsing a commit goes from taking about the same amount of time (~299ns) the half-life of polonium-212 takes2 to less than a microsecond.

Build

To build this Go library locally just run:

make

You'd need Ragel 6.10 to be present into your machine.



Analytics

Documentation

Overview

SPDX-License-Identifier: Apache-2.0

Copyright © 2020- Leonardo Di Donato <leodidonato@gmail.com>

SPDX-License-Identifier: Apache-2.0

Copyright © 2020- Leonardo Di Donato <leodidonato@gmail.com>

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BestEfforter

type BestEfforter interface {
	WithBestEffort()
	HasBestEffort() bool
}

BestEfforter is an interface that wraps the methods about the best effort mode.

type ConventionalCommit

type ConventionalCommit struct {
	Type        string
	Description string
	Scope       *string // optional
	Exclamation bool
	Body        *string             // optional
	Footers     map[string][]string // optional
	TypeConfig  TypeConfig
}

ConventionalCommit represents a commit message as per Conventional Commits specification.

func (*ConventionalCommit) HasFooter

func (c *ConventionalCommit) HasFooter() bool

HasFooter tells whether the receiving commit message struct has one or more trailers.

func (*ConventionalCommit) IsBreakingChange

func (c *ConventionalCommit) IsBreakingChange() bool

IsBreakingChange tells whether the receiving commit message struct represents a breaking change or not.

func (*ConventionalCommit) IsFeat added in v0.11.0

func (c *ConventionalCommit) IsFeat() bool

IsFeat tells whether the receiving commit message struct represents a feat change or not.

func (*ConventionalCommit) IsFix added in v0.11.0

func (c *ConventionalCommit) IsFix() bool

IsFix tells whether the receiving commit message struct represents a fix change or not.

func (*ConventionalCommit) Ok

func (c *ConventionalCommit) Ok() bool

Ok tells whether the receiving commit message is well-formed or not.

A minimally well-formed commit message has at least a valid type and a non empty description.

func (*ConventionalCommit) VersionBump added in v0.11.0

func (c *ConventionalCommit) VersionBump(strategy VersionBumpStrategy) VersionBump

VersionBump tells which version bump the receiving commit message mandates.

type Logger

type Logger interface {
	WithLogger(l *logrus.Logger)
}

Logger represents parser able to log.

type Machine

type Machine interface {
	Parse(input []byte) (Message, error)
	BestEfforter
	TypeConfigurer
	Logger
}

Machine represent a FSM able to parse a conventional commit and return it in an structured way.

type MachineOption

type MachineOption func(m Machine) Machine

MachineOption represents the type of option setters for Machine instances.

func WithBestEffort

func WithBestEffort() MachineOption

WithBestEffort ...

func WithLogger

func WithLogger(l *logrus.Logger) MachineOption

WithLogger ...

func WithTypes

func WithTypes(t TypeConfig) MachineOption

WithTypes ...

type Message

type Message interface {
	Ok() bool
	IsBreakingChange() bool
	IsFeat() bool
	IsFix() bool
	VersionBump(VersionBumpStrategy) VersionBump
	HasFooter() bool
}

Message represent a conventional commit message.

type TypeConfig

type TypeConfig int

TypeConfig represent the set of types the parser should use.

const (
	// TypesMinimal is the minimal set of types.
	TypesMinimal TypeConfig = iota
	// TypesConventional represents the conventional set of types.
	// See https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional
	TypesConventional
	// TypesFalco represents the set of types that Falco uses for its release notes.
	// See https://github.com/falcosecurity/falco
	TypesFalco
	// TypesFreeForm represents a free-form set of types.
	TypesFreeForm
)

type TypeConfigurer

type TypeConfigurer interface {
	WithTypes(t TypeConfig)
}

TypeConfigurer represents parsers with the option to enable different commit message types.

type VersionBump added in v0.11.0

type VersionBump int

VersionBump represent the set of possible version bumps a commit can mandate.

const (
	UnknownVersion VersionBump = iota
	PatchVersion
	MinorVersion
	MajorVersion
)

func DefaultStrategy added in v0.11.0

func DefaultStrategy(c *ConventionalCommit) VersionBump

DefaultStrategy is a basic, opiniated strategy to evaluate the version bump.

type VersionBumpStrategy added in v0.11.0

type VersionBumpStrategy func(*ConventionalCommit) VersionBump

VersionBumpStrategy represents a strategy how to evaluate the version bump depending on the TypeConfig initially used and the commits type.

Directories

Path Synopsis
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0
tools
removecomments command
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0
snake2camel command
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: Apache-2.0

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL