Skip to content

Commit

Permalink
Add get-BuildInfo service + build-issues collection in the build-info
Browse files Browse the repository at this point in the history
  • Loading branch information
barbelity authored Feb 10, 2019
1 parent 8cd4d3b commit e92594c
Show file tree
Hide file tree
Showing 13 changed files with 394 additions and 12 deletions.
23 changes: 22 additions & 1 deletion artifactory/buildinfo/buildinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type BuildInfo struct {
Properties Env `json:"properties,omitempty"`
ArtifactoryPrincipal string `json:"artifactoryPrincipal,omitempty"`
BuildUrl string `json:"url,omitempty"`
Issues *Issues `json:"issues,omitempty"`
*Vcs
}

Expand All @@ -117,6 +118,25 @@ type Dependency struct {
*Checksum
}

type Issues struct {
Tracker *Tracker `json:"tracker,omitempty"`
AggregateBuildIssues bool `json:"aggregateBuildIssues,omitempty"`
AggregationBuildStatus string `json:"aggregationBuildStatus,omitempty"`
AffectedIssues []AffectedIssue `json:"affectedIssues,omitempty"`
}

type Tracker struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}

type AffectedIssue struct {
Key string `json:"key,omitempty"`
Url string `json:"url,omitempty"`
Summary string `json:"summary,omitempty"`
Aggregated bool `json:"aggregated,omitempty"`
}

