Skip to content

Commit

Permalink
feat: use the pipeline model for commits
Browse files Browse the repository at this point in the history
This commit allows us to start using pipelines inside the project. This still isn't the final form, but it is a good base to start.
  • Loading branch information
fallion authored and Simon Prochazka committed Dec 2, 2020
1 parent 1298b0e commit 453b908
Show file tree
Hide file tree
Showing 15 changed files with 239 additions and 142 deletions.
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package root_runner
package commitpipeline

import (
history "github.com/aevea/git/v2"
"github.com/go-git/go-git/v5/plumbing"
)

func commitsBetweenBranches(gitRepo *history.Git, options RunnerOptions) ([]plumbing.Hash, error) {
func (pipeline *Pipeline) commitsBetweenBranches(gitRepo *history.Git) ([]plumbing.Hash, error) {
var commits []plumbing.Hash

currentBranch, currentBranchErr := gitRepo.CurrentBranch()
if currentBranchErr != nil {
return nil, currentBranchErr
}

sameBranch, err := IdentifySameBranch(currentBranch.Name().String(), options.UpstreamBranch, gitRepo)
sameBranch, err := IdentifySameBranch(currentBranch.Name().String(), pipeline.options.UpstreamBranch, gitRepo)

if err != nil {
return nil, err
Expand All @@ -26,17 +26,17 @@ func commitsBetweenBranches(gitRepo *history.Git, options RunnerOptions) ([]plum
return nil, err
}

if options.AllCommits {
if pipeline.options.AllCommits {
return commitsOnSameBranch, nil
}

// If no limit is set then check just the last commits. This is to prevent breaking repositories that did not check commits before.
if options.Limit == 0 {
if pipeline.options.Limit == 0 {
commits = append(commits, commitsOnSameBranch[0])
return commits, nil
}

limit := options.Limit
limit := pipeline.options.Limit

// The limit cannot be longer than the amount of commits found
if limit > len(commitsOnSameBranch) {
Expand All @@ -50,7 +50,7 @@ func commitsBetweenBranches(gitRepo *history.Git, options RunnerOptions) ([]plum
return commits, nil
}

commitsOnBranch, err := gitRepo.BranchDiffCommits(currentBranch.Name().String(), options.UpstreamBranch)
commitsOnBranch, err := gitRepo.BranchDiffCommits(currentBranch.Name().String(), pipeline.options.UpstreamBranch)

if err != nil {
return nil, err
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package root_runner
package commitpipeline

import (
"testing"
Expand All @@ -12,14 +12,18 @@ func TestAllCommits(t *testing.T) {

assert.NoError(t, err)

options := RunnerOptions{
options := Options{
Path: "",
UpstreamBranch: "master",
Limit: 0,
AllCommits: true,
}

commits, err := commitsBetweenBranches(gitRepo, options)
pipeline, err := New(nil, nil, &options)

assert.NoError(t, err)

commits, err := pipeline.commitsBetweenBranches(gitRepo)

assert.NoError(t, err)
assert.Len(t, commits, 102)
Expand All @@ -40,14 +44,18 @@ func TestLimitCommits(t *testing.T) {

assert.NoError(t, err)

options := RunnerOptions{
options := Options{
Path: "",
UpstreamBranch: "master",
Limit: 50,
AllCommits: false,
}

commits, err := commitsBetweenBranches(gitRepo, options)
pipeline, err := New(nil, nil, &options)

assert.NoError(t, err)

commits, err := pipeline.commitsBetweenBranches(gitRepo)

assert.NoError(t, err)
assert.Len(t, commits, 50)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package root_runner
package commitpipeline

import (
"strings"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package root_runner
package commitpipeline

import (
"testing"
Expand Down
2 changes: 2 additions & 0 deletions internal/commitpipeline/docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package commitpipeline handles all work related to commits
package commitpipeline
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package root_runner
package commitpipeline

import (
history "github.com/aevea/git/v2"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package root_runner
package commitpipeline

import history "github.com/aevea/git/v2"

// logBranch outputs the branch which is being checked into the console
func (runner *Runner) logBranch(gitRepo *history.Git) error {
func (pipeline *Pipeline) logBranch(gitRepo *history.Git) error {
branch, err := gitRepo.CurrentBranch()

if err != nil {
return err
}

runner.Logger.Printf("Starting analysis of commits on branch %s", branch.Name())
pipeline.Logger.Printf("Starting analysis of commits on branch %s", branch.Name())

return nil
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package root_runner
package commitpipeline

import (
"bytes"
"io/ioutil"
"log"
"testing"

Expand All @@ -16,11 +15,9 @@ func TestLogBranch(t *testing.T) {
testLogger := log.Logger{}
testLogger.SetOutput(&testString)

runner := Runner{
DebugLogger: log.New(ioutil.Discard, "", 0),
Logger: &testLogger,
Debug: false,
}
runner, err := New(&testLogger, nil, nil)

assert.NoError(t, err)

gitRepo, err := history.OpenGit("../../testdata/commits-on-master", nil)

Expand Down
56 changes: 56 additions & 0 deletions internal/commitpipeline/pipeline.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package commitpipeline

import (
"io/ioutil"
"log"
"os"
)

type Pipeline struct {
Logger *log.Logger
DebugLogger *log.Logger
args []string
options Options
}

type Options struct {
// Path to repository
Path string
// UpstreamBranch is the branch against which to check
UpstreamBranch string
// Limit will limit how far back to check on upstream branch.
Limit int
// AllCommits will check all the commits on the upstream branch. Regardless of Limit setting.
AllCommits bool
Strict bool
}

func New(logger, debugLogger *log.Logger, options *Options, args ...string) (*Pipeline, error) {
if logger == nil {
logger = log.New(os.Stdout, "", 0)
}
if debugLogger == nil {
debugLogger = log.New(ioutil.Discard, "[DEBUG] ", 0)
}

if options == nil {
options = &Options{
Path: ".",
UpstreamBranch: "master",
Limit: 0,
AllCommits: false,
Strict: true,
}
}

return &Pipeline{
Logger: logger,
DebugLogger: debugLogger,
options: *options,
args: args,
}, nil
}

func (Pipeline) Name() string {
return "commit-pipeline"
}
108 changes: 108 additions & 0 deletions internal/commitpipeline/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package commitpipeline

import (
"errors"
"os"

"github.com/aevea/commitsar/internal/dispatcher"
"github.com/aevea/commitsar/pkg/text"
history "github.com/aevea/git/v2"
"github.com/aevea/quoad"
"github.com/go-git/go-git/v5/plumbing"
"github.com/logrusorgru/aurora"
)

func (pipeline *Pipeline) Run() (*dispatcher.PipelineSuccess, error) {
gitRepo, err := history.OpenGit(pipeline.options.Path, pipeline.DebugLogger)

if err != nil {
return nil, err
}

err = pipeline.logBranch(gitRepo)

if err != nil {
return nil, err
}

var commits []plumbing.Hash

if len(pipeline.args) == 0 {
commitsBetweenBranches, err := pipeline.commitsBetweenBranches(gitRepo)

if err != nil {
return nil, err
}

commits = commitsBetweenBranches
} else {
commitsBetweenHashes, err := commitsBetweenHashes(gitRepo, pipeline.args)

if err != nil {
return nil, err
}

commits = commitsBetweenHashes
}

var filteredCommits []plumbing.Hash

for _, commitHash := range commits {
commitObject, commitErr := gitRepo.Commit(commitHash)

if commitErr != nil {
return nil, commitErr
}

parsedCommit := quoad.ParseCommitMessage(commitObject.Message)

pipeline.DebugLogger.Printf("Commit found: [hash] %v [message] %v \n", parsedCommit.Hash.String(), parsedCommit.Heading)

if !text.IsMergeCommit(commitObject.Message) && !text.IsInitialCommit(commitObject.Message) {
filteredCommits = append(filteredCommits, commitHash)
}
}

pipeline.Logger.Printf("\n%v commits filtered out\n", len(commits)-len(filteredCommits))
pipeline.Logger.Printf("\nFound %v commit to check\n", len(filteredCommits))

if len(filteredCommits) == 0 {
return nil, errors.New(aurora.Red("No commits found, please check you are on a branch outside of main").String())
}

var faultyCommits []text.FailingCommit

for _, commitHash := range filteredCommits {
commitObject, commitErr := gitRepo.Commit(commitHash)

if commitErr != nil {
return nil, commitErr
}

parsedCommit := quoad.ParseCommitMessage(commitObject.Message)

textErr := text.CheckMessageTitle(parsedCommit, pipeline.options.Strict)

if textErr != nil {
faultyCommits = append(faultyCommits, text.FailingCommit{Hash: commitHash.String(), Message: parsedCommit.Heading, Error: textErr})
}
}

if len(faultyCommits) != 0 {
failingCommitTable := text.FormatFailingCommits(faultyCommits)
failingCommitTable.SetOutputMirror(os.Stdout)
failingCommitTable.Render()

pipeline.Logger.Printf("%v of %v commits are not conventional commit compliant\n", aurora.Red(len(faultyCommits)), aurora.Red(len(commits)))

pipeline.Logger.Print("\nExpected format is for example: chore(ci): this is a test\n")
pipeline.Logger.Print("Please see https://www.conventionalcommits.org for help on how to structure commits\n\n")

return nil, errors.New(aurora.Red("Not all commits are conventional commits, please check the commits listed above").String())
}

return &dispatcher.PipelineSuccess{
Message: aurora.Sprintf(aurora.Green("All %v commits are conventional commit compliant\n"), len(filteredCommits)),
PipelineName: pipeline.Name(),
}, nil
}
15 changes: 7 additions & 8 deletions internal/dispatcher/dispatcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,25 @@ func TestDispatcher(t *testing.T) {

type TestPipeline struct {
TestName string
TestFn func(chan PipelineError) *PipelineSuccess
TestFn func() (*PipelineSuccess, error)
}

func (p TestPipeline) Name() string {
return p.TestName
}

func (p TestPipeline) Run(errChannel chan PipelineError) *PipelineSuccess {
return p.TestFn(errChannel)
func (p TestPipeline) Run() (*PipelineSuccess, error) {
return p.TestFn()
}

func successPipeline(chan PipelineError) *PipelineSuccess {
func successPipeline() (*PipelineSuccess, error) {
return &PipelineSuccess{
PipelineName: "pipeline1",
Message: "It succeeded",
}
}, nil
}

func failPipeline(errChan chan PipelineError) *PipelineSuccess {
errChan <- PipelineError{PipelineName: "pipeline2", Data: []FailureData{{Name: "test", Value: "test2"}}, Error: errors.New("some error")}
func failPipeline() (*PipelineSuccess, error) {

return nil
return nil, errors.New("some error")
}
2 changes: 1 addition & 1 deletion internal/dispatcher/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package dispatcher
// Pipeliner interface describes the requirements for pipelines the dispatcher can run
type Pipeliner interface {
Name() string
Run(chan PipelineError) *PipelineSuccess
Run() (*PipelineSuccess, error)
}

// FailureData is used to build the table output
Expand Down
9 changes: 8 additions & 1 deletion internal/dispatcher/work.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ func (dispatch *Dispatcher) work(

if more {
dispatch.debugLogger.Printf("Starting pipeline: %s", pipeline.Name())
success := pipeline.Run(errorChannel)
success, err := pipeline.Run()

if err != nil {
errorChannel <- PipelineError{
Error: err,
PipelineName: pipeline.Name(),
}
}

if success != nil {
successChan <- *success
Expand Down
Loading

0 comments on commit 453b908

Please sign in to comment.