Report unwanted import path and declaration usages

faillint

Faillint is a simple Go linter that fails when a specific set of import paths or exported path's functions, constant, vars or types are used. It's meant to be used in CI/CD environments to catch rules you want to enforce in your projects.

As an example, you could enforce the usage of github.com/pkg/errors instead of the errors package. To prevent the usage of the errors package, you can configure faillint to fail whenever someone imports the errors package in this case. To make sure fmt.Errorf is not used for creating errors as well, you can configure to fail on such single function of fmt as well.

faillint

Install

go install github.com/fatih/faillint@latest

Example

Assume we have the following file:

package a

import (
        "errors"
)

func foo() error {
        return errors.New("bar!")
}

Let's run faillint to check if errors import is used and report it:

$ faillint -paths "errors=github.com/pkg/errors" a.go
a.go:4:2: package "errors" shouldn't be imported, suggested: "github.com/pkg/errors"

Usage

faillint works on a file, directory or a Go package:

$ faillint -paths "errors,fmt.{Errorf}" foo.go # pass a file
$ faillint -paths "errors,fmt.{Errorf}" ./...  # recursively analyze all files
$ faillint -paths "errors,fmt.{Errorf}" github.com/fatih/gomodifytags # or pass a package

By default, faillint will not check any import paths. You need to explicitly define it with the -paths flag, which is comma-separated list. Some examples are:

# Fail if the errors package is used.
-paths "errors"

# Fail if the old context package is imported.
-paths "golang.org/x/net/context"

# Fail both on stdlib log and errors package to enforce other internal libraries.
-paths "log,errors"

# Fail if any of Print, Printf of Println function were used from fmt library.
-paths "fmt.{Print,Printf,Println}"

