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  }