upload.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package bundler
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "os"
  8. "strings"
  9. "google.golang.org/protobuf/proto"
  10. "github.com/sqlc-dev/sqlc/internal/config"
  11. "github.com/sqlc-dev/sqlc/internal/info"
  12. "github.com/sqlc-dev/sqlc/internal/plugin"
  13. "github.com/sqlc-dev/sqlc/internal/quickdb"
  14. pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
  15. )
  16. var ErrNoProject = errors.New(`project uploads require a cloud project
  17. If you don't have a project, you can create one from the sqlc Cloud
  18. dashboard at https://dashboard.sqlc.dev/. If you have a project, ensure
  19. you've set its id as the value of the "project" field within the "cloud"
  20. section of your sqlc configuration. The id will look similar to
  21. "01HA8TWGMYPHK0V2GGMB3R2TP9".`)
  22. var ErrNoAuthToken = errors.New(`project uploads require an auth token
  23. If you don't have an auth token, you can create one from the sqlc Cloud
  24. dashboard at https://dashboard.sqlc.dev/. If you have an auth token, ensure
  25. you've set it as the value of the SQLC_AUTH_TOKEN environment variable.`)
  26. type Uploader struct {
  27. configPath string
  28. config *config.Config
  29. dir string
  30. client pb.QuickClient
  31. }
  32. type QuerySetArchive struct {
  33. Name string
  34. Queries []string
  35. Schema []string
  36. Request *plugin.GenerateRequest
  37. }
  38. func NewUploader(configPath, dir string, conf *config.Config) *Uploader {
  39. return &Uploader{
  40. configPath: configPath,
  41. config: conf,
  42. dir: dir,
  43. }
  44. }
  45. func (up *Uploader) Validate() error {
  46. if up.config.Cloud.Project == "" {
  47. return ErrNoProject
  48. }
  49. if up.config.Cloud.AuthToken == "" {
  50. return ErrNoAuthToken
  51. }
  52. if up.client == nil {
  53. client, err := quickdb.NewClientFromConfig(up.config.Cloud)
  54. if err != nil {
  55. return fmt.Errorf("client init failed: %w", err)
  56. }
  57. up.client = client
  58. }
  59. return nil
  60. }
  61. var envvars = []string{
  62. "GITHUB_REPOSITORY",
  63. "GITHUB_REF",
  64. "GITHUB_REF_NAME",
  65. "GITHUB_REF_TYPE",
  66. "GITHUB_SHA",
  67. }
  68. func annotate() map[string]string {
  69. labels := map[string]string{}
  70. for _, ev := range envvars {
  71. key := strings.ReplaceAll(strings.ToLower(ev), "_", ".")
  72. labels[key] = os.Getenv(ev)
  73. }
  74. return labels
  75. }
  76. func BuildRequest(ctx context.Context, dir, configPath string, results []*QuerySetArchive, tags []string) (*pb.UploadArchiveRequest, error) {
  77. conf, err := readFile(dir, configPath)
  78. if err != nil {
  79. return nil, err
  80. }
  81. res := &pb.UploadArchiveRequest{
  82. SqlcVersion: info.Version,
  83. Config: conf,
  84. Tags: tags,
  85. Annotations: annotate(),
  86. }
  87. for i, result := range results {
  88. schema, err := readFiles(dir, result.Schema)
  89. if err != nil {
  90. return nil, err
  91. }
  92. queries, err := readFiles(dir, result.Queries)
  93. if err != nil {
  94. return nil, err
  95. }
  96. name := result.Name
  97. if name == "" {
  98. name = fmt.Sprintf("queryset_%d", i)
  99. }
  100. genreq, err := proto.Marshal(result.Request)
  101. if err != nil {
  102. return nil, err
  103. }
  104. res.QuerySets = append(res.QuerySets, &pb.QuerySet{
  105. Name: name,
  106. Schema: schema,
  107. Queries: queries,
  108. CodegenRequest: &pb.File{
  109. Name: "codegen_request.pb",
  110. Contents: genreq,
  111. },
  112. })
  113. }
  114. return res, nil
  115. }
  116. func (up *Uploader) buildRequest(ctx context.Context, results []*QuerySetArchive, tags []string) (*pb.UploadArchiveRequest, error) {
  117. return BuildRequest(ctx, up.dir, up.configPath, results, tags)
  118. }
  119. func (up *Uploader) DumpRequestOut(ctx context.Context, result []*QuerySetArchive) error {
  120. req, err := up.buildRequest(ctx, result, []string{})
  121. if err != nil {
  122. return err
  123. }
  124. slog.Info("config", "file", req.Config.Name, "bytes", len(req.Config.Contents))
  125. for _, qs := range req.QuerySets {
  126. slog.Info("codegen_request", "queryset", qs.Name, "file", "codegen_request.pb")
  127. for _, file := range qs.Schema {
  128. slog.Info("schema", "queryset", qs.Name, "file", file.Name, "bytes", len(file.Contents))
  129. }
  130. for _, file := range qs.Queries {
  131. slog.Info("query", "queryset", qs.Name, "file", file.Name, "bytes", len(file.Contents))
  132. }
  133. }
  134. return nil
  135. }
  136. func (up *Uploader) Upload(ctx context.Context, result []*QuerySetArchive, tags []string) error {
  137. if err := up.Validate(); err != nil {
  138. return err
  139. }
  140. req, err := up.buildRequest(ctx, result, tags)
  141. if err != nil {
  142. return err
  143. }
  144. if _, err := up.client.UploadArchive(ctx, req); err != nil {
  145. return fmt.Errorf("upload error: %w", err)
  146. }
  147. return nil
  148. }