github.1git.de/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  }