Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions cmd/repo/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"

"github.com/giantswarm/devctl/cmd/repo/find"
"github.com/giantswarm/devctl/cmd/repo/setup"
)

Expand Down Expand Up @@ -35,6 +36,20 @@ func New(config Config) (*cobra.Command, error) {

var err error

var findCmd *cobra.Command
{
c := find.Config{
Logger: config.Logger,
Stderr: config.Stderr,
Stdout: config.Stdout,
}

findCmd, err = find.New(c)
if err != nil {
return nil, microerror.Mask(err)
}
}

var setupCmd *cobra.Command
{
c := setup.Config{
Expand Down Expand Up @@ -67,6 +82,7 @@ func New(config Config) (*cobra.Command, error) {

f.Init(c)

c.AddCommand(findCmd)
c.AddCommand(setupCmd)

return c, nil
Expand Down
124 changes: 124 additions & 0 deletions cmd/repo/find/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Package find provides the 'repo find' command, which helps to discover
// GitHub repositories with certain features, or certain features missing.
package find

import (
"io"
"os"

"github.com/giantswarm/microerror"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

const (
name = "find"
description = `Find repositories based on very specific criteria

The --what flag allows to specify what search criteria should be used. When combining several critaria,
a repository will be returned when it's macthing at least one criteria (boolean OR).

Example:

devctl repo find --what NO_DESCRIPTION --must-have-codeowners

Note: archived repositories are always excluded.

Criteria:

DEFAULT_BRANCH_MASTER

The default branch is named 'master'. We want to rename these to 'main'.

HAS_DOCS_DIR

The repo has a directory named 'docs' on the root level. This is the place
where we want to store technical documentation for the repo.

HAS_PR_TEMPLATE_IN_DOCS

Has the file docs/pull_request_template.md, which is not the desired location.
We want this to be in .github/pull_request_template.md.

BAD_CODEOWNERS

Finds repositories with errors in CODEOWNERS files.

NO_CODEOWNERS

There is no CODEOWNERS file in the root folder, which means that the repository
has no owner. We want repos to have owners, ideally.

BAD_DEFAULT_BRANCH_PROTECTION_GO

The Go repo has no effective protection rules for the default branch.

NO_DEPENDABOT_ALERTS

Dependabot security alerts are disabled. Note: this is independent from
version updates via Dependabot.

NO_DEPENDENCY_GRAPH

Returns repos where the dependency graph feature is inactive. We want it to be
active.

NO_DESCRIPTION

Repository description is missing. We want a meaningful description to be present,
to understand easily what the repository is about, even from lists.

NO_README

Repository has no README.md file in the root folder. We want thjis to be present,
to have some basic info and documentation available.

README_OLD_CIRCLECI_BAGDE

There is an outdated (broken) CircleCI badge is present in the README. This should
better get replaced by an up-to-date one, as it can otherwise not fulfil its purpose,
and broken images never make a good impression.

README_OLD_GODOC_LINK

The README contains an outdated godoc.org link. Should be pkg.go.dev nowadays.
`
)

type Config struct {
Logger *logrus.Logger
Stderr io.Writer
Stdout io.Writer
}

func New(config Config) (*cobra.Command, error) {
if config.Logger == nil {
return nil, microerror.Maskf(invalidConfigError, "%T.Logger must not be empty", config)
}
if config.Stderr == nil {
config.Stderr = os.Stderr
}
if config.Stdout == nil {
config.Stdout = os.Stdout
}

f := &flag{}

r := &runner{
flag: f,
logger: config.Logger,
stderr: config.Stderr,
stdout: config.Stdout,
}

c := &cobra.Command{
Use: name,
Short: description,
Long: description,
RunE: r.Run,
}

f.Init(c)

return c, nil
}
30 changes: 30 additions & 0 deletions cmd/repo/find/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package find

import "github.com/giantswarm/microerror"

var invalidConfigError = &microerror.Error{
Kind: "invalidConfigError",
}

// IsInvalidConfig asserts invalidConfigError.
func IsInvalidConfig(err error) bool {
return microerror.Cause(err) == invalidConfigError
}

var invalidFlagError = &microerror.Error{
Kind: "invalidFlagError",
}

// IsInvalidFlag asserts invalidFlagError.
func IsInvalidFlag(err error) bool {
return microerror.Cause(err) == invalidFlagError
}

var envVarNotFoundError = &microerror.Error{
Kind: "envVarNotFoundError",
}

// IsEnvVarNotFound asserts envVarNotFoundError.
func IsEnvVarNotFound(err error) bool {
return microerror.Cause(err) == envVarNotFoundError
}
22 changes: 22 additions & 0 deletions cmd/repo/find/flag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package find

import "github.com/spf13/cobra"

type flag struct {
What []string
MustHaveCodeowners bool

IncludeArchived bool
IncludeFork bool
}

func (f *flag) Init(cmd *cobra.Command) {
cmd.PersistentFlags().BoolVar(&f.IncludeArchived, "include-archived", false, "Also return archived repositories.")
cmd.PersistentFlags().BoolVar(&f.IncludeFork, "include-fork", false, "Also return giantswarm forks of repositories.")
cmd.PersistentFlags().StringSliceVar(&f.What, "what", []string{}, "What repos to find. See full help for all available criteria.")
cmd.PersistentFlags().BoolVar(&f.MustHaveCodeowners, "must-have-codeowners", false, "Only return repositories that have CODEOWNERS.")
}

func (f *flag) Validate() error {
return nil
}
Loading