Skip to content

Commit

Permalink
Artifactory Release Lifecycle Management - Support release bundle dis…
Browse files Browse the repository at this point in the history
…tribution by project (#913)
  • Loading branch information
RobiNino authored Mar 18, 2024
1 parent e419c2a commit 90669db
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 93 deletions.
2 changes: 1 addition & 1 deletion distribution/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (sm *DistributionServicesManager) DistributeReleaseBundleSync(params distri
return distributeBundleService.Distribute()
}

func (sm *DistributionServicesManager) GetDistributionStatus(params services.DistributionStatusParams) (*[]services.DistributionStatusResponse, error) {
func (sm *DistributionServicesManager) GetDistributionStatus(params services.DistributionStatusParams) (*[]distribution.DistributionStatusResponse, error) {
distributeBundleService := services.NewDistributionStatusService(sm.client)
distributeBundleService.DistDetails = sm.config.GetServiceDetails()
return distributeBundleService.GetStatus(params)
Expand Down
8 changes: 6 additions & 2 deletions distribution/services/distribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func (dr *DistributeReleaseBundleV1Service) GetDistributionParams() distribution
return dr.DistributeParams
}

func (dr *DistributeReleaseBundleV1Service) GetProjectKey() string {
return ""
}

func NewDistributeReleaseBundleV1Service(client *jfroghttpclient.JfrogHttpClient) *DistributeReleaseBundleV1Service {
return &DistributeReleaseBundleV1Service{client: client}
}
Expand Down Expand Up @@ -94,14 +98,14 @@ func (dr *DistributeReleaseBundleV1Service) waitForDistribution(distributeParams
if err != nil {
return false, errorutils.CheckError(err)
}
if (*response)[0].Status == Failed {
if (*response)[0].Status == distribution.Failed {
bytes, err := json.Marshal(response)
if err != nil {
return false, errorutils.CheckError(err)
}
return false, errorutils.CheckErrorf("Distribution failed: " + clientUtils.IndentJson(bytes))
}
if (*response)[0].Status == Completed {
if (*response)[0].Status == distribution.Completed {
log.Info("Distribution Completed!")
return false, nil
}
Expand Down
52 changes: 3 additions & 49 deletions distribution/services/getstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (ds *DistributionStatusService) GetDistDetails() auth.ServiceDetails {
return ds.DistDetails
}

func (ds *DistributionStatusService) GetStatus(distributionStatusParams DistributionStatusParams) (*[]DistributionStatusResponse, error) {
func (ds *DistributionStatusService) GetStatus(distributionStatusParams DistributionStatusParams) (*[]distribution.DistributionStatusResponse, error) {
if err := ds.checkParameters(distributionStatusParams); err != nil {
return nil, err
}
Expand All @@ -45,7 +45,7 @@ func (ds *DistributionStatusService) checkParameters(distributionStatusParams Di
return errorutils.CheckError(err)
}

func (ds *DistributionStatusService) execGetStatus(name, version, trackerId string) (*[]DistributionStatusResponse, error) {
func (ds *DistributionStatusService) execGetStatus(name, version, trackerId string) (*[]distribution.DistributionStatusResponse, error) {
httpClientsDetails := ds.DistDetails.CreateHttpClientDetails()
url := ds.BuildUrlForGetStatus(ds.DistDetails.GetUrl(), name, version, trackerId)

Expand All @@ -58,7 +58,7 @@ func (ds *DistributionStatusService) execGetStatus(name, version, trackerId stri
}
log.Debug("Distribution response:", resp.Status)
log.Debug(utils.IndentJson(body))
var distributionStatusResponse []DistributionStatusResponse
var distributionStatusResponse []distribution.DistributionStatusResponse
stringBody := string(body)
if !strings.HasPrefix(stringBody, "[") {
stringBody = "[" + stringBody + "]"
Expand Down Expand Up @@ -92,49 +92,3 @@ type DistributionStatusParams struct {
func NewDistributionStatusParams() DistributionStatusParams {
return DistributionStatusParams{}
}

type DistributionType string

const (
Distribute DistributionType = "distribute"
DeleteReleaseBundleVersion DistributionType = "delete_release_bundle_version"
)

type DistributionStatus string

const (
NotDistributed DistributionStatus = "Not distributed"
InProgress DistributionStatus = "In progress"
InQueue DistributionStatus = "In queue"
Completed DistributionStatus = "Completed"
Failed DistributionStatus = "Failed"
)

type DistributionStatusResponse struct {
Id json.Number `json:"distribution_id"`
FriendlyId json.Number `json:"distribution_friendly_id,omitempty"`
Type DistributionType `json:"type,omitempty"`
Name string `json:"release_bundle_name,omitempty"`
Version string `json:"release_bundle_version,omitempty"`
Status DistributionStatus `json:"status,omitempty"`
DistributionRules []distribution.DistributionRulesBody `json:"distribution_rules,omitempty"`
Sites []DistributionSiteStatus `json:"sites,omitempty"`
}

type DistributionSiteStatus struct {
Status string `json:"status,omitempty"`
Error string `json:"general_error,omitempty"`
TargetArtifactory TargetArtifactory `json:"target_artifactory,omitempty"`
TotalFiles json.Number `json:"total_files,omitempty"`
TotalBytes json.Number `json:"total_bytes,omitempty"`
DistributedBytes json.Number `json:"distributed_bytes,omitempty"`
DistributedFiles json.Number `json:"distributed_files,omitempty"`
FileErrors []string `json:"file_errors,omitempty"`
FilesInProgress []string `json:"files_in_progress,omitempty"`
}

type TargetArtifactory struct {
ServiceId string `json:"service_id"`
Name string `json:"name"`
Type string `json:"type"`
}
7 changes: 4 additions & 3 deletions lifecycle/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,12 @@ func (lcs *LifecycleServicesManager) DistributeReleaseBundle(rbDetails lifecycle
distributeBundleService.AutoCreateRepo = distributeParams.AutoCreateRepo
distributeBundleService.Sync = distributeParams.Sync
distributeBundleService.MaxWaitMinutes = distributeParams.MaxWaitMinutes
distributeBundleService.ProjectKey = distributeParams.ProjectKey

m := &distributeBundleService.Modifications.PathMappings
*m = []utils.PathMapping{}
mappings := &distributeBundleService.Modifications.PathMappings
*mappings = []utils.PathMapping{}
for _, pathMapping := range distributeParams.PathMappings {
*m = append(*m,
*mappings = append(*mappings,
distribution.CreatePathMappingsFromPatternAndTarget(pathMapping.Pattern, pathMapping.Target)...)
}
return distributeBundleService.Distribute()
Expand Down
2 changes: 1 addition & 1 deletion lifecycle/services/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (rbs *ReleaseBundlesService) DeleteReleaseBundleVersionPromotion(rbDetails
}

func (rbs *ReleaseBundlesService) deleteReleaseBundle(params CommonOptionalQueryParams, restApi string) error {
queryParams := getProjectQueryParam(params.ProjectKey)
queryParams := distribution.GetProjectQueryParam(params.ProjectKey)
queryParams[async] = strconv.FormatBool(params.Async)
requestFullUrl, err := utils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), restApi, queryParams)
if err != nil {
Expand Down
12 changes: 7 additions & 5 deletions lifecycle/services/distribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type DistributeReleaseBundleService struct {
Sync bool
MaxWaitMinutes int
DistributeParams distribution.DistributionParams
ProjectKey string
Modifications
}

Expand All @@ -36,6 +37,7 @@ type DistributeReleaseBundleParams struct {
MaxWaitMinutes int
DistributionRules []*distribution.DistributionCommonParams
PathMappings []PathMapping
ProjectKey string
}

func (dr *DistributeReleaseBundleService) GetHttpClient() *jfroghttpclient.JfrogHttpClient {
Expand All @@ -58,10 +60,6 @@ func (dr *DistributeReleaseBundleService) GetMaxWaitMinutes() int {
return dr.MaxWaitMinutes
}

func (dr *DistributeReleaseBundleService) IsAutoCreateRepo() bool {
return dr.AutoCreateRepo
}

func (dr *DistributeReleaseBundleService) GetRestApi(name, version string) string {
return path.Join(distributionBaseApi, distribute, name, version)
}
Expand All @@ -74,6 +72,10 @@ func (dr *DistributeReleaseBundleService) GetDistributionParams() distribution.D
return dr.DistributeParams
}

func (dr *DistributeReleaseBundleService) GetProjectKey() string {
return dr.ProjectKey
}

func NewDistributeReleaseBundleService(client *jfroghttpclient.JfrogHttpClient) *DistributeReleaseBundleService {
return &DistributeReleaseBundleService{client: client}
}
Expand Down Expand Up @@ -111,7 +113,7 @@ type PathMapping struct {

func (rbs *ReleaseBundlesService) getReleaseBundleDistributions(rbDetails ReleaseBundleDetails, projectKey string) (distributionsResp GetDistributionsResponse, body []byte, err error) {
restApi := GetReleaseBundleDistributionsApi(rbDetails)
requestFullUrl, err := clientUtils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), restApi, getProjectQueryParam(projectKey))
requestFullUrl, err := clientUtils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), restApi, distribution.GetProjectQueryParam(projectKey))
if err != nil {
return
}
Expand Down
11 changes: 2 additions & 9 deletions lifecycle/services/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/jfrog/jfrog-client-go/auth"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
"github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/distribution"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"net/http"
Expand Down Expand Up @@ -36,7 +37,7 @@ type ReleaseBundleOperation interface {
}

func (rbs *ReleaseBundlesService) doOperation(operation ReleaseBundleOperation) ([]byte, error) {
queryParams := getProjectQueryParam(operation.getOperationParams().ProjectKey)
queryParams := distribution.GetProjectQueryParam(operation.getOperationParams().ProjectKey)
queryParams[async] = strconv.FormatBool(operation.getOperationParams().Async)
requestFullUrl, err := utils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), operation.getOperationRestApi(), queryParams)
if err != nil {
Expand Down Expand Up @@ -67,14 +68,6 @@ func (rbs *ReleaseBundlesService) doOperation(operation ReleaseBundleOperation)
return body, errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK)
}

func getProjectQueryParam(projectKey string) map[string]string {
queryParams := make(map[string]string)
if projectKey != "" {
queryParams["project"] = projectKey
}
return queryParams
}

type ReleaseBundleDetails struct {
ReleaseBundleName string `json:"release_bundle_name,omitempty"`
ReleaseBundleVersion string `json:"release_bundle_version,omitempty"`
Expand Down
30 changes: 15 additions & 15 deletions lifecycle/services/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import (
"net/http"
"path"
"time"

dsServices "github.com/jfrog/jfrog-client-go/distribution/services"
)

const (
Expand Down Expand Up @@ -64,7 +62,7 @@ func (rbs *ReleaseBundlesService) getReleaseBundleOperationStatus(restApi string
}

func (rbs *ReleaseBundlesService) getReleaseBundleStatus(restApi string, projectKey string) (statusResp ReleaseBundleStatusResponse, body []byte, err error) {
requestFullUrl, err := utils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), restApi, getProjectQueryParam(projectKey))
requestFullUrl, err := utils.BuildUrl(rbs.GetLifecycleDetails().GetUrl(), restApi, distribution.GetProjectQueryParam(projectKey))
if err != nil {
return
}
Expand Down Expand Up @@ -98,14 +96,14 @@ func (rbs *ReleaseBundlesService) GetReleaseBundleSpecification(rbDetails Releas
return
}

func (dbs *DistributeReleaseBundleService) getReleaseBundleDistributionStatus(distributeParams *distribution.DistributionParams, trackerId json.Number) (statusResp *dsServices.DistributionStatusResponse, body []byte, err error) {
func (dr *DistributeReleaseBundleService) getReleaseBundleDistributionStatus(distributeParams *distribution.DistributionParams, trackerId json.Number) (statusResp *distribution.DistributionStatusResponse, body []byte, err error) {
restApi := path.Join(distributionBaseApi, trackersApi, distributeParams.Name, distributeParams.Version, trackerId.String())
requestFullUrl, err := utils.BuildUrl(dbs.LcDetails.GetUrl(), restApi, nil)
requestFullUrl, err := utils.BuildUrl(dr.LcDetails.GetUrl(), restApi, distribution.GetProjectQueryParam(dr.GetProjectKey()))
if err != nil {
return
}
httpClientsDetails := dbs.LcDetails.CreateHttpClientDetails()
resp, body, _, err := dbs.client.SendGet(requestFullUrl, true, &httpClientsDetails)
httpClientsDetails := dr.LcDetails.CreateHttpClientDetails()
resp, body, _, err := dr.client.SendGet(requestFullUrl, true, &httpClientsDetails)
if err != nil {
return
}
Expand Down Expand Up @@ -151,22 +149,22 @@ func (rbs *ReleaseBundlesService) waitForRbOperationCompletion(restApi, projectK
return getStatusResponse(finalRespBody)
}

func (dbs *DistributeReleaseBundleService) waitForDistributionOperationCompletion(distributeParams *distribution.DistributionParams, trackerId json.Number) error {
maxWait := time.Duration(dbs.GetMaxWaitMinutes()) * time.Minute
func (dr *DistributeReleaseBundleService) waitForDistributionOperationCompletion(distributeParams *distribution.DistributionParams, trackerId json.Number) error {
maxWait := time.Duration(dr.GetMaxWaitMinutes()) * time.Minute
if maxWait.Minutes() < 1 {
maxWait = defaultMaxWait
}

pollingAction := func() (shouldStop bool, responseBody []byte, err error) {
statusResponse, responseBody, err := dbs.getReleaseBundleDistributionStatus(distributeParams, trackerId)
statusResponse, responseBody, err := dr.getReleaseBundleDistributionStatus(distributeParams, trackerId)
if err != nil {
return true, nil, err
}

switch statusResponse.Status {
case dsServices.NotDistributed, dsServices.InProgress, dsServices.InQueue:
case distribution.NotDistributed, distribution.InProgress, distribution.InQueue:
return false, nil, nil
case dsServices.Failed, dsServices.Completed:
case distribution.Failed, distribution.Completed:
return true, responseBody, nil
default:
return true, nil, errorutils.CheckErrorf("received unexpected status: '%s'", statusResponse.Status)
Expand All @@ -183,14 +181,16 @@ func (dbs *DistributeReleaseBundleService) waitForDistributionOperationCompletio
return err
}

var dsStatusResponse dsServices.DistributionStatusResponse
var dsStatusResponse distribution.DistributionStatusResponse
if err = json.Unmarshal(finalRespBody, &dsStatusResponse); err != nil {
return errorutils.CheckError(err)
}

if dsStatusResponse.Status != dsServices.Completed {
if dsStatusResponse.Status != distribution.Completed {
for _, st := range dsStatusResponse.Sites {
err = errors.Join(err, fmt.Errorf("target %s name:%s error:%s", st.TargetArtifactory.Type, st.TargetArtifactory.Name, st.Error))
if st.Status != distribution.Completed {
err = errors.Join(err, fmt.Errorf("target %s name:%s error:%s", st.TargetArtifactory.Type, st.TargetArtifactory.Name, st.Error))
}
}
return errorutils.CheckError(err)
}
Expand Down
10 changes: 5 additions & 5 deletions tests/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func createSignDistributeDelete(t *testing.T) {
// Assert release bundle in "completed" status
response, err = testsBundleDistributionStatusService.GetStatus(distributionStatusParams)
if assert.NoError(t, err) && assert.NotEmpty(t, *response) {
assert.Equal(t, services.Completed, (*response)[0].Status)
assert.Equal(t, distribution.Completed, (*response)[0].Status)
}
}

Expand Down Expand Up @@ -357,7 +357,7 @@ func createSignSyncDistributeDelete(t *testing.T) {
}
response, err := testsBundleDistributionStatusService.GetStatus(distributionStatusParams)
if assert.NoError(t, err) && assert.NotEmpty(t, *response) {
assert.Equal(t, services.Completed, (*response)[0].Status)
assert.Equal(t, distribution.Completed, (*response)[0].Status)
}
}

Expand Down Expand Up @@ -548,12 +548,12 @@ func waitForDistribution(t *testing.T, bundleName string) {
assert.Len(t, *response, 1)

switch (*response)[0].Status {
case services.Completed:
case distribution.Completed:
return
case services.Failed:
case distribution.Failed:
t.Error("Distribution failed for " + bundleName + "/" + bundleVersion)
return
case services.InProgress, services.NotDistributed:
case distribution.InProgress, distribution.NotDistributed:
// Wait
}
t.Log("Waiting for " + bundleName + "/" + bundleVersion + "...")
Expand Down
Loading

0 comments on commit 90669db

Please sign in to comment.