From 2708bff1686ecc0e4756399e41c5c03459dd880c Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Thu, 19 Nov 2020 16:21:09 +0100 Subject: [PATCH 1/3] Amazing new verbose mode --- cmd/src/campaign_progress_printer.go | 94 ++++++++++++++++++++++++++-- cmd/src/campaigns_common.go | 2 +- internal/campaigns/service.go | 9 ++- 3 files changed, 93 insertions(+), 12 deletions(-) diff --git a/cmd/src/campaign_progress_printer.go b/cmd/src/campaign_progress_printer.go index 171659a377..71a55977ab 100644 --- a/cmd/src/campaign_progress_printer.go +++ b/cmd/src/campaign_progress_printer.go @@ -9,10 +9,12 @@ import ( "github.com/sourcegraph/src-cli/internal/output" ) -func newCampaignProgressPrinter(out *output.Output, numParallelism int) *campaignProgressPrinter { +func newCampaignProgressPrinter(out *output.Output, verbose bool, numParallelism int) *campaignProgressPrinter { return &campaignProgressPrinter{ out: out, + verbose: verbose, + numParallelism: numParallelism, completedTasks: map[string]bool{}, @@ -26,6 +28,8 @@ func newCampaignProgressPrinter(out *output.Output, numParallelism int) *campaig type campaignProgressPrinter struct { out *output.Output + verbose bool + progress output.ProgressWithStatusBars numStatusBars int @@ -134,14 +138,38 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus } for _, ts := range newlyCompleted { - statusText, err := taskStatusText(ts) + if p.verbose { + p.progress.WriteLine(output.Linef("", output.StylePending, "%s", ts.RepoName)) + + if ts.ChangesetSpec == nil { + p.progress.Verbosef(" No changes") + } else { + fileDiffs, err := diff.ParseMultiFileDiff([]byte(ts.ChangesetSpec.Commits[0].Diff)) + if err != nil { + p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) + continue + } + + lines, err := verboseDiffSummary(fileDiffs) + if err != nil { + p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) + continue + } + + for _, line := range lines { + p.progress.Verbose(line) + } + } + + p.progress.Verbose("") + } + + statusText, err := taskStatusBarText(ts) if err != nil { p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) continue } - p.progress.Verbosef("%-*s %s", p.maxRepoName, ts.RepoName, statusText) - if idx, ok := p.repoStatusBar[ts.RepoName]; ok { // Log that this task completed, but only if there is no // currently executing one in this bar, to avoid flicker. @@ -163,7 +191,7 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus continue } - statusText, err := taskStatusText(ts) + statusText, err := taskStatusBarText(ts) if err != nil { p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) continue @@ -181,7 +209,7 @@ type statusTexter interface { StatusText() string } -func taskStatusText(ts *campaigns.TaskStatus) (string, error) { +func taskStatusBarText(ts *campaigns.TaskStatus) (string, error) { var statusText string if ts.IsCompleted() { @@ -223,3 +251,57 @@ func taskStatusText(ts *campaigns.TaskStatus) (string, error) { return statusText, nil } + +func verboseDiffSummary(fileDiffs []*diff.FileDiff) ([]string, error) { + var ( + lines []string + + maxFilenameLen int + sumInsertions int + sumDeletions int + ) + + fileStats := make(map[string]string, len(fileDiffs)) + + for _, f := range fileDiffs { + name := f.NewName + if name == "/dev/null" { + name = f.OrigName + } + + if len(name) > maxFilenameLen { + maxFilenameLen = len(name) + } + + stat := f.Stat() + + sumInsertions += int(stat.Added) + int(stat.Changed) + sumDeletions += int(stat.Deleted) + int(stat.Changed) + + num := stat.Added + 2*stat.Changed + stat.Deleted + + fileStats[name] = fmt.Sprintf("%d %s", num, diffStatDiagram(stat)) + } + + for file, stats := range fileStats { + lines = append(lines, fmt.Sprintf("\t%-*s | %s", maxFilenameLen, file, stats)) + } + + var insertionsPlural string + if sumInsertions != 0 { + insertionsPlural = "s" + } + + var deletionsPlural string + if sumDeletions != 1 { + deletionsPlural = "s" + } + + lines = append(lines, fmt.Sprintf(" %s, %s, %s", + diffStatDescription(fileDiffs), + fmt.Sprintf("%d insertion%s", sumInsertions, insertionsPlural), + fmt.Sprintf("%d deletion%s", sumDeletions, deletionsPlural), + )) + + return lines, nil +} diff --git a/cmd/src/campaigns_common.go b/cmd/src/campaigns_common.go index c34545065d..6927d74788 100644 --- a/cmd/src/campaigns_common.go +++ b/cmd/src/campaigns_common.go @@ -232,7 +232,7 @@ func campaignsExecute(ctx context.Context, out *output.Output, svc *campaigns.Se campaignsCompletePending(pending, "Resolved repositories") } - p := newCampaignProgressPrinter(out, opts.Parallelism) + p := newCampaignProgressPrinter(out, *verbose, opts.Parallelism) specs, err := svc.ExecuteCampaignSpec(ctx, repos, executor, campaignSpec, p.PrintStatuses) if err != nil { return "", "", err diff --git a/internal/campaigns/service.go b/internal/campaigns/service.go index 6e15dae6df..5b285da17b 100644 --- a/internal/campaigns/service.go +++ b/internal/campaigns/service.go @@ -188,11 +188,10 @@ type ExecutorOpts struct { Parallelism int Timeout time.Duration - ClearCache bool - KeepLogs bool - VerboseLogger bool - TempDir string - CacheDir string + ClearCache bool + KeepLogs bool + TempDir string + CacheDir string } func (svc *Service) NewExecutor(opts ExecutorOpts) Executor { From 81c205c3b952d012c666233bb581abf8057b9a33 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Fri, 20 Nov 2020 17:56:03 +0100 Subject: [PATCH 2/3] Clean up code --- cmd/src/campaign_progress_printer.go | 29 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/cmd/src/campaign_progress_printer.go b/cmd/src/campaign_progress_printer.go index 71a55977ab..a8b7936755 100644 --- a/cmd/src/campaign_progress_printer.go +++ b/cmd/src/campaign_progress_printer.go @@ -138,18 +138,23 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus } for _, ts := range newlyCompleted { + var fileDiffs []*diff.FileDiff + + if ts.ChangesetSpec != nil { + var err error + fileDiffs, err = diff.ParseMultiFileDiff([]byte(ts.ChangesetSpec.Commits[0].Diff)) + if err != nil { + p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) + continue + } + } + if p.verbose { p.progress.WriteLine(output.Linef("", output.StylePending, "%s", ts.RepoName)) if ts.ChangesetSpec == nil { p.progress.Verbosef(" No changes") } else { - fileDiffs, err := diff.ParseMultiFileDiff([]byte(ts.ChangesetSpec.Commits[0].Diff)) - if err != nil { - p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) - continue - } - lines, err := verboseDiffSummary(fileDiffs) if err != nil { p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) @@ -164,16 +169,16 @@ func (p *campaignProgressPrinter) PrintStatuses(statuses []*campaigns.TaskStatus p.progress.Verbose("") } - statusText, err := taskStatusBarText(ts) - if err != nil { - p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) - continue - } - if idx, ok := p.repoStatusBar[ts.RepoName]; ok { // Log that this task completed, but only if there is no // currently executing one in this bar, to avoid flicker. if _, ok := p.statusBarRepo[idx]; !ok { + statusText, err := taskStatusBarText(ts) + if err != nil { + p.progress.Verbosef("%-*s failed to display status: %s", p.maxRepoName, ts.RepoName, err) + continue + } + if ts.Err != nil { p.progress.StatusBarFailf(idx, statusText) } else { From cfd7ee1a97e9a41b23f1118a34746c67bf7ca2b0 Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Mon, 23 Nov 2020 09:05:09 +0100 Subject: [PATCH 3/3] Add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5310caf3b..52fdf22383 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ All notable changes to `src-cli` are documented in this file. ### Changed +- `src campaign [apply|preview]` now prints more detailed information about the diffs produced in each repository when run in verbose mode with `-v`. [#390](https://github.com/sourcegraph/src-cli/pull/390) + ### Fixed - If `src campaign [validate|apply|preview]` was aborted while it was downloading repository archives it could leave behind partial ZIP files that would produce an error on the next run. This is now fixed by deleting partial files on abort. [#388](https://github.com/sourcegraph/src-cli/pull/388)