From 1b2bfe28f8383b4cf8a57e79222555cc512696e7 Mon Sep 17 00:00:00 2001 From: delarea Date: Mon, 11 Mar 2024 18:13:42 +0200 Subject: [PATCH] add import --- artifactory/emptymanager.go | 5 ++ artifactory/manager.go | 5 ++ artifactory/services/release.go | 84 +++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 artifactory/services/release.go diff --git a/artifactory/emptymanager.go b/artifactory/emptymanager.go index 1e9387150..f6968584d 100644 --- a/artifactory/emptymanager.go +++ b/artifactory/emptymanager.go @@ -105,6 +105,7 @@ type ArtifactoryServicesManager interface { FileList(relativePath string, optionalParams utils.FileListParams) (*utils.FileListResponse, error) GetStorageInfo() (*utils.StorageInfo, error) CalculateStorageInfo() error + ReleaseBundleImport(string) error } // By using this struct, you have the option of overriding only some of the ArtifactoryServicesManager @@ -465,6 +466,10 @@ func (esm *EmptyArtifactoryServicesManager) CalculateStorageInfo() error { panic("Failed: Method is not implemented") } +func (esm *EmptyArtifactoryServicesManager) ReleaseBundleImport(string) error { + panic("Failed: Method is not implemented") +} + // Compile time check of interface implementation. // Since EmptyArtifactoryServicesManager can be used by tests external to this project, we want this project's tests to fail, // if EmptyArtifactoryServicesManager stops implementing the ArtifactoryServicesManager interface. diff --git a/artifactory/manager.go b/artifactory/manager.go index 2d19c9871..80db3c49c 100644 --- a/artifactory/manager.go +++ b/artifactory/manager.go @@ -605,3 +605,8 @@ func (sm *ArtifactoryServicesManagerImp) CalculateStorageInfo() error { storageService := services.NewStorageService(sm.config.GetServiceDetails(), sm.client) return storageService.StorageInfoRefresh() } + +func (sm *ArtifactoryServicesManagerImp) ReleaseBundleImport(filePath string) error { + releaseService := services.NewReleaseService(sm.config.GetServiceDetails(), sm.client) + return releaseService.ImportReleaseBundle(filePath) +} diff --git a/artifactory/services/release.go b/artifactory/services/release.go new file mode 100644 index 000000000..6f701d029 --- /dev/null +++ b/artifactory/services/release.go @@ -0,0 +1,84 @@ +package services + +import ( + "encoding/json" + "github.com/jfrog/jfrog-client-go/artifactory/services/utils" + "github.com/jfrog/jfrog-client-go/auth" + "github.com/jfrog/jfrog-client-go/http/jfroghttpclient" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + ioutils "github.com/jfrog/jfrog-client-go/utils/io" + "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "net/http" + "strings" +) + +const ( + conflictErrorMessage = "Bundle already exists" + importRestApiEndpoint = "api/release/import" + // TODO change this when the bug is fixed + // https://jfrog-int.atlassian.net/browse/JR-8542 + tempImportRestApiEndpoint = "ui/api/v1/ui/release/import" + octetStream = "application/octet-stream" +) + +type ReleaseService struct { + client *jfroghttpclient.JfrogHttpClient + ArtDetails auth.ServiceDetails + Progress ioutils.ProgressMgr +} + +type ErrorResponseWithMessage struct { + Errors []ErrorDetail `json:"errors"` +} + +type ErrorDetail struct { + Status int `json:"status"` + Message string `json:"message"` +} + +func NewReleaseService(artDetails auth.ServiceDetails, client *jfroghttpclient.JfrogHttpClient) *ReleaseService { + return &ReleaseService{client: client, ArtDetails: artDetails} +} + +func (rs *ReleaseService) GetJfrogHttpClient() *jfroghttpclient.JfrogHttpClient { + return rs.client +} + +func (rs *ReleaseService) ImportReleaseBundle(filePath string) (err error) { + // Load desired file + content, err := fileutils.ReadFile(filePath) + if err != nil { + return + } + // Upload file + httpClientsDetails := rs.ArtDetails.CreateHttpClientDetails() + + // TODO replace URL when artifactory bug is fixed + //url := rs.ArtDetails.GetUrl() + importRestApiEndpoint + tempUrl := strings.TrimSuffix(rs.ArtDetails.GetUrl(), "/artifactory/") + "/" + tempImportRestApiEndpoint + + utils.SetContentType(octetStream, &httpClientsDetails.Headers) + var resp *http.Response + var body []byte + log.Info("Uploading archive...") + if resp, body, err = rs.client.SendPost(tempUrl, content, &httpClientsDetails); err != nil { + return + } + // When a release bundle already exists, don't return an error message of failure. + if resp.StatusCode == http.StatusBadRequest { + response := ErrorResponseWithMessage{} + if err = json.Unmarshal(body, &response); err != nil { + return + } + if response.Errors[0].Message == conflictErrorMessage { + log.Warn("Bundle already exists, did not upload a new bundle") + return + } + } + if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusAccepted); err != nil { + return + } + log.Info("Upload Successful") + return +}