From ca710a4a1687e78775904394a730591d46dcdbd5 Mon Sep 17 00:00:00 2001 From: Damien Menanteau Date: Mon, 21 Oct 2024 18:47:25 +0200 Subject: [PATCH] [#403] Move retro file saving operation from engine to filesystem package To limit engine package's responsibilities - created a dedicated filesystem/io_utils.go file for providing FS related operations --- src/engine/tcr.go | 8 +--- src/filesystem/io_utils.go | 43 ++++++++++++++++++ src/filesystem/io_utils_test.go | 78 +++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 src/filesystem/io_utils.go create mode 100644 src/filesystem/io_utils_test.go diff --git a/src/engine/tcr.go b/src/engine/tcr.go index 56e69be6..2836fa11 100644 --- a/src/engine/tcr.go +++ b/src/engine/tcr.go @@ -236,14 +236,8 @@ func (tcr *TCREngine) PrintStats(p params.Params) { func (tcr *TCREngine) GenerateRetro(p params.Params) { tcrEvents := tcrLogsToEvents(tcr.queryVCSLogs(p)) markdown := retro.GenerateMarkdown(filepath.Base(tcr.vcs.GetRootDir()), &tcrEvents) - retroPath := filepath.Join(tcr.sourceTree.GetBaseDir(), retroFileName) - err := os.WriteFile(retroPath, []byte(markdown), 0644) //nolint:gosec - if err != nil { - report.PostError(err) - } else { - report.PostInfo("Retro file: ", retroPath) - } + filesystem.WriteFile(retroPath, []byte(markdown)) } func tcrLogsToEvents(tcrLogs vcs.LogItems) (tcrEvents events.TcrEvents) { diff --git a/src/filesystem/io_utils.go b/src/filesystem/io_utils.go new file mode 100644 index 00000000..cee23b2b --- /dev/null +++ b/src/filesystem/io_utils.go @@ -0,0 +1,43 @@ +/* +Copyright (c) 2024 Murex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package filesystem + +import ( + "github.com/murex/tcr/report" + "github.com/spf13/afero" +) + +var appFs afero.Fs + +func init() { + appFs = afero.NewOsFs() +} + +// WriteFile writes provided data into a file. +func WriteFile(path string, data []byte) { + report.PostInfo("Saving file: ", path) + err := afero.WriteFile(appFs, path, data, 0644) //nolint:gosec + if err != nil { + report.PostError(err) + } +} diff --git a/src/filesystem/io_utils_test.go b/src/filesystem/io_utils_test.go new file mode 100644 index 00000000..41a42260 --- /dev/null +++ b/src/filesystem/io_utils_test.go @@ -0,0 +1,78 @@ +/* +Copyright (c) 2024 Murex + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package filesystem + +import ( + "github.com/murex/tcr/report" + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" + "io/fs" + "os" + "testing" +) + +const pathWithPermError = "/path/with/permission/err" + +type mockFs struct { + afero.MemMapFs +} + +func (m *mockFs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) { + if name == pathWithPermError { + return nil, fs.ErrPermission + } + return m.MemMapFs.OpenFile(name, flag, perm) +} + +func Test_write_file_reports_fs_errors(t *testing.T) { + appFs = &mockFs{MemMapFs: afero.MemMapFs{}} + + tests := []struct { + description string + path string + expected int + }{ + { + description: "no error", + path: "my-file.txt", + expected: 0, + }, + { + description: "permission error", + path: pathWithPermError, + expected: 1, + }, + } + + for _, test := range tests { + t.Run(test.description, func(t *testing.T) { + sniffer := report.NewSniffer(func(msg report.Message) bool { + return msg.Type.Category == report.Error + }) + WriteFile(test.path, []byte("some stuff")) + sniffer.Stop() + assert.Equal(t, test.expected, sniffer.GetMatchCount()) + }) + } + +}