github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/source/gitlab/gitlab.go (about)

     1  package gitlab
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"path"
    10  	"strconv"
    11  
    12  	"github.com/hashicorp/go-retryablehttp"
    13  	"github.com/xanzy/go-gitlab"
    14  
    15  	"github.com/kubri/kubri/source"
    16  )
    17  
    18  type Config struct {
    19  	Owner string
    20  	Repo  string
    21  	URL   string
    22  }
    23  
    24  type gitlabSource struct {
    25  	client *gitlab.Client
    26  	repo   string
    27  }
    28  
    29  func New(c Config) (*source.Source, error) {
    30  	var opt []gitlab.ClientOptionFunc
    31  	if c.URL != "" {
    32  		opt = append(opt, gitlab.WithBaseURL(c.URL))
    33  	}
    34  
    35  	client, err := gitlab.NewClient(os.Getenv("GITLAB_TOKEN"), opt...)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	s := &gitlabSource{
    41  		client: client,
    42  		repo:   c.Owner + "/" + c.Repo,
    43  	}
    44  
    45  	return source.New(s), nil
    46  }
    47  
    48  func (s *gitlabSource) ListReleases(ctx context.Context) ([]*source.Release, error) {
    49  	releases, _, err := s.client.Releases.ListReleases(s.repo, nil, gitlab.WithContext(ctx))
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	r := make([]*source.Release, 0, len(releases))
    55  	for _, release := range releases {
    56  		r = append(r, s.parseRelease(ctx, release))
    57  	}
    58  
    59  	return r, nil
    60  }
    61  
    62  func (s *gitlabSource) GetRelease(ctx context.Context, version string) (*source.Release, error) {
    63  	r, _, err := s.client.Releases.GetRelease(s.repo, version, gitlab.WithContext(ctx))
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	return s.parseRelease(ctx, r), nil
    69  }
    70  
    71  func (s *gitlabSource) parseRelease(ctx context.Context, release *gitlab.Release) *source.Release {
    72  	r := &source.Release{
    73  		Name:        release.Name,
    74  		Description: release.Description,
    75  		Version:     release.TagName,
    76  		Date:        *release.CreatedAt,
    77  		Assets:      make([]*source.Asset, 0, len(release.Assets.Links)),
    78  	}
    79  
    80  	for _, l := range release.Assets.Links {
    81  		size, err := s.getSize(ctx, l.URL)
    82  		if err != nil {
    83  			log.Printf("failed to get size for %s: %s\n", l.Name, err)
    84  		}
    85  
    86  		r.Assets = append(r.Assets, &source.Asset{
    87  			Name: l.Name,
    88  			URL:  l.URL,
    89  			Size: size,
    90  		})
    91  	}
    92  
    93  	return r
    94  }
    95  
    96  func (s *gitlabSource) UploadAsset(ctx context.Context, version, name string, data []byte) error {
    97  	file, _, err := s.client.Projects.UploadFile(s.repo, bytes.NewReader(data), name, gitlab.WithContext(ctx))
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	u := s.client.BaseURL()
   103  	u.Path = path.Join(s.repo, file.URL)
   104  	url := u.String()
   105  
   106  	opt := &gitlab.CreateReleaseLinkOptions{Name: &name, URL: &url}
   107  	_, _, err = s.client.ReleaseLinks.CreateReleaseLink(s.repo, version, opt, gitlab.WithContext(ctx))
   108  
   109  	return err
   110  }
   111  
   112  func (s *gitlabSource) DownloadAsset(ctx context.Context, version, name string) ([]byte, error) {
   113  	links, _, err := s.client.ReleaseLinks.ListReleaseLinks(s.repo, version, nil)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	for _, link := range links {
   119  		if link.Name == name {
   120  			req, err := retryablehttp.NewRequest(http.MethodGet, link.URL, nil)
   121  			if err != nil {
   122  				return nil, err
   123  			}
   124  
   125  			var buf bytes.Buffer
   126  			_, err = s.client.Do(req.WithContext(ctx), &buf)
   127  			if err != nil {
   128  				return nil, err
   129  			}
   130  
   131  			return buf.Bytes(), nil
   132  		}
   133  	}
   134  
   135  	return nil, source.ErrAssetNotFound
   136  }
   137  
   138  func (s *gitlabSource) getSize(ctx context.Context, url string) (int, error) {
   139  	req, err := retryablehttp.NewRequest(http.MethodHead, url, nil)
   140  	if err != nil {
   141  		return 0, err
   142  	}
   143  
   144  	r, err := s.client.Do(req.WithContext(ctx), nil)
   145  	if err != nil {
   146  		return 0, err
   147  	}
   148  
   149  	return strconv.Atoi(r.Header.Get("Content-Length"))
   150  }