name: inverse layout: true class: center, middle, inverse --- name: normarl layout: true --- template: inverse # pre-commit-go (in 6 minutes or less) .footnote[[github.com/maruel/pre-commit-go](https://github.com/maruel/pre-commit-go)] --- template: normal # Genesis - Want to run tests all the time because I'm a lousy coder - Good at Design but make lots of typos - I'm also impatient so I want it to be *smart* and *fast* - `pcg` is quick to type --- template: normal # Goals .center[ ## Fast ## Correct ## Versatile ## Simple ## Safe ] --- template: normal # Dependency DAG analysis ``` $GOPATH/src/github.com/$USER/foo/ - cmd/foo - pkg/a - pkg/b - pkg/c - pkg/d - pkg/e ``` You touch `pkg/b/doc.go`. What is tested? --- template: normal # Dependency DAG analysis ``` $GOPATH/src/github.com/$USER/foo/ - cmd/foo imports pkg/a and pkg/e - pkg/a imports pkg/b - pkg/b imports pkg/c and pkg/e - pkg/c imports pkg/d - pkg/d imports pkg/e - pkg/e ``` You touch `pkg/b/doc.go`. What is tested? --- template: normal # Dependency DAG analysis ``` $GOPATH/src/github.com/$USER/foo/ - cmd/foo imports pkg/a and pkg/e - pkg/a imports pkg/b - pkg/b imports pkg/c and pkg/e - pkg/c imports pkg/d - pkg/d imports pkg/e - pkg/e ``` You touch `pkg/b/doc.go`. What is tested? If you use `go test ./...` the answer is .center[.large[everything]] --- template: normal # Dependency DAG analysis ``` $GOPATH/src/github.com/$USER/foo/ - cmd/foo imports pkg/a and pkg/e - pkg/a imports pkg/b - pkg/b imports pkg/c and pkg/e - pkg/c imports pkg/d - pkg/d imports pkg/e - pkg/e ``` You touch `pkg/b/doc.go`. What is tested? With `pcg` - Packages tested: `cmd/foo`, `pkg/a` and `pkg/b` - `pkg/c`, `pkg/d` and `pkg/e` are left alone --- template: normal # Native checks (packages) ### build - Builds only test-less packages ### coverage - Enforces minimum coverage per package - Supports global inference! (*explained later*) ### test - Runs `go test` in parallel - Supports optional flags like `-short` or `-race` --- template: normal # Native checks (files) ### copyright - Enforces copyright header on sources, e.g.: ``` // Copyright 2015 The Foo Authors. All rights reserved. // Use of this source code is governed by a WTFPL-style // license that can be found in the LICENSE file. ``` ### gofmt - Enforces [gofmt -s](https://golang.org/cmd/gofmt/) ### goimports - Enforces [goimports](https://golang.org/x/tools/cmd/goimports) --- template: normal # Native checks (linters) ### errcheck - Uses [errcheck](https://github.com/kisielk/errcheck) linter (I like this one) ### golint - Use [golint](https://github.com/golang/lint/golint) linter - Supports blacklisting messages ### govet - Use [go tool vet](https://golang.org/x/tools/cmd/vet) linter - Supports blacklisting messages --- template: normal # Custom checks `pcg` will soon support custom `go get`'able checks (still incomplete) Extensibility built-in --- template: normal # Checks ### Smart Checks are either *package level* or *file level*: - `gofmt` is file level - `test` is package level ### DAG analysis Differentiate between modified packages and transitive dependencies - `test` runs on all transitive dependencies - `errcheck` runs only on modified packages --- template: normal # Checks ### Contextual The same check has different behavior depending on mode: *On commit*: `go test -short` vs *On push*: `go test -race` ### Designed to be fast in the common flow --- template: normal # Runs automatically Upon execution, `pcg` sets itself as: - .git/hooks/pre-commit - .git/hooks/pre-push so it is run automatically afterward. Viral design, trivial installation. --- template: normal ## Acts on change (Δ), not repo ### git commit - Δ of what is in the git staging index - *Automatically stash if needed* - Tests must be fast: default hard limit 2 seconds - Uses `-short` by default ### git push - Δ between code being pushed and upstream - Slower tests; default hard limit 15 seconds - Uses `-race` instead of `-short` --- template: normal # Continuous Integration ### On CI - All checks on all files, and more checks if desired - CI mode if environment variable `CI=true` is set - Defined on all popular hosted CI systems Review of hosted CI systems supporting Go: [maruel.ca/post/ci-go-review/](https://maruel.ca/post/ci-go-review/) --- template: normal # Executed manually ### Running `pcg` manually Δ between local and tracked branch, runs same tests as *on push* ### Running a mode manually `pcg run -m lint` runs non-default linter checks, only on relevant code Use `pcg run -m lint -a` to run on all code --- template: normal # Configuration file `pre-commit-go.yml` ### Location - Checkout's root - Hidden in `.git/` - User global settings in `~/.config/` ### Properties - Defines what checks are enabled in each mode - Not required, `pcg` aims for sane defaults - `pcg writeconfig` generates the defaults - Can be used to force version upgrade --- class: center, middle # Extra slides If used less than 6 minutes, there's other great tools to talk about! --- template: inverse # panicparse *Crash your app in style* .footnote[[github.com/maruel/panicparse](https://github.com/maruel/panicparse)] --- template: normal # Turns this .small[ ``` panic: oh goroutine 11 [running]: github.com/luci/luci-go/client/archiver.(*archiver).PushFile(0xc208032410, 0xc20968a3c0, 0x5b, 0xc20988c280, 0x7d, 0x0, 0x0) /gopath/src/github.com/luci/luci-go/client/archiver/archiver.go:325 +0x2c4 github.com/luci/luci-go/client/isolate.archive(0x7fbdab7a5218, 0xc208032410, 0xc20803b0b0, 0x22, 0xc208046370, 0xc20804666a, 0x17, 0x0, 0x0, 0x0, ...) /gopath/src/github.com/luci/luci-go/client/isolate/isolate.go:148 +0x12d2 github.com/luci/luci-go/client/isolate.Archive(0x7fbdab7a5218, 0xc208032410, 0xc20803b0b0, 0x22, 0xc208046370, 0x0, 0x0) /gopath/src/github.com/luci/luci-go/client/isolate/isolate.go:102 +0xc9 main.func·004(0x7fffc3b8f13a, 0x2c) /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:166 +0x7cd created by main.(*batchArchiveRun).main /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:167 +0x42c goroutine 1 [chan receive]: main.(*batchArchiveRun).main(0xc2080300b0, 0x7fbdab7a50b8, 0x9979a0, 0xc20800a070, 0x3, 0x3, 0x0, 0x0) /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:175 +0x54c main.(*batchArchiveRun).Run(0xc2080300b0, 0x7fbdab7a50b8, 0x9979a0, 0xc20800a070, 0x3, 0x3, 0xc208038010) /gopath/src/github.com/luci/luci-go/client/cmd/isolate/batch_archive.go:203 +0x28d github.com/maruel/subcommands.Run(0x7fbdab7a50b8, 0x9979a0, 0xc20800a010, 0x9, 0x9, 0x43d185) /gopath/src/github.com/maruel/subcommands/subcommands.go:262 +0x405 main.main() /gopath/src/github.com/luci/luci-go/client/cmd/isolate/main.go:28 +0x70 goroutine 5 [syscall]: os/signal.loop() /golang/src/os/signal/signal_unix.go:21 +0x1f created by os/signal.init·1 /golang/src/os/signal/signal_unix.go:27 +0x35 ``` ] --- template: normal # Into this ![screenshot](https://raw.githubusercontent.com/wiki/maruel/panicparse/screenshot3.png) --- template: normal # Try it out: *Crash your app in style* ``` go get github.com/maruel/panicparse/cmd/pp echo -e 'package main\nfunc main() {panic("!")}' > c.go go run c.go |& pp ``` --- template: inverse # covg *Coverage, fast, global* .footnote[Included in [github.com/maruel/pre-commit-go](https://github.com/maruel/pre-commit-go)] --- template: normal # Standalone global inference coverage Running test on a package contributes coverage on all imported packages. Gives broader picture of coverage scenario, permits focusing on actually untested corner cases. E.g. unit tests in package `foo/bar` will contribute coverage in `foo/goo` when unit tests calls out in this package. --- template: inverse # webskel *Hugo based framework* .footnote[[github.com/maruel/webskel](https://github.com/maruel/webskel)] --- template: normal # Hugo based framework Includes: - Static ordered pages and generated NavBar - Blog - [remarkjs.com](https://remarkjs.com) based presentation - This presentation is using this - Metadata: Twitter, Facebook, Google & Bing - Instructions for: - [cloudflare.com](https://cloudflare.com) https fronting - github page generated via [codeship.com](https://codeship.com) Powers https://maruel.ca --- template: inverse # Other Go projects .footnote[[maruel.ca/page/projects/](https://maruel.ca/page/projects/)] --- template: normal # Other Go projects [maruel.ca/page/projects/](https://maruel.ca/page/projects/) - Circular buffer (in-memory log serving over HTTP) - FLIR lepton IR camera driver code serves images over websocket - subcommands for automatic typo correction - serve-dir to quickly serve a directory - Isolate: Content addressed cache (used in Chromium infrastructure, does >120 million lookups per day) - Reed-Solomon error correction - Fortuna PRNG