func isHttpError(err error) bool {
	if err == nil {
		return false
	}
	if uerr, ok := err.(*url.Error); ok {
		err = uerr.Err
	}
	switch err := err.(type) {
	default:
		return false
	case *net.OpError:
		return err.Op == "dial" && err.Net == "tcp"
	case *net.DNSError:
		return true
	case net.Error:
		return err.Timeout() || err.Temporary()
	}
}
isHttpError checks if the given error is a request timeout or a network
failure - in those cases we want to just retry the request.
package main
import (
	"context"
	"errors"
	"flag"
	"fmt"
	"net"
	"net/url"
	"os"
	"time"
	"github.com/kevinburke/bigtext"
	git "github.com/kevinburke/go-git"
	"github.com/kevinburke/remoteci"
	travis "github.com/kevinburke/travis/lib"
	"github.com/pkg/browser"
)
const help = `The travis binary interacts with Travis CI.
Usage: 
	travis command [arguments]
The commands are:
	enable              Enable builds for this repository.
	open                Open the latest branch build in a browser.
	sync                Sync repos for the account.
	version             Print the current version
	wait                Wait for tests to finish on a branch.
Use "travis help [command]" for more information about a command.
`
func usage() {
	fmt.Fprintf(os.Stderr, help)
	flag.PrintDefaults()
}
func init() {
	flag.Usage = usage
}
func newClient(org string) (*travis.Client, error) {
	token, err := travis.GetToken(org)
	if err != nil {
		return nil, err
	}
	return travis.NewClient(token), nil
}
var errNoBuilds = errors.New("travis: no builds")
func getLatestBuild(client *travis.Client, org, repo, branch string) (*travis.Build, error) {
	builds, err := getBuilds(client, org, repo, branch)
	if err != nil {
		return nil, err
	}
	if len(builds) == 0 {
		return nil, errNoBuilds
	}
	return builds[0], nil
}
func getBuild(client *travis.Client, id int64) (*travis.Build, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	return client.Builds.Get(ctx, id, "build.jobs", "job.config")
}
func getBuilds(client *travis.Client, org, repo, branch string) ([]*travis.Build, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	slug := url.PathEscape(org + "/" + repo)
	builds := make([]*travis.Build, 0)
	resp := &travis.ListResponse{
		Data: &builds,
	}
	path := "/repo/" + slug + "/builds?branch.name=" + url.QueryEscape(branch)
	if err := client.RequestRetryUnauth(ctx, "GET", path, nil, resp); err != nil {
		return nil, err
	}
	return builds, nil
}
func doEnable(flags *flag.FlagSet, remoteStr string) {
	remote, err := git.GetRemoteURL(remoteStr)
	checkError(err, "getting remote URL")
	client, err := newClient(remote.Path)
	checkError(err, "getting token")
	slug := remote.Path + "/" + remote.RepoName
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := client.Repos.Activate(ctx, slug); err != nil {
		failError(err, "activating repository")
	}
	fmt.Printf("%s/%s enabled\n", travis.WebHost, slug)
}
func doOpen(flags *flag.FlagSet, remoteStr string) {
	args := flags.Args()
	branch, err := getBranchFromArgs(args)
	checkError(err, "getting git branch")
	remote, err := git.GetRemoteURL(remoteStr)
	checkError(err, "getting remote URL")
	client, err := newClient(remote.Path)
	checkError(err, "getting token")
	latestBuild, err := getLatestBuild(client, remote.Path, remote.RepoName, branch)
	checkError(err, "getting latest build")
	if err := browser.OpenURL(latestBuild.WebURL()); err != nil {
		checkError(err, "opening url "+latestBuild.WebURL())
	}
}
func getBranchFromArgs(args []string) (string, error) {
	if len(args) == 0 {
		return git.CurrentBranch()
	} else {
		return args[0], nil
	}
}
func checkError(err error, msg string) {
	if err != nil {
		failError(err, msg)
	}
}
func failError(err error, msg string) {
	fmt.Fprintf(os.Stderr, "Error %s: %v\n", msg, err)
	os.Exit(1)
}