diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6242fc6..d203943 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,8 +12,15 @@ jobs: uses: actions/setup-go@v5 with: go-version: 1.24.x + - name: Set up Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' + - run: cargo install cargo-binstall + # This sets up the binaries required for gix. + - run: cargo binstall gitoxide --force - run: make test + - run: make test_with_gix + - run: make test_with_git diff --git a/.gitignore b/.gitignore index ec0aa9e..50c4b5b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ dist __pycache__ vendor .history/ +.idea/ +.devcontainer/ \ No newline at end of file diff --git a/Makefile b/Makefile index 28950c9..f7303df 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,12 @@ test: test_with_git: build CODECRAFTERS_REPOSITORY_DIR=$(shell pwd)/internal/test_helpers/pass_all \ - CODECRAFTERS_TEST_CASES_JSON='[{"slug":"gg4","tester_log_prefix":"stage-1","title":"Stage #1: Initialize the .git directory"},{"slug":"ic4","tester_log_prefix":"stage-2","title":"Stage #2: Read a blob object"},{"slug":"jt4","tester_log_prefix":"stage-3","title":"Stage #3: Create a blob object"},{"slug":"kp1","tester_log_prefix":"stage-4","title":"Stage #4: Read a tree object"},{"slug":"fe4","tester_log_prefix":"stage-5","title":"Stage #5: Write a tree object"},{"slug":"jm9","tester_log_prefix":"stage-6","title":"Stage #6: Create a commit"},{"slug":"mg6","tester_log_prefix":"stage-7","title":"Stage #7: Clone a repository"}]' \ + CODECRAFTERS_TEST_CASES_JSON='[{"slug":"gg4","tester_log_prefix":"stage-1","title":"Stage #1: Initialize the .git directory"},{"slug":"ic4","tester_log_prefix":"stage-2","title":"Stage #2: Read a blob object"},{"slug":"jt4","tester_log_prefix":"stage-3","title":"Stage #3: Create a blob object"},{"slug":"kp1","tester_log_prefix":"stage-4","title":"Stage #4: Read a tree object"},{"slug":"fe4","tester_log_prefix":"stage-5","title":"Stage #5: Write a tree object"},{"slug":"jm9","tester_log_prefix":"stage-6","title":"Stage #6: Create a commit"}]' \ + $(shell pwd)/dist/main.out + +test_with_gix: build + CODECRAFTERS_REPOSITORY_DIR=$(shell pwd)/internal/test_helpers/clone \ + CODECRAFTERS_TEST_CASES_JSON='[{"slug":"mg6","tester_log_prefix":"stage-7","title":"Stage #7: Clone a repository"}]' \ $(shell pwd)/dist/main.out copy_course_file: diff --git a/internal/stage_clone_repository.go b/internal/stage_clone_repository.go index a0cb9fa..11a3725 100644 --- a/internal/stage_clone_repository.go +++ b/internal/stage_clone_repository.go @@ -2,7 +2,9 @@ package internal import ( "fmt" + "io" "os" + "os/exec" "path" "github.com/codecrafters-io/tester-utils/random" @@ -31,7 +33,7 @@ func (r TestRepo) randomFile() TestFile { return r.exampleFiles[random.RandomInt(0, len(r.exampleFiles))] } -var testRepos []TestRepo = []TestRepo{ +var testRepos = []TestRepo{ { url: "https://github.com/codecrafters-io/git-sample-1", exampleCommits: []string{ @@ -90,6 +92,46 @@ func testCloneRepository(harness *test_case_harness.TestCaseHarness) error { testRepo := randomRepo() logger.Infof("$ ./%s clone %s ", path.Base(executable.Path), testRepo.url) + + oldGitPath, err := exec.LookPath("git") + if err != nil { + return fmt.Errorf("git executable not found: %v", err) + } + oldGitDir := path.Dir(oldGitPath) + logger.Debugf("Found git executable at: %s", oldGitPath) + + tmpGitDir, err := os.MkdirTemp("/tmp", "git-*") + if err != nil { + return err + } + logger.Debugf("Created temporary directory for git clone: %s", tmpGitDir) + tmpGitPath := path.Join(tmpGitDir, "git") + defer os.RemoveAll(tmpGitDir) + + // Copy the custom_executable to the output path + command := fmt.Sprintf("sudo mv %s %s", oldGitPath, tmpGitDir) + logger.Debugf(command) + copyCmd := exec.Command("sh", "-c", command) + copyCmd.Stdout = os.Stdout + copyCmd.Stderr = os.Stderr + if err := copyCmd.Run(); err != nil { + return fmt.Errorf("CodeCrafters Internal Error: mv1 failed: %w", err) + } + logger.Debugf("mv-ed git to temp directory: %s", tmpGitDir) + + logger.Infof("$ git clone %s %s", testRepo.url, "test_dir") + + //////// which git + // command = fmt.Sprint("which git") + // logger.Debugf(command) + // cmd := exec.Command("sh", "-c", command) + // cmd.Stdout = os.Stdout + // cmd.Stderr = os.Stderr + // if err := cmd.Run(); err != nil { + // return fmt.Errorf("CodeCrafters Internal Error: mv1 failed: %w", err) + // } + // logger.Debugf("mv-ed git to temp directory: %s", tmpGitDir) + result, err := executable.Run("clone", testRepo.url, "test_dir") if err != nil { return err @@ -136,5 +178,23 @@ func testCloneRepository(harness *test_case_harness.TestCaseHarness) error { } logger.Successf("File contents verified") + defer func() error { + // Copy the custom_executable to the output path + command := fmt.Sprintf("sudo mv %s %s", tmpGitPath, oldGitDir) + logger.Debugf(command) + copyCmd := exec.Command("sh", "-c", command) + copyCmd.Stdout = io.Discard + copyCmd.Stderr = io.Discard + if err := copyCmd.Run(); err != nil { + return fmt.Errorf("CodeCrafters Internal Error: mv2 failed: %w", err) + } + logger.Debugf("mv-ed git to og directory: %s", oldGitDir) + + if err := os.RemoveAll(tmpGitDir); err != nil { + return fmt.Errorf("CodeCrafters Internal Error: delete directory failed: %s", tmpGitDir) + } + return nil + }() + return nil } diff --git a/internal/test_helpers/clone/codecrafters.yml b/internal/test_helpers/clone/codecrafters.yml new file mode 100644 index 0000000..533cd7a --- /dev/null +++ b/internal/test_helpers/clone/codecrafters.yml @@ -0,0 +1,11 @@ +# This is the current stage that you're on. +# +# Whenever you want to advance to the next stage, +# bump this to the next number. +current_stage: 1 + +# Set this to true if you want debug logs. +# +# These can be VERY verbose, so we suggest turning them off +# unless you really need them. +debug: true diff --git a/internal/test_helpers/clone/your_git.sh b/internal/test_helpers/clone/your_git.sh new file mode 100755 index 0000000..b187125 --- /dev/null +++ b/internal/test_helpers/clone/your_git.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +if [ "$1" = "init" ] +then + ein init "@$" +fi + +if [ "$1" = "cat-file" ] +then + gix cat "@$" +fi + +exec gix "$@" diff --git a/internal/test_helpers/pass_all/your_git.sh b/internal/test_helpers/pass_all/your_git.sh index d7d4c22..59758cb 100755 --- a/internal/test_helpers/pass_all/your_git.sh +++ b/internal/test_helpers/pass_all/your_git.sh @@ -1,5 +1,9 @@ #!/bin/sh +git config --global user.email "you@example.com" +git config --global user.name "Your Name" +git config --global init.defaultBranch "main" + if [ "$1" = "write-tree" ] then git add .