update: 完善系统
This commit is contained in:
parent
c5a5e45c97
commit
7979662086
1
devDocker.sh
Normal file
1
devDocker.sh
Normal file
@ -0,0 +1 @@
|
|||||||
|
docker run -it --rm --name $(basename `pwd`) -v `pwd`:`pwd` -w `pwd` -p 3001:3001 -v ~/.ssh:/root/.ssh golang:1.18.2 /bin/bash
|
215
main.go
215
main.go
@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -60,12 +61,136 @@ func init() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getBranch(str string) (string) {
|
||||||
|
r, _ := regexp.Compile("refs/heads/(.*)")
|
||||||
|
matchArr := r.FindStringSubmatch(str)
|
||||||
|
if len(matchArr) > 0 {
|
||||||
|
return matchArr[len(matchArr)-1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func runCommand(script string, projectPath string, isFile bool) (error) {
|
||||||
|
log.Printf("Running script: %s\n", script)
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if (isFile) {
|
||||||
|
cmd = exec.Command(script)
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/bash", "-c", script)
|
||||||
|
}
|
||||||
|
cmd.Stdout = logFile
|
||||||
|
cmd.Stderr = logFile
|
||||||
|
cmd.Dir = projectPath
|
||||||
|
err := cmd.Run()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func manageProj(projectPath string, payload GogsPayload) (error) {
|
||||||
|
// 如果没有这个文件夹就现clone下来
|
||||||
|
if _, err := os.Stat(projectPath); os.IsNotExist(err) {
|
||||||
|
log.Printf("%s is not exist, start clone", projectPath)
|
||||||
|
// 创建文件夹
|
||||||
|
os.Mkdir(projectPath, os.ModePerm)
|
||||||
|
// 给文件夹权限
|
||||||
|
os.Chmod(projectPath, os.ModePerm)
|
||||||
|
// clone 到指定文件夹
|
||||||
|
script := "git clone " + payload.Repository.SSHURL + " " + projectPath
|
||||||
|
runErr := runCommand(script, projectPath, false)
|
||||||
|
if runErr != nil {
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 切换到指定的分支
|
||||||
|
branch := getBranch(payload.Ref)
|
||||||
|
script := "git checkout " + branch
|
||||||
|
runErr := runCommand(script, projectPath, false)
|
||||||
|
if runErr != nil {
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
// 拉取代码
|
||||||
|
script = "git pull"
|
||||||
|
runErr = runCommand(script, projectPath, false)
|
||||||
|
if runErr != nil {
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
// 切换到指定的commit
|
||||||
|
script = "git reset --hard " + payload.After
|
||||||
|
runErr = runCommand(script, projectPath, false)
|
||||||
|
if runErr != nil {
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func manageDeploy(scriptPath string, projectPath string) (error) {
|
||||||
|
// 如果用户是Root就给部署文件添加执行权限
|
||||||
|
if os.Getenv("HOME") == "/root" {
|
||||||
|
log.Printf("Cur user is root, chmod u=rwx to %s", scriptPath)
|
||||||
|
script := "chmod u=rwx " + scriptPath
|
||||||
|
runErr := runCommand(script, projectPath, false)
|
||||||
|
if runErr != nil {
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 开始执行脚本
|
||||||
|
runErr := runCommand(scriptPath, projectPath, true)
|
||||||
|
return runErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkNeedDeploy(payload GogsPayload) (Config, bool) {
|
||||||
|
// 我们这个系统简单点,只要本次提交包含了部署信号,就直接部署最后一个commit
|
||||||
|
config := Config{
|
||||||
|
Repo: "",
|
||||||
|
Path: home,
|
||||||
|
Script: "deploy.py",
|
||||||
|
Signal: "{D}",
|
||||||
|
Branch: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到指定的项目,获取用户配置
|
||||||
|
for _, item := range configs {
|
||||||
|
if item.Repo == payload.Repository.FullName {
|
||||||
|
config.Repo = item.Repo
|
||||||
|
if item.Path != "" {
|
||||||
|
config.Path = item.Path
|
||||||
|
}
|
||||||
|
if item.Script != "" {
|
||||||
|
config.Script = item.Script
|
||||||
|
}
|
||||||
|
if item.Signal != "" {
|
||||||
|
config.Signal = item.Signal
|
||||||
|
}
|
||||||
|
if item.Branch != "" {
|
||||||
|
config.Branch = item.Branch
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否需要执行部署脚本,优先分支,然后是推送信息
|
||||||
|
|
||||||
|
// 分支匹配
|
||||||
|
if config.Branch != "" && config.Branch == getBranch(payload.Ref) {
|
||||||
|
return config, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 推送信息匹配
|
||||||
|
for _, commit := range payload.Commits {
|
||||||
|
if strings.Contains(commit.Message, config.Signal) {
|
||||||
|
return config, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
addr := flag.String("a", ":3001", "Address to listen on")
|
addr := flag.String("a", ":3001", "Address to listen on")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
||||||
// 解析Payload
|
// 获取请求体
|
||||||
reqBody, err := ioutil.ReadAll(r.Body)
|
reqBody, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error reading request body: %v\n", err)
|
log.Printf("Error reading request body: %v\n", err)
|
||||||
@ -73,6 +198,7 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析payload
|
||||||
var payload GogsPayload
|
var payload GogsPayload
|
||||||
err = json.Unmarshal(reqBody, &payload)
|
err = json.Unmarshal(reqBody, &payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,65 +207,42 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Received: [Name] %s [Sender] %s", payload.Repository.FullName, payload.Sender.FullName)
|
// 打印代码库名称以及推送者
|
||||||
|
log.Printf("Received: [Repository] %s [Sender] %s", payload.Repository.FullName, payload.Sender.Username)
|
||||||
|
|
||||||
// 寻找包含Signal的commit
|
// 检查是否需要部署
|
||||||
for _, commit := range payload.Commits {
|
deployConfig, needDeploy := checkNeedDeploy(payload)
|
||||||
// 寻找配置
|
|
||||||
c := Config{
|
|
||||||
Path: home,
|
|
||||||
Script: "deploy.py",
|
|
||||||
Signal: "{D}",
|
|
||||||
}
|
|
||||||
for _, config := range configs {
|
|
||||||
if config.Repo == payload.Repository.FullName {
|
|
||||||
c.Repo = config.Repo
|
|
||||||
if config.Path != "" {
|
|
||||||
c.Path = config.Path
|
|
||||||
}
|
|
||||||
if config.Script != "" {
|
|
||||||
c.Script = config.Script
|
|
||||||
}
|
|
||||||
if config.Signal != "" {
|
|
||||||
c.Signal = config.Signal
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 包含部署信号
|
// 不需要部署就直接返回
|
||||||
if strings.Contains(commit.Message, c.Signal) {
|
if (!needDeploy) {
|
||||||
log.Printf("Commit: [SHA] %s [Message] %s", commit.ID, commit.Message)
|
log.Print("No deploy commit found\n\n")
|
||||||
log.Println("Ready to deploy")
|
w.Write([]byte("No deploy commit found. Skip."))
|
||||||
|
return
|
||||||
if c.Repo == "" {
|
|
||||||
log.Println("Using default config")
|
|
||||||
}
|
|
||||||
|
|
||||||
projectPath := fmt.Sprintf(c.Path+"/%s/", payload.Repository.Name)
|
|
||||||
scriptPath := projectPath + c.Script
|
|
||||||
log.Printf("Running script: %s\n", scriptPath)
|
|
||||||
|
|
||||||
// 开始执行脚本
|
|
||||||
cmd := exec.Command(scriptPath)
|
|
||||||
cmd.Stdout = logFile
|
|
||||||
cmd.Stderr = logFile
|
|
||||||
cmd.Dir = projectPath
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error running deploy script: %v\n", err)
|
|
||||||
w.Write([]byte(fmt.Sprintf("Deploy script error: %s", err)))
|
|
||||||
} else {
|
|
||||||
log.Print("Deploy finished\n\n")
|
|
||||||
w.Write([]byte("Deploy finished"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Print("No deploy commit found\n\n")
|
// 准备部署,生成项目地址和脚本地址
|
||||||
w.Write([]byte("No deploy commit found. Skip."))
|
projectPath := fmt.Sprintf(deployConfig.Path+"/%s/", payload.Repository.Name)
|
||||||
|
scriptPath := projectPath + deployConfig.Script
|
||||||
|
|
||||||
|
// 处理项目,clone并切换到指定的分支和commit
|
||||||
|
err = manageProj(projectPath, payload)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error running manageProj script: %v\n", err)
|
||||||
|
w.Write([]byte(fmt.Sprintf("manageProj script error: %s", err)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 给脚本添加权限并执行脚本
|
||||||
|
err = manageDeploy(scriptPath, projectPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error running deploy script: %v\n", err)
|
||||||
|
w.Write([]byte(fmt.Sprintf("Deploy script error: %s", err)))
|
||||||
|
} else {
|
||||||
|
log.Print("Deploy finished\n\n")
|
||||||
|
w.Write([]byte("Deploy finished"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Println("Webhook service started at " + *addr)
|
log.Println("Webhook service started at " + *addr)
|
||||||
|
2
model.go
2
model.go
@ -9,6 +9,8 @@ type Config struct {
|
|||||||
Script string `json:"script"`
|
Script string `json:"script"`
|
||||||
// 信号:commit messgae里包含信号,则执行脚本
|
// 信号:commit messgae里包含信号,则执行脚本
|
||||||
Signal string `json:"signal"`
|
Signal string `json:"signal"`
|
||||||
|
// 分支 指定分支执行脚本
|
||||||
|
Branch string `json:"branch"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GogsPayload struct {
|
type GogsPayload struct {
|
||||||
|
78
path.dio
Normal file
78
path.dio
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<mxfile host="65bd71144e">
|
||||||
|
<diagram id="gu7OVYjIMTTFq4SVhP3i" name="第 1 页">
|
||||||
|
<mxGraphModel dx="1406" dy="958" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0"/>
|
||||||
|
<mxCell id="1" parent="0"/>
|
||||||
|
<mxCell id="4" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="240" y="190" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="2" value="收到请求" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="40" y="160" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="6" value="" style="edgeStyle=none;html=1;" edge="1" parent="1">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="360" y="190" as="sourcePoint"/>
|
||||||
|
<mxPoint x="440" y="190" as="targetPoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="8" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" target="7">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<mxPoint x="300" y="220" as="sourcePoint"/>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="7" value="返回空" style="whiteSpace=wrap;html=1;rounded=0;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="240" y="300" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="9" value="不需要" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="255" y="250" width="50" height="20" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="10" value="需要" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="380" y="170" width="40" height="20" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="11" value="是否需要部署" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="240" y="140" width="120" height="100" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="16" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="12" target="15">
|
||||||
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="18" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="12" target="17">
|
||||||
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="12" value="文件夹是否存在" style="strokeWidth=2;html=1;shape=mxgraph.flowchart.decision;whiteSpace=wrap;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="440" y="140" width="100" height="100" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="20" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="15" target="19">
|
||||||
|
<mxGeometry relative="1" as="geometry">
|
||||||
|
<Array as="points">
|
||||||
|
<mxPoint x="670" y="370"/>
|
||||||
|
</Array>
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="15" value="创建文件夹" style="whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="430" y="340" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="22" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="17" target="21">
|
||||||
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="17" value="给脚本附权限" style="whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="610" y="160" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="19" value="" style="shape=waypoint;sketch=0;size=6;pointerEvents=1;points=[];fillColor=default;resizable=0;rotatable=0;perimeter=centerPerimeter;snapToPoint=1;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="650" y="200" width="40" height="40" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="24" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="21" target="23">
|
||||||
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="21" value="执行脚本" style="whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="810" y="160" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="23" value="返回" style="whiteSpace=wrap;html=1;strokeWidth=2;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="1010" y="160" width="120" height="60" as="geometry"/>
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
Loading…
x
Reference in New Issue
Block a user