From 6859e011926b60a720913b6154ebd0c56f02306f Mon Sep 17 00:00:00 2001 From: Layla Manley Date: Tue, 5 Dec 2023 19:03:27 +0000 Subject: [PATCH] commit 1 --- .devcontainer/Dockerfile | 6 +++ .devcontainer/devcontainer.json | 24 +++++++++++ git/cmd.go | 19 +++++++++ git/cmd_test.go | 28 +++++++++++++ git/commit.go | 36 +++++++++++++++++ git/git.go | 36 +++++++++++++++++ git/pull.go | 23 +++++++++++ git/squash.go | 72 +++++++++++++++++++++++++++++++++ go.mod | 11 +++++ go.sum | 11 +++++ magefile.go | 22 ++++++++++ 11 files changed, 288 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 git/cmd.go create mode 100644 git/cmd_test.go create mode 100644 git/commit.go create mode 100644 git/git.go create mode 100644 git/pull.go create mode 100644 git/squash.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 magefile.go diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..5d2b5e2 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,6 @@ +FROM mcr.microsoft.com/devcontainers/go:1-1.21-bullseye + +# Install Magefile from GitHub release +ARG MAGE_VERSION=1.15.0 + +RUN wget -q https://github.com/magefile/mage/releases/download/v${MAGE_VERSION}/mage_${MAGE_VERSION}_Linux-64bit.tar.gz -O - | tar -xz -C /usr/local/bin diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..0f056d3 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,24 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/go +{ + "name": "Go", + + "build": { + "dockerfile": "Dockerfile" + } + + // Features to add to the dev container. More info: https://containers.dev/features. + //"features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "go version", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/git/cmd.go b/git/cmd.go new file mode 100644 index 0000000..788ece7 --- /dev/null +++ b/git/cmd.go @@ -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 +} diff --git a/git/cmd_test.go b/git/cmd_test.go new file mode 100644 index 0000000..2e3191c --- /dev/null +++ b/git/cmd_test.go @@ -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") +} diff --git a/git/commit.go b/git/commit.go new file mode 100644 index 0000000..5a5d830 --- /dev/null +++ b/git/commit.go @@ -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) +} diff --git a/git/git.go b/git/git.go new file mode 100644 index 0000000..b778f30 --- /dev/null +++ b/git/git.go @@ -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 +} diff --git a/git/pull.go b/git/pull.go new file mode 100644 index 0000000..163b31f --- /dev/null +++ b/git/pull.go @@ -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 +} diff --git a/git/squash.go b/git/squash.go new file mode 100644 index 0000000..3a13b0a --- /dev/null +++ b/git/squash.go @@ -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 +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..be03d4a --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module gitea.layla.gg/layla/gsquash + +go 1.21 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/magefile/mage v1.15.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..77634e8 --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= +github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/magefile.go b/magefile.go new file mode 100644 index 0000000..18a8b13 --- /dev/null +++ b/magefile.go @@ -0,0 +1,22 @@ +//go:build mage + +package main + +import ( + "github.com/magefile/mage/sh" +) + +// Build builds the binary +func Build() error { + return sh.RunV("go", "build", "-o", "gsquash", "main.go") +} + +// Install installs the binary +func Install() error { + return sh.RunV("go", "install") +} + +// Test runs the tests +func Test() error { + return sh.RunV("go", "test", "./...") +}