Skip to content

Commit

Permalink
Committer reviewer for rbv2
Browse files Browse the repository at this point in the history
  • Loading branch information
lesnerd committed Feb 23, 2025
1 parent 373315d commit 43a273e
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 31 deletions.
2 changes: 2 additions & 0 deletions artifactory/utils/vcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package utils

import (
"errors"
"fmt"
buildinfo "github.com/jfrog/build-info-go/entities"
gofrogcmd "github.com/jfrog/gofrog/io"
utils2 "github.com/jfrog/jfrog-cli-artifactory/evidence/utils"
Expand Down Expand Up @@ -163,6 +164,7 @@ func getMatchingRevisionFromBuild(buildInfo *buildinfo.BuildInfo, vcsUrl string)
break
}
}
log.Info(fmt.Sprintf("base commit: %s for build name: %s and build number: %s", lastVcsRevision, buildInfo.Name, buildInfo.Number))
return lastVcsRevision
}

Expand Down
5 changes: 5 additions & 0 deletions evidence/cli/command_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ func validateFoundSubjects(ctx *components.Context, foundSubjects []string) erro
return nil
}

if slices.Contains(foundSubjects, typeFlag) && slices.Contains(foundSubjects, releaseBundle) {
return nil
}

if slices.Contains(foundSubjects, typeFlag) && attemptSetBuildNameAndNumber(ctx) {
return nil
}
Expand Down Expand Up @@ -192,6 +196,7 @@ func platformToEvidenceUrls(rtDetails *coreConfig.ServerDetails) {
rtDetails.ArtifactoryUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "artifactory/"
rtDetails.EvidenceUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "evidence/"
rtDetails.MetadataUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "metadata/"
rtDetails.LifecycleUrl = utils.AddTrailingSlashIfNeeded(rtDetails.Url) + "lifecycle/"
}

func assertValueProvided(c *components.Context, fieldName string) error {
Expand Down
18 changes: 14 additions & 4 deletions evidence/cli/command_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,23 @@ func (ebc *evidenceGitHubCommand) CreateEvidence(ctx *components.Context, server
ebc.ctx.GetStringFlagValue(project),
ebc.ctx.GetStringFlagValue(buildName),
ebc.ctx.GetStringFlagValue(buildNumber),
ebc.ctx.GetStringFlagValue(typeFlag))
ebc.ctx.GetStringFlagValue(typeFlag),
ebc.ctx.GetStringFlagValue(releaseBundle),
ebc.ctx.GetStringFlagValue(releaseBundleVersion))
return ebc.execute(createCmd)
}

