Slide 1

Slide 1 text

Diff’ing Go library
 API changes Go Conference 2015 Winter
 @motemen, motemen.github.io

Slide 2

Slide 2 text

About me - @motemen on GitHub/Twitter/Hatena - Chief engineer at Hatena - Loves: Go, git - Wrote: ghq, gore and more

Slide 3

Slide 3 text

Diff’ing Go library API changes - Introduction of a tool recently I’ve written: gompat - Motivation, overview & Implementation

Slide 4

Slide 4 text

Motivation

Slide 5

Slide 5 text

“go get -u” and pray - Go packages can be obtained as “latest” - Dependent libraries may introduce breaking changes without your notice - Could use “vendoring” or “revision locking”

Slide 6

Slide 6 text

How can we: - Know dependent libraries’ API changes? - Know to what version to update them? - Know if we are introducing breaking changes
 to our package?

Slide 7

Slide 7 text

API changes overview

Slide 8

Slide 8 text

API entities - Package-level and published: • Functions and methods (func) • Types (type) • Variables (var), Constants (const) - May be changed by the package update

Slide 9

Slide 9 text

Changes: the obvious = Unchanged + Added - Deleted

Slide 10

Slide 10 text

! Breaking - Named API entities with their interface changed • Users have to modify API usages - … except for the “compatible” case (later)

Slide 11

Slide 11 text

Breaking: struct type example - Struct field deleted - Struct field type changed // before type BreakingT struct { Foo string Bar bool } // after type BreakingT struct { Bar int }

Slide 12

Slide 12 text

Breaking: function example - Parameter types, number changed - Return value types, number changed // before func BreakingF(n, m int) int // after func BreakingF(b bool) (int, error)

Slide 13

Slide 13 text

* Compatible - API signatures changed - Users don’t need their API usages

Slide 14

Slide 14 text

Compatible: function example - Function changed to variadic // before func CompatibleF(n, m int) // after func CompatibleF(n, m int, opts ...string)

Slide 15

Slide 15 text

Compatible: struct type example - Public field added * Breaking for T{x, y, z} initializers // before type CompatibleT struct { Foo int } // after type CompatibleT struct { Foo int Bar bool }

Slide 16

Slide 16 text

Compatible: other cases - Value changed from const to var - Function parameter type became more general • eg. *bytes.Buffer to io.Reader

Slide 17

Slide 17 text

API Changes = Unchanged + Added * Compatible ! Breaking - Deleted

Slide 18

Slide 18 text

Enter Gompatible

Slide 19

Slide 19 text

! motemen/gompatible - Compares API of a package under two revisions - Produces change kinds per API entities • Added / Removed / Breaking / Compatible

Slide 20

Slide 20 text

cmd/gompat - Main entrypoint of gompatible - Usage: • gompat rev..rev package

Slide 21

Slide 21 text

Inside Gompatible

Slide 22

Slide 22 text

Gompatible tasks - Mostly achieved by std packages: • Load packages at revisions • Load API signatures from packages • Compare type information

Slide 23

Slide 23 text

go/types - Formerly x/tools/go/types - Generates type information from source ASTs - Entrypoint: *types.Package • pkg.Scope().Lookup(“main”) → *types.Func • fun.Type() → *types.Signature • sig.Params(), sig.Results() → *types.Tuple

Slide 24

Slide 24 text

go/types - Can query on types • types.Implements(Type, *Interface) • types.AssignableTo(Type, Type)

Slide 25

Slide 25 text

go/types - It’s a lot of work (and maybe chore) to: • Convert import path to source code directory • Filtering out e.g. *_test.go or *_windows.go’s • Parse source files and combine them as package • Then process typings by go/types

Slide 26

Slide 26 text

x/tools/go/loader - Package path and filenames to *loader.Program • Syntactically parsed and typed packages - Built for command line tools • loader.Config.FromArgs([]string, bool) • Users: x/tools/cmd/… - (Can see loader.FromArgsUsage inside oracle -help)

Slide 27

Slide 27 text

x/tools/go/loader: Usage // set up configuration conf := &loader.Config{ Build: &build.Context{…}, ParserMode: parser.ParseComments, TypeChecker: types.Config{…}, } // specify package path & files conf.CreateFromFilenames(path, files...) // load the program program, _ := conf.Load() // access packages for _, pkg := range program.Created {...}

Slide 28

Slide 28 text

go/build - Used by loader.Config - Handles build information of Go source code files - Know target files under some GOOS, -tag, etc. • Convert import path to source code directory • Filtering out e.g. *_test.go or *_windows.go’s

Slide 29

Slide 29 text

go/build - Entrypoint: *build.Context • Set GOOS or BuildTags and call ImportDir() • Can override ReadDir, OpenFile ‣ Can Build source code on virtual filesystems

Slide 30

Slide 30 text

! sourcegraph/go-vcs - Virtual source tree at revisions on git/mercurial - Implements x/tools/godoc/vfs.FileSystem • Open(string) (ReadSeekCloser, error) • ReadDir(string) ([]os.FileInfo, error)

Slide 31

Slide 31 text

Inside gompatible - Assign sourcegraph/go-vcs's implementation to go/build.Context - Use go/loader with the build context to obtain type information of two packages - Compare APIs using compatibility rules

Slide 32

Slide 32 text

TODO - Support for: • Vendoring • Mercurial (hg) • More complicated changes - Web interface

Slide 33

Slide 33 text

Diff’ing Go library API changes https://motemen.github.io/