github.com/jdhenke/godel@v0.0.0-20161213181855-abeb3861bf0d/apps/distgo/cmd/publish/artifactory_publish.go (about) 1 // Copyright 2016 Palantir Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package publish 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "net/http" 23 "net/url" 24 "path" 25 "strings" 26 27 "github.com/pkg/errors" 28 29 "github.com/palantir/godel/apps/distgo/params" 30 ) 31 32 type ArtifactoryConnectionInfo struct { 33 BasicConnectionInfo 34 Repository string 35 } 36 37 func (a ArtifactoryConnectionInfo) Publish(buildSpec params.ProductBuildSpec, paths ProductPaths, stdout io.Writer) (rURL string, rErr error) { 38 artifactoryURL := strings.Join([]string{a.URL, "artifactory"}, "/") 39 baseURL := strings.Join([]string{artifactoryURL, a.Repository, paths.productPath}, "/") 40 41 artifactExists := func(fi fileInfo, dstFileName, username, password string) bool { 42 rawCheckArtifactURL := strings.Join([]string{artifactoryURL, "api", "storage", a.Repository, paths.productPath, dstFileName}, "/") 43 checkArtifactURL, err := url.Parse(rawCheckArtifactURL) 44 if err != nil { 45 return false 46 } 47 48 header := http.Header{} 49 req := http.Request{ 50 Method: http.MethodGet, 51 URL: checkArtifactURL, 52 Header: header, 53 } 54 req.SetBasicAuth(username, password) 55 56 if resp, err := http.DefaultClient.Do(&req); err == nil { 57 defer func() { 58 if err := resp.Body.Close(); err != nil && rErr == nil { 59 rErr = errors.Wrapf(err, "failed to close response body for URL %s", rawCheckArtifactURL) 60 } 61 }() 62 63 if bytes, err := ioutil.ReadAll(resp.Body); err == nil { 64 var jsonMap map[string]*json.RawMessage 65 if err := json.Unmarshal(bytes, &jsonMap); err == nil { 66 if checksumJSON, ok := jsonMap["checksums"]; ok && checksumJSON != nil { 67 var dstChecksums checksums 68 if err := json.Unmarshal(*checksumJSON, &dstChecksums); err == nil { 69 return fi.checksums.match(dstChecksums) 70 } 71 } 72 } 73 } 74 return false 75 } 76 return false 77 } 78 79 artifactURL, err := a.uploadArtifacts(baseURL, paths, artifactExists, stdout) 80 if err != nil { 81 return artifactURL, err 82 } 83 84 // compute SHA-256 checksums for artifacts 85 if err := computeArtifactChecksums(artifactoryURL, a.Repository, a.Username, a.Password, paths, stdout); err != nil { 86 // if triggering checksum computation fails, print message but don't throw error 87 fmt.Fprintln(stdout, "Uploading artifacts succeeded, but failed to trigger computation of SHA-256 checksums:", err) 88 } 89 return artifactURL, err 90 } 91 92 func computeArtifactChecksums(artifactoryURL, repoKey, username, password string, paths ProductPaths, stdout io.Writer) error { 93 artifactURL := strings.Join([]string{paths.productPath, path.Base(paths.artifactPath)}, "/") 94 if err := artifactorySetSHA256Checksum(artifactoryURL, repoKey, artifactURL, username, password, stdout); err != nil { 95 return errors.Wrapf(err, "") 96 } 97 pomPath := strings.Join([]string{paths.productPath, path.Base(paths.pomFilePath)}, "/") 98 if err := artifactorySetSHA256Checksum(artifactoryURL, repoKey, pomPath, username, password, stdout); err != nil { 99 return errors.Wrapf(err, "") 100 } 101 return nil 102 } 103 104 func artifactorySetSHA256Checksum(baseURLString, repoKey, filePath, username, password string, stdout io.Writer) (rErr error) { 105 apiURLString := baseURLString + "/api/checksum/sha256" 106 uploadURL, err := url.Parse(apiURLString) 107 if err != nil { 108 return errors.Wrapf(err, "failed to parse %v as URL", apiURLString) 109 } 110 111 jsonContent := fmt.Sprintf(`{"repoKey":"%v","path":"%v"}`, repoKey, filePath) 112 reader := strings.NewReader(jsonContent) 113 114 header := http.Header{} 115 header.Set("Content-Type", "application/json") 116 req := http.Request{ 117 Method: http.MethodPost, 118 URL: uploadURL, 119 Header: header, 120 Body: ioutil.NopCloser(reader), 121 ContentLength: int64(len([]byte(jsonContent))), 122 } 123 req.SetBasicAuth(username, password) 124 125 resp, err := http.DefaultClient.Do(&req) 126 if err != nil { 127 return errors.Wrapf(err, "failed to trigger computation of SHA-256 checksum for %v", filePath) 128 } 129 defer func() { 130 if err := resp.Body.Close(); err != nil && rErr == nil { 131 rErr = errors.Wrapf(err, "failed to close response body for URL %s", apiURLString) 132 } 133 }() 134 135 if resp.StatusCode >= http.StatusBadRequest { 136 return errors.Errorf("triggering computation of SHA-256 checksum for %v resulted in response: %v", filePath, resp.Status) 137 } 138 return nil 139 }