Skip to content

Commit 89b91f5

Browse files
authored
Support getting git log since previous build (#40)
1 parent a839c7e commit 89b91f5

File tree

6 files changed

+418
-199
lines changed

6 files changed

+418
-199
lines changed

artifactory/commands/buildinfo/addgit.go

Lines changed: 16 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,26 @@ package buildinfo
22

33
import (
44
"errors"
5-
"io"
6-
"os"
7-
"os/exec"
8-
"strconv"
9-
5+
"github.com/forPelevin/gomoji"
106
buildinfo "github.com/jfrog/build-info-go/entities"
117
gofrogcmd "github.com/jfrog/gofrog/io"
12-
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
8+
"github.com/jfrog/jfrog-cli-artifactory/artifactory/utils"
139
"github.com/jfrog/jfrog-cli-core/v2/common/build"
1410
"github.com/jfrog/jfrog-cli-core/v2/common/project"
1511
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"
1812
clientutils "github.com/jfrog/jfrog-client-go/utils"
19-
20-
"github.com/forPelevin/gomoji"
2113
"github.com/jfrog/jfrog-client-go/utils/errorutils"
22-
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
2314
"github.com/jfrog/jfrog-client-go/utils/log"
2415
"github.com/spf13/viper"
16+
"strconv"
2517
)
2618

2719
const (
2820
GitLogLimit = 100
2921
ConfigIssuesPrefix = "issues."
3022
ConfigParseValueError = "Failed parsing %s from configuration file: %s"
3123
MissingConfigurationError = "Configuration file must contain: %s"
24+
gitParsingPrettyFormat = "format:%s"
3225
)
3326

3427
type BuildAddGitCommand struct {
@@ -84,15 +77,9 @@ func (config *BuildAddGitCommand) Run() error {
8477
}
8578

8679
// 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-
}
80+
config.dotGitPath, err = utils.GetDotGit(config.dotGitPath)
81+
if err != nil {
82+
return err
9683
}
9784

9885
// Collect URL, branch and revision into GitManager.
@@ -105,7 +92,7 @@ func (config *BuildAddGitCommand) Run() error {
10592
// Collect issues if required.
10693
var issues []buildinfo.AffectedIssue
10794
if config.configFilePath != "" {
108-
issues, err = config.collectBuildIssues(gitManager.GetUrl())
95+
issues, err = config.collectBuildIssues()
10996
if err != nil {
11097
return err
11198
}
@@ -163,77 +150,31 @@ func (config *BuildAddGitCommand) CommandName() string {
163150
return "rt_build_add_git"
164151
}
165152

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

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

178159
// Create config's IssuesConfigurations from the provided spec file.
179-
err = config.createIssuesConfigs()
160+
err := config.createIssuesConfigs()
180161
if err != nil {
181162
return nil, err
182163
}
183164

184-
// Get latest build's VCS revision from Artifactory.
185-
lastVcsRevision, err := config.getLatestVcsRevision(vcsUrl)
165+
var foundIssues []buildinfo.AffectedIssue
166+
logRegExp, err := createLogRegExpHandler(config.issuesConfig, &foundIssues)
186167
if err != nil {
187168
return nil, err
188169
}
189170

190171
// 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)
172+
gitDetails := utils.GitLogDetails{DotGitPath: config.dotGitPath, LogLimit: config.issuesConfig.LogLimit, PrettyFormat: gitParsingPrettyFormat}
173+
err = utils.ParseGitLogFromLastBuild(config.issuesConfig.ServerDetails, config.buildConfiguration, gitDetails, logRegExp)
196174
if err != nil {
197-
return
198-
}
199-
200-
errRegExp, err := createErrRegExpHandler(lastVcsRevision)
201-
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")
175+
return nil, err
235176
}
236-
return
177+
return foundIssues, nil
237178
}
238179

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

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-
299211
func (config *BuildAddGitCommand) createIssuesConfigs() (err error) {
300212
// Read file's data.
301213
err = config.issuesConfig.populateIssuesConfigsFromSpec(config.configFilePath)
@@ -323,50 +235,6 @@ func (config *BuildAddGitCommand) createIssuesConfigs() (err error) {
323235
return
324236
}
325237

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-
370238
func (ic *IssuesConfiguration) populateIssuesConfigsFromSpec(configFilePath string) (err error) {
371239
var vConfig *viper.Viper
372240
vConfig, err = project.ReadConfigFile(configFilePath, project.YAML)
@@ -461,30 +329,3 @@ type IssuesConfiguration struct {
461329
AggregationStatus string
462330
ServerID string
463331
}
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: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
package buildinfo
22

33
import (
4+
buildinfo "github.com/jfrog/build-info-go/entities"
5+
"github.com/jfrog/jfrog-cli-artifactory/artifactory/utils"
6+
"github.com/jfrog/jfrog-cli-core/v2/common/build"
7+
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
8+
"github.com/jfrog/jfrog-cli-core/v2/utils/log"
9+
"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
10+
testsutils "github.com/jfrog/jfrog-client-go/utils/tests"
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
413
"os"
514
"path/filepath"
615
"strconv"
716
"strings"
817
"testing"
918
"time"
10-
11-
buildinfo "github.com/jfrog/build-info-go/entities"
12-
testsutils "github.com/jfrog/jfrog-client-go/utils/tests"
13-
"github.com/stretchr/testify/assert"
14-
"github.com/stretchr/testify/require"
15-
16-
"github.com/jfrog/jfrog-cli-core/v2/common/build"
17-
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
18-
"github.com/jfrog/jfrog-cli-core/v2/utils/log"
19-
"github.com/jfrog/jfrog-cli-core/v2/utils/tests"
2019
)
2120

2221
const (
@@ -255,13 +254,20 @@ func TestAddGitDoCollect(t *testing.T) {
255254
dotGitPath: dotGitPath,
256255
}
257256

257+
gitDetails := utils.GitLogDetails{DotGitPath: config.dotGitPath, LogLimit: config.issuesConfig.LogLimit, PrettyFormat: gitParsingPrettyFormat}
258+
var issues []buildinfo.AffectedIssue
259+
logRegExp, err := createLogRegExpHandler(config.issuesConfig, &issues)
260+
if err != nil {
261+
t.Error(err)
262+
}
263+
258264
// Collect issues
259-
issues, err := config.DoCollect(config.issuesConfig, "")
265+
err = utils.ParseGitLogFromLastVcsRevision(gitDetails, logRegExp, "")
260266
if err != nil {
261267
t.Error(err)
262268
}
263269
if len(issues) != 2 {
264-
// Error - should be empty
270+
// Error - should find 2 issues
265271
t.Errorf("Issues list expected to have 2 issues, instead found %d issues: %v", len(issues), issues)
266272
}
267273

@@ -276,7 +282,8 @@ func TestAddGitDoCollect(t *testing.T) {
276282
baseDir, dotGitPath = tests.PrepareDotGitDir(t, originalFolder, filepath.Join("..", "testdata"))
277283

278284
// 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")
285+
issues = []buildinfo.AffectedIssue{}
286+
err = utils.ParseGitLogFromLastVcsRevision(gitDetails, logRegExp, "6198a6294722fdc75a570aac505784d2ec0d1818")
280287
if err != nil {
281288
t.Error(err)
282289
}
@@ -286,7 +293,8 @@ func TestAddGitDoCollect(t *testing.T) {
286293
}
287294

288295
// 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")
296+
issues = []buildinfo.AffectedIssue{}
297+
err = utils.ParseGitLogFromLastVcsRevision(gitDetails, logRegExp, "abcdefABCDEF1234567890123456789012345678")
290298
assert.NoError(t, err)
291299
assert.Empty(t, issues)
292300

0 commit comments

Comments
 (0)