Resolve committed module identity from Git objects

This commit is contained in:
2026-10-10 14:20:09 +00:00
parent 7eebbbbfc3
commit 54cc6baf95
13 changed files with 478 additions and 158 deletions

View File

@@ -75,22 +75,84 @@ func ResolveSelection(repositoryDir, moduleDir string) (Selection, error) {
// FromCommitted derives identity from the selected module declaration at a
// captured commit. The selected module must contain its own go.mod.
func FromCommitted(ctx context.Context, repositoryDir, moduleDir, version, commit string) (Identity, error) {
selection, err := ResolveSelection(repositoryDir, moduleDir)
resolver, err := committedPaths(repositoryDir, commit)
if err != nil {
return Identity{}, err
return Identity{Version: version}, err
}
return FromCommittedSelection(ctx, selection, version, commit)
selection, err := selectCommittedDirectory(ctx, resolver, moduleDir)
if err != nil {
return Identity{Selection: selection, Version: version}, err
}
return fromCommittedSelection(ctx, selection, version, commit, resolver)
}
// ResolveCommittedSelection resolves directory selection without reading the
// module declaration or requiring the directory to be materialized.
func ResolveCommittedSelection(ctx context.Context, repositoryDir, moduleDir, commit string) (Selection, error) {
resolver, err := committedPaths(repositoryDir, commit)
if err != nil {
return Selection{}, err
}
return selectCommittedDirectory(ctx, resolver, moduleDir)
}
func committedPaths(repositoryDir, commit string) (git.PathResolver, error) {
repositoryAbs, err := filepath.Abs(repositoryDir)
if err != nil {
return git.PathResolver{}, err
}
repositoryAbs, err = filepath.EvalSymlinks(repositoryAbs)
if err != nil {
return git.PathResolver{}, err
}
return git.CommittedPaths(repositoryAbs, commit), nil
}
func selectCommittedDirectory(ctx context.Context, resolver git.PathResolver, moduleDir string) (Selection, error) {
selection := Selection{RepositoryDir: resolver.RepositoryDir}
if moduleDir == "" {
moduleDir = "."
}
if filepath.IsAbs(moduleDir) {
return selection, fmt.Errorf("module directory must be repository-relative: %q", moduleDir)
}
directory, err := resolver.ResolveDestination(ctx, "go.mod", filepath.ToSlash(moduleDir))
if err != nil {
return selection, fmt.Errorf("resolve committed module directory: %w", err)
}
if directory.Kind != git.DestinationDirectory {
return selection, fmt.Errorf("selected committed module directory %q resolves to %s at %q", moduleDir, directory.Kind, directory.Path)
}
selection.ModuleDir = filepath.Join(resolver.RepositoryDir, filepath.FromSlash(directory.Path))
selection.ModuleSubdir = directory.Path
return selection, nil
}
// FromCommittedSelection derives identity from a previously resolved module
// selection and the selected module declaration at a captured commit.
func FromCommittedSelection(ctx context.Context, selection Selection, version, commit string) (Identity, error) {
return fromCommittedSelection(ctx, selection, version, commit, git.CommittedPaths(selection.RepositoryDir, commit))
}
func fromCommittedSelection(ctx context.Context, selection Selection, version, commit string, resolver git.PathResolver) (Identity, error) {
identity := Identity{Selection: selection, Version: version}
if err := ctx.Err(); err != nil {
return Identity{}, fmt.Errorf("resolve committed release identity: %w", err)
return identity, fmt.Errorf("resolve committed release identity: %w", err)
}
declaration, err := git.ReadCommitFile(ctx, selection.RepositoryDir, commit, moduleFilePath(selection.ModuleSubdir))
declarationPath, err := resolver.ResolveDestination(ctx, "go.mod", moduleFilePath(selection.ModuleSubdir))
if err != nil {
return Identity{}, fmt.Errorf("read selected module declaration at %s: %w", commit, err)
return identity, fmt.Errorf("resolve selected module declaration at %s: %w", commit, err)
}
if declarationPath.Kind != git.DestinationEntry {
return identity, fmt.Errorf("selected module declaration resolves to %s at %q", declarationPath.Kind, declarationPath.Path)
}
entry, _, err := resolver.Lookup(ctx, declarationPath.Path)
if err != nil {
return identity, err
}
declaration, err := git.ReadBlob(ctx, selection.RepositoryDir, entry.ObjectID)
if err != nil {
return identity, fmt.Errorf("read selected module declaration at %s: %w", commit, err)
}
return Derive(selection, declaration, version)
}