Skip to content

Commit cd93390

Browse files
feat(upload): Point upload command at new endpoint (#2772)
* feat(upload): Point upload command at new endpoint * fix(config): Remove unused project field --------- Co-authored-by: Andrew Benton <andrew@sqlc.dev>
1 parent 48ddd19 commit cd93390

File tree

9 files changed

+360
-175
lines changed

9 files changed

+360
-175
lines changed

docs/howto/upload.md

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,26 @@
11
# Uploading projects
22

3-
*This feature requires signing up for [sqlc Cloud](https://app.sqlc.dev), which is currently in beta.*
3+
*Added in v1.22.0*
44

5-
Uploading your project ensures that future releases of sqlc do not break your
6-
existing code. Similar to Rust's [crater](https://github.com/rust-lang/crater)
7-
project, uploaded projects are tested against development releases of sqlc to
5+
Uploading an archive of your project ensures that future releases of sqlc do not
6+
break your code. Similar to Rust's [crater](https://github.com/rust-lang/crater)
7+
project, uploaded archives are tested against development releases of sqlc to
88
verify correctness.
99

10+
Interested in uploading projects? Sign up [here](https://docs.google.com/forms/d/e/1FAIpQLSdxoMzJ7rKkBpuez-KyBcPNyckYV-5iMR--FRB7WnhvAmEvKg/viewform) or send us an email
11+
at [hello@sqlc.dev](mailto:hello@sqlc.dev).
12+
1013
## Add configuration
1114

1215
After creating a project, add the project ID to your sqlc configuration file.
1316

1417
```yaml
15-
version: "1"
16-
project:
17-
id: "<PROJECT-ID>"
18-
packages: []
19-
```
20-
21-
```json
22-
{
23-
"version": "1",
24-
"project": {
25-
"id": "<PROJECT-ID>"
26-
},
27-
"packages": [
28-
]
29-
}
18+
version: "2"
19+
cloud:
20+
project: "<PROJECT-ID>"
3021
```
3122
32-
You'll also need to create an API token and make it available via the
23+
You'll also need to create an auth token and make it available via the
3324
`SQLC_AUTH_TOKEN` environment variable.
3425

3526
```shell
@@ -38,13 +29,14 @@ export SQLC_AUTH_TOKEN=sqlc_xxxxxxxx
3829

3930
## Dry run
4031

41-
You can see what's included when uploading your project by using using the `--dry-run` flag:
32+
You can see what's included when uploading your project by using using the
33+
`--dry-run` flag:
4234

4335
```shell
4436
sqlc upload --dry-run
4537
```
4638

47-
The output will be the exact HTTP request sent by `sqlc`.
39+
The output is the request `sqlc` would have sent without the `--dry-run` flag.
4840

4941
## Upload
5042

@@ -54,4 +46,4 @@ Once you're ready to upload, remove the `--dry-run` flag.
5446
sqlc upload
5547
```
5648

57-
By uploading your project, you're making sqlc more stable and reliable. Thanks!
49+
By uploading your project, you're making sqlc more stable and reliable. Thanks!

internal/bundler/metadata.go

Lines changed: 0 additions & 16 deletions
This file was deleted.

internal/bundler/multipart.go

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,55 @@
11
package bundler
22

33
import (
4-
"io"
5-
"mime/multipart"
64
"os"
75
"path/filepath"
86

97
"github.com/sqlc-dev/sqlc/internal/config"
8+
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
109
"github.com/sqlc-dev/sqlc/internal/sql/sqlpath"
1110
)
1211

13-
func writeInputs(w *multipart.Writer, file string, conf *config.Config) error {
12+
func readInputs(file string, conf *config.Config) ([]*pb.File, error) {
1413
refs := map[string]struct{}{}
1514
refs[filepath.Base(file)] = struct{}{}
1615

1716
for _, pkg := range conf.SQL {
1817
for _, paths := range []config.Paths{pkg.Schema, pkg.Queries} {
1918
files, err := sqlpath.Glob(paths)
2019
if err != nil {
21-
return err
20+
return nil, err
2221
}
2322
for _, file := range files {
2423
refs[file] = struct{}{}
2524
}
2625
}
2726
}
2827

28+
var files []*pb.File
2929
for file, _ := range refs {
30-
if err := addPart(w, file); err != nil {
31-
return err
32-
}
33-
}
34-
35-
params, err := projectMetadata()
36-
if err != nil {
37-
return err
38-
}
39-
params = append(params, [2]string{"project_id", conf.Project.ID})
40-
for _, val := range params {
41-
if err = w.WriteField(val[0], val[1]); err != nil {
42-
return err
30+
contents, err := os.ReadFile(file)
31+
if err != nil {
32+
return nil, err
4333
}
34+
files = append(files, &pb.File{
35+
Name: file,
36+
Contents: contents,
37+
})
4438
}
45-
return nil
39+
return files, nil
4640
}
4741

48-
func addPart(w *multipart.Writer, file string) error {
49-
h, err := os.Open(file)
50-
if err != nil {
51-
return err
52-
}
53-
defer h.Close()
54-
part, err := w.CreateFormFile("inputs", file)
55-
if err != nil {
56-
return err
57-
}
58-
_, err = io.Copy(part, h)
59-
if err != nil {
60-
return err
61-
}
62-
return nil
63-
}
64-
65-
func writeOutputs(w *multipart.Writer, dir string, output map[string]string) error {
42+
func readOutputs(dir string, output map[string]string) ([]*pb.File, error) {
43+
var files []*pb.File
6644
for filename, contents := range output {
6745
rel, err := filepath.Rel(dir, filename)
6846
if err != nil {
69-
return err
70-
}
71-
part, err := w.CreateFormFile("outputs", rel)
72-
if err != nil {
73-
return err
74-
}
75-
if _, err := io.WriteString(part, contents); err != nil {
76-
return err
47+
return nil, err
7748
}
49+
files = append(files, &pb.File{
50+
Name: rel,
51+
Contents: []byte(contents),
52+
})
7853
}
79-
return nil
54+
return files, nil
8055
}

internal/bundler/upload.go

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
11
package bundler
22

33
import (
4-
"bytes"
54
"context"
65
"fmt"
7-
"io"
8-
"mime/multipart"
9-
"net/http"
10-
"net/http/httputil"
116
"os"
127

8+
"google.golang.org/protobuf/encoding/protojson"
9+
1310
"github.com/sqlc-dev/sqlc/internal/config"
11+
"github.com/sqlc-dev/sqlc/internal/info"
12+
"github.com/sqlc-dev/sqlc/internal/quickdb"
13+
pb "github.com/sqlc-dev/sqlc/internal/quickdb/v1"
1414
)
1515

1616
type Uploader struct {
1717
token string
1818
configPath string
1919
config *config.Config
2020
dir string
21+
client pb.QuickClient
2122
}
2223

2324
func NewUploader(configPath, dir string, conf *config.Config) *Uploader {
@@ -30,47 +31,44 @@ func NewUploader(configPath, dir string, conf *config.Config) *Uploader {
3031
}
3132

3233
func (up *Uploader) Validate() error {
33-
if up.config.Project.ID == "" {
34-
return fmt.Errorf("project.id is not set")
34+
if up.config.Cloud.Project == "" {
35+
return fmt.Errorf("cloud.project is not set")
3536
}
3637
if up.token == "" {
3738
return fmt.Errorf("SQLC_AUTH_TOKEN environment variable is not set")
3839
}
40+
if up.client == nil {
41+
client, err := quickdb.NewClientFromConfig(up.config.Cloud)
42+
if err != nil {
43+
return fmt.Errorf("client init failed: %w", err)
44+
}
45+
up.client = client
46+
}
3947
return nil
4048
}
4149

42-
func (up *Uploader) buildRequest(ctx context.Context, result map[string]string) (*http.Request, error) {
43-
body := bytes.NewBuffer([]byte{})
44-
w := multipart.NewWriter(body)
45-
if err := writeInputs(w, up.configPath, up.config); err != nil {
46-
return nil, err
47-
}
48-
if err := writeOutputs(w, up.dir, result); err != nil {
49-
return nil, err
50-
}
51-
if err := w.Close(); err != nil {
50+
func (up *Uploader) buildRequest(ctx context.Context, result map[string]string) (*pb.UploadArchiveRequest, error) {
51+
ins, err := readInputs(up.configPath, up.config)
52+
if err != nil {
5253
return nil, err
5354
}
54-
req, err := http.NewRequest("POST", "https://api.sqlc.dev/upload", body)
55+
outs, err := readOutputs(up.dir, result)
5556
if err != nil {
5657
return nil, err
5758
}
58-
// Set sqlc-version header
59-
req.Header.Set("Content-Type", w.FormDataContentType())
60-
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", up.token))
61-
return req.WithContext(ctx), nil
59+
return &pb.UploadArchiveRequest{
60+
SqlcVersion: info.Version,
61+
Inputs: ins,
62+
Outputs: outs,
63+
}, nil
6264
}
6365

6466
func (up *Uploader) DumpRequestOut(ctx context.Context, result map[string]string) error {
6567
req, err := up.buildRequest(ctx, result)
6668
if err != nil {
6769
return err
6870
}
69-
dump, err := httputil.DumpRequest(req, true)
70-
if err != nil {
71-
return err
72-
}
73-
os.Stdout.Write(dump)
71+
fmt.Println(protojson.Format(req))
7472
return nil
7573
}
7674

@@ -82,18 +80,8 @@ func (up *Uploader) Upload(ctx context.Context, result map[string]string) error
8280
if err != nil {
8381
return err
8482
}
85-
client := &http.Client{}
86-
resp, err := client.Do(req)
87-
if err != nil {
88-
return err
89-
}
90-
if resp.StatusCode >= 400 {
91-
body, err := io.ReadAll(resp.Body)
92-
defer resp.Body.Close()
93-
if err != nil {
94-
return fmt.Errorf("upload error: endpoint returned non-200 status code: %d", resp.StatusCode)
95-
}
96-
return fmt.Errorf("upload error: %d: %s", resp.StatusCode, string(body))
83+
if _, err := up.client.UploadArchive(ctx, req); err != nil {
84+
return fmt.Errorf("upload error: %w", err)
9785
}
9886
return nil
9987
}

internal/config/config.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,13 @@ const (
5656

5757
type Config struct {
5858
Version string `json:"version" yaml:"version"`
59-
Project Project `json:"project" yaml:"project"`
6059
Cloud Cloud `json:"cloud" yaml:"cloud"`
6160
SQL []SQL `json:"sql" yaml:"sql"`
6261
Gen Gen `json:"overrides,omitempty" yaml:"overrides"`
6362
Plugins []Plugin `json:"plugins" yaml:"plugins"`
6463
Rules []Rule `json:"rules" yaml:"rules"`
6564
}
6665

67-
type Project struct {
68-
ID string `json:"id" yaml:"id"`
69-
}
70-
7166
type Database struct {
7267
URI string `json:"uri" yaml:"uri"`
7368
Managed bool `json:"managed" yaml:"managed"`

internal/config/v_one.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
type V1GenerateSettings struct {
1212
Version string `json:"version" yaml:"version"`
1313
Cloud Cloud `json:"cloud" yaml:"cloud"`
14-
Project Project `json:"project" yaml:"project"`
1514
Packages []v1PackageSettings `json:"packages" yaml:"packages"`
1615
Overrides []Override `json:"overrides,omitempty" yaml:"overrides,omitempty"`
1716
Rename map[string]string `json:"rename,omitempty" yaml:"rename,omitempty"`
@@ -132,7 +131,6 @@ func (c *V1GenerateSettings) ValidateGlobalOverrides() error {
132131
func (c *V1GenerateSettings) Translate() Config {
133132
conf := Config{
134133
Version: c.Version,
135-
Project: c.Project,
136134
Cloud: c.Cloud,
137135
Rules: c.Rules,
138136
}

internal/config/v_one.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@
88
"version": {
99
"const": "1"
1010
},
11-
"project": {
12-
"type": "object",
13-
"properties": {
14-
"id": {
15-
"type": "string"
16-
}
17-
}
18-
},
1911
"cloud": {
2012
"type": "object",
2113
"properties": {

internal/config/v_two.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@
88
"version": {
99
"const": "2"
1010
},
11-
"project": {
12-
"type": "object",
13-
"properties": {
14-
"id": {
15-
"type": "string"
16-
}
17-
}
18-
},
1911
"cloud": {
2012
"type": "object",
2113
"properties": {

0 commit comments

Comments
 (0)