最近抽空重新把自己的服务器也整理了下,因为每次代码发布及最终程序部署都比较麻烦,因此顺手写了个简易版的自动化部署程序,主要用到的还是GOGS的web钩子和用golang写的一个简单的web发布工具,细节见下。

具体原理是在服务器上部署发布程序,然后在gogs上面配置相应项目的钩子,指定调用gogs的事件。我的是只要推送代码,就会调用发布程序。
2024-11-16T12:01:44.png

2024-11-16T12:02:05.png

package main
import (
   "bytes"
   "flag"
   "fmt"
   "gopkg.in/src-d/go-git.v4"
   gitHttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
   "io"
   "log"
   "net/http"
   "net/url"
   "os"
   "os/exec"
   "strconv"
   "sync"
   "time"
)

var (
   path         = "/www/html"
   gitUrl       = "https://gogs.liigoo.com/tttt/blog.git"
   gitUsername  = "test"
   gitPassword  = "test"

   listenHost   = "0.0.0.0"
   listenPort   = 9990
   mu            sync.Mutex
)

func main() {

   host := flag.String("h",listenHost,"ip address")
   port := flag.Int("p", listenPort, "port")

   flag.CommandLine.Parse(os.Args[1:])

   middleware := func(fns ...func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
      return func(w http.ResponseWriter, r *http.Request) {
         for _, fn := range fns {
            fn(w, r)
         }
      }
   }

   server := &http.Server{
      Addr: *host + ":" + strconv.Itoa(*port),
      ReadTimeout: 300 *time.Second,
      WriteTimeout: 300 *time.Second,
   }

![WX20190918-140547@2x.png][3]   http.HandleFunc("/", middleware(outPut, helloWord))
   http.HandleFunc("/release/blog", middleware(outPut, releaseBlog))

   log.Printf("listening on %s:%d\n", *host, *port)
   err := server.ListenAndServe()
   if err != nil {
      log.Fatal(err)
   }
}

func outPut(w http.ResponseWriter, r *http.Request) {
   fmt.Printf("userHeader: %v \n", r.Header)
   fmt.Printf("method: %v \n", r.Method)
   fmt.Printf("form: %v \n", r.Form)
   fmt.Printf("requestUrl: %v \n", r.RequestURI)
   fmt.Printf("remoteAddr: %v \n", r.RemoteAddr)
}

func helloWord(w http.ResponseWriter, r *http.Request) {
   io.WriteString(w, "hello world")
}

func releaseBlog(w http.ResponseWriter, r *http.Request) {

   err, p := getParse("p", w, r)
   if err != nil {
      log.Fatal(err.Error())
   }

   if p != "blog" {
      io.WriteString(w, "项目名称错误...")
      return
   }

   mu.Lock()
   defer mu.Unlock()

   if !checkPath() {
      if err := clone(); err != nil {
         io.WriteString(w, fmt.Sprintf("克隆仓库失败, err: %v", err.Error()))
         return
      }
   }

   err = pull()
   if err != nil {
      if err := execShell(fmt.Sprintf("rm -rf %v && mkdir -p %v && chmod -R 777 %v", path, path, path)); err != nil {
         io.WriteString(w, fmt.Sprintf("删除目录失败, err: %v", err.Error()))
         return
      }
      if err := clone(); err != nil {
         io.WriteString(w, fmt.Sprintf("拉取代码失败, err: %v", err.Error()))
         return
      }
   }

   io.WriteString(w, "上线发布成功!")
   return

}


func getParse(k string, _ http.ResponseWriter, r *http.Request) (error, string) {
   queryForm, err := url.ParseQuery(r.URL.RawQuery)
   if err == nil && len(queryForm[k]) > 0 {
      return nil, queryForm[k][0]
   }
   return err, ""
}

func pull() error {

   defer func() {
      if err := recover(); err != nil {
      }
   }()

   r, err := git.PlainOpen(path)
   if err != nil {
      return err
   }

   w, err := r.Worktree()
   if err != nil {
      return err
   }

   err = w.Pull(&git.PullOptions{
      RemoteName: "origin",
      Auth: &gitHttp.BasicAuth {
         Username: gitUsername,
         Password: gitPassword,
      },
   })
   if err != nil {
      return err
   }

   ref, err := r.Head()
   fmt.Println(ref.Name())
   if err != nil {
      return err
   }
   commit, err := r.CommitObject  (ref.Hash())
   if err != nil {
      return err
   }

   fmt.Println(commit)
   return nil
}

func clone() error {

   r, err := git.PlainClone(path, false, &git.CloneOptions{
      Auth: &gitHttp.BasicAuth{
         Username: gitUsername,
         Password: gitPassword,
      },
      URL:      gitUrl,
      Progress: os.Stdout,
   })
   if err != nil {
      fmt.Println(err.Error())
      return err
   }

   ref, err := r.Head()

   fmt.Println(ref)
   if err != nil {
      fmt.Println(err.Error())
      return err
   }
   commit, err := r.CommitObject(ref.Hash())
   if err != nil {
      fmt.Println(err.Error())
      return err
   }

   fmt.Println(commit)
   return nil
}

func checkPath() bool {

   p, err := os.Stat(path)
   if err != nil {
      return false
   }

   return p.IsDir()
}

func execShell(script string) error {

   cmd := exec.Command("/bin/bash", "-c", script)

   var out bytes.Buffer
   var stderr bytes.Buffer
   cmd.Stdout = &out
   cmd.Stderr = &stderr

   err := cmd.Run()
   fmt.Println(stderr.String())
   return err
}