Skip to content

Commit

Permalink
feat(conventional_commit)!: allow custom type
Browse files Browse the repository at this point in the history
Any type that matches [a-zA-Z0-9_]+ is allowed.

BREAKING CHANGE:

- Remove SemverReleaseType.
- Remove ConventionalCommit.isVersionableCommit.
- Remove ConventionalCommit.semverReleaseType.

Fixes #363
  • Loading branch information
blaugold authored and Salakar committed Sep 23, 2022
1 parent 917be21 commit e55edb5
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 141 deletions.
9 changes: 2 additions & 7 deletions packages/conventional_commit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

---

Parse a git commit message into a [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) format.
Parse a git commit message into a
[Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) format.

## Example

Expand Down Expand Up @@ -50,17 +51,11 @@ void main() {
print(parsedCommit.breakingChangeDescription);
// : This is a breaking change because of X Y Z.
print(parsedCommit.semverReleaseType);
// : SemverReleaseType.major
print(parsedCommit.footers);
// : ['Co-authored-by: @Salakar', 'Refs #123 #456']
print(parsedCommit.isMergeCommit);
// : false
print(parsedCommit.isVersionableCommit);
// : true
}
```

Expand Down
10 changes: 1 addition & 9 deletions packages/conventional_commit/example/conventional_commit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import 'package:conventional_commit/conventional_commit.dart';

const commitMessageExample = '''
feat(cool): An exciting new feature.
feat(cool): An exciting new feature.
A body describing this commit in more detail.
Expand Down Expand Up @@ -37,17 +37,9 @@ void main() {
print(parsedCommit.breakingChangeDescription);
// : This is a breaking change because of X Y Z.

// Note this api may be removed in future.
print(parsedCommit.semverReleaseType);
// : SemverReleaseType.major

print(parsedCommit.footers);
// : ['Co-authored-by: @Salakar', 'Refs #123 #456']

print(parsedCommit.isMergeCommit);
// : false

// Note this api may be removed in future.
print(parsedCommit.isVersionableCommit);
// : true
}
109 changes: 34 additions & 75 deletions packages/conventional_commit/lib/conventional_commit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
*
*/

final _conventionalCommitRegex = RegExp(
r'(?<type>build|chore|ci|docs|feat|fix|bug|perf|refactor|revert|style|test)(?<scope>\([a-zA-Z0-9_,\s\*]+\)?((?=:\s?)|(?=!:\s?)))?(?<breaking>!)?(?<description>:\s?.*)?|^(?<merge>Merge \w+)',
final _mergeCommitPrefixRegex = RegExp('^Merged? (.*?:)?');

final _conventionalCommitHeaderRegex = RegExp(
r'(?<type>[a-zA-Z0-9_]+)(\((?<scope>[a-zA-Z0-9_,\s\*]+)\))?(?<breaking>!)?: ?(?<description>.+)',
);

final _breakingChangeRegex =
Expand All @@ -27,18 +29,6 @@ final _footerRegex = RegExp(
multiLine: true,
);

/// Indicates the semver release type this commit message creates.
enum SemverReleaseType {
/// A patch release indicates non-breaking changes (e.g. bug fixes).
patch,

/// Indicates new API changes have been made (e.g. new features).
minor,

/// A major release is when the breaking changes have been introduced.
major,
}

/// A representation of a parsed conventional commit message.
///
/// Parsing is based upon the Conventional Commits 1.0.0 specification available
Expand Down Expand Up @@ -75,30 +65,33 @@ class ConventionalCommit {
/// ```
static ConventionalCommit? tryParse(String commitMessage) {
final header = commitMessage.split('\n')[0];
final match = _conventionalCommitRegex.firstMatch(header);
final mergeCommitPrefixMatch = _mergeCommitPrefixRegex.firstMatch(header);
final isMergeCommit = mergeCommitPrefixMatch != null;
final headerMatch = _conventionalCommitHeaderRegex.firstMatch(
isMergeCommit ? header.substring(mergeCommitPrefixMatch!.end) : header,
);

if (match == null) {
if (headerMatch == null) {
if (isMergeCommit) {
return ConventionalCommit._(
header: header,
isMergeCommit: isMergeCommit,
isBreakingChange: false,
scopes: [],
);
}
return null;
}

final isMergeCommit = match.namedGroup('merge') != null;
if (isMergeCommit) {
return ConventionalCommit._(
header: header,
isMergeCommit: isMergeCommit,
isBreakingChange: false,
scopes: [],
);
}

final type = match.namedGroup('type');
var description = (match.namedGroup('description') ?? '').trim();
description = description.replaceAll(RegExp(r'^:\s'), '').trim();
if (description.isEmpty) {
return null;
}
final type = headerMatch.namedGroup('type')!.toLowerCase();
final scopes = (headerMatch.namedGroup('scope') ?? '')
.split(',')
.map((scope) => scope.trim())
.where((scope) => scope.isNotEmpty)
.toList();
final description = headerMatch.namedGroup('description')!.trim();

final isBreakingChange = match.namedGroup('breaking') != null ||
final isBreakingChange = headerMatch.namedGroup('breaking') != null ||
commitMessage.contains('BREAKING: ') ||
commitMessage.contains('BREAKING CHANGE: ');

Expand Down Expand Up @@ -159,14 +152,6 @@ class ConventionalCommit {
)
.toList();

final scopes = (match.namedGroup('scope') ?? '')
.replaceAll(RegExp(r'^\('), '')
.replaceAll(RegExp(r'\)$'), '')
.split(',')
.map((e) => e.trim())
.where((element) => element.isNotEmpty)
.toList();

return ConventionalCommit._(
body: body,
breakingChangeDescription: breakingChangeDescription,
Expand All @@ -186,6 +171,12 @@ class ConventionalCommit {
/// The type specified in this commit, e.g. `feat`.
final String? type;

/// Whether this commit adds a new feature.
bool get isFeature => type == 'feat';

/// Whether this commit represents a bug fix.
bool get isFix => type == 'fix';

/// Whether this commit was a breaking change, e.g. `!` was specified after
/// the scopes in the commit message.
final bool isBreakingChange;
Expand Down Expand Up @@ -222,42 +213,10 @@ class ConventionalCommit {
/// also be used as a token.
final List<String> footers;

// TODO(Salakar): this api should probably not be in this package
/// Whether this commit should trigger a version bump in it's residing
/// package.
bool get isVersionableCommit {
if (isMergeCommit) return false;
return isBreakingChange ||
[
'docs', // TODO: what if markdown docs and not code docs
'feat',
'fix',
'bug',
'perf',
'refactor',
'revert',
].contains(type);
}

// TODO(Salakar): this api should probably not be in this package
/// Returns the [SemverReleaseType] for this commit, e.g.
/// [SemverReleaseType.major].
SemverReleaseType get semverReleaseType {
if (isBreakingChange) {
return SemverReleaseType.major;
}

if (type == 'feat') {
return SemverReleaseType.minor;
}

return SemverReleaseType.patch;
}

@override
String toString() {
return '''
ConventionalCommit[
ConventionalCommit(
type="$type",
scopes=$scopes,
description="$description",
Expand All @@ -266,6 +225,6 @@ ConventionalCommit[
isBreakingChange=$isBreakingChange,
breakingChangeDescription=$breakingChangeDescription,
footers=$footers
]''';
)''';
}
}
55 changes: 5 additions & 50 deletions packages/conventional_commit/test/conventional_commit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ void main() {
expect(ConventionalCommit.tryParse(': new feature'), isNull);
expect(ConventionalCommit.tryParse(' (): new feature'), isNull);
expect(ConventionalCommit.tryParse('feat()'), isNull);
expect(ConventionalCommit.tryParse('custom: new feature'), isNull);
});

test('accepts commit messages with or without a space before description',
Expand Down Expand Up @@ -98,6 +97,7 @@ void main() {
expect(conventionalCommit?.type, 'feat');
expect(conventionalCommit?.scopes, ['scope']);
expect(conventionalCommit?.description, 'new feature');
expect(conventionalCommit?.isMergeCommit, true);
},
);

Expand All @@ -108,8 +108,6 @@ void main() {
expect(commit.body, equals('This also fixes an issue something else.'));
expect(commit.type, equals('feat'));
expect(commit.scopes, equals(['*']));
expect(commit.isVersionableCommit, isTrue);
expect(commit.semverReleaseType, SemverReleaseType.minor);
});

test('header', () {
Expand Down Expand Up @@ -208,6 +206,10 @@ void main() {
ConventionalCommit.tryParse('test(scope)!: foo bar')!.type,
equals('test'),
);
expect(
ConventionalCommit.tryParse('FIX: foo bar')!.type,
equals('fix'),
);
});

test('isBreakingChange', () {
Expand Down Expand Up @@ -361,53 +363,6 @@ void main() {
);
});

test('isVersionableCommit', () {
expect(
ConventionalCommit.tryParse('chore!: foo bar')!.isVersionableCommit,
isTrue,
);
expect(
ConventionalCommit.tryParse('docs: foo bar')!.isVersionableCommit,
isTrue,
);
expect(
ConventionalCommit.tryParse('refactor(scope): foo bar')!
.isVersionableCommit,
isTrue,
);
expect(
ConventionalCommit.tryParse('revert(scope,dope)!: foo bar')!
.isVersionableCommit,
isTrue,
);
expect(
ConventionalCommit.tryParse('ci(scope,dope): foo bar')!
.isVersionableCommit,
isFalse,
);
});

test('semverReleaseType', () {
expect(
ConventionalCommit.tryParse('chore!: foo bar')!.semverReleaseType,
equals(SemverReleaseType.major),
);
expect(
ConventionalCommit.tryParse('docs: foo bar')!.semverReleaseType,
equals(SemverReleaseType.patch),
);
expect(
ConventionalCommit.tryParse('refactor(scope): foo bar')!
.semverReleaseType,
equals(SemverReleaseType.patch),
);
expect(
ConventionalCommit.tryParse('feat(scope,dope): foo bar')!
.semverReleaseType,
equals(SemverReleaseType.minor),
);
});

test('body', () {
// With a multi-line/paragraph body.
expect(
Expand Down

0 comments on commit e55edb5

Please sign in to comment.