Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: set remote URL after cloning git repo [IDE-674] #692

Merged
merged 3 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions application/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ func getParsedEnvFromShell(shell string) gotenv.Env {
ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second)
defer cancelFunc()

// deepcode ignore CommandInjection: false positive
env, err := exec.CommandContext(ctx, shell, "--login", "-i", "-c", "env && exit").Output()
if err != nil {
return gotenv.Env{}
Expand Down
51 changes: 51 additions & 0 deletions internal/vcs/git_cloner.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package vcs

import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/otiai10/copy"
"github.com/rs/zerolog"
Expand Down Expand Up @@ -48,9 +49,59 @@ func Clone(logger *zerolog.Logger, srcRepoPath string, destinationPath string, t
return targetRepo, nil
}

// Patch Origin Remote for the cloned repo. This is only necessary if we use checkout since the remote origin URL will be the srcRepoPath
err = patchClonedRepoRemoteOrigin(logger, srcRepoPath, clonedRepo)
if err != nil {
logger.Error().Err(err).Msgf("Could not patch origin remote url in cloned repo %s", destinationPath)
}
return clonedRepo, nil
}

func patchClonedRepoRemoteOrigin(logger *zerolog.Logger, srcRepoPath string, clonedRepo *git.Repository) error {
srcRepo, err := git.PlainOpen(srcRepoPath)
if err != nil {
logger.Error().Err(err).Msgf("Could not open source repo: %s", srcRepoPath)
return err
}

srcConfig, err := srcRepo.Config()
if err != nil {
logger.Error().Err(err).Msg("Could not get config from source repo")
return err
}

var originURLs []string
if origin, ok := srcConfig.Remotes["origin"]; ok && len(origin.URLs) > 0 {
originURLs = origin.URLs
} else {
logger.Warn().Msg("Source repo has no origin remote or no URLs. Skipping patching clone origin")
return nil
}

clonedConfig, err := clonedRepo.Config()
if err != nil {
logger.Error().Err(err).Msg("Could not get config from cloned repo")
return err
}

if origin, ok := clonedConfig.Remotes["origin"]; ok {
origin.URLs = originURLs
} else {
clonedConfig.Remotes["origin"] = &config.RemoteConfig{
Name: "origin",
URLs: originURLs,
}
}

err = clonedRepo.Storer.SetConfig(clonedConfig)
if err != nil {
logger.Error().Err(err).Msg("Could not set config for cloned repo")
return err
}

return nil
}

func cloneRepoWithFsCopy(logger *zerolog.Logger, srcRepoPath string, destinationRepoPath string, targetBranchReferenceName plumbing.ReferenceName) *git.Repository {
repo, err := git.PlainOpen(srcRepoPath)
if err != nil {
Expand Down
70 changes: 70 additions & 0 deletions internal/vcs/git_cloner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package vcs

import (
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/snyk/snyk-ls/internal/testutil"
Expand All @@ -40,6 +41,31 @@ func TestClone_ShouldClone(t *testing.T) {
assert.NoError(t, err)
}

func TestClone_ShouldClone_SameOriginRemoteUrl(t *testing.T) {
c := testutil.UnitTest(t)
repoPath := t.TempDir()
srcRepo, _ := initGitRepo(t, repoPath, false)

tmpFolderPath := t.TempDir()
cloneTargetBranchName := "master"
clonedRepo, err := Clone(c.Logger(), repoPath, tmpFolderPath, cloneTargetBranchName)

assert.NotNil(t, clonedRepo)
assert.NoError(t, err)

srcConfig, err := srcRepo.Config()
assert.NoError(t, err)
remoteSrcConfig := srcConfig.Remotes["origin"]
assert.NotNil(t, remoteSrcConfig)

clonedRepoConfig, err := clonedRepo.Config()
assert.NoError(t, err)
remoteDstConfig := clonedRepoConfig.Remotes["origin"]
assert.NotNil(t, remoteDstConfig)

assert.Equal(t, remoteSrcConfig.URLs[0], remoteDstConfig.URLs[0])
}

func TestClone_InvalidBranchName(t *testing.T) {
c := testutil.UnitTest(t)
repoPath := t.TempDir()
Expand Down Expand Up @@ -75,6 +101,40 @@ func TestClone_DetachedHead_TargetBranchExists(t *testing.T) {
assert.NotNil(t, cloneRepo)
}

func TestClone_DetachedHead_TargetBranchExists_SameOriginRemoteUrl(t *testing.T) {
c := testutil.UnitTest(t)
repoPath := t.TempDir()
destinationPath := t.TempDir()
srcRepo, currentHead := initGitRepo(t, repoPath, true)
worktree, err := srcRepo.Worktree()
assert.NoError(t, err)
_, err = worktree.Commit("testCommit", &git.CommitOptions{
Author: &object.Signature{Name: t.Name()},
})
assert.NoError(t, err)

// Now checkout the old head hash
err = worktree.Checkout(&git.CheckoutOptions{Hash: currentHead.Hash()})
assert.NoError(t, err)
cloneTargetBranchName := "master"
clonedRepo, err := Clone(c.Logger(), repoPath, destinationPath, cloneTargetBranchName)

assert.NoError(t, err)
assert.NotNil(t, clonedRepo)

srcConfig, err := srcRepo.Config()
assert.NoError(t, err)
remoteSrcConfig := srcConfig.Remotes["origin"]
assert.NotNil(t, remoteSrcConfig)

clonedRepoConfig, err := clonedRepo.Config()
assert.NoError(t, err)
remoteDstConfig := clonedRepoConfig.Remotes["origin"]
assert.NotNil(t, remoteDstConfig)

assert.Equal(t, remoteSrcConfig.URLs[0], remoteDstConfig.URLs[0])
}

func TestClone_DetachedHead_TargetBranchDoesNotExists(t *testing.T) {
c := testutil.UnitTest(t)
repoPath := t.TempDir()
Expand Down Expand Up @@ -221,8 +281,18 @@ func initGitRepo(t *testing.T, repoPath string, isModified bool) (*git.Repositor
})
assert.NoError(t, err)
}

head, err := repo.Head()
assert.NoError(t, err)

repoConfig, err := repo.Config()
assert.NoError(t, err)

repoConfig.Remotes["origin"] = &config.RemoteConfig{
Name: "origin",
URLs: []string{"[email protected]:snyk/snyk-goof.git"},
}
err = repo.Storer.SetConfig(repoConfig)
assert.NoError(t, err)
return repo, head
}