| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "context" |
| "fmt" |
| "strconv" |
| "strings" |
| |
| "golang.org/x/vulndb/internal/issues" |
| ) |
| |
| // issueParser implements the "parseArgs" function of the command |
| // interface, and can be used by commands that operate on Github issues. |
| type issueParser struct { |
| ic issueClient |
| toProcess map[string]*issues.Issue |
| open []*issues.Issue |
| } |
| |
| const issueStateOpen = "open" |
| |
| func (*issueParser) inputType() string { |
| return "issue" |
| } |
| |
| func (ip *issueParser) openIssues(ctx context.Context) ([]*issues.Issue, error) { |
| if ip.open == nil { |
| open, err := ip.ic.Issues(ctx, issues.IssuesOptions{State: issueStateOpen}) |
| if err != nil { |
| return nil, err |
| } |
| ip.open = open |
| } |
| return ip.open, nil |
| } |
| |
| func (ip *issueParser) parseArgs(ctx context.Context, args []string) (issNums []string, _ error) { |
| if len(args) > 0 { |
| return argsToIDs(args) |
| } |
| |
| // If no arguments are provided, operate on all open issues. |
| open, err := ip.openIssues(ctx) |
| if err != nil { |
| return nil, err |
| } |
| |
| for _, iss := range open { |
| n := strconv.Itoa(iss.Number) |
| ip.toProcess[n] = iss |
| issNums = append(issNums, n) |
| } |
| |
| return issNums, nil |
| } |
| |
| func (ip *issueParser) setup(ctx context.Context, env environment) error { |
| ic, err := env.IssueClient(ctx) |
| if err != nil { |
| return err |
| } |
| ip.ic = ic |
| ip.toProcess = make(map[string]*issues.Issue) |
| return nil |
| } |
| |
| func (ip *issueParser) lookup(ctx context.Context, issNum string) (any, error) { |
| iss, ok := ip.toProcess[issNum] |
| if !ok { |
| n, err := strconv.Atoi(issNum) |
| if err != nil { |
| return nil, err |
| } |
| iss, err := ip.ic.Issue(ctx, n) |
| if err != nil { |
| return nil, err |
| } |
| ip.toProcess[issNum] = iss |
| return iss, nil |
| } |
| |
| return iss, nil |
| } |
| |
| func argsToIDs(args []string) ([]string, error) { |
| var githubIDs []string |
| parseGithubID := func(s string) (int, error) { |
| id, err := strconv.Atoi(s) |
| if err != nil { |
| return 0, fmt.Errorf("invalid GitHub issue ID: %q", s) |
| } |
| return id, nil |
| } |
| for _, arg := range args { |
| if !strings.Contains(arg, "-") { |
| _, err := parseGithubID(arg) |
| if err != nil { |
| return nil, err |
| } |
| githubIDs = append(githubIDs, arg) |
| continue |
| } |
| from, to, _ := strings.Cut(arg, "-") |
| fromID, err := parseGithubID(from) |
| if err != nil { |
| return nil, err |
| } |
| toID, err := parseGithubID(to) |
| if err != nil { |
| return nil, err |
| } |
| if fromID > toID { |
| return nil, fmt.Errorf("%v > %v", fromID, toID) |
| } |
| for id := fromID; id <= toID; id++ { |
| githubIDs = append(githubIDs, strconv.Itoa(id)) |
| } |
| } |
| return githubIDs, nil |
| } |