Skip to content

Commit 91541a8

Browse files
committed
Generify git log parsing
1 parent f895d8a commit 91541a8

File tree

3 files changed

+245
-174
lines changed

3 files changed

+245
-174
lines changed

artifactory/commands/buildinfo/addgit.go

Lines changed: 14 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,18 @@ package buildinfo
22

33
import (
44
"errors"
5-
"io"
6-
"os"
7-
"os/exec"
5+
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
86
"strconv"
97

108
buildinfo "github.com/jfrog/build-info-go/entities"
119
gofrogcmd "github.com/jfrog/gofrog/io"
12-
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
1310
"github.com/jfrog/jfrog-cli-core/v2/common/build"
1411
"github.com/jfrog/jfrog-cli-core/v2/common/project"
1512
utilsconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
16-
"github.com/jfrog/jfrog-client-go/artifactory/services"
17-
artclientutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
1813
clientutils "github.com/jfrog/jfrog-client-go/utils"
1914

2015
"github.com/forPelevin/gomoji"
2116
"github.com/jfrog/jfrog-client-go/utils/errorutils"
22-
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
2317
"github.com/jfrog/jfrog-client-go/utils/log"
2418
"github.com/spf13/viper"
2519
)
@@ -29,6 +23,7 @@ const (
2923
ConfigIssuesPrefix = "issues."
3024
ConfigParseValueError = "Failed parsing %s from configuration file: %s"
3125
MissingConfigurationError = "Configuration file must contain: %s"
26+
gitParsingPrettyFormat = "format:%s"
3227
)
3328