func (ebc *evidenceGitHubCommand) validateEvidenceBuildContext(ctx *components.Context) error {
if !ctx.IsFlagSet(buildNumber) || assertValueProvided(ctx, buildNumber) != nil {
return errorutils.CheckErrorf("--%s is a mandatory field for creating a Release Bundle evidence", buildNumber)
if !ctx.IsFlagSet(typeFlag) {
return errorutils.CheckErrorf("--%s is a mandatory field for creating a GitHub evidence", typeFlag)
}
return nil
if ctx.IsFlagSet(buildName) && assertValueProvided(ctx, buildName) == nil {
return nil
}
if ctx.IsFlagSet(releaseBundle) && assertValueProvided(ctx, releaseBundle) == nil &&
ctx.IsFlagSet(releaseBundleVersion) && assertValueProvided(ctx, releaseBundleVersion) == nil {
return nil
}
return errorutils.CheckErrorf("Either --build-name or --release-bundle and --release-bundle-version " +
"are mandatory fields for creating a GitHub evidence")
}
167 changes: 155 additions & 12 deletions evidence/create_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/common/build"
coreConfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory"
"github.com/jfrog/jfrog-client-go/http/httpclient"
rtutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"net/http"
"os"
"regexp"
"strings"
Expand All @@ -26,19 +30,24 @@ const (
FlagTypeCommitterReviewer FlagType = "gh-commiter"
FlagTypeOther FlagType = "other"
)
const releaseBundleInternalApi = "api/v2/release_bundle/internal/graph/"
const releaseBundleApi = "api/v2/release_bundle/records/"

const ghDefaultPredicateType = "https://jfrog.com/evidence/gh-commiter/v1"
const ghDefaultPredicateType = "https://jfrog.com/evidence/git-committer-reviewer/v1"

const gitFormat = `format:'{"commit":"%H","abbreviated_commit":"%h","tree":"%T","abbreviated_tree":"%t","parent":"%P","abbreviated_parent":"%p","subject":"%s","sanitized_subject_line":"%f","author":{"name":"%aN","email":"%aE","date":"%aD"},"commiter":{"name":"%cN","email":"%cE","date":"%cD"}}'`

type createGitHubEvidence struct {
createEvidenceBase
project string
buildName string
buildNumber string
project string
buildName string
buildNumber string
releaseBundle string
releaseBundleVersion string
}

func NewCreateGithub(serverDetails *coreConfig.ServerDetails, predicateFilePath, predicateType, markdownFilePath, key, keyId, project, buildName, buildNumber, typeFlag string) Command {
func NewCreateGithub(serverDetails *coreConfig.ServerDetails,
predicateFilePath, predicateType, markdownFilePath, key, keyId, project, buildName, buildNumber, typeFlag, rbName, rbVersion string) Command {
flagType := getFlagType(typeFlag)
return &createGitHubEvidence{
createEvidenceBase: createEvidenceBase{
Expand All @@ -50,9 +59,11 @@ func NewCreateGithub(serverDetails *coreConfig.ServerDetails, predicateFilePath,
keyId: keyId,
flagType: flagType,
},
project: project,
buildName: buildName,
buildNumber: buildNumber,
project: project,
buildName: buildName,
buildNumber: buildNumber,
releaseBundle: rbName,
releaseBundleVersion: rbVersion,
}
}

Expand All @@ -78,6 +89,17 @@ func (c *createGitHubEvidence) Run() error {
if !isRunningUnderGitHubAction() {
return errors.New("this command is intended to be run under GitHub Actions")
}
if c.buildName == "" && c.releaseBundle == "" {
return errors.New("build name or release bundle name is required")
}

if c.releaseBundle != "" {
err := c.getBuildFromReleaseBundle()
if err != nil {
return err
}
}

evidencePredicate, err := c.committerReviewerEvidence()
if err != nil {
return err
Expand All @@ -88,9 +110,18 @@ func (c *createGitHubEvidence) Run() error {
log.Error("failed to create Artifactory client", err)
return err
}
subject, sha256, err := c.buildBuildInfoSubjectPath(artifactoryClient)
if err != nil {
return err

var subject, sha256 string
if c.releaseBundle != "" && c.releaseBundleVersion != "" {
subject, sha256, err = c.buildReleaseBundleSubjectPath(artifactoryClient)
if err != nil {
return err
}
} else {
subject, sha256, err = c.buildBuildInfoSubjectPath(artifactoryClient)
if err != nil {
return err
}
}
envelope, err := c.createEnvelopeWithPredicateAndPredicateType(subject,
sha256, ghDefaultPredicateType, evidencePredicate)
Expand Down Expand Up @@ -125,6 +156,18 @@ func (c *createGitHubEvidence) buildBuildInfoSubjectPath(artifactoryClient artif
return buildInfoPath, buildInfoChecksum, nil
}

func (c *createGitHubEvidence) buildReleaseBundleSubjectPath(artifactoryClient artifactory.ArtifactoryServicesManager) (string, string, error) {
repoKey := buildRepoKey(c.project)
manifestPath := buildManifestPath(repoKey, c.releaseBundle, c.releaseBundleVersion)

manifestChecksum, err := c.getFileChecksum(manifestPath, artifactoryClient)
if err != nil {
return "", "", err
}

return manifestPath, manifestChecksum, nil
}

func isRunningUnderGitHubAction() bool {
return os.Getenv("GITHUB_ACTIONS") == "true"
}
Expand Down Expand Up @@ -177,7 +220,7 @@ func marshalEvidenceToGitLogEntryView(evidence []byte) (*model.GitLogEntryView,

func (c *createGitHubEvidence) committerReviewerEvidence() ([]byte, error) {
if c.createEvidenceBase.flagType != FlagTypeCommitterReviewer {
return nil, errors.New("flag type must be gh-commiter")
return nil, errors.New("flag type is not supported")
}

createBuildConfiguration := c.createBuildConfiguration()
Expand All @@ -195,8 +238,108 @@ func (c *createGitHubEvidence) createBuildConfiguration() *build.BuildConfigurat
return buildConfiguration
}

func (c *createGitHubEvidence) getBuildFromReleaseBundle() error {
releaseBundleResponse, err := c.getPreviousReleaseBundle()
if err != nil {
return err
}
if len(releaseBundleResponse.ReleaseBundles) == 0 {
return errors.New("no release bundles found")
}
if len(releaseBundleResponse.ReleaseBundles) > 1 {
// Get the previous release bundle
c.releaseBundleVersion = releaseBundleResponse.ReleaseBundles[1].ReleaseBundleVersion
} else {
c.releaseBundleVersion = releaseBundleResponse.ReleaseBundles[0].ReleaseBundleVersion
}

rbv2Graph, err := c.getReleaseBundleGraph()
if err != nil {
return err
}
for _, node := range rbv2Graph.Root.Nodes {
if node.Type == "buildinfo" {
c.buildName = node.Name
c.buildNumber = node.Version
break
}
}
// Get the current release bundle to put the evidence on
c.releaseBundleVersion = releaseBundleResponse.ReleaseBundles[0].ReleaseBundleVersion
return nil
}

func (c *createGitHubEvidence) getReleaseBundleGraph() (*model.GraphResponse, error) {
authConfig, err := c.serverDetails.CreateArtAuthConfig()
if err != nil {
return nil, err
}

artifactoryApiUrl, err := rtutils.BuildUrl(c.serverDetails.GetLifecycleUrl(), releaseBundleInternalApi+c.releaseBundle+"/"+c.releaseBundleVersion, make(map[string]string))
if err != nil {
return nil, err
}

artHttpDetails := authConfig.CreateHttpClientDetails()
client, err := httpclient.ClientBuilder().Build()
if err != nil {
return nil, err
}
resp, body, _, err := client.SendGet(artifactoryApiUrl, true, artHttpDetails, "")
if err != nil {
return nil, err
}
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil {
return nil, err
}
graphResponse := &model.GraphResponse{}
if err = json.Unmarshal(body, &graphResponse); err != nil {
return nil, errorutils.CheckError(err)
}
return graphResponse, nil
}

func (c *createGitHubEvidence) getPreviousReleaseBundle() (*model.ReleaseBundlesResponse, error) {
authConfig, err := c.serverDetails.CreateArtAuthConfig()
if err != nil {
return nil, err
}

queryParams := map[string]string{
"project": c.project,
}
artifactoryApiUrl, err := rtutils.BuildUrl(c.serverDetails.GetLifecycleUrl(), releaseBundleApi+c.releaseBundle, queryParams)
if err != nil {
return nil, err
}

artHttpDetails := authConfig.CreateHttpClientDetails()
client, err := httpclient.ClientBuilder().Build()
if err != nil {
return nil, err
}
resp, body, _, err := client.SendGet(artifactoryApiUrl, true, artHttpDetails, "")
if err != nil {
return nil, err
}
if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil {
return nil, err
}

response := &model.ReleaseBundlesResponse{}
if err := json.Unmarshal(body, response); err != nil {
return nil, errorutils.CheckError(err)
}
return response, nil
}

type PackageVersionResponseContent struct {
Version string `json:"Version,omitempty"`
}

func getGitCommitInfo(serverDetails *coreConfig.ServerDetails, createBuildConfiguration *build.BuildConfiguration, gitDetails artifactoryUtils.GitLogDetails) ([]byte, error) {
owner, repository, err := gitHubRepositoryDetails()
log.Info(fmt.Sprintf("owner: %s repository: %s", owner, repository))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion evidence/create_github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (m *MockBuildAndVcsDetails) GetLastBuildLink(serverDetails *coreConfig.Serv

func TestNewCreateGithub(t *testing.T) {
serverDetails := &coreConfig.ServerDetails{}
command := NewCreateGithub(serverDetails, "path/to/predicate.json", "predicateType", "path/to/markdown.md", "key", "keyId", "myProject", "myBuild", "123", "gh-commiter")
command := NewCreateGithub(serverDetails, "path/to/predicate.json", "predicateType", "path/to/markdown.md", "key", "keyId", "myProject", "myBuild", "123", "gh-commiter", "", "")

assert.NotNil(t, command)

Expand Down
49 changes: 49 additions & 0 deletions evidence/model/release_bundle_graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package model

import "time"

type GraphResponse struct {
Root Root `json:"root,omitempty"`
}

// Root corresponds to the "root" key.
// All fields are pointers to allow for null values.
type Root struct {
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Repository string `json:"repository,omitempty"`
CreatedMillis int64 `json:"created_millis,omitempty"`
Nodes []Node `json:"nodes,omitempty"`
Evidence []any `json:"evidence,omitempty"`
}

// Node represents items in the "nodes" array (recursively).
// Again, all fields are pointers to allow them to be nil.
type Node struct {
Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Repository string `json:"repository,omitempty"`
CreatedMillis int64 `json:"created_millis,omitempty"`
Nodes []Node `json:"nodes,omitempty"`
Evidence []any `json:"evidence,omitempty"`
PackageID string `json:"package_id,omitempty"`
}

type ReleaseBundle struct {
Status string `json:"status"`
RepositoryKey string `json:"repository_key"`
ReleaseBundleName string `json:"release_bundle_name"`
ReleaseBundleVersion string `json:"release_bundle_version"`
ServiceID string `json:"service_id"`
CreatedBy string `json:"created_by"`
Created time.Time `json:"created"`
}

type ReleaseBundlesResponse struct {
ReleaseBundles []ReleaseBundle `json:"release_bundles"`
Total int `json:"total"`
Limit int `json:"limit"`
Offset int `json:"offset"`
}
16 changes: 8 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@ module github.com/jfrog/jfrog-cli-artifactory

go 1.23.4

toolchain go1.23.5

require (
github.com/c-bata/go-prompt v0.2.5
github.com/forPelevin/gomoji v1.2.0
github.com/jfrog/build-info-go v1.10.9
github.com/jfrog/froggit-go v1.16.2
github.com/jfrog/froggit-go v0.0.0-00010101000000-000000000000
github.com/jfrog/gofrog v1.7.6
github.com/jfrog/jfrog-cli-core/v2 v2.58.0
github.com/jfrog/jfrog-client-go v1.50.0
Expand Down Expand Up @@ -119,7 +117,6 @@ require (
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
Expand All @@ -135,11 +132,14 @@ require (
sigs.k8s.io/yaml v1.4.0 // indirect
)

//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250130104846-27e495de291e
replace github.com/jfrog/jfrog-cli-core/v2 => github.com/EyalDelarea/jfrog-cli-core/v2 v2.0.0-20250206084646-819832cab1e1

//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250212021126-e5223ab616af
replace github.com/jfrog/jfrog-cli-core/v2 => github.com/EyalDelarea/jfrog-cli-core/v2 v2.0.0-20250212163056-052cba06bfea

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250126110945-81abbdde452f

//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20240811150357-12a9330a2d67
//replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240811142930-ab9715567376

replace github.com/jfrog/froggit-go => github.com/EyalDelarea/froggit-go v1.6.1-0.20250204105801-761f8d527d7f

replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20250203111011-4ff16d3d42be
replace github.com/jfrog/jfrog-client-go => github.com/lesnerd/jfrog-client-go v0.0.0-20250216170623-d841f33debec
Loading

0 comments on commit 43a273e

Please sign in to comment.