1

I have a program written in Go which runs Git to connect to GitHub. I'm trying to write a (unit) test for this program, hence I want to set up my own HTTP server inside the test to mock out GitHub. Essentially, to locally run the simplest possible fake version of GitHub (a remote Git hosting site).

I thought that it would be enough to create a test Git repository and serve the directory over HTTP. However, this doesn't seem to work. Here's my attempt (written in Go) and the output. (Assume /my/local/testrepo is a directory on my machine that contains a Git repo).

package main

import (
    "fmt"
    "net/http"
    "os/exec"
    "time"
)

func main() {
    // Set up Git server
    http.Handle("/", http.FileServer(http.Dir("/my/local/testrepo")))
    go http.ListenAndServe(":8080", nil)
    time.Sleep(1 * time.Second)

    out, err := exec.Command("git", "clone", "http://localhost:8080/").CombinedOutput()
    if err != nil {
        fmt.Printf("exec error: %v\n\n", err)
    }
    fmt.Println(string(out))
}

output:

exec error: exit status 128

Cloning into 'localhost'...
remote: 404 page not found
fatal: repository 'http://localhost:8080/' not found

How do I make this work?

0

3 Answers 3

0

For testing, use a local git repository:

cd /some/path
mkdir testrepo
cd testrepo
git init

then do

    out, err := exec.Command("git", "clone", "/some/path/testrepo/.git").CombinedOutput()

Note that you'll have to give the path to the pure repository, “.../testrepo /.git in this case. This should make unit testing much easier, too.

Sign up to request clarification or add additional context in comments.

Comments

0

Thanks to someone for leaving a comment about "dumb" and "smart" Git HTTP protocols, which was since deleted, but this helped me find the solution.

I was doing two things wrong. Firstly, in the source repo, you need to run git update-server-info before it can be served over HTTP. I assume this sets up the correct files that the Git client expects when cloning.

Secondly, the repo URL provided to git clone needs to be the exact path to the .git folder for the repo. In my case, I needed to pass in http://localhost:8080/.git.

1 Comment

The comment was mine, but I didn't delete it. Perhaps moderators.
0

For those curious, this is how you can run a "smart" HTTP Git server:

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/cgi"
    "os"
    "os/exec"
)

// Run a Git server using the "smart" HTTP Git protocol
// Run with the env variable GIT_PROJECT_ROOT pointing to a folder containing
// Git repos you want to serve
func main() {
    reposRoot := os.Getenv("GIT_PROJECT_ROOT")
    if reposRoot == "" {
        log.Fatal("GIT_PROJECT_ROOT env variable not set")
    }

    gitPath, err := exec.LookPath("git")
    if err != nil {
        log.Fatalf("cannot find git: %v", err)
    }
    log.Printf("using git at %q", gitPath)

    gitHandler := &cgi.Handler{
        Path: gitPath,
        Args: []string{"http-backend"},
        Env: []string{
            fmt.Sprintf("GIT_PROJECT_ROOT=%s", reposRoot),
            "GIT_HTTP_EXPORT_ALL=true",
        },
    }

    log.Fatal(http.ListenAndServe(":8080", gitHandler))
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.