blob: f4d7d5f40b4c8a49acce7e7969ac7a194648d44c [file] [log] [blame]
// 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 (
"cmp"
"context"
"fmt"
"slices"
"golang.org/x/exp/maps"
"golang.org/x/tools/txtar"
"golang.org/x/vulndb/cmd/vulnreport/log"
"golang.org/x/vulndb/internal/issues"
"gopkg.in/yaml.v3"
)
type issueClient interface {
Issues(context.Context, issues.IssuesOptions) ([]*issues.Issue, error)
Issue(context.Context, int) (*issues.Issue, error)
SetLabels(context.Context, int, []string) error
AddComments(context.Context, int, []string) error
Reference(int) string
}
var _ issueClient = &memIC{}
type memIC struct {
is map[int]issues.Issue
}
func newMemIC(archive []byte) (*memIC, error) {
ar := txtar.Parse(archive)
m := &memIC{
is: make(map[int]issues.Issue),
}
for _, f := range ar.Files {
var iss issues.Issue
if err := yaml.Unmarshal(f.Data, &iss); err != nil {
return nil, err
}
m.is[iss.Number] = iss
}
return m, nil
}
func (m *memIC) Issue(_ context.Context, n int) (*issues.Issue, error) {
if i, ok := m.is[n]; ok {
return &i, nil
}
return nil, fmt.Errorf("issue %d not found", n)
}
func (m *memIC) Issues(_ context.Context, opts issues.IssuesOptions) (result []*issues.Issue, err error) {
if len(opts.Labels) != 0 {
return nil, fmt.Errorf("label option not supported for in-memory issues client")
}
all := maps.Values(m.is)
slices.SortFunc(all, func(a, b issues.Issue) int { return cmp.Compare(a.Number, b.Number) })
for _, i := range all {
i := i
if opts.State != "" && opts.State != i.State {
continue
}
result = append(result, &i)
}
return result, nil
}
// TODO(tatianabradley): Write the modified issues to the test golden file.
func (m *memIC) SetLabels(_ context.Context, n int, labels []string) error {
if iss, ok := m.is[n]; ok {
iss.Labels = labels
m.is[n] = iss
return nil
}
return fmt.Errorf("issue %d not found", n)
}
func (m *memIC) AddComments(_ context.Context, n int, comments []string) error {
if iss, ok := m.is[n]; ok {
for _, comment := range comments {
// TODO(tatianabradley): Store this instead of just printing it out.
log.Outf("posted comment to issue %d: %s", iss.Number, comment)
}
return nil
}
return fmt.Errorf("issue %d not found", n)
}
func (*memIC) Reference(n int) string {
return fmt.Sprintf("test-issue-tracker/%d", n)
}