From 60ff93d6720565b3fd97966c1143032cee1f581f Mon Sep 17 00:00:00 2001 From: Nikolay Mitrofanov Date: Wed, 28 Jan 2026 22:01:27 +0300 Subject: [PATCH 1/5] validate multiple apiVersions and kinds in ParseIndex func Signed-off-by: Nikolay Mitrofanov --- pkg/yaml/validation/index.go | 30 +++++++++++ pkg/yaml/validation/index_test.go | 73 +++++++++++++++++++++++++++ pkg/yaml/validation/validator_test.go | 15 ++++++ 3 files changed, 118 insertions(+) diff --git a/pkg/yaml/validation/index.go b/pkg/yaml/validation/index.go index 9c02885..a29d349 100644 --- a/pkg/yaml/validation/index.go +++ b/pkg/yaml/validation/index.go @@ -15,8 +15,10 @@ package validation import ( + "bytes" "fmt" "io" + "regexp" "strings" "sigs.k8s.io/yaml" @@ -62,7 +64,12 @@ func ParseIndex(reader io.Reader, opts ...ParseIndexOption) (*SchemaIndex, error return nil, fmt.Errorf("%w: %w", ErrRead, err) } + if err := contentHasMultipleSchemaKeys(content); err != nil { + return nil, err + } + index := SchemaIndex{} + err = yaml.Unmarshal(content, &index) if err != nil { return nil, fmt.Errorf("%w %w: schema index unmarshal failed: %w", ErrKindValidationFailed, ErrKindInvalidYAML, err) @@ -137,3 +144,26 @@ func (i *SchemaIndex) invalidIndexErr(doc []byte) error { ErrKindValidationFailed, i.Version, i.Kind, string(doc), ) } + +var ( + apiVersionRegex = regexp.MustCompile(`(?m)^apiVersion:.*$`) + kindRegex = regexp.MustCompile(`(?m)^kind:.*$`) + errSeparator = []byte(" ") +) + +func multipleKeysErr(keyName string, keys [][]byte) error { + joinedKeys := bytes.Join(keys, errSeparator) + return fmt.Errorf("%w: multiple %s keys found: %s", ErrKindValidationFailed, keyName, string(joinedKeys)) +} + +func contentHasMultipleSchemaKeys(content []byte) error { + if res := apiVersionRegex.FindAll(content, 2); len(res) > 1 { + return multipleKeysErr("apiVersion", res) + } + + if res := kindRegex.FindAll(content, 2); len(res) > 1 { + return multipleKeysErr("kind", res) + } + + return nil +} diff --git a/pkg/yaml/validation/index_test.go b/pkg/yaml/validation/index_test.go index d2f7d01..b9dfda7 100644 --- a/pkg/yaml/validation/index_test.go +++ b/pkg/yaml/validation/index_test.go @@ -142,6 +142,66 @@ value: 1 opts: []ParseIndexOption{ParseIndexWithoutCheckValid()}, }, + { + name: "multiple api versions", + reader: strings.NewReader(` +apiVersion: deckhouse.io/v1 +kind: TestKind +key: key +value: 1 +apiVersion: deckhouse.io/v1 +kkey: vval +`), + errs: []error{ErrKindValidationFailed}, + opts: []ParseIndexOption{ParseIndexWithoutCheckValid()}, + }, + + { + name: "multiple kinds", + reader: strings.NewReader(` +apiVersion: deckhouse.io/v1 +kind: TestKind +key: key +value: 1 +kind: AnotherKind +kkey: vval +`), + errs: []error{ErrKindValidationFailed}, + opts: []ParseIndexOption{ParseIndexWithoutCheckValid()}, + }, + + { + name: "multiple api versions and kinds", + reader: strings.NewReader(` +# apiVersion here +apiVersion: deckhouse.io/v1 +kind: TestKind +key: key +value: 1 +apiVersion: deckhouse.io/v1 +kind: AnotherKind +kkey: vval +`), + errs: []error{ErrKindValidationFailed}, + opts: []ParseIndexOption{ParseIndexWithoutCheckValid()}, + }, + + { + name: "multiple api versions and kinds", + reader: strings.NewReader(` +# apiVersion here +apiVersion: deckhouse.io/v1 +kind: TestKind +key: key +value: 1 +apiVersion: deckhouse.io/v1 +kind: AnotherKind +kkey: vval +`), + errs: []error{ErrKindValidationFailed}, + opts: []ParseIndexOption{ParseIndexWithoutCheckValid()}, + }, + { name: "happy case", reader: strings.NewReader(` @@ -149,6 +209,19 @@ apiVersion: deckhouse.io/v1 kind: TestKind sshUser: ubuntu sshPort: 2200 +`), + errs: nil, + }, + + { + name: "not fail if apiVersion and kind string presents but not keys", + reader: strings.NewReader(` +# apiVersion here +apiVersion: deckhouse.io/v1 # apiVersion: here +# kind here +kind: TestKind # kind: here +key: apiVersion +value: kind `), errs: nil, }, diff --git a/pkg/yaml/validation/validator_test.go b/pkg/yaml/validation/validator_test.go index c1384e7..a9d0474 100644 --- a/pkg/yaml/validation/validator_test.go +++ b/pkg/yaml/validation/validator_test.go @@ -339,6 +339,21 @@ sshAgentPrivateKeys: {"a": "b"} errSubstring: fmt.Sprintf(`"TestKind, deckhouse.io/v1": %s:`, ErrDocumentValidationFailed.Error()), opts: []ValidateOption{ValidateWithNoPrettyError(true)}, }, + { + name: "multiple api versions and kinds", + doc: ` +apiVersion: deckhouse.io/v1 +kind: TestKind +sshUser: ubuntu +sshPort: "port" +sshAgentPrivateKeys: {"a": "b"} +apiVersion: deckhouse.io/v1 +kind: AnotherKind +key: key +`, + errSubstring: "DocumentKindValidationFailed: multiple apiVersion keys found: apiVersion: deckhouse.io/v1 apiVersion: deckhouse.io/v1", + errKind: ErrKindValidationFailed, + }, } for _, test := range tests { From 021a0871fa93f1ff84c3a82d16d44cb1c0500586 Mon Sep 17 00:00:00 2001 From: Nikolay Mitrofanov Date: Wed, 28 Jan 2026 22:03:28 +0300 Subject: [PATCH 2/5] validate multiple apiVersions and kinds in ParseIndex func Signed-off-by: Nikolay Mitrofanov --- pkg/yaml/validation/index.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/yaml/validation/index.go b/pkg/yaml/validation/index.go index a29d349..ebd4f6f 100644 --- a/pkg/yaml/validation/index.go +++ b/pkg/yaml/validation/index.go @@ -64,6 +64,8 @@ func ParseIndex(reader io.Reader, opts ...ParseIndexOption) (*SchemaIndex, error return nil, fmt.Errorf("%w: %w", ErrRead, err) } + // we cannot use yaml.UnmarshalStrict here + // because strict unmarshal also verify that another keys not present if err := contentHasMultipleSchemaKeys(content); err != nil { return nil, err } From 6765ec0bcfaa594e7fef25d228b049bf0e3fe374 Mon Sep 17 00:00:00 2001 From: Nikolay Mitrofanov Date: Wed, 28 Jan 2026 22:52:41 +0300 Subject: [PATCH 3/5] fix deprecated comment Signed-off-by: Nikolay Mitrofanov --- pkg/log/dummy.go | 8 ++++++++ pkg/log/in_memory.go | 8 ++++++++ pkg/log/logger.go | 16 ++++++++-------- pkg/log/pretty.go | 10 +++++++++- pkg/log/process.go | 6 +++--- pkg/log/process_test.go | 33 +++++++++++++++++++++++++++++++++ pkg/log/silent.go | 8 ++++++++ pkg/log/simple.go | 8 ++++++++ pkg/log/tee.go | 8 ++++++++ 9 files changed, 93 insertions(+), 12 deletions(-) diff --git a/pkg/log/dummy.go b/pkg/log/dummy.go index c8bfc94..f0ad42d 100644 --- a/pkg/log/dummy.go +++ b/pkg/log/dummy.go @@ -70,6 +70,8 @@ func (d *DummyLogger) InfoFWithoutLn(format string, a ...interface{}) { fmt.Printf(format, a...) } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (d *DummyLogger) InfoLn(a ...interface{}) { fmt.Println(a...) } @@ -78,6 +80,8 @@ func (d *DummyLogger) ErrorFWithoutLn(format string, a ...interface{}) { fmt.Printf(format, a...) } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (d *DummyLogger) ErrorLn(a ...interface{}) { fmt.Println(a...) } @@ -88,6 +92,8 @@ func (d *DummyLogger) DebugFWithoutLn(format string, a ...interface{}) { } } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (d *DummyLogger) DebugLn(a ...interface{}) { if d.isDebug { fmt.Println(a...) @@ -106,6 +112,8 @@ func (d *DummyLogger) FailRetry(l string) { d.Fail(l) } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (d *DummyLogger) WarnLn(a ...interface{}) { fmt.Println(a...) } diff --git a/pkg/log/in_memory.go b/pkg/log/in_memory.go index a83539f..ad724fc 100644 --- a/pkg/log/in_memory.go +++ b/pkg/log/in_memory.go @@ -172,6 +172,8 @@ func (l *InMemoryLogger) InfoFWithoutLn(format string, a ...interface{}) { l.parent.InfoFWithoutLn(format, a...) } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (l *InMemoryLogger) InfoLn(a ...interface{}) { l.writeEntityFormatted(listToString(a)) l.parent.InfoLn(a...) @@ -182,6 +184,8 @@ func (l *InMemoryLogger) ErrorFWithoutLn(format string, a ...interface{}) { l.parent.ErrorFWithoutLn(format, a...) } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (l *InMemoryLogger) ErrorLn(a ...interface{}) { l.writeEntityWithPrefix(l.errorPrefix, listToString(a)) l.parent.ErrorLn(a...) @@ -196,6 +200,8 @@ func (l *InMemoryLogger) DebugFWithoutLn(format string, a ...interface{}) { l.parent.DebugFWithoutLn(format, a...) } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (l *InMemoryLogger) DebugLn(a ...interface{}) { if l.notDebug { return @@ -210,6 +216,8 @@ func (l *InMemoryLogger) WarnFWithoutLn(format string, a ...interface{}) { l.parent.WarnFWithoutLn(format, a...) } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (l *InMemoryLogger) WarnLn(a ...interface{}) { l.writeEntityFormatted(listToString(a)) l.parent.WarnLn(a...) diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 08d09e3..d57036b 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -108,27 +108,27 @@ type baseLogger interface { Process(Process, string, func() error) error InfoFWithoutLn(format string, a ...interface{}) + // InfoLn - // Deprecated: - // Use InfoF(string) it add \n to end + // Deprecated: Use InfoF(string) it add \n to end InfoLn(a ...interface{}) ErrorFWithoutLn(format string, a ...interface{}) + // ErrorLn - // Deprecated: - // Use ErrorF(string) it add \n to end + // Deprecated: Use ErrorF(string) it add \n to end ErrorLn(a ...interface{}) DebugFWithoutLn(format string, a ...interface{}) + // DebugLn - // Deprecated: - // Use DebugF(string) it add \n to end + // Deprecated: Use DebugF(string) it add \n to end DebugLn(a ...interface{}) WarnFWithoutLn(format string, a ...interface{}) + // WarnLn - // Deprecated: - // Use WarnF(string) it add \n to end + // Deprecated: Use WarnF(string) it add \n to end WarnLn(a ...interface{}) Success(string) diff --git a/pkg/log/pretty.go b/pkg/log/pretty.go index 4ae8708..151dd7c 100644 --- a/pkg/log/pretty.go +++ b/pkg/log/pretty.go @@ -121,6 +121,8 @@ func (d *PrettyLogger) InfoFWithoutLn(format string, a ...interface{}) { d.logboekLogger.Info().LogF(format, a...) } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (d *PrettyLogger) InfoLn(a ...interface{}) { d.logboekLogger.Info().LogLn(a...) } @@ -129,6 +131,8 @@ func (d *PrettyLogger) ErrorFWithoutLn(format string, a ...interface{}) { d.logboekLogger.Error().LogF(format, a...) } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (d *PrettyLogger) ErrorLn(a ...interface{}) { d.logboekLogger.Error().LogLn(a...) } @@ -147,6 +151,8 @@ func (d *PrettyLogger) DebugFWithoutLn(format string, a ...interface{}) { } } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (d *PrettyLogger) DebugLn(a ...interface{}) { if d.debugLogWriter != nil { o := fmt.Sprintln(a...) @@ -173,6 +179,8 @@ func (d *PrettyLogger) FailRetry(l string) { d.Fail(l) } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (d *PrettyLogger) WarnLn(a ...interface{}) { a = append([]interface{}{"❗ ~ "}, a...) d.InfoLn(color.New(color.Bold).Sprint(a...)) @@ -184,7 +192,7 @@ func (d *PrettyLogger) WarnFWithoutLn(format string, a ...interface{}) { } func (d *PrettyLogger) JSON(content []byte) { - d.InfoLn(prettyJSON(content)) + d.InfoF(prettyJSON(content)) } func (d *PrettyLogger) Write(content []byte) (int, error) { diff --git a/pkg/log/process.go b/pkg/log/process.go index b968557..176bed4 100644 --- a/pkg/log/process.go +++ b/pkg/log/process.go @@ -105,7 +105,7 @@ func (l *wrappedProcessLogger) ProcessStart(msg string) { l.processes.push(p) - l.logger.InfoLn(msg) + l.logger.InfoF(msg) } func (l *wrappedProcessLogger) ProcessEnd() { @@ -116,7 +116,7 @@ func (l *wrappedProcessLogger) ProcessEnd() { msg = fmt.Sprintf("%s (%s)", p.Msg, p.formatTime()) } - l.logger.InfoLn(msg) + l.logger.InfoF(msg) } func (l *wrappedProcessLogger) ProcessFail() { @@ -127,5 +127,5 @@ func (l *wrappedProcessLogger) ProcessFail() { msg = fmt.Sprintf("%s FAILED (%s)", p.Msg, p.formatTime()) } - l.logger.ErrorLn(msg) + l.logger.ErrorF(msg) } diff --git a/pkg/log/process_test.go b/pkg/log/process_test.go index 457d8c9..fd8b7a4 100644 --- a/pkg/log/process_test.go +++ b/pkg/log/process_test.go @@ -99,4 +99,37 @@ func TestProcessLoggers(t *testing.T) { }) }) } + + t.Run("Add new line to process messages", func(t *testing.T) { + assertNewLine := func(t *testing.T, logger *InMemoryLogger, count int) { + startMatches, err := logger.AllMatches(&Match{ + Suffix: []string{"\n"}, + }) + + require.NoError(t, err) + require.Len(t, startMatches, count) + + for i := 0; i < count; i++ { + require.NotEmpty(t, startMatches[i], "should contains new line") + } + } + + expectedLoggerSuccess := NewInMemoryLoggerWithParent(NewPrettyLogger(LoggerOptions{})) + successLogger := newWrappedProcessLogger(expectedLoggerSuccess) + + successLogger.ProcessStart("Process start") + assertNewLine(t, expectedLoggerSuccess, 1) + + successLogger.ProcessEnd() + assertNewLine(t, expectedLoggerSuccess, 2) + + expectedLoggerFail := NewInMemoryLoggerWithParent(NewPrettyLogger(LoggerOptions{})) + failLogger := newWrappedProcessLogger(expectedLoggerFail) + + failLogger.ProcessStart("Process fail") + assertNewLine(t, expectedLoggerFail, 1) + + failLogger.ProcessFail() + assertNewLine(t, expectedLoggerFail, 2) + }) } diff --git a/pkg/log/silent.go b/pkg/log/silent.go index fa31259..d8914b0 100644 --- a/pkg/log/silent.go +++ b/pkg/log/silent.go @@ -74,6 +74,8 @@ func (d *SilentLogger) InfoFWithoutLn(format string, a ...interface{}) { } } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (d *SilentLogger) InfoLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -86,6 +88,8 @@ func (d *SilentLogger) ErrorFWithoutLn(format string, a ...interface{}) { } } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (d *SilentLogger) ErrorLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -98,6 +102,8 @@ func (d *SilentLogger) DebugFWithoutLn(format string, a ...interface{}) { } } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (d *SilentLogger) DebugLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -122,6 +128,8 @@ func (d *SilentLogger) FailRetry(l string) { } } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (d *SilentLogger) WarnLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) diff --git a/pkg/log/simple.go b/pkg/log/simple.go index c68daa2..559d224 100644 --- a/pkg/log/simple.go +++ b/pkg/log/simple.go @@ -85,6 +85,8 @@ func (d *SimpleLogger) InfoFWithoutLn(format string, a ...interface{}) { d.logger.Info(fmt.Sprintf(format, a...)) } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (d *SimpleLogger) InfoLn(a ...interface{}) { d.logger.Info(listToString(a)) } @@ -93,6 +95,8 @@ func (d *SimpleLogger) ErrorFWithoutLn(format string, a ...interface{}) { d.logger.Error(fmt.Sprintf(format, a...)) } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (d *SimpleLogger) ErrorLn(a ...interface{}) { d.logger.Error(listToString(a)) } @@ -103,6 +107,8 @@ func (d *SimpleLogger) DebugFWithoutLn(format string, a ...interface{}) { } } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (d *SimpleLogger) DebugLn(a ...interface{}) { if d.isDebug { d.logger.Debug(listToString(a)) @@ -126,6 +132,8 @@ func (d *SimpleLogger) WarnFWithoutLn(format string, a ...interface{}) { d.logger.Warn(fmt.Sprintf(format, a...)) } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (d *SimpleLogger) WarnLn(a ...interface{}) { d.logger.Warn(listToString(a)) } diff --git a/pkg/log/tee.go b/pkg/log/tee.go index e0766aa..e11b685 100644 --- a/pkg/log/tee.go +++ b/pkg/log/tee.go @@ -125,6 +125,8 @@ func (d *TeeLogger) InfoFWithoutLn(format string, a ...interface{}) { d.writeToFile(fmt.Sprintf(format, a...)) } +// InfoLn +// Deprecated: Use InfoF(string) it add \n to end func (d *TeeLogger) InfoLn(a ...interface{}) { d.l.InfoLn(a...) @@ -137,6 +139,8 @@ func (d *TeeLogger) ErrorFWithoutLn(format string, a ...interface{}) { d.writeToFile(fmt.Sprintf(format, a...)) } +// ErrorLn +// Deprecated: Use ErrorF(string) it add \n to end func (d *TeeLogger) ErrorLn(a ...interface{}) { d.l.ErrorLn(a...) @@ -149,6 +153,8 @@ func (d *TeeLogger) DebugFWithoutLn(format string, a ...interface{}) { d.writeToFile(fmt.Sprintf(format, a...)) } +// DebugLn +// Deprecated: Use DebugF(string) it add \n to end func (d *TeeLogger) DebugLn(a ...interface{}) { d.l.DebugLn(a...) @@ -173,6 +179,8 @@ func (d *TeeLogger) FailRetry(l string) { d.writeToFile(l) } +// WarnLn +// Deprecated: Use WarnF(string) it add \n to end func (d *TeeLogger) WarnLn(a ...interface{}) { d.l.WarnLn(a...) From d03631dc3b22b59c070f5771b3a2ff18abbca23c Mon Sep 17 00:00:00 2001 From: Nikolay Mitrofanov Date: Wed, 28 Jan 2026 22:55:16 +0300 Subject: [PATCH 4/5] fix deprecated comment Signed-off-by: Nikolay Mitrofanov --- pkg/log/logger.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/log/logger.go b/pkg/log/logger.go index d57036b..b8fea4f 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -128,6 +128,7 @@ type baseLogger interface { WarnFWithoutLn(format string, a ...interface{}) // WarnLn + // // Deprecated: Use WarnF(string) it add \n to end WarnLn(a ...interface{}) From ca4152f31e7c50a1f2377579b377f75cc700648c Mon Sep 17 00:00:00 2001 From: Nikolay Mitrofanov Date: Wed, 28 Jan 2026 23:31:23 +0300 Subject: [PATCH 5/5] trim last line Signed-off-by: Nikolay Mitrofanov --- pkg/log/dummy.go | 12 ++-- pkg/log/in_memory.go | 12 ++-- pkg/log/ln_logger_wrapper.go | 5 +- pkg/log/ln_logger_wrapper_test.go | 94 ++++++++++++++++++++++++++++++- pkg/log/logger.go | 17 ++++-- pkg/log/pretty.go | 12 ++-- pkg/log/silent.go | 12 ++-- pkg/log/simple.go | 12 ++-- pkg/log/tee.go | 12 ++-- 9 files changed, 156 insertions(+), 32 deletions(-) diff --git a/pkg/log/dummy.go b/pkg/log/dummy.go index f0ad42d..1ce93d0 100644 --- a/pkg/log/dummy.go +++ b/pkg/log/dummy.go @@ -71,7 +71,8 @@ func (d *DummyLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (d *DummyLogger) InfoLn(a ...interface{}) { fmt.Println(a...) } @@ -81,7 +82,8 @@ func (d *DummyLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (d *DummyLogger) ErrorLn(a ...interface{}) { fmt.Println(a...) } @@ -93,7 +95,8 @@ func (d *DummyLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (d *DummyLogger) DebugLn(a ...interface{}) { if d.isDebug { fmt.Println(a...) @@ -113,7 +116,8 @@ func (d *DummyLogger) FailRetry(l string) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (d *DummyLogger) WarnLn(a ...interface{}) { fmt.Println(a...) } diff --git a/pkg/log/in_memory.go b/pkg/log/in_memory.go index ad724fc..48cbbd7 100644 --- a/pkg/log/in_memory.go +++ b/pkg/log/in_memory.go @@ -173,7 +173,8 @@ func (l *InMemoryLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (l *InMemoryLogger) InfoLn(a ...interface{}) { l.writeEntityFormatted(listToString(a)) l.parent.InfoLn(a...) @@ -185,7 +186,8 @@ func (l *InMemoryLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (l *InMemoryLogger) ErrorLn(a ...interface{}) { l.writeEntityWithPrefix(l.errorPrefix, listToString(a)) l.parent.ErrorLn(a...) @@ -201,7 +203,8 @@ func (l *InMemoryLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (l *InMemoryLogger) DebugLn(a ...interface{}) { if l.notDebug { return @@ -217,7 +220,8 @@ func (l *InMemoryLogger) WarnFWithoutLn(format string, a ...interface{}) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (l *InMemoryLogger) WarnLn(a ...interface{}) { l.writeEntityFormatted(listToString(a)) l.parent.WarnLn(a...) diff --git a/pkg/log/ln_logger_wrapper.go b/pkg/log/ln_logger_wrapper.go index fc55d3a..67181fe 100644 --- a/pkg/log/ln_logger_wrapper.go +++ b/pkg/log/ln_logger_wrapper.go @@ -14,6 +14,8 @@ package log +import "strings" + // formatWithNewLineLogger // we often use *F function, but for pretty log we use "\n" in end of string // this interface and wrapper help us for get rit of this @@ -42,5 +44,6 @@ func (w *formatWithNewLineLoggerWrapper) WarnF(format string, a ...any) { } func addLnToFormat(format string) string { - return format + "\n" + // remove last new line to avoid add double new lines + return strings.TrimSuffix(format, "\n") + "\n" } diff --git a/pkg/log/ln_logger_wrapper_test.go b/pkg/log/ln_logger_wrapper_test.go index 0e469a7..2edd790 100644 --- a/pkg/log/ln_logger_wrapper_test.go +++ b/pkg/log/ln_logger_wrapper_test.go @@ -17,21 +17,80 @@ package log import ( "errors" "fmt" + "strings" "testing" "github.com/stretchr/testify/require" ) func TestLnLoggerWrapper(t *testing.T) { - logger := NewInMemoryLoggerWithParent(NewSimpleLogger(LoggerOptions{IsDebug: true})) + emptyStringTests := []struct { + name string + do func(w formatWithNewLineLogger) + }{ + { + name: "ErrorF", + do: func(w formatWithNewLineLogger) { + w.ErrorF("") + }, + }, - assertAddNewLine := func(t *testing.T, msg string) { + { + name: "WarnF", + do: func(w formatWithNewLineLogger) { + w.WarnF("") + }, + }, + + { + name: "InfoF", + do: func(w formatWithNewLineLogger) { + w.InfoF("") + }, + }, + + { + name: "DebugF", + do: func(w formatWithNewLineLogger) { + w.DebugF("") + }, + }, + } + + for _, test := range emptyStringTests { + t.Run(fmt.Sprintf("Log empty line for %s", test.name), func(t *testing.T) { + logger := NewInMemoryLoggerWithParent(NewPrettyLogger(LoggerOptions{IsDebug: true})) + wrapper := newFormatWithNewLineLoggerWrapper(logger) + + test.do(wrapper) + + matches, err := logger.AllMatches(&Match{ + Prefix: []string{"\n"}, + }) + + require.NoError(t, err) + require.Len(t, matches, 1, "should one match") + require.Equal(t, "\n", matches[0], "should produce new line") + }) + } + + logger := NewInMemoryLoggerWithParent(NewPrettyLogger(LoggerOptions{IsDebug: true})) + + assertAddNewLine := func(t *testing.T, msg string) string { matches, err := logger.AllMatches(&Match{ Prefix: []string{fmt.Sprintf("%s\n", msg)}, }) require.NoError(t, err) require.Len(t, matches, 1, msg) + + return matches[0] + } + + assertCountNewLines := func(t *testing.T, msg string, expected int) { + match := assertAddNewLine(t, msg) + count := strings.Count(match, "\n") + require.Equal(t, expected, count, "should contain %d trailing new lines", expected) } wrapper := newFormatWithNewLineLoggerWrapper(logger) @@ -42,18 +101,49 @@ func TestLnLoggerWrapper(t *testing.T) { wrapper.ErrorF("VariablesError %s %v", "msg", true) assertAddNewLine(t, "VariablesError msg true") + // trim one new line + wrapper.ErrorF("ErrorOneLn\n") + assertCountNewLines(t, "ErrorOneLn", 1) + // save multiple new lines expected one + wrapper.ErrorF("ErrorMultiLn\n\n\n") + assertCountNewLines(t, "ErrorMultiLn\n\n", 3) + wrapper.WarnF("Warn") assertAddNewLine(t, "Warn") wrapper.WarnF("VariablesWarn %s %v", "msg", true) assertAddNewLine(t, "VariablesWarn msg true") + // trim one new line + wrapper.WarnF("WarnOneLn\n") + assertCountNewLines(t, "WarnOneLn", 1) + // save multiple new lines expected one + wrapper.WarnF("WarnMultiLn\n\n") + assertCountNewLines(t, "WarnMultiLn\n", 2) + wrapper.InfoF("Info") assertAddNewLine(t, "Info") wrapper.InfoF("VariablesInfo %s %v", "msg", errors.New("error")) assertAddNewLine(t, "VariablesInfo msg error") + // trim one new line + wrapper.InfoF("InfoOneLn\n") + assertCountNewLines(t, "InfoOneLn", 1) + // save multiple new lines expected one + wrapper.InfoF("InfoMultiLn\n\n\n\n") + assertCountNewLines(t, "InfoMultiLn\n\n\n", 4) + + wrapper.DebugF("Debug") + assertAddNewLine(t, "Debug") + wrapper.DebugF("VariablesDebug %v %s", 42, "msg") assertAddNewLine(t, "VariablesDebug 42 msg") + + // trim one new line + wrapper.DebugF("DebugOneLn\n") + assertCountNewLines(t, "DebugOneLn", 1) + // save multiple new lines expected one + wrapper.DebugF("DebugMultiLn\n\n\n\n\n") + assertCountNewLines(t, "DebugMultiLn\n\n\n\n", 5) } diff --git a/pkg/log/logger.go b/pkg/log/logger.go index b8fea4f..6d3fdfd 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -110,26 +110,29 @@ type baseLogger interface { InfoFWithoutLn(format string, a ...interface{}) // InfoLn - // Deprecated: Use InfoF(string) it add \n to end + // Deprecated: + // Use InfoF(string) it add \n to end InfoLn(a ...interface{}) ErrorFWithoutLn(format string, a ...interface{}) // ErrorLn - // Deprecated: Use ErrorF(string) it add \n to end + // Deprecated: + // Use ErrorF(string) it add \n to end ErrorLn(a ...interface{}) DebugFWithoutLn(format string, a ...interface{}) // DebugLn - // Deprecated: Use DebugF(string) it add \n to end + // Deprecated: + // Use DebugF(string) it add \n to end DebugLn(a ...interface{}) WarnFWithoutLn(format string, a ...interface{}) // WarnLn - // - // Deprecated: Use WarnF(string) it add \n to end + // Deprecated: + // Use WarnF(string) it add \n to end WarnLn(a ...interface{}) Success(string) @@ -150,18 +153,22 @@ type formatWithNewLineLogger interface { // InfoF // Warning! InfoF add \n to end of message. // If you do not have \n to end of message please use InfoFWithoutLn + // Also trim last new line from format InfoF(format string, a ...any) // ErrorF // Warning! ErrorF add \n to end of message. // If you do not have \n to end of message please use ErrorFWithoutLn + // Also trim last new line from format ErrorF(format string, a ...any) // DebugF // Warning! DebugF add \n to end of message. // If you do not have \n to end of message please use DebugFWithoutLn + // Also trim last new line from format DebugF(format string, a ...any) // WarnF // Warning! WarnF add \n to end of message. // If you do not have \n to end of message please use WarnFWithoutLn + // Also trim last new line from format WarnF(format string, a ...any) } diff --git a/pkg/log/pretty.go b/pkg/log/pretty.go index 151dd7c..50d537d 100644 --- a/pkg/log/pretty.go +++ b/pkg/log/pretty.go @@ -122,7 +122,8 @@ func (d *PrettyLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (d *PrettyLogger) InfoLn(a ...interface{}) { d.logboekLogger.Info().LogLn(a...) } @@ -132,7 +133,8 @@ func (d *PrettyLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (d *PrettyLogger) ErrorLn(a ...interface{}) { d.logboekLogger.Error().LogLn(a...) } @@ -152,7 +154,8 @@ func (d *PrettyLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (d *PrettyLogger) DebugLn(a ...interface{}) { if d.debugLogWriter != nil { o := fmt.Sprintln(a...) @@ -180,7 +183,8 @@ func (d *PrettyLogger) FailRetry(l string) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (d *PrettyLogger) WarnLn(a ...interface{}) { a = append([]interface{}{"❗ ~ "}, a...) d.InfoLn(color.New(color.Bold).Sprint(a...)) diff --git a/pkg/log/silent.go b/pkg/log/silent.go index d8914b0..42b8a5a 100644 --- a/pkg/log/silent.go +++ b/pkg/log/silent.go @@ -75,7 +75,8 @@ func (d *SilentLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (d *SilentLogger) InfoLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -89,7 +90,8 @@ func (d *SilentLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (d *SilentLogger) ErrorLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -103,7 +105,8 @@ func (d *SilentLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (d *SilentLogger) DebugLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) @@ -129,7 +132,8 @@ func (d *SilentLogger) FailRetry(l string) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (d *SilentLogger) WarnLn(a ...interface{}) { if d.t != nil { d.t.writeToFile(fmt.Sprintln(a...)) diff --git a/pkg/log/simple.go b/pkg/log/simple.go index 559d224..66ad5b5 100644 --- a/pkg/log/simple.go +++ b/pkg/log/simple.go @@ -86,7 +86,8 @@ func (d *SimpleLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (d *SimpleLogger) InfoLn(a ...interface{}) { d.logger.Info(listToString(a)) } @@ -96,7 +97,8 @@ func (d *SimpleLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (d *SimpleLogger) ErrorLn(a ...interface{}) { d.logger.Error(listToString(a)) } @@ -108,7 +110,8 @@ func (d *SimpleLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (d *SimpleLogger) DebugLn(a ...interface{}) { if d.isDebug { d.logger.Debug(listToString(a)) @@ -133,7 +136,8 @@ func (d *SimpleLogger) WarnFWithoutLn(format string, a ...interface{}) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (d *SimpleLogger) WarnLn(a ...interface{}) { d.logger.Warn(listToString(a)) } diff --git a/pkg/log/tee.go b/pkg/log/tee.go index e11b685..d0d2d3f 100644 --- a/pkg/log/tee.go +++ b/pkg/log/tee.go @@ -126,7 +126,8 @@ func (d *TeeLogger) InfoFWithoutLn(format string, a ...interface{}) { } // InfoLn -// Deprecated: Use InfoF(string) it add \n to end +// Deprecated: +// Use InfoF(string) it add \n to end func (d *TeeLogger) InfoLn(a ...interface{}) { d.l.InfoLn(a...) @@ -140,7 +141,8 @@ func (d *TeeLogger) ErrorFWithoutLn(format string, a ...interface{}) { } // ErrorLn -// Deprecated: Use ErrorF(string) it add \n to end +// Deprecated: +// Use ErrorF(string) it add \n to end func (d *TeeLogger) ErrorLn(a ...interface{}) { d.l.ErrorLn(a...) @@ -154,7 +156,8 @@ func (d *TeeLogger) DebugFWithoutLn(format string, a ...interface{}) { } // DebugLn -// Deprecated: Use DebugF(string) it add \n to end +// Deprecated: +// Use DebugF(string) it add \n to end func (d *TeeLogger) DebugLn(a ...interface{}) { d.l.DebugLn(a...) @@ -180,7 +183,8 @@ func (d *TeeLogger) FailRetry(l string) { } // WarnLn -// Deprecated: Use WarnF(string) it add \n to end +// Deprecated: +// Use WarnF(string) it add \n to end func (d *TeeLogger) WarnLn(a ...interface{}) { d.l.WarnLn(a...)