Skip to content

Commit 7dd0084

Browse files
authored
feat(regup): add --server flag to regup command for targeted server updates (#757)
1 parent fcaf902 commit 7dd0084

File tree

2 files changed

+400
-39
lines changed

2 files changed

+400
-39
lines changed

cmd/regup/app/update.go

Lines changed: 99 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,33 @@ var (
2121
count int
2222
dryRun bool
2323
githubToken string
24+
serverName string
2425
)
2526

27+
type serverWithName struct {
28+
name string
29+
server *registry.Server
30+
}
31+
2632
var updateCmd = &cobra.Command{
2733
Use: "update",
2834
Short: "Update registry entries with latest information",
29-
Long: `Update the oldest entries in the registry with the latest GitHub stars and pulls information.`,
30-
RunE: updateCmdFunc,
35+
Long: `Update entries in the registry with the latest GitHub stars and pulls information.
36+
By default, updates the oldest entry. Use --count to update multiple oldest entries,
37+
or --server to update a specific server by name.`,
38+
RunE: updateCmdFunc,
3139
}
3240

3341
func init() {
3442
updateCmd.Flags().IntVarP(&count, "count", "c", 1, "Number of entries to update (default 1)")
3543
updateCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Perform a dry run without making changes")
3644
updateCmd.Flags().StringVarP(&githubToken, "github-token", "t", "",
3745
"GitHub token for API authentication (can also be set via GITHUB_TOKEN env var)")
46+
updateCmd.Flags().StringVarP(&serverName, "server", "s", "",
47+
"Specific server name to update")
48+
49+
// Mark count and server flags as mutually exclusive
50+
updateCmd.MarkFlagsMutuallyExclusive("count", "server")
3851
}
3952

4053
func updateCmdFunc(_ *cobra.Command, _ []string) error {
@@ -43,69 +56,112 @@ func updateCmdFunc(_ *cobra.Command, _ []string) error {
4356
githubToken = os.Getenv("GITHUB_TOKEN")
4457
}
4558

46-
// Read the registry file directly
59+
// Load registry
60+
reg, err := loadRegistry()
61+
if err != nil {
62+
return err
63+
}
64+
65+
// Select servers to update
66+
servers, err := selectServersToUpdate(reg)
67+
if err != nil {
68+
return err
69+
}
70+
71+
// Update servers
72+
updatedServers := updateServers(servers)
73+
74+
// Save results
75+
return saveResults(reg, updatedServers)
76+
}
77+
78+
func loadRegistry() (*registry.Registry, error) {
4779
registryPath := filepath.Join("pkg", "registry", "data", "registry.json")
4880
// #nosec G304 -- This is a known file path
4981
data, err := os.ReadFile(registryPath)
5082
if err != nil {
51-
return fmt.Errorf("failed to read registry file: %w", err)
83+
return nil, fmt.Errorf("failed to read registry file: %w", err)
5284
}
5385

54-
// Parse the registry
5586
var reg registry.Registry
5687
if err := json.Unmarshal(data, &reg); err != nil {
57-
return fmt.Errorf("failed to parse registry: %w", err)
88+
return nil, fmt.Errorf("failed to parse registry: %w", err)
89+
}
90+
91+
return &reg, nil
92+
}
93+
94+
func selectServersToUpdate(reg *registry.Registry) ([]serverWithName, error) {
95+
if serverName != "" {
96+
return selectSpecificServer(reg, serverName)
5897
}
5998

60-
// Create a slice of servers with their names
61-
type serverWithName struct {
62-
name string
63-
server *registry.Server
99+
return selectOldestServers(reg)
100+
}
101+
102+
func selectSpecificServer(reg *registry.Registry, name string) ([]serverWithName, error) {
103+
server, exists := reg.Servers[name]
104+
if !exists {
105+
return nil, fmt.Errorf("server '%s' not found in registry", name)
64106
}
107+
server.Name = name
108+
return []serverWithName{{name: name, server: server}}, nil
109+
}
110+
111+
func selectOldestServers(reg *registry.Registry) ([]serverWithName, error) {
65112
servers := make([]serverWithName, 0, len(reg.Servers))
66113
for name, server := range reg.Servers {
67-
// Set the name field on each server
68114
server.Name = name
69115
servers = append(servers, serverWithName{name: name, server: server})
70116
}
71117

72118
// Sort servers by last updated time (oldest first)
73119
sort.Slice(servers, func(i, j int) bool {
74-
var lastUpdatedI, lastUpdatedJ string
120+
return isOlder(servers[i].server, servers[j].server)
121+
})
75122

76-
// Handle nil metadata
77-
if servers[i].server.Metadata != nil {
78-
lastUpdatedI = servers[i].server.Metadata.LastUpdated
79-
}
80-
if servers[j].server.Metadata != nil {
81-
lastUpdatedJ = servers[j].server.Metadata.LastUpdated
82-
}
123+
// Limit to the requested count
124+
limit := count
125+
if limit > len(servers) {
126+
limit = len(servers)
127+
logger.Warnf("Requested count %d exceeds available servers, limiting to %d", count, len(servers))
128+
}
83129

84-
timeI, errI := time.Parse(time.RFC3339, lastUpdatedI)
85-
timeJ, errJ := time.Parse(time.RFC3339, lastUpdatedJ)
130+
return servers[:limit], nil
131+
}
86132

87-
// If we can't parse either time, put it at the beginning to ensure it gets updated
88-
if errI != nil {
89-
return true
90-
}
91-
if errJ != nil {
92-
return false
93-
}
133+
func isOlder(serverI, serverJ *registry.Server) bool {
134+
var lastUpdatedI, lastUpdatedJ string
94135

95-
return timeI.Before(timeJ)
96-
})
136+
if serverI.Metadata != nil {
137+
lastUpdatedI = serverI.Metadata.LastUpdated
138+
}
139+
if serverJ.Metadata != nil {
140+
lastUpdatedJ = serverJ.Metadata.LastUpdated
141+
}
97142

98-
// Limit to the requested count
99-
if count > len(servers) {
100-
count = len(servers)
101-
logger.Warnf("Requested count %d exceeds available servers, limiting to %d", count, len(servers))
143+
timeI, errI := time.Parse(time.RFC3339, lastUpdatedI)
144+
timeJ, errJ := time.Parse(time.RFC3339, lastUpdatedJ)
145+
146+
// If both times are invalid or missing, fall back to name comparison for stability
147+
if errI != nil && errJ != nil {
148+
return serverI.Name < serverJ.Name
149+
}
150+
// If only I is invalid, treat I as older
151+
if errI != nil {
152+
return true
102153
}
103-
servers = servers[:count]
154+
// If only J is invalid, treat J as older
155+
if errJ != nil {
156+
return false
157+
}
158+
159+
return timeI.Before(timeJ)
160+
}
104161

105-
// Keep track of updated servers
106-
updatedServers := make([]string, 0, count)
162+
func updateServers(servers []serverWithName) []string {
163+
updatedServers := make([]string, 0, len(servers))
107164

108-
// Update each server
109165
for _, s := range servers {
110166
logger.Infof("Updating server: %s", s.name)
111167

@@ -117,6 +173,10 @@ func updateCmdFunc(_ *cobra.Command, _ []string) error {
117173
updatedServers = append(updatedServers, s.name)
118174
}
119175

176+
return updatedServers
177+
}
178+
179+
func saveResults(reg *registry.Registry, updatedServers []string) error {
120180
// If we're in dry run mode, don't save changes
121181
if dryRun {
122182
logger.Info("Dry run completed, no changes made")
@@ -129,7 +189,7 @@ func updateCmdFunc(_ *cobra.Command, _ []string) error {
129189
reg.LastUpdated = time.Now().Format("2006-01-02 15:04:05")
130190

131191
// Save the updated registry
132-
if err := saveRegistry(&reg, updatedServers); err != nil {
192+
if err := saveRegistry(reg, updatedServers); err != nil {
133193
return fmt.Errorf("failed to save registry: %w", err)
134194
}
135195

0 commit comments

Comments
 (0)