Skip to content

Commit

Permalink
TravisCI integration: Build and Push, both Executable and Docker Image
Browse files Browse the repository at this point in the history
* Added docker build, executable build, docker push, executable push.
* Ensured push only happened for tagged builds or personal machine builds.
* Ensured Fork PRs do not get pushed.

Rebased and Modified from work of @rtluckie
- #69
- add docker-login make target
- add docker-build-clean make target
- use cache image for docker-build make target
- add docker-push make target
- add build-dist-push make target
- split compilation steps in Dockerfile into discrete layers
  • Loading branch information
dcwangmit01 authored and rtluckie committed Sep 19, 2018
1 parent 35885b9 commit f618831
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 58 deletions.
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
sudo: required
language: go
go: '1.10.3'
go_import_path: github.com/cisco-sso/kdk
services:
- docker
script:
- make ci
deploy:
- provider: script
skip_cleanup: true
script: make ci
on:
tags: true
122 changes: 64 additions & 58 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
.DEFAULT_GOAL=help

DOCKER_REGISTRY ?=
IMAGE_PREFIX ?= ciscosso
SHORT_NAME ?= kdk
TARGETS ?= darwin/amd64 linux/amd64 linux/386 linux/arm linux/arm64 linux/ppc64le linux/s390x windows/amd64
DIST_DIRS = find * -type d -exec
VERSION ?= $(shell git describe --tags --long --dirty | sed 's/-0-........$$//; s/-/+/2')
VERSION := $(shell ./scripts/cicd.sh version)
BASE_IMAGE ?= $(IMAGE_PREFIX)/$(SHORT_NAME)
NEW_IMAGE_TAG ?= $(BASE_IMAGE):$(VERSION)

# go option
GO ?= go
PKG := $(shell dep ensure)
PKG :=
TAGS :=
TESTS := .
TESTFLAGS :=
Expand All @@ -16,71 +19,74 @@ GOFLAGS :=
BINDIR := $(CURDIR)/bin

LDFLAGS += -X github.com/cisco-sso/kdk/pkg/kdk.Version=${VERSION}
LDFLAGS += -extldflags "-static"

# Required for globs to work correctly
SHELL=/bin/bash

.PHONY: all
all: build
PUBLISH := $(shell ./scripts/cicd.sh publish?)

.PHONY: build
build:
GOBIN=$(BINDIR) $(GO) install $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./
#####################################################################

.PHONY: checks deps gofmt \
ci build build-cross \
docker-build docker-push \
bin-build bin-push \
clean help

checks: ## Check the system before building
./scripts/cicd.sh checks

# usage: make clean build-cross dist VERSION=1.0.0
.PHONY: build-cross
build-cross: LDFLAGS += -extldflags "-static"
build-cross: clean bootstrap
CGO_ENABLED=0 gox -parallel=3 -output="_dist/{{.OS}}-{{.Arch}}/{{.Dir}}" -osarch='$(TARGETS)' $(GOFLAGS) $(if $(TAGS),-tags '$(TAGS)',) -ldflags '$(LDFLAGS)' ./

.PHONY: dist
dist:
( \
cd _dist && \
$(DIST_DIRS) cp ../LICENSE {} \; && \
$(DIST_DIRS) cp ../README.md {} \; && \
$(DIST_DIRS) tar -zcf $(SHORT_NAME)-${VERSION}-{}.tar.gz {} \; \
)

.PHONY: check-docker
check-docker:
@if [ -z $$(which docker) ]; then \
echo "Missing \`docker\` client which is required for development"; \
exit 2; \
fi

.PHONY: docker-build
docker-build: check-docker
docker build --rm -t ${IMAGE} -t ${MUTABLE_IMAGE} files

.PHONY: gofmt
gofmt:
deps: ## Ensure dependencies are installed
./scripts/cicd.sh deps

gofmt: ## Format all golang code
gofmt -w -s $$(find ./cmd ./pkg -type f -name '*.go')

.PHONY: clean
clean:
@rm -rf $(BINDIR) ./_dist ./bin vendor
ci: docker-build bin-build docker-push bin-push ## Run the CICD build, and publish depending on circumstances

.PHONY: release
release:
goreleaser --debug
build: checks deps ## Build locally for local os/arch creating bin in ./
GOBIN=$(BINDIR) $(GO) install $(GOFLAGS) -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./

