Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/fbjorn/azure-devops-slack

Forward pull request notifications from Azure DevOps to Slack
https://github.com/fbjorn/azure-devops-slack

azure azure-devops pull-requests slack slack-bot

Last synced: about 1 month ago
JSON representation

Forward pull request notifications from Azure DevOps to Slack

Awesome Lists containing this project

README

        

# Slack 🤝 Azure DevOps code reviews

![Docker Image Version (latest semver)](https://img.shields.io/docker/v/fbjorn/devops-slack-pr-webhook?label=DockerHub&logo=docker&color=green&logoColor=white)

Do you

- 🚀 collaboratively work on code in Azure DevOps,
- 🧑‍💻 use Slack for work related communication,
- 🥵 hate spammy notifications in your mailbox?

Well, then you might like an idea to receive notifications from pull requests into
Slack.

It requires a bit of setup, but then all (configured) team members will be able to get
informed in direct messages:

1. **When a pull request is created, and they are assigned as reviewers**
image

2. **When their pull request is approved**
image

3. **When someone leaves a comment on their PRs**
image

4. When someone replies to their comment _[IN PROGRESS]_

# Setup

First of all, I think that all this information is sensitive since you're working in
private repositories. Thus, your data should not be transferred to 3rd parties. That's
why I didn't create a shared Slack application. It's up to you to host your own
notification webhook, because each DevOps event gets transferred through it.

## 1. Collect information about users

Slack doesn't know anything about your Azure users and vice versa. So you will have to
create a mapping for them manually. Moreover, not everyone in your team might want to
opt in for such notifications, so it's still a wise idea to compose this list by hands.

If you have an Azure CLI installed (and `jq` as a bonus), you can use this snippet:

```shell
az devops user list | jq ".items[].user | [.displayName, .mailAddress]"
```

Otherwise, go to `Organization settings` -> `Users` (or ask your admin to gather this
information) and save a list of emails and usernames.

Follow this article to
[find user IDs in Slack](https://www.workast.com/help/article/how-to-find-a-slack-user-id/).

After that, create a `users.yaml` in the repository root with the following structure:

```yaml
users:
- name_filter: Jane Doe
emails: ["[email protected]"]
slack_id: ABCDFOOBAR
```

Name filter is used to match a user if it's not matched by the email (there are some
cases when users change their emails but not the display name). It can be just a surname
or a name as well if it's kinda unique.

## 2. Create a Slack application

1. Go to Slack application management and [create a new app](https://api.slack.com/apps)
2. Choose "From an app manifest", select your workspace and copy the content from
[slack-app.manifest.json](./slack-app.manifest.json). Pick another name based on your
preferences. The important there is the permission to `chat:write`, otherwise the app
won't be able to post messages to DMs.
3. Go to "OAuth & Permissions" and save the value of `Bot User OAuth Token`

## 3. Deploy the webhook

There are few options for how you can deploy it. Feel free to suggest more. If you
decide to deploy it as a Google Cloud function, then you have to create a `.env` file
with the settings. If you want to deploy it as a Docker container, then it's up to you
how to pass the configuration inside. Anyway, the service is configured via the
environment variables.

```dotenv
# [REQUIRED]
# Slack application token from the previous step
SLACK_BOT_TOKEN=xoxb-123-foobar

# [REQUIRED for Docker, OPTIONAL for cloud functions]
# A list of users that will receive the messages from the bot.
# If you deploy as a Cloud Function, then no need to add it - the list will be
# taken automatically from `users.yaml`. If you deploy as a docker container,
# run `poetry run invoke convert-users`, this is the value you shoud set.
USERS='[ ]'

# [OPTIONAL]
# An HTTP header that you might want to configure later when setting up
# an event subscription in Azure DevOps. The value is up to you
API_KEY=foo-bar

# [OPTIONAL]
# Set this if you want to log the DevOps events and additional debug information
DEBUG=1
```

### Google Cloud Functions

Run the following command to deploy it from your computer or CI. Requires
[gcloud](https://cloud.google.com/sdk/docs/install) to be installed.

```bash
poetry run invoke deploy-cloud-function --help
```

### Anywhere as a Docker image

Deploy this image to a platform you like and don't forget to set environment variables.

```shell
fbjorn/devops-slack-pr-webhook:latest
```

The image is uploaded to
[DockerHub](https://hub.docker.com/repository/docker/fbjorn/devops-slack-pr-webhook)
automatically from GitHub Actions.

## 4. Set up triggers in Azure DevOps

Finally, go to Project Settings in Azure DevOps:
`https://dev.azure.com///_settings/`.

Open "Service hooks" section and click a plus icon for adding:

- `Web hooks / Pull request commented on` (v2.0)
- `Web hooks / Pull request created` (v1.0)
- `Web hooks / Pull request updated` (v1.0)

For each of them, enter the URL of the service that you deployed on a previous step.

Optionally, add an HTTP header `X-API-KEY:` if you configured it in the settings.

Save an enjoy being up-to-date 🎉

# Installation and local development

```shell
# install project dependencies
poetry install

# set up pre-commit hooks (required if you want to make PRs)
pre-commit install

# get information about useful commands
poetry run invoke --help

# run unit tests
poetry run pytest

# update unit test snapshots
poetry run pytest --snapshot-update

# export Poetry dependencies to Cloud Functions -acceptable format
poetry export > requirements.txt
```

## Recording Azure DevOps events for unit tests

```shell
# 1. Run ngrok or other tool that exposes a local port to the internet
ngrok http 8080

# 2. Edit corresponding service hook in Azure DevOps and set the new URL there

# 3. Run the following command and perform an action you'd like to record
# (for example merging a pull request)
poetry run invoke record-test-sample foo
```

This will create a `foo.json` under [tests/samples](./tests/samples) and you can use
this file for testing the parser logic.

Most likely, you don't want to expose IDs of your projects or users recording event
samples for tests. Neither do I. For that purpose, there's a script that simplifies
this. Create an `obfuscate.yaml` in the repo root with the following content:

```yaml
- from: Foo
into: Bar
```

And then run:

```shell
poetry run invoke obfuscate-tests
```

It will replace all `Foo` occurrences in samples with `Bar`.

# Contribution

Every PR and suggestion is welcomed. My team is using this project on daily basis, but
your Azure setup might be different resulting in potential bugs. Don't hesitate to
report issues, or record your event sample and add it to test cases.

I believe this project is a great example of a service to deploy as a stateless cloud
function, but I only tested it with Google. If you have successfully deployed it to
another cloud provider, please let me know, so we can update the instructions.