diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index 9253c3501..9e28382d9 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -14,3 +14,4 @@ stages: - template: templates/stages/test-and-package-stage.yml - template: templates/stages/changelog-stage.yml - template: templates/stages/release-deploy-stage.yml + - template: templates/stages/notify-stage.yml diff --git a/.azure-pipelines/templates/stages/notify-stage.yml b/.azure-pipelines/templates/stages/notify-stage.yml new file mode 100644 index 000000000..e1ea4871f --- /dev/null +++ b/.azure-pipelines/templates/stages/notify-stage.yml @@ -0,0 +1,20 @@ +stages: + - stage: Notify + condition: succeededOrFailed() + jobs: + - job: notify_release_finished + pool: + vmImage: ubuntu-latest + steps: + - task: DownloadSecureFile@1 + name: webhook_url + inputs: + secureFile: mattermost_webhook_url_release_notify + - bash: | + set -e + python -m venv venv + source venv/bin/activate + tools/pip_install.py requests + AUTHOR_NAME="$(git log -1 --pretty=format:'%an')" + tools/notify_mattermost.py "${AUTHOR_NAME}" $(webhook_url.secureFilePath) + displayName: Send mattermost message diff --git a/.azure-pipelines/templates/stages/release-deploy-stage.yml b/.azure-pipelines/templates/stages/release-deploy-stage.yml index 8bf259446..866d6994d 100644 --- a/.azure-pipelines/templates/stages/release-deploy-stage.yml +++ b/.azure-pipelines/templates/stages/release-deploy-stage.yml @@ -1,4 +1,6 @@ stages: + # tools/notify_mattermost.py depends on this stage being named 'Deploy' + # If you change the name here, please remember to update that script as well - stage: Deploy jobs: - template: ../jobs/common-deploy-jobs.yml diff --git a/tools/notify_mattermost.py b/tools/notify_mattermost.py new file mode 100755 index 000000000..320f90c64 --- /dev/null +++ b/tools/notify_mattermost.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +""" +Script to notify the person doing the release that the Azure run was successful. + +Run: + +python tools/notify_mattermost.py GITHUB_AUTHOR_NAME MATTERMOST_WEBHOOK_URL +""" +import os +import random +import requests +import sys + +repo_name = os.environ['BUILD_REPOSITORY_ID'] +build_id = os.environ['BUILD_BUILDID'] + +def get_greeting(): + fun_greetings = [ + 'Hey', + 'Paging', + 'Hi', + 'Pinging', + ] + return random.choice(fun_greetings) + +def get_message(): + fun_success_messages = [ + 'the certbot release is ready to come out of the oven!', + "it's release-finishing go time!", + 'all certbot release systems are set for launch!', + ] + + # https://learn.microsoft.com/en-us/rest/api/azure/devops/build/timeline/get?view=azure-devops-rest-7.1 + timeline_url = f'https://dev.azure.com/{repo_name}/_apis/build/builds/{build_id}/timeline/?api-version=7.1' + response = requests.get(timeline_url) + response.raise_for_status() + data = response.json() + deploy_record = next((rec for rec in data['records'] if rec['name'] == 'Deploy'), None) + if deploy_record is None: + raise RuntimeError('Unable to find the record for the Deploy stage') + deploy_result = deploy_record['result'] + if deploy_result in ['succeeded', 'succeededWithIssues']: + message = random.choice(fun_success_messages) + elif deploy_result in ['skipped', 'failed', 'abandoned']: + message = "the release pipeline has failed." + else: + raise RuntimeError('Unexpected stage result {0}'.format(deploy_result)) + return message + +def get_mattermost_url(): + # This should be a mattermost webhook url that posts to a specific channel, + # created by certbotbot, with a file containing the url saved in azure pipelines secret + # files, under pipelines > library. The secret file will need to be given permission to + # be used by the specific pipeline, in this case 'release.' + url_path = sys.argv[2] + with open(url_path, 'r') as file: + url = file.read().rstrip() + return url + +def get_headers(): + headers = { + 'Content-Type': 'application/json', + } + return headers + +def get_content(): + build_url = f'https://dev.azure.com/{repo_name}/_build/results?buildId={build_id}&view=results' + + # We use github author here because it's what we have access to. If the name sometimes + # changes, add any name it might be. Check the git log. + requested_for = sys.argv[1].rstrip() + # This is a map of team member github author names to opensource mattermost username + usernames_map = { + 'Will Greenberg': 'willg', + 'Erica Portnoy': 'erica', + 'Brad Warren': 'brad', + 'ohemorange': 'erica', + } + + if requested_for in usernames_map: + text_body = f'{get_greeting()} @{usernames_map[requested_for]}, {get_message()}\n{build_url}' + else: + text_body = (f"{get_greeting()} {requested_for}, {get_message()}\nIf you'd like to get @ mentioned for " + "releases you do in the future, please modify tools/notify_mattermost.py with your " + f"git author name.\n{build_url}") + + content = { + 'text': text_body, + } + return content + +response = requests.request( + method='POST', + url=get_mattermost_url(), + headers=get_headers(), + json=get_content(), +) +response.raise_for_status()