Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions e2e/converge_progress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,28 @@ step: verify.#Step & { checks: [{
}
got := string(out)

wants := []string{
"yconverge dependency base",
"yconverge converge-mode=replace",
"yconverge target dependent",
// userPath in pkg/yconverge prints CWD-relative paths so the
// shown form matches what -k accepts. Tests run with CWD set
// to the e2e/ package dir, so the resolved path traverses
// up to /tmp/<TestName>/... -- we substring-match the segment
// the user would care about ("/base" / "/dependent") rather
// than pinning the long ../../../tmp/.../ prefix.
wantSubs := []string{
"yconverge dependency",
"/base\nyconverge converge-mode=replace\n",
"yconverge target",
"/dependent\n",
"yconverge check 1/1 exec",
}
for _, w := range wants {
for _, w := range wantSubs {
if !strings.Contains(got, w) {
t.Errorf("missing progress line %q\nfull output:\n%s", w, got)
t.Errorf("missing progress substring %q\nfull output:\n%s", w, got)
}
}

// Order matters: dependency before target, target before check.
depIdx := strings.Index(got, "yconverge dependency base")
tgtIdx := strings.Index(got, "yconverge target dependent")
depIdx := strings.Index(got, "yconverge dependency")
tgtIdx := strings.Index(got, "yconverge target")
chkIdx := strings.Index(got, "yconverge check 1/1 exec")
if !(depIdx < tgtIdx && tgtIdx < chkIdx) {
t.Errorf("progress lines out of order: dep=%d target=%d check=%d\nfull output:\n%s",
Expand Down
40 changes: 40 additions & 0 deletions pkg/yconverge/userpath_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package yconverge

import (
"os"
"path/filepath"
"strings"
"testing"
)

// TestUserPath_RelativeToCWD: a path under cwd renders as a
// short relative string -- the shape `-k <path>` accepts and
// the user can `cd` to.
func TestUserPath_RelativeToCWD(t *testing.T) {
tmp := t.TempDir()
t.Chdir(tmp)
got := userPath(filepath.Join(tmp, "base"))
if got != "base" {
t.Fatalf("got %q, want %q", got, "base")
}
}

// TestUserPath_TraversesUp: a path outside cwd produces the
// `../...` form. Long but still actionable in a shell.
func TestUserPath_TraversesUp(t *testing.T) {
root := t.TempDir()
if err := os.MkdirAll(filepath.Join(root, "a/b"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(filepath.Join(root, "x"), 0o755); err != nil {
t.Fatal(err)
}
t.Chdir(filepath.Join(root, "a/b"))
got := userPath(filepath.Join(root, "x"))
if !strings.HasPrefix(got, "..") {
t.Fatalf("got %q, expected `..`-prefixed path", got)
}
if !strings.HasSuffix(got, "/x") {
t.Fatalf("got %q, expected trailing /x", got)
}
}
33 changes: 28 additions & 5 deletions pkg/yconverge/yconverge.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ func (o Options) progressOut() io.Writer {
return os.Stdout
}

// userPath turns an absolute filesystem path into something
// readable to the user: a CWD-relative form that matches the
// shape of the -k argument they typed. Tab-completion and a
// follow-up `cd <shown>` Just Work.
//
// Falls back to the absolute path when filepath.Rel can't
// compute one (rare; happens across drive letters on Windows
// or when the cwd is otherwise unrelated to the target).
//
// The diagnostic zap log lines keep RelPath(cueRoot, step) --
// structured fields meant for log aggregation are more useful
// in module-relative form, which doesn't depend on cwd-at-log-time.
func userPath(absPath string) string {
cwd, err := os.Getwd()
if err != nil {
return absPath
}
rel, err := filepath.Rel(cwd, absPath)
if err != nil {
return absPath
}
return rel
}

// Result holds the outcome of a yconverge run.
type Result struct {
// Steps lists the directories that were converged, in order.
Expand Down Expand Up @@ -111,9 +135,8 @@ func Run(ctx context.Context, opts Options, logger *zap.Logger) (*Result, error)
zap.Int("steps", len(steps)),
)
for _, step := range steps[:len(steps)-1] {
rel := RelPath(cueRoot, step)
logger.Debug("converge dependency", zap.String("dir", rel))
fmt.Fprintf(opts.progressOut(), "yconverge dependency %s\n", rel)
logger.Debug("converge dependency", zap.String("dir", RelPath(cueRoot, step)))
fmt.Fprintf(opts.progressOut(), "yconverge dependency %s\n", userPath(step))
depOpts := Options{
Context: opts.Context,
KustomizeDir: step,
Expand All @@ -127,7 +150,7 @@ func Run(ctx context.Context, opts Options, logger *zap.Logger) (*Result, error)
Stdout: opts.Stdout,
}
if _, err := convergeSingle(ctx, depOpts, logger); err != nil {
return nil, fmt.Errorf("dependency %s: %w", rel, err)
return nil, fmt.Errorf("dependency %s: %w", userPath(step), err)
}
}
}
Expand All @@ -137,7 +160,7 @@ func Run(ctx context.Context, opts Options, logger *zap.Logger) (*Result, error)
// header for what the user explicitly passed via -k.
logger.Debug("converge target", zap.String("dir", RelPath(cueRoot, absDir)))
if hasDeps {
fmt.Fprintf(opts.progressOut(), "yconverge target %s\n", RelPath(cueRoot, absDir))
fmt.Fprintf(opts.progressOut(), "yconverge target %s\n", userPath(absDir))
}
if _, err := convergeSingle(ctx, opts, logger); err != nil {
return nil, err
Expand Down