Debian Go Team: Module-Aware Builds Transition Guide (WIP)

This Guide explains the new workflow for Modern, Module-Aware builds using dh-go.

The Long-Term Benefits

By aligning Debian's build environment with modern upstream Go standards via Go Workspaces, we eliminate Debian-specific GOPATH hacks that previously made local debugging difficult and almost impossible for upstream to help. When a Debian maintainer or user encounters a test failure or runtime bug in a package, they can now reproduce and debug it in almost the exact same build environment that the upstream developer expected.

This makes it easier for the whole Debian community to contribute back to the Go community. Build fixes and patches that work in Debian can be directly applied upstream with minimal rework, turning the whole Debian community (maintainers and users) into active, direct contributors to the Go ecosystem.

How Module-Aware Builds Work in Debian

Under Modern Module-Aware Builds (GO111MODULE=on), dependency resolution is entirely driven by the native Go compiler reading the upstream go.mod file.

To satisfy Debian's strict offline build requirement without fetching modules over the internet, dh-go automatically generates a Go Workspace under the build directory (e.g., debian/_build/go.work) during the build process. This go.work file redirect Go compiler to lookup module from the Go Import Path in go.mod file to the module on filesystem under /usr/share/gocode/src (provided by installed -dev packages).

Important: Because dh-go uses the standard Go compiler instead of old GOPATH workarounds, the Go Import Path in Debian sources should stay as identical as possible to upstream. Keeping our import path identical makes it easy for both Debian maintainers and upstream developers to reproduce build failures, test failures, and security issues. This also makes it much easier to get help from upstream and give back to upstream.

Real World Transition Examples

Since dh-go is available in unstable.

Porting golang-github-pocketbase-pocketbase to dh-go

1. Build-deps update in debian/control

2. Clean up dh-sequence-golang

3. Upload to unstable

Newer upstream release with Go Import Path changes

When we updating golang-github-pocketbase-pocketbase to version 0.40.2+ds1-1, the we got FTBFS with a missing module dependency error.

1. Check missing module dependency FTBFS error

The build stopped due to a missing module dependency in the workspace:

src/github.com/pocketbase/pocketbase/apis/backup_create.go:8:2: no required module provides package github.com/pocketbase/ozzo-validation/v4; to add it:
        cd /build/reproducible-path/golang-github-pocketbase-pocketbase-0.40.2+ds1/debian/_build/src/github.com/pocketbase/pocketbase
        go get github.com/pocketbase/ozzo-validation/v4

2. Investigation Upstream Dependency Changes

When we unsure what happened or what to use. Check the https://pkg.go.dev and found this note from upstream:

[!NOTE] This is a fork of github.com/go-ozzo/ozzo-validation@v4.3.0 as the original project has changed ownership and the new maintainer cannot be trusted.

I do plan to create eventually a new validation library from scratch more suited for our needs in PocketBase since ozzo-validation is known to have some minor performance and obscure regex issues, but until then this fork will have to be used.

We confirmed why upstream switched from github.com/go-ozzo/ozzo-validation/v4(the name convention was wrong on golang-github-go-ozzo-ozzo-validation.v4-dev) to forked github.com/pocketbase/ozzo-validation/v4.

3. Resolution Strategy

Instead of patching to use the untrusted library, we should package the fork github.com/pocketbase/ozzo-validation/v4 as golang-github-pocketbase-ozzo-validation-v4-dev package. This keeps import paths identical to upstream and ensures proper support from upstream for a long run.

4. Satisfy Upstream Dependency

Fork or create a new package with ITP. After that. Package builds fine without additional patches after updated build-deps to golang-github-pocketbase-ozzo-validation-v4.

Renaming Legacy Package

Example: Renaming golang-github-google-go-github to golang-github-google-go-github-v60.

1. Fork from old one

Find the package repo and then fork to go-team/packages namespace on salsa.

2. Renaming with Major API Version

In debian/control:

  1. Update Source: to golang-github-google-go-github-v60.
  2. Update the binary package to golang-github-google-go-github-v60-dev.
  3. Update Go-Import-Path: to github.com/google/go-github/v60
  4. Update VCS-Tags: point to the new Salsa repository name with -v60.

In debian/watch:

  1. Upgrade to Version 5 format.
  2. Set Major API Version in Matching-Pattern: refs/tags/v(60\.[\d.]+)

In debian/changelog:

  1. Rename the package.
  2. Target unstable with a new debian version entry (60.0.0-1).

  3. Explaining the package rename for the v60 API version transition.

3. If Tests Failed

  1. This package has some tests FAILED. The go.mod requires
    •         github.com/google/go-cmp v0.6.0
              github.com/google/go-querystring v1.1.0
      • and we have in Debian:
         golang-github-google-go-cmp-dev | 0.7.0-1       | unstable     | all
         golang-github-google-go-querystring-dev | 1.2.0-1       | unstable     | all
      Suspect we need backport upstream changes.
  2. Add upstream git as remote: git remote add upstream https://github.com/google/go-github.git, and then git fetch upstream.

  3. Check git log from upstream/master with the FAILED Strings: git log upstream/master  -S "UnsupportedTypeError" -p.

  4. Cherry-pick the upstream commit and then run dpkg-source --commit to generate patch in quilt format under debian/patches/.

4. Lintian clean and Upload

  1. Polish the package until it's lintian clean.
  2. If package builds and all tests passed. Do Source+Binary upload to NEW. (Source-only upload will get reject from NEW)

Packaging Rules & Best Practices

1. Respect Upstream Import Paths & Package Naming Conventions

2. Handling Upstream Module Relocations & Legacy Package Renames

If dependencies in Build-Depends or Depends still use old legacy GOPATH names, follow this renaming process:

3. Minimal Patching & Identical Sources

4. Always Run Tests & Avoid Path Exclusion

5. Handling Circular Build-Dependencies

In modern Go ecosystems, core libraries often depend on each other (Package A needs Package B, but Package B needs Package A). While Go's upstream ecosystem relies on dynamic "get the latest" fetching, Debian requires strict order-of-source builds.

6. Upstream First Reporting