github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/apps/distgo/cmd/publish/bintray_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  	"fmt"
    19  	"io"
    20  	"io/ioutil"
    21  	"net/http"
    22  	"net/url"
    23  	"path"
    24  	"strings"
    25  
    26  	"github.com/pkg/errors"
    27  
    28  	"github.com/palantir/godel/apps/distgo/params"
    29  )
    30  
    31  type BintrayConnectionInfo struct {
    32  	BasicConnectionInfo
    33  	Subject       string
    34  	Repository    string
    35  	Release       bool
    36  	DownloadsList bool
    37  }
    38  
    39  func (b *BintrayConnectionInfo) Publish(buildSpec params.ProductBuildSpec, paths ProductPaths, stdout io.Writer) ([]string, error) {
    40  	baseURL := strings.Join([]string{b.URL, "content", b.Subject, b.Repository, buildSpec.ProductName, buildSpec.ProductVersion, paths.productPath}, "/")
    41  	artifactURLs, err := b.uploadArtifacts(baseURL, paths, nil, stdout)
    42  	if err != nil {
    43  		return artifactURLs, err
    44  	}
    45  	if b.Release {
    46  		if err := b.release(buildSpec, stdout); err != nil {
    47  			fmt.Fprintln(stdout, "Uploading artifacts succeeded, but publish of uploaded artifacts failed:", err)
    48  		}
    49  	}
    50  	if b.DownloadsList {
    51  		if err := b.addToDownloadsList(buildSpec, paths, stdout); err != nil {
    52  			fmt.Fprintln(stdout, "Uploading artifacts succeeded, but addings artifact to downloads list failed:", err)
    53  		}
    54  	}
    55  	return artifactURLs, err
    56  }
    57  
    58  func (b *BintrayConnectionInfo) release(buildSpec params.ProductBuildSpec, stdout io.Writer) error {
    59  	publishURLString := strings.Join([]string{b.URL, "content", b.Subject, b.Repository, buildSpec.ProductName, buildSpec.ProductVersion, "publish"}, "/")
    60  	return b.runBintrayCommand(publishURLString, http.MethodPost, `{"publish_wait_for_secs":-1}`, "running Bintray publish for uploaded artifacts", stdout)
    61  }
    62  
    63  func (b *BintrayConnectionInfo) addToDownloadsList(buildSpec params.ProductBuildSpec, paths ProductPaths, stdout io.Writer) error {
    64  	for _, currArtifactPath := range paths.artifactPaths {
    65  		downloadsListURLString := strings.Join([]string{b.URL, "file_metadata", b.Subject, b.Repository, paths.productPath, path.Base(currArtifactPath)}, "/")
    66  		if err := b.runBintrayCommand(downloadsListURLString, http.MethodPut, `{"list_in_downloads":true}`, "adding artifact to Bintray downloads list for package", stdout); err != nil {
    67  			return err
    68  		}
    69  	}
    70  	return nil
    71  }
    72  
    73  func (b *BintrayConnectionInfo) runBintrayCommand(urlString, httpMethod, jsonContent, cmdMsg string, stdout io.Writer) (rErr error) {
    74  	url, err := url.Parse(urlString)
    75  	if err != nil {
    76  		return errors.Wrapf(err, "failed to parse %v as URL", urlString)
    77  	}
    78  
    79  	capitalizedMsg := cmdMsg
    80  	if len(cmdMsg) > 0 {
    81  		capitalizedMsg = strings.ToUpper(string(cmdMsg[0])) + cmdMsg[1:]
    82  	}
    83  
    84  	fmt.Fprintf(stdout, "%s...", capitalizedMsg)
    85  	defer func() {
    86  		fmt.Fprintln(stdout)
    87  	}()
    88  
    89  	reader := strings.NewReader(jsonContent)
    90  
    91  	header := http.Header{}
    92  	header.Set("Content-Type", "application/json")
    93  	req := http.Request{
    94  		Method:        httpMethod,
    95  		URL:           url,
    96  		Header:        header,
    97  		Body:          ioutil.NopCloser(reader),
    98  		ContentLength: int64(len([]byte(jsonContent))),
    99  	}
   100  	req.SetBasicAuth(b.Username, b.Password)
   101  
   102  	resp, err := http.DefaultClient.Do(&req)
   103  	if err != nil {
   104  		return errors.Wrapf(err, "%s", cmdMsg)
   105  	}
   106  	defer func() {
   107  		if err := resp.Body.Close(); err != nil && rErr == nil {
   108  			rErr = errors.Wrapf(err, "failed to close response body for URL %s", urlString)
   109  		}
   110  	}()
   111  
   112  	if resp.StatusCode >= http.StatusBadRequest {
   113  		return errors.Errorf("%s resulted in response: %v", cmdMsg, resp.Status)
   114  	}
   115  
   116  	fmt.Fprint(stdout, "done")
   117  
   118  	return nil
   119  }