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