美文网首页
golang项目持续集成Travis-CI实践

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

作者: 尽情的嘲笑我吧 | 来源:发表于2019-04-26 15:26 被阅读0次

    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依赖也好,持续构建也好,都挺合适。

    还是印证了那句话:

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

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

    参考链接:

    相关文章

      网友评论

          本文标题:golang项目持续集成Travis-CI实践

          本文链接:https://www.haomeiwen.com/subject/nqfqnqtx.html