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

2019-04-26  本文已影响0人  尽情的嘲笑我吧

shorturl

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

1 Travis-ci支持

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

所以在决定给某一个项目添加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依赖也好,持续构建也好,都挺合适。

还是印证了那句话:

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

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

参考链接:

上一篇下一篇

猜你喜欢

热点阅读