-
Notifications
You must be signed in to change notification settings - Fork 2
/
publish.go
165 lines (145 loc) · 4.28 KB
/
publish.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// This package is used to patch release of private repositories, pulling the assets that
// should be used by brew into this repo. It is used for `qlik-cli`.
// Run it with:
//
// go run publish.go
//
// and note that it requires two envorinment variables.
//
// GITHUB_TOKEN - a Personal Access Token with repo rights and possibly sso.
// REPO_API_URL - the URL used to access the repo from the Github API, should look something
// like this: https://api.github.com/repos/:org/:repo
//
// Also note, this program will be triggered by a CircleCI job (which will most likely be triggered
// remotely).
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"regexp"
"strings"
)
const path = "./bin/qlik-cli/"
var token string
var repo string
type Release struct {
AssetsURL string `json:"assets_url"`
Tag string `json:"tag_name"`
}
type Asset struct {
URL string `json:"url"`
Name string `json:"name"`
Tag string
}
// main retrieves releases from a repo, retrieves assets for those releases and downloads
// the assets for Mac and Linux and places them in this repo. Lastly it patches the formula
// to point towards these local files.
func main() {
token = os.Getenv("GITHUB_TOKEN")
if token == "" {
check(fmt.Errorf("GITHUB_TOKEN not set"))
}
repo = os.Getenv("REPO_API_URL")
if repo == "" {
check(fmt.Errorf("REPO_API_URL not set, should be 'https://api.github.com/repos/:org/:repo'"))
}
releasesURL := fmt.Sprintf("%s/releases", strings.TrimRight(repo, "/"))
fmt.Fprintf(os.Stderr, "Fetching releases from: %q\n", releasesURL)
req, err := http.NewRequest("GET", releasesURL, nil)
check(err)
req.Header.Set("Authorization", "token "+token)
body := call(req)
b, err := ioutil.ReadAll(body)
check(err)
body.Close()
releases := []*Release{}
check(json.Unmarshal(b, &releases))
for _, release := range releases {
fmt.Fprintf(os.Stderr, "Found release %s: ", release.Tag)
if !release.present() {
fmt.Fprintln(os.Stderr, "not present")
release.getAssets()
} else {
fmt.Fprintln(os.Stderr, "present")
}
}
patchFormula()
}
// patchFormula replaces the present download URLs with ones pointing to this repo.
// It also removes the 'homepage' field as it's erroneous in this case.
func patchFormula() {
fmt.Fprintln(os.Stderr, "Patching formula")
formula := "./Formula/qlik-cli.rb"
data, err := ioutil.ReadFile(formula)
re := regexp.MustCompile(`\s+homepage.+`)
data = re.ReplaceAll(data, []byte{})
check(err)
old := strings.Replace(repo, "api.", "", 1)
old = strings.Replace(old, "/repos", "", 1)
old += "/releases/download"
newURL := []byte("https://raw.githubusercontent.com/qlik-oss/homebrew-taps/master/bin/qlik-cli")
data = bytes.Replace(data, []byte(old), newURL, -1)
check(ioutil.WriteFile(formula, data, 0644))
}
func (r *Release) present() bool {
fi, err := os.Stat(path + r.Tag)
if err != nil {
return false
}
return fi.IsDir()
}
func (r *Release) getAssets() {
err := os.MkdirAll(path+r.Tag, 0755)
check(err)
fmt.Fprintf(os.Stderr, "Fetching the asset from: %s\n", r.AssetsURL)
req, err := http.NewRequest("GET", r.AssetsURL, nil)
check(err)
req.Header.Set("Authorization", "token "+token)
body := call(req)
b, err := ioutil.ReadAll(body)
defer body.Close()
check(err)
assets := []*Asset{}
check(json.Unmarshal(b, &assets))
for _, asset := range assets {
fmt.Fprintf(os.Stderr, "Found asset with name: %s, tag: %s, URL: %s\n", asset.Name, asset.Tag, asset.URL)
asset.Tag = r.Tag
if strings.Contains(asset.Name, "Darwin") || strings.Contains(asset.Name, "Linux") {
asset.download()
}
}
}
func (a *Asset) download() {
fmt.Fprintf(os.Stderr, "Downloading (%s) %s\n", a.Tag, a.Name)
req, err := http.NewRequest("GET", a.URL, nil)
check(err)
req.Header.Set("Authorization", "token "+token)
req.Header.Set("Accept", "application/octet-stream")
body := call(req)
file, err := os.Create(path + a.Tag + "/" + a.Name)
if err != nil {
check(err)
}
defer body.Close()
_, err = io.Copy(file, body)
check(err)
}
func call(req *http.Request) io.ReadCloser {
res, err := http.DefaultClient.Do(req)
check(err)
if res.StatusCode != http.StatusOK {
check(fmt.Errorf("Status: %s", res.Status))
}
return res.Body
}
func check(err error) {
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}