golang项目持续集成Travis-CI实践

shorturl

shorturl是一个demo,其实是用来测试travis-ci的集成效果。上面的build history 记录了每次的build历程。下面一点点来看看一个golang项目是如何添加持续集成的吧。

1 Travis-ci支持

Travis-ci的工作流程大致有这么几步:

  • 从关联了权限的GitHub仓库中拉取代码
  • 根据.travis.yml中设置好的环境建造容器
  • 把repository扔到容器中,按照定制的stages一点点去执行
  • 反馈集成结果

所以在决定给某一个项目添加travis集成之前,我们是需要先有一个repository的,然后在 https://travis-ci.org 上关联GitHub对应的仓库,打开持续集成开关即可。

2 .travis.yml

第一部分说到 Travis-CI会根据.travis.yml 设置好的环境参数去创建对应的容器,可见这个文件是很重要的。一个待持续集成的项目根目录下必然需要提供一个这样的文件,官网有一个教程:https://docs.travis-ci.com/user/languages/go/ 不过我看的云里雾里的,还是从阮一峰-travis-ci持续集成指南 中大致摸索了一个结构。

# .travis.yml
language:    # 指明使用的语言
  - go 

go:          # 语言版本号
  - "1.x"    # x表示对应前缀的最新版本
  - "1.10"   # 注意,需要 "1.10" 版本的时候必须表示为字符串形式,如果写成 1.10 则会使用 1.1 版本
  - "1.10.x"
  - master   # 默认使用最新版本

script:      # 执行的脚步,但是go默认会执行下面的这些命令的,所以可以不用写
  - go get -v
  - go test -v ./...

3 Hello World

架子搭好了,下面先来一个简单的测试。还好有Git,可以方便的乘坐时光机到某一个版本的快照,具体的代码可以参考:https://github.com/guoruibiao/shorturl/tree/298b7bfc978cda8dc4ae6a53c0186e9a6060c53a

对应的.travis.yml 内容也在里面了,这里先单独摘出来,如下:

# .travis.yml
language:    # 指明使用的语言
  - go 

go:          # 语言版本号
  - "1.11.5"   # 默认使用最新版本,注意,需要 "1.10" 版本的时候必须表示为字符串形式,如果写成 1.10 则会使用 1.1 版本;x表示对应前缀的最新版本

script:      # 执行的脚步,但是go默认会执行下面的这些命令的,所以可以不用写
  - go get -v
  - go test ./...

通过push提交代码后,Travis-ci会受到hook通知,开启build, 对应的构建号为:524402743

详细的构建日志可以参考链接为: build-log

至此,一个简单的集成测试流程就算走通了。但是如果只是这样,持续集成也就有点太鸡肋了不是,下面一点点来丰富它。

4 短链服务

短链接服务在某些比如短信,邮件,微博等限制字数的业务场景下还是使用的比较频繁的,下面借助新浪短链的服务来代理下,做一个简单的短链生成服务。

代码:https://github.com/guoruibiao/shorturl/tree/8c5b567a2a72f6b79572445cf7026c0d0f46c92f

本地测试

func Test_SinaURLShort(t *testing.T) {
    originurl := "https://github.com"
    dao, _ := New()
    response, _ := dao.SinaURLShort(originurl)
    if response.URLS[0].ShortURL == "http://t.cn/RxnlTYR" {
        t.Log("SinaURLShort passed")
    } else {
        t.Error("SinaURLShort failed", originurl, " to ", response.URLS[0].ShortURL)
    }
}

输出内容:

Running tool: /usr/local/Cellar/go/1.11.5/libexec/bin/go test -timeout 30s shorturl/dao -run ^(Test_SinaURLShort)$

ok      shorturl/dao    0.631s
Success: Tests passed.

5 添加持续集成

本地代码编写,测试通过了,但不是说就一定可以通过集成测试套件,因为我就发现了一个问题。

现象是:本地好好的,push到GitHub后,触发Travis-CI的构建 => 失败

查看下构建记录:524408121

$ go version
go version go1.11.5 linux/amd64
go.env
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/travis/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/travis/gopath"
GOPROXY=""
GORACE=""
GOROOT="/home/travis/.gimme/versions/go1.11.5.linux.amd64"
GOTMPDIR=""
GOTOOLDIR="/home/travis/.gimme/versions/go1.11.5.linux.amd64/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build040675356=/tmp/go-build -gno-record-gcc-switches"
install
0.00s$ travis_install_go_dependencies 1.11.5 -v
Makefile detected
0.34s$ go get -v
github.com/guoruibiao/shorturl
The command "go get -v" exited with 0.
0.08s$ go test ./...
dao/shortdao.go:7:2: cannot find package "shorturl/model" in any of:
    /home/travis/.gimme/versions/go1.11.5.linux.amd64/src/shorturl/model (from $GOROOT)
    /home/travis/gopath/src/shorturl/model (from $GOPATH)
The command "go test ./..." exited with 1.
Done. Your build exited with 1.

终于发现问题了,是package未在GOPATH中找到引起的。难怪会构建失败了。

6 问题fix实践

既然构建日志都说是package没找到了,那么让它找到应该就好了吧。看GOPATH的内容,发现test集合中的包是从github.com/xxx/yyy中去查找的。那这么说,import的时候直接写死应该就可以了吧。

代码:596c9ebd84ffbbd68a8febfd52551d40dc665eab
构建结果: 524410672

