• Stars
    star
    343
  • Rank 123,371 (Top 3 %)
  • Language
    Go
  • License
    Apache License 2.0
  • Created over 4 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Like `go get` but for Go tools! CI Automating versioning of Go binaries in a nested, isolated Go modules.

bingo

go.dev reference Latest Release CI Go Report Card Slack

go get like, simple CLI that allows automated versioning of Go package level binaries (e.g required as dev tools by your project!) built on top of Go Modules, allowing reproducible dev environments.

Demo

Features

From our experience all repositories and projects require some tools and binaries to be present on the machine to be able to perform various development operations like building, formatting, releasing or static analysis. For smooth development all such tools should be pinned to a certain version and bounded to the code commits there were meant to be used against.

Go modules does not aim to solve this problem, and even if they will do at some point it will not be on the package level, which makes it impossible to e.g pin minor version X.Y.0 of package module1/cmd/abc and version X.Z.0 of module1/cmd/def.

At the end bingo, has following features:

  • It allows maintaining separate, hidden, nested Go modules for Go buildable packages you need without obfuscating your own module or worrying with tool's cross dependencies!
  • Package level versioning, which allows versioning different (or the same!) package multiple times from a single module in different versions.
  • Works also for non-Go projects. It only requires the tools to be written in Go.
  • No need to install bingo in order to use pinned tools. This avoids the "chicken & egg" problem. You only need go build.
  • Easy upgrade, downgrade, addition, and removal of the needed binary's version, with no risk of dependency conflicts.
    • NOTE: Tools are often not following semantic versioning, so bingo allows to pin by commit ID.
  • Immutable binary names. This creates a reliable way for users and CIs to use expected version of the binaries, reinstalling on-demand only if needed.
  • Works with all buildable Go projects, including pre Go modules and complex projects with complex directives like replace, retract or exclude statements. (e.g Prometheus)
  • Optional, automatic integration with Makefiles.

You can read full a story behind bingo in this blog post.

