This commit is contained in:
2023-12-05 19:03:27 +00:00
commit 6859e01192
11 changed files with 288 additions and 0 deletions

19
git/cmd.go Normal file
View File

@ -0,0 +1,19 @@
package git
import "os/exec"
// Execute runs a git command and returns the stdout
func (g *Git) Execute(args ...string) (string, error) {
cmd := exec.Command("git", args...)
if g.WorkingDir != "" {
cmd.Dir = g.WorkingDir
}
// Run and return stdout
out, err := cmd.Output()
if err != nil {
return "", err
}
return string(out), nil
}

28
git/cmd_test.go Normal file
View File

@ -0,0 +1,28 @@
package git
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestExecute runs a unit test with testify for git.Execute
func TestExecute(t *testing.T) {
require := require.New(t)
assert := assert.New(t)
// Create a new git
git := NewGit(&NewGitInput{
Executable: "git",
})
// Run the command
out, err := git.Execute("version")
// Assert that the command ran successfully
require.NoError(err)
// Assert that the output contains 'git version'
assert.Contains(out, "git version")
}

36
git/commit.go Normal file
View File

@ -0,0 +1,36 @@
package git
import "strconv"
// GetHash returns the commit hash for the current HEAD
func (g *Git) GetHash() (string, error) {
out, err := g.Execute("rev-parse", "HEAD")
if err != nil {
return "", err
}
return out, nil
}
// GetCommitRemote returns the commit hash for the current HEAD on the remote
func (g *Git) GetCommitRemote() (string, error) {
out, err := g.Execute("ls-remote", "origin", "HEAD")
if err != nil {
return "", err
}
return out, nil
}
// GetCommitsAhead returns the number of commits ahead of main
func (g *Git) GetCommitsAhead() (int, error) {
out, err := g.Execute("rev-list", "--count", "HEAD", "^"+g.MainBranch)
if err != nil {
return 0, err
}
return strconv.Atoi(out)
}

36
git/git.go Normal file
View File

@ -0,0 +1,36 @@
package git
type Git struct {
// Executable is the path to the git executable
Executable string
// WorkingDir is the path to the working directory
WorkingDir string
// MainBranch is the name of the main branch
MainBranch string
}
// NewGitInput is the input type for NewGit
type NewGitInput struct {
// Executable is the path to the git executable
Executable string
// WorkingDir is the path to the working directory
WorkingDir *string
// MainBranch is the name of the main branch
MainBranch string
}
// NewGit creates a new Git
func NewGit(input *NewGitInput) *Git {
git := &Git{
Executable: input.Executable,
}
if git.Executable == "" {
git.Executable = "git"
}
if git.MainBranch == "" {
git.MainBranch = "main"
}
return git
}

23
git/pull.go Normal file
View File

@ -0,0 +1,23 @@
package git
// Pull pulls the latest changes from the remote
func (g *Git) Pull() error {
_, err := g.Execute("pull")
if err != nil {
return err
}
return nil
}
// PullMain pulls the latest changes from the remote main branch
func (g *Git) PullMain() error {
_, err := g.Execute("pull", "origin", g.MainBranch)
if err != nil {
return err
}
return nil
}

72
git/squash.go Normal file
View File

@ -0,0 +1,72 @@
package git
import (
"strconv"
"strings"
)
// SquashInput contains the input for Squash
type SquashInput struct {
Message *string
}
// Squash squashes everything every commit ahead of main into one commit
func (g *Git) Squash(input SquashInput) error {
// Get the current commit hash
hash, err := g.GetHash()
if err != nil {
return err
}
// Get the commit hash on the remote
remote, err := g.GetCommitRemote()
if err != nil {
return err
}
// If the hashes are the same, there's nothing to squash
if hash == remote {
return nil
}
// Get the number of commits ahead of main
commits, err := g.GetCommitsAhead()
if err != nil {
return err
}
message := ""
if input.Message != nil {
message = *input.Message
} else {
// Get array of commit messages
out, err := g.Execute("log", "--pretty=format:%s", "-n", strconv.Itoa(commits))
if err != nil {
return err
}
messages := strings.Split(out, "\n")
// Add `-` to each message
for i, m := range messages {
messages[i] = "- " + m
}
// Join the messages
message = strings.Join(messages, "\n")
// Add header comment
message = "# Squashed " + strconv.Itoa(commits) + " commits\n\n" + message
}
// Squash the current commit into the previous commits
_, err = g.Execute("rebase", "-i", hash+"~"+strconv.Itoa(commits), "-x", "git commit --amend -m \""+message+"\" ")
if err != nil {
return err
}
return nil
}