-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathmain.go
142 lines (120 loc) · 3.87 KB
/
main.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"flag"
"fmt"
"math/rand"
"os"
"path/filepath"
"sort"
"time"
"github.com/golang/glog"
"github.com/google/go-github/v58/github"
"golang.org/x/oauth2"
"github.com/wangyoucao577/assets-uploader/util"
"github.com/wangyoucao577/assets-uploader/util/appversion"
)
func main() {
flag.Parse()
appversion.PrintExit()
defer glog.Flush()
if err := flags.validate(); err != nil {
util.ErrExit(err)
}
repoOwner, repoName, err := util.ParseRepo(flags.repo)
if err != nil {
util.ErrExit(err)
}
retry := flags.retry
minDuration := 3
maxDuration := 15
for {
retry--
err = uploadAsset(repoOwner, repoName, flags.tag, flags.file, flags.mediaType, flags.token, flags.baseUrl, flags.overwrite)
if err != nil {
if retry == 0 {
util.ErrExit(err)
} else {
randomDuration := time.Duration(minDuration + rand.Intn(maxDuration-minDuration))
retryDuration := time.Second * randomDuration
glog.Warningf("Upload asset error, will retry in %s: %v\n", retryDuration.String(), err)
time.Sleep(retryDuration) // retry after 3-15 seconds
continue
}
}
break // break when succeed
}
}
func uploadAsset(repoOwner, repoName, tag, assetPath, mediaType, token string, baseUrl string, overwrite bool) error {
// read-write client
rwContext, cancel := context.WithCancel(context.Background())
defer cancel()
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
tc := oauth2.NewClient(rwContext, ts)
client := github.NewClient(tc)
if baseUrl != "" {
client, _ = client.WithEnterpriseURLs(baseUrl, baseUrl)
}
var release *github.RepositoryRelease
var err error
// get release by tag or name
if tag != "" {
release, _, err = client.Repositories.GetReleaseByTag(rwContext, repoOwner, repoName, tag)
} else if flags.releaseName != "" {
release, err = getReleaseByName(rwContext, client, repoOwner, repoName, flags.releaseName)
}
if err != nil {
return err
}
assetName := filepath.Base(assetPath)
if overwrite { // remove old one if it's exist already
var assets []*github.ReleaseAsset
assets, _, err = client.Repositories.ListReleaseAssets(rwContext, repoOwner, repoName, release.GetID(), &github.ListOptions{PerPage: 100})
if err != nil {
return err
}
for _, asset := range assets {
if asset.GetName() == assetName {
// found exist one, delete it
if _, err = client.Repositories.DeleteReleaseAsset(rwContext, repoOwner, repoName, asset.GetID()); err != nil {
return err
}
glog.Infof("Deleted old asset, id %d, name '%s', url '%s'\n", asset.GetID(), asset.GetName(), asset.GetBrowserDownloadURL())
break
}
}
}
// open file for uploading
f, err := os.Open(assetPath) // For read access.
if err != nil {
return err
}
defer f.Close()
// upload
releaseAsset, _, err := client.Repositories.UploadReleaseAsset(rwContext, repoOwner, repoName, release.GetID(), &github.UploadOptions{
Name: assetName,
Label: "",
MediaType: mediaType,
}, f)
if err != nil {
return err
}
glog.Infof("Upload asset succeed, id %d, name '%s', url: '%s'\n", releaseAsset.GetID(), releaseAsset.GetName(), releaseAsset.GetBrowserDownloadURL())
return nil
}
// getReleaseByName lists all releases, sort them by created-at and picks the first/newest one with the given name.
func getReleaseByName(ctx context.Context, client *github.Client, repoOwner, repoName, releaseName string) (*github.RepositoryRelease, error) {
releases, _, err := client.Repositories.ListReleases(ctx, repoOwner, repoName, nil)
if err != nil {
return nil, err
}
sort.SliceStable(releases, func(i, j int) bool {
return releases[i].CreatedAt.After(releases[j].CreatedAt.Time)
})
for _, release := range releases { // assume they are some kind of sorted, first pick (newest)
if release.GetName() == releaseName {
return release, nil
}
}
return nil, fmt.Errorf("no release found with name: %q", releaseName)
}