1
0

main.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. //go:generate go run .
  2. package main
  3. import (
  4. "archive/zip"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "os"
  10. "path/filepath"
  11. "strings"
  12. "runtime"
  13. "github.com/spf13/afero"
  14. "github.com/spf13/afero/zipfs"
  15. "github.com/uozi-tech/cosy/logger"
  16. )
  17. // GitHubRelease represents the structure of GitHub's release API response
  18. type GitHubRelease struct {
  19. TagName string `json:"tag_name"`
  20. }
  21. const (
  22. githubAPIURL = "https://api.github.com/repos/go-acme/lego/releases/latest"
  23. configDir = "internal/cert/config"
  24. )
  25. func main() {
  26. logger.Init("release")
  27. _, file, _, ok := runtime.Caller(0)
  28. if !ok {
  29. logger.Error("Unable to get the current file")
  30. return
  31. }
  32. basePath := filepath.Join(filepath.Dir(file), "../../")
  33. // Get the latest release tag
  34. tag, err := getLatestReleaseTag()
  35. if err != nil {
  36. logger.Errorf("Error getting latest release tag: %v\n", err)
  37. os.Exit(1)
  38. }
  39. logger.Infof("Latest release tag: %s", tag)
  40. zipFile, err := downloadAndExtract(tag)
  41. if err != nil {
  42. logger.Errorf("Error downloading and extracting: %v\n", err)
  43. os.Exit(1)
  44. }
  45. if err := copyTomlFiles(zipFile, basePath, tag); err != nil {
  46. logger.Errorf("Error copying TOML files: %v\n", err)
  47. os.Exit(1)
  48. }
  49. logger.Info("Successfully updated provider config")
  50. }
  51. // getLatestReleaseTag fetches the latest release tag from GitHub API
  52. func getLatestReleaseTag() (string, error) {
  53. logger.Info("Fetching latest release tag...")
  54. req, err := http.NewRequest("GET", githubAPIURL, nil)
  55. if err != nil {
  56. return "", err
  57. }
  58. // Add User-Agent header to avoid GitHub API limitations
  59. req.Header.Set("User-Agent", "NGINX-UI-LegoConfigure")
  60. client := &http.Client{}
  61. resp, err := client.Do(req)
  62. if err != nil {
  63. return "", err
  64. }
  65. defer resp.Body.Close()
  66. if resp.StatusCode != http.StatusOK {
  67. return "", fmt.Errorf("bad status from GitHub API: %s", resp.Status)
  68. }
  69. var release GitHubRelease
  70. if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
  71. return "", err
  72. }
  73. if release.TagName == "" {
  74. return "", fmt.Errorf("no tag name found in the latest release")
  75. }
  76. return release.TagName, nil
  77. }
  78. // downloadAndExtract downloads the lego repository for a specific tag and extracts it
  79. func downloadAndExtract(tag string) (string, error) {
  80. downloadURL := fmt.Sprintf("https://github.com/go-acme/lego/archive/refs/tags/%s.zip", tag)
  81. // Download the file
  82. logger.Infof("Downloading lego repository for tag %s...", tag)
  83. resp, err := http.Get(downloadURL)
  84. if err != nil {
  85. return "", err
  86. }
  87. defer resp.Body.Close()
  88. if resp.StatusCode != http.StatusOK {
  89. return "", fmt.Errorf("bad status: %s", resp.Status)
  90. }
  91. // Create the file
  92. out, err := os.CreateTemp("", "lego-"+tag+".zip")
  93. if err != nil {
  94. return "", err
  95. }
  96. defer out.Close()
  97. // Write the body to file
  98. _, err = io.Copy(out, resp.Body)
  99. if err != nil {
  100. return "", err
  101. }
  102. return out.Name(), nil
  103. }
  104. func copyTomlFiles(zipFile, basePath, tag string) error {
  105. // Open the zip file
  106. logger.Info("Extracting files...")
  107. zipReader, err := zip.OpenReader(zipFile)
  108. if err != nil {
  109. return err
  110. }
  111. defer zipReader.Close()
  112. // Extract files
  113. tag = strings.TrimPrefix(tag, "v")
  114. zfs := zipfs.New(&zipReader.Reader)
  115. afero.Walk(zfs, "./lego-"+tag+"/providers", func(path string, info os.FileInfo, err error) error {
  116. if info == nil || info.IsDir() {
  117. return nil
  118. }
  119. if !strings.HasSuffix(info.Name(), ".toml") {
  120. return nil
  121. }
  122. if err != nil {
  123. return err
  124. }
  125. data, err := afero.ReadFile(zfs, path)
  126. if err != nil {
  127. return err
  128. }
  129. // Write to the destination file
  130. destPath := filepath.Join(basePath, configDir, info.Name())
  131. if err := os.WriteFile(destPath, data, 0644); err != nil {
  132. return err
  133. }
  134. logger.Infof("Copied: %s", info.Name())
  135. return nil
  136. })
  137. // Clean up zip file
  138. return os.Remove(zipFile)
  139. }