├── client ├── test │ ├── tmp │ ├── testkill.sh │ ├── fmt_test.go │ ├── test.json │ └── master.json ├── .DS_Store ├── api │ ├── .DS_Store │ ├── devops.sh │ ├── sh │ │ └── dollarkillerx1easyutils8081master.sh │ ├── router │ │ └── app.go │ ├── httprouter_registered │ │ └── httprouter.go │ ├── main.go │ ├── config.yml │ └── controller │ │ └── main.go ├── defs │ └── githubapi.go ├── initialization │ └── initialization.go └── config │ └── config.go ├── .DS_Store ├── README ├── one.png └── gowith.png ├── cmd ├── .DS_Store ├── config.yml ├── main.go ├── logic │ └── logic_main.go └── config │ └── config.go ├── server ├── .DS_Store ├── web │ ├── .DS_Store │ ├── config.yml │ ├── httprouter_registered │ │ └── httprouter.go │ ├── routers │ │ └── app.go │ ├── main.go │ └── controller │ │ └── main_controller.go └── config │ └── config.go ├── .gitignore ├── config.yml ├── common └── resp.go ├── test └── one_test.go ├── LICENSE ├── utils └── utils.go ├── go.mod ├── README.md └── go.sum /client/test/tmp: -------------------------------------------------------------------------------- 1 | PID 2 | 6303 3 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/.DS_Store -------------------------------------------------------------------------------- /README/one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/README/one.png -------------------------------------------------------------------------------- /cmd/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/cmd/.DS_Store -------------------------------------------------------------------------------- /client/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/client/.DS_Store -------------------------------------------------------------------------------- /server/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/server/.DS_Store -------------------------------------------------------------------------------- /README/gowith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/README/gowith.png -------------------------------------------------------------------------------- /client/api/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/client/api/.DS_Store -------------------------------------------------------------------------------- /server/web/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dollarkillerx/easydevops/HEAD/server/web/.DS_Store -------------------------------------------------------------------------------- /client/test/testkill.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | lsof -i :8083 | awk '{print $2}'> tmp 3 | pid=$(awk 'NR==2{print}' tmp); 4 | kill -9 $pid -------------------------------------------------------------------------------- /server/web/config.yml: -------------------------------------------------------------------------------- 1 | 2 | # easydevops 自动生成文件 server 服务器端 3 | 4 | app: 5 | host: "0.0.0.0:8083" # 服务器运行 6 | server_key: "dollarkiller" # 服务器key 用于用户验证 7 | -------------------------------------------------------------------------------- /client/api/devops.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | kill -9 $(grep webserver) 4 | 5 | cd ~/newweb/ 6 | 7 | git pull https:/github.com/sdsd 8 | 9 | cd webserver 10 | 11 | ./webserver & 12 | -------------------------------------------------------------------------------- /client/api/sh/dollarkillerx1easyutils8081master.sh: -------------------------------------------------------------------------------- 1 | 2 | #! /bin/sh 3 | 4 | lsof -i :8081 | awk '{print $2}'> tmp 5 | pid=$(awk 'NR==2{print}' tmp); 6 | kill -9 $pid 7 | 8 | cd /home/s/easydevops 9 | ./api 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | .idea 14 | client/api/api 15 | client/api/tmp 16 | cmd/cmd 17 | server/web/web -------------------------------------------------------------------------------- /cmd/config.yml: -------------------------------------------------------------------------------- 1 | 2 | # devops生成文件 开发机 cli 端 3 | 4 | app: 5 | devops_server: "http://0.0.0.0:8083/upfile" # devops 服务器地址 https:// ... 6 | server_key: "xxxxxx" # 上传 devops 服务器秘钥 7 | key: "mmc" # 文件同步 秘钥 (服务器同步数据时需要) 8 | 9 | 10 | devops: 11 | full_name: "" # 名称 例如 dollarkillerx/easyutils 12 | branch: "master" # 分支 13 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | 2 | # devops生成文件 开发机 cli 端 3 | 4 | app: 5 | devops_server: "http://0.0.0.0:8083/upfile" # devops 服务器地址 https:// ... 6 | server_key: "" # 上传 devops 服务器秘钥 7 | key: "mmc" # 文件同步 秘钥 (服务器同步数据时需要) 8 | 9 | 10 | devops: 11 | full_name: "dollarkillerx/easyutils" # 名称 例如 dollarkillerx/easyutils 12 | branch: "master" # 分支 13 | -------------------------------------------------------------------------------- /client/api/router/app.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:06 2019-09-16 6 | */ 7 | package router 8 | 9 | import ( 10 | controller2 "easydevops/client/api/controller" 11 | "github.com/julienschmidt/httprouter" 12 | ) 13 | 14 | func RegisterRouter(app *httprouter.Router) { 15 | app.POST("/update", controller2.Rundevops) 16 | } 17 | -------------------------------------------------------------------------------- /server/web/httprouter_registered/httprouter.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:02 2019-09-16 6 | */ 7 | package httprouter_registered 8 | 9 | import ( 10 | "easydevops/server/web/routers" 11 | "github.com/julienschmidt/httprouter" 12 | ) 13 | 14 | func RegisterHttprouter() *httprouter.Router { 15 | router := httprouter.New() 16 | 17 | routers.RegisterRouter(router) 18 | 19 | return router 20 | } 21 | -------------------------------------------------------------------------------- /server/web/routers/app.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:06 2019-09-16 6 | */ 7 | package routers 8 | 9 | import ( 10 | "easydevops/server/web/controller" 11 | "github.com/julienschmidt/httprouter" 12 | ) 13 | 14 | func RegisterRouter(app *httprouter.Router) { 15 | app.POST("/upfile", controller.UpFile) // cli端 上传文件 需要秘钥才能上传 16 | 17 | app.POST("/getfile",controller.GetFile) // 需要秘钥才能获取 18 | } 19 | -------------------------------------------------------------------------------- /client/api/httprouter_registered/httprouter.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:02 2019-09-16 6 | */ 7 | package httprouter_registered 8 | 9 | import ( 10 | router3 "easydevops/client/api/router" 11 | "github.com/julienschmidt/httprouter" 12 | ) 13 | 14 | func RegisterHttprouter() *httprouter.Router { 15 | router := httprouter.New() 16 | 17 | router3.RegisterRouter(router) 18 | 19 | return router 20 | } 21 | -------------------------------------------------------------------------------- /client/defs/githubapi.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:08 2019-09-16 6 | */ 7 | package defs 8 | 9 | type GithubAPI struct { 10 | Branch string `json:"ref" form:"ref"` 11 | Repository struct { 12 | FullName string `json:"full_name" form:"full_name"` 13 | } 14 | Commits []struct{ 15 | Message string `json:"message" form:"message"` 16 | } 17 | } 18 | 19 | // "ref": "refs/heads/master", 20 | // "ref": "refs/heads/test", 21 | -------------------------------------------------------------------------------- /common/resp.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 通用返回 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 14:51 2019-09-21 6 | */ 7 | package common 8 | 9 | import "net/http" 10 | 11 | type Resp struct { 12 | 13 | } 14 | 15 | func (r *Resp) Auth401(w http.ResponseWriter) { 16 | w.WriteHeader(401) 17 | w.Write([]byte("401")) 18 | } 19 | 20 | func (r *Resp) Ok200(w http.ResponseWriter) { 21 | w.WriteHeader(200) 22 | w.Write([]byte("200")) 23 | } 24 | 25 | func (r *Resp) Bad500(w http.ResponseWriter) { 26 | w.WriteHeader(500) 27 | w.Write([]byte("500")) 28 | } -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 自动更新工具 开发机用cli 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 09:58 2019-09-21 6 | */ 7 | package main 8 | 9 | import ( 10 | "easydevops/cmd/logic" 11 | "easydevops/utils" 12 | "github.com/dollarkillerx/easyutils/clog" 13 | ) 14 | 15 | // zip打包当前目录 16 | 17 | func init() { 18 | clog.Println("系统初始化 完毕") 19 | } 20 | 21 | func main() { 22 | loc := logic.Logic{} 23 | 24 | loc.Bale() // 打包 25 | loc.Up() // 上传 26 | 27 | util := utils.Utils{} 28 | util.Github() // 同步github 29 | 30 | clog.Println("更新以及全部提交") 31 | } 32 | -------------------------------------------------------------------------------- /client/api/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:01 2019-09-16 6 | */ 7 | package main 8 | 9 | import ( 10 | httprouter_registered2 "easydevops/client/api/httprouter_registered" 11 | "easydevops/client/config" 12 | "easydevops/client/initialization" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "log" 15 | "net/http" 16 | ) 17 | 18 | func init() { 19 | // 进行项目初始化 20 | initialization.Initialization() 21 | } 22 | 23 | func main() { 24 | app := httprouter_registered2.RegisterHttprouter() 25 | 26 | clog.Println("http://" + config.Basis.App.Host) 27 | log.Fatal(http.ListenAndServe(config.Basis.App.Host, app)) 28 | } 29 | -------------------------------------------------------------------------------- /test/one_test.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 10:03 2019-09-21 6 | */ 7 | package test 8 | 9 | import ( 10 | "easydevops/utils" 11 | "github.com/dollarkillerx/easyutils/clog" 12 | "log" 13 | "testing" 14 | ) 15 | 16 | func TestOne(t *testing.T) { 17 | as := []string{"sadas", "regre"} 18 | a(as...) 19 | } 20 | 21 | func a(arg ...string) { 22 | for _, k := range arg { 23 | log.Println(k) 24 | } 25 | } 26 | 27 | 28 | func TestRun(t *testing.T) { 29 | //lsof -i :8081 | awk '{print $2}'> tmp | pid=$(awk 'NR==2{print}' tmp) | echo $pid; 30 | i := utils.Utils{} 31 | 32 | e, s, i2 := i.Exec( "sh","lsof", "-i", ":8081", "| awk '{print $2}'> tmp | pid=$(awk 'NR==2{print}' tmp) | echo $pid;") 33 | clog.PrintWa(e) 34 | clog.Println(s) 35 | clog.Println(i2) 36 | } -------------------------------------------------------------------------------- /client/api/config.yml: -------------------------------------------------------------------------------- 1 | # devops生成文件 请填写完成检查确认后 再 运行啊 (每次运行会重写sh模块) 2 | 3 | 4 | # 这devops系统配置 5 | app: 6 | host: "0.0.0.0:8083" 7 | devops_server: "http://0.0.0.0:8083/getfile" # devops 服务器地址 https:// ... 8 | server_key: "xxxxxx" # 上传 devops 服务器秘钥 9 | 10 | # 要自动化部署应用的配置 11 | devops: 12 | node: 13 | - port: "8081" # 程序运行端口 14 | full_name: "dollarkillerx/easyutils" # 名称 例如 dollarkillerx/easyutils 15 | branch: "master" # 分支 16 | key: "key" # 文件同步 秘钥 (服务器同步数据时需要) 17 | giturl: "https://github" # git pull url 地址 (你要先配置一下秘钥啊!) 18 | runname: "api" # 运行程序的name 19 | dirpath: "/home/s" # 绝对路径 20 | secondarydirectory: "" # 如果有二级目录 就填写在这里 21 | email: "" # 部署成功收邮件通知 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /client/test/fmt_test.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:57 2019-09-16 6 | */ 7 | package test 8 | 9 | import ( 10 | "fmt" 11 | "github.com/dollarkillerx/easyutils/clog" 12 | "log" 13 | "strings" 14 | "testing" 15 | ) 16 | 17 | func TestFmt(t *testing.T) { 18 | sprintf := fmt.Sprintf(sh1, "ss", "sd", "cs", "ss") 19 | clog.Println(sprintf) 20 | } 21 | 22 | var sh1 = ` 23 | #! /bin/sh 24 | 25 | kill -9 $(grep %s) 26 | 27 | cd %s 28 | 29 | git pull %s 30 | 31 | 32 | ./%s & 33 | ` 34 | 35 | func TestFull(t *testing.T) { 36 | s := getgitpath("dollarkillerx/easyutils") 37 | clog.Println(s) 38 | 39 | gitpath := getgitpath("dollarkillerx/easyutils/") 40 | if string(gitpath[len(gitpath)-1]) == "/" { 41 | gitpath = gitpath[:len(gitpath)-1] 42 | } 43 | 44 | log.Println(gitpath) 45 | 46 | } 47 | 48 | func getgitpath(full string) string { 49 | index := strings.Index(full, "/") 50 | 51 | return full[(index + 1):] 52 | } 53 | -------------------------------------------------------------------------------- /server/web/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 14:19 2019-09-21 6 | */ 7 | package main 8 | 9 | import ( 10 | "easydevops/server/config" 11 | "easydevops/server/web/httprouter_registered" 12 | "github.com/dollarkillerx/easyutils" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "log" 15 | "net/http" 16 | "os" 17 | ) 18 | 19 | func init() { 20 | // 初始化 服务器 21 | b, e := easyutils.PathExists("./file") 22 | if e == nil && b == true { 23 | // 如果存在 就删除历史数据 24 | e := os.RemoveAll("./file") 25 | if e != nil { 26 | clog.PrintWa("历史 文件 删除 失败 请手动删除") 27 | os.Exit(0) 28 | } 29 | } 30 | 31 | // 创建 文件存放目录 32 | e = easyutils.DirPing("./file") 33 | if e != nil { 34 | clog.PrintWa("初始化文件目录失败") 35 | os.Exit(0) 36 | } 37 | } 38 | 39 | 40 | func main() { 41 | httprouter := httprouter_registered.RegisterHttprouter() 42 | 43 | clog.Println("http://" + config.Basis.App.Host) 44 | log.Fatal(http.ListenAndServe(config.Basis.App.Host, httprouter)) 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dollarkillerx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/config/config.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 14:18 2019-09-21 6 | */ 7 | package config 8 | 9 | import ( 10 | "github.com/dollarkillerx/easyutils" 11 | "github.com/dollarkillerx/easyutils/clog" 12 | "gopkg.in/yaml.v2" 13 | "io/ioutil" 14 | ) 15 | 16 | type base struct { 17 | App struct { 18 | Host string `yaml:"host"` 19 | ServerKey string `json:"server_key" yaml:"server_key"` 20 | } 21 | } 22 | 23 | var ( 24 | Basis *base 25 | ) 26 | 27 | func init() { 28 | 29 | // 判断配置文件是否存在 如果不存在 则创建 30 | b, e := easyutils.PathExists("./config.yml") 31 | if e != nil || b == false { 32 | createConfig() 33 | panic("请填写配置文件") 34 | } 35 | 36 | Basis = &base{} 37 | 38 | bytes, e := ioutil.ReadFile("./config.yml") 39 | if e != nil { 40 | panic(e.Error()) 41 | } 42 | 43 | e = yaml.Unmarshal(bytes, Basis) 44 | if e != nil { 45 | panic(e.Error()) 46 | }else { 47 | clog.Println(Basis) 48 | } 49 | } 50 | 51 | func createConfig() { 52 | err := ioutil.WriteFile("config.yml", []byte(devposconfig), 00666) 53 | if err != nil { 54 | panic("配置文件 创建失败") 55 | } 56 | } 57 | 58 | var devposconfig = ` 59 | # easydevops 自动生成文件 server 服务器端 60 | 61 | app: 62 | host: "0.0.0.0:8083" # 服务器运行 63 | server_key: "" # 服务器key 用于用户验证 64 | ` 65 | 66 | -------------------------------------------------------------------------------- /cmd/logic/logic_main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 主逻辑 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:31 2019-09-21 6 | */ 7 | package logic 8 | 9 | import ( 10 | "easydevops/cmd/config" 11 | "easydevops/utils" 12 | "github.com/dollarkillerx/easyutils/clog" 13 | "github.com/dollarkillerx/easyutils/httplib" 14 | "os" 15 | "strings" 16 | ) 17 | 18 | type Logic struct { 19 | } 20 | 21 | // 打包 22 | func (l *Logic) Bale() { 23 | i := utils.Utils{} 24 | 25 | i.Zip(l.GetName()) 26 | clog.Println("文件打包完毕") 27 | } 28 | 29 | 30 | // 上传 31 | func (l *Logic) Up() { 32 | clog.Println("文件开始上传到 devops") 33 | clog.Println(l.GetName()) 34 | s := config.Basis.App.DevopsServer 35 | 36 | post := httplib.Post(s) 37 | post.Param("server_key",config.Basis.App.ServerKey) 38 | post.Param("key",config.Basis.App.Key) 39 | post.PostFile("file", l.GetName()+".tar.gz") 40 | i, e := post.String() 41 | 42 | if e != nil { 43 | clog.PrintWa("上传到 devops服务器失败 请检查填写是否正确") 44 | os.Exit(0) 45 | } 46 | 47 | switch i { 48 | case "200": 49 | clog.Println("打包文件 上传完毕") 50 | case "401": 51 | clog.PrintWa("打包文件 上传失败 401") 52 | os.Exit(0) 53 | case "500": 54 | clog.PrintWa("打包文件 上传失败 500") 55 | os.Exit(0) 56 | default: 57 | clog.PrintWa("未知错误!" + i) 58 | os.Exit(0) 59 | } 60 | 61 | // 文件上传完毕 删除本地文件 62 | e = os.Remove(l.GetName() + ".tar.gz") 63 | if e != nil { 64 | clog.PrintWa("清理冗余数据失败") 65 | } 66 | } 67 | 68 | // 未来会添加读取 .gitignore 来判断哪些文件不更新 69 | func (l *Logic) GetName() string { 70 | fullName := strings.Replace(config.Basis.Devops.FullName, "/", "1", -1) 71 | name := fullName + config.Basis.Devops.Branch 72 | return name 73 | } -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 本项目 通用utils 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 10:01 2019-09-21 6 | */ 7 | package utils 8 | 9 | import ( 10 | "bytes" 11 | "crypto/md5" 12 | "fmt" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "github.com/dollarkillerx/easyutils/compression" 15 | "io" 16 | "os" 17 | "os/exec" 18 | ) 19 | 20 | type Utils struct { 21 | } 22 | 23 | func Util() *Utils { 24 | return &Utils{} 25 | } 26 | 27 | func (u *Utils) Exec(sh string, arg ...string) (error, string, string) { 28 | var stdout bytes.Buffer 29 | var stderr bytes.Buffer 30 | cmd := exec.Command(sh, arg...) 31 | cmd.Stdout = &stdout // 输出 32 | cmd.Stderr = &stderr // 输出错误 33 | err := cmd.Run() 34 | return err, stdout.String(), stderr.String() 35 | } 36 | 37 | func (u *Utils) Zip(name string) { 38 | zip := compression.Tar{} 39 | err := zip.Tar(".", name) 40 | if err != nil { 41 | panic(err) 42 | } 43 | } 44 | 45 | func (u *Utils) Github() { 46 | e, s, i2 := u.Exec("git", "add", ".") 47 | if e != nil { 48 | clog.Println(s) 49 | clog.Println(i2) 50 | } 51 | clog.Println("github add 完毕") 52 | e, s, i2 = u.Exec("git", "commit", "-m", "EasyDevOps") 53 | if e != nil { 54 | clog.Println(s) 55 | clog.Println(i2) 56 | } 57 | clog.Println("github commit 完毕") 58 | e, s, i2 = u.Exec("git", "push") 59 | if e != nil { 60 | clog.Println(s) 61 | clog.Println(i2) 62 | } 63 | clog.Println("github push 完毕") 64 | } 65 | 66 | // 获取文件hash md5 67 | func (u *Utils) Md5File(path string) (string, error) { 68 | file, err := os.Open(path) 69 | defer file.Close() 70 | if err != nil { 71 | return "", err 72 | } 73 | 74 | h := md5.New() 75 | _, err = io.Copy(h, file) 76 | if err != nil { 77 | return "", err 78 | } 79 | 80 | return fmt.Sprintf("%x", h.Sum(nil)), nil 81 | } 82 | -------------------------------------------------------------------------------- /cmd/config/config.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: cmd 配置模块 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:21 2019-09-21 6 | */ 7 | package config 8 | 9 | import ( 10 | "github.com/dollarkillerx/easyutils" 11 | "github.com/dollarkillerx/easyutils/clog" 12 | "gopkg.in/yaml.v2" 13 | "io/ioutil" 14 | "os" 15 | ) 16 | 17 | type Node struct { 18 | FullName string `yaml:"full_name"` 19 | Branch string `yaml:"branch"` 20 | } 21 | 22 | type base struct { 23 | App struct { 24 | DevopsServer string `json:"devops_server" yaml:"devops_server"` 25 | ServerKey string `json:"server_key" yaml:"server_key"` 26 | Key string `json:"key" yaml:"key"` 27 | } 28 | Devops Node `json:"devops" yaml:"devops"` 29 | } 30 | 31 | var ( 32 | Basis *base 33 | ) 34 | 35 | func init() { 36 | // 判断配置文件是否存在 如果不存在 则创建 37 | b, e := easyutils.PathExists("./devconfig.yml") 38 | if e != nil || b == false { 39 | createConfig() 40 | clog.Println("配置文件初始化完成") 41 | clog.PrintEr("请填写配置文件 并检查是否填写正确") 42 | os.Exit(0) 43 | } 44 | 45 | Basis = &base{} 46 | 47 | bytes, e := ioutil.ReadFile("./devconfig.yml") 48 | if e != nil { 49 | panic(e.Error()) 50 | } 51 | 52 | e = yaml.Unmarshal(bytes, Basis) 53 | if e != nil { 54 | panic(e.Error()) 55 | } 56 | } 57 | 58 | func createConfig() { 59 | err := ioutil.WriteFile("devconfig.yml", []byte(devposconfig), 00666) 60 | if err != nil { 61 | panic("配置文件 创建失败") 62 | } 63 | } 64 | 65 | var devposconfig = ` 66 | # devops生成文件 开发机 cli 端 67 | 68 | app: 69 | devops_server: "http://0.0.0.0:8083/upfile" # devops 服务器地址 https:// ... 70 | server_key: "" # 上传 devops 服务器秘钥 71 | key: "" # 文件同步 秘钥 (服务器同步数据时需要) 72 | 73 | 74 | devops: 75 | full_name: "" # 名称 例如 dollarkillerx/easyutils 76 | branch: "master" # 分支 77 | ` 78 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module easydevops 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect 7 | github.com/casbin/casbin v1.9.1 // indirect 8 | github.com/couchbase/go-couchbase v0.0.0-20190916184909-f83e63d76bc4 // indirect 9 | github.com/couchbase/gomemcached v0.0.0-20190920220213-2b4197fedf38 // indirect 10 | github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b // indirect 11 | github.com/dollarkillerx/easyutils v0.0.0-20190921081604-08d9395753f7 12 | github.com/edsrzf/mmap-go v1.0.0 // indirect 13 | github.com/go-redis/redis v6.15.5+incompatible // indirect 14 | github.com/gogo/protobuf v1.3.0 // indirect 15 | github.com/golang/protobuf v1.3.2 // indirect 16 | github.com/golang/snappy v0.0.1 // indirect 17 | github.com/julienschmidt/httprouter v1.2.0 18 | github.com/lib/pq v1.2.0 // indirect 19 | github.com/mattn/go-sqlite3 v1.11.0 // indirect 20 | github.com/mojocn/base64Captcha v0.0.0-20190801020520-752b1cd608b2 // indirect 21 | github.com/onsi/ginkgo v1.10.1 // indirect 22 | github.com/onsi/gomega v1.7.0 // indirect 23 | github.com/pelletier/go-toml v1.4.0 // indirect 24 | github.com/pkg/errors v0.8.1 25 | github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92 // indirect 26 | github.com/syndtr/goleveldb v1.0.0 // indirect 27 | github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec // indirect 28 | golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 // indirect 29 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a // indirect 30 | golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72 // indirect 31 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect 32 | golang.org/x/sys v0.0.0-20190920190810-ef0ce1748380 // indirect 33 | golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72 // indirect 34 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 35 | gopkg.in/yaml.v2 v2.2.2 36 | ) 37 | -------------------------------------------------------------------------------- /client/initialization/initialization.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 项目初始化 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:47 2019-09-16 6 | */ 7 | package initialization 8 | 9 | import ( 10 | "easydevops/client/config" 11 | "fmt" 12 | "github.com/dollarkillerx/easyutils" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "io/ioutil" 15 | "strings" 16 | ) 17 | 18 | func Initialization() { 19 | // 如果用户填写了配置文件 就生成 devops.sh 20 | createDevops() 21 | } 22 | 23 | func createDevops() { 24 | // 创建sh 脚本存放目录 25 | err := easyutils.DirPing("./sh") 26 | if err != nil { 27 | clog.PrintWa("脚本存放目录 创建失败") 28 | panic(err) 29 | } 30 | 31 | // 遍历整个 devops > node 32 | for _, k := range config.Basis.Devops.Node { 33 | // 脚本名称 34 | name := strings.Replace(k.FullName, "/", "1", -1) 35 | shName := name + k.Port + k.Branch + ".sh" 36 | shPath := "./sh/" + shName 37 | 38 | ks := k.Dirpath + "/easydevops" 39 | 40 | // 如果没有二级目录 41 | if k.Secondarydirectory == "" { 42 | sh := fmt.Sprintf(sh1, k.Port, ks, k.Runname) 43 | err := ioutil.WriteFile(shPath, []byte(sh), 00666) 44 | if err != nil { 45 | clog.PrintWa("sh文件创建失败") 46 | panic(err) 47 | } 48 | } else { 49 | // 如果存在二级目录 50 | sh := fmt.Sprintf(sh2, k.Port, ks, k.Secondarydirectory,k.Runname) 51 | err := ioutil.WriteFile(shPath, []byte(sh), 00666) 52 | if err != nil { 53 | clog.PrintWa("sh文件创建失败") 54 | panic(err) 55 | } 56 | } 57 | } 58 | clog.Println("sh脚本初始化完毕") 59 | } 60 | 61 | func getgitpath(full string) string { 62 | index := strings.Index(full, "/") 63 | 64 | return full[(index + 1):] 65 | } 66 | 67 | var sh1 = ` 68 | #! /bin/sh 69 | 70 | lsof -i :%s | awk '{print $2}'> tmp 71 | pid=$(awk 'NR==2{print}' tmp); 72 | kill -9 $pid 73 | 74 | cd %s 75 | ./%s 76 | ` 77 | 78 | var sh2 = ` 79 | #! /bin/sh 80 | 81 | lsof -i :%s | awk '{print $2}'> tmp 82 | pid=$(awk 'NR==2{print}' tmp); 83 | kill -9 $pid 84 | 85 | cd %s 86 | cd %s 87 | ./%s 88 | ` 89 | -------------------------------------------------------------------------------- /server/web/controller/main_controller.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 中心配置文件 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 14:42 2019-09-21 6 | */ 7 | package controller 8 | 9 | import ( 10 | "easydevops/common" 11 | "easydevops/server/config" 12 | "github.com/dollarkillerx/easyutils" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "github.com/dollarkillerx/easyutils/gcache" 15 | "github.com/julienschmidt/httprouter" 16 | "io/ioutil" 17 | "net/http" 18 | "os" 19 | "strings" 20 | ) 21 | 22 | func UpFile(w http.ResponseWriter, r *http.Request, params httprouter.Params) { 23 | r.ParseMultipartForm(200 << 20) // 设置上传文件最大大小 200M 24 | r.ParseForm() 25 | resp := common.Resp{} 26 | server_key := r.FormValue("server_key") 27 | 28 | if server_key != config.Basis.App.ServerKey { 29 | clog.Println(server_key) 30 | resp.Auth401(w) 31 | return 32 | } 33 | key := r.FormValue("key") 34 | file, header, e := r.FormFile("file") 35 | if file != nil { 36 | defer file.Close() 37 | } 38 | if strings.Index(header.Filename,"tar.gz") == -1 { 39 | resp.Auth401(w) 40 | return 41 | } 42 | key = easyutils.Sha256Encode(key) 43 | 44 | // 判断key是否存在,如果存在 就删除原来的数据 45 | get, b := gcache.CacheGet(key) 46 | if b { 47 | // 删除原来的数据 48 | os.Remove(get.(string)) 49 | } 50 | 51 | fileh := easyutils.SuperRand() 52 | filepath := "./file/" + fileh + ".tar.gz" 53 | e = gcache.CacheSet(key, filepath) 54 | if e != nil { 55 | resp.Bad500(w) 56 | return 57 | } 58 | 59 | bytes, e := ioutil.ReadAll(file) 60 | if e != nil { 61 | resp.Bad500(w) 62 | return 63 | } 64 | 65 | e = ioutil.WriteFile(filepath, bytes, 00666) 66 | if e != nil { 67 | resp.Bad500(w) 68 | return 69 | } 70 | 71 | resp.Ok200(w) 72 | } 73 | 74 | func GetFile(w http.ResponseWriter, r *http.Request, params httprouter.Params) { 75 | r.ParseForm() 76 | server_key := r.FormValue("server_key") 77 | resp := common.Resp{} 78 | 79 | if server_key != config.Basis.App.ServerKey { 80 | resp.Auth401(w) 81 | return 82 | } 83 | key := r.FormValue("key") 84 | key = easyutils.Sha256Encode(key) 85 | get, b := gcache.CacheGet(key) 86 | if !b { 87 | resp.Auth401(w) 88 | return 89 | } 90 | 91 | filepath := get.(string) 92 | bytes, e := ioutil.ReadFile(filepath) 93 | if e != nil { 94 | resp.Auth401(w) 95 | return 96 | } 97 | 98 | w.WriteHeader(200) 99 | //w.Header().Set("Content-Type","application/octet-stream") 100 | //w.Header().Set("Content-Disposition","attachment; filename=hc.tar.gz") 101 | //w.Header().Set("Content-Transfer-Encoding", "binary") 102 | 103 | w.Write(bytes) 104 | // 如果文件 下载完毕就删除文件 105 | os.Remove(filepath) 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easydevops 2 | easydevops 最小化的自动构建部署 3 | 4 | ### 分支 5 | - gowith 尽量的去github分支 (掌握在自己手里) 6 | - native 依赖github分支 和jenkins走的一样的流派 7 | - master gowith分支稳定版本 8 | ### 如何使用 9 | 运行 .api 文件 10 | 11 | 第一次运行会生成config.yml 配置文件 12 | 13 | 填写完成后 检查填写是否正确 如果正确就再次运行 14 | 15 | 未来新添加 直接 在配置文件添加 然后重启 api文件 即可 16 | 17 | 18 | ### 配置文件夹讲解 19 | ``` 20 | devops: 21 | node: 22 | - port: "8086" # 程序运行端口 23 | full_name: "dollarkillerx/easyutils" # 名称 例如 dollarkillerx/easyutils 24 | branch: "es" # 分支 25 | giturl: "https://github.sads" # git pull url 地址 (你要先配置一下秘钥啊!) 26 | runname: "dollarki" # 运行程序的name 27 | dirpath: "/asdasd/asdasdasd" # 项目的路径 绝对路径 28 | secondarydirectory: "" # 如果执行程序在二级目录中 请填写(相对路径) 29 | - port: "8082" 30 | full_name: "dollarkillerx/easyutils" 31 | branch: "us" 32 | giturl: "https://github.sads" 33 | runname: "dollarki" 34 | dirpath: "/asdasd/asdasdasd/us" 35 | secondarydirectory: "/asdsaadsad" 36 | ``` 37 | 38 | ### 更新日志 39 | - 2019-11-11 新增配置文件热加载 40 | 41 | ### 基础 教程 42 | - 程序默认webhook地址: http://0.0.0.0:8083/update 43 | - 先去github 添加钩子 44 | 45 | ![github添加钩子](./README/one.png) 46 | 47 | - 第一次运行程序 会生成config.yml 文件 用户只需填写 启动即可 (请认真检查啊) 48 | 49 | - 如果添加网站呢? 直接添加到配置文件即可 然后重启服务就行 50 | 51 | ### GoWith (解决 github包过大问题) 52 | ![](./README/gowith.png) 53 | 54 | 55 | 注: 暂不支持 win (仅支持mac or linux) 56 | 57 | ``` 58 | . 59 | ├── LICENSE 60 | ├── README 61 | │   ├── gowith.png 62 | │   └── one.png 63 | ├── README.md 64 | ├── client # 部署客户端 65 | │   ├── api 66 | │   │   ├── api 67 | │   │   ├── config.yml 68 | │   │   ├── controller 69 | │   │   │   └── main.go 70 | │   │   ├── devops.sh 71 | │   │   ├── httprouter_registered 72 | │   │   │   └── httprouter.go 73 | │   │   ├── main.go 74 | │   │   ├── router 75 | │   │   │   └── app.go 76 | │   │   └── sh 77 | │   ├── config 78 | │   │   └── config.go 79 | │   ├── defs 80 | │   │   └── githubapi.go 81 | │   ├── initialization 82 | │   │   └── initialization.go 83 | │   └── test 84 | │   ├── fmt_test.go 85 | │   ├── master.json 86 | │   ├── test.json 87 | │   ├── testkill.sh 88 | │   └── tmp 89 | ├── cmd # 提交cli 工具 90 | │   ├── cmd 91 | │   ├── config 92 | │   │   └── config.go 93 | │   ├── config.yml 94 | │   ├── logic 95 | │   │   └── logic_main.go 96 | │   ├── main.go 97 | │   └── test 98 | ├── common 99 | │   └── resp.go 100 | ├── config.yml 101 | ├── go.mod 102 | ├── go.sum 103 | ├── server # 任务中心 104 | │   ├── config 105 | │   │   └── config.go 106 | │   └── web 107 | │   ├── config.yml 108 | │   ├── controller 109 | │   │   └── main_controller.go 110 | │   ├── file 111 | │   ├── httprouter_registered 112 | │   │   └── httprouter.go 113 | │   ├── main.go 114 | │   ├── routers 115 | │   │   └── app.go 116 | │   └── web 117 | ├── test 118 | │   └── one_test.go 119 | └── utils 120 | └── utils.go 121 | ``` 122 | 123 | 124 | -------------------------------------------------------------------------------- /client/config/config.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:05 2019-09-16 6 | */ 7 | package config 8 | 9 | import ( 10 | "easydevops/utils" 11 | "github.com/dollarkillerx/easyutils" 12 | "gopkg.in/yaml.v2" 13 | "io/ioutil" 14 | "log" 15 | "time" 16 | ) 17 | 18 | type Node struct { 19 | Port string `yaml:"port"` 20 | FullName string `yaml:"full_name"` 21 | Key string `json:"key" yaml:"key"` 22 | Branch string `yaml:"branch"` 23 | Runname string `yaml:"runname"` 24 | Dirpath string `yaml:"dirpath"` 25 | Secondarydirectory string `yaml:"secondarydirectory"` 26 | Email string `yaml:"email"` 27 | } 28 | 29 | type base struct { 30 | App struct { 31 | Host string `yaml:"host"` 32 | DevopsServer string `json:"devops_server" yaml:"devops_server"` 33 | ServerKey string `json:"server_key" yaml:"server_key"` 34 | } 35 | Devops struct { 36 | Node []Node `yaml:"node"` 37 | } 38 | } 39 | 40 | var ( 41 | Basis *base 42 | ) 43 | 44 | func init() { 45 | hasCode := "" 46 | // 写入热加载 47 | for { 48 | select { 49 | case <-time.After(time.Millisecond * 200): 50 | md5, e := utils.Util().Md5File("./config.yml") 51 | if e != nil { 52 | // 判断配置文件是否存在 如果不存在 则创建 53 | b, e := easyutils.PathExists("./config.yml") 54 | if e != nil || b == false { 55 | createConfig() 56 | log.Fatalln("请填写配置文件") 57 | } 58 | } else { 59 | if md5 != hasCode { 60 | hasCode = md5 61 | // 重载配置文件 62 | log.Println("重载配置文件") 63 | initConf() 64 | } 65 | } 66 | } 67 | } 68 | 69 | } 70 | 71 | // 载入conf 72 | func initConf() { 73 | Basis = &base{} 74 | 75 | bytes, e := ioutil.ReadFile("./config.yml") 76 | if e != nil { 77 | panic(e.Error()) 78 | } 79 | 80 | e = yaml.Unmarshal(bytes, Basis) 81 | if e != nil { 82 | panic(e.Error()) 83 | } 84 | } 85 | 86 | func createConfig() { 87 | err := ioutil.WriteFile("config.yml", []byte(devposconfig), 00666) 88 | if err != nil { 89 | panic("配置文件 创建失败") 90 | } 91 | } 92 | 93 | var devposconfig = ` 94 | # devops生成文件 请填写完成检查确认后 再 运行啊 (每次运行会重写sh模块) 95 | 96 | 97 | # 这devops系统配置 98 | app: 99 | host: "0.0.0.0:8083" 100 | devops_server: "http://0.0.0.0:8083/getfile" # devops 服务器地址 https:// ... 101 | server_key: "xxxxxx" # 上传 devops 服务器秘钥 102 | 103 | # 要自动化部署应用的配置 104 | devops: 105 | node: 106 | - port: "8081" # 程序运行端口 107 | full_name: "dollarkillerx/easyutils" # 名称 例如 dollarkillerx/easyutils 108 | branch: "master" # 分支 109 | key: "key" # 文件同步 秘钥 (服务器同步数据时需要) 110 | runname: "api" # 运行程序的name 111 | dirpath: "/home/s" # 绝对路径 112 | secondarydirectory: "" # 如果有二级目录 就填写在这里 113 | email: "" # 部署成功收邮件通知 114 | - port: "8082" 115 | full_name: "" 116 | branch: "es" 117 | key: "key" 118 | runname: "" 119 | dirpath: "" 120 | secondarydirectory: "" 121 | email: "" 122 | ` 123 | -------------------------------------------------------------------------------- /client/api/controller/main.go: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: DollarKiller 3 | * @Description: 4 | * @Github: https://github.com/dollarkillerx 5 | * @Date: Create in 11:08 2019-09-16 6 | */ 7 | package controller 8 | 9 | import ( 10 | "easydevops/client/config" 11 | "easydevops/client/defs" 12 | "github.com/dollarkillerx/easyutils" 13 | "github.com/dollarkillerx/easyutils/clog" 14 | "github.com/dollarkillerx/easyutils/compression" 15 | "github.com/dollarkillerx/easyutils/formband" 16 | "github.com/dollarkillerx/easyutils/gemail" 17 | "github.com/dollarkillerx/easyutils/httplib" 18 | "github.com/julienschmidt/httprouter" 19 | "github.com/pkg/errors" 20 | "io/ioutil" 21 | "net/http" 22 | "os" 23 | "os/exec" 24 | "strconv" 25 | "strings" 26 | ) 27 | 28 | func reLanuch(sh string) { 29 | cmd := exec.Command("sh", sh) 30 | err := cmd.Start() 31 | if err != nil { 32 | clog.Println(err) 33 | } 34 | err = cmd.Wait() 35 | } 36 | 37 | func Rundevops(w http.ResponseWriter, r *http.Request, params httprouter.Params) { 38 | data := defs.GithubAPI{} 39 | err := formband.Band(r, &data) 40 | if err != nil { 41 | clog.Println(err) 42 | return 43 | } 44 | 45 | // 更具commit 判断 是否是真的更新 46 | if data.Commits[0].Message != "EasyDevOps" { 47 | // 直接返回 48 | return 49 | }else { 50 | clog.Println("收到github更新任务 进行更新") 51 | clog.Println(data.Repository.FullName + " : " + data.Branch) 52 | } 53 | 54 | shpath := checkexis(data.Repository.FullName, data.Branch) 55 | if shpath != "" { 56 | err,email := dow(data.Repository.FullName, data.Branch) 57 | if err != nil { 58 | return 59 | } 60 | reLanuch(shpath) 61 | 62 | // 如果没有任何 问题发送邮件成功更新 63 | if email != "" { 64 | gemail.SendNifoLog([]string{email},"EasyDevops",data.Repository.FullName + " " + data.Branch + " 200 OK 成功更新") 65 | } 66 | } 67 | } 68 | 69 | // 下载对应脚本 70 | func dow(name, branch string) (error,string) { 71 | for _,k := range config.Basis.Devops.Node { 72 | if k.FullName == name { 73 | if strings.Index(branch, k.Branch) != -1 { 74 | // 找到对应下载 脚本的地址 75 | post := httplib.Post(config.Basis.App.DevopsServer) 76 | post.Param("server_key",config.Basis.App.ServerKey) 77 | post.Param("key",k.Key) 78 | response, e := post.Response() 79 | defer response.Body.Close() 80 | if e != nil { 81 | if k.Email != "" { 82 | gemail.SendNifoLog([]string{k.Email},"EasyDevops",k.FullName + " " + k.Branch + " 更新失败 (下载 错误)") 83 | } 84 | return errors.New("dow err"),"" 85 | } 86 | if response.StatusCode != 200 { 87 | if k.Email != "" { 88 | gemail.SendNifoLog([]string{k.Email},"EasyDevops",k.FullName + " " + k.Branch + " 更新失败 (下载 没有权限 key是否错误?)" + strconv.Itoa(response.StatusCode)) 89 | } 90 | return errors.New("dow err"),"" 91 | } 92 | 93 | // 文件 下载到对应目录 94 | 95 | filepath := k.Dirpath + "/easydevops" 96 | // 清理原始数据 97 | b, e := easyutils.PathExists(filepath) 98 | if e != nil || b == false { 99 | os.RemoveAll(filepath) 100 | } 101 | e = easyutils.DirPing(filepath) 102 | if e!= nil { 103 | clog.Println(e) 104 | } 105 | 106 | bytes, e := ioutil.ReadAll(response.Body) 107 | if e != nil { 108 | if k.Email != "" { 109 | gemail.SendNifoLog([]string{k.Email},"EasyDevops",k.FullName + " " + k.Branch + " 更新失败 (下载 解析失败IO)") 110 | } 111 | return errors.New("dow err"),"" 112 | } 113 | // 下载文件到指定位置 114 | e = ioutil.WriteFile(filepath + "/easydevops.tar.gz", bytes, 00666) 115 | if e != nil { 116 | if k.Email != "" { 117 | gemail.SendNifoLog([]string{k.Email},"EasyDevops",k.FullName + " " + k.Branch + " 更新失败 (下载 文件copy失败)") 118 | } 119 | return errors.New("dow err"),"" 120 | } 121 | 122 | // 解压文件 123 | tar := compression.Tar{} 124 | e = tar.UnTar(filepath+"/easydevops.tar.gz", filepath) 125 | if e != nil { 126 | if k.Email != "" { 127 | emlog := k.FullName + " " + k.Branch + " 更新失败 (下载 解压失败) filepath: " + filepath + " exPath: " + filepath +"/easydevops.tar.gz" + " error: " + e.Error() 128 | gemail.SendNifoLog([]string{k.Email},"EasyDevops",emlog) 129 | } 130 | return errors.New("dow err"),"" 131 | } 132 | return nil,k.Email 133 | } 134 | } 135 | } 136 | return errors.New("not dev"),"" 137 | } 138 | 139 | // 查询是否存在这个 如果找到 返回对应的脚本地址 140 | func checkexis(name, branch string) string { 141 | 142 | for _, k := range config.Basis.Devops.Node { 143 | // 如果找到了 144 | if k.FullName == name { 145 | // 再判断brench 146 | if strings.Index(branch, k.Branch) != -1 { 147 | // 返回脚本地址 148 | name := strings.Replace(k.FullName, "/", "1", -1) 149 | shName := name + k.Port + k.Branch + ".sh" 150 | shPath := "./sh/" + shName 151 | return shPath 152 | } 153 | } 154 | } 155 | 156 | return "" 157 | } 158 | 159 | -------------------------------------------------------------------------------- /client/test/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "ref": "refs/heads/test", 3 | "before": "0000000000000000000000000000000000000000", 4 | "after": "05300bfb10912f370ac74a5cbc2ed2095a60466c", 5 | "repository": { 6 | "id": 208684536, 7 | "node_id": "MDEwOlJlcG9zaXRvcnkyMDg2ODQ1MzY=", 8 | "name": "Cartoon5", 9 | "full_name": "dollarkillerx/Cartoon5", 10 | "private": true, 11 | "owner": { 12 | "name": "dollarkillerx", 13 | "email": "dollarkiller@vip.qq.com", 14 | "login": "dollarkillerx", 15 | "id": 46174840, 16 | "node_id": "MDQ6VXNlcjQ2MTc0ODQw", 17 | "avatar_url": "https://avatars0.githubusercontent.com/u/46174840?v=4", 18 | "gravatar_id": "", 19 | "url": "https://api.github.com/users/dollarkillerx", 20 | "html_url": "https://github.com/dollarkillerx", 21 | "followers_url": "https://api.github.com/users/dollarkillerx/followers", 22 | "following_url": "https://api.github.com/users/dollarkillerx/following{/other_user}", 23 | "gists_url": "https://api.github.com/users/dollarkillerx/gists{/gist_id}", 24 | "starred_url": "https://api.github.com/users/dollarkillerx/starred{/owner}{/repo}", 25 | "subscriptions_url": "https://api.github.com/users/dollarkillerx/subscriptions", 26 | "organizations_url": "https://api.github.com/users/dollarkillerx/orgs", 27 | "repos_url": "https://api.github.com/users/dollarkillerx/repos", 28 | "events_url": "https://api.github.com/users/dollarkillerx/events{/privacy}", 29 | "received_events_url": "https://api.github.com/users/dollarkillerx/received_events", 30 | "type": "User", 31 | "site_admin": false 32 | }, 33 | "html_url": "https://github.com/dollarkillerx/Cartoon5", 34 | "description": "Cartoon5", 35 | "fork": false, 36 | "url": "https://github.com/dollarkillerx/Cartoon5", 37 | "forks_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/forks", 38 | "keys_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/keys{/key_id}", 39 | "collaborators_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/collaborators{/collaborator}", 40 | "teams_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/teams", 41 | "hooks_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/hooks", 42 | "issue_events_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues/events{/number}", 43 | "events_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/events", 44 | "assignees_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/assignees{/user}", 45 | "branches_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/branches{/branch}", 46 | "tags_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/tags", 47 | "blobs_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/blobs{/sha}", 48 | "git_tags_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/tags{/sha}", 49 | "git_refs_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/refs{/sha}", 50 | "trees_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/trees{/sha}", 51 | "statuses_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/statuses/{sha}", 52 | "languages_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/languages", 53 | "stargazers_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/stargazers", 54 | "contributors_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/contributors", 55 | "subscribers_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/subscribers", 56 | "subscription_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/subscription", 57 | "commits_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/commits{/sha}", 58 | "git_commits_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/commits{/sha}", 59 | "comments_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/comments{/number}", 60 | "issue_comment_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues/comments{/number}", 61 | "contents_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/contents/{+path}", 62 | "compare_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/compare/{base}...{head}", 63 | "merges_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/merges", 64 | "archive_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/{archive_format}{/ref}", 65 | "downloads_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/downloads", 66 | "issues_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues{/number}", 67 | "pulls_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/pulls{/number}", 68 | "milestones_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/milestones{/number}", 69 | "notifications_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/notifications{?since,all,participating}", 70 | "labels_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/labels{/name}", 71 | "releases_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/releases{/id}", 72 | "deployments_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/deployments", 73 | "created_at": 1568597425, 74 | "updated_at": "2019-09-16T02:46:10Z", 75 | "pushed_at": 1568602098, 76 | "git_url": "git://github.com/dollarkillerx/Cartoon5.git", 77 | "ssh_url": "git@github.com:dollarkillerx/Cartoon5.git", 78 | "clone_url": "https://github.com/dollarkillerx/Cartoon5.git", 79 | "svn_url": "https://github.com/dollarkillerx/Cartoon5", 80 | "homepage": null, 81 | "size": 1, 82 | "stargazers_count": 0, 83 | "watchers_count": 0, 84 | "language": "Smarty", 85 | "has_issues": true, 86 | "has_projects": true, 87 | "has_downloads": true, 88 | "has_wiki": true, 89 | "has_pages": false, 90 | "forks_count": 0, 91 | "mirror_url": null, 92 | "archived": false, 93 | "disabled": false, 94 | "open_issues_count": 0, 95 | "license": { 96 | "key": "mit", 97 | "name": "MIT License", 98 | "spdx_id": "MIT", 99 | "url": "https://api.github.com/licenses/mit", 100 | "node_id": "MDc6TGljZW5zZTEz" 101 | }, 102 | "forks": 0, 103 | "open_issues": 0, 104 | "watchers": 0, 105 | "default_branch": "master", 106 | "stargazers": 0, 107 | "master_branch": "master" 108 | }, 109 | "pusher": { 110 | "name": "dollarkillerx", 111 | "email": "dollarkiller@vip.qq.com" 112 | }, 113 | "sender": { 114 | "login": "dollarkillerx", 115 | "id": 46174840, 116 | "node_id": "MDQ6VXNlcjQ2MTc0ODQw", 117 | "avatar_url": "https://avatars0.githubusercontent.com/u/46174840?v=4", 118 | "gravatar_id": "", 119 | "url": "https://api.github.com/users/dollarkillerx", 120 | "html_url": "https://github.com/dollarkillerx", 121 | "followers_url": "https://api.github.com/users/dollarkillerx/followers", 122 | "following_url": "https://api.github.com/users/dollarkillerx/following{/other_user}", 123 | "gists_url": "https://api.github.com/users/dollarkillerx/gists{/gist_id}", 124 | "starred_url": "https://api.github.com/users/dollarkillerx/starred{/owner}{/repo}", 125 | "subscriptions_url": "https://api.github.com/users/dollarkillerx/subscriptions", 126 | "organizations_url": "https://api.github.com/users/dollarkillerx/orgs", 127 | "repos_url": "https://api.github.com/users/dollarkillerx/repos", 128 | "events_url": "https://api.github.com/users/dollarkillerx/events{/privacy}", 129 | "received_events_url": "https://api.github.com/users/dollarkillerx/received_events", 130 | "type": "User", 131 | "site_admin": false 132 | }, 133 | "created": true, 134 | "deleted": false, 135 | "forced": false, 136 | "base_ref": "refs/heads/master", 137 | "compare": "https://github.com/dollarkillerx/Cartoon5/compare/test", 138 | "commits": [], 139 | "head_commit": { 140 | "id": "05300bfb10912f370ac74a5cbc2ed2095a60466c", 141 | "tree_id": "c6bccec56ad3e7e382b11198aeda048dc226ce4e", 142 | "distinct": true, 143 | "message": "init", 144 | "timestamp": "2019-09-16T10:45:41+08:00", 145 | "url": "https://github.com/dollarkillerx/Cartoon5/commit/05300bfb10912f370ac74a5cbc2ed2095a60466c", 146 | "author": { 147 | "name": "Dollarkillerx", 148 | "email": "dollarkiller@vip.qq.com", 149 | "username": "dollarkillerx" 150 | }, 151 | "committer": { 152 | "name": "Dollarkillerx", 153 | "email": "dollarkiller@vip.qq.com", 154 | "username": "dollarkillerx" 155 | }, 156 | "added": [ 157 | ".idea/Cartoon5.iml", 158 | ".idea/misc.xml", 159 | ".idea/modules.xml", 160 | ".idea/vcs.xml", 161 | ".idea/workspace.xml", 162 | "Cartoon5", 163 | "Cartoon5.tar.gz", 164 | "config.yml", 165 | "config/base.go", 166 | "controllers/home.go", 167 | "datasources/cache/gcache.go", 168 | "datasources/pgsql_conn/pgsql.go", 169 | "main.go", 170 | "routers/router.go", 171 | "static/js/reload.min.js", 172 | "views/index.tpl" 173 | ], 174 | "removed": [], 175 | "modified": [ 176 | "README.md" 177 | ] 178 | } 179 | } -------------------------------------------------------------------------------- /client/test/master.json: -------------------------------------------------------------------------------- 1 | { 2 | "ref": "refs/heads/master", 3 | "before": "b61cd27c0bfe30cbac7a731a6ce22790d9e1f6f7", 4 | "after": "05300bfb10912f370ac74a5cbc2ed2095a60466c", 5 | "repository": { 6 | "id": 208684536, 7 | "node_id": "MDEwOlJlcG9zaXRvcnkyMDg2ODQ1MzY=", 8 | "name": "Cartoon5", 9 | "full_name": "dollarkillerx/Cartoon5", 10 | "private": true, 11 | "owner": { 12 | "name": "dollarkillerx", 13 | "email": "dollarkiller@vip.qq.com", 14 | "login": "dollarkillerx", 15 | "id": 46174840, 16 | "node_id": "MDQ6VXNlcjQ2MTc0ODQw", 17 | "avatar_url": "https://avatars0.githubusercontent.com/u/46174840?v=4", 18 | "gravatar_id": "", 19 | "url": "https://api.github.com/users/dollarkillerx", 20 | "html_url": "https://github.com/dollarkillerx", 21 | "followers_url": "https://api.github.com/users/dollarkillerx/followers", 22 | "following_url": "https://api.github.com/users/dollarkillerx/following{/other_user}", 23 | "gists_url": "https://api.github.com/users/dollarkillerx/gists{/gist_id}", 24 | "starred_url": "https://api.github.com/users/dollarkillerx/starred{/owner}{/repo}", 25 | "subscriptions_url": "https://api.github.com/users/dollarkillerx/subscriptions", 26 | "organizations_url": "https://api.github.com/users/dollarkillerx/orgs", 27 | "repos_url": "https://api.github.com/users/dollarkillerx/repos", 28 | "events_url": "https://api.github.com/users/dollarkillerx/events{/privacy}", 29 | "received_events_url": "https://api.github.com/users/dollarkillerx/received_events", 30 | "type": "User", 31 | "site_admin": false 32 | }, 33 | "html_url": "https://github.com/dollarkillerx/Cartoon5", 34 | "description": "Cartoon5", 35 | "fork": false, 36 | "url": "https://github.com/dollarkillerx/Cartoon5", 37 | "forks_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/forks", 38 | "keys_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/keys{/key_id}", 39 | "collaborators_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/collaborators{/collaborator}", 40 | "teams_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/teams", 41 | "hooks_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/hooks", 42 | "issue_events_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues/events{/number}", 43 | "events_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/events", 44 | "assignees_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/assignees{/user}", 45 | "branches_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/branches{/branch}", 46 | "tags_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/tags", 47 | "blobs_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/blobs{/sha}", 48 | "git_tags_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/tags{/sha}", 49 | "git_refs_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/refs{/sha}", 50 | "trees_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/trees{/sha}", 51 | "statuses_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/statuses/{sha}", 52 | "languages_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/languages", 53 | "stargazers_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/stargazers", 54 | "contributors_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/contributors", 55 | "subscribers_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/subscribers", 56 | "subscription_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/subscription", 57 | "commits_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/commits{/sha}", 58 | "git_commits_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/git/commits{/sha}", 59 | "comments_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/comments{/number}", 60 | "issue_comment_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues/comments{/number}", 61 | "contents_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/contents/{+path}", 62 | "compare_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/compare/{base}...{head}", 63 | "merges_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/merges", 64 | "archive_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/{archive_format}{/ref}", 65 | "downloads_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/downloads", 66 | "issues_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/issues{/number}", 67 | "pulls_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/pulls{/number}", 68 | "milestones_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/milestones{/number}", 69 | "notifications_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/notifications{?since,all,participating}", 70 | "labels_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/labels{/name}", 71 | "releases_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/releases{/id}", 72 | "deployments_url": "https://api.github.com/repos/dollarkillerx/Cartoon5/deployments", 73 | "created_at": 1568597425, 74 | "updated_at": "2019-09-16T01:32:24Z", 75 | "pushed_at": 1568601968, 76 | "git_url": "git://github.com/dollarkillerx/Cartoon5.git", 77 | "ssh_url": "git@github.com:dollarkillerx/Cartoon5.git", 78 | "clone_url": "https://github.com/dollarkillerx/Cartoon5.git", 79 | "svn_url": "https://github.com/dollarkillerx/Cartoon5", 80 | "homepage": null, 81 | "size": 1, 82 | "stargazers_count": 0, 83 | "watchers_count": 0, 84 | "language": null, 85 | "has_issues": true, 86 | "has_projects": true, 87 | "has_downloads": true, 88 | "has_wiki": true, 89 | "has_pages": false, 90 | "forks_count": 0, 91 | "mirror_url": null, 92 | "archived": false, 93 | "disabled": false, 94 | "open_issues_count": 0, 95 | "license": { 96 | "key": "mit", 97 | "name": "MIT License", 98 | "spdx_id": "MIT", 99 | "url": "https://api.github.com/licenses/mit", 100 | "node_id": "MDc6TGljZW5zZTEz" 101 | }, 102 | "forks": 0, 103 | "open_issues": 0, 104 | "watchers": 0, 105 | "default_branch": "master", 106 | "stargazers": 0, 107 | "master_branch": "master" 108 | }, 109 | "pusher": { 110 | "name": "dollarkillerx", 111 | "email": "dollarkiller@vip.qq.com" 112 | }, 113 | "sender": { 114 | "login": "dollarkillerx", 115 | "id": 46174840, 116 | "node_id": "MDQ6VXNlcjQ2MTc0ODQw", 117 | "avatar_url": "https://avatars0.githubusercontent.com/u/46174840?v=4", 118 | "gravatar_id": "", 119 | "url": "https://api.github.com/users/dollarkillerx", 120 | "html_url": "https://github.com/dollarkillerx", 121 | "followers_url": "https://api.github.com/users/dollarkillerx/followers", 122 | "following_url": "https://api.github.com/users/dollarkillerx/following{/other_user}", 123 | "gists_url": "https://api.github.com/users/dollarkillerx/gists{/gist_id}", 124 | "starred_url": "https://api.github.com/users/dollarkillerx/starred{/owner}{/repo}", 125 | "subscriptions_url": "https://api.github.com/users/dollarkillerx/subscriptions", 126 | "organizations_url": "https://api.github.com/users/dollarkillerx/orgs", 127 | "repos_url": "https://api.github.com/users/dollarkillerx/repos", 128 | "events_url": "https://api.github.com/users/dollarkillerx/events{/privacy}", 129 | "received_events_url": "https://api.github.com/users/dollarkillerx/received_events", 130 | "type": "User", 131 | "site_admin": false 132 | }, 133 | "created": false, 134 | "deleted": false, 135 | "forced": false, 136 | "base_ref": null, 137 | "compare": "https://github.com/dollarkillerx/Cartoon5/compare/b61cd27c0bfe...05300bfb1091", 138 | "commits": [ 139 | { 140 | "id": "05300bfb10912f370ac74a5cbc2ed2095a60466c", 141 | "tree_id": "c6bccec56ad3e7e382b11198aeda048dc226ce4e", 142 | "distinct": true, 143 | "message": "init", 144 | "timestamp": "2019-09-16T10:45:41+08:00", 145 | "url": "https://github.com/dollarkillerx/Cartoon5/commit/05300bfb10912f370ac74a5cbc2ed2095a60466c", 146 | "author": { 147 | "name": "Dollarkillerx", 148 | "email": "dollarkiller@vip.qq.com", 149 | "username": "dollarkillerx" 150 | }, 151 | "committer": { 152 | "name": "Dollarkillerx", 153 | "email": "dollarkiller@vip.qq.com", 154 | "username": "dollarkillerx" 155 | }, 156 | "added": [ 157 | ".idea/Cartoon5.iml", 158 | ".idea/misc.xml", 159 | ".idea/modules.xml", 160 | ".idea/vcs.xml", 161 | ".idea/workspace.xml", 162 | "Cartoon5", 163 | "Cartoon5.tar.gz", 164 | "config.yml", 165 | "config/base.go", 166 | "controllers/home.go", 167 | "datasources/cache/gcache.go", 168 | "datasources/pgsql_conn/pgsql.go", 169 | "main.go", 170 | "routers/router.go", 171 | "static/js/reload.min.js", 172 | "views/index.tpl" 173 | ], 174 | "removed": [], 175 | "modified": [ 176 | "README.md" 177 | ] 178 | } 179 | ], 180 | "head_commit": { 181 | "id": "05300bfb10912f370ac74a5cbc2ed2095a60466c", 182 | "tree_id": "c6bccec56ad3e7e382b11198aeda048dc226ce4e", 183 | "distinct": true, 184 | "message": "init", 185 | "timestamp": "2019-09-16T10:45:41+08:00", 186 | "url": "https://github.com/dollarkillerx/Cartoon5/commit/05300bfb10912f370ac74a5cbc2ed2095a60466c", 187 | "author": { 188 | "name": "Dollarkillerx", 189 | "email": "dollarkiller@vip.qq.com", 190 | "username": "dollarkillerx" 191 | }, 192 | "committer": { 193 | "name": "Dollarkillerx", 194 | "email": "dollarkiller@vip.qq.com", 195 | "username": "dollarkillerx" 196 | }, 197 | "added": [ 198 | ".idea/Cartoon5.iml", 199 | ".idea/misc.xml", 200 | ".idea/modules.xml", 201 | ".idea/vcs.xml", 202 | ".idea/workspace.xml", 203 | "Cartoon5", 204 | "Cartoon5.tar.gz", 205 | "config.yml", 206 | "config/base.go", 207 | "controllers/home.go", 208 | "datasources/cache/gcache.go", 209 | "datasources/pgsql_conn/pgsql.go", 210 | "main.go", 211 | "routers/router.go", 212 | "static/js/reload.min.js", 213 | "views/index.tpl" 214 | ], 215 | "removed": [], 216 | "modified": [ 217 | "README.md" 218 | ] 219 | } 220 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 3 | github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= 4 | github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM= 5 | github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o= 6 | github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ= 7 | github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= 8 | github.com/bluele/gcache v0.0.0-20190518031135-bc40bd653833/go.mod h1:8c4/i2VlovMO2gBnHGQPN5EJw+H0lx1u/5p+cgsXtCk= 9 | github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= 10 | github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= 11 | github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE= 12 | github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog= 13 | github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= 14 | github.com/couchbase/go-couchbase v0.0.0-20181122212707-3e9b6e1258bb/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= 15 | github.com/couchbase/go-couchbase v0.0.0-20190913050104-3db08c407d17/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= 16 | github.com/couchbase/go-couchbase v0.0.0-20190916184909-f83e63d76bc4/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U= 17 | github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= 18 | github.com/couchbase/gomemcached v0.0.0-20190910024640-4e485a3d895f/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= 19 | github.com/couchbase/gomemcached v0.0.0-20190920220213-2b4197fedf38/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c= 20 | github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= 21 | github.com/couchbase/goutils v0.0.0-20190315194238-f9d42b11473b/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= 22 | github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= 23 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 24 | github.com/dollarkillerx/easyutils v0.0.0-20190916023602-08d48d75f37e h1:fqxu6bVoagJ+tjYAI03+Dl8YYaI+dRo539mITmCVITQ= 25 | github.com/dollarkillerx/easyutils v0.0.0-20190916023602-08d48d75f37e/go.mod h1:vI2nCMB7VtvNSPs7RrCWvceV+TJtv9QhKJcER/HkMG0= 26 | github.com/dollarkillerx/easyutils v0.0.0-20190921081604-08d9395753f7 h1:SId7rKTMZS4/y6bp8mXSuk+PKMmFiP4Ho4nLxCrpbbU= 27 | github.com/dollarkillerx/easyutils v0.0.0-20190921081604-08d9395753f7/go.mod h1:sJYKii3OJsQnGEuMvuc9FHrH7wlQhLM+Ac3qMfg8A8o= 28 | github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 29 | github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 30 | github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= 31 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 32 | github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= 33 | github.com/go-redis/redis v6.15.5+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= 34 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 35 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 36 | github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 37 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= 38 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 39 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 40 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 41 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 42 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 43 | github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 44 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 45 | github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= 46 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 47 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 48 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 49 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 50 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 51 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 52 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 53 | github.com/mojocn/base64Captcha v0.0.0-20190716153509-e5e80f1b3816 h1:WLPZyFMPPLf6WBs0X4nuLIYJoXSEane8vpCy5YnA2fs= 54 | github.com/mojocn/base64Captcha v0.0.0-20190716153509-e5e80f1b3816/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY= 55 | github.com/mojocn/base64Captcha v0.0.0-20190801020520-752b1cd608b2 h1:daZqE/T/yEoKIQNd3rwNeLsiS0VpZFfJulR0t/rtgAE= 56 | github.com/mojocn/base64Captcha v0.0.0-20190801020520-752b1cd608b2/go.mod h1:wAQCKEc5bDujxKRmbT6/vTnTt5CjStQ8bRfPWUuz/iY= 57 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 58 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 59 | github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 60 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 61 | github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 62 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 63 | github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= 64 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 65 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 66 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 67 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 68 | github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= 69 | github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= 70 | github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= 71 | github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= 72 | github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= 73 | github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE= 74 | github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= 75 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 76 | github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= 77 | github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= 78 | golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 79 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 80 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 81 | golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 82 | golang.org/x/image v0.0.0-20190501045829-6d32002ffd75/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 83 | golang.org/x/image v0.0.0-20190729225735-1bd0cf576493 h1:hw8b4aUfc6J+8Ekj2V0VCmgBCGQ9azXN0lo/I/NSw1Q= 84 | golang.org/x/image v0.0.0-20190729225735-1bd0cf576493/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 85 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0= 86 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 87 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 88 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 89 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 90 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 91 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 92 | golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc= 93 | golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 94 | golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72 h1:PdU68SuVQNpTFEyGl0zoQOMysY+E0innv/QbAqV853w= 95 | golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 96 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 97 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 98 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 99 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 100 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 101 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 102 | golang.org/x/sys v0.0.0-20190730183949-1393eb018365/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20190913121621-c3b328c6e5a7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 104 | golang.org/x/sys v0.0.0-20190920190810-ef0ce1748380/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 105 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 106 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 107 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 108 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 109 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 110 | golang.org/x/tools v0.0.0-20190730215328-ed3277de2799/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= 111 | golang.org/x/tools v0.0.0-20190916020655-1ccc110ba9df/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 112 | golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 113 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 114 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 115 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 116 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 117 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= 118 | gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= 119 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 120 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 121 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 122 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 123 | --------------------------------------------------------------------------------