publisher.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "strings"
  10. "time"
  11. )
  12. type publisher struct {
  13. apiKey string
  14. apiUri string
  15. product string
  16. dryRun bool
  17. enterprise bool
  18. baseArchiveUrl string
  19. builder releaseBuilder
  20. }
  21. type releaseBuilder interface {
  22. prepareRelease(baseArchiveUrl, whatsNewUrl string, releaseNotesUrl string, nightly bool) (*release, error)
  23. }
  24. func (p *publisher) doRelease(whatsNewUrl string, releaseNotesUrl string, nightly bool) error {
  25. currentRelease, err := p.builder.prepareRelease(p.baseArchiveUrl, whatsNewUrl, releaseNotesUrl, nightly)
  26. if err != nil {
  27. return err
  28. }
  29. if err := p.postRelease(currentRelease); err != nil {
  30. return err
  31. }
  32. return nil
  33. }
  34. func (p *publisher) postRelease(r *release) error {
  35. err := p.postRequest("/versions", r, fmt.Sprintf("Create Release %s", r.Version))
  36. if err != nil {
  37. return err
  38. }
  39. err = p.postRequest("/versions/"+r.Version, r, fmt.Sprintf("Update Release %s", r.Version))
  40. if err != nil {
  41. return err
  42. }
  43. for _, b := range r.Builds {
  44. err = p.postRequest(fmt.Sprintf("/versions/%s/packages", r.Version), b, fmt.Sprintf("Create Build %s %s", b.Os, b.Arch))
  45. if err != nil {
  46. return err
  47. }
  48. err = p.postRequest(fmt.Sprintf("/versions/%s/packages/%s/%s", r.Version, b.Arch, b.Os), b, fmt.Sprintf("Update Build %s %s", b.Os, b.Arch))
  49. if err != nil {
  50. return err
  51. }
  52. }
  53. return nil
  54. }
  55. type buildArtifact struct {
  56. os string
  57. arch string
  58. urlPostfix string
  59. }
  60. func (t buildArtifact) getUrl(baseArchiveUrl, version string, isBeta bool) string {
  61. prefix := "-"
  62. rhelReleaseExtra := ""
  63. if t.os == "deb" {
  64. prefix = "_"
  65. }
  66. if !isBeta && t.os == "rhel" {
  67. rhelReleaseExtra = "-1"
  68. }
  69. url := strings.Join([]string{baseArchiveUrl, prefix, version, rhelReleaseExtra, t.urlPostfix}, "")
  70. return url
  71. }
  72. var buildArtifactConfigurations = []buildArtifact{
  73. {
  74. os: "deb",
  75. arch: "arm64",
  76. urlPostfix: "_arm64.deb",
  77. },
  78. {
  79. os: "rhel",
  80. arch: "arm64",
  81. urlPostfix: ".aarch64.rpm",
  82. },
  83. {
  84. os: "linux",
  85. arch: "arm64",
  86. urlPostfix: ".linux-arm64.tar.gz",
  87. },
  88. {
  89. os: "deb",
  90. arch: "armv7",
  91. urlPostfix: "_armhf.deb",
  92. },
  93. {
  94. os: "rhel",
  95. arch: "armv7",
  96. urlPostfix: ".armhfp.rpm",
  97. },
  98. {
  99. os: "linux",
  100. arch: "armv7",
  101. urlPostfix: ".linux-armv7.tar.gz",
  102. },
  103. {
  104. os: "darwin",
  105. arch: "amd64",
  106. urlPostfix: ".darwin-amd64.tar.gz",
  107. },
  108. {
  109. os: "deb",
  110. arch: "amd64",
  111. urlPostfix: "_amd64.deb",
  112. },
  113. {
  114. os: "rhel",
  115. arch: "amd64",
  116. urlPostfix: ".x86_64.rpm",
  117. },
  118. {
  119. os: "linux",
  120. arch: "amd64",
  121. urlPostfix: ".linux-amd64.tar.gz",
  122. },
  123. {
  124. os: "win",
  125. arch: "amd64",
  126. urlPostfix: ".windows-amd64.zip",
  127. },
  128. }
  129. func newBuild(baseArchiveUrl string, ba buildArtifact, version string, isBeta bool, sha256 string) build {
  130. return build{
  131. Os: ba.os,
  132. Url: ba.getUrl(baseArchiveUrl, version, isBeta),
  133. Sha256: sha256,
  134. Arch: ba.arch,
  135. }
  136. }
  137. func (p *publisher) apiUrl(url string) string {
  138. return fmt.Sprintf("%s/%s%s", p.apiUri, p.product, url)
  139. }
  140. func (p *publisher) postRequest(url string, obj interface{}, desc string) error {
  141. jsonBytes, err := json.Marshal(obj)
  142. if err != nil {
  143. return err
  144. }
  145. if p.dryRun {
  146. log.Println(fmt.Sprintf("POST to %s:", p.apiUrl(url)))
  147. log.Println(string(jsonBytes))
  148. return nil
  149. }
  150. req, err := http.NewRequest(http.MethodPost, p.apiUrl(url), bytes.NewReader(jsonBytes))
  151. if err != nil {
  152. return err
  153. }
  154. req.Header.Add("Authorization", "Bearer "+p.apiKey)
  155. req.Header.Add("Content-Type", "application/json")
  156. res, err := http.DefaultClient.Do(req)
  157. if err != nil {
  158. return err
  159. }
  160. if res.StatusCode == http.StatusOK {
  161. log.Printf("Action: %s \t OK", desc)
  162. return nil
  163. }
  164. if res.Body != nil {
  165. defer res.Body.Close()
  166. body, err := ioutil.ReadAll(res.Body)
  167. if err != nil {
  168. return err
  169. }
  170. if strings.Contains(string(body), "already exists") || strings.Contains(string(body), "Nothing to update") {
  171. log.Printf("Action: %s \t Already exists", desc)
  172. } else {
  173. log.Printf("Action: %s \t Failed - Status: %v", desc, res.Status)
  174. log.Printf("Resp: %s", body)
  175. log.Fatalf("Quiting")
  176. }
  177. }
  178. return nil
  179. }
  180. type release struct {
  181. Version string `json:"version"`
  182. ReleaseDate time.Time `json:"releaseDate"`
  183. Stable bool `json:"stable"`
  184. Beta bool `json:"beta"`
  185. Nightly bool `json:"nightly"`
  186. WhatsNewUrl string `json:"whatsNewUrl"`
  187. ReleaseNotesUrl string `json:"releaseNotesUrl"`
  188. Builds []build `json:"-"`
  189. }
  190. type build struct {
  191. Os string `json:"os"`
  192. Url string `json:"url"`
  193. Sha256 string `json:"sha256"`
  194. Arch string `json:"arch"`
  195. }