github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/source/github/github.go (about) 1 package github 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "mime" 9 "net/http" 10 "os" 11 "path" 12 13 "github.com/google/go-github/github" 14 "golang.org/x/oauth2" 15 16 "github.com/kubri/kubri/source" 17 ) 18 19 type Config struct { 20 Owner string 21 Repo string 22 } 23 24 type githubSource struct { 25 client *github.Client 26 owner string 27 repo string 28 } 29 30 func New(c Config) (*source.Source, error) { 31 var client *http.Client 32 if token := os.Getenv("GITHUB_TOKEN"); token != "" { 33 ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}) 34 client = oauth2.NewClient(context.Background(), ts) 35 } 36 37 s := &githubSource{ 38 client: github.NewClient(client), 39 owner: c.Owner, 40 repo: c.Repo, 41 } 42 43 return source.New(s), nil 44 } 45 46 func (s *githubSource) ListReleases(ctx context.Context) ([]*source.Release, error) { 47 releases, _, err := s.client.Repositories.ListReleases(ctx, s.owner, s.repo, nil) 48 if err != nil { 49 return nil, err 50 } 51 52 r := make([]*source.Release, 0, len(releases)) 53 for _, release := range releases { 54 r = append(r, parseRelease(release)) 55 } 56 57 return r, nil 58 } 59 60 func (s *githubSource) GetRelease(ctx context.Context, version string) (*source.Release, error) { 61 r, _, err := s.client.Repositories.GetReleaseByTag(ctx, s.owner, s.repo, version) 62 if err != nil { 63 return nil, err 64 } 65 66 return parseRelease(r), nil 67 } 68 69 func parseRelease(release *github.RepositoryRelease) *source.Release { 70 r := &source.Release{ 71 Name: release.GetName(), 72 Description: release.GetBody(), 73 Version: release.GetTagName(), 74 Date: release.PublishedAt.Time, 75 Prerelease: release.GetPrerelease(), 76 Assets: make([]*source.Asset, 0, len(release.Assets)), 77 } 78 79 for _, asset := range release.Assets { 80 r.Assets = append(r.Assets, &source.Asset{ 81 Name: asset.GetName(), 82 URL: asset.GetBrowserDownloadURL(), 83 Size: asset.GetSize(), 84 }) 85 } 86 87 return r 88 } 89 90 func (s *githubSource) UploadAsset(ctx context.Context, version, name string, data []byte) error { 91 release, _, err := s.client.Repositories.GetReleaseByTag(ctx, s.owner, s.repo, version) 92 if err != nil { 93 return err 94 } 95 96 u := fmt.Sprintf("repos/%s/%s/releases/%d/assets?name=%s", s.owner, s.repo, release.GetID(), name) 97 mediaType := mime.TypeByExtension(path.Ext(name)) 98 req, err := s.client.NewUploadRequest(u, bytes.NewReader(data), int64(len(data)), mediaType) 99 if err != nil { 100 return err 101 } 102 103 _, err = s.client.Do(ctx, req, nil) 104 return err 105 } 106 107 func (s *githubSource) DownloadAsset(ctx context.Context, version, name string) ([]byte, error) { 108 release, _, err := s.client.Repositories.GetReleaseByTag(ctx, s.owner, s.repo, version) 109 if err != nil { 110 return nil, err 111 } 112 113 for _, asset := range release.Assets { 114 if asset.GetName() == name { 115 r, u, err := s.client.Repositories.DownloadReleaseAsset(ctx, s.owner, s.repo, asset.GetID()) 116 if err != nil { 117 return nil, err 118 } 119 if r != nil { 120 defer r.Close() 121 return io.ReadAll(r) 122 } 123 124 req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil) 125 if err != nil { 126 return nil, err 127 } 128 res, err := http.DefaultClient.Do(req) 129 if err != nil { 130 return nil, err 131 } 132 defer res.Body.Close() 133 return io.ReadAll(res.Body) 134 } 135 } 136 137 return nil, source.ErrAssetNotFound 138 }