Skip to content

Commit 81003d6

Browse files
authored
Add Slack features (#3)
* Update README, fix examples, add .gitignore * Slack PR Author * Slack PR Author * test no token set * test no token set * test no token set * iterate * iterate * iterate * iterate * iterate * iterate * iterate * iterate * iterate * add example * remove unecessary line in example * Break up README lines and clarify on Slack user
1 parent fbd1d79 commit 81003d6

File tree

6 files changed

+227
-25
lines changed

6 files changed

+227
-25
lines changed

.circleci/config.yml

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,55 @@
1-
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
21
version: 2.1
3-
# Use a package of configuration called an orb.
2+
43
orbs:
5-
# Declare a dependency on the welcome-orb
6-
welcome: circleci/[email protected]
7-
# Orchestrate or schedule a set of jobs
4+
# dev version needs to be manually deployed to accurately test commit changes.
5+
# Once deployed, update <alpha> to reflect the version deployed.
6+
ghpr: narrativescience/ghpr@dev:alpha
7+
8+
commands:
9+
pack-validate:
10+
description: Pack and validate the orb config
11+
steps:
12+
- run:
13+
name: Pack config
14+
command: circleci config pack src > orb.yml
15+
- run:
16+
name: Valid orb.yml
17+
command: circleci orb validate orb.yml
18+
19+
jobs:
20+
test:
21+
machine: true
22+
steps:
23+
- ghpr/build-prospective-branch
24+
- ghpr/slack-pr-author:
25+
message: ":tada: Tests passed!"
26+
27+
publish:
28+
machine: true
29+
steps:
30+
- pack-validate
31+
- run:
32+
name: Publish new orb version
33+
command: |
34+
# TODO figure out how to configure CLI so publishing works
35+
circleci orb publish orb.yml "narrativescience/ghpr@$CIRCLE_TAG"
36+
837
workflows:
9-
# Name the workflow "welcome"
10-
welcome:
11-
# Run the welcome/run job in its own container
38+
pull_request:
1239
jobs:
13-
- welcome/run
40+
- test:
41+
context: opensource
42+
filters:
43+
branches:
44+
ignore:
45+
- master
46+
# TODO uncomment and make it possible to auto-publish
47+
# publish:
48+
# jobs:
49+
# - publish:
50+
# context: opensource
51+
# filters:
52+
# tags:
53+
# only: /v[0-9]+(\.[0-9]+)*/
54+
# branches:
55+
# ignore: /.*/

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
orb.yml

README.md

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,47 @@
1-
# CircleCI Orb: GitHub PR [![CircleCI Orb Version](https://img.shields.io/badge/endpoint.svg?url=https://badges.circleci.io/orb/narrativescience/ghpr)](https://circleci.com/orbs/registry/orb/narrativescience/ghpr) [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
1+
# CircleCI Orb: GitHub PR
22

3-
[View in CircleCI Orb Registry](https://circleci.com/orbs/registry/orb/narrativescience/ghpr)
3+
[![CircleCI Orb Version](https://img.shields.io/badge/endpoint.svg?url=https://badges.circleci.io/orb/narrativescience/ghpr)](https://circleci.com/orbs/registry/orb/narrativescience/ghpr)
4+
[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
45

5-
Set of git utilities to manage GitHub Pull Requests in CI, namely simulating the result of
6-
merging the head branch into the PR's target base branch.
6+
Set of git utilities to manage GitHub Pull Requests in CI.
7+
This orb was created to address the need to simulate the result of merging the head branch
8+
into a PR's target base branch.
79

8-
To use, create a service GitHub user with at least Read access to your repository and set the following environment variables in a [Context](https://circleci.com/docs/2.0/contexts/) or your [Project's Environment Variables](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project):
10+
Additional features:
911

10-
* `GITHUB_USERNAME` - Username of the service user that has read/write permissions to the repo.
11-
* `GITHUB_PASSWORD` - Password of the service user.
12-
* `GITHUB_EMAIL` - Email of the service user.
12+
- Posting PR comments on success/failure/always
13+
- Sending Slack notifications to PR authors
1314

1415
The commands in the orb will expose the following environment variables:
1516

1617
* `GITHUB_PR_BASE_BRANCH` - The base branch for the PR.
1718
* `GITHUB_PR_NUMBER` - The number of the PR.
19+
20+
## Getting Started
21+
22+
To use this orb, there are a few environment variables to set.
23+
These can be set in a [Context](https://circleci.com/docs/2.0/contexts/)
24+
or your [Project's Environment Variables](https://circleci.com/docs/2.0/env-vars/#setting-an-environment-variable-in-a-project).
25+
26+
### Setting up a GitHub service user
27+
28+
It's recommended to create a service GitHub user with at least Read access to your
29+
repository and set the following environment variables:
30+
31+
* `GITHUB_USERNAME` - Username of the service user that has read/write permissions to the repo.
32+
* `GITHUB_PASSWORD` - Password of the service user.
33+
* `GITHUB_EMAIL` - Email of the service user.
34+
35+
### Enabling Slack Notifications
36+
37+
To use the Slack related orb commands, create or use an existing
38+
[workspace bot](https://slack.com/help/articles/115005265703-Create-a-bot-for-your-workspace)
39+
and set the following environment variables:
40+
41+
* `SLACK_OAUTH_TOKEN` - [OAuth token](https://api.slack.com/docs/token-types#bot) for the Slack
42+
bot that will be used to send Slack messages.
43+
44+
This orb uses the [email associated with commits](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address)
45+
to look up the user in a Slack workspace. Therefore, to receive notifications, committers
46+
should set their `user.email` in their `git config` to be the same email associated with their Slack account.
47+
Messages show as being sent by the user associated with the `SLACK_OAUTH_TOKEN`.

src/@orb.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ description: Bundle of utils for GitHub pull requests
44
examples:
55
test-pull-request:
66
description: |
7-
Run pull request tests on a temporary branch resulting from merging the PR's head branch into the base branch, and send a comment on test failure.
7+
Run pull request tests on a temporary branch resulting from merging the PR's head branch into the base branch. Post a PR comment on test failure, but Slack the author on success.
88
usage:
99
version: 2.1
1010
orbs:
11-
jq: circleci/[email protected]
12-
gh-pr: narrativescience/[email protected]
11+
ghpr: narrativescience/[email protected]
1312
jobs:
1413
run-test:
15-
docker:
16-
- image: circleci/python:3.7.1
14+
machine: true
1715
steps:
18-
- gh-pr/build-prospective-branch
16+
- ghpr/build-prospective-branch
1917
- some-test-command
20-
- gh-pr/post-pr-comment:
18+
- ghpr/post-pr-comment:
2119
comment: "some message"
2220
when: on_fail
21+
- ghpr/slack-pr-author:
22+
message: ":tada: Tests passed!"

src/commands/post-pr-comment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ parameters:
1616
steps:
1717
- run:
1818
name: Post comment to PR
19+
when: << parameters.when >>
1920
command: |
2021
GITHUB_PR_NUMBER=$(echo "$CIRCLE_PULL_REQUEST" | sed "s/.*\/pull\///")
2122
curl \
2223
-X POST \
2324
-d "{\"body\": \"<< parameters.comment >>\"}" \
2425
--user "${GITHUB_USERNAME}:${GITHUB_PASSWORD}" \
2526
"https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/issues/${GITHUB_PR_NUMBER}/comments"
26-
when: << parameters.when >>

src/commands/slack-pr-author.yml

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
description: |
2+
Send a Slack direct message to the PR author, or to a channel, @mentioning the PR author.
3+
Requires `SLACK_OAUTH_TOKEN` to be set as an environment variable.
4+
5+
For more details, see https://github.com/NarrativeScience/circleci-orb-ghpr#enabling-slack-notifactions
6+
parameters:
7+
message:
8+
description: |
9+
The message to send.
10+
Supports Slack mrkdown syntax - https://api.slack.com/reference/surfaces/formatting#basics
11+
type: string
12+
when:
13+
description: Condition for when the DM should be sent
14+
type: enum
15+
enum:
16+
- on_success
17+
- on_fail
18+
- always
19+
default: on_success
20+
channel:
21+
description: |
22+
Optional channel to send a message to, ex. `#some-channel`.
23+
If provided, will message the channel but @mention the PR author.
24+
Otherwise, the message is sent to the PR author directly.
25+
type: string
26+
default: ""
27+
steps:
28+
- run:
29+
name: Slack PR author
30+
when: << parameters.when >>
31+
command: |
32+
# Check `jq` dependency
33+
if ! (command -v jq >/dev/null 2>&1); then
34+
echo "This command requires jq to be installed"
35+
exit 1
36+
fi
37+
38+
# Check `SLACK_OAUTH_TOKEN` is set
39+
if [[ -z ${SLACK_OAUTH_TOKEN+x} ]]; then
40+
echo "This command requires SLACK_OAUTH_TOKEN to be set"
41+
exit 1
42+
fi
43+
44+
API_GITHUB="https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
45+
46+
GITHUB_PR_NUMBER=$(echo "$CIRCLE_PULL_REQUEST" | sed "s/.*\/pull\///")
47+
PR_REQUEST_URL="$API_GITHUB/pulls/$GITHUB_PR_NUMBER"
48+
PR_RESPONSE=$(curl --user "${GITHUB_USERNAME}:${GITHUB_PASSWORD}" "$PR_REQUEST_URL")
49+
PR_TITLE=$(echo $PR_RESPONSE | jq -e '.title' | tr -d '"')
50+
51+
# Get the merge_commit_sha. This is so we can message the PR author, not the commit
52+
# author who may not be the PR author.
53+
MERGE_COMMIT_SHA=$(echo $PR_RESPONSE | jq -e '.merge_commit_sha' | tr -d '"')
54+
55+
# Sadly, PR_RESPONSE doesn't include the email associated with the MERGE_COMMIT_SHA.
56+
# So we have to get that from the commit information.
57+
COMMIT_REQUEST_URL="$API_GITHUB/commits/$MERGE_COMMIT_SHA"
58+
COMMIT_RESPONSE=$(curl --user "${GITHUB_USERNAME}:${GITHUB_PASSWORD}" "$COMMIT_REQUEST_URL")
59+
PR_AUTHOR_EMAIL=$(echo $COMMIT_RESPONSE | jq -e '.commit.author.email' | tr -d '"')
60+
61+
SLACK_USER=$(curl -H 'Content-Type: application/x-www-form-urlencoded' \
62+
-H 'Cache-Control: no-cache' \
63+
-d "token=$SLACK_OAUTH_TOKEN" \
64+
-d "email=$PR_AUTHOR_EMAIL" \
65+
"https://slack.com/api/users.lookupByEmail")
66+
SLACK_USER_ID=$(echo $SLACK_USER | jq -e '.user.id' | tr -d '"')
67+
68+
if [[ $SLACK_USER_ID == "null" ]]; then
69+
echo "No Slack user found with email $PR_AUTHOR_EMAIL"
70+
exit 1
71+
fi
72+
73+
MESSAGE="*<< parameters.message >>*"
74+
CHANNEL=$SLACK_USER_ID
75+
76+
if [[ -n "<< parameters.channel >>" ]]; then
77+
MESSAGE="$MESSAGE\n<@$SLACK_USER_ID>"
78+
CHANNEL="<< parameters.channel >>"
79+
fi
80+
81+
BLOCKS="[
82+
{
83+
\"type\": \"section\",
84+
\"text\": {
85+
\"type\": \"mrkdwn\",
86+
\"text\": \"$MESSAGE\"
87+
},
88+
\"accessory\": {
89+
\"type\": \"button\",
90+
\"text\": {
91+
\"type\": \"plain_text\",
92+
\"text\": \"Visit Job\"
93+
},
94+
\"url\": \"$CIRCLE_BUILD_URL\"
95+
}
96+
},
97+
{
98+
\"type\": \"section\",
99+
\"text\": {
100+
\"type\": \"mrkdwn\",
101+
\"text\": \"*Pull Request:* <$CIRCLE_PULL_REQUEST|$PR_TITLE>\"
102+
}
103+
},
104+
{
105+
\"type\": \"context\",
106+
\"elements\": [
107+
{
108+
\"type\": \"mrkdwn\",
109+
\"text\": \"Project: *$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME*\"
110+
},
111+
{
112+
\"type\": \"mrkdwn\",
113+
\"text\": \"Branch: *$CIRCLE_BRANCH*\"
114+
}
115+
]
116+
}
117+
]"
118+
119+
CURL_ARGS=(
120+
-X POST
121+
-H 'Content-Type: application/x-www-form-urlencoded'
122+
-H 'Cache-Control: no-cache'
123+
-d "token=$SLACK_OAUTH_TOKEN"
124+
-d 'as_user=true'
125+
-d "channel=$CHANNEL"
126+
-d "blocks=$BLOCKS"
127+
)
128+
curl "${CURL_ARGS[@]}" "https://slack.com/api/chat.postMessage"

0 commit comments

Comments
 (0)