type Checksum struct {
Sha1 string `json:"sha1,omitempty"`
Md5 string `json:"md5,omitempty"`
Expand All @@ -136,8 +156,9 @@ type Partial struct {
Dependencies []Dependency `json:"Dependencies,omitempty"`
Env Env `json:"Env,omitempty"`
Timestamp int64 `json:"Timestamp,omitempty"`
*Vcs
ModuleId string `json:"ModuleId,omitempty"`
Issues *Issues `json:"Issues,omitempty"`
*Vcs
}

func (partials Partials) Len() int {
Expand Down
6 changes: 6 additions & 0 deletions artifactory/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,9 @@ func (sm *ArtifactoryServicesManager) Ping() ([]byte, error) {
func (sm *ArtifactoryServicesManager) GetConfig() Config {
return sm.config
}

func (sm *ArtifactoryServicesManager) GetBuildInfo(params services.BuildInfoParams) (*buildinfo.BuildInfo, error) {
buildInfoService := services.NewBuildInfoService(sm.client)
buildInfoService.ArtDetails = sm.config.GetArtDetails()
return buildInfoService.GetBuildInfo(params)
}
68 changes: 68 additions & 0 deletions artifactory/services/buildinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package services

import (
"encoding/json"
"fmt"
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/jfrog/jfrog-client-go/artifactory/buildinfo"
rthttpclient "github.com/jfrog/jfrog-client-go/artifactory/httpclient"
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
)

type BuildInfoService struct {
client *rthttpclient.ArtifactoryHttpClient
ArtDetails auth.ArtifactoryDetails
}

func NewBuildInfoService(client *rthttpclient.ArtifactoryHttpClient) *BuildInfoService {
return &BuildInfoService{client: client}
}

func (bis *BuildInfoService) GetArtifactoryDetails() auth.ArtifactoryDetails {
return bis.ArtDetails
}

func (bis *BuildInfoService) SetArtifactoryDetails(rt auth.ArtifactoryDetails) {
bis.ArtDetails = rt
}

func (bis *BuildInfoService) GetJfrogHttpClient() (*rthttpclient.ArtifactoryHttpClient, error) {
return bis.client, nil
}

func (bis *BuildInfoService) IsDryRun() bool {
return false
}

type BuildInfoParams struct {
BuildName string
BuildNumber string
}

func (bis *BuildInfoService) GetBuildInfo(params BuildInfoParams) (*buildinfo.BuildInfo, error) {
// Resolve LATEST build number from Artifactory if required.
name, number, err := utils.GetBuildNameAndNumberFromArtifactory(params.BuildName, params.BuildNumber, bis)
if err != nil {
return nil, err
}

// Get build-info json from Artifactory.
httpClientsDetails := bis.GetArtifactoryDetails().CreateHttpClientDetails()
buildInfoUrl := fmt.Sprintf("%sapi/build/%s/%s", bis.GetArtifactoryDetails().GetUrl(), name, number)
log.Debug("Getting build-info from: ", buildInfoUrl)
_, body, _, err := bis.client.SendGet(buildInfoUrl, true, &httpClientsDetails)
if err != nil {
return nil, err
}

// Build BuildInfo struct from json.
var buildInfoJson struct {
BuildInfo buildinfo.BuildInfo `json:"buildInfo,omitempty"`
}
if err := json.Unmarshal(body, &buildInfoJson); err != nil {
return nil, err
}

return &buildInfoJson.BuildInfo, nil
}
21 changes: 13 additions & 8 deletions artifactory/services/utils/artifactoryutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ import (
"sync"
)

const ARTIFACTORY_SYMLINK = "symlink.dest"
const SYMLINK_SHA1 = "symlink.destsha1"
const (
ARTIFACTORY_SYMLINK = "symlink.dest"
SYMLINK_SHA1 = "symlink.destsha1"
Latest = "LATEST"
LastRelease = "LAST_RELEASE"
)

func UploadFile(localPath, url, logMsgPrefix string, artifactoryDetails *auth.ArtifactoryDetails, details *fileutils.FileDetails,
httpClientsDetails httputils.HttpClientDetails, client *rthttpclient.ArtifactoryHttpClient, retries int) (*http.Response, []byte, error) {
Expand Down Expand Up @@ -105,13 +109,14 @@ func IsSubPath(paths []string, index int, separator string) bool {
// If no buildNumber provided LATEST wil be downloaded.
// If buildName or buildNumber contains "/" (slash) it should be escaped by "\" (backslash).
// Result examples of parsing: "aaa/123" > "aaa"-"123", "aaa" > "aaa"-"LATEST", "aaa\\/aaa" > "aaa/aaa"-"LATEST", "aaa/12\\/3" > "aaa"-"12/3".
func getBuildNameAndNumber(buildIdentifier string, flags CommonConf) (string, string, error) {
const Latest = "LATEST"
const LastRelease = "LAST_RELEASE"
func getBuildNameAndNumberFromBuildIdentifier(buildIdentifier string, flags CommonConf) (string, string, error) {
buildName, buildNumber := parseBuildNameAndNumber(buildIdentifier)
return GetBuildNameAndNumberFromArtifactory(buildName, buildNumber, flags)
}

func GetBuildNameAndNumberFromArtifactory(buildName, buildNumber string, flags CommonConf) (string, string, error) {
if buildNumber == Latest || buildNumber == LastRelease {
return getBuildNumberFromArtifactory(buildName, buildNumber, flags)
return getLatestBuildNumberFromArtifactory(buildName, buildNumber, flags)
}
return buildName, buildNumber, nil
}
Expand Down Expand Up @@ -173,7 +178,7 @@ type build struct {
BuildNumber string `json:"buildNumber"`
}

func getBuildNumberFromArtifactory(buildName, buildNumber string, flags CommonConf) (string, string, error) {
func getLatestBuildNumberFromArtifactory(buildName, buildNumber string, flags CommonConf) (string, string, error) {
restUrl := flags.GetArtifactoryDetails().GetUrl() + "api/build/patternArtifacts"
body, err := createBodyForLatestBuildRequest(buildName, buildNumber)
if err != nil {
Expand Down Expand Up @@ -221,7 +226,7 @@ func filterAqlSearchResultsByBuild(specFile *ArtifactoryCommonParams, itemsToFil
var aqlSearchErr error
var buildArtifactsSha1 map[string]bool
var wg sync.WaitGroup
buildName, buildNumber, err := getBuildNameAndNumber(specFile.Build, flags)
buildName, buildNumber, err := getBuildNameAndNumberFromBuildIdentifier(specFile.Build, flags)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion artifactory/services/utils/searchutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const (

// Use this function when searching by build without pattern or aql
func SearchBySpecWithBuild(specFile *ArtifactoryCommonParams, flags CommonConf) ([]ResultItem, error) {
buildName, buildNumber, err := getBuildNameAndNumber(specFile.Build, flags)
buildName, buildNumber, err := getBuildNameAndNumberFromBuildIdentifier(specFile.Build, flags)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/go-cmp v0.2.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jfrog/gofrog v1.0.2
github.com/jfrog/gofrog v1.0.4
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e // indirect
github.com/mholt/archiver v2.1.0+incompatible
github.com/mitchellh/go-homedir v1.0.0 // indirect
Expand Down
66 changes: 65 additions & 1 deletion utils/io/fileutils/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"errors"
"fmt"
"github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils/checksum"
Expand All @@ -16,7 +17,11 @@ import (
"strings"
)

const SYMLINK_FILE_CONTENT = ""
const (
SYMLINK_FILE_CONTENT = ""
File TraverseItemType = "file"
Folder TraverseItemType = "dir"
)

var tempDirPath string

Expand Down Expand Up @@ -400,3 +405,62 @@ func CopyDir(fromPath, toPath string, includeDirs bool) error {
}
return err
}

// Returns the path to the directory in which itemToFind is located.
// Traversing through directories from current work-dir to root.
// traverseType determines whether looking for a file or dir.
func GetFileOrDirPath(itemToFInd string, traverseItemType TraverseItemType) (string, error) {
// Create a map to store all paths visited, to avoid running in circles.
visitedPaths := make(map[string]bool)
// Get the current directory.
wd, err := os.Getwd()
if err != nil {
return wd, errorutils.CheckError(err)
}
defer os.Chdir(wd)

// Get the OS root.
osRoot := os.Getenv("SYSTEMDRIVE")
if osRoot != "" {
// If this is a Windows machine:
osRoot += "\\"
} else {
// Unix:
osRoot = "/"
}

// Check if the current directory includes itemToFind. If not, check the parent directory
// and so on.
exists := false
for {
// If itemToFind is found in the current directory, return the path.
if traverseItemType == File {
exists, err = IsFileExists(filepath.Join(wd, itemToFInd), false)
} else {
exists, err = IsDirExists(filepath.Join(wd, itemToFInd), false)
}
if err != nil || exists {
return wd, err
}

// If this the OS root, we can stop.
if wd == osRoot {
break
}

// Save this path.
visitedPaths[wd] = true
// CD to the parent directory.
wd = filepath.Dir(wd)
os.Chdir(wd)

// If we already visited this directory, it means that there's a loop and we can stop.
if visitedPaths[wd] {
return "", errorutils.CheckError(errors.New(fmt.Sprintf("Could not find %s.", itemToFInd)))
}
}

return "", errorutils.CheckError(errors.New(fmt.Sprintf("Could not find %s.", itemToFInd)))
}

type TraverseItemType string
111 changes: 111 additions & 0 deletions utils/io/fileutils/files_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package fileutils

import (
"os"
"path/filepath"
"strconv"
"testing"
)
Expand All @@ -26,3 +28,112 @@ func TestIsSsh(t *testing.T) {
})
}
}

func TestGetFileOrDirPathFile(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Error(err)
}
defer os.Chdir(wd)

// CD into a directory with a go.mod file.
projectRoot := filepath.Join("testdata", "project")
err = os.Chdir(projectRoot)
if err != nil {
t.Error(err)
}

// Make projectRoot an absolute path.
projectRoot, err = os.Getwd()
if err != nil {
t.Error(err)
}

// Get the project root.
root, err := GetFileOrDirPath("go.mod", File)
if err != nil {
t.Error(err)
}
if root != projectRoot {
t.Error("Expecting", projectRoot, "got:", root)
}

// CD back to the original directory.
if err := os.Chdir(wd); err != nil {
t.Error(err)
}

// CD into a sub directory in the same project, and expect to get the same project root.
os.Chdir(wd)
projectSubDirectory := filepath.Join("testdata", "project", "dir")
err = os.Chdir(projectSubDirectory)
if err != nil {
t.Error(err)
}
root, err = GetFileOrDirPath("go.mod", File)
if err != nil {
t.Error(err)
}
if root != projectRoot {
t.Error("Expecting", projectRoot, "got:", root)
}

// CD back to the original directory.
if err := os.Chdir(wd); err != nil {
t.Error(err)
}

// Now CD into a directory outside the project, and expect to get a different project root.
noProjectRoot := filepath.Join("testdata", "noproject")
err = os.Chdir(noProjectRoot)
if err != nil {
t.Error(err)
}
root, err = GetFileOrDirPath("go.mod", File)
if err != nil {
t.Error(err)
}
if root == projectRoot {
t.Error("Expecting a different value than", root)
}
}

func TestGetFileOrDirPathFolder(t *testing.T) {
wd, err := os.Getwd()
if err != nil {
t.Error(err)
}
defer os.Chdir(wd)

// Create path to directory to find.
dirPath := filepath.Join("testdata")
err = os.Chdir(dirPath)
if err != nil {
t.Error(err)
}
// Get absolute path.
dirPath, err = os.Getwd()
if err != nil {
t.Error(err)
}
// CD back to the original directory.
if err := os.Chdir(wd); err != nil {
t.Error(err)
}

// Go to starting dir to search from.
searchFromDir := filepath.Join("testdata", "project", "dir")
err = os.Chdir(searchFromDir)
if err != nil {
t.Error(err)
}

// Get the directory path.
root, err := GetFileOrDirPath("noproject", Folder)
if err != nil {
t.Error(err)
}
if root != dirPath {
t.Error("Expecting", dirPath, "got:", root)
}
}
Empty file.
Empty file.
Empty file.
Loading

0 comments on commit e92594c

Please sign in to comment.