Skip to content

Commit a5e2a44

Browse files
authored
Add functions for interacting with git (#55)
1 parent 00b17ce commit a5e2a44

File tree

12 files changed

+932
-196
lines changed

12 files changed

+932
-196
lines changed

.circleci/config.yml

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
defaults: &defaults
2-
docker:
3-
- image: 087285199408.dkr.ecr.us-east-1.amazonaws.com/circle-ci-test-image-base:tf14.4
4-
version: 2
2+
machine:
3+
enabled: true
4+
image: ubuntu-2004:202111-02
5+
env: &env
6+
environment:
7+
GRUNTWORK_INSTALLER_VERSION: v0.0.36
8+
TERRATEST_LOG_PARSER_VERSION: v0.40.1
9+
TERRAFORM_AWS_CI_VERSION: v0.41.1
10+
TFENV_VERSION: NONE
11+
TERRAFORM_VERSION: 1.0.11
12+
TERRAGRUNT_VERSION: NONE
13+
PACKER_VERSION: NONE
14+
GOLANG_VERSION: 1.17
15+
GO111MODULE: auto
16+
version: 2.1
517
jobs:
618
test:
719
<<: *defaults
20+
<<: *env
821
steps:
922
- checkout
23+
- run:
24+
name: install gruntwork utils
25+
command: |
26+
curl -Ls https://raw.githubusercontent.com/gruntwork-io/gruntwork-installer/master/bootstrap-gruntwork-installer.sh | bash /dev/stdin --version "${GRUNTWORK_INSTALLER_VERSION}"
27+
gruntwork-install --module-name "gruntwork-module-circleci-helpers" --repo "https://github.com/gruntwork-io/terraform-aws-ci" --tag "$TERRAFORM_AWS_CI_VERSION"
28+
gruntwork-install --binary-name "terratest_log_parser" --repo "https://github.com/gruntwork-io/terratest" --tag "${TERRATEST_LOG_PARSER_VERSION}"
29+
configure-environment-for-gruntwork-module \
30+
--tfenv-version ${TFENV_VERSION} \
31+
--terraform-version ${TERRAFORM_VERSION} \
32+
--terragrunt-version ${TERRAGRUNT_VERSION} \
33+
--packer-version ${PACKER_VERSION} \
34+
--go-version ${GOLANG_VERSION}
1035
- run: run-go-tests
1136
workflows:
1237
version: 2

git/auth.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package git
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/gruntwork-io/go-commons/shell"
7+
"github.com/hashicorp/go-multierror"
8+
)
9+
10+
// ConfigureForceHTTPS configures git to force usage of https endpoints instead of SSH based endpoints for the three
11+
// primary VCS platforms (GitHub, GitLab, BitBucket).
12+
func ConfigureForceHTTPS() error {
13+
opts := shell.NewShellOptions()
14+
15+
var allErr error
16+
17+
for _, host := range []string{"github.com", "gitlab.com", "bitbucket.org"} {
18+
if err := shell.RunShellCommand(
19+
opts,
20+
"git", "config", "--global",
21+
fmt.Sprintf("url.https://%s.insteadOf", host),
22+
fmt.Sprintf("ssh://git@%s", host),
23+
); err != nil {
24+
allErr = multierror.Append(allErr, err)
25+
}
26+
27+
if err := shell.RunShellCommand(
28+
opts,
29+
"git", "config", "--global",
30+
fmt.Sprintf("url.https://%s/.insteadOf", host),
31+
fmt.Sprintf("git@%s:", host),
32+
); err != nil {
33+
allErr = multierror.Append(allErr, err)
34+
}
35+
}
36+
return allErr
37+
}
38+
39+
// ConfigureHTTPSAuth configures git with username and password to authenticate with the given VCS host when interacting
40+
// with git over HTTPS. This uses the cache credentials store to configure the credentials. Refer to the git
41+
// documentation on credentials storage for more information:
42+
// https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage
43+
func ConfigureHTTPSAuth(gitUsername string, gitOauthToken string, vcsHost string) error {
44+
opts := shell.NewShellOptions()
45+
if err := shell.RunShellCommand(
46+
opts,
47+
"git", "config", "--global",
48+
"credential.helper",
49+
"cache --timeout 3600",
50+
); err != nil {
51+
return err
52+
}
53+
54+
if gitUsername == "" {
55+
gitUsername = "git"
56+
}
57+
credentialsStoreInput := fmt.Sprintf(`protocol=https
58+
host=%s
59+
username=%s
60+
password=%s`, vcsHost, gitUsername, gitOauthToken)
61+
return shell.RunShellCommandWithInput(opts, credentialsStoreInput, "git", "credential-cache", "store")
62+
}

