diff --git a/Gopkg.lock b/Gopkg.lock index a8ac023..c3ab402 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -9,14 +9,6 @@ revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" version = "v0.3.1" -[[projects]] - branch = "master" - digest = "1:9a9d9b4d7ec58633859ec57581d6a56e5ce0b16996bb127d712f6819bacce3a4" - name = "github.com/broqiang/go-blog" - packages = ["app/config"] - pruneopts = "UT" - revision = "7a0e7b6f8f33b8c98b70c4cb0e7a8dc6c7e13a5a" - [[projects]] digest = "1:36fe9527deed01d2a317617e59304eb2c4ce9f8a24115bcc5c2e37b3aee5bae4" name = "github.com/gin-contrib/sse" @@ -121,7 +113,6 @@ analyzer-version = 1 input-imports = [ "github.com/BurntSushi/toml", - "github.com/broqiang/go-blog/app/config", "github.com/gin-gonic/gin", "github.com/microcosm-cc/bluemonday", "golang.org/x/net/html", diff --git a/README.md b/README.md index 6f009f8..fbad79c 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,18 @@ server { } ``` -## 后记 +## 配置 github 钩子 -到这里就基本配置完成了,现在只是初步完成,还有部分功能未完善,根据实际的使用再慢慢完善,欢迎 star 支持下。 \ No newline at end of file +在 `https://github.com/BroQiang/blog-docs` 项目中添加一个 Webhooks, 配置下面内容: + +- Payload URL: `https://broqiang.com/webhook` + +- Content type: 选择 `application/json` + +- Secret: 自定义一个密钥,要和 `config.toml` 中的 secret 的值保持一直 + +钩子生效后, blog-docs 再 push 的时候 mdblog 就可以自动更新文档并显示了。 + +## 更新日志 + +### 2019-04-28 添加 github 钩子,自动同步 blog-docs 的文档 diff --git a/app/config/config.go b/app/config/config.go index fac1fe3..ff87242 100644 --- a/app/config/config.go +++ b/app/config/config.go @@ -51,6 +51,9 @@ type Config struct { // 百度统计 的 key Tongji string + + // Github 钩子中配置的 Secret + Secret string } // Log 是日志相关的配置 diff --git a/app/http/controllers/public.go b/app/http/controllers/public.go index 5149189..d9fe47a 100644 --- a/app/http/controllers/public.go +++ b/app/http/controllers/public.go @@ -1,10 +1,16 @@ package controllers import ( + "crypto/hmac" + "crypto/sha1" + "encoding/hex" "io/ioutil" + "os/exec" "path/filepath" "strings" + "github.com/broqiang/mdblog/app/mylog" + "github.com/broqiang/mdblog/app/config" "github.com/broqiang/mdblog/app/mdfile" "github.com/gin-gonic/gin" @@ -67,3 +73,69 @@ func mergeH(c *gin.Context, h gin.H) gin.H { func ToKeywords(works ...string) string { return strings.Join(works, ",") } + +// Webhook github 钩子 +func Webhook(c *gin.Context) { + singn := c.GetHeader("X-Hub-Signature") + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + mylog.LogErr.Printf("github hook %v", err) + return + } + + if !checkSecret(singn, body) { + mylog.Error("github hook check secret failure.") + return + } + + pullDocs() + + // 从新初始化博客列表的内容 + mdfile.Model.Reload() +} + +// 向 github 发起 pull 请求,更新文档 +func pullDocs() { + // 获取文档保存的路径 + docPath := filepath.Join(config.Root, config.Cfg.MarkdownDir) + // 执行 git pull + cmd := exec.Command("git", "pull") + // 切换到命令要执行的目录 + cmd.Dir = docPath + + // 执行,并返回结果 + res, err := cmd.Output() + + if err == nil { + mylog.Infof("git pull success. \n%s", res) + } else { + mylog.Errorf("git pull failure, %v", err) + } + +} + +// 检测 github 传过来的 key +func checkSecret(singn string, body []byte) bool { + if len(singn) != 45 || !strings.HasPrefix(singn, "sha1=") { + return false + } + + // github 中对应的加密串, 从配置文件去获取 + secret := []byte(config.Cfg.Secret) + + // 通过加密串和 body 计算签名 + mac := hmac.New(sha1.New, secret) + mac.Write(body) + mKey := mac.Sum(nil) + + // Hex 解码 + singnature := make([]byte, 20) + hex.Decode(singnature, []byte(singn[5:])) + + // 比较签名是否一直 + if hmac.Equal(singnature, mKey) { + return true + } + + return false +} diff --git a/app/mdfile/list.go b/app/mdfile/list.go index 3f650f3..5b29d64 100644 --- a/app/mdfile/list.go +++ b/app/mdfile/list.go @@ -24,6 +24,7 @@ type List interface { ArticleByPath(string) (Article, error) ArticlesByCategory(string) Articles ArticlesByTag(string) Articles + Reload() } // Categories 是文章分类的切片(数组) diff --git a/app/mdfile/listmap.go b/app/mdfile/listmap.go index 6a7efb2..fe16ed6 100644 --- a/app/mdfile/listmap.go +++ b/app/mdfile/listmap.go @@ -13,6 +13,11 @@ type ListMap struct { Tags Tags } +// Reload 重新加载文档 +func (list *ListMap) Reload() { + Model = new() +} + // CategoriesAll 获取所有的分类列表 func (list *ListMap) CategoriesAll() Categories { diff --git a/app/mylog/logger.go b/app/mylog/logger.go index 346f319..4c88cba 100644 --- a/app/mylog/logger.go +++ b/app/mylog/logger.go @@ -1,6 +1,7 @@ package mylog import ( + "fmt" "log" "os" "path" @@ -153,3 +154,23 @@ func (lw *LogWriter) newFile() *os.File { return file } + +// Info 打印 info 信息 +func Info(vals ...interface{}) { + LogInfo.Output(2, fmt.Sprintln(vals...)) +} + +// Infof 指定格式的 info 日志 +func Infof(format string, vals ...interface{}) { + LogInfo.Output(2, fmt.Sprintf(format, vals...)) +} + +// Error 错误日志 +func Error(vals ...interface{}) { + LogErr.Output(2, fmt.Sprintln(vals...)) +} + +// Errorf 指定格式的错误日志 +func Errorf(format string, vals ...interface{}) { + LogErr.Output(2, fmt.Sprintf(format, vals...)) +} diff --git a/app/routes/web.go b/app/routes/web.go index 71fc7e7..b6343aa 100644 --- a/app/routes/web.go +++ b/app/routes/web.go @@ -9,18 +9,23 @@ import ( // New 初始化路由 func New(e *gin.Engine) { // 注册全局的中间件 - e.Use(gin.Logger(), midderware.Recovery, midderware.Sites, midderware.Navigation) + e.Use(gin.Logger(), midderware.Recovery) - // 出现错误的页面 - e.GET("/errors", midderware.Errors) - - // 404 页面 - e.NoRoute(midderware.NotFound) + e.POST("/webhook", controllers.Webhook) // 前台页面组,添加右侧标签的中间件 - front := e.Group("/", midderware.Tags) + front := e.Group("/", midderware.Sites, midderware.Navigation, midderware.Tags) { + // 出现错误的页面 + e.GET("/errors", midderware.Errors) + + // 404 页面 + e.NoRoute(midderware.NotFound) + + // 首页 front.GET("/", controllers.Home) + // about 页 + front.GET("/about", controllers.About) // 博客文章详情 diff --git a/config/config.example.toml b/config/config.example.toml index a62d37f..501f163 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -25,6 +25,9 @@ icp = "需要填入你自己的备案号" # 百度统计的 key ,如果不使用的话,不配置或使用空字符串即可 tongji = "" +# github 钩子中配置的 Secret, 要和钩子的配置保持一致 +secret = "broqiang.com" + # 日志相关的配置 [log] # 日志保存位置,默认是应用根目录下生成日志文件