简单的自动部署
最近抽空重新把自己的服务器也整理了下,因为每次代码发布及最终程序部署都比较麻烦,因此顺手写了个简易版的自动化部署程序,主要用到的还是GOGS的web钩子和用golang写的一个简单的web发布工具,细节见下。
具体原理是在服务器上部署发布程序,然后在gogs上面配置相应项目的钩子,指定调用gogs的事件。我的是只要推送代码,就会调用发布程序。

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
}本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
评论已关闭