diff --git a/go.mod b/go.mod index 36b2217..a0ba35b 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,14 @@ module github.com/gruntwork-io/git-xargs go 1.18 require ( + github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 github.com/go-git/go-git/v5 v5.6.1 github.com/google/go-github/v43 v43.0.0 github.com/gruntwork-io/go-commons v0.8.2 github.com/pterm/pterm v0.12.42 github.com/sirupsen/logrus v1.7.0 github.com/stretchr/testify v1.7.0 + github.com/tcnksm/go-gitconfig v0.1.2 github.com/urfave/cli v1.22.5 golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 ) @@ -17,7 +19,6 @@ require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect github.com/cloudflare/circl v1.1.0 // indirect github.com/containerd/console v1.0.3 // indirect diff --git a/go.sum b/go.sum index e229c00..a7f18b8 100644 --- a/go.sum +++ b/go.sum @@ -420,6 +420,7 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -518,6 +519,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tcnksm/go-gitconfig v0.1.2 h1:iiDhRitByXAEyjgBqsKi9QU4o2TNtv9kPP3RgPgXBPw= +github.com/tcnksm/go-gitconfig v0.1.2/go.mod h1:/8EhP4H7oJZdIPyT+/UIsG87kTzrzM4UsLGSItWYCpE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -928,6 +931,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/repository/repo-operations.go b/repository/repo-operations.go index d1f3761..ad449ba 100644 --- a/repository/repo-operations.go +++ b/repository/repo-operations.go @@ -10,10 +10,12 @@ import ( "strings" "time" + "github.com/ProtonMail/go-crypto/openpgp" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/sirupsen/logrus" + gitconfig "github.com/tcnksm/go-gitconfig" "github.com/google/go-github/v43/github" @@ -306,6 +308,60 @@ func commitLocalChanges(status git.Status, config *config.GitXargsConfig, reposi "Repo": remoteRepository.GetName(), }).Debug("Local repository worktree no longer clean, will stage and add new files and commit changes") + signingKeyID, err := gitconfig.Global("user.signingkey") + + // Define the commit options with the All field set to true + commitOps := &git.CommitOptions{ + All: true, + } + + // If user.signingkey is defined and there's no error retrieving it, add the signing key to the commit options + if err == nil && signingKeyID != "" { + // Log the found signing key ID + logger.WithFields(logrus.Fields{ + "SigningKeyID": signingKeyID, + }).Debug("Found signing key in git global config, will attempt to use it for commit.") + + gpgProgramPath, err := gitconfig.Global("gpg.program") + if err != nil { + gpgProgramPath, err = exec.LookPath("gpg") + if err != nil { + logger.WithFields(logrus.Fields{ + "Error": err.Error(), + }).Debug("Failed to locate GPG program.") + return err + } + } + logger.WithFields(logrus.Fields{ + "GPGProgramPath": gpgProgramPath, + }).Debug("Located GPG program.") + + // Export the signing key + keyData, err := exec.Command(gpgProgramPath, "--export-secret-keys", "--armor", signingKeyID).Output() + if err != nil { + logger.WithFields(logrus.Fields{ + "Error": err.Error(), + "GPGProgramPath": gpgProgramPath, + "SigningKeyID": signingKeyID, + }).Debug("Failed to export signing key.") + return err + } + logger.Debug("Successfully exported signing key.") + + // Load the exported key into an *openpgp.Entity object + keyRing, err := openpgp.ReadArmoredKeyRing(bytes.NewReader(keyData)) + if err != nil { + logger.WithFields(logrus.Fields{ + "Error": err.Error(), + }).Debug("Failed to load signing key into openpgp.Entity object.") + return err + } + logger.Debug("Successfully loaded signing key into openpgp.Entity object.") + + // Set the SignKey field in the commitOps object if we have a signing key to use in our git config + commitOps.SignKey = keyRing[0] + } + // Track the fact that worktree changes were made following execution config.Stats.TrackSingle(stats.WorktreeStatusDirty, remoteRepository) @@ -331,9 +387,6 @@ func commitLocalChanges(status git.Status, config *config.GitXargsConfig, reposi // With all our untracked files staged, we can now create a commit, passing the All // option when configuring our commit option so that all modified and deleted files // will have their changes committed - commitOps := &git.CommitOptions{ - All: true, - } _, commitErr := worktree.Commit(config.CommitMessage, commitOps)