github.phpd.cn/goreleaser/goreleaser@v0.92.0/internal/pipe/artifactory/artifactory.go (about) 1 // Package artifactory provides a Pipe that push to artifactory 2 package artifactory 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 h "net/http" 9 10 "github.com/goreleaser/goreleaser/internal/http" 11 "github.com/goreleaser/goreleaser/internal/pipe" 12 "github.com/goreleaser/goreleaser/pkg/context" 13 ) 14 15 // artifactoryResponse reflects the response after an upload request 16 // to Artifactory. 17 type artifactoryResponse struct { 18 Repo string `json:"repo,omitempty"` 19 Path string `json:"path,omitempty"` 20 Created string `json:"created,omitempty"` 21 CreatedBy string `json:"createdBy,omitempty"` 22 DownloadURI string `json:"downloadUri,omitempty"` 23 MimeType string `json:"mimeType,omitempty"` 24 Size string `json:"size,omitempty"` 25 Checksums artifactoryChecksums `json:"checksums,omitempty"` 26 OriginalChecksums artifactoryChecksums `json:"originalChecksums,omitempty"` 27 URI string `json:"uri,omitempty"` 28 } 29 30 // artifactoryChecksums reflects the checksums generated by 31 // Artifactory 32 type artifactoryChecksums struct { 33 SHA1 string `json:"sha1,omitempty"` 34 MD5 string `json:"md5,omitempty"` 35 SHA256 string `json:"sha256,omitempty"` 36 } 37 38 // Pipe for Artifactory 39 type Pipe struct{} 40 41 // String returns the description of the pipe 42 func (Pipe) String() string { 43 return "releasing to Artifactory" 44 } 45 46 // Default sets the pipe defaults 47 func (Pipe) Default(ctx *context.Context) error { 48 for i := range ctx.Config.Artifactories { 49 ctx.Config.Artifactories[i].ChecksumHeader = "X-Checksum-SHA256" 50 } 51 return http.Defaults(ctx.Config.Artifactories) 52 } 53 54 // Publish artifacts to artifactory 55 // 56 // Docs: https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-Example-DeployinganArtifact 57 func (Pipe) Publish(ctx *context.Context) error { 58 if len(ctx.Config.Artifactories) == 0 { 59 return pipe.Skip("artifactory section is not configured") 60 } 61 62 // Check requirements for every instance we have configured. 63 // If not fulfilled, we can skip this pipeline 64 for _, instance := range ctx.Config.Artifactories { 65 if skip := http.CheckConfig(ctx, &instance, "artifactory"); skip != nil { 66 return pipe.Skip(skip.Error()) 67 } 68 } 69 70 return http.Upload(ctx, ctx.Config.Artifactories, "artifactory", func(res *h.Response) error { 71 if err := checkResponse(res); err != nil { 72 return err 73 } 74 var r artifactoryResponse 75 err := json.NewDecoder(res.Body).Decode(&r) 76 return err 77 }) 78 79 } 80 81 // An ErrorResponse reports one or more errors caused by an API request. 82 type errorResponse struct { 83 Response *h.Response // HTTP response that caused this error 84 Errors []Error `json:"errors"` // more detail on individual errors 85 } 86 87 func (r *errorResponse) Error() string { 88 return fmt.Sprintf("%v %v: %d %+v", 89 r.Response.Request.Method, r.Response.Request.URL, 90 r.Response.StatusCode, r.Errors) 91 } 92 93 // An Error reports more details on an individual error in an ErrorResponse. 94 type Error struct { 95 Status int `json:"status"` // Error code 96 Message string `json:"message"` // Message describing the error. 97 } 98 99 // checkResponse checks the API response for errors, and returns them if 100 // present. A response is considered an error if it has a status code outside 101 // the 200 range. 102 // API error responses are expected to have either no response 103 // body, or a JSON response body that maps to ErrorResponse. Any other 104 // response body will be silently ignored. 105 func checkResponse(r *h.Response) error { 106 if c := r.StatusCode; 200 <= c && c <= 299 { 107 return nil 108 } 109 errorResponse := &errorResponse{Response: r} 110 data, err := ioutil.ReadAll(r.Body) 111 if err == nil && data != nil { 112 err := json.Unmarshal(data, errorResponse) 113 if err != nil { 114 return err 115 } 116 } 117 return errorResponse 118 }