Skip to content

Commit 6fd5b1f

Browse files
committed
feat(lib.Datasets.Save): add force flag to skip empty-commit checking
1 parent 1d9aa57 commit 6fd5b1f

File tree

14 files changed

+74
-37
lines changed

14 files changed

+74
-37
lines changed

actions/actions_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"testing"
99

1010
"github.com/libp2p/go-libp2p-crypto"
11-
"github.com/qri-io/qfs/cafs"
1211
"github.com/qri-io/dataset/dstest"
1312
"github.com/qri-io/qfs"
13+
"github.com/qri-io/qfs/cafs"
1414
"github.com/qri-io/qfs/httpfs"
1515
"github.com/qri-io/qfs/localfs"
1616
"github.com/qri-io/qfs/muxfs"
@@ -116,7 +116,7 @@ func addCitiesDataset(t *testing.T, node *p2p.QriNode) repo.DatasetRef {
116116
t.Fatal(err.Error())
117117
}
118118

119-
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false)
119+
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false, false)
120120
if err != nil {
121121
t.Fatal(err.Error())
122122
}
@@ -129,7 +129,7 @@ func addFlourinatedCompoundsDataset(t *testing.T, node *p2p.QriNode) repo.Datase
129129
t.Fatal(err.Error())
130130
}
131131

132-
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false)
132+
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false, false)
133133
if err != nil {
134134
t.Fatal(err.Error())
135135
}
@@ -145,7 +145,7 @@ func addNowTransformDataset(t *testing.T, node *p2p.QriNode) repo.DatasetRef {
145145
// this was put here to satisfy qri-io/qri/actions.TestUpdateDatasetLocal
146146
tc.Input.Peername = "peer"
147147

148-
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false)
148+
ref, err := SaveDataset(node, tc.Input, nil, nil, false, true, false, false)
149149
if err != nil {
150150
t.Fatal(err.Error())
151151
}

actions/dataset.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
)
1616

