prow/repoowners/repoowners.go
func (c *Client) LoadRepoOwners(org, repo, base string) (RepoOwner, error) {
	log := c.logger.WithFields(logrus.Fields{"org": org, "repo": repo, "base": base})
	cloneRef := fmt.Sprintf("%s/%s", org, repo)
	fullName := fmt.Sprintf("%s:%s", cloneRef, base)
	mdYaml := c.mdYAMLEnabled(org, repo)

	sha, err := c.ghc.GetRef(org, repo, fmt.Sprintf("heads/%s", base))
	if err != nil {
		return nil, fmt.Errorf("failed to get current SHA for %s: %v", fullName, err)
	}

	c.lock.Lock()
	defer c.lock.Unlock()
	entry, ok := c.cache[fullName]
	if !ok || entry.sha != sha || entry.owners == nil || !entry.matchesMDYAML(mdYaml) {
		gitRepo, err := c.git.Clone(cloneRef)
		if err != nil {
			return nil, fmt.Errorf("failed to clone %s: %v", cloneRef, err)
		}
		defer gitRepo.Clean()

		reusable := entry.fullyLoaded() && entry.matchesMDYAML(mdYaml)
		// In most sha changed cases, the files associated with the owners are unchanged.
		// The cached entry can continue to be used, so need do git diff
		if reusable {
			changes, err := gitRepo.Diff(sha, entry.sha)
			if err != nil {
				return nil, fmt.Errorf("failed to diff %s with %s", sha, entry.sha)
			}
			for _, change := range changes {
				if mdYaml && strings.HasSuffix(change, ".md") ||
					strings.HasSuffix(change, aliasesFileName) ||
					strings.HasSuffix(change, ownersFileName) {
					reusable = false
					break
				}
			}
		}
		if reusable {
			entry.sha = sha
		} else {
			if err := gitRepo.Checkout(base); err != nil {
				return nil, err
			}

			if entry.aliases == nil || entry.sha != sha {
				// aliases must be loaded
				entry.aliases = loadAliasesFrom(gitRepo.Dir, log)
			}

			dirBlacklistPatterns := append(c.ownersDirBlacklist().DirBlacklist(org, repo), commonDirBlacklist...)
			var dirBlacklist []*regexp.Regexp
			for _, pattern := range dirBlacklistPatterns {
				re, err := regexp.Compile(pattern)
				if err != nil {
					log.WithError(err).Errorf("Invalid OWNERS dir blacklist regexp %q.", pattern)
					continue
				}
				dirBlacklist = append(dirBlacklist, re)
			}

			entry.owners, err = loadOwnersFrom(gitRepo.Dir, mdYaml, entry.aliases, dirBlacklist, log)
			if err != nil {
				return nil, fmt.Errorf("failed to load RepoOwners for %s: %v", fullName, err)
			}
			entry.sha = sha
			c.cache[fullName] = entry
		}
	}

	if c.skipCollaborators(org, repo) {
		log.Debugf("Skipping collaborator checks for %s/%s", org, repo)
		return entry.owners, nil
	}

	var owners *RepoOwners
	// Filter collaborators. We must filter the RepoOwners struct even if it came from the cache
	// because the list of collaborators could have changed without the git SHA changing.
	collaborators, err := c.ghc.ListCollaborators(org, repo)
	if err != nil {
		log.WithError(err).Errorf("Failed to list collaborators while loading RepoOwners. Skipping collaborator filtering.")
		owners = entry.owners
	} else {
		owners = entry.owners.filterCollaborators(collaborators)
	}
	return owners, nil
}
func (c *Client) LoadRepoOwners(org, repo, base string) (RepoOwner, error) {
	log := c.logger.WithFields(logrus.Fields{"org": org, "repo": repo, "base": base})
	cloneRef := fmt.Sprintf("%s/%s", org, repo)
	fullName := fmt.Sprintf("%s:%s", cloneRef, base)
	mdYaml := c.mdYAMLEnabled(org, repo)

	sha, err := c.ghc.GetRef(org, repo, fmt.Sprintf("heads/%s", base))
	if err != nil {
		return nil, fmt.Errorf("failed to get current SHA for %s: %v", fullName, err)
	}

	c.lock.Lock()
	defer c.lock.Unlock()
	entry, ok := c.cache[fullName]
	if !ok || entry.sha != sha || entry.owners == nil || !entry.matchesMDYAML(mdYaml) {
		gitRepo, err := c.git.Clone(cloneRef)
		if err != nil {
			return nil, fmt.Errorf("failed to clone %s: %v", cloneRef, err)
		}
		defer gitRepo.Clean()

		reusable := entry.fullyLoaded() && entry.matchesMDYAML(mdYaml)
		// In most sha changed cases, the files associated with the owners are unchanged.
		// The cached entry can continue to be used, so need do git diff
		if reusable {
			changes, err := gitRepo.Diff(sha, entry.sha)
			if err != nil {
				return nil, fmt.Errorf("failed to diff %s with %s", sha, entry.sha)
			}
			for _, change := range changes {
				if mdYaml && strings.HasSuffix(change, ".md") ||
					strings.HasSuffix(change, aliasesFileName) ||
					strings.HasSuffix(change, ownersFileName) {
					reusable = false
					break
				}
			}
		}
		if reusable {
			entry.sha = sha
		} else {
			if err := gitRepo.Checkout(base); err != nil {
				return nil, err
			}

			if entry.aliases == nil || entry.sha != sha {
				// aliases must be loaded
				entry.aliases = loadAliasesFrom(gitRepo.Dir, log)
			}

			dirBlacklistPatterns := append(c.ownersDirBlacklist().DirBlacklist(org, repo), commonDirBlacklist...)
			var dirBlacklist []*regexp.Regexp
			for _, pattern := range dirBlacklistPatterns {
				re, err := regexp.Compile(pattern)
				if err != nil {
					log.WithError(err).Errorf("Invalid OWNERS dir blacklist regexp %q.", pattern)
					continue
				}
				dirBlacklist = append(dirBlacklist, re)
			}

			entry.owners, err = loadOwnersFrom(gitRepo.Dir, mdYaml, entry.aliases, dirBlacklist, log)
			if err != nil {
				return nil, fmt.Errorf("failed to load RepoOwners for %s: %v", fullName, err)
			}
			entry.sha = sha
			c.cache[fullName] = entry
		}
	}

	if c.skipCollaborators(org, repo) {
		log.Debugf("Skipping collaborator checks for %s/%s", org, repo)
		return entry.owners, nil
	}

	var owners *RepoOwners
	// Filter collaborators. We must filter the RepoOwners struct even if it came from the cache
	// because the list of collaborators could have changed without the git SHA changing.
	collaborators, err := c.ghc.ListCollaborators(org, repo)
	if err != nil {
		log.WithError(err).Errorf("Failed to list collaborators while loading RepoOwners. Skipping collaborator filtering.")
		owners = entry.owners
	} else {
		owners = entry.owners.filterCollaborators(collaborators)
	}
	return owners, nil
}
func ( c * Client ) LoadRepoOwners ( org , repo , base string ) ( RepoOwner , error ) { log := c . logger . WithFields ( logrus . Fields { " " : org , " " : repo , " " : base } ) cloneRef := fmt . Sprintf ( " " , org , repo ) fullName := fmt . Sprintf ( " " , cloneRef , base ) mdYaml := c . mdYAMLEnabled ( org , repo ) sha , err := c . ghc . GetRef ( org , repo , fmt . Sprintf ( " " , base ) ) if err != nil { return nil , fmt . Errorf ( " " , fullName , err ) } c . lock . Lock ( ) defer c . lock . Unlock ( ) entry , ok := c . cache [ fullName ] if ! ok || entry . sha != sha || entry . owners == nil || ! entry . matchesMDYAML ( mdYaml ) { gitRepo , err := c . git . Clone ( cloneRef ) if err != nil { return nil , fmt . Errorf ( " " , cloneRef , err ) } defer gitRepo . Clean ( ) reusable := entry . fullyLoaded ( ) && entry . matchesMDYAML ( mdYaml ) // In most sha changed cases, the files associated with the owners are unchanged. // The cached entry can continue to be used, so need do git diff if reusable { changes , err := gitRepo . Diff ( sha , entry . sha ) if err != nil { return nil , fmt . Errorf ( " " , sha , entry . sha ) } for _ , change := range changes { if mdYaml && strings . HasSuffix ( change , " " ) || strings . HasSuffix ( change , aliasesFileName ) || strings . HasSuffix ( change , ownersFileName ) { reusable = false break } } } if reusable { entry . sha = sha } else { if err := gitRepo . Checkout ( base ) ; err != nil { return nil , err } if entry . aliases == nil || entry . sha != sha { // aliases must be loaded entry . aliases = loadAliasesFrom ( gitRepo . Dir , log ) } dirBlacklistPatterns := append ( c . ownersDirBlacklist ( ) . DirBlacklist ( org , repo ) , commonDirBlacklist ... ) var dirBlacklist [ ] * regexp . Regexp for _ , pattern := range dirBlacklistPatterns { re , err := regexp . Compile ( pattern ) if err != nil { log . WithError ( err ) . Errorf ( " " , pattern ) continue } dirBlacklist = append ( dirBlacklist , re ) } entry . owners , err = loadOwnersFrom ( gitRepo . Dir , mdYaml , entry . aliases , dirBlacklist , log ) if err != nil { return nil , fmt . Errorf ( " " , fullName , err ) } entry . sha = sha c . cache [ fullName ] = entry } } if c . skipCollaborators ( org , repo ) { log . Debugf ( " " , org , repo ) return entry . owners , nil } var owners * RepoOwners // Filter collaborators. We must filter the RepoOwners struct even if it came from the cache // because the list of collaborators could have changed without the git SHA changing. collaborators , err := c . ghc . ListCollaborators ( org , repo ) if err != nil { log . WithError ( err ) . Errorf ( " " ) owners = entry . owners } else { owners = entry . owners . filterCollaborators ( collaborators ) } return owners , nil }
// LoadRepoOwners returns an up-to-date RepoOwners struct for the specified repo.
// Note: The returned *RepoOwners should be treated as read only.
LoadRepoOwners returns an up - to - date RepoOwners struct for the specified repo . Note : The returned * RepoOwners should be treated as read only .