/
upload_release_asset.go
148 lines (131 loc) · 4.66 KB
/
upload_release_asset.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
143
144
145
146
147
148
package githubutils
import (
"context"
"crypto/sha256"
"encoding/hex"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/avast/retry-go"
"github.com/google/go-github/github"
"github.com/wx-chevalier/go-utils/contextutils"
"github.com/wx-chevalier/go-utils/versionutils"
)
type ReleaseAssetSpec struct {
Name string
ParentPath string
UploadSHA bool
}
type UploadReleaseAssetSpec struct {
Owner string
Repo string
Assets []ReleaseAssetSpec
SkipAlreadyExists bool
}
func UploadReleaseAssetCli(spec *UploadReleaseAssetSpec) {
version := versionutils.GetReleaseVersionOrExitGracefully()
ctx := context.TODO()
client := GetClientOrExit(ctx)
release := GetReleaseOrExit(ctx, client, version, spec)
uploadReleaseAssetsOrExit(ctx, client, release, spec)
}
func uploadReleaseAssetsOrExit(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec) {
for _, assetSpec := range spec.Assets {
uploadReleaseAssetOrExit(ctx, client, release, spec, assetSpec)
}
}
func uploadReleaseAssetOrExit(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec, asset ReleaseAssetSpec) {
if spec.SkipAlreadyExists && assetAlreadyExists(release, asset.Name) {
return
}
path := filepath.Join(asset.ParentPath, asset.Name)
uploadFileOrExit(ctx, client, release, spec, asset.Name, path)
if asset.UploadSHA {
uploadShaOrExit(ctx, client, release, spec, asset)
}
}
func uploadShaOrExit(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec, asset ReleaseAssetSpec) {
path := filepath.Join(asset.ParentPath, asset.Name)
file, err := os.Open(path)
defer file.Close()
if err != nil {
log.Fatal(err)
}
shaName := asset.Name + ".sha256"
shaPath := filepath.Join(asset.ParentPath, shaName)
writeSha256OrExit(ctx, file, shaPath)
uploadFileOrExit(ctx, client, release, spec, shaName, shaPath)
}
func uploadFileOrExit(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec, name, path string) {
file, err := os.Open(path)
defer file.Close()
if err != nil {
contextutils.LoggerFrom(ctx).Fatalf("Error reading file %s: %s", path, err.Error())
}
// Using default retry settings for now, 10 attempts, 100ms delay with backoff
err = retry.Do(func() error {
return tryUploadAsset(ctx, client, release, spec, name, file)
})
if err != nil {
contextutils.LoggerFrom(ctx).Fatalf("Error uploading assets. Error was: %s", err.Error())
}
}
func tryUploadAsset(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec, name string, file *os.File) error {
opts := &github.UploadOptions{
Name: name,
}
_, _, err := client.Repositories.UploadReleaseAsset(ctx, spec.Owner, spec.Repo, release.GetID(), opts, file)
if err != nil {
loadedRelease, _, _ := client.Repositories.GetRelease(ctx, spec.Owner, spec.Repo, release.GetID())
if loadedRelease != nil {
tryDeleteAsset(ctx, client, loadedRelease, spec, name)
}
}
return err
}
func tryDeleteAsset(ctx context.Context, client *github.Client, release *github.RepositoryRelease, spec *UploadReleaseAssetSpec, name string) error {
for _, asset := range release.Assets {
if asset.GetName() == name {
_, err := client.Repositories.DeleteReleaseAsset(ctx, spec.Owner, spec.Repo, asset.GetID())
if err != nil {
return err
}
}
}
return nil
}
func writeSha256OrExit(ctx context.Context, file *os.File, outputPath string) {
h := sha256.New()
if _, err := io.Copy(h, file); err != nil {
contextutils.LoggerFrom(ctx).Fatal(err)
}
sha256String := hex.EncodeToString(h.Sum(nil)) + " " + filepath.Base(file.Name()) + "\n"
err := ioutil.WriteFile(outputPath, []byte(sha256String), 0700)
if err != nil {
contextutils.LoggerFrom(ctx).Fatal(err)
}
}
func assetAlreadyExists(release *github.RepositoryRelease, name string) bool {
for _, asset := range release.Assets {
if asset.GetName() == name {
return true
}
}
return false
}
func GetClientOrExit(ctx context.Context) *github.Client {
client, err := GetClient(ctx)
if err != nil {
contextutils.LoggerFrom(ctx).Fatalf("Could not get github client. Error was: %s", err.Error())
}
return client
}
func GetReleaseOrExit(ctx context.Context, client *github.Client, version *versionutils.Version, spec *UploadReleaseAssetSpec) *github.RepositoryRelease {
release, _, err := client.Repositories.GetReleaseByTag(ctx, spec.Owner, spec.Repo, version.String())
if err != nil {
contextutils.LoggerFrom(ctx).Fatalf("Could not find release %s. Error was: %s", version.String(), err.Error())
}
return release
}