1---
2version: 2
3
4references:
5  images:
6    go: &GOLANG_IMAGE circleci/golang:1.12.16
7    middleman: &MIDDLEMAN_IMAGE hashicorp/middleman-hashicorp:0.3.40
8    ember: &EMBER_IMAGE circleci/node:8-browsers
9
10  paths:
11    test-results: &TEST_RESULTS_DIR /tmp/test-results
12
13  cache:
14    yarn: &YARN_CACHE_KEY consul-ui-v1-{{ checksum "ui-v2/yarn.lock" }}
15    rubygem: &RUBYGEM_CACHE_KEY static-site-gems-v1-{{ checksum "Gemfile.lock" }}
16
17  environment: &ENVIRONMENT
18    TEST_RESULTS_DIR: *TEST_RESULTS_DIR
19    GOTESTSUM_RELEASE: 0.3.3
20    EMAIL: noreply@hashicorp.com
21    GIT_AUTHOR_NAME: circleci-consul
22    GIT_COMMITTER_NAME: circleci-consul
23    S3_ARTIFACT_BUCKET: consul-dev-artifacts
24    BASH_ENV: .circleci/bash_env.sh
25    VAULT_BINARY_VERSION: 1.2.2
26
27jobs:
28  # lint consul tests
29  lint-consul-retry:
30    docker:
31      - image: *GOLANG_IMAGE
32    steps:
33      - checkout
34      - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry
35
36  # Runs go fmt and go vet
37  go-fmt-and-vet:
38    docker:
39      - image: *GOLANG_IMAGE
40    steps:
41      - checkout
42      - restore_cache:
43          keys:
44            - consul-modcache-v1-{{ checksum "go.mod" }}
45      - run:
46          command: go mod download
47      - save_cache:
48          key: consul-modcache-v1-{{ checksum "go.mod" }}
49          paths:
50            - /go/pkg/mod
51      - run:
52          name: check go fmt
53          command: |
54            files="$(go fmt ./... ; (cd api && go fmt ./... | sed 's@^@api/@') ; (cd sdk && go fmt ./... | sed 's@^@sdk/@'))"
55            if [ -n "$files" ]; then
56                echo "The following file(s) do not conform to go fmt:"
57                echo "$files"
58                exit 1
59            fi
60      - run:
61          command: |
62            go vet ./... && \
63              (cd api && go vet ./...) && \
64              (cd sdk && go vet ./...)
65    environment:
66      <<: *ENVIRONMENT
67
68  # checks vendor directory is correct
69  check-vendor:
70    docker:
71      - image: *GOLANG_IMAGE
72    environment:
73      <<: *ENVIRONMENT
74    steps:
75      - checkout
76      - restore_cache:
77          keys:
78            - consul-modcache-v1-{{ checksum "go.mod" }}
79      - run:
80          command: make update-vendor
81      - save_cache:
82          key: consul-modcache-v1-{{ checksum "go.mod" }}
83          paths:
84            - /go/pkg/mod
85      - run: |
86          if ! git diff --exit-code; then
87            echo "Git directory has vendor changes"
88            exit 1
89          fi
90
91  go-test:
92    docker:
93      - image: *GOLANG_IMAGE
94    parallelism: 4
95    environment:
96      <<: *ENVIRONMENT
97      GOTAGS: "" # No tags for OSS but there are for enterprise
98      # GOMAXPROCS defaults to number of cores on underlying hardware, set explicitly to avoid OOM issues https://support.circleci.com/hc/en-us/articles/360034684273-common-GoLang-memory-issues
99      GOMAXPROCS: 2 # medium (default) boxes are 2 vCPUs, 4GB RAM https://circleci.com/docs/2.0/configuration-reference/#docker-executor
100    steps:
101      - checkout
102      - restore_cache: # restore cache from earlier job
103          keys:
104            - consul-modcache-v1-{{ checksum "go.mod" }}
105      - attach_workspace:
106          at: /go/bin
107      - run: mkdir -p $TEST_RESULTS_DIR
108      - run: sudo apt-get update && sudo apt-get install -y rsyslog
109      - run: sudo service rsyslog start
110      - run: |
111          PACKAGE_NAMES=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname)
112          echo "Running $(echo $PACKAGE_NAMES | wc -w) packages"
113          echo $PACKAGE_NAMES
114          gotestsum --format=short-verbose --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- -tags=$GOTAGS -p 2 -cover -coverprofile=cov_$CIRCLE_NODE_INDEX.part $PACKAGE_NAMES
115
116      # save coverage report parts
117      - persist_to_workspace:
118          root: .
119          paths:
120            - cov_*.part
121
122      - store_test_results:
123          path: *TEST_RESULTS_DIR
124      - store_artifacts:
125          path: *TEST_RESULTS_DIR
126
127  # split off a job for the API package since it is separate
128  go-test-api:
129    docker:
130      - image: *GOLANG_IMAGE
131    environment:
132      <<: *ENVIRONMENT
133      GOTAGS: "" # No tags for OSS but there are for enterprise
134    steps:
135      - checkout
136      - restore_cache: # restore cache from dev-build job
137          keys:
138            - consul-modcache-v1-{{ checksum "go.mod" }}
139      - attach_workspace:
140          at: /go/bin
141      - run: mkdir -p $TEST_RESULTS_DIR
142      - run:
143          working_directory: api
144          command: |
145            PACKAGE_NAMES=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname)
146            gotestsum --format=short-verbose --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- -tags=$GOTAGS -cover -coverprofile=cov_api.part $PACKAGE_NAMES
147
148      # save coverage report parts
149      - persist_to_workspace:
150          root: ./api
151          paths:
152            - cov_*.part
153
154      - store_test_results:
155          path: *TEST_RESULTS_DIR
156      - store_artifacts:
157          path: *TEST_RESULTS_DIR
158
159  # combine code coverage results from the parallel circleci executors
160  coverage-merge:
161    docker:
162      - image: *GOLANG_IMAGE
163    environment:
164      <<: *ENVIRONMENT
165    steps:
166      - checkout
167      - attach_workspace:
168          at: .
169      - run: mkdir -p $TEST_RESULTS_DIR
170      - run:
171          name: merge coverage reports
172          command: |
173            echo "mode: set" > coverage.out
174            grep -h -v "mode: set" cov_*.part >> coverage.out
175            go tool cover -html=coverage.out -o $TEST_RESULTS_DIR/coverage.html
176      - run:
177          name: codecov upload
178          command: bash <(curl -s https://codecov.io/bash) -v -C $CIRCLE_SHA1 -f '!agent/bindata_assetfs.go'
179      - store_artifacts:
180          path: *TEST_RESULTS_DIR
181
182  # build all distros
183  build-distros: &build-distros
184    docker:
185      - image: *GOLANG_IMAGE
186    environment: &build-env
187      <<: *ENVIRONMENT
188    steps:
189      - checkout
190      - restore_cache: # restore cache from dev-build job
191          keys:
192            - consul-modcache-v1-{{ checksum "go.mod" }}
193      - run: ./build-support/scripts/build-local.sh
194
195      # save dev build to CircleCI
196      - store_artifacts:
197          path: ./pkg/bin
198
199  # build all 386 architecture supported OS binaries
200  build-386:
201    <<: *build-distros
202    environment:
203      <<: *build-env
204      XC_OS: "darwin freebsd linux windows"
205      XC_ARCH: "386"
206
207  # build all amd64 architecture supported OS binaries
208  build-amd64:
209    <<: *build-distros
210    environment:
211      <<: *build-env
212      XC_OS: "darwin freebsd linux solaris windows"
213      XC_ARCH: "amd64"
214
215  # build all arm/arm64 architecture supported OS binaries
216  build-arm:
217    docker:
218      - image: *GOLANG_IMAGE
219    environment:
220      <<: *ENVIRONMENT
221      CGO_ENABLED: 1
222      GOOS: linux
223    steps:
224      - checkout
225      - run: sudo apt-get update && sudo apt-get install -y gcc-arm-linux-gnueabi gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu
226      - run:
227          environment:
228            GOARM: 5
229            CC: arm-linux-gnueabi-gcc
230            GOARCH: arm
231          command: go build -o ./pkg/bin/linux_armel/consul  -ldflags="${GOLDFLAGS}"
232      - run:
233          environment:
234            GOARM: 6
235            CC: arm-linux-gnueabihf-gcc
236            GOARCH: arm
237          command: go build -o ./pkg/bin/linux_armhf/consul  -ldflags="${GOLDFLAGS}"
238      - run:
239          environment:
240            CC: aarch64-linux-gnu-gcc
241            GOARCH: arm64
242          command: go build -o ./pkg/bin/linux_aarch64/consul  -ldflags="${GOLDFLAGS}"
243      - store_artifacts:
244          path: ./pkg/bin
245
246  # create a development build
247  dev-build:
248    docker:
249      - image: *GOLANG_IMAGE
250    environment:
251      <<: *ENVIRONMENT
252    steps:
253      - checkout
254      - restore_cache:
255          keys:
256            - consul-modcache-v1-{{ checksum "go.mod" }}
257      - run:
258          command: make dev
259      - save_cache:
260          key: consul-modcache-v1-{{ checksum "go.mod" }}
261          paths:
262            - /go/pkg/mod
263
264      # save dev build to pass to downstream jobs
265      - persist_to_workspace:
266          root: /go/bin
267          paths:
268            - consul
269
270  # upload development build to s3
271  dev-upload-s3:
272    docker:
273      - image: circleci/python:stretch
274    environment:
275      <<: *ENVIRONMENT
276    steps:
277      - run:
278          name: Install awscli
279          command: sudo pip install awscli
280      # get consul binary
281      - attach_workspace:
282          at: bin/
283      - run:
284          name: package binary
285          command: tar -czf consul.tar.gz -C bin/ .
286      - run:
287          name: Upload to s3
288          command: |
289            if [ -n "${S3_ARTIFACT_PATH}" ]; then
290              aws s3 cp \
291              --metadata "CIRCLECI=${CIRCLECI},CIRCLE_BUILD_URL=${CIRCLE_BUILD_URL},CIRCLE_BRANCH=${CIRCLE_BRANCH}" \
292              "consul.tar.gz" "s3://${S3_ARTIFACT_BUCKET}/${S3_ARTIFACT_PATH}/${CIRCLE_SHA1}.tar.gz"
293            else
294              echo "CircleCI - S3_ARTIFACT_PATH was not set"
295              exit 1
296            fi
297
298  # upload dev docker image
299  dev-upload-docker:
300    docker:
301      - image: circleci/golang:latest # use a circleci image so the attach_workspace step works (has ca-certs installed)
302    environment:
303      <<: *ENVIRONMENT
304    steps:
305      - checkout
306      # get consul binary
307      - attach_workspace:
308          at: bin/
309      - setup_remote_docker:
310          docker_layer_caching: true
311      - run: make ci.dev-docker
312
313  # Nomad 0.8 builds on go0.10
314  # Run integration tests on nomad/v0.8.7
315  nomad-integration-0_8:
316    docker:
317      - image: circleci/golang:1.10
318    environment:
319      <<: *ENVIRONMENT
320      NOMAD_WORKING_DIR: &NOMAD_WORKING_DIR /go/src/github.com/hashicorp/nomad
321      NOMAD_VERSION: v0.8.7
322    steps: &NOMAD_INTEGRATION_TEST_STEPS
323      - run: git clone https://github.com/hashicorp/nomad.git --branch ${NOMAD_VERSION} ${NOMAD_WORKING_DIR}
324
325      # get consul binary
326      - attach_workspace:
327          at: /go/bin
328
329      # make test result directory
330      - run: mkdir -p $TEST_RESULTS_DIR
331
332      # make dev build of nomad
333      - run:
334          command: make pkg/linux_amd64/nomad
335          working_directory: *NOMAD_WORKING_DIR
336
337      # update gotestsum
338      - run: curl -sSL "https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_RELEASE}/gotestsum_${GOTESTSUM_RELEASE}_linux_amd64.tar.gz" | sudo tar --overwrite -xz -C /usr/local/bin gotestsum
339
340      # run integration tests
341      - run:
342          command: gotestsum --format=short-verbose --junitfile $TEST_RESULTS_DIR/results.xml -- ./command/agent/consul -run TestConsul
343          working_directory: *NOMAD_WORKING_DIR
344
345      # store test results for CircleCI
346      - store_test_results:
347          path: *TEST_RESULTS_DIR
348      - store_artifacts:
349          path: *TEST_RESULTS_DIR
350
351  # run integration tests on nomad/master
352  nomad-integration-master:
353    docker:
354      - image: *GOLANG_IMAGE
355    environment:
356      <<: *ENVIRONMENT
357      NOMAD_WORKING_DIR: /go/src/github.com/hashicorp/nomad
358      NOMAD_VERSION: master
359    steps: *NOMAD_INTEGRATION_TEST_STEPS
360
361  build-website:
362    # setting the working_directory along with the checkout path allows us to not have
363    # to cd into the website/ directory for commands
364    working_directory: ~/project/website
365    docker:
366      - image: *MIDDLEMAN_IMAGE
367    steps:
368      - checkout:
369          path: ~/project
370
371      # restores gem cache
372      - restore_cache:
373          key: *RUBYGEM_CACHE_KEY
374
375      - run:
376          name: install gems
377          command: bundle check || bundle install --path vendor/bundle --retry=3
378
379      # saves gem cache if we have changed the Gemfile
380      - save_cache:
381          key: *RUBYGEM_CACHE_KEY
382          paths:
383            - ~/project/website/vendor/bundle
384
385      # exclude guides directory since they moved to learn.hashicorp.com
386      # keep index.html which points to learn
387      - run:
388          name: exclude guides
389          command: find ./source/docs/guides -type f -not -name 'index.html.md' -delete
390
391      - run:
392          name: middleman build
393          command: bundle exec middleman build
394
395      - run:
396          name: add missing tar binary
397          command: apk update && apk add tar
398
399      # saves website build directory
400      - persist_to_workspace:
401          root: .
402          paths:
403            - build
404
405  deploy-website:
406    # setting the working_directory along with the checkout path allows us to not have
407    # to cd into the website/ directory for commands
408    working_directory: ~/project/website
409    docker:
410      - image: *MIDDLEMAN_IMAGE
411    steps:
412      - checkout:
413          path: ~/project
414
415      - run:
416          name: add missing tar binary
417          command: apk update && apk add tar
418
419      # attach website build directory
420      - attach_workspace:
421          at: ~/project/website
422
423      # restores gem cache
424      - restore_cache:
425          key: *RUBYGEM_CACHE_KEY
426      # rerun build with 'ENV=production' to add analytics
427      - run:
428          name: install gems
429          command: bundle check || bundle install --path vendor/bundle --retry=3
430
431      # exclude guides directory since they moved to learn.hashicorp.com
432      # keep index.html which points to learn
433      - run:
434          name: exclude guides
435          command: find ./source/docs/guides -type f -not -name 'index.html.md' -delete
436
437      # rerun build with 'ENV=production' to add analytics
438      - run:
439          name: middleman build
440          command: bundle exec middleman build
441
442      - run:
443          name: website deploy
444          command: ./scripts/deploy.sh
445
446  # Link check on a temporary netlify deployed site
447  docs-link-checker:
448    docker:
449      - image: circleci/node:lts
450    steps:
451      - checkout
452      # attach website build directory
453      - attach_workspace:
454          at: ~/project/website
455      - run: ./website/scripts/link-check.sh
456
457  # build frontend yarn cache
458  frontend-cache:
459    docker:
460      - image: *EMBER_IMAGE
461    steps:
462      - checkout
463
464      # cache yarn deps
465      - restore_cache:
466          key: *YARN_CACHE_KEY
467
468      - run:
469          name: install yarn packages
470          command: cd ui-v2 && yarn install
471
472      - save_cache:
473          key: *YARN_CACHE_KEY
474          paths:
475            - ui-v2/node_modules
476
477  # build ember so frontend tests run faster
478  ember-build:
479    docker:
480      - image: *EMBER_IMAGE
481    steps:
482      - checkout
483      - restore_cache:
484          key: *YARN_CACHE_KEY
485      - run: cd ui-v2 && make build-ci
486
487      # saves the build to a workspace to be passed to a downstream job
488      - persist_to_workspace:
489          root: ui-v2
490          paths:
491            - dist
492
493  # run ember frontend tests
494  ember-test-oss:
495    docker:
496      - image: *EMBER_IMAGE
497    environment:
498      EMBER_TEST_REPORT: test-results/report-oss.xml #outputs test report for CircleCI test summary
499    steps:
500      - checkout
501      - restore_cache:
502          key: *YARN_CACHE_KEY
503      - attach_workspace:
504          at: ui-v2
505      - run:
506          working_directory: ui-v2
507          command: make test-oss-ci
508      - store_test_results:
509          path: ui-v2/test-results
510  # run ember frontend tests
511  ember-test-ent:
512    docker:
513      - image: *EMBER_IMAGE
514    environment:
515      EMBER_TEST_REPORT: test-results/report-ent.xml #outputs test report for CircleCI test summary
516    steps:
517      - checkout
518      - restore_cache:
519          key: *YARN_CACHE_KEY
520      - attach_workspace:
521          at: ui-v2
522      - run:
523          working_directory: ui-v2
524          command: make test-ci
525      - store_test_results:
526          path: ui-v2/test-results
527
528  envoy-integration-test-1.10.0:
529    docker:
530      # We only really need bash and docker-compose which is installed on all
531      # Circle images but pick Go since we have to pick one of them.
532      - image: *GOLANG_IMAGE
533    environment:
534      ENVOY_VERSIONS: "1.10.0"
535    steps: &ENVOY_INTEGRATION_TEST_STEPS
536      - checkout
537      # Get go binary from workspace
538      - attach_workspace:
539          at: .
540      - setup_remote_docker:
541          docker_layer_caching: true
542      # Build the consul-dev image from the already built binary
543      - run: docker build -t consul-dev -f ./build-support/docker/Consul-Dev.dockerfile .
544      - run:
545          name: Envoy Integration Tests
546          command: make test-envoy-integ SKIP_DOCKER_BUILD=1
547          environment:
548            # tput complains if this isn't set to something.
549            TERM: ansi
550      - store_artifacts:
551          path: ./test/integration/connect/envoy/workdir/logs
552          destination: container-logs
553
554  envoy-integration-test-1.11.2:
555    docker:
556      - image: *GOLANG_IMAGE
557    environment:
558      ENVOY_VERSIONS: "1.11.2"
559    steps: *ENVOY_INTEGRATION_TEST_STEPS
560
561  envoy-integration-test-1.12.2:
562    docker:
563      - image: *GOLANG_IMAGE
564    environment:
565      ENVOY_VERSIONS: "1.12.2"
566    steps: *ENVOY_INTEGRATION_TEST_STEPS
567
568  envoy-integration-test-1.13.0:
569    docker:
570      - image: *GOLANG_IMAGE
571    environment:
572      ENVOY_VERSIONS: "1.13.0"
573    steps: *ENVOY_INTEGRATION_TEST_STEPS
574
575  # run tests on vault ca provider integration tests
576  vault-ca-provider:
577    docker:
578      - image: *GOLANG_IMAGE
579    environment:
580      <<: *ENVIRONMENT
581    steps:
582      # Install vault
583      - run: |
584          wget -q -O /tmp/vault.zip https://releases.hashicorp.com/vault/${VAULT_BINARY_VERSION}/vault_${VAULT_BINARY_VERSION}_linux_amd64.zip
585          sudo unzip -d /usr/local/bin /tmp/vault.zip
586          rm -rf /tmp/vault*
587      # Create directory to store test results
588      - run: mkdir -p $TEST_RESULTS_DIR
589      # Gather deps to run go tests
590      - checkout
591      - restore_cache:
592          keys:
593            - consul-modcache-v1-{{ checksum "go.mod" }}
594      # Run go tests
595      - run: make test-vault-ca-provider
596      - store_test_results:
597          path: *TEST_RESULTS_DIR
598
599workflows:
600  version: 2
601  go-tests:
602    jobs:
603      - check-vendor:
604          filters:
605            branches:
606              ignore:
607                - stable-website
608      - lint-consul-retry
609      - go-fmt-and-vet:
610          requires:
611            - check-vendor
612      - dev-build:
613          requires:
614            - go-fmt-and-vet
615      - go-test: &go-test
616          requires:
617            - dev-build
618      - go-test-api: *go-test
619      - coverage-merge:
620          requires:
621            - go-test
622            - go-test-api
623  build-distros:
624    jobs:
625      - check-vendor:
626          filters:
627            branches:
628              ignore:
629                - stable-website
630      - build-386: &require-check-vendor
631          requires:
632            - check-vendor
633      - build-amd64: *require-check-vendor
634      - build-arm: *require-check-vendor
635  test-integrations:
636    jobs:
637      - dev-build:
638          filters:
639            branches:
640              ignore:
641                - stable-website
642      - dev-upload-s3: &dev-upload
643          requires:
644            - dev-build
645          filters:
646            branches:
647              ignore:
648                - /^pull\/.*$/ # only push dev builds from non forks
649      - dev-upload-docker:
650          <<: *dev-upload
651          context: consul-ci
652      - nomad-integration-master:
653          requires:
654            - dev-build
655      - nomad-integration-0_8:
656          requires:
657            - dev-build
658      - envoy-integration-test-1.10.0:
659          requires:
660            - dev-build
661      - envoy-integration-test-1.11.2:
662          requires:
663            - dev-build
664      - envoy-integration-test-1.12.2:
665          requires:
666            - dev-build
667      - envoy-integration-test-1.13.0:
668          requires:
669            - dev-build
670      - vault-ca-provider:
671          requires:
672            - dev-build
673  website:
674    jobs:
675      - build-website
676      - docs-link-checker:
677          requires:
678            - build-website
679          filters:
680            branches:
681              ignore:
682                - /^pull\/.*$/ # only run link checker on non forks
683      - deploy-website:
684          requires:
685            - docs-link-checker
686          context: static-sites
687          filters:
688            branches:
689              only: stable-website
690  frontend:
691    jobs:
692      - frontend-cache:
693          filters:
694            branches:
695              ignore:
696                - stable-website
697      - ember-build:
698          requires:
699            - frontend-cache
700      - ember-test-oss:
701          requires:
702            - ember-build
703      - ember-test-ent:
704          requires:
705            - ember-build
706