Add test coverage comments to PRs (#15183)

* add test coverage comments to PRs

* [skip ci] update test coverage

* [skip ci] add .gitattributes to avoid merge conflicts with test coverage

* exempt main and release branches from coverage job

* [skip ci] update test coverage

* [skip ci] update test coverage

* clean up debug line, exit early if missing files

* [skip ci] update test coverage

* extract repository into variable to make porting to ENT easier

* [skip ci] update test coverage

Co-authored-by: hc-github-team-consul-core <github-team-consul-core@hashicorp.com>
This commit is contained in:
skpratt 2022-11-10 14:43:37 -06:00 committed by GitHub
parent ee56e06f22
commit 958c9dd905
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 12564 additions and 19 deletions

View File

@ -56,7 +56,6 @@ steps:
url=https://github.com/gotestyourself/gotestsum/releases/download url=https://github.com/gotestyourself/gotestsum/releases/download
curl -sSL "${url}/v${GOTESTSUM_RELEASE}/gotestsum_${GOTESTSUM_RELEASE}_linux_${ARCH}.tar.gz" | \ curl -sSL "${url}/v${GOTESTSUM_RELEASE}/gotestsum_${GOTESTSUM_RELEASE}_linux_${ARCH}.tar.gz" | \
sudo tar -xz --overwrite -C /usr/local/bin gotestsum sudo tar -xz --overwrite -C /usr/local/bin gotestsum
get-aws-cli: &get-aws-cli get-aws-cli: &get-aws-cli
run: run:
name: download and install AWS CLI name: download and install AWS CLI
@ -67,7 +66,6 @@ steps:
gpg --verify awscliv2.sig awscliv2.zip gpg --verify awscliv2.sig awscliv2.zip
unzip awscliv2.zip unzip awscliv2.zip
sudo ./aws/install sudo ./aws/install
# This step MUST be at the end of any set of steps due to the 'when' condition # This step MUST be at the end of any set of steps due to the 'when' condition
notify-slack-failure: &notify-slack-failure notify-slack-failure: &notify-slack-failure
name: notify-slack-failure name: notify-slack-failure
@ -94,7 +92,6 @@ steps:
else else
echo "Not posting slack failure notifications for non-main branch" echo "Not posting slack failure notifications for non-main branch"
fi fi
commands: commands:
assume-role: assume-role:
description: "Assume role to an ARN" description: "Assume role to an ARN"
@ -121,7 +118,6 @@ commands:
echo "export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')" >> $BASH_ENV echo "export AWS_SECRET_ACCESS_KEY=$(echo $CREDENTIALS | jq -r '.SecretAccessKey')" >> $BASH_ENV
echo "export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.SessionToken')" >> $BASH_ENV echo "export AWS_SESSION_TOKEN=$(echo $CREDENTIALS | jq -r '.SessionToken')" >> $BASH_ENV
fi fi
run-go-test-full: run-go-test-full:
parameters: parameters:
go_test_flags: go_test_flags:
@ -134,15 +130,13 @@ commands:
- run: - run:
name: go test name: go test
command: | command: |
mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile mkdir -p $TEST_RESULTS_DIR /tmp/jsonfile /tmp/coverage
PACKAGE_NAMES=$(go list -tags "$GOTAGS" ./... | circleci tests split --split-by=timings --timings-type=classname) PACKAGE_NAMES=$(go list -tags "$GOTAGS" ./... | circleci tests split --split-by=timings --timings-type=classname)
echo "Running $(echo $PACKAGE_NAMES | wc -w) packages" echo "Running $(echo $PACKAGE_NAMES | wc -w) packages"
echo $PACKAGE_NAMES echo $PACKAGE_NAMES
# some tests expect this umask, and arm images have a different default # some tests expect this umask, and arm images have a different default
umask 0022 umask 0022
<< parameters.go_test_flags >> << parameters.go_test_flags >>
gotestsum \ gotestsum \
--format=short-verbose \ --format=short-verbose \
--jsonfile /tmp/jsonfile/go-test-${CIRCLE_NODE_INDEX}.log \ --jsonfile /tmp/jsonfile/go-test-${CIRCLE_NODE_INDEX}.log \
@ -154,14 +148,17 @@ commands:
--junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \
-tags="$GOTAGS" -p 2 \ -tags="$GOTAGS" -p 2 \
${GO_TEST_FLAGS-} \ ${GO_TEST_FLAGS-} \
-cover -coverprofile=coverage.txt -cover -coverprofile=/tmp/coverage/test-coverage-$CIRCLE_NODE_INDEX || true
- store_test_results: - store_test_results:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- store_artifacts: - store_artifacts:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- store_artifacts: - store_artifacts:
path: /tmp/jsonfile path: /tmp/jsonfile
- persist_to_workspace:
root: /tmp
paths:
- coverage
- run: &rerun-fails-report - run: &rerun-fails-report
name: "Re-run fails report" name: "Re-run fails report"
command: | command: |
@ -280,7 +277,6 @@ jobs:
echo "Generated code was not updated correctly" echo "Generated code was not updated correctly"
exit 1 exit 1
fi fi
go-test-arm64: go-test-arm64:
machine: machine:
image: *UBUNTU_CI_IMAGE image: *UBUNTU_CI_IMAGE
@ -355,7 +351,6 @@ jobs:
-tags="$GOTAGS" -p 2 \ -tags="$GOTAGS" -p 2 \
-race -gcflags=all=-d=checkptr=0 \ -race -gcflags=all=-d=checkptr=0 \
$pkgs $pkgs
- store_test_results: - store_test_results:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- store_artifacts: - store_artifacts:
@ -396,7 +391,6 @@ jobs:
--junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \
-tags="$GOTAGS" -p 2 \ -tags="$GOTAGS" -p 2 \
-short -short
- store_test_results: - store_test_results:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- store_artifacts: - store_artifacts:
@ -433,7 +427,6 @@ jobs:
--junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \ --junitfile $TEST_RESULTS_DIR/gotestsum-report.xml -- \
-tags="$GOTAGS" -cover -coverprofile=coverage.txt \ -tags="$GOTAGS" -cover -coverprofile=coverage.txt \
./... ./...
- store_test_results: - store_test_results:
path: *TEST_RESULTS_DIR path: *TEST_RESULTS_DIR
- store_artifacts: - store_artifacts:
@ -458,7 +451,6 @@ jobs:
target="./pkg/bin/${GOOS}_${GOARCH}/" target="./pkg/bin/${GOOS}_${GOARCH}/"
GOOS="$os" CGO_ENABLED=0 go build -o "${target}" -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}" GOOS="$os" CGO_ENABLED=0 go build -o "${target}" -ldflags "${GOLDFLAGS}" -tags "${GOTAGS}"
done done
# save dev build to CircleCI # save dev build to CircleCI
- store_artifacts: - store_artifacts:
path: ./pkg/bin path: ./pkg/bin
@ -530,7 +522,6 @@ jobs:
make dev make dev
mkdir -p /home/circleci/go/bin mkdir -p /home/circleci/go/bin
cp ./bin/consul /home/circleci/go/bin/consul cp ./bin/consul /home/circleci/go/bin/consul
# save dev build to pass to downstream jobs # save dev build to pass to downstream jobs
- persist_to_workspace: - persist_to_workspace:
root: /home/circleci/go/bin root: /home/circleci/go/bin
@ -722,11 +713,9 @@ jobs:
if ! git diff --quiet --exit-code HEAD^! ui/; then if ! git diff --quiet --exit-code HEAD^! ui/; then
git config --local user.email "github-team-consul-core@hashicorp.com" git config --local user.email "github-team-consul-core@hashicorp.com"
git config --local user.name "hc-github-team-consul-core" git config --local user.name "hc-github-team-consul-core"
# -B resets the CI branch to main which may diverge history # -B resets the CI branch to main which may diverge history
# but we will force push anyways. # but we will force push anyways.
git checkout -B ci/main-assetfs-build main git checkout -B ci/main-assetfs-build main
short_sha=$(git rev-parse --short HEAD) short_sha=$(git rev-parse --short HEAD)
git add agent/uiserver/dist/ git add agent/uiserver/dist/
git commit -m "auto-updated agent/uiserver/dist/ from commit ${short_sha}" git commit -m "auto-updated agent/uiserver/dist/ from commit ${short_sha}"
@ -989,7 +978,6 @@ jobs:
fi fi
echo "export LOCAL_COMMIT_SHA=${LOCAL_COMMIT_SHA}" >> $BASH_ENV echo "export LOCAL_COMMIT_SHA=${LOCAL_COMMIT_SHA}" >> $BASH_ENV
git checkout ${LOCAL_COMMIT_SHA} git checkout ${LOCAL_COMMIT_SHA}
short_ref=$(git rev-parse --short ${LOCAL_COMMIT_SHA}) short_ref=$(git rev-parse --short ${LOCAL_COMMIT_SHA})
echo "export TF_VAR_ami_owners=$LOAD_TEST_AMI_OWNERS" >> $BASH_ENV echo "export TF_VAR_ami_owners=$LOAD_TEST_AMI_OWNERS" >> $BASH_ENV
echo "export TF_VAR_vpc_name=$short_ref" >> $BASH_ENV echo "export TF_VAR_vpc_name=$short_ref" >> $BASH_ENV
@ -1036,6 +1024,83 @@ jobs:
steps: steps:
- run: "echo ok" - run: "echo ok"
show-coverage:
docker:
- image: *GOLANG_IMAGE
steps:
- checkout
- attach_workspace:
at: /tmp
- run:
name: collate coverage output into single file and convert to readable format
command: |
mkdir -p /tmp/output
echo "mode: set" > cov.txt
for f in /tmp/coverage/*; do tail -n +2 $f >> cov.txt; done
go tool cover -func=cov.txt -o /tmp/output/coverage_by_function.txt
cp cov.txt /tmp/output/cov.txt
- run: sudo apt-get install jq
- run:
name: get diff of test coverage from changes
command: |
repository="consul"
file_url_response=$(curl --location --request GET "https://api.github.com/repos/hashicorp/$repository/contents/.github/cover.out?ref=$TEST_COVERAGE_GOLDEN_BRANCH" \
-u $GH_USER:$GH_TOKEN)
if [ $(echo $file_url_response | jq length) -eq 0 ]; then
echo "No coverage report file found"
exit 1
else
file_download_url=$(echo $file_url_response | jq -r '.download_url')
fi
echo "Downloading $file_download_url"
curl "$file_download_url" > main_cov.txt
echo "mode: set" > diff_cov.txt
comm -13 <(sort main_cov.txt) <(sort cov.txt) >> diff_cov.txt
go tool cover -html=diff_cov.txt -o /tmp/output/diff_coverage_heatmap.html
- store_artifacts:
path: /tmp/output
- run:
name: post results to GitHub PR
command: |
repository="consul"
pr_response=$(curl --location --request GET "https://api.github.com/repos/hashicorp/$repository/pulls?head=hashicorp:$CIRCLE_BRANCH&state=open" \
-u $GH_USER:$GH_TOKEN)
if [ $(echo $pr_response | jq length) -eq 0 ]; then
echo "No PR found to update"
exit 1
else
pr_comment_url=$(echo $pr_response | jq -r ".[]._links.comments.href")
fi
new_cov_percent=$(tail -1 /tmp/output/coverage_by_function.txt | awk -F' ' '{print $NF}')
go tool cover -func=main_cov.txt -o main_cov_by_func.txt
main_go_test_cov_percent=$(tail -1 main_cov_by_func.txt | awk -F' ' '{print $NF}')
artifacts=$(curl -X GET "https://circleci.com/api/v2/project/github/hashicorp/$repository/$CIRCLE_BUILD_NUM/artifacts" \
-H "Accept: application/json" \
-u "$CIRCLE_API_TOKEN:")
heatmap_url=$(echo $artifacts | jq -r '.items|.[]|select(.path | endswith("heatmap.html"))|.url')
message="All unit tests passed! Your changes bring test coverage over affected code to $new_cov_percent. Total coverage in main is $main_go_test_cov_percent. [See coverage delta for your changes]($heatmap_url)"
curl --location --request POST "$pr_comment_url" \
-u hc-github-team-consul-core:$HC_GITHUB_TEAM_CONSUL_CORE_GITHUB_TOKEN \
--header 'Content-Type: application/json' \
--data-raw '{
"body": "'"$message"'"
}'
- add_ssh_keys:
fingerprints:
- "b1:4d:ed:a5:4f:e1:39:28:37:ab:bd:4d:06:e5:24:ca"
- run:
name: push latest coverage results to github
command: |
cp cov.txt .github/go_test_coverage.txt
git config user.email "github-team-consul-core@hashicorp.com"
git config user.name "hc-github-team-consul-core"
git add .github/go_test_coverage.txt
git commit -m "[skip ci] update test coverage"
git push --set-upstream origin $CIRCLE_BRANCH
workflows: workflows:
version: 2 version: 2
# verify-ci is a no-op workflow that must run on every PR. It is used in a # verify-ci is a no-op workflow that must run on every PR. It is used in a
@ -1089,6 +1154,15 @@ workflows:
<<: *filter-ignore-non-go-branches <<: *filter-ignore-non-go-branches
- go-test-race: *filter-ignore-non-go-branches - go-test-race: *filter-ignore-non-go-branches
- go-test-32bit: *filter-ignore-non-go-branches - go-test-32bit: *filter-ignore-non-go-branches
- show-coverage:
requires:
- go-test
filters:
branches:
ignore:
- main # we don't want tests run in main to overwrite coverage reports from the latest merge
- /^release\/.*$/ # we don't want to compare coverage on release branches
- noop - noop
build-distros: build-distros:
unless: << pipeline.parameters.trigger-load-test >> unless: << pipeline.parameters.trigger-load-test >>
@ -1202,4 +1276,4 @@ workflows:
only: only:
- main - main
jobs: jobs:
- load-test - load-test

1
.github/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
go_test_coverage.txt binary

12470
.github/go_test_coverage.txt vendored Normal file

File diff suppressed because it is too large Load Diff