Files
zeekayandHanzo Dev 1ab6e799c1 cd: the module is github.com/hanzoai/cd, where it is actually hosted
go.mod still declared `module github.com/hanzoai/deploy` after the repo was
renamed. A Go module path is not cosmetic — it is the resolvable location. So
`go get github.com/hanzoai/cd` could not work, and anything importing this
module had to spell a name that no longer exists at that address. The build log
of v3.6.0 is where it surfaced: the compiler was still emitting
github.com/hanzoai/deploy/cmd/cd/commands.

3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile
and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to
ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from
the module path, replaced separately so neither could clobber the other.

go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 21:16:24 -07:00

86 lines
2.4 KiB
Go

package repository
import (
"path/filepath"
"strings"
securejoin "github.com/cyphar/filepath-securejoin"
log "github.com/sirupsen/logrus"
"github.com/hanzoai/cd/reposerver/apiclient"
"github.com/hanzoai/cd/util/io/files"
)
// getApplicationRootPath returns the common root path (shortest shared structure between all paths) among a
// set of application-related paths for manifest generation. AppPath is the lower possible value
func getApplicationRootPath(q *apiclient.ManifestRequest, appPath, repoPath string) string {
paths := getPaths(q, appPath, repoPath)
if len(paths) == 0 {
// backward compatibility, by default the root path is the repoPath
return repoPath
}
// the app path must be the lower possible value
commonParts := strings.Split(appPath, string(filepath.Separator))
var disjoint bool
for _, path := range paths {
parts := strings.Split(path, string(filepath.Separator))
// find the minimum length between the current common parts and the current path
minLen := func(a, b int) int {
if a < b {
return a
}
return b
}(len(commonParts), len(parts))
// check if diverge /disjoint in some point
for i := range minLen {
if commonParts[i] != parts[i] {
commonParts = commonParts[:i]
disjoint = true
break
}
}
// for non-disjoint paths
if !disjoint && minLen < len(commonParts) {
commonParts = commonParts[:minLen]
}
}
return string(filepath.Separator) + filepath.Join(commonParts...)
}
// getPaths retrieves all absolute paths associated with the generation of application manifests.
func getPaths(q *apiclient.ManifestRequest, appPath, repoPath string) []string {
var paths []string
for annotationPath := range strings.SplitSeq(q.AnnotationManifestGeneratePaths, ";") {
if annotationPath == "" {
continue
}
var err error
var path, unsafePath string
if filepath.IsAbs(annotationPath) {
unsafePath = filepath.Clean(annotationPath)
} else {
appRelPath, err := files.RelativePath(appPath, repoPath)
if err != nil {
log.Errorf("error building app relative path: %v", err)
continue
}
unsafePath = filepath.Clean(filepath.Join(appRelPath, annotationPath))
}
path, err = securejoin.SecureJoin(repoPath, unsafePath)
if err != nil {
log.Errorf("error joining repoPath %q and absolute unsafePath %q: %v", repoPath, unsafePath, err)
continue
}
paths = append(paths, path)
}
return paths
}