github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/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) (rURLs []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 artifactURLs, err := a.uploadArtifacts(baseURL, paths, artifactExists, stdout) 80 if err != nil { 81 return artifactURLs, 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 artifactURLs, err 90 } 91 92 func computeArtifactChecksums(artifactoryURL, repoKey, username, password string, paths ProductPaths, stdout io.Writer) error { 93 for _, currArtifactPath := range paths.artifactPaths { 94 currArtifactURL := strings.Join([]string{paths.productPath, path.Base(currArtifactPath)}, "/") 95 if err := artifactorySetSHA256Checksum(artifactoryURL, repoKey, currArtifactURL, username, password, stdout); err != nil { 96 return errors.Wrapf(err, "") 97 } 98 } 99 pomPath := strings.Join([]string{paths.productPath, path.Base(paths.pomFilePath)}, "/") 100 if err := artifactorySetSHA256Checksum(artifactoryURL, repoKey, pomPath, username, password, stdout); err != nil { 101 return errors.Wrapf(err, "") 102 } 103 return nil 104 } 105 106 func artifactorySetSHA256Checksum(baseURLString, repoKey, filePath, username, password string, stdout io.Writer) (rErr error) { 107 apiURLString := baseURLString + "/api/checksum/sha256" 108 uploadURL, err := url.Parse(apiURLString) 109 if err != nil { 110 return errors.Wrapf(err, "failed to parse %v as URL", apiURLString) 111 } 112 113 jsonContent := fmt.Sprintf(`{"repoKey":"%v","path":"%v"}`, repoKey, filePath) 114 reader := strings.NewReader(jsonContent) 115 116 header := http.Header{} 117 header.Set("Content-Type", "application/json") 118 req := http.Request{ 119 Method: http.MethodPost, 120 URL: uploadURL, 121 Header: header, 122 Body: ioutil.NopCloser(reader), 123 ContentLength: int64(len([]byte(jsonContent))), 124 } 125 req.SetBasicAuth(username, password) 126 127 resp, err := http.DefaultClient.Do(&req) 128 if err != nil { 129 return errors.Wrapf(err, "failed to trigger computation of SHA-256 checksum for %v", filePath) 130 } 131 defer func() { 132 if err := resp.Body.Close(); err != nil && rErr == nil { 133 rErr = errors.Wrapf(err, "failed to close response body for URL %s", apiURLString) 134 } 135 }() 136 137 if resp.StatusCode >= http.StatusBadRequest { 138 return errors.Errorf("triggering computation of SHA-256 checksum for %v resulted in response: %v", filePath, resp.Status) 139 } 140 return nil 141 }