HAS_GIT := $(shell command -v git;)
HAS_DEP := $(shell command -v dep;)
HAS_GORELEASER := $(shell command -v goreleaser;)
build-cross: checks deps ## Build locally for all os/arch combinations in ./_dist
@# # usage: make clean build-cross dist VERSION=1.0.0
CGO_ENABLED=0 gox -parallel=3 \
-output="_dist/{{.OS}}-{{.Arch}}/{{.Dir}}" \
-osarch='$(TARGETS)' $(GOFLAGS) $(if $(TAGS),-tags '$(TAGS)',) \
-ldflags '$(LDFLAGS)' ./

.PHONY: bootstrap
bootstrap:
ifndef HAS_GIT
$(error You must install Git)
endif
ifndef HAS_DEP
go get -u github.com/golang/dep/cmd/dep
endif
ifndef HAS_GOX
go get -u github.com/mitchellh/gox
docker-build: checks ## Build the docker image
docker pull $(BASE_IMAGE):latest
docker build -t $(NEW_IMAGE_TAG) --cache-from $(BASE_IMAGE):latest -f files/Dockerfile files

docker-push: checks ## Publish the docker image
ifeq ($(PUBLISH),true)
@echo "Executing docker push for build"
echo "$${DOCKER_PASSWORD}" | docker login -u "$${DOCKER_USERNAME}" --password-stdin
docker push $(NEW_IMAGE_TAG)
docker tag $(NEW_IMAGE_TAG) $(BASE_IMAGE):latest
docker push $(BASE_IMAGE):latest
else
@echo "Skipping docker push"
endif
ifndef HAS_GORELEASER
go get -u github.com/goreleaser/goreleaser

bin-build: build-cross ## Build the binary executable

bin-push: checks deps # Publish the binary executable
ifeq ($(PUBLISH),true)
@echo "Executing bin push for build"
git status
git reset --hard HEAD
goreleaser release --rm-dist --debug
else
@echo "Skipping bin push"
endif
dep ensure

clean: ## Clean up the build dirs
@rm -rf $(BINDIR) ./_dist ./bin vendor .vendor-new .venv

help: ## Print list of Makefile targets
@# Taken from https://github.com/spf13/hugo/blob/master/Makefile
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
cut -d ":" -f1- | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
91 changes: 91 additions & 0 deletions scripts/cicd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env bash
set -euo pipefail

checks() {
if ! which git &>/dev/null; then
echo "You must install Git"
return 1
fi
if ! which go &>/dev/null; then
echo "You must install Go"
return 1
fi
if ! which docker &>/dev/null; then
echo "You must install Docker"
return 1
fi
return 0
}

deps() {
if ! which dep &>/dev/null; then
go get -u github.com/golang/dep/cmd/dep
fi
if ! which gox &>/dev/null; then
go get -u github.com/mitchellh/gox
fi
if ! which goreleaser &>/dev/null; then
go get -u github.com/goreleaser/goreleaser
fi

dep ensure
}

publish?() {
# Figure out whether to release the docker image and executable binary
# The lack of setting PUBLISH to anything means its undefined

tag_of_current_commit="$(git describe --exact-match --tags HEAD || true)"
latest_tag_in_repo="$(git describe --tags | cut -d '-' -f1)"
if [ "$tag_of_current_commit" != "$latest_tag_in_repo" ]; then
echo "Not publishing because current HEAD is not equal to the latest tag" >&2
echo false
return 1
fi
if [[ -z ${DOCKER_USERNAME+x} ]]; then
echo "Not publishing because DOCKER_USERNAME is unset" >&2
echo false
return 1
fi
if [[ -z ${DOCKER_PASSWORD+x} ]]; then
echo "Not publishing because DOCKER_USERNAME is unset" >&2
echo false
return 1
fi
if [[ ! -z ${TRAVIS_TAG+x} ]]; then
echo "Publish because we are building a Tag on TravisCI" >&2
echo true
return 0
fi
if [[ -z ${CI+x} ]]; then
echo "Publish because we are building on a local machine" >&2
echo true
return 0
fi

echo "Not publishing because of unmet conditions" >&2
echo false
return 1
}

version() {
echo $(git describe --tags --long --dirty | sed 's/-0-........$$//;')
}

case "$1" in
checks)
checks
;;
deps)
deps
;;
publish?)
publish?
;;
version)
version
;;
*)
echo $"Usage: $0 {checks|deps|publish?|version}"
exit 1
esac

0 comments on commit f618831

Please sign in to comment.