gogroup

package module
v0.0.0-...-d3d06dd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 2, 2023 License: MIT Imports: 10 Imported by: 0

README

gogroup

Check correctness of import groups in Go source, and fix files that have bad grouping.

Concept

Each project should choose a canonical import grouping. For example:

  • First standard imports
  • Then imports starting with "local/"
  • Finally third party imports.

Groups should be separated by empty lines, and within each group imports should be sorted.

So this is allowed:

// In a.go
import (
	"os"
	"testing"
	
	"local/bar"
	"local/foo"
	
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

But this is not, because of an extra empty line, and local/foo being out of position.

// In b.go
import (
	"os"
	
	"testing"
	
	"local/bar"
	
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
	"local/foo"
)

Installation

Either install by running go install github.com/vasi-stripe/gogroup/cmd/gogroup@latest (>= go 1.17), go get github.com/vasi-stripe/gogroup/cmd/gogroup (< go 1.17) or, if you have cloned the code, run go install ./... from the cloned dir.

Usage

Check which files validate this order:

bash$ gogroup -order std,prefix=local/,other a.go b.go
b.go:6: Extra empty line inside import group at "testing"
bash$ echo $?
3

Fixup files to match this order:

bash$ gogroup -order std,prefix=local/,other -rewrite a.go b.go
Fixed b.go.

Then check git diff, to ensure that nothing broke. Now b.go should look like a.go.

Support

The following import structures are currently supported:

  1. A single import declaration, without parens:

    // Optional comment
    import "foo"
    
  2. A single import declaration with parens:

    // Optional comment
    import (
      "something" // Optional comment
    
      // Optional comment
      "another/thing"
      "one/more/thing"
      name "import/with/name"
      . "dot/import"
    )
    

All of these allow doc comments and named imports.

TODO

  • Write tests, check coverage
  • Improve validation messages
  • Figure out what to do with different structures:
    • Multiple import declarations. Are these allowed? Do we merge these together?

      import (
      	"something"
      )
      import (
      	"another/thing"
      )
      
    • Spaces at start/end of import declaration. Get rid of them?

      import (
      
      	"something"
      
      )
      
    • Random comments. Are these allowed? If we move things around, where do these comments end up?

      import (
      	"something"
      
      	// Random comment in the middle.
      
      	// Normal doc comment, this is already ok.
      	"another/thing"
      	// Trailing comment.
      )
      
      // Comment in the middle of import declarations.
      
      // Normal doc comment, this is ok.
      import (
      	"something/else"
      )
      
    • import "C" statements. We should try hard to keep these separate from other imports.

      import (
      	"something"
      )
      
      // Random comment.
      
      // #cgo CFLAGS: -DPNG_DEBUG=1
      // #cgo amd64 386 CFLAGS: -DX86=1
      // #cgo LDFLAGS: -lpng
      // #include <png.h>
      import "C"
      
      import (
      	"another/thing"
      )
      

Documentation

Overview

Package gogroup helps to group import statements in Go files.

Unlike goimports, it does not maintain existing import statement groups. Instead, it allows defining a canonical order of import statements, and fixes up files to enforce this order.

Whatever order of import statements is used, the following rules are enforced:

- Import statements within the same group have no empty lines between them. - Between two groups is an empty line. - Within a group, statements are sorted by path.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Grouper

type Grouper interface {
	// Group determines the import group that an import statement should be in.
	//
	// The input is the package import path, eg: "os" or "github.com/example/repo".
	//
	// The output is the group number. If two import statements should be in the same
	// group, their group number should be identical. If an import statement should
	// be in a group after another import statement, its group number should be higher.
	// Otherwise, group numbers are arbitrary. Gaps between group numbers are explicitly
	// allowed.
	Group(pkgPath string) (group int)
}

A Grouper determines groupings of import statements.

type Processor

type Processor struct {
	// contains filtered or unexported fields
}

Processor processes files according to import grouping rules.

func NewProcessor

func NewProcessor(grouper Grouper) *Processor

NewProcessor creates a new Processor with a given group definition.

func (*Processor) Reformat

func (p *Processor) Reformat(fileName string, r io.Reader) (io.Reader, error)

Reformat both formats the file with goimports, and repairs any import groupings.

The fileName is necessary for determining missing imports.

func (*Processor) Repair

func (p *Processor) Repair(fileName string, r io.Reader) (io.Reader, error)

Repair repairs the import grouping of a source file.

If no repairs are necessary, a nil io.Reader will be returned. If repairs are needed, the new file content will be available in the returned io.Reader.

The fileName parameter is needed for error reporting only. You may leave it blank.

func (*Processor) Validate

func (p *Processor) Validate(fileName string, r io.Reader) (validErr *ValidationError, err error)

Validate determines whether the existing import grouping of a source file is correct, according to our grouping rules.

If the grouping is correct, Validate will return nil, nil. If an unexpected error occurs, Validate returns an error in err. Otherwise, if the grouping is incorrect, Validate returns an error in validErr.

The fileName parameter is needed for error reporting only. You may leave it blank.

type ValidationError

type ValidationError struct {
	// Line is the line of the file at which the error occurred.
	Line int
	// ImportPath is the path being imported.
	ImportPath string
	// Message is a description of why this was an error.
	Message string
}

ValidationError is an error about incorrect import grouping.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL