Introduction

In the previous blog post, I discussed how to solve the problem of installing private extension packages from Gitlab, but I also discovered a series of issues:

  • Pulling directly from Gitlab Repository: The biggest problem with this approach is that if there are code changes in the dependent package, you have to go through the entire Gitflow process each time, which is quite cumbersome!
  • Using replace to substitute Gitlab packages with local directories: This approach solves the above problem but creates a new one - when development is complete and code is submitted, you need to manually delete all the replace configurations in the go.mod file. This is manageable if the project has only one or two packages, but it becomes a disaster with more.

Workspace was created to solve this problem. It has higher priority than go.mod, so if you create a go.work file in the project directory, you only need to configure replace in go.work.

Initializing Workspace

Before initializing a Workspace for the project, we can see that the GOWORK configuration in Go Env (line 32) is currently empty:

go env
GO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/George/Library/Caches/go-build"
GOENV="/Users/George/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/George/Develop/Go/pkg/mod"
GONOPROXY=""
GONOSUMDB="gitlab.example.com/services/modules"
GOOS="darwin"
GOPATH="/Users/George/Develop/Go"
GOPRIVATE=""
GOPROXY="direct"
GOROOT="/opt/homebrew/Cellar/go/1.19.2/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.19.2/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.19.2"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/George/Develop/GA/udfs/server/go.mod"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/p6/g0wwf37d165dfg5hvqtr9l180000gn/T/go-build1666497732=/tmp/go-build -gno-record-gcc-switches -fno-common"

Next, execute the command to initialize the Workspace:

go work init .
cat go.work
go 1.19

use .

This will create a go.work file in the project directory. Now if you check Go Env again, you’ll find that the value of GOWORK has changed to go.work in the current directory:

GOWORK="/Users/George/Develop/udfs/server/go.work"

Installing Dependencies Locally

You can include multiple local package paths in use, so that during local development, Go will automatically replace remote packages with those under the Workspace:

cat go.work
go 1.19

use (
    .
    ../modules/inquiry
)

You can also use replace in go.work to substitute dependencies declared in go.mod with local package paths:

go work edit -replace=gitlab.example.com/services/modules/inquiry=/Users/George/Develop/services/modules/inquiry
cat go.work
go 1.19

use .

replace gitlab.example.com/services/modules/inquiry => /Users/George/Develop/services/modules/inquiry

This defines a replace in the go.work file, using the local project as the package source. The local directory can be a relative or absolute path, but the directory must contain a go.mod file.

Additionally, you should add the go.work and go.work.sum files to the .gitignore configuration file, otherwise it will cause the package to not be found in CI/CD.

Conclusion

At this point, the local development problem is solved, avoiding the need to go through the package release process every time there’s a modification. But a new problem arises: in the CI/CD process, how do we specify whether to install from a Release Tag or from a test branch based on the environment?

I will continue to explore this issue in future CI/CD practices and look for best practice solutions!

I hope this is helpful, Happy hacking…