# Fail if the package is imported including sub paths starting with
  "golang.org/x/net/". In example: `golang.org/x/net/context`, 
  `golang.org/x/net/nettest`, .nettest`, ...
-paths "golang.org/x/net/..."

If you have a preferred import path to suggest, append the suggestion after a = character:

# Fail if the errors package is used and suggest to use github.com/pkg/errors.
-paths "errors=github.com/pkg/errors"

# Fail for the old context import path and suggest to use the stdlib context.
-paths "golang.org/x/net/context=context"

# Fail both on stdlib log and errors package to enforce other libraries.
-paths "log=go.uber.org/zap,errors=github.com/pkg/errors"

# Fail on fmt.Errorf and suggest the Errorf function from github.compkg/errors instead.
-paths "fmt.{Errorf}=github.com/pkg/errors.{Errorf}"

Ignoring problems

If you want to ignore a problem reported by faillint you can add a lint directive based on staticcheck's design.

Line-based lint directives

Line-based lint directives can be applied to imports or functions you want to tolerate. The format is,

//lint:ignore faillint reason

For example,

package a

import (
        //lint:ignore faillint Whatever your reason is.
        "errors"
        "fmt" //lint:ignore faillint Whatever your reason is.
)

func foo() error {
        //lint:ignore faillint Whatever your reason is.
        return errors.New("bar!")
}

File-based lint directives

File-based lint directives can be applied to ignore faillint problems in a whole file. The format is,

//lint:file-ignore faillint reason

This may be placed anywhere in the file but conventionally it should be placed at, or near, the top of the file.

For example,

//lint:file-ignore faillint This file should be ignored by faillint.

package a

import (
        "errors"
)

func foo() error {
        return errors.New("bar!")
}

The need for this tool?

Most of these checks should be probably detected during the review cycle. But it's totally normal to accidentally import them (we're all humans in the end).

Second, tools like goimports favors certain packages. As an example going forward if you decided to use github.com/pkg/errors in you project, and write errors.New() in a new file, goimports will automatically import the errors package (and not github.com/pkg/errors). The code will perfectly compile. faillint would be able to detect and report it to you.

Credits

This tool is built on top of the excellent go/analysis package that makes it easy to write custom analyzers in Go. If you're interested in writing a tool, check out my Using go/analysis to write a custom linter blog post.

Part of the code is modified and based on astutil.UsesImport

Owner
Fatih Arslan
Software Engineer. Gopher and Coffee geek. Creator of vim-go. Tool maker.
Fatih Arslan
Comments
  • Added support for unwanted function; added more tests.

    Added support for unwanted function; added more tests.

    Fixes: https://github.com/fatih/faillint/issues/7

    Changes

    • No more globals :heart:
    • Separate tests for parsing (as it gets a bit more complex now) and tests.
    • Add some test edge cases for imports as well (e.g named imports).
    • Fixes some edge cases like whitespaces etc.
    • Support for unwanted functions with {Func1,Func2} notion.
  • Add failing for certain methods in a given package (i.e: fmt.Errorf)

    Add failing for certain methods in a given package (i.e: fmt.Errorf)

    Currently faillint only fails on package level (based on the import path). We should also make it possible to fail for a sub-set of exported functions, types or variables (i.e: ast.TypeSpec and ast.ValueSpec should be enough).

    Why is this useful? Let's look at this example:

    If a user opted to use github.com/pkg/errors not only want they prevent the usage of errors package, they probably also want to avoid using fmt.Errorf and start using errors.Errorf method from the github.com/pkg/errors package. There are many reasons for that. For example the github.com/pkg/errors package includes stack information in each error value. Hence they want to make sure all errors are created with the github.com/pkg/errors package.

    We could still use the paths flags and could define the sub-set with a dot identifier. For example the following command could fail for all usages of errors and the usage of fmt.Errorf:

    faillint --paths "errors,fmt.Errorf"
    

    If anyone wants to work on this, please comment on the PR before starting on it. I'll work on that at some point otherwise.

  • Comment imports to tolerate exceptions

    Comment imports to tolerate exceptions

    Imagine wanting to avoid a package but, in practice, needing to be able to tolerate exceptions to it (while using faillint in a CI pipeline). Much like many linting tools I wonder if the import could be annotated like,

    import (
        "github.com/gogo/protobuf/proto" // faillint: gogo is tolerated here because XYZ.
    )
    

    So if we had -path "github.com/gogo/protobuf/proto=github.com/golang/protobuf/proto" but faillint saw a // faillint: annotation it would suppress its objection (and if no objections exit zero).

  • package imported without types errors when using with Go 1.18

    package imported without types errors when using with Go 1.18

    When using this tool with Go 1.18, I'm seeing errors like

    faillint: internal error: package "time" without types was imported from "github.com/github/my-project-repo/constants"
    

    This might be fixed by bumping golang.org/x/tools to a newer version

  • [Feature Request] Support excluding packages

    [Feature Request] Support excluding packages

    It would be nice to have a flag to exclude a package from a scan.

    Example

    faillint -paths google.golang.org/grpc/status ./pkg/... -exclude ./pkg/server/...
    

    instead of having to do

    faillint -paths google.golang.org/grpc/status ./pkg/log/... ./pkg/metrics/... ./pkg/internal/... # and so on and so forth
    
  • Upgrade `golang.org/x/tools` to latest version to get a bug fix

    Upgrade `golang.org/x/tools` to latest version to get a bug fix

    Signed-off-by: Alvin Lin [email protected]

    After upgrading to Go 1.19, I started to get this error: Unexpected package creation during export data loading.

    Googling around I found this. So I thought I'd upgrade golang.org/x/tools to latest version to see if it fixes my issue, and it did.

  • Bump `golang.org/x/tools` version to latest

    Bump `golang.org/x/tools` version to latest

    This PR fixes constant overflow errors which occur when faillint loads any go1.17 module that has statements assigning math.MaxFloat64 to any float64 variables (see #24 and here), by bumping golang.org/x/tools to latest release (v0.1.8).

  • Error

    Error "could not import C" when using CGO

    if I run this target without build it fails with the error in the title. https://github.com/arribada/i360/blob/master/Makefile#L108

    Here is a github action. https://github.com/arribada/i360/runs/1800460336?check_suite_focus=true

    When I add build as a prerequisite for this target it works fine.

  • Analyse go files with buildtags

    Analyse go files with buildtags

    We have some tests with a buildtag // +build requires_docker at the beginning of the file and I've just realised these files are skipped by faillint and I can't find a way to specify build tags (I also checked a bit the source code). Is there any way to get it working on source files with build tags?

  • Add support to path prefixes

    Add support to path prefixes

    We have some use cases where we would like to blacklist an import path prefix so that all import packages belonging to that prefix are blacklisted as well. Would be of any interest to add such feature to the project?

  • Skip generated files.

    Skip generated files.

    Hey :wave:

    Any ideas on how to deal with generated files? How can we easily ignore those without many faillint invocations?

    /home/bwplotka/Repos/thanos/pkg/store/storepb/types.pb.go:18:13: declaration "Errorf" from package "fmt" shouldn't be used, suggested: "github.com/pkg/errors.{Errorf}"

    I tried find . -type f -name "*.go" | grep -v vendor/ | grep -vE '*.pb.go' | xargs $(FAILLINT) -paths $(FAILLINT_PATHS) but got:

    -: named files must all be in one directory; have ./test/e2e/ and ./test/e2e/e2ethanos/
    faillint: error during loading
    
  • Add ability to lint only test/benchmark/fuzz functions

    Add ability to lint only test/benchmark/fuzz functions

    Thank you for this tool! I have a use case where I want to ban time.Sleep from test functions to avoid flaky tests. Instead of time.Sleep with a hard-coded timeout, I want to push others to use functions that would retry some operations continuously until some deadline. For that, faillint should be able to operate only on Test*, Benchmark*, and Fuzz* functions. What do you think? Would you be open to adding such an option?

  • Possibility to detect function from a struct

    Possibility to detect function from a struct

    I'd like a way to block github.com/jmoiron/sqlx, struct DB, function Select, Exec, Must*

    • Must* functions are dangerous in a service context (assuming you don't have recover middleware)
    • Select, Exec, and a few others don't take a context, we need to use *Context( for cancellation aware versions.

    The issue is that these aren't top level functions or vars, but are nested inside an *sqlx.DB.

    Wanted expression:

    github.com/jmoiron/sqlx.DB.{Select,Exec,Must*}
    
  • Dot imports

    Dot imports

    I'd like to forbid dot imports on some projects, could faillint catch package aliases or explicitly . with -paths?

    e.g.

    import (
       . "github.com/pkg/errors"
    )
    
import csv into existing table postgresql or cockroachdb

import csv into existing table postgresql or cockroachdb

Nov 1, 2021
In one particular project, i had to import some key/value data to Prometheus. So i have decided to create my custom-built Node Exporter in Golang.
In one particular project, i had to import some key/value data to Prometheus. So i have decided to create my custom-built Node Exporter in Golang.

In one particular project, i had to import some key/value data to Prometheus. So i have decided to create my custom-built Node Exporter in Golang.

May 19, 2022
Quickly collect data from thousands of exposed Elasticsearch or Kibana instances and generate a report to be reviewed.
Quickly collect data from thousands of exposed Elasticsearch or Kibana instances and generate a report to be reviewed.

elasticpwn Quickly collects data from exposed Elasticsearch or Kibana instances and generates a report to be reviewed. It mainly aims for sensitive da

Nov 9, 2022
Auto daily report for HITSZ Students.

auto-report Auto daily report for HITSZ Students. Usage Report Once Golang go run main.go -u your-studentID -p your-password -e your-email Docker dock

Aug 25, 2022
:runner:runs go generate recursively on a specified path or environment variable and can filter by regex

Package generate Package generate runs go generate recursively on a specified path or environment variable like $GOPATH and can filter by regex Why wo

Sep 27, 2022
[TOOL, CLI] - Filter and examine Go type structures, interfaces and their transitive dependencies and relationships. Export structural types as TypeScript value object or bare type representations.

typex Examine Go types and their transitive dependencies. Export results as TypeScript value objects (or types) declaration. Installation go get -u gi

Dec 6, 2022
:chart_with_upwards_trend: Monitors Go MemStats + System stats such as Memory, Swap and CPU and sends via UDP anywhere you want for logging etc...

Package stats Package stats allows for gathering of statistics regarding your Go application and system it is running on and sent them via UDP to a se

Nov 10, 2022
James is your butler and helps you to create, build, debug, test and run your Go projects
James is your butler and helps you to create, build, debug, test and run your Go projects

go-james James is your butler and helps you to create, build, debug, test and run your Go projects. When you often create new apps using Go, it quickl

Oct 8, 2022
GoThanks automatically stars Go's official repository and your go.mod github dependencies, providing a simple way to say thanks to the maintainers of the modules you use and the contributors of Go itself.
GoThanks automatically stars Go's official repository and your go.mod github dependencies, providing a simple way  to say thanks to the maintainers of the modules you use and the contributors of Go itself.

Give thanks (in the form of a GitHub ★) to your fellow Go modules maintainers. About GoThanks performs the following operations Sends a star to Go's r

Dec 24, 2022
A simple Cron library for go that can execute closures or functions at varying intervals, from once a second to once a year on a specific date and time. Primarily for web applications and long running daemons.

Cron.go This is a simple library to handle scheduled tasks. Tasks can be run in a minimum delay of once a second--for which Cron isn't actually design

Dec 17, 2022
Library to work with MimeHeaders and another mime types. Library support wildcards and parameters.

Mime header Motivation This library created to help people to parse media type data, like headers, and store and match it. The main features of the li

Nov 9, 2022
The new home of the CUE language! Validate and define text-based and dynamic configuration

The CUE Data Constraint Language Configure, Unify, Execute CUE is an open source data constraint language which aims to simplify tasks involving defin

Dec 31, 2022
Hack this repo and add your name to the list above. Creativity and style encouraged in both endeavors.

Hack this repo and add your name to the list above. Creativity and style encouraged in both endeavors.

Oct 1, 2021
A comprehensive training, nutrition, and social platform for martial artists and combat sport athletes

COMHRAC Comhrac (Gaelic for "Combat") is a comprehensive training, nutrition, and social platform for martial artists and combat sport athletes. Devel

Oct 17, 2021
Purpose: dump slack messages, users and files using browser token and cookie.

Slack Dumper Purpose: dump slack messages, users and files using browser token and cookie. Typical usecase scenarios: You want to archive your private

Jan 2, 2023
Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app.
Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app.

Package buildinfo provides basic building blocks and instructions to easily add build and release information to your app. This is done by replacing variables in main during build with ldflags.

Nov 14, 2021
Phalanx is a cloud-native full-text search and indexing server written in Go built on top of Bluge that provides endpoints through gRPC and traditional RESTful API.

Phalanx Phalanx is a cloud-native full-text search and indexing server written in Go built on top of Bluge that provides endpoints through gRPC and tr

Dec 25, 2022
Highly extensible, customizable application launcher and window switcher written in less than 300 lines of Golang and fyne
Highly extensible, customizable application launcher and window switcher written in less than 300 lines of Golang and fyne

golauncher A go application launcher A simple, highly extensible, customizable application launcher and window switcher written in less than 300 lines

Aug 21, 2022
Go package and associated command line utility to generate random yet human-readable names and identifiers
Go package and associated command line utility to generate random yet human-readable names and identifiers

namegen | What's this? Go package and associated command line utility to generate random yet human-readable names and identifiers. Somewhat inspired b

Oct 19, 2022