git/auth_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package git
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/gruntwork-io/terratest/modules/docker"
8+
terragit "github.com/gruntwork-io/terratest/modules/git"
9+
"github.com/gruntwork-io/terratest/modules/random"
10+
)
11+
12+
func TestIntegrationGitAuth(t *testing.T) {
13+
t.Parallel()
14+
15+
tag := "gruntwork-io/go-commons:" + strings.ToLower(random.UniqueId())
16+
ref := terragit.GetCurrentGitRef(t)
17+
docker.Build(t, "./test", &docker.BuildOptions{
18+
Tags: []string{tag},
19+
BuildArgs: []string{"repo_ref=" + ref},
20+
})
21+
docker.Run(t, tag, &docker.RunOptions{
22+
Remove: true,
23+
EnvironmentVariables: []string{"GITHUB_OAUTH_TOKEN"},
24+
})
25+
}

git/doc.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Package git contains routines for interacting with git over the CLI. Unlike go-git, this is not a pure go library for
2+
// interacting with git, and relies on the git command line being available locally. This is meant to provide high level
3+
// interfaces used throughout various Gruntwork CLIs.
4+
//
5+
// NOTE: The tests for these packages are intentionally stored in a separate test folder, rather than the go
6+
// converntional style of source_test.go files. This is done to ensure that the tests for the packages are run in a
7+
// separate docker container, as many functions in this package pollute the global git configuration.
8+
package git

git/error.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package git
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// TargetDirectoryNotExistsErr is returned when the target directory of the git commands does not exist or is not a
8+
// directory.
9+
type TargetDirectoryNotExistsErr struct {
10+
dirPath string
11+
}
12+
13+
func (err TargetDirectoryNotExistsErr) Error() string {
14+
return fmt.Sprintf("%s does not exist or is not a directory", err.dirPath)
15+
}

git/git.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package git
2+
3+
import (
4+
"github.com/gruntwork-io/go-commons/files"
5+
"github.com/gruntwork-io/go-commons/shell"
6+
)
7+
8+
// Clone runs git clone to clone the specified repository into the given target directory.
9+
func Clone(repo string, targetDir string) error {
10+
if !files.IsDir(targetDir) {
11+
return TargetDirectoryNotExistsErr{dirPath: targetDir}
12+
}
13+
14+
opts := shell.NewShellOptions()
15+
return shell.RunShellCommand(opts, "git", "clone", repo, targetDir)
16+
}
17+
18+
// Checkout checks out the given ref for the repo cloned in the target directory.
19+
func Checkout(ref string, targetDir string) error {
20+
if !files.IsDir(targetDir) {
21+
return TargetDirectoryNotExistsErr{dirPath: targetDir}
22+
}
23+
24+
opts := shell.NewShellOptions()
25+
opts.WorkingDir = targetDir
26+
return shell.RunShellCommand(opts, "git", "checkout", ref)
27+
}