Requirements

  • Go 1.17+
  • Linux or MacOS (Want Windows support? Helps us out)
  • All tools that you wish to "pin" have to be built in Go (they don't need to use Go modules at all).

Installing

In your repository (does not need to be a Go project)

go install github.com/bwplotka/bingo@latest

For go version before 1.17 use go get github.com/bwplotka/bingo instead.

Recommended: Ideally you want to pin bingo tool to the single version too (inception!). Do it via:

bingo get -l github.com/bwplotka/bingo

Usage

go get but for binaries!

The key idea is that you can manage your tools similar to your Go dependencies via go get:

bingo get [<package or binary>[@version1 or none,version2,version3...]]

For example:

After this, make sure to commit .bingo directory in git repository, so the tools will stay versioned! Once pinned, anyone can install correct version of the tool with correct dependencies by either doing:

bingo get <tool>

For example bingo get faillint

... or without bingo:

go build -mod=mod -modfile .bingo/<tool>.mod -o=$GOBIN/<tool>-<version>

For example go build -mod=mod -modfile .bingo/faillint.mod -o=$GOBIN/faillint-v1.5.0

bingo allows to easily maintain a separate, nested Go Module for each binary. By default, it will keep it .bingo/<tool>.mod This allows to correctly pin the binary without polluting the main go module or other's tool module.

Using Installed Tools

bingo get builds pinned tool or tools in your $GOBIN path. Binaries have a name following <provided-tool-name>-<version> pattern. So after installation you can do:

  • From shell:
${GOBIN}/<tool>-<version> <args>

For example: ${GOBIN}/faillint-v1.5.0

While it's not the easiest for humans to read or type, it's essential to ensure your scripts use pinned version instead of some non-deterministic "latest version".

NOTE: If you use -l option, bingo creates symlink to . Use it with care as it's easy to have side effects by having another binary with same name e.g on CI.

bingo does not have run command (for a reason), it provides useful helper variables for script or adhoc use:

NOTE: Below helpers makes it super easy to install or use pinned binaries without even installing bingo (it will use just go build!) 💖

  • From shell:
source .bingo/variables.env
${<PROVIDED_TOOL_NAME>} <args>
  • From Makefile:
include .bingo/Variables.mk
run:
	$(<PROVIDED_TOOL_NAME>) <args>

Real life examples!

Let's show a few, real, sometimes novel examples showcasing bingo capabilities:

  1. golangci-lint is all-in-one lint framework. It's important to pin it on CI so CI runs are reproducible no matter what new linters are added, removed or changed in new release. Let's pin it to v1.35.2 and use path recommended by https://golangci-lint.run/usage/install/#install-from-source doc: github.com/golangci/golangci-lint/cmd/golangci-lint (funny enough they discourage go get exactly because of the lack of pinning features bingo have!)

    bingo get github.com/golangci/golangci-lint/cmd/[email protected]

    This will pin to that commit and install ${GOBIN}/golangci-lint-v1.35.2

  2. It's very common in Go world to use goimports, popular gofmt replacement which formats Go code including imports. However, not many know that it's breaking compatibility a lot between versions (there are no releases). If you want to assert certain formatting of the Go code in the CI etc your only option is to pin goimports version. You can do it via bingo get:

    bingo get golang.org/x/tools/cmd/goimports@latest

    This will install (at the time of writing) latest binary: ${GOBIN}/goimports-v0.0.0-20210112230658-8b4aab62c064

  3. You rather like older formatting? No issue, let's downgrade. Since goimports was already installed you can reference it by just goimports. Let's pick the commit we want e.g e64124511800702a4d8d79e04cf6f1af32e7bef2:

    bingo get goimports@e64124511800702a4d8d79e04cf6f1af32e7bef2

    This will pin to that commit and install ${GOBIN}/goimports-v0.0.0-20200519204825-e64124511800

  4. Installing (and pinning) multiple versions:

    bingo get goimports@e64124511800702a4d8d79e04cf6f1af32e7bef2,v0.0.0-20200601175630-2caf76543d99,af9456bb636557bdc2b14301a9d48500fdecc053

    This will pin and install three versions of goimports. Very useful to compatibility testing.

  5. Updating to the current latest:

    bingo get goimports@latest

    This will find the latest module version, pin and install it.

  6. Listing binaries you have pinned:

    bingo list
  7. Unpinning goimports totally from the project:

    bingo get goimports@none

    PS: go get also allows @none suffix! Did you know? I didn't (:*

  8. Installing all tools:

    bingo get
  9. Bonus: Have you ever dreamed to pin command from bigger project like... thanos? I was. Can you even install it using Go tooling? Let's try:

    go get github.com/thanos-io/thanos/cmd/[email protected]
    # Output: go: cannot use path@version syntax in GOPATH mode

    Ups you cannot use this in non-Go project at all... (: Let's create setup go mod and retry:

    go mod init _
    # Output: go: creating new go.mod: module 
    go get github.com/thanos-io/thanos/cmd/[email protected]
    # go get github.com/thanos-io/thanos/cmd/[email protected]
    # go: downloading github.com/thanos-io/thanos v0.17.2
    # go: found github.com/thanos-io/thanos/cmd/thanos in github.com/thanos-io/thanos v0.17.2
    # go get: github.com/thanos-io/[email protected] requires
    # github.com/cortexproject/[email protected] requires
    # github.com/thanos-io/[email protected] requires
    # github.com/cortexproject/[email protected] requires
    # github.com/thanos-io/[email protected] requires
    # github.com/cortexproject/[email protected] requires
    # github.com/thanos-io/[email protected] requires
    # github.com/cortexproject/[email protected] requires
    # github.com/thanos-io/[email protected] requires
    # github.com/cortexproject/[email protected] requires
    # github.com/prometheus/[email protected] requires
    # github.com/prometheus/[email protected] requires
    # k8s.io/[email protected]+incompatible: reading https://proxy.golang.org/k8s.io/client-go/@v/v12.0.0+incompatible.mod: 410 Gone
    # server response: not found: k8s.io/[email protected]+incompatible: invalid version: +incompatible suffix not allowed: module contains a go.mod file, so semantic import versioning is required

    The reasoning is complex but TL;DR: Go Modules are just sometimes hard to be properly used for some projects. This is why bigger projects like Kubernetes, Prometheus or Thanos has to use replace statements (plus others like exclude or retract). To make this go get work we would need to manually craft replace statements in our own go mod file. But what if we don't want to do that or don't know how or simply we want to install pinned version of Thanos locally without having Go project? Just use bingo:

    bingo get github.com/thanos-io/thanos/cmd/[email protected]
    ${GOBIN}/thanos-v0.17.2 --help

Advanced Techniques

  • Using advanced go build flags and environment variables.

To tell bingo to use certain env vars and tags during build time, just add them as a comment to the go.mod file manually and do bingo get. Done!

NOTE: Order of comment matters. First bingo expects relative package name (optional), then environment variables, then flags. All space delimited.

Real example from production project that relies on extended Hugo.

module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT

go 1.16

require github.com/gohugoio/hugo v0.83.1 // CGO_ENABLED=1 -tags=extended

Run bingo list to see if build options are parsed correctly. Run bingo get to install all binaries including the modified one with new build flags.

Production Usage

To see production example see:

Contributing

Any contributions are welcome! Just use GitHub Issues and Pull Requests as usual. We follow Thanos Go coding style guide.

See an extensive and up-to-date description of the bingo usage below:

Command Help

bingo: 'go get' like, simple CLI that allows automated versioning of 
Go package level binaries (e.g required as dev tools by your project!) 

built on top of Go Modules, allowing reproducible dev environments. 
'bingo' allows to easily maintain a separate, nested Go Module for each binary. 

For detailed examples and documentation see: https://github.com/bwplotka/bingo

Usage:
  bingo [command]

Commands:
  completion  Generate the autocompletion script for the specified shell
  get         add development tools to the current project (e.g: bingo get github.com/fatih/faillint@latest)
  list        List enumerates all or one binary that are/is currently pinned in this project. 
  version     Prints bingo Version.

Options:
  -h, --help            help for bingo
  -m, --moddir string   Directory where separate modules for each binary will be maintained. 
                        Feel free to commit this directory to your VCS to bond binary versions to your project code. 
                        If the directory does not exist bingo logs and assumes a fresh project. (default ".bingo")
  -v, --verbose         Print more

Use "bingo [command] --help" for more information about a command.

Initial Author

@bwplotka inspired by Paul's research and with a bit of help from Duco (:

More Repositories

1

mimic

mimic: Define your Deployments, Infrastructure and Configuration as a Go Code 🚀
Go
238
star
2

mdox

Format your docs; autogenerate from flags or Go structs or even generate versioned website directly from markdown!
Go
67
star
3

unity-grpc

gRPC lib ported to support .Net 3.5 (unity 4+) with Tutorial and example
C#
46
star
4

demo-nav

Lightweight shell library for smooth, interactive demos using terminal.
Shell
40
star
5

efficiency-coding-advent

Go
30
star
6

tracing-go

Pragmatic and minimalistic module for collecting and sending traces from Go code 💪🏽
Go
24
star
7

flagarize

Flagarize your Go struct to initialize your even complex struct from flags! 🚀
Go
13
star
8

promeval

Test your Prometheus configuration locally before rollout! (:
Go
10
star
9

my

Personal website with Hugo, KeepIt theme and some automation! (:
HTML
8
star
10

oidc

Golang Open ID Connect (OIDC) client library.
Go
8
star
11

correlator

Small HTTP Service enabling smart correlations between cloud-native data.
Go
7
star
12

go-httpt

Awesome, quick golang HTTP client mocking! ✨
Go
5
star
13

go-httplog

Robust, smart logger for Golang http handlers
Go
5
star
14

remote-write-hole

Effiecient binary for analysing and benchmarking Prometheus Remote Write clients.
4
star
15

kubelet-bench

Example Go-based e2e benchmark for various Kubelet operations without spinning up whole K8s cluster.
Go
3
star
16

go-jwt

Golang JSON Web Token builder with easy to use API for JWS and nested JWT (JWS+JWE)
Go
3
star
17

serenity-formula

Salt formulas and scripts for deployment Mesos with Serenity (also under DCOS)
SaltStack
3
star
18

prombenchy

The simplistic and experimental alternative to beloved Prombench tool for benchmarking Prometheus based systems on Kubernetes.
Shell
3
star
19

mesos-modules-dev

Improved docker for building mesos modules. Tested as a base for building Serenity.
2
star
20

go-tokenauth

Bunch of useful token based auth sources!
Go
2
star
21

docker-mesos-clion

Develop Apache Mesos via Clion in docker environment!
Shell
2
star
22

serenity-pypeline

Python pipeline for serenity
Python
1
star
23

edge-detector-gpgu

Edge detector - implemented in MPI and OpenCL for academic project.
C
1
star
24

pwave

Simple & smart header-only library for signal generation.
C++
1
star
25

go-ipfilter

Tiny Golang lib for IP filtering. (e.g private only)
Go
1
star
26

go-proto-bench

Decode/Encode Benchmarks for Various OSS Go Protocol buffers (proto) Generators
Go
1
star
27

obs-example-app

Example Go application showing integrations with the state of the art CNCF observability signals
1
star
28

prom-source-http

Simple dynamic file content serving HTTP server.
Go
1
star
29

killertutorials

1
star
30

docker-dev-intellij

Docker image for IntelliJ IDEA Community + GO with GO building/development/testing environment.
Shell
1
star
31

launchpad-blueprint-collector

Collect needed Launchpad blueprints into casual .csv and manage them via Excel!
Python
1
star
32

w3-graph

Walrus graph visualization using WebGL via THREE.js lib.
JavaScript
1
star