From ab99f738b74a2558d8fa0ffcf306f0516dbd7310 Mon Sep 17 00:00:00 2001 From: dankeboy36 Date: Fri, 21 Nov 2025 13:33:49 +0100 Subject: [PATCH] fix: return `AlreadyExists` when archive exists Signed-off-by: dankeboy36 --- commands/cmderrors/cmderrors.go | 19 ++++++++++++++++ commands/service_sketch_archive.go | 2 +- internal/integrationtest/arduino-cli.go | 14 ++++++++++++ .../integrationtest/daemon/daemon_test.go | 22 +++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/commands/cmderrors/cmderrors.go b/commands/cmderrors/cmderrors.go index 38eef33bcc1..a511a150402 100644 --- a/commands/cmderrors/cmderrors.go +++ b/commands/cmderrors/cmderrors.go @@ -755,6 +755,25 @@ func (e *NotFoundError) GRPCStatus() *status.Status { return status.New(codes.NotFound, e.Error()) } +// AlreadyExists is returned when creating a resource failed because one already exists +type AlreadyExists struct { + Message string + Cause error +} + +func (e *AlreadyExists) Error() string { + return composeErrorMsg(e.Message, e.Cause) +} + +func (e *AlreadyExists) Unwrap() error { + return e.Cause +} + +// GRPCStatus converts the error into a *status.Status +func (e *AlreadyExists) GRPCStatus() *status.Status { + return status.New(codes.AlreadyExists, e.Error()) +} + // PermissionDeniedError is returned when a resource cannot be accessed or modified type PermissionDeniedError struct { Message string diff --git a/commands/service_sketch_archive.go b/commands/service_sketch_archive.go index c4cde916321..0bfd20df0a4 100644 --- a/commands/service_sketch_archive.go +++ b/commands/service_sketch_archive.go @@ -66,7 +66,7 @@ func (s *arduinoCoreServerImpl) ArchiveSketch(ctx context.Context, req *rpc.Arch if !req.GetOverwrite() { if archivePath.Exist() { - return nil, &cmderrors.InvalidArgumentError{Message: i18n.Tr("Archive already exists")} + return nil, &cmderrors.AlreadyExists{Message: i18n.Tr("Archive already exists")} } } diff --git a/internal/integrationtest/arduino-cli.go b/internal/integrationtest/arduino-cli.go index c2debdbb445..2eee7c72f68 100644 --- a/internal/integrationtest/arduino-cli.go +++ b/internal/integrationtest/arduino-cli.go @@ -741,3 +741,17 @@ func (inst *ArduinoCLIInstance) NewSketch(ctx context.Context, sketchName, sketc logCallf(">>> NewSketch(%+v)\n", req) return inst.cli.daemonClient.NewSketch(ctx, req) } + +// ArchiveSketch calls the "ArchiveSketch" gRPC method. +func (cli *ArduinoCLI) ArchiveSketch(ctx context.Context, sketchPath, archivePath string, includeBuildDir, overwrite bool) (*commands.ArchiveSketchResponse, error) { + req := &commands.ArchiveSketchRequest{ + SketchPath: sketchPath, + ArchivePath: archivePath, + IncludeBuildDir: includeBuildDir, + Overwrite: overwrite, + } + logCallf(">>> ArchiveSketch(%+v)\n", req) + resp, err := cli.daemonClient.ArchiveSketch(ctx, req) + logCallf("err=%v\n", err) + return resp, err +} diff --git a/internal/integrationtest/daemon/daemon_test.go b/internal/integrationtest/daemon/daemon_test.go index 20171e66da7..ff9ccd3a08e 100644 --- a/internal/integrationtest/daemon/daemon_test.go +++ b/internal/integrationtest/daemon/daemon_test.go @@ -663,6 +663,28 @@ func TestDaemonCreateSketch(t *testing.T) { require.NoError(t, err) } +func TestDaemonArchiveSketchAlreadyExists(t *testing.T) { + env, cli := integrationtest.CreateEnvForDaemon(t) + defer env.CleanUp() + + sketchDir := cli.CopySketch("sketch_simple") + archivePath := cli.WorkingDir().Join("ArchiveSketchAlreadyExists.zip") + if archivePath.Exist() { + require.NoError(t, archivePath.Remove()) + } + t.Cleanup(func() { _ = archivePath.Remove() }) + + _, err := cli.ArchiveSketch(context.Background(), sketchDir.String(), archivePath.String(), false, false) + require.NoError(t, err) + + _, err = cli.ArchiveSketch(context.Background(), sketchDir.String(), archivePath.String(), false, false) + require.Error(t, err) + st, ok := status.FromError(err) + require.True(t, ok) + require.Equal(t, codes.AlreadyExists, st.Code()) + require.Contains(t, st.Message(), "Archive already exists") +} + func analyzeUpdateIndexClient(t *testing.T, cl commands.ArduinoCoreService_UpdateIndexClient) (map[string]*commands.DownloadProgressEnd, error) { analyzer := NewDownloadProgressAnalyzer(t) for {