对于带有子包的 golang 源,AWS CodeBuild 失败

AWS CodeBuild fails for golang source with sub-packages

当我尝试使用 CodeBuild golang 映像 1.10 构建我的 golang 项目时,它失败了,无法找到子包。一些背景:

申请组织如下:

/go/src/company/app
/go/src/company/app/sub1
/go/src/company/app/sub2
etc...

这在我的开发机器上构建良好。但是,当通过 codebuild 拉取时,它被拉入不同的目录 (/codebuild/output/srcNNN/src/<some path>),其中 <some path> 根据触发构建的内容而变化。

我最初是通过将代码从其拉取位置复制到 golang 目录 (/codebuild/output/srcNNN) 来使其工作的,但是由于 GOPATH 目录的 CodeBuild 环境变量插入了 /go: (/go:/codebuild/output/srcNNN) 在前面,我用观察到的数../../...来复制。然而,这很丑陋,一旦我以不同的方式触发构建就失败了。

我的问题是是否有一个好的方法来让它工作?我的下一个想法是将字符串操作应用于观察到的路径并复制到那里以获得(希望)更高的可靠性。但这只有在 GOPATH 符合我的假设时才有效。

如有任何想法,我们将不胜感激。


澄清: 代码中导入包时,外部包导入如下:

import (
    "context"
    ...
}

子包未显式导入,但在部署代码时找到,如上所示 (/go/src/company/app)。但是,AWS CodeBuild 不会以这种方式引入代码。

如果您使用的是 golang 1.11 或更高版本,请参阅下面的 更新 以获得完整答案...我们不再使用我最初的解决方法。

我能够得到 答案。我将 post 放在这里以防它对其他人有帮助,但它依赖于在 AWS CodeBuild 中观察到的行为才能工作,所以我认为它并不理想。

在我的 buildspec.yaml 中,我可以通过以下方式使构建工作:

  1. 通过从开头删除“/go:”从 ${GOPATH} 获得 ${THEGOPATH}
  2. 复制所有代码到${THEGOPATH}/src/<app path>
  3. 正在将其他存储库复制到 ${THEGOPATH}/src/<other app path>
  4. 正常导入外部依赖项(在我们的例子中,go get ./... 或显式)
  5. 构建并强制输出名称(从 CodeBuild 启动时它使用不同的目录名称)

buildspec.yaml 类似于以下内容:

phases:
  install:
    commands:
      - echo GOPATH - $GOPATH
      - export THEGOPATH=`echo $GOPATH | cut -c 5-`
      - echo THEGOPATH = $THEGOPATH
      - mkdir -p ${THEGOPATH}/src/company/app1
      - mkdir -p  ${THEGOPATH}/src/company/other_repository_dependency
      - echo Copy source files to go root
      - cp -a ${CODEBUILD_SRC_DIR}/. ${THEGOPATH}/src/company/app1/${PACKAGE}
      - cp -a ${CODEBUILD_SRC_DIR_other_dep}/. ${THEGOPATH}/src/app/other_repository_dependecy/.
      - ls ${THEGOPATH}/src/
  build:
    commands:
      - echo Build started on `date`
      - echo Getting packages
      - go get ./...
      - echo DOING THE BUILD
      - go build -ldflags "<some flags>" -o "appname"
      - go test ./...
  post_build:
    commands:
      - echo Build completed on `date`
      - ls -al
      - pwd
artifacts:
  files:
    - appname

更新 -- 更好地修复 今天我们尝试使用 go modules(自 1.11 起可用)进行构建,请参阅 here 了解 go modules 的解释。

我们使用 go modules 在 go.mod 文件中将当前源模块 app1 定义为 company-name.com,如下所示:

module company-name.com/app1

go 1.12
require (
   ... *for example*
   github.com/golang/mock v1.3.1
   github.com/google/btree v1.0.0 // indirect
   github.com/google/go-cmp v0.3.0
   ... *etc*

我们甚至以这种方式引用我们的外部文件(尽管您需要弄清楚如何使用您的 git 存储库进行身份验证。我们使用构建规范中内置的凭据助手来进行 https 身份验证)。所以,我们的导入块现在看起来像这样:

     import ( 
       "company-name.com/app1/subpackage1"
       abbrev "company-name.com/app1/subpackage2"
       "company-name.com/externalpkg"  // In another private git repo of ours
       ... //etc
     )
     ... //golang source follows here*

最后,我们将以下环境变量添加到构建规范中:

  variables:
    GO111MODULE: "on"
    git-credential-helper: yes

这些确保模块在路径中工作(感谢 amwill04 提醒我我的遗漏)并允许我们的 Git 存储库的凭据正确设置。

在这样做的过程中,我们完成了所需的一切:

  1. 通过更改对 go 模块的引用,我们可以轻松地引用子包
  2. 我们能够锁定所有依赖项的版本
  3. 通过在 company-name.com 实现一个简单的服务器,我们可以从我们的应用程序中引用其他私有模块

这是我采用的方法。

version: 0.2

env:
  variables:
    PACKAGE: "github.com/rhyselsmore/foo"

phases:
  install:
    commands:
      # AWS Codebuild Go images use /go for the $GOPATH so let's copy our
      # application source code into that directory structure.
      - mkdir -p "/go/src/$(dirname ${PACKAGE})"
      - ln -s "${CODEBUILD_SRC_DIR}" "/go/src/${PACKAGE}"
      - # Make sure we're in the package directort within our GOPATH
      - cd "/go/src/${PACKAGE}"

现在假设 PACKAGE 变量是您正在构建的存储库的根目录,我们可以发出 go 命令。让我们分解一下 line-by-line.

- mkdir -p "/go/src/$(dirname ${PACKAGE})"

这会在 GOPATH 中为您的包创建一个新目录。

- ln -s "${CODEBUILD_SRC_DIR}" "/go/src/${PACKAGE}"

这会创建一个符号 link 从您的 CodeBuild 项目的根目录到您的 Go 包。

- cd "/go/src/${PACKAGE}"

这会为您的其余 Codebuild 操作做好准备,以便在您的 Go 包的 CWD 中进行。