Skip to content

Commit

Permalink
Merge pull request #4 from AppDifferentia/add-commit-lint-implementation
Browse files Browse the repository at this point in the history
Add commit lint implementation
  • Loading branch information
weisunOW authored Sep 8, 2021
2 parents c944159 + dbe315d commit 21dcb3c
Show file tree
Hide file tree
Showing 29 changed files with 755 additions and 243 deletions.
15 changes: 15 additions & 0 deletions Sources/DangerSwiftCommitLint/CommitChecker/BodyEmptyLine.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

struct BodyEmptyLine: CommitLint, Hashable {
static var linterMessage = "Please separate commit message subject from body with newline."

private let bodyLinesOfText: [String]

init(_ commitMessage: GitCommitMessage) {
bodyLinesOfText = commitMessage.bodyLinesOfText
}

var fail: Bool {
bodyLinesOfText.isEmpty ? false : bodyLinesOfText.first?.isEmpty == false
}
}

This file was deleted.

16 changes: 0 additions & 16 deletions Sources/DangerSwiftCommitLint/CommitChecker/CommitChecker.swift

This file was deleted.

17 changes: 17 additions & 0 deletions Sources/DangerSwiftCommitLint/CommitChecker/CommitLint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

public protocol CommitLint {
static var linterMessage: String { get }

var fail: Bool { get }

init(_ commitMessage: GitCommitMessage)

static func fail(_ commitMessage: GitCommitMessage) -> Bool
}

public extension CommitLint {
static func fail(_ commitMessage: GitCommitMessage) -> Bool {
Self(commitMessage).fail
}
}
28 changes: 0 additions & 28 deletions Sources/DangerSwiftCommitLint/CommitChecker/CommitMessage.swift

This file was deleted.

31 changes: 31 additions & 0 deletions Sources/DangerSwiftCommitLint/CommitChecker/GitCommitMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Danger
import Foundation

/// An abstraction of Git commit message for `DangerSwiftCommitLint`.
public struct GitCommitMessage: Hashable {
/// First line of the commit message
public let subject: String
/// Rest of the commit message
public let bodyLinesOfText: [String]
// Commit SHA value
public let sha: String?

init(
subject: String,
bodyLinesOfText: [String],
sha: String
) {
self.subject = subject
self.bodyLinesOfText = bodyLinesOfText
self.sha = sha
}

/// Initialize `GitCommitMessage` with `Danger.Git.Commit.message`
/// - Parameter gitCommit: An instance of `Danger.Git.Commit`
public init(_ gitCommit: Git.Commit) {
let commitMessageLines = gitCommit.message.components(separatedBy: .newlines)
subject = commitMessageLines.first ?? ""
bodyLinesOfText = Array(commitMessageLines.dropFirst())
sha = gitCommit.sha
}
}
15 changes: 0 additions & 15 deletions Sources/DangerSwiftCommitLint/CommitChecker/SubjectCapCheck.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

