in release/calculate.go [30:173]
func Calculate(finder ModuleFinder, tags git.ModuleTags, config repotools.Config, annotations []changelog.Annotation) (map[string]*Module, error) {
rootDir := finder.Root()
repositoryModules := finder.Modules()
moduleAnnotations := make(map[string][]changelog.Annotation)
for _, annotation := range annotations {
for _, am := range annotation.Modules {
moduleAnnotations[am] = append(moduleAnnotations[am], annotation)
}
}
// Add modules to the tree that have been tombstoned, and removed.
for moduleTag := range tags {
if m := repositoryModules.Get(moduleTag); m == nil {
if _, err := repositoryModules.InsertRel(moduleTag, tombstonedModuleAttrib); err != nil {
return nil, fmt.Errorf("failed to insert tombstone module, %w", err)
}
}
}
checkedModules := map[string]*Module{}
for it := repositoryModules.Iterator(); ; {
module := it.Next()
if module == nil {
break
}
var latestVersion string
var hasChanges bool
var changes []string
// Tombstone modules must have no files, (excludes submodules).
if module.HasAttribute(tombstonedModuleAttrib) {
files, err := listRelFiles(rootDir, module.AbsPath())
if err != nil {
return nil, fmt.Errorf("failed to list tombstone module files, %w", err)
}
files, err = gomod.FilterModuleFiles(module, files)
if err != nil {
return nil, fmt.Errorf("failed to filter tombstone module files, %w", err)
}
if len(files) != 0 {
return nil, fmt.Errorf("tombstone module has go source files, %v", files)
}
continue
}
moduleFile, err := gomod.LoadModuleFile(module.AbsPath(), nil, true)
if err != nil {
return nil, fmt.Errorf("failed to load module file: %w", err)
}
modulePath, err := gomod.GetModulePath(moduleFile)
if err != nil {
return nil, fmt.Errorf("failed to read module path: %w", err)
}
latestVersion, ok := tags.Latest(module.Path())
if ok {
startTag, err := git.ToModuleTag(module.Path(), latestVersion)
if err != nil {
log.Fatalf("failed to convert module path and version to tag: %v", err)
}
changes, err = git.Changes(finder.Root(), startTag, "HEAD", module.Path())
if err != nil {
log.Fatalf("failed to get git changes: %v", err)
}
// Only consider changes that are specific to this module. Other
// module changes will be considered separately.
changes, err = gomod.FilterModuleFiles(module, changes)
if err != nil {
return nil, fmt.Errorf("failed to determine module changes: %w", err)
}
hasChanges = len(changes) != 0
if !hasChanges {
// Check if any of the submodules have been "carved out" of
// this module since the last tagged release
for it := module.Iterator(); ; {
subModule := it.Next()
if subModule == nil {
break
}
// Ignore Tombstoned modules, since they no longer exist locally.
if module.HasAttribute(tombstonedModuleAttrib) {
continue
}
// Is an existing submodule?
// - yes, skip existing modules
// - no, check if new modules is a carve out
if _, ok := tags.Latest(subModule.Path()); ok {
continue
}
// Did parent module contain this path previously in its tree?
treeFiles, err := git.LsTree(rootDir, startTag, subModule.Path())
if err != nil {
return nil, fmt.Errorf("failed to list git tree: %v", err)
}
carvedOut, err := isModuleCarvedOut(subModule, treeFiles)
if err != nil {
return nil, err
}
if carvedOut {
hasChanges = true
break
}
}
}
}
var changeReason ModuleChange
if hasChanges && len(latestVersion) > 0 {
// Has changes and is an existing module
changeReason |= SourceChange
} else if len(latestVersion) == 0 {
// New module with changes.
changeReason |= NewModule
}
checkedModules[modulePath] = &Module{
File: moduleFile,
RelativeRepoPath: module.Path(),
Latest: latestVersion,
Changes: changeReason,
FileChanges: changes,
ChangeAnnotations: moduleAnnotations[module.Path()],
ModuleConfig: config.Modules[module.Path()],
}
}
if err := CalculateDependencyUpdates(checkedModules); err != nil {
return nil, err
}
return checkedModules, nil
}