github.com/FollowTheProcess/tag@v0.4.2/git/git.go (about) 1 // Package git implements tags interface with git in order to interact 2 // with tags and make commits. 3 package git 4 5 import ( 6 "bytes" 7 "errors" 8 "os/exec" 9 "strings" 10 ) 11 12 var ( 13 gitCommand = exec.Command // An internal reassignment of exec.Command for testing 14 ErrNoTagsFound = errors.New("No tags found") // ErrNoTagsFound is the signal that the current repo has no tags 15 ) 16 17 // Commit performs a git commit with a message. 18 func Commit(message string) (string, error) { 19 cmd := gitCommand("git", "commit", "-m", message) 20 out, err := cmd.CombinedOutput() 21 return string(out), err 22 } 23 24 // Add stages all files. 25 func Add() error { 26 cmd := gitCommand("git", "add", "-A") 27 return cmd.Run() 28 } 29 30 // Push performs a git push to the configured remote. 31 func Push() (string, error) { 32 cmd := gitCommand("git", "push", "--follow-tags", "--atomic") 33 out, err := cmd.CombinedOutput() 34 if err != nil { 35 return string(out), err 36 } 37 return string(out), nil 38 } 39 40 // ListTags lists all tags in descending order (latest at the top). 41 func ListTags(limit int) (tags string, limitHit bool, err error) { 42 // git will return nothing if there are no tags 43 cmd := gitCommand("git", "tag", "--sort=-version:refname") 44 out, err := cmd.CombinedOutput() 45 if bytes.Equal(out, []byte("")) { 46 return "", false, ErrNoTagsFound 47 } 48 lines := bytes.Split(out, []byte("\n")) 49 if len(lines) > limit { 50 limitHit = true 51 lines = lines[:limit] 52 } 53 return string(bytes.Join(lines, []byte("\n"))), limitHit, err 54 } 55 56 // LatestTag returns the name of the latest tag. 57 func LatestTag() (string, error) { 58 cmd := gitCommand("git", "describe", "--tags", "--abbrev=0") 59 out, err := cmd.CombinedOutput() 60 if bytes.Contains(out, []byte("fatal: No names found")) { 61 return "", ErrNoTagsFound 62 } 63 return strings.TrimSpace(string(out)), err 64 } 65 66 // CreateTag creates an annotated git tag with an optional message 67 // if the message is an empty string, the tag name will be used. 68 func CreateTag(tag, message string) (string, error) { 69 if message == "" { 70 message = tag 71 } 72 cmd := gitCommand("git", "tag", "-a", tag, "-m", message) 73 out, err := cmd.CombinedOutput() 74 return string(out), err 75 } 76 77 // IsRepo detects whether or not we are currently in a git repo. 78 func IsRepo() bool { 79 cmd := gitCommand("git", "rev-parse", "--is-inside-work-tree") 80 out, err := cmd.CombinedOutput() 81 if err != nil { 82 return false 83 } 84 if !bytes.Equal(bytes.TrimSpace(bytes.ToLower(out)), []byte("true")) { 85 return false 86 } 87 return true 88 } 89 90 // Branch gets the name of the current git branch. 91 func Branch() (string, error) { 92 cmd := gitCommand("git", "rev-parse", "--abbrev-ref", "HEAD") 93 out, err := cmd.CombinedOutput() 94 if err != nil { 95 return string(out), err 96 } 97 return strings.TrimSpace(string(out)), nil 98 } 99 100 // IsDirty checks whether or not the working tree is dirty. 101 func IsDirty() (bool, error) { 102 cmd := gitCommand("git", "status", "--porcelain") 103 out, err := cmd.CombinedOutput() 104 if err != nil { 105 return false, err 106 } 107 status := strings.TrimSpace(string(out)) 108 if len(status) > 1 { 109 return true, nil 110 } 111 return false, nil 112 }