Files
livekit/magefile.go
T
Benjamin PrachtandGitHub 2cad1cc936 Update renovate and pinning behavior, run tools from go.mod (#4759)
- Renovate

config:recommended (config:base is deprecated) and matchPackageNames globs instead of the deprecated matchPackagePrefixes.
Vulnerability alerts get a fast path: 2-day quarantine, no concurrency/hourly/schedule limits.
Go modules are no longer grouped into one "go deps" PR — each gets its own, so a bad bump can be reverted alone. The pion modules stay grouped as a documented exception: they're co-released and interdependent, so individual PRs wouldn't build.
First-party github.com/livekit/** skips the 2-week quarantine.
go.mod's go directive is no longer an update target — the build toolchain is pinned in the Dockerfile instead.
Dockerfile deps get pinDigests; the golang image is ungrouped with separateMinorPatch so a patch and a minor bump are each separately approvable.
Custom manager to bump the builder image's -alpineA.B suffix together with its digest, which the stock docker manager holds fixed.

- Pinning

Both Dockerfiles pin golang and alpine by digest alongside the readable tag.
GOTOOLCHAIN=local so a go.mod bump fails loudly instead of silently downloading a different toolchain.
apk upgrade in the runtime stage — a digest pin plus the 2-week quarantine would otherwise ship base-package CVEs Alpine has already fixed. This relies on a cold layer cache, which holds today because the release workflow configures no buildx cache; there's a comment saying so.
Workflows resolve the Go version from the Dockerfile via .github/scripts/go-version.sh, so tests, releases and images share one toolchain.

- Tools

All four code generators now come from the module graph, and tools/tools.go (the pre-Go-1.24 blank-import idiom) is replaced by go.mod tool directives:

tool	how	why
goimports	go tool	lives in x/tools — its own module is the one being selected
gotestfmt	go tool	zero dependencies, nothing to skew
wire	go run	pins x/tools v0.24.1; building it in our graph changes its output
counterfeiter	go run	unchanged, matches its //go:generate directives

The wire distinction is load-bearing. Building wire inside our module raises it from the x/tools v0.24.1 it pins to our v0.48.0, and that module version difference changes what it generates: it falls back to v/v2/v3 instead of deriving real identifiers from the type. wire_gen.go is regenerated here to match the in-module build — a cosmetic rename of 9 lines, with no other change to the generated code.

golangci-lint deliberately keeps its action rather than becoming a tool: it pins its own x/tools (v0.44.0 vs our v0.48.0) for the analyzers it bundles, adding it to go.mod would double our go.mod/go.sum (158→338 / 441→889 lines), and the action supplies caching, only-new-issues and PR annotations that invoking a binary can't. Its version stays manual by request.
2026-08-17 09:25:02 -07:00

222 lines
5.9 KiB
Go

// Copyright 2023 LiveKit, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build mage
// +build mage
package main
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"strings"
"github.com/magefile/mage/mg"
"github.com/livekit/livekit-server/version"
"github.com/livekit/mageutil"
_ "github.com/livekit/psrpc"
)
const (
goChecksumFile = ".checksumgo"
imageName = "livekit/livekit-server"
)
// Default target to run when none is specified
// If not set, running mage will list available targets
var (
Default = Build
checksummer = mageutil.NewChecksummer(".", goChecksumFile, ".go", ".mod")
)
func init() {
checksummer.IgnoredPaths = []string{
"pkg/service/wire_gen.go",
"pkg/rtc/types/typesfakes",
}
}
// downloads module deps at the versions pinned in go.mod
//
// Code generators are not installed here: they run as `go run <pkg>` from their
// //go:generate directives (see pkg/service/wire_gen.go and the counterfeiter
// directives under pkg/), so they always execute at the version go.mod pins and
// Renovate keeps them current alongside every other module.
func Deps() error {
return mageutil.Run(context.Background(), "go mod download")
}
// builds LiveKit server
func Build() error {
mg.Deps(generateWire)
if !checksummer.IsChanged() {
fmt.Println("up to date")
return nil
}
fmt.Println("building...")
if err := os.MkdirAll("bin", 0755); err != nil {
return err
}
if err := mageutil.RunDir(context.Background(), "cmd/server", "go build -o ../../bin/livekit-server"); err != nil {
return err
}
checksummer.WriteChecksum()
return nil
}
// builds binary that runs on linux
func BuildLinux() error {
mg.Deps(generateWire)
if !checksummer.IsChanged() {
fmt.Println("up to date")
return nil
}
fmt.Println("building...")
if err := os.MkdirAll("bin", 0755); err != nil {
return err
}
buildArch := os.Getenv("GOARCH")
if len(buildArch) == 0 {
buildArch = "amd64"
}
cmd := mageutil.CommandDir(context.Background(), "cmd/server", "go build -buildvcs=false -o ../../bin/livekit-server-" + buildArch)
cmd.Env = []string{
"GOOS=linux",
"GOARCH=" + buildArch,
"HOME=" + os.Getenv("HOME"),
"GOPATH=" + os.Getenv("GOPATH"),
}
if err := cmd.Run(); err != nil {
return err
}
checksummer.WriteChecksum()
return nil
}
func Deadlock() error {
ctx := context.Background()
if err := mageutil.Run(ctx, "go get github.com/sasha-s/go-deadlock"); err != nil {
return err
}
if err := mageutil.Pipe("grep -rl sync.Mutex ./pkg", "xargs sed -i -e s/sync.Mutex/deadlock.Mutex/g"); err != nil {
return err
}
if err := mageutil.Pipe("grep -rl sync.RWMutex ./pkg", "xargs sed -i -e s/sync.RWMutex/deadlock.RWMutex/g"); err != nil {
return err
}
if err := mageutil.Pipe("grep -rl deadlock.Mutex\\|deadlock.RWMutex ./pkg", "xargs go tool goimports -w"); err != nil {
return err
}
if err := mageutil.Run(ctx, "go mod tidy"); err != nil {
return err
}
return nil
}
func Sync() error {
if err := mageutil.Pipe("grep -rl deadlock.Mutex ./pkg", "xargs sed -i -e s/deadlock.Mutex/sync.Mutex/g"); err != nil {
return err
}
if err := mageutil.Pipe("grep -rl deadlock.RWMutex ./pkg", "xargs sed -i -e s/deadlock.RWMutex/sync.RWMutex/g"); err != nil {
return err
}
if err := mageutil.Pipe("grep -rl sync.Mutex\\|sync.RWMutex ./pkg", "xargs go tool goimports -w"); err != nil {
return err
}
if err := mageutil.Run(context.Background(), "go mod tidy"); err != nil {
return err
}
return nil
}
// builds and publish snapshot docker image
func PublishDocker() error {
// don't publish snapshot versions as latest or minor version
if !strings.Contains(version.Version, "SNAPSHOT") {
return errors.New("Cannot publish non-snapshot versions")
}
versionImg := fmt.Sprintf("%s:v%s", imageName, version.Version)
cmd := exec.Command("docker", "buildx", "build",
"--push", "--platform", "linux/amd64,linux/arm64",
"--tag", versionImg,
".")
mageutil.ConnectStd(cmd)
if err := cmd.Run(); err != nil {
return err
}
return nil
}
// run unit tests, skipping integration
func Test() error {
mg.Deps(generateWire, setULimit)
return mageutil.Run(context.Background(), "go test -short ./... -count=1")
}
// run all tests including integration
func TestAll() error {
mg.Deps(generateWire, setULimit)
return mageutil.Run(context.Background(), "go test ./... -count=1 -timeout=4m -v")
}
// runs the SDK test server (cmd/test-server) in the foreground
func TestServer() error {
return mageutil.Run(context.Background(), "go run ./cmd/test-server")
}
// runs golangci-lint
func Lint() error {
if _, err := exec.LookPath("golangci-lint"); err != nil {
return errors.New("golangci-lint is not installed, install instructions: https://golangci-lint.run/docs/welcome/install/")
}
return mageutil.Run(context.Background(), "golangci-lint run ./...")
}
// cleans up builds
func Clean() {
fmt.Println("cleaning...")
os.RemoveAll("bin")
os.Remove(goChecksumFile)
}
// regenerate code
func Generate() error {
mg.Deps(generateWire)
fmt.Println("generating...")
return mageutil.Run(context.Background(), "go generate ./...")
}
// code generation for wiring
func generateWire() error {
if !checksummer.IsChanged() {
return nil
}
fmt.Println("wiring...")
// Matches the //go:generate directive in pkg/service/wire_gen.go, so running
// wire here and running `go generate ./...` produce the same output.
return mageutil.RunDir(context.Background(), "pkg/service", "go run github.com/google/wire/cmd/wire")
}