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