diff --git a/.circleci/config.yml b/.circleci/config.yml index 65be891..55ccfc5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -43,7 +43,9 @@ jobs: working_directory: /home/circleci/go/src/github.com/influxdata/influx-cli steps: - checkout - - run: make influx + - run: make crossbuild + - store_artifacts: + path: dist test: docker: diff --git a/.gitignore b/.gitignore index dc517dd..5202ed6 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.so *.dylib bin/ +dist/ # Test binary, built with `go test -c` *.test diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..0d98ead --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,25 @@ +project_name: influx-cli +builds: + - id: influx + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + ignore: + - goos: darwin + goarch: arm64 + - goos: windows + goarch: arm64 + main: ./cmd/influx + env: + - CGO_ENABLED=0 + ldflags: + - -s -w -X main.version={{if .IsSnapshot}}dev{{else}}{{.Version}}{{end}} -X main.commit={{.ShortCommit}} -X main.date={{.Date}} + binary: influx + +# Do not make github release +release: + disable: true diff --git a/Makefile b/Makefile index f3f2758..23283de 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ fmt: $(SOURCES_NO_VENDOR) go run github.com/daixiang0/gci -w $^ bin/$(GOOS)/influx: $(SOURCES) - $(GO_BUILD) -o $@ ./cmd/$(shell basename "$@") + CGO_ENABLED=0 $(GO_BUILD) -o $@ ./cmd/$(shell basename "$@") .DEFAULT_GOAL := influx influx: bin/$(GOOS)/influx @@ -46,6 +46,26 @@ influx: bin/$(GOOS)/influx vendor: go.mod go.sum go mod vendor +GORELEASER_VERSION := v0.165.0 +bin/goreleaser-$(GORELEASER_VERSION): + ./etc/download-goreleaser.sh $(GORELEASER_VERSION) + +goreleaser: bin/goreleaser-$(GORELEASER_VERSION) + +build: bin/goreleaser-$(GORELEASER_VERSION) +ifdef VERSION + GORELEASER_CURRENT_TAG=$(VERSION) bin/goreleaser-$(GORELEASER_VERSION) build --rm-dist --single-target +else + bin/goreleaser-$(GORELEASER_VERSION) build --rm-dist --single-target --snapshot +endif + +crossbuild: bin/goreleaser-$(GORELEASER_VERSION) +ifdef VERSION + GORELEASER_CURRENT_TAG=$(VERSION) bin/goreleaser-$(GORELEASER_VERSION) build --rm-dist +else + bin/goreleaser-$(GORELEASER_VERSION) build --snapshot --rm-dist +endif + clean: $(RM) -r bin $(RM) -r vendor @@ -77,4 +97,4 @@ test-race: $(GO_TEST) -v -race -count=1 $(GO_TEST_PATHS) ### List of all targets that don't produce a file -.PHONY: influx openapi fmt build checkfmt checktidy staticcheck vet mock test test-race +.PHONY: influx openapi fmt build crossbuild goreleaser checkfmt checktidy staticcheck vet mock test test-race diff --git a/README.md b/README.md index 13b7a8b..378a78a 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,19 @@ Our goals are to: ## Building -Run `make` to build the CLI. The output binary will be written to `bin/$(GOOS)/influx`. +### Development build +Run `make` or `make influx` to build the CLI. The output binary will be written to `bin/$(GOOS)/influx`. + +### Release build +We use [`goreleaser`](https://goreleaser.com/) to manage cross-building the CLI for release. Run `make build` +to build the CLI with release settings for your current `GOOS` and `GOARCH`. Run `make crossbuild` to build +the CLI for all `GOOS`/`GOARCH` pairs supported by the CLI. The output binary/binaries will be written under +`dist/influx_${GOOS}_${GOARCH}/`. ### Regenerating OpenAPI client We use [`OpenAPITools/openapi-generator`](https://github.com/OpenAPITools/openapi-generator) to generate -the underlying HTTP client used by the CLI. Run `make openapi` to re-generate the code. You'll need Docker +the underlying HTTP client used by the CLI. Run `make openapi` to re-generate the code. You'll need Docker running locally for the script to work. ## Running diff --git a/etc/download-goreleaser.sh b/etc/download-goreleaser.sh new file mode 100755 index 0000000..f06ea21 --- /dev/null +++ b/etc/download-goreleaser.sh @@ -0,0 +1,406 @@ +#!/bin/sh +set -e + +################################ NOTE ################################ +# To avoid piping a `curl` call into `sh`, this was downloaded from: # +# https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh # +# on May 21, 2021. The only modification made was to append `-` # +# to the name of the generated binary. # +###################################################################### + +# Code generated by godownloader on 2019-12-25T12:47:14Z. DO NOT EDIT. +# + +usage() { + this=$1 + cat </dev/null +} +echoerr() { + echo "$@" 1>&2 +} +log_prefix() { + echo "$0" +} +_logp=6 +log_set_priority() { + _logp="$1" +} +log_priority() { + if test -z "$1"; then + echo "$_logp" + return + fi + [ "$1" -le "$_logp" ] +} +log_tag() { + case $1 in + 0) echo "emerg" ;; + 1) echo "alert" ;; + 2) echo "crit" ;; + 3) echo "err" ;; + 4) echo "warning" ;; + 5) echo "notice" ;; + 6) echo "info" ;; + 7) echo "debug" ;; + *) echo "$1" ;; + esac +} +log_debug() { + log_priority 7 || return 0 + echoerr "$(log_prefix)" "$(log_tag 7)" "$@" +} +log_info() { + log_priority 6 || return 0 + echoerr "$(log_prefix)" "$(log_tag 6)" "$@" +} +log_err() { + log_priority 3 || return 0 + echoerr "$(log_prefix)" "$(log_tag 3)" "$@" +} +log_crit() { + log_priority 2 || return 0 + echoerr "$(log_prefix)" "$(log_tag 2)" "$@" +} +uname_os() { + os=$(uname -s | tr '[:upper:]' '[:lower:]') + case "$os" in + cygwin_nt*) os="windows" ;; + mingw*) os="windows" ;; + msys_nt*) os="windows" ;; + esac + echo "$os" +} +uname_arch() { + arch=$(uname -m) + case $arch in + x86_64) arch="amd64" ;; + x86) arch="386" ;; + i686) arch="386" ;; + i386) arch="386" ;; + aarch64) arch="arm64" ;; + armv5*) arch="armv5" ;; + armv6*) arch="armv6" ;; + armv7*) arch="armv7" ;; + esac + echo ${arch} +} +uname_os_check() { + os=$(uname_os) + case "$os" in + darwin) return 0 ;; + dragonfly) return 0 ;; + freebsd) return 0 ;; + linux) return 0 ;; + android) return 0 ;; + nacl) return 0 ;; + netbsd) return 0 ;; + openbsd) return 0 ;; + plan9) return 0 ;; + solaris) return 0 ;; + windows) return 0 ;; + esac + log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" + return 1 +} +uname_arch_check() { + arch=$(uname_arch) + case "$arch" in + 386) return 0 ;; + amd64) return 0 ;; + arm64) return 0 ;; + armv5) return 0 ;; + armv6) return 0 ;; + armv7) return 0 ;; + ppc64) return 0 ;; + ppc64le) return 0 ;; + mips) return 0 ;; + mipsle) return 0 ;; + mips64) return 0 ;; + mips64le) return 0 ;; + s390x) return 0 ;; + amd64p32) return 0 ;; + esac + log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" + return 1 +} +untar() { + tarball=$1 + case "${tarball}" in + *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;; + *.tar) tar --no-same-owner -xf "${tarball}" ;; + *.zip) unzip "${tarball}" ;; + *) + log_err "untar unknown archive format for ${tarball}" + return 1 + ;; + esac +} +http_download_curl() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") + else + code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") + fi + if [ "$code" != "200" ]; then + log_debug "http_download_curl received HTTP status $code" + return 1 + fi + return 0 +} +http_download_wget() { + local_file=$1 + source_url=$2 + header=$3 + if [ -z "$header" ]; then + wget -q -O "$local_file" "$source_url" + else + wget -q --header "$header" -O "$local_file" "$source_url" + fi +} +http_download() { + log_debug "http_download $2" + if is_command curl; then + http_download_curl "$@" + return + elif is_command wget; then + http_download_wget "$@" + return + fi + log_crit "http_download unable to find wget or curl" + return 1 +} +http_copy() { + tmp=$(mktemp) + http_download "${tmp}" "$1" "$2" || return 1 + body=$(cat "$tmp") + rm -f "${tmp}" + echo "$body" +} +github_release() { + owner_repo=$1 + version=$2 + test -z "$version" && version="latest" + giturl="https://github.com/${owner_repo}/releases/${version}" + json=$(http_copy "$giturl" "Accept:application/json") + test -z "$json" && return 1 + version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') + test -z "$version" && return 1 + echo "$version" +} +hash_sha256() { + TARGET=${1:-/dev/stdin} + if is_command gsha256sum; then + hash=$(gsha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command sha256sum; then + hash=$(sha256sum "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command shasum; then + hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 + echo "$hash" | cut -d ' ' -f 1 + elif is_command openssl; then + hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 + echo "$hash" | cut -d ' ' -f a + else + log_crit "hash_sha256 unable to find command to compute sha-256 hash" + return 1 + fi +} +hash_sha256_verify() { + TARGET=$1 + checksums=$2 + if [ -z "$checksums" ]; then + log_err "hash_sha256_verify checksum file not specified in arg2" + return 1 + fi + BASENAME=${TARGET##*/} + want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) + if [ -z "$want" ]; then + log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" + return 1 + fi + got=$(hash_sha256 "$TARGET") + if [ "$want" != "$got" ]; then + log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" + return 1 + fi +} +cat /dev/null <