git/git_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package git
2+
3+
import (
4+
"io/ioutil"
5+
"path/filepath"
6+
"testing"
7+
8+
"github.com/gruntwork-io/go-commons/files"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestGitClone(t *testing.T) {
14+
t.Parallel()
15+
16+
tmpDir, err := ioutil.TempDir("", "git-test")
17+
require.NoError(t, err)
18+
require.NoError(t, Clone("https://github.com/gruntwork-io/go-commons.git", tmpDir))
19+
assert.True(t, files.FileExists(filepath.Join(tmpDir, "LICENSE.txt")))
20+
}
21+
22+
func TestGitCheckout(t *testing.T) {
23+
t.Parallel()
24+
25+
tmpDir, err := ioutil.TempDir("", "git-test")
26+
require.NoError(t, err)
27+
require.NoError(t, Clone("https://github.com/gruntwork-io/go-commons.git", tmpDir))
28+
require.NoError(t, Checkout("v0.10.0", tmpDir))
29+
assert.False(t, files.FileExists(filepath.Join(tmpDir, "git", "git_test.go")))
30+
}

git/test/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM golang:1.17
2+
ARG repo_ref="master"
3+
4+
# Clone the go-commons repo and checkout the desired ref
5+
RUN mkdir -p /workspace \
6+
&& git clone https://github.com/gruntwork-io/go-commons.git /workspace/go-commons \
7+
&& git -C /workspace/go-commons checkout ${repo_ref}
8+
9+
WORKDIR /workspace/go-commons
10+
CMD ["go", "test", "-v", "-tags", "gittest", "./git/test"]

git/test/auth_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//go:build gittest
2+
3+
package gittest
4+
5+
import (
6+
"io/ioutil"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
11+
"github.com/gruntwork-io/go-commons/files"
12+
"github.com/gruntwork-io/go-commons/git"
13+
"github.com/gruntwork-io/terratest/modules/environment"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
const (
19+
gitPATEnvName = "GITHUB_OAUTH_TOKEN"
20+
)
21+
22+
// NOTE: All these tests should be run in the provided docker environment to avoid polluting the local git configuration
23+
// settings. The tests will assert that it is running in the docker environment, and will fail if it is not.
24+
25+
func TestHTTPSAuth(t *testing.T) {
26+
t.Parallel()
27+
28+
currentDir, err := os.Getwd()
29+
require.NoError(t, err)
30+
require.Equal(t, "/workspace/go-commons/git/test", currentDir)
31+
32+
environment.RequireEnvVar(t, gitPATEnvName)
33+
gitPAT := os.Getenv(gitPATEnvName)
34+
require.NoError(t, git.ConfigureHTTPSAuth("git", gitPAT, "github.com"))
35+
36+
tmpDir, err := ioutil.TempDir("", "git-test")
37+
require.NoError(t, err)
38+
require.NoError(t, git.Clone("https://github.com/gruntwork-io/terraform-aws-lambda.git", tmpDir))
39+
assert.True(t, files.IsDir(filepath.Join(tmpDir, "modules/lambda")))
40+
}
41+
42+
func TestForceHTTPS(t *testing.T) {
43+
t.Parallel()
44+
45+
currentDir, err := os.Getwd()
46+
require.NoError(t, err)
47+
require.Equal(t, "/workspace/go-commons/git/test", currentDir)
48+
49+
environment.RequireEnvVar(t, gitPATEnvName)
50+
gitPAT := os.Getenv(gitPATEnvName)
51+
require.NoError(t, git.ConfigureHTTPSAuth("git", gitPAT, "github.com"))
52+
require.NoError(t, git.ConfigureForceHTTPS())
53+
54+
tmpDir, err := ioutil.TempDir("", "git-test")
55+
require.NoError(t, err)
56+
require.NoError(t, git.Clone("git@github.com:gruntwork-io/terraform-aws-lambda.git", tmpDir))
57+
assert.True(t, files.IsDir(filepath.Join(tmpDir, "modules/lambda")))
58+
}

go.mod

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ module github.com/gruntwork-io/go-commons
33
go 1.13
44

55
require (
6-
github.com/agext/levenshtein v1.2.3 // indirect
7-
github.com/aws/aws-sdk-go v1.38.0
6+
github.com/aws/aws-sdk-go v1.40.56
87
github.com/aws/aws-sdk-go-v2 v1.7.0
98
github.com/aws/aws-sdk-go-v2/config v1.1.6
109
github.com/aws/aws-sdk-go-v2/internal/ini v1.1.0 // indirect
@@ -14,30 +13,16 @@ require (
1413
github.com/fatih/color v1.9.0
1514
github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0
1615
github.com/go-sql-driver/mysql v1.5.0 // indirect
17-
github.com/go-test/deep v1.0.7 // indirect
18-
github.com/google/go-cmp v0.5.5 // indirect
19-
github.com/gruntwork-io/terratest v0.32.9
16+
github.com/gruntwork-io/terratest v0.40.1
2017
github.com/hashicorp/errwrap v1.1.0 // indirect
2118
github.com/hashicorp/go-multierror v1.1.0
22-
github.com/hashicorp/hcl/v2 v2.9.1 // indirect
23-
github.com/kr/pretty v0.2.1 // indirect
24-
github.com/kr/text v0.2.0 // indirect
25-
github.com/kylelemons/godebug v1.1.0 // indirect
2619
github.com/mattn/go-colorable v0.1.7 // indirect
2720
github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326
28-
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
29-
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
3021
github.com/pquerna/otp v1.2.1-0.20191009055518-468c2dd2b58d // indirect
31-
github.com/sirupsen/logrus v1.6.0
32-
github.com/stretchr/testify v1.6.1
22+
github.com/sirupsen/logrus v1.8.1
23+
github.com/stretchr/testify v1.7.0
3324
github.com/urfave/cli v1.22.4
34-
github.com/zclconf/go-cty v1.8.1 // indirect
35-
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670
36-
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
37-
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d // indirect
25+
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
3826
golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 // indirect
39-
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
4027
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
41-
gopkg.in/yaml.v2 v2.3.0 // indirect
42-
gopkg.in/yaml.v3 v3.0.0-20210107172259-749611fa9fcc // indirect
4328
)

0 commit comments

Comments
 (0)