Skip to content

Commit 69275d6

Browse files
alvin-huanghanshasselberg
authored andcommitted
Add CircleCI Configuration (#11)
* fix go.sum for checksum mismatch * remove gocov tools * add circleci config * fix error statement * use golang 1.12.4 * add a version label to Dockerfile for introspection in build script * add make target for publishing a Dockerfile * add circleci config for dockerfile linting and building on tags * add docker publishing script * use an ENTRYPOINT instead of a CMD for published docker * go.sum updates * make INTTEST requirement more clear * use the consul-aws.version LABEL
1 parent ad7d8ad commit 69275d6

File tree

6 files changed

+293
-44
lines changed

6 files changed

+293
-44
lines changed

.circleci/config.yml

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
version: 2.1
2+
3+
references:
4+
images:
5+
go: &GOLANG_IMAGE circleci/golang:1.12.4
6+
consul-current: &CONSUL_IMAGE_CURRENT consul:1.4.4
7+
consul-previous: &CONSUL_IMAGE_PREVIOUS consul:1.4.3
8+
9+
# reusable 'executor' object for jobs
10+
executors:
11+
go:
12+
docker:
13+
- image: *GOLANG_IMAGE
14+
environment:
15+
- TEST_RESULTS: /tmp/test-results # path to where test results are saved
16+
17+
jobs:
18+
go-fmt-and-vet:
19+
executor: go
20+
steps:
21+
- checkout
22+
23+
# Restore go module cache if there is one
24+
- restore_cache:
25+
keys:
26+
- consul-aws-modcache-v1-{{ checksum "go.mod" }}
27+
28+
- run: go mod download
29+
30+
# Save go module cache if the go.mod file has changed
31+
- save_cache:
32+
key: consul-aws-modcache-v1-{{ checksum "go.mod" }}
33+
paths:
34+
- "/go/pkg/mod"
35+
36+
# check go fmt output because it does not report non-zero when there are fmt changes
37+
- run:
38+
name: check go fmt
39+
command: |
40+
files=$(go fmt ./...)
41+
if [ -n "$files" ]; then
42+
echo "The following file(s) do not conform to go fmt:"
43+
echo "$files"
44+
exit 1
45+
fi
46+
- run: go vet ./...
47+
48+
test:
49+
parameters:
50+
consul-version:
51+
description: What version of Consul to test against
52+
type: string
53+
executor: go
54+
environment:
55+
NAMESPACEID: ns-btldyxsz7rymvf4x # AWS Cloud Map Namespace for CI
56+
NAMESPACEIDHTTP: ns-dhshakmjzetizgi2 # AWS Cloud Map Namespace for CI
57+
docker: # the docker stanza will overwrite the executor so we need to define GOLANG_IMAGE again here
58+
- image: *GOLANG_IMAGE
59+
- image: << parameters.consul-version >>
60+
parallelism: 1 # make this explicit in case we need to parallelize in the future
61+
steps:
62+
- checkout
63+
- run: mkdir -p $TEST_RESULTS
64+
65+
# Restore go module cache if there is one
66+
- restore_cache:
67+
keys:
68+
- consul-aws-modcache-v1-{{ checksum "go.mod" }}
69+
70+
# run go tests with gotestsum
71+
- run: |
72+
PACKAGE_NAMES=$(go list ./...)
73+
gotestsum --format=short-verbose --junitfile $TEST_RESULTS/gotestsum-report.xml -- $PACKAGE_NAMES
74+
- store_test_results:
75+
path: /tmp/test-results
76+
- store_artifacts:
77+
path: /tmp/test-results
78+
79+
build-distros:
80+
executor: go
81+
environment:
82+
GOXPARALLEL: 2 # CircleCI containers are 2 CPU x 4GB RAM
83+
steps:
84+
- checkout
85+
86+
# Restore go module cache if there is one
87+
- restore_cache:
88+
keys:
89+
- consul-aws-modcache-v1-{{ checksum "go.mod" }}
90+
91+
- run: make tools
92+
- run: ./build-support/scripts/build-local.sh
93+
94+
# save dev build to CircleCI
95+
- store_artifacts:
96+
path: ./pkg/bin
97+
98+
# Lints all *.dockerfile but don't fail at this time
99+
dockerfile-lint:
100+
docker:
101+
- image: hadolint/hadolint:latest-debian
102+
steps:
103+
- run: apt-get -qq update; apt-get -y install git # the hadolint container doesn't have git
104+
- checkout
105+
- run:
106+
name: Dockefile lint
107+
command: |
108+
for file in $(find . -type f -name *.dockerfile); do
109+
hadolint $file || true
110+
done
111+
112+
# Builds and publishes Docker Container to Dockerhub for tagged releases
113+
docker-build:
114+
executor: go
115+
steps:
116+
- checkout
117+
- setup_remote_docker:
118+
docker_layer_caching: true
119+
- run:
120+
name: wait for release package
121+
command: |
122+
CONSUL_AWS_VERSION=$(echo ${CIRCLE_TAG} | sed 's/v\(.*\)/\1/')
123+
echo "curl-ing https://releases.hashicorp.com/${CIRCLE_PROJECT_REPONAME}/${CONSUL_AWS_VERSION}/${CIRCLE_PROJECT_REPONAME}_${CONSUL_AWS_VERSION}_linux_amd64.zip"
124+
until [ $SECONDS -ge 300 ] && exit 1; do
125+
curl -o /dev/null --fail --silent "https://releases.hashicorp.com/${CIRCLE_PROJECT_REPONAME}/${CONSUL_AWS_VERSION}/${CIRCLE_PROJECT_REPONAME}_${CONSUL_AWS_VERSION}_linux_amd64.zip" && exit
126+
echo -n "."
127+
sleep 2
128+
done
129+
- run: make docker-publish
130+
workflows:
131+
version: 2
132+
test-and-build:
133+
jobs:
134+
- go-fmt-and-vet
135+
- test:
136+
name: test-previous-consul-version
137+
consul-version: *CONSUL_IMAGE_PREVIOUS
138+
requires:
139+
- go-fmt-and-vet
140+
- test:
141+
name: test-current-consul-version
142+
consul-version: *CONSUL_IMAGE_CURRENT
143+
# The resources created in the tests with the two consul versions are the same
144+
# This can be changed to run in parallel once a prefix/uniqueness is added to the tests
145+
requires:
146+
- test-previous-consul-version
147+
- build-distros:
148+
requires:
149+
- test-current-consul-version
150+
docker-build-and-publish:
151+
jobs:
152+
- dockerfile-lint:
153+
filters:
154+
tags:
155+
only: /^v\d+\.\d+\.\d+$/
156+
- docker-build:
157+
requires:
158+
- dockerfile-lint
159+
filters:
160+
tags:
161+
only: /^v\d+\.\d+\.\d+$/
162+
branches:
163+
ignore: /.*/

Makefile

+12-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ GOTOOLS = \
88
github.com/magiconair/vendorfmt/cmd/vendorfmt \
99
github.com/mitchellh/gox \
1010
golang.org/x/tools/cmd/cover \
11-
golang.org/x/tools/cmd/stringer \
12-
github.com/axw/gocov/gocov \
13-
gopkg.in/matm/v1/gocov-html
11+
golang.org/x/tools/cmd/stringer
1412

1513
DEV_IMAGE?=consul-aws-dev
1614
GO_BUILD_TAG?=consul-aws-build-go
@@ -20,6 +18,12 @@ GIT_DESCRIBE?=$(shell git describe --tags --always)
2018
GIT_IMPORT=github.com/hashicorp/consul-aws/version
2119
GOLDFLAGS=-X $(GIT_IMPORT).GitCommit=$(GIT_COMMIT)$(GIT_DIRTY) -X $(GIT_IMPORT).GitDescribe=$(GIT_DESCRIBE)
2220

21+
# Docker Image publishing variables
22+
DOCKER_IMAGE_NAME=consul-aws
23+
DOCKER_ORG=hashicorp
24+
export DOCKER_IMAGE_NAME
25+
export DOCKER_ORG
26+
2327
export GIT_COMMIT
2428
export GIT_DIRTY
2529
export GIT_DESCRIBE
@@ -105,10 +109,14 @@ go-build-image:
105109
@echo "Building Golang build container"
106110
@docker build $(NOCACHE) $(QUIET) --build-arg 'GOTOOLS=$(GOTOOLS)' -t $(GO_BUILD_TAG) - < build-support/docker/Build-Go.dockerfile
107111

112+
docker-publish:
113+
@echo "Building Docker Image"
114+
@$(SHELL) $(CURDIR)/build-support/scripts/publish-docker.sh
115+
108116
clean:
109117
@rm -rf \
110118
$(CURDIR)/bin \
111119
$(CURDIR)/pkg
112120

113121

114-
.PHONY: all bin clean dev dist docker-images go-build-image test tools
122+
.PHONY: all bin clean dev dist docker-images go-build-image test tools docker-publish

build-support/docker/Release.dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ ENV VERSION=$VERSION
1919
# This is the location of the releases.
2020
ENV HASHICORP_RELEASES=https://releases.hashicorp.com
2121

22+
# Add a label for introspection of version
23+
LABEL consul-aws.version=$VERSION
24+
2225
# Create a non-root user to run the software.
2326
RUN addgroup ${NAME} && \
2427
adduser -S -G ${NAME} ${NAME}
@@ -59,4 +62,4 @@ RUN set -eux && \
5962
rm -rf /root/.gnupg
6063

6164
USER ${NAME}
62-
CMD /bin/${NAME}
65+
ENTRYPOINT /bin/${NAME}
+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/bin/bash
2+
3+
# Description:
4+
# This script will publish consul-aws containers to Dockerhub. It should only run on tagged
5+
# branches within CI and all the variables needed are populated either by CircleCI or the Makefile.
6+
7+
# To publish a new container, make sure the following environment variables are set:
8+
# * CIRCLE_TAG - the version of the consul-aws binary you want to build an image for
9+
# * DOCKER_ORG - to the organization of the docker image
10+
# * DOCKER_IMAGE_NAME - to the name of the docker image
11+
12+
function get_latest_docker_version {
13+
# Arguments:
14+
# $1 - Docker Org
15+
# $2 - Docker Image Name
16+
#
17+
#
18+
# Returns:
19+
# 0 - success (version in the 'latest' container echoed)
20+
# 1 - 'latest' tag does not exist or label could not be found
21+
22+
docker_latest=$(docker inspect --format='{{ index .Config.Labels "consul-aws.version" }}' "$1"/"$2":latest 2> /dev/null)
23+
24+
if [ -z "$docker_latest" ]; then
25+
return 1
26+
else
27+
echo "$docker_latest"
28+
return 0
29+
fi
30+
}
31+
32+
function get_latest_docker_minor_version {
33+
# Arguments:
34+
# $1 - Docker Org
35+
# $2 - Docker Image Name
36+
# $3 - Minor Version Tag
37+
#
38+
# Returns:
39+
# 0 - success (version in the latest minor version container echoed)
40+
# 1 - tag does not exist or label could not be found
41+
docker_latest_minor=$(docker inspect --format='{{ index .Config.Labels "consul-aws.version" }}' "$1"/"$2":"$3" 2> /dev/null)
42+
43+
if [ -z "$docker_latest_minor" ]; then
44+
return 1
45+
else
46+
echo "$docker_latest_minor"
47+
return 0
48+
fi
49+
}
50+
51+
function higher_version {
52+
# Arguments:
53+
# $1 - first version to compare
54+
# $2 - second version to compare
55+
#
56+
# Returns:
57+
# higher version of two arguments
58+
59+
higher_version=$(echo -e "$1\n$2" | sort -rV | head -n 1)
60+
echo "$higher_version"
61+
}
62+
function main() {
63+
# check for necessary variables
64+
: "${CIRCLE_TAG?"Need to set CIRCLE_TAG"}"
65+
: "${DOCKER_ORG?"Need to set DOCKER_ORG"}"
66+
: "${DOCKER_IMAGE_NAME?"Need to set DOCKER_IMAGE_NAME"}"
67+
68+
# trims v from version, ex: v1.2.3 -> 1.2.3; this maps to releases.hashicorp.com
69+
CURRENT_TAG_VERSION=$(echo "$CIRCLE_TAG" | sed 's/v\(.*\)/\1/')
70+
71+
# trims the patch part of the git tag to compare
72+
MINOR_VERSION=${CIRCLE_TAG%.[0-9]*}
73+
DOCKER_MINOR_TAG="${MINOR_VERSION#v}-latest"
74+
75+
LATEST_DOCKER_MINOR_VERSION=$(get_latest_docker_minor_version "$DOCKER_ORG" "$DOCKER_IMAGE_NAME" "$DOCKER_MINOR_TAG")
76+
LATEST_DOCKER_VERSION=$(get_latest_docker_version "$DOCKER_ORG" "$DOCKER_IMAGE_NAME")
77+
78+
# Login to Dockerhub
79+
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
80+
81+
# build current branch tag image
82+
docker build -t "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" --build-arg NAME="$DOCKER_IMAGE_NAME" --build-arg VERSION="$CURRENT_TAG_VERSION" -f "$(pwd)"/build-support/docker/Release.dockerfile "$(pwd)"/build-support/docker
83+
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION"
84+
85+
# check to see if the current tag is higher than the latest minor version on dockerhub
86+
HIGHER_MINOR_VERSION=$(higher_version "$CURRENT_TAG_VERSION" "$LATEST_DOCKER_MINOR_VERSION")
87+
88+
# if the higher version is the current tag, we tag the current image with the minor tag
89+
if [ "$HIGHER_MINOR_VERSION" = "$CURRENT_TAG_VERSION" ]; then
90+
echo "Tagging a new minor latest image"
91+
docker tag "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$DOCKER_MINOR_TAG"
92+
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$DOCKER_MINOR_TAG"
93+
fi
94+
95+
# check to see if the current tag is higher than the latest version on dockerhub
96+
HIGHER_LATEST_VERSION=$(higher_version "$CURRENT_TAG_VERSION" "$LATEST_DOCKER_VERSION")
97+
98+
# if:
99+
# * we didn't find a version from the 'latest' image, it means it doesn't exist
100+
# * or if the current tag version is higher than the latest docker one
101+
# we build latest
102+
if [ -z "$LATEST_DOCKER_VERSION" ] || [ "$HIGHER_LATEST_VERSION" = "$CURRENT_TAG_VERSION" ]; then
103+
echo "Tagging a new latest docker image"
104+
docker tag "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":"$CURRENT_TAG_VERSION" "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":latest
105+
docker push "$DOCKER_ORG"/"$DOCKER_IMAGE_NAME":latest
106+
fi
107+
108+
return 0
109+
}
110+
main "$@"
111+
exit $?

catalog/sync_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414

1515
func TestSync(t *testing.T) {
1616
if len(os.Getenv("INTTEST")) == 0 {
17-
t.Skip("no int test env")
17+
t.Skip("Set INTTEST=1 to enable integration tests")
1818
}
1919
namespaceID := os.Getenv("NAMESPACEID")
2020
if len(namespaceID) == 0 {
@@ -42,7 +42,7 @@ func runSyncTest(t *testing.T, namespaceID string) {
4242

4343
err = createServiceInConsul(c, cID, cName)
4444
if err != nil {
45-
t.Fatalf("error creating service in aws: %s", err)
45+
t.Fatalf("error creating service in Consul: %s", err)
4646
}
4747

4848
aID, err := createServiceInAWS(a, namespaceID, aName)

0 commit comments

Comments
 (0)