3429
type BuildAddGitCommand struct {
@@ -84,15 +79,9 @@ func (config *BuildAddGitCommand) Run() error {
8479
}
8580

8681
// Find .git if it wasn't provided in the command.
87-
if config.dotGitPath == "" {
88-
var exists bool
89-
config.dotGitPath, exists, err = fileutils.FindUpstream(".git", fileutils.Any)
90-
if err != nil {
91-
return err
92-
}
93-
if !exists {
94-
return errorutils.CheckErrorf("Could not find .git")
95-
}
82+
config.dotGitPath, err = utils.GetDotGit(config.dotGitPath)
83+
if err != nil {
84+
return err
9685
}
9786

9887
// Collect URL, branch and revision into GitManager.
@@ -105,7 +94,7 @@ func (config *BuildAddGitCommand) Run() error {
10594
// Collect issues if required.
10695
var issues []buildinfo.AffectedIssue
10796
if config.configFilePath != "" {
108-
issues, err = config.collectBuildIssues(gitManager.GetUrl())
97+
issues, err = config.collectBuildIssues()
10998
if err != nil {
11099
return err
111100
}
@@ -163,77 +152,31 @@ func (config *BuildAddGitCommand) CommandName() string {
163152
return "rt_build_add_git"
164153
}
165154

166-
func (config *BuildAddGitCommand) collectBuildIssues(vcsUrl string) ([]buildinfo.AffectedIssue, error) {
155+
func (config *BuildAddGitCommand) collectBuildIssues() ([]buildinfo.AffectedIssue, error) {
167156
log.Info("Collecting build issues from VCS...")
168157

169-
// Check that git exists in path.
170-
_, err := exec.LookPath("git")
171-
if err != nil {
172-
return nil, errorutils.CheckError(err)
173-
}
174-
175158
// Initialize issues-configuration.
176159
config.issuesConfig = new(IssuesConfiguration)
177160

178161
// Create config's IssuesConfigurations from the provided spec file.
179-
err = config.createIssuesConfigs()
162+
err := config.createIssuesConfigs()
180163
if err != nil {
181164
return nil, err
182165
}
183166

184-
// Get latest build's VCS revision from Artifactory.
185-
lastVcsRevision, err := config.getLatestVcsRevision(vcsUrl)
167+
var foundIssues []buildinfo.AffectedIssue
168+
logRegExp, err := createLogRegExpHandler(config.issuesConfig, &foundIssues)
186169
if err != nil {
187170
return nil, err
188171
}
189172

190173
// Run issues collection.
191-
return config.DoCollect(config.issuesConfig, lastVcsRevision)
192-
}
193-
194-
func (config *BuildAddGitCommand) DoCollect(issuesConfig *IssuesConfiguration, lastVcsRevision string) (foundIssues []buildinfo.AffectedIssue, err error) {
195-
logRegExp, err := createLogRegExpHandler(issuesConfig, &foundIssues)
196-
if err != nil {
197-
return
198-
}
199-
200-
errRegExp, err := createErrRegExpHandler(lastVcsRevision)
174+
gitDetails := utils.GitParsingDetails{DotGitPath: config.dotGitPath, LogLimit: config.issuesConfig.LogLimit, PrettyFormat: gitParsingPrettyFormat}
175+
err = utils.ParseGitLogsFromLastBuild(config.issuesConfig.ServerDetails, config.buildConfiguration, gitDetails, logRegExp)
201176
if err != nil {
202-
return
203-
}
204-
205-
// Get log with limit, starting from the latest commit.
206-
logCmd := &LogCmd{logLimit: issuesConfig.LogLimit, lastVcsRevision: lastVcsRevision}
207-
208-
// Change working dir to where .git is.
209-
wd, err := os.Getwd()
210-
if errorutils.CheckError(err) != nil {
211-
return
212-
}
213-
defer func() {
214-
err = errors.Join(err, errorutils.CheckError(os.Chdir(wd)))
215-
}()
216-
err = os.Chdir(config.dotGitPath)
217-
if errorutils.CheckError(err) != nil {
218-
return
219-
}
220-
221-
// Run git command.
222-
_, _, exitOk, err := gofrogcmd.RunCmdWithOutputParser(logCmd, false, logRegExp, errRegExp)
223-
if errorutils.CheckError(err) != nil {
224-
var revisionRangeError RevisionRangeError
225-
if errors.As(err, &revisionRangeError) {
226-
// Revision not found in range. Ignore and don't collect new issues.
227-
log.Info(err.Error())
228-
return []buildinfo.AffectedIssue{}, nil
229-
}
230-
return
231-
}
232-
if !exitOk {
233-
// May happen when trying to run git log for non-existing revision.
234-
err = errorutils.CheckErrorf("failed executing git log command")
177+
return nil, err
235178
}
236-
return
179+
return foundIssues, nil
237180
}
238181

239182
// Creates a regexp handler to parse and fetch issues from the output of the git log command.
@@ -267,35 +210,6 @@ func createLogRegExpHandler(issuesConfig *IssuesConfiguration, foundIssues *[]bu
267210
return &logRegExp, nil
268211
}
269212

270-
// Error to be thrown when revision could not be found in the git revision range.
271-
type RevisionRangeError struct {
272-
ErrorMsg string
273-
}
274-
275-
func (err RevisionRangeError) Error() string {
276-
return err.ErrorMsg
277-
}
278-
279-
// Creates a regexp handler to handle the event of revision missing in the git revision range.
280-
func createErrRegExpHandler(lastVcsRevision string) (*gofrogcmd.CmdOutputPattern, error) {
281-
// Create regex pattern.
282-
invalidRangeExp, err := clientutils.GetRegExp(`fatal: Invalid revision range [a-fA-F0-9]+\.\.`)
283-
if err != nil {
284-
return nil, err
285-
}
286-
287-
// Create handler with exec function.
288-
errRegExp := gofrogcmd.CmdOutputPattern{
289-
RegExp: invalidRangeExp,
290-
ExecFunc: func(pattern *gofrogcmd.CmdOutputPattern) (string, error) {
291-
// Revision could not be found in the revision range, probably due to a squash / revert. Ignore and don't collect new issues.
292-
errMsg := "Revision: '" + lastVcsRevision + "' that was fetched from latest build info does not exist in the git revision range. No new issues are added."
293-
return "", RevisionRangeError{ErrorMsg: errMsg}
294-
},
295-
}
296-
return &errRegExp, nil
297-
}
298-
299213
func (config *BuildAddGitCommand) createIssuesConfigs() (err error) {
300214
// Read file's data.
301215
err = config.issuesConfig.populateIssuesConfigsFromSpec(config.configFilePath)
@@ -323,50 +237,6 @@ func (config *BuildAddGitCommand) createIssuesConfigs() (err error) {
323237
return
324238
}
325239

326-
func (config *BuildAddGitCommand) getLatestVcsRevision(vcsUrl string) (string, error) {
327-
// Get latest build's build-info from Artifactory
328-
buildInfo, err := config.getLatestBuildInfo(config.issuesConfig)
329-
if err != nil {
330-
return "", err
331-
}
332-
333-
// Get previous VCS Revision from BuildInfo.
334-
lastVcsRevision := ""
335-
for _, vcs := range buildInfo.VcsList {
336-
if vcs.Url == vcsUrl {
337-
lastVcsRevision = vcs.Revision
338-
break
339-
}
340-
}
341-
342-
return lastVcsRevision, nil
343-
}
344-
345-
// Returns build info, or empty build info struct if not found.
346-
func (config *BuildAddGitCommand) getLatestBuildInfo(issuesConfig *IssuesConfiguration) (*buildinfo.BuildInfo, error) {
347-
// Create services manager to get build-info from Artifactory.
348-
sm, err := utils.CreateServiceManager(issuesConfig.ServerDetails, -1, 0, false)
349-
if err != nil {
350-
return nil, err
351-
}
352-
353-
// Get latest build-info from Artifactory.
354-
buildName, err := config.buildConfiguration.GetBuildName()
355-
if err != nil {
356-
return nil, err
357-
}
358-
buildInfoParams := services.BuildInfoParams{BuildName: buildName, BuildNumber: artclientutils.LatestBuildNumberKey}
359-
publishedBuildInfo, found, err := sm.GetBuildInfo(buildInfoParams)
360-
if err != nil {
361-
return nil, err
362-
}
363-
if !found {
364-
return &buildinfo.BuildInfo{}, nil
365-
}
366-
367-
return &publishedBuildInfo.BuildInfo, nil
368-
}
369-
370240
func (ic *IssuesConfiguration) populateIssuesConfigsFromSpec(configFilePath string) (err error) {
371241
var vConfig *viper.Viper
372242
vConfig, err = project.ReadConfigFile(configFilePath, project.YAML)
@@ -461,30 +331,3 @@ type IssuesConfiguration struct {
461331
AggregationStatus string
462332
ServerID string
463333
}
464-
465-
type LogCmd struct {
466-
logLimit int
467-
lastVcsRevision string
468-
}
469-
470-
func (logCmd *LogCmd) GetCmd() *exec.Cmd {
471-
var cmd []string
472-
cmd = append(cmd, "git")
473-
cmd = append(cmd, "log", "--pretty=format:%s", "-"+strconv.Itoa(logCmd.logLimit))
474-
if logCmd.lastVcsRevision != "" {
475-
cmd = append(cmd, logCmd.lastVcsRevision+"..")
476-
}
477-
return exec.Command(cmd[0], cmd[1:]...)
478-
}
479-
480-
func (logCmd *LogCmd) GetEnv() map[string]string {
481-
return map[string]string{}
482-
}
483-
484-
func (logCmd *LogCmd) GetStdWriter() io.WriteCloser {
485-
return nil
486-
}
487-
488-
func (logCmd *LogCmd) GetErrWriter() io.WriteCloser {
489-
return nil
490-
}

artifactory/commands/buildinfo/addgit_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package buildinfo
22

33
import (
4+
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
45
"os"
56
"path/filepath"
67
"strconv"
@@ -255,8 +256,15 @@ func TestAddGitDoCollect(t *testing.T) {
255256
dotGitPath: dotGitPath,
256257
}
257258

259+
gitDetails := utils.GitParsingDetails{DotGitPath: config.dotGitPath, LogLimit: config.issuesConfig.LogLimit, PrettyFormat: gitParsingPrettyFormat}
260+
var issues []buildinfo.AffectedIssue
261+
logRegExp, err := createLogRegExpHandler(config.issuesConfig, &issues)
262+
if err != nil {
263+
t.Error(err)
264+
}
265+
258266
// Collect issues
259-
issues, err := config.DoCollect(config.issuesConfig, "")
267+
err = utils.ParseGitLogsFromLastVcsRevision(gitDetails, logRegExp, "")
260268
if err != nil {
261269
t.Error(err)
262270
}
@@ -276,7 +284,8 @@ func TestAddGitDoCollect(t *testing.T) {
276284
baseDir, dotGitPath = tests.PrepareDotGitDir(t, originalFolder, filepath.Join("..", "testdata"))
277285

278286
// Collect issues - we pass a revision, so only 2 of the 4 existing issues should be collected
279-
issues, err = config.DoCollect(config.issuesConfig, "6198a6294722fdc75a570aac505784d2ec0d1818")
287+
issues = []buildinfo.AffectedIssue{}
288+
err = utils.ParseGitLogsFromLastVcsRevision(gitDetails, logRegExp, "6198a6294722fdc75a570aac505784d2ec0d1818")
280289
if err != nil {
281290
t.Error(err)
282291
}
@@ -286,7 +295,8 @@ func TestAddGitDoCollect(t *testing.T) {
286295
}
287296

288297
// Test collection with a made up revision - the command should not throw an error, and 0 issues should be returned.
289-
issues, err = config.DoCollect(config.issuesConfig, "abcdefABCDEF1234567890123456789012345678")
298+
issues = []buildinfo.AffectedIssue{}
299+
err = utils.ParseGitLogsFromLastVcsRevision(gitDetails, logRegExp, "abcdefABCDEF1234567890123456789012345678")
290300
assert.NoError(t, err)
291301
assert.Empty(t, issues)
292302

0 commit comments

Comments
 (0)