apicompat checks recent changes to a Go project for backwards incompatible changes

Introduction

Build Status Coverage Status GoDoc

apicompat is a tool to check for the introduction of backwards incompatible changes.

apicompat:

  • Guarantees that all consumers of a library will still build without failure
  • Only checks exported declarations
  • There are no false positives (if there are, it's a bug)
  • Not every backwards incompatible change can be detected, swapping argument parameters and other changes still need to be considered by the library author
  • Can be simply consumed as a library
  • Is in its infancy, see Status, feedback and review appreciated
  • Was originally named abicheck during early development

Secondary tasks could include:

  • Detecting current semver and suggesting an appropriate increase
  • Listing all changes for help in writing release notes/commit messages.

Try at abicheck.bradleyf.id.au or via CLI:

go get -u github.com/bradleyfalzon/apicompat/cmd/apicompat
cd /your/project/dir/with/committed/changes
apicompat

Proposed Arguments

apicompat also comes with a command line tool, as well as being used as a library, the following are the proposed flags and arguments for the command line tool.

-vcs    (auto|git|svn|etc) - Version control system to use (default: auto)
-before revision           - Revisions to check as before  (default: if unstaged changes, check those, else check last two commits)
-after  revision           - Revisions to check as after   (default: if unstaged changes, check those, else check last two commits)
-vcsDir path               - Path to root VCS directory    (default: let VCS tool search)
-all                       - Show non-breaking changes as well as breaking (default: false)

apicompat        # current package only
apicompat ./...  # check subdirectory packages

Another tool, called abichanges may also be included which will list all detected changes to assist in producing release notes.

Status

apicompat is currently under heavy development and refactoring. This initial version was a proof of concept and shortcuts were taken. The current tasks are focused on (but not limited to):

  • Adding Mercurial, SVN and potentially other VCS systems
  • Improve VCS options such as:
    • Detection of VCS and flag to overwrite
    • Choosing base VCS path to allow running for a different directory
    • Filtering vendor/ directories (if this is the best place to do it, or leave it to go/type ast packages)
    • Check subdirectories if ran from a subdirectory of the VCS (currently checks all committed code)
  • Add docs, flow diagram and fixing of existing docs
  • Improve output formats (such as vim quickfix)
  • Move these tasks to GitHub issues
  • Once all other steps have been completed, performance will be investigated

Testing

This uses golden masters for the tests, currently (and only due to time constraints) testdata/ directory contains before.go and after.go, which are before and after versions of a test package, each time go test is ran, the output is compared to testdata/exp.txt, which should not change.

If adding new test cases, you should expect the test to fail as the code changes should create a difference with exp.txt. Then, you'll need to update the golden master (see below), and commit those changes. If you add a new test case to before.go and after.go, and the tests still pass, you've uncovered a bug within apicompat which will need a code change to fix, once code has change, the tests should fail, so update the master, review all your changes and commit.

  • This uses golden master testdata/exp.txt for the tests
  • Run tests with: go test
  • Update master with: go test -args update
  • Alternatively to do a test run: go install && ( cd testgit; ./make.sh && apicompat )
Comments
  • Optimise parse phase for any performance gain

    Optimise parse phase for any performance gain

    abicheck is two phase, the first phase determines all the exported declarations (once for the before version, and once again for the after version), the second phase compares all the .

    The first phase runs in parallel now, but the second phase does not.

  • fix #24

    fix #24

    :) bar$ apicompat 
    HEAD:github.com/hydroflame/foo/bar/b.go:3: breaking change declaration removed
        type T struct{}
    
    :) bar$ apicompat ./...
    HEAD:github.com/hydroflame/foo/bar/b.go:3: breaking change declaration removed
        type T struct{}
    
    :) bar$ apicompat ../...
    HEAD:github.com/hydroflame/foo/bar/b.go:3: breaking change declaration removed
        type T struct{}
    
    :) bar$ cd && apicompat github.com/hydroflame/foo/...
    HEAD:github.com/hydroflame/foo/bar/b.go:3: breaking change declaration removed
        type T struct{}
    
    :) ~$ cd && apicompat github.com/hydroflame/foo/bar
    HEAD:github.com/hydroflame/foo/bar/b.go:3: breaking change declaration removed
        type T struct{}
    

    package github.com/hydroflame/foo/bar is a random package containing a single change since it's last commit, and it seems to be detected every possible way now

  • apicompat not picking up subpackages on Travis CI

    apicompat not picking up subpackages on Travis CI

    I'm attempting to use apicompat on TravisCI. For some reason apicompat is not able to pickup the subpackages within the project directory.

    Example: https://travis-ci.org/lionelbarrow/braintree-go/jobs/248235954

  • Go Dependency Management Discussion

    Go Dependency Management Discussion

    Hello! I was reading a blog post at https://blog.gopheracademy.com/advent-2016/saga-go-dependency-management/ about the tool that a group of devs, "Vendor Committee" have been working on for Go to solve the issues, and they explicitly called out for a tool:

    A tool that can statically analyze a project and suggest the next SemVer tag to use for the next release

    I was wondering if you @bradleyfalzon wouldn't mind if I put forward this tool as a starting point perhaps for that?

  • Func parameter inferred types detected as a breaking change

    Func parameter inferred types detected as a breaking change

    The following is not a breaking change:

    go1.5:ftoa.go:50: breaking change parameter types changed
            func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte
            func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte
    
  • Fix import paths not including the full path

    Fix import paths not including the full path

    Currently the packages are keyed by name, not import path. So there's collisions between something like html/template and text/template (just as an example, the stdlib packages don't have this issue).

  • Check changes in build constraints

    Check changes in build constraints

    Investigate check if the package has introduced or increased build constraints, such as // +build go1.5.

    I've never used them myself, are they per file? Per package? Is it something that can be checked.

  • Revise cmd/apicompat output format and exit codes.

    Revise cmd/apicompat output format and exit codes.

    Remove extra newline between changes, the apicompat.Change already formats each change with a trailing newline, and whether that's correct or not, it's simpler the leave that behaviour as is.

    The exit codes were inconsistent as well, now, if there's an internal error the exit status will 1, if there's a breaking change it will be 2, else it will be 0.

    Fixes #34.

  • git exec error in Travis CI environment

    git exec error in Travis CI environment

    I run this in my travis-ci script section:

    test -z "$(apicompat -before master -after HEAD ./... | tee /dev/stderr)"
    

    it gives error:

    apicompat: go/build error: could not execute git [--git-dir /home/travis/gopath/src/github.com/ahmetalpbalkan/go-linq/.git ls-tree master ./], error: exit status 128
    

    Any ideas what this error might be about?

    I also tried this:

    test -z "$(apicompat -before ${TRAVIS_COMMIT_RANGE%...*} -after ${TRAVIS_COMMIT_RANGE#*...} ./... | tee /dev/stderr)"
    

    it gives the same error. I think the apicompat can do better here by preserving the error output from the executed git command (perhaps by passing it down its own stdout/stderr).

  • Exit code when there is breaking changes?

    Exit code when there is breaking changes?

    It looks like apicompat currently returns exit code 0 when there is a breaking change:

    $ apicompat -before master -after HEAD; echo $?
    master:intersect.go:72: breaking change declaration removed
    	func (q Query) IntersectByT(q2 Query, selectorFn interface{}) Query
    
    0
    

    Is this by design? Making it exit with non-zero code would help the CI scripts which make use of exit codes a great deal.

    Also it looks like there's an empty line (\n\n) at the end of the command (before 0). Is that also by design?

  • Ignore internal packages

    Ignore internal packages

    https://docs.google.com/document/d/1e8kOo3r51b2BWtTs_1uADIA5djfXhPT36s6eHVRIvaU/edit

    These aren't exported and should be ignored.

    Similar to vendor path in #22

  • import path not found

    import path not found

    When I try to run this against a project using Go111Modules I just get an error:

    $ apicompat
    import path not found
    

    I'm guessing this doesn't support Go111Modules yet?

  • error comparing declarations: missing ',' in parameter list

    error comparing declarations: missing ',' in parameter list

    This is not a critical issue for me; reporting it for your benefit only. You should prioritize accordingly.

    I noticed the following unexpected error in GopherCI (https://gci.gopherci.io/analysis/1198) from apicompat:

    $ apicompat -before 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3 ./...
    error comparing declarations: 2:77: missing ',' in parameter list parsing: package expr
    type ExternalService interface{MarkRead(ctx context.Context, repo github.com/shurcooL/notifications.RepoSpec, threadType string, threadID uint64) error; Notify(ctx context.Context, repo github.com/shurcooL/notifications.RepoSpec, threadType string, threadID uint64, nr github.com/shurcooL/notifications.NotificationRequest) error; Subscribe(ctx context.Context, repo github.com/shurcooL/notifications.RepoSpec, threadType string, threadID uint64, subscribers []github.com/shurcooL/users.UserSpec) error}
         0  *ast.GenDecl {
         1  .  TokPos: -
         2  .  Tok: type
         3  .  Lparen: -
         4  .  Specs: []ast.Spec (len = 1) {
         5  .  .  0: *ast.TypeSpec {
         6  .  .  .  Name: *ast.Ident {
         7  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:13:6
         8  .  .  .  .  Name: "Service"
         9  .  .  .  .  Obj: *ast.Object {
        10  .  .  .  .  .  Kind: type
        11  .  .  .  .  .  Name: "Service"
        12  .  .  .  .  .  Decl: *(obj @ 5)
        13  .  .  .  .  }
        14  .  .  .  }
        15  .  .  .  Assign: -
        16  .  .  .  Type: *ast.InterfaceType {
        17  .  .  .  .  Interface: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:13:14
        18  .  .  .  .  Methods: *ast.FieldList {
        19  .  .  .  .  .  Opening: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:13:24
        20  .  .  .  .  .  List: []*ast.Field (len = 4) {
        21  .  .  .  .  .  .  0: *ast.Field {
        22  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
        23  .  .  .  .  .  .  .  .  0: *ast.Ident {
        24  .  .  .  .  .  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:2
        25  .  .  .  .  .  .  .  .  .  Name: "List"
        26  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
        27  .  .  .  .  .  .  .  .  .  .  Kind: func
        28  .  .  .  .  .  .  .  .  .  .  Name: "List"
        29  .  .  .  .  .  .  .  .  .  .  Decl: *(obj @ 21)
        30  .  .  .  .  .  .  .  .  .  }
        31  .  .  .  .  .  .  .  .  }
        32  .  .  .  .  .  .  .  }
        33  .  .  .  .  .  .  .  Type: *ast.FuncType {
        34  .  .  .  .  .  .  .  .  Func: -
        35  .  .  .  .  .  .  .  .  Params: *ast.FieldList {
        36  .  .  .  .  .  .  .  .  .  Opening: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:6
        37  .  .  .  .  .  .  .  .  .  List: []*ast.Field (len = 2) {
        38  .  .  .  .  .  .  .  .  .  .  0: *ast.Field {
        39  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
        40  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Ident {
        41  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:7
        42  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "ctx"
        43  .  .  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
        44  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Kind: var
        45  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "ctx"
        46  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *ast.Field {
        47  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
        48  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  0: *(obj @ 40)
        49  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        50  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *ast.SelectorExpr {
        51  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  X: *ast.Ident {
        52  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:11
        53  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "context"
        54  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        55  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Sel: *ast.Ident {
        56  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:19
        57  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "Context"
        58  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        59  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        60  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        61  .  .  .  .  .  .  .  .  .  .  .  .  .  }
        62  .  .  .  .  .  .  .  .  .  .  .  .  }
        63  .  .  .  .  .  .  .  .  .  .  .  }
        64  .  .  .  .  .  .  .  .  .  .  .  Type: *(obj @ 50)
        65  .  .  .  .  .  .  .  .  .  .  }
        66  .  .  .  .  .  .  .  .  .  .  1: *ast.Field {
        67  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
        68  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Ident {
        69  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: 5a67cc840e31516e2b2e1ab0b839ecb628ec56b9~3:notifications.go:16:28
        70  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "opt"
        71  .  .  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
        72  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Kind: var
        73  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "opt"
        74  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *ast.Field {
        75  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
        76  .  .  .  .  .  .  .  .  .  .  .  .  .  .  . ...237791 bytes suppressed....  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: HEAD:notifications.go:87:2
      1340  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "HTMLURL"
      1341  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Obj: *ast.Object {
      1342  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Kind: var
      1343  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "HTMLURL"
      1344  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Decl: *ast.Field {
      1345  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Names: []*ast.Ident (len = 1) {
      1346  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  0: *(obj @ 1338)
      1347  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1348  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *ast.Ident {
      1349  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: HEAD:notifications.go:87:12
      1350  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "string"
      1351  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1352  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1353  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1354  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1355  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1356  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *(obj @ 1348)
      1357  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1358  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1359  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Closing: HEAD:notifications.go:88:1
      1360  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1361  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Incomplete: false
      1362  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1363  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1364  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1365  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1366  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1367  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1368  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1369  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1370  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *(obj @ 1194)
      1371  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1372  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1373  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Closing: HEAD:notifications.go:44:103
      1374  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1375  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Results: *ast.FieldList {
      1376  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Opening: -
      1377  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  List: []*ast.Field (len = 1) {
      1378  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  0: *ast.Field {
      1379  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Type: *ast.Ident {
      1380  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  NamePos: HEAD:notifications.go:44:105
      1381  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Name: "error"
      1382  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1383  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1384  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1385  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Closing: -
      1386  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1387  .  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1388  .  .  .  .  .  .  .  .  .  .  .  .  .  }
      1389  .  .  .  .  .  .  .  .  .  .  .  .  }
      1390  .  .  .  .  .  .  .  .  .  .  .  .  Closing: HEAD:notifications.go:45:1
      1391  .  .  .  .  .  .  .  .  .  .  .  }
      1392  .  .  .  .  .  .  .  .  .  .  .  Incomplete: false
      1393  .  .  .  .  .  .  .  .  .  .  }
      1394  .  .  .  .  .  .  .  .  .  }
      1395  .  .  .  .  .  .  .  .  }
      1396  .  .  .  .  .  .  .  }
      1397  .  .  .  .  .  .  }
      1398  .  .  .  .  .  }
      1399  .  .  .  .  .  Closing: HEAD:notifications.go:26:1
      1400  .  .  .  .  }
      1401  .  .  .  .  Incomplete: false
      1402  .  .  .  }
      1403  .  .  }
      1404  .  }
      1405  .  Rparen: -
      1406  }
    

    The code compiles without errors. I'm not sure what this is. It might be related to alias support (#27), but it doesn't look that way. notifications.ExternalService is a pretty simple interface.

    I can provide additional information if needed, just ask.

  • Support default GOPATH

    Support default GOPATH

    There's a few cases were we've assumed GOPATH is set in the env, this may no longer be true when go moves to a default go path: https://github.com/golang/go/issues/17262#issuecomment-255880927

    Check some locations, such as: https://github.com/bradleyfalzon/apicompat/blob/7fa1f07f7a414ebdedb155a64e6eaeed61769585/apicompat.go#L146 https://github.com/bradleyfalzon/apicompat/blob/7fa1f07f7a414ebdedb155a64e6eaeed61769585/apicompat.go#L193

  • Monitor Alias Experiment

    Monitor Alias Experiment

    This may have far reaching consequences, or may not at all.

    There's at least appears to be added ast.AliasSpec.

    See CLs related to https://github.com/golang/go/issues/16339

  • Consider dropping import path support

    Consider dropping import path support

    It's not possible to determine ahead of time which VCS path for a given import path without adding more code.

    It maybe simpler to not support checking import paths, and instead, only check the local directory and it's sub directories.

errcheck checks that you checked errors.

errcheck errcheck is a program for checking for unchecked errors in go programs. Install go get -u github.com/kisielk/errcheck errcheck requires Go 1

Jan 1, 2023
This is a style verifier intended to be used with the Gerrit checks plugin.

GERRITFMT This is a style verifier intended to be used with the Gerrit checks plugin. HOW TO USE Install formatters: go install github.com/bazelbuild/

Dec 29, 2022
Fast division, modulus and divisibility checks in Go for divisors known only at runtime.

fastdiv Fast division, modulus and divisibility checks for divisors known only at runtime via the method of: "Faster Remainder by Direct Computation:

Jan 8, 2023
The Golang linter that checks that there is no simultaneous return of `nil` error and an invalid value.

nilnil Checks that there is no simultaneous return of nil error and an invalid value. Installation & usage $ go install github.com/Antonboom/nilnil@la

Dec 14, 2022
Go linter which checks for dangerous unicode character sequences

bidichk - checks for dangerous unicode character sequences bidichk finds dangerous unicode character sequences in Go source files. Considered dangerou

Oct 5, 2022
nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

nostdglobals is a simple Go linter that checks for usages of global variables defined in the go standard library

Feb 17, 2022
dont-interface calculates how many interface{} are declared or used in your project?

dont-interface calculates how many interface{} are declared or used in your project?

Jun 9, 2022
list or create gitlab project level variables for gitops

intro gitlab ci requires some env variables, for diffent projects these env vars may be same. so we have this cmd tool -- gitlab-vars install simplely

Dec 1, 2021
Bridge REMOV will allow you to safely transfer NFT from RMRK to MOVR and backwards

remov Inspiration Our aim is to expand the capabilities of blockchain and make a secure way for transferring NFT between RMRK and MOVR blockchain. The

Dec 5, 2021
archy is an static binary to determine current kernel and machine architecture, with backwards compatible flags to uname, and offers alternative output format of Go runtime (i.e. GOOS, GOARCH).

archy archy is an simple binary to determine current kernel and machine architecture, which wraps uname and alternatively can read from Go runtime std

Mar 18, 2022
Go linter that checks types that are json encoded - reports unsupported types and unnecessary error checks

Checks types passed to the json encoding functions. Reports unsupported types and reports occations, where the check for the returned error can be omited.

Oct 7, 2022
preflight helps you verify scripts and executables to mitigate chain of supply attacks such as the recent Codecov hack.
preflight helps you verify scripts and executables to mitigate chain of supply attacks such as the recent Codecov hack.

?? Mitigate chain of supply attacks ?? Verify your curl scripts and executables ?? What is it? preflight helps you verify scripts and executables to m

Nov 18, 2022
Shows your recent browser history in tree style. 树状展示浏览器历史 (For Edge / Chromium / Chrome)
Shows your recent browser history in tree style. 树状展示浏览器历史  (For Edge / Chromium / Chrome)

Tree Style Histyle This extension shows your recent browser history in tree style. When you browser pages from internet, you always jump from one page

Jan 3, 2023
ChangeTower is intended to help you watch changes in webpages and get notified of any changes written in Go

ChangeTower is intended to help you watch changes in webpages and get notified of any changes written in Go

Nov 17, 2022
Builds and restarts a Go project when it crashes or some watched file changes
Builds and restarts a Go project when it crashes or some watched file changes

gaper Used to build and restart a Go project when it crashes or some watched file changes Aimed to be used in development only. Changelog See Releases

Dec 30, 2022
Library for enabling asynchronous health checks in your service

go-health A library that enables async dependency health checking for services running on an orchestrated container platform such as kubernetes or mes

Jan 4, 2023