Skip to content

Commit

Permalink
Merge pull request #15 from AlexeiVainshtein/supoprtGoNewApi
Browse files Browse the repository at this point in the history
Support Artifactory Go API
  • Loading branch information
eyalbe4 committed Dec 13, 2018
2 parents 8ab8018 + 1790cc3 commit 6a0910d
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 90 deletions.
95 changes: 25 additions & 70 deletions artifactory/services/go/go.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package _go

import (
"encoding/base64"
"errors"
"fmt"
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/errors/httperrors"
"github.com/jfrog/jfrog-client-go/httpclient"
"github.com/jfrog/jfrog-client-go/utils/version"
"strings"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
)

type GoService struct {
Expand All @@ -28,99 +26,56 @@ func (gs *GoService) SetArtDetails(artDetails auth.ArtifactoryDetails) {
}

func (gs *GoService) PublishPackage(params GoParams) error {
url, err := utils.BuildArtifactoryUrl(gs.ArtDetails.GetUrl(), "api/go/"+params.GetTargetRepo(), make(map[string]string))
clientDetails := gs.ArtDetails.CreateHttpClientDetails()

utils.AddHeader("X-GO-MODULE-VERSION", params.GetVersion(), &clientDetails.Headers)
utils.AddHeader("X-GO-MODULE-CONTENT", base64.StdEncoding.EncodeToString(params.GetModContent()), &clientDetails.Headers)
artifactoryVersion, err := gs.ArtDetails.GetVersion()
if err != nil {
return err
}
if !shouldUseHeaders(artifactoryVersion) {
createUrlPath(params, &url)
} else {
addPropertiesHeaders(params.GetProps(), &clientDetails.Headers)
}

resp, body, err := gs.client.UploadFile(params.GetZipPath(), url, clientDetails, 0)
if err != nil {
return err
}
return httperrors.CheckResponseStatus(resp, body, 201)
}

// This is needed when using Artifactory older then 6.5.0
func addPropertiesHeaders(props string, headers *map[string]string) error {
properties, err := utils.ParseProperties(props, utils.JoinCommas)
if err != nil {
return err
}
headersMap := properties.ToHeadersMap()
for k, v := range headersMap {
utils.AddHeader("X-ARTIFACTORY-PROPERTY-"+k, v, headers)
publisher := GetCompatiblePublisher(artifactoryVersion)
if publisher == nil {
return errorutils.CheckError(errors.New(fmt.Sprintf("Unsupported version of Artifactory: %s", artifactoryVersion)))
}
return nil
}

func createUrlPath(params GoParams, url *string) error {
*url = strings.Join([]string{*url, params.GetModuleId(), "@v", params.GetVersion() + ".zip"}, "/")
properties, err := utils.ParseProperties(params.GetProps(), utils.JoinCommas)
if err != nil {
return err
}
*url = strings.Join([]string{*url, properties.ToEncodedString()}, ";")
if strings.HasSuffix(*url, ";") {
tempUrl := *url
tempUrl = tempUrl[:len(tempUrl)-1]
*url = tempUrl
}
return nil
}

// Returns true if needed to use properties as header (Artifactory version between 6.2.0 and 6.5.0)
// or false if need to use matrix params (Artifactory version 6.5.0 and above).
func shouldUseHeaders(artifactoryVersion string) bool {
propertiesApi := "6.5.0"
if version.Compare(artifactoryVersion, propertiesApi) < 0 && artifactoryVersion != "development" {
return true
}
return false
return publisher.PublishPackage(params, gs.client, gs.ArtDetails)
}

type GoParams struct {
ZipPath string
ModPath string
ModContent []byte
Version string
Props string
TargetRepo string
ModuleId string
}

func (gpi *GoParams) GetZipPath() string {
return gpi.ZipPath
func (gp *GoParams) GetZipPath() string {
return gp.ZipPath
}

func (gpi *GoParams) GetModContent() []byte {
return gpi.ModContent
func (gp *GoParams) GetModContent() []byte {
return gp.ModContent
}

func (gpi *GoParams) GetVersion() string {
return gpi.Version
func (gp *GoParams) GetVersion() string {
return gp.Version
}

func (gpi *GoParams) GetProps() string {
return gpi.Props
func (gp *GoParams) GetProps() string {
return gp.Props
}

func (gpi *GoParams) GetTargetRepo() string {
return gpi.TargetRepo
func (gp *GoParams) GetTargetRepo() string {
return gp.TargetRepo
}

func (gpi *GoParams) GetModuleId() string {
return gpi.ModuleId
func (gp *GoParams) GetModuleId() string {
return gp.ModuleId
}

func (gp *GoParams) GetModPath() string {
return gp.ModPath
}

func NewGoParams() GoParams {
return GoParams{}
}
}
41 changes: 21 additions & 20 deletions artifactory/services/go/go_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package _go

import (
"reflect"
"strings"
"testing"
)
Expand All @@ -9,16 +10,20 @@ func TestCreateUrlPath(t *testing.T) {

tests := []struct {
name string
params GoParams
extension string
moduleId string
version string
props string
url string
expectedUrl string
}{
{"withBuildProperties", GoParams{ZipPath: "path/to/zip/file", Version: "v1.1.1", TargetRepo: "ArtiRepo", ModuleId: "github.com/jfrog/test", Props: "build.name=a;build.number=1"}, "http://test.url/", "http://test.url//github.com/jfrog/test/@v/v1.1.1.zip;build.name=a;build.number=1"},
{"withoutBuildProperties", GoParams{ZipPath: "path/to/zip/file", Version: "v1.1.1", TargetRepo: "ArtiRepo", ModuleId: "github.com/jfrog/test"}, "http://test.url/", "http://test.url//github.com/jfrog/test/@v/v1.1.1.zip"},
{"withBuildProperties", ".zip", "github.com/jfrog/test", "v1.1.1", "build.name=a;build.number=1", "http://test.url/", "http://test.url//github.com/jfrog/test/@v/v1.1.1.zip;build.name=a;build.number=1"},
{"withoutBuildProperties", ".zip", "github.com/jfrog/test", "v1.1.1", "", "http://test.url/", "http://test.url//github.com/jfrog/test/@v/v1.1.1.zip"},
{"withoutBuildPropertiesModExtension", ".mod", "github.com/jfrog/test", "v1.1.1", "", "http://test.url/", "http://test.url//github.com/jfrog/test/@v/v1.1.1.mod"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
createUrlPath(test.params, &test.url)
createUrlPath(test.moduleId, test.version, test.props, test.extension, &test.url)
if !strings.EqualFold(test.url, test.expectedUrl) {
t.Error("Expected:", test.expectedUrl, "Got:", test.url)
}
Expand All @@ -29,26 +34,22 @@ func TestCreateUrlPath(t *testing.T) {
func TestShouldUseHeaders(t *testing.T) {
tests := []struct {
artifactoryVersion string
expectedResult bool
expectedResult string
}{
{"6.5.0", false},
{"6.2.0", true},
{"5.9.0", true},
{"6.0.0", true},
{"6.6.0", false},
{"development", false},
{"6.10.2", false},
{"6.5.0", "*_go.publishWithMatrixParams"},
{"6.2.0", "*_go.publishWithHeader"},
{"5.9.0", "*_go.publishWithHeader"},
{"6.0.0", "*_go.publishWithHeader"},
{"6.6.0", "*_go.publishWithoutApi"},
{"development", "*_go.publishWithoutApi"},
{"6.10.2", "*_go.publishWithoutApi"},
}
for _, test := range tests {
t.Run(test.artifactoryVersion, func(t *testing.T) {
result := shouldUseHeaders(test.artifactoryVersion)
if result && !test.expectedResult {
t.Error("Expected:", test.expectedResult, "Got:", result)
}

if !result && test.expectedResult {
t.Error("Expected:", test.expectedResult, "Got:", result)
result := GetCompatiblePublisher(test.artifactoryVersion)
if reflect.TypeOf(result).String() != test.expectedResult {
t.Error("Expected:", test.expectedResult, "Got:", reflect.TypeOf(result).String())
}
})
}
}
}
29 changes: 29 additions & 0 deletions artifactory/services/go/goutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package _go

import (
"encoding/base64"
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/utils/io/httputils"
"strings"
)

func addHeaders(params GoParams, clientDetails *httputils.HttpClientDetails) {
utils.AddHeader("X-GO-MODULE-VERSION", params.GetVersion(), &clientDetails.Headers)
utils.AddHeader("X-GO-MODULE-CONTENT", base64.StdEncoding.EncodeToString(params.GetModContent()), &clientDetails.Headers)
}

func createUrlPath(moduleId, version, props, extension string, url *string) error {
*url = strings.Join([]string{*url, moduleId, "@v", version + extension}, "/")
properties, err := utils.ParseProperties(props, utils.JoinCommas)
if err != nil {
return err
}

*url = strings.Join([]string{*url, properties.ToEncodedString()}, ";")
if strings.HasSuffix(*url, ";") {
tempUrl := *url
tempUrl = tempUrl[:len(tempUrl)-1]
*url = tempUrl
}
return nil
}
27 changes: 27 additions & 0 deletions artifactory/services/go/publish.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package _go

import (
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/jfrog/jfrog-client-go/httpclient"
)

var publishers []PublishGoPackage

type PublishGoPackage interface {
isCompatible(artifactoryVersion string) bool
PublishPackage(params GoParams, client *httpclient.HttpClient, ArtDetails auth.ArtifactoryDetails) error
}

func register(publishApi PublishGoPackage) {
publishers = append(publishers, publishApi)
}

// Returns the compatible publisher to Artifactory
func GetCompatiblePublisher(artifactoryVersion string) PublishGoPackage {
for _, publisher := range publishers {
if publisher.isCompatible(artifactoryVersion) {
return publisher
}
}
return nil
}
65 changes: 65 additions & 0 deletions artifactory/services/go/publishmodandzip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package _go

import (
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/errors/httperrors"
"github.com/jfrog/jfrog-client-go/httpclient"
"github.com/jfrog/jfrog-client-go/utils/version"
"net/url"
"strings"
)

func init() {
register(&publishWithoutApi{})
}

// Support for Artifactory 6.6.0 and above API
type publishWithoutApi struct {
}

func (pwa *publishWithoutApi) isCompatible(artifactoryVersion string) bool {
propertiesApi := "6.6.0"
if version.Compare(artifactoryVersion, propertiesApi) < 0 && artifactoryVersion != "development" {
return false
}
return true
}

func (pwa *publishWithoutApi) PublishPackage(params GoParams, client *httpclient.HttpClient, ArtDetails auth.ArtifactoryDetails) error {
url, err := utils.BuildArtifactoryUrl(ArtDetails.GetUrl(), params.GetTargetRepo(), make(map[string]string))
if err != nil {
return err
}
zipUrl := url
moduleId := strings.Split(params.GetModuleId(), ":")
err = createUrlPath(moduleId[0], params.GetVersion(), params.GetProps(), ".zip", &zipUrl)
if err != nil {
return err
}
clientDetails := ArtDetails.CreateHttpClientDetails()

addGoVersion(params, &zipUrl)
resp, body, err := client.UploadFile(params.GetZipPath(), zipUrl, clientDetails, 0)
if err != nil {
return err
}
err = httperrors.CheckResponseStatus(resp, body, 201)
if err != nil {
return err
}
err = createUrlPath(moduleId[0], params.GetVersion(), params.GetProps(), ".mod", &url)
if err != nil {
return err
}
addGoVersion(params, &url)
resp, body, err = client.UploadFile(params.GetModPath(), url, clientDetails, 0)
if err != nil {
return err
}
return httperrors.CheckResponseStatus(resp, body, 201)
}

func addGoVersion(params GoParams, urlPath *string) {
*urlPath += ";go.version=" + url.QueryEscape(params.GetVersion())
}
49 changes: 49 additions & 0 deletions artifactory/services/go/publishwithheaders.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package _go

import (
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/errors/httperrors"
"github.com/jfrog/jfrog-client-go/httpclient"
"github.com/jfrog/jfrog-client-go/utils/version"
)

func init() {
register(&publishWithHeader{})
}

// Support for Artifactory older then 6.5.0 API
type publishWithHeader struct {
}

func (pwh *publishWithHeader) isCompatible(artifactoryVersion string) bool {
propertiesApi := "6.5.0"
if version.Compare(artifactoryVersion, propertiesApi) < 0 {
return true
}
return false
}

func (pwh *publishWithHeader) PublishPackage(params GoParams, client *httpclient.HttpClient, ArtDetails auth.ArtifactoryDetails) error {
url, err := utils.BuildArtifactoryUrl(ArtDetails.GetUrl(), "api/go/"+params.GetTargetRepo(), make(map[string]string))
clientDetails := ArtDetails.CreateHttpClientDetails()
addHeaders(params, &clientDetails)
addPropertiesHeaders(params.GetProps(), &clientDetails.Headers)
resp, body, err := client.UploadFile(params.GetZipPath(), url, clientDetails, 0)
if err != nil {
return err
}
return httperrors.CheckResponseStatus(resp, body, 201)
}

func addPropertiesHeaders(props string, headers *map[string]string) error {
properties, err := utils.ParseProperties(props, utils.JoinCommas)
if err != nil {
return err
}
headersMap := properties.ToHeadersMap()
for k, v := range headersMap {
utils.AddHeader("X-ARTIFACTORY-PROPERTY-"+k, v, headers)
}
return nil
}

0 comments on commit 6a0910d

Please sign in to comment.