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
9 changes: 4 additions & 5 deletions internal/qualitygate/diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ package diff
import (
"context"
"os"
"os/exec"
"path/filepath"
"reflect"
"testing"

"github.com/larksuite/cli/internal/testutil/gitcmd"
)

func TestScopeIncludesChangedSkillAndRelatedDomain(t *testing.T) {
Expand Down Expand Up @@ -122,17 +123,15 @@ func writeFile(t *testing.T, repo, rel, content string) {

func runGit(t *testing.T, repo string, args ...string) {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = repo
cmd := gitcmd.Command(repo, args...)
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("git %v failed: %v\n%s", args, err, out)
}
}

func gitOutput(t *testing.T, repo string, args ...string) string {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = repo
cmd := gitcmd.Command(repo, args...)
out, err := cmd.Output()
if err != nil {
t.Fatalf("git %v failed: %v", args, err)
Expand Down
9 changes: 4 additions & 5 deletions internal/qualitygate/publiccontent/collect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ package publiccontent
import (
"context"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"

"github.com/larksuite/cli/internal/testutil/gitcmd"
)

func TestCollectScansOnlyCurrentContributionAndMetadata(t *testing.T) {
Expand Down Expand Up @@ -855,8 +856,7 @@ func runGit(t *testing.T, repo string, args ...string) {
if len(args) > 0 && args[0] == "commit" {
args = append([]string{"commit", "--no-verify"}, args[1:]...)
}
cmd := exec.Command("git", args...)
cmd.Dir = repo
cmd := gitcmd.Command(repo, args...)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %v failed: %v\n%s", args, err, out)
Expand All @@ -865,8 +865,7 @@ func runGit(t *testing.T, repo string, args ...string) {

func runGitOutput(t *testing.T, repo string, args ...string) []byte {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = repo
cmd := gitcmd.Command(repo, args...)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %v failed: %v\n%s", args, err, out)
Expand Down
5 changes: 3 additions & 2 deletions internal/qualitygate/rules/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import (
"context"
"encoding/json"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"

qdiff "github.com/larksuite/cli/internal/qualitygate/diff"
"github.com/larksuite/cli/internal/qualitygate/manifest"
"github.com/larksuite/cli/internal/qualitygate/report"
"github.com/larksuite/cli/internal/testutil/gitcmd"
"github.com/larksuite/cli/internal/vfs"
)

Expand Down Expand Up @@ -599,7 +599,8 @@ func TestNormalizeDiagnosticFileHandlesAbsoluteRepo(t *testing.T) {

func runGit(t *testing.T, repo string, args ...string) {
t.Helper()
cmd := exec.Command("git", append([]string{"-c", "core.hooksPath=/dev/null", "-C", repo}, args...)...)
commandArgs := append([]string{"-c", "core.hooksPath=/dev/null"}, args...)
cmd := gitcmd.Command(repo, commandArgs...)
cmd.Env = append(os.Environ(), "GIT_AUTHOR_DATE=2026-06-17T00:00:00Z", "GIT_COMMITTER_DATE=2026-06-17T00:00:00Z")
out, err := cmd.CombinedOutput()
if err != nil {
Expand Down
55 changes: 55 additions & 0 deletions internal/testutil/gitcmd/gitcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

// Package gitcmd provides Git process helpers for tests that use temporary
// repositories.
package gitcmd

import (
"os"
"os/exec"
"strconv"
"testing"
)

const (
maintenanceAutoDetach = "maintenance.autoDetach"
gcAutoDetach = "gc.autoDetach"
)

// Command creates a Git command whose automatic maintenance stays in the
// command lifecycle, so temporary repository cleanup cannot race a detached
// maintenance process.
func Command(dir string, args ...string) *exec.Cmd {
commandArgs := make([]string, 0, len(args)+4)
commandArgs = append(commandArgs,
"-c", maintenanceAutoDetach+"=false",
"-c", gcAutoDetach+"=false",
)
commandArgs = append(commandArgs, args...)
cmd := exec.Command("git", commandArgs...)
cmd.Dir = dir
return cmd
}

// SetSynchronousMaintenanceEnv applies the same lifecycle contract to every
// Git process started by the current test, including processes created through
// production command runners. Tests using it must not run in parallel.
func SetSynchronousMaintenanceEnv(t *testing.T) {
t.Helper()
count := 0
if value, ok := os.LookupEnv("GIT_CONFIG_COUNT"); ok {
parsed, err := strconv.Atoi(value)
if err != nil || parsed < 0 {
t.Fatalf("invalid GIT_CONFIG_COUNT %q", value)

Check warning on line 44 in internal/testutil/gitcmd/gitcmd.go

View check run for this annotation

Codecov / codecov/patch

internal/testutil/gitcmd/gitcmd.go#L44

Added line #L44 was not covered by tests
}
count = parsed
}
for _, key := range []string{maintenanceAutoDetach, gcAutoDetach} {
index := strconv.Itoa(count)
t.Setenv("GIT_CONFIG_KEY_"+index, key)
t.Setenv("GIT_CONFIG_VALUE_"+index, "false")
count++
}
t.Setenv("GIT_CONFIG_COUNT", strconv.Itoa(count))
}
47 changes: 47 additions & 0 deletions internal/testutil/gitcmd/gitcmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT

package gitcmd

import (
"os/exec"
"strings"
"testing"
)

func TestCommandDisablesDetachedMaintenance(t *testing.T) {
for _, key := range []string{"maintenance.autoDetach", "gc.autoDetach"} {
cmd := Command(t.TempDir(), "config", "--get", "--type=bool", key)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git config %s: %v\n%s", key, err, out)
}
if got := strings.TrimSpace(string(out)); got != "false" {
t.Fatalf("%s = %q, want false", key, got)
}
}
}

func TestSetSynchronousMaintenanceEnv(t *testing.T) {
t.Setenv("GIT_CONFIG_COUNT", "1")
t.Setenv("GIT_CONFIG_KEY_0", "user.name")
t.Setenv("GIT_CONFIG_VALUE_0", "Existing Test User")
SetSynchronousMaintenanceEnv(t)
for key, want := range map[string]string{
"user.name": "Existing Test User",
maintenanceAutoDetach: "false",
gcAutoDetach: "false",
} {
cmd := exec.Command("git", "config", "--get", "--type=bool", key)
if key == "user.name" {
cmd = exec.Command("git", "config", "--get", key)
}
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git config %s: %v\n%s", key, err, out)
}
if got := strings.TrimSpace(string(out)); got != want {
t.Fatalf("%s = %q, want %q", key, got, want)
}
}
}
15 changes: 14 additions & 1 deletion lint/errscontract/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ func writeFixture(t *testing.T, files fixtureRepo) string {

func runGit(t *testing.T, root string, args ...string) string {
t.Helper()
cmd := exec.Command("git", args...)
commandArgs := []string{
"-c", "maintenance.autoDetach=false",
"-c", "gc.autoDetach=false",
}
commandArgs = append(commandArgs, args...)
cmd := exec.Command("git", commandArgs...)
cmd.Dir = root
out, err := cmd.CombinedOutput()
if err != nil {
Expand All @@ -43,6 +48,14 @@ func runGit(t *testing.T, root string, args ...string) string {
return strings.TrimSpace(string(out))
}

func TestRunGitDisablesDetachedMaintenance(t *testing.T) {
for _, key := range []string{"maintenance.autoDetach", "gc.autoDetach"} {
if got := runGit(t, t.TempDir(), "config", "--get", "--type=bool", key); got != "false" {
t.Fatalf("%s = %q, want false", key, got)
}
}
}

func TestLoadSubtypeAllowlist_ExtractsTypedConstValues(t *testing.T) {
root := writeFixture(t, fixtureRepo{
"errs/subtypes.go": `package errs
Expand Down
6 changes: 4 additions & 2 deletions shortcuts/apps/apps_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/larksuite/cli/internal/cmdutil"
"github.com/larksuite/cli/internal/core"
"github.com/larksuite/cli/internal/httpmock"
"github.com/larksuite/cli/internal/testutil/gitcmd"
"github.com/larksuite/cli/shortcuts/common"
)

Expand Down Expand Up @@ -929,8 +930,7 @@ func TestAppsInit_NonEmpty_SingleInitCommit(t *testing.T) {
// gitMust runs a git command in dir with a real binary, failing the test on error.
func gitMust(t *testing.T, dir string, args ...string) string {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = dir
cmd := gitcmd.Command(dir, args...)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %v in %s failed: %v\n%s", args, dir, err, out)
Expand All @@ -946,6 +946,7 @@ func TestCommitAndPushIfDirty_RealGit_IgnoredAgentDir(t *testing.T) {
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git not available")
}
gitcmd.SetSynchronousMaintenanceEnv(t)
// Bare remote so `git push origin sprint/default` succeeds.
remote := t.TempDir()
gitMust(t, remote, "init", "--bare", "-q", "--initial-branch", defaultInitBranch)
Expand Down Expand Up @@ -1067,6 +1068,7 @@ func TestCommitAndPushIfDirty_RealGit_NonEmptyUpgrade(t *testing.T) {
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git not available")
}
gitcmd.SetSynchronousMaintenanceEnv(t)
remote := t.TempDir()
gitMust(t, remote, "init", "--bare", "-q", "--initial-branch", defaultInitBranch)

Expand Down
Loading