Skip to content

Commit

Permalink
Fix lints across codebase, as enforced via golangci-lint config
Browse files Browse the repository at this point in the history
  • Loading branch information
tom--pollard committed Apr 30, 2021
1 parent 87f77af commit 8b2ae40
Show file tree
Hide file tree
Showing 25 changed files with 260 additions and 122 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15

- name: Run tests
run: go test -v ./...

Expand Down
28 changes: 18 additions & 10 deletions cmd/scheduled-feed/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import (
"strings"
"time"

"github.com/robfig/cron"
log "github.com/sirupsen/logrus"

"github.com/ossf/package-feeds/config"
"github.com/ossf/package-feeds/feeds/scheduler"
"github.com/ossf/package-feeds/publisher"

"github.com/robfig/cron"
log "github.com/sirupsen/logrus"
)

// FeedHandler is a handler that fetches new packages from various feeds
// FeedHandler is a handler that fetches new packages from various feeds.
type FeedHandler struct {
scheduler *scheduler.Scheduler
pub publisher.Publisher
Expand Down Expand Up @@ -56,7 +56,10 @@ func (handler *FeedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Error(w, "error polling for packages - see logs for more information", http.StatusInternalServerError)
return
}
w.Write([]byte(fmt.Sprintf("%d packages processed", processed)))
_, err := w.Write([]byte(fmt.Sprintf("%d packages processed", processed)))
if err != nil {
http.Error(w, "unexpected error during http server write: %w", http.StatusInternalServerError)
}
}

