From e0dda22fe967ee06f21ff6880696644f6dc9b4ec Mon Sep 17 00:00:00 2001 From: Denis Bilenko Date: Fri, 24 Jan 2025 17:25:36 +0100 Subject: [PATCH] add acceptance/selftest --- acceptance/bundle/git-permerror/output.txt | 9 + .../bundle/templates/dbt-sql/output.txt | 1 + .../templates/default-python/output.txt | 1 + .../bundle/templates/default-sql/output.txt | 1 + libs/log/handler/friendly.go | 158 +----------------- 5 files changed, 21 insertions(+), 149 deletions(-) diff --git a/acceptance/bundle/git-permerror/output.txt b/acceptance/bundle/git-permerror/output.txt index 2b52134ab..c0214ca60 100644 --- a/acceptance/bundle/git-permerror/output.txt +++ b/acceptance/bundle/git-permerror/output.txt @@ -3,6 +3,7 @@ >>> chmod 000 .git >>> $CLI bundle validate +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied Name: git-permerror @@ -16,6 +17,7 @@ Found 1 error Exit code: 1 >>> $CLI bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied @@ -26,6 +28,7 @@ Exit code: 1 } >>> withdir subdir/a/b $CLI bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied @@ -41,12 +44,16 @@ Exit code: 1 >>> chmod 000 .git/HEAD >>> $CLI bundle validate -o json +Warn: failed to load current branch: open HEAD: permission denied +Warn: failed to load latest commit: open HEAD: permission denied { "bundle_root_path": ".", "inferred": true } >>> withdir subdir/a/b $CLI bundle validate -o json +Warn: failed to load current branch: open HEAD: permission denied +Warn: failed to load latest commit: open HEAD: permission denied { "bundle_root_path": ".", "inferred": true @@ -58,6 +65,7 @@ Exit code: 1 >>> chmod 000 .git/config >>> $CLI bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied @@ -68,6 +76,7 @@ Exit code: 1 } >>> withdir subdir/a/b $CLI bundle validate -o json +Warn: failed to read .git: unable to load repository specific gitconfig: open config: permission denied Error: unable to load repository specific gitconfig: open config: permission denied diff --git a/acceptance/bundle/templates/dbt-sql/output.txt b/acceptance/bundle/templates/dbt-sql/output.txt index 972c7e152..a04047faa 100644 --- a/acceptance/bundle/templates/dbt-sql/output.txt +++ b/acceptance/bundle/templates/dbt-sql/output.txt @@ -22,6 +22,7 @@ Workspace: Validation OK! >>> $CLI bundle validate -t prod +Warn: target with 'mode: production' should specify an explicit 'targets.prod.git' configuration Name: my_dbt_sql Target: prod Workspace: diff --git a/acceptance/bundle/templates/default-python/output.txt b/acceptance/bundle/templates/default-python/output.txt index 5493ac2cf..8c925e568 100644 --- a/acceptance/bundle/templates/default-python/output.txt +++ b/acceptance/bundle/templates/default-python/output.txt @@ -20,6 +20,7 @@ Workspace: Validation OK! >>> $CLI bundle validate -t prod +Warn: target with 'mode: production' should specify an explicit 'targets.prod.git' configuration Name: my_default_python Target: prod Workspace: diff --git a/acceptance/bundle/templates/default-sql/output.txt b/acceptance/bundle/templates/default-sql/output.txt index fe0139093..d07e90c69 100644 --- a/acceptance/bundle/templates/default-sql/output.txt +++ b/acceptance/bundle/templates/default-sql/output.txt @@ -22,6 +22,7 @@ Workspace: Validation OK! >>> $CLI bundle validate -t prod +Warn: target with 'mode: production' should specify an explicit 'targets.prod.git' configuration Name: my_default_sql Target: prod Workspace: diff --git a/libs/log/handler/friendly.go b/libs/log/handler/friendly.go index 33b88a9e2..cd03a75e3 100644 --- a/libs/log/handler/friendly.go +++ b/libs/log/handler/friendly.go @@ -5,9 +5,7 @@ import ( "fmt" "io" "log/slog" - "strings" "sync" - "time" "github.com/databricks/cli/libs/log" ) @@ -19,7 +17,6 @@ import ( // https://github.com/golang/example/blob/master/slog-handler-guide/README.md type friendlyHandler struct { opts Options - goas []groupOrAttrs mu *sync.Mutex out io.Writer @@ -53,11 +50,11 @@ func NewFriendlyHandler(out io.Writer, opts *Options) slog.Handler { // Cache (colorized) level strings. // The colors to use for each level are configured in `colors.go`. - h.levelTrace = h.sprintf(ttyColorLevelTrace, "%5s", "TRACE") - h.levelDebug = h.sprintf(ttyColorLevelDebug, "%5s", "DEBUG") - h.levelInfo = h.sprintf(ttyColorLevelInfo, "%5s", "INFO") - h.levelWarn = h.sprintf(ttyColorLevelWarn, "%5s", "WARN") - h.levelError = h.sprintf(ttyColorLevelError, "%5s", "ERROR") + h.levelTrace = h.sprintf(ttyColorLevelTrace, "%s", "Trace: ") + h.levelDebug = h.sprintf(ttyColorLevelDebug, "%s", "Debug: ") + h.levelInfo = h.sprintf(ttyColorLevelInfo, "%s", "Info: ") + h.levelWarn = h.sprintf(ttyColorLevelWarn, "%s", "Warn: ") + h.levelError = h.sprintf(ttyColorLevelError, "%s", "Error: ") return h } @@ -90,159 +87,22 @@ func (h *friendlyHandler) Enabled(ctx context.Context, level slog.Level) bool { return level >= h.opts.Level.Level() } -type handleState struct { - h *friendlyHandler - - buf []byte - prefix string - - // Keep stack of groups to pass to [slog.ReplaceAttr] function. - groups []string -} - -func (h *friendlyHandler) handleState() *handleState { - return &handleState{ - h: h, - - buf: make([]byte, 0, 1024), - prefix: "", - } -} - -func (s *handleState) openGroup(name string) { - s.groups = append(s.groups, name) - s.prefix += name + "." -} - -func (s *handleState) closeGroup(name string) { - s.prefix = s.prefix[:len(s.prefix)-len(name)-1] - s.groups = s.groups[:len(s.groups)-1] -} - -func (s *handleState) append(args ...any) { - s.buf = fmt.Append(s.buf, args...) -} - -func (s *handleState) appendf(format string, args ...any) { - s.buf = fmt.Appendf(s.buf, format, args...) -} - -func (s *handleState) appendAttr(a slog.Attr) { - if rep := s.h.opts.ReplaceAttr; rep != nil && a.Value.Kind() != slog.KindGroup { - // Resolve before calling ReplaceAttr, so the user doesn't have to. - a.Value = a.Value.Resolve() - a = rep(s.groups, a) - } - - // Resolve the Attr's value before doing anything else. - a.Value = a.Value.Resolve() - - // Ignore empty Attrs. - if a.Equal(slog.Attr{}) { - return - } - - switch a.Value.Kind() { - case slog.KindGroup: - attrs := a.Value.Group() - // Output only non-empty groups. - if len(attrs) > 0 { - if a.Key != "" { - s.openGroup(a.Key) - } - for _, aa := range attrs { - s.appendAttr(aa) - } - if a.Key != "" { - s.closeGroup(a.Key) - } - } - case slog.KindTime: - s.append( - " ", - s.h.sprint(ttyColorAttrKey, s.prefix, a.Key), - s.h.sprint(ttyColorAttrSeparator, "="), - s.h.sprint(ttyColorAttrValue, a.Value.Time().Format(time.RFC3339Nano)), - ) - default: - str := a.Value.String() - format := "%s" - - // Quote values wih spaces, to make them easy to parse. - if strings.ContainsAny(str, " \t\n") { - format = "%q" - } - - s.append( - " ", - s.h.sprint(ttyColorAttrKey, s.prefix, a.Key), - s.h.sprint(ttyColorAttrSeparator, "="), - s.h.sprint(ttyColorAttrValue, fmt.Sprintf(format, str)), - ) - } -} - // Handle implements slog.Handler. func (h *friendlyHandler) Handle(ctx context.Context, r slog.Record) error { - state := h.handleState() - state.append(h.sprintf(ttyColorTime, "%02d:%02d:%02d ", r.Time.Hour(), r.Time.Minute(), r.Time.Second())) - state.appendf("%s ", h.coloredLevel(r)) - state.append(h.sprint(ttyColorMessage, r.Message)) + out := fmt.Sprintf("%s%s\n", h.coloredLevel(r), h.sprint(ttyColorMessage, r.Message)) - // Handle state from WithGroup and WithAttrs. - goas := h.goas - if r.NumAttrs() == 0 { - // If the record has no Attrs, remove groups at the end of the list; they are empty. - for len(goas) > 0 && goas[len(goas)-1].group != "" { - goas = goas[:len(goas)-1] - } - } - for _, goa := range goas { - if goa.group != "" { - state.openGroup(goa.group) - } else { - for _, a := range goa.attrs { - state.appendAttr(a) - } - } - } - - // Add attributes from the record. - r.Attrs(func(a slog.Attr) bool { - state.appendAttr(a) - return true - }) - - // Add newline. - state.append("\n") - - // Write the log line. h.mu.Lock() defer h.mu.Unlock() - _, err := h.out.Write(state.buf) + _, err := h.out.Write([]byte(out)) return err } -func (h *friendlyHandler) withGroupOrAttrs(goa groupOrAttrs) *friendlyHandler { - h2 := *h - h2.goas = make([]groupOrAttrs, len(h.goas)+1) - copy(h2.goas, h.goas) - h2.goas[len(h2.goas)-1] = goa - return &h2 -} - // WithGroup implements slog.Handler. func (h *friendlyHandler) WithGroup(name string) slog.Handler { - if name == "" { - return h - } - return h.withGroupOrAttrs(groupOrAttrs{group: name}) + return h } // WithAttrs implements slog.Handler. func (h *friendlyHandler) WithAttrs(attrs []slog.Attr) slog.Handler { - if len(attrs) == 0 { - return h - } - return h.withGroupOrAttrs(groupOrAttrs{attrs: attrs}) + return h }