struct SubjectCapitalLetter: CommitLint, Hashable {
static let linterMessage = "Please start commit message subject with capital letter."

private let firstCharacter: Character?

init(_ commitMessage: GitCommitMessage) {
firstCharacter = commitMessage.subject.first
}

var fail: Bool {
firstCharacter?.isLowercase ?? false
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import Foundation

struct SubjectLengthCheck: CommitChecker {
struct SubjectLength: CommitLint, Hashable {
private enum GeneratedSubjectPattern {
static let git = #"^Merge branch '.+' into "#
static let gitHub = #"^Merge pull request #\d+ from "#
}

static let warningMessage = "Please limit commit message subject line to 50 characters."
static let linterMessage = "Please limit commit message subject line to 50 characters."

private let subject: String

init(message: CommitMessage) {
subject = message.subject
init(_ commitMessage: GitCommitMessage) {
subject = commitMessage.subject
}

var fail: Bool {
subject.count > 50 && isMergeCommit == false
}
}

private extension SubjectLengthCheck {
private extension SubjectLength {
var isMergeCommit: Bool {
subject =~ GeneratedSubjectPattern.git || subject =~ GeneratedSubjectPattern.gitHub
}
Expand Down
15 changes: 15 additions & 0 deletions Sources/DangerSwiftCommitLint/CommitChecker/SubjectPeriod.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

struct SubjectPeriod: CommitLint, Hashable {
static var linterMessage = "Please remove period from end of commit message subject line."

private let subject: String

init(_ commitMessage: GitCommitMessage) {
subject = commitMessage.subject
}

var fail: Bool {
subject.last == "."
}
}

This file was deleted.

15 changes: 15 additions & 0 deletions Sources/DangerSwiftCommitLint/CommitChecker/SubjectWord.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

struct SubjectWord: CommitLint, Hashable {
static var linterMessage = "Please use more than one word in commit message."

private let subject: String

init(_ commitMessage: GitCommitMessage) {
subject = commitMessage.subject
}

var fail: Bool {
subject.split(separator: " ").count < 2
}
}
15 changes: 0 additions & 15 deletions Sources/DangerSwiftCommitLint/CommitChecker/SubjectWordCheck.swift

This file was deleted.

109 changes: 109 additions & 0 deletions Sources/DangerSwiftCommitLint/Configuration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import Foundation

public extension DangerSwiftCommitLint {
/// All commit checkers provided by `DangerSwiftCommitLint`
enum CommitCheckerType: CaseIterable, Hashable {
/// Commit subject and body are separated by an empty line (`CommitChecker/BodyEmptyLineCheck`)
case bodyEmptyLine
/// Commit subject begins with a capital letter (`CommitChecker/SubjectCapCheck`)
case subjectCapitalLetter
/// Commit subject is no longer than 50 characters (`CommitChecker/SubjectLengthCheck`)
case subjectLength
/// Commit subject does not end in a period (`CommitChecker/SubjectPeriodCheck`)
case subjectPeriod
/// Commit subject is more than one word (`CommitChecker/SubjectWordCheck`)
case subjectWord
}

/// Checker selection
enum CommitCheckerSelection {
/// Select all checkers
case all
/// Select a set of checkers
case selected(Set<CommitCheckerType>)
}

struct Configuration {
let limit: Int

private let disabled: CommitCheckerSelection
private let warn: CommitCheckerSelection
private let fail: CommitCheckerSelection
private let customCheckers: [CommitLint.Type]

/// Initialize the configuration.
/// - Parameters:
/// - disabled: The selected checks to skip.
/// - warn: The selected checks to warn on.
/// - fail: The selected checks to fail on.
/// - limit: The number of commits to check.
/// - customCheckers: An array of custom checkers.
public init(
disabled: CommitCheckerSelection = .selected([]),
warn: CommitCheckerSelection = .selected([]),
fail: CommitCheckerSelection = .all,
limit: Int = 0,
customCheckers: [CommitLint.Type] = []
) {
self.disabled = disabled
self.warn = warn
self.fail = fail
self.limit = limit
self.customCheckers = customCheckers
}
}
}

extension DangerSwiftCommitLint.Configuration {
static var defaultCheckers: [CommitLint.Type] {
DangerSwiftCommitLint.CommitCheckerType.allCases.map(\.type)
}

var allCheckers: [CommitLint.Type] {
Self.defaultCheckers + customCheckers
}

var disabledCheckers: [CommitLint.Type] {
switch disabled {
case .all:
return allCheckers
case let .selected(disabled):
return disabled.map(\.type)
}
}

var enabledCheckers: [CommitLint.Type] {
allCheckers.filter { checker in
disabledCheckers.contains { $0 == checker } == false
}
}

var warningCheckers: [CommitLint.Type] {
switch warn {
case .all:
return allCheckers
case let .selected(warningCheckers):
return enabledCheckers.filter { type in
warningCheckers.map(\.type).contains { $0 == type }
}
}
}

var failingCheckers: [CommitLint.Type] {
enabledCheckers.filter { type in
warningCheckers.contains { $0 == type } == false
}
}
}

private extension DangerSwiftCommitLint.CommitCheckerType {
var type: CommitLint.Type {
switch self {
case .bodyEmptyLine: return BodyEmptyLine.self
case .subjectCapitalLetter: return SubjectCapitalLetter.self
case .subjectLength: return SubjectCapitalLetter.self
case .subjectPeriod: return SubjectPeriod.self
case .subjectWord: return SubjectWord.self
}
}
}
Loading

0 comments on commit 21dcb3c

Please sign in to comment.