From 41130022f2ec67a983cc02e7a9d3127241bcf907 Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Mon, 7 Aug 2023 08:08:20 +0300
Subject: [PATCH 1/8] init commit
---
commands/utils/params.go | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/commands/utils/params.go b/commands/utils/params.go
index d0c9c7678..8e6e61a07 100644
--- a/commands/utils/params.go
+++ b/commands/utils/params.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "github.com/go-git/go-git/v5"
xrutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"net/http"
"net/url"
@@ -43,6 +44,11 @@ type FrogbotUtils struct {
type RepoAggregator []Repository
+// NewRepoAggregator returns an initialized RepoAggregator with an empty repository
+func NewRepoAggregator() RepoAggregator {
+ return RepoAggregator{{Params: Params{Scan: Scan{Projects: []Project{{}}}}}}
+}
+
type Repository struct {
Params `yaml:"params,omitempty"`
OutputWriter
@@ -209,7 +215,13 @@ func (g *Git) setDefaultsIfNeeded(git *Git) (err error) {
g.RepoName = git.RepoName
}
if len(g.Branches) == 0 {
- g.Branches = append(g.Branches, git.Branches...)
+ branch := getTrimmedEnv(GitBaseBranchEnv)
+ if branch == "" {
+ if branch, err = getBranchFromDotGit(); err != nil {
+ return err
+ }
+ g.Branches = append(g.Branches, branch)
+ }
}
if g.BranchNameTemplate == "" {
branchTemplate := getTrimmedEnv(BranchNameTemplateEnv)
@@ -247,6 +259,22 @@ func (g *Git) setDefaultsIfNeeded(git *Git) (err error) {
return
}
+func getBranchFromDotGit() (string, error) {
+ dotGit, err := git.PlainOpen(".")
+ if err != nil {
+ return "", errors.New("unable to retrieve the branch to scan, as the .git folder was not found in the current working directory. The error that was received: " + err.Error())
+ }
+ ref, err := dotGit.Head()
+ if err != nil {
+ return "", err
+ }
+ branchName := ref.Name().String()
+ if branchName == "" {
+ return "", errors.New("branch is missing. Please set the branch to scan in you frogbot-config.yml or in your JF_GIT_BASE_BRANCH environment variable")
+ }
+ return strings.TrimPrefix(branchName, "refs/heads/"), nil
+}
+
func validateHashPlaceHolder(template string) error {
if template != "" && !strings.Contains(template, BranchHashPlaceHolder) {
return fmt.Errorf("branch name template must contain %s", BranchHashPlaceHolder)
@@ -335,7 +363,8 @@ func BuildRepoAggregator(configFileContent []byte, gitParams *Git, server *corec
// If there is no config file, the function returns a RepoAggregator with an empty repository.
func unmarshalFrogbotConfigYaml(yamlContent []byte) (result RepoAggregator, err error) {
if len(yamlContent) == 0 {
- return RepoAggregator{{Params: Params{Scan: Scan{Projects: []Project{{}}}}}}, nil
+ result = NewRepoAggregator()
+ return
}
err = yaml.Unmarshal(yamlContent, &result)
return
From df0c5ede4215db9213b542bc744ede2468139af4 Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Mon, 7 Aug 2023 17:20:43 +0300
Subject: [PATCH 2/8] Fix open pull request against the wrong branch
---
commands/commands.go | 12 +--
commands/createfixpullrequests.go | 45 ++++----
commands/createfixpullrequests_test.go | 4 +-
commands/scanandfixrepos_test.go | 2 +-
commands/scanpullrequest_test.go | 9 +-
commands/scanpullrequests_test.go | 8 +-
commands/utils/git.go | 57 +++++-----
commands/utils/git_test.go | 61 ++++++++++-
commands/utils/params.go | 143 +++++++++++--------------
commands/utils/params_test.go | 30 +++---
commands/utils/utils.go | 8 +-
11 files changed, 211 insertions(+), 168 deletions(-)
diff --git a/commands/commands.go b/commands/commands.go
index 4c51524c2..a9c7c10c4 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -20,7 +20,7 @@ type FrogbotCommand interface {
func Exec(command FrogbotCommand, name string) (err error) {
// Get frogbotUtils that contains the config, server, and VCS client
log.Info("Frogbot version:", utils.FrogbotVersion)
- frogbotUtils, err := utils.GetFrogbotDetails()
+ frogbotUtils, err := utils.GetFrogbotDetails(name)
if err != nil {
return err
}
@@ -51,7 +51,7 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Invoke the command interface
log.Info(fmt.Sprintf("Running Frogbot %q command", name))
- err = command.Run(frogbotUtils.Repositories, frogbotUtils.Client)
+ err = command.Run(frogbotUtils.Repositories, frogbotUtils.GitClient)
// Wait for a signal, letting us know that the usage reporting is done.
<-usageReportSent
@@ -65,7 +65,7 @@ func Exec(command FrogbotCommand, name string) (err error) {
func GetCommands() []*clitool.Command {
return []*clitool.Command{
{
- Name: "scan-pull-request",
+ Name: utils.ScanPullRequest,
Aliases: []string{"spr"},
Usage: "Scans a pull request with JFrog Xray for security vulnerabilities.",
Action: func(ctx *clitool.Context) error {
@@ -74,7 +74,7 @@ func GetCommands() []*clitool.Command {
Flags: []clitool.Flag{},
},
{
- Name: "create-fix-pull-requests",
+ Name: utils.CreateFixPullRequests,
Aliases: []string{"cfpr"},
Usage: "Scan the current branch and create pull requests with fixes if needed",
Action: func(ctx *clitool.Context) error {
@@ -83,7 +83,7 @@ func GetCommands() []*clitool.Command {
Flags: []clitool.Flag{},
},
{
- Name: "scan-pull-requests",
+ Name: utils.ScanPullRequests,
Aliases: []string{"sprs"},
Usage: "Scans all the open pull requests within a single or multiple repositories with JFrog Xray for security vulnerabilities",
Action: func(ctx *clitool.Context) error {
@@ -92,7 +92,7 @@ func GetCommands() []*clitool.Command {
Flags: []clitool.Flag{},
},
{
- Name: "scan-and-fix-repos",
+ Name: utils.ScanAndFixRepos,
Aliases: []string{"safr"},
Usage: "Scan single or multiple repositories and create pull requests with fixes if any security vulnerabilities are found",
Action: func(ctx *clitool.Context) error {
diff --git a/commands/createfixpullrequests.go b/commands/createfixpullrequests.go
index 07b5f0d6f..60f256a8c 100644
--- a/commands/createfixpullrequests.go
+++ b/commands/createfixpullrequests.go
@@ -43,27 +43,30 @@ type CreateFixPullRequestsCmd struct {
handlers map[coreutils.Technology]packagehandlers.PackageHandler
}
-func (cfp *CreateFixPullRequestsCmd) Run(repoAggregator utils.RepoAggregator, client vcsclient.VcsClient) error {
- if err := utils.ValidateSingleRepoConfiguration(&repoAggregator); err != nil {
+func (cfp *CreateFixPullRequestsCmd) Run(repoAggregator utils.RepoAggregator, client vcsclient.VcsClient) (err error) {
+ if err = utils.ValidateSingleRepoConfiguration(&repoAggregator); err != nil {
return err
}
repository := repoAggregator[0]
for _, branch := range repository.Branches {
- err := cfp.scanAndFixRepository(&repository, branch, client)
- if err != nil {
- return err
+ if err = cfp.scanAndFixRepository(&repository, branch, client); err != nil {
+ return
}
}
- return nil
+ return
}
func (cfp *CreateFixPullRequestsCmd) scanAndFixRepository(repository *utils.Repository, branch string, client vcsclient.VcsClient) (err error) {
- cfp.baseWd, err = os.Getwd()
- if err != nil {
+ if cfp.baseWd, err = os.Getwd(); err != nil {
+ return
+ }
+ if err = cfp.setCommandPrerequisites(repository, branch, client); err != nil {
return
}
- cfp.setCommandPrerequisites(repository, branch, client)
for i := range repository.Projects {
+ if err = cfp.gitManager.Checkout(branch); err != nil {
+ return fmt.Errorf("failed to checkout to %s branch before scanning. The following error has been received:\n%s", branch, err.Error())
+ }
cfp.details.Project = &repository.Projects[i]
cfp.projectTech = ""
if err = cfp.scanAndFixProject(repository); err != nil {
@@ -73,7 +76,7 @@ func (cfp *CreateFixPullRequestsCmd) scanAndFixRepository(repository *utils.Repo
return
}
-func (cfp *CreateFixPullRequestsCmd) setCommandPrerequisites(repository *utils.Repository, branch string, client vcsclient.VcsClient) {
+func (cfp *CreateFixPullRequestsCmd) setCommandPrerequisites(repository *utils.Repository, branch string, client vcsclient.VcsClient) (err error) {
cfp.details = utils.NewScanDetails(client, &repository.Server, &repository.Git).
SetXrayGraphScanParams(repository.Watches, repository.JFrogProjectKey).
SetFailOnInstallationErrors(*repository.FailOnSecurityIssues).
@@ -82,12 +85,14 @@ func (cfp *CreateFixPullRequestsCmd) setCommandPrerequisites(repository *utils.R
SetMinSeverity(repository.MinSeverity)
cfp.aggregateFixes = repository.Git.AggregateFixes
cfp.OutputWriter = utils.GetCompatibleOutputWriter(repository.GitProvider)
+ cfp.gitManager, err = utils.NewGitManager(cfp.dryRun, cfp.dryRunRepoPath, ".", "origin", cfp.details.Token, cfp.details.Username, cfp.details.Git)
+ return
}
func (cfp *CreateFixPullRequestsCmd) scanAndFixProject(repository *utils.Repository) error {
var fixNeeded bool
// A map that contains the full project paths as a keys
- // The value is a map of vulnerable package names -> the details of the vulnerable packages.x
+ // The value is a map of vulnerable package names -> the details of the vulnerable packages.
// That means we have a map of all the vulnerabilities that were found in a specific folder, along with their full details.
vulnerabilitiesByPathMap := make(map[string]map[string]*utils.VulnerabilityDetails)
projectFullPathWorkingDirs := getFullPathWorkingDirs(cfp.details.Project.WorkingDirs, cfp.baseWd)
@@ -147,12 +152,6 @@ func (cfp *CreateFixPullRequestsCmd) getVulnerabilitiesMap(scanResults *xrayutil
}
func (cfp *CreateFixPullRequestsCmd) fixVulnerablePackages(vulnerabilitiesByWdMap map[string]map[string]*utils.VulnerabilityDetails) (err error) {
- if cfp.gitManager == nil {
- cfp.gitManager, err = utils.NewGitManager(cfp.dryRun, cfp.dryRunRepoPath, ".", "origin", cfp.details.Token, cfp.details.Username, cfp.details.Git)
- if err != nil {
- return
- }
- }
clonedRepoDir, restoreBaseDir, err := cfp.cloneRepository()
if err != nil {
return
@@ -186,12 +185,12 @@ func (cfp *CreateFixPullRequestsCmd) fixProjectVulnerabilities(fullProjectPath s
// 'CD' into the relevant working directory
if projectWorkingDir != "" {
- restoreDir, err := utils.Chdir(projectWorkingDir)
- if err != nil {
- return err
+ var restoreDirFunc func() error
+ if restoreDirFunc, err = utils.Chdir(projectWorkingDir); err != nil {
+ return
}
defer func() {
- err = errors.Join(err, restoreDir())
+ err = errors.Join(err, restoreDirFunc())
}()
}
@@ -203,7 +202,7 @@ func (cfp *CreateFixPullRequestsCmd) fixProjectVulnerabilities(fullProjectPath s
// After fixing the current vulnerability, checkout to the base branch to start fixing the next vulnerability
log.Debug("Running git checkout to base branch:", cfp.details.Branch())
- if e := cfp.gitManager.CheckoutLocalBranch(cfp.details.Branch()); e != nil {
+ if e := cfp.gitManager.Checkout(cfp.details.Branch()); e != nil {
err = errors.Join(err, cfp.handleUpdatePackageErrors(e))
return
}
@@ -545,7 +544,7 @@ func (cfp *CreateFixPullRequestsCmd) aggregateFixAndOpenPullRequest(vulnerabilit
}
}
log.Info("-----------------------------------------------------------------")
- if e := cfp.gitManager.CheckoutLocalBranch(cfp.details.Branch()); e != nil {
+ if e := cfp.gitManager.Checkout(cfp.details.Branch()); e != nil {
err = errors.Join(err, e)
}
return
diff --git a/commands/createfixpullrequests_test.go b/commands/createfixpullrequests_test.go
index ca30109f1..932718d39 100644
--- a/commands/createfixpullrequests_test.go
+++ b/commands/createfixpullrequests_test.go
@@ -141,7 +141,7 @@ func TestCreateFixPullRequestsCmd_Run(t *testing.T) {
var port string
server := httptest.NewServer(createHttpHandler(t, &port, test.repoName))
port = server.URL[strings.LastIndex(server.URL, ":")+1:]
- gitTestParams := utils.GitClientInfo{
+ gitTestParams := utils.Git{
GitProvider: vcsutils.GitHub,
VcsInfo: vcsclient.VcsInfo{
Token: "123456",
@@ -241,7 +241,7 @@ pr body
server.Close()
}()
port = server.URL[strings.LastIndex(server.URL, ":")+1:]
- gitTestParams := &utils.GitClientInfo{
+ gitTestParams := &utils.Git{
GitProvider: vcsutils.GitHub,
VcsInfo: vcsclient.VcsInfo{
Token: "123456",
diff --git a/commands/scanandfixrepos_test.go b/commands/scanandfixrepos_test.go
index 1c7768e7e..1454cba3e 100644
--- a/commands/scanandfixrepos_test.go
+++ b/commands/scanandfixrepos_test.go
@@ -37,7 +37,7 @@ func TestScanAndFixRepos(t *testing.T) {
defer server.Close()
port = server.URL[strings.LastIndex(server.URL, ":")+1:]
- gitTestParams := utils.GitClientInfo{
+ gitTestParams := utils.Git{
GitProvider: vcsutils.GitHub,
RepoOwner: "jfrog",
VcsInfo: vcsclient.VcsInfo{
diff --git a/commands/scanpullrequest_test.go b/commands/scanpullrequest_test.go
index 924a73bb7..210ab1728 100644
--- a/commands/scanpullrequest_test.go
+++ b/commands/scanpullrequest_test.go
@@ -598,8 +598,8 @@ func TestVerifyGitHubFrogbotEnvironmentNoReviewers(t *testing.T) {
func TestVerifyGitHubFrogbotEnvironmentOnPrem(t *testing.T) {
repoConfig := &utils.Repository{
- Params: utils.Params{Git: utils.Git{GitClientInfo: utils.GitClientInfo{
- VcsInfo: vcsclient.VcsInfo{APIEndpoint: "https://acme.vcs.io"}}},
+ Params: utils.Params{Git: utils.Git{
+ VcsInfo: vcsclient.VcsInfo{APIEndpoint: "https://acme.vcs.io"}},
},
}
@@ -609,7 +609,7 @@ func TestVerifyGitHubFrogbotEnvironmentOnPrem(t *testing.T) {
}
func prepareConfigAndClient(t *testing.T, configPath string, server *httptest.Server, serverParams coreconfig.ServerDetails) (utils.RepoAggregator, vcsclient.VcsClient) {
- gitTestParams := &utils.GitClientInfo{
+ gitTestParams := &utils.Git{
GitProvider: vcsutils.GitHub,
RepoOwner: "jfrog",
VcsInfo: vcsclient.VcsInfo{
@@ -839,7 +839,8 @@ func TestDeletePreviousPullRequestMessages(t *testing.T) {
repository := &utils.Repository{
Params: utils.Params{
Git: utils.Git{
- GitClientInfo: utils.GitClientInfo{RepoName: "repo", RepoOwner: "owner"},
+ RepoName: "repo",
+ RepoOwner: "owner",
PullRequestID: 17,
},
},
diff --git a/commands/scanpullrequests_test.go b/commands/scanpullrequests_test.go
index 57f07c4bc..fbeca8510 100644
--- a/commands/scanpullrequests_test.go
+++ b/commands/scanpullrequests_test.go
@@ -20,11 +20,9 @@ var gitParams = &utils.Repository{
OutputWriter: &utils.SimplifiedOutput{},
Params: utils.Params{
Git: utils.Git{
- GitClientInfo: utils.GitClientInfo{
- RepoOwner: "repo-owner",
- Branches: []string{"master"},
- RepoName: "repo-name",
- },
+ RepoOwner: "repo-owner",
+ Branches: []string{"master"},
+ RepoName: "repo-name",
},
},
}
diff --git a/commands/utils/git.go b/commands/utils/git.go
index 7b3a0ec66..dd018142b 100644
--- a/commands/utils/git.go
+++ b/commands/utils/git.go
@@ -80,13 +80,12 @@ func NewGitManager(dryRun bool, clonedRepoPath, projectPath, remoteName, token,
return &GitManager{repository: repository, dryRunRepoPath: clonedRepoPath, remoteName: remoteName, auth: basicAuth, dryRun: dryRun, customTemplates: templates, git: g}, nil
}
-func (gm *GitManager) CheckoutLocalBranch(branchName string) error {
- err := gm.createBranchAndCheckout(branchName, false)
- if err != nil {
- err = fmt.Errorf("'git checkout %s' failed with error: %s", branchName, err.Error())
+func (gm *GitManager) Checkout(branchName string) error {
+ log.Debug("Running git checkout to branch:", branchName)
+ if err := gm.createBranchAndCheckout(branchName, false); err != nil {
+ return fmt.Errorf("'git checkout %s' failed with error: %s", branchName, err.Error())
}
- log.Debug("Running git checkout to local branch:", branchName)
- return err
+ return nil
}
func (gm *GitManager) Clone(destinationPath, branchName string) error {
@@ -152,6 +151,14 @@ func (gm *GitManager) CreateBranchAndCheckout(branchName string) error {
}
func (gm *GitManager) createBranchAndCheckout(branchName string, create bool) error {
+ currentBranch, err := getCurrentBranch(gm.repository)
+ if err != nil {
+ return err
+ }
+ if currentBranch == branchName {
+ log.Debug("Skipping `git checkout`, as the branch name is already the same as the current branch")
+ return nil
+ }
checkoutConfig := &git.CheckoutOptions{
Create: create,
Branch: getFullBranchName(branchName),
@@ -164,6 +171,14 @@ func (gm *GitManager) createBranchAndCheckout(branchName string, create bool) er
return worktree.Checkout(checkoutConfig)
}
+func getCurrentBranch(repository *git.Repository) (string, error) {
+ head, err := repository.Head()
+ if err != nil {
+ return "", err
+ }
+ return head.Name().Short(), nil
+}
+
func (gm *GitManager) AddAllAndCommit(commitMessage string) error {
log.Debug("Running git add all and commit...")
err := gm.addAll()
@@ -388,28 +403,6 @@ func (gm *GitManager) generateHTTPSCloneUrl() (url string, err error) {
}
}
-func (gm *GitManager) CheckoutRemoteBranch(branchName string) error {
- var checkoutConfig *git.CheckoutOptions
- if gm.dryRun {
- // On dry runs we mimic remote as local branches.
- checkoutConfig = &git.CheckoutOptions{
- Branch: plumbing.NewBranchReferenceName(branchName),
- Force: true,
- }
- } else {
- checkoutConfig = &git.CheckoutOptions{
- Branch: plumbing.NewRemoteReferenceName(gm.remoteName, branchName),
- Force: true,
- }
- }
- log.Debug("Running git checkout to remote branch:", branchName)
- worktree, err := gm.repository.Worktree()
- if err != nil {
- return err
- }
- return worktree.Checkout(checkoutConfig)
-}
-
func toBasicAuth(token, username string) *githttp.BasicAuth {
// The username can be anything except for an empty string
if username == "" {
@@ -429,6 +422,14 @@ func getFullBranchName(branchName string) plumbing.ReferenceName {
return plumbing.NewBranchReferenceName(plumbing.ReferenceName(branchName).Short())
}
+func GetBranchFromDotGit() (string, error) {
+ currentRepo, err := git.PlainOpen(".")
+ if err != nil {
+ return "", errors.New("unable to retrieve the branch to scan, as the .git folder was not found in the current working directory. The error that was received: " + err.Error())
+ }
+ return getCurrentBranch(currentRepo)
+}
+
func loadCustomTemplates(commitMessageTemplate, branchNameTemplate, pullRequestTitleTemplate string) (CustomTemplates, error) {
template := CustomTemplates{
commitMessageTemplate: commitMessageTemplate,
diff --git a/commands/utils/git_test.go b/commands/utils/git_test.go
index fc0ac6e0d..07eadcfc5 100644
--- a/commands/utils/git_test.go
+++ b/commands/utils/git_test.go
@@ -1,10 +1,14 @@
package utils
import (
+ "github.com/go-git/go-git/v5"
+ "github.com/go-git/go-git/v5/plumbing/object"
"github.com/jfrog/froggit-go/vcsclient"
"github.com/jfrog/froggit-go/vcsutils"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
+ "github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/stretchr/testify/assert"
+ "os"
"testing"
)
@@ -232,7 +236,7 @@ func TestConvertSSHtoHTTPS(t *testing.T) {
}
for _, test := range testsCases {
t.Run(test.vcsProvider.String(), func(t *testing.T) {
- gm := GitManager{git: &Git{GitClientInfo: GitClientInfo{GitProvider: test.vcsProvider, RepoName: test.repoName, RepoOwner: test.repoOwner, VcsInfo: vcsclient.VcsInfo{Project: test.projectName, APIEndpoint: test.apiEndpoint}}}}
+ gm := GitManager{git: &Git{GitProvider: test.vcsProvider, RepoName: test.repoName, RepoOwner: test.repoOwner, VcsInfo: vcsclient.VcsInfo{Project: test.projectName, APIEndpoint: test.apiEndpoint}}}
remoteUrl, err := gm.generateHTTPSCloneUrl()
if remoteUrl == "" {
assert.Equal(t, err.Error(), "unsupported version control provider: Bitbucket Cloud")
@@ -243,3 +247,58 @@ func TestConvertSSHtoHTTPS(t *testing.T) {
})
}
}
+
+func TestGitManager_Checkout(t *testing.T) {
+ tmpDir, err := fileutils.CreateTempDir()
+ assert.NoError(t, err)
+ defer func() {
+ assert.NoError(t, fileutils.RemoveTempDir(tmpDir))
+ }()
+ restoreWd, err := Chdir(tmpDir)
+ defer func() {
+ assert.NoError(t, restoreWd())
+ }()
+ gitManager := createFakeDotGit(t, tmpDir)
+ // Get the current branch that is set as HEAD
+ headRef, err := gitManager.repository.Head()
+ assert.NoError(t, err)
+ assert.Equal(t, headRef.Name().Short(), "master")
+ // Create 'dev' branch and checkout
+ err = gitManager.CreateBranchAndCheckout("dev")
+ assert.NoError(t, err)
+ var currBranch string
+ currBranch, err = getCurrentBranch(gitManager.repository)
+ assert.NoError(t, err)
+ assert.Equal(t, "dev", currBranch)
+ // Checkout back to 'master'
+ assert.NoError(t, gitManager.Checkout("master"))
+ currBranch, err = getCurrentBranch(gitManager.repository)
+ assert.NoError(t, err)
+ assert.Equal(t, "master", currBranch)
+}
+
+func createFakeDotGit(t *testing.T, testPath string) *GitManager {
+ // Initialize a new in-memory repository
+ repo, err := git.PlainInit(testPath, false)
+ assert.NoError(t, err)
+ // Create a new file and add it to the worktree
+ filename := "README.md"
+ content := []byte("# My New Repository\n\nThis is a sample repository created using go-git.")
+ err = os.WriteFile(filename, content, 0644)
+ assert.NoError(t, err)
+ worktree, err := repo.Worktree()
+ assert.NoError(t, err)
+ _, err = worktree.Add(filename)
+ assert.NoError(t, err)
+ // Commit the changes to the new main branch
+ _, err = worktree.Commit("Initial commit", &git.CommitOptions{
+ Author: &object.Signature{
+ Name: "Your Name",
+ Email: "your@email.com",
+ },
+ })
+ assert.NoError(t, err)
+ manager, err := NewGitManager(true, testPath, testPath, "origin", "", "", &Git{})
+ assert.NoError(t, err)
+ return manager
+}
diff --git a/commands/utils/params.go b/commands/utils/params.go
index 8666022af..6df27a5e1 100644
--- a/commands/utils/params.go
+++ b/commands/utils/params.go
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
- "github.com/go-git/go-git/v5"
xrutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils"
"net/http"
"net/url"
@@ -38,7 +37,7 @@ var (
type FrogbotDetails struct {
Repositories RepoAggregator
ServerDetails *coreconfig.ServerDetails
- Client vcsclient.VcsClient
+ GitClient vcsclient.VcsClient
ReleasesRepo string
}
@@ -61,8 +60,8 @@ type Params struct {
JFrogPlatform `yaml:"jfrogPlatform,omitempty"`
}
-func (p *Params) setDefaultsIfNeeded(gitClientInfo *GitClientInfo) error {
- if err := p.Git.setDefaultsIfNeeded(gitClientInfo); err != nil {
+func (p *Params) setDefaultsIfNeeded(gitParamsFromEnv *Git) error {
+ if err := p.Git.setDefaultsIfNeeded(gitParamsFromEnv); err != nil {
return err
}
if err := p.JFrogPlatform.setDefaultsIfNeeded(); err != nil {
@@ -186,41 +185,39 @@ func (jp *JFrogPlatform) setDefaultsIfNeeded() (err error) {
return
}
-type GitClientInfo struct {
+type Git struct {
GitProvider vcsutils.VcsProvider
vcsclient.VcsInfo
- RepoName string `yaml:"repoName,omitempty"`
- Branches []string `yaml:"branches,omitempty"`
- RepoOwner string
-}
-
-type Git struct {
- GitClientInfo `yaml:",inline"`
- BranchNameTemplate string `yaml:"branchNameTemplate,omitempty"`
- CommitMessageTemplate string `yaml:"commitMessageTemplate,omitempty"`
- PullRequestTitleTemplate string `yaml:"pullRequestTitleTemplate,omitempty"`
- EmailAuthor string `yaml:"emailAuthor,omitempty"`
- AggregateFixes bool `yaml:"aggregateFixes,omitempty"`
+ RepoOwner string
+ RepoName string `yaml:"repoName,omitempty"`
+ Branches []string `yaml:"branches,omitempty"`
+ BranchNameTemplate string `yaml:"branchNameTemplate,omitempty"`
+ CommitMessageTemplate string `yaml:"commitMessageTemplate,omitempty"`
+ PullRequestTitleTemplate string `yaml:"pullRequestTitleTemplate,omitempty"`
+ EmailAuthor string `yaml:"emailAuthor,omitempty"`
+ AggregateFixes bool `yaml:"aggregateFixes,omitempty"`
PullRequestID int
}
-func (g *Git) setDefaultsIfNeeded(gitClientInfo *GitClientInfo) (err error) {
- g.RepoOwner = gitClientInfo.RepoOwner
- g.GitProvider = gitClientInfo.GitProvider
- g.VcsInfo = gitClientInfo.VcsInfo
+func (g *Git) setDefaultsIfNeeded(gitParamsFromEnv *Git) (err error) {
+ g.RepoOwner = gitParamsFromEnv.RepoOwner
+ g.GitProvider = gitParamsFromEnv.GitProvider
+ g.VcsInfo = gitParamsFromEnv.VcsInfo
if g.RepoName == "" {
- if gitClientInfo.RepoName == "" {
+ if gitParamsFromEnv.RepoName == "" {
return fmt.Errorf("repository name is missing. please set the repository name in your %s file or as the %s environment variable", FrogbotConfigFile, GitRepoEnv)
}
- g.RepoName = gitClientInfo.RepoName
+ g.RepoName = gitParamsFromEnv.RepoName
}
if len(g.Branches) == 0 {
- branch := getTrimmedEnv(GitBaseBranchEnv)
- if branch == "" {
- if branch, err = getBranchFromDotGit(); err != nil {
- return err
+ if len(gitParamsFromEnv.Branches) == 0 {
+ var branch string
+ if branch, err = GetBranchFromDotGit(); err != nil {
+ return
}
g.Branches = append(g.Branches, branch)
+ } else {
+ g.Branches = append(g.Branches, gitParamsFromEnv.Branches...)
}
}
if g.BranchNameTemplate == "" {
@@ -248,8 +245,8 @@ func (g *Git) setDefaultsIfNeeded(gitClientInfo *GitClientInfo) (err error) {
}
if g.PullRequestID == UndefinedPrID {
if idStr := getTrimmedEnv(GitPullRequestIDEnv); idStr != "" {
- idNum, err := strconv.Atoi(idStr)
- if err != nil {
+ var idNum int
+ if idNum, err = strconv.Atoi(idStr); err != nil {
return fmt.Errorf("failed parsing pull request ID as a number. ID as string : %s", idStr)
}
g.PullRequestID = idNum
@@ -258,22 +255,6 @@ func (g *Git) setDefaultsIfNeeded(gitClientInfo *GitClientInfo) (err error) {
return
}
-func getBranchFromDotGit() (string, error) {
- dotGit, err := git.PlainOpen(".")
- if err != nil {
- return "", errors.New("unable to retrieve the branch to scan, as the .git folder was not found in the current working directory. The error that was received: " + err.Error())
- }
- ref, err := dotGit.Head()
- if err != nil {
- return "", err
- }
- branchName := ref.Name().String()
- if branchName == "" {
- return "", errors.New("branch is missing. Please set the branch to scan in you frogbot-config.yml or in your JF_GIT_BASE_BRANCH environment variable")
- }
- return strings.TrimPrefix(branchName, "refs/heads/"), nil
-}
-
func validateHashPlaceHolder(template string) error {
if template != "" && !strings.Contains(template, BranchHashPlaceHolder) {
return fmt.Errorf("branch name template must contain %s", BranchHashPlaceHolder)
@@ -281,13 +262,13 @@ func validateHashPlaceHolder(template string) error {
return nil
}
-func GetFrogbotDetails() (frogbotUtils *FrogbotDetails, err error) {
+func GetFrogbotDetails(commandName string) (frogbotUtils *FrogbotDetails, err error) {
// Get server and git details
jfrogServer, err := extractJFrogCredentialsFromEnvs()
if err != nil {
return
}
- gitClientInfo, err := extractGitInfoFromEnvs()
+ gitParamsFromEnv, err := extractGitParamsFromEnvs()
if err != nil {
return
}
@@ -298,56 +279,50 @@ func GetFrogbotDetails() (frogbotUtils *FrogbotDetails, err error) {
// Build a version control client for REST API requests
client, err := vcsclient.
- NewClientBuilder(gitClientInfo.GitProvider).
- ApiEndpoint(gitClientInfo.APIEndpoint).
- Token(gitClientInfo.Token).
- Project(gitClientInfo.Project).
+ NewClientBuilder(gitParamsFromEnv.GitProvider).
+ ApiEndpoint(gitParamsFromEnv.APIEndpoint).
+ Token(gitParamsFromEnv.Token).
+ Project(gitParamsFromEnv.Project).
Logger(log.GetLogger()).
- Username(gitClientInfo.Username).
+ Username(gitParamsFromEnv.Username).
Build()
if err != nil {
return nil, err
}
- configAggregator, err := getConfigAggregator(client, gitClientInfo, jfrogServer)
+ configAggregator, err := getConfigAggregator(client, gitParamsFromEnv, jfrogServer, commandName)
if err != nil {
return nil, err
}
- return &FrogbotDetails{Repositories: configAggregator, Client: client, ServerDetails: jfrogServer, ReleasesRepo: os.Getenv(jfrogReleasesRepoEnv)}, err
+ return &FrogbotDetails{Repositories: configAggregator, GitClient: client, ServerDetails: jfrogServer, ReleasesRepo: os.Getenv(jfrogReleasesRepoEnv)}, err
}
// getConfigAggregator returns a RepoAggregator based on frogbot-config.yml and environment variables.
-func getConfigAggregator(gitClient vcsclient.VcsClient, gitClientInfo *GitClientInfo, jfrogServer *coreconfig.ServerDetails) (RepoAggregator, error) {
- configFileContent, err := getConfigFileContent(gitClient, gitClientInfo)
+func getConfigAggregator(gitClient vcsclient.VcsClient, gitParamsFromEnv *Git, jfrogServer *coreconfig.ServerDetails, commandName string) (RepoAggregator, error) {
+ configFileContent, err := getConfigFileContent(gitClient, gitParamsFromEnv, commandName)
// Don't return error in case of a missing frogbot-config.yml file
// If an error occurs due to a missing file, attempt to generate an environment variable-based configuration aggregator as an alternative.
var errMissingConfig *ErrMissingConfig
if !errors.As(err, &errMissingConfig) && len(configFileContent) == 0 {
return nil, err
}
- return BuildRepoAggregator(configFileContent, gitClientInfo, jfrogServer)
+ return BuildRepoAggregator(configFileContent, gitParamsFromEnv, jfrogServer)
}
// The getConfigFileContent function retrieves the frogbot-config.yml file content.
// If the JF_GIT_REPO and JF_GIT_OWNER environment variables are set, this function will attempt to retrieve the frogbot-config.yml file from the target repository based on these variables.
// If these variables aren't set, this function will attempt to retrieve the frogbot-config.yml file from the current working directory.
-func getConfigFileContent(gitClient vcsclient.VcsClient, gitClientInfo *GitClientInfo) (configFileContent []byte, err error) {
- configFileContent, err = readConfigFromTarget(gitClient, gitClientInfo)
- var errMissingConfig *ErrMissingConfig
- missingConfigErr := errors.As(err, &errMissingConfig)
- if err != nil && !missingConfigErr {
- return nil, err
- }
- // Read the config from the current working dir
- if len(configFileContent) == 0 {
+func getConfigFileContent(gitClient vcsclient.VcsClient, gitParamsFromEnv *Git, commandName string) (configFileContent []byte, err error) {
+ if commandName == ScanAndFixRepos || commandName == CreateFixPullRequests {
configFileContent, err = ReadConfigFromFileSystem(osFrogbotConfigPath)
+ return
}
- return
+ return readConfigFromTarget(gitClient, gitParamsFromEnv)
}
-// BuildRepoAggregator receive a frogbot-config.yml file content along with the GitClientInfo and ServerDetails parameters.
+// BuildRepoAggregator receives the content of a frogbot-config.yml file, along with the Git (built from environment variables) and ServerDetails parameters.
// Returns a RepoAggregator instance with all the defaults and necessary fields.
-func BuildRepoAggregator(configFileContent []byte, gitClientInfo *GitClientInfo, server *coreconfig.ServerDetails) (resultAggregator RepoAggregator, err error) {
+func BuildRepoAggregator(configFileContent []byte, gitParamsFromEnv *Git, server *coreconfig.ServerDetails) (resultAggregator RepoAggregator, err error) {
var cleanAggregator RepoAggregator
// Unmarshal the frogbot-config.yml file if exists
if cleanAggregator, err = unmarshalFrogbotConfigYaml(configFileContent); err != nil {
@@ -355,8 +330,8 @@ func BuildRepoAggregator(configFileContent []byte, gitClientInfo *GitClientInfo,
}
for _, repository := range cleanAggregator {
repository.Server = *server
- repository.OutputWriter = GetCompatibleOutputWriter(gitClientInfo.GitProvider)
- if err = repository.Params.setDefaultsIfNeeded(gitClientInfo); err != nil {
+ repository.OutputWriter = GetCompatibleOutputWriter(gitParamsFromEnv.GitProvider)
+ if err = repository.Params.setDefaultsIfNeeded(gitParamsFromEnv); err != nil {
return
}
resultAggregator = append(resultAggregator, repository)
@@ -406,10 +381,10 @@ func extractJFrogCredentialsFromEnvs() (*coreconfig.ServerDetails, error) {
return &server, nil
}
-func extractGitInfoFromEnvs() (*GitClientInfo, error) {
+func extractGitParamsFromEnvs() (*Git, error) {
e := &ErrMissingEnv{}
var err error
- clientInfo := &GitClientInfo{}
+ clientInfo := &Git{}
// Branch & Repo names are mandatory variables.
// Must be set in the frogbot-config.yml or as an environment variables.
// Validation performed later
@@ -418,7 +393,9 @@ func extractGitInfoFromEnvs() (*GitClientInfo, error) {
if err = readParamFromEnv(GitBaseBranchEnv, &branch); err != nil && !e.IsMissingEnvErr(err) {
return nil, err
}
- clientInfo.Branches = []string{branch}
+ if branch != "" {
+ clientInfo.Branches = []string{branch}
+ }
// Set the repository name
if err = readParamFromEnv(GitRepoEnv, &clientInfo.RepoName); err != nil && !e.IsMissingEnvErr(err) {
return nil, err
@@ -564,22 +541,26 @@ func getBoolEnv(envKey string, defaultValue bool) (bool, error) {
}
// readConfigFromTarget reads the .frogbot/frogbot-config.yml from the target repository
-func readConfigFromTarget(client vcsclient.VcsClient, clientInfo *GitClientInfo) (configContent []byte, err error) {
- if clientInfo.RepoName != "" && clientInfo.RepoOwner != "" {
- log.Debug("Downloading", FrogbotConfigFile, "from target", clientInfo.RepoOwner, "/", clientInfo.RepoName)
+func readConfigFromTarget(client vcsclient.VcsClient, gitParamsFromEnv *Git) (configContent []byte, err error) {
+ repoName := gitParamsFromEnv.RepoName
+ repoOwner := gitParamsFromEnv.RepoOwner
+ branches := gitParamsFromEnv.Branches
+ if repoName != "" && repoOwner != "" {
+ log.Debug("Downloading", FrogbotConfigFile, "from target", repoOwner, "/", repoName)
var branch string
- if len(clientInfo.Branches) == 0 {
+ if len(branches) == 0 {
log.Debug(GitBaseBranchEnv, "is missing. Assuming that the", FrogbotConfigFile, "file exists on default branch")
} else {
- branch = clientInfo.Branches[0]
+ // We encounter this scenario when the JF_GIT_BASE_BRANCH is defined. In this situation, we have only one branch.
+ branch = branches[0]
log.Debug("the", FrogbotConfigFile, "will be downloaded from the", branch, "branch")
}
gitFrogbotConfigPath := fmt.Sprintf("%s/%s", frogbotConfigDir, FrogbotConfigFile)
var statusCode int
- configContent, statusCode, err = client.DownloadFileFromRepo(context.Background(), clientInfo.RepoOwner, clientInfo.RepoName, branch, gitFrogbotConfigPath)
+ configContent, statusCode, err = client.DownloadFileFromRepo(context.Background(), repoOwner, repoName, branch, gitFrogbotConfigPath)
if statusCode == http.StatusNotFound {
- log.Debug(fmt.Sprintf("the %s file wasn't recognized in the %s repository owned by %s", gitFrogbotConfigPath, clientInfo.RepoName, clientInfo.RepoOwner))
+ log.Debug(fmt.Sprintf("the %s file wasn't recognized in the %s repository owned by %s", gitFrogbotConfigPath, repoName, repoOwner))
// If .frogbot/frogbot-config.yml isn't found, we'll try to run Frogbot using environment variables
return nil, &ErrMissingConfig{errFrogbotConfigNotFound.Error()}
}
diff --git a/commands/utils/params_test.go b/commands/utils/params_test.go
index d6a8d48e3..d3cf88354 100644
--- a/commands/utils/params_test.go
+++ b/commands/utils/params_test.go
@@ -112,15 +112,15 @@ func TestExtractClientInfo(t *testing.T) {
assert.NoError(t, SanitizeEnv())
}()
- _, err := extractGitInfoFromEnvs()
+ _, err := extractGitParamsFromEnvs()
assert.EqualError(t, err, "JF_GIT_PROVIDER should be one of: 'github', 'gitlab', 'bitbucketServer' or 'azureRepos'")
SetEnvAndAssert(t, map[string]string{GitProvider: "github"})
- _, err = extractGitInfoFromEnvs()
+ _, err = extractGitParamsFromEnvs()
assert.EqualError(t, err, "'JF_GIT_OWNER' environment variable is missing")
SetEnvAndAssert(t, map[string]string{GitRepoOwnerEnv: "jfrog"})
- _, err = extractGitInfoFromEnvs()
+ _, err = extractGitParamsFromEnvs()
assert.EqualError(t, err, "'JF_GIT_TOKEN' environment variable is missing")
}
@@ -147,7 +147,7 @@ func TestExtractAndAssertRepoParams(t *testing.T) {
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitInfoFromEnvs()
+ gitParams, err := extractGitParamsFromEnvs()
assert.NoError(t, err)
configFileContent, err := ReadConfigFromFileSystem(configParamsTestFile)
assert.NoError(t, err)
@@ -190,7 +190,7 @@ func TestBuildRepoAggregatorWithEmptyScan(t *testing.T) {
}()
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitInfoFromEnvs()
+ gitParams, err := extractGitParamsFromEnvs()
assert.NoError(t, err)
configFileContent, err := ReadConfigFromFileSystem(configEmptyScanParamsTestFile)
assert.NoError(t, err)
@@ -225,7 +225,7 @@ func testExtractAndAssertProjectParams(t *testing.T, project Project) {
func extractAndAssertParamsFromEnv(t *testing.T, platformUrl, basicAuth bool) {
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitInfoFromEnvs()
+ gitParams, err := extractGitParamsFromEnvs()
assert.NoError(t, err)
configFile, err := BuildRepoAggregator(nil, gitParams, server)
assert.NoError(t, err)
@@ -314,7 +314,7 @@ func TestGenerateConfigAggregatorFromEnv(t *testing.T) {
assert.NoError(t, SanitizeEnv())
}()
- gitClientInfo := GitClientInfo{
+ gitParams := Git{
GitProvider: vcsutils.GitHub,
VcsInfo: vcsclient.VcsInfo{
APIEndpoint: "https://github.com",
@@ -330,7 +330,7 @@ func TestGenerateConfigAggregatorFromEnv(t *testing.T) {
User: "admin",
Password: "password",
}
- repoAggregator, err := BuildRepoAggregator(nil, &gitClientInfo, &server)
+ repoAggregator, err := BuildRepoAggregator(nil, &gitParams, &server)
assert.NoError(t, err)
repo := repoAggregator[0]
assert.Equal(t, "repoName", repo.RepoName)
@@ -338,12 +338,12 @@ func TestGenerateConfigAggregatorFromEnv(t *testing.T) {
assert.Equal(t, false, *repo.FailOnSecurityIssues)
assert.Equal(t, "Medium", repo.MinSeverity)
assert.Equal(t, true, repo.FixableOnly)
- assert.Equal(t, gitClientInfo.RepoOwner, repo.RepoOwner)
- assert.Equal(t, gitClientInfo.Token, repo.Token)
- assert.Equal(t, gitClientInfo.APIEndpoint, repo.APIEndpoint)
- assert.ElementsMatch(t, gitClientInfo.Branches, repo.Branches)
+ assert.Equal(t, gitParams.RepoOwner, repo.RepoOwner)
+ assert.Equal(t, gitParams.Token, repo.Token)
+ assert.Equal(t, gitParams.APIEndpoint, repo.APIEndpoint)
+ assert.ElementsMatch(t, gitParams.Branches, repo.Branches)
assert.Equal(t, repo.PullRequestID, repo.PullRequestID)
- assert.Equal(t, gitClientInfo.GitProvider, repo.GitProvider)
+ assert.Equal(t, gitParams.GitProvider, repo.GitProvider)
assert.Equal(t, repo.BranchNameTemplate, repo.BranchNameTemplate)
assert.Equal(t, repo.CommitMessageTemplate, repo.CommitMessageTemplate)
assert.Equal(t, repo.PullRequestTitleTemplate, repo.PullRequestTitleTemplate)
@@ -463,7 +463,7 @@ func TestBuildMergedRepoAggregator(t *testing.T) {
testFilePath := filepath.Join("..", "testdata", "config", "frogbot-config-test-params-merge.yml")
fileContent, err := os.ReadFile(testFilePath)
assert.NoError(t, err)
- gitClientInfo := &GitClientInfo{
+ gitParams := &Git{
GitProvider: vcsutils.GitHub,
VcsInfo: vcsclient.VcsInfo{
APIEndpoint: "endpoint.com",
@@ -479,7 +479,7 @@ func TestBuildMergedRepoAggregator(t *testing.T) {
User: "admin",
Password: "password",
}
- repoAggregator, err := BuildRepoAggregator(fileContent, gitClientInfo, &server)
+ repoAggregator, err := BuildRepoAggregator(fileContent, gitParams, &server)
assert.NoError(t, err)
repo := repoAggregator[0]
assert.Equal(t, repo.AggregateFixes, false)
diff --git a/commands/utils/utils.go b/commands/utils/utils.go
index e75b2e5b0..2cee2c3d5 100644
--- a/commands/utils/utils.go
+++ b/commands/utils/utils.go
@@ -26,8 +26,12 @@ import (
)
const (
- RootDir = "."
- branchNameRegex = `[~^:?\\\[\]@{}*]`
+ ScanPullRequest = "scan-pull-request"
+ ScanPullRequests = "scan-pull-requests"
+ CreateFixPullRequests = "create-fix-pull-requests"
+ ScanAndFixRepos = "scan-and-fix-repos"
+ RootDir = "."
+ branchNameRegex = `[~^:?\\\[\]@{}*]`
// Branch validation error messages
branchInvalidChars = "branch name cannot contain the following chars ~, ^, :, ?, *, [, ], @, {, }"
From db01835ddc04fa56e6c19387b51041c94026203d Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Mon, 7 Aug 2023 17:23:19 +0300
Subject: [PATCH 3/8] Fix open pull request against the wrong branch
---
commands/commands.go | 14 +++++++-------
commands/utils/params.go | 2 +-
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/commands/commands.go b/commands/commands.go
index a9c7c10c4..efc17db59 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -18,15 +18,15 @@ type FrogbotCommand interface {
}
func Exec(command FrogbotCommand, name string) (err error) {
- // Get frogbotUtils that contains the config, server, and VCS client
+ // Get frogbotDetails that contains the config, server, and VCS client
log.Info("Frogbot version:", utils.FrogbotVersion)
- frogbotUtils, err := utils.GetFrogbotDetails(name)
+ frogbotDetails, err := utils.GetFrogbotDetails(name)
if err != nil {
return err
}
// Build the server configuration file
- originalJfrogHomeDir, tempJFrogHomeDir, err := utils.BuildServerConfigFile(frogbotUtils.ServerDetails)
+ originalJfrogHomeDir, tempJFrogHomeDir, err := utils.BuildServerConfigFile(frogbotDetails.ServerDetails)
if err != nil {
return err
}
@@ -36,8 +36,8 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Set releases remote repository env if needed
previousReleasesRepoEnv := os.Getenv(coreutils.ReleasesRemoteEnv)
- if frogbotUtils.ReleasesRepo != "" {
- if err = os.Setenv(coreutils.ReleasesRemoteEnv, fmt.Sprintf("frogbot/%s", frogbotUtils.ReleasesRepo)); err != nil {
+ if frogbotDetails.ReleasesRepo != "" {
+ if err = os.Setenv(coreutils.ReleasesRemoteEnv, fmt.Sprintf("frogbot/%s", frogbotDetails.ReleasesRepo)); err != nil {
return
}
defer func() {
@@ -47,11 +47,11 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Send a usage report
usageReportSent := make(chan error)
- go utils.ReportUsage(name, frogbotUtils.ServerDetails, usageReportSent)
+ go utils.ReportUsage(name, frogbotDetails.ServerDetails, usageReportSent)
// Invoke the command interface
log.Info(fmt.Sprintf("Running Frogbot %q command", name))
- err = command.Run(frogbotUtils.Repositories, frogbotUtils.GitClient)
+ err = command.Run(frogbotDetails.Repositories, frogbotDetails.GitClient)
// Wait for a signal, letting us know that the usage reporting is done.
<-usageReportSent
diff --git a/commands/utils/params.go b/commands/utils/params.go
index 6df27a5e1..327145568 100644
--- a/commands/utils/params.go
+++ b/commands/utils/params.go
@@ -262,7 +262,7 @@ func validateHashPlaceHolder(template string) error {
return nil
}
-func GetFrogbotDetails(commandName string) (frogbotUtils *FrogbotDetails, err error) {
+func GetFrogbotDetails(commandName string) (frogbotDetails *FrogbotDetails, err error) {
// Get server and git details
jfrogServer, err := extractJFrogCredentialsFromEnvs()
if err != nil {
From 22ef63fbc39399598e7f44930e65f3ab40c1844b Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Tue, 8 Aug 2023 08:02:13 +0300
Subject: [PATCH 4/8] fix static analysis
---
commands/utils/git_test.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/commands/utils/git_test.go b/commands/utils/git_test.go
index 07eadcfc5..965a501e7 100644
--- a/commands/utils/git_test.go
+++ b/commands/utils/git_test.go
@@ -254,7 +254,8 @@ func TestGitManager_Checkout(t *testing.T) {
defer func() {
assert.NoError(t, fileutils.RemoveTempDir(tmpDir))
}()
- restoreWd, err := Chdir(tmpDir)
+ var restoreWd func() error
+ restoreWd, err = Chdir(tmpDir)
defer func() {
assert.NoError(t, restoreWd())
}()
From d26cf18a3b863444c7eccf5636fe3e1c59a4c653 Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Tue, 8 Aug 2023 08:37:42 +0300
Subject: [PATCH 5/8] fix static analysis
---
commands/utils/git_test.go | 1 +
1 file changed, 1 insertion(+)
diff --git a/commands/utils/git_test.go b/commands/utils/git_test.go
index 965a501e7..9d6897ce5 100644
--- a/commands/utils/git_test.go
+++ b/commands/utils/git_test.go
@@ -256,6 +256,7 @@ func TestGitManager_Checkout(t *testing.T) {
}()
var restoreWd func() error
restoreWd, err = Chdir(tmpDir)
+ assert.NoError(t, err)
defer func() {
assert.NoError(t, restoreWd())
}()
From 0182fd9b7f67d23bb7c90b4e3b7045fe458dfcc2 Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Tue, 8 Aug 2023 13:50:11 +0300
Subject: [PATCH 6/8] cr changes
---
commands/commands.go | 14 +++++++-------
commands/utils/params.go | 4 ++--
commands/utils/params_test.go | 12 ++++++------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/commands/commands.go b/commands/commands.go
index efc17db59..a9c7c10c4 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -18,15 +18,15 @@ type FrogbotCommand interface {
}
func Exec(command FrogbotCommand, name string) (err error) {
- // Get frogbotDetails that contains the config, server, and VCS client
+ // Get frogbotUtils that contains the config, server, and VCS client
log.Info("Frogbot version:", utils.FrogbotVersion)
- frogbotDetails, err := utils.GetFrogbotDetails(name)
+ frogbotUtils, err := utils.GetFrogbotDetails(name)
if err != nil {
return err
}
// Build the server configuration file
- originalJfrogHomeDir, tempJFrogHomeDir, err := utils.BuildServerConfigFile(frogbotDetails.ServerDetails)
+ originalJfrogHomeDir, tempJFrogHomeDir, err := utils.BuildServerConfigFile(frogbotUtils.ServerDetails)
if err != nil {
return err
}
@@ -36,8 +36,8 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Set releases remote repository env if needed
previousReleasesRepoEnv := os.Getenv(coreutils.ReleasesRemoteEnv)
- if frogbotDetails.ReleasesRepo != "" {
- if err = os.Setenv(coreutils.ReleasesRemoteEnv, fmt.Sprintf("frogbot/%s", frogbotDetails.ReleasesRepo)); err != nil {
+ if frogbotUtils.ReleasesRepo != "" {
+ if err = os.Setenv(coreutils.ReleasesRemoteEnv, fmt.Sprintf("frogbot/%s", frogbotUtils.ReleasesRepo)); err != nil {
return
}
defer func() {
@@ -47,11 +47,11 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Send a usage report
usageReportSent := make(chan error)
- go utils.ReportUsage(name, frogbotDetails.ServerDetails, usageReportSent)
+ go utils.ReportUsage(name, frogbotUtils.ServerDetails, usageReportSent)
// Invoke the command interface
log.Info(fmt.Sprintf("Running Frogbot %q command", name))
- err = command.Run(frogbotDetails.Repositories, frogbotDetails.GitClient)
+ err = command.Run(frogbotUtils.Repositories, frogbotUtils.GitClient)
// Wait for a signal, letting us know that the usage reporting is done.
<-usageReportSent
diff --git a/commands/utils/params.go b/commands/utils/params.go
index 327145568..40735149b 100644
--- a/commands/utils/params.go
+++ b/commands/utils/params.go
@@ -268,7 +268,7 @@ func GetFrogbotDetails(commandName string) (frogbotDetails *FrogbotDetails, err
if err != nil {
return
}
- gitParamsFromEnv, err := extractGitParamsFromEnvs()
+ gitParamsFromEnv, err := extractGitInfoFromEnvs()
if err != nil {
return
}
@@ -381,7 +381,7 @@ func extractJFrogCredentialsFromEnvs() (*coreconfig.ServerDetails, error) {
return &server, nil
}
-func extractGitParamsFromEnvs() (*Git, error) {
+func extractGitInfoFromEnvs() (*Git, error) {
e := &ErrMissingEnv{}
var err error
clientInfo := &Git{}
diff --git a/commands/utils/params_test.go b/commands/utils/params_test.go
index 14db66334..5a8ec278b 100644
--- a/commands/utils/params_test.go
+++ b/commands/utils/params_test.go
@@ -112,15 +112,15 @@ func TestExtractClientInfo(t *testing.T) {
assert.NoError(t, SanitizeEnv())
}()
- _, err := extractGitParamsFromEnvs()
+ _, err := extractGitInfoFromEnvs()
assert.EqualError(t, err, "JF_GIT_PROVIDER should be one of: 'github', 'gitlab', 'bitbucketServer' or 'azureRepos'")
SetEnvAndAssert(t, map[string]string{GitProvider: "github"})
- _, err = extractGitParamsFromEnvs()
+ _, err = extractGitInfoFromEnvs()
assert.EqualError(t, err, "'JF_GIT_OWNER' environment variable is missing")
SetEnvAndAssert(t, map[string]string{GitRepoOwnerEnv: "jfrog"})
- _, err = extractGitParamsFromEnvs()
+ _, err = extractGitInfoFromEnvs()
assert.EqualError(t, err, "'JF_GIT_TOKEN' environment variable is missing")
}
@@ -147,7 +147,7 @@ func TestExtractAndAssertRepoParams(t *testing.T) {
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitParamsFromEnvs()
+ gitParams, err := extractGitInfoFromEnvs()
assert.NoError(t, err)
configFileContent, err := ReadConfigFromFileSystem(configParamsTestFile)
assert.NoError(t, err)
@@ -190,7 +190,7 @@ func TestBuildRepoAggregatorWithEmptyScan(t *testing.T) {
}()
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitParamsFromEnvs()
+ gitParams, err := extractGitInfoFromEnvs()
assert.NoError(t, err)
configFileContent, err := ReadConfigFromFileSystem(configEmptyScanParamsTestFile)
assert.NoError(t, err)
@@ -225,7 +225,7 @@ func testExtractAndAssertProjectParams(t *testing.T, project Project) {
func extractAndAssertParamsFromEnv(t *testing.T, platformUrl, basicAuth bool) {
server, err := extractJFrogCredentialsFromEnvs()
assert.NoError(t, err)
- gitParams, err := extractGitParamsFromEnvs()
+ gitParams, err := extractGitInfoFromEnvs()
assert.NoError(t, err)
configFile, err := BuildRepoAggregator(nil, gitParams, server)
assert.NoError(t, err)
From ee72f7940aeee30a03fc756f8368e45a0fc7e632 Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Wed, 9 Aug 2023 12:50:00 +0300
Subject: [PATCH 7/8] CR changes
---
commands/commands.go | 10 +++++-----
commands/utils/git.go | 8 --------
commands/utils/params.go | 38 ++++++++++++++++++--------------------
3 files changed, 23 insertions(+), 33 deletions(-)
diff --git a/commands/commands.go b/commands/commands.go
index a9c7c10c4..46e217fa2 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -17,10 +17,10 @@ type FrogbotCommand interface {
Run(config utils.RepoAggregator, client vcsclient.VcsClient) error
}
-func Exec(command FrogbotCommand, name string) (err error) {
+func Exec(command FrogbotCommand, commandName string) (err error) {
// Get frogbotUtils that contains the config, server, and VCS client
log.Info("Frogbot version:", utils.FrogbotVersion)
- frogbotUtils, err := utils.GetFrogbotDetails(name)
+ frogbotUtils, err := utils.GetFrogbotDetails(commandName)
if err != nil {
return err
}
@@ -47,17 +47,17 @@ func Exec(command FrogbotCommand, name string) (err error) {
// Send a usage report
usageReportSent := make(chan error)
- go utils.ReportUsage(name, frogbotUtils.ServerDetails, usageReportSent)
+ go utils.ReportUsage(commandName, frogbotUtils.ServerDetails, usageReportSent)
// Invoke the command interface
- log.Info(fmt.Sprintf("Running Frogbot %q command", name))
+ log.Info(fmt.Sprintf("Running Frogbot %q command", commandName))
err = command.Run(frogbotUtils.Repositories, frogbotUtils.GitClient)
// Wait for a signal, letting us know that the usage reporting is done.
<-usageReportSent
if err == nil {
- log.Info(fmt.Sprintf("Frogbot %q command finished successfully", name))
+ log.Info(fmt.Sprintf("Frogbot %q command finished successfully", commandName))
}
return err
}
diff --git a/commands/utils/git.go b/commands/utils/git.go
index dd018142b..fc941d2b3 100644
--- a/commands/utils/git.go
+++ b/commands/utils/git.go
@@ -151,14 +151,6 @@ func (gm *GitManager) CreateBranchAndCheckout(branchName string) error {
}
func (gm *GitManager) createBranchAndCheckout(branchName string, create bool) error {
- currentBranch, err := getCurrentBranch(gm.repository)
- if err != nil {
- return err
- }
- if currentBranch == branchName {
- log.Debug("Skipping `git checkout`, as the branch name is already the same as the current branch")
- return nil
- }
checkoutConfig := &git.CheckoutOptions{
Create: create,
Branch: getFullBranchName(branchName),
diff --git a/commands/utils/params.go b/commands/utils/params.go
index 40735149b..8c65da9b8 100644
--- a/commands/utils/params.go
+++ b/commands/utils/params.go
@@ -209,16 +209,14 @@ func (g *Git) setDefaultsIfNeeded(gitParamsFromEnv *Git) (err error) {
}
g.RepoName = gitParamsFromEnv.RepoName
}
- if len(g.Branches) == 0 {
- if len(gitParamsFromEnv.Branches) == 0 {
- var branch string
- if branch, err = GetBranchFromDotGit(); err != nil {
- return
- }
- g.Branches = append(g.Branches, branch)
- } else {
- g.Branches = append(g.Branches, gitParamsFromEnv.Branches...)
+ if len(g.Branches) == 0 && len(gitParamsFromEnv.Branches) == 0 {
+ var branch string
+ if branch, err = GetBranchFromDotGit(); err != nil {
+ return
}
+ g.Branches = append(g.Branches, branch)
+ } else if len(g.Branches) == 0 {
+ g.Branches = append(g.Branches, gitParamsFromEnv.Branches...)
}
if g.BranchNameTemplate == "" {
branchTemplate := getTrimmedEnv(BranchNameTemplateEnv)
@@ -384,7 +382,7 @@ func extractJFrogCredentialsFromEnvs() (*coreconfig.ServerDetails, error) {
func extractGitInfoFromEnvs() (*Git, error) {
e := &ErrMissingEnv{}
var err error
- clientInfo := &Git{}
+ gitEnvParams := &Git{}
// Branch & Repo names are mandatory variables.
// Must be set in the frogbot-config.yml or as an environment variables.
// Validation performed later
@@ -394,45 +392,45 @@ func extractGitInfoFromEnvs() (*Git, error) {
return nil, err
}
if branch != "" {
- clientInfo.Branches = []string{branch}
+ gitEnvParams.Branches = []string{branch}
}
// Set the repository name
- if err = readParamFromEnv(GitRepoEnv, &clientInfo.RepoName); err != nil && !e.IsMissingEnvErr(err) {
+ if err = readParamFromEnv(GitRepoEnv, &gitEnvParams.RepoName); err != nil && !e.IsMissingEnvErr(err) {
return nil, err
}
// Non-mandatory Git Api Endpoint, if not set, default values will be used.
- if err = readParamFromEnv(GitApiEndpointEnv, &clientInfo.APIEndpoint); err != nil && !e.IsMissingEnvErr(err) {
+ if err = readParamFromEnv(GitApiEndpointEnv, &gitEnvParams.APIEndpoint); err != nil && !e.IsMissingEnvErr(err) {
return nil, err
}
- if err = verifyValidApiEndpoint(clientInfo.APIEndpoint); err != nil {
+ if err = verifyValidApiEndpoint(gitEnvParams.APIEndpoint); err != nil {
return nil, err
}
// Set the Git provider
- if clientInfo.GitProvider, err = extractVcsProviderFromEnv(); err != nil {
+ if gitEnvParams.GitProvider, err = extractVcsProviderFromEnv(); err != nil {
return nil, err
}
// Set the git repository owner name (organization)
- if err = readParamFromEnv(GitRepoOwnerEnv, &clientInfo.RepoOwner); err != nil {
+ if err = readParamFromEnv(GitRepoOwnerEnv, &gitEnvParams.RepoOwner); err != nil {
return nil, err
}
// Set the access token to the git provider
- if err = readParamFromEnv(GitTokenEnv, &clientInfo.Token); err != nil {
+ if err = readParamFromEnv(GitTokenEnv, &gitEnvParams.Token); err != nil {
return nil, err
}
// Set Bitbucket Server username
// Mandatory only for Bitbucket Server, this authentication detail is required for performing git operations.
- if err = readParamFromEnv(GitUsernameEnv, &clientInfo.Username); err != nil && !e.IsMissingEnvErr(err) {
+ if err = readParamFromEnv(GitUsernameEnv, &gitEnvParams.Username); err != nil && !e.IsMissingEnvErr(err) {
return nil, err
}
// Set Azure Repos Project name
// Mandatory for Azure Repos only
- if err = readParamFromEnv(GitProjectEnv, &clientInfo.Project); err != nil && clientInfo.GitProvider == vcsutils.AzureRepos {
+ if err = readParamFromEnv(GitProjectEnv, &gitEnvParams.Project); err != nil && gitEnvParams.GitProvider == vcsutils.AzureRepos {
return nil, err
}
- return clientInfo, nil
+ return gitEnvParams, nil
}
func verifyValidApiEndpoint(apiEndpoint string) error {
From c5d3c9b403ccacc6baf6ec23afa085f494f8ee7f Mon Sep 17 00:00:00 2001
From: Omer Zidkoni
Date: Wed, 9 Aug 2023 13:59:36 +0300
Subject: [PATCH 8/8] Fix tests
---
commands/createfixpullrequests.go | 6 +++---
commands/createfixpullrequests_test.go | 2 +-
.../aggregate-multi-dir/git/COMMIT_EDITMSG | 2 +-
.../aggregate-multi-dir/git/index | Bin 412 -> 412 bytes
.../aggregate-multi-dir/git/logs/HEAD | 2 +-
.../git/logs/refs/heads/main | 2 +-
.../11/a23eda8941289a57af01af4929e3a6fd024dd7 | Bin 0 -> 57 bytes
.../20/cfb0cbabf22f1c12d626eec6e6dd834f4e43d1 | 2 --
.../4432f7bbfd21f68525f7b9bf738931e91c37b9} | Bin 103 -> 103 bytes
.../59/fbea5efff5cfe6a005f33aaadbf21d58dc4af8 | 2 ++
.../61/a70d8baf4dd63a6b1b01f87791cb73425caf55 | Bin 57 -> 0 bytes
.../be/180a62cd192cb4ef53647c6d907074d428d724 | Bin 63 -> 0 bytes
.../ff/94a18e368955fa7b7dfd66774838a64dc15efc | Bin 0 -> 62 bytes
.../aggregate-multi-dir/git/refs/heads/main | 2 +-
14 files changed, 10 insertions(+), 10 deletions(-)
create mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/11/a23eda8941289a57af01af4929e3a6fd024dd7
delete mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/20/cfb0cbabf22f1c12d626eec6e6dd834f4e43d1
rename commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/{b1/d50a083f2239a3ff3b3ed2d1bbaea16d17c1ee => 3e/4432f7bbfd21f68525f7b9bf738931e91c37b9} (62%)
create mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/59/fbea5efff5cfe6a005f33aaadbf21d58dc4af8
delete mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/61/a70d8baf4dd63a6b1b01f87791cb73425caf55
delete mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/be/180a62cd192cb4ef53647c6d907074d428d724
create mode 100644 commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/ff/94a18e368955fa7b7dfd66774838a64dc15efc
diff --git a/commands/createfixpullrequests.go b/commands/createfixpullrequests.go
index 60f256a8c..2dcdeb31c 100644
--- a/commands/createfixpullrequests.go
+++ b/commands/createfixpullrequests.go
@@ -63,10 +63,10 @@ func (cfp *CreateFixPullRequestsCmd) scanAndFixRepository(repository *utils.Repo
if err = cfp.setCommandPrerequisites(repository, branch, client); err != nil {
return
}
+ if err = cfp.gitManager.Checkout(branch); err != nil {
+ return fmt.Errorf("failed to checkout to %s branch before scanning. The following error has been received:\n%s", branch, err.Error())
+ }
for i := range repository.Projects {
- if err = cfp.gitManager.Checkout(branch); err != nil {
- return fmt.Errorf("failed to checkout to %s branch before scanning. The following error has been received:\n%s", branch, err.Error())
- }
cfp.details.Project = &repository.Projects[i]
cfp.projectTech = ""
if err = cfp.scanAndFixProject(repository); err != nil {
diff --git a/commands/createfixpullrequests_test.go b/commands/createfixpullrequests_test.go
index 4d94270ac..a370aa011 100644
--- a/commands/createfixpullrequests_test.go
+++ b/commands/createfixpullrequests_test.go
@@ -91,7 +91,7 @@ func TestCreateFixPullRequestsCmd_Run(t *testing.T) {
repoName: "aggregate-multi-dir",
testDir: "createfixpullrequests/aggregate-multi-dir",
expectedBranches: []string{"frogbot-update-npm-dependencies"},
- expectedDiff: []string{"diff --git a/npm1/package.json b/npm1/package.json\nindex ae09978..286211d 100644\n--- a/npm1/package.json\n+++ b/npm1/package.json\n@@ -9,8 +9,8 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"uuid\": \"^9.0.0\",\n- \"minimatch\":\"3.0.2\",\n- \"mpath\": \"0.7.0\"\n+ \"minimatch\": \"^3.0.5\",\n+ \"mpath\": \"^0.8.4\",\n+ \"uuid\": \"^9.0.0\"\n }\n-}\n\\ No newline at end of file\n+}\ndiff --git a/npm2/package.json b/npm2/package.json\nindex be180a6..14b5c7a 100644\n--- a/npm2/package.json\n+++ b/npm2/package.json\n@@ -1,5 +1,5 @@\n {\n \"dependencies\": {\n- \"minimist\": \"^1.2.5\"\n+ \"minimist\": \"^1.2.6\"\n }\n }\n"},
+ expectedDiff: []string{"diff --git a/npm1/package.json b/npm1/package.json\nindex ae09978..286211d 100644\n--- a/npm1/package.json\n+++ b/npm1/package.json\n@@ -9,8 +9,8 @@\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n- \"uuid\": \"^9.0.0\",\n- \"minimatch\":\"3.0.2\",\n- \"mpath\": \"0.7.0\"\n+ \"minimatch\": \"^3.0.5\",\n+ \"mpath\": \"^0.8.4\",\n+ \"uuid\": \"^9.0.0\"\n }\n-}\n\\ No newline at end of file\n+}\ndiff --git a/npm2/package.json b/npm2/package.json\nindex ff94a18..14b5c7a 100644\n--- a/npm2/package.json\n+++ b/npm2/package.json\n@@ -1,5 +1,5 @@\n {\n \"dependencies\": {\n- \"minimist\": \"1.2.5\"\n+ \"minimist\": \"^1.2.6\"\n }\n }\n"},
packageDescriptorPaths: []string{"npm1/package.json", "npm2/package.json"},
aggregateFixes: true,
configPath: "testdata/createfixpullrequests/aggregate-multi-dir/.frogbot/frogbot-config.yml",
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/COMMIT_EDITMSG b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/COMMIT_EDITMSG
index b2c0d99a7..b1b716105 100644
--- a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/COMMIT_EDITMSG
+++ b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/COMMIT_EDITMSG
@@ -1 +1 @@
-fix tests
+init
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/index b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/index
index 6c359bb82ebd30469488972bab6b554c8de79951..cf9043747ba7d5e64e8d69e945d8b1ca115472a2 100644
GIT binary patch
delta 205
zcmbQkJcn7u#WTp6fq{Vuh?!IN+1--aUHBhHGcqvnvnYp|PgL;~2T9%gYYCPD(om_W
zi7l4aAgM=vzF;XJ4V8*vU}#*zz`*zwXtD?poBW@$u+OYB^jCH5-?VZMi)FqCfkhRbB)6K;J0JJDic>n+a
delta 205
zcmbQkJcn7u#WTp6fq{Vuh?!G%e7~eSiMJ9)Gcqvnv&hC=oT%a{zEf(w-jnam}D2i;n%Ee)?WV!giwcVwQyVotu6+ifHvM!^VNaAwd?)ARctg@vUf0R!=UF;OI
gK6G+AqoT;|&aTkxsxrH#vyb^rhX
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/HEAD b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/HEAD
index d4a6b8be3..8f31b400b 100644
--- a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/HEAD
+++ b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/HEAD
@@ -1 +1 @@
-0000000000000000000000000000000000000000 20cfb0cbabf22f1c12d626eec6e6dd834f4e43d1 Omer Zidkoni 1689852711 +0300 commit (initial): fix tests
+0000000000000000000000000000000000000000 59fbea5efff5cfe6a005f33aaadbf21d58dc4af8 Omer Zidkoni 1691578013 +0300 commit (initial): init
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/refs/heads/main b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/refs/heads/main
index d4a6b8be3..8f31b400b 100644
--- a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/refs/heads/main
+++ b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/logs/refs/heads/main
@@ -1 +1 @@
-0000000000000000000000000000000000000000 20cfb0cbabf22f1c12d626eec6e6dd834f4e43d1 Omer Zidkoni 1689852711 +0300 commit (initial): fix tests
+0000000000000000000000000000000000000000 59fbea5efff5cfe6a005f33aaadbf21d58dc4af8 Omer Zidkoni 1691578013 +0300 commit (initial): init
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/11/a23eda8941289a57af01af4929e3a6fd024dd7 b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/11/a23eda8941289a57af01af4929e3a6fd024dd7
new file mode 100644
index 0000000000000000000000000000000000000000..b548a06530c89b05e9e234035210da16cd5c869b
GIT binary patch
literal 57
zcmV-90LK4#0V^p=O;s>4U@$Z=Ff%bxC`e4sPE1eL%PP*#WB5O1VV_xN=&$P9ziH(j
P7R!7O#{B^Rk1G>sU{M!%
literal 0
HcmV?d00001
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/20/cfb0cbabf22f1c12d626eec6e6dd834f4e43d1 b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/20/cfb0cbabf22f1c12d626eec6e6dd834f4e43d1
deleted file mode 100644
index ef0858726..000000000
--- a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/20/cfb0cbabf22f1c12d626eec6e6dd834f4e43d1
+++ /dev/null
@@ -1,2 +0,0 @@
-x��K
-1@]���4�tD��{w��Z�:���+�|/IkU��ig��y��.T��5P)���c��sF��ل�ޥåq�k�OyU8Ê ï¿½ï¿½Q��I� p^�er���5Î����Ҕ��M7� �7�
\ No newline at end of file
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/b1/d50a083f2239a3ff3b3ed2d1bbaea16d17c1ee b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/3e/4432f7bbfd21f68525f7b9bf738931e91c37b9
similarity index 62%
rename from commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/b1/d50a083f2239a3ff3b3ed2d1bbaea16d17c1ee
rename to commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/3e/4432f7bbfd21f68525f7b9bf738931e91c37b9
index fef22e8a2036e423706f7a9b51c4d10b82f38bb2..0641f5f1a4ee354ff40eb6b9d82cc5068e475c29 100644
GIT binary patch
delta 32
ocmYdKpWq|ySTOPKT0i&R$cL{buUBW;#eJK8^1Btot~~Wn0Q-LrbpQYW
delta 32
ocmYdKpWq{{SZJC5z3P5;*v(5l_NUb6>6LXw%5yR73sbiR0O)fKJ^%m!
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/59/fbea5efff5cfe6a005f33aaadbf21d58dc4af8 b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/59/fbea5efff5cfe6a005f33aaadbf21d58dc4af8
new file mode 100644
index 000000000..ba487150c
--- /dev/null
+++ b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/59/fbea5efff5cfe6a005f33aaadbf21d58dc4af8
@@ -0,0 +1,2 @@
+x��A� E]s�ٛ�)��x��� EC'!����+�|?y�'n��ٞF�(O��b,��2{k�P�ő�9`"a���wX[�p�ۇ�
+�n���yIܮ�
h��Hp֤��U��H����u��d5
\ No newline at end of file
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/61/a70d8baf4dd63a6b1b01f87791cb73425caf55 b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/61/a70d8baf4dd63a6b1b01f87791cb73425caf55
deleted file mode 100644
index af1a192778d8feafeb97f3957cdc3fe2cc26069a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 57
zcmV-90LK4#0V^p=O;s>4U@$Z=Ff%bxC`e4sPE1eL%PP*#W7sFbm2_58XUqHGl$zWL
P1tnKBuB!k5aYPY1Pe&Ed
diff --git a/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/be/180a62cd192cb4ef53647c6d907074d428d724 b/commands/testdata/createfixpullrequests/aggregate-multi-dir/git/objects/be/180a62cd192cb4ef53647c6d907074d428d724
deleted file mode 100644
index d83aed2c86b91f1f58d6f03c80b60afb84f03411..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 63
zcmb