code: func uploadAsset(ctx *context.Context, put *config.Put, artifact artifact.Artifact, kind string, check ResponseChecker) error {
  	envBase := fmt.Sprintf("%s_%s_", strings.ToUpper(kind), strings.ToUpper(put.Name))
  	username := put.Username
  	if username == "" {
  		// username not configured: using env
  		username = ctx.Env[envBase+"USERNAME"]
  	}
  	secret := ctx.Env[envBase+"SECRET"]
  
  	// Generate the target url
  	targetURL, err := resolveTargetTemplate(ctx, put, artifact)
  	if err != nil {
  		msg := fmt.Sprintf("%s: error while building the target url", kind)
  		log.WithField("instance", put.Name).WithError(err).Error(msg)
  		return errors.Wrap(err, msg)
  	}
  
  	// Handle the artifact
  	asset, err := assetOpen(kind, &artifact)
  	if err != nil {
  		return err
  	}
  	defer asset.ReadCloser.Close() // nolint: errcheck
  
  	// The target url needs to contain the artifact name
  	if !strings.HasSuffix(targetURL, "/") {
  		targetURL += "/"
  	}
  	targetURL += artifact.Name
  
  	var headers = map[string]string{}
  	if put.ChecksumHeader != "" {
  		sum, err := artifact.Checksum("sha256")
  		if err != nil {
  			return err
  		}
  		headers[put.ChecksumHeader] = sum
  	}
  
  	_, err = uploadAssetToServer(ctx, put, targetURL, username, secret, headers, asset, check)
  	if err != nil {
  		msg := fmt.Sprintf("%s: upload failed", kind)
  		log.WithError(err).WithFields(log.Fields{
  			"instance": put.Name,
  			"username": username,
  		}).Error(msg)
  		return errors.Wrap(err, msg)
  	}
  
  	log.WithFields(log.Fields{
  		"instance": put.Name,
  		"mode":     put.Mode,
  	}).Info("uploaded successful")
  
  	return nil
  }
docs: // uploadAsset uploads file to target and logs all actions