Skip to content

Commit

Permalink
feat(policy): add policy enforcement; enforce git commit policy (side…
Browse files Browse the repository at this point in the history
…rolabs#17)

feat(policy): add policy enforcement; enforce git commit policy
  • Loading branch information
andrewrynhard authored Jul 6, 2017
1 parent 9927a05 commit 03caad0
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 59 deletions.
16 changes: 16 additions & 0 deletions conform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ metadata:

default: image

policies:
git:
types:
- "docs"
- "style"
- "refactor"
- "perf"
- "test"
- "chore"
scopes:
- "ci"
- "docker"
- "git"
- "policy"
- "*"

scripts:
init : |
#!/bin/bash
Expand Down
12 changes: 12 additions & 0 deletions conform/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Config struct {
Debug bool
Default *string `yaml:"default"`
Metadata *Metadata `yaml:"metadata"`
Policies *Policies `yaml:"policies"`
Scripts map[string]string `yaml:"scripts"`
Templates map[string]string `yaml:"templates"`
Rules map[string]*Rule `yaml:"rules"`
Expand All @@ -23,6 +24,17 @@ type Metadata struct {
Registry *string `yaml:"registry"`
}

// Policies contains policies that are enforced.
type Policies struct {
Git *Git `yaml:"git"`
}

// Git contains git specific policies.
type Git struct {
Types []string `yaml:"types"`
Scopes []string `yaml:"scopes"`
}

// Rule contains rules.
type Rule struct {
Templates []string `yaml:"templates"`
Expand Down
89 changes: 31 additions & 58 deletions conform/enforce.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import (
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"text/template"

"github.com/Masterminds/sprig"
"github.com/autonomy/conform/conform/config"
"github.com/autonomy/conform/conform/git"
"github.com/autonomy/conform/conform/policy"
)

// Enforcer performs all the build actions for a rule.
Expand All @@ -29,10 +29,6 @@ func NewEnforcer(rule string) (enforcer *Enforcer, err error) {
if err != nil {
return
}
err = exportAll(gitInfo)
if err != nil {
return
}
date := []byte{}
if gitInfo.IsTag {
date, err = exec.Command("/bin/date").Output()
Expand Down Expand Up @@ -146,8 +142,38 @@ func (e *Enforcer) ExecuteScript(script string) error {
return fmt.Errorf("Script %q is not defined in conform.yaml", script)
}

// EnforcePolicies enforces all defined polcies. In the case that the working
// tree is dirty, all git policies are skipped.
func (e *Enforcer) EnforcePolicies() {
if !e.GitInfo.IsDirty {
enforceGitPolicy(
e.GitInfo,
&git.ConventionalCommitsOptions{
Message: e.GitInfo.Message,
Types: e.config.Policies.Git.Types,
Scopes: e.config.Policies.Git.Scopes,
},
)
}
}

func enforceGitPolicy(p policy.Policy, opts *git.ConventionalCommitsOptions) {
report, err := p.Compliance(opts)
if err != nil {
fmt.Print(err)
os.Exit(1)
}
if !report.Valid {
for _, err := range report.Errors {
fmt.Printf("%s", err)
os.Exit(1)
}
}
}

// ExecuteRule performs all the relevant actions specified in its' declaration.
func (e *Enforcer) ExecuteRule() error {
e.EnforcePolicies()
if t, ok := e.config.Rules[e.rule]; ok {
fmt.Printf("Enforcing %q\n", e.rule)
for _, s := range t.Before {
Expand Down Expand Up @@ -177,59 +203,6 @@ func (e *Enforcer) ExecuteRule() error {
return fmt.Errorf("Rule %q is not defined in conform.yaml", e.rule)
}

func exportAll(gitInfo *git.Info) (err error) {
fmt.Printf("Branch: %s\n", gitInfo.Branch)
err = ExportConformVar("branch", gitInfo.Branch)
if err != nil {
return
}
fmt.Printf("SHA: %s\n", gitInfo.SHA)
err = ExportConformVar("sha", gitInfo.SHA)
if err != nil {
return
}
fmt.Printf("Tag: %s\n", gitInfo.Tag)
err = ExportConformVar("tag", gitInfo.Tag)
if err != nil {
return
}
fmt.Printf("IsTag: %s\n", strconv.FormatBool(gitInfo.IsTag))
err = ExportConformVar("is_tag", strconv.FormatBool(gitInfo.IsTag))
if err != nil {
return
}
fmt.Printf("Prerelease: %s\n", gitInfo.Prerelease)
err = ExportConformVar("prerelease", gitInfo.Prerelease)
if err != nil {
return
}
fmt.Printf("IsPrerelease: %s\n", strconv.FormatBool(gitInfo.IsPrerelease))
err = ExportConformVar("is_prerelease", strconv.FormatBool(gitInfo.IsPrerelease))
if err != nil {
return
}
fmt.Printf("Status: \n%s\n", strings.TrimRight(gitInfo.Status, "\n"))
err = ExportConformVar("status", strconv.FormatBool(gitInfo.IsDirty))
if err != nil {
return
}
fmt.Printf("IsDirty: %s\n", strconv.FormatBool(gitInfo.IsDirty))
err = ExportConformVar("is_dirty", strconv.FormatBool(gitInfo.IsDirty))
if err != nil {
return
}

return
}

// ExportConformVar exports variable prefixed with CONFORM_
func ExportConformVar(name, value string) (err error) {
variable := fmt.Sprintf("CONFORM_%s", strings.ToUpper(name))
err = os.Setenv(variable, value)

return
}

// FormatImageNameDirty formats the image name.
func (e *Enforcer) FormatImageNameDirty() string {
return fmt.Sprintf("%s:%s", *e.config.Metadata.Repository, "dirty")
Expand Down
98 changes: 97 additions & 1 deletion conform/git/git.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package git

import (
"fmt"
"strconv"
"strings"

"github.com/Masterminds/semver"
// git "github.com/libgit2/git2go"
"github.com/autonomy/conform/conform/utilities"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
)
Expand All @@ -14,6 +18,7 @@ type Info struct {
Tag string
Prerelease string
Status string
Message string
IsTag bool
IsPrerelease bool
IsDirty bool
Expand Down Expand Up @@ -51,12 +56,18 @@ func NewInfo() (info *Info, err error) {
return
}

message, err := Message(repo, isDirty)
if err != nil {
return
}

info = &Info{
Branch: branch,
SHA: sha,
Tag: tag,
Prerelease: prerelease,
Status: status,
Message: message,
IsTag: isTag,
IsPrerelease: isPrerelease,
IsDirty: isDirty,
Expand All @@ -75,6 +86,12 @@ func Branch(repo *git.Repository) (branch string, err error) {
branch = ref.Name().Short()
}

fmt.Printf("Branch: %s\n", branch)
err = utilities.ExportConformVar("branch", branch)
if err != nil {
return
}

return
}

Expand All @@ -86,6 +103,12 @@ func SHA(repo *git.Repository) (sha string, err error) {
}
sha = ref.Hash().String()[0:7]

fmt.Printf("SHA: %s\n", sha)
err = utilities.ExportConformVar("sha", sha)
if err != nil {
return
}

return
}

Expand All @@ -111,6 +134,17 @@ func Tag(repo *git.Repository) (tag string, isTag bool, err error) {
return
}

fmt.Printf("Tag: %s\n", tag)
err = utilities.ExportConformVar("tag", tag)
if err != nil {
return
}
fmt.Printf("IsTag: %s\n", strconv.FormatBool(isTag))
err = utilities.ExportConformVar("is_tag", strconv.FormatBool(isTag))
if err != nil {
return
}

return
}

Expand All @@ -128,6 +162,17 @@ func Prerelease(tag string, isTag bool) (prerelease string, isPrerelease bool, e
}
}

fmt.Printf("Prerelease: %s\n", prerelease)
err = utilities.ExportConformVar("prerelease", prerelease)
if err != nil {
return
}
fmt.Printf("IsPrerelease: %s\n", strconv.FormatBool(isPrerelease))
err = utilities.ExportConformVar("is_prerelease", strconv.FormatBool(isPrerelease))
if err != nil {
return
}

return
}

Expand All @@ -138,12 +183,63 @@ func Status(repo *git.Repository) (status string, isDirty bool, err error) {
return
}
worktreeStatus, err := worktree.Status()
if err != nil {
return
}
if worktreeStatus.IsClean() {
status = " nothing to commit, working tree clean"
} else {
isDirty = true
status = worktreeStatus.String()
}

fmt.Printf("Status: \n%s\n", strings.TrimRight(status, "\n"))
err = utilities.ExportConformVar("status", strconv.FormatBool(isDirty))
if err != nil {
return
}
fmt.Printf("IsDirty: %s\n", strconv.FormatBool(isDirty))
err = utilities.ExportConformVar("is_dirty", strconv.FormatBool(isDirty))
if err != nil {
return
}

return
}

// Message returns the commit message. In the case that a commit has multiple
// parents, the message of the last parent is returned.
func Message(repo *git.Repository, isDirty bool) (message string, err error) {
ref, err := repo.Head()
if err != nil {
return
}
commit, err := repo.CommitObject(ref.Hash())
if err != nil {
return
}
if commit.NumParents() != 1 {
parents := commit.Parents()
for i := 1; i <= commit.NumParents(); i++ {
next, err := parents.Next()
if err != nil {
return "", err
}
if i == commit.NumParents() {
message = next.Message
}
}
} else {
message = commit.Message
}

if !isDirty {
fmt.Printf("Message: %s\n", strings.TrimRight(message, "\n"))
err = utilities.ExportConformVar("message", message)
if err != nil {
return
}
}

return
}
Loading

0 comments on commit 03caad0

Please sign in to comment.