mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
110 lines
3.5 KiB
Go
110 lines
3.5 KiB
Go
package transportrequest
|
|
|
|
import (
|
|
"fmt"
|
|
gitUtils "github.com/SAP/jenkins-library/pkg/git"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/piperutils"
|
|
"github.com/go-git/go-git/v5"
|
|
"github.com/go-git/go-git/v5/plumbing/object"
|
|
"github.com/pkg/errors"
|
|
"os"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
var logRange = gitUtils.LogRange
|
|
var findLabelsInCommits = FindLabelsInCommits
|
|
|
|
type iTransportRequestGitUtils interface {
|
|
PlainOpen(directory string) (*git.Repository, error)
|
|
}
|
|
type transportRequestGitUtils struct {
|
|
}
|
|
|
|
func (g *transportRequestGitUtils) PlainOpen(directory string) (*git.Repository, error) {
|
|
r, err := gitUtils.PlainOpen(directory)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Unable to open git repository at '%s'", directory)
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// FindIDInRange finds a ID according to the label in a commit range <from>..<to>.
|
|
// We assume the git repo is present in the current working directory.
|
|
func FindIDInRange(label, from, to string) (string, error) {
|
|
|
|
return findIDInRange(label, from, to, &transportRequestGitUtils{})
|
|
}
|
|
|
|
func findIDInRange(label, from, to string, trGitUtils iTransportRequestGitUtils) (string, error) {
|
|
|
|
workdir, err := os.Getwd()
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "Cannot open git repo in current working directory '%s'", workdir)
|
|
}
|
|
log.Entry().Infof("Opening git repo at '%s'", workdir)
|
|
|
|
r, err := trGitUtils.PlainOpen(workdir)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "Unable to open git repository at '%s'", workdir)
|
|
}
|
|
|
|
cIter, err := logRange(r, from, to)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "Cannot retrieve '%s'. Unable to resolve commits in range '%s..%s'", label, from, to)
|
|
}
|
|
|
|
ids, err := findLabelsInCommits(cIter, label)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "Cannot retrieve '%s'. Unable to traverse commits in range '%s..%s'", label, from, to)
|
|
}
|
|
|
|
if len(ids) > 1 {
|
|
return "", fmt.Errorf("More than one values found for label '%s' in range '%s..%s': '%s'", label, from, to, ids)
|
|
}
|
|
if len(ids) == 0 {
|
|
return "", fmt.Errorf("No values found for '%s' in range '%s..%s'", label, from, to)
|
|
}
|
|
return ids[0], nil
|
|
}
|
|
|
|
// FindLabelsInCommits a label is considered to be something like
|
|
// key: label, e.g. TransportRequest: 123456
|
|
// These labels are expected to be contained in the git commit message as
|
|
// a separate line in the commit message body.
|
|
// In case several labels are found they are returned in ascending order.
|
|
func FindLabelsInCommits(commits object.CommitIter, label string) ([]string, error) {
|
|
labelRegex, err := regexp.Compile(finishLabel(label))
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("Cannot extract label: %w", err)
|
|
}
|
|
ids := []string{}
|
|
err = commits.ForEach(func(c *object.Commit) error {
|
|
for _, e := range labelRegex.FindAllStringSubmatch(c.Message, -1) {
|
|
if len(e) < 2 { // the first entry is the full match, the second entry (at index 1) is the group
|
|
return fmt.Errorf("Cannot extract label '%s' from commit '%s': '%s'", label, c.ID(), c.Message)
|
|
}
|
|
ids = append(ids, e[1])
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return []string{}, fmt.Errorf("Cannot extract label: %w", err)
|
|
}
|
|
|
|
labels := piperutils.UniqueStrings(ids)
|
|
sort.Strings(labels)
|
|
return labels, nil
|
|
}
|
|
|
|
func finishLabel(label string) string {
|
|
// contains prefix, like the old default
|
|
if strings.ContainsAny(label, ":=") {
|
|
return fmt.Sprintf(`(?m)^\s*%s\s*(\S*)\s*$`, label)
|
|
}
|
|
// contains key only, like the new default
|
|
return fmt.Sprintf(`(?m)^\s*%s\s*:\s*(\S*)\s*$`, label)
|
|
}
|