1717
// SaveDataset initializes a dataset from a dataset pointer and data file
18-
func SaveDataset(node *p2p.QriNode, changes *dataset.Dataset, secrets map[string]string, scriptOut io.Writer, dryRun, pin, convertFormatToPrev bool) (ref repo.DatasetRef, err error) {
18+
func SaveDataset(node *p2p.QriNode, changes *dataset.Dataset, secrets map[string]string, scriptOut io.Writer, dryRun, pin, convertFormatToPrev, force bool) (ref repo.DatasetRef, err error) {
1919
var (
2020
prevPath string
2121
pro *profile.Profile
@@ -87,7 +87,7 @@ func SaveDataset(node *p2p.QriNode, changes *dataset.Dataset, secrets map[string
8787
// let's make history, if it exists:
8888
changes.PreviousPath = prevPath
8989

90-
return base.CreateDataset(r, node.LocalStreams, changes, prev, dryRun, pin)
90+
return base.CreateDataset(r, node.LocalStreams, changes, prev, dryRun, pin, force)
9191
}
9292

9393
// UpdateRemoteDataset brings a reference to the latest version, syncing to the

actions/dataset_test.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func TestUpdateRemoteDataset(t *testing.T) {
5252
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
5353

5454
// run a local update to advance history
55-
now0, err := SaveDataset(peers[0], ds, nil, nil, false, true, false)
55+
now0, err := SaveDataset(peers[0], ds, nil, nil, false, true, false, false)
5656
if err != nil {
5757
t.Error(err)
5858
}
@@ -120,7 +120,7 @@ func TestSaveDataset(t *testing.T) {
120120
}
121121
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
122122

123-
ref, err := SaveDataset(n, ds, nil, nil, true, false, false)
123+
ref, err := SaveDataset(n, ds, nil, nil, true, false, false, false)
124124
if err != nil {
125125
t.Errorf("dry run error: %s", err.Error())
126126
}
@@ -143,7 +143,7 @@ func TestSaveDataset(t *testing.T) {
143143
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
144144

145145
// test save
146-
ref, err = SaveDataset(n, ds, nil, nil, false, true, false)
146+
ref, err = SaveDataset(n, ds, nil, nil, false, true, false, false)
147147
if err != nil {
148148
t.Error(err)
149149
}
@@ -173,7 +173,7 @@ func TestSaveDataset(t *testing.T) {
173173
ds.Transform.OpenScriptFile(nil)
174174

175175
// dryrun should work
176-
ref, err = SaveDataset(n, ds, secrets, nil, true, false, false)
176+
ref, err = SaveDataset(n, ds, secrets, nil, true, false, false, false)
177177
if err != nil {
178178
t.Fatal(err)
179179
}
@@ -200,7 +200,7 @@ func TestSaveDataset(t *testing.T) {
200200
ds.Transform.OpenScriptFile(nil)
201201

202202
// test save with transform
203-
ref, err = SaveDataset(n, ds, secrets, nil, false, true, false)
203+
ref, err = SaveDataset(n, ds, secrets, nil, false, true, false, false)
204204
if err != nil {
205205
t.Fatal(err)
206206
}
@@ -219,7 +219,7 @@ func TestSaveDataset(t *testing.T) {
219219
},
220220
}
221221

222-
ref, err = SaveDataset(n, ds, nil, nil, false, true, false)
222+
ref, err = SaveDataset(n, ds, nil, nil, false, true, false, false)
223223
if err != nil {
224224
t.Error(err)
225225
}
@@ -247,7 +247,7 @@ func TestSaveDataset(t *testing.T) {
247247
t.Error(err)
248248
}
249249

250-
ref, err = SaveDataset(n, ds, secrets, nil, false, true, false)
250+
ref, err = SaveDataset(n, ds, secrets, nil, false, true, false, false)
251251
if err != nil {
252252
t.Error(err)
253253
}
@@ -256,18 +256,17 @@ func TestSaveDataset(t *testing.T) {
256256
}
257257
}
258258

259-
260259
func TestSaveDatasetWithoutStructureOrBody(t *testing.T) {
261260
n := newTestNode(t)
262261

263262
ds := &dataset.Dataset{
264-
Name: "no_st_or_body_test",
263+
Name: "no_st_or_body_test",
265264
Meta: &dataset.Meta{
266265
Title: "test title",
267266
},
268267
}
269268

270-
_, err := SaveDataset(n, ds, nil, nil, false, false, false)
269+
_, err := SaveDataset(n, ds, nil, nil, false, false, false, false)
271270
expect := "creating a new dataset requires a structure or a body"
272271
if err == nil || err.Error() != expect {
273272
t.Errorf("expected error, but got %s", err.Error())

api/datasets.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ func (h *DatasetHandlers) saveHandler(w http.ResponseWriter, r *http.Request) {
477477
Private: r.FormValue("private") == "true",
478478
DryRun: r.FormValue("dry_run") == "true",
479479
ReturnBody: r.FormValue("return_body") == "true",
480+
Force: r.FormValue("force") == "true",
480481
ConvertFormatToPrev: true,
481482
ScriptOutput: scriptOutput,
482483
}

base/base_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
"testing"
99

1010
"github.com/libp2p/go-libp2p-crypto"
11-
"github.com/qri-io/qfs/cafs"
1211
"github.com/qri-io/dataset/dstest"
1312
"github.com/qri-io/ioes"
1413
"github.com/qri-io/qfs"
14+
"github.com/qri-io/qfs/cafs"
1515
"github.com/qri-io/qri/repo"
1616
"github.com/qri-io/qri/repo/profile"
1717
"github.com/qri-io/registry/regserver/mock"
@@ -62,7 +62,7 @@ func addCitiesDataset(t *testing.T, r repo.Repo) repo.DatasetRef {
6262
t.Fatal(err.Error())
6363
}
6464

65-
ref, err := CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true)
65+
ref, err := CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true, false)
6666
if err != nil {
6767
t.Fatal(err.Error())
6868
}
@@ -94,7 +94,7 @@ func updateCitiesDataset(t *testing.T, r repo.Repo) repo.DatasetRef {
9494
tc.Input.PreviousPath = ""
9595
}()
9696

97-
ref, err = CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true)
97+
ref, err = CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true, false)
9898
if err != nil {
9999
t.Fatal(err.Error())
100100
}
@@ -107,7 +107,7 @@ func addFlourinatedCompoundsDataset(t *testing.T, r repo.Repo) repo.DatasetRef {
107107
t.Fatal(err.Error())
108108
}
109109

110-
ref, err := CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true)
110+
ref, err := CreateDataset(r, ioes.NewDiscardIOStreams(), tc.Input, nil, false, true, false)
111111
if err != nil {
112112
t.Fatal(err.Error())
113113
}

base/dataset.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func ListDatasets(r repo.Repo, limit, offset int, RPC, publishedOnly bool) (res
108108
// CreateDataset uses dsfs to add a dataset to a repo's store, updating all
109109
// references within the repo if successful. CreateDataset is a lower-level
110110
// component of github.com/qri-io/qri/actions.CreateDataset
111-
func CreateDataset(r repo.Repo, streams ioes.IOStreams, ds, dsPrev *dataset.Dataset, dryRun, pin bool) (ref repo.DatasetRef, err error) {
111+
func CreateDataset(r repo.Repo, streams ioes.IOStreams, ds, dsPrev *dataset.Dataset, dryRun, pin, force bool) (ref repo.DatasetRef, err error) {
112112
var (
113113
pro *profile.Profile
114114
path string
@@ -124,7 +124,7 @@ func CreateDataset(r repo.Repo, streams ioes.IOStreams, ds, dsPrev *dataset.Data
124124
return
125125
}
126126

127-
if path, err = dsfs.CreateDataset(r.Store(), ds, dsPrev, r.PrivateKey(), pin); err != nil {
127+
if path, err = dsfs.CreateDataset(r.Store(), ds, dsPrev, r.PrivateKey(), pin, force); err != nil {
128128
return
129129
}
130130
if ds.PreviousPath != "" && ds.PreviousPath != "/" {

base/dataset_test.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ func TestCreateDataset(t *testing.T) {
7474
}
7575
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
7676

77-
if _, err := CreateDataset(r, streams, &dataset.Dataset{}, &dataset.Dataset{}, false, true); err == nil {
77+
if _, err := CreateDataset(r, streams, &dataset.Dataset{}, &dataset.Dataset{}, false, true, false); err == nil {
7878
t.Error("expected bad dataset to error")
7979
}
8080

81-
ref, err := CreateDataset(r, streams, ds, &dataset.Dataset{}, false, true)
81+
ref, err := CreateDataset(r, streams, ds, &dataset.Dataset{}, false, true, false)
8282
if err != nil {
8383
t.Fatal(err.Error())
8484
}
@@ -96,7 +96,7 @@ func TestCreateDataset(t *testing.T) {
9696

9797
prev := ref.Dataset
9898

99-
ref, err = CreateDataset(r, streams, ds, prev, false, true)
99+
ref, err = CreateDataset(r, streams, ds, prev, false, true, false)
100100
if err != nil {
101101
t.Fatal(err.Error())
102102
}
@@ -107,6 +107,19 @@ func TestCreateDataset(t *testing.T) {
107107
if len(refs) != 1 {
108108
t.Errorf("ref length mismatch. expected 1, got: %d", len(refs))
109109
}
110+
111+
ds.PreviousPath = ref.Path
112+
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
113+
prev = ref.Dataset
114+
115+
if ref, err = CreateDataset(r, streams, ds, prev, false, true, false); err == nil {
116+
t.Error("expected unchanged dataset with no force flag to error")
117+
}
118+
119+
ds.SetBodyFile(qfs.NewMemfileBytes("body.json", []byte("[]")))
120+
if ref, err = CreateDataset(r, streams, ds, prev, false, true, true); err != nil {
121+
t.Errorf("unexpected force-save error: %s", err)
122+
}
110123
}
111124

112125
func TestFetchDataset(t *testing.T) {
@@ -328,7 +341,7 @@ func TestDatasetPinning(t *testing.T) {
328341
return
329342
}
330343

331-
ref2, err := CreateDataset(r, streams, tc.Input, nil, false, false)
344+
ref2, err := CreateDataset(r, streams, tc.Input, nil, false, false, false)
332345
if err != nil {
333346
t.Error(err.Error())
334347
return

cmd/save.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ commit message and title to the save.`,
6565
cmd.Flags().StringSliceVar(&o.Secrets, "secrets", nil, "transform secrets as comma separated key,value,key,value,... sequence")
6666
cmd.Flags().BoolVarP(&o.Publish, "publish", "p", false, "publish this dataset to the registry")
6767
cmd.Flags().BoolVar(&o.DryRun, "dry-run", false, "simulate saving a dataset")
68+
cmd.Flags().BoolVar(&o.Force, "force", false, "force a new commit, even if no changes are detected")
6869
cmd.Flags().BoolVarP(&o.KeepFormat, "keep-format", "k", false, "convert incoming data to stored data format")
6970

7071
return cmd
@@ -86,6 +87,7 @@ type SaveOptions struct {
8687
Publish bool
8788
DryRun bool
8889
KeepFormat bool
90+
Force bool
8991
Secrets []string
9092

9193
DatasetRequests *lib.DatasetRequests
@@ -145,6 +147,7 @@ func (o *SaveOptions) Run() (err error) {
145147
DryRun: o.DryRun,
146148
Recall: o.Recall,
147149
ConvertFormatToPrev: o.KeepFormat,
150+
Force: o.Force,
148151
}
149152

150153
if o.Secrets != nil {

lib/datasets.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ type SaveParams struct {
204204
ConvertFormatToPrev bool
205205
// string of references to recall before saving
206206
Recall string
207+
// force a new commit, even if no changes are detected
208+
Force bool
207209
// optional writer to have transform script record standard output to
208210
// note: this won't work over RPC, only on local calls
209211
ScriptOutput io.Writer
@@ -255,7 +257,8 @@ func (r *DatasetRequests) Save(p *SaveParams, res *repo.DatasetRef) (err error)
255257
if ds.Name == "" {
256258
return fmt.Errorf("name is required")
257259
}
258-
if ds.BodyPath == "" &&
260+
if !p.Force &&
261+
ds.BodyPath == "" &&
259262
ds.Body == nil &&
260263
ds.BodyBytes == nil &&
261264
ds.Structure == nil &&
@@ -269,7 +272,7 @@ func (r *DatasetRequests) Save(p *SaveParams, res *repo.DatasetRef) (err error)
269272
return
270273
}
271274

272-
ref, err := actions.SaveDataset(r.node, ds, p.Secrets, p.ScriptOutput, p.DryRun, true, p.ConvertFormatToPrev)
275+
ref, err := actions.SaveDataset(r.node, ds, p.Secrets, p.ScriptOutput, p.DryRun, true, p.ConvertFormatToPrev, p.Force)
273276
if err != nil {
274277
log.Debugf("create ds error: %s\n", err.Error())
275278
return err

lib/datasets_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,24 @@ func TestDatasetRequestsSave(t *testing.T) {
140140
}
141141
}
142142

143+
func TestDatasetRequestsForceSave(t *testing.T) {
144+
node := newTestQriNode(t)
145+
ref := addCitiesDataset(t, node)
146+
r := NewDatasetRequests(node, nil)
147+
148+
res := &repo.DatasetRef{}
149+
if err := r.Save(&SaveParams{Dataset: &dataset.Dataset{Name: ref.Name, Peername: ref.Peername}}, res); err == nil {
150+
t.Error("expected empty save without force flag to error")
151+
}
152+
153+
if err := r.Save(&SaveParams{
154+
Dataset: &dataset.Dataset{Name: ref.Name, Peername: ref.Peername},
155+
Force: true,
156+
}, res); err != nil {
157+
t.Errorf("expected empty save with flag to not error. got: %s", err.Error())
158+
}
159+
}
160+
143161
func TestDatasetRequestsSaveRecall(t *testing.T) {
144162
node := newTestQriNode(t)
145163
ref := addNowTransformDataset(t, node)

lib/lib_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import (
88
"testing"
99

1010
crypto "github.com/libp2p/go-libp2p-crypto"
11-
"github.com/qri-io/qfs/cafs"
1211
"github.com/qri-io/dataset/dstest"
1312
"github.com/qri-io/qfs"
13+
"github.com/qri-io/qfs/cafs"
1414
"github.com/qri-io/qri/actions"
1515
"github.com/qri-io/qri/p2p"
1616
"github.com/qri-io/qri/p2p/test"
@@ -79,7 +79,7 @@ func addCitiesDataset(t *testing.T, node *p2p.QriNode) repo.DatasetRef {
7979
ds.Name = tc.Name
8080
ds.BodyBytes = tc.Body
8181

82-
ref, err := actions.SaveDataset(node, ds, nil, nil, false, true, false)
82+
ref, err := actions.SaveDataset(node, ds, nil, nil, false, true, false, false)
8383
if err != nil {
8484
t.Fatal(err.Error())
8585
}
@@ -95,7 +95,7 @@ func addNowTransformDataset(t *testing.T, node *p2p.QriNode) repo.DatasetRef {
9595
ds.Name = tc.Name
9696
ds.Transform.ScriptPath = "testdata/now_tf/transform.star"
9797

98-
ref, err := actions.SaveDataset(node, ds, nil, nil, false, true, false)
98+
ref, err := actions.SaveDataset(node, ds, nil, nil, false, true, false, false)
9999
if err != nil {
100100
t.Fatal(err.Error())
101101
}

p2p/log_diff_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import (
44
"context"
55
"testing"
66

7-
"github.com/qri-io/qfs/cafs"
87
"github.com/qri-io/dataset/dstest"
98
"github.com/qri-io/ioes"
9+
"github.com/qri-io/qfs/cafs"
1010
"github.com/qri-io/qri/base"
1111
p2ptest "github.com/qri-io/qri/p2p/test"
1212
)
@@ -31,7 +31,7 @@ func TestRequestLogDiff(t *testing.T) {
3131
}
3232

3333
// add a dataset to peer 4
34-
ref, err := base.CreateDataset(peers[4].Repo, streams, tc.Input, nil, false, true)
34+
ref, err := base.CreateDataset(peers[4].Repo, streams, tc.Input, nil, false, true, false)
3535
if err != nil {
3636
t.Fatal(err)
3737
}
@@ -50,7 +50,7 @@ func TestRequestLogDiff(t *testing.T) {
5050
update.Name = tc.Name
5151

5252
// add an update on peer 4
53-
ref2, err := base.CreateDataset(peers[4].Repo, streams, update, tc.Input, false, true)
53+
ref2, err := base.CreateDataset(peers[4].Repo, streams, update, tc.Input, false, true, false)
5454
if err != nil {
5555
t.Fatal(err)
5656
}

0 commit comments

Comments
 (0)