2024-08-04 19:44:50 +00:00
|
|
|
package github
|
2024-08-04 22:59:57 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
|
|
|
|
2024-08-14 02:55:18 +00:00
|
|
|
"github.com/badjware/gitforgefs/fstree"
|
2024-08-04 22:59:57 +00:00
|
|
|
"github.com/google/go-github/v63/github"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Organization struct {
|
|
|
|
ID int64
|
|
|
|
Name string
|
|
|
|
|
|
|
|
mux sync.Mutex
|
|
|
|
|
|
|
|
// hold org content
|
|
|
|
childRepositories map[string]fstree.RepositorySource
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Organization) GetGroupID() uint64 {
|
|
|
|
return uint64(o.ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *Organization) InvalidateContentCache() {
|
|
|
|
o.mux.Lock()
|
|
|
|
defer o.mux.Unlock()
|
|
|
|
|
|
|
|
// clear child repositories from cache
|
|
|
|
o.childRepositories = nil
|
|
|
|
}
|
|
|
|
|
2024-08-09 03:44:12 +00:00
|
|
|
func (c *githubClient) fetchOrganization(orgName string) (*Organization, error) {
|
2024-08-04 22:59:57 +00:00
|
|
|
c.organizationCacheMux.RLock()
|
2024-08-09 03:44:12 +00:00
|
|
|
cachedId, found := c.organizationNameToIDMap[orgName]
|
2024-08-04 22:59:57 +00:00
|
|
|
if found {
|
|
|
|
cachedOrg := c.organizationCache[cachedId]
|
|
|
|
c.organizationCacheMux.RUnlock()
|
|
|
|
|
|
|
|
// if found in cache, return the cached reference
|
2024-08-09 03:44:12 +00:00
|
|
|
c.logger.Debug("Organization cache hit", "org_name", orgName)
|
2024-08-04 22:59:57 +00:00
|
|
|
return cachedOrg, nil
|
|
|
|
} else {
|
|
|
|
c.organizationCacheMux.RUnlock()
|
|
|
|
|
2024-08-09 03:44:12 +00:00
|
|
|
c.logger.Debug("Organization cache miss", "org_name", orgName)
|
2024-08-04 22:59:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If not found in cache, fetch organization infos from API
|
2024-08-09 03:44:12 +00:00
|
|
|
githubOrg, _, err := c.client.Organizations.Get(context.Background(), orgName)
|
2024-08-04 22:59:57 +00:00
|
|
|
if err != nil {
|
2024-08-09 03:44:12 +00:00
|
|
|
return nil, fmt.Errorf("failed to fetch organization with name %v: %v", orgName, err)
|
2024-08-04 22:59:57 +00:00
|
|
|
}
|
|
|
|
newOrg := Organization{
|
|
|
|
ID: *githubOrg.ID,
|
|
|
|
Name: *githubOrg.Login,
|
|
|
|
|
|
|
|
childRepositories: nil,
|
|
|
|
}
|
|
|
|
|
|
|
|
// save in cache
|
|
|
|
c.organizationCacheMux.Lock()
|
|
|
|
c.organizationCache[newOrg.ID] = &newOrg
|
2024-08-05 01:00:34 +00:00
|
|
|
c.organizationNameToIDMap[newOrg.Name] = newOrg.ID
|
2024-08-04 22:59:57 +00:00
|
|
|
c.organizationCacheMux.Unlock()
|
|
|
|
|
|
|
|
return &newOrg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *githubClient) fetchOrganizationContent(org *Organization) (map[string]fstree.GroupSource, map[string]fstree.RepositorySource, error) {
|
|
|
|
org.mux.Lock()
|
|
|
|
defer org.mux.Unlock()
|
|
|
|
|
|
|
|
// Get cached data if available
|
|
|
|
// TODO: cache cache invalidation?
|
|
|
|
if org.childRepositories == nil {
|
|
|
|
childRepositories := make(map[string]fstree.RepositorySource)
|
|
|
|
|
|
|
|
// Fetch the organization repositories
|
|
|
|
repositoryListOpt := &github.RepositoryListByOrgOptions{
|
|
|
|
ListOptions: github.ListOptions{PerPage: 100},
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
githubRepositories, response, err := c.client.Repositories.ListByOrg(context.Background(), org.Name, repositoryListOpt)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("failed to fetch repository in github: %v", err)
|
|
|
|
}
|
|
|
|
for _, githubRepository := range githubRepositories {
|
|
|
|
repository := c.newRepositoryFromGithubRepository(githubRepository)
|
|
|
|
if repository != nil {
|
|
|
|
childRepositories[repository.Path] = repository
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if response.NextPage == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
// Get the next page
|
|
|
|
repositoryListOpt.Page = response.NextPage
|
|
|
|
}
|
|
|
|
|
|
|
|
org.childRepositories = childRepositories
|
|
|
|
}
|
|
|
|
return make(map[string]fstree.GroupSource), org.childRepositories, nil
|
|
|
|
}
|