Skip to content

Commit bd1c084

Browse files
committed
Merge branch 'master' into add-coauthor-support
2 parents 0a8c188 + dee1ff0 commit bd1c084

File tree

12 files changed

+159
-84
lines changed

12 files changed

+159
-84
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,14 @@ jobs:
3636
- name: Test code
3737
# we're passing -short so that we skip the integration tests, which will be run in parallel below
3838
run: |
39-
go test ./... -short
39+
mkdir -p /tmp/code_coverage
40+
go test ./... -short -cover -args "-test.gocoverdir=/tmp/code_coverage"
41+
- name: Upload code coverage artifacts
42+
uses: actions/upload-artifact@v3
43+
with:
44+
name: coverage-unit-${{ matrix.os }}-${{ github.run_id }}
45+
path: /tmp/code_coverage
46+
4047
integration-tests:
4148
strategy:
4249
fail-fast: false
@@ -86,8 +93,17 @@ jobs:
8693
- name: Print git version
8794
run: git --version
8895
- name: Test code
96+
env:
97+
# See https://go.dev/blog/integration-test-coverage
98+
LAZYGIT_GOCOVERDIR: /tmp/code_coverage
8999
run: |
100+
mkdir -p /tmp/code_coverage
90101
./scripts/run_integration_tests.sh
102+
- name: Upload code coverage artifacts
103+
uses: actions/upload-artifact@v3
104+
with:
105+
name: coverage-integration-${{ matrix.git-version }}-${{ github.run_id }}
106+
path: /tmp/code_coverage
91107
build:
92108
runs-on: ubuntu-latest
93109
env:
@@ -169,3 +185,31 @@ jobs:
169185
mode: exactly
170186
count: 1
171187
labels: "ignore-for-release, feature, enhancement, bug, maintenance, docs, i18n"
188+
upload-coverage:
189+
# List all jobs that produce coverage files
190+
needs: [unit-tests, integration-tests]
191+
runs-on: ubuntu-latest
192+
steps:
193+
- name: Checkout code
194+
uses: actions/checkout@v3
195+
196+
- name: Download all coverage artifacts
197+
uses: actions/download-artifact@v3
198+
with:
199+
path: /tmp/code_coverage
200+
201+
- name: Combine coverage files
202+
run: |
203+
# Find all directories in /tmp/code_coverage and create a comma-separated list
204+
COVERAGE_DIRS=$(find /tmp/code_coverage -mindepth 1 -maxdepth 1 -type d -printf '/tmp/code_coverage/%f,' | sed 's/,$//')
205+
echo "Coverage directories: $COVERAGE_DIRS"
206+
# Run the combine command with the generated list
207+
go tool covdata textfmt -i=$COVERAGE_DIRS -o coverage.out
208+
echo "Combined coverage:"
209+
go tool cover -func coverage.out | tail -1 | awk '{print $3}'
210+
211+
- name: Upload to Codacy
212+
run: |
213+
CODACY_PROJECT_TOKEN=${{ secrets.CODACY_PROJECT_TOKEN }} \
214+
bash <(curl -Ls https://coverage.codacy.com/get.sh) report \
215+
--force-coverage-parser go -r coverage.out

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,5 @@ __debug_bin
4242

4343
.worktrees
4444
demo/output/*
45+
46+
coverage.out

README.md

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

docs/keybindings/Keybindings_en.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
141141
<pre>
142142
<kbd>&lt;c-o&gt;</kbd>: Copy branch name to clipboard
143143
<kbd>i</kbd>: Show git-flow options
144-
<kbd>&lt;space&gt;</kbd>: Checkout
144+
<kbd>&lt;space&gt;</kbd>: Checkout, enter '-' to switch to last
145145
<kbd>n</kbd>: New branch
146146
<kbd>o</kbd>: Create pull request
147147
<kbd>O</kbd>: Create pull request options

pkg/gui/pty.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ func (gui *Gui) onResize() error {
4545
func (gui *Gui) newPtyTask(view *gocui.View, cmd *exec.Cmd, prefix string) error {
4646
width, _ := gui.Views.Main.Size()
4747
pager := gui.git.Config.GetPager(width)
48+
externalDiffCommand := gui.Config.GetUserConfig().Git.Paging.ExternalDiffCommand
4849

49-
if pager == "" {
50+
if pager == "" && externalDiffCommand == "" {
5051
// if we're not using a custom pager we don't need to use a pty
5152
return gui.newCmdTask(view, cmd, prefix)
5253
}

pkg/i18n/english.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,7 @@ func EnglishTranslationSet() TranslationSet {
874874
CantRebaseOntoSelf: "You cannot rebase a branch onto itself",
875875
CantMergeBranchIntoItself: "You cannot merge a branch into itself",
876876
ForceCheckout: "Force checkout",
877-
CheckoutByName: "Checkout by name",
877+
CheckoutByName: "Checkout by name, enter '-' to switch to last",
878878
NewBranch: "New branch",
879879
NoBranchesThisRepo: "No branches for this repo",
880880
CommitWithoutMessageErr: "You cannot commit without a commit message",

pkg/integration/clients/cli.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,18 @@ func RunCLI(testNames []string, slow bool, sandbox bool, waitForDebugger bool, r
2929
inputDelay = SLOW_INPUT_DELAY
3030
}
3131

32-
err := components.RunTests(
33-
getTestsToRun(testNames),
34-
log.Printf,
35-
runCmdInTerminal,
36-
runAndPrintFatalError,
37-
sandbox,
38-
waitForDebugger,
39-
raceDetector,
40-
inputDelay,
41-
1,
42-
)
32+
err := components.RunTests(components.RunTestArgs{
33+
Tests: getTestsToRun(testNames),
34+
Logf: log.Printf,
35+
RunCmd: runCmdInTerminal,
36+
TestWrapper: runAndPrintFatalError,
37+
Sandbox: sandbox,
38+
WaitForDebugger: waitForDebugger,
39+
RaceDetector: raceDetector,
40+
CodeCoverageDir: "",
41+
InputDelay: inputDelay,
42+
MaxAttempts: 1,
43+
})
4344
if err != nil {
4445
log.Print(err.Error())
4546
}

pkg/integration/clients/go_test.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,17 @@ func TestIntegration(t *testing.T) {
2828
parallelTotal := tryConvert(os.Getenv("PARALLEL_TOTAL"), 1)
2929
parallelIndex := tryConvert(os.Getenv("PARALLEL_INDEX"), 0)
3030
raceDetector := os.Getenv("LAZYGIT_RACE_DETECTOR") != ""
31+
// LAZYGIT_GOCOVERDIR is the directory where we write coverage files to. If this directory
32+
// is defined, go binaries built with the -cover flag will write coverage files to
33+
// to it.
34+
codeCoverageDir := os.Getenv("LAZYGIT_GOCOVERDIR")
3135
testNumber := 0
3236

33-
err := components.RunTests(
34-
tests.GetTests(),
35-
t.Logf,
36-
runCmdHeadless,
37-
func(test *components.IntegrationTest, f func() error) {
37+
err := components.RunTests(components.RunTestArgs{
38+
Tests: tests.GetTests(),
39+
Logf: t.Logf,
40+
RunCmd: runCmdHeadless,
41+
TestWrapper: func(test *components.IntegrationTest, f func() error) {
3842
defer func() { testNumber += 1 }()
3943
if testNumber%parallelTotal != parallelIndex {
4044
return
@@ -52,13 +56,14 @@ func TestIntegration(t *testing.T) {
5256
assert.NoError(t, err)
5357
})
5458
},
55-
false,
56-
false,
57-
raceDetector,
58-
0,
59+
Sandbox: false,
60+
WaitForDebugger: false,
61+
RaceDetector: raceDetector,
62+
CodeCoverageDir: codeCoverageDir,
63+
InputDelay: 0,
5964
// Allow two attempts at each test to get around flakiness
60-
2,
61-
)
65+
MaxAttempts: 2,
66+
})
6267

6368
assert.NoError(t, err)
6469
}

pkg/integration/clients/tui.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -385,17 +385,18 @@ func quit(g *gocui.Gui, v *gocui.View) error {
385385
}
386386

387387
func runTuiTest(test *components.IntegrationTest, sandbox bool, waitForDebugger bool, raceDetector bool, inputDelay int) {
388-
err := components.RunTests(
389-
[]*components.IntegrationTest{test},
390-
log.Printf,
391-
runCmdInTerminal,
392-
runAndPrintError,
393-
sandbox,
394-
waitForDebugger,
395-
raceDetector,
396-
inputDelay,
397-
1,
398-
)
388+
err := components.RunTests(components.RunTestArgs{
389+
Tests: []*components.IntegrationTest{test},
390+
Logf: log.Printf,
391+
RunCmd: runCmdInTerminal,
392+
TestWrapper: runAndPrintError,
393+
Sandbox: sandbox,
394+
WaitForDebugger: waitForDebugger,
395+
RaceDetector: raceDetector,
396+
CodeCoverageDir: "",
397+
InputDelay: inputDelay,
398+
MaxAttempts: 1,
399+
})
399400
if err != nil {
400401
log.Println(err.Error())
401402
}

pkg/integration/components/runner.go

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,32 @@ const (
2020
GIT_CONFIG_GLOBAL_ENV_VAR = "GIT_CONFIG_GLOBAL"
2121
)
2222

23+
type RunTestArgs struct {
24+
Tests []*IntegrationTest
25+
Logf func(format string, formatArgs ...interface{})
26+
RunCmd func(cmd *exec.Cmd) (int, error)
27+
TestWrapper func(test *IntegrationTest, f func() error)
28+
Sandbox bool
29+
WaitForDebugger bool
30+
RaceDetector bool
31+
CodeCoverageDir string
32+
InputDelay int
33+
MaxAttempts int
34+
}
35+
2336
// This function lets you run tests either from within `go test` or from a regular binary.
2437
// The reason for having two separate ways of testing is that `go test` isn't great at
2538
// showing what's actually happening during the test, but it's still good at running
2639
// tests in telling you about their results.
27-
func RunTests(
28-
tests []*IntegrationTest,
29-
logf func(format string, formatArgs ...interface{}),
30-
runCmd func(cmd *exec.Cmd) (int, error),
31-
testWrapper func(test *IntegrationTest, f func() error),
32-
sandbox bool,
33-
waitForDebugger bool,
34-
raceDetector bool,
35-
inputDelay int,
36-
maxAttempts int,
37-
) error {
40+
func RunTests(args RunTestArgs) error {
3841
projectRootDir := lazycoreUtils.GetLazyRootDirectory()
3942
err := os.Chdir(projectRootDir)
4043
if err != nil {
4144
return err
4245
}
4346

4447
testDir := filepath.Join(projectRootDir, "test", "_results")
45-
46-
if err := buildLazygit(waitForDebugger, raceDetector); err != nil {
48+
if err := buildLazygit(args); err != nil {
4749
return err
4850
}
4951

@@ -52,21 +54,21 @@ func RunTests(
5254
return err
5355
}
5456

55-
for _, test := range tests {
57+
for _, test := range args.Tests {
5658
test := test
5759

58-
testWrapper(test, func() error { //nolint: thelper
60+
args.TestWrapper(test, func() error { //nolint: thelper
5961
paths := NewPaths(
6062
filepath.Join(testDir, test.Name()),
6163
)
6264

63-
for i := 0; i < maxAttempts; i++ {
64-
err := runTest(test, paths, projectRootDir, logf, runCmd, sandbox, waitForDebugger, raceDetector, inputDelay, gitVersion)
65+
for i := 0; i < args.MaxAttempts; i++ {
66+
err := runTest(test, args, paths, projectRootDir, gitVersion)
6567
if err != nil {
66-
if i == maxAttempts-1 {
68+
if i == args.MaxAttempts-1 {
6769
return err
6870
}
69-
logf("retrying test %s", test.Name())
71+
args.Logf("retrying test %s", test.Name())
7072
} else {
7173
break
7274
}
@@ -81,42 +83,37 @@ func RunTests(
8183

8284
func runTest(
8385
test *IntegrationTest,
86+
args RunTestArgs,
8487
paths Paths,
8588
projectRootDir string,
86-
logf func(format string, formatArgs ...interface{}),
87-
runCmd func(cmd *exec.Cmd) (int, error),
88-
sandbox bool,
89-
waitForDebugger bool,
90-
raceDetector bool,
91-
inputDelay int,
9289
gitVersion *git_commands.GitVersion,
9390
) error {
9491
if test.Skip() {
95-
logf("Skipping test %s", test.Name())
92+
args.Logf("Skipping test %s", test.Name())
9693
return nil
9794
}
9895

9996
if !test.ShouldRunForGitVersion(gitVersion) {
100-
logf("Skipping test %s for git version %d.%d.%d", test.Name(), gitVersion.Major, gitVersion.Minor, gitVersion.Patch)
97+
args.Logf("Skipping test %s for git version %d.%d.%d", test.Name(), gitVersion.Major, gitVersion.Minor, gitVersion.Patch)
10198
return nil
10299
}
103100

104101
if err := prepareTestDir(test, paths, projectRootDir); err != nil {
105102
return err
106103
}
107104

108-
cmd, err := getLazygitCommand(test, paths, projectRootDir, sandbox, waitForDebugger, inputDelay)
105+
cmd, err := getLazygitCommand(test, args, paths, projectRootDir)
109106
if err != nil {
110107
return err
111108
}
112109

113-
pid, err := runCmd(cmd)
110+
pid, err := args.RunCmd(cmd)
114111

115112
// Print race detector log regardless of the command's exit status
116-
if raceDetector {
113+
if args.RaceDetector {
117114
logPath := fmt.Sprintf("%s.%d", raceDetectorLogsPath(), pid)
118115
if bytes, err := os.ReadFile(logPath); err == nil {
119-
logf("Race detector log:\n" + string(bytes))
116+
args.Logf("Race detector log:\n" + string(bytes))
120117
}
121118
}
122119

@@ -139,20 +136,19 @@ func prepareTestDir(
139136
return createFixture(test, paths, rootDir)
140137
}
141138

142-
func buildLazygit(debug bool, raceDetector bool) error {
143-
// // TODO: remove this line!
144-
// // skipping this because I'm not making changes to the app code atm.
145-
// return nil
146-
139+
func buildLazygit(testArgs RunTestArgs) error {
147140
args := []string{"go", "build"}
148-
if debug {
141+
if testArgs.WaitForDebugger {
149142
// Disable compiler optimizations (-N) and inlining (-l) because this
150143
// makes debugging work better
151144
args = append(args, "-gcflags=all=-N -l")
152145
}
153-
if raceDetector {
146+
if testArgs.RaceDetector {
154147
args = append(args, "-race")
155148
}
149+
if testArgs.CodeCoverageDir != "" {
150+
args = append(args, "-cover")
151+
}
156152
args = append(args, "-o", tempLazygitPath(), filepath.FromSlash("pkg/integration/clients/injector/main.go"))
157153
osCommand := oscommands.NewDummyOSCommand()
158154
return osCommand.Cmd.New(args).Run()
@@ -183,7 +179,7 @@ func getGitVersion() (*git_commands.GitVersion, error) {
183179
return git_commands.ParseGitVersion(versionStr)
184180
}
185181

186-
func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandbox bool, waitForDebugger bool, inputDelay int) (*exec.Cmd, error) {
182+
func getLazygitCommand(test *IntegrationTest, args RunTestArgs, paths Paths, rootDir string) (*exec.Cmd, error) {
187183
osCommand := oscommands.NewDummyOSCommand()
188184

189185
err := os.RemoveAll(paths.Config())
@@ -211,11 +207,18 @@ func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandb
211207

212208
cmdObj := osCommand.Cmd.New(cmdArgs)
213209

210+
if args.CodeCoverageDir != "" {
211+
// We set this explicitly here rather than inherit it from the test runner's
212+
// environment because the test runner has its own coverage directory that
213+
// it writes to and so if we pass GOCOVERDIR to that, it will be overwritten.
214+
cmdObj.AddEnvVars("GOCOVERDIR=" + args.CodeCoverageDir)
215+
}
216+
214217
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", TEST_NAME_ENV_VAR, test.Name()))
215-
if sandbox {
218+
if args.Sandbox {
216219
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", SANDBOX_ENV_VAR, "true"))
217220
}
218-
if waitForDebugger {
221+
if args.WaitForDebugger {
219222
cmdObj.AddEnvVars(fmt.Sprintf("%s=true", WAIT_FOR_DEBUGGER_ENV_VAR))
220223
}
221224
// Set a race detector log path only to avoid spamming the terminal with the
@@ -227,8 +230,8 @@ func getLazygitCommand(test *IntegrationTest, paths Paths, rootDir string, sandb
227230
}
228231
}
229232

230-
if inputDelay > 0 {
231-
cmdObj.AddEnvVars(fmt.Sprintf("INPUT_DELAY=%d", inputDelay))
233+
if args.InputDelay > 0 {
234+
cmdObj.AddEnvVars(fmt.Sprintf("INPUT_DELAY=%d", args.InputDelay))
232235
}
233236

234237
cmdObj.AddEnvVars(fmt.Sprintf("%s=%s", GIT_CONFIG_GLOBAL_ENV_VAR, globalGitConfigPath(rootDir)))

0 commit comments

Comments
 (0)