发现构建成功了,也在一定程度上验证了我们的猜想。不过这种解法总觉得怪怪的,因为本地代码中github.com/xxx/yyy中是没有这个package的,直接写到代码中,有点不伦不类。

7 还得是GOPATH

弄完第6部分已经凌晨一点了,还是头发比较重要,睡觉去。不过脑袋里却依然萦绕着这个问题,想了想,还得是GOPATH的锅。在Travis-ci的运行容器中,有这么一条内容:

git clone github.com/xxx/yyy xxx/yyy

也就是说它最终进到了yyy目录,即$GOPATH/src/github.com/xxx/yyy和我本地开发环境中 yyy$GOPATH/src/yyy 的路径是不一致的。这也是为啥一直在提示找不到package的问题所在。

那么如何确定就是这个问题呢?还得是从容器本身的运行流程下手了,切入点还是.travis.yml

# .travis.yml
language:    # 指明使用的语言
  - go 

go:          # 语言版本号
  - "1.11.5"   # 默认使用最新版本,注意,需要 "1.10" 版本的时候必须表示为字符串形式,如果写成 1.10 则会使用 1.1 版本;x表示对应前缀的最新版本


before_script:
  - go get github.com/gin-gonic/gin

script:      # 执行的脚步,但是go默认会执行下面的这些命令的,所以可以不用写
  #- go get -v
  - ls
  - echo $GOPATH
  - echo $PWD
  - cd $GOPATH/src
  - mv $GOPATH/src/github.com/guoruibiao/shorturl $GOPATH/src/
  - echo $PWD
  - cd ./shorturl/
  - go test -v ./...

构建号:524756302

从日志的输出结果看,的确是这个问题。

$ echo $GOPATH
/home/travis/gopath
The command "echo $GOPATH" exited with 0.
0.00s$ echo $PWD
/home/travis/gopath/src/github.com/guoruibiao/shorturl
The command "echo $PWD" exited with 0.
0.00s$ cd $GOPATH/src
The command "cd $GOPATH/src" exited with 0.
0.00s$ mv $GOPATH/src/github.com/guoruibiao/shorturl $GOPATH/src/
The command "mv $GOPATH/src/github.com/guoruibiao/shorturl $GOPATH/src/" exited with 0.
0.00s$ echo $PWD
/home/travis/gopath/src
The command "echo $PWD" exited with 0.
0.00s$ cd ./shorturl/
The command "cd ./shorturl/" exited with 0.
7.67s$ go test -v ./...
?       shorturl    [no test files]
=== RUN   Test_SinaURLShort
--- PASS: Test_SinaURLShort (1.36s)
    shortdao_test.go:12: SinaURLShort passed
PASS
ok      shorturl/dao    1.369s
?       shorturl/model  [no test files]
=== RUN   Test_ShortURL
--- FAIL: Test_ShortURL (1.10s)
    shorturl_test.go:18: service shorturl result failed
FAIL
FAIL    shorturl/service    1.108s
?       shorturl/utils  [no test files]
The command "go test -v ./..." exited with 1.
Done. Your build exited with 1.

finally,那接下来修改下容器运行就好了。

8 模拟重试

有问题不可怕,一点点去试错,去修复就好了。

代码:4a5fd91316c5428fec5b793e6ef341083aa6743d

构建号:524757287

7.83s$ go test -v ./...
?       shorturl    [no test files]
=== RUN   Test_SinaURLShort
--- PASS: Test_SinaURLShort (1.44s)
    shortdao_test.go:12: SinaURLShort passed
PASS
ok      shorturl/dao    1.448s
?       shorturl/model  [no test files]
=== RUN   Test_ShortURL
--- PASS: Test_ShortURL (1.10s)
PASS
ok      shorturl/service    1.108s
?       shorturl/utils  [no test files]
The command "go test -v ./..." exited with 0.

这样就搞定了,本地代码就和Travis-CI容器中的一致了。

9 反思

再来瞅瞅这个目录结构。

➜  shorturl git:(master) ✗ tree -L 2
.
├── Dockerfile
├── Makefile
├── README.md
├── app.go
├── dao
│   ├── shortdao.go
│   └── shortdao_test.go
├── model
│   └── model.go
├── service
│   ├── shorturl.go
│   └── shorturl_test.go
└── utils
    └── utils.go

最后回顾这个问题的时候,我也在想,这中import到底合不合适。

package dao

import (
    "encoding/json"
    "io/ioutil"
    "net/http"

    "shorturl/model"
    // model "github.com/guoruibiao/shorturl/model"
)

或许本地开发,使用没啥问题,但是做出来的项目有时候不仅仅是用一次就完事了的,基于重用的原则,下面的那个引入应该才是最为规范的。然后我去GitHub上搜了搜,看看人家的项目中都是怎么import的,不出意外,人家都是用的全路径引入的模式。我目前对dep还不太了解,或许会有一个更好的解决方案,这里暂且先不写了。

// TODO Learn go dep ...

后来前大佬同事todd 聊这个话题来着,发现是开发的时候选址就错了,一般来讲,规范的开发目录本身就得是:

$GOPATH/src/github.com/username/repository-name

这样引入package依赖也好,持续构建也好,都挺合适。

还是印证了那句话:

一个人可以走得很快,但两个人可以走的很远。

分享、交流,才能碰撞出思维的闪光点。

参考链接:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容