Using Go Workspace to Implement Local Extension Packages

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
andgo.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…