From 6b82be60611c2059f9d7e10dfb7bcda82d398ba0 Mon Sep 17 00:00:00 2001 From: Anas Muhammed Date: Mon, 29 Jul 2024 21:59:43 +0400 Subject: [PATCH] feat: reset old files --- internal/github/plugin.go | 1 + internal/github/publish_github_gist.go | 18 +++++- internal/github/publish_github_gist_test.go | 62 +++++++++++++++++++ mocks/internalpkg/github/gist_client.go | 68 +++++++++++++++++++++ plugin/pluginapi/v1/cty.pb.go | 26 ++++---- 5 files changed, 162 insertions(+), 13 deletions(-) diff --git a/internal/github/plugin.go b/internal/github/plugin.go index 89e1a286..35464564 100644 --- a/internal/github/plugin.go +++ b/internal/github/plugin.go @@ -42,6 +42,7 @@ type IssuesClient interface { type GistClient interface { Create(ctx context.Context, gist *gh.Gist) (*gh.Gist, *gh.Response, error) + Get(ctx context.Context, id string) (*gh.Gist, *gh.Response, error) Edit(ctx context.Context, id string, gist *gh.Gist) (*gh.Gist, *gh.Response, error) } diff --git a/internal/github/publish_github_gist.go b/internal/github/publish_github_gist.go index 86d4701f..52f8e550 100644 --- a/internal/github/publish_github_gist.go +++ b/internal/github/publish_github_gist.go @@ -170,7 +170,23 @@ func publishGithubGist(loader ClientLoaderFn) plugin.PublishFunc { } slog.InfoContext(ctx, "created gist", "url", *gist.HTMLURL) } else { - gist, _, err := client.Gists().Edit(ctx, gistId.AsString(), payload) + + gist, _, err := client.Gists().Get(ctx, gistId.AsString()) + if err != nil { + return diagnostics.Diag{{ + Severity: hcl.DiagError, + Summary: "Failed to retreive gist", + Detail: err.Error(), + }} + } + // reset all old files + for _, file := range gist.Files { + _, exists := payload.Files[gh.GistFilename(*file.Filename)] + if !exists { + payload.Files[gh.GistFilename(*file.Filename)] = gh.GistFile{} + } + } + gist, _, err = client.Gists().Edit(ctx, gistId.AsString(), payload) if err != nil { return diagnostics.Diag{{ Severity: hcl.DiagError, diff --git a/internal/github/publish_github_gist_test.go b/internal/github/publish_github_gist_test.go index 0faa72f7..ee14a415 100644 --- a/internal/github/publish_github_gist_test.go +++ b/internal/github/publish_github_gist_test.go @@ -153,3 +153,65 @@ func (s *GithubPublishGistTestSuite) TestFilenameOptional() { }) s.Require().Nil(diags) } + +func (s *GithubPublishGistTestSuite) TestResetOldFiles() { + s.cli.On("Gists").Return(s.gistCli) + s.gistCli.On("Get", mock.Anything, "gistid").Return(&gh.Gist{ + Files: map[gh.GistFilename]gh.GistFile{ + "oldfile.md": { + Filename: gh.String("oldfile.md"), + Content: gh.String("old content"), + }, + }, + }, &gh.Response{}, nil) + s.gistCli.On("Edit", mock.Anything, "gistid", &gh.Gist{ + Description: gh.String("test description"), + Public: gh.Bool(false), + Files: map[gh.GistFilename]gh.GistFile{ + "oldfile.md": {}, + "test_document.md": { + Content: gh.String("# Header 1\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit."), + Filename: gh.String("test_document.md"), + }, + }, + }).Return(&gh.Gist{HTMLURL: gh.String("http://gist.github.com/mock")}, &gh.Response{}, nil) + ctx := context.Background() + titleMeta := plugin.MapData{ + "provider": plugin.StringData("title"), + "plugin": plugin.StringData("blackstork/builtin"), + } + diags := s.plugin.Publish(ctx, "github_gist", &plugin.PublishParams{ + Config: cty.ObjectVal(map[string]cty.Value{ + "github_token": cty.StringVal("testtoken"), + }), + Args: cty.ObjectVal(map[string]cty.Value{ + "description": cty.StringVal("test description"), + "filename": cty.StringVal(""), + "make_public": cty.NullVal(cty.Bool), + "gist_id": cty.StringVal("gistid"), + }), + Format: plugin.OutputFormatMD, + DataContext: plugin.MapData{ + "document": plugin.MapData{ + "meta": plugin.MapData{ + "name": plugin.StringData("test_document"), + }, + "content": plugin.MapData{ + "type": plugin.StringData("section"), + "children": plugin.ListData{ + plugin.MapData{ + "type": plugin.StringData("element"), + "markdown": plugin.StringData("# Header 1"), + "meta": titleMeta, + }, + plugin.MapData{ + "type": plugin.StringData("element"), + "markdown": plugin.StringData("Lorem ipsum dolor sit amet, consectetur adipiscing elit."), + }, + }, + }, + }, + }, + }) + s.Require().Nil(diags) +} diff --git a/mocks/internalpkg/github/gist_client.go b/mocks/internalpkg/github/gist_client.go index 1f7ca9c7..f61c9c51 100644 --- a/mocks/internalpkg/github/gist_client.go +++ b/mocks/internalpkg/github/gist_client.go @@ -160,6 +160,74 @@ func (_c *GistClient_Edit_Call) RunAndReturn(run func(context.Context, string, * return _c } +// Get provides a mock function with given fields: ctx, id +func (_m *GistClient) Get(ctx context.Context, id string) (*github.Gist, *github.Response, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *github.Gist + var r1 *github.Response + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*github.Gist, *github.Response, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *github.Gist); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*github.Gist) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) *github.Response); ok { + r1 = rf(ctx, id) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + if rf, ok := ret.Get(2).(func(context.Context, string) error); ok { + r2 = rf(ctx, id) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GistClient_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type GistClient_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - ctx context.Context +// - id string +func (_e *GistClient_Expecter) Get(ctx interface{}, id interface{}) *GistClient_Get_Call { + return &GistClient_Get_Call{Call: _e.mock.On("Get", ctx, id)} +} + +func (_c *GistClient_Get_Call) Run(run func(ctx context.Context, id string)) *GistClient_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *GistClient_Get_Call) Return(_a0 *github.Gist, _a1 *github.Response, _a2 error) *GistClient_Get_Call { + _c.Call.Return(_a0, _a1, _a2) + return _c +} + +func (_c *GistClient_Get_Call) RunAndReturn(run func(context.Context, string) (*github.Gist, *github.Response, error)) *GistClient_Get_Call { + _c.Call.Return(run) + return _c +} + // NewGistClient creates a new instance of GistClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewGistClient(t interface { diff --git a/plugin/pluginapi/v1/cty.pb.go b/plugin/pluginapi/v1/cty.pb.go index 168cdf9d..e1bf1dba 100644 --- a/plugin/pluginapi/v1/cty.pb.go +++ b/plugin/pluginapi/v1/cty.pb.go @@ -156,45 +156,46 @@ type isCty_Data interface { } type Cty_Primitive_ struct { - Primitive *Cty_Primitive `protobuf:"bytes,1,opt,name=primitive,proto3,oneof"` // DONE + Primitive *Cty_Primitive `protobuf:"bytes,1,opt,name=primitive,proto3,oneof"` } type Cty_Object_ struct { - Object *Cty_Object `protobuf:"bytes,2,opt,name=object,proto3,oneof"` // DONE + Object *Cty_Object `protobuf:"bytes,2,opt,name=object,proto3,oneof"` } type Cty_Map struct { - Map *Cty_Mapping `protobuf:"bytes,3,opt,name=map,proto3,oneof"` // DONE + Map *Cty_Mapping `protobuf:"bytes,3,opt,name=map,proto3,oneof"` } type Cty_List struct { - List *Cty_Sequence `protobuf:"bytes,4,opt,name=list,proto3,oneof"` // DONE + List *Cty_Sequence `protobuf:"bytes,4,opt,name=list,proto3,oneof"` } type Cty_Set struct { - Set *Cty_Sequence `protobuf:"bytes,5,opt,name=set,proto3,oneof"` // DONE + Set *Cty_Sequence `protobuf:"bytes,5,opt,name=set,proto3,oneof"` } type Cty_Tuple struct { - Tuple *Cty_Sequence `protobuf:"bytes,6,opt,name=tuple,proto3,oneof"` // DONE + Tuple *Cty_Sequence `protobuf:"bytes,6,opt,name=tuple,proto3,oneof"` } type Cty_Null struct { // Specifies type of null value - Null *CtyType `protobuf:"bytes,7,opt,name=null,proto3,oneof"` // DONE + Null *CtyType `protobuf:"bytes,7,opt,name=null,proto3,oneof"` } type Cty_Caps struct { - Caps *Cty_Capsule `protobuf:"bytes,8,opt,name=caps,proto3,oneof"` // DONE + Caps *Cty_Capsule `protobuf:"bytes,8,opt,name=caps,proto3,oneof"` } type Cty_Unknown struct { // Specifies type of the unknown value - Unknown *CtyType `protobuf:"bytes,9,opt,name=unknown,proto3,oneof"` // DONE + Unknown *CtyType `protobuf:"bytes,9,opt,name=unknown,proto3,oneof"` } type Cty_Dyn struct { - Dyn *Cty_Dynamic `protobuf:"bytes,10,opt,name=dyn,proto3,oneof"` // DONE + // DynamicPseudoType + Dyn *Cty_Dynamic `protobuf:"bytes,10,opt,name=dyn,proto3,oneof"` } func (*Cty_Primitive_) isCty_Data() {} @@ -395,7 +396,7 @@ type Cty_Primitive_Str struct { } type Cty_Primitive_Num struct { - // empty bytes used when encoding the type + // empty value is used for marking the type Num []byte `protobuf:"bytes,2,opt,name=num,proto3,oneof"` } @@ -518,7 +519,8 @@ type Cty_Sequence struct { unknownFields protoimpl.UnknownFields Data []*Cty `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - // Original sequence is empty, element added to preserve the type (unless it's a tuple) + // Original sequence is empty, element added to preserve the type + // Not true for empty tuples, since they are valid values OnlyType bool `protobuf:"varint,2,opt,name=onlyType,proto3" json:"onlyType,omitempty"` }