diff --git a/docs-api.html b/docs-api.html new file mode 100644 index 0000000..87f4b9e --- /dev/null +++ b/docs-api.html @@ -0,0 +1,15 @@ + + + + API docs - Ukigumo agent server(Go edition) + + + Ukigumo::Agent +
+

API docs - Ukigumo agent server(Go edition)

+
+ hehehe +
+
+ + diff --git a/index.html b/index.html new file mode 100644 index 0000000..2a6fd1c --- /dev/null +++ b/index.html @@ -0,0 +1,15 @@ + + + +

Ukigumo agent server(Go edition)

+
+ +
+
+ +
+ + + diff --git a/ukigumo-agent.go b/ukigumo-agent.go new file mode 100644 index 0000000..4a5270e --- /dev/null +++ b/ukigumo-agent.go @@ -0,0 +1,287 @@ +package main + +import ( + "bytes" + "encoding/json" + "log" + "net/http" + "net/url" + "path" + + "fmt" + "html/template" + "os" + "os/exec" + "os/user" + "time" + + flags "github.com/jessevdk/go-flags" +) + +// Endpoint URL +var endpoint string +var workDir string + +const ( + StatusSuccess = "1" + StatusFail = "2" + StatusNA = "3" + StatusSkip = "4" + StatusPending = "5" + StatusTimeout = "6" +) + +func RunCommand(buf *bytes.Buffer, cmd string, args ...string) error { + buf.Write([]byte("\n++ " + time.Now().String() + " ++\n")) + + c := exec.Command(cmd, args...) + out, err := c.CombinedOutput() + buf.Write(out) + return err +} + +/** +* Perl project using Module::Build + */ +func RunBuildPL(buf *bytes.Buffer) (string, []byte, error) { + err := RunCommand(buf, "perl", "Build.PL") + if err != nil { + return StatusNA, buf.Bytes(), err + } + + err = RunCommand(buf, "./Build") + if err != nil { + return StatusNA, buf.Bytes(), err + } + + err = RunCommand(buf, "./Build", "test") + if err != nil { + return StatusFail, buf.Bytes(), err + } + + return StatusSuccess, buf.Bytes(), nil +} + +/** +* Perl project using ExtUtils::MakeMaker + */ +func RunMakefilePL(buf *bytes.Buffer) (string, []byte, error) { + err := RunCommand(buf, "perl", "Makefile.PL") + if err != nil { + return StatusNA, buf.Bytes(), err + } + + err = RunCommand(buf, "make") + if err != nil { + return StatusNA, buf.Bytes(), err + } + + err = RunCommand(buf, "make", "test") + if err != nil { + return StatusFail, buf.Bytes(), err + } + + return StatusSuccess, buf.Bytes(), nil +} + +/** + * Run test suites. + */ +func RunTests() (string, []byte, error) { + buf := bytes.NewBuffer(nil) + + if _, err := os.Stat(".ukigumo.yml"); err == nil { + return StatusNA, buf.Bytes(), fmt.Errorf(".ukigumo.yml is not supported yet") + } else if _, err := os.Stat("Build.PL"); err == nil { + return RunBuildPL(buf) + } else if _, err := os.Stat("Makefile.PL"); err == nil { + return RunMakefilePL(buf) + } else { + return StatusNA, buf.Bytes(), fmt.Errorf("Unknown project type. There is no .ukigumo.yml, Makefile.PL or Build.PL.") + } +} + +var version = "v0.0.1" + +type Response map[string]interface{} + +func (r Response) String() (s string) { + b, err := json.Marshal(r) + if err != nil { + s = "" + return + } + s = string(b) + return +} + +func handler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + t, _ := template.ParseFiles("index.html") + t.Execute(w, nil) +} + +func docsApiHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + t, _ := template.ParseFiles("docs-api.html") + t.Execute(w, nil) +} + +func runWorker(repository string, branch string) { + buf := bytes.NewBuffer(nil) + + // TODO we should care the directory traversal + tmpdir := path.Join(workDir, url.QueryEscape(repository), url.QueryEscape(branch)) + os.RemoveAll(tmpdir) + + log.Printf("Testing %s@%s to %s", repository, branch, tmpdir) + + // git clone + os.MkdirAll(tmpdir, 0777) + err := RunCommand(buf, "git", "clone", "--branch", branch, repository, tmpdir) + if err != nil { + log.Printf("git clone failed: %s", buf.Bytes()[:]) + return + } + + log.Printf("run tests") + + log.Printf("... Finished!") +} + +func enqueueHandler(w http.ResponseWriter, r *http.Request) { + repository := r.FormValue("repository") + branch := r.FormValue("branch") + + if len(repository) == 0 { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + fmt.Fprint(w, Response{"success": false, "message": "Missing mandatory parameter: repository"}) + return + } + + if len(branch) == 0 { + branch = "master" + } + + go runWorker(repository, branch) + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + fmt.Fprint(w, Response{"success": true, "message": "enqueued."}) +} + +func startServer() { + // TODO /api/github_hook + http.HandleFunc("/", handler) + http.HandleFunc("/docs/api", docsApiHandler) + http.HandleFunc("/api/v0/enqueue", enqueueHandler) + http.ListenAndServe(":8080", nil) +} + +type cmdOptions struct { + Help bool `short:"h" long:"help" description:"show this help message and exit"` + EndPoint string `long:"endpoint" description:"End Point"` + WorkDir string `long:"workdir" description:"Working directory"` + Project string `long:"project" description:"project name"` + Version bool `long:"version" description:"print the version and exit"` +} + +// curl -X POST http://localhost:8080/api/v0/enqueue\?repository\=git://github.com/tokuhirom/Acme-Failing.git +func main() { + opts := &cmdOptions{} + parser := flags.NewParser(opts, flags.PrintErrors) + parser.Name = "ukigumo-agent" + parser.Usage = "[OPTIONS]" + + _, err := parser.Parse() + + if err != nil { + parser.WriteHelp(os.Stdout) + os.Exit(1) + } + + if opts.Help { + parser.WriteHelp(os.Stdout) + os.Exit(1) + } + + if opts.Version { + fmt.Fprintf(os.Stderr, "ukigumo-agent: %s\n", version) + return + } + if len(opts.EndPoint) == 0 { + log.Fatal("You must set endpoint url by arguments.") + } + endpoint = opts.EndPoint + + if len(opts.WorkDir) == 0 { + usr, err := user.Current() + if err != nil { + log.Fatal(err) + } + workDir = path.Join(usr.HomeDir, ".go-ukigumo-agent") + } else { + workDir = opts.WorkDir + } + err = os.MkdirAll(workDir, 0777) + if err != nil { + log.Fatal(err) + } + log.Print("working directory is: " + workDir) + + startServer() + + /* + + project := opts.Project + if len(project) == 0 { + pwd, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + + project = path.Base(pwd) + } + + log.Printf("Endpoint: %s", endpoint) + status, out, err := RunTests() + log.Printf("status: %s", status) + if err == nil { + // succeeded. + log.Printf("out: %s", out) + + resp, err := http.PostForm(endpoint, + url.Values{ + "status": {status}, + "project": {project}, + "branch": {"master"}, + "vc_log": {""}, + "body": {string(out[:])}, + "revision": {"1"}, + "repo": {"http://example.com"}, + }) + if err != nil { + log.Fatal(err) + } + log.Print(resp) + } else { + // failed. + log.Print(err) + log.Print(string(out[:])) + + resp, err := http.PostForm(endpoint, + url.Values{ + "status": {status}, + "project": {project}, + "branch": {"master"}, + "vc_log": {""}, + "body": {string(out[:])}, + "revision": {"1"}, + "repo": {"http://example.com"}, + }) + if err != nil { + log.Fatal(err) + } + log.Print(resp) + } + */ +} diff --git a/ukigumo-client.go b/ukigumo-client.go deleted file mode 100644 index c56ce6f..0000000 --- a/ukigumo-client.go +++ /dev/null @@ -1,184 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "log" - "net/http" - "net/url" - "os" - "os/exec" - "path" - "time" - - flags "github.com/jessevdk/go-flags" -) - -const ( - STATUS_SUCCESS = "1" - STATUS_FAIL = "2" - STATUS_NA = "3" - STATUS_SKIP = "4" - STATUS_PENDING = "5" - STATUS_TIMEOUT = "6" -) - -func RunCommand(buf *bytes.Buffer, cmd string, args ...string) error { - buf.Write([]byte("\n++ " + time.Now().String() + " ++\n")) - - c := exec.Command(cmd, args...) - out, err := c.CombinedOutput() - buf.Write(out) - return err -} - -/** -* Perl project using Module::Build - */ -func RunBuildPL(buf *bytes.Buffer) (string, []byte, error) { - err := RunCommand(buf, "perl", "Build.PL") - if err != nil { - return STATUS_NA, buf.Bytes(), err - } - - err = RunCommand(buf, "./Build") - if err != nil { - return STATUS_NA, buf.Bytes(), err - } - - err = RunCommand(buf, "./Build", "test") - if err != nil { - return STATUS_FAIL, buf.Bytes(), err - } - - return STATUS_SUCCESS, buf.Bytes(), nil -} - -/** -* Perl project using ExtUtils::MakeMaker - */ -func RunMakefilePL(buf *bytes.Buffer) (string, []byte, error) { - err := RunCommand(buf, "perl", "Makefile.PL") - if err != nil { - return STATUS_NA, buf.Bytes(), err - } - - err = RunCommand(buf, "make") - if err != nil { - return STATUS_NA, buf.Bytes(), err - } - - err = RunCommand(buf, "make", "test") - if err != nil { - return STATUS_FAIL, buf.Bytes(), err - } - - return STATUS_SUCCESS, buf.Bytes(), nil -} - -/** - * Run test suites. - */ -func RunTests() (string, []byte, error) { - buf := bytes.NewBuffer(nil) - - if _, err := os.Stat(".ukigumo.yml"); err == nil { - return STATUS_NA, buf.Bytes(), fmt.Errorf(".ukigumo.yml is not supported yet") - } else if _, err := os.Stat("Build.PL"); err == nil { - return RunBuildPL(buf) - } else if _, err := os.Stat("Makefile.PL"); err == nil { - return RunMakefilePL(buf) - } else { - return STATUS_NA, buf.Bytes(), fmt.Errorf("Unknown project type. There is no .ukigumo.yml, Makefile.PL or Build.PL.") - } -} - -var version = "v0.0.1" - -type cmdOptions struct { - Help bool `short:"h" long:"help" description:"show this help message and exit"` - EndPoint string `long:"endpoint" description:"End Point"` - Project string `long:"project" description:"project name"` - Version bool `long:"version" description:"print the version and exit"` -} - -func main() { - opts := &cmdOptions{} - parser := flags.NewParser(opts, flags.PrintErrors) - parser.Name = "ukigumo-client" - parser.Usage = "[OPTIONS]" - - _, err := parser.Parse() - - if err != nil { - parser.WriteHelp(os.Stdout) - os.Exit(1) - } - - if opts.Help { - parser.WriteHelp(os.Stdout) - os.Exit(1) - } - - if opts.Version { - fmt.Fprintf(os.Stderr, "ukigumo-client: %s\n", version) - return - } - - if len(opts.EndPoint) == 0 { - log.Fatal("You must set endpoint url by arguments.") - } - endpoint := opts.EndPoint - - project := opts.Project - if len(project) == 0 { - pwd, err := os.Getwd() - if err != nil { - log.Fatal(err) - } - - project = path.Base(pwd) - } - - log.Printf("Endpoint: %s", endpoint) - status, out, err := RunTests() - log.Printf("status: %s", status) - if err == nil { - // succeeded. - log.Printf("out: %s", out) - - resp, err := http.PostForm(endpoint, - url.Values{ - "status": {status}, - "project": {project}, - "branch": {"master"}, - "vc_log": {""}, - "body": {string(out[:])}, - "revision": {"1"}, - "repo": {"http://example.com"}, - }) - if err != nil { - log.Fatal(err) - } - log.Print(resp) - } else { - // failed. - log.Print(err) - log.Print(string(out[:])) - - resp, err := http.PostForm(endpoint, - url.Values{ - "status": {status}, - "project": {project}, - "branch": {"master"}, - "vc_log": {""}, - "body": {string(out[:])}, - "revision": {"1"}, - "repo": {"http://example.com"}, - }) - if err != nil { - log.Fatal(err) - } - log.Print(resp) - } -}