github.com/creativeprojects/go-selfupdate@v1.2.0/gitlab_source.go (about)

     1  package selfupdate
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/http"
     8  	"os"
     9  
    10  	"github.com/xanzy/go-gitlab"
    11  )
    12  
    13  // GitLabConfig is an object to pass to NewGitLabSource
    14  type GitLabConfig struct {
    15  	// APIToken represents GitLab API token. If it's not empty, it will be used for authentication for the API
    16  	APIToken string
    17  	// BaseURL is a base URL of your private GitLab instance
    18  	BaseURL string
    19  }
    20  
    21  // GitLabSource is used to load release information from GitLab
    22  type GitLabSource struct {
    23  	api     *gitlab.Client
    24  	token   string
    25  	baseURL string
    26  }
    27  
    28  // NewGitLabSource creates a new GitLabSource from a config object.
    29  // It initializes a GitLab API client.
    30  // If you set your API token to the $GITLAB_TOKEN environment variable, the client will use it.
    31  // You can pass an empty GitLabSource{} to use the default configuration
    32  // The function will return an error if the GitLab Enterprise URLs in the config object cannot be parsed
    33  func NewGitLabSource(config GitLabConfig) (*GitLabSource, error) {
    34  	token := config.APIToken
    35  	if token == "" {
    36  		// try the environment variable
    37  		token = os.Getenv("GITLAB_TOKEN")
    38  	}
    39  	option := make([]gitlab.ClientOptionFunc, 0, 1)
    40  	if config.BaseURL != "" {
    41  		option = append(option, gitlab.WithBaseURL(config.BaseURL))
    42  	}
    43  	client, err := gitlab.NewClient(token, option...)
    44  	if err != nil {
    45  		return nil, fmt.Errorf("cannot create GitLab client: %w", err)
    46  	}
    47  	return &GitLabSource{
    48  		api:     client,
    49  		token:   token,
    50  		baseURL: config.BaseURL,
    51  	}, nil
    52  }
    53  
    54  // ListReleases returns all available releases
    55  func (s *GitLabSource) ListReleases(ctx context.Context, repository Repository) ([]SourceRelease, error) {
    56  	pid, err := repository.Get()
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	rels, _, err := s.api.Releases.ListReleases(pid, nil, gitlab.WithContext(ctx))
    62  	if err != nil {
    63  		return nil, fmt.Errorf("list releases: %w", err)
    64  	}
    65  	releases := make([]SourceRelease, len(rels))
    66  	for i, rel := range rels {
    67  		releases[i] = NewGitLabRelease(rel)
    68  	}
    69  	return releases, nil
    70  }
    71  
    72  // DownloadReleaseAsset downloads an asset from a release.
    73  // It returns an io.ReadCloser: it is your responsibility to Close it.
    74  func (s *GitLabSource) DownloadReleaseAsset(ctx context.Context, rel *Release, assetID int64) (io.ReadCloser, error) {
    75  	if rel == nil {
    76  		return nil, ErrInvalidRelease
    77  	}
    78  	var downloadUrl string
    79  	if rel.AssetID == assetID {
    80  		downloadUrl = rel.AssetURL
    81  	} else if rel.ValidationAssetID == assetID {
    82  		downloadUrl = rel.ValidationAssetURL
    83  	}
    84  	if downloadUrl == "" {
    85  		return nil, fmt.Errorf("asset ID %d: %w", assetID, ErrAssetNotFound)
    86  	}
    87  
    88  	log.Printf("downloading %q", downloadUrl)
    89  	client := http.DefaultClient
    90  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, downloadUrl, http.NoBody)
    91  	if err != nil {
    92  		log.Print(err)
    93  		return nil, err
    94  	}
    95  
    96  	if s.token != "" {
    97  		// verify request is from same domain not to leak token
    98  		ok, err := canUseTokenForDomain(s.baseURL, downloadUrl)
    99  		if err != nil {
   100  			return nil, err
   101  		}
   102  		if ok {
   103  			req.Header.Set("PRIVATE-TOKEN", s.token)
   104  		}
   105  	}
   106  	response, err := client.Do(req)
   107  
   108  	if err != nil {
   109  		log.Print(err)
   110  		return nil, err
   111  	}
   112  
   113  	return response.Body, nil
   114  }
   115  
   116  // Verify interface
   117  var _ Source = &GitLabSource{}