diff --git a/README.md b/README.md index a047e37..be19792 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Built on AvaloniaEdit; editor components adapted from [ILSpy](https://github.com Siegi and Chris recorded a brief [Introduction to Stampeded!](https://youtu.be/r16YIcvLlg4) for you to get a glimpse at what the IRE is capable of. +To see it at work on a C# repository, take the [feature tours](docs/tour/README.md): eight short walks with screenshots, each under five minutes, that you can follow in a demo repository. + # Motivation ## What was great in eg gitk, Fork and other tools? diff --git a/docs/README.md b/docs/README.md index d8c6030..06124a6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,6 +16,8 @@ Start with [architecture.md](architecture.md). The rest can be read in any order `CLAUDE.md` in the repository root is the short orientation version of the same material. +What the tool does, as opposed to how it is built, is in the [feature tours](tour/README.md). + ## The shortest possible tour A review is opened (`ReviewWorkspace.OpenPrAsync`), which fetches the PR head, computes the merge diff --git a/docs/tour/01-open-and-read.md b/docs/tour/01-open-and-read.md new file mode 100644 index 0000000..e8cb7dc --- /dev/null +++ b/docs/tour/01-open-and-read.md @@ -0,0 +1,77 @@ +# Tour 1: Open a pull request and read it + +Reading a review here is mostly a keyboard job: file by file, hunk by hunk. This tour takes +pull request #1 of the demo repository from the start page to the last file. + +## 1. The start page + +**Review > Open from URL...**, `christophwille/stampeded-demo`. + +![The start page: repositories, open pull requests, branches](images/01-01-start-page.png) + +Three columns: repositories you've opened recently, the open pull requests with CI state and +size, and your local branches - each with the pull request it belongs to and whether it still +matches the remote. Start typing in any list to filter it. + +## 2. The overview + +Double-click **#1 Price herds by weight class**. + +![The overview of pull request #1](images/01-02-overview.png) + +This is the review's home tab: a rough reading-time estimate, CI, who has reviewed, the +linked issue, the description rendered. The Explorer on the left lists the changed files in +reading order - tests first, since they tell you what the change is supposed to do. Below it +is the whole repository at the pull request's head, not only the files that changed. + +Your clone was not touched to get here. The head sits in a detached worktree in the tool's +cache; your working tree and index stay as they were. + +## 3. The first file + +Press `]`. + +![A unified diff with word-level changes](images/01-03-first-file.png) + +`]` and `[` step through the files. You get both line numbers, the changed words inside a +changed line, and syntax colours and folding as in an editor. That's not cosmetic: the diff +really is source code to the tool, which is what tour 2 is about. + +## 4. Hunks and viewed flags + +`n` and `p` jump between hunks. `v` marks the file viewed and opens the next one - and so does +`n` once you're past the last hunk. + +![Two files ticked off in the Explorer](images/01-04-viewed-and-on.png) + +`o` takes you to the overview and back to the file you came from. + +## 5. Collapsed context and resolved threads + +![Unchanged lines folded into a bar, a resolved thread on one line](images/01-05-context-gap.png) + +Unchanged runs collapse into a bar that tells you how many lines it hides. Click it to get +them back, all at once or twenty at a time. A resolved thread shrinks to a single line until +you ask for it. The strip along the right edge is the whole file at a glance: red and green +where it changed, amber where somebody commented. + +## 6. Side by side + +**View > Side-by-Side Layout**. + +![The same file, side by side](images/01-06-side-by-side.png) + +Your choice sticks. Either way, a file is one tab. + +## 7. Closing and reopening + +Quit halfway through and open the pull request again: the files you ticked are still ticked. +That state is local, keyed by repository and pull request - and it's what tour 5 builds on +when the author pushes again. + +One oddity in this pull request: the author renamed `Pricing.cs` to `PriceCalculator.cs`, but +you see one file added and one deleted. Over the whole change, too little of the file +survives for git to call it a rename. [Tour 3](03-commit-by-commit.md) reads the same change +commit by commit, and there it is one. + +Next: [Navigate the code in the diff](02-navigate-the-code.md) diff --git a/docs/tour/02-navigate-the-code.md b/docs/tour/02-navigate-the-code.md new file mode 100644 index 0000000..98861a3 --- /dev/null +++ b/docs/tour/02-navigate-the-code.md @@ -0,0 +1,78 @@ +# Tour 2: Navigate the code in the diff + +A web diff is text. Here, both sides of the diff are compiled: Roslyn loads the solution at +the pull request's head, plus a second view of it as it was at the merge base. So whatever +your IDE can tell you about a symbol, the diff can too - on added lines, context lines and +removed lines alike. + +Open pull request #1 of the demo repository and go to `src/Corral/HerdReport.cs`. The +References pane tells you when the solution has loaded; for the demo that's a few seconds. + +## 1. Hover + +Rest the pointer on `ClassOf`. + +![Quick info for a method, over the diff](images/02-01-hover.png) + +Signature, doc comment and null state, same as in the IDE. + +## 2. Go to definition + +Put the caret on `ClassOf` and press `F12`, or Ctrl+click it. + +![The definition, in the file that declares it](images/02-02-definition.png) + +If the target file is part of the change you land in its diff, otherwise in plain source. +`Alt+Left` takes you back, `Alt+Right` forward again. + +## 3. Find references + +`Shift+F12` on `PriceFor`. + +![References, the ones on changed lines marked](images/02-03-references.png) + +A `*` marks the references on lines this pull request changes, so you can tell the call sites +the author touched from the ones that were left alone. Double-click to jump. + +## 4. Go to definition from a removed line + +One of the removed lines in `HerdReport.cs` calls `pricing.FlatPrice(a)`, a method this pull +request deletes. Put the caret on it and press `F12`. + +![The deleted method, reached from a removed line](images/02-04-removed-code.png) + +You land in `Pricing.cs` as it was before the change - a file that doesn't exist at the head +any more. Hover and find references work there as well, so "what did this do, and who else +called it?" doesn't mean leaving the review. + +## 5. Go to definition in a NuGet package + +`F12` on `Humanize`, which comes from the Humanizer package. + +![A type from a NuGet package, decompiled](images/02-05-decompiled.png) + +No source in the repository, so the type is decompiled and opened read-only. + +## 6. Call graph + +Caret on `Summarize`, then **Navigate > Call Graph from Caret**. + +![The call graph of a changed method](images/02-06-call-graph.png) + +Incoming and outgoing calls, expandable level by level. Tick **Only members this review +changes** to cut the graph down to the part the pull request is actually about. + +## 7. Structure and Map + +Two more panes share the Explorer's corner. **Structure** is the outline of the file in +front, with the members the change touches tinted: + +![The outline of the file in front](images/02-07-structure.png) + +**Map** lists every changed member of the pull request, grouped by file - green for added, +blue for modified, red for removed. One look tells you this change drops a method, adds an +enum and rewrites one function, before you've read a line of it: + +![Every changed member of the pull request](images/02-08-change-map.png) + +Next: [Read it commit by commit](03-commit-by-commit.md) diff --git a/docs/tour/03-commit-by-commit.md b/docs/tour/03-commit-by-commit.md new file mode 100644 index 0000000..48214a6 --- /dev/null +++ b/docs/tour/03-commit-by-commit.md @@ -0,0 +1,68 @@ +# Tour 3: Read it commit by commit + +Some pull requests are a series: each commit one step, meant to be read in order. Pull +request #1 of the demo repository is four of them, and its description says what each is for. + +## 1. Enter the commit scope + +**Review > Commit by Commit**, or the first button in the Explorer's toolbar. + +![The review narrowed to its first commit](images/03-01-commit-scope.png) + +Everything goes purple, so you can't mistake one commit for the whole change. The Explorer +shows the commit message and only the files that commit touched, and the overview is +recomputed for it. + +## 2. The rename, as a rename + +Open `PriceCalculator.cs`. + +![The first commit: a rename and one changed line](images/03-02-rename.png) + +In the whole change this file looked brand new (tour 1). In the commit that renamed it, it's +an `R` and a single changed line. + +## 3. Step through the commits + +`Ctrl+]` goes to the next commit, `Ctrl+[` to the previous one. + +![The second commit](images/03-03-next-commit.png) + +Viewed flags are kept per commit, so `v` works the way it does in the whole change. Comments +belong to the pull request: the thread on line 13 shows up in the commit that wrote that +line. + +**Review > Whole Change** gets you out again. Try to approve with part of the series unread +and you'll be told so instead. + +## 4. The Commits pane + +Back in the whole change, open **Commits**. + +![Commits of the review, the files of one, its message](images/03-04-commits-pane.png) + +Select a commit to see its files and full message. Double-click a file to see what that one +commit did to it, without switching scope. + +## 5. Blame + +Press `b`. + +![The blame margin on a diff](images/03-05-blame.png) + +Both sides get blamed: a removed line shows the commit that originally wrote it, an added +line the commit of this pull request that added it. The margin is tinted by age, so the lines +this pull request wrote stand out from the ones it inherited. + +## 6. File history + +The **History** pane follows whatever file is in front. + +![The history of the file in front](images/03-06-history.png) + +It lists the commits that touched the file on the branch your clone has checked out - in +other words, where the file was before this change. Double-click a commit for its diff. +**Navigate > History of Selection** searches the same history for the commits that added or +removed the text you've selected. + +Next: [Comment and submit](04-comment-and-submit.md) diff --git a/docs/tour/04-comment-and-submit.md b/docs/tour/04-comment-and-submit.md new file mode 100644 index 0000000..a4289e8 --- /dev/null +++ b/docs/tour/04-comment-and-submit.md @@ -0,0 +1,74 @@ +# Tour 4: Comment and submit + +You write comments right where the code is, and they stay on your machine until you submit. +The author gets one review, not a drip of notifications. + +Open pull request #1 of the demo repository and go to `src/Corral/PriceCalculator.cs`. + +## 1. Existing threads + +![A posted thread between the lines it is about](images/04-01-thread.png) + +Threads from the host sit in the diff, under the line they're about, with Reply and Resolve +right there. The Explorer shows a count per file: amber while something is still open, green +once it's all settled. + +## 2. Comment at the caret + +Put the caret on a line and press `c`. + +![The comment editor on a line](images/04-02-comment-editor.png) + +`Ctrl+Enter` saves, `Esc` closes. Once you've typed something, clicking into the code behind +the editor won't dismiss it and take your text with it. + +## 3. Drafts + +![The draft, in place](images/04-03-draft.png) + +The draft sits where it will be posted, with Edit and Delete on it, and it's still there +after you close the app. + +## 4. Suggest a change + +`c` on another line, then **Suggest a change**. The editor is prefilled with a suggestion +block holding that line, ready for you to rewrite. + +![A suggestion being written](images/04-04-suggestion.png) + +On GitHub the author can commit a suggestion with one click. Azure DevOps has no such thing, +so there it posts as a plain code block. + +## 5. Reply + +Click **Reply** on the posted thread. + +![A reply and a suggestion, both drafts](images/04-05-reply.png) + +Replies are drafts too. + +## 6. The Comments pane and the review page + +The **Comments** pane lists every draft and posted comment of the review. Double-click one to +go to it. + +![The Comments pane](images/04-06-comments-pane.png) + +**Review > Approve / Request Changes...** opens the review page: each comment quoted with the +code around it, the way the author will see it. The summary goes in the box at the bottom. + +![The review page before submitting](images/04-07-review.png) + +## 7. Submit + +![The review after submitting](images/04-08-submitted.png) + +**Comment** posts the three drafts as one review. **Approve** and **Request Changes** are +greyed out in this picture because it was taken by the pull request's own author, and GitHub +doesn't accept either verdict from the author. On somebody else's pull request they're live. + +If a draft sits on a line the host would reject - outside the diff, or in a generated file - +it's kept as a local draft instead of sinking the whole review, and the result line tells you +how many were. + +Next: [Come back after a force push](05-after-a-force-push.md) diff --git a/docs/tour/05-after-a-force-push.md b/docs/tour/05-after-a-force-push.md new file mode 100644 index 0000000..5b16714 --- /dev/null +++ b/docs/tour/05-after-a-force-push.md @@ -0,0 +1,57 @@ +# Tour 5: Come back after a force push + +You've read a pull request. Then the author rebases onto a newer `main`, amends a commit and +force-pushes. On the web you're more or less starting over: the commits you read are gone, +and "changes since your last review" is either unavailable or full of other people's work +that came along with the rebase. + +This tour needs a push, so you can't follow it in the shared demo repository. Fork it and run +its `stage.ps1` if you want to try it yourself. + +## 1. The first pass + +Pull request #2, every file ticked off with `v`. There's one thread, on line 29 of `Herd.cs`. + +![The first pass: all files viewed, a comment on line 29](images/05-01-first-pass.png) + +## 2. The push + +The author rebases onto `main` (which gained a commit in the meantime), moves `IsValidBrand` +to the end of its file and adds a third commit. `stage.ps1 -Push2` does exactly that. + +Reload with `F5`, or simply open the pull request again. + +![After the push: two files still ticked, the rest marked new](images/05-02-after-the-push.png) + +The two files that read the same as before are still ticked. The other six are unticked +again - you did read them, just not as they are now - and `new!` flags a file that changed +since you did. + +## 3. Since your last pass + +**Review > Since Last Pass**. + +![Only what the author changed since the first reading](images/05-03-since-last-pass.png) + +Three files instead of eight, and in them only what the author actually edited. Whatever +`main` brought in through the rebase is not in this diff, even though it is part of the +difference between the two pushes. + +The trick: this isn't old head against new head. The work you already read is replayed onto +the new base as a tree, and the new head is diffed against that. The window stays orange for +as long as you're in this scope. + +**Review > Last Pass Was** lets you pick what counts as your last pass: the last file you +ticked off (the default, because opening a review isn't the same as reading it), your last +submitted review, or the last time you opened it. + +## 4. Comments after the push + +![The thread, now on line 38](images/05-04-moved-comment.png) + +The thread was written against line 29 of a commit that's no longer on the branch. It now +sits on line 38: same statement, in the method that moved. When the host can no longer say +which line a comment belongs to, the line is found again by its content - and if that fails, +by the member it was written in. + +Next: [CI, tests and coverage](06-ci-tests-coverage.md) diff --git a/docs/tour/06-ci-tests-coverage.md b/docs/tour/06-ci-tests-coverage.md new file mode 100644 index 0000000..ac541a6 --- /dev/null +++ b/docs/tour/06-ci-tests-coverage.md @@ -0,0 +1,54 @@ +# Tour 6: CI, tests and coverage + +A red check tells you something failed. This tour goes from there to the line that's wrong, +and to the lines no test ran at all - on the pull request's head, without checking anything +out. + +Open pull request #3 of the demo repository. One of its tests fails on purpose. + +## 1. Checks + +![A failing check on the overview and in the Checks pane](images/06-01-checks.png) + +The overview doesn't hide it: CI is failing, is this even ready for review? The **Checks** +pane lists the runs, failures first. Double-click a failed run and you get the log of the +step that failed, not the whole job. + +## 2. Run the tests + +**Tools > Run Tests**. + +![The failing test in the Tests pane](images/06-02-tests.png) + +The tests run in the head worktree, so the result is the pull request's and your own checkout +stays out of it. Failures are listed above the live output; double-click one to open the +frame it failed in. The command line is yours to edit if you want a filter or a different +solution. + +## 3. Coverage + +**Tools > Run + Coverage**, then open `src/Corral/Herd.cs`. + +![Covered and uncovered added lines in the gutter](images/06-03-coverage.png) + +The strip next to the line numbers is green where a test ran the line and red where none +did. `u` jumps to the next *added* line without coverage, and the Explorer shows how many +each file has (`5!`). Here, `Clear()` was added and no test ever calls it. + +This wraps the run in `dotnet-coverage`, which you need to install once: +`dotnet tool install -g dotnet-coverage`. + +## 4. Run A/B: base against head + +**Tools > Run A/B (base vs head)**. + +![Test output of base and head, side by side](images/06-04-a-b.png) + +The tests run at the merge base and again at the head, and the result line is about the +difference: one test newly failing, none fixed, none already broken at the base. The two +outputs open as a diff. + +**Tools > Impacted Test Filter** fills in a filter for the tests the change affects - handy +when the full suite is too slow to run for every review. + +Next: [Review a local branch](07-local-branches.md) diff --git a/docs/tour/07-local-branches.md b/docs/tour/07-local-branches.md new file mode 100644 index 0000000..22e531b --- /dev/null +++ b/docs/tour/07-local-branches.md @@ -0,0 +1,47 @@ +# Tour 7: Review a local branch + +None of the earlier tours actually needs a pull request. You can review your own branch the +same way, before anyone else gets to see it. + +In a clone of the demo repository, `./stage.ps1 -Local` sets up the branch for this tour: +`local/dirty-work`, one commit on top of an older `main`, plus an uncommitted edit. + +## 1. Branches on the start page + +**View > Start Page**. + +![Local branches with their pull request and sync state](images/07-01-branches.png) + +Each branch shows its commit count, the pull request it belongs to and how it stands against +the remote: `in sync`, or - like `feature/brand-registry` here, after the force push of +tour 5 - `2 ahead, 4 behind`. The context menu can pull a branch from the remote without +checking it out. And if you left a rebase or merge unfinished, a banner here offers Resolve, +Continue, Skip and Abort. + +## 2. Open the branch + +Double-click `local/dirty-work`. + +![A local review, with uncommitted work in it](images/07-02-local-range.png) + +The review is the branch against its merge base with `main`. The branch is checked out and +the checkout is dirty, so the head is your working tree: the overview says so, and the commit +list has an `uncommitted` row above the one real commit. + +## 3. Committed and uncommitted changes + +![Committed and uncommitted changes in one diff](images/07-03-uncommitted.png) + +`AverageWeight` isn't committed yet; the `OrderBy` is. Both read, navigate and fold like any +other change, so you get to catch what a reviewer would before there is a reviewer. + +## 4. Run the application + +**Tools > Run Application**. + +![The output of the command line project](images/07-04-run.png) + +The **Run** pane lists the executable projects in the review's worktree and runs the one you +pick, with arguments if it takes any. + +Next: [Merge](08-merge.md) diff --git a/docs/tour/08-merge.md b/docs/tour/08-merge.md new file mode 100644 index 0000000..4fd5143 --- /dev/null +++ b/docs/tour/08-merge.md @@ -0,0 +1,53 @@ +# Tour 8: Merge + +Merging isn't a verdict, and the UI keeps it apart from the three buttons that are. + +The demo repository has a one-line pull request for this, **Fix typo in CLI help**. It's #4 +in the pictures, but its number changes every time the demo is staged again. Please don't +merge it in the shared repository - fork it if you want to follow along. + +## 1. The merge state + +**Review > Merge Pull Request...** opens the review page, where the merge block sits next to +the verdicts. + +![The merge block: nothing blocks it](images/08-01-merge-state.png) + +The line above the button answers "why can't I merge this?": failing checks, a missing +approval, a branch behind its target, a draft. You get two reasons at most, the rest is in +the tooltip. GitHub only works this out when somebody asks, so for a pull request nobody has +looked at yet the first answer is that it doesn't know; the refresh button at the top right +asks again. + +The dropdown offers only the merge methods the repository allows, and remembers what you +picked. + +## 2. Merge + +![The confirmation before merging](images/08-02-confirm.png) + +A merge is for everyone and can't be taken back from here, so you're asked once - with the +method, both branches, and whether the head branch should go as well. + +![Merged](images/08-03-merged.png) + +## 3. The merge queue + +When several approved pull requests are waiting for the same target, every merge makes the +next one stale. The **Merge Queue** pane - at the bottom of the picture above - is a queue +shared by everyone who reviews the repository with this tool. It lives in a ref on the +remote, so there's no server and nothing to set up. + +Add the pull request in front, with the merge method you want, and switch **Drive** on. It +merges the first entry that can be merged and skips the ones that can't, telling you why. If +an entry gets pushed to after it was queued, it has to be queued again. Entries that have +left the queue stay listed, with the reason. + +## Offline + +What only the host knows about a pull request - description, comments, checks - is cached +when you read it. Open the same pull request without a network and it's read from that cache +plus the commits already in your clone. The review tells you it's offline, and won't let you +submit or merge. + +Back to the [index](README.md). diff --git a/docs/tour/README.md b/docs/tour/README.md new file mode 100644 index 0000000..6fc9a77 --- /dev/null +++ b/docs/tour/README.md @@ -0,0 +1,53 @@ +# Stampeded! in eight short tours + +Each tour takes under five minutes and stands on its own, so pick whichever one you're +curious about. They assume you review code regularly and want to see what this tool gives +you that a web diff doesn't. + +Every screenshot was taken in +[christophwille/stampeded-demo](https://github.com/christophwille/stampeded-demo), a small C# +solution whose pull requests are staged for exactly this and kept open. You can follow every +step there yourself. + +| | Tour | What it shows | +| --- | --- | --- | +| 1 | [Open a pull request and read it](01-open-and-read.md) | the start page, the overview, walking files and hunks from the keyboard, viewed flags, unified and side by side | +| 2 | [Navigate the code in the diff](02-navigate-the-code.md) | hover, go to definition, find references, removed code that is still navigable, call graph, a decompiled NuGet type | +| 3 | [Read it commit by commit](03-commit-by-commit.md) | the commit scope, per-commit files, blame, the history of a file | +| 4 | [Comment and submit](04-comment-and-submit.md) | drafts, suggestions, replies, the review page, submitting | +| 5 | [Come back after a force push](05-after-a-force-push.md) | what survives a rebase: viewed flags, comments, and a diff of only what the author changed since | +| 6 | [CI, tests and coverage](06-ci-tests-coverage.md) | failing checks, running the tests of the head, coverage in the gutter, base against head | +| 7 | [Review a local branch](07-local-branches.md) | a review without a pull request, uncommitted work included | +| 8 | [Merge](08-merge.md) | what blocks a merge, merging, the merge queue | + +## Before the first tour + +You need `git`, the GitHub CLI logged in (`gh auth login`) and the .NET 10 SDK. Stampeded! has +no token of its own; it sees what your `gh` sees. + + dotnet run --project src/Stampeded + +Then **Review > Open from URL...** and enter `christophwille/stampeded-demo`. It asks where to +clone to, once. + +The keys used throughout are in **Help > Keyboard Shortcuts**. Single letters act whenever the +focus is not in a text box. + +## Re-shooting the screenshots + +The images are not taken by hand. Each one is a small script under [shots/](shots) - the +commands of the app's own screenshot harness (`ScreenshotWatcher`, see [../ui.md](../ui.md)) - +and [shoot.ps1](shoot.ps1) plays them: + + ../../../stampeded-demo/stage.ps1 # the pull requests as first read + ./shoot.ps1 -Start -Demo ../../../stampeded-demo -Fresh + ./shoot.ps1 '01-*' + ./shoot.ps1 -Stop + +The tours are shot in order, and some depend on what an earlier shot left behind (a file +ticked off, a draft written). Three steps happen outside the app: `stage.ps1 -Push2` between +the first and second shot of tour 5, `stage.ps1 -Local` before tour 7, and tour 8 really +merges a pull request, which `stage.ps1` then opens again under a new number. + +Shots that click by position (`press:`, `move:`) hold window coordinates. They are right for +the window size `shoot.ps1` sets and need another look when the layout changes. diff --git a/docs/tour/images/01-01-start-page.png b/docs/tour/images/01-01-start-page.png new file mode 100644 index 0000000..5215086 Binary files /dev/null and b/docs/tour/images/01-01-start-page.png differ diff --git a/docs/tour/images/01-02-overview.png b/docs/tour/images/01-02-overview.png new file mode 100644 index 0000000..9801cf1 Binary files /dev/null and b/docs/tour/images/01-02-overview.png differ diff --git a/docs/tour/images/01-03-first-file.png b/docs/tour/images/01-03-first-file.png new file mode 100644 index 0000000..e5c30b8 Binary files /dev/null and b/docs/tour/images/01-03-first-file.png differ diff --git a/docs/tour/images/01-04-viewed-and-on.png b/docs/tour/images/01-04-viewed-and-on.png new file mode 100644 index 0000000..fd857fe Binary files /dev/null and b/docs/tour/images/01-04-viewed-and-on.png differ diff --git a/docs/tour/images/01-05-context-gap.png b/docs/tour/images/01-05-context-gap.png new file mode 100644 index 0000000..f400195 Binary files /dev/null and b/docs/tour/images/01-05-context-gap.png differ diff --git a/docs/tour/images/01-06-side-by-side.png b/docs/tour/images/01-06-side-by-side.png new file mode 100644 index 0000000..aadd81a Binary files /dev/null and b/docs/tour/images/01-06-side-by-side.png differ diff --git a/docs/tour/images/02-01-hover.png b/docs/tour/images/02-01-hover.png new file mode 100644 index 0000000..ef6910d Binary files /dev/null and b/docs/tour/images/02-01-hover.png differ diff --git a/docs/tour/images/02-02-definition.png b/docs/tour/images/02-02-definition.png new file mode 100644 index 0000000..5949e3f Binary files /dev/null and b/docs/tour/images/02-02-definition.png differ diff --git a/docs/tour/images/02-03-references.png b/docs/tour/images/02-03-references.png new file mode 100644 index 0000000..c1906d3 Binary files /dev/null and b/docs/tour/images/02-03-references.png differ diff --git a/docs/tour/images/02-04-removed-code.png b/docs/tour/images/02-04-removed-code.png new file mode 100644 index 0000000..37147a1 Binary files /dev/null and b/docs/tour/images/02-04-removed-code.png differ diff --git a/docs/tour/images/02-05-decompiled.png b/docs/tour/images/02-05-decompiled.png new file mode 100644 index 0000000..6e53964 Binary files /dev/null and b/docs/tour/images/02-05-decompiled.png differ diff --git a/docs/tour/images/02-06-call-graph.png b/docs/tour/images/02-06-call-graph.png new file mode 100644 index 0000000..62ff5ed Binary files /dev/null and b/docs/tour/images/02-06-call-graph.png differ diff --git a/docs/tour/images/02-07-structure.png b/docs/tour/images/02-07-structure.png new file mode 100644 index 0000000..aaa4060 Binary files /dev/null and b/docs/tour/images/02-07-structure.png differ diff --git a/docs/tour/images/02-08-change-map.png b/docs/tour/images/02-08-change-map.png new file mode 100644 index 0000000..935a1ad Binary files /dev/null and b/docs/tour/images/02-08-change-map.png differ diff --git a/docs/tour/images/03-01-commit-scope.png b/docs/tour/images/03-01-commit-scope.png new file mode 100644 index 0000000..385bc90 Binary files /dev/null and b/docs/tour/images/03-01-commit-scope.png differ diff --git a/docs/tour/images/03-02-rename.png b/docs/tour/images/03-02-rename.png new file mode 100644 index 0000000..0e4ffd9 Binary files /dev/null and b/docs/tour/images/03-02-rename.png differ diff --git a/docs/tour/images/03-03-next-commit.png b/docs/tour/images/03-03-next-commit.png new file mode 100644 index 0000000..553c926 Binary files /dev/null and b/docs/tour/images/03-03-next-commit.png differ diff --git a/docs/tour/images/03-04-commits-pane.png b/docs/tour/images/03-04-commits-pane.png new file mode 100644 index 0000000..733b292 Binary files /dev/null and b/docs/tour/images/03-04-commits-pane.png differ diff --git a/docs/tour/images/03-05-blame.png b/docs/tour/images/03-05-blame.png new file mode 100644 index 0000000..fcd278b Binary files /dev/null and b/docs/tour/images/03-05-blame.png differ diff --git a/docs/tour/images/03-06-history.png b/docs/tour/images/03-06-history.png new file mode 100644 index 0000000..d112e52 Binary files /dev/null and b/docs/tour/images/03-06-history.png differ diff --git a/docs/tour/images/04-01-thread.png b/docs/tour/images/04-01-thread.png new file mode 100644 index 0000000..3d5293f Binary files /dev/null and b/docs/tour/images/04-01-thread.png differ diff --git a/docs/tour/images/04-02-comment-editor.png b/docs/tour/images/04-02-comment-editor.png new file mode 100644 index 0000000..411cac7 Binary files /dev/null and b/docs/tour/images/04-02-comment-editor.png differ diff --git a/docs/tour/images/04-03-draft.png b/docs/tour/images/04-03-draft.png new file mode 100644 index 0000000..1b87a05 Binary files /dev/null and b/docs/tour/images/04-03-draft.png differ diff --git a/docs/tour/images/04-04-suggestion.png b/docs/tour/images/04-04-suggestion.png new file mode 100644 index 0000000..9bc8d0f Binary files /dev/null and b/docs/tour/images/04-04-suggestion.png differ diff --git a/docs/tour/images/04-05-reply.png b/docs/tour/images/04-05-reply.png new file mode 100644 index 0000000..19cc173 Binary files /dev/null and b/docs/tour/images/04-05-reply.png differ diff --git a/docs/tour/images/04-06-comments-pane.png b/docs/tour/images/04-06-comments-pane.png new file mode 100644 index 0000000..33eb4dc Binary files /dev/null and b/docs/tour/images/04-06-comments-pane.png differ diff --git a/docs/tour/images/04-07-review.png b/docs/tour/images/04-07-review.png new file mode 100644 index 0000000..704cb75 Binary files /dev/null and b/docs/tour/images/04-07-review.png differ diff --git a/docs/tour/images/04-08-submitted.png b/docs/tour/images/04-08-submitted.png new file mode 100644 index 0000000..c2fd3f2 Binary files /dev/null and b/docs/tour/images/04-08-submitted.png differ diff --git a/docs/tour/images/05-01-first-pass.png b/docs/tour/images/05-01-first-pass.png new file mode 100644 index 0000000..35de194 Binary files /dev/null and b/docs/tour/images/05-01-first-pass.png differ diff --git a/docs/tour/images/05-02-after-the-push.png b/docs/tour/images/05-02-after-the-push.png new file mode 100644 index 0000000..3b205d7 Binary files /dev/null and b/docs/tour/images/05-02-after-the-push.png differ diff --git a/docs/tour/images/05-03-since-last-pass.png b/docs/tour/images/05-03-since-last-pass.png new file mode 100644 index 0000000..d586572 Binary files /dev/null and b/docs/tour/images/05-03-since-last-pass.png differ diff --git a/docs/tour/images/05-04-moved-comment.png b/docs/tour/images/05-04-moved-comment.png new file mode 100644 index 0000000..d58f6ec Binary files /dev/null and b/docs/tour/images/05-04-moved-comment.png differ diff --git a/docs/tour/images/06-01-checks.png b/docs/tour/images/06-01-checks.png new file mode 100644 index 0000000..b06875e Binary files /dev/null and b/docs/tour/images/06-01-checks.png differ diff --git a/docs/tour/images/06-02-tests.png b/docs/tour/images/06-02-tests.png new file mode 100644 index 0000000..0fc7201 Binary files /dev/null and b/docs/tour/images/06-02-tests.png differ diff --git a/docs/tour/images/06-03-coverage.png b/docs/tour/images/06-03-coverage.png new file mode 100644 index 0000000..b8512ba Binary files /dev/null and b/docs/tour/images/06-03-coverage.png differ diff --git a/docs/tour/images/06-04-a-b.png b/docs/tour/images/06-04-a-b.png new file mode 100644 index 0000000..7093e6b Binary files /dev/null and b/docs/tour/images/06-04-a-b.png differ diff --git a/docs/tour/images/07-01-branches.png b/docs/tour/images/07-01-branches.png new file mode 100644 index 0000000..7dac25d Binary files /dev/null and b/docs/tour/images/07-01-branches.png differ diff --git a/docs/tour/images/07-02-local-range.png b/docs/tour/images/07-02-local-range.png new file mode 100644 index 0000000..c6a1acb Binary files /dev/null and b/docs/tour/images/07-02-local-range.png differ diff --git a/docs/tour/images/07-03-uncommitted.png b/docs/tour/images/07-03-uncommitted.png new file mode 100644 index 0000000..94020bb Binary files /dev/null and b/docs/tour/images/07-03-uncommitted.png differ diff --git a/docs/tour/images/07-04-run.png b/docs/tour/images/07-04-run.png new file mode 100644 index 0000000..48a2664 Binary files /dev/null and b/docs/tour/images/07-04-run.png differ diff --git a/docs/tour/images/08-01-merge-state.png b/docs/tour/images/08-01-merge-state.png new file mode 100644 index 0000000..73b61a7 Binary files /dev/null and b/docs/tour/images/08-01-merge-state.png differ diff --git a/docs/tour/images/08-02-confirm.png b/docs/tour/images/08-02-confirm.png new file mode 100644 index 0000000..56f897e Binary files /dev/null and b/docs/tour/images/08-02-confirm.png differ diff --git a/docs/tour/images/08-03-merged.png b/docs/tour/images/08-03-merged.png new file mode 100644 index 0000000..b03e1bd Binary files /dev/null and b/docs/tour/images/08-03-merged.png differ diff --git a/docs/tour/shoot.ps1 b/docs/tour/shoot.ps1 new file mode 100644 index 0000000..cbf151a --- /dev/null +++ b/docs/tour/shoot.ps1 @@ -0,0 +1,232 @@ +<# +.SYNOPSIS +Takes the screenshots of the feature tours, through the app's own screenshot harness. + +.DESCRIPTION +A shot is a text file under shots/, named like the image it produces under images/. Its lines +are the harness commands described in docs/ui.md (ScreenshotWatcher). Two things are added +here, because a command that opens something has not finished when the capture is taken: + + --- ends one request and starts the next; the image is the last one's capture + sleep:N waits N seconds after the request it is written in + screen after that wait, takes the image from the operating system instead (Windows); + requests after it still run, to tidy up, and no longer change the image + screen:X,Y the same, with a tooltip drawn under the point X,Y of the window + +The harness renders the window, and on Windows a tooltip, a flyout or the comment editor is +a window of its own that such a rendering does not contain. "screen" asks each of the app's +windows to print itself and puts them together - not a copy of the screen, so nothing that +happens to lie over the app can end up in an image. A tooltip opens where the real pointer +is, which a pointer moved by the harness is not; "screen:X,Y" puts it where it belongs. + +The app is started once and driven shot by shot: + + ./shoot.ps1 -Start -Demo ../../../stampeded-demo -Pr 1 -Fresh + ./shoot.ps1 01-* # every shot of the first tour, in name order + ./shoot.ps1 -Stop + ./shoot.ps1 -Verify # every image is referenced, every reference has an image + +.PARAMETER Start +Starts the app on the demo clone with the window, zoom, theme and layout the tours are shot +at, and with nothing but the demo clone in the recent list - a start page shot must not show +what else the person shooting has been reviewing. The settings replaced are put back by -Stop. + +.PARAMETER Fresh +With -Start: forgets what was read in the demo repository (viewed flags, drafts, pass heads). +#> +param( + [Parameter(Position = 0)][string[]]$Shots, + [switch]$Start, + [string]$Demo, + [int]$Pr, + [switch]$Fresh, + [switch]$Stop, + [switch]$Verify +) + +$ErrorActionPreference = 'Stop' +$repo = Resolve-Path "$PSScriptRoot/../.." +$settings = Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'stampeded' +$kept = Join-Path ([IO.Path]::GetTempPath()) 'stampeded-tour-settings' +$pidFile = Join-Path $kept 'pid' +$framed = 'window.txt', 'zoom.txt', 'theme.txt', 'diff-layout.txt', 'scope-mode.txt', 'tab-rows.txt', 'recent-repos.txt', 'delete-branch.txt', 'merge-method.txt' + +if ($Start) { + if (Test-Path $pidFile) { throw 'Already started. Run -Stop first.' } + $Demo = Resolve-Path $Demo + New-Item -ItemType Directory -Force $kept, $settings | Out-Null + foreach ($name in $framed) { + if (Test-Path "$settings/$name") { Move-Item "$settings/$name" "$kept/$name" -Force } + } + Set-Content "$settings/window.txt" '80 40 1600 1000 normal' -NoNewline + Set-Content "$settings/theme.txt" 'Light' -NoNewline + Set-Content "$settings/diff-layout.txt" 'unified' -NoNewline + Set-Content "$settings/scope-mode.txt" 'whole' -NoNewline + Set-Content "$settings/tab-rows.txt" 'single' -NoNewline + Set-Content "$settings/recent-repos.txt" $Demo + if ($Fresh) { + Remove-Item "$settings/reviews/$(Split-Path $Demo -Leaf)_*" -ErrorAction Ignore + } + $exe = Get-ChildItem "$repo/src/Stampeded/bin/Debug/net10.0/Stampeded*" -Include 'Stampeded.exe', 'Stampeded' | + Select-Object -First 1 + if (-not $exe) { throw 'Build the app first: dotnet build Stampeded.slnx' } + $arguments = @("`"$Demo`"") + if ($Pr) { $arguments += '--pr', $Pr } + # The harness names its trigger file /tmp/..., which on Windows is \tmp on the drive of + # the working directory - so the app is started from a known one. + $app = Start-Process $exe -ArgumentList $arguments -WorkingDirectory $repo -PassThru + Set-Content $pidFile $app.Id + Write-Host "Started, pid $($app.Id). Give a review time to load before the first shot." + return +} + +if ($Stop) { + if (Test-Path $pidFile) { + Stop-Process -Id (Get-Content $pidFile) -ErrorAction Ignore + Remove-Item $pidFile + } + foreach ($name in $framed) { + Remove-Item "$settings/$name" -ErrorAction Ignore + if (Test-Path "$kept/$name") { Move-Item "$kept/$name" "$settings/$name" } + } + Write-Host 'Stopped, settings restored.' + return +} + +if ($Verify) { + $referenced = Get-ChildItem "$PSScriptRoot/*.md" | Select-String -Pattern '\(images/([^)]+\.png)\)' -AllMatches | + ForEach-Object { $_.Matches } | ForEach-Object { $_.Groups[1].Value } | Sort-Object -Unique + $present = @(Get-ChildItem "$PSScriptRoot/images/*.png" | ForEach-Object Name) + $missing = @($referenced | Where-Object { $_ -notin $present }) + $unused = @($present | Where-Object { $_ -notin $referenced }) + $missing | ForEach-Object { Write-Host "referenced, not there: $_" } + $unused | ForEach-Object { Write-Host "there, not referenced: $_" } + if ($missing -or $unused) { exit 1 } + Write-Host "$($present.Count) images, all referenced." + return +} + +if (-not (Test-Path $pidFile)) { throw 'Not started. Run -Start first.' } +$trigger = [IO.Path]::GetFullPath("/tmp/stampeded-screenshot-request.$(Get-Content $pidFile)", $repo) +New-Item -ItemType Directory -Force (Split-Path $trigger), "$PSScriptRoot/images" | Out-Null +$scratch = Join-Path $kept 'intermediate.png' + +Add-Type -AssemblyName System.Drawing +Add-Type -ReferencedAssemblies System.Drawing, System.Drawing.Common, System.Drawing.Primitives, System.Collections, System.Private.Windows.GdiPlus, System.Private.Windows.Core -TypeDefinition @' +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; + +public static class WindowShot +{ + delegate bool EnumProc(IntPtr window, IntPtr state); + [StructLayout(LayoutKind.Sequential)] struct RECT { public int Left, Top, Right, Bottom; } + [StructLayout(LayoutKind.Sequential)] struct POINT { public int X, Y; } + [DllImport("user32.dll")] static extern bool EnumWindows(EnumProc callback, IntPtr state); + [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr window, out uint process); + [DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr window); + [DllImport("user32.dll")] static extern bool PrintWindow(IntPtr window, IntPtr dc, uint flags); + [DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr window, out RECT rect); + [DllImport("user32.dll")] static extern bool GetClientRect(IntPtr window, out RECT rect); + [DllImport("user32.dll")] static extern bool ClientToScreen(IntPtr window, ref POINT point); + [DllImport("user32.dll")] static extern IntPtr SetThreadDpiAwarenessContext(IntPtr context); + + static Bitmap Print(IntPtr window, int width, int height, uint flags) + { + var bitmap = new Bitmap(width, height); + using (var g = Graphics.FromImage(bitmap)) + { + IntPtr dc = g.GetHdc(); + PrintWindow(window, dc, flags); + g.ReleaseHdc(dc); + } + return bitmap; + } + + /// The client area of a process's main window with every other visible window of that + /// process drawn over it where it sits, scaled to the size the harness renders at. + public static void Save(int process, IntPtr main, string path, int width, int height, int tipX, int tipY) + { + // Per-monitor aware, or every rectangle comes back in pretend pixels. + SetThreadDpiAwarenessContext(new IntPtr(-4)); + var others = new List(); + EnumWindows((window, _) => { + uint owner; + GetWindowThreadProcessId(window, out owner); + if (owner == process && window != main && IsWindowVisible(window)) + others.Add(window); + return true; + }, IntPtr.Zero); + RECT client; + GetClientRect(main, out client); + var origin = new POINT(); + ClientToScreen(main, ref origin); + // 1 = client area only, 2 = render what the compositor holds, not what GDI last drew. + using (var whole = Print(main, client.Right, client.Bottom, 3)) + { + using (var g = Graphics.FromImage(whole)) + { + // Enumeration is front to back; paint back to front. + for (int i = others.Count - 1; i >= 0; i--) + { + RECT rect; + GetWindowRect(others[i], out rect); + if (rect.Right - rect.Left <= 0 || rect.Bottom - rect.Top <= 0) + continue; + // A tip sits below the pointer, clear of the line it is about. + int x = tipX < 0 ? rect.Left - origin.X + : Math.Max(0, Math.Min(tipX * client.Right / width, client.Right - (rect.Right - rect.Left) - 8)); + int y = tipX < 0 ? rect.Top - origin.Y : (tipY + 14) * client.Right / width; + using (var popup = Print(others[i], rect.Right - rect.Left, rect.Bottom - rect.Top, 2)) + g.DrawImage(popup, x, y); + } + } + using (var scaled = new Bitmap(width, height)) + { + using (var g = Graphics.FromImage(scaled)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.DrawImage(whole, 0, 0, width, height); + } + scaled.Save(path, System.Drawing.Imaging.ImageFormat.Png); + } + } + } +} +'@ + +$files = $Shots -split ',' | ForEach-Object { Get-ChildItem "$PSScriptRoot/shots/$_.txt" } | Sort-Object Name +foreach ($file in $files) { + $image = Join-Path "$PSScriptRoot/images" ($file.BaseName + '.png') + $requests = @(((Get-Content $file -Raw) ?? '') -split '(?m)^---\s*$') + $taken = $false + for ($i = 0; $i -lt $requests.Count; $i++) { + $lines = $requests[$i] -split '\r?\n' | Where-Object { $_.Trim() -and -not $_.StartsWith('#') } + $sleep = $lines | Where-Object { $_ -match '^sleep:(\d+)$' } | ForEach-Object { [int]$Matches[1] } + $target = ($i -eq $requests.Count - 1 -and -not $taken) ? $image : $scratch + Remove-Item $target -ErrorAction Ignore + Set-Content $trigger (@($target) + @($lines | Where-Object { $_ -notmatch '^(sleep:|screen)' })) + $waited = 0 + while (-not (Test-Path $target)) { + Start-Sleep -Milliseconds 250 + if (($waited += 250) -gt 15000) { throw "$($file.Name): no capture. Is the app still running?" } + } + if ($sleep) { Start-Sleep -Seconds ($sleep | Measure-Object -Sum).Sum } + $screen = $lines | Where-Object { $_ -match '^screen(:(\d+),(\d+))?$' } | Select-Object -First 1 + if ($screen) { + $null = $screen -match '^screen(:(\d+),(\d+))?$' + $tipX, $tipY = $Matches[2] ? ([int]$Matches[2], [int]$Matches[3]) : (-1, -1) + # The harness capture just taken says what size the image is to be. + $size = [System.Drawing.Image]::FromFile($target) + $width, $height = $size.Width, $size.Height + $size.Dispose() + $app = Get-Process -Id (Get-Content $pidFile) + [WindowShot]::Save($app.Id, $app.MainWindowHandle, $image, $width, $height, $tipX, $tipY) + $taken = $true + } + } + Write-Host "$($file.BaseName).png" +} diff --git a/docs/tour/shots/01-01-start-page.txt b/docs/tour/shots/01-01-start-page.txt new file mode 100644 index 0000000..e69de29 diff --git a/docs/tour/shots/01-02-overview.txt b/docs/tour/shots/01-02-overview.txt new file mode 100644 index 0000000..6acc55e --- /dev/null +++ b/docs/tour/shots/01-02-overview.txt @@ -0,0 +1,3 @@ +open-url:christophwille/stampeded-demo/pull/1 +sleep:25 +--- diff --git a/docs/tour/shots/01-03-first-file.txt b/docs/tour/shots/01-03-first-file.txt new file mode 100644 index 0000000..f7c6604 --- /dev/null +++ b/docs/tour/shots/01-03-first-file.txt @@ -0,0 +1,3 @@ +key:OemCloseBrackets +sleep:3 +--- diff --git a/docs/tour/shots/01-04-viewed-and-on.txt b/docs/tour/shots/01-04-viewed-and-on.txt new file mode 100644 index 0000000..c08cc17 --- /dev/null +++ b/docs/tour/shots/01-04-viewed-and-on.txt @@ -0,0 +1,6 @@ +key:V +sleep:3 +--- +key:N +sleep:1 +--- diff --git a/docs/tour/shots/01-05-context-gap.txt b/docs/tour/shots/01-05-context-gap.txt new file mode 100644 index 0000000..6ae0860 --- /dev/null +++ b/docs/tour/shots/01-05-context-gap.txt @@ -0,0 +1,3 @@ +open-file:src/Corral/HerdReport.cs +sleep:3 +--- diff --git a/docs/tour/shots/01-06-side-by-side.txt b/docs/tour/shots/01-06-side-by-side.txt new file mode 100644 index 0000000..4d2776d --- /dev/null +++ b/docs/tour/shots/01-06-side-by-side.txt @@ -0,0 +1,6 @@ +open-file:src/Corral/HerdReport.cs +sleep:3 +--- +sbs +sleep:4 +--- diff --git a/docs/tour/shots/02-01-hover.txt b/docs/tour/shots/02-01-hover.txt new file mode 100644 index 0000000..f61cb40 --- /dev/null +++ b/docs/tour/shots/02-01-hover.txt @@ -0,0 +1,9 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +move:795,455 +sleep:2 +screen:795,455 +--- +move:345,71 +sleep:1 diff --git a/docs/tour/shots/02-02-definition.txt b/docs/tour/shots/02-02-definition.txt new file mode 100644 index 0000000..1a36cf8 --- /dev/null +++ b/docs/tour/shots/02-02-definition.txt @@ -0,0 +1,7 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +press:795,455 +release:795,455 +key:F12 +--- diff --git a/docs/tour/shots/02-03-references.txt b/docs/tour/shots/02-03-references.txt new file mode 100644 index 0000000..16d8490 --- /dev/null +++ b/docs/tour/shots/02-03-references.txt @@ -0,0 +1,8 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +press:715,437 +release:715,437 +key:Shift+F12 +sleep:3 +--- diff --git a/docs/tour/shots/02-04-removed-code.txt b/docs/tour/shots/02-04-removed-code.txt new file mode 100644 index 0000000..9665598 --- /dev/null +++ b/docs/tour/shots/02-04-removed-code.txt @@ -0,0 +1,8 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +press:1005,403 +release:1005,403 +key:F12 +sleep:2 +--- diff --git a/docs/tour/shots/02-05-decompiled.txt b/docs/tour/shots/02-05-decompiled.txt new file mode 100644 index 0000000..e4011f8 --- /dev/null +++ b/docs/tour/shots/02-05-decompiled.txt @@ -0,0 +1,8 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +press:750,490 +release:750,490 +key:F12 +sleep:6 +--- diff --git a/docs/tour/shots/02-06-call-graph.txt b/docs/tour/shots/02-06-call-graph.txt new file mode 100644 index 0000000..3beb3f4 --- /dev/null +++ b/docs/tour/shots/02-06-call-graph.txt @@ -0,0 +1,15 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +press:560,263 +release:560,263 +--- +callgraph +sleep:4 +--- +expand:CallTree:2 +sleep:2 +--- +expand:CallTree:1 +sleep:2 +--- diff --git a/docs/tour/shots/02-07-structure.txt b/docs/tour/shots/02-07-structure.txt new file mode 100644 index 0000000..676b642 --- /dev/null +++ b/docs/tour/shots/02-07-structure.txt @@ -0,0 +1,6 @@ +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +pane:Structure +sleep:2 +--- diff --git a/docs/tour/shots/02-08-change-map.txt b/docs/tour/shots/02-08-change-map.txt new file mode 100644 index 0000000..f1a7183 --- /dev/null +++ b/docs/tour/shots/02-08-change-map.txt @@ -0,0 +1,3 @@ +pane:Map +sleep:2 +--- diff --git a/docs/tour/shots/03-01-commit-scope.txt b/docs/tour/shots/03-01-commit-scope.txt new file mode 100644 index 0000000..41e81d0 --- /dev/null +++ b/docs/tour/shots/03-01-commit-scope.txt @@ -0,0 +1,6 @@ +pane:Explorer +overview +--- +commit-scope +sleep:5 +--- diff --git a/docs/tour/shots/03-02-rename.txt b/docs/tour/shots/03-02-rename.txt new file mode 100644 index 0000000..f9ff3e7 --- /dev/null +++ b/docs/tour/shots/03-02-rename.txt @@ -0,0 +1,3 @@ +open-file:src/Corral/PriceCalculator.cs +sleep:3 +--- diff --git a/docs/tour/shots/03-03-next-commit.txt b/docs/tour/shots/03-03-next-commit.txt new file mode 100644 index 0000000..3fcb7a9 --- /dev/null +++ b/docs/tour/shots/03-03-next-commit.txt @@ -0,0 +1,6 @@ +key:Ctrl+OemCloseBrackets +sleep:4 +--- +open-file:src/Corral/PriceCalculator.cs +sleep:3 +--- diff --git a/docs/tour/shots/03-04-commits-pane.txt b/docs/tour/shots/03-04-commits-pane.txt new file mode 100644 index 0000000..b81d081 --- /dev/null +++ b/docs/tour/shots/03-04-commits-pane.txt @@ -0,0 +1,6 @@ +pane:Commits +sleep:2 +--- +select:CommitList:1 +sleep:2 +--- diff --git a/docs/tour/shots/03-05-blame.txt b/docs/tour/shots/03-05-blame.txt new file mode 100644 index 0000000..df11e5e --- /dev/null +++ b/docs/tour/shots/03-05-blame.txt @@ -0,0 +1,9 @@ +commit-exit +sleep:4 +--- +open-file:src/Corral/HerdReport.cs +sleep:2 +--- +key:B +sleep:3 +--- diff --git a/docs/tour/shots/03-06-history.txt b/docs/tour/shots/03-06-history.txt new file mode 100644 index 0000000..d4e4ba1 --- /dev/null +++ b/docs/tour/shots/03-06-history.txt @@ -0,0 +1,6 @@ +key:B +sleep:2 +--- +pane:History +sleep:3 +--- diff --git a/docs/tour/shots/04-01-thread.txt b/docs/tour/shots/04-01-thread.txt new file mode 100644 index 0000000..8f021ea --- /dev/null +++ b/docs/tour/shots/04-01-thread.txt @@ -0,0 +1,4 @@ +pane:References +open-file:src/Corral/PriceCalculator.cs +sleep:3 +--- diff --git a/docs/tour/shots/04-02-comment-editor.txt b/docs/tour/shots/04-02-comment-editor.txt new file mode 100644 index 0000000..26f3f6c --- /dev/null +++ b/docs/tour/shots/04-02-comment-editor.txt @@ -0,0 +1,9 @@ +press:450,473 +release:450,473 +--- +comment +sleep:1 +--- +type:Where do 0.9 and 1.1 come from? A constant with a name would say. +sleep:1 +screen diff --git a/docs/tour/shots/04-03-draft.txt b/docs/tour/shots/04-03-draft.txt new file mode 100644 index 0000000..d86add3 --- /dev/null +++ b/docs/tour/shots/04-03-draft.txt @@ -0,0 +1,3 @@ +key:Ctrl+Enter +sleep:2 +--- diff --git a/docs/tour/shots/04-04-suggestion.txt b/docs/tour/shots/04-04-suggestion.txt new file mode 100644 index 0000000..08925db --- /dev/null +++ b/docs/tour/shots/04-04-suggestion.txt @@ -0,0 +1,26 @@ +# The block is typed rather than taken from "Suggest a change": that button lives in the +# editor popup, which is a window of its own that the harness cannot click into. +goto:src/Corral/PriceCalculator.cs:14 +sleep:2 +--- +comment +sleep:1 +--- +type:```suggestion +--- +key:Enter +--- +type: <= 600 => WeightClass.Standard, +--- +key:Enter +--- +type:``` +--- +key:Enter +--- +type:The table says heavy is above 600 kg, so 600 itself is still standard. +sleep:1 +screen +--- +key:Ctrl+Enter +sleep:2 diff --git a/docs/tour/shots/04-05-reply.txt b/docs/tour/shots/04-05-reply.txt new file mode 100644 index 0000000..aa3ad93 --- /dev/null +++ b/docs/tour/shots/04-05-reply.txt @@ -0,0 +1,8 @@ +click:Reply +sleep:1 +--- +type:Standard is meant to start at 350. I will fix the table rather than the code. +--- +key:Ctrl+Enter +sleep:2 +--- diff --git a/docs/tour/shots/04-06-comments-pane.txt b/docs/tour/shots/04-06-comments-pane.txt new file mode 100644 index 0000000..af9ed19 --- /dev/null +++ b/docs/tour/shots/04-06-comments-pane.txt @@ -0,0 +1,3 @@ +pane:Comments +sleep:2 +--- diff --git a/docs/tour/shots/04-07-review.txt b/docs/tour/shots/04-07-review.txt new file mode 100644 index 0000000..f032f78 --- /dev/null +++ b/docs/tour/shots/04-07-review.txt @@ -0,0 +1,4 @@ +pane:References +menu:Approve / Request Changes... +sleep:3 +--- diff --git a/docs/tour/shots/04-08-submitted.txt b/docs/tour/shots/04-08-submitted.txt new file mode 100644 index 0000000..e05819b --- /dev/null +++ b/docs/tour/shots/04-08-submitted.txt @@ -0,0 +1,3 @@ +click:Comment +sleep:10 +--- diff --git a/docs/tour/shots/05-01-first-pass.txt b/docs/tour/shots/05-01-first-pass.txt new file mode 100644 index 0000000..504a9cb --- /dev/null +++ b/docs/tour/shots/05-01-first-pass.txt @@ -0,0 +1,39 @@ +open-url:christophwille/stampeded-demo/pull/2 +sleep:25 +--- +key:OemCloseBrackets +sleep:3 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +key:V +sleep:2 +--- +goto:src/Corral/Herd.cs:29 +sleep:3 +--- diff --git a/docs/tour/shots/05-02-after-the-push.txt b/docs/tour/shots/05-02-after-the-push.txt new file mode 100644 index 0000000..ec2b3cf --- /dev/null +++ b/docs/tour/shots/05-02-after-the-push.txt @@ -0,0 +1,6 @@ +key:F5 +sleep:25 +--- +overview +sleep:2 +--- diff --git a/docs/tour/shots/05-03-since-last-pass.txt b/docs/tour/shots/05-03-since-last-pass.txt new file mode 100644 index 0000000..594e2ba --- /dev/null +++ b/docs/tour/shots/05-03-since-last-pass.txt @@ -0,0 +1,3 @@ +since-last-pass +sleep:6 +--- diff --git a/docs/tour/shots/05-04-moved-comment.txt b/docs/tour/shots/05-04-moved-comment.txt new file mode 100644 index 0000000..5b240a6 --- /dev/null +++ b/docs/tour/shots/05-04-moved-comment.txt @@ -0,0 +1,3 @@ +goto:src/Corral/Herd.cs:38 +sleep:4 +--- diff --git a/docs/tour/shots/06-01-checks.txt b/docs/tour/shots/06-01-checks.txt new file mode 100644 index 0000000..8b37755 --- /dev/null +++ b/docs/tour/shots/06-01-checks.txt @@ -0,0 +1,6 @@ +open-url:christophwille/stampeded-demo/pull/3 +sleep:25 +--- +pane:Checks +sleep:4 +--- diff --git a/docs/tour/shots/06-02-tests.txt b/docs/tour/shots/06-02-tests.txt new file mode 100644 index 0000000..0202503 --- /dev/null +++ b/docs/tour/shots/06-02-tests.txt @@ -0,0 +1,6 @@ +menu:Run Tests +sleep:45 +--- +pane:Tests +sleep:1 +--- diff --git a/docs/tour/shots/06-03-coverage.txt b/docs/tour/shots/06-03-coverage.txt new file mode 100644 index 0000000..b21e724 --- /dev/null +++ b/docs/tour/shots/06-03-coverage.txt @@ -0,0 +1,9 @@ +menu:Run + Coverage +sleep:60 +--- +open-file:src/Corral/Herd.cs +sleep:3 +--- +key:U +sleep:1 +--- diff --git a/docs/tour/shots/06-04-a-b.txt b/docs/tour/shots/06-04-a-b.txt new file mode 100644 index 0000000..26055eb --- /dev/null +++ b/docs/tour/shots/06-04-a-b.txt @@ -0,0 +1,3 @@ +menu:Run A/B (base vs head) +sleep:100 +--- diff --git a/docs/tour/shots/07-01-branches.txt b/docs/tour/shots/07-01-branches.txt new file mode 100644 index 0000000..55bafbb --- /dev/null +++ b/docs/tour/shots/07-01-branches.txt @@ -0,0 +1,6 @@ +close-review +sleep:3 +--- +menu:Start Page +sleep:5 +--- diff --git a/docs/tour/shots/07-02-local-range.txt b/docs/tour/shots/07-02-local-range.txt new file mode 100644 index 0000000..8e2510f --- /dev/null +++ b/docs/tour/shots/07-02-local-range.txt @@ -0,0 +1,3 @@ +open-range:main:local/dirty-work +sleep:20 +--- diff --git a/docs/tour/shots/07-03-uncommitted.txt b/docs/tour/shots/07-03-uncommitted.txt new file mode 100644 index 0000000..4156f89 --- /dev/null +++ b/docs/tour/shots/07-03-uncommitted.txt @@ -0,0 +1,3 @@ +open-file:src/Corral/Herd.cs +sleep:3 +--- diff --git a/docs/tour/shots/07-04-run.txt b/docs/tour/shots/07-04-run.txt new file mode 100644 index 0000000..ae52c5d --- /dev/null +++ b/docs/tour/shots/07-04-run.txt @@ -0,0 +1,4 @@ +pane:Run +menu:Run Application +sleep:25 +--- diff --git a/docs/tour/shots/08-01-merge-state.txt b/docs/tour/shots/08-01-merge-state.txt new file mode 100644 index 0000000..884b90f --- /dev/null +++ b/docs/tour/shots/08-01-merge-state.txt @@ -0,0 +1,13 @@ +pane:References +open-url:christophwille/stampeded-demo/pull/4 +sleep:25 +--- +menu:Merge Pull Request... +sleep:5 +--- +# GitHub works the merge state out when it is first asked, and the answer to that first +# question is "unknown": ask again. +press:1259,64 +release:1259,64 +sleep:6 +--- diff --git a/docs/tour/shots/08-02-confirm.txt b/docs/tour/shots/08-02-confirm.txt new file mode 100644 index 0000000..fd675fc --- /dev/null +++ b/docs/tour/shots/08-02-confirm.txt @@ -0,0 +1,4 @@ +press:1240,557 +release:1240,557 +sleep:3 +--- diff --git a/docs/tour/shots/08-03-merged.txt b/docs/tour/shots/08-03-merged.txt new file mode 100644 index 0000000..f3641f8 --- /dev/null +++ b/docs/tour/shots/08-03-merged.txt @@ -0,0 +1,4 @@ +pane:MergeQueue +click:Merge (merge) +sleep:15 +---