From 00224c248094d32b65b1ec54e87e1d855e9359cb Mon Sep 17 00:00:00 2001 From: Gary Verhaegen Date: Mon, 3 Feb 2020 16:29:13 +0100 Subject: [PATCH] ci: alert Slack on PR build completion (#4286) One of the outputs of our brainstorming about how to make CI better was that it is annoying to have to "babysit" pull requests. This PR attempts to introduce a notification mechanism by which Azure will notify people on Slack when a build finishes, so they know they need to go and rerun or merge the corresponding PR. This commit also changes the existing $Slack.URL variable to $Slack.team-daml, to make more explicit where the Slack message is being sent to (Slack works with one token per destination channel). Both $Slack.URL and $Slack.team-daml are currently defined as the same token in Azure. CHANGELOG_BEGIN CHANGELOG_END --- azure-cron.yml | 2 +- azure-pipelines.yml | 97 ++++++++++++++++++++++++++++++++-------- ci/slack_user_ids | 4 ++ ci/tell-slack-failed.yml | 2 +- 4 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 ci/slack_user_ids diff --git a/azure-cron.yml b/azure-cron.yml index 36eb8dc33d..eb4d2b1cf8 100644 --- a/azure-cron.yml +++ b/azure-cron.yml @@ -45,7 +45,7 @@ jobs: -i \ -H 'Content-type: application/json' \ --data "{\"text\":\" *FAILED* Daily Docs: \n\"}" \ - $(Slack.URL) + $(Slack.team-daml) condition: and(failed(), eq(variables['Build.SourceBranchName'], 'master')) - template: ci/tell-slack-failed.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 01e7b02931..1258944e0d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,17 @@ pr: - master jobs: + - job: git_sha + pool: + name: 'linux-pool' + steps: + - bash: | + set -euo pipefail + echo "##vso[task.setvariable variable=branch;isOutput=true]$(git rev-parse 'HEAD^2')" + echo "##vso[task.setvariable variable=master;isOutput=true]$(git rev-parse 'HEAD^1')" + echo "##vso[task.setvariable variable=fork_point;isOutput=true]$(git merge-base --fork-point 'HEAD^1' 'HEAD^2')" + name: out + - job: check_standard_change_label condition: eq(variables['Build.Reason'], 'PullRequest') pool: @@ -306,7 +317,16 @@ jobs: - job: collect_build_data condition: always() - dependsOn: ["Linux", "macOS", "Windows", "Windows_signing", "perf", "release", "check_standard_change_label", "write_ledger_dump"] + dependsOn: + - Linux + - macOS + - Windows + - Windows_signing + - perf + - release + - check_standard_change_label + - write_ledger_dump + - git_sha pool: name: "linux-pool" variables: @@ -342,6 +362,11 @@ jobs: dump.machine: $[ dependencies.write_ledger_dump.outputs['start.machine'] ] dump.end: $[ dependencies.write_ledger_dump.outputs['end.time'] ] dump.status: $[ dependencies.write_ledger_dump.result ] + + branch_sha: $[ dependencies.git_sha.outputs['out.branch'] ] + master_sha: $[ dependencies.git_sha.outputs['out.master'] ] + fork_sha: $[ dependencies.git_sha.outputs['out.fork_point'] ] + # Using expression syntax so we get an empty string if not set, rather # than the raw $(VarName) string. Expression syntax works on the # variables key, but not on the env one, so we need an extra indirection. @@ -360,23 +385,12 @@ jobs: - checkout: none - bash: | set -euo pipefail - # Note: this is going to get the current master commit, not the + # Note: this is going to get the PR branch commit, not the # result of the merge (i.e. this is not using the same commit as the - # other jobs in this build). This seems good enough here as all we - # really want is the dev-env, and conflicts should be pretty rare - # there. It _does_ mean this may fail to catch changes that would - # break this job, e.g. incompatible updates of jq or gcloud. - # Note: Azure doe snot guarantee a clean workspace and dev-env - # doesn't nest, so we need to handle both a clean slate and an - # existing, dirty workspace. - if [ -d .git ]; then - git fetch - git reset --hard - git clean -xffd - git checkout origin/master - else - git clone https://github.com/digital-asset/daml.git ./ - fi + # other jobs in this build). + git fetch origin $(branch_sha) + git checkout $(branch_sha) + eval "$(./dev-env/bin/dade-assist)" REPORT=$(mktemp) @@ -420,7 +434,10 @@ jobs: "queued_by": "$(Build.QueuedBy)", "reason": "$(Build.Reason)", "branch": "$(Build.SourceBranch)", - "commit_sha": "$(Build.SourceVersion)", + "merge_commit": "$(Build.SourceVersion)", + "branch_commit": "$(branch_sha)", + "master_commit": "$(master_sha)", + "fork_point_commit": "$(fork_sha)", "commit_message": $(echo -n "$COMMIT_MSG" | jq -sR), "is_fork": "$(System.PullRequest.IsFork)", "pr": "$PR_NUM", @@ -472,3 +489,47 @@ jobs: # value or empty string, but not $(Azure.Variable.Name)). PR_NUM: $(pr.num) PR_BRANCH: $(pr.branch) + + - job: notify_user + condition: always() + dependsOn: + - git_sha + - collect_build_data + pool: + name: 'linux-pool' + variables: + pr.num: $[ variables['System.PullRequest.PullRequestNumber'] ] + branch_sha: $[ dependencies.git_sha.outputs['out.branch'] ] + steps: + - checkout: none + - bash: | + set -euo pipefail + + git fetch origin $(branch_sha) + git checkout $(branch_sha) + + + tell_slack() { + local MESSAGE=$1 + local USER_ID=$2 + curl -XPOST \ + -i \ + -H 'Content-Type: application/json' \ + --data "{\"text\":\"<@${USER_ID}> for has completed with status ${MESSAGE}.\"}" \ + $(Slack.team-daml-ci) + } + + EMAIL=$(git log -n 1 --format=%ae) + user_registered() { + cat ci/slack_user_ids | grep $EMAIL + } + + user_id() { + echo $(cat ci/slack_user_ids | grep $EMAIL | awk '{print $2}') + } + + if user_registered; then + tell_slack "$(Agent.JobStatus)" "$(user_id)" + else + echo "User $(user_id) did not opt in for notifications." + fi diff --git a/ci/slack_user_ids b/ci/slack_user_ids new file mode 100644 index 0000000000..97392bc509 --- /dev/null +++ b/ci/slack_user_ids @@ -0,0 +1,4 @@ +gary.verhaegen@digitalasset.com UEHSF89AQ +shayne.fletcher@digitalasset.com UBRBXAJHY +shayne@shaynefletcher.org UBRBXAJHY +stefano.baghino@digitalasset.com UD3MUK6TA diff --git a/ci/tell-slack-failed.yml b/ci/tell-slack-failed.yml index d590cb92ab..d6d2f1c045 100644 --- a/ci/tell-slack-failed.yml +++ b/ci/tell-slack-failed.yml @@ -6,5 +6,5 @@ steps: -i \ -H 'Content-type: application/json' \ --data "{\"text\":\" *FAILED* $(Agent.JobName): \n\"}" \ - $(Slack.URL) + $(Slack.team-daml) condition: and(failed(), eq(variables['Build.SourceBranchName'], 'master'))