Skip to content

Commit

Permalink
fix: squash all commits of initial boot config
Browse files Browse the repository at this point in the history
  • Loading branch information
hferentschik committed Oct 9, 2019
1 parent 13dc01d commit 38f6373
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 49 deletions.
7 changes: 6 additions & 1 deletion pkg/cmd/step/verify/step_verify_environments.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,12 @@ func (o *StepVerifyEnvironmentsOptions) pushDevEnvironmentUpdates(environmentRep
return errors.Wrap(err, "failed to modify dev environment config")
}

err = gitter.AddCommit(localRepoDir, "chore(config): update configuration")
err = gitter.Add(localRepoDir, ".")
if err != nil {
return errors.Wrap(err, "unable to add stage commit")
}

err = gitter.CommitDir(localRepoDir, "chore(config): update configuration")
if err != nil {
return errors.Wrapf(err, "unable to commit changes to environment repo in %s", localRepoDir)
}
Expand Down
152 changes: 104 additions & 48 deletions pkg/gits/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import (
"net/url"
"os"
"os/user"
"path"
"path/filepath"
"sort"
"strings"

"gopkg.in/src-d/go-git.v4/config"

uuid "github.com/satori/go.uuid"

"github.com/jenkins-x/jx/pkg/util"
Expand Down Expand Up @@ -730,63 +734,115 @@ func FindTagForVersion(dir string, version string, gitter Gitter) (string, error
// head of the toBranch on the duplicated repo to fromCommitish. It returns the GitRepository for the duplicated repo
func DuplicateGitRepoFromCommitish(toOrg string, toName string, fromGitURL string, fromCommitish string, toBranch string, private bool, provider GitProvider, gitter Gitter) (*GitRepository, error) {
duplicateInfo, err := provider.GetRepository(toOrg, toName)
if err == nil {
return duplicateInfo, nil
}

// If the duplicate doesn't exist create it
log.Logger().Debugf(errors.Wrapf(err, "getting repository %s/%s", toOrg, toName).Error())
fromInfo, err := ParseGitURL(fromGitURL)
if err != nil {
log.Logger().Debugf(errors.Wrapf(err, "getting repository %s/%s", toOrg, toName).Error())
fromInfo, err := ParseGitURL(fromGitURL)
if err != nil {
return nil, errors.Wrapf(err, "parsing %s", fromGitURL)
}
fromInfo, err = provider.GetRepository(fromInfo.Organisation, fromInfo.Name)
if err != nil {
return nil, errors.Wrapf(err, "getting repo for %s", fromGitURL)
}
duplicateInfo, err = provider.CreateRepository(toOrg, toName, private)
if err != nil {
return nil, errors.Wrapf(err, "failed to create GitHub repo %s/%s", toOrg, toName)
}
dir, err := ioutil.TempDir("", "")
if err != nil {
return nil, errors.WithStack(err)
}
err = gitter.Clone(fromInfo.CloneURL, dir)
if err != nil {
return nil, errors.Wrapf(err, "failed to clone %s", fromInfo.CloneURL)
}
if !strings.Contains(fromCommitish, "/") {
// if the commitish looks like a tag, fetch the tags
err = gitter.FetchTags(dir)
if err != nil {
return nil, errors.Wrapf(err, "failed to fetch tags fromGitURL %s", fromInfo.CloneURL)
}
} else {
parts := strings.Split(fromCommitish, "/")
err = gitter.FetchBranch(dir, parts[0], parts[1])
if err != nil {
return nil, errors.Wrapf(err, "failed to fetch %s fromGitURL %s", fromCommitish, fromInfo.CloneURL)
}
}
err = gitter.Reset(dir, fromCommitish, true)
if err != nil {
return nil, errors.Wrapf(err, "failed to reset to %s", fromCommitish)
}
userDetails := provider.UserAuth()
duplicatePushURL, err := gitter.CreateAuthenticatedURL(duplicateInfo.CloneURL, &userDetails)
return nil, errors.Wrapf(err, "parsing %s", fromGitURL)
}
fromInfo, err = provider.GetRepository(fromInfo.Organisation, fromInfo.Name)
if err != nil {
return nil, errors.Wrapf(err, "getting repo for %s", fromGitURL)
}
duplicateInfo, err = provider.CreateRepository(toOrg, toName, private)
if err != nil {
return nil, errors.Wrapf(err, "failed to create GitHub repo %s/%s", toOrg, toName)
}
dir, err := ioutil.TempDir("", "")
if err != nil {
return nil, errors.WithStack(err)
}
err = gitter.Clone(fromInfo.CloneURL, dir)
if err != nil {
return nil, errors.Wrapf(err, "failed to clone %s", fromInfo.CloneURL)
}
if !strings.Contains(fromCommitish, "/") {
// if the commitish looks like a tag, fetch the tags
err = gitter.FetchTags(dir)
if err != nil {
return nil, errors.Wrapf(err, "failed to create push URL for %s", duplicateInfo.CloneURL)
return nil, errors.Wrapf(err, "failed to fetch tags fromGitURL %s", fromInfo.CloneURL)
}
err = gitter.SetRemoteURL(dir, "origin", duplicateInfo.CloneURL)
} else {
parts := strings.Split(fromCommitish, "/")
err = gitter.FetchBranch(dir, parts[0], parts[1])
if err != nil {
return nil, errors.Wrapf(err, "failed to set remote url to %s", duplicateInfo.CloneURL)
return nil, errors.Wrapf(err, "failed to fetch %s fromGitURL %s", fromCommitish, fromInfo.CloneURL)
}
err = gitter.Push(dir, duplicatePushURL, true, false, fmt.Sprintf("%s:%s", "HEAD", toBranch))
}
err = gitter.Reset(dir, fromCommitish, true)
if err != nil {
return nil, errors.Wrapf(err, "failed to reset to %s", fromCommitish)
}

err = SquashIntoSingleCommit(dir, fmt.Sprintf("initial config based of %s/%s with ref %s", toOrg, toName, fromCommitish), gitter)
if err != nil {
return nil, err
}

userDetails := provider.UserAuth()
duplicatePushURL, err := gitter.CreateAuthenticatedURL(duplicateInfo.CloneURL, &userDetails)
if err != nil {
return nil, errors.Wrapf(err, "failed to create push URL for %s", duplicateInfo.CloneURL)
}
err = gitter.SetRemoteURL(dir, "origin", duplicateInfo.CloneURL)
if err != nil {
return nil, errors.Wrapf(err, "failed to set remote url to %s", duplicateInfo.CloneURL)
}
err = gitter.Push(dir, duplicatePushURL, true, false, fmt.Sprintf("%s:%s", "HEAD", toBranch))
if err != nil {
return nil, errors.Wrapf(err, "failed to push HEAD to %s", toBranch)
}
log.Logger().Infof("Duplicated Git repository %s to %s\n", util.ColorInfo(fromInfo.HTMLURL), util.ColorInfo(duplicateInfo.HTMLURL))
log.Logger().Infof("Setting upstream to %s\n", util.ColorInfo(duplicateInfo.HTMLURL))

return duplicateInfo, nil
}

// SquashIntoSingleCommit takes the git repository in the specified directory and squashes all commits into a single
// one using the specified message.
func SquashIntoSingleCommit(repoDir string, commitMsg string, gitter Gitter) error {
cfg := config.NewConfig()
data, err := ioutil.ReadFile(filepath.Join(repoDir, ".git", "config"))
if err != nil {
return errors.Wrapf(err, "failed to load git config from %s", repoDir)
}

err = cfg.Unmarshal(data)
if err != nil {
return errors.Wrapf(err, "failed to unmarshal %s", repoDir)
}

err = os.RemoveAll(path.Join(repoDir, ".git"))
if err != nil {
return errors.Wrap(err, "unable to squash")
}

err = gitter.Init(repoDir)
if err != nil {
return errors.Wrap(err, "unable to init git")
}

for _, remote := range cfg.Remotes {
err = gitter.AddRemote(repoDir, remote.Name, remote.URLs[0])
if err != nil {
return nil, errors.Wrapf(err, "failed to push HEAD to %s", toBranch)
return errors.Wrap(err, "unable to update remote")
}
log.Logger().Infof("Duplicated Git repository %s to %s\n", util.ColorInfo(fromInfo.HTMLURL), util.ColorInfo(duplicateInfo.HTMLURL))
log.Logger().Infof("Setting upstream to %s\n", util.ColorInfo(duplicateInfo.HTMLURL))
}
return duplicateInfo, nil

err = gitter.Add(repoDir, ".")
if err != nil {
return errors.Wrap(err, "unable to add stage commit")
}

err = gitter.CommitDir(repoDir, commitMsg)
if err != nil {
return errors.Wrap(err, "unable to add initial commit")
}
return nil
}

// GetGitInfoFromDirectory obtains remote origin HTTPS and current branch of a given directory and fails if it's not a git repository
Expand Down
54 changes: 54 additions & 0 deletions pkg/gits/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"

Expand Down Expand Up @@ -2257,3 +2258,56 @@ func TestGetGitInfoFromDirectoryNoGit(t *testing.T) {

assert.Equal(t, fmt.Sprintf("there was a problem obtaining the remote Git URL of directory %s: failed to unmarshal due to no GitConfDir defined", dir), err.Error())
}

func Test_SquashIntoSingleCommit(t *testing.T) {
gitDir, err := ioutil.TempDir("", "test-repo")
assert.NoError(t, err)
defer func() {
os.RemoveAll(gitDir)
}()

gitter := gits.NewGitCLI()

err = gitter.Init(gitDir)
assert.NoError(t, err)

readmePath := filepath.Join(gitDir, readme)
err = ioutil.WriteFile(readmePath, []byte("readme"), 0600)
assert.NoError(t, err)
err = gitter.Add(gitDir, readme)
assert.NoError(t, err)
err = gitter.CommitDir(gitDir, "adding readme")
assert.NoError(t, err)

contributingPath := filepath.Join(gitDir, contributing)
err = ioutil.WriteFile(contributingPath, []byte("contribute"), 0600)
assert.NoError(t, err)
err = gitter.Add(gitDir, contributing)
assert.NoError(t, err)
err = gitter.CommitDir(gitDir, "adding contribute")
assert.NoError(t, err)

assert.Equal(t, 2, commitCount(t, gitDir))

err = gits.SquashIntoSingleCommit(gitDir, "squashed", gitter)
assert.NoError(t, err)

assert.Equal(t, 1, commitCount(t, gitDir))
assert.FileExists(t, filepath.Join(gitDir, readme))
assert.FileExists(t, filepath.Join(gitDir, contributing))
}

func commitCount(t *testing.T, repoDir string) int {
args := []string{"rev-list", "--count", "HEAD"}
cmd := util.Command{
Dir: repoDir,
Name: "git",
Args: args,
}
out, err := cmd.RunWithoutRetry()
assert.NoError(t, err)

count, err := strconv.Atoi(out)
assert.NoError(t, err)
return count
}

0 comments on commit 38f6373

Please sign in to comment.