-
Notifications
You must be signed in to change notification settings - Fork 3
/
cloudbuild.yaml
192 lines (155 loc) · 7.97 KB
/
cloudbuild.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# To trigger manually, use `gcloud builds submit --config cloudbuild.yaml`
# Note: manual triggers differ from GitHub triggers on the available built in substitution values
# deploy/make_cloud_build_env_file.sh is responsible for providing local fallbacks as needed
# [START django_cloudbuild]
steps:
- id: "Make .env.cloud_build for subsequent steps"
name: gcr.io/cloud-builders/gcloud
env:
- "BRANCH_NAME=${BRANCH_NAME}"
- "COMMIT_SHA=${COMMIT_SHA}"
script: |
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
echo "Write .env.cloud_build to disk, to provide consistent project configuration (no secrets) in subsequent steps"
deploy/make_cloud_build_env_file.sh "${BRANCH_NAME}" "${COMMIT_SHA}"
- id: "Run tests"
name: "gcr.io/cloud-builders/docker"
script: |
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
echo "Get cloud build project configuration values"
source .env.cloud_build
echo "Make globally writable coverge dir, to be mounted as a volume on the test container"
mkdir --mode 777 ./coverage
echo "Build images for testing, run tests and create report"
# NOTE: Tests are run within docker compose. When "--exit-code-from" is used, and the build or a command fails, this flag will cause the step to fail.
# Test coverage reports are generated twice:
# 1 - to terminal to be printed in Cloud Build Logs
# 2 - to coverage.json in mounted ./coverage volume.
docker compose -f docker-compose.run-tests.yaml up --exit-code-from server
echo "Tear down tests"
docker compose -f docker-compose.run-tests.yaml down -v
- id: "Run format checks"
name: "gcr.io/cloud-builders/docker"
script: |
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
echo "Get cloud build project configuration values"
source .env.cloud_build
echo "Build images for format checking"
# NOTE: Tests are run within docker compose. When "--exit-code-from" is used, and the build or a command fails, this flag will cause the step to fail.
docker compose -f docker-compose.run-format-checks.yaml up --exit-code-from server
echo "Tear down format-checking"
docker compose -f docker-compose.run-format-checks.yaml down -v
- id: "Upload test coverage reports to Google Cloud Storage"
name: 'gcr.io/cloud-builders/gsutil'
script: |
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
echo "Get cloud build project configuration values"
source .env.cloud_build
# Instantiate a failure reasons array
failure_reasons=()
echo "Copy test coverage report from docker volume to a google cloud storage bucket."
timestamp=$(date +%s)
gsutil cp ./coverage/coverage.json "gs://${TEST_COVERAGE_BUCKET_NAME}/${BRANCH_NAME}/${timestamp}-${COMMIT_SHA}.json"
# Install jq and bc
apt-get update && apt-get install -y jq bc
this_commit_coverage=$(jq '.totals.percent_covered' ./coverage/coverage.json | awk '{printf "%.2f\n", $1}')
echo ""
echo "This commit's report: gs://${TEST_COVERAGE_BUCKET_NAME}/${BRANCH_NAME}/${timestamp}-${COMMIT_SHA}.json"
echo "This commit's test coverage: ${this_commit_coverage}%"
echo ""
echo "Retrieving coverage report for the last commit to the main GitHub deployment branch."
last_github_deployment_branch_coverage_report=$(gsutil ls "gs://${TEST_COVERAGE_BUCKET_NAME}/${GITHUB_MAIN_BRANCH_NAME}" | sort | tail -n 2 | head -n 1)
if [ -z "${last_github_deployment_branch_coverage_report}" ]; then
echo "No coverage reports for the main GitHub deployment branch found."
coverage_difference=${this_commit_coverage}
else
# Find coverage delta between this commit and last commit to main GitHub deployment branch.
echo "Last commit to the main GitHub deployment branch's report: ${last_github_deployment_branch_coverage_report}"
echo ""
echo "Calculating last commit to the main GitHub deployment branch's test coverage."
gsutil cp ${last_github_deployment_branch_coverage_report} ./coverage/last_github_deployment_branch_coverage_report.json
last_github_deployment_branch_coverage=$(jq '.totals.percent_covered' ./coverage/last_github_deployment_branch_coverage_report.json | awk '{printf "%.2f\n", $1}')
echo "Last commit to the main GitHub deployment branch's test coverage: ${last_github_deployment_branch_coverage}%"
echo ""
# echo "Test coverage threshold: ${TEST_COVERAGE_THRESHOLD}"
# echo ""
# echo "This commit's total test coverage: ${this_commit_coverage}%"
echo ""
coverage_difference=$(echo "${this_commit_coverage} - ${last_github_deployment_branch_coverage}" | bc)
fi
echo "------------------------------------------"
echo "Total coverage threshold: ${TEST_COVERAGE_THRESHOLD}%"
echo "Delta threshold: ${TEST_DELTA_THRESHOLD}%"
echo ""
echo "This commit: ${this_commit_coverage}%"
echo "Last main or master commit: ${last_github_deployment_branch_coverage}%"
echo "------------------------------------------"
echo "Delta between commits: ${coverage_difference}%"
echo ""
# Compare delta
if (( $(echo "${coverage_difference} < ${TEST_DELTA_THRESHOLD}" | bc -l) )); then
echo "Test coverage dropped to (${coverage_difference}%) which is more than the delta threshold of ${TEST_DELTA_THRESHOLD}%"
echo "Please increase the number of unit tests."
failure_reasons+=(" - the test coverage dropped more than the allowed delta from the main deployment branch ")
else
echo "Test coverage delta is within range."
fi
# Compare total coverage
if (( $(echo "${this_commit_coverage} < ${TEST_COVERAGE_THRESHOLD}" | bc -l) )); then
echo ""
echo "Coverage (${this_commit_coverage}%) is below the threshold of (${TEST_COVERAGE_THRESHOLD}%)"
echo "Please add more unit tests. See the test coverage report for more details."
echo ""
failure_reasons+=(" - total coverage is below threshold")
else
echo "Coverage (${this_commit_coverage}%) is above the threshold of ${TEST_COVERAGE_THRESHOLD}."
fi
if [ ${#failure_reasons[@]} -eq 0 ]; then
echo "Test coverage is suficient - continuing..."
else
echo "Insufficent test coverage"
for reason in "${failure_reasons[@]}"; do
echo "$reason"
done
# Exit/fail build if not the main branch; we want to enforce coverage on branches at PR time,
# but not totally block development/deployment from main over it
if [[ "${BRANCH_NAME}" != "${GITHUB_MAIN_BRANCH_NAME}" ]]; then
exit 1
else
echo "Continuing despite insufficient coverage..."
fi
fi
- id: "Build and push app and management image if main"
name: "gcr.io/cloud-builders/docker"
script: |
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
echo "Get cloud build environment variables"
source .env.cloud_build
if [[ "${BRANCH_NAME}" == "${GITHUB_MAIN_BRANCH_NAME}" ]]; then
echo "Build a new application run time image"
docker build -t "${RUNTIME_IMAGE_NAME_FOR_RUN}" -f ./server/Dockerfile.prod ./server
echo "Push the app run time image to the project's artifact registry"
docker push "${RUNTIME_IMAGE_NAME_FOR_RUN}"
echo "Build a corresponding management image"
docker build -t "${MANAGEMENT_IMAGE_NAME_FOR_RUN}" -f ./server/Dockerfile.dev-management ./server
echo "Push the management image to the project's artifact registry"
docker push "${MANAGEMENT_IMAGE_NAME_FOR_RUN}"
else
echo "pass"
fi
# [END django_cloudbuild]