func main() {
Expand Down Expand Up @@ -88,7 +91,7 @@ func main() {
}
sched := scheduler.New(feeds)

log.Printf("listening on port %v", appConfig.HttpPort)
log.Printf("listening on port %v", appConfig.HTTPPort)
delta, err := time.ParseDuration(appConfig.CutoffDelta)
if err != nil {
log.Fatal(err)
Expand All @@ -103,22 +106,27 @@ func main() {
cronjob := cron.New()
crontab := fmt.Sprintf("@every %s", delta.String())
log.Printf("Running a timer %s", crontab)
cronjob.AddFunc(crontab, func() { cronrequest(appConfig.HttpPort) })
err := cronjob.AddFunc(crontab, func() { cronRequest(appConfig.HTTPPort) })
if err != nil {
log.Fatal(err)
}
cronjob.Start()
}

http.Handle("/", handler)
if err := http.ListenAndServe(fmt.Sprintf(":%v", appConfig.HttpPort), nil); err != nil {
if err := http.ListenAndServe(fmt.Sprintf(":%v", appConfig.HTTPPort), nil); err != nil {
log.Fatal(err)
}
}

func cronrequest(port int) {
func cronRequest(port int) {
client := &http.Client{
Timeout: 10 * time.Second,
}
_, err := client.Get(fmt.Sprintf("http://localhost:%v", port))
resp, err := client.Get(fmt.Sprintf("http://localhost:%v", port))
if err != nil {
log.Printf("http request failed: %v", err)
return
}
resp.Body.Close()
}
43 changes: 25 additions & 18 deletions config/scheduledfeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ package config
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strconv"

"github.com/mitchellh/mapstructure"
"gopkg.in/yaml.v3"

"github.com/ossf/package-feeds/feeds"
"github.com/ossf/package-feeds/feeds/crates"
"github.com/ossf/package-feeds/feeds/goproxy"
Expand All @@ -21,12 +25,14 @@ import (
"github.com/ossf/package-feeds/publisher/gcppubsub"
"github.com/ossf/package-feeds/publisher/kafkapubsub"
"github.com/ossf/package-feeds/publisher/stdout"
"gopkg.in/yaml.v3"
)

"github.com/mitchellh/mapstructure"
var (
errUnknownFeed = errors.New("unknown feed type")
errUnknownPub = errors.New("unknown publisher type")
)

// Loads a ScheduledFeedConfig struct from a yaml config file
// Loads a ScheduledFeedConfig struct from a yaml config file.
func FromFile(configPath string) (*ScheduledFeedConfig, error) {
data, err := ioutil.ReadFile(configPath)
if err != nil {
Expand All @@ -36,11 +42,11 @@ func FromFile(configPath string) (*ScheduledFeedConfig, error) {
return NewConfigFromBytes(data)
}

// Loads a ScheduledFeedConfig struct from a yaml bytes
func NewConfigFromBytes(bytes []byte) (*ScheduledFeedConfig, error) {
// Loads a ScheduledFeedConfig struct from a yaml bytes.
func NewConfigFromBytes(yamlBytes []byte) (*ScheduledFeedConfig, error) {
config := Default()

err := unmarshalStrict(bytes, config)
err := unmarshalStrict(yamlBytes, config)
if err != nil {
return nil, err
}
Expand All @@ -49,7 +55,7 @@ func NewConfigFromBytes(bytes []byte) (*ScheduledFeedConfig, error) {
return config, nil
}

// Applies environment variables to the configuration
// Applies environment variables to the configuration.
func (config *ScheduledFeedConfig) applyEnvVars() {
// Support legacy env var definition for gcp pub sub.
pubURL := os.Getenv("OSSMALWARE_TOPIC_URL")
Expand All @@ -66,19 +72,20 @@ func (config *ScheduledFeedConfig) applyEnvVars() {
port, err := strconv.Atoi(portStr)

if portProvided && err == nil {
config.HttpPort = port
config.HTTPPort = port
}
}

func AddTo(ls *[]int, value int) {
*ls = append(*ls, value)
}

// Constructs a map of ScheduledFeeds to enable based on the EnabledFeeds provided from configuration, indexed by the feed type.
func (sConfig *ScheduledFeedConfig) GetScheduledFeeds() (map[string]feeds.ScheduledFeed, error) {
// Constructs a map of ScheduledFeeds to enable based on the EnabledFeeds provided
// from configuration, indexed by the feed type.
func (config *ScheduledFeedConfig) GetScheduledFeeds() (map[string]feeds.ScheduledFeed, error) {
var err error
scheduledFeeds := map[string]feeds.ScheduledFeed{}
for _, entry := range sConfig.EnabledFeeds {
for _, entry := range config.EnabledFeeds {
switch entry {
case crates.FeedName:
scheduledFeeds[entry] = crates.Feed{}
Expand All @@ -95,7 +102,7 @@ func (sConfig *ScheduledFeedConfig) GetScheduledFeeds() (map[string]feeds.Schedu
case rubygems.FeedName:
scheduledFeeds[entry] = rubygems.Feed{}
default:
err = fmt.Errorf("unknown feed type %v", entry)
err = fmt.Errorf("%w : %v", errUnknownFeed, entry)
}
}

Expand All @@ -112,14 +119,14 @@ func (pc PublisherConfig) ToPublisher(ctx context.Context) (publisher.Publisher,
var err error
switch pc.Type {
case gcppubsub.PublisherType:
var gcpConfig gcppubsub.GCPPubSubConfig
var gcpConfig gcppubsub.Config
err = strictDecode(pc.Config, &gcpConfig)
if err != nil {
return nil, fmt.Errorf("failed to decode gcppubsub config: %w", err)
}
return gcppubsub.FromConfig(ctx, gcpConfig)
case kafkapubsub.PublisherType:
var kafkaConfig kafkapubsub.KafkaPubSubConfig
var kafkaConfig kafkapubsub.Config
err = strictDecode(pc.Config, &kafkaConfig)
if err != nil {
return nil, fmt.Errorf("failed to decode kafkapubsub config: %w", err)
Expand All @@ -128,14 +135,14 @@ func (pc PublisherConfig) ToPublisher(ctx context.Context) (publisher.Publisher,
case stdout.PublisherType:
return stdout.New(), nil
default:
err = fmt.Errorf("unknown publisher type %v", pc.Type)
err = fmt.Errorf("%w : %v", errUnknownPub, pc.Type)
}
return nil, err
}

// Decode an input using mapstruct decoder with strictness enabled, errors will be returned in
// the case of unused fields.
func strictDecode(input interface{}, out interface{}) error {
func strictDecode(input, out interface{}) error {
strictDecoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
ErrorUnused: true,
Result: out,
Expand All @@ -160,7 +167,7 @@ func Default() *ScheduledFeedConfig {
PubConfig: PublisherConfig{
Type: stdout.PublisherType,
},
HttpPort: 8080,
HTTPPort: 8080,
CutoffDelta: "5m",
Timer: false,
}
Expand All @@ -173,7 +180,7 @@ func Default() *ScheduledFeedConfig {
func unmarshalStrict(data []byte, out interface{}) error {
dec := yaml.NewDecoder(bytes.NewReader(data))
dec.KnownFields(true)
if err := dec.Decode(out); err != nil && err != io.EOF {
if err := dec.Decode(out); err != nil && !errors.Is(err, io.EOF) {
return err
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion config/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package config
type ScheduledFeedConfig struct {
PubConfig PublisherConfig `yaml:"publisher"`
EnabledFeeds []string `yaml:"enabled_feeds"`
HttpPort int `yaml:"http_port,omitempty"`
HTTPPort int `yaml:"http_port,omitempty"`
CutoffDelta string `yaml:"cutoff_delta"`
Timer bool `yaml:"timer"`
}
Expand Down
9 changes: 4 additions & 5 deletions feeds/crates/crates.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type crates struct {
JustUpdated []*Package `json:"just_updated"`
}

// Package stores the information from crates.io updates
// Package stores the information from crates.io updates.
type Package struct {
ID string `json:"id"`
Name string `json:"name"`
Expand All @@ -33,7 +33,7 @@ type Package struct {
Repository string `json:"repository"`
}

// Gets crates.io packages
// Gets crates.io packages.
func fetchPackages() ([]*Package, error) {
resp, err := httpClient.Get(baseURL)
if err != nil {
Expand All @@ -46,12 +46,11 @@ func fetchPackages() ([]*Package, error) {
if err != nil {
return nil, err
}
// TODO: We should check both the NewCrates as well
// TODO: We should check both the NewCrates as well.
return v.JustUpdated, nil
}

type Feed struct {
}
type Feed struct{}

func (feed Feed) Latest(cutoff time.Time) ([]*feeds.Package, error) {
pkgs := []*feeds.Package{}
Expand Down
10 changes: 6 additions & 4 deletions feeds/crates/crates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ import (
func TestCratesLatest(t *testing.T) {
t.Parallel()

handlers := map[string]testutils.HttpHandlerFunc{
handlers := map[string]testutils.HTTPHandlerFunc{
"/api/v1/summary": cratesSummaryResponse,
}
srv := testutils.HttpServerMock(handlers)
srv := testutils.HTTPServerMock(handlers)

baseURL = srv.URL + "/api/v1/summary"
feed := Feed{}

cutoff := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
pkgs, err := feed.Latest(cutoff)

if err != nil {
t.Fatalf("feed.Latest returned error: %v", err)
}
Expand All @@ -47,7 +46,7 @@ func TestCratesLatest(t *testing.T) {
}

func cratesSummaryResponse(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte(`
_, err := w.Write([]byte(`
{
"just_updated": [
{
Expand Down Expand Up @@ -109,4 +108,7 @@ func cratesSummaryResponse(w http.ResponseWriter, r *http.Request) {
]
}
`))
if err != nil {
http.Error(w, testutils.UnexpectedWriteError(err), http.StatusInternalServerError)
}
}
7 changes: 5 additions & 2 deletions feeds/feed.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package feeds

import (
"errors"
"fmt"
"time"

Expand All @@ -9,11 +10,13 @@ import (

const schemaVer = "1.0"

var errCutoff = errors.New("package was created before cutoff time")

type ScheduledFeed interface {
Latest(cutoff time.Time) ([]*Package, error)
}

// Marshalled json output validated against package.schema.json
// Marshalled json output validated against package.schema.json.
type Package struct {
Name string `json:"name"`
Version string `json:"version"`
Expand All @@ -24,7 +27,7 @@ type Package struct {

func NewPackage(created, cutoff time.Time, name, version, feed string) (*Package, error) {
if created.Before(cutoff) {
return nil, fmt.Errorf("package was created before cutoff time: %s", cutoff.String())
return nil, fmt.Errorf("%w : %s", errCutoff, cutoff.String())
}
log.WithFields(log.Fields{
"feed": feed,
Expand Down
12 changes: 4 additions & 8 deletions feeds/feed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import (
"github.com/xeipuuv/gojsonschema"
)

const schema_path = "../package.schema.json"
const schemaPath = "../package.schema.json"

type extendPackage struct {
*Package
NonConformingField string `json:"non_conforming_field"`
}

var (
schemaLoader = gojsonschema.NewReferenceLoader("file://" + schema_path)
schemaLoader = gojsonschema.NewReferenceLoader("file://" + schemaPath)
dummyPackage = &Package{
Name: "foobarpackage",
Version: "1.0.0",
Expand All @@ -31,7 +31,6 @@ func TestValidSchema(t *testing.T) {

validPackage := gojsonschema.NewGoLoader(dummyPackage)
result, err := gojsonschema.Validate(schemaLoader, validPackage)

if err != nil {
panic(err.Error())
}
Expand All @@ -51,10 +50,9 @@ func TestInvalidSchema(t *testing.T) {
// The Schema defines that additional properties are not valid, ensure enforcement
// against an extra struct field. If an extra field is added, the SchemVer minor should
// be incremented to advertise an additive change.
invalid_package := &extendPackage{dummyPackage, "extrafield"}
invalidField := gojsonschema.NewGoLoader(invalid_package)
invalidPackage := &extendPackage{dummyPackage, "extrafield"}
invalidField := gojsonschema.NewGoLoader(invalidPackage)
result, err := gojsonschema.Validate(schemaLoader, invalidField)

if err != nil {
panic(err.Error())
}
Expand All @@ -68,13 +66,11 @@ func TestInvalidSchema(t *testing.T) {
dummyPackage.SchemaVer = ""
invalidFormat := gojsonschema.NewGoLoader(dummyPackage)
result, err = gojsonschema.Validate(schemaLoader, invalidFormat)

if err != nil {
panic(err.Error())
}

if result.Valid() {
t.Fatalf("Non-conformant field format incorrectly validated")
}

}
Loading

0 comments on commit 8b2ae40